From 25dbfe4c0f5a41c2420f6fe4a39d515068618b06 Mon Sep 17 00:00:00 2001 From: Craig Barnes Date: Fri, 14 Sep 2012 06:54:40 +0100 Subject: [PATCH 01/40] Import Lua release 5.2.1 --- Makefile | 114 + README | 6 + doc/contents.html | 531 ++ doc/logo.gif | Bin 0 -> 4232 bytes doc/lua.1 | 116 + doc/lua.css | 83 + doc/luac.1 | 118 + doc/manual.css | 24 + doc/manual.html | 10425 ++++++++++++++++++++++++++++++++++ doc/osi-certified-72x60.png | Bin 0 -> 3774 bytes doc/readme.html | 410 ++ src/Makefile | 187 + src/lapi.c | 1281 +++++ src/lapi.h | 24 + src/lauxlib.c | 958 ++++ src/lauxlib.h | 212 + src/lbaselib.c | 459 ++ src/lbitlib.c | 209 + src/lcode.c | 882 +++ src/lcode.h | 83 + src/lcorolib.c | 155 + src/lctype.c | 52 + src/lctype.h | 95 + src/ldblib.c | 398 ++ src/ldebug.c | 580 ++ src/ldebug.h | 34 + src/ldo.c | 668 +++ src/ldo.h | 46 + src/ldump.c | 173 + src/lfunc.c | 161 + src/lfunc.h | 33 + src/lgc.c | 1205 ++++ src/lgc.h | 147 + src/linit.c | 67 + src/liolib.c | 657 +++ src/llex.c | 527 ++ src/llex.h | 78 + src/llimits.h | 309 + src/lmathlib.c | 283 + src/lmem.c | 99 + src/lmem.h | 50 + src/loadlib.c | 725 +++ src/lobject.c | 289 + src/lobject.h | 610 ++ src/lopcodes.c | 107 + src/lopcodes.h | 288 + src/loslib.c | 323 ++ src/lparser.c | 1635 ++++++ src/lparser.h | 119 + src/lstate.c | 322 ++ src/lstate.h | 228 + src/lstring.c | 185 + src/lstring.h | 46 + src/lstrlib.c | 972 ++++ src/ltable.c | 588 ++ src/ltable.h | 41 + src/ltablib.c | 283 + src/ltm.c | 77 + src/ltm.h | 57 + src/lua.c | 496 ++ src/lua.h | 439 ++ src/lua.hpp | 9 + src/luac.c | 432 ++ src/luaconf.h | 546 ++ src/lualib.h | 55 + src/lundump.c | 258 + src/lundump.h | 28 + src/lvm.c | 868 +++ src/lvm.h | 45 + src/lzio.c | 76 + src/lzio.h | 65 + 71 files changed, 32151 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 doc/contents.html create mode 100644 doc/logo.gif create mode 100644 doc/lua.1 create mode 100644 doc/lua.css create mode 100644 doc/luac.1 create mode 100644 doc/manual.css create mode 100644 doc/manual.html create mode 100644 doc/osi-certified-72x60.png create mode 100644 doc/readme.html create mode 100644 src/Makefile create mode 100644 src/lapi.c create mode 100644 src/lapi.h create mode 100644 src/lauxlib.c create mode 100644 src/lauxlib.h create mode 100644 src/lbaselib.c create mode 100644 src/lbitlib.c create mode 100644 src/lcode.c create mode 100644 src/lcode.h create mode 100644 src/lcorolib.c create mode 100644 src/lctype.c create mode 100644 src/lctype.h create mode 100644 src/ldblib.c create mode 100644 src/ldebug.c create mode 100644 src/ldebug.h create mode 100644 src/ldo.c create mode 100644 src/ldo.h create mode 100644 src/ldump.c create mode 100644 src/lfunc.c create mode 100644 src/lfunc.h create mode 100644 src/lgc.c create mode 100644 src/lgc.h create mode 100644 src/linit.c create mode 100644 src/liolib.c create mode 100644 src/llex.c create mode 100644 src/llex.h create mode 100644 src/llimits.h create mode 100644 src/lmathlib.c create mode 100644 src/lmem.c create mode 100644 src/lmem.h create mode 100644 src/loadlib.c create mode 100644 src/lobject.c create mode 100644 src/lobject.h create mode 100644 src/lopcodes.c create mode 100644 src/lopcodes.h create mode 100644 src/loslib.c create mode 100644 src/lparser.c create mode 100644 src/lparser.h create mode 100644 src/lstate.c create mode 100644 src/lstate.h create mode 100644 src/lstring.c create mode 100644 src/lstring.h create mode 100644 src/lstrlib.c create mode 100644 src/ltable.c create mode 100644 src/ltable.h create mode 100644 src/ltablib.c create mode 100644 src/ltm.c create mode 100644 src/ltm.h create mode 100644 src/lua.c create mode 100644 src/lua.h create mode 100644 src/lua.hpp create mode 100644 src/luac.c create mode 100644 src/luaconf.h create mode 100644 src/lualib.h create mode 100644 src/lundump.c create mode 100644 src/lundump.h create mode 100644 src/lvm.c create mode 100644 src/lvm.h create mode 100644 src/lzio.c create mode 100644 src/lzio.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..bd9515fd84 --- /dev/null +++ b/Makefile @@ -0,0 +1,114 @@ +# Makefile for installing Lua +# See doc/readme.html for installation and customization instructions. + +# == 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 and doc directories, +# 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 +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. +INSTALL= install -p +INSTALL_EXEC= $(INSTALL) -m 0755 +INSTALL_DATA= $(INSTALL) -m 0644 +# +# If you don't have "install" you can use "cp" instead. +# INSTALL= cp -p +# INSTALL_EXEC= $(INSTALL) +# INSTALL_DATA= $(INSTALL) + +# Other utilities. +MKDIR= mkdir -p +RM= rm -f + +# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE ======= + +# Convenience platforms targets. +PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris + +# What to install. +TO_BIN= lua luac +TO_INC= lua.h luaconf.h lualib.h lauxlib.h lua.hpp +TO_LIB= liblua.a +TO_MAN= lua.1 luac.1 + +# Lua version and release. +V= 5.2 +R= $V.1 + +# Targets start here. +all: $(PLAT) + +$(PLATS) clean: + cd src && $(MAKE) $@ + +test: dummy + src/lua -v + +install: dummy + cd src && $(MKDIR) $(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) + +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) + +local: + $(MAKE) install INSTALL_TOP=../install + +none: + @echo "Please do 'make PLATFORM' where PLATFORM is one of these:" + @echo " $(PLATS)" + @echo "See doc/readme.html for complete instructions." + +# make may get confused with test/ and install/ +dummy: + +# echo config parameters +echo: + @cd src && $(MAKE) -s echo + @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 + +# (end of Makefile) diff --git a/README b/README new file mode 100644 index 0000000000..253d110692 --- /dev/null +++ b/README @@ -0,0 +1,6 @@ + +This is Lua 5.2.1, released on 08 Jun 2012. + +For installation instructions, license details, and +further information about Lua, see doc/readme.html. + diff --git a/doc/contents.html b/doc/contents.html new file mode 100644 index 0000000000..9f5060519f --- /dev/null +++ b/doc/contents.html @@ -0,0 +1,531 @@ + + + +Lua 5.2 Reference Manual - contents + + + + + + + +
+

+ +Lua 5.2 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. + +

+start +· +contents +· +index +


+ +Copyright © 2011–2012 Lua.org, PUC-Rio. +Freely available under the terms of the +Lua license. + + +

Contents

+ + +

Index

+ + + + + + + +
+

Lua functions

+

+_G
+_VERSION
+ +

+assert
+collectgarbage
+dofile
+error
+getmetatable
+ipairs
+loadfile
+load
+next
+pairs
+pcall
+print
+rawequal
+rawget
+rawlen
+rawset
+require
+select
+setmetatable
+tonumber
+tostring
+type
+xpcall
+ +

+bit32.arshift
+bit32.band
+bit32.bnot
+bit32.bor
+bit32.btest
+bit32.bxor
+bit32.extract
+bit32.lrotate
+bit32.lshift
+bit32.replace
+bit32.rrotate
+bit32.rshift
+ +

+coroutine.create
+coroutine.resume
+coroutine.running
+coroutine.status
+coroutine.wrap
+coroutine.yield
+ +

+debug.debug
+debug.getuservalue
+debug.gethook
+debug.getinfo
+debug.getlocal
+debug.getmetatable
+debug.getregistry
+debug.getupvalue
+debug.setuservalue
+debug.sethook
+debug.setlocal
+debug.setmetatable
+debug.setupvalue
+debug.traceback
+debug.upvalueid
+debug.upvaluejoin
+ +

+file:close
+file:flush
+file:lines
+file:read
+file:seek
+file:setvbuf
+file:write
+ +

+io.close
+io.flush
+io.input
+io.lines
+io.open
+io.output
+io.popen
+io.read
+io.stderr
+io.stdin
+io.stdout
+io.tmpfile
+io.type
+io.write
+ +

+

 

+

+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.huge
+math.ldexp
+math.log
+math.max
+math.min
+math.modf
+math.pi
+math.pow
+math.rad
+math.random
+math.randomseed
+math.sin
+math.sinh
+math.sqrt
+math.tan
+math.tanh
+ +

+os.clock
+os.date
+os.difftime
+os.execute
+os.exit
+os.getenv
+os.remove
+os.rename
+os.setlocale
+os.time
+os.tmpname
+ +

+package.config
+package.cpath
+package.loaded
+package.loadlib
+package.path
+package.preload
+package.searchers
+package.searchpath
+ +

+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.pack
+table.remove
+table.sort
+table.unpack
+ +

+

C API

+

+lua_Alloc
+lua_CFunction
+lua_Debug
+lua_Hook
+lua_Integer
+lua_Number
+lua_Reader
+lua_State
+lua_Unsigned
+lua_Writer
+ +

+lua_absindex
+lua_arith
+lua_atpanic
+lua_call
+lua_callk
+lua_checkstack
+lua_close
+lua_compare
+lua_concat
+lua_copy
+lua_createtable
+lua_dump
+lua_error
+lua_gc
+lua_getallocf
+lua_getctx
+lua_getfield
+lua_getglobal
+lua_gethook
+lua_gethookcount
+lua_gethookmask
+lua_getinfo
+lua_getlocal
+lua_getmetatable
+lua_getstack
+lua_gettable
+lua_gettop
+lua_getupvalue
+lua_getuservalue
+lua_insert
+lua_isboolean
+lua_iscfunction
+lua_isfunction
+lua_islightuserdata
+lua_isnil
+lua_isnone
+lua_isnoneornil
+lua_isnumber
+lua_isstring
+lua_istable
+lua_isthread
+lua_isuserdata
+lua_len
+lua_load
+lua_newstate
+lua_newtable
+lua_newthread
+lua_newuserdata
+lua_next
+lua_pcall
+lua_pcallk
+lua_pop
+lua_pushboolean
+lua_pushcclosure
+lua_pushcfunction
+lua_pushfstring
+lua_pushinteger
+lua_pushlightuserdata
+lua_pushliteral
+lua_pushlstring
+lua_pushnil
+lua_pushnumber
+lua_pushstring
+lua_pushthread
+lua_pushvalue
+lua_pushvfstring
+lua_rawequal
+lua_rawget
+lua_rawgeti
+lua_rawlen
+lua_rawset
+lua_rawseti
+lua_rawgetp
+lua_rawsetp
+lua_register
+lua_remove
+lua_replace
+lua_resume
+lua_setallocf
+lua_setfield
+lua_setglobal
+lua_sethook
+lua_setlocal
+lua_setmetatable
+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
+lua_tounsigned
+lua_tounsignedx
+lua_touserdata
+lua_type
+lua_typename
+lua_upvalueid
+lua_upvalueindex
+lua_upvaluejoin
+lua_version
+lua_xmove
+lua_yield
+lua_yieldk
+ +

+

auxiliary library

+

+luaL_Buffer
+luaL_Reg
+ +

+luaL_addchar
+luaL_addlstring
+luaL_addsize
+luaL_addstring
+luaL_addvalue
+luaL_argcheck
+luaL_argerror
+luaL_buffinit
+luaL_buffinitsize
+luaL_callmeta
+luaL_checkany
+luaL_checkinteger
+luaL_checkint
+luaL_checklong
+luaL_checklstring
+luaL_checknumber
+luaL_checkoption
+luaL_checkstack
+luaL_checkstring
+luaL_checktype
+luaL_checkudata
+luaL_checkunsigned
+luaL_checkversion
+luaL_dofile
+luaL_dostring
+luaL_error
+luaL_execresult
+luaL_fileresult
+luaL_getmetafield
+luaL_getmetatable
+luaL_getsubtable
+luaL_gsub
+luaL_len
+luaL_loadbuffer
+luaL_loadbufferx
+luaL_loadfile
+luaL_loadfilex
+luaL_loadstring
+luaL_newlib
+luaL_newlibtable
+luaL_newmetatable
+luaL_newstate
+luaL_openlibs
+luaL_optinteger
+luaL_optint
+luaL_optlong
+luaL_optlstring
+luaL_optnumber
+luaL_optstring
+luaL_optunsigned
+luaL_prepbuffer
+luaL_prepbuffsize
+luaL_pushresult
+luaL_pushresultsize
+luaL_ref
+luaL_requiref
+luaL_setfuncs
+luaL_setmetatable
+luaL_testudata
+luaL_tolstring
+luaL_traceback
+luaL_typename
+luaL_unref
+luaL_where
+ +

+ +
+ +Last update: +Sat May 26 08:52:25 BRT 2012 + + + + + 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..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 new file mode 100644 index 0000000000..7fafbb1bb6 --- /dev/null +++ b/doc/lua.css @@ -0,0 +1,83 @@ +body { + color: #000000 ; + background-color: #FFFFFF ; + font-family: Helvetica, Arial, sans-serif ; + text-align: justify ; + margin-right: 30px ; + margin-left: 30px ; +} + +h1, h2, h3, h4 { + font-family: Verdana, Geneva, sans-serif ; + font-weight: normal ; + font-style: italic ; +} + +h2 { + padding-top: 0.4em ; + padding-bottom: 0.4em ; + padding-left: 30px ; + padding-right: 30px ; + margin-left: -30px ; + background-color: #E0E0FF ; +} + +h3 { + padding-left: 0.5em ; + border-left: solid #E0E0FF 1em ; +} + +table h3 { + padding-left: 0px ; + border-left: none ; +} + +a:link { + color: #000080 ; + background-color: inherit ; + text-decoration: none ; +} + +a:visited { + background-color: inherit ; + text-decoration: none ; +} + +a:link:hover, a:visited:hover { + color: #000080 ; + background-color: #E0E0FF ; +} + +a:link:active, a:visited:active { + color: #FF0000 ; +} + +hr { + border: 0 ; + height: 1px ; + color: #a0a0a0 ; + background-color: #a0a0a0 ; +} + +:target { + background-color: #F8F8F8 ; + 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: 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 new file mode 100644 index 0000000000..b49b362937 --- /dev/null +++ b/doc/manual.css @@ -0,0 +1,24 @@ +h3 code { + font-family: inherit ; + font-size: inherit ; +} + +pre, code { + font-size: 12pt ; +} + +span.apii { + float: right ; + font-family: inherit ; + font-style: normal ; + font-size: small ; + color: gray ; +} + +p+h1, ul+h1 { + padding-top: 0.4em ; + padding-bottom: 0.4em ; + padding-left: 30px ; + margin-left: -30px ; + background-color: #E0E0FF ; +} diff --git a/doc/manual.html b/doc/manual.html new file mode 100644 index 0000000000..4ba084dfc8 --- /dev/null +++ b/doc/manual.html @@ -0,0 +1,10425 @@ + + + + +Lua 5.2 Reference Manual + + + + + + + +
+

+ +Lua 5.2 Reference Manual +

+ +by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes +

+ +Copyright © 2011–2012 Lua.org, PUC-Rio. +Freely available under the terms of the +Lua license. + +


+

+ +contents +· +index + + +

+ + + + + + +

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, 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++. + + +

+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. +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, +for interactive or batch use. + + +

+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, +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 – Basic Concepts

+ +

+This section describes the basic concepts of the language. + + + +

2.1 – 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. +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: +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; +it usually represents the absence of a useful value. +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.) +String represents immutable sequences of bytes. + +Lua is 8-bit clean: +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 §3.4.9). + + +

+The type userdata is provided to allow arbitrary C data to +be stored in Lua variables. +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. +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. +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.6). +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 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, 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 +providing a.name as syntactic sugar for a["name"]. +There are several convenient ways to create tables in Lua +(see §3.4.8). + + +

+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). + + +

+Like indices, +the values of table fields 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 raw equality in the language. +The expressions a[i] and a[j] +denote the same table element +if and only if i and j are raw equal +(that is, equal without metamethods). + + +

+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 +of a given value (see §6.1). + + + + + +

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 local variable called _ENV (see §3.3.2), +so _ENV itself is never a global name in a chunk. + + +

+Despite the existence of this external _ENV variable and +the translation of global names, +_ENV is a completely regular name. +In particular, +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 (see §3.5). + + +

+Any table used as the value of _ENV is 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 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 +and several functions there operate on that 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.) + + +

+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 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. + + + + + +

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 +the compilation or execution of a Lua chunk, +control returns to the host, +which can take appropriate measures +(such as printing 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 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 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. +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; +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. + + + + + +

2.4 – Metatables and Metamethods

+ +

+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" of the value's metatable. +If it finds one, +Lua calls this function to perform the addition. + + +

+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 +using the getmetatable function. + + +

+You can replace the metatable of tables +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. + + +

+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). + + +

+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 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) +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 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. +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 + +

+     metatable(obj)[event]
+

+This should be read as + +

+     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). + + +

+For the unary - and # operators, +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. +(For most uses this extra argument is irrelevant.) + + + +

    + +
  • "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
    +

    +By using 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(···)
    +         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
    +       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. +

  • + +
  • "eq": +the == operation. + +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, +and the values are either tables or full userdata. + +
    +     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
    +

    +The "eq" event is defined as follows: + +

    +     function eq_event (op1, op2)
    +       if op1 == op2 then   -- primitive equal?
    +         return true   -- values are equal
    +       end
    +       -- try metamethod
    +       local h = getequalhandler(op1, op2)
    +       if h then
    +         return not not h(op1, op2)
    +       else
    +         return false
    +       end
    +     end
    +

    +Note that the result is always a boolean. +

  • + +
  • "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 = getbinhandler(op1, op2, "__lt")
    +         if h then
    +           return not not h(op1, op2)
    +         else
    +           error(···)
    +         end
    +       end
    +     end
    +

    +Note that the result is always a boolean. +

  • + +
  • "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 = getbinhandler(op1, op2, "__le")
    +         if h then
    +           return not not 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). + + +

    +As with the other comparison operators, +the result is always a boolean. +

  • + +
  • "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.) + + +
    +     function gettable_event (table, key)
    +       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
    +       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. +Note that the metamethod is tried only +when key is not present in table. + + +
    +     function settable_event (table, key, value)
    +       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
    +       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
    +

    +

  • + +
  • "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
    +

    +

  • + +
+ + + + +

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: +strings, tables, userdata, functions, threads, internal structures, 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 +(e.g., a value of 100 means an internal value of 1). + + +

+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. + + +

+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 is 200, +which means that the collector runs at "twice" +the speed of memory allocation. + + +

+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. +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

+ +

+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 +(such as closing files, network or database connections, +or freeing your own memory). + + +

+For an object (table or userdata) to be finalized when collected, +you must mark it for finalization. + +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 object will not be marked for finalization. +However, after an object is marked, +you can freely change the __gc field of its metatable. + + +

+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 object in that list: + +

+     function gc_event (obj)
+       local h = metatable(obj).__gc
+       if type(h) == "function" then
+         h(obj)
+       end
+     end
+
+ +

+At the end of each garbage-collection cycle, +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 object marked last in the program. +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, +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. + + +

+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. + + + + + +

2.5.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 +__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. + + +

+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 through its value, +the pair is removed. + + +

+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 +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). +Although strings are subject to garbage collection, +they do not have an explicit construction, +and therefore are not removed from weak tables. + + +

+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. + + + + + + + +

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. + + +

+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. + + +

+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, +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. + + +

+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. + + +

+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. + + +

+As an example of how coroutines work, +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
+
+ +

+You can also create and manipulate coroutines through the C API: +see functions lua_newthread, lua_resume, +and lua_yield. + + + + + +

3 – 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. + + +

+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 §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. + + +

+Names +(also called identifiers) +in Lua can be any string of letters, +digits, and underscores, +not beginning with a digit. +Identifiers are used to name variables, table fields, and labels. + + +

+The following keywords are reserved +and cannot be used as names: + + +

+     and       break     do        else      elseif    end
+     false     for       function  goto      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 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]). +A backslash followed by a real newline +results in a newline in the string. +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 literal string +into multiple lines without adding the newlines and spaces +into the string contents. + + +

+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, +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 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, +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. + + +

+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. + + +

+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 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 'p' or 'P'. +Examples of valid numerical constants are + +

+     3     3.0     3.1416     314.16e-2     0.31416E1
+     0xff  0x0.1E  0xA23p-4   0X1.921FB54442D18P+1
+
+ +

+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. + + + + + +

3.2 – 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 function's formal parameter, +which is a particular kind of local variable): + +

+	var ::= Name
+

+Name denotes identifiers, as defined in §3.1. + + +

+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. + + +

+Square brackets are used to index a table: + +

+	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 +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 syntax var.Name is just syntactic sugar for +var["Name"]: + +

+	var ::= prefixexp ‘.’ Name
+
+ +

+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). + + + + + +

3.3 – 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. + + + +

3.3.1 – Blocks

+ +

+A block is a list of statements, +which are executed sequentially: + +

+	block ::= {stat}
+

+Lua has empty statements +that allow you to separate statements with semicolons, +start a block with a semicolon +or write two semicolons in sequence: + +

+	stat ::= ‘;’
+
+ +

+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 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 +(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). +The resulting function always has _ENV as its only upvalue, +even if it does not use that variable. + + +

+A chunk can be stored in a file or in a string inside the host program. +To execute a chunk, +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 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. + + + + + + +

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: + +

+	stat ::= varlist ‘=’ explist
+	varlist ::= var {‘,’ var}
+	explist ::= exp {‘,’ exp}
+

+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 + +

+     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, +and + +

+     x, y, z = y, z, x
+

+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.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.) + + +

+An assignment to a global variable x = val +is equivalent to the assignment +_ENV.x = val (see §2.2). + + + + + +

3.3.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 §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. + + +

+The goto statement transfers the program control to a label. +For syntactical reasons, +labels in Lua are considered statements too: + + + +

+	stat ::= goto Name
+	stat ::= label
+	label ::= ‘::’ 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. + + +

+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
+

+A break ends the innermost enclosing loop. + + +

+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 idiom do return end, +because now return is the last statement in its (inner) block. + + + + + +

3.3.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 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: + +

    + +
  • +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. +
  • + +
  • +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. +
  • + +
+ +

+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}
+

+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)
+         if var_1 == nil then break end
+         var = var_1
+         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. +
  • + +
+ + + + +

3.3.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 §3.4.9. + + + + + +

3.3.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 §3.3.3). +Otherwise, all variables are initialized with nil. + + +

+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 visibility rules for local variables are explained in §3.5. + + + + + + + +

3.4 – Expressions

+ +

+The basic expressions in Lua are the following: + +

+	exp ::= prefixexp
+	exp ::= nil | false | true
+	exp ::= Number
+	exp ::= String
+	exp ::= functiondef
+	exp ::= tableconstructor
+	exp ::= ‘...’
+	exp ::= exp binop exp
+	exp ::= unop exp
+	prefixexp ::= var | functioncall | ‘(’ exp ‘)’
+
+ +

+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. + + +

+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 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 expression is enclosed in parentheses). +In all other contexts, +Lua adjusts the result list to one element, +discarding all values except the first one. + + +

+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 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.) + + + +

3.4.1 – Arithmetic Operators

+Lua supports the usual arithmetic operators: +the binary + (addition), +- (subtraction), * (multiplication), +/ (division), % (modulo), and ^ (exponentiation); +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. +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. + + + + + +

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 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. +For complete control over how numbers are converted to strings, +use the format function from the string library +(see string.format). + + + + + +

3.4.3 – 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 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, 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. + + +

+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. + + + + + +

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: + +

+     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.) + + + + + +

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). + + + + + +

3.4.6 – The Length Operator

+ +

+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). + + +

+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, +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 + +

+     {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 positive numeric keys of that table.) +Note, however, that non-numeric keys do not interfere +with whether a table is a sequence. + + + + + +

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. + + + + + +

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 ::= ‘{’ [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 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 §3.4.9). + + +

+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). + + +

+The form + +

+	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. + + +

+Arguments have the following syntax: + +

+	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. + + +

+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

+ +

+The syntax for function definition is + +

+	functiondef ::= function funcbody
+	funcbody ::= ‘(’ [parlist] ‘)’ 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 () body end
+

+translates to + +

+     f = function () body end
+

+The statement + +

+     function t.a.b.c.f () body end
+

+translates to + +

+     t.a.b.c.f = function () body end
+

+The statement + +

+     local function f () body end
+

+translates to + +

+     local f; f = function () body end
+

+not to + +

+     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, +whose value has type function. +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) +is the final value of the expression. + + +

+Parameters act as local variables that are +initialized with the argument values: + +

+	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 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
+
+ +

+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. + + +

+ +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, +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 + +

+     t.a.b.c.f = function (self, params) body end
+
+ + + + + + +

3.5 – Visibility Rules

+ +

+ +Lua is a lexically scoped language. +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: + +

+     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. +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. + + + + + +

4 – 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. +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. + + +

+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 the macro LUA_USE_APICHECK defined. + + + +

4.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. +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, +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 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) +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. + + + + + +

4.2 – Stack Size

+ +

+When you interact with the 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 ensure that the stack has extra slots when pushing new elements. + + +

+Whenever Lua calls C, +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. + + +

+When you call a Lua function +without a fixed number of results (see lua_call), +Lua ensures that the stack has enough size for all results, +but it does not ensure any extra space. +So, before pushing anything in the stack after such a call +you should use lua_checkstack. + + + + + +

4.3 – Valid and Acceptable Indices

+ +

+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 <= 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. + + +

+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. + + +

+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). + + + + + +

4.4 – C Closures

+ +

+When a C function is created, +it is possible to associate some values with it, +thus creating a C closure +(see lua_pushcclosure); +these values are called upvalues and are +accessible to the function whenever it 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. +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. + + + + + +

4.5 – Registry

+ +

+Lua provides a 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. +Any C library can store data into this table, +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, +or any Lua object created by your code. +As with global names, +string keys starting with an underscore followed by +uppercase letters are reserved for Lua. + + +

+The integer keys in the registry are used by the reference mechanism, +implemented by the auxiliary library, +and by some predefined values. +Therefore, integer keys should not be used for other purposes. + + +

+When you create a new Lua state, +its registry comes with some predefined values. +These predefined values are indexed with integer keys +defined as constants in lua.h. +The following constants are defined: + +

    +
  • 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 +the global environment. +
  • +
+ + + + +

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.) +When Lua faces any error +(such as a memory allocation error, 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 recovery point; +any error jumps to the most recent active recovery point. + + +

+If an error happens outside any protected environment, +Lua calls a panic function (see lua_atpanic) +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 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. +The documentation for each function indicates whether +it can throw errors. + + +

+Inside a C function you can throw an error by calling lua_error. + + + + + +

4.7 – Handling Yields in C

+ +

+Internally, Lua uses the C longjmp facility to yield a coroutine. +Therefore, if a function foo calls an API function +and this API function yields +(directly or indirectly by calling another function that yields), +Lua cannot return to foo any more, +because the longjmp removes its frame from the C stack. + + +

+To avoid this kind of problem, +Lua raises an error whenever it tries to yield across an API call, +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 a yield. + + +

+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, +which we will call the callee function, +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.) + + +

+Suppose the running thread yields while executing the callee function. +After the thread resumes, +it eventually will finish running the callee function. +However, +the callee function cannot return to the original function, +because its frame in the C stack was destroyed by the yield. +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 +of 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. +(For instance, +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 were the return +of the original function. + + +

+The only difference in the Lua state between the original function +and its continuation is the result of a call to lua_getctx. + + + + + +

4.8 – 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 can 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; +'e' means the function may throw errors; +'v' means the function may throw an error on purpose. + + + +


lua_absindex

+[-0, +0, –] +

int 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,
+                             size_t osize,
+                             size_t nsize);
+ +

+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, an opaque pointer passed to lua_newstate; +ptr, a pointer to the block being allocated/reallocated/freed; +osize, the original size of the block or some code about what +is being allocated; +nsize, the new size of the block. + + +

+When ptr is not NULL, +osize is the size of the block pointed by ptr, +that is, the size given when it was allocated or reallocated. + + +

+When ptr is NULL, +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) +Lua is creating a new object of that type. +When osize is some other value, +Lua is allocating memory for something else. + + +

+Lua assumes the following behavior from the allocator function: + + +

+When nsize is zero, +the allocator should behave like free +and return NULL. + + +

+When nsize is not zero, +the allocator should behave like realloc. +The allocator returns NULL +if and only if it cannot fulfill the request. +Lua assumes that the allocator never fails when +osize >= nsize. + + +

+Here is a simple implementation for the allocator function. +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;  (void)osize;  /* not used */
+       if (nsize == 0) {
+         free(ptr);
+         return NULL;
+       }
+       else
+         return realloc(ptr, nsize);
+     }
+

+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. +(Although Standard C does not ensure this behavior, +it seems to be a safe assumption.) + + + + + +


lua_arith

+[-(2|1), +1, e] +

void lua_arith (lua_State *L, int op);
+ +

+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). + + +

+The value of op must be one of the following constants: + +

+ + + + +

lua_atpanic

+[-0, +0, –] +

lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
+ +

+Sets a new panic function and returns the old one (see §4.6). + + + + + +


lua_call

+[-(nargs+1), +nresults, e] +

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 +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 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 +(with a longjmp). + + +

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

+     a = f("how", t.x, 14)
+

+Here it is in C: + +

+     lua_getglobal(L, "f");                  /* function to be called */
+     lua_pushstring(L, "how");                        /* 1st argument */
+     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_setglobal(L, "a");                         /* set global '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_callk

+[-(nargs + 1), +nresults, e] +

void lua_callk (lua_State *L, int nargs, int nresults, int ctx,
+                lua_CFunction k);
+ +

+This function behaves exactly like lua_call, +but allows the called function to yield (see §4.7). + + + + + +


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 +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. +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 +discarded 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");
+           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

+[-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 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. +This function never shrinks the stack; +if the stack is already larger than the new size, +it is left unchanged. + + + + + +


lua_close

+[-0, +0, –] +

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, +because all resources are naturally released when the host program ends. +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. + + + + + +


lua_compare

+[-0, +0, e] +

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 +(that is, it may call metamethods). +Otherwise returns 0. +Also returns 0 if any of the indices is non valid. + + +

+The value of op must be one of the following constants: + +

    + +
  • LUA_OPEQ: compares for equality (==)
  • +
  • LUA_OPLT: compares for less than (<)
  • +
  • LUA_OPLE: compares for less or equal (<=)
  • + +
+ + + + +

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 value on the stack +(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 §3.4.5). + + + + + +


lua_copy

+[-0, +0, –] +

void lua_copy (lua_State *L, int fromidx, int toidx);
+ +

+Moves the element at the valid index fromidx +into the valid index toidx +without shifting any element +(therefore replacing the value at that position). + + + + + +


lua_createtable

+[-0, +1, e] +

void lua_createtable (lua_State *L, int narr, int nrec);
+ +

+Creates a new empty table and pushes it onto the stack. +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. + + + + + +


lua_dump

+[-0, +0, e] +

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, +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 +call to the writer; +0 means no errors. + + +

+This function does not pop the Lua function from the stack. + + + + + +


lua_error

+[-1, +0, v] +

int lua_error (lua_State *L);
+ +

+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). + + + + + +


lua_gc

+[-0, +0, e] +

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. +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 experimentally tune the value of data. +The function returns 1 if the step finished a +garbage-collection cycle. +
  • + +
  • 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: +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: +returns a boolean that tells whether the collector is running +(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 these options, +see collectgarbage. + + + + + +


lua_getallocf

+[-0, +0, –] +

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_getctx

+[-0, +0, –] +

int lua_getctx (lua_State *L, int *ctx);
+ +

+This function is called by a continuation function (see §4.7) +to retrieve the status of the thread and a context information. + + +

+When called in the original function, +lua_getctx always returns LUA_OK +and does not change the value of its argument ctx. +When called inside a continuation function, +lua_getctx returns LUA_YIELD and sets +the value of ctx to be the context information +(the value passed as the ctx argument +to the callee together with the continuation function). + + +

+When the callee is lua_pcallk, +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 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); +the value of ctx will be set to the context information, +as in the case of a yield. + + + + + +


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. +As in Lua, this function may trigger a metamethod +for the "index" event (see §2.4). + + + + + +


lua_getglobal

+[-0, +1, e] +

void lua_getglobal (lua_State *L, const char *name);
+ +

+Pushes onto the stack the value of the global name. + + + + + +


lua_getmetatable

+[-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 value does not have a metatable, +the function returns 0 and pushes nothing on the stack. + + + + + +


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 +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.4). + + + + + +


lua_gettop

+[-0, +0, –] +

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). + + + + + +


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);
+ +

+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 signed integral values. + + +

+By default it is a ptrdiff_t, +which is usually the largest signed integral type the machine handles +"comfortably". + + + + + +


lua_isboolean

+[-0, +0, –] +

int lua_isboolean (lua_State *L, int index);
+ +

+Returns 1 if the value at the given acceptable index is a boolean, +and 0 otherwise. + + + + + +


lua_iscfunction

+[-0, +0, –] +

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

+[-0, +0, –] +

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

+[-0, +0, –] +

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

+[-0, +0, –] +

int lua_isnil (lua_State *L, int index);
+ +

+Returns 1 if the value at the given acceptable index is nil, +and 0 otherwise. + + + + + +


lua_isnone

+[-0, +0, –] +

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), +and 0 otherwise. + + + + + +


lua_isnoneornil

+[-0, +0, –] +

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) +or if the value at this index is nil, +and 0 otherwise. + + + + + +


lua_isnumber

+[-0, +0, –] +

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

+[-0, +0, –] +

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

+[-0, +0, –] +

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

+[-0, +0, –] +

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

+[-0, +0, –] +

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_len

+[-0, +1, e] +

void lua_len (lua_State *L, int index);
+ +

+Returns the "length" of the value at the given acceptable index; +it is equivalent to the '#' operator in Lua (see §3.4.6). +The result is pushed on the stack. + + + + + +


lua_load

+[-0, +1, –] +

int lua_load (lua_State *L,
+              lua_Reader reader,
+              void *data,
+              const char *source,
+              const char *mode);
+ +

+Loads a Lua chunk (without running it). +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: + +

    + +
  • LUA_OK: no errors;
  • + +
  • LUA_ERRSYNTAX: +syntax error during precompilation;
  • + +
  • LUA_ERRMEM: +memory allocation error;
  • + +
  • 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.) +
  • + +
+ +

+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. + + +

+The source argument gives a name to the chunk, +which is used for error messages and in debug information (see §4.9). + + +

+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 +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). + + + + + +


lua_newstate

+[-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 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 +passes to the allocator in every call. + + + + + +


lua_newtable

+[-0, +1, e] +

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). + + + + + +


lua_newthread

+[-0, +1, e] +

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 thread returned by this function shares with the original thread +its global environment, +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

+[-0, +1, e] +

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. +The host program can freely use this memory. + + + + + +


lua_next

+[-1, +(2|0), e] +

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: + +

+     /* table is in the stack at index 't' */
+     lua_pushnil(L);  /* first key */
+     while (lua_next(L, t) != 0) {
+       /* 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)));
+       /* removes 'value'; keeps 'key' for next iteration */
+       lua_pop(L, 1);
+     }
+
+ +

+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 may change +the value at the given index; +this confuses the next call to lua_next. + + +

+See function next for the caveats of modifying +the table during its traversal. + + + + + +


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 this configuration file you can change +Lua to operate with another type for numbers (e.g., float or long). + + + + + +


lua_pcall

+[-(nargs + 1), +(nresults|1), –] +

int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);
+ +

+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 msgh is 0, +then the error message returned on the stack +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.) +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. + + +

+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. + + +

+The lua_pcall function returns one of the following codes +(defined in lua.h): + +

    + +
  • LUA_OK (0): +success.
  • + +
  • LUA_ERRRUN: +a runtime error. +
  • + +
  • LUA_ERRMEM: +memory allocation error. +For such errors, Lua does not call the message handler. +
  • + +
  • LUA_ERRERR: +error while running the message handler. +
  • + +
  • 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.) +
  • + +
+ + + + +

lua_pcallk

+[-(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, +but allows the called function to yield (see §4.7). + + + + + +


lua_pop

+[-n, +0, –] +

void lua_pop (lua_State *L, int n);
+ +

+Pops n elements from the stack. + + + + + +


lua_pushboolean

+[-0, +1, –] +

void lua_pushboolean (lua_State *L, int b);
+ +

+Pushes a boolean value with value b onto the stack. + + + + + +


lua_pushcclosure

+[-n, +1, e] +

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 §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 +(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, +with the argument n telling how many values should be +associated with the function. +lua_pushcclosure also pops these values from the stack. + + +

+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 never throws a memory error. + + + + + +


lua_pushcfunction

+[-0, +1, –] +

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 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 +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. + + + + + +


lua_pushfstring

+[-0, +1, e] +

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, +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 +(and deallocation, through garbage collection). +
  • + +
  • +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 byte). +
  • + +
+ + + + +

lua_pushinteger

+[-0, +1, –] +

void lua_pushinteger (lua_State *L, lua_Integer n);
+ +

+Pushes a number with value n onto the stack. + + + + + +


lua_pushlightuserdata

+[-0, +1, –] +

void lua_pushlightuserdata (lua_State *L, void *p);
+ +

+Pushes a light userdata onto the stack. + + +

+Userdata represent C values in Lua. +A light userdata represents a pointer, a void*. +It is a value (like a number): +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. + + + + + +


lua_pushliteral

+[-0, +1, e] +

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. + + + + + +


lua_pushlstring

+[-0, +1, e] +

const char *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 any binary data, +including embedded zeros. + + +

+Returns a pointer to the internal copy of the string. + + + + + +


lua_pushnil

+[-0, +1, –] +

void lua_pushnil (lua_State *L);
+ +

+Pushes a nil value onto the stack. + + + + + +


lua_pushnumber

+[-0, +1, –] +

void lua_pushnumber (lua_State *L, lua_Number n);
+ +

+Pushes a number with value n onto the stack. + + + + + +


lua_pushstring

+[-0, +1, e] +

const char *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. + + +

+Returns a pointer to the internal copy of the string. + + +

+If s is NULL, pushes nil and returns NULL. + + + + + +


lua_pushthread

+[-0, +1, –] +

int lua_pushthread (lua_State *L);
+ +

+Pushes the thread represented by L onto the stack. +Returns 1 if this thread is the main thread of its state. + + + + + +


lua_pushvalue

+[-0, +1, –] +

void lua_pushvalue (lua_State *L, int index);
+ +

+Pushes a copy of the element at the given valid index +onto the stack. + + + + + +


lua_pushvfstring

+[-0, +1, e] +

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

+[-0, +0, –] +

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

+[-1, +1, –] +

void lua_rawget (lua_State *L, int index);
+ +

+Similar to lua_gettable, but does a raw access +(i.e., without metamethods). + + + + + +


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 table at the given valid index. +The access is raw; +that is, it does not invoke metamethods. + + + + + +


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, –] +

size_t lua_rawlen (lua_State *L, int index);
+ +

+Returns the raw "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 ('#') +with no metamethods; +for userdata, this is the size of the block of memory allocated +for the userdata; +for other values, it is 0. + + + + + +


lua_rawset

+[-2, +0, e] +

void lua_rawset (lua_State *L, int index);
+ +

+Similar to lua_settable, but does a raw assignment +(i.e., without metamethods). + + + + + +


lua_rawseti

+[-1, +0, e] +

void lua_rawseti (lua_State *L, int index, int n);
+ +

+Does the equivalent of t[n] = v, +where t is the table at the given valid 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_rawsetp

+[-1, +0, e] +

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,
+                                    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. +The block must exist until the reader function is called again. +To signal the end of the chunk, +the reader must return NULL or set size to zero. +The reader function may return pieces of any size greater than zero. + + + + + +


lua_register

+[-0, +0, e] +

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

+[-1, +0, –] +

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

+[-1, +0, –] +

void lua_replace (lua_State *L, int index);
+ +

+Moves the top element into the given position +without shifting any element +(therefore replacing the value at the given position), +and then pops the top element. + + + + + +


lua_resume

+[-?, +?, –] +

int lua_resume (lua_State *L, lua_State *from, int nargs);
+ +

+Starts and resumes a coroutine in a given thread. + + +

+To start a coroutine, +you push onto the thread stack the main function plus any arguments; +then you call lua_resume, +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. +lua_resume returns +LUA_YIELD if the coroutine yields, +LUA_OK 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. +The error message is on the top of the stack. + + +

+To resume a coroutine, you put on its stack only the values to +be passed as results from yield, +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, –] +

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_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 +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.4). + + + + + +


lua_setglobal

+[-1, +0, e] +

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. + + + + + +


lua_setmetatable

+[-1, +0, –] +

void 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

+[-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, +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.4). + + + + + +


lua_settop

+[-?, +?, –] +

void lua_settop (lua_State *L, int index);
+ +

+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. + + + + + +


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;
+ +

+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 accessible through this structure. + + +

+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. + + + + + +


lua_status

+[-0, +0, –] +

int lua_status (lua_State *L);
+ +

+Returns the status of the thread L. + + +

+The status can be 0 (LUA_OK) for a normal thread, +an error code if the thread finished the execution +of a lua_resume with an error, +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 coroutine). + + + + + +


lua_toboolean

+[-0, +0, –] +

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 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.) + + + + + +


lua_tocfunction

+[-0, +0, –] +

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

+[-0, +0, –] +

lua_Integer lua_tointeger (lua_State *L, int index);
+ +

+Equivalent to lua_tointegerx with isnum equal to 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_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 +indicates whether the operation succeeded. + + + + + +


lua_tolstring

+[-0, +0, e] +

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. +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 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') +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 +will be valid after the corresponding value is removed from the stack. + + + + + +


lua_tonumber

+[-0, +0, –] +

lua_Number lua_tonumber (lua_State *L, int index);
+ +

+Equivalent to lua_tonumberx with isnum equal to 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_tonumberx returns 0. + + +

+If isnum is not NULL, +its referent is assigned a boolean value that +indicates whether the operation succeeded. + + + + + +


lua_topointer

+[-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. +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

+[-0, +0, e] +

const char *lua_tostring (lua_State *L, int index);
+ +

+Equivalent to lua_tolstring with len equal to NULL. + + + + + +


lua_tothread

+[-0, +0, –] +

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_tounsigned

+[-0, +0, –] +

lua_Unsigned lua_tounsigned (lua_State *L, int index);
+ +

+Equivalent to lua_tounsignedx with isnum equal to 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 not 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);
+ +

+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

+[-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. +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, +and +LUA_TLIGHTUSERDATA. + + + + + +


lua_typename

+[-0, +0, –] +

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_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);
+ +

+Returns the address of the version number stored in the Lua core. +When called with a valid lua_State, +returns the address of the version used to create that state. +When called with NULL, +returns the address of the version running the call. + + + + + +


lua_Writer

+
typedef int (*lua_Writer) (lua_State *L,
+                           const void* p,
+                           size_t sz,
+                           void* ud);
+ +

+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), +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 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);
+ +

+This function is equivalent to lua_yieldk, +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. + + + + + +


lua_yieldk

+[-?, +?, –] +

int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k);
+ +

+Yields a coroutine. + + +

+This function should only be called as the +return expression of a C function, as follows: + +

+     return lua_yieldk (L, n, i, k);
+

+When a C function calls lua_yieldk 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. + + +

+When the coroutine is resumed again, +Lua calls the given continuation function k to continue +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 +replaced by the arguments passed to lua_resume. +Moreover, +the continuation function may access the value ctx +by calling lua_getctx. + + + + + + + +

4.9 – 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 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 */
+  other fields
+} lua_Debug;
+ +

+A structure used to carry different pieces of +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, +call lua_getinfo. + + +

+The fields of lua_Debug have the following meaning: + +

    + +
  • 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 +the file name follows the '@'. +If source starts with a '=', +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. +
  • + +
  • 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 the function is a Lua function, +"C" if it is a C function, +"main" if it 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. +
  • + +
  • 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 can be the value of multiple global variables, +while others can 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.) +
  • + +
  • 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: +the number of upvalues of the function. +
  • + +
  • nparams: +the number of fixed parameters of the function +(always 0 for C functions). +
  • + +
  • isvararg: +true if the function is a vararg function +(always true for C functions). +
  • + +
+ + + + +

lua_gethook

+[-0, +0, –] +

lua_Hook lua_gethook (lua_State *L);
+ +

+Returns the current hook function. + + + + + +


lua_gethookcount

+[-0, +0, –] +

int lua_gethookcount (lua_State *L);
+ +

+Returns the current hook count. + + + + + +


lua_gethookmask

+[-0, +0, –] +

int lua_gethookmask (lua_State *L);
+ +

+Returns the current hook mask. + + + + + +


lua_getinfo

+[-(0|1), +(0|1|2), e] +

int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
+ +

+Gets 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 from 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_getglobal(L, "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, short_src, +linedefined, lastlinedefined, and what; +
  • + +
  • 'l': fills in the field currentline; +
  • + +
  • 't': fills in the field istailcall; +
  • + +
  • 'u': fills in the fields +nups, nparams, and isvararg; +
  • + +
  • '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). + + + + + +


lua_getlocal

+[-0, +(0|1), –] +

const char *lua_getlocal (lua_State *L, lua_Debug *ar, int n);
+ +

+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; +see debug.getlocal for details about variable indices +and names. + + +

+lua_getlocal pushes the variable's value onto the stack +and returns its name. + + +

+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 +the number of active local variables. + + + + + +


lua_getstack

+[-0, +0, –] +

int lua_getstack (lua_State *L, int level, lua_Debug *ar);
+ +

+Gets 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 +(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. + + + + + +


lua_getupvalue

+[-0, +(0|1), –] +

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, +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 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_HOOKTAILCALL, 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 call events, event can be LUA_HOOKCALL, +the normal value, or LUA_HOOKTAILCALL, for a tail call; +in this case, there will be no corresponding return event. + + +

+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. + + +

+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. + + + + + +


lua_sethook

+[-0, +0, –] +

int lua_sethook (lua_State *L, lua_Hook f, int mask, int count);
+ +

+Sets the debugging 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, +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, +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. +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 +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

+[-(0|1), +0, –] +

const char *lua_setlocal (lua_State *L, 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) +when the index is greater than +the number of active local variables. + + + + + +


lua_setupvalue

+[-(0|1), +0, –] +

const char *lua_setupvalue (lua_State *L, int funcindex, int n);
+ +

+Sets the value of a closure's upvalue. +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. + + + + + +


lua_upvalueid

+[-0, +0, –] +

void *lua_upvalueid (lua_State *L, int funcindex, int n);
+ +

+Returns an 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). + + +

+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. + + + + + +


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 funcindex1 +refer to the n2-th upvalue of the Lua closure at index funcindex2. + + + + + + + +

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 +interactions between C and Lua, +the auxiliary library provides higher-level functions for some +common tasks. + + +

+All functions and types 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 +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. + + +

+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. +Because the error message is formatted for arguments +(e.g., "bad argument #1"), +you should not use these functions for other stack values. + + +

+Functions called luaL_check* +always throw an error if the check is not satisfied. + + + +

5.1 – Functions and Types

+ +

+Here we list all functions and types from the auxiliary library +in alphabetical order. + + + +


luaL_addchar

+[-?, +?, e] +

void luaL_addchar (luaL_Buffer *B, char c);
+ +

+Adds the byte c to the buffer B +(see luaL_Buffer). + + + + + +


luaL_addlstring

+[-?, +?, e] +

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 can contain embedded zeros. + + + + + +


luaL_addsize

+[-?, +?, e] +

void luaL_addsize (luaL_Buffer *B, size_t n);
+ +

+Adds to the buffer B (see luaL_Buffer) +a string of length n previously copied to the +buffer area (see luaL_prepbuffer). + + + + + +


luaL_addstring

+[-?, +?, e] +

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 cannot contain embedded zeros. + + + + + +


luaL_addvalue

+[-1, +?, e] +

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

+[-0, +0, v] +

void luaL_argcheck (lua_State *L,
+                    int cond,
+                    int arg,
+                    const char *extramsg);
+ +

+Checks whether cond is true. +If not, raises an error with a standard message. + + + + + +


luaL_argerror

+[-0, +0, v] +

int luaL_argerror (lua_State *L, int arg, const char *extramsg);
+ +

+Raises an error with a standard message +that includes extramsg as a comment. + + +

+This function never returns, +but it is an idiom to use it in C functions +as return luaL_argerror(args). + + + + + +


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 declare a variable b of type luaL_Buffer.
  • + +
  • Then initialize it with a call luaL_buffinit(L, &b).
  • + +
  • +Then add string pieces to the buffer calling any of +the luaL_add* functions. +
  • + +
  • +Finish by calling luaL_pushresult(&b). +This call leaves the final string on the top of the stack. +
  • + +
+ +

+If you know beforehand the total size of the resulting string, +you can use the buffer like this: + +

    + +
  • First declare a variable b of type luaL_Buffer.
  • + +
  • Then initialize it and preallocate a space of +size sz with a call luaL_buffinitsize(L, &b, sz).
  • + +
  • Then copy the string into that space.
  • + +
  • +Finish by calling luaL_pushresultsize(&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. +So, while using a buffer, you cannot assume that you know where +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 +level when the buffer was initialized, +plus the final string on its top. + + + + + +


luaL_buffinit

+[-0, +0, –] +

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_buffinitsize

+[-?, +?, e] +

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);
+ +

+Calls a metamethod. + + +

+If the object at index obj has a metatable and this +metatable has a field e, +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, +this function returns false (without pushing any value on the stack). + + + + + +


luaL_checkany

+[-0, +0, v] +

void luaL_checkany (lua_State *L, int arg);
+ +

+Checks whether the function has an argument +of any type (including nil) at position arg. + + + + + +


luaL_checkint

+[-0, +0, v] +

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. + + + + + +


luaL_checkinteger

+[-0, +0, v] +

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. + + + + + +


luaL_checklong

+[-0, +0, v] +

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. + + + + + +


luaL_checklstring

+[-0, +0, v] +

const char *luaL_checklstring (lua_State *L, int arg, size_t *l);
+ +

+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. + + +

+This function uses lua_tolstring to get its result, +so all conversions and caveats of that function apply here. + + + + + +


luaL_checknumber

+[-0, +0, v] +

lua_Number luaL_checknumber (lua_State *L, int arg);
+ +

+Checks whether the function argument arg is a number +and returns this number. + + + + + +


luaL_checkoption

+[-0, +0, v] +

int luaL_checkoption (lua_State *L,
+                      int arg,
+                      const char *def,
+                      const char *const lst[]);
+ +

+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. +Raises an error if the argument is not a string or +if the string cannot be found. + + +

+If def is not NULL, +the function uses def as a default value when +there is no argument arg or when this argument is nil. + + +

+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

+[-0, +0, v] +

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 +(or NULL for no additional text). + + + + + +


luaL_checkstring

+[-0, +0, v] +

const char *luaL_checkstring (lua_State *L, int arg);
+ +

+Checks whether the function argument arg is a string +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

+[-0, +0, v] +

void luaL_checktype (lua_State *L, int arg, int t);
+ +

+Checks whether the function argument arg has type t. +See lua_type for the encoding of types for t. + + + + + +


luaL_checkudata

+[-0, +0, v] +

void *luaL_checkudata (lua_State *L, int arg, const char *tname);
+ +

+Checks whether the function argument arg is a userdata +of the type tname (see luaL_newmetatable) and +returns the userdata address (see lua_touserdata). + + + + + +


luaL_checkunsigned

+[-0, +0, v] +

lua_Unsigned luaL_checkunsigned (lua_State *L, int arg);
+ +

+Checks whether the function argument arg is a number +and returns this number cast to a lua_Unsigned. + + + + + +


luaL_checkversion

+[-0, +0, –] +

void luaL_checkversion (lua_State *L);
+ +

+Checks whether the core running the call, +the core that created the Lua state, +and the code making the call are all using the same version of Lua. +Also checks whether the core running the call +and the core that created the Lua state +are using the same address space. + + + + + +


luaL_dofile

+[-0, +?, e] +

int luaL_dofile (lua_State *L, const char *filename);
+ +

+Loads and runs the given file. +It is defined as the following macro: + +

+     (luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))
+

+It returns false if there are no errors +or true in case of errors. + + + + + +


luaL_dostring

+[-0, +?, –] +

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 false if there are no errors +or true in case of errors. + + + + + +


luaL_error

+[-0, +0, v] +

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. +It also adds at the beginning of the message the file name and +the line number where the error occurred, +if this information is available. + + +

+This function never returns, +but it is an idiom to use it in C functions +as return luaL_error(args). + + + + + +


luaL_execresult

+[-0, +3, e] +

int luaL_execresult (lua_State *L, int stat);
+ +

+This function produces the return values for +process-related functions in the standard library +(os.execute and io.close). + + + + + +


luaL_fileresult

+[-0, +(1|3), e] +

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.). + + + + + +


luaL_getmetafield

+[-0, +(0|1), e] +

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 false and pushes nothing. + + + + + +


luaL_getmetatable

+[-0, +1, –] +

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_getsubtable

+[-0, +1, e] +

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, e] +

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_len

+[-0, +0, e] +

int luaL_len (lua_State *L, int index);
+ +

+Returns the "length" of the value at the given acceptable 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. +(This case only can happen through metamethods.) + + + + + +


luaL_loadbuffer

+[-0, +1, –] +

int luaL_loadbuffer (lua_State *L,
+                     const char *buff,
+                     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 +buffer pointed to 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. +The string mode works as in function lua_load. + + + + + +


luaL_loadfile

+[-0, +1, e] +

int luaL_loadfile (lua_State *L, const char *filename);
+ +

+Equivalent to luaL_loadfilex with mode equal to NULL. + + + + + +


luaL_loadfilex

+[-0, +1, e] +

int luaL_loadfilex (lua_State *L, const char *filename,
+                                            const char *mode);
+ +

+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 #. + + +

+The string mode works as in function lua_load. + + +

+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 or the file has a wrong mode. + + +

+As lua_load, this function only loads the chunk; +it does not run it. + + + + + +


luaL_loadstring

+[-0, +1, –] +

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. + + +

+Also as lua_load, this function only loads the chunk; +it does not run it. + + + + + +


luaL_newlib

+[-0, +1, e] +

int luaL_newlib (lua_State *L, const luaL_Reg *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, e] +

int luaL_newlibtable (lua_State *L, const luaL_Reg l[]);
+ +

+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). + + +

+It is implemented as a macro. +The array l must be the actual array, +not a pointer to it. + + + + + +


luaL_newmetatable

+[-0, +1, e] +

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 onto the stack the final value associated +with tname in the registry. + + + + + +


luaL_newstate

+[-0, +0, –] +

lua_State *luaL_newstate (void);
+ +

+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 §4.6) 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_openlibs

+[-0, +0, e] +

void luaL_openlibs (lua_State *L);
+ +

+Opens all standard Lua libraries into the given state. + + + + + +


luaL_optint

+[-0, +0, v] +

int luaL_optint (lua_State *L, int arg, int d);
+ +

+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. +Otherwise, raises an error. + + + + + +


luaL_optinteger

+[-0, +0, v] +

lua_Integer luaL_optinteger (lua_State *L,
+                             int arg,
+                             lua_Integer d);
+ +

+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. +Otherwise, raises an error. + + + + + +


luaL_optlong

+[-0, +0, v] +

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 this argument is absent or is nil, +returns d. +Otherwise, raises an error. + + + + + +


luaL_optlstring

+[-0, +0, v] +

const char *luaL_optlstring (lua_State *L,
+                             int arg,
+                             const char *d,
+                             size_t *l);
+ +

+If the function argument arg 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, +fills the position *l with the result's length. + + + + + +


luaL_optnumber

+[-0, +0, v] +

lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number d);
+ +

+If the function argument arg is a number, +returns this number. +If this argument is absent or is nil, +returns d. +Otherwise, raises an error. + + + + + +


luaL_optstring

+[-0, +0, v] +

const char *luaL_optstring (lua_State *L,
+                            int arg,
+                            const char *d);
+ +

+If the function argument arg is a string, +returns this string. +If this argument is absent or is nil, +returns d. +Otherwise, raises an error. + + + + + +


luaL_optunsigned

+[-0, +0, v] +

lua_Unsigned luaL_optunsigned (lua_State *L,
+                               int arg,
+                               lua_Unsigned u);
+ +

+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. +Otherwise, raises an error. + + + + + +


luaL_prepbuffer

+[-?, +?, e] +

char *luaL_prepbuffer (luaL_Buffer *B);
+ +

+Equivalent to luaL_prepbuffsize +with the predefined size LUAL_BUFFERSIZE. + + + + + +


luaL_prepbuffsize

+[-?, +?, e] +

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 +luaL_addsize with the size of the string to actually add +it to the buffer. + + + + + +


luaL_pushresult

+[-?, +1, e] +

void luaL_pushresult (luaL_Buffer *B);
+ +

+Finishes the use of buffer B leaving the final string on +the top of the stack. + + + + + +


luaL_pushresultsize

+[-?, +1, e] +

void luaL_pushresultsize (luaL_Buffer *B, size_t sz);
+ +

+Equivalent to the sequence luaL_addsize, luaL_pushresult. + + + + + +


luaL_ref

+[-1, +0, e] +

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 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 +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_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 +in which both name and func are NULL. + + + + + +


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. + + +

+Leaves a copy of that result on the stack. + + + + + +


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). + + +

+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, e] +

void *luaL_testudata (lua_State *L, int arg, const char *tname);
+ +

+This function works like luaL_checkudata, +except that, when the test fails, +it returns NULL instead of throwing an error. + + + + + +


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, e] +

void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
+                     int level);
+ +

+Creates and pushes a traceback of the stack L1. +If msg is not NULL it is appended +at the beginning of the traceback. +The level parameter tells at which level +to start the traceback. + + + + + +


luaL_typename

+[-0, +0, –] +

const char *luaL_typename (lua_State *L, int index);
+ +

+Returns the name of the type of the value at the given index. + + + + + +


luaL_unref

+[-0, +0, –] +

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

+[-0, +1, e] +

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 following 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. + + + + + + + +

6 – Standard Libraries

+ +

+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 requirements that +deserve an implementation in C (e.g., table.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 (§6.1);
  • + +
  • coroutine library (§6.2);
  • + +
  • package library (§6.3);
  • + +
  • string manipulation (§6.4);
  • + +
  • table manipulation (§6.5);
  • + +
  • mathematical functions (§6.6) (sin, log, etc.);
  • + +
  • bitwise operations (§6.7);
  • + +
  • input and output (§6.8);
  • + +
  • operating system facilities (§6.9);
  • + +
  • debug facilities (§6.10).
  • + +

+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. + + +

+To have access to these libraries, +the C host program should call the luaL_openlibs function, +which opens all standard libraries. +Alternatively, +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), +luaopen_string (for the string library), +luaopen_table (for the table library), +luaopen_math (for the mathematical 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). +These functions are declared in lualib.h. + + + +

6.1 – Basic Functions

+ +

+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. + + +

+


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. +It performs different functions according to its first argument, opt: + +

    + +
  • "collect": +performs a full garbage-collection cycle. +This is the default option. +
  • + +
  • "stop": +stops automatic execution of the garbage collector. +The collector will run only when explicitly invoked, +until a call to restart it. +
  • + +
  • "restart": +restarts automatic execution of the garbage collector. +
  • + +
  • "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, +so the following equality is always true: + +
    +     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": +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 experimentally tune the value of arg. +Returns true if the step finished a collection cycle. +
  • + +
  • "setpause": +sets arg as the new value for the pause of +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.5). +Returns the previous value for step. +
  • + +
  • "isrunning": +returns a boolean that tells whether the collector is running +(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. +
  • + +
+ + + +

+


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 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])

+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, if the message is a string. +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 (see §2.2). +Lua itself does not use this variable; +changing its value does not affect any environment, +nor vice-versa. + + + + +

+


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)

+ + +

+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 [, env]]])

+ + +

+Loads a chunk. + + +

+If ld is a string, the chunk is this string. +If ld is a function, +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 there are no syntactic 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 or to env, +if that parameter is given. +When loading main chunks, +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 ld, if ld is a string, +or to "=(load)" otherwise. + + +

+The string mode controls whether the chunk can be text or binary +(that is, a precompiled 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 [, mode [, env]]])

+ + +

+Similar to load, +but gets the chunk from file filename +or from the standard input, +if no file name is given. + + + + +

+


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 its associated value. +When called with nil as its second argument, +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. +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. + + +

+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.) + + +

+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)

+ + +

+If t has a metamethod __pairs, +calls it with t as argument and returns the first three +results from the call. + + +

+Otherwise, +returns three values: the next function, the table t, and nil, +so that the construction + +

+     for k,v in pairs(t) do body end
+

+will iterate over all key–value pairs of table t. + + +

+See function next for the caveats of modifying +the table during its traversal. + + + + +

+


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), +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 (···)

+Receives any number of arguments +and prints their values to stdout, +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, +for instance for debugging. +For complete control over the output, +use string.format and io.write. + + + + +

+


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 may be any value. + + + + +

+


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, +without invoking any metamethod. +table must be a table, +index any value different from nil and NaN, +and value any Lua value. + + +

+This function returns table. + + + + +

+


select (index, ···)

+ + +

+If index is a number, +returns all arguments after argument number index; +a negative number indexes from the end (-1 is the last argument). +Otherwise, index must be the string "#", +and select returns the total number of extra arguments it received. + + + + +

+


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])

+ + +

+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. + + +

+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. +If the string e is not a valid numeral in the given base, +the function returns nil. + + + + +

+


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.) + + +

+If the metatable of v has a "__tostring" field, +then tostring calls the corresponding value +with v 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". + + + + +

+


_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". + + + + +

+


xpcall (f, msgh [, arg1, ···])

+ + +

+This function is similar to pcall, +except that it sets a new message handler msgh. + + + + + + + +

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.6 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 values val1, ... are passed +as the arguments to the body function. +If the coroutine has yielded, +resume restarts it; +the values val1, ... are passed +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 plus a boolean, +true when the running coroutine is the main one. + + + + +

+


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 (···)

+ + +

+Suspends the execution of the calling coroutine. +Any arguments to yield are passed as extra results to resume. + + + + + + + +

6.3 – Modules

+ +

+The package library provides basic +facilities for loading modules in Lua. +It exports one function directly in the global environment: +require. +Everything else is exported in a table package. + + +

+


require (modname)

+ + +

+Loads the given module. +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]. +Otherwise, it tries to find a loader for the module. + + +

+To find a loader, +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.searchers. + + +

+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. +If that also fails, +it tries an all-in-one loader (see package.searchers). + + +

+Once a loader is found, +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 +has not assigned any value to package.loaded[modname], +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 the module, +then require raises an error. + + + + +

+


package.config

+ + +

+A string describing some compile-time configurations for packages. +This string is a sequence of lines: + +

    + +
  • The first line is the directory separator string. +Default is '\' for Windows and '/' for all other systems.
  • + +
  • The second line is the character that separates templates in a path. +Default is ';'.
  • + +
  • The third line is the string that marks the +substitution points in a template. +Default is '?'.
  • + +
  • The fourth line is a string that, in a path in Windows, +is replaced by the executable's directory. +Default is '!'.
  • + +
  • The fifth line is a mark to ignore all text before it +when building the luaopen_ function name. +Default is '-'.
  • + +
+ + + +

+


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_5_2 +or the environment variable LUA_CPATH +or a default path defined in luaconf.h. + + + + +

+ +


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. + + +

+This variable is only a reference to the real table; +assignments to this variable do not change the +table used by require. + + + + +

+


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 prototype 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 those environment variables are 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

+ + +

+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 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 searcher 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. +The search is done as described in function package.searchpath. + + +

+The third searcher looks for a loader as a C library, +using the path given by the variable package.cpath. +Again, +the search is done as described in function package.searchpath. +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. + + +

+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. + + + + +

+


package.searchpath (name, path [, sep [, rep]])

+ + +

+Searches for the given name in the given path. + + +

+A path is a string containing a sequence of +templates separated by semicolons. +For each template, +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 rep +(the system's directory separator, by default), +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 the name foo.a +will try to open the files +./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 the file), +or nil plus an error message if none succeeds. +(This error message lists all file names it tried to open.) + + + + + + + +

6.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 +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). + + +

+The string library assumes one-byte character encodings. + + +

+


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. +These indices are corrected +following the same rules of function string.sub. + + +

+Numerical codes are not necessarily portable across platforms. + + + + +

+


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. + + +

+Numerical codes are not necessarily portable across platforms. + + + + +

+


string.dump (function)

+ + +

+Returns a string containing a binary representation of the given function, +so that a later load on this string returns +a copy of the function (but with new upvalues). + + + + +

+


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 +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 can 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, +then in a successful match +the captured values are also returned, +after the two indices. + + + + +

+


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 C function sprintf. +The only differences are that the options/modifiers +*, h, L, l, n, +and p are not supported +and that there is an extra option, q. +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')
+

+may produce the string: + +

+     "a string with \"quotes\" and \
+      new line"
+
+ +

+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 +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, +it is converted to one following the same rules of tostring. + + + + +

+


string.gmatch (s, pattern)

+Returns an iterator function that, +each time it is called, +returns the next captures from pattern over the string s. +If pattern specifies no captures, +then the whole match is produced in each call. + + +

+As an example, the following loop +will iterate over all the words from string s, +printing one per line: + +

+     s = "hello world from Lua"
+     for w in string.gmatch(s, "%a+") do
+       print(w)
+     end
+

+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
+
+ +

+For this function, a caret '^' at the start of a pattern does not +work as an anchor, as this would prevent the iteration. + + + + +

+


string.gsub (s, pattern, repl [, n])

+Returns a copy of s +in which all (or the first n, if given) +occurrences of the pattern have been +replaced by a replacement string specified by repl, +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. + + +

+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 %d, +with d between 1 and 9, +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 repl is a function, then this function is called every time a +match occurs, with all captured substrings passed as arguments, +in order. + + +

+In any case, +if the pattern specifies no captures, +then it behaves as if the whole pattern was inside a capture. + + +

+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). + + +

+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 load(s)()
+         end)
+     --> x="4+5 = 9"
+     
+     local t = {name="lua", version="5.2"}
+     x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t)
+     --> x="lua-5.2.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 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])

+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 can be negative. + + + + +

+


string.rep (s, n [, sep])

+Returns a string that is the concatenation of n copies of +the string s separated by the string sep. +The default value for sep is the empty string +(that is, no separator). + + + + +

+


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 can 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. + + +

+If, after the translation of negative indices, +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, +i is greater than j, +the function returns the empty string. + + + + +

+


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. + + + +

6.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 +^$()%.[]*+-?) +represents the character x itself. +
  • + +
  • .: (a dot) represents all characters.
  • + +
  • %a: represents all letters.
  • + +
  • %c: represents all control characters.
  • + +
  • %d: represents all digits.
  • + +
  • %g: represents all printable characters except space.
  • + +
  • %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.
  • + +
  • %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 can be specified by +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. +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. + + + + + +

Pattern Item:

+A pattern item can 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. +
  • + +
  • +%f[set], a frontier pattern; +such item matches an empty string at any position such that +the next character belongs to set +and the previous character does not belong to set. +The set set is interpreted as previously described. +The beginning and the end of the subject are handled as if +they were the character '\0'. +
  • + +
+ + + + +

Pattern:

+A pattern is a sequence of pattern items. +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. +At other positions, +'^' and '$' have no special meaning and represent themselves. + + + + + +

Captures:

+A pattern can 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. + + + + + + + + + + + +

6.5 – Table Manipulation

+ +

+This library provides generic functions for table manipulation. +It provides all its functions inside the table table. + + +

+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. + + +

+For performance reasons, +all table accesses (get/set) performed by these functions are raw. + + +

+


table.concat (list [, sep [, i [, 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 #list. +If i is greater than j, returns the empty string. + + + + +

+


table.insert (list, [pos,] value)

+ + +

+Inserts element value at position pos in list, +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. + + + + +

+


table.pack (···)

+ + +

+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 resulting table may not be a sequence. + + + + +

+


table.remove (list [, pos])

+ + +

+Removes from list the element at position pos, +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 +of list t. + + + + +

+


table.sort (list [, comp])

+ + +

+Sorts list elements in a given order, in-place, +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(list[i+1],list[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.unpack (list [, i [, j]])

+ + +

+Returns the elements from the given table. +This function is equivalent to + +

+     return list[i], list[i+1], ···, list[j]
+

+By default, i is 1 and j is #list. + + + + + + + +

6.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 (y, x)

+ + +

+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 x 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 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 +that rounds the quotient towards zero. + + + + +

+


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 [, base])

+ + +

+Returns the logarithm of x in the given base. +The default for base is e +(so that the function returns the natural 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 of π. + + + + +

+


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 Standard C. +(No guarantees can be given for its statistical properties.) + + +

+When called without arguments, +returns a uniform pseudo-random real 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, +math.random returns a uniform 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. + + + + + + + +

6.7 – Bitwise Operations

+ +

+This library provides bitwise operations. +It provides all its functions inside the table bit32. + + +

+Unless otherwise stated, +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.bnot(0) is 0xFFFFFFFF, +which is different from -1. + + +

+


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 (···)

+ + +

+Returns the bitwise and of its operands. + + + + +

+


bit32.bnot (x)

+ + +

+Returns the bitwise negation of x. +For any integer x, +the following identity holds: + +

+     assert(bit32.bnot(x) == (-1 - x) % 2^32)
+
+ + + +

+


bit32.bor (···)

+ + +

+Returns the bitwise or of its operands. + + + + +

+


bit32.btest (···)

+ + +

+Returns a boolean signaling +whether the bitwise and of its operands is different from zero. + + + + +

+


bit32.bxor (···)

+ + +

+Returns the bitwise exclusive or of its operands. + + + + +

+


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]. + + +

+The default for width is 1. + + + + +

+


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)

+ + +

+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(bit32.lrotate(x, disp) == bit32.lrotate(x, disp % 32))
+

+In particular, +negative displacements rotate to the right. + + + + +

+


bit32.lshift (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, +displacements with absolute values higher than 31 +result in zero (all bits are shifted out). + + +

+For positive displacements, +the following equality holds: + +

+     assert(bit32.lshift(b, disp) == (b * 2^disp) % 2^32)
+
+ + + +

+


bit32.rrotate (x, disp)

+ + +

+Returns the number x rotated disp bits to the right. +The number disp may be any representable integer. + + +

+For any valid displacement, +the following identity holds: + +

+     assert(bit32.rrotate(x, disp) == bit32.rrotate(x, disp % 32))
+

+In particular, +negative displacements rotate to the left. + + + + +

+


bit32.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 31 +result in zero (all bits are shifted out). + + +

+For positive displacements, +the following equality holds: + +

+     assert(bit32.rshift(b, disp) == math.floor(b % 2^32 / 2^disp))
+
+ +

+This shift operation is what is called logical shift. + + + + + + + +

6.8 – 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 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. +The I/O library never closes these files. + + +

+Unless otherwise stated, +all I/O functions return nil on failure +(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. + + +

+


io.close ([file])

+ + +

+Equivalent to file:close(). +Without a file, closes the default output file. + + + + +

+


io.flush ()

+ + +

+Equivalent to io.output():flush(). + + + + +

+


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, +instead of returning an error code. + + + + +

+


io.lines ([filename ···])

+ + +

+Opens the given file name in read mode +and returns an iterator function that +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. + + +

+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. + + +

+In case of errors this function raises the error, +instead of returning an error code. + + + + +

+


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 can also have a 'b' at the end, +which is needed in some systems to open the file in binary mode. + + + + +

+


io.output ([file])

+ + +

+Similar to io.input, but operates over the default output file. + + + + +

+


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 +(if mode is "r", the default) +or to write data to this program +(if mode is "w"). + + + + +

+


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. +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 (···)

+ + +

+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. + + +

+When closing a file handle created with io.popen, +file:close returns the same values +returned by os.execute. + + + + +

+


file:flush ()

+ + +

+Saves any written data to file. + + + + +

+


file:lines (···)

+ + +

+Returns an iterator function that, +each time it is called, +reads the file according to the given formats. +When no format is given, +uses "*l" as a default. +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. + + +

+In case of errors this function raises the error, +instead of returning an error code. + + + + +

+


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, +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. +
  • + +
  • "*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. +
  • + +
  • "*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 bytes, +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, seek returns the final file position, +measured in bytes from the beginning of the file. +If seek 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; 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 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, size +specifies the size of the buffer, in bytes. +The default is an appropriate size. + + + + +

+


file:write (···)

+ + +

+Writes the value of each of its arguments to file. +The arguments must be strings or numbers. + + +

+In case of success, this function returns file. +Otherwise it returns nil plus a string describing the error. + + + + + + + +

6.9 – 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, +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 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), +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. + + +

+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")). + + +

+On some systems, +this function may be not thread safe. + + + + +

+


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. +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: + +

    + +
  • "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. + + + + +

+


os.exit ([code [, close])

+ + +

+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 true. + + +

+If the optional second argument close is true, +closes the Lua state before exiting. + + + + +

+


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 empty directory, on POSIX systems) +with the given name. +If this function fails, it returns nil, +plus a string describing the error and the error code. + + + + +

+


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 and the error code. + + + + +

+


os.setlocale (locale [, category])

+ + +

+Sets the current locale of the program. +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"; +the default category is "all". +The function returns the name of the new locale, +or nil if the request cannot be honored. + + +

+If locale is the empty string, +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. + + +

+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 (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. + + +

+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 +os.date and os.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 explicitly removed when no longer needed. + + +

+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 +in the time between getting the name and creating the file.) +You still have to open the file to use it +and to remove it (even if you do not use it). + + +

+When possible, +you may prefer to use io.tmpfile, +which automatically removes the file when the program ends. + + + + + + + +

6.10 – The Debug Library

+ +

+This library provides +the functionality of the debug interface (§4.9) to Lua programs. +You should exert care when using this library. +Several of its functions +violate basic assumptions about Lua code +(e.g., that variables local to a function +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. + + +

+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, +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 +within any function and so have no direct access to local variables. + + + + +

+


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 ([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 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 f is a number larger than the number of active functions, +then getinfo returns nil. + + +

+The returned table can 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. +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. + + +

+For instance, the expression debug.getinfo(1,"n").name returns +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. + + + + +

+


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 f of the stack. +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.) + + +

+Variable names starting with '(' (open parentheses) +represent internal variables +(loop control variables, temporaries, varargs, and C function locals). + + +

+The parameter f may also be a function. +In that case, getlocal returns only the name of function parameters. + + + + +

+


debug.getmetatable (value)

+ + +

+Returns the metatable of the given value +or nil if it does not have a metatable. + + + + +

+


debug.getregistry ()

+ + +

+Returns the registry table (see §4.5). + + + + +

+


debug.getupvalue (f, up)

+ + +

+This function returns the name and the value of the upvalue +with index up of the function f. +The function returns nil if there is no upvalue with the given index. + + + + +

+


debug.getuservalue (u)

+ + +

+Returns the Lua value associated to u. +If u is not a userdata, +returns nil. + + + + +

+


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.
  • +

+With a count different from zero, +the hook is called after every count instructions. + + +

+When called without arguments, +debug.sethook turns off the hook. + + +

+When the hook is called, its first parameter is a string +describing the event that has triggered its call: +"call" (or "tail call"), +"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 +the running function +(level 0 is the getinfo function, +and level 1 is the hook function). + + + + +

+


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, +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. + + +

+See debug.getlocal for more information about +variable indices and names. + + + + +

+


debug.setmetatable (value, table)

+ + +

+Sets the metatable for the given value to the given table +(which can be nil). +Returns value. + + + + +

+


debug.setupvalue (f, up, value)

+ + +

+This function assigns the value value to the upvalue +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. + + + + +

+


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]])

+ + +

+If message is present but is neither a string nor nil, +this function returns message without further processing. +Otherwise, +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 +to start the traceback +(default is 1, the function calling traceback). + + + + +

+


debug.upvalueid (f, 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 (f1, n1, f2, n2)

+ + +

+Make the n1-th upvalue of the Lua closure f1 +refer to the n2-th upvalue of the Lua closure f2. + + + + + + + +

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 standalone language. +An interpreter for Lua as a standalone language, +called simply lua, +is provided with the standard distribution. +The standalone interpreter includes +all standard libraries, including the debug library. +Its usage is: + +

+     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;
  • +
  • -E: ignores environment variables;
  • +
  • --: 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, +lua behaves as lua -v -i +when the standard input (stdin) is a terminal, +and as lua - otherwise. + + +

+When called without option -E, +the interpreter checks for an environment variable LUA_INIT_5_2 +(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. + + +

+When called with option -E, +besides ignoring LUA_INIT, +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. + + +

+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, +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 at 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 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" }
+

+and finally runs the file b.lua. +The script is called with arg[1], arg[2], ... +as arguments; +it can also access these arguments with the vararg expression '...'. + + +

+In interactive mode, +if you write an incomplete statement, +the interpreter waits for its completion +by issuing a different prompt. + + +

+In case of unprotected errors in the script, +the interpreter reports the error to the standard error stream. +If the error object is a string, +the interpreter adds a stack traceback to it. +Otherwise, if the error object has a metamethod __tostring, +the interpreter calls this metamethod to produce the final message. +Finally, if the error object is nil, +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 +calling os.exit to terminate. + + +

+To allow the use of Lua as a +script interpreter in Unix systems, +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, +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.) + + + +

8 – Incompatibilities with the Previous Version

+ +

+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 by compiling Lua with +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. + + + +

8.1 – Changes in the Language

+
    + +
  • +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 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 +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. +

  • + +
  • +Lua identifiers cannot use locale-dependent letters. +
  • + +
  • +Doing a step or a full collection in the garbage collector +does not restart the collector if it has been stopped. +
  • + +
  • +Weak tables with weak keys now perform like ephemeron tables. +
  • + +
  • +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 that +there will 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. +
  • + +
+ + + + +

8.2 – Changes in the Libraries

+
    + +
  • +Function module is deprecated. +It is easy to set up a module with regular Lua code. +Modules are not expected to set global variables. +
  • + +
  • +Functions setfenv and getfenv were removed, +because of the changes in environments. +
  • + +
  • +Function math.log10 is deprecated. +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. +
  • + +
  • +Character class %z in patterns is deprecated, +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 +(load and loadfile) +are potentially insecure when loading untrusted binary data. +(Actually, those functions were already insecure because +of flaws in the verification algorithm.) +When in doubt, +use the mode argument of those functions +to restrict them to loading textual chunks. +
  • + +
  • +The standard paths in the official distribution may +change between versions. +
  • + +
+ + + + +

8.3 – Changes in the API

+
    + +
  • +Pseudoindex LUA_GLOBALSINDEX was removed. +You must get the global environment from the registry +(see §4.5). +
  • + +
  • +Pseudoindex LUA_ENVIRONINDEX +and functions lua_getfenv/lua_setfenv +were removed, +as C functions no longer have environments. +
  • + +
  • +Function luaL_register is deprecated. +Use luaL_setfuncs so that your module does not create globals. +(Modules are not expected to set global variables anymore.) +
  • + +
  • +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 for finalization, +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 removed. +Write your own version if you need it. +
  • + +
  • +Function lua_cpcall is deprecated. +You can simply push the function with lua_pushcfunction +and call it with lua_pcall. +
  • + +
  • +Functions lua_equal and lua_lessthan are deprecated. +Use the new lua_compare with appropriate options instead. +
  • + +
  • +Function lua_objlen was renamed lua_rawlen. +
  • + +
  • +Function lua_load has an extra parameter, mode. +Pass NULL to simulate the old behavior. +
  • + +
  • +Function lua_resume has an extra parameter, from. +Pass NULL or the thread doing the call. +
  • + +
+ + + + +

9 – The Complete Syntax of Lua

+ +

+Here is the complete syntax of Lua in extended BNF. +(It does not describe operator precedences.) + + + + +

+
+	chunk ::= block
+
+	block ::= {stat} [retstat]
+
+	stat ::=  ‘;’ | 
+		 varlist ‘=’ explist | 
+		 functioncall | 
+		 label | 
+		 break | 
+		 goto Name | 
+		 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 explist do block end | 
+		 function funcname funcbody | 
+		 local function Name funcbody | 
+		 local namelist [‘=’ explist] 
+
+	retstat ::= return [explist] [‘;’]
+
+	label ::= ‘::’ Name ‘::’
+
+	funcname ::= Name {‘.’ Name} [‘:’ Name]
+
+	varlist ::= var {‘,’ var}
+
+	var ::=  Name | prefixexp ‘[’ exp ‘]’ | prefixexp ‘.’ Name 
+
+	namelist ::= Name {‘,’ Name}
+
+	explist ::= exp {‘,’ exp}
+
+	exp ::=  nil | false | true | Number | String | ‘...’ | functiondef | 
+		 prefixexp | tableconstructor | exp binop exp | unop exp 
+
+	prefixexp ::= var | functioncall | ‘(’ exp ‘)’
+
+	functioncall ::=  prefixexp args | prefixexp ‘:’ Name args 
+
+	args ::=  ‘(’ [explist] ‘)’ | tableconstructor | String 
+
+	functiondef ::= function funcbody
+
+	funcbody ::= ‘(’ [parlist] ‘)’ block end
+
+	parlist ::= namelist [‘,’ ‘...’] | ‘...’
+
+	tableconstructor ::= ‘{’ [fieldlist] ‘}’
+
+	fieldlist ::= field {fieldsep field} [fieldsep]
+
+	field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp
+
+	fieldsep ::= ‘,’ | ‘;’
+
+	binop ::= ‘+’ | ‘-’ | ‘*’ | ‘/’ | ‘^’ | ‘%’ | ‘..’ | 
+		 ‘<’ | ‘<=’ | ‘>’ | ‘>=’ | ‘==’ | ‘~=’ | 
+		 and | or
+
+	unop ::= ‘-’ | not | ‘#’
+
+
+ +

+ + + + + + + +


+ +Last update: +Fri Jun 8 16:13:40 BRT 2012 + + + + + diff --git a/doc/osi-certified-72x60.png b/doc/osi-certified-72x60.png new file mode 100644 index 0000000000000000000000000000000000000000..07df5f6ee7a7a8b2108025dcd815f73f145a83af GIT binary patch literal 3774 zcmV;v4ngsWP)$kl5 zqcT7g&?zu8?ezWYz4zUB-|zR9d+&Qy2xAN{qY(ew0A7^*gV^7jytKqPFV3{hZfovn zs%x!l>(m&Gdb8C+5XeR7>h0kj=o=X3A39;2KLYfEMt>p1YMW~dt`rpAC{lN~P>5pq zH1L4nAdCT17}*hN=LnEsvMl=5Ij^QArAa&_V~zoht-Ei~)E~(Ivhe0#jik{t$isEK znCH$TxCB8EKmcF>3@pRaHpbR%Gqm*dsZA4H{j(NjZFp^iNFW+RBx6R*X19J*`0XG5 z^Y>cR=^Hi9#ovYGlbFSr#Q*^PgCGC^gb*SC5TcBfzQLe-r2m!Quik&_g9XzTj0qSR zD`FkG_RYWDa^+#UUxL&t+!K+&(ion@Fd`5l5p7{Qsva9vegC|4^NzJUMvn)^gqWsF zvu^j=%FfCVg^cgbXDRl1DE$lsfe;BjjmFmRHER~E-MeWoNsyyNHCpG%Y}igd_(Md;&9La8_B075NDRX9gTD zIHY`}9E~aGi9Kk1@P~rmPna=*=gz~UTdTpsQmjX)J23%v9NliQS)8`xJh6Qz_nE~e z&tP|!dcJdo;JMNa3>afSx$lko8>fp-I}OiCVz(dOF1u6e8$IrsSP?=5mp~lkaFqm? zAUMxRq%ecIu3WE)Uf=%p8g z+RSY?G=VO%wAfdICj?Uzb+5jr{8m|)i#{M}JjaDIoXf#1=DYLwX;1EW&sijPvm6EkBGuOx6r~lKv`g`yH?)|&PRUr$5Ibw2HBM7C74XvE@gaPjN+@;j$J)AgYhnT-U5m+wj|Wz8K630AfO8PUoGD^^Mcq zY9C<~%wUm^u%ox5P21)KNN0$(v^OI$A~?iwsS_fRu1+`EH|CRdpA4zsk8Z#|?x@^vVEAL+2JxH%&^{JUU%B=?EU7`Ar*Q|JvqPofcBt765(*f5JI$>=3{<%K)4ei zogo$)5XP}_X$y^pIYyWTt}EAnhTq}u4sAdBvC(WC{I#x4^>$vCvQ0UDs^18sAQG9o zEaP0qjrSSv1W0FyO%9&y$@em~n@8}}EXBG6x%ew49J_q%l@As_XnNpi|MTTPr~ca_ zW%uon6dBKL*pvzYFvf<~p6K8hK9BDNNN0$7xp^hWC3n^7FoQ?P(=m(6!Pj&S2f1fqH=`(w)KcPl5aEi2}~4hF*f*g}vaS-=c7v>N8c z{yNM*%+azq=@prWtgpi~^3?^AsJqS(>=pb=6PrGH#=O{Hcho$_F#MtsK$$3e2fZvg zy}!-V%`+uFMOW87LIgu3vKuMgqwY0}*Sd;aokQp(F#-{}Ss(Iy1iekY1ZQX?1WEL? z7=zq`lH-#Hw=bHRio3yPun%`c5rI1Hb|wTSWTs|12Mg#QkkwTmy zAYul0H*_b(BnkP#!R_&p@d54uz0JKthGv3C^fdKS%~alookE`QX@%#MQN2=SFWrOha7Ij7ImStNaWsy~? zsylUeT02_-z-G4s0L!v=+Wx|cxr$tmY&$a1by8z#6HBp!*9{@mU9XQ0h@L%V_R}4g z&s#2{MCOj4`5ux-SUautC5@{U895o-biKMWWoQ09{|jx8wz}@_(ep%Yk4{90C#s6-sa}fU5{}m>#>VtE_b#5bn8O+3k{&6GoEkB;yGie;A_5Uy zqPN*tU()pE+_&~``5XX({el-xT_}%`%fsc>_0@m5{+FhXru>rpyLESe31R>cK^FFrCm+#WL$-D{Z3*9>Lg{wi}xEYn_`@Hy`-d z1N}kIY%@Eu&Bpe|Rr6N;%Yk>6&RI$lgpIO26BYT%C!dU-o4bqqQpGY?p6lPru6Hzc z@WuSDI^BYaDH*>R)~)$V1J0Edn4r(9vo>E<2XjOJr2*G124;t^U+p{iUnZN5oapCpCk(F}}<#3ZZli!Nk z^UWT;Q9qm-i`i$kJS}5P%puBJ<&krTO;*#$Y7d$o96EbQ{aF1XFpTj}wf}eI|IOba z%w}_CWu?JjkV>U-ad9L$@Mu$CU;pUQBZgt5QmI@n=W@9K(A(SF-rnxzy|_!5ekKqCQTad`sa|&&Q6jfy}iAEst?|mH*emIjg9SB zRVWlHl?r3bvh2qnf6V6(+>4TulB%kzFveeh{k1?K*t&J=m>dk9P8SjqQdn4sF;*&- z(b3VFnVH$y*$Rb%rs zefJ#z#KpyZ_0?C$jvY%)O?7a?7#}%u1OT>d*)keF*REZ=c=4j6tkr5MilS*cB_$;< zFArmEv)Oby-7}4>TD9uE_ulKT4s6Bp@^Y0*rBEo&o;?cy8#Zi^%jH+DTv4f1SFc_L zfc5LwXJ=;vKt@K!?%liR&!6Almmq$2R@G|tg$oyGnpP+jQBhF<(9qCOR8%AuiBtJCSc zyu1LQw6wIQre^Zw$^E0N)#}R1%J}$rkw`Qc#z0A{)dIkjDN`I(PfyS2=x9f~R4N64 zPe1*1=gytQ#l=RWao4V0bLY-=?Bpl*dQDA@LZMJ9l{Gar$;rvzfB$`Tb#+==T0=ua zSy@?1N{UXWyL9Q&#*G`Zv$GE#JXljxBauj2T3VD!rO9N<%F3#*uP-Sn(P%W=w{Jgx z{(NC!VNOmC0OaN6ZQHg@tJQw^;fGtdZUulVSFX&NGv~~iGoO9-nNq0~2n78w23E{L zmth7T3|W>10ISuSm6cUgRCMXmr5!tV0D!x@`?6)rcI?<8lgZ#IIehqVOiYYpi@x#3 z8xau^+1c4ER;th&( zVHk--A`l3|!os9dsYatANm8TH96x@%qM{-&FmUtc&2qVX-MV%A_U(J~%{TY#*<&ym zX3Ur|c$No?u%e>k#EBDaZEY7XUVLH`0zh|n zw_~XRz;RH!y1MS)zn_X$Km70mNs@ZKo~G$z$BuD09F}FpVzEY}F&d2ug#rLPJUpgPpKh}a^y$-i zJl@%}XHT6vRaaNHckf=MQYn>6Fk&*D<+ja0B z5C{a#&CQN-V`HPyXe3EeAP~gH#>U3RayT5ZSd1}tbaaSNDAZ^)j%n&QHMoE=7KubA zlWEeVNpiV7Dk=&gzM|0Dz(>0HA5Q-_F}_znz(xxqbU~E|+`a#EH|V zPjA|^DJLg~rs?+f_6rv-T)upnAP7fChoq;cFJHcV=gyt)zWXjs(+gZ<%kMDTlOd1+TFW%&z(D`)oKF*0@Bmd zLqkIy?RvewprGK+ojWv5%Ve?@D^>&r1p$CcrMhuv}x1&joiO~|IC>)G) + + +Lua 5.2 readme + + + + + + + +
+

+Lua +Welcome to Lua 5.2 +

+ +

+about +· +installation +· +changes +· +license +· +reference manual + +

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 +provides complete information +about Lua, +including +an +executive summary +and +updated +documentation, +especially the +reference manual, +which may differ slightly from the +local copy +distributed in this package. + +

Installing Lua

+ +

+Lua is distributed in +source +form. +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 +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. +See also +instructions for other systems +and +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.1. +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. + 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 the Makefile. You'll + probably need the right permissions to install files. + +

+ To build and install Lua in one step, do "make xxx install", + where xxx is your platform name. + +

+ To install Lua locally, do "make local". + This will create a directory install with subdirectories + bin, include, lib, man, + 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. + +

+
+ 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. + 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 available to experts by editing the Lua sources. + +

+ 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: +
+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 lcorolib.c ldblib.c liolib.c +lmathlib.c loslib.c lstrlib.c ltablib.c loadlib.c linit.c +
+interpreter: +
+ library, lua.c +
+compiler: +
+ library, luac.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 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. + 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

+ +

+Here are the main changes introduced in Lua 5.2. +The +reference manual +lists the +incompatibilities that had to be introduced. + +

Main changes

+
    +
  • yieldable pcall and metamethods +
  • 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: +

Language

+
    +
  • no more fenv for threads or functions +
  • tables honor the __len metamethod +
  • hex and \z 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

+
    +
  • arguments for function called through xpcall +
  • 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 +
  • 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

+
    +
  • main thread predefined in the registry +
  • 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 +
  • nparams and isvararg available in debug API +
  • new lua_Unsigned +
+ +

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 +
  • parser uses much less C-stack space (no more auto arrays) +
+ +

Lua standalone interpreter

+
    +
  • new -E option to avoid environment variables +
  • handling of non-string error messages +
+ +

License

+ +[osi certified] + + +

+Lua is free software distributed under the terms of the +MIT license +reproduced below; +it may 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, see +this. + +

+Copyright © 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 "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 May 29 21:57:51 BRT 2012 + + + + + diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000000..8c9ee677ee --- /dev/null +++ b/src/Makefile @@ -0,0 +1,187 @@ +# Makefile for building Lua +# See ../doc/readme.html for installation and customization instructions. + +# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= + +# Your platform. See PLATS for possible values. +PLAT= none + +CC= gcc +CFLAGS= -O2 -Wall -DLUA_COMPAT_ALL $(SYSCFLAGS) $(MYCFLAGS) +LDFLAGS= $(SYSLDFLAGS) $(MYLDFLAGS) +LIBS= -lm $(SYSLIBS) $(MYLIBS) + +AR= ar rcu +RANLIB= ranlib +RM= rm -f + +SYSCFLAGS= +SYSLDFLAGS= +SYSLIBS= + +MYCFLAGS= +MYLDFLAGS= +MYLIBS= +MYOBJS= + +# == 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 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 lcorolib.o ldblib.o liolib.o \ + lmathlib.o loslib.o lstrlib.o ltablib.o loadlib.o linit.o +BASE_O= $(CORE_O) $(LIB_O) $(MYOBJS) + +LUA_T= lua +LUA_O= lua.o + +LUAC_T= luac +LUAC_O= luac.o + +ALL_O= $(BASE_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) + +o: $(ALL_O) + +a: $(ALL_A) + +$(LUA_A): $(BASE_O) + $(AR) $@ $(BASE_O) + $(RANLIB) $@ + +$(LUA_T): $(LUA_O) $(LUA_A) + $(CC) -o $@ $(LDFLAGS) $(LUA_O) $(LUA_A) $(LIBS) + +$(LUAC_T): $(LUAC_O) $(LUA_A) + $(CC) -o $@ $(LDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS) + +clean: + $(RM) $(ALL_T) $(ALL_O) + +depend: + @$(CC) $(CFLAGS) -MM l*.c + +echo: + @echo "PLAT= $(PLAT)" + @echo "CC= $(CC)" + @echo "CFLAGS= $(CFLAGS)" + @echo "LDFLAGS= $(SYSLDFLAGS)" + @echo "LIBS= $(LIBS)" + @echo "AR= $(AR)" + @echo "RANLIB= $(RANLIB)" + @echo "RM= $(RM)" + +# Convenience targets for popular platforms +ALL= all + +none: + @echo "Please do 'make PLATFORM' where PLATFORM is one of these:" + @echo " $(PLATS)" + +aix: + $(MAKE) $(ALL) CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-ldl" SYSLDFLAGS="-brtl -bexpall" + +ansi: + $(MAKE) $(ALL) SYSCFLAGS="-DLUA_ANSI" + +bsd: + $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-Wl,-E" + +freebsd: + $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -lreadline" + +generic: $(ALL) + +linux: + $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline -lncurses" + +macosx: + $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX" SYSLIBS="-lreadline" + +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" + +solaris: + $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-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 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 \ + 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 +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 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 \ + 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 +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 +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 +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 +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 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 +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 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 +lua.o: lua.c lua.h luaconf.h lauxlib.h lualib.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 + diff --git a/src/lapi.c b/src/lapi.c new file mode 100644 index 0000000000..1854fe6159 --- /dev/null +++ b/src/lapi.c @@ -0,0 +1,1281 @@ +/* +** $Id: lapi.c,v 2.164 2012/06/08 15:14:04 roberto Exp $ +** Lua API +** See Copyright Notice in lua.h +*/ + + +#include +#include + +#define lapi_c +#define LUA_CORE + +#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 "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lundump.h" +#include "lvm.h" + + + +const char lua_ident[] = + "$LuaVersion: " LUA_COPYRIGHT " $" + "$LuaAuthors: " LUA_AUTHORS " $"; + + +/* value at a non-valid index */ +#define NONVALIDVALUE cast(TValue *, luaO_nilobject) + +/* 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) { + CallInfo *ci = L->ci; + if (idx > 0) { + TValue *o = ci->func + idx; + api_check(L, idx <= ci->top - (ci->func + 1), "unacceptable index"); + if (o >= L->top) return NONVALIDVALUE; + else return o; + } + else if (idx > LUA_REGISTRYINDEX) { + api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); + return L->top + idx; + } + else if (idx == LUA_REGISTRYINDEX) + return &G(L)->l_registry; + else { /* upvalues */ + idx = LUA_REGISTRYINDEX - idx; + api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); + if (ttislcf(ci->func)) /* light C function? */ + return NONVALIDVALUE; /* it has no upvalues */ + else { + CClosure *func = clCvalue(ci->func); + return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : NONVALIDVALUE; + } + } +} + + +/* +** to be called 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; + CallInfo *ci = L->ci; + lua_lock(L); + if (L->stack_last - L->top > size) /* stack large enough? */ + res = 1; /* yes; check is OK */ + else { /* no; need to grow 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 */ + 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; +} + + +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); + 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); + } + 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 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; +} + + + +/* +** basic stack manipulation +*/ + + +/* +** 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)); +} + + +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 - (func + 1), "new top too large"); + while (L->top < (func + 1) + idx) + setnilvalue(L->top++); + L->top = (func + 1) + idx; + } + else { + api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top"); + L->top += idx+1; /* `subtract' index (index is negative) */ + } + lua_unlock(L); +} + + +LUA_API void lua_remove (lua_State *L, int idx) { + StkId p; + lua_lock(L); + p = index2addr(L, idx); + api_checkvalidindex(L, p); + while (++p < L->top) setobjs2s(L, p-1, p); + L->top--; + lua_unlock(L); +} + + +LUA_API void lua_insert (lua_State *L, int idx) { + StkId p; + 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); + setobjs2s(L, p, L->top); + lua_unlock(L); +} + + +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? */ + luaC_barrier(L, clCvalue(L->ci->func), 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); + 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, index2addr(L, idx)); + api_incr_top(L); + lua_unlock(L); +} + + + +/* +** access functions (stack -> C) +*/ + + +LUA_API int lua_type (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + return (isvalid(o) ? ttypenv(o) : LUA_TNONE); +} + + +LUA_API const char *lua_typename (lua_State *L, int t) { + UNUSED(L); + return ttypename(t); +} + + +LUA_API int lua_iscfunction (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + return (ttislcf(o) || (ttisCclosure(o))); +} + + +LUA_API int lua_isnumber (lua_State *L, int idx) { + TValue n; + const TValue *o = index2addr(L, idx); + return tonumber(o, &n); +} + + +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_isuserdata (lua_State *L, int 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 = index2addr(L, index1); + StkId o2 = index2addr(L, index2); + return (isvalid(o1) && isvalid(o2)) ? luaV_rawequalobj(o1, o2) : 0; +} + + +LUA_API void lua_arith (lua_State *L, int op) { + StkId o1; /* 1st operand */ + StkId o2; /* 2nd operand */ + lua_lock(L); + 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, o1, o1, o2, cast(TMS, op - LUA_OPADD + TM_ADD)); + L->top--; + lua_unlock(L); +} + + +LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) { + StkId o1, o2; + int i = 0; + lua_lock(L); /* may call tag method */ + o1 = index2addr(L, index1); + o2 = index2addr(L, index2); + 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; +} + + +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 (isnum) *isnum = 1; + return nvalue(o); + } + else { + if (isnum) *isnum = 0; + return 0; + } +} + + +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 { + if (isnum) *isnum = 0; + return 0; + } +} + + +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_number2unsigned(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); +} + + +LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { + 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? */ + if (len != NULL) *len = 0; + lua_unlock(L); + return NULL; + } + luaC_checkGC(L); + o = index2addr(L, idx); /* previous call may reallocate the stack */ + lua_unlock(L); + } + if (len != NULL) *len = tsvalue(o)->len; + return svalue(o); +} + + +LUA_API size_t lua_rawlen (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + 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)); + default: return 0; + } +} + + +LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + if (ttislcf(o)) return fvalue(o); + 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 (ttypenv(o)) { + case LUA_TUSERDATA: return (rawuvalue(o) + 1); + case LUA_TLIGHTUSERDATA: return pvalue(o); + default: return NULL; + } +} + + +LUA_API lua_State *lua_tothread (lua_State *L, int 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 = index2addr(L, idx); + switch (ttype(o)) { + case LUA_TTABLE: return hvalue(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: + case LUA_TLIGHTUSERDATA: + return lua_touserdata(L, idx); + default: return NULL; + } +} + + + +/* +** push functions (C -> stack) +*/ + + +LUA_API void lua_pushnil (lua_State *L) { + lua_lock(L); + setnilvalue(L->top); + api_incr_top(L); + lua_unlock(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); +} + + +LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { + lua_lock(L); + setnvalue(L->top, cast_num(n)); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushunsigned (lua_State *L, lua_Unsigned u) { + lua_Number n; + lua_lock(L); + n = lua_unsigned2number(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); + luaC_checkGC(L); + ts = luaS_newlstr(L, s, len); + setsvalue2s(L, L->top, ts); + api_incr_top(L); + lua_unlock(L); + return getstr(ts); +} + + +LUA_API const char *lua_pushstring (lua_State *L, const char *s) { + if (s == NULL) { + lua_pushnil(L); + return NULL; + } + 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); + } +} + + +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 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; +} + + +LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { + lua_lock(L); + if (n == 0) { + setfvalue(L->top, fn); + } + else { + Closure *cl; + api_checknelems(L, n); + api_check(L, n <= MAXUPVAL, "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); + setclCvalue(L, L->top, cl); + } + api_incr_top(L); + lua_unlock(L); +} + + +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_pushlightuserdata (lua_State *L, void *p) { + lua_lock(L); + setpvalue(L->top, p); + api_incr_top(L); + lua_unlock(L); +} + + +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) +*/ + + +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); + t = index2addr(L, idx); + 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; + 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); + lua_unlock(L); +} + + +LUA_API void lua_rawget (lua_State *L, int idx) { + StkId t; + lua_lock(L); + 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); +} + + +LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { + StkId t; + lua_lock(L); + 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); +} + + +LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { + Table *t; + lua_lock(L); + luaC_checkGC(L); + 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); +} + + +LUA_API int lua_getmetatable (lua_State *L, int objindex) { + const TValue *obj; + Table *mt = NULL; + int res; + lua_lock(L); + obj = index2addr(L, objindex); + switch (ttypenv(obj)) { + case LUA_TTABLE: + mt = hvalue(obj)->metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(obj)->metatable; + break; + default: + mt = G(L)->mt[ttypenv(obj)]; + break; + } + if (mt == NULL) + res = 0; + else { + sethvalue(L, L->top, mt); + api_incr_top(L); + res = 1; + } + lua_unlock(L); + return res; +} + + +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); + } else + setnilvalue(L->top); + api_incr_top(L); + lua_unlock(L); +} + + +/* +** set functions (stack -> Lua) +*/ + + +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); + 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); +} + + +LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { + StkId t; + 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 */ + lua_unlock(L); +} + + +LUA_API void lua_rawset (lua_State *L, int idx) { + StkId t; + lua_lock(L); + api_checknelems(L, 2); + 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); +} + + +LUA_API void lua_rawseti (lua_State *L, int idx, int n) { + StkId t; + lua_lock(L); + api_checknelems(L, 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); +} + + +LUA_API int lua_setmetatable (lua_State *L, int objindex) { + TValue *obj; + Table *mt; + lua_lock(L); + api_checknelems(L, 1); + obj = index2addr(L, objindex); + api_checkvalidindex(L, obj); + if (ttisnil(L->top - 1)) + mt = NULL; + else { + api_check(L, ttistable(L->top - 1), "table expected"); + mt = hvalue(L->top - 1); + } + 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, gcvalue(obj), mt); + } + break; + } + default: { + G(L)->mt[ttypenv(obj)] = mt; + break; + } + } + L->top--; + lua_unlock(L); + return 1; +} + + +LUA_API void lua_setuservalue (lua_State *L, int idx) { + StkId o; + 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; + 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)); + } + L->top--; + lua_unlock(L); +} + + +/* +** `load' and `call' functions (run Lua code) +*/ + + +#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; +} + + +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); + 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? */ + 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); +} + + + +/* +** 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 = cast(struct CallS *, ud); + luaD_call(L, c->func, c->nresults, 0); +} + + + +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); + api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); + checkresults(L, nargs, nresults); + if (errfunc == 0) + func = 0; + else { + StkId o = index2addr(L, errfunc); + api_checkvalidindex(L, o); + func = savestack(L, o); + } + c.func = L->top - (nargs+1); /* function to be called */ + 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->extra = 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; +} + + +LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, + const char *chunkname, const char *mode) { + ZIO z; + int status; + lua_lock(L); + if (!chunkname) chunkname = "?"; + luaZ_init(L, &z, reader, data); + status = luaD_protectedparser(L, &z, chunkname, mode); + if (status == LUA_OK) { /* no errors? */ + 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->upvals[0]->v, gt); + luaC_barrier(L, f->upvals[0], gt); + } + } + lua_unlock(L); + return status; +} + + +LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) { + int status; + TValue *o; + lua_lock(L); + api_checknelems(L, 1); + o = L->top - 1; + if (isLfunction(o)) + status = luaU_dump(L, getproto(o), writer, data, 0); + else + status = 1; + lua_unlock(L); + return status; +} + + +LUA_API int lua_status (lua_State *L) { + return L->status; +} + + +/* +** Garbage-collection function +*/ + +LUA_API int lua_gc (lua_State *L, int what, int data) { + int res = 0; + global_State *g; + lua_lock(L); + g = G(L); + switch (what) { + case LUA_GCSTOP: { + g->gcrunning = 0; + break; + } + case LUA_GCRESTART: { + luaE_setdebt(g, 0); + g->gcrunning = 1; + break; + } + case LUA_GCCOLLECT: { + luaC_fullgc(L, 0); + break; + } + case LUA_GCCOUNT: { + /* GC values are expressed in Kbytes: #bytes/2^10 */ + res = cast_int(gettotalbytes(g) >> 10); + break; + } + case LUA_GCCOUNTB: { + res = cast_int(gettotalbytes(g) & 0x3ff); + break; + } + case LUA_GCSTEP: { + if (g->gckind == KGC_GEN) { /* generational mode? */ + res = (g->GCestimate == 0); /* true if it will do major collection */ + luaC_forcestep(L); /* do a single step */ + } + else { + 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; + } + case LUA_GCSETPAUSE: { + res = g->gcpause; + g->gcpause = data; + break; + } + case LUA_GCSETMAJORINC: { + res = g->gcmajorinc; + g->gcmajorinc = data; + break; + } + case LUA_GCSETSTEPMUL: { + res = g->gcstepmul; + g->gcstepmul = data; + break; + } + case LUA_GCISRUNNING: { + res = g->gcrunning; + 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 */ + } + lua_unlock(L); + return res; +} + + + +/* +** miscellaneous functions +*/ + + +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 idx) { + StkId t; + int more; + lua_lock(L); + 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); + } + else /* no more elements */ + L->top -= 1; /* remove key */ + lua_unlock(L); + return more; +} + + +LUA_API void lua_concat (lua_State *L, int n) { + lua_lock(L); + api_checknelems(L, n); + if (n >= 2) { + luaC_checkGC(L); + luaV_concat(L, n); + } + else if (n == 0) { /* push empty string */ + setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); + api_incr_top(L); + } + /* else n == 1; nothing to do */ + lua_unlock(L); +} + + +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); + if (ud) *ud = G(L)->ud; + 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); +} + + +LUA_API void *lua_newuserdata (lua_State *L, size_t size) { + Udata *u; + lua_lock(L); + luaC_checkGC(L); + u = luaS_newudata(L, size, NULL); + setuvalue(L, L->top, u); + api_incr_top(L); + lua_unlock(L); + return u + 1; +} + + + +static const char *aux_upvalue (StkId fi, int n, TValue **val, + GCObject **owner) { + 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); + 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 = p->upvalues[n-1].name; + return (name == NULL) ? "" : getstr(name); + } + default: return NULL; /* not a closure */ + } +} + + +LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { + const char *name; + TValue *val = NULL; /* to avoid warnings */ + lua_lock(L); + name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL); + if (name) { + setobj2s(L, L->top, val); + api_incr_top(L); + } + lua_unlock(L); + return name; +} + + +LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { + const char *name; + TValue *val = NULL; /* to avoid warnings */ + GCObject *owner = NULL; /* to avoid warnings */ + StkId fi; + lua_lock(L); + fi = index2addr(L, funcindex); + api_checknelems(L, 1); + name = aux_upvalue(fi, n, &val, &owner); + if (name) { + L->top--; + setobj(L, val, L->top); + luaC_barrier(L, owner, L->top); + } + lua_unlock(L); + return name; +} + + +static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) { + LClosure *f; + StkId fi = index2addr(L, fidx); + 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->upvals[n - 1]; /* get its upvalue pointer */ +} + + +LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) { + StkId fi = index2addr(L, fidx); + 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; + } + } +} + + +LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1, + int fidx2, int n2) { + LClosure *f1; + UpVal **up1 = getupvalref(L, fidx1, n1, &f1); + UpVal **up2 = getupvalref(L, fidx2, n2, NULL); + *up1 = *up2; + luaC_objbarrier(L, f1, *up2); +} + diff --git a/src/lapi.h b/src/lapi.h new file mode 100644 index 0000000000..0909a3911d --- /dev/null +++ b/src/lapi.h @@ -0,0 +1,24 @@ +/* +** $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 +*/ + +#ifndef lapi_h +#define lapi_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") + + +#endif diff --git a/src/lauxlib.c b/src/lauxlib.c new file mode 100644 index 0000000000..36ae7e629f --- /dev/null +++ b/src/lauxlib.c @@ -0,0 +1,958 @@ +/* +** $Id: lauxlib.c,v 1.244 2012/05/31 20:28:45 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. +*/ + +#define lauxlib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" + + +/* +** {====================================================== +** 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) { + if (level == 0 || !lua_istable(L, -1)) + return 0; /* not found */ + lua_pushnil(L); /* start 'next' loop */ + 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) */ + 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') { + 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? */ + 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' */ + if (narg == 0) /* error is in the self argument itself? */ + return luaL_error(L, "calling " LUA_QS " on bad self", ar.name); + } + if (ar.name == NULL) + ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?"; + return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)", + narg, ar.name, extramsg); +} + + +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); +} + + +static void tag_error (lua_State *L, int narg, int tag) { + typeerror(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, "Sl", &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_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? */ + lua_pushboolean(L, 1); + else + lua_pushnil(L); + lua_pushstring(L, what); + lua_pushinteger(L, stat); + return 3; /* return true/nil,what,code */ + } +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Userdata's metatable manipulation +** ======================================================= +*/ + +LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { + luaL_getmetatable(L, tname); /* try to get metatable */ + 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_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ + return 1; +} + + +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? */ + if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ + luaL_getmetatable(L, tname); /* get correct metatable */ + 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; + } + } + 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) 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 *msg) { + /* 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 + luaL_error(L, "stack overflow"); + } +} + + +LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) { + if (lua_type(L, narg) != t) + tag_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_checklstring (lua_State *L, int narg, size_t *len) { + const char *s = lua_tolstring(L, narg, len); + if (!s) tag_error(L, narg, LUA_TSTRING); + return s; +} + + +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_checklstring(L, narg, len); +} + + +LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) { + int isnum; + lua_Number d = lua_tonumberx(L, narg, &isnum); + if (!isnum) + tag_error(L, narg, LUA_TNUMBER); + return d; +} + + +LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) { + return luaL_opt(L, luaL_checknumber, narg, def); +} + + +LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) { + int isnum; + lua_Integer d = lua_tointegerx(L, narg, &isnum); + if (!isnum) + tag_error(L, narg, LUA_TNUMBER); + return d; +} + + +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); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Generic Buffer manipulation +** ======================================================= +*/ + +/* +** check whether buffer is using a userdata on the stack as a temporary +** buffer +*/ +#define buffonstack(B) ((B)->b != (B)->initb) + + +/* +** 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, "buffer too large"); + /* 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; + B->size = newsize; + } + return &B->b[B->n]; +} + + +LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { + char *b = luaL_prepbuffsize(B, l); + memcpy(b, s, l * sizeof(char)); + luaL_addsize(B, l); +} + + +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) { + 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 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) { + B->L = L; + 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); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Reference system +** ======================================================= +*/ + +/* index of free-list header */ +#define freelist 0 + + +LUALIB_API int luaL_ref (lua_State *L, int t) { + int ref; + if (lua_isnil(L, -1)) { + lua_pop(L, 1); /* remove from stack */ + return LUA_REFNIL; /* `nil' has a unique fixed reference */ + } + t = lua_absindex(L, t); + 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_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */ + } + else /* no free elements */ + ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */ + lua_rawseti(L, t, ref); + return ref; +} + + +LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { + if (ref >= 0) { + t = lua_absindex(L, t); + lua_rawgeti(L, t, freelist); + lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */ + lua_pushinteger(L, ref); + lua_rawseti(L, t, freelist); /* t[freelist] = ref */ + } +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Load functions +** ======================================================= +*/ + +typedef struct LoadF { + 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; /* not used */ + 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 { /* 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); /* read block */ + } + return lf->buff; +} + + +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 %s %s: %s", what, filename, serr); + lua_remove(L, fnameindex); + return LUA_ERRFILE; +} + + +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 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 (LoadF *lf, int *cp) { + int c = *cp = skipBOM(lf); + if (c == '#') { /* first line is a comment (Unix exec. file)? */ + do { /* skip first line */ + c = getc(lf->f); + } while (c != EOF && c != '\n') ; + *cp = getc(lf->f); /* skip end-of-line, if present */ + return 1; /* there was a comment */ + } + else return 0; /* no comment */ +} + + +LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, + const char *mode) { + 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, "open", fnameindex); + } + 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 != EOF) + lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ + status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode); + readstatus = ferror(lf.f); + if (filename) fclose(lf.f); /* close file (even in case of errors) */ + if (readstatus) { + lua_settop(L, fnameindex); /* ignore results from `lua_load' */ + return errfile(L, "read", 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; /* not used */ + if (ls->size == 0) return NULL; + *size = ls->size; + ls->size = 0; + return ls->s; +} + + +LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size, + const char *name, const char *mode) { + LoadS ls; + ls.s = buff; + ls.size = size; + return lua_load(L, getS, &ls, name, mode); +} + + +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 = lua_absindex(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; + int isnum; + lua_len(L, idx); + l = (int)lua_tointegerx(L, -1, &isnum); + if (!isnum) + 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); +} + + +/* +** {====================================================== +** Compatibility with 5.1 module functions +** ======================================================= +*/ +#if defined(LUA_COMPAT_MODULE) + +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 { + 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++; + return size; +} + + +/* +** 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_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_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 */ + } + 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) { + luaL_pushmodule(L, libname, libsize(l)); /* get/create library table */ + lua_insert(L, -(nup + 1)); /* move library table to below upvalues */ + } + if (l) + luaL_setfuncs(L, l, nup); + else + lua_pop(L, nup); /* remove upvalues */ +} + +#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_checkversion(L); + luaL_checkstack(L, nup, "too many upvalues"); + 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); + 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 int luaL_getsubtable (lua_State *L, int idx, const char *fname) { + lua_getfield(L, idx, fname); + if (lua_istable(L, -1)) return 1; /* table already there */ + else { + lua_pop(L, 1); /* remove previous result */ + idx = lua_absindex(L, idx); + 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 */ + } +} + + +/* +** 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_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 */ + if (glb) { + lua_pushvalue(L, -1); /* copy of 'mod' */ + lua_setglobal(L, modname); /* _G[modname] = module */ + } +} + + +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); +} + + +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); + return NULL; + } + else + return realloc(ptr, nsize); +} + + +static int panic (lua_State *L) { + luai_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", + lua_tostring(L, -1)); + return 0; /* return to Lua to abort */ +} + + +LUALIB_API lua_State *luaL_newstate (void) { + lua_State *L = lua_newstate(l_alloc, NULL); + if (L) lua_atpanic(L, &panic); + 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 %f, 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 new file mode 100644 index 0000000000..ac4d15fbb9 --- /dev/null +++ b/src/lauxlib.h @@ -0,0 +1,212 @@ +/* +** $Id: lauxlib.h,v 1.120 2011/11/29 15:55:08 roberto Exp $ +** Auxiliary functions for building Lua libraries +** See Copyright Notice in lua.h +*/ + + +#ifndef lauxlib_h +#define lauxlib_h + + +#include +#include + +#include "lua.h" + + + +/* extra error code for `luaL_load' */ +#define LUA_ERRFILE (LUA_ERRERR+1) + + +typedef struct luaL_Reg { + const char *name; + lua_CFunction func; +} 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 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_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_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); +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); + +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_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) + +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_loadfilex) (lua_State *L, const char *filename, + const char *mode); + +#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL) + +LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, + const char *name, const char *mode); +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); + +LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); + +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); + +LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, + lua_CFunction openf, int glb); + +/* +** =============================================================== +** some useful macros +** =============================================================== +*/ + + +#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)) +#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_typename(L,i) lua_typename(L, lua_type(L,(i))) + +#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, LUA_MULTRET, 0)) + +#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))) + +#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL) + + +/* +** {====================================================== +** Generic Buffer manipulation +** ======================================================= +*/ + +typedef struct luaL_Buffer { + char *b; /* buffer address */ + size_t size; /* buffer size */ + size_t n; /* number of characters in buffer */ + lua_State *L; + char initb[LUAL_BUFFERSIZE]; /* initial buffer */ +} luaL_Buffer; + + +#define luaL_addchar(B,c) \ + ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \ + ((B)->b[(B)->n++] = (c))) + +#define luaL_addsize(B,s) ((B)->n += (s)) + +LUALIB_API void (luaL_buffinit) (lua_State *L, 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) + +/* }====================================================== */ + + + +/* +** {====================================================== +** 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) + +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); + +#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0)) + +#endif + + +#endif + + diff --git a/src/lbaselib.c b/src/lbaselib.c new file mode 100644 index 0000000000..dbfcb02cfc --- /dev/null +++ b/src/lbaselib.c @@ -0,0 +1,459 @@ +/* +** $Id: lbaselib.c,v 1.274 2012/04/27 14:13:19 roberto Exp $ +** Basic library +** See Copyright Notice in lua.h +*/ + + + +#include +#include +#include +#include + +#define lbaselib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +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; + 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_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) luai_writestring("\t", 1); + luai_writestring(s, l); + lua_pop(L, 1); /* pop result */ + } + luai_writeline(); + return 0; +} + + +#define SPACECHARS " \f\n\r\t\v" + +static int luaB_tonumber (lua_State *L) { + 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; 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++; + 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); /* not a number */ + return 1; +} + + +static int luaB_error (lua_State *L) { + int level = luaL_optint(L, 2, 1); + 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); + } + return lua_error(L); +} + + +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_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")) + return luaL_error(L, "cannot change a protected metatable"); + lua_settop(L, 2); + lua_setmetatable(L, 1); + return 1; +} + + +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_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); + lua_settop(L, 2); + lua_rawget(L, 1); + return 1; +} + +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; +} + + +static int luaB_collectgarbage (lua_State *L) { + static const char *const opts[] = {"stop", "restart", "collect", + "count", "step", "setpause", "setstepmul", + "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}; + int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; + int ex = luaL_optint(L, 2, 0); + 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)); + lua_pushinteger(L, b); + return 2; + } + case LUA_GCSTEP: case LUA_GCISRUNNING: { + lua_pushboolean(L, res); + return 1; + } + default: { + lua_pushinteger(L, res); + return 1; + } + } +} + + +static int luaB_type (lua_State *L) { + luaL_checkany(L, 1); + lua_pushstring(L, luaL_typename(L, 1)); + return 1; +} + + +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_pushcfunction(L, iter); /* 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 */ + if (lua_next(L, 1)) + return 2; + else { + lua_pushnil(L); + return 1; + } +} + + +static int luaB_pairs (lua_State *L) { + return pairsmeta(L, "__pairs", 0, luaB_next); +} + + +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)) ? 1 : 2; +} + + +static int luaB_ipairs (lua_State *L) { + return pairsmeta(L, "__ipairs", 1, ipairsaux); +} + + +static int load_aux (lua_State *L, int status) { + if (status == LUA_OK) + return 1; + else { + lua_pushnil(L); + lua_insert(L, -2); /* put before error message */ + return 2; /* return nil plus error message */ + } +} + + +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 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); +} + + +/* +** {====================================================== +** Generic Read function +** ======================================================= +*/ + + +/* +** 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 5 + + +/* +** 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) { + (void)(ud); /* not used */ + 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)) { + lua_pop(L, 1); /* pop result */ + *size = 0; + return NULL; + } + else if (!lua_isstring(L, -1)) + luaL_error(L, "reader function must return a string"); + lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ + return lua_tolstring(L, RESERVEDSLOT, 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"); + if (s != NULL) { /* loading a string? */ + const char *chunkname = luaL_optstring(L, 2, s); + status = luaL_loadbufferx(L, s, l, chunkname, mode); + } + else { /* loading from a reader function */ + 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, 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); +} + +/* }====================================================== */ + + +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); + 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) { + if (!lua_toboolean(L, 1)) + return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); + return lua_gettop(L); +} + + +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 = n + i; + else if (i > n) i = n; + luaL_argcheck(L, 1 <= i, 1, "index out of range"); + return n - i; + } +} + + +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); + 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)); +} + + +static int luaB_xpcall (lua_State *L) { + int status; + 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, 0, pcallcont); + return finishpcall(L, (status == LUA_OK)); +} + + +static int luaB_tostring (lua_State *L) { + luaL_checkany(L, 1); + luaL_tolstring(L, 1, NULL); + return 1; +} + + +static const luaL_Reg base_funcs[] = { + {"assert", luaB_assert}, + {"collectgarbage", luaB_collectgarbage}, + {"dofile", luaB_dofile}, + {"error", luaB_error}, + {"getmetatable", luaB_getmetatable}, + {"ipairs", luaB_ipairs}, + {"loadfile", luaB_loadfile}, + {"load", luaB_load}, +#if defined(LUA_COMPAT_LOADSTRING) + {"loadstring", luaB_load}, +#endif + {"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}, + {"setmetatable", luaB_setmetatable}, + {"tonumber", luaB_tonumber}, + {"tostring", luaB_tostring}, + {"type", luaB_type}, + {"xpcall", luaB_xpcall}, + {NULL, NULL} +}; + + +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_setfuncs(L, base_funcs, 0); + lua_pushliteral(L, LUA_VERSION); + lua_setfield(L, -2, "_VERSION"); /* set global _VERSION */ + return 1; +} + diff --git a/src/lbitlib.c b/src/lbitlib.c new file mode 100644 index 0000000000..7533b85c5a --- /dev/null +++ b/src/lbitlib.c @@ -0,0 +1,209 @@ +/* +** $Id: lbitlib.c,v 1.16 2011/06/20 16:35:23 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" +#include "lualib.h" + + +/* number of bits to consider in a number */ +#if !defined(LUA_NBITS) +#define LUA_NBITS 32 +#endif + + +#define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1)) + +/* macro to trim extra bits */ +#define trim(x) ((x) & ALLONES) + + +/* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */ +#define mask(n) (~((ALLONES << 1) << ((n) - 1))) + + +typedef lua_Unsigned b_uint; + + + +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 &= luaL_checkunsigned(L, i); + return trim(r); +} + + +static int b_and (lua_State *L) { + b_uint r = andaux(L); + lua_pushunsigned(L, 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 |= luaL_checkunsigned(L, i); + lua_pushunsigned(L, trim(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 ^= luaL_checkunsigned(L, i); + lua_pushunsigned(L, trim(r)); + return 1; +} + + +static int b_not (lua_State *L) { + b_uint r = ~luaL_checkunsigned(L, 1); + lua_pushunsigned(L, trim(r)); + return 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 >= LUA_NBITS) r = 0; + else r >>= i; + } + else { /* shift left */ + if (i >= LUA_NBITS) r = 0; + else r <<= i; + r = trim(r); + } + lua_pushunsigned(L, r); + return 1; +} + + +static int b_lshift (lua_State *L) { + return b_shift(L, luaL_checkunsigned(L, 1), luaL_checkint(L, 2)); +} + + +static int b_rshift (lua_State *L) { + return b_shift(L, luaL_checkunsigned(L, 1), -luaL_checkint(L, 2)); +} + + +static int b_arshift (lua_State *L) { + b_uint r = luaL_checkunsigned(L, 1); + int i = luaL_checkint(L, 2); + if (i < 0 || !(r & ((b_uint)1 << (LUA_NBITS - 1)))) + return b_shift(L, r, -i); + else { /* arithmetic shift for 'negative' number */ + if (i >= LUA_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 = luaL_checkunsigned(L, 1); + i &= (LUA_NBITS - 1); /* i = i % NBITS */ + r = trim(r); + r = (r << i) | (r >> (LUA_NBITS - i)); + lua_pushunsigned(L, trim(r)); + return 1; +} + + +static int b_lrot (lua_State *L) { + return b_rot(L, luaL_checkint(L, 2)); +} + + +static int b_rrot (lua_State *L) { + return b_rot(L, -luaL_checkint(L, 2)); +} + + +/* +** 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 negative"); + 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}, + {NULL, NULL} +}; + + + +LUAMOD_API int luaopen_bit32 (lua_State *L) { + luaL_newlib(L, bitlib); + return 1; +} + diff --git a/src/lcode.c b/src/lcode.c new file mode 100644 index 0000000000..614e452f9c --- /dev/null +++ b/src/lcode.c @@ -0,0 +1,882 @@ +/* +** $Id: lcode.c,v 2.60 2011/08/30 16:26:41 roberto Exp $ +** Code generator for Lua +** See Copyright Notice in lua.h +*/ + + +#include + +#define lcode_c +#define LUA_CORE + +#include "lua.h" + +#include "lcode.h" +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "llex.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" +#include "lstring.h" +#include "ltable.h" +#include "lvm.h" + + +#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; + 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 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, n - 1, 0); /* else no optimization */ +} + + +int luaK_jump (FuncState *fs) { + 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; +} + + +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); +} + + +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); + 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 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 */ + else + return (pc+1)+offset; /* turn offset into absolute position */ +} + + +static Instruction *getjumpcontrol (FuncState *fs, int pc) { + Instruction *pi = &fs->f->code[pc]; + if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) + return pi-1; + else + return pi; +} + + +/* +** 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) { + for (; list != NO_JUMP; list = getjump(fs, list)) { + Instruction i = *getjumpcontrol(fs, list); + if (GET_OPCODE(i) != OP_TESTSET) return 1; + } + return 0; /* not found */ +} + + +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 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)) + patchtestreg(fs, list, NO_REG); +} + + +static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, + int dtarget) { + while (list != NO_JUMP) { + int next = getjump(fs, list); + if (patchtestreg(fs, list, 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); + fs->jpc = NO_JUMP; +} + + +void luaK_patchlist (FuncState *fs, int list, int target) { + if (target == fs->pc) + luaK_patchtohere(fs, list); + else { + lua_assert(target < fs->pc); + patchlistaux(fs, list, target, NO_REG, 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); +} + + +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 = getjump(fs, list)) != NO_JUMP) /* find last element */ + list = next; + fixjump(fs, list, 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->ls->L, f->code, fs->pc, f->sizecode, Instruction, + MAX_INT, "opcodes"); + f->code[fs->pc] = i; + /* save corresponding line information */ + 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++; +} + + +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_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, OP_LOADKX, reg, 0); + codeextraarg(fs, k); + return p; + } +} + + +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_byte(newstack); + } +} + + +void luaK_reserveregs (FuncState *fs, int n) { + luaK_checkstack(fs, n); + fs->freereg += n; +} + + +static void freereg (FuncState *fs, int reg) { + if (!ISK(reg) && reg >= fs->nactvar) { + fs->freereg--; + lua_assert(reg == fs->freereg); + } +} + + +static void freeexp (FuncState *fs, expdesc *e) { + if (e->k == VNONRELOC) + freereg(fs, e->u.info); +} + + +static int addk (FuncState *fs, TValue *key, TValue *v) { + lua_State *L = fs->ls->L; + TValue *idx = luaH_set(L, fs->h, key); + Proto *f = fs->f; + int k, oldsize; + if (ttisnumber(idx)) { + lua_Number n = nvalue(idx); + lua_number2int(k, n); + 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 */ + } + /* 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++]); + setobj(L, &f->k[k], v); + fs->nk++; + luaC_barrier(L, f, v); + return k; +} + + +int luaK_stringK (FuncState *fs, TString *s) { + TValue o; + 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->ls->L; + TValue o; + 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--; + } + else + n = addk(fs, &o, &o); /* regular case */ + return n; +} + + +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 */ + sethvalue(fs->ls->L, &k, fs->h); + return addk(fs, &k, &v); +} + + +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); + } + 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->u.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 */ + } +} + + +void luaK_dischargevars (FuncState *fs, expdesc *e) { + switch (e->k) { + case VLOCAL: { + e->k = VNONRELOC; + break; + } + case VUPVAL: { + e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); + e->k = VRELOCABLE; + break; + } + case VINDEXED: { + 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; + } + case VVARARG: + case VCALL: { + luaK_setoneret(fs, e); + break; + } + default: break; /* there is one value available (somewhere) */ + } +} + + +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 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_codek(fs, reg, e->u.info); + break; + } + case VKNUM: { + luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval)); + break; + } + case VRELOCABLE: { + Instruction *pc = &getcode(fs, e); + SETARG_A(*pc, reg); + break; + } + case VNONRELOC: { + if (reg != e->u.info) + luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0); + break; + } + default: { + lua_assert(e->k == VVOID || e->k == VJMP); + return; /* nothing to do... */ + } + } + e->u.info = reg; + e->k = VNONRELOC; +} + + +static void discharge2anyreg (FuncState *fs, expdesc *e) { + if (e->k != VNONRELOC) { + luaK_reserveregs(fs, 1); + discharge2reg(fs, e, fs->freereg-1); + } +} + + +static void exp2reg (FuncState *fs, expdesc *e, int reg) { + discharge2reg(fs, e, reg); + if (e->k == VJMP) + 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 */ + int p_t = NO_JUMP; /* position of an eventual LOAD true */ + if (need_value(fs, e->t) || need_value(fs, e->f)) { + 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); + } + final = luaK_getlabel(fs); + patchlistaux(fs, e->f, final, reg, p_f); + patchlistaux(fs, e->t, final, reg, p_t); + } + e->f = e->t = NO_JUMP; + e->u.info = reg; + e->k = VNONRELOC; +} + + +void luaK_exp2nextreg (FuncState *fs, expdesc *e) { + luaK_dischargevars(fs, e); + freeexp(fs, e); + luaK_reserveregs(fs, 1); + 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->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.info; +} + + +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); + else + luaK_dischargevars(fs, 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 fits in RK operand? */ + e->u.info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE)); + e->k = VK; + return RKASK(e->u.info); + } + else break; + } + case VKNUM: { + e->u.info = luaK_numberK(fs, e->u.nval); + e->k = VK; + /* go through */ + } + case VK: { + if (e->u.info <= MAXINDEXRK) /* constant fits in argC? */ + return RKASK(e->u.info); + else break; + } + default: break; + } + /* not a constant in the right range: put it in a register */ + return luaK_exp2anyreg(fs, e); +} + + +void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { + switch (var->k) { + case VLOCAL: { + freeexp(fs, ex); + exp2reg(fs, ex, var->u.info); + return; + } + case VUPVAL: { + int e = luaK_exp2anyreg(fs, ex); + 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, var->u.ind.t, var->u.ind.idx, e); + break; + } + default: { + lua_assert(0); /* invalid var kind to store */ + break; + } + } + freeexp(fs, ex); +} + + +void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { + int ereg; + luaK_exp2anyreg(fs, e); + ereg = e->u.info; /* register where 'e' was placed */ + freeexp(fs, e); + 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); +} + + +static void invertjump (FuncState *fs, expdesc *e) { + 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))); +} + + +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 condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); + } + /* else go through */ + } + discharge2anyreg(fs, e); + freeexp(fs, e); + return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond); +} + + +void luaK_goiftrue (FuncState *fs, expdesc *e) { + int pc; /* pc of last jump */ + luaK_dischargevars(fs, e); + switch (e->k) { + case VJMP: { + invertjump(fs, e); + pc = e->u.info; + break; + } + case VK: case VKNUM: case VTRUE: { + pc = NO_JUMP; /* always true; do nothing */ + break; + } + default: { + pc = jumponcond(fs, e, 0); + break; + } + } + luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */ + luaK_patchtohere(fs, e->t); + e->t = NO_JUMP; +} + + +void luaK_goiffalse (FuncState *fs, expdesc *e) { + int pc; /* pc of last jump */ + luaK_dischargevars(fs, e); + switch (e->k) { + case VJMP: { + pc = e->u.info; + break; + } + case VNIL: case VFALSE: { + pc = NO_JUMP; /* always false; do nothing */ + break; + } + default: { + pc = jumponcond(fs, e, 1); + break; + } + } + luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */ + luaK_patchtohere(fs, e->f); + e->f = NO_JUMP; +} + + +static void codenot (FuncState *fs, expdesc *e) { + luaK_dischargevars(fs, e); + switch (e->k) { + case VNIL: case VFALSE: { + e->k = VTRUE; + break; + } + case VK: case VKNUM: case VTRUE: { + e->k = VFALSE; + break; + } + case VJMP: { + invertjump(fs, e); + break; + } + case VRELOCABLE: + case VNONRELOC: { + discharge2anyreg(fs, e); + freeexp(fs, e); + e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0); + e->k = VRELOCABLE; + break; + } + default: { + lua_assert(0); /* cannot happen */ + break; + } + } + /* interchange true and false lists */ + { int temp = e->f; e->f = e->t; e->t = temp; } + removevalues(fs, e->f); + removevalues(fs, e->t); +} + + +void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { + lua_assert(!hasjumps(t)); + 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; +} + + +static int constfolding (OpCode op, expdesc *e1, expdesc *e2) { + lua_Number r; + if (!isnumeral(e1) || !isnumeral(e2)) return 0; + 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; +} + + +static void codearith (FuncState *fs, OpCode op, + expdesc *e1, expdesc *e2, int line) { + if (constfolding(op, e1, e2)) + return; + else { + int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0; + int o1 = luaK_exp2RK(fs, e1); + if (o1 > o2) { + freeexp(fs, e1); + freeexp(fs, e2); + } + else { + freeexp(fs, e2); + freeexp(fs, e1); + } + e1->u.info = luaK_codeABC(fs, op, 0, o1, o2); + e1->k = VRELOCABLE; + luaK_fixline(fs, line); + } +} + + +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.info = condjump(fs, op, cond, o1, o2); + e1->k = VJMP; +} + + +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) { + case OPR_MINUS: { + 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, 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, line); + break; + } + default: lua_assert(0); + } +} + + +void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { + switch (op) { + case OPR_AND: { + luaK_goiftrue(fs, v); + break; + } + case OPR_OR: { + luaK_goiffalse(fs, v); + break; + } + case OPR_CONCAT: { + luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */ + break; + } + 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; + } + } +} + + +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 */ + luaK_dischargevars(fs, e2); + 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, &e2->t, e1->t); + *e1 = *e2; + break; + } + case OPR_CONCAT: { + luaK_exp2val(fs, e2); + if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) { + lua_assert(e1->u.info == GETARG_B(getcode(fs, e2))-1); + freeexp(fs, e1); + 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' */ + 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, line); + break; + } + case OPR_EQ: case OPR_LT: case OPR_LE: { + codecomp(fs, cast(OpCode, op - OPR_EQ + OP_EQ), 1, e1, e2); + break; + } + case OPR_NE: case OPR_GT: case OPR_GE: { + codecomp(fs, cast(OpCode, op - OPR_NE + OP_EQ), 0, e1, e2); + break; + } + default: lua_assert(0); + } +} + + +void luaK_fixline (FuncState *fs, int line) { + fs->f->lineinfo[fs->pc - 1] = line; +} + + +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 if (c <= MAXARG_Ax) { + luaK_codeABC(fs, OP_SETLIST, base, b, 0); + 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 new file mode 100644 index 0000000000..5a1fa9feac --- /dev/null +++ b/src/lcode.h @@ -0,0 +1,83 @@ +/* +** $Id: lcode.h,v 1.58 2011/08/30 16:26:41 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 (ORDER OP) +*/ +typedef enum BinOpr { + OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW, + OPR_CONCAT, + OPR_EQ, OPR_LT, OPR_LE, + OPR_NE, OPR_GT, OPR_GE, + OPR_AND, OPR_OR, + OPR_NOBINOPR +} BinOpr; + + +typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; + + +#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) + +#define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) + +#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) + +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_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); +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_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); +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_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); +LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); +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); + + +#endif diff --git a/src/lcorolib.c b/src/lcorolib.c new file mode 100644 index 0000000000..c7932d90f2 --- /dev/null +++ b/src/lcorolib.c @@ -0,0 +1,155 @@ +/* +** $Id: lcorolib.c,v 1.4 2012/04/27 18:59:04 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, L, 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; + 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; +} + + +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/lctype.c b/src/lctype.c new file mode 100644 index 0000000000..55e433a5dd --- /dev/null +++ b/src/lctype.c @@ -0,0 +1,52 @@ +/* +** $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 /* { */ + +#include + +LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = { + 0x00, /* EOZ */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */ + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */ + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */ + 0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */ + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */ + 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05, + 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */ + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */ + 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* e. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* f. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +#endif /* } */ diff --git a/src/lctype.h b/src/lctype.h new file mode 100644 index 0000000000..99c7d12237 --- /dev/null +++ b/src/lctype.h @@ -0,0 +1,95 @@ +/* +** $Id: lctype.h,v 1.12 2011/07/15 12:50:29 roberto Exp $ +** 'ctype' functions for Lua +** See Copyright Notice in lua.h +*/ + +#ifndef lctype_h +#define lctype_h + +#include "lua.h" + + +/* +** 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 +*/ + +#if !defined(LUA_USE_CTYPE) + +#if 'A' == 65 && '0' == 48 +/* ASCII case: can use its own tables; faster and fixed */ +#define LUA_USE_CTYPE 0 +#else +/* must use standard C ctype */ +#define LUA_USE_CTYPE 1 +#endif + +#endif + + +#if !LUA_USE_CTYPE /* { */ + +#include + +#include "llimits.h" + + +#define ALPHABIT 0 +#define DIGITBIT 1 +#define PRINTBIT 2 +#define SPACEBIT 3 +#define XDIGITBIT 4 + + +#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 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)) + +/* +** this 'ltolower' only works for alphabetic characters +*/ +#define ltolower(c) ((c) | ('A' ^ 'a')) + + +/* two more entries for 0 and -1 (EOZ) */ +LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2]; + + +#else /* }{ */ + +/* +** use standard C ctypes +*/ + +#include + + +#define lislalpha(c) (isalpha(c) || (c) == '_') +#define lislalnum(c) (isalnum(c) || (c) == '_') +#define lisdigit(c) (isdigit(c)) +#define lisspace(c) (isspace(c)) +#define lisprint(c) (isprint(c)) +#define lisxdigit(c) (isxdigit(c)) + +#define ltolower(c) (tolower(c)) + +#endif /* } */ + +#endif + diff --git a/src/ldblib.c b/src/ldblib.c new file mode 100644 index 0000000000..c022694573 --- /dev/null +++ b/src/ldblib.c @@ -0,0 +1,398 @@ +/* +** $Id: ldblib.c,v 1.132 2012/01/19 20:14:44 roberto Exp $ +** Interface from Lua to its debug API +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include + +#define ldblib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +#define HOOKKEY "_HKEY" + + + +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)) { + lua_pushnil(L); /* no metatable */ + } + return 1; +} + + +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"); + lua_settop(L, 2); + lua_setmetatable(L, 1); + return 1; /* return 1st argument */ +} + + +static int db_getuservalue (lua_State *L) { + if (lua_type(L, 1) != LUA_TUSERDATA) + lua_pushnil(L); + else + lua_getuservalue(L, 1); + return 1; +} + + +static int db_setuservalue (lua_State *L) { + if (lua_type(L, 1) == LUA_TLIGHTUSERDATA) + luaL_argerror(L, 1, "full userdata expected, got light userdata"); + luaL_checktype(L, 1, LUA_TUSERDATA); + if (!lua_isnoneornil(L, 2)) + luaL_checktype(L, 2, LUA_TTABLE); + lua_settop(L, 2); + lua_setuservalue(L, 1); + return 1; +} + + +static void settabss (lua_State *L, const char *i, const char *v) { + lua_pushstring(L, v); + lua_setfield(L, -2, i); +} + + +static void settabsi (lua_State *L, const char *i, int v) { + lua_pushinteger(L, v); + lua_setfield(L, -2, i); +} + + +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; + return lua_tothread(L, 1); + } + else { + *arg = 0; + return 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); + 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 */ + return 1; + } + } + else if (lua_isfunction(L, arg+1)) { + lua_pushfstring(L, ">%s", options); + options = lua_tostring(L, -1); + lua_pushvalue(L, arg+1); + lua_xmove(L, L1, 1); + } + else + 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_createtable(L, 0, 2); + 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); + 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; + lua_State *L1 = getthread(L, &arg); + lua_Debug ar; + const char *name; + 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; + } + } +} + + +static int db_setlocal (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + lua_Debug ar; + 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; +} + + +static int auxupvalue (lua_State *L, int get) { + const char *name; + int n = luaL_checkint(L, 2); + luaL_checktype(L, 1, LUA_TFUNCTION); + 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 db_getupvalue (lua_State *L) { + return auxupvalue(L, 1); +} + + +static int db_setupvalue (lua_State *L) { + luaL_checkany(L, 3); + return auxupvalue(L, 0); +} + + +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; +} + + +#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"}; + gethooktable(L); + lua_pushthread(L); + lua_rawget(L, -2); + if (lua_isfunction(L, -1)) { + lua_pushstring(L, hooknames[(int)ar->event]); + if (ar->currentline >= 0) + lua_pushinteger(L, ar->currentline); + else lua_pushnil(L); + lua_assert(lua_getinfo(L, "lS", ar)); + lua_call(L, 2, 0); + } +} + + +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 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 int db_sethook (lua_State *L) { + int arg, mask, count; + lua_Hook func; + lua_State *L1 = getthread(L, &arg); + if (lua_isnoneornil(L, arg+1)) { + lua_settop(L, arg+1); + func = NULL; mask = 0; count = 0; /* turn off hooks */ + } + else { + const char *smask = luaL_checkstring(L, arg+2); + luaL_checktype(L, arg+1, LUA_TFUNCTION); + count = luaL_optint(L, arg+3, 0); + func = hookf; mask = makemask(smask, count); + } + if (gethooktable(L) == 0) { /* creating hook table? */ + lua_pushstring(L, "k"); + lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */ + lua_pushvalue(L, -1); + lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */ + } + lua_pushthread(L1); lua_xmove(L1, L, 1); + lua_pushvalue(L, arg+1); + lua_rawset(L, -3); /* set new hook */ + lua_sethook(L1, func, mask, count); /* set hooks */ + return 0; +} + + +static int db_gethook (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + char buff[5]; + int mask = lua_gethookmask(L1); + lua_Hook hook = lua_gethook(L1); + if (hook != NULL && hook != hookf) /* external hook? */ + lua_pushliteral(L, "external hook"); + else { + gethooktable(L); + lua_pushthread(L1); lua_xmove(L1, L, 1); + lua_rawget(L, -2); /* get hook */ + lua_remove(L, -2); /* remove hook table */ + } + lua_pushstring(L, unmakemask(mask, buff)); + lua_pushinteger(L, lua_gethookcount(L1)); + return 3; +} + + +static int db_debug (lua_State *L) { + for (;;) { + char buffer[250]; + 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)) + luai_writestringerror("%s\n", lua_tostring(L, -1)); + lua_settop(L, 0); /* remove eventual returns */ + } +} + + +static int db_traceback (lua_State *L) { + int arg; + lua_State *L1 = getthread(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); + } + return 1; +} + + +static const luaL_Reg dblib[] = { + {"debug", db_debug}, + {"getuservalue", db_getuservalue}, + {"gethook", db_gethook}, + {"getinfo", db_getinfo}, + {"getlocal", db_getlocal}, + {"getregistry", db_getregistry}, + {"getmetatable", db_getmetatable}, + {"getupvalue", db_getupvalue}, + {"upvaluejoin", db_upvaluejoin}, + {"upvalueid", db_upvalueid}, + {"setuservalue", db_setuservalue}, + {"sethook", db_sethook}, + {"setlocal", db_setlocal}, + {"setmetatable", db_setmetatable}, + {"setupvalue", db_setupvalue}, + {"traceback", db_traceback}, + {NULL, NULL} +}; + + +LUAMOD_API int luaopen_debug (lua_State *L) { + luaL_newlib(L, dblib); + return 1; +} + diff --git a/src/ldebug.c b/src/ldebug.c new file mode 100644 index 0000000000..43f8f046ff --- /dev/null +++ b/src/ldebug.c @@ -0,0 +1,580 @@ +/* +** $Id: ldebug.c,v 2.89 2012/01/20 22:05:50 roberto Exp $ +** Debug Interface +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include + + +#define ldebug_c +#define LUA_CORE + +#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 "lvm.h" + + + +#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL) + + +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)->p); +} + + +static int currentline (CallInfo *ci) { + return getfuncline(ci_func(ci)->p, currentpc(ci)); +} + + +/* +** 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; + } + if (isLua(L->ci)) + L->oldpc = L->ci->u.l.savedpc; + L->hook = func; + L->basehookcount = count; + resethookcount(L); + L->hookmask = cast_byte(mask); + return 1; +} + + +LUA_API lua_Hook lua_gethook (lua_State *L) { + return L->hook; +} + + +LUA_API int lua_gethookmask (lua_State *L) { + return L->hookmask; +} + + +LUA_API int lua_gethookcount (lua_State *L) { + return L->basehookcount; +} + + +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 = ci->previous) + level--; + if (level == 0 && ci != &L->base_ci) { /* level found? */ + status = 1; + ar->i_ci = ci; + } + else status = 0; /* no such level */ + lua_unlock(L); + return status; +} + + +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) + 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)) { + 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; + 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 + 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) { + const char *name; + lua_lock(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(clLvalue(L->top - 1)->p, n, 0); + } + else { /* active function; get information through 'ar' */ + StkId pos = 0; /* to avoid warnings */ + name = findlocal(L, ar->i_ci, n, &pos); + 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) { + 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); + L->top--; /* pop value */ + lua_unlock(L); + return name; +} + + +static void funcinfo (lua_Debug *ar, Closure *cl) { + if (noLuaClosure(cl)) { + ar->source = "=[C]"; + ar->linedefined = -1; + ar->lastlinedefined = -1; + ar->what = "C"; + } + else { + 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); +} + + +static void collectvalidlines (lua_State *L, Closure *f) { + if (noLuaClosure(f)) { + setnilvalue(L->top); + incr_top(L); + } + else { + int i; + TValue v; + 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); + 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 */ + } +} + + +static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, + Closure *f, CallInfo *ci) { + int status = 1; + for (; *what; what++) { + switch (*what) { + case 'S': { + funcinfo(ar, f); + break; + } + case 'l': { + ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1; + break; + } + case 'u': { + ar->nups = (f == NULL) ? 0 : f->c.nupvalues; + if (noLuaClosure(f)) { + 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': { + /* 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; + } + break; + } + case 'L': + case 'f': /* handled by lua_getinfo */ + break; + default: status = 0; /* invalid option */ + } + } + return status; +} + + +LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { + int status; + Closure *cl; + CallInfo *ci; + StkId func; + lua_lock(L); + if (*what == '>') { + ci = NULL; + func = L->top - 1; + api_check(L, ttisfunction(func), "function expected"); + what++; /* skip the '>' */ + L->top--; /* pop function */ + } + else { + ci = ar->i_ci; + func = ci->func; + lua_assert(ttisfunction(ci->func)); + } + cl = ttisclosure(func) ? clvalue(func) : NULL; + status = auxgetinfo(L, what, ar, cl, ci); + if (strchr(what, 'f')) { + setobjs2s(L, L->top, func); + incr_top(L); + } + if (strchr(what, 'L')) + collectvalidlines(L, cl); + lua_unlock(L); + return status; +} + + +/* +** {====================================================== +** Symbolic Execution +** ======================================================= +*/ + +static const char *getobjname (Proto *p, int lastpc, int reg, + const char **name); + + +/* +** find a "name" for the RK value 'c' +*/ +static void kname (Proto *p, int pc, int c, const char **name) { + if (ISK(c)) { /* is 'c' a constant? */ + TValue *kvalue = &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 */ + const char *what = getobjname(p, pc, 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 */ +} + + +/* +** try to find last instruction before 'lastpc' that modified register 'reg' +*/ +static int findsetreg (Proto *p, int lastpc, int reg) { + int pc; + 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_LOADNIL: { + int b = GETARG_B(i); + if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */ + setreg = pc; + break; + } + case OP_TFORCALL: { + if (reg >= a + 2) setreg = pc; /* affect all regs above its base */ + break; + } + case OP_CALL: + case OP_TAILCALL: { + if (reg >= a) setreg = pc; /* affect all registers above base */ + break; + } + 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_TEST: { + if (reg == a) setreg = pc; /* jumped code can change 'a' */ + break; + } + default: + if (testAMode(op) && reg == a) /* any instruction that set A */ + setreg = pc; + break; + } + } + 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; + 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: /* 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; + case OP_SETTABUP: + 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 +** (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++) + if (o == p) return 1; + return 0; +} + + +static const char *getupvalname (CallInfo *ci, const TValue *o, + const char **name) { + LClosure *c = ci_func(ci); + int i; + for (i = 0; i < c->nupvalues; i++) { + if (c->upvals[i]->v == o) { + *name = upvalname(c->p, i); + return "upvalue"; + } + } + return NULL; +} + + +l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { + CallInfo *ci = L->ci; + const char *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(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)", + op, kind, name, t); + else + luaG_runerror(L, "attempt to %s a %s value", op, t); +} + + +l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2) { + if (ttisstring(p1) || ttisnumber(p1)) p1 = p2; + lua_assert(!ttisstring(p1) && !ttisnumber(p2)); + luaG_typeerror(L, p1, "concatenate"); +} + + +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 */ + luaG_typeerror(L, p2, "perform arithmetic on"); +} + + +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); +} + + +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); + TString *src = ci_func(ci)->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); + } +} + + +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); + 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, 0); /* call it */ + } + luaD_throw(L, LUA_ERRRUN); +} + + +l_noret 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 new file mode 100644 index 0000000000..fe39556b06 --- /dev/null +++ b/src/ldebug.h @@ -0,0 +1,34 @@ +/* +** $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 +*/ + +#ifndef ldebug_h +#define ldebug_h + + +#include "lstate.h" + + +#define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1) + +#define getfuncline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : 0) + +#define resethookcount(L) (L->hookcount = L->basehookcount) + +/* Active Lua function (given call info) */ +#define ci_func(ci) (clLvalue((ci)->func)) + + +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 new file mode 100644 index 0000000000..d18e33cd41 --- /dev/null +++ b/src/ldo.c @@ -0,0 +1,668 @@ +/* +** $Id: ldo.c,v 2.105 2012/06/08 15:14:04 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" + +#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 "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lundump.h" +#include "lvm.h" +#include "lzio.h" + + + + +/* +** {====================================================== +** Error-recovery functions +** ======================================================= +*/ + +/* +** 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) && !defined(LUA_USE_LONGJMP) +/* 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 { + struct lua_longjmp *previous; + luai_jmpbuf b; + volatile int status; /* error code */ +}; + + +static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { + switch (errcode) { + case LUA_ERRMEM: { /* memory error? */ + setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ + break; + } + case LUA_ERRERR: { + setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); + break; + } + default: { + setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ + break; + } + } + L->top = oldtop + 1; +} + + +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 */ + } + 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(); + } + } +} + + +int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { + unsigned short oldnCcalls = L->nCcalls; + struct lua_longjmp lj; + 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 */ + L->nCcalls = oldnCcalls; + return lj.status; +} + +/* }====================================================== */ + + +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) + gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack; + for (ci = L->ci; ci != NULL; ci = ci->previous) { + ci->top = (ci->top - oldstack) + L->stack; + ci->func = (ci->func - oldstack) + L->stack; + if (isLua(ci)) + ci->u.l.base = (ci->u.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 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_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 = 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; + if (newsize > LUAI_MAXSTACK) { /* stack overflow? */ + luaD_reallocstack(L, ERRORSTACKSIZE); + luaG_runerror(L, "stack overflow"); + } + else + luaD_reallocstack(L, newsize); + } +} + + +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 */ +} + + +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_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, ci->top); + lua_Debug ar; + ar.event = event; + ar.currentline = line; + ar.i_ci = ci; + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + 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; + 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; + StkId base, fixed; + 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); + } + return base; +} + + +static StkId tryfuncTM (lua_State *L, StkId func) { + 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(L, p, p-1); + incr_top(L); + func = restorestack(L, funcr); /* previous call may change stack */ + setobj2s(L, func, tm); /* tag method is the new function to be called */ + return func; +} + + + +#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) { + lua_CFunction f; + 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); /* now it must be a function */ + } + } +} + + +int luaD_poscall (lua_State *L, StkId firstResult) { + StkId res; + int wanted, i; + 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 */ + 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++); + while (i-- > 0) + setnilvalue(res++); + L->top = res; + return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */ +} + + +/* +** 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, int allowyield) { + if (++L->nCcalls >= LUAI_MAXCCALLS) { + if (L->nCcalls == LUAI_MAXCCALLS) + luaG_runerror(L, "C stack overflow"); + 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--; + L->nCcalls--; + luaC_checkGC(L); +} + + +static void finishCcall (lua_State *L) { + CallInfo *ci = L->ci; + int n; + lua_assert(ci->u.c.k != NULL); /* must have a continuation */ + lua_assert(L->nny == 0); + /* 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' */ + } + } +} + + +/* +** 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->extra); + 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 handler and should not kill the coroutine.) +*/ +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); + 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) { + int nCcalls = L->nCcalls; + StkId firstArg = cast(StkId, ud); + CallInfo *ci = L->ci; + 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? */ + 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; + ci->func = restorestack(L, ci->extra); + 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; + 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 */ + } + luaD_poscall(L, firstArg); /* finish 'luaD_precall' */ + } + unroll(L, NULL); + } + lua_assert(nCcalls == L->nCcalls); +} + + +LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) { + int status; + lua_lock(L); + luai_userstateresume(L, nargs); + 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); + 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->nny = 1; /* do not allow yields */ + L->nCcalls--; + lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0)); + lua_unlock(L); + return status; +} + + +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); + api_checknelems(L, nresults); + 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; + ci->extra = savestack(L, ci->func); /* save current 'func' */ + 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->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 */ + lua_unlock(L); + 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; + 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 != LUA_OK) { /* an error occurred? */ + StkId oldtop = restorestack(L, old_top); + luaF_close(L, oldtop); /* close possible pending closures */ + seterrorobj(L, status, oldtop); + L->ci = old_ci; + L->allowhook = old_allowhooks; + L->nny = old_nny; + luaD_shrinkstack(L); + } + L->errfunc = old_errfunc; + return status; +} + + + +/* +** Execute a protected parser. +*/ +struct SParser { /* data to `f_parser' */ + ZIO *z; + Mbuffer buff; /* dynamic structure used by the scanner */ + Dyndata dyd; /* dynamic structures used by the parser */ + const char *mode; + const char *name; +}; + + +static void checkmode (lua_State *L, const char *mode, const char *x) { + if (mode && strchr(mode, x[0]) == NULL) { + luaO_pushfstring(L, + "attempt to load a %s chunk (mode is " LUA_QS ")", x, mode); + luaD_throw(L, LUA_ERRSYNTAX); + } +} + + +static void f_parser (lua_State *L, void *ud) { + int i; + 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"); + cl = luaU_undump(L, p->z, &p->buff, p->name); + } + else { + checkmode(L, p->mode, "text"); + 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); + } +} + + +int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, + const char *mode) { + struct SParser p; + int status; + L->nny++; /* cannot yield during parsing */ + p.z = z; p.name = name; p.mode = mode; + 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.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/ldo.h b/src/ldo.h new file mode 100644 index 0000000000..27b837d999 --- /dev/null +++ b/src/ldo.h @@ -0,0 +1,46 @@ +/* +** $Id: ldo.h,v 2.20 2011/11/29 15:55:08 roberto Exp $ +** Stack and Call structure of Lua +** See Copyright Notice in lua.h +*/ + +#ifndef ldo_h +#define ldo_h + + +#include "lobject.h" +#include "lstate.h" +#include "lzio.h" + + +#define luaD_checkstack(L,n) if (L->stack_last - L->top <= (n)) \ + luaD_growstack(L, n); else condmovestack(L); + + +#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))) + + +/* 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, + const char *mode); +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, + 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_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 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 new file mode 100644 index 0000000000..d5e6a47cb3 --- /dev/null +++ b/src/ldump.c @@ -0,0 +1,173 @@ +/* +** $Id: ldump.c,v 2.17 2012/01/23 23:02:10 roberto Exp $ +** save precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +#include + +#define ldump_c +#define LUA_CORE + +#include "lua.h" + +#include "lobject.h" +#include "lstate.h" +#include "lundump.h" + +typedef struct { + lua_State* L; + lua_Writer writer; + void* data; + int strip; + int status; +} DumpState; + +#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) +{ + if (D->status==0) + { + lua_unlock(D->L); + D->status=(*D->writer)(D->L,b,size,D->data); + lua_lock(D->L); + } +} + +static void DumpChar(int y, DumpState* D) +{ + char x=(char)y; + DumpVar(x,D); +} + +static void DumpInt(int x, DumpState* D) +{ + DumpVar(x,D); +} + +static void DumpNumber(lua_Number x, DumpState* D) +{ + DumpVar(x,D); +} + +static void DumpVector(const void* b, int n, size_t size, DumpState* D) +{ + DumpInt(n,D); + DumpMem(b,n,size,D); +} + +static void DumpString(const TString* s, DumpState* D) +{ + if (s==NULL) + { + size_t size=0; + DumpVar(size,D); + } + else + { + size_t size=s->tsv.len+1; /* include trailing '\0' */ + DumpVar(size,D); + DumpBlock(getstr(s),size*sizeof(char),D); + } +} + +#define DumpCode(f,D) DumpVector(f->code,f->sizecode,sizeof(Instruction),D) + +static void DumpFunction(const Proto* f, DumpState* D); + +static void DumpConstants(const Proto* f, DumpState* D) +{ + int i,n=f->sizek; + DumpInt(n,D); + for (i=0; ik[i]; + DumpChar(ttypenv(o),D); + switch (ttypenv(o)) + { + case LUA_TNIL: + break; + case LUA_TBOOLEAN: + DumpChar(bvalue(o),D); + break; + case LUA_TNUMBER: + DumpNumber(nvalue(o),D); + break; + case LUA_TSTRING: + DumpString(rawtsvalue(o),D); + break; + default: lua_assert(0); + } + } + n=f->sizep; + DumpInt(n,D); + for (i=0; ip[i],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; + 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; + 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].name,D); +} + +static void DumpFunction(const Proto* f, DumpState* D) +{ + DumpInt(f->linedefined,D); + DumpInt(f->lastlinedefined,D); + DumpChar(f->numparams,D); + DumpChar(f->is_vararg,D); + DumpChar(f->maxstacksize,D); + DumpCode(f,D); + DumpConstants(f,D); + DumpUpvalues(f,D); + DumpDebug(f,D); +} + +static void DumpHeader(DumpState* D) +{ + lu_byte 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_Writer w, void* data, int strip) +{ + DumpState D; + D.L=L; + D.writer=w; + D.data=data; + D.strip=strip; + D.status=0; + DumpHeader(&D); + DumpFunction(f,&D); + return D.status; +} diff --git a/src/lfunc.c b/src/lfunc.c new file mode 100644 index 0000000000..4fd27fe5eb --- /dev/null +++ b/src/lfunc.c @@ -0,0 +1,161 @@ +/* +** $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 +*/ + + +#include + +#define lfunc_c +#define LUA_CORE + +#include "lua.h" + +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" + + + +Closure *luaF_newCclosure (lua_State *L, int n) { + Closure *c = &luaC_newobj(L, LUA_TCCL, sizeCclosure(n), NULL, 0)->cl; + c->c.nupvalues = cast_byte(n); + return c; +} + + +Closure *luaF_newLclosure (lua_State *L, int n) { + Closure *c = &luaC_newobj(L, LUA_TLCL, sizeLclosure(n), NULL, 0)->cl; + c->l.p = NULL; + c->l.nupvalues = cast_byte(n); + while (n--) c->l.upvals[n] = NULL; + return c; +} + + +UpVal *luaF_newupval (lua_State *L) { + UpVal *uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), NULL, 0)->uv; + 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 (*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, 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 */ + uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), pp, 0)->uv; + uv->v = level; /* current value lives in the stack */ + 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 (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 */ + if (isdead(g, o)) + luaF_freeupval(L, uv); /* free upvalue */ + else { + 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 */ + gch(o)->next = g->allgc; /* link upvalue into 'allgc' list */ + g->allgc = o; + luaC_checkupvalcolor(g, uv); + } + } +} + + +Proto *luaF_newproto (lua_State *L) { + 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->cache = NULL; + f->sizecode = 0; + f->lineinfo = NULL; + f->sizelineinfo = 0; + f->upvalues = NULL; + f->sizeupvalues = 0; + f->numparams = 0; + f->is_vararg = 0; + f->maxstacksize = 0; + f->locvars = NULL; + f->sizelocvars = 0; + f->linedefined = 0; + f->lastlinedefined = 0; + f->source = NULL; + return f; +} + + +void luaF_freeproto (lua_State *L, Proto *f) { + 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); +} + + +/* +** Look for n-th local variable at line `line' in function `func'. +** Returns NULL if not found. +*/ +const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { + int 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 getstr(f->locvars[i].varname); + } + } + return NULL; /* not found */ +} + diff --git a/src/lfunc.h b/src/lfunc.h new file mode 100644 index 0000000000..e236a717c6 --- /dev/null +++ b/src/lfunc.h @@ -0,0 +1,33 @@ +/* +** $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 +*/ + +#ifndef lfunc_h +#define lfunc_h + + +#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))) + + +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 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_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 new file mode 100644 index 0000000000..06f972a725 --- /dev/null +++ b/src/lgc.c @@ -0,0 +1,1205 @@ +/* +** $Id: lgc.c,v 2.133 2012/05/31 21:28:59 roberto Exp $ +** Garbage Collector +** See Copyright Notice in lua.h +*/ + +#include + +#define lgc_c +#define LUA_CORE + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" + + + +/* +** cost of sweeping one element (the size of a small object divided +** by some adjust for the sweep speed) +*/ +#define GCSWEEPCOST ((sizeof(TString) + 4) / 4) + +/* maximum number of elements to sweep in each single step */ +#define GCSWEEPMAX (cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4)) + +/* maximum number of finalizers to call in each GC step */ +#define GCFINALIZENUM 4 + + +/* +** macro to adjust 'stepmul': 'stepmul' is actually used like +** 'stepmul / STEPMULADJ' (value chosen by tests) +*/ +#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)) + + +/* +** '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 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)); } + +#define markobject(g,t) { if ((t) && iswhite(obj2gco(t))) \ + reallymarkobject(g, obj2gco(t)); } + +static void reallymarkobject (global_State *g, GCObject *o); + + +/* +** {====================================================== +** Generic functions +** ======================================================= +*/ + + +/* +** one after last element in a hash array +*/ +#define gnodelast(h) gnode(h, cast(size_t, sizenode(h))) + + +/* +** link table 'h' into list pointed by 'p' +*/ +#define linktable(h,p) ((h)->gclist = *(p), *(p) = obj2gco(h)) + + +/* +** 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 (valiswhite(gkey(n))) + setdeadvalue(gkey(n)); /* unused and unmarked key; remove it */ +} + + +/* +** 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 (global_State *g, const TValue *o) { + if (!iscollectable(o)) return 0; + else if (ttisstring(o)) { + markobject(g, rawtsvalue(o)); /* strings are `values', so are never weak */ + return 0; + } + else return iswhite(gcvalue(o)); +} + + +/* +** barrier that moves collector forward, that is, mark the white object +** being pointed by a black object. +*/ +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(gch(o)->tt != LUA_TTABLE); + if (keepinvariant(g)) /* must keep invariant? */ + reallymarkobject(g, v); /* restore invariant */ + 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. (Current implementation +** only works for tables; access to 'gclist' is not uniform across +** different types.) +*/ +void luaC_barrierback_ (lua_State *L, GCObject *o) { + global_State *g = G(L); + 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; +} + + +/* +** 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 +*/ +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); + char *raw = cast(char *, luaM_newobject(L, novariant(tt), sz)); + GCObject *o = obj2gco(raw + offset); + if (list == NULL) + list = &g->allgc; /* standard list for collectable objects */ + gch(o)->marked = luaC_white(g); + gch(o)->tt = tt; + gch(o)->next = *list; + *list = o; + return o; +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** Mark functions +** ======================================================= +*/ + + +/* +** mark an object. Userdata, strings, and closed upvalues are visited +** and turned black here. 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) { + lu_mem size; + white2gray(o); + switch (gch(o)->tt) { + case LUA_TSHRSTR: + case LUA_TLNGSTR: { + 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); + size = sizeudata(gco2u(o)); + break; + } + case LUA_TUPVAL: { + UpVal *uv = gco2uv(o); + markvalue(g, uv->v); + 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; + return; + } + case LUA_TCCL: { + gco2ccl(o)->gclist = g->gray; + g->gray = o; + return; + } + case LUA_TTABLE: { + linktable(gco2t(o), &g->gray); + return; + } + case LUA_TTHREAD: { + gco2th(o)->gclist = g->gray; + g->gray = o; + return; + } + case LUA_TPROTO: { + gco2p(o)->gclist = g->gray; + g->gray = o; + return; + } + default: lua_assert(0); return; + } + gray2black(o); + g->GCmemtrav += size; +} + + +/* +** mark metamethods for basic types +*/ +static void markmt (global_State *g) { + int i; + for (i=0; i < LUA_NUMTAGS; i++) + markobject(g, g->mt[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) { + makewhite(g, o); + reallymarkobject(g, o); + } +} + + +/* +** 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) { + 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 (global_State *g) { + 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 */ +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Traverse functions +** ======================================================= +*/ + +static void traverseweakvalue (global_State *g, Table *h) { + Node *n, *limit = gnodelast(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? */ + removeentry(n); /* remove it */ + else { + lua_assert(!ttisnil(gkey(n))); + markvalue(g, gkey(n)); /* mark key */ + if (!hasclears && iscleared(g, gval(n))) /* is there a white value? */ + hasclears = 1; /* table will have to be cleared */ + } + } + 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 white keys */ + int prop = 0; /* true if table has entry "white-key -> white-value" */ + Node *n, *limit = gnodelast(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])); + } + } + /* 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 (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 */ + } + else if (valiswhite(gval(n))) { /* value not marked yet? */ + marked = 1; + reallymarkobject(g, gcvalue(gval(n))); /* mark it now */ + } + } + 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; +} + + +static void traversestrongtable (global_State *g, Table *h) { + Node *n, *limit = gnodelast(h); + int i; + for (i = 0; i < h->sizearray; i++) /* traverse array part */ + markvalue(g, &h->array[i]); + for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ + checkdeadkey(n); + if (ttisnil(gval(n))) /* entry is empty? */ + removeentry(n); /* remove it */ + else { + lua_assert(!ttisnil(gkey(n))); + markvalue(g, gkey(n)); /* mark key */ + markvalue(g, gval(n)); /* mark value */ + } + } +} + + +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? */ + ((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 */ + } + else /* not weak */ + traversestrongtable(g, h); + return sizeof(Table) + sizeof(TValue) * h->sizearray + + sizeof(Node) * sizenode(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 */ + 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 */ + 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 */ + 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 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 sizeCclosure(cl->nupvalues); +} + +static lu_mem traverseLclosure (global_State *g, LClosure *cl) { + int i; + markobject(g, cl->p); /* mark its prototype */ + for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ + markobject(g, cl->upvals[i]); + return sizeLclosure(cl->nupvalues); +} + + +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 < th->top; o++) + markvalue(g, o); + if (g->gcstate == GCSatomic) { /* final traversal? */ + StkId lim = th->stack + th->stacksize; /* real end of stack */ + for (; o < lim; o++) /* clear not-marked stack slice */ + setnilvalue(o); + } + return sizeof(lua_State) + sizeof(TValue) * th->stacksize; +} + + +/* +** traverse one gray object, turning it to black (except for threads, +** which are always gray). +*/ +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; /* remove from 'gray' list */ + size = traversetable(g, h); + break; + } + case LUA_TLCL: { + LClosure *cl = gco2lcl(o); + g->gray = cl->gclist; /* remove from 'gray' list */ + size = traverseLclosure(g, cl); + break; + } + case LUA_TCCL: { + CClosure *cl = gco2ccl(o); + 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; /* remove from 'gray' list */ + th->gclist = g->grayagain; + g->grayagain = o; /* insert into 'grayagain' list */ + black2gray(o); + size = traversestack(g, th); + break; + } + case LUA_TPROTO: { + Proto *p = gco2p(o); + g->gray = p->gclist; /* remove from 'gray' list */ + size = traverseproto(g, p); + break; + } + default: lua_assert(0); return; + } + g->GCmemtrav += size; +} + + +static void propagateall (global_State *g) { + while (g->gray) propagatemark(g); +} + + +static void propagatelist (global_State *g, GCObject *l) { + lua_assert(g->gray == NULL); /* no grays left */ + 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); +} + + +static void convergeephemerons (global_State *g) { + int changed; + do { + GCObject *w; + 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))) { /* traverse marked some value? */ + propagateall(g); /* propagate changes */ + changed = 1; /* will have to revisit all ephemeron tables */ + } + } + } while (changed); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Sweep Functions +** ======================================================= +*/ + + +/* +** clear entries with unmarked keys from all weaktables in list 'l' up +** to element '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(g, 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 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(g, o)) /* value was collected? */ + setnilvalue(o); /* remove value */ + } + for (n = gnode(h, 0); n < limit; n++) { + if (!ttisnil(gval(n)) && iscleared(g, gval(n))) { + setnilvalue(gval(n)); /* remove value ... */ + removeentry(n); /* and remove entry from table */ + } + } + } +} + + +static void freeobj (lua_State *L, GCObject *o) { + switch (gch(o)->tt) { + case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; + case LUA_TLCL: { + luaM_freemem(L, o, sizeLclosure(gco2lcl(o)->nupvalues)); + break; + } + case LUA_TCCL: { + luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); + break; + } + case LUA_TUPVAL: luaF_freeupval(L, gco2uv(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_TSHRSTR: + G(L)->strt.nuse--; + /* go through */ + case LUA_TLNGSTR: { + luaM_freemem(L, o, sizestring(gco2ts(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); + + +/* +** 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 (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) { + global_State *g = G(L); + 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); /* 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 */ + /* update marks */ + gch(curr)->marked = cast_byte((marked & toclear) | toset); + p = &gch(curr)->next; /* go to next element */ + } + } + return (*p == NULL) ? NULL : p; +} + + +/* +** sweep a list until a live object (or end of list) +*/ +static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) { + GCObject ** old = p; + int i = 0; + do { + i++; + p = sweeplist(L, p, 1); + } while (p == old); + if (n) *n += i; + return p; +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Finalization +** ======================================================= +*/ + +static void checkSizes (lua_State *L) { + global_State *g = G(L); + 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 */ + } +} + + +static GCObject *udata2finalize (global_State *g) { + GCObject *o = g->tobefnz; /* get first element */ + 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(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 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); + 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; + int running = g->gcrunning; + L->allowhook = 0; /* stop debug hooks during GC metamethod */ + g->gcrunning = 0; /* avoid GC steps */ + setobj2s(L, L->top, tm); /* push finalizer... */ + 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->gcrunning = running; /* restore state */ + if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ + if (status == LUA_ERRRUN) { /* is there an error object? */ + const char *msg = (ttisstring(L->top - 1)) + ? svalue(L->top - 1) + : "no message"; + luaO_pushfstring(L, "error in __gc metamethod (%s)", msg); + status = LUA_ERRGCMM; /* error in __gc metamethod */ + } + luaD_throw(L, status); /* re-throw error */ + } + } +} + + +/* +** move all unreachable objects (or 'all' objects) that need +** finalization from list 'finobj' to list 'tobefnz' (to be finalized) +*/ +static void separatetobefnz (lua_State *L, int all) { + global_State *g = G(L); + 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(!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 'finobj' list */ + gch(curr)->next = *lastnext; /* link at the end of 'tobefnz' list */ + *lastnext = curr; + lastnext = &gch(curr)->next; + } + } +} + + +/* +** 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, GCObject *o, Table *mt) { + global_State *g = G(L); + 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 'o' to 'finobj' list */ + GCObject **p; + GCheader *ho = gch(o); + if (g->sweepgc == &ho->next) { /* avoid removing current sweep object */ + lua_assert(issweepphase(g)); + g->sweepgc = sweeptolive(L, g->sweepgc, NULL); + } + /* 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(ho->marked, SEPARATED); /* mark it as such */ + if (!keepinvariant(g)) /* not keeping invariant? */ + makewhite(g, o); /* "sweep" object */ + else + resetoldbit(o); /* see MOVE OLD rule */ + } +} + +/* }====================================================== */ + + +/* +** {====================================================== +** GC control +** ======================================================= +*/ + + +#define sweepphases \ + (bitmask(GCSsweepstring) | bitmask(GCSsweepudata) | bitmask(GCSsweep)) + + +/* +** enter first sweep phase (strings) and prepare pointers for other +** sweep phases. The calls to 'sweeptolive' 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. +** Returns how many objects it sweeped. +*/ +static int entersweep (lua_State *L) { + global_State *g = G(L); + int n = 0; + g->gcstate = GCSsweepstring; + lua_assert(g->sweepgc == NULL && g->sweepfin == NULL); + /* prepare to sweep strings, finalizable objects, and regular objects */ + g->sweepstrgc = 0; + g->sweepfin = sweeptolive(L, &g->finobj, &n); + g->sweepgc = sweeptolive(L, &g->allgc, &n); + return n; +} + + +/* +** 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->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->gckind = KGC_NORMAL; + entersweep(L); + luaC_runtilstate(L, ~sweepphases); + } +} + + +/* +** call all pending finalizers +*/ +static void callallpendingfinalizers (lua_State *L, int propagateerrors) { + global_State *g = G(L); + while (g->tobefnz) { + resetoldbit(g->tobefnz); + GCTM(L, 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); + g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ + g->gckind = KGC_NORMAL; + sweepwholelist(L, &g->finobj); /* finalizers can create objs. in 'finobj' */ + sweepwholelist(L, &g->allgc); + 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 l_mem atomic (lua_State *L) { + global_State *g = G(L); + l_mem work = -g->GCmemtrav; /* start counting work */ + GCObject *origweak, *origall; + lua_assert(!iswhite(obj2gco(g->mainthread))); + markobject(g, L); /* mark running thread */ + /* 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); + propagateall(g); /* propagate changes */ + work += g->GCmemtrav; /* stop counting (do not (re)count grays) */ + /* traverse objects caught by write barrier and by 'remarkupvals' */ + retraversegrays(g); + work -= g->GCmemtrav; /* restart counting */ + convergeephemerons(g); + /* at this point, all strongly accessible objects are marked. */ + /* clear values from weak tables, before checking finalizers */ + clearvalues(g, g->weak, NULL); + clearvalues(g, g->allweak, NULL); + origweak = g->weak; origall = g->allweak; + work += g->GCmemtrav; /* stop counting (objects being finalized) */ + separatetobefnz(L, 0); /* separate objects to be finalized */ + markbeingfnz(g); /* mark objects that will be finalized */ + propagateall(g); /* remark, to propagate `preserveness' */ + work -= g->GCmemtrav; /* restart counting */ + convergeephemerons(g); + /* at this point, all resurrected objects are marked. */ + /* remove dead objects from weak 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, g->weak, origweak); + clearvalues(g, g->allweak, origall); + g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ + work += g->GCmemtrav; /* complete counting */ + return work; /* estimate of memory marked by 'atomic' */ +} + + +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))); + g->gcstate = GCSpropagate; + return g->GCmemtrav; + } + case GCSpropagate: { + if (g->gray) { + lu_mem oldtrav = g->GCmemtrav; + propagatemark(g); + return g->GCmemtrav - oldtrav; /* memory traversed in this step */ + } + else { /* no more `gray' objects */ + lu_mem work; + int sw; + g->gcstate = GCSatomic; /* finish mark phase */ + g->GCestimate = g->GCmemtrav; /* save what was counted */; + work = atomic(L); /* add what was traversed by 'atomic' */ + g->GCestimate += work; /* estimate of total memory traversed */ + sw = entersweep(L); + return work + sw * GCSWEEPCOST; + } + } + case GCSsweepstring: { + 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 i * GCSWEEPCOST; + } + case GCSsweepudata: { + if (g->sweepfin) { + g->sweepfin = sweeplist(L, g->sweepfin, GCSWEEPMAX); + return GCSWEEPMAX*GCSWEEPCOST; + } + else { + g->gcstate = GCSsweep; + return 0; + } + } + 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; /* finish collection */ + return GCSWEEPCOST; + } + } + default: lua_assert(0); return 0; + } +} + + +/* +** 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); + while (!testbit(statesmask, g->gcstate)) + singlestep(L); +} + + +static void generationalcollection (lua_State *L) { + global_State *g = G(L); + 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)); + if (gettotalbytes(g) > (estimate / 100) * g->gcmajorinc) + g->GCestimate = 0; /* signal for a major collection */ + } + luaE_setdebt(g, stddebt(g)); +} + + +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 */ + /* 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; + do { /* always perform at least one single step */ + lu_mem work = singlestep(L); /* do some work */ + debt -= work; + } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause); + if (g->gcstate == GCSpause) + debt = stddebtest(g, g->GCestimate); /* pause until next cycle */ + else + debt = (debt / stepmul) * STEPMULADJ; /* convert 'work units' to Kb */ + luaE_setdebt(g, debt); +} + + +/* +** performs a basic GC step +*/ +void luaC_forcestep (lua_State *L) { + global_State *g = G(L); + int i; + if (isgenerational(g)) generationalcollection(L); + else incstep(L); + /* 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 */ +} + + +/* +** performs a basic GC step only if collector is running +*/ +void luaC_step (lua_State *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) +*/ +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; + else { + g->gckind = KGC_NORMAL; + callallpendingfinalizers(L, 1); + } + 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) */ + 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)); + if (origkind == KGC_GEN) { /* generational mode? */ + /* generational mode must always start in propagate phase */ + luaC_runtilstate(L, bitmask(GCSpropagate)); + } + g->gckind = origkind; + 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 new file mode 100644 index 0000000000..bdd5cce6cf --- /dev/null +++ b/src/lgc.h @@ -0,0 +1,147 @@ +/* +** $Id: lgc.h,v 2.56 2012/05/23 15:43:14 roberto Exp $ +** Garbage Collector +** See Copyright Notice in lua.h +*/ + +#ifndef lgc_h +#define lgc_h + + +#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). +*/ + + + +/* 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 +*/ +#define GCSpropagate 0 +#define GCSatomic 1 +#define GCSsweepstring 2 +#define GCSsweepudata 3 +#define GCSsweep 4 +#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 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) + + +/* +** 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)) + + +/* 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 /* 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) */ + +#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) + + +#define iswhite(x) testbits((x)->gch.marked, WHITEBITS) +#define isblack(x) testbit((x)->gch.marked, BLACKBIT) +#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 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) + +#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) + +#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) + + +#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))) \ + luaC_barrier_(L,obj2gco(p),gcvalue(v)); } + +#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_barrier_(L,obj2gco(p),obj2gco(o)); } + +#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_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, + GCObject **list, int offset); +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, GCObject *o, Table *mt); +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 new file mode 100644 index 0000000000..8d3aa6576f --- /dev/null +++ b/src/linit.c @@ -0,0 +1,67 @@ +/* +** $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 +#define LUA_LIB + +#include "lua.h" + +#include "lualib.h" +#include "lauxlib.h" + + +/* +** 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_COLIBNAME, luaopen_coroutine}, + {LUA_TABLIBNAME, luaopen_table}, + {LUA_IOLIBNAME, luaopen_io}, + {LUA_OSLIBNAME, luaopen_os}, + {LUA_STRLIBNAME, luaopen_string}, + {LUA_BITLIBNAME, luaopen_bit32}, + {LUA_MATHLIBNAME, luaopen_math}, + {LUA_DBLIBNAME, luaopen_debug}, + {NULL, NULL} +}; + + +/* +** these libs are preloaded and must be required before used +*/ +static const luaL_Reg preloadedlibs[] = { + {NULL, NULL} +}; + + +LUALIB_API void luaL_openlibs (lua_State *L) { + const luaL_Reg *lib; + /* call open functions from 'loadedlibs' and set results to global table */ + for (lib = loadedlibs; lib->func; lib++) { + luaL_requiref(L, lib->name, lib->func, 1); + lua_pop(L, 1); /* remove lib */ + } + /* add open functions from 'preloadedlibs' into 'package.preload' table */ + luaL_getsubtable(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 _PRELOAD table */ +} + diff --git a/src/liolib.c b/src/liolib.c new file mode 100644 index 0000000000..4814aa2c2a --- /dev/null +++ b/src/liolib.c @@ -0,0 +1,657 @@ +/* +** $Id: liolib.c,v 2.108 2011/11/25 12:50:03 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 +#include + +#define liolib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#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 /* } */ + +/* }====================================================== */ + + +/* +** {====================================================== +** 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) && !defined(_CRTIMP_TYPEINFO) \ + && defined(_MSC_VER) && (_MSC_VER >= 1400) +/* Windows (but not DDK) and Visual C++ 2005 or higher */ + +#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 luaL_Stream LStream; + + +#define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE)) + +#define isclosed(p) ((p)->closef == NULL) + + +static int io_type (lua_State *L) { + LStream *p; + luaL_checkany(L, 1); + p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE); + if (p == NULL) + lua_pushnil(L); /* not a file */ + else if (isclosed(p)) + lua_pushliteral(L, "closed file"); + else + lua_pushliteral(L, "file"); + return 1; +} + + +static int f_tostring (lua_State *L) { + LStream *p = tolstream(L); + if (isclosed(p)) + lua_pushliteral(L, "file (closed)"); + else + lua_pushfstring(L, "file (%p)", p->f); + return 1; +} + + +static FILE *tofile (lua_State *L) { + LStream *p = tolstream(L); + if (isclosed(p)) + luaL_error(L, "attempt to use a closed file"); + lua_assert(p->f); + return p->f; +} + + +/* +** 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 LStream *newprefile (lua_State *L) { + LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream)); + p->closef = NULL; /* mark file handle as 'closed' */ + luaL_setmetatable(L, LUA_FILEHANDLE); + return p; +} + + +static int aux_close (lua_State *L) { + LStream *p = tolstream(L); + lua_CFunction cf = p->closef; + p->closef = NULL; /* mark stream as closed */ + return (*cf)(L); /* close it */ +} + + +static int io_close (lua_State *L) { + if (lua_isnone(L, 1)) /* no argument? */ + lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */ + tofile(L); /* make sure argument is an open stream */ + return aux_close(L); +} + + +static int f_gc (lua_State *L) { + LStream *p = tolstream(L); + if (!isclosed(p) && p->f != NULL) + aux_close(L); /* ignore closed and incompletely open files */ + return 0; +} + + +/* +** function to close regular files +*/ +static int io_fclose (lua_State *L) { + LStream *p = tolstream(L); + int res = fclose(p->f); + return luaL_fileresult(L, (res == 0), NULL); +} + + +static LStream *newfile (lua_State *L) { + LStream *p = newprefile(L); + p->f = NULL; + p->closef = &io_fclose; + return p; +} + + +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"); + LStream *p = newfile(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] == '\0'))) + 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; +} + + +/* +** function to close 'popen' files +*/ +static int io_pclose (lua_State *L) { + LStream *p = tolstream(L); + return luaL_execresult(L, lua_pclose(L, p->f)); +} + + +static int io_popen (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "r"); + LStream *p = newprefile(L); + p->f = lua_popen(L, filename, mode); + p->closef = &io_pclose; + return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; +} + + +static int io_tmpfile (lua_State *L) { + LStream *p = newfile(L); + p->f = tmpfile(); + return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; +} + + +static FILE *getiofile (lua_State *L, const char *findex) { + LStream *p; + lua_getfield(L, LUA_REGISTRYINDEX, findex); + p = (LStream *)lua_touserdata(L, -1); + if (isclosed(p)) + luaL_error(L, "standard %s file is closed", findex + strlen(IO_PREFIX)); + return p->f; +} + + +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) + opencheck(L, filename, mode); + else { + tofile(L); /* check that it's a valid file handle */ + lua_pushvalue(L, 1); + } + lua_setfield(L, LUA_REGISTRYINDEX, f); + } + /* return current value */ + lua_getfield(L, LUA_REGISTRYINDEX, f); + return 1; +} + + +static int io_input (lua_State *L) { + return g_iofile(L, IO_INPUT, "r"); +} + + +static int io_output (lua_State *L) { + return g_iofile(L, IO_OUTPUT, "w"); +} + + +static int io_readline (lua_State *L); + + +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 */ + 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, 0); + return 1; +} + + +static int io_lines (lua_State *L) { + int toclose; + if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ + if (lua_isnil(L, 1)) { /* no file name? */ + lua_getfield(L, LUA_REGISTRYINDEX, 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 { /* open a new file */ + const char *filename = luaL_checkstring(L, 1); + opencheck(L, filename, "r"); + lua_replace(L, 1); /* put file at index 1 */ + toclose = 1; /* close it after iteration */ + } + aux_lines(L, toclose); + return 1; +} + + +/* +** {====================================================== +** READ +** ======================================================= +*/ + + +static int read_number (lua_State *L, FILE *f) { + lua_Number d; + if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) { + lua_pushnumber(L, d); + return 1; + } + else { + lua_pushnil(L); /* "result" to be removed */ + return 0; /* read fails */ + } +} + + +static int test_eof (lua_State *L, FILE *f) { + int c = getc(f); + ungetc(c, f); + lua_pushlstring(L, NULL, 0); + return (c != EOF); +} + + +static int read_line (lua_State *L, FILE *f, int chop) { + luaL_Buffer b; + luaL_buffinit(L, &b); + for (;;) { + size_t l; + char *p = luaL_prepbuffer(&b); + if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */ + luaL_pushresult(&b); /* close buffer */ + return (lua_rawlen(L, -1) > 0); /* check whether read something */ + } + l = strlen(p); + if (l == 0 || p[l-1] != '\n') + luaL_addsize(&b, l); + else { + luaL_addsize(&b, l - chop); /* chop 'eol' if needed */ + luaL_pushresult(&b); /* close buffer */ + return 1; /* read at least an `eol' */ + } + } +} + + +#define MAX_SIZE_T (~(size_t)0) + +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); + for (;;) { + char *p = luaL_prepbuffsize(&b, rlen); + size_t nr = fread(p, sizeof(char), rlen, f); + luaL_addsize(&b, nr); + 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 (nr > 0); /* true iff read something */ +} + + +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, 1); + n = first+1; /* to return 1 result */ + } + 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_tointeger(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 */ + success = read_number(L, f); + break; + case 'l': /* line */ + 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_all(L, f); /* read entire file */ + success = 1; /* always success */ + break; + default: + return luaL_argerror(L, n, "invalid format"); + } + } + } + } + if (ferror(f)) + return luaL_fileresult(L, 0, NULL); + 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), 2); +} + + +static int io_readline (lua_State *L) { + LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1)); + int i; + int n = (int)lua_tointeger(L, lua_upvalueindex(2)); + if (isclosed(p)) /* file is already closed? */ + return luaL_error(L, "file is already closed"); + 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, p->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 (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)); + aux_close(L); /* close it */ + } + return 0; + } +} + +/* }====================================================== */ + + +static int g_write (lua_State *L, FILE *f, int arg) { + int nargs = lua_gettop(L) - arg; + int status = 1; + for (; nargs--; arg++) { + if (lua_type(L, arg) == LUA_TNUMBER) { + /* optimization: could be done exactly as for strings */ + status = status && + fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; + } + else { + size_t l; + const char *s = luaL_checklstring(L, arg, &l); + status = status && (fwrite(s, sizeof(char), l, f) == l); + } + } + if (status) return 1; /* file handle already on stack top */ + else return luaL_fileresult(L, status, NULL); +} + + +static int io_write (lua_State *L) { + return g_write(L, getiofile(L, IO_OUTPUT), 1); +} + + +static int f_write (lua_State *L) { + FILE *f = tofile(L); + lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ + return g_write(L, f, 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); + int op = luaL_checkoption(L, 2, "cur", modenames); + 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_pushnumber(L, (lua_Number)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); + 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 luaL_fileresult(L, res == 0, NULL); +} + + + +static int io_flush (lua_State *L) { + return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); +} + + +static int f_flush (lua_State *L) { + return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL); +} + + +/* +** functions for 'io' library +*/ +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}, + {"write", io_write}, + {NULL, NULL} +}; + + +/* +** methods for file handles +*/ +static const luaL_Reg flib[] = { + {"close", io_close}, + {"flush", f_flush}, + {"lines", f_lines}, + {"read", f_read}, + {"seek", f_seek}, + {"setvbuf", f_setvbuf}, + {"write", f_write}, + {"__gc", f_gc}, + {"__tostring", f_tostring}, + {NULL, NULL} +}; + + +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_setfuncs(L, flib, 0); /* add file methods to new metatable */ + lua_pop(L, 1); /* pop new metatable */ +} + + +/* +** function to (not) close the standard files stdin, stdout, and stderr +*/ +static int io_noclose (lua_State *L) { + LStream *p = tolstream(L); + p->closef = &io_noclose; /* keep file opened */ + lua_pushnil(L); + lua_pushliteral(L, "cannot close standard file"); + return 2; +} + + +static void createstdfile (lua_State *L, FILE *f, const char *k, + const char *fname) { + LStream *p = newprefile(L); + p->f = f; + p->closef = &io_noclose; + if (k != NULL) { + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */ + } + lua_setfield(L, -2, fname); /* add file to module */ +} + + +LUAMOD_API int luaopen_io (lua_State *L) { + luaL_newlib(L, iolib); /* new module */ + createmeta(L); + /* create (and set) default files */ + createstdfile(L, stdin, IO_INPUT, "stdin"); + createstdfile(L, stdout, IO_OUTPUT, "stdout"); + createstdfile(L, stderr, NULL, "stderr"); + return 1; +} + diff --git a/src/llex.c b/src/llex.c new file mode 100644 index 0000000000..c4d8c65b6f --- /dev/null +++ b/src/llex.c @@ -0,0 +1,527 @@ +/* +** $Id: llex.c,v 2.61 2012/01/23 23:05:51 roberto Exp $ +** Lexical Analyzer +** See Copyright Notice in lua.h +*/ + + +#include +#include + +#define llex_c +#define LUA_CORE + +#include "lua.h" + +#include "lctype.h" +#include "ldo.h" +#include "llex.h" +#include "lobject.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "lzio.h" + + + +#define next(ls) (ls->current = zgetc(ls->z)) + + + +#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') + + +/* ORDER RESERVED */ +static const char *const luaX_tokens [] = { + "and", "break", "do", "else", "elseif", + "end", "false", "for", "function", "goto", "if", + "in", "local", "nil", "not", "or", "repeat", + "return", "then", "true", "until", "while", + "..", "...", "==", ">=", "<=", "~=", "::", "", + "", "", "" +}; + + +#define save_and_next(ls) (save(ls, ls->current), next(ls)) + + +static l_noret lexerror (LexState *ls, const char *msg, int token); + + +static void save (LexState *ls, int c) { + Mbuffer *b = ls->buff; + if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) { + size_t newsize; + 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[luaZ_bufflen(b)++] = cast(char, c); +} + + +void luaX_init (lua_State *L) { + int i; + for (i=0; itsv.extra = cast_byte(i+1); /* reserved word */ + } +} + + +const char *luaX_token2str (LexState *ls, int token) { + if (token < FIRST_RESERVED) { + 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) + return luaO_pushfstring(ls->L, LUA_QS, s); + else + return s; + } +} + + +static const char *txtToken (LexState *ls, int token) { + switch (token) { + case TK_NAME: + case TK_STRING: + case TK_NUMBER: + save(ls, '\0'); + return luaO_pushfstring(ls->L, LUA_QS, luaZ_buffer(ls->buff)); + default: + return luaX_token2str(ls, token); + } +} + + +static l_noret 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 %s", msg, txtToken(ls, token)); + luaD_throw(ls->L, LUA_ERRSYNTAX); +} + + +l_noret luaX_syntaxerror (LexState *ls, const char *msg) { + lexerror(ls, msg, ls->t.token); +} + + +/* +** 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); /* create new string */ + setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ + 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); + } + 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)); + 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, + 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; + ls->linenumber = 1; + ls->lastline = 1; + ls->source = 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 */ +} + + + +/* +** ======================================================= +** LEXICAL ANALYZER +** ======================================================= +*/ + + + +static int check_next (LexState *ls, const char *set) { + if (ls->current == '\0' || !strchr(set, ls->current)) + return 0; + save_and_next(ls); + return 1; +} + + +/* +** 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); + while (n--) + if (p[n] == from) p[n] = to; +} + + +#if !defined(getlocaledecpoint) +#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 +*/ +static void trydecpoint (LexState *ls, SemInfo *seminfo) { + char old = ls->decpoint; + ls->decpoint = getlocaledecpoint(); + buffreplace(ls, old, ls->decpoint); /* try new decimal separator */ + 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); + } +} + + +/* LUA_NUMBER */ +/* +** this function is quite liberal in what it accepts, as 'luaO_str2d' +** will reject ill-formed numerals. +*/ +static void read_numeral (LexState *ls, SemInfo *seminfo) { + const char *expo = "Ee"; + int first = ls->current; + lua_assert(lisdigit(ls->current)); + save_and_next(ls); + if (first == '0' && check_next(ls, "Xx")) /* hexadecimal? */ + expo = "Pp"; + for (;;) { + if (check_next(ls, expo)) /* exponent part? */ + check_next(ls, "+-"); /* optional exponent sign */ + if (lisxdigit(ls->current) || ls->current == '.') + save_and_next(ls); + else break; + } + save(ls, '\0'); + buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ + if (!buff2d(ls->buff, &seminfo->r)) /* format error? */ + trydecpoint(ls, seminfo); /* try to update decimal point separator */ +} + + +/* +** 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; + 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 sep) { + save_and_next(ls); /* skip 2nd `[' */ + if (currIsNewline(ls)) /* string starts with a newline? */ + inclinenumber(ls); /* skip it */ + for (;;) { + switch (ls->current) { + case EOZ: + lexerror(ls, (seminfo) ? "unfinished long string" : + "unfinished long comment", TK_EOS); + break; /* to avoid warnings */ + case ']': { + if (skip_sep(ls) == sep) { + save_and_next(ls); /* skip 2nd `]' */ + goto endloop; + } + break; + } + case '\n': case '\r': { + save(ls, '\n'); + inclinenumber(ls); + if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ + break; + } + default: { + if (seminfo) save_and_next(ls); + else next(ls); + } + } + } endloop: + if (seminfo) + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep), + luaZ_bufflen(ls->buff) - 2*(2 + sep)); +} + + +static void escerror (LexState *ls, int *c, int n, const char *msg) { + int i; + luaZ_resetbuffer(ls->buff); /* prepare error message */ + save(ls, '\\'); + for (i = 0; i < n && c[i] != EOZ; i++) + save(ls, c[i]); + lexerror(ls, msg, TK_STRING); +} + + +static int readhexaesc (LexState *ls) { + 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]); + } + return r; +} + + +static int readdecesc (LexState *ls) { + 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); + } + if (r > UCHAR_MAX) + escerror(ls, c, i, "decimal escape too large"); + return r; +} + + +static void read_string (LexState *ls, int del, SemInfo *seminfo) { + save_and_next(ls); /* keep delimiter (for error messages) */ + while (ls->current != del) { + switch (ls->current) { + case EOZ: + lexerror(ls, "unfinished string", TK_EOS); + break; /* to avoid warnings */ + case '\n': + case '\r': + lexerror(ls, "unfinished string", TK_STRING); + break; /* to avoid warnings */ + case '\\': { /* escape sequences */ + int c; /* final character to be saved */ + next(ls); /* do not save the `\' */ + switch (ls->current) { + 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); + } + goto no_save; + } + default: { + if (!lisdigit(ls->current)) + escerror(ls, &ls->current, 1, "invalid escape sequence"); + /* digital escape \ddd */ + c = readdecesc(ls); + goto only_save; + } + } + read_save: next(ls); /* read next character */ + only_save: save(ls, c); /* save 'c' */ + no_save: break; + } + default: + save_and_next(ls); + } + } + save_and_next(ls); /* skip delimiter */ + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, + luaZ_bufflen(ls->buff) - 2); +} + + +static int llex (LexState *ls, SemInfo *seminfo) { + luaZ_resetbuffer(ls->buff); + for (;;) { + switch (ls->current) { + case '\n': case '\r': { /* line breaks */ + inclinenumber(ls); + break; + } + 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 == '[') { /* 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); /* 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); /* skip until end of line (or end of file) */ + break; + } + case '[': { /* long string or simply '[' */ + int sep = skip_sep(ls); + if (sep >= 0) { + read_long_string(ls, seminfo, sep); + return TK_STRING; + } + else if (sep == -1) return '['; + else lexerror(ls, "invalid long string delimiter", TK_STRING); + } + case '=': { + 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; } + } + case '>': { + 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; } + } + case ':': { + next(ls); + if (ls->current != ':') return ':'; + else { next(ls); return TK_DBCOLON; } + } + case '"': case '\'': { /* short literal strings */ + read_string(ls, ls->current, seminfo); + return TK_STRING; + } + case '.': { /* '.', '..', '...', or number */ + save_and_next(ls); + if (check_next(ls, ".")) { + if (check_next(ls, ".")) + return TK_DOTS; /* '...' */ + else return TK_CONCAT; /* '..' */ + } + else if (!lisdigit(ls->current)) return '.'; + /* 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 (lislalpha(ls->current)) { /* identifier or reserved word? */ + TString *ts; + do { + save_and_next(ls); + } while (lislalnum(ls->current)); + ts = luaX_newstring(ls, luaZ_buffer(ls->buff), + luaZ_bufflen(ls->buff)); + seminfo->ts = ts; + if (isreserved(ts)) /* reserved word? */ + return ts->tsv.extra - 1 + FIRST_RESERVED; + else { + return TK_NAME; + } + } + else { /* single-char tokens (+ - / ...) */ + int c = ls->current; + next(ls); + return c; + } + } + } + } +} + + +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 */ +} + + +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 new file mode 100644 index 0000000000..9ca8a29948 --- /dev/null +++ b/src/llex.h @@ -0,0 +1,78 @@ +/* +** $Id: llex.h,v 1.72 2011/11/30 12:43:51 roberto Exp $ +** Lexical Analyzer +** See Copyright Notice in lua.h +*/ + +#ifndef llex_h +#define llex_h + +#include "lobject.h" +#include "lzio.h" + + +#define FIRST_RESERVED 257 + + + +/* +* WARNING: if you change the order of this enumeration, +* grep "ORDER RESERVED" +*/ +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_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_DBCOLON, TK_EOS, + TK_NUMBER, TK_NAME, TK_STRING +}; + +/* number of reserved words */ +#define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1)) + + +typedef union { + lua_Number r; + TString *ts; +} SemInfo; /* semantics information */ + + +typedef struct Token { + int token; + SemInfo seminfo; +} 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; /* current function (parser) */ + struct lua_State *L; + ZIO *z; /* input stream */ + Mbuffer *buff; /* buffer for tokens */ + struct Dyndata *dyd; /* dynamic structures used by the parser */ + TString *source; /* current source name */ + TString *envn; /* environment variable name */ + char decpoint; /* locale decimal point */ +} LexState; + + +LUAI_FUNC void luaX_init (lua_State *L); +LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, + 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); +LUAI_FUNC l_noret 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 new file mode 100644 index 0000000000..fc9de1a11b --- /dev/null +++ b/src/llimits.h @@ -0,0 +1,309 @@ +/* +** $Id: llimits.h,v 1.99 2012/05/28 20:32:28 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 + + +#include "lua.h" + + +typedef unsigned LUA_INT32 lu_int32; + +typedef LUAI_UMEM lu_mem; + +typedef LUAI_MEM l_mem; + + + +/* 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) + +#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2) + +#define MAX_LMEM ((l_mem) ((MAX_LUMEM >> 1) - 2)) + + +#define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */ + +/* +** 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 int)(lu_mem)(p)) + + + +/* 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; + + +/* result of a `usual argument conversion' over lua_Number */ +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) ((void)0) +#define check_exp(c,e) (e) +#define lua_longassert(c) ((void)0) +#endif + +/* +** assertion for checking API calls +*/ +#if !defined(luai_apicheck) + +#if defined(LUA_USE_APICHECK) +#include +#define luai_apicheck(L,e) assert(e) +#else +#define luai_apicheck(L,e) lua_assert(e) +#endif + +#endif + +#define api_check(l,e,msg) luai_apicheck(l,(e) && msg) + + +#if !defined(UNUSED) +#define UNUSED(x) ((void)(x)) /* to avoid warnings */ +#endif + + +#define cast(t, exp) ((t)(exp)) + +#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)) + + +/* +** 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.) +*/ +#if !defined(LUAI_MAXCCALLS) +#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 + + +/* +** type for virtual-machine instructions +** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) +*/ +typedef lu_int32 Instruction; + + + +/* maximum stack for a Lua function */ +#define MAXSTACK 250 + + + +/* minimum size for the string table (must be power of 2) */ +#if !defined(MINSTRTABSIZE) +#define MINSTRTABSIZE 32 +#endif + + +/* minimum size for string buffer */ +#if !defined(LUA_MINBUFFER) +#define LUA_MINBUFFER 32 +#endif + + +#if !defined(lua_lock) +#define lua_lock(L) ((void) 0) +#define lua_unlock(L) ((void) 0) +#endif + +#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,L1) ((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 + +/* +** 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. +** 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) /* { */ +/* 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 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_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_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_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 /* } */ + + +/* 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 + + + +#if defined(ltable_c) && !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 + + + +/* +** macro to control inclusion of some hard tests on stack reallocation +*/ +#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 condchangemem(L) \ + ((void)(!(G(L)->gcrunning) || (luaC_fullgc(L, 0), 1))) +#endif + +#endif diff --git a/src/lmathlib.c b/src/lmathlib.c new file mode 100644 index 0000000000..c3c605e86b --- /dev/null +++ b/src/lmathlib.c @@ -0,0 +1,283 @@ +/* +** $Id: lmathlib.c,v 1.81 2012/05/18 17:47:53 roberto Exp $ +** Standard mathematical library +** See Copyright Notice in lua.h +*/ + + +#include +#include + +#define lmathlib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#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) + + + +static int math_abs (lua_State *L) { + lua_pushnumber(L, l_tg(fabs)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_sin (lua_State *L) { + lua_pushnumber(L, l_tg(sin)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_sinh (lua_State *L) { + lua_pushnumber(L, l_tg(sinh)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_cos (lua_State *L) { + lua_pushnumber(L, l_tg(cos)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_cosh (lua_State *L) { + lua_pushnumber(L, l_tg(cosh)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_tan (lua_State *L) { + lua_pushnumber(L, l_tg(tan)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_tanh (lua_State *L) { + lua_pushnumber(L, l_tg(tanh)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_asin (lua_State *L) { + lua_pushnumber(L, l_tg(asin)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_acos (lua_State *L) { + lua_pushnumber(L, l_tg(acos)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_atan (lua_State *L) { + lua_pushnumber(L, l_tg(atan)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_atan2 (lua_State *L) { + 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, l_tg(ceil)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_floor (lua_State *L) { + lua_pushnumber(L, l_tg(floor)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_fmod (lua_State *L) { + lua_pushnumber(L, l_tg(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_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))); + return 1; +} + +static int math_pow (lua_State *L) { + lua_pushnumber(L, l_tg(pow)(luaL_checknumber(L, 1), + luaL_checknumber(L, 2))); + return 1; +} + +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); + 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); + } + lua_pushnumber(L, res); + return 1; +} + +#if defined(LUA_COMPAT_LOG10) +static int math_log10 (lua_State *L) { + lua_pushnumber(L, l_tg(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))); + return 1; +} + +static int math_deg (lua_State *L) { + lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE); + return 1; +} + +static int math_rad (lua_State *L) { + lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE); + return 1; +} + +static int math_frexp (lua_State *L) { + int 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, l_tg(ldexp)(luaL_checknumber(L, 1), + luaL_checkint(L, 2))); + return 1; +} + + + +static int math_min (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + lua_Number dmin = luaL_checknumber(L, 1); + int i; + for (i=2; i<=n; i++) { + lua_Number d = luaL_checknumber(L, i); + if (d < dmin) + dmin = d; + } + lua_pushnumber(L, dmin); + return 1; +} + + +static int math_max (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + lua_Number dmax = luaL_checknumber(L, 1); + int i; + for (i=2; i<=n; i++) { + lua_Number d = luaL_checknumber(L, i); + if (d > dmax) + dmax = d; + } + lua_pushnumber(L, dmax); + return 1; +} + + +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 */ + 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 */ + 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] */ + 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] */ + break; + } + default: return luaL_error(L, "wrong number of arguments"); + } + return 1; +} + + +static int math_randomseed (lua_State *L) { + srand(luaL_checkunsigned(L, 1)); + (void)rand(); /* discard first value to avoid undesirable correlations */ + return 0; +} + + +static const luaL_Reg mathlib[] = { + {"abs", math_abs}, + {"acos", math_acos}, + {"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}, + {"fmod", math_fmod}, + {"frexp", math_frexp}, + {"ldexp", math_ldexp}, +#if defined(LUA_COMPAT_LOG10) + {"log10", math_log10}, +#endif + {"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} +}; + + +/* +** Open math library +*/ +LUAMOD_API int luaopen_math (lua_State *L) { + luaL_newlib(L, mathlib); + 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.c b/src/lmem.c new file mode 100644 index 0000000000..3f88496e09 --- /dev/null +++ b/src/lmem.c @@ -0,0 +1,99 @@ +/* +** $Id: lmem.c,v 1.84 2012/05/23 15:41:53 roberto Exp $ +** Interface to Memory Manager +** See Copyright Notice in lua.h +*/ + + +#include + +#define lmem_c +#define LUA_CORE + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" + + + +/* +** About the realloc function: +** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); +** (`osize' is the old size, `nsize' is the new size) +** +** * 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); +** particularly, frealloc(ud, NULL, 0, 0) does nothing +** (which is equivalent to free(NULL) in ANSI C) +** +** frealloc returns NULL if it cannot create or reallocate the area +** (any reallocation to an equal or smaller size cannot fail!) +*/ + + + +#define MINSIZEARRAY 4 + + +void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems, + 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, "too many %s (limit is %d)", what, limit); + newsize = limit; /* still have at least one free place */ + } + else { + newsize = (*size)*2; + if (newsize < MINSIZEARRAY) + newsize = MINSIZEARRAY; /* minimum size */ + } + newblock = luaM_reallocv(L, block, *size, newsize, size_elems); + *size = newsize; /* update only when everything else is OK */ + return newblock; +} + + +l_noret luaM_toobig (lua_State *L) { + luaG_runerror(L, "memory allocation error: block too big"); +} + + + +/* +** generic allocation routine. +*/ +void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { + void *newblock; + global_State *g = G(L); + size_t realosize = (block) ? osize : 0; + lua_assert((realosize == 0) == (block == NULL)); +#if defined(HARDMEMTESTS) + 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 (g->gcrunning) { + 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->GCdebt = (g->GCdebt + nsize) - realosize; + return newblock; +} + diff --git a/src/lmem.h b/src/lmem.h new file mode 100644 index 0000000000..535dfe07f3 --- /dev/null +++ b/src/lmem.h @@ -0,0 +1,50 @@ +/* +** $Id: lmem.h,v 1.38 2011/12/02 13:26:54 roberto Exp $ +** Interface to Memory Manager +** See Copyright Notice in lua.h +*/ + +#ifndef lmem_h +#define lmem_h + + +#include + +#include "llimits.h" +#include "lua.h" + + +#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))) + +#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) luaM_reallocv(L, (b), n, 0, sizeof((b)[0])) + +#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))) + +#define luaM_reallocvector(L, v,oldn,n,t) \ + ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t)))) + +LUAI_FUNC l_noret 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_growaux_ (lua_State *L, void *block, int *size, + size_t size_elem, int limit, + const char *what); + +#endif + diff --git a/src/loadlib.c b/src/loadlib.c new file mode 100644 index 0000000000..a9959277bd --- /dev/null +++ b/src/loadlib.c @@ -0,0 +1,725 @@ +/* +** $Id: loadlib.c,v 1.111 2012/05/30 12:33:44 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 Windows, and a stub for other +** systems. +*/ + + +/* +** if needed, includes windows header before everything else +*/ +#if defined(_WIN32) +#include +#endif + + +#include +#include + + +#define loadlib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** LUA_PATH and LUA_CPATH are the names of the environment +** variables that Lua check to set its paths. +*/ +#if !defined(LUA_PATH) +#define LUA_PATH "LUA_PATH" +#endif + +#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. +** 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 + + +/* +** 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_" + +/* separator for open functions in C libraries */ +#define LUA_OFSEP "_" + + +/* table (in the registry) that keeps handles for all loaded C libraries */ +#define CLIBS "_CLIBS" + +#define LIB_FAIL "open" + + +/* error codes for ll_loadfunc */ +#define ERRLIB 1 +#define ERRFUNC 2 + +#define setprogdir(L) ((void)0) + + +/* +** system-dependent functions +*/ +static void ll_unloadlib (void *lib); +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_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, int seeglb) { + void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL)); + 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(LUA_DL_DLL) +/* +** {====================================================================== +** This is an implementation of loadlib for Windows using native functions. +** ======================================================================= +*/ + +#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; + DWORD nsize = sizeof(buff)/sizeof(char); + DWORD n = GetModuleFileNameA(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_EXEC_DIR, buff); + lua_remove(L, -2); /* remove original string */ + } +} + + +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)/sizeof(char), NULL)) + lua_pushstring(L, buffer); + else + lua_pushfstring(L, "system error %d\n", error); +} + +static void ll_unloadlib (void *lib) { + FreeLibrary((HMODULE)lib); +} + + +static void *ll_load (lua_State *L, const char *path, int seeglb) { + HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS); + (void)(seeglb); /* not used: symbols are 'global' by default */ + 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((HMODULE)lib, sym); + if (f == NULL) pusherror(L); + return f; +} + +/* }====================================================== */ + + +#else +/* +** {====================================================== +** Fallback for other systems +** ======================================================= +*/ + +#undef LIB_FAIL +#define LIB_FAIL "absent" + + +#define DLMSG "dynamic libraries not enabled; check your Lua installation" + + +static void ll_unloadlib (void *lib) { + (void)(lib); /* not used */ +} + + +static void *ll_load (lua_State *L, const char *path, int seeglb) { + (void)(path); (void)(seeglb); /* not used */ + lua_pushliteral(L, DLMSG); + return NULL; +} + + +static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { + (void)(lib); (void)(sym); /* not used */ + lua_pushliteral(L, DLMSG); + return NULL; +} + +/* }====================================================== */ +#endif + + +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 for CLIBS table: calls 'll_unloadlib' for all lib +** handles in list CLIBS +*/ +static int gctm (lua_State *L) { + 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_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); + if (f == NULL) + return ERRFUNC; /* unable to find function */ + lua_pushcfunction(L, f); /* else create new function */ + return 0; /* no errors */ + } +} + + +static int ll_loadlib (lua_State *L) { + const char *path = luaL_checkstring(L, 1); + const char *init = luaL_checkstring(L, 2); + 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' function +** ======================================================= +*/ + + +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_PATH_SEP) path++; /* skip separators */ + if (*path == '\0') return NULL; /* no more templates */ + 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 *searchpath (lua_State *L, const char *name, + const char *path, + 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, 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); + lua_remove(L, -2); /* remove path template */ + if (readable(filename)) /* does file exist and is readable? */ + return filename; /* return that file name */ + lua_pushfstring(L, "\n\tno file " LUA_QS, filename); + lua_remove(L, -2); /* remove file name */ + luaL_addvalue(&msg); /* concatenate error msg. entry */ + } + luaL_pushresult(&msg); /* create error message */ + return NULL; /* not found */ +} + + +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, 4, LUA_DIRSEP)); + 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 *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, ".", dirsep); +} + + +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)); +} + + +static int searcher_Lua (lua_State *L) { + const char *filename; + const char *name = luaL_checkstring(L, 1); + 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); +} + + +static int loadfunc (lua_State *L, const char *filename, const char *modname) { + const char *funcname; + 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, 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, LUA_POF"%s", modname); + return ll_loadfunc(L, filename, funcname); +} + + +static int searcher_C (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + 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); +} + + +static int searcher_Croot (lua_State *L) { + 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", LUA_CSUBSEP); + if (filename == NULL) return 1; /* root not found */ + if ((stat = loadfunc(L, filename, name)) != 0) { + 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; + } + } + lua_pushstring(L, filename); /* will be 2nd argument to module */ + return 2; +} + + +static int searcher_preload (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD"); + lua_getfield(L, -1, name); + if (lua_isnil(L, -1)) /* not found? */ + lua_pushfstring(L, "\n\tno field package.preload['%s']", name); + return 1; +} + + +static void findloader (lua_State *L, const char *name) { + int i; + 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"); + /* iterate over available searchers to find a loader */ + for (i = 1; ; i++) { + lua_rawgeti(L, 3, i); /* get a searcher */ + 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, -1)); + } + lua_pushstring(L, name); + lua_call(L, 1, 2); /* call it */ + if (lua_isfunction(L, -2)) /* did it find a loader? */ + return; /* module loader found */ + else if (lua_isstring(L, -2)) { /* searcher returned error message? */ + lua_pop(L, 1); /* remove extra return */ + 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 */ + if (!lua_isnil(L, -1)) /* non-nil return? */ + lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ + lua_getfield(L, 2, name); + 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 */ + } + return 1; +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** 'module' function +** ======================================================= +*/ +#if defined(LUA_COMPAT_MODULE) + +/* +** changes the environment 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_setupvalue(L, -2, 1); + lua_pop(L, 1); /* remove function */ +} + + +static void dooptions (lua_State *L, int n) { + int i; + for (i = 2; i <= n; i++) { + 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); + } + } +} + + +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); + 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? */ + lua_pop(L, 1); + else { /* no; initialize it */ + lua_pop(L, 1); + modinit(L, modname); + } + lua_pushvalue(L, -1); + set_env(L); + dooptions(L, lastarg); + return 1; +} + + +static int ll_seeall (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + if (!lua_getmetatable(L, 1)) { + lua_createtable(L, 0, 1); /* create new metatable */ + lua_pushvalue(L, -1); + lua_setmetatable(L, 1); + } + lua_pushglobaltable(L); + lua_setfield(L, -2, "__index"); /* mt.__index = _G */ + return 0; +} + +#endif +/* }====================================================== */ + + + +/* auxiliary mark (for internal use) */ +#define AUXMARK "\1" + + +/* +** return registry.LUA_NOENV as a boolean +*/ +static int noenv (lua_State *L) { + int b; + lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); + b = lua_toboolean(L, -1); + lua_pop(L, 1); /* remove value */ + return b; +} + + +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 || noenv(L)) /* 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_PATH_SEP LUA_PATH_SEP, + LUA_PATH_SEP AUXMARK LUA_PATH_SEP); + 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}, + {"searchpath", ll_searchpath}, +#if defined(LUA_COMPAT_MODULE) + {"seeall", ll_seeall}, +#endif + {NULL, NULL} +}; + + +static const luaL_Reg ll_funcs[] = { +#if defined(LUA_COMPAT_MODULE) + {"module", ll_module}, +#endif + {"require", ll_require}, + {NULL, NULL} +}; + + +static void createsearcherstable (lua_State *L) { + static const lua_CFunction searchers[] = + {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL}; + int i; + /* create 'searchers' table */ + lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); + /* fill it with pre-defined searchers */ + for (i=0; searchers[i] != NULL; i++) { + lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */ + 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' */ +#endif + lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */ + /* 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_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); + lua_setfield(L, -2, "loaded"); + /* set field `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 */ + 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.c b/src/lobject.c new file mode 100644 index 0000000000..cf0f75446d --- /dev/null +++ b/src/lobject.c @@ -0,0 +1,289 @@ +/* +** $Id: lobject.c,v 2.55 2011/11/30 19:30:16 roberto Exp $ +** Some generic functions over Lua objects +** See Copyright Notice in lua.h +*/ + +#include +#include +#include +#include + +#define lobject_c +#define LUA_CORE + +#include "lua.h" + +#include "lctype.h" +#include "ldebug.h" +#include "ldo.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "lvm.h" + + + +LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT}; + + +/* +** converts an integer to a "floating point byte", represented as +** (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; /* exponent */ + if (x < 8) return x; + while (x >= 0x10) { + x = (x+1) >> 1; + e++; + } + return ((e+1) << 3) | (cast_int(x) - 8); +} + + +/* converts back */ +int luaO_fb2int (int x) { + int e = (x >> 3) & 0x1f; + if (e == 0) return x; + else return ((x & 7) + 8) << (e - 1); +} + + +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, + 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 + }; + int l = 0; + x--; + while (x >= 256) { l += 8; x >>= 8; } + return l + log_2[x]; +} + + +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(NULL, v1); + default: lua_assert(0); return 0; + } +} + + +int luaO_hexavalue (int c) { + if (lisdigit(c)) return c - '0'; + else return ltolower(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; +} + + +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))); + (*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; + 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); + if (endptr == s) return 0; /* nothing recognized */ + while (lisspace(cast_uchar(*endptr))) endptr++; + return (endptr == s + len); /* OK if no trailing characters */ +} + + + +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 = 0; + for (;;) { + const char *e = strchr(fmt, '%'); + if (e == NULL) break; + setsvalue2s(L, L->top, luaS_newlstr(L, fmt, e-fmt)); + incr_top(L); + switch (*(e+1)) { + case 's': { + const char *s = va_arg(argp, char *); + if (s == NULL) s = "(null)"; + pushstr(L, s, strlen(s)); + break; + } + case 'c': { + char buff; + buff = cast(char, va_arg(argp, int)); + pushstr(L, &buff, 1); + break; + } + case 'd': { + setnvalue(L->top, cast_num(va_arg(argp, int))); + incr_top(L); + break; + } + case 'f': { + setnvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); + incr_top(L); + break; + } + case 'p': { + char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */ + int l = sprintf(buff, "%p", va_arg(argp, void *)); + pushstr(L, buff, l); + break; + } + case '%': { + pushstr(L, "%", 1); + break; + } + default: { + luaG_runerror(L, + "invalid option " LUA_QL("%%%c") " to " LUA_QL("lua_pushfstring"), + *(e + 1)); + } + } + n += 2; + fmt = e+2; + } + pushstr(L, fmt, strlen(fmt)); + if (n > 0) luaV_concat(L, n + 1); + return svalue(L->top - 1); +} + + +const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { + const char *msg; + va_list argp; + va_start(argp, fmt); + msg = luaO_pushvfstring(L, fmt, argp); + va_end(argp); + return msg; +} + + +/* number of chars of a literal string without the ending \0 */ +#define LL(x) (sizeof(x)/sizeof(char) - 1) + +#define RETS "..." +#define PRE "[string \"" +#define POS "\"]" + +#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 * sizeof(char)); + else { /* truncate it */ + addstr(out, source + 1, bufflen - 1); + *out = '\0'; + } + } + else if (*source == '@') { /* file name */ + if (l <= bufflen) /* small enough? */ + 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 * sizeof(char)); + } + } + 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) + 1; /* save space for prefix+suffix+'\0' */ + 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) * sizeof(char)); + } +} + diff --git a/src/lobject.h b/src/lobject.h new file mode 100644 index 0000000000..ca75a028c2 --- /dev/null +++ b/src/lobject.h @@ -0,0 +1,610 @@ +/* +** $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 +*/ + + +#ifndef lobject_h +#define lobject_h + + +#include + + +#include "llimits.h" +#include "lua.h" + + +/* +** Extra tags for non-values +*/ +#define LUA_TPROTO LUA_NUMTAGS +#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 +*/ + +#define VARBITS (3 << 4) + + +/* +** LUA_TFUNCTION variants: +** 0 - Lua function +** 1 - light C function +** 2 - regular C function (closure) +*/ + +/* 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 */ + + +/* +** LUA_TSTRING variants */ +#define LUA_TSHRSTR (LUA_TSTRING | (0 << 4)) /* short strings */ +#define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) /* long strings */ + + +/* 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 +*/ +typedef union GCObject GCObject; + + +/* +** 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 + + +/* +** Common header in struct form +*/ +typedef struct GCheader { + CommonHeader; +} GCheader; + + + +/* +** Union of all Lua values +*/ +typedef union Value Value; + + +#define numfield lua_Number n; /* numbers */ + + + +/* +** 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_ + +typedef struct lua_TValue TValue; + + +/* macro defining a nil value */ +#define NILCONSTANT {NULL}, LUA_TNIL + + +#define val_(o) ((o)->value_) +#define num_(o) (val_(o).n) + + +/* raw type tag of a TValue */ +#define rttype(o) ((o)->tt_) + +/* tag with no variants (bits 0-3) */ +#define novariant(x) ((x) & 0x0F) + +/* 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) (novariant(rttype(o))) + + +/* Macros to test type */ +#define checktag(o,t) (rttype(o) == (t)) +#define checktype(o,t) (ttypenv(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) checktype((o), LUA_TSTRING) +#define ttisshrstring(o) checktag((o), ctb(LUA_TSHRSTR)) +#define ttislngstring(o) checktag((o), ctb(LUA_TLNGSTR)) +#define ttistable(o) checktag((o), ctb(LUA_TTABLE)) +#define ttisfunction(o) checktype(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), LUA_TDEADKEY) + +#define ttisequal(o1,o2) (rttype(o1) == rttype(o2)) + +/* Macros to access values */ +#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), &val_(o).gc->u) +#define uvalue(o) (&rawuvalue(o)->uv) +#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) +/* 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)) + + +#define iscollectable(o) (rttype(o) & BIT_ISCOLLECTABLE) + + +/* Macros for internal tests */ +#define righttt(obj) (ttype(obj) == gcvalue(obj)->gch.tt) + +#define checkliveness(g,obj) \ + lua_longassert(!iscollectable(obj) || \ + (righttt(obj) && !isdead(g,gcvalue(obj)))) + + +/* Macros to set values */ +#define settt_(o,t) ((o)->tt_=(t)) + +#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) \ + { TValue *io=(obj); val_(io).f=(x); settt_(io, LUA_TLCF); } + +#define setpvalue(obj,x) \ + { TValue *io=(obj); val_(io).p=(x); settt_(io, LUA_TLIGHTUSERDATA); } + +#define setbvalue(obj,x) \ + { 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 *io=(obj); \ + TString *x_ = (x); \ + val_(io).gc=cast(GCObject *, x_); settt_(io, ctb(x_->tsv.tt)); \ + checkliveness(G(L),io); } + +#define setuvalue(L,obj,x) \ + { TValue *io=(obj); \ + val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TUSERDATA)); \ + checkliveness(G(L),io); } + +#define setthvalue(L,obj,x) \ + { 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 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 *io=(obj); \ + val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TTABLE)); \ + checkliveness(G(L),io); } + +#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY) + + + +#define setobj(L,obj1,obj2) \ + { const TValue *io2=(obj2); TValue *io1=(obj1); \ + io1->value_ = io2->value_; io1->tt_ = io2->tt_; \ + checkliveness(G(L),io1); } + + +/* +** different types of assignments, according to destination +*/ + +/* from stack to (same) stack */ +#define setobjs2s setobj +/* 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 */ +#define setobj2t setobj +/* to new object */ +#define setobj2n setobj +#define setsvalue2n setsvalue + + +/* check whether a number is valid (useful only for NaN trick) */ +#define luai_checknum(L,o,c) { /* empty */ } + + +/* +** {====================================================== +** NaN Trick +** ======================================================= +*/ +#if defined(LUA_NANTRICK) + +/* +** 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') +*/ + +/* 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 + +#undef TValuefields +#undef NILCONSTANT + +#if (LUA_IEEEENDIAN == 0) /* { */ + +/* little endian */ +#define TValuefields \ + union { struct { Value v__; int tt__; } i; double d__; } u +#define NILCONSTANT {{{NULL}, tag2tt(LUA_TNIL)}} +/* field-access macros */ +#define v_(o) ((o)->u.i.v__) +#define d_(o) ((o)->u.d__) +#define tt_(o) ((o)->u.i.tt__) + +#else /* }{ */ + +/* big endian */ +#define TValuefields \ + 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__) + +#endif /* } */ + +#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) ((tt_(o) & NNMASK) != NNMARK) + +#define tag2tt(t) (NNMARK | (t)) + +#undef rttype +#define rttype(o) (ttisnumber(o) ? LUA_TNUMBER : tt_(o) & 0xff) + +#undef settt_ +#define settt_(o,t) (tt_(o) = 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 +#undef checktype +#define checktag(o,t) (tt_(o) == tag2tt(t)) +#define checktype(o,t) (ctb(tt_(o) | VARBITS) == ctb(tag2tt(t) | VARBITS)) + +#undef ttisequal +#define ttisequal(o1,o2) \ + (ttisnumber(o1) ? ttisnumber(o2) : (tt_(o1) == tt_(o2))) + + +#undef luai_checknum +#define luai_checknum(L,o,c) { if (!ttisnumber(o)) c; } + +#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 +*/ +typedef union TString { + L_Umaxalign dummy; /* ensures maximum alignment for strings */ + struct { + CommonHeader; + lu_byte extra; /* reserved words for short strings; "has hash" for longs */ + unsigned int hash; + size_t len; /* number of characters in string */ + } tsv; +} TString; + + +/* get the actual string (array of bytes) from a TString */ +#define getstr(ts) cast(const char *, (ts) + 1) + +/* 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 { + CommonHeader; + struct Table *metatable; + struct Table *env; + size_t len; /* number of bytes */ + } uv; +} Udata; + + + +/* +** Description of an upvalue for function prototypes +*/ +typedef struct Upvaldesc { + TString *name; /* upvalue name (for debug information) */ + 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 +*/ +typedef struct Proto { + CommonHeader; + 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 (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; /* used for debug information */ + int sizeupvalues; /* size of 'upvalues' */ + int sizek; /* size of `k' */ + int sizecode; + int sizelineinfo; + int sizep; /* size of `p' */ + int sizelocvars; + int linedefined; + int lastlinedefined; + GCObject *gclist; + lu_byte numparams; /* number of fixed parameters */ + lu_byte is_vararg; + lu_byte maxstacksize; /* maximum stack used by this function */ +} Proto; + + + +/* +** Lua Upvalues +*/ +typedef struct UpVal { + CommonHeader; + TValue *v; /* points to stack or to its own value */ + union { + TValue value; /* the value (when closed) */ + struct { /* double linked list (when open) */ + struct UpVal *prev; + struct UpVal *next; + } l; + } u; +} UpVal; + + +/* +** Closures +*/ + +#define ClosureHeader \ + CommonHeader; lu_byte nupvalues; GCObject *gclist + +typedef struct CClosure { + ClosureHeader; + lua_CFunction f; + TValue upvalue[1]; /* list of upvalues */ +} CClosure; + + +typedef struct LClosure { + ClosureHeader; + struct Proto *p; + UpVal *upvals[1]; /* list of upvalues */ +} LClosure; + + +typedef union Closure { + CClosure c; + LClosure l; +} Closure; + + +#define isLfunction(o) ttisLclosure(o) + +#define getproto(o) (clLvalue(o)->p) + + +/* +** Tables +*/ + +typedef union TKey { + struct { + TValuefields; + struct Node *next; /* for chaining */ + } nk; + TValue tvk; +} TKey; + + +typedef struct Node { + TValue i_val; + TKey i_key; +} Node; + + +typedef struct Table { + CommonHeader; + lu_byte flags; /* 1<

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); +LUAI_FUNC int luaO_fb2int (int 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_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, ...); +LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len); + + +#endif + diff --git a/src/lopcodes.c b/src/lopcodes.c new file mode 100644 index 0000000000..ef73692754 --- /dev/null +++ b/src/lopcodes.c @@ -0,0 +1,107 @@ +/* +** $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 +*/ + + +#define lopcodes_c +#define LUA_CORE + + +#include "lopcodes.h" + + +/* ORDER OP */ + +LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { + "MOVE", + "LOADK", + "LOADKX", + "LOADBOOL", + "LOADNIL", + "GETUPVAL", + "GETTABUP", + "GETTABLE", + "SETTABUP", + "SETUPVAL", + "SETTABLE", + "NEWTABLE", + "SELF", + "ADD", + "SUB", + "MUL", + "DIV", + "MOD", + "POW", + "UNM", + "NOT", + "LEN", + "CONCAT", + "JMP", + "EQ", + "LT", + "LE", + "TEST", + "TESTSET", + "CALL", + "TAILCALL", + "RETURN", + "FORLOOP", + "FORPREP", + "TFORCALL", + "TFORLOOP", + "SETLIST", + "CLOSURE", + "VARARG", + "EXTRAARG", + NULL +}; + + +#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) + +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, 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 */ + ,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 */ + ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */ + ,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_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, 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 */ + ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */ + ,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, 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 new file mode 100644 index 0000000000..07d2b3f39a --- /dev/null +++ b/src/lopcodes.h @@ -0,0 +1,288 @@ +/* +** $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 +*/ + +#ifndef lopcodes_h +#define lopcodes_h + +#include "llimits.h" + + +/*=========================================================================== + We assume that instructions are unsigned numbers. + All instructions have an opcode in the first 6 bits. + Instructions can have the following fields: + `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 + + 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. +===========================================================================*/ + + +enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */ + + +/* +** size and position of opcode arguments. +*/ +#define SIZE_C 9 +#define SIZE_B 9 +#define SIZE_Bx (SIZE_C + SIZE_B) +#define SIZE_A 8 +#define SIZE_Ax (SIZE_C + SIZE_B + SIZE_A) + +#define SIZE_OP 6 + +#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_Ax POS_A + + +/* +** limits for opcode arguments. +** we use (signed) int to manipulate most arguments, +** so they must fit in LUAI_BITSINT-1 bits (-1 for sign) +*/ +#if SIZE_Bx < LUAI_BITSINT-1 +#define MAXARG_Bx ((1<>1) /* `sBx' is signed */ +#else +#define MAXARG_Bx MAX_INT +#define MAXARG_sBx MAX_INT +#endif + +#if SIZE_Ax < LUAI_BITSINT-1 +#define MAXARG_Ax ((1<>POS_OP) & MASK1(SIZE_OP,0))) +#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \ + ((cast(Instruction, o)<>pos) & MASK1(size,0))) +#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \ + ((cast(Instruction, v)<= 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++ */ + +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)) */ +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) > 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)) + + +LUAI_DDEC const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */ + + +/* number of list items to accumulate before a SETLIST instruction */ +#define LFIELDS_PER_FLUSH 50 + + +#endif diff --git a/src/loslib.c b/src/loslib.c new file mode 100644 index 0000000000..489755b6f5 --- /dev/null +++ b/src/loslib.c @@ -0,0 +1,323 @@ +/* +** $Id: loslib.c,v 1.39 2012/05/23 15:37:09 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" + + +/* +** 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 + + +/* +** By default, Lua uses gmtime/localtime, except when POSIX is available, +** where it uses gmtime_r/localtime_r +*/ +#if defined(LUA_USE_GMTIME_R) + +#define l_gmtime(t,r) gmtime_r(t,r) +#define l_localtime(t,r) localtime_r(t,r) + +#elif !defined(l_gmtime) + +#define l_gmtime(t,r) ((void)r, gmtime(t)) +#define l_localtime(t,r) ((void)r, localtime(t)) + +#endif + + + +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_pushboolean(L, stat); /* true if there is a shell */ + return 1; + } +} + + +static int os_remove (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + 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 luaL_fileresult(L, rename(fromname, toname) == 0, fromname); +} + + +static int os_tmpname (lua_State *L) { + 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; +} + + +static int os_getenv (lua_State *L) { + lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ + return 1; +} + + +static int os_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_pushinteger(L, value); + lua_setfield(L, -2, key); +} + +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); +} + +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, isnum; + lua_getfield(L, -1, key); + 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; + } + lua_pop(L, 1); + return res; +} + + +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)); + struct tm tmr, *stm; + if (*s == '!') { /* UTC? */ + stm = l_gmtime(&t, &tmr); + s++; /* skip `!' */ + } + else + stm = l_localtime(&t, &tmr); + 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 cc[4]; + luaL_Buffer b; + cc[0] = '%'; + luaL_buffinit(L, &b); + 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 */ + s = checkoption(L, s + 1, cc); + reslen = strftime(buff, sizeof(buff), cc, stm); + luaL_addlstring(&b, buff, reslen); + } + } + luaL_pushresult(&b); + } + return 1; +} + + +static int os_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, (lua_Number)t); + return 1; +} + + +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; +} + +/* }====================================================== */ + + +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", + "numeric", "time", NULL}; + const char *l = luaL_optstring(L, 1, NULL); + int op = luaL_checkoption(L, 2, "all", catnames); + lua_pushstring(L, setlocale(cat[op], l)); + return 1; +} + + +static int os_exit (lua_State *L) { + 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); + if (L) exit(status); /* 'if' to avoid warnings for unreachable 'return' */ + return 0; +} + + +static const luaL_Reg syslib[] = { + {"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} +}; + +/* }====================================================== */ + + + +LUAMOD_API int luaopen_os (lua_State *L) { + luaL_newlib(L, syslib); + return 1; +} + diff --git a/src/lparser.c b/src/lparser.c new file mode 100644 index 0000000000..b3eb3ca923 --- /dev/null +++ b/src/lparser.c @@ -0,0 +1,1635 @@ +/* +** $Id: lparser.c,v 2.128 2012/05/20 14:51:23 roberto Exp $ +** Lua Parser +** See Copyright Notice in lua.h +*/ + + +#include + +#define lparser_c +#define LUA_CORE + +#include "lua.h" + +#include "lcode.h" +#include "ldebug.h" +#include "ldo.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 "ltable.h" + + + +/* maximum number of local variables per function (must be smaller + than 250, due to the bytecode format) */ +#define MAXVARS 200 + + +#define hasmultret(k) ((k) == VCALL || (k) == VVARARG) + + + +/* +** nodes for block list (list of active blocks) +*/ +typedef struct BlockCnt { + struct BlockCnt *previous; /* chain */ + 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 */ +} BlockCnt; + + + +/* +** prototypes for recursive non-terminal functions +*/ +static void statement (LexState *ls); +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); + } +} + + +/* semantic error */ +static l_noret semerror (LexState *ls, const char *msg) { + ls->t.token = 0; /* remove 'near to' from final message */ + luaX_syntaxerror(ls, msg); +} + + +static l_noret error_expected (LexState *ls, int token) { + luaX_syntaxerror(ls, + luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token))); +} + + +static l_noret 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(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); +} + + +static void checklimit (FuncState *fs, int v, int l, const char *what) { + if (v > l) errorlimit(fs, l, what); +} + + +static int testnext (LexState *ls, int c) { + if (ls->t.token == c) { + luaX_next(ls); + return 1; + } + else return 0; +} + + +static void check (LexState *ls, int c) { + if (ls->t.token != c) + error_expected(ls, c); +} + + +static void checknext (LexState *ls, int c) { + check(ls, c); + luaX_next(ls); +} + + +#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 (!testnext(ls, what)) { + if (where == ls->linenumber) + error_expected(ls, what); + else { + luaX_syntaxerror(ls, luaO_pushfstring(ls->L, + "%s expected (to close %s at line %d)", + luaX_token2str(ls, what), luaX_token2str(ls, who), where)); + } + } +} + + +static TString *str_checkname (LexState *ls) { + TString *ts; + check(ls, TK_NAME); + ts = ls->t.seminfo.ts; + luaX_next(ls); + return ts; +} + + +static void init_exp (expdesc *e, expkind k, int i) { + e->f = e->t = NO_JUMP; + e->k = k; + e->u.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 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, 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); + return fs->nlocvars++; +} + + +static void new_localvar (LexState *ls, TString *name) { + FuncState *fs = ls->fs; + Dyndata *dyd = ls->dyd; + int reg = registerlocalvar(ls, name); + checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, + 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(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 LocVar *getlocvar (FuncState *fs, int i) { + int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx; + lua_assert(idx < fs->nlocvars); + return &fs->f->locvars[idx]; +} + + +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; + } +} + + +static void removevars (FuncState *fs, int tolevel) { + fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel); + while (fs->nactvar > tolevel) + getlocvar(fs, --fs->nactvar)->endpc = fs->pc; +} + + +static int searchupvalue (FuncState *fs, TString *name) { + int i; + Upvaldesc *up = fs->f->upvalues; + for (i = 0; i < fs->nups; i++) { + if (luaS_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; + checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); + 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->ls->L, f, name); + return fs->nups++; +} + + +static int searchvar (FuncState *fs, TString *n) { + int i; + for (i=fs->nactvar-1; i >= 0; i--) { + if (luaS_eqstr(n, getlocvar(fs, i)->varname)) + return i; + } + return -1; /* not found */ +} + + +/* + Mark block where variable at given level was defined + (to emit close instructions later). +*/ +static void markupval (FuncState *fs, int level) { + BlockCnt *bl = fs->bl; + while (bl->nactvar > level) bl = bl->previous; + bl->upval = 1; +} + + +/* + 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 VVOID; /* default is global */ + else { + 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 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; + } + } +} + + +static void singlevar (LexState *ls, expdesc *var) { + TString *varname = str_checkname(ls); + FuncState *fs = ls->fs; + if (singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */ + expdesc key; + 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] */ + } +} + + +static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { + FuncState *fs = ls->fs; + int extra = nvars - nexps; + if (hasmultret(e->k)) { + extra++; /* includes call itself */ + 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 */ + if (extra > 0) { + int reg = fs->freereg; + luaK_reserveregs(fs, extra); + luaK_nil(fs, reg, extra); + } + } +} + + +static void enterlevel (LexState *ls) { + lua_State *L = ls->L; + ++L->nCcalls; + checklimit(ls->fs, L->nCcalls, LUAI_MAXCCALLS, "C levels"); +} + + +#define leavelevel(ls) ((ls)->L->nCcalls--) + + +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(luaS_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(vname)); + 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 (luaS_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, SHRT_MAX, "labels/gotos"); + 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 (luaS_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 exits 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; + lua_assert(fs->freereg == fs->nactvar); +} + + +/* +** 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 l_noret undefgoto (LexState *ls, Labeldesc *gt) { + const char *msg = isreserved(gt->name) + ? "<%s> at line %d not inside a loop" + : "no visible label " LUA_QS " for at line %d"; + 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); + lua_assert(bl->nactvar == fs->nactvar); + fs->freereg = fs->nactvar; /* free registers */ + 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 */ +} + + +/* +** adds a new prototype into list of prototypes +*/ +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(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions"); + while (oldsize < f->sizep) f->p[oldsize++] = NULL; + } + 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) */ +} + + +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 */ + fs->ls = ls; + ls->fs = fs; + fs->pc = 0; + 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->dyd->actvar.n; + fs->bl = NULL; + f = fs->f; + f->source = ls->source; + f->maxstacksize = 2; /* registers 0/1 are always valid */ + fs->h = luaH_new(L); + /* anchor table of constants (to avoid being collected) */ + sethvalue2s(L, L->top, fs->h); + incr_top(L); + enterblock(fs, bl, 0); +} + + +static void close_func (LexState *ls) { + lua_State *L = ls->L; + FuncState *fs = ls->fs; + Proto *f = fs->f; + luaK_ret(fs, 0, 0); /* final return */ + 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); + f->sizelineinfo = fs->pc; + 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; + luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar); + f->sizelocvars = fs->nlocvars; + luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc); + f->sizeupvalues = fs->nups; + lua_assert(fs->bl == NULL); + ls->fs = fs->prev; + /* last token read was anchored in defunct function; must re-anchor it */ + anchor_token(ls); + L->top--; /* pop table of constants */ + luaC_checkGC(L); +} + + + +/*============================================================*/ +/* 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; + expdesc key; + luaK_exp2anyregup(fs, v); + luaX_next(ls); /* skip the dot or colon */ + checkname(ls, &key); + luaK_indexed(fs, v, &key); +} + + +static void yindex (LexState *ls, expdesc *v) { + /* index -> '[' expr ']' */ + luaX_next(ls); /* skip the '[' */ + expr(ls, v); + luaK_exp2val(ls->fs, v); + checknext(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 reg = ls->fs->freereg; + expdesc key, val; + int rkkey; + if (ls->t.token == TK_NAME) { + checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); + checkname(ls, &key); + } + else /* ls->t.token == '[' */ + yindex(ls, &key); + cc->nh++; + checknext(ls, '='); + rkkey = luaK_exp2RK(fs, &key); + expr(ls, &val); + luaK_codeABC(fs, OP_SETTABLE, cc->t->u.info, rkkey, 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_setlist(fs, cc->t->u.info, cc->na, cc->tostore); /* flush */ + cc->tostore = 0; /* no more items pending */ + } +} + + +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.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.info, cc->na, cc->tostore); + } +} + + +static void listfield (LexState *ls, struct ConsControl *cc) { + /* listfield -> exp */ + expr(ls, &cc->v); + 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 -> '{' [ field { sep field } [sep] ] '}' + sep -> ',' | ';' */ + 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 */ + checknext(ls, '{'); + do { + lua_assert(cc.v.k == VVOID || cc.tostore > 0); + if (ls->t.token == '}') break; + closelistfield(fs, &cc); + field(ls, &cc); + } 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_int2fb(cc.nh)); /* set initial table size */ +} + +/* }====================================================================== */ + + + +static void parlist (LexState *ls) { + /* parlist -> [ param { `,' param } ] */ + FuncState *fs = ls->fs; + Proto *f = fs->f; + int nparams = 0; + f->is_vararg = 0; + if (ls->t.token != ')') { /* is `parlist' not empty? */ + do { + switch (ls->t.token) { + case TK_NAME: { /* param -> NAME */ + new_localvar(ls, str_checkname(ls)); + nparams++; + break; + } + case TK_DOTS: { /* param -> `...' */ + luaX_next(ls); + f->is_vararg = 1; + break; + } + default: luaX_syntaxerror(ls, " or " LUA_QL("...") " expected"); + } + } while (!f->is_vararg && testnext(ls, ',')); + } + adjustlocalvars(ls, nparams); + f->numparams = cast_byte(fs->nactvar); + luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ +} + + +static void body (LexState *ls, expdesc *e, int ismethod, int line) { + /* body -> `(' parlist `)' block END */ + FuncState new_fs; + BlockCnt 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 */ + adjustlocalvars(ls, 1); + } + parlist(ls); + checknext(ls, ')'); + statlist(ls); + new_fs.f->lastlinedefined = ls->linenumber; + check_match(ls, TK_END, TK_FUNCTION, line); + codeclosure(ls, e); + close_func(ls); +} + + +static int explist (LexState *ls, expdesc *v) { + /* explist -> expr { `,' expr } */ + int n = 1; /* at least one expression */ + expr(ls, v); + while (testnext(ls, ',')) { + luaK_exp2nextreg(ls->fs, v); + expr(ls, v); + n++; + } + return n; +} + + +static void funcargs (LexState *ls, expdesc *f, int line) { + FuncState *fs = ls->fs; + expdesc args; + int base, nparams; + switch (ls->t.token) { + case '(': { /* funcargs -> `(' [ explist ] `)' */ + luaX_next(ls); + if (ls->t.token == ')') /* arg list is empty? */ + args.k = VVOID; + else { + explist(ls, &args); + luaK_setmultret(fs, &args); + } + check_match(ls, ')', '(', line); + break; + } + case '{': { /* funcargs -> constructor */ + constructor(ls, &args); + break; + } + case TK_STRING: { /* funcargs -> STRING */ + codestring(ls, &args, ls->t.seminfo.ts); + luaX_next(ls); /* must use `seminfo' before `next' */ + break; + } + default: { + luaX_syntaxerror(ls, "function arguments expected"); + } + } + lua_assert(f->k == VNONRELOC); + base = f->u.info; /* base register for call */ + if (hasmultret(args.k)) + nparams = LUA_MULTRET; /* open call */ + else { + if (args.k != VVOID) + luaK_exp2nextreg(fs, &args); /* close last argument */ + nparams = fs->freereg - (base+1); + } + 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 */ +} + + + + +/* +** {====================================================================== +** Expression parsing +** ======================================================================= +*/ + + +static void primaryexp (LexState *ls, expdesc *v) { + /* primaryexp -> NAME | '(' expr ')' */ + switch (ls->t.token) { + case '(': { + int line = ls->linenumber; + luaX_next(ls); + expr(ls, v); + check_match(ls, ')', '(', line); + luaK_dischargevars(ls->fs, v); + return; + } + case TK_NAME: { + singlevar(ls, v); + return; + } + default: { + luaX_syntaxerror(ls, "unexpected symbol"); + } + } +} + + +static void suffixedexp (LexState *ls, expdesc *v) { + /* suffixedexp -> + primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ + FuncState *fs = ls->fs; + int line = ls->linenumber; + primaryexp(ls, v); + for (;;) { + switch (ls->t.token) { + case '.': { /* fieldsel */ + fieldsel(ls, v); + break; + } + case '[': { /* `[' exp1 `]' */ + expdesc key; + luaK_exp2anyregup(fs, v); + yindex(ls, &key); + luaK_indexed(fs, v, &key); + break; + } + case ':': { /* `:' NAME funcargs */ + expdesc key; + luaX_next(ls); + checkname(ls, &key); + luaK_self(fs, v, &key); + funcargs(ls, v, line); + break; + } + case '(': case TK_STRING: case '{': { /* funcargs */ + luaK_exp2nextreg(fs, v); + funcargs(ls, v, line); + break; + } + default: return; + } + } +} + + +static void simpleexp (LexState *ls, expdesc *v) { + /* simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... | + constructor | FUNCTION body | suffixedexp */ + switch (ls->t.token) { + case TK_NUMBER: { + init_exp(v, VKNUM, 0); + v->u.nval = ls->t.seminfo.r; + break; + } + case TK_STRING: { + codestring(ls, v, ls->t.seminfo.ts); + break; + } + case TK_NIL: { + init_exp(v, VNIL, 0); + break; + } + case TK_TRUE: { + init_exp(v, VTRUE, 0); + break; + } + case TK_FALSE: { + init_exp(v, VFALSE, 0); + break; + } + case TK_DOTS: { /* vararg */ + FuncState *fs = ls->fs; + check_condition(ls, fs->f->is_vararg, + "cannot use " LUA_QL("...") " outside a vararg function"); + init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); + break; + } + case '{': { /* constructor */ + constructor(ls, v); + return; + } + case TK_FUNCTION: { + luaX_next(ls); + body(ls, v, 0, ls->linenumber); + return; + } + default: { + suffixedexp(ls, v); + return; + } + } + luaX_next(ls); +} + + +static UnOpr getunopr (int op) { + switch (op) { + case TK_NOT: return OPR_NOT; + case '-': return OPR_MINUS; + case '#': return OPR_LEN; + default: return OPR_NOUNOPR; + } +} + + +static BinOpr getbinopr (int op) { + switch (op) { + case '+': return OPR_ADD; + case '-': return OPR_SUB; + case '*': return OPR_MUL; + case '/': return OPR_DIV; + case '%': return OPR_MOD; + 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; + } +} + + +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}, /* ^, .. (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 */ + + +/* +** 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, int limit) { + BinOpr op; + UnOpr uop; + 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, line); + } + 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; + 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, line); + op = nextop; + } + leavelevel(ls); + return op; /* return first untreated operator */ +} + + +static void expr (LexState *ls, expdesc *v) { + subexpr(ls, v, 0); +} + +/* }==================================================================== */ + + + +/* +** {====================================================================== +** Rules for Statements +** ======================================================================= +*/ + + +static void block (LexState *ls) { + /* block -> statlist */ + FuncState *fs = ls->fs; + BlockCnt bl; + enterblock(fs, &bl, 0); + statlist(ls); + leaveblock(fs); +} + + +/* +** 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 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) { /* 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, extra, v->u.info, 0); + luaK_reserveregs(fs, 1); + } +} + + +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 -> ',' suffixedexp assignment */ + struct LHS_assign nv; + nv.prev = lh; + suffixedexp(ls, &nv.v); + if (nv.v.k != VINDEXED) + check_conflict(ls, lh, &nv.v); + checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS, + "C levels"); + assignment(ls, &nv, nvars+1); + } + else { /* assignment -> `=' explist */ + int nexps; + checknext(ls, '='); + nexps = explist(ls, &e); + if (nexps != nvars) { + adjust_assign(ls, nvars, nexps, &e); + if (nexps > nvars) + ls->fs->freereg -= nexps - nvars; /* remove extra values */ + } + else { + luaK_setoneret(ls->fs, &e); /* close last expression */ + luaK_storevar(ls->fs, &lh->v, &e); + return; /* avoid default */ + } + } + init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ + luaK_storevar(ls->fs, &lh->v, &e); +} + + +static int cond (LexState *ls) { + /* cond -> exp */ + expdesc v; + expr(ls, &v); /* read condition */ + if (v.k == VNIL) v.k = VFALSE; /* `falses' are all equal here */ + luaK_goiftrue(ls->fs, &v); + return v.f; +} + + +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 */ +} + + +/* check for repeated labels on the same block */ +static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) { + int i; + for (i = fs->bl->firstlabel; i < ll->n; i++) { + if (luaS_eqstr(label, ll->arr[i].name)) { + 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); + } + } +} + + +/* 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; + Labellist *ll = &ls->dyd->label; + int l; /* index of new label being created */ + checkrepeated(fs, ll, label); /* check for repeated labels */ + checknext(ls, TK_DBCOLON); /* skip double colon */ + /* create new entry for this label */ + l = newlabelentry(ls, ll, label, line, fs->pc); + 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; + } + findgotos(ls, &ll->arr[l]); +} + + +static void whilestat (LexState *ls, int line) { + /* whilestat -> WHILE cond DO block END */ + FuncState *fs = ls->fs; + int whileinit; + int condexit; + BlockCnt bl; + luaX_next(ls); /* skip WHILE */ + whileinit = luaK_getlabel(fs); + condexit = cond(ls); + enterblock(fs, &bl, 1); + checknext(ls, TK_DO); + block(ls); + luaK_jumpto(fs, whileinit); + check_match(ls, TK_END, TK_WHILE, line); + leaveblock(fs); + luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ +} + + +static void repeatstat (LexState *ls, int line) { + /* repeatstat -> REPEAT block UNTIL cond */ + int condexit; + FuncState *fs = ls->fs; + int repeat_init = luaK_getlabel(fs); + BlockCnt bl1, bl2; + enterblock(fs, &bl1, 1); /* loop block */ + enterblock(fs, &bl2, 0); /* scope block */ + luaX_next(ls); /* skip REPEAT */ + statlist(ls); + check_match(ls, TK_UNTIL, TK_REPEAT, line); + condexit = cond(ls); /* read condition (inside scope block) */ + 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 */ +} + + +static int exp1 (LexState *ls) { + expdesc e; + int reg; + expr(ls, &e); + luaK_exp2nextreg(ls->fs, &e); + lua_assert(e.k == VNONRELOC); + reg = e.u.info; + return reg; +} + + +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, 3); /* control variables */ + checknext(ls, TK_DO); + 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); + block(ls); + leaveblock(fs); /* end of scope for declared variables */ + luaK_patchtohere(fs, prep); + 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); +} + + +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)"); + new_localvarliteral(ls, "(for limit)"); + new_localvarliteral(ls, "(for step)"); + new_localvar(ls, varname); + checknext(ls, '='); + exp1(ls); /* initial value */ + checknext(ls, ','); + exp1(ls); /* limit */ + if (testnext(ls, ',')) + exp1(ls); /* optional step */ + else { /* default step = 1 */ + luaK_codek(fs, fs->freereg, luaK_numberK(fs, 1)); + luaK_reserveregs(fs, 1); + } + forbody(ls, base, line, 1, 1); +} + + +static void forlist (LexState *ls, TString *indexname) { + /* forlist -> NAME {,NAME} IN explist forbody */ + FuncState *fs = ls->fs; + expdesc e; + 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)"); + new_localvarliteral(ls, "(for state)"); + new_localvarliteral(ls, "(for control)"); + /* create declared variables */ + 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, explist(ls, &e), &e); + luaK_checkstack(fs, 3); /* extra space to call generator */ + forbody(ls, base, line, nvars - 3, 0); +} + + +static void forstat (LexState *ls, int line) { + /* forstat -> FOR (fornum | forlist) END */ + FuncState *fs = ls->fs; + TString *varname; + BlockCnt bl; + enterblock(fs, &bl, 1); /* scope for loop and control variables */ + luaX_next(ls); /* skip `for' */ + varname = str_checkname(ls); /* first variable name */ + switch (ls->t.token) { + case '=': fornum(ls, varname, line); break; + case ',': case TK_IN: forlist(ls, varname); break; + 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) */ +} + + +static void test_then_block (LexState *ls, int *escapelist) { + /* test_then_block -> [IF | ELSEIF] cond THEN block */ + 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 */ + expr(ls, &v); /* read condition */ + checknext(ls, TK_THEN); + 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 */ + skipnoopstat(ls); /* skip other no-op statements */ + 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 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 */ + check_match(ls, TK_END, TK_IF, line); + luaK_patchtohere(fs, escapelist); /* patch escape list to 'if' end */ +} + + +static void localfunc (LexState *ls) { + expdesc b; + FuncState *fs = ls->fs; + 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 */ + /* debug information will only see the variable after this point! */ + getlocvar(fs, b.u.info)->startpc = fs->pc; +} + + +static void localstat (LexState *ls) { + /* stat -> LOCAL NAME {`,' NAME} [`=' explist] */ + int nvars = 0; + int nexps; + expdesc e; + do { + new_localvar(ls, str_checkname(ls)); + nvars++; + } while (testnext(ls, ',')); + if (testnext(ls, '=')) + nexps = explist(ls, &e); + else { + e.k = VVOID; + nexps = 0; + } + adjust_assign(ls, nvars, nexps, &e); + adjustlocalvars(ls, nvars); +} + + +static int funcname (LexState *ls, expdesc *v) { + /* funcname -> NAME {fieldsel} [`:' NAME] */ + int ismethod = 0; + singlevar(ls, v); + while (ls->t.token == '.') + fieldsel(ls, v); + if (ls->t.token == ':') { + ismethod = 1; + fieldsel(ls, v); + } + return ismethod; +} + + +static void funcstat (LexState *ls, int line) { + /* funcstat -> FUNCTION funcname body */ + int ismethod; + expdesc v, b; + luaX_next(ls); /* skip FUNCTION */ + 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 */ +} + + +static void exprstat (LexState *ls) { + /* stat -> func | assignment */ + FuncState *fs = ls->fs; + struct LHS_assign v; + 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 */ + } +} + + +static void retstat (LexState *ls) { + /* stat -> RETURN [explist] [';'] */ + FuncState *fs = ls->fs; + expdesc e; + int first, nret; /* registers with returned values */ + if (block_follow(ls, 1) || ls->t.token == ';') + first = nret = 0; /* return no values */ + else { + nret = explist(ls, &e); /* optional return values */ + 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); + } + 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_ret(fs, first, nret); + testnext(ls, ';'); /* skip optional semicolon */ +} + + +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 ';' */ + break; + } + case TK_IF: { /* stat -> ifstat */ + ifstat(ls, line); + break; + } + case TK_WHILE: { /* stat -> whilestat */ + whilestat(ls, line); + break; + } + case TK_DO: { /* stat -> DO block END */ + luaX_next(ls); /* skip DO */ + block(ls); + check_match(ls, TK_END, TK_DO, line); + break; + } + case TK_FOR: { /* stat -> forstat */ + forstat(ls, line); + break; + } + case TK_REPEAT: { /* stat -> repeatstat */ + repeatstat(ls, line); + break; + } + case TK_FUNCTION: { /* stat -> funcstat */ + funcstat(ls, line); + break; + } + case TK_LOCAL: { /* stat -> localstat */ + luaX_next(ls); /* skip LOCAL */ + if (testnext(ls, TK_FUNCTION)) /* local function? */ + localfunc(ls); + else + localstat(ls); + break; + } + case TK_DBCOLON: { /* stat -> label */ + luaX_next(ls); /* skip double colon */ + labelstat(ls, str_checkname(ls), line); + break; + } + case TK_RETURN: { /* stat -> retstat */ + luaX_next(ls); /* skip RETURN */ + retstat(ls); + break; + } + case TK_BREAK: /* stat -> breakstat */ + case TK_GOTO: { /* stat -> 'goto' NAME */ + gotostat(ls, luaK_jump(ls->fs)); + break; + } + default: { /* stat -> func | assignment */ + exprstat(ls); + 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); +} + +/* }====================================================================== */ + + +/* +** 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; + 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, 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 cl; /* it's on the stack too */ +} + diff --git a/src/lparser.h b/src/lparser.h new file mode 100644 index 0000000000..301167d4f5 --- /dev/null +++ b/src/lparser.h @@ -0,0 +1,119 @@ +/* +** $Id: lparser.h,v 1.70 2012/05/08 13:53:33 roberto Exp $ +** Lua Parser +** See Copyright Notice in lua.h +*/ + +#ifndef lparser_h +#define lparser_h + +#include "llimits.h" +#include "lobject.h" +#include "lzio.h" + + +/* +** Expression descriptor +*/ + +typedef enum { + VVOID, /* no value */ + VNIL, + VTRUE, + 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, /* t = table register/upvalue; idx = index R/K */ + VJMP, /* info = instruction pc */ + VRELOCABLE, /* info = instruction pc */ + 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 { /* 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' */ +} expdesc; + + +/* description of active local variable */ +typedef struct Vardesc { + short idx; /* variable index in stack */ +} Vardesc; + + +/* 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 */ + + +/* 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 BlockCnt *bl; /* chain of current blocks */ + int pc; /* next position to code (equivalent to `ncode') */ + int lasttarget; /* 'label' of last 'jump label' */ + int jpc; /* list of pending jumps to `pc' */ + int nk; /* number of elements in `k' */ + int np; /* number of elements in `p' */ + 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; + + +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 new file mode 100644 index 0000000000..3c00c28559 --- /dev/null +++ b/src/lstate.c @@ -0,0 +1,322 @@ +/* +** $Id: lstate.c,v 2.98 2012/05/30 12:33:44 roberto Exp $ +** Global State +** See Copyright Notice in lua.h +*/ + + +#include +#include + +#define lstate_c +#define LUA_CORE + +#include "lua.h" + +#include "lapi.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "llex.h" +#include "lmem.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" + + +#if !defined(LUAI_GCPAUSE) +#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 + + +#define MEMERRMSG "not enough memory" + + +/* +** a macro to help the creation of a unique random seed when a state is +** created; the seed is used to randomize hashes. +*/ +#if !defined(luai_makeseed) +#include +#define luai_makeseed() cast(size_t, time(NULL)) +#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 { + LX l; + global_State g; +} LG; + + + +#define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l))) + + +/* +** Compute an initial seed as random as possible. In ANSI, rely on +** Address Space Layout Randomization (if present) to increase +** randomness.. +*/ +#define addbuff(b,p,e) \ + { size_t t = cast(size_t, e); \ + memcpy(buff + p, &t, sizeof(t)); p += sizeof(t); } + +static unsigned int makeseed (lua_State *L) { + char buff[4 * sizeof(size_t)]; + unsigned int h = luai_makeseed(); + int p = 0; + addbuff(buff, p, L); /* heap variable */ + addbuff(buff, p, &h); /* local variable */ + addbuff(buff, p, luaO_nilobject); /* global variable */ + addbuff(buff, p, &lua_newstate); /* public function */ + lua_assert(p == sizeof(buff)); + return luaS_hash(buff, p, h); +} + + +/* +** set GCdebt to a new value keeping the value (totalbytes + GCdebt) +** invariant +*/ +void luaE_setdebt (global_State *g, l_mem debt) { + g->totalbytes -= (debt - g->GCdebt); + g->GCdebt = debt; +} + + +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) { + int i; CallInfo *ci; + /* initialize stack array */ + 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; + /* initialize first ci */ + ci = &L1->base_ci; + ci->next = ci->previous = NULL; + ci->callstatus = 0; + ci->func = L1->top; + setnilvalue(L1->top++); /* 'function' entry for this 'ci' */ + ci->top = L1->top + LUA_MINSTACK; + L1->ci = ci; +} + + +static void freestack (lua_State *L) { + 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); /* free stack array */ +} + + +/* +** Create registry table and its predefined values +*/ +static void init_registry (lua_State *L, global_State *g) { + 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); + luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &mt); + /* registry[LUA_RIDX_GLOBALS] = table of globals */ + sethvalue(L, &mt, luaH_new(L)); + luaH_setint(L, registry, LUA_RIDX_GLOBALS, &mt); +} + + +/* +** 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 */ + init_registry(L, g); + luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ + luaT_init(L); + luaX_init(L); + /* pre-create memory-error message */ + g->memerrmsg = luaS_newliteral(L, MEMERRMSG); + luaS_fix(g->memerrmsg); /* it should never be collected */ + g->gcrunning = 1; /* allow gc */ +} + + +/* +** 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; + L->ci = NULL; + L->stacksize = 0; + L->errorJmp = NULL; + L->nCcalls = 0; + L->hook = NULL; + L->hookmask = 0; + L->basehookcount = 0; + L->allowhook = 1; + resethookcount(L); + L->openupval = NULL; + L->nny = 1; + L->status = LUA_OK; + L->errfunc = 0; +} + + +static void close_state (lua_State *L) { + global_State *g = G(L); + luaF_close(L, L->stack); /* close all upvalues for this thread */ + luaC_freeallobjects(L); /* collect all objects */ + luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); + luaZ_freebuffer(L, &g->buff); + freestack(L); + lua_assert(gettotalbytes(g) == sizeof(LG)); + (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ +} + + +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)); + L1->hookmask = L->hookmask; + L1->basehookcount = L->basehookcount; + L1->hook = L->hook; + resethookcount(L1); + luai_userstatethread(L, L1); + stack_init(L1, L); /* init stack */ + lua_unlock(L); + 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(L, L1); + freestack(L1); + luaM_free(L, l); +} + + +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, LUA_TTHREAD, sizeof(LG))); + if (l == NULL) return NULL; + 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; + preinit_state(L, g); + g->frealloc = f; + g->ud = ud; + g->mainthread = L; + g->seed = makeseed(L); + g->uvhead.u.l.prev = &g->uvhead; + g->uvhead.u.l.next = &g->uvhead; + g->gcrunning = 0; /* no GC while building state */ + g->GCestimate = 0; + g->strt.size = 0; + g->strt.nuse = 0; + g->strt.hash = NULL; + setnilvalue(&g->l_registry); + luaZ_initbuffer(L, &g->buff); + g->panic = NULL; + g->version = lua_version(NULL); + g->gcstate = GCSpause; + 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); + g->GCdebt = 0; + 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) { + /* memory allocation error: free partial state */ + close_state(L); + L = NULL; + } + else + luai_userstateopen(L); + return L; +} + + +LUA_API void lua_close (lua_State *L) { + L = G(L)->mainthread; /* only the main thread can be closed */ + lua_lock(L); + luai_userstateclose(L); + close_state(L); +} + + diff --git a/src/lstate.h b/src/lstate.h new file mode 100644 index 0000000000..29f810ba04 --- /dev/null +++ b/src/lstate.h @@ -0,0 +1,228 @@ +/* +** $Id: lstate.h,v 2.81 2012/06/08 15:14:04 roberto Exp $ +** Global State +** See Copyright Notice in lua.h +*/ + +#ifndef lstate_h +#define lstate_h + +#include "lua.h" + +#include "lobject.h" +#include "ltm.h" +#include "lzio.h" + + +/* + +** 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->allgc. 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.) +** +** Objects with finalizers are kept in the list g->finobj. +** +** The list g->tobefnz links all objects being finalized. + +*/ + + +struct lua_longjmp; /* defined in ldo.c */ + + + +/* extra stack space to handle TM calls and some other extras */ +#define EXTRA_STACK 5 + + +#define BASIC_STACK_SIZE (2*LUA_MINSTACK) + + +/* kinds of Garbage Collection */ +#define KGC_NORMAL 0 +#define KGC_EMERGENCY 1 /* gc was forced by an allocation failure */ +#define KGC_GEN 2 /* generational collection */ + + +typedef struct stringtable { + GCObject **hash; + lu_int32 nuse; /* number of elements */ + int size; +} stringtable; + + +/* +** 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 this function */ + lu_byte callstatus; + ptrdiff_t extra; + 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; + 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 CIST_HOOKYIELD (1<<7) /* last hook called yielded */ + + +#define isLua(ci) ((ci)->callstatus & CIST_LUA) + + +/* +** `global state', shared by all threads of this state +*/ +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 - GCdebt */ + l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ + 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 */ + 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 *finobj; /* list of collectable objects with finalizers */ + 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 */ + 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 */ + 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; + const lua_Number *version; /* pointer to version number */ + 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; + + +/* +** `per thread' state +*/ +struct lua_State { + CommonHeader; + lu_byte status; + StkId top; /* first free slot in the stack */ + global_State *l_G; + CallInfo *ci; /* call info for current function */ + const Instruction *oldpc; /* last pc traced */ + StkId stack_last; /* last free slot in the stack */ + 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; + int hookcount; + lua_Hook hook; + 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) */ +}; + + +#define G(L) (L->l_G) + + +/* +** Union of all collectable objects +*/ +union GCObject { + GCheader gch; /* common header */ + union TString ts; + union Udata u; + union Closure cl; + struct Table h; + struct Proto p; + struct UpVal uv; + struct lua_State th; /* thread */ +}; + + +#define gch(o) (&(o)->gch) + +/* macros to convert a GCObject into a specific value */ +#define rawgco2ts(o) \ + check_exp(novariant((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 gco2lcl(o) check_exp((o)->gch.tt == LUA_TLCL, &((o)->cl.l)) +#define gco2ccl(o) check_exp((o)->gch.tt == LUA_TCCL, &((o)->cl.c)) +#define gco2cl(o) \ + check_exp(novariant((o)->gch.tt) == LUA_TFUNCTION, &((o)->cl)) +#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 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))) + + +/* 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); + + +#endif + diff --git a/src/lstring.c b/src/lstring.c new file mode 100644 index 0000000000..8b959f19d0 --- /dev/null +++ b/src/lstring.c @@ -0,0 +1,185 @@ +/* +** $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 +*/ + + +#include + +#define lstring_c +#define LUA_CORE + +#include "lua.h" + +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#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 (a == b) || /* same instance or... */ + ((len == b->tsv.len) && /* equal length and ... */ + (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ +} + + +/* +** equality for strings +*/ +int luaS_eqstr (TString *a, TString *b) { + return (a->tsv.tt == b->tsv.tt) && + (a->tsv.tt == LUA_TSHRSTR ? eqshrstr(a, b) : luaS_eqlngstr(a, b)); +} + + +unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) { + unsigned int h = seed ^ l; + size_t 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; +} + + +/* +** resizes the string table +*/ +void luaS_resize (lua_State *L, int newsize) { + int i; + stringtable *tb = &G(L)->strt; + /* 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 = 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; + resetoldbit(p); /* see MOVE OLD rule */ + p = next; + } + } + 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; +} + + +/* +** creates a new string object +*/ +static TString *createstrobj (lua_State *L, const char *str, size_t l, + int tag, unsigned int h, GCObject **list) { + TString *ts; + size_t totalsize; /* total size of TString object */ + totalsize = sizeof(TString) + ((l + 1) * sizeof(char)); + ts = &luaC_newobj(L, tag, totalsize, list, 0)->ts; + ts->tsv.len = l; + ts->tsv.hash = h; + ts->tsv.extra = 0; + memcpy(ts+1, str, l*sizeof(char)); + ((char *)(ts+1))[l] = '\0'; /* ending 0 */ + return ts; +} + + +/* +** creates a new short string, inserting it into string table +*/ +static TString *newshrstr (lua_State *L, const char *str, size_t l, + unsigned int h) { + GCObject **list; /* (pointer to) list where it will be inserted */ + stringtable *tb = &G(L)->strt; + TString *s; + if (tb->nuse >= cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) + luaS_resize(L, tb->size*2); /* too crowded */ + list = &tb->hash[lmod(h, tb->size)]; + s = createstrobj(L, str, l, LUA_TSHRSTR, h, list); + tb->nuse++; + return s; +} + + +/* +** checks whether short string exists and reuses it or creates a new one +*/ +static TString *internshrstr (lua_State *L, const char *str, size_t l) { + GCObject *o; + global_State *g = G(L); + unsigned int h = luaS_hash(str, l, g->seed); + for (o = g->strt.hash[lmod(h, g->strt.size)]; + o != NULL; + o = gch(o)->next) { + TString *ts = rawgco2ts(o); + 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; + } + } + return newshrstr(L, str, l, h); /* not found; create a new string */ +} + + +/* +** new string (with explicit length) +*/ +TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { + if (l <= LUAI_MAXSHORTLEN) /* short string? */ + return internshrstr(L, str, l); + else { + if (l + 1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) + luaM_toobig(L); + return createstrobj(L, str, l, LUA_TLNGSTR, G(L)->seed, NULL); + } +} + + +/* +** new zero-terminated string +*/ +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)) + luaM_toobig(L); + u = &luaC_newobj(L, LUA_TUSERDATA, sizeof(Udata) + s, NULL, 0)->u; + u->uv.len = s; + u->uv.metatable = NULL; + u->uv.env = e; + return u; +} + diff --git a/src/lstring.h b/src/lstring.h new file mode 100644 index 0000000000..d312ff3d2b --- /dev/null +++ b/src/lstring.h @@ -0,0 +1,46 @@ +/* +** $Id: lstring.h,v 1.49 2012/02/01 21:57:15 roberto Exp $ +** String table (keep all strings handled by Lua) +** See Copyright Notice in lua.h +*/ + +#ifndef lstring_h +#define lstring_h + +#include "lgc.h" +#include "lobject.h" +#include "lstate.h" + + +#define sizestring(s) (sizeof(union TString)+((s)->len+1)*sizeof(char)) + +#define sizeudata(u) (sizeof(union Udata)+(u)->len) + +#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ + (sizeof(s)/sizeof(char))-1)) + +#define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT) + + +/* +** test whether a string is a reserved word +*/ +#define isreserved(s) ((s)->tsv.tt == LUA_TSHRSTR && (s)->tsv.extra > 0) + + +/* +** equality for short strings, which are always internalized +*/ +#define eqshrstr(a,b) check_exp((a)->tsv.tt == LUA_TSHRSTR, (a) == (b)) + + +LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed); +LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); +LUAI_FUNC int luaS_eqstr (TString *a, TString *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 new file mode 100644 index 0000000000..e13098bb6e --- /dev/null +++ b/src/lstrlib.c @@ -0,0 +1,972 @@ +/* +** $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 +*/ + + +#include +#include +#include +#include +#include + +#define lstrlib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#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)) + + + +static int str_len (lua_State *L) { + size_t l; + luaL_checklstring(L, 1, &l); + lua_pushinteger(L, (lua_Integer)l); + return 1; +} + + +/* 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 (0u - (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); + 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 > l) end = l; + if (start <= end) + lua_pushlstring(L, s + start - 1, end - start + 1); + else lua_pushliteral(L, ""); + return 1; +} + + +static int str_reverse (lua_State *L) { + size_t l, i; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + 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; +} + + +static int str_lower (lua_State *L) { + size_t l; + size_t i; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + char *p = luaL_buffinitsize(L, &b, l); + for (i=0; i> 1) + +static int str_rep (lua_State *L) { + size_t l, lsep; + const char *s = luaL_checklstring(L, 1, &l); + int n = luaL_checkint(L, 2); + 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; + 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); + } + return 1; +} + + +static int str_byte (lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &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 < 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) /* (size_t -> int) overflow? */ + return luaL_error(L, "string slice too long"); + luaL_checkstack(L, n, "string slice too long"); + for (i=0; i= ms->level || ms->capture[l].len == CAP_UNFINISHED) + return luaL_error(ms->L, "invalid capture index %%%d", l + 1); + return l; +} + + +static int capture_to_close (MatchState *ms) { + int level = ms->level; + for (level--; level>=0; level--) + if (ms->capture[level].len == CAP_UNFINISHED) return level; + return luaL_error(ms->L, "invalid pattern capture"); +} + + +static const char *classend (MatchState *ms, const char *p) { + switch (*p++) { + case L_ESC: { + if (p == ms->p_end) + luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")"); + return p+1; + } + case '[': { + if (*p == '^') p++; + do { /* look for a `]' */ + if (p == ms->p_end) + luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")"); + if (*(p++) == L_ESC && p < ms->p_end) + p++; /* skip escapes (e.g. `%]') */ + } while (*p != ']'); + return p+1; + } + default: { + return p; + } + } +} + + +static int match_class (int c, int cl) { + int res; + switch (tolower(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; + case 'u' : res = isupper(c); break; + case 'w' : res = isalnum(c); break; + case 'x' : res = isxdigit(c); break; + case 'z' : res = (c == 0); break; /* deprecated option */ + default: return (cl == c); + } + return (islower(cl) ? res : !res); +} + + +static int matchbracketclass (int c, const char *p, const char *ec) { + int sig = 1; + if (*(p+1) == '^') { + sig = 0; + p++; /* skip the `^' */ + } + while (++p < ec) { + if (*p == L_ESC) { + p++; + if (match_class(c, uchar(*p))) + return sig; + } + else if ((*(p+1) == '-') && (p+2 < ec)) { + p+=2; + if (uchar(*(p-2)) <= c && c <= uchar(*p)) + return sig; + } + else if (uchar(*p) == c) return sig; + } + return !sig; +} + + +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 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) + luaL_error(ms->L, "malformed pattern " + "(missing arguments to " LUA_QL("%%b") ")"); + if (*s != *p) return NULL; + else { + int b = *p; + int e = *(p+1); + int cont = 1; + while (++s < ms->src_end) { + if (*s == e) { + if (--cont == 0) return s+1; + } + else if (*s == b) cont++; + } + } + return NULL; /* string ends out of balance */ +} + + +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)) + i++; + /* keeps trying to match with the maximum repetitions */ + while (i>=0) { + const char *res = match(ms, (s+i), ep+1); + if (res) return res; + i--; /* else didn't match; reduce 1 repetition to try again */ + } + return NULL; +} + + +static const char *min_expand (MatchState *ms, const char *s, + const char *p, const char *ep) { + for (;;) { + const char *res = match(ms, s, ep+1); + if (res != NULL) + return res; + else if (ssrc_end && singlematch(uchar(*s), p, ep)) + s++; /* try with one more repetition */ + else return NULL; + } +} + + +static const char *start_capture (MatchState *ms, const char *s, + const char *p, int what) { + const char *res; + int level = ms->level; + 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; + if ((res=match(ms, s, p)) == NULL) /* match failed? */ + ms->level--; /* undo capture */ + return res; +} + + +static const char *end_capture (MatchState *ms, const char *s, + const char *p) { + int l = capture_to_close(ms); + const char *res; + 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 (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 (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? */ + 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; + } + } + 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 '-': { /* 0 or more repetitions (minimum) */ + return min_expand(ms, s, p, ep); + } + default: { + if (!m) return NULL; + s++; p=ep; goto init; /* else return match(ms, s+1, ep); */ + } + } + } + } +} + + + +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 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; + 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 */ +} + + +/* check whether pattern has no special characters */ +static int nospecials (const char *p, size_t l) { + size_t upto = 0; + do { + if (strpbrk(p + upto, SPECIALS)) + return 0; /* pattern has a special character */ + upto += strlen(p + upto) + 1; /* may have more after \0 */ + } while (upto <= l); + return 1; /* no special chars found */ +} + + +static int str_find_aux (lua_State *L, int find) { + 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 > ls + 1) { /* start after string's end? */ + lua_pushnil(L); /* cannot find anything */ + return 1; + } + /* explicit request or no special characters? */ + if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { + /* do a plain search */ + 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 + lp); + return 2; + } + } + else { + MatchState ms; + 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 + ls; + ms.p_end = p + lp; + 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 */ + return push_captures(&ms, NULL, 0) + 2; + } + else + return push_captures(&ms, s1, res); + } + } while (s1++ < ms.src_end && !anchor); + } + lua_pushnil(L); /* not found */ + return 1; +} + + +static int str_find (lua_State *L) { + return str_find_aux(L, 1); +} + + +static int str_match (lua_State *L) { + return str_find_aux(L, 0); +} + + +static int gmatch_aux (lua_State *L) { + MatchState ms; + size_t ls, lp; + const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); + 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++) { + const char *e; + ms.level = 0; + if ((e = match(&ms, src, p)) != NULL) { + lua_Integer newstart = e-s; + if (e == src) newstart++; /* empty match? go at least one position */ + lua_pushinteger(L, newstart); + lua_replace(L, lua_upvalueindex(3)); + return push_captures(&ms, src, e); + } + } + return 0; /* not found */ +} + + +static int gmatch (lua_State *L) { + luaL_checkstring(L, 1); + luaL_checkstring(L, 2); + lua_settop(L, 2); + lua_pushinteger(L, 0); + lua_pushcclosure(L, gmatch_aux, 3); + return 1; +} + + +static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, + const char *e) { + size_t l, i; + const char *news = lua_tolstring(ms->L, 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]))) { + 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 { + push_onecapture(ms, news[i] - '1', s, e); + luaL_addvalue(b); /* add capture to accumulated result */ + } + } + } +} + + +static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, + const char *e, int tr) { + lua_State *L = ms->L; + switch (tr) { + 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: { /* 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_addvalue(b); /* add result to accumulator */ +} + + +static int str_gsub (lua_State *L) { + size_t srcl, lp; + const char *src = luaL_checklstring(L, 1, &srcl); + 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 == '^'); + size_t 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); + 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; + e = match(&ms, src, p); + if (e) { + n++; + add_value(&ms, &b, src, e, tr); + } + if (e && e>src) /* non empty match? */ + src = e; /* skip it */ + else if (src < ms.src_end) + luaL_addchar(&b, *src++); + else break; + if (anchor) break; + } + luaL_addlstring(&b, src, ms.src_end-src); + luaL_pushresult(&b); + lua_pushinteger(L, n); /* number of substitutions */ + return 2; +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** 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_INTFRMLEN) /* { */ +#if defined(LUA_USE_LONGLONG) + +#define LUA_INTFRMLEN "ll" +#define LUA_INTFRM_T long long + +#else + +#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 + + +/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ +#define MAX_ITEM 512 +/* 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) { + size_t l; + const char *s = luaL_checklstring(L, arg, &l); + luaL_addchar(b, '"'); + while (l--) { + if (*s == '"' || *s == '\\' || *s == '\n') { + luaL_addchar(b, '\\'); + luaL_addchar(b, *s); + } + else if (*s == '\0' || iscntrl(uchar(*s))) { + char buff[10]; + if (!isdigit(uchar(*(s+1)))) + sprintf(buff, "\\%d", (int)uchar(*s)); + else + sprintf(buff, "\\%03d", (int)uchar(*s)); + luaL_addstring(b, buff); + } + else + luaL_addchar(b, *s); + s++; + } + luaL_addchar(b, '"'); +} + +static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { + const char *p = strfrmt; + while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip 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) */ + if (*p == '.') { + p++; + 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)"); + *(form++) = '%'; + memcpy(form, strfrmt, (p - strfrmt + 1) * sizeof(char)); + form += p - strfrmt + 1; + *form = '\0'; + return p; +} + + +/* +** add length modifier into formats +*/ +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, lenmod); + form[l + lm - 1] = spec; + form[l + lm] = '\0'; +} + + +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); + const char *strfrmt_end = strfrmt+sfl; + luaL_Buffer b; + luaL_buffinit(L, &b); + while (strfrmt < strfrmt_end) { + if (*strfrmt != L_ESC) + luaL_addchar(&b, *strfrmt++); + else if (*++strfrmt == L_ESC) + luaL_addchar(&b, *strfrmt++); /* %% */ + else { /* format item */ + char form[MAX_FORMAT]; /* to store the format (`%...') */ + 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': { + nb = sprintf(buff, form, luaL_checkint(L, arg)); + break; + } + 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; + luaL_argcheck(L, -1 < diff && diff < 1, arg, + "not a number in proper range"); + addlenmod(form, LUA_INTFRMLEN); + nb = sprintf(buff, form, ni); + break; + } + 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; + luaL_argcheck(L, -1 < diff && diff < 1, arg, + "not a non-negative number in proper range"); + addlenmod(form, LUA_INTFRMLEN); + nb = sprintf(buff, form, ni); + 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)); + break; + } + case 'q': { + addquoted(L, &b, arg); + break; + } + case 's': { + size_t 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 */ + luaL_addvalue(&b); + break; + } + else { + nb = sprintf(buff, form, s); + lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ + break; + } + } + default: { /* also treat cases `pnLlh' */ + return luaL_error(L, "invalid option " LUA_QL("%%%c") " to " + LUA_QL("format"), *(strfrmt - 1)); + } + } + luaL_addsize(&b, nb); + } + } + luaL_pushresult(&b); + return 1; +} + +/* }====================================================== */ + + +static const luaL_Reg strlib[] = { + {"byte", str_byte}, + {"char", str_char}, + {"dump", str_dump}, + {"find", str_find}, + {"format", str_format}, + {"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} +}; + + +static void createmetatable (lua_State *L) { + lua_createtable(L, 0, 1); /* table to be metatable for strings */ + lua_pushliteral(L, ""); /* dummy string */ + lua_pushvalue(L, -2); /* copy table */ + lua_setmetatable(L, -2); /* set table as metatable for strings */ + lua_pop(L, 1); /* pop dummy string */ + lua_pushvalue(L, -2); /* get string library */ + lua_setfield(L, -2, "__index"); /* metatable.__index = string */ + lua_pop(L, 1); /* pop metatable */ +} + + +/* +** Open string library +*/ +LUAMOD_API int luaopen_string (lua_State *L) { + luaL_newlib(L, strlib); + createmetatable(L); + return 1; +} + diff --git a/src/ltable.c b/src/ltable.c new file mode 100644 index 0000000000..ffa5ecb36a --- /dev/null +++ b/src/ltable.c @@ -0,0 +1,588 @@ +/* +** $Id: ltable.c,v 2.71 2012/05/23 15:37:09 roberto Exp $ +** Lua tables (hash) +** See Copyright Notice in lua.h +*/ + + +/* +** 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. +** Hence even when the load factor reaches 100%, performance remains good. +*/ + +#include + +#define ltable_c +#define LUA_CORE + +#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" +#include "lvm.h" + + +/* +** max size of array part is 2^MAXBITS +*/ +#if LUAI_BITSINT >= 32 +#define MAXBITS 30 +#else +#define MAXBITS (LUAI_BITSINT-2) +#endif + +#define MAXASIZE (1 << MAXBITS) + + +#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)) + + +#define dummynode (&dummynode_) + +#define isdummy(n) ((n) == dummynode) + +static const Node dummynode_ = { + {NILCONSTANT}, /* value */ + {{NILCONSTANT, NULL}} /* key */ +}; + + +/* +** hash for lua_Numbers +*/ +static Node *hashnum (const Table *t, lua_Number n) { + int i; + luai_hashnum(i, n); + if (i < 0) { + if (cast(unsigned int, i) == 0u - i) /* use unsigned to avoid overflows */ + i = 0; /* handle INT_MIN */ + i = -i; /* must be a positive value */ + } + return hashmod(t, i); +} + + + +/* +** returns the `main' position of an element in a table (that is, the index +** of its hash value) +*/ +static Node *mainposition (const Table *t, const TValue *key) { + switch (ttype(key)) { + case LUA_TNUMBER: + return hashnum(t, nvalue(key)); + case LUA_TLNGSTR: { + TString *s = rawtsvalue(key); + if (s->tsv.extra == 0) { /* no hash? */ + s->tsv.hash = luaS_hash(getstr(s), s->tsv.len, s->tsv.hash); + s->tsv.extra = 1; /* now it has its hash */ + } + return hashstr(t, rawtsvalue(key)); + } + case LUA_TSHRSTR: + return hashstr(t, rawtsvalue(key)); + case LUA_TBOOLEAN: + 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)); + } +} + + +/* +** 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) { + if (ttisnumber(key)) { + lua_Number n = nvalue(key); + int k; + lua_number2int(k, n); + if (luai_numeq(cast_num(k), n)) + return k; + } + return -1; /* `key' did not match some condition */ +} + + +/* +** 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 signaled by -1. +*/ +static int findindex (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 { + Node *n = mainposition(t, key); + for (;;) { /* check whether `key' is somewhere in the chain */ + /* key may be dead already, but it is ok to use it in `next' */ + if (luaV_rawequalobj(gkey(n), key) || + (ttisdeadkey(gkey(n)) && iscollectable(key) && + deadvalue(gkey(n)) == gcvalue(key))) { + i = cast_int(n - gnode(t, 0)); /* key index in hash table */ + /* hash elements are numbered after array ones */ + return i + t->sizearray; + } + else n = gnext(n); + if (n == NULL) + luaG_runerror(L, "invalid key to " LUA_QL("next")); /* key not found */ + } + } +} + + +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_num(i+1)); + 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(L, key, gkey(gnode(t, i))); + setobj2s(L, key+1, gval(gnode(t, i))); + return 1; + } + } + return 0; /* no more elements */ +} + + +/* +** {============================================================= +** Rehash +** ============================================================== +*/ + + +static int computesizes (int nums[], int *narray) { + int 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 > 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[luaO_ceillog2(k)]++; /* count as such */ + return 1; + } + else + return 0; +} + + +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 */ + } + /* 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; + } + 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))) { + ause += countint(gkey(n), nums); + totaluse++; + } + } + *pnasize += ause; + return totaluse; +} + + +static void setarrayvector (lua_State *L, Table *t, int size) { + int i; + luaM_reallocvector(L, t->array, t->sizearray, size, TValue); + for (i=t->sizearray; iarray[i]); + t->sizearray = 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 *, dummynode); /* use common `dummynode' */ + lsize = 0; + } + else { + int i; + lsize = luaO_ceillog2(size); + if (lsize > MAXBITS) + luaG_runerror(L, "table overflow"); + size = twoto(lsize); + t->node = luaM_newvector(L, size, Node); + for (i=0; ilsizenode = cast_byte(lsize); + t->lastfree = gnode(t, size); /* all positions are free */ +} + + +void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { + int i; + int oldasize = t->sizearray; + int oldhsize = t->lsizenode; + 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); + if (nasize < oldasize) { /* array part must shrink? */ + t->sizearray = nasize; + /* re-insert elements from vanishing slice */ + for (i=nasize; iarray[i])) + luaH_setint(L, t, i + 1, &t->array[i]); + } + /* shrink array */ + luaM_reallocvector(L, t->array, oldasize, nasize, TValue); + } + /* re-insert elements from hash part */ + for (i = twoto(oldhsize) - 1; i >= 0; i--) { + Node *old = nold+i; + 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, cast(size_t, twoto(oldhsize))); /* free old array */ +} + + +void luaH_resizearray (lua_State *L, Table *t, int nasize) { + int nsize = isdummy(t->node) ? 0 : sizenode(t); + luaH_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 with 2^(i-1) < k <= 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 */ + luaH_resize(L, t, nasize, totaluse - na); +} + + + +/* +** }============================================================= +*/ + + +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); + t->array = NULL; + t->sizearray = 0; + setnodevector(L, t, 0); + return t; +} + + +void luaH_free (lua_State *L, Table *t) { + if (!isdummy(t->node)) + luaM_freearray(L, t->node, cast(size_t, sizenode(t))); + luaM_freearray(L, t->array, t->sizearray); + luaM_free(L, t); +} + + +static Node *getfreepos (Table *t) { + while (t->lastfree > t->node) { + t->lastfree--; + 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 +** 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. +*/ +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 */ + /* 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)); + 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 */ + gnext(othern) = n; /* redo the chain with `n' in place of `mp' */ + *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ + 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 */ + gnext(n) = gnext(mp); /* chain new position */ + gnext(mp) = n; + mp = n; + } + } + setobj2t(L, gkey(mp), key); + luaC_barrierback(L, obj2gco(t), key); + lua_assert(ttisnil(gval(mp))); + return gval(mp); +} + + +/* +** search function for integers +*/ +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]; + else { + 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; + } +} + + +/* +** search function for short strings +*/ +const TValue *luaH_getstr (Table *t, TString *key) { + Node *n = hashstr(t, key); + lua_assert(key->tsv.tt == LUA_TSHRSTR); + do { /* check whether `key' is somewhere in the chain */ + if (ttisshrstring(gkey(n)) && eqshrstr(rawtsvalue(gkey(n)), key)) + return gval(n); /* that's it */ + else n = gnext(n); + } while (n); + return luaO_nilobject; +} + + +/* +** main search function +*/ +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_TNUMBER: { + int k; + lua_Number n = nvalue(key); + lua_number2int(k, n); + if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */ + return luaH_getint(t, k); /* use specialized version */ + /* else go through */ + } + default: { + Node *n = mainposition(t, key); + do { /* check whether `key' is somewhere in the chain */ + if (luaV_rawequalobj(gkey(n), key)) + return gval(n); /* that's it */ + else n = gnext(n); + } while (n); + return luaO_nilobject; + } + } +} + + +/* +** 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); + if (p != luaO_nilobject) + return cast(TValue *, p); + else return luaH_newkey(L, t, 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) + cell = cast(TValue *, p); + else { + TValue k; + setnvalue(&k, cast_num(key)); + cell = luaH_newkey(L, t, &k); + } + setobj2t(L, cell, value); +} + + +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_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_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_getint(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 (isdummy(t->node)) /* 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 isdummy(n); } + +#endif diff --git a/src/ltable.h b/src/ltable.h new file mode 100644 index 0000000000..2f6f5c2dc8 --- /dev/null +++ b/src/ltable.h @@ -0,0 +1,41 @@ +/* +** $Id: ltable.h,v 2.16 2011/08/17 20:26:47 roberto Exp $ +** Lua tables (hash) +** See Copyright Notice in lua.h +*/ + +#ifndef ltable_h +#define ltable_h + +#include "lobject.h" + + +#define gnode(t,i) (&(t)->node[i]) +#define gkey(n) (&(n)->i_key.tvk) +#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 void luaH_setint (lua_State *L, Table *t, int key, TValue *value); +LUAI_FUNC const TValue *luaH_getstr (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); +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); + + +#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/ltablib.c b/src/ltablib.c new file mode 100644 index 0000000000..a52add03da --- /dev/null +++ b/src/ltablib.c @@ -0,0 +1,283 @@ +/* +** $Id: ltablib.c,v 1.63 2011/11/28 17:26:30 roberto Exp $ +** Library for Table Manipulation +** See Copyright Notice in lua.h +*/ + + +#include + +#define ltablib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +#define aux_getn(L,n) \ + (luaL_checktype(L, n, LUA_TTABLE), luaL_len(L, n)) + + +#if defined(LUA_COMPAT_MAXN) +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; +} +#endif + + +static int tinsert (lua_State *L) { + int e = aux_getn(L, 1) + 1; /* first empty element */ + int pos; /* where to insert new element */ + 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")); + } + } + lua_rawseti(L, 1, pos); /* t[pos] = v */ + return 0; +} + + +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 */ + lua_rawgeti(L, 1, pos); /* result = t[pos] */ + for ( ;pos 0) { /* at least one element? */ + int i; + lua_pushvalue(L, 1); + lua_rawseti(L, -2, 1); /* insert first element */ + lua_replace(L, 1); /* move table into index 1 */ + for (i = n; i >= 2; i--) /* assign other elements */ + lua_rawseti(L, 1, i); + } + return 1; /* return table */ +} + + +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, 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 */ + 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.) +** ======================================================= +*/ + + +static void set2 (lua_State *L, int i, int j) { + lua_rawseti(L, 1, i); + lua_rawseti(L, 1, j); +} + +static int sort_comp (lua_State *L, int a, int b) { + if (!lua_isnil(L, 2)) { /* function? */ + int res; + lua_pushvalue(L, 2); + lua_pushvalue(L, a-1); /* -1 to compensate function */ + lua_pushvalue(L, b-2); /* -2 to compensate function and `a' */ + lua_call(L, 2, 1); + res = lua_toboolean(L, -1); + lua_pop(L, 1); + return res; + } + else /* a < b? */ + return lua_compare(L, a, b, LUA_OPLT); +} + +static void auxsort (lua_State *L, int l, int u) { + while (l < u) { /* for tail recursion */ + int i, j; + /* sort elements a[l], a[(l+u)/2] and a[u] */ + lua_rawgeti(L, 1, l); + lua_rawgeti(L, 1, u); + if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */ + set2(L, l, u); /* swap a[l] - a[u] */ + else + lua_pop(L, 2); + if (u-l == 1) break; /* only 2 elements */ + i = (l+u)/2; + lua_rawgeti(L, 1, i); + lua_rawgeti(L, 1, l); + if (sort_comp(L, -2, -1)) /* 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"); + 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<=l) luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[j] */ + } + if (j + +#define ltm_c +#define LUA_CORE + +#include "lua.h" + +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" + + +static const char udatatypename[] = "userdata"; + +LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = { + "no value", + "nil", "boolean", udatatypename, "number", + "string", "table", "function", udatatypename, "thread", + "proto", "upval" /* these last two cases are used for tests only */ +}; + + +void luaT_init (lua_State *L) { + static const char *const luaT_eventname[] = { /* ORDER TM */ + "__index", "__newindex", + "__gc", "__mode", "__len", "__eq", + "__add", "__sub", "__mul", "__div", "__mod", + "__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 */ + } +} + + +/* +** function to be used with macro "fasttm": optimized for absence of +** tag methods +*/ +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_byte(1u<metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(o)->metatable; + break; + default: + 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 new file mode 100644 index 0000000000..89bdc19a1e --- /dev/null +++ b/src/ltm.h @@ -0,0 +1,57 @@ +/* +** $Id: ltm.h,v 2.11 2011/02/28 17:32:10 roberto Exp $ +** Tag methods +** See Copyright Notice in lua.h +*/ + +#ifndef ltm_h +#define ltm_h + + +#include "lobject.h" + + +/* +* WARNING: if you change the order of this enumeration, +* grep "ORDER TM" +*/ +typedef enum { + TM_INDEX, + TM_NEWINDEX, + TM_GC, + TM_MODE, + TM_LEN, + TM_EQ, /* last tag method with `fast' access */ + TM_ADD, + TM_SUB, + TM_MUL, + TM_DIV, + TM_MOD, + TM_POW, + TM_UNM, + TM_LT, + TM_LE, + TM_CONCAT, + TM_CALL, + TM_N /* number of elements in the enum */ +} TMS; + + + +#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) + +#define ttypename(x) luaT_typenames_[(x) + 1] +#define objtypename(x) ttypename(ttypenv(x)) + +LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS]; + + +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 new file mode 100644 index 0000000000..7614c7030b --- /dev/null +++ b/src/lua.c @@ -0,0 +1,496 @@ +/* +** $Id: lua.c,v 1.205 2012/05/23 15:37:09 roberto Exp $ +** Lua stand-alone interpreter +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include + +#define lua_c + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +#if !defined(LUA_PROMPT) +#define LUA_PROMPT "> " +#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) +#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 +** 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; + +static const char *progname = LUA_PROGNAME; + + + +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) { + signal(i, SIG_DFL); /* if another SIGINT happens before lstop, + terminate process (default action) */ + lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); +} + + +static void print_usage (const char *badoption) { + luai_writestringerror("%s: ", progname); + if (badoption[1] == 'e' || badoption[1] == 'l') + luai_writestringerror("'%s' needs argument\n", badoption); + else + 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" + " -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" + , + progname); +} + + +static void l_message (const char *pname, const char *msg) { + if (pname) luai_writestringerror("%s: ", pname); + luai_writestringerror("%s\n", msg); +} + + +static int report (lua_State *L, int status) { + 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; +} + + +/* 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); + } +} + + +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)"); + } + return 1; +} + + +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, nres, base); + signal(SIGINT, SIG_DFL); + lua_remove(L, base); /* remove traceback function */ + return status; +} + + +static void print_version (void) { + luai_writestring(LUA_COPYRIGHT, strlen(LUA_COPYRIGHT)); + luai_writeline(); +} + + +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]); + lua_createtable(L, narg, n + 1); + for (i=0; i < argc; i++) { + lua_pushstring(L, argv[i]); + lua_rawseti(L, -2, i - n); + } + return narg; +} + + +static int dofile (lua_State *L, const char *name) { + int status = luaL_loadfile(L, name); + 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, 0); + return report(L, status); +} + + +static int dolibrary (lua_State *L, const char *name) { + int status; + lua_getglobal(L, "require"); + lua_pushstring(L, name); + status = docall(L, 1, 1); /* call 'require(name)' */ + if (status == LUA_OK) + lua_setglobal(L, name); /* global[name] = require return */ + return report(L, status); +} + + +static const char *get_prompt (lua_State *L, int firstline) { + const char *p; + 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 */ + return p; +} + +/* mark in error messages for incomplete statements */ +#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, EOFMARK) == 0) { + lua_pop(L, 1); + return 1; + } + } + return 0; /* else... */ +} + + +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 (!pushline(L, 1)) + return -1; /* no input */ + for (;;) { /* repeat until gets a complete line */ + 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; + 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, 1); + lua_remove(L, 1); /* remove line */ + return status; +} + + +static void dotty (lua_State *L) { + int status; + const char *oldprogname = progname; + progname = NULL; + while ((status = loadline(L)) != -1) { + 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"); + 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, + "error calling " LUA_QL("print") " (%s)", + lua_tostring(L, -1))); + } + } + lua_settop(L, 0); /* clear stack */ + luai_writeline(); + progname = oldprogname; +} + + +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 == LUA_OK) + status = docall(L, narg, LUA_MULTRET); + else + lua_pop(L, narg); + return report(L, status); +} + + +/* check that argument has no extra characters at the end */ +#define noextrachars(x) {if ((x)[2] != '\0') return -1;} + + +/* 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? */ + return i; + switch (argv[i][1]) { /* option */ + case '-': + noextrachars(argv[i]); + return (argv[i+1] != NULL ? i+1 : 0); + case '\0': + return i; + case 'E': + args[has_E] = 1; + break; + case 'i': + noextrachars(argv[i]); + args[has_i] = 1; /* go through */ + case 'v': + noextrachars(argv[i]); + args[has_v] = 1; + break; + case 'e': + 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' */ + 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... */ + return -i; /* ...as a negative value */ + } + } + return 0; +} + + +static int runargs (lua_State *L, char **argv, int n) { + int i; + for (i = 1; i < n; i++) { + 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)") != 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) != LUA_OK) + return 0; /* stop if file fails */ + break; + } + default: break; + } + } + return 1; +} + + +static int handle_luainit (lua_State *L) { + 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, name); +} + + +static int pmain (lua_State *L) { + int argc = (int)lua_tointeger(L, 1); + char **argv = (char **)lua_touserdata(L, 2); + int script; + 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, args); + if (script < 0) { /* invalid arg? */ + print_usage(argv[-script]); + return 0; + } + if (args[has_v]) print_version(); + if (args[has_E]) { /* option '-E'? */ + lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */ + lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); + } + /* 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); + if (!args[has_E] && handle_luainit(L) != LUA_OK) + return 0; /* error running LUA_INIT */ + /* 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 (args[has_i]) /* -i option? */ + dotty(L); + else if (script == 0 && !args[has_e] && !args[has_v]) { /* no arguments? */ + if (lua_stdin_is_tty()) { + print_version(); + dotty(L); + } + else dofile(L, NULL); /* executes stdin as a file */ + } + lua_pushboolean(L, 1); /* signal no errors */ + return 1; +} + + +int main (int argc, char **argv) { + 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; + } + /* call 'pmain' in protected mode */ + 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); + return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE; +} + diff --git a/src/lua.h b/src/lua.h new file mode 100644 index 0000000000..a3a3a70c69 --- /dev/null +++ b/src/lua.h @@ -0,0 +1,439 @@ +/* +** $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 +*/ + + +#ifndef lua_h +#define lua_h + +#include +#include + + +#include "luaconf.h" + + +#define LUA_VERSION_MAJOR "5" +#define LUA_VERSION_MINOR "2" +#define LUA_VERSION_NUM 502 +#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-2012 Lua.org, 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) + + +/* +** pseudo-indices +*/ +#define LUA_REGISTRYINDEX LUAI_FIRSTPSEUDOIDX +#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i)) + + +/* thread status */ +#define LUA_OK 0 +#define LUA_YIELD 1 +#define LUA_ERRRUN 2 +#define LUA_ERRSYNTAX 3 +#define LUA_ERRMEM 4 +#define LUA_ERRGCMM 5 +#define LUA_ERRERR 6 + + +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_Reader) (lua_State *L, void *ud, size_t *sz); + +typedef int (*lua_Writer) (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 +*/ +#define LUA_TNONE (-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_NUMTAGS 9 + + + +/* minimum Lua stack available to a C function */ +#define LUA_MINSTACK 20 + + +/* predefined values in the registry */ +#define LUA_RIDX_MAINTHREAD 1 +#define LUA_RIDX_GLOBALS 2 +#define LUA_RIDX_LAST LUA_RIDX_GLOBALS + + +/* type of numbers in Lua */ +typedef LUA_NUMBER lua_Number; + + +/* type for integer functions */ +typedef LUA_INTEGER lua_Integer; + +/* unsigned integer type */ +typedef LUA_UNSIGNED lua_Unsigned; + + + +/* +** generic extra include file +*/ +#if defined(LUA_USER_H) +#include LUA_USER_H +#endif + + + +/* +** 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_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); + + +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); +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); + + +/* +** 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 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); +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_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, + 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_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); +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); + + +/* +** 'load' and 'call' functions (load and run Lua code) +*/ +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, + const char *mode); + +LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data); + + +/* +** coroutine functions +*/ +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, lua_State *from, int narg); +LUA_API int (lua_status) (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_GCCOUNTB 4 +#define LUA_GCSTEP 5 +#define LUA_GCSETPAUSE 6 +#define LUA_GCSETSTEPMUL 7 +#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); + + +/* +** miscellaneous functions +*/ + +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); + + + +/* +** =============================================================== +** some useful macros +** =============================================================== +*/ + +#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) + +#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) + +#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_pushglobaltable(L) \ + lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS) + +#define lua_tostring(L,i) lua_tolstring(L, (i), NULL) + + + +/* +** {====================================================================== +** Debug API +** ======================================================================= +*/ + + +/* +** Event codes +*/ +#define LUA_HOOKCALL 0 +#define LUA_HOOKRET 1 +#define LUA_HOOKLINE 2 +#define LUA_HOOKCOUNT 3 +#define LUA_HOOKTAILCALL 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 */ + + +/* 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 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); + + +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 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 */ + struct CallInfo *i_ci; /* active function */ +}; + +/* }====================================================================== */ + + +/****************************************************************************** +* 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 +* "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. +******************************************************************************/ + + +#endif diff --git a/src/lua.hpp b/src/lua.hpp new file mode 100644 index 0000000000..ec417f5946 --- /dev/null +++ b/src/lua.hpp @@ -0,0 +1,9 @@ +// lua.hpp +// Lua header files for C++ +// <> not supplied automatically because Lua also compiles as C++ + +extern "C" { +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" +} diff --git a/src/luac.c b/src/luac.c new file mode 100644 index 0000000000..5081836d4c --- /dev/null +++ b/src/luac.c @@ -0,0 +1,432 @@ +/* +** $Id: luac.c,v 1.69 2011/11/29 17:46:33 lhf Exp $ +** Lua compiler (saves bytecodes to files; also list bytecodes) +** See Copyright Notice in lua.h +*/ + +#include +#include +#include +#include + +#define luac_c +#define LUA_CORE + +#include "lua.h" +#include "lauxlib.h" + +#include "lobject.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 */ + +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; /* actual output file name */ +static const char* progname=PROGNAME; /* actual program name */ + +static void fatal(const char* message) +{ + fprintf(stderr,"%s: %s\n",progname,message); + exit(EXIT_FAILURE); +} + +static void cannot(const char* what) +{ + fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno)); + exit(EXIT_FAILURE); +} + +static void usage(const char* message) +{ + if (*message=='-') + fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message); + else + fprintf(stderr,"%s: %s\n",progname,message); + fprintf(stderr, + "usage: %s [options] [filenames]\n" + "Available options are:\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" + " -v show version information\n" + " -- stop handling options\n" + " - stop handling options and process stdin\n" + ,progname,Output); + exit(EXIT_FAILURE); +} + +#define IS(s) (strcmp(argv[i],s)==0) + +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)) + +static const Proto* combine(lua_State* L, int n) +{ + if (n==1) + return toproto(L,-1); + else + { + Proto* f; + int i=n; + if (lua_load(L,reader,&i,"=(" PROGNAME ")",NULL)!=LUA_OK) fatal(lua_tostring(L,-1)); + f=toproto(L,-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; + return f; + } +} + +static int writer(lua_State* L, const void* p, size_t size, void* u) +{ + UNUSED(L); + return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0); +} + +static int pmain(lua_State* L) +{ + int argc=(int)lua_tointeger(L,1); + char** argv=(char**)lua_touserdata(L,2); + const Proto* f; + int i; + if (!lua_checkstack(L,argc)) fatal("too many input files"); + for (i=0; i1); + if (dumping) + { + FILE* D= (output==NULL) ? stdout : fopen(output,"wb"); + if (D==NULL) cannot("open"); + lua_lock(L); + luaU_dump(L,f,writer,D,stripping); + lua_unlock(L); + if (ferror(D)) cannot("write"); + if (fclose(D)) cannot("close"); + } + return 0; +} + +int main(int argc, char* argv[]) +{ + lua_State* L; + int i=doargs(argc,argv); + argc-=i; argv+=i; + if (argc<=0) usage("no input files given"); + L=luaL_newstate(); + if (L==NULL) fatal("cannot create state: not enough memory"); + lua_pushcfunction(L,&pmain); + lua_pushinteger(L,argc); + lua_pushlightuserdata(L,argv); + 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.68 2011/09/30 10:21:20 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 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) : "-") +#define MYK(x) (-1-(x)) + +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) ? (MYK(INDEXK(b))) : b); + if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (MYK(INDEXK(c))) : c); + break; + case iABx: + printf("%d",a); + if (getBMode(o)==OpArgK) printf(" %d",MYK(bx)); + if (getBMode(o)==OpArgU) printf(" %d",bx); + break; + case iAsBx: + printf("%d %d",a,sbx); + break; + case iAx: + printf("%d",MYK(ax)); + break; + } + switch (o) + { + case OP_LOADK: + printf("\t; "); PrintConstant(f,bx); + 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 new file mode 100644 index 0000000000..e4335df904 --- /dev/null +++ b/src/luaconf.h @@ -0,0 +1,546 @@ +/* +** $Id: luaconf.h,v 1.172 2012/05/11 14:14:42 roberto Exp $ +** Configuration file for Lua +** See Copyright Notice in lua.h +*/ + + +#ifndef lconfig_h +#define lconfig_h + +#include +#include + + +/* +** ================================================================== +** Search for "@@" to find all configurable definitions. +** =================================================================== +*/ + + +/* +@@ 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(LUA_ANSI) && defined(__STRICT_ANSI__) +#define LUA_ANSI +#endif + + +#if !defined(LUA_ANSI) && defined(_WIN32) && !defined(_WIN32_WCE) +#define LUA_WIN /* enable goodies for regular Windows platforms */ +#endif + +#if defined(LUA_WIN) +#define LUA_DL_DLL +#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ +#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 */ +#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 + + + +/* +@@ LUA_USE_POSIX includes all functionality 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 +#define LUA_USE_GMTIME_R +#endif + + + +/* +@@ 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. +*/ +#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. +*/ +#define LUA_LDIR "!\\lua\\" +#define LUA_CDIR "!\\" +#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"?.dll;" LUA_CDIR"loadall.dll;" ".\\?.dll" + +#else /* }{ */ + +#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR "/" +#define LUA_ROOT "/usr/local/" +#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 /* } */ + + +/* +@@ 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 + + +/* +@@ 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. +@@ 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 +** 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 + +#endif /* } */ + + +/* 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_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. 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(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ + defined(__ELF__) /* { */ +#define LUAI_FUNC __attribute__((visibility("hidden"))) extern +#define LUAI_DDEC LUAI_FUNC +#define LUAI_DDEF /* empty */ + +#else /* }{ */ +#define LUAI_FUNC extern +#define LUAI_DDEC extern +#define LUAI_DDEF /* empty */ +#endif /* } */ + + + +/* +@@ 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 want a different size. +*/ +#define LUA_IDSIZE 60 + + +/* +@@ 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) +#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. +** (A format string with one argument is enough for Lua...) +*/ +#define luai_writestringerror(s,p) \ + (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 + + + +/* +** {================================================================== +** Compatibility with previous versions +** =================================================================== +*/ + +/* +@@ LUA_COMPAT_ALL controls all compatibility options. +** You can define it to get all options, or change specific options +** to fit your specific needs. +*/ +#if defined(LUA_COMPAT_ALL) /* { */ + +/* +@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'. +** You can replace it with 'table.unpack'. +*/ +#define LUA_COMPAT_UNPACK + +/* +@@ LUA_COMPAT_LOADERS controls the presence of table 'package.loaders'. +** You can replace it with 'package.searchers'. +*/ +#define LUA_COMPAT_LOADERS + +/* +@@ 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)), \ + lua_pushlightuserdata(L,(u)), \ + lua_pcall(L,1,0,0)) + + +/* +@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library. +** You can rewrite 'log10(x)' as 'log(x, 10)'. +*/ +#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. +*/ +#define LUA_COMPAT_MAXN + +/* +@@ 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_strlen(L,i) lua_rawlen(L, (i)) + +#define lua_objlen(L,i) lua_rawlen(L, (i)) + +#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_MODULE controls compatibility with previous +** module functions 'module' (Lua) and 'luaL_register' (C). +*/ +#define LUA_COMPAT_MODULE + +#endif /* } */ + +/* }================================================================== */ + + + +/* +@@ 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 LUAI_BITSINT 16 +#elif INT_MAX > 2147483640L /* }{ */ +/* 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 /* } */ + + +/* +@@ 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. Probably you do not need to change +** this. +*/ +#if LUAI_BITSINT >= 32 /* { */ +#define LUA_INT32 int +#define LUAI_UMEM size_t +#define LUAI_MEM ptrdiff_t +#else /* }{ */ +/* 16-bit ints */ +#define LUA_INT32 long +#define LUAI_UMEM unsigned long +#define LUAI_MEM long +#endif /* } */ + + +/* +@@ 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). +*/ +#if LUAI_BITSINT >= 32 +#define LUAI_MAXSTACK 1000000 +#else +#define LUAI_MAXSTACK 15000 +#endif + +/* reserve some space for error handling */ +#define LUAI_FIRSTPSEUDOIDX (-LUAI_MAXSTACK - 1000) + + + + +/* +@@ 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 + + + + +/* +** {================================================================== +@@ 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_NUMBER_DOUBLE +#define LUA_NUMBER double + +/* +@@ LUAI_UACNUMBER is the result of an 'usual argument conversion' +@* over a number. +*/ +#define LUAI_UACNUMBER double + + +/* +@@ 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. +*/ +#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. +*/ + +/* 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)) +#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(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_UNSIGNED is the integral type used by lua_pushunsigned/lua_tounsigned. +** It must have at least 32 bits. +*/ +#define LUA_UNSIGNED unsigned LUA_INT32 + + + +/* +** Some tricks with doubles +*/ + +#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 + + +/* pentium 32 bits? */ +#elif defined(__i386__) || defined(__i386) || defined(__X86__) /* }{ */ + +#define LUA_IEEE754TRICK +#define LUA_IEEELL +#define LUA_IEEEENDIAN 0 +#define LUA_NANTRICK + +/* pentium 64 bits? */ +#elif defined(__x86_64) /* }{ */ + +#define LUA_IEEE754TRICK +#define LUA_IEEEENDIAN 0 + +#elif defined(__POWERPC__) || defined(__ppc__) /* }{ */ + +#define LUA_IEEE754TRICK +#define LUA_IEEEENDIAN 1 + +#else /* }{ */ + +/* assume IEEE754 and a 32-bit integer type */ +#define LUA_IEEE754TRICK + +#endif /* } */ + +#endif /* } */ + +/* }================================================================== */ + + + + +/* =================================================================== */ + +/* +** Local configuration. You can use this space to add your redefinitions +** without modifying the main part of the file. +*/ + + + +#endif + diff --git a/src/lualib.h b/src/lualib.h new file mode 100644 index 0000000000..9fd126bf78 --- /dev/null +++ b/src/lualib.h @@ -0,0 +1,55 @@ +/* +** $Id: lualib.h,v 1.43 2011/12/08 12:11:37 roberto Exp $ +** Lua standard libraries +** See Copyright Notice in lua.h +*/ + + +#ifndef lualib_h +#define lualib_h + +#include "lua.h" + + + +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); + +#define LUA_IOLIBNAME "io" +LUAMOD_API int (luaopen_io) (lua_State *L); + +#define LUA_OSLIBNAME "os" +LUAMOD_API int (luaopen_os) (lua_State *L); + +#define LUA_STRLIBNAME "string" +LUAMOD_API int (luaopen_string) (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); + +#define LUA_DBLIBNAME "debug" +LUAMOD_API int (luaopen_debug) (lua_State *L); + +#define LUA_LOADLIBNAME "package" +LUAMOD_API int (luaopen_package) (lua_State *L); + + +/* open all previous libraries */ +LUALIB_API void (luaL_openlibs) (lua_State *L); + + + +#if !defined(lua_assert) +#define lua_assert(x) ((void)0) +#endif + + +#endif diff --git a/src/lundump.c b/src/lundump.c new file mode 100644 index 0000000000..54de011a45 --- /dev/null +++ b/src/lundump.c @@ -0,0 +1,258 @@ +/* +** $Id: lundump.c,v 2.22 2012/05/08 13:53:33 roberto Exp $ +** load precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +#include + +#define lundump_c +#define LUA_CORE + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstring.h" +#include "lundump.h" +#include "lzio.h" + +typedef struct { + lua_State* L; + ZIO* Z; + Mbuffer* b; + const char* name; +} LoadState; + +static l_noret error(LoadState* S, const char* why) +{ + luaO_pushfstring(S->L,"%s: %s precompiled chunk",S->name,why); + luaD_throw(S->L,LUA_ERRSYNTAX); +} + +#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) + +#if !defined(luai_verifycode) +#define luai_verifycode(L,b,f) /* empty */ +#endif + +static void LoadBlock(LoadState* S, void* b, size_t size) +{ + if (luaZ_read(S->Z,b,size)!=0) error(S,"truncated"); +} + +static int LoadChar(LoadState* S) +{ + char x; + LoadVar(S,x); + return x; +} + +static int LoadInt(LoadState* S) +{ + int x; + LoadVar(S,x); + if (x<0) error(S,"corrupted"); + return x; +} + +static lua_Number LoadNumber(LoadState* S) +{ + lua_Number x; + LoadVar(S,x); + return x; +} + +static TString* LoadString(LoadState* S) +{ + size_t size; + LoadVar(S,size); + if (size==0) + return NULL; + else + { + char* s=luaZ_openspace(S->L,S->b,size); + LoadBlock(S,s,size*sizeof(char)); + return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */ + } +} + +static void LoadCode(LoadState* S, Proto* f) +{ + int n=LoadInt(S); + f->code=luaM_newvector(S->L,n,Instruction); + f->sizecode=n; + LoadVector(S,f->code,n,sizeof(Instruction)); +} + +static void LoadFunction(LoadState* S, Proto* f); + +static void LoadConstants(LoadState* S, Proto* f) +{ + int i,n; + n=LoadInt(S); + f->k=luaM_newvector(S->L,n,TValue); + f->sizek=n; + for (i=0; ik[i]); + for (i=0; ik[i]; + int t=LoadChar(S); + switch (t) + { + case LUA_TNIL: + setnilvalue(o); + break; + case LUA_TBOOLEAN: + setbvalue(o,LoadChar(S)); + break; + case LUA_TNUMBER: + setnvalue(o,LoadNumber(S)); + break; + case LUA_TSTRING: + setsvalue2n(S->L,o,LoadString(S)); + break; + default: lua_assert(0); + } + } + 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]=luaF_newproto(S->L); + LoadFunction(S,f->p[i]); + } +} + +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=LoadByte(S); + f->upvalues[i].idx=LoadByte(S); + } +} + +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; + 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); + for (i=0; iupvalues[i].name=LoadString(S); +} + +static void LoadFunction(LoadState* S, Proto* f) +{ + f->linedefined=LoadInt(S); + f->lastlinedefined=LoadInt(S); + f->numparams=LoadByte(S); + f->is_vararg=LoadByte(S); + f->maxstacksize=LoadByte(S); + LoadCode(S,f); + LoadConstants(S,f); + LoadUpvalues(S,f); + LoadDebug(S,f); +} + +/* the code below must be consistent with the code in luaU_header */ +#define N0 LUAC_HEADERSIZE +#define N1 (sizeof(LUA_SIGNATURE)-sizeof(char)) +#define N2 N1+2 +#define N3 N2+6 + +static void LoadHeader(LoadState* S) +{ + lu_byte h[LUAC_HEADERSIZE]; + lu_byte s[LUAC_HEADERSIZE]; + luaU_header(h); + 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"); + if (memcmp(h,s,N3)!=0) error(S,"incompatible"); else error(S,"corrupted"); +} + +/* +** load precompiled chunk +*/ +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]) + S.name="binary string"; + else + S.name=name; + S.L=L; + S.Z=Z; + S.b=buff; + LoadHeader(&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') +#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 change the code below be sure to update LoadHeader and FORMAT above +* and LUAC_HEADERSIZE in lundump.h +*/ +void luaU_header (lu_byte* h) +{ + int x=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 new file mode 100644 index 0000000000..2b8accecb8 --- /dev/null +++ b/src/lundump.h @@ -0,0 +1,28 @@ +/* +** $Id: lundump.h,v 1.39 2012/05/08 13:53:33 roberto Exp $ +** load precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +#ifndef lundump_h +#define lundump_h + +#include "lobject.h" +#include "lzio.h" + +/* load one chunk; from lundump.c */ +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); + +/* dump one chunk; from ldump.c */ +LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip); + +/* 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 new file mode 100644 index 0000000000..b77eac26d0 --- /dev/null +++ b/src/lvm.c @@ -0,0 +1,868 @@ +/* +** $Id: lvm.c,v 2.152 2012/06/08 15:14:04 roberto Exp $ +** Lua virtual machine +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include + +#define lvm_c +#define LUA_CORE + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lvm.h" + + + +/* limit for table tag-method chains (to avoid loops) */ +#define MAXTAGLOOP 100 + + +const TValue *luaV_tonumber (const TValue *obj, TValue *n) { + lua_Number num; + if (ttisnumber(obj)) return obj; + if (ttisstring(obj) && luaO_str2d(svalue(obj), tsvalue(obj)->len, &num)) { + setnvalue(n, num); + return n; + } + else + return NULL; +} + + +int luaV_tostring (lua_State *L, StkId obj) { + if (!ttisnumber(obj)) + return 0; + else { + char s[LUAI_MAXNUMBER2STR]; + lua_Number n = nvalue(obj); + int l = lua_number2str(s, n); + setsvalue2s(L, obj, luaS_newlstr(L, s, l)); + return 1; + } +} + + +static void traceexec (lua_State *L) { + CallInfo *ci = L->ci; + lu_byte mask = L->hookmask; + int counthook = ((mask & LUA_MASKCOUNT) && L->hookcount == 0); + if (counthook) + resethookcount(L); /* reset count */ + if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ + ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ + return; /* do not call hook again (VM yielded, so it did not move) */ + } + if (counthook) + luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ + if (mask & LUA_MASKLINE) { + 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, */ + 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); /* call line hook */ + } + L->oldpc = ci->u.l.savedpc; + if (L->status == LUA_YIELD) { /* did hook yield? */ + if (counthook) + L->hookcount = 1; /* undo decrement to zero */ + ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ + ci->callstatus |= CIST_HOOKYIELD; /* mark that it yieled */ + ci->func = L->top - 1; /* protect stack below results */ + luaD_throw(L, LUA_YIELD); + } +} + + +static void callTM (lua_State *L, const TValue *f, const TValue *p1, + 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); /* 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 */ + p3 = restorestack(L, result); + setobjs2s(L, p3, --L->top); + } +} + + +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 get */ + if (!ttisnil(res) || /* result is not 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)) { + callTM(L, tm, t, key, val, 1); + return; + } + t = tm; /* else repeat with 'tm' */ + } + luaG_runerror(L, "loop in gettable"); +} + + +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); + 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 metamethod */ + } + 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; + } + t = tm; /* else repeat with 'tm' */ + } + luaG_runerror(L, "loop in settable"); +} + + +static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event) { + const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ + if (ttisnil(tm)) + tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ + if (ttisnil(tm)) return 0; + callTM(L, tm, p1, p2, res, 1); + return 1; +} + + +static const TValue *get_equalTM (lua_State *L, Table *mt1, Table *mt2, + TMS event) { + 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); + if (tm2 == NULL) return NULL; /* no metamethod */ + if (luaV_rawequalobj(tm1, tm2)) /* same metamethods? */ + return tm1; + return NULL; +} + + +static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, + TMS event) { + if (!call_binTM(L, p1, p2, L->top, event)) + return -1; /* no metamethod */ + else + return !l_isfalse(L->top); +} + + +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); + 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 == 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; + } + } +} + + +int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { + int res; + if (ttisnumber(l) && ttisnumber(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)) < 0) + luaG_ordererror(L, l, r); + return res; +} + + +int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { + int res; + if (ttisnumber(l) && ttisnumber(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)) >= 0) /* first try `le' */ + return res; + else if ((res = call_orderTM(L, r, l, TM_LT)) < 0) /* else try `lt' */ + luaG_ordererror(L, l, r); + return !res; +} + + +/* +** 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(ttisequal(t1, t2)); + 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); /* true must be 1 !! */ + case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); + case LUA_TLCF: return fvalue(t1) == fvalue(t2); + case LUA_TSHRSTR: return eqshrstr(rawtsvalue(t1), rawtsvalue(t2)); + case LUA_TLNGSTR: return luaS_eqlngstr(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: + 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 */ + return !l_isfalse(L->top); +} + + +void luaV_concat (lua_State *L, int total) { + lua_assert(total >= 2); + do { + 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 operand is empty? */ + (void)tostring(L, top - 2); /* result is first operand */ + else if (ttisstring(top-2) && tsvalue(top-2)->len == 0) { + setobjs2s(L, top - 2, top - 1); /* result is second op. */ + } + else { + /* at least two non-empty string values; get as many as possible */ + size_t tl = tsvalue(top-1)->len; + char *buffer; + int i; + /* collect total length */ + 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; + n = i; + do { /* concat all strings */ + size_t l = tsvalue(top-i)->len; + 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 */ + L->top -= n-1; /* popped 'n' strings and pushed one */ + } while (total > 1); /* repeat until only 1 result left */ +} + + +void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { + const TValue *tm; + switch (ttypenv(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, rb, 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 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); +} + + +/* +** 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, 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? */ + 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 +*/ +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); + 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_GETTABUP: 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 = 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) */ + 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_SETTABUP: case OP_SETTABLE: + break; + default: lua_assert(0); + } +} + + + +/* +** 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)) +#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i)) +#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \ + 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) \ + (k + (GETARG_Bx(i) != 0 ? GETARG_Bx(i) - 1 : GETARG_Ax(*ci->u.l.savedpc++))) + + +/* 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,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) { \ + TValue *rb = RKB(i); \ + TValue *rc = RKC(i); \ + if (ttisnumber(rb) && ttisnumber(rc)) { \ + lua_Number nb = nvalue(rb), nc = nvalue(rc); \ + setnvalue(ra, op(L, nb, nc)); \ + } \ + else { Protect(luaV_arith(L, ra, rb, rc, tm)); } } + + +#define vmdispatch(o) switch(o) +#define vmcase(l,b) case l: {b} break; +#define vmcasenb(l,b) case l: {b} /* nb = no break */ + +void luaV_execute (lua_State *L) { + CallInfo *ci = L->ci; + LClosure *cl; + TValue *k; + StkId base; + newframe: /* reentry point when frame changes (call/return) */ + lua_assert(ci == L->ci); + cl = clLvalue(ci->func); + 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)) { + 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); + vmdispatch (GET_OPCODE(i)) { + vmcase(OP_MOVE, + setobjs2s(L, ra, RB(i)); + ) + vmcase(OP_LOADK, + 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, + setbvalue(ra, GETARG_B(i)); + if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */ + ) + vmcase(OP_LOADNIL, + int b = GETARG_B(i); + do { + setnilvalue(ra++); + } while (b--); + ) + vmcase(OP_GETUPVAL, + int b = GETARG_B(i); + setobj2s(L, ra, cl->upvals[b]->v); + ) + 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)); + ) + 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); + ) + vmcase(OP_SETTABLE, + Protect(luaV_settable(L, ra, RKB(i), RKC(i))); + ) + 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)); + checkGC(L, ra + 1); + ) + vmcase(OP_SELF, + StkId rb = RB(i); + setobjs2s(L, ra+1, rb); + Protect(luaV_gettable(L, rb, RKC(i), ra)); + ) + vmcase(OP_ADD, + arith_op(luai_numadd, TM_ADD); + ) + vmcase(OP_SUB, + arith_op(luai_numsub, TM_SUB); + ) + vmcase(OP_MUL, + arith_op(luai_nummul, TM_MUL); + ) + vmcase(OP_DIV, + arith_op(luai_numdiv, TM_DIV); + ) + vmcase(OP_MOD, + arith_op(luai_nummod, TM_MOD); + ) + vmcase(OP_POW, + arith_op(luai_numpow, TM_POW); + ) + vmcase(OP_UNM, + TValue *rb = RB(i); + if (ttisnumber(rb)) { + lua_Number nb = nvalue(rb); + setnvalue(ra, luai_numunm(L, nb)); + } + else { + Protect(luaV_arith(L, ra, rb, rb, TM_UNM)); + } + ) + vmcase(OP_NOT, + TValue *rb = RB(i); + int res = l_isfalse(rb); /* next assignment may change this value */ + setbvalue(ra, res); + ) + vmcase(OP_LEN, + Protect(luaV_objlen(L, ra, RB(i))); + ) + 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)); + ra = RA(i); /* 'luav_concat' may invoke TMs and move the stack */ + rb = b + base; + setobjs2s(L, ra, rb); + checkGC(L, (ra >= rb ? ra + 1 : rb)); + L->top = ci->top; /* restore top */ + ) + vmcase(OP_JMP, + dojump(ci, i, 0); + ) + vmcase(OP_EQ, + TValue *rb = RKB(i); + TValue *rc = RKC(i); + Protect( + if (cast_int(equalobj(L, rb, rc)) != GETARG_A(i)) + ci->u.l.savedpc++; + else + donextjump(ci); + ) + ) + vmcase(OP_LT, + Protect( + if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) + ci->u.l.savedpc++; + else + donextjump(ci); + ) + ) + vmcase(OP_LE, + Protect( + if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) + ci->u.l.savedpc++; + else + donextjump(ci); + ) + ) + vmcase(OP_TEST, + 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)) + ci->u.l.savedpc++; + else { + setobjs2s(L, ra, rb); + donextjump(ci); + } + ) + 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; + } + else { /* Lua function */ + ci = L->ci; + ci->callstatus |= CIST_REENTRY; + goto newframe; /* restart luaV_execute over new Lua function */ + } + ) + 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? */ + base = ci->u.l.base; + 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); + goto newframe; /* restart luaV_execute over new Lua function */ + } + ) + vmcasenb(OP_RETURN, + int b = GETARG_B(i); + if (b != 0) L->top = ra+b-1; + if (cl->p->sizep > 0) luaF_close(L, base); + b = luaD_poscall(L, ra); + 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); + goto newframe; /* restart luaV_execute over new Lua function */ + } + ) + 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); + if (luai_numlt(L, 0, step) ? luai_numle(L, idx, limit) + : luai_numle(L, limit, idx)) { + ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ + setnvalue(ra, idx); /* update internal index... */ + setnvalue(ra+3, idx); /* ...and external index */ + } + ) + vmcase(OP_FORPREP, + const TValue *init = ra; + const TValue *plimit = ra+1; + const TValue *pstep = ra+2; + 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(L, nvalue(ra), nvalue(pstep))); + ci->u.l.savedpc += GETARG_sBx(i); + ) + vmcasenb(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), 1)); + L->top = ci->top; + i = *(ci->u.l.savedpc++); /* go to next instruction */ + ra = RA(i); + lua_assert(GET_OPCODE(i) == OP_TFORLOOP); + goto l_tforloop; + ) + vmcase(OP_TFORLOOP, + l_tforloop: + if (!ttisnil(ra + 1)) { /* continue loop? */ + setobjs2s(L, ra, ra + 1); /* save control variable */ + ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ + } + ) + vmcase(OP_SETLIST, + int n = GETARG_B(i); + int c = GETARG_C(i); + int last; + Table *h; + 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++); + } + luai_runtimecheck(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-allocate it at once */ + for (; n > 0; n--) { + TValue *val = ra+n; + luaH_setint(L, h, last--, val); + luaC_barrierback(L, obj2gco(h), val); + } + L->top = ci->top; /* correct top (in case of previous open call) */ + ) + 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 + setclLvalue(L, ra, ncl); /* push cashed closure */ + checkGC(L, ra + 1); + ) + vmcase(OP_VARARG, + int b = GETARG_B(i) - 1; + int j; + 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 */ + L->top = ra + n; + } + for (j = 0; j < b; j++) { + if (j < n) { + setobjs2s(L, ra + j, base - n + j); + } + else { + setnilvalue(ra + j); + } + } + ) + vmcase(OP_EXTRAARG, + lua_assert(0); + ) + } + } +} + diff --git a/src/lvm.h b/src/lvm.h new file mode 100644 index 0000000000..ec35822406 --- /dev/null +++ b/src/lvm.h @@ -0,0 +1,45 @@ +/* +** $Id: lvm.h,v 2.17 2011/05/31 18:27:56 roberto Exp $ +** Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#ifndef lvm_h +#define lvm_h + + +#include "ldo.h" +#include "lobject.h" +#include "ltm.h" + + +#define tostring(L,o) (ttisstring(o) || (luaV_tostring(L, o))) + +#define tonumber(o,n) (ttisnumber(o) || (((o) = luaV_tonumber(o,n)) != NULL)) + +#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_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); +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_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 new file mode 100644 index 0000000000..8b77054e0b --- /dev/null +++ b/src/lzio.c @@ -0,0 +1,76 @@ +/* +** $Id: lzio.c,v 1.35 2012/05/14 13:34:18 roberto Exp $ +** Buffered streams +** See Copyright Notice in lua.h +*/ + + +#include + +#define lzio_c +#define LUA_CORE + +#include "lua.h" + +#include "llimits.h" +#include "lmem.h" +#include "lstate.h" +#include "lzio.h" + + +int luaZ_fill (ZIO *z) { + size_t 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; /* discount char being returned */ + z->p = buff; + return cast_uchar(*(z->p++)); +} + + +void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { + z->L = L; + z->reader = reader; + z->data = data; + z->n = 0; + z->p = NULL; +} + + +/* --------------------------------------------------------------- read --- */ +size_t luaZ_read (ZIO *z, void *b, size_t n) { + while (n) { + size_t m; + 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; + z->p += m; + b = (char *)b + m; + n -= m; + } + return 0; +} + +/* ------------------------------------------------------------------------ */ +char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) { + if (n > buff->buffsize) { + if (n < LUA_MINBUFFER) n = LUA_MINBUFFER; + luaZ_resizebuffer(L, buff, n); + } + return buff->buffer; +} + + diff --git a/src/lzio.h b/src/lzio.h new file mode 100644 index 0000000000..08682301e8 --- /dev/null +++ b/src/lzio.h @@ -0,0 +1,65 @@ +/* +** $Id: lzio.h,v 1.26 2011/07/15 12:48:03 roberto Exp $ +** Buffered streams +** See Copyright Notice in lua.h +*/ + + +#ifndef lzio_h +#define lzio_h + +#include "lua.h" + +#include "lmem.h" + + +#define EOZ (-1) /* end of stream */ + +typedef struct Zio ZIO; + +#define zgetc(z) (((z)->n--)>0 ? cast_uchar(*(z)->p++) : luaZ_fill(z)) + + +typedef struct Mbuffer { + char *buffer; + size_t n; + size_t buffsize; +} Mbuffer; + +#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) + +#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), \ + (buff)->buffsize = size) + +#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 */ + + + +/* --------- Private Part ------------------ */ + +struct Zio { + size_t n; /* bytes still unread */ + const char *p; /* current position in buffer */ + lua_Reader reader; /* reader function */ + void* data; /* additional data */ + lua_State *L; /* Lua state (for reader) */ +}; + + +LUAI_FUNC int luaZ_fill (ZIO *z); + +#endif From 7013587840efcbb1873ec4c73419c64db954d369 Mon Sep 17 00:00:00 2001 From: Craig Barnes Date: Sat, 15 Sep 2012 02:03:31 +0100 Subject: [PATCH 02/40] Add .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..6917571df2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.[oa] +src/lua +src/luac From efbcaba839a6a400c7e60ba2a878be63238b119a Mon Sep 17 00:00:00 2001 From: Craig Barnes Date: Sun, 16 Jun 2013 10:54:47 +0100 Subject: [PATCH 03/40] Import Lua 5.2.2 --- README | 2 +- doc/contents.html | 18 +-- doc/lua.css | 6 +- doc/manual.css | 6 +- doc/manual.html | 314 +++++++++++++++++++++++++++++----------------- doc/readme.html | 10 +- src/Makefile | 2 +- src/lapi.c | 45 +++---- src/lauxlib.c | 13 +- src/lbaselib.c | 33 +++-- src/lbitlib.c | 6 +- src/lcode.c | 11 +- src/lcorolib.c | 4 +- src/ldebug.c | 10 +- src/ldo.c | 15 ++- src/lfunc.c | 4 +- src/lgc.c | 90 +++++++------ src/lgc.h | 16 ++- src/liolib.c | 26 ++-- src/llex.c | 10 +- src/llimits.h | 8 +- src/lmathlib.c | 72 +++++------ src/lmem.h | 15 ++- src/lobject.c | 20 ++- src/lobject.h | 7 +- src/loslib.c | 4 +- src/lparser.c | 11 +- src/lstate.c | 4 +- src/lstate.h | 4 +- src/lstring.c | 6 +- src/lstrlib.c | 207 ++++++++++++++++++------------ src/ltable.c | 6 +- src/ltablib.c | 20 +-- src/lua.c | 7 +- src/lua.h | 13 +- src/luaconf.h | 25 ++-- src/lvm.c | 7 +- src/lvm.h | 5 +- 38 files changed, 631 insertions(+), 451 deletions(-) diff --git a/README b/README index 253d110692..6e2aee6ce3 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ -This is Lua 5.2.1, released on 08 Jun 2012. +This is Lua 5.2.2, released on 21 Mar 2013. 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 9f5060519f..0ce297da19 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -23,7 +23,7 @@

The reference manual is the official definition of the Lua language. For a complete introduction to Lua programming, see the book -Programming in Lua. +Programming in Lua.

start @@ -33,7 +33,7 @@

index
-Copyright © 2011–2012 Lua.org, PUC-Rio. +Copyright © 2011–2013 Lua.org, PUC-Rio. Freely available under the terms of the Lua license. @@ -149,8 +149,8 @@

Lua functions

error
getmetatable
ipairs
-loadfile
load
+loadfile
next
pairs
pcall
@@ -385,6 +385,7 @@

C API

lua_pushcclosure
lua_pushcfunction
lua_pushfstring
+lua_pushglobaltable
lua_pushinteger
lua_pushlightuserdata
lua_pushliteral
@@ -393,15 +394,16 @@

C API

lua_pushnumber
lua_pushstring
lua_pushthread
+lua_pushunsigned
lua_pushvalue
lua_pushvfstring
lua_rawequal
lua_rawget
lua_rawgeti
+lua_rawgetp
lua_rawlen
lua_rawset
lua_rawseti
-lua_rawgetp
lua_rawsetp
lua_register
lua_remove
@@ -460,8 +462,8 @@

auxiliary library

luaL_buffinitsize
luaL_callmeta
luaL_checkany
-luaL_checkinteger
luaL_checkint
+luaL_checkinteger
luaL_checklong
luaL_checklstring
luaL_checknumber
@@ -492,8 +494,8 @@

auxiliary library

luaL_newmetatable
luaL_newstate
luaL_openlibs
-luaL_optinteger
luaL_optint
+luaL_optinteger
luaL_optlong
luaL_optlstring
luaL_optnumber
@@ -521,10 +523,10 @@

auxiliary library


Last update: -Sat May 26 08:52:25 BRT 2012 +Tue Mar 12 11:22:18 BRT 2013 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..85365363fb 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. @@ -8348,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. @@ -8990,6 +9061,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 +9486,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 +9497,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 +9521,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 +9556,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 +9637,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 +9828,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 +10497,10 @@

    9 – The Complete Syntax of Lua


    Last update: -Fri Jun 8 16:13:40 BRT 2012 +Thu Mar 21 12:58:59 BRT 2013 diff --git a/doc/readme.html b/doc/readme.html index 2ff294ec37..5b9e47ecba 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. @@ -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

      @@ -372,7 +374,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 +402,10 @@

      License


      Last update: -Tue May 29 21:57:51 BRT 2012 +Fri Feb 22 09:24:20 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..791d85454f 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.171 2013/03/16 21:10:18 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 unreachable; 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..2e989d661b 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.248 2013/03/21 13:54:57 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"); @@ -598,7 +599,7 @@ static int skipBOM (LoadF *lf) { lf->n = 0; do { c = getc(lf->f); - if (c == EOF || c != *(unsigned char *)p++) return c; + if (c == EOF || c != *(const 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 */ diff --git a/src/lbaselib.c b/src/lbaselib.c index dbfcb02cfc..540e9a5cc0 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.276 2013/02/21 13:44:53 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); } /* }====================================================== */ @@ -338,7 +336,8 @@ static int dofilecont (lua_State *L) { static int luaB_dofile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); lua_settop(L, 1); - if (luaL_loadfile(L, fname) != LUA_OK) lua_error(L); + if (luaL_loadfile(L, fname) != LUA_OK) + return lua_error(L); lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); return dofilecont(L); } diff --git a/src/lbitlib.c b/src/lbitlib.c index 7533b85c5a..9637532e3d 100644 --- a/src/lbitlib.c +++ b/src/lbitlib.c @@ -1,5 +1,5 @@ /* -** $Id: lbitlib.c,v 1.16 2011/06/20 16:35:23 roberto Exp $ +** $Id: lbitlib.c,v 1.18 2013/03/19 13:19:12 roberto Exp $ ** Standard library for bitwise operations ** See Copyright Notice in lua.h */ @@ -147,7 +147,9 @@ static int b_rrot (lua_State *L) { /* ** get field and width arguments for field-manipulation functions, -** checking whether they are valid +** checking whether they are valid. +** ('luaL_error' called without 'return' to avoid later warnings about +** 'width' being used uninitialized.) */ static int fieldargs (lua_State *L, int farg, int *width) { int f = luaL_checkint(L, farg); 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/lcorolib.c b/src/lcorolib.c index c7932d90f2..1326c8146c 100644 --- a/src/lcorolib.c +++ b/src/lcorolib.c @@ -1,5 +1,5 @@ /* -** $Id: lcorolib.c,v 1.4 2012/04/27 18:59:04 roberto Exp $ +** $Id: lcorolib.c,v 1.5 2013/02/21 13:44:53 roberto Exp $ ** Coroutine Library ** See Copyright Notice in lua.h */ @@ -73,7 +73,7 @@ static int luaB_auxwrap (lua_State *L) { lua_insert(L, -2); lua_concat(L, 2); } - lua_error(L); /* propagate error */ + return lua_error(L); /* propagate error */ } return r; } 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..535e988ae0 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.140 2013/03/16 21:10:18 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); @@ -459,7 +450,7 @@ static lu_mem traversetable (global_State *g, Table *h) { else /* not weak */ traversestrongtable(g, h); return sizeof(Table) + sizeof(TValue) * h->sizearray + - sizeof(Node) * sizenode(h); + sizeof(Node) * cast(size_t, sizenode(h)); } @@ -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)) @@ -918,7 +924,7 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { ** 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. -** Returns how many objects it sweeped. +** Returns how many objects it swept. */ static int entersweep (lua_State *L) { global_State *g = G(L); @@ -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/liolib.c b/src/liolib.c index 4814aa2c2a..3f80db1927 100644 --- a/src/liolib.c +++ b/src/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.108 2011/11/25 12:50:03 roberto Exp $ +** $Id: liolib.c,v 2.111 2013/03/21 13:57:27 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -29,6 +29,20 @@ #include "lualib.h" +#if !defined(lua_checkmode) + +/* +** Check whether 'mode' matches '[rwa]%+?b?'. +** Change this macro to accept other modes for 'fopen' besides +** the standard ones. +*/ +#define lua_checkmode(mode) \ + (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \ + (*mode != '+' || ++mode) && /* skip if char is '+' */ \ + (*mode != 'b' || ++mode) && /* skip if char is 'b' */ \ + (*mode == '\0')) + +#endif /* ** {====================================================== @@ -212,14 +226,8 @@ static int io_open (lua_State *L) { const char *filename = luaL_checkstring(L, 1); const char *mode = luaL_optstring(L, 2, "r"); LStream *p = newfile(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] == '\0'))) - return luaL_error(L, "invalid mode " LUA_QS - " (should match " LUA_QL("[rwa]%%+?b?") ")", mode); + const char *md = mode; /* to traverse/check mode */ + luaL_argcheck(L, lua_checkmode(md), 2, "invalid mode"); p->f = fopen(filename, mode); return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; } diff --git a/src/llex.c b/src/llex.c index c4d8c65b6f..1a32e348b0 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.63 2013/03/16 21:10:18 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; } } @@ -313,7 +313,7 @@ static int readhexaesc (LexState *ls) { 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 */ + for (i = 1; i < 3; i++) { /* read two hexadecimal digits */ c[i] = next(ls); if (!lisxdigit(c[i])) escerror(ls, c, i + 1, "hexadecimal digit expected"); diff --git a/src/llimits.h b/src/llimits.h index fc9de1a11b..1b8c79bda2 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.103 2013/02/20 14:08:56 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_mathop(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..a49f1fd25a 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.83 2013/03/07 18:21:32 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); + int ep = luaL_checkint(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..5f850999a9 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.40 2013/02/20 14:08:21 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 "comparison 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..c152785a5a 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.58 2013/02/20 14:08:56 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_mathop(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..ad798b4e2a 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.65 2013/03/07 18:17:24 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,17 @@ 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"); 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..eb0482b8f4 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.285 2013/03/15 13:04:22 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" @@ -119,6 +119,11 @@ typedef LUA_UNSIGNED lua_Unsigned; #endif +/* +** RCS ident string +*/ +extern const char lua_ident[]; + /* ** state manipulation @@ -413,7 +418,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..df802c9526 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.176 2013/03/16 21:10:18 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -44,7 +44,7 @@ #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_STRTODHEX /* assume 'strtod' handles hex formats */ #define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ #define LUA_USE_LONGLONG /* assume support for long long */ #endif @@ -53,7 +53,7 @@ #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_STRTODHEX /* assume 'strtod' handles hex formats */ #define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ #define LUA_USE_LONGLONG /* assume support for long long */ #endif @@ -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..657d5c456a 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.155 2013/03/16 21:10:18 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -83,7 +83,7 @@ static void traceexec (lua_State *L) { if (counthook) L->hookcount = 1; /* undo decrement to zero */ ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ - ci->callstatus |= CIST_HOOKYIELD; /* mark that it yieled */ + ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ ci->func = L->top - 1; /* protect stack below results */ luaD_throw(L, LUA_YIELD); } @@ -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 950db94fc42fd6fa9186c0aa9410a0f721504112 Mon Sep 17 00:00:00 2001 From: Craig Barnes Date: Sat, 6 Jul 2013 03:38:48 +0100 Subject: [PATCH 04/40] Import Lua 5.3.0 (work1) --- Makefile | 4 +- README | 2 +- doc/contents.html | 12 +- doc/manual.html | 353 ++++++++++++++++++++++++++++----------- doc/readme.html | 16 +- src/.fix | 2 + src/Makefile | 9 +- src/lapi.c | 141 +++++++++------- src/lauxlib.c | 47 +++--- src/lauxlib.h | 14 +- src/lbaselib.c | 71 ++++---- src/lbitlib.c | 18 +- src/lcode.c | 126 +++++++++----- src/lcode.h | 6 +- src/ldblib.c | 15 +- src/ldebug.c | 70 ++++++-- src/ldebug.h | 9 +- src/ldo.c | 15 +- src/ldump.c | 20 ++- src/lgc.c | 13 +- src/liolib.c | 45 +++-- src/llex.c | 57 ++++--- src/llex.h | 8 +- src/llimits.h | 113 ++----------- src/lmathlib.c | 56 +++++-- src/lobject.c | 161 ++++++++++++++---- src/lobject.h | 143 +++------------- src/lopcodes.c | 4 +- src/lopcodes.h | 3 +- src/loslib.c | 10 +- src/lparser.c | 19 ++- src/lparser.h | 8 +- src/lstring.c | 6 +- src/lstrlib.c | 109 ++++-------- src/ltable.c | 83 +++++---- src/ltable.h | 7 +- src/ltm.c | 74 +++++++- src/ltm.h | 17 +- src/lua.h | 24 +-- src/luac.c | 6 +- src/luaconf.h | 200 +++++++++++----------- src/lundump.c | 16 +- src/lvm.c | 418 ++++++++++++++++++++++++++++------------------ src/lvm.h | 25 +-- src/lzio.h | 6 +- 45 files changed, 1549 insertions(+), 1032 deletions(-) create mode 100644 src/.fix diff --git a/Makefile b/Makefile index bd9515fd84..e8092654f0 100644 --- a/Makefile +++ b/Makefile @@ -45,8 +45,8 @@ TO_LIB= liblua.a TO_MAN= lua.1 luac.1 # Lua version and release. -V= 5.2 -R= $V.1 +V= 5.3 +R= $V.0 # Targets start here. all: $(PLAT) diff --git a/README b/README index 6e2aee6ce3..70ec4137db 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ -This is Lua 5.2.2, released on 21 Mar 2013. +This is Lua 5.3.0 (work1), released on 5 Jul 2013. 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 0ce297da19..fb11593935 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -1,7 +1,7 @@ -Lua 5.2 Reference Manual - contents +Lua 5.3 Reference Manual - contents - - - - -
      -

      - -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. - -

      -start -· -contents -· -index -


      - -Copyright © 2014 Lua.org, PUC-Rio. -Freely available under the terms of the -Lua license. - - -

      Contents

      - - -

      Index

      - - - - - - - -
      -

      Lua functions

      -

      -basic
      -_G
      -_VERSION
      - -assert
      -collectgarbage
      -dofile
      -error
      -getmetatable
      -ipairs
      -load
      -loadfile
      -next
      -pairs
      -pcall
      -print
      -rawequal
      -rawget
      -rawlen
      -rawset
      -require
      -select
      -setmetatable
      -tonumber
      -tostring
      -type
      -xpcall
      - -

      -coroutine
      -coroutine.create
      -coroutine.isyieldable
      -coroutine.resume
      -coroutine.running
      -coroutine.status
      -coroutine.wrap
      -coroutine.yield
      - -

      -debug
      -debug.debug
      -debug.gethook
      -debug.getinfo
      -debug.getlocal
      -debug.getmetatable
      -debug.getregistry
      -debug.getupvalue
      -debug.getuservalue
      -debug.sethook
      -debug.setlocal
      -debug.setmetatable
      -debug.setupvalue
      -debug.setuservalue
      -debug.traceback
      -debug.upvalueid
      -debug.upvaluejoin
      - -

      -io
      -io.close
      -io.flush
      -io.input
      -io.lines
      -io.open
      -io.output
      -io.popen
      -io.read
      -io.stderr
      -io.stdin
      -io.stdout
      -io.tmpfile
      -io.type
      -io.write
      - -file:close
      -file:flush
      -file:lines
      -file:read
      -file:seek
      -file:setvbuf
      -file:write
      - -

      -

       

      -

      -math
      -math.abs
      -math.acos
      -math.asin
      -math.atan
      -math.ceil
      -math.cos
      -math.deg
      -math.exp
      -math.floor
      -math.fmod
      -math.huge
      -math.log
      -math.max
      -math.maxinteger
      -math.min
      -math.mininteger
      -math.modf
      -math.pi
      -math.rad
      -math.random
      -math.randomseed
      -math.sin
      -math.sqrt
      -math.tan
      -math.tointeger
      -math.type
      -math.ult
      - -

      -os
      -os.clock
      -os.date
      -os.difftime
      -os.execute
      -os.exit
      -os.getenv
      -os.remove
      -os.rename
      -os.setlocale
      -os.time
      -os.tmpname
      - -

      -package
      -package.config
      -package.cpath
      -package.loaded
      -package.loadlib
      -package.path
      -package.preload
      -package.searchers
      -package.searchpath
      - -

      -string
      -string.byte
      -string.char
      -string.dump
      -string.find
      -string.format
      -string.gmatch
      -string.gsub
      -string.len
      -string.lower
      -string.match
      -string.pack
      -string.packsize
      -string.rep
      -string.reverse
      -string.sub
      -string.unpack
      -string.upper
      - -

      -table
      -table.concat
      -table.insert
      -table.move
      -table.pack
      -table.remove
      -table.sort
      -table.unpack
      - -

      -utf8
      -utf8.char
      -utf8.charpattern
      -utf8.codepoint
      -utf8.codes
      -utf8.len
      -utf8.offset
      - -

      environment
      variables

      -LUA_CPATH
      -LUA_CPATH_5_3
      -LUA_INIT
      -LUA_INIT_5_3
      -LUA_PATH
      -LUA_PATH_5_3
      - -
      -

      C API

      -

      -lua_Alloc
      -lua_CFunction
      -lua_Debug
      -lua_Hook
      -lua_Integer
      -lua_KContext
      -lua_KFunction
      -lua_Number
      -lua_Reader
      -lua_State
      -lua_Unsigned
      -lua_Writer
      - -

      -lua_absindex
      -lua_arith
      -lua_atpanic
      -lua_call
      -lua_callk
      -lua_checkstack
      -lua_close
      -lua_compare
      -lua_concat
      -lua_copy
      -lua_createtable
      -lua_dump
      -lua_error
      -lua_gc
      -lua_getallocf
      -lua_getextraspace
      -lua_getfield
      -lua_getglobal
      -lua_gethook
      -lua_gethookcount
      -lua_gethookmask
      -lua_geti
      -lua_getinfo
      -lua_getlocal
      -lua_getmetatable
      -lua_getstack
      -lua_gettable
      -lua_gettop
      -lua_getupvalue
      -lua_getuservalue
      -lua_insert
      -lua_isboolean
      -lua_iscfunction
      -lua_isfunction
      -lua_isinteger
      -lua_islightuserdata
      -lua_isnil
      -lua_isnone
      -lua_isnoneornil
      -lua_isnumber
      -lua_isstring
      -lua_istable
      -lua_isthread
      -lua_isuserdata
      -lua_isyieldable
      -lua_len
      -lua_load
      -lua_newstate
      -lua_newtable
      -lua_newthread
      -lua_newuserdata
      -lua_next
      -lua_numbertointeger
      -lua_pcall
      -lua_pcallk
      -lua_pop
      -lua_pushboolean
      -lua_pushcclosure
      -lua_pushcfunction
      -lua_pushfstring
      -lua_pushglobaltable
      -lua_pushinteger
      -lua_pushlightuserdata
      -lua_pushliteral
      -lua_pushlstring
      -lua_pushnil
      -lua_pushnumber
      -lua_pushstring
      -lua_pushthread
      -lua_pushvalue
      -lua_pushvfstring
      -lua_rawequal
      -lua_rawget
      -lua_rawgeti
      -lua_rawgetp
      -lua_rawlen
      -lua_rawset
      -lua_rawseti
      -lua_rawsetp
      -lua_register
      -lua_remove
      -lua_replace
      -lua_resume
      -lua_rotate
      -lua_setallocf
      -lua_setfield
      -lua_setglobal
      -lua_sethook
      -lua_seti
      -lua_setlocal
      -lua_setmetatable
      -lua_settable
      -lua_settop
      -lua_setupvalue
      -lua_setuservalue
      -lua_status
      -lua_stringtonumber
      -lua_toboolean
      -lua_tocfunction
      -lua_tointeger
      -lua_tointegerx
      -lua_tolstring
      -lua_tonumber
      -lua_tonumberx
      -lua_topointer
      -lua_tostring
      -lua_tothread
      -lua_touserdata
      -lua_type
      -lua_typename
      -lua_upvalueid
      -lua_upvalueindex
      -lua_upvaluejoin
      -lua_version
      -lua_xmove
      -lua_yield
      -lua_yieldk
      - -

      -

      auxiliary library

      -

      -luaL_Buffer
      -luaL_Reg
      -luaL_Stream
      - -

      -luaL_addchar
      -luaL_addlstring
      -luaL_addsize
      -luaL_addstring
      -luaL_addvalue
      -luaL_argcheck
      -luaL_argerror
      -luaL_buffinit
      -luaL_buffinitsize
      -luaL_callmeta
      -luaL_checkany
      -luaL_checkinteger
      -luaL_checklstring
      -luaL_checknumber
      -luaL_checkoption
      -luaL_checkstack
      -luaL_checkstring
      -luaL_checktype
      -luaL_checkudata
      -luaL_checkversion
      -luaL_dofile
      -luaL_dostring
      -luaL_error
      -luaL_execresult
      -luaL_fileresult
      -luaL_getmetafield
      -luaL_getmetatable
      -luaL_getsubtable
      -luaL_gsub
      -luaL_len
      -luaL_loadbuffer
      -luaL_loadbufferx
      -luaL_loadfile
      -luaL_loadfilex
      -luaL_loadstring
      -luaL_newlib
      -luaL_newlibtable
      -luaL_newmetatable
      -luaL_newstate
      -luaL_openlibs
      -luaL_optinteger
      -luaL_optlstring
      -luaL_optnumber
      -luaL_optstring
      -luaL_prepbuffer
      -luaL_prepbuffsize
      -luaL_pushresult
      -luaL_pushresultsize
      -luaL_ref
      -luaL_requiref
      -luaL_setfuncs
      -luaL_setmetatable
      -luaL_testudata
      -luaL_tolstring
      -luaL_traceback
      -luaL_typename
      -luaL_unref
      -luaL_where
      - -

      standard library

      -

      -luaopen_base
      -luaopen_coroutine
      -luaopen_debug
      -luaopen_io
      -luaopen_math
      -luaopen_os
      -luaopen_package
      -luaopen_string
      -luaopen_table
      -luaopen_utf8
      - -

      constants

      -LUA_ERRERR
      -LUA_ERRFILE
      -LUA_ERRGCMM
      -LUA_ERRMEM
      -LUA_ERRRUN
      -LUA_ERRSYNTAX
      -LUA_HOOKCALL
      -LUA_HOOKCOUNT
      -LUA_HOOKLINE
      -LUA_HOOKRET
      -LUA_HOOKTAILCALL
      -LUA_MASKCALL
      -LUA_MASKCOUNT
      -LUA_MASKLINE
      -LUA_MASKRET
      -LUA_MAXINTEGER
      -LUA_MININTEGER
      -LUA_MINSTACK
      -LUA_MULTRET
      -LUA_NOREF
      -LUA_OK
      -LUA_OPADD
      -LUA_OPBAND
      -LUA_OPBNOT
      -LUA_OPBOR
      -LUA_OPBXOR
      -LUA_OPDIV
      -LUA_OPEQ
      -LUA_OPIDIV
      -LUA_OPLE
      -LUA_OPLT
      -LUA_OPMOD
      -LUA_OPMUL
      -LUA_OPPOW
      -LUA_OPSHL
      -LUA_OPSHR
      -LUA_OPSUB
      -LUA_OPUNM
      -LUA_REFNIL
      -LUA_REGISTRYINDEX
      -LUA_RIDX_GLOBALS
      -LUA_RIDX_MAINTHREAD
      -LUA_TBOOLEAN
      -LUA_TFUNCTION
      -LUA_TLIGHTUSERDATA
      -LUA_TNIL
      -LUA_TNONE
      -LUA_TNUMBER
      -LUA_TSTRING
      -LUA_TTABLE
      -LUA_TTHREAD
      -LUA_TUSERDATA
      -LUA_USE_APICHECK
      -LUA_YIELD
      -LUAL_BUFFERSIZE
      - -
      - -
      - -Last update: -Tue Dec 9 21:26:07 BRST 2014 - - - - - 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 411531b9ed..0000000000 --- a/doc/lua.1 +++ /dev/null @@ -1,111 +0,0 @@ -.TH LUA 1 "$Date: 2014/12/10 15:55:45 $" -.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 the line contains an expression or list of expressions, -then the line is evaluated and the results are printed. -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. -.LP -At the very start, -before even handling the command line, -.B lua -checks the contents of the environment variables -.B LUA_INIT_5_3 -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 deleted file mode 100644 index 3199a2b6e8..0000000000 --- a/doc/lua.css +++ /dev/null @@ -1,105 +0,0 @@ -html { - background-color: #F8F8F8 ; -} - -body { - border: solid #a0a0a0 1px ; - border-radius: 20px ; - padding: 26px ; - margin: 16px ; - color: #000000 ; - background-color: #FFFFFF ; - font-family: Helvetica, Arial, sans-serif ; - text-align: justify ; -} - -h1, h2, h3, h4 { - font-family: Verdana, Geneva, sans-serif ; - font-weight: normal ; - font-style: normal ; -} - -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 ; -} - -h3 { - padding-left: 0.5em ; - border-left: solid #D0D0FF 1em ; -} - -table h3 { - padding-left: 0px ; - border-left: none ; -} - -a:link { - color: #000080 ; - background-color: inherit ; - text-decoration: none ; -} - -a:visited { - background-color: inherit ; - text-decoration: none ; -} - -a:link:hover, a:visited:hover { - color: #000080 ; - background-color: #D0D0FF ; - border-radius: 4px; -} - -a:link:active, a:visited:active { - color: #FF0000 ; -} - -h1 a img { - vertical-align: text-bottom ; -} - -hr { - border: 0 ; - height: 1px ; - color: #a0a0a0 ; - background-color: #a0a0a0 ; - display: none ; -} - -table hr { - display: block ; -} - -:target { - background-color: #F8F8F8 ; - padding: 8px ; - border: solid #a0a0a0 2px ; - border-radius: 8px ; -} - -.footer { - color: gray ; - font-size: x-small ; -} - -input[type=text] { - border: solid #a0a0a0 2px ; - border-radius: 2em ; - background-image: url('images/search.png') ; - background-repeat: no-repeat ; - background-position: 4px center ; - padding-left: 20px ; - height: 2em ; -} - -pre.session { - background-color: #F8F8F8 ; - padding: 1em ; - border-radius: 8px ; -} diff --git a/doc/luac.1 b/doc/luac.1 deleted file mode 100644 index 33a4ed00ac..0000000000 --- a/doc/luac.1 +++ /dev/null @@ -1,118 +0,0 @@ -.\" $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 deleted file mode 100644 index ca613cd9fb..0000000000 --- a/doc/manual.css +++ /dev/null @@ -1,27 +0,0 @@ -h3 code { - font-family: inherit ; - font-size: inherit ; -} - -pre, code { - font-size: 12pt ; -} - -span.apii { - 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 ; -} diff --git a/doc/manual.html b/doc/manual.html deleted file mode 100644 index b64747db78..0000000000 --- a/doc/manual.html +++ /dev/null @@ -1,10778 +0,0 @@ - - - - -Lua 5.3 Reference Manual - - - - - - - -
      -

      - -Lua 5.3 Reference Manual -

      - -by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes -

      - -Copyright © 2014 Lua.org, PUC-Rio. -Freely available under the terms of the -Lua license. - -


      -

      - -contents -· -index - - -

      - - - - - - -

      1 – Introduction

      - -

      -Lua is an extension programming language designed to support -general procedural programming with data description -facilities. -Lua also offers good support for object-oriented programming, -functional programming, and data-driven programming. -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++. - - -

      -As 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. -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, -for interactive or batch use. - - -

      -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, -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 – Basic Concepts

      - -

      -This section describes the basic concepts of the language. - - - -

      2.1 – 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. -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: -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; -it usually represents the absence of a useful value. -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 both -integer numbers and real (floating-point) numbers. -String represents immutable sequences of bytes. - -Lua is 8-bit clean: -strings can contain any 8-bit value, -including embedded zeros ('\0'). -Lua is also encoding-agnostic; -it makes no assumptions about the contents of a string. - - -

      -The type number uses two internal representations, -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). -Therefore, -the programmer may choose to mostly ignore the difference -between integers and floats -or to assume complete control over the representation of each number. -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 -is particularly attractive -for small machines and embedded systems. -(See macro LUA_32BITS in file luaconf.h.) - - -

      -Lua can call (and manipulate) functions written in Lua and -functions written in C (see §3.4.10). -Both are represented by the type function. - - -

      -The type userdata is provided to allow arbitrary C data to -be stored in Lua variables. -A userdata value represents a block of raw memory. -There are two kinds of userdata: -full userdata, -which is an object with a block of memory managed by Lua, -and light userdata, -which is simply a C pointer value. -Userdata has no predefined operations in Lua, -except assignment and identity test. -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. -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.6). -Lua threads are not related to operating-system threads. -Lua supports coroutines on all systems, -even those that do not support threads natively. - - -

      -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.) -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, 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 -providing a.name as syntactic sugar for a["name"]. -There are several convenient ways to create tables in Lua -(see §3.4.9). - - -

      -We use the term sequence to denote a table where -the set of all positive numeric keys is equal to {1..n} -for some non-negative integer n, -which is called the length of the sequence (see §3.4.7). - - -

      -Like indices, -the values of table fields 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.11). - - -

      -The indexing of tables follows -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 and j are raw equal -(that is, equal without metamethods). -In particular, floats with integral values -are equal to their respective integers -(e.g., 1.0 == 1). -To avoid ambiguities, -any float with integral value used as a key -is converted to its respective integer. -For instance, if you write a[2.0] = true, -the actual key inserted into the table will be the -integer 2. -(On the other hand, -2 and "2" are different Lua values and therefore -denote different table entries.) - - -

      -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 -of a given value (see §6.1). - - - - - -

      2.2 – Environments and the Global Environment

      - -

      -As will be discussed in §3.2 and §3.3.3, -any reference to a free name -(that is, a name not bound to any declaration) var -is syntactically translated to _ENV.var. -Moreover, every chunk is compiled in the scope of -an external local variable named _ENV (see §3.3.2), -so _ENV itself is never a free name in a chunk. - - -

      -Despite the existence of this external _ENV variable and -the translation of free names, -_ENV is a completely regular name. -In particular, -you can define new variables and parameters with that name. -Each reference to a free name uses the _ENV that is -visible at that point in the program, -following the usual visibility rules of Lua (see §3.5). - - -

      -Any table used as the value of _ENV is 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 global variable _G is initialized with this same value. -(_G is never used internally.) - - -

      -When Lua loads a chunk, -the default value for its _ENV upvalue -is the global environment (see load). -Therefore, by default, -free names in Lua code refer to entries in the global environment -(and, therefore, they are also called global variables). -Moreover, all standard libraries are loaded in the global environment -and some functions there operate on that 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.) - - - - - -

      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. -(When you use Lua standalone, -the lua application is the host program.) -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). - - -

      -Lua code can explicitly generate an error by calling the -error function. -If you need to catch errors in Lua, -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 whose error object is a string, -but programs may generate errors with -any value as the error object. -It is up to the Lua program or its host to handle such error objects. - - -

      -When you use xpcall or lua_pcall, -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. -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; -so, an error inside the message handler -will call the message handler again. -If this loop goes on for too long, -Lua breaks it and returns an appropriate message. - - - - - -

      2.4 – Metatables and Metamethods

      - -

      -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" of the value's metatable. -If it finds one, -Lua calls this function to perform the addition. - - -

      -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 -using the getmetatable function. - - -

      -You can replace the metatable of tables -using the setmetatable function. -You cannot change the metatable of other types from Lua -(except by using the debug library (§6.10)); -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). - - -

      -A metatable controls how an object behaves in -arithmetic operations, bitwise operations, -order comparisons, concatenation, length operation, calls, and indexing. -A metatable also can define a function to be called -when a userdata or a table is garbage collected (§2.5). - - -

      -A detailed list of events controlled by metatables is given next. -Each operation is identified by its corresponding event name. -The key for each event is a string with its name prefixed by -two underscores, '__'; -for instance, the key for operation "add" is the -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), -the metamethod is computed and called with a dummy second operand, -equal to the first one. -This extra operand is only to simplify Lua's internals -(by making these operators behave like a binary operation) -and may be removed in future versions. -(For most uses this extra operand is irrelevant.) - - - -

        - -
      • "add": -the + operation. - -If any operand for an addition is not a number -(nor a string coercible to a number), -Lua will try to call a metamethod. -First, Lua will check the first operand (even if it is valid). -If that operand does not define a metamethod for the "__add" event, -then Lua will check the second operand. -If Lua can find a metamethod, -it calls the metamethod with the two operands as arguments, -and the result of the call -(adjusted to one value) -is the result of the operation. -Otherwise, -it raises an error. -
      • - -
      • "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. -
      • - -
      • "pow": -the ^ (exponentiation) operation. - -Behavior similar to the "add" operation. -
      • - -
      • "unm": -the - (unary minus) operation. - -Behavior similar to the "add" operation. -
      • - -
      • "idiv": -the // (floor division) operation. - -Behavior similar to the "add" operation. -
      • - -
      • "band": -the & (bitwise and) operation. - -Behavior similar to the "add" operation, -except that Lua will try a metamethod -if any operator is neither an integer -nor a value coercible to an integer (see §3.4.3). -
      • - -
      • "bor": -the | (bitwise or) operation. - -Behavior similar to the "band" operation. -
      • - -
      • "bxor": -the ~ (bitwise exclusive or) operation. - -Behavior similar to the "band" operation. -
      • - -
      • "bnot": -the ~ (bitwise unary not) operation. - -Behavior similar to the "band" operation. -
      • - -
      • "shl": -the << (bitwise left shift) operation. - -Behavior similar to the "band" operation. -
      • - -
      • "shr": -the >> (bitwise right shift) operation. - -Behavior similar to the "band" operation. -
      • - -
      • "concat": -the .. (concatenation) operation. - -Behavior similar to the "add" operation, -except that Lua will try a metamethod -if any operator is neither a string nor a number -(which is always coercible to a string). -
      • - -
      • "len": -the # (length) operation. - -If the object is not a string, -Lua will try its metamethod. -If there is a metamethod, -Lua calls it with the object as argument, -and the result of the call -(always adjusted to one value) -is the result of the operation. -If there is no metamethod but the object is a table, -then Lua uses the table length operation (see §3.4.7). -Otherwise, Lua raises an error. -
      • - -
      • "eq": -the == (equal) operation. - -Behavior similar to the "add" operation, -except that Lua will try a metamethod only when the values -being compared are either both tables or both full userdata -and they are not primitively equal. -The result of the call is always converted to a boolean. -
      • - -
      • "lt": -the < (less than) operation. - -Behavior similar to the "add" operation, -except that Lua will try a metamethod only when the values -being compared are neither both numbers nor both strings. -The result of the call is always converted to a boolean. -
      • - -
      • "le": -the <= (less equal) operation. - -Unlike other operations, -The less-equal operation can use two different events. -First, Lua looks for the "__le" metamethod in both operands, -like in the "lt" operation. -If it cannot find such a metamethod, -then it will try the "__lt" event, -assuming that a <= b is equivalent to not (b < a). -As with the other comparison operators, -the result is always a boolean. -
      • - -
      • "index": -The indexing access table[key]. - -This event happens when table is not a table or -when key is not present in table. -The metamethod is looked up in table. - - -

        -Despite the name, -the metamethod for this event can be either a function or a table. -If it is a function, -it is called with table and key as arguments. -If it is a table, -the final result is the result of indexing this table with key. -(This indexing is regular, not raw, -and therefore can trigger another metamethod.) -

      • - -
      • "newindex": -The indexing assignment table[key] = value. - -Like the index event, -this event happens when table is not a table or -when key is not present in table. -The metamethod is looked up in table. - - -

        -Like with indexing, -the metamethod for this event can be either a function or a table. -If it is a function, -it is called with table, key, and value as arguments. -If it is a table, -Lua does an indexing assignment to this table with the same key and value. -(This assignment is regular, not raw, -and therefore can trigger another metamethod.) - - -

        -Whenever there is a "newindex" metamethod, -Lua does not perform the primitive assignment. -(If necessary, -the metamethod itself can call rawset -to do the assignment.) -

      • - -
      • "call": -The call operation func(args). - -This event happens when Lua tries to call a non-function value -(that is, func is not a function). -The metamethod is looked up in func. -If present, -the metamethod is called with func as its first argument, -followed by the arguments of the original call (args). -
      • - -
      - - - - -

      2.5 – Garbage Collection

      - -

      -Lua performs automatic memory management. -This means that -you do not have to worry about allocating memory for new objects -or 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: -strings, tables, userdata, functions, threads, internal structures, 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 -(e.g., a value of 100 means an internal value of 1). - - -

      -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. - - -

      -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. -You should not use values smaller than 100, -because they make the collector too slow and -can result in the collector never finishing a cycle. -The default is 200, -which means that the collector runs at "twice" -the speed of memory allocation. - - -

      -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. -You can also use these functions to control -the collector directly (e.g., stop and restart it). - - - -

      2.5.1 – Garbage-Collection Metamethods

      - -

      -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 -(such as closing files, network or database connections, -or freeing your own memory). - - -

      -For an object (table or userdata) to be finalized when collected, -you must mark it for finalization. - -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 object will not be marked for finalization. -However, after an object has been marked, -you can freely change the __gc field of its metatable. - - -

      -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 goes through that list: -For each object in the list, -it checks the object's __gc metamethod; -if it is a function, -Lua calls it with the object as its single argument. -If the metamethod is not a function, -Lua simply ignores it. - - -

      -At the end of each garbage-collection cycle, -the finalizers for objects are called in -the reverse order that the objects were marked for finalization, -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 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, -that object (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 the resurrection is permanent. -Moreover, if the finalizer marks a finalizing object for finalization again, -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 is unreachable and not marked for finalization. - - -

      -When you close a state (see lua_close), -Lua calls the finalizers of all objects marked for finalization, -following the reverse order that they were marked. -If any finalizer marks objects for collection during that phase, -these marks have no effect. - - - - - -

      2.5.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 -__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. - - -

      -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 through its value, -the pair is removed. - - -

      -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 -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 their associated values are collected). -Although strings are subject to garbage collection, -they do not have an explicit construction, -and therefore are not removed from weak tables. - - -

      -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. - - - - - - - -

      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. - - -

      -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. - - -

      -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, -the coroutine starts its execution, -at the first line of its main function. -Extra arguments passed to coroutine.resume are passed -as arguments to the coroutine's 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 case of normal termination, -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. - - -

      -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. - - -

      -As an example of how coroutines work, -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
      -
      - -

      -You can also create and manipulate coroutines through the C API: -see functions lua_newthread, lua_resume, -and lua_yield. - - - - - -

      3 – 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. - - -

      -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 §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. - - -

      -Names -(also called identifiers) -in Lua can be any string of letters, -digits, and underscores, -not beginning with a digit. -Identifiers are used to name variables, table fields, and labels. - - -

      -The following keywords are reserved -and cannot be used as names: - - -

      -     and       break     do        else      elseif    end
      -     false     for       function  goto      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, -programs should avoid creating -names that start with an underscore followed by -one or more uppercase letters (such as _VERSION). - - -

      -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 '\z' skips the following span -of white-space characters, -including line breaks; -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. - - -

      -Strings in Lua can contain any 8-bit value, including embedded zeros, -which can be specified as '\0'. -More generally, -we can specify any byte in a literal string 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 sequence is to be followed by a digit, -it must be expressed using exactly three digits.) - - -

      -The UTF-8 encoding of a Unicode character -can be inserted in a literal string with -the escape sequence \u{XXX} -(note the mandatory enclosing brackets), -where XXX is a sequence of one or more hexadecimal digits -representing the character code point. - - -

      -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 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 same 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. - - -

      -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. - - -

      -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 (or numeral) -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 'p' or 'P'. -A numeric constant with a fractional dot or an exponent -denotes a float; -otherwise it denotes an integer. -Examples of valid integer constants are - -

      -     3   345   0xff   0xBEBADA
      -

      -Examples of valid float constants are - -

      -     3.0     3.1416     314.16e-2     0.31416E1     34e1
      -     0x0.1E  0xA23p-4   0X1.921FB54442D18P+1
      -
      - -

      -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. - - - - - -

      3.2 – 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 function's formal parameter, -which is a particular kind of local variable): - -

      -	var ::= Name
      -

      -Name denotes identifiers, as defined in §3.1. - - -

      -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. - - -

      -Square brackets are used to index a table: - -

      -	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 -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 syntax var.Name is just syntactic sugar for -var["Name"]: - -

      -	var ::= prefixexp ‘.’ Name
      -
      - -

      -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). - - - - - -

      3.3 – 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. - - - -

      3.3.1 – Blocks

      - -

      -A block is a list of statements, -which are executed sequentially: - -

      -	block ::= {stat}
      -

      -Lua has empty statements -that allow you to separate statements with semicolons, -start a block with a semicolon -or write two semicolons in sequence: - -

      -	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: - -

      -	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 statement in the middle -of another block (see §3.3.4). - - - - - -

      3.3.2 – Chunks

      - -

      -The unit of compilation 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 -(see §3.4.11). -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). -The resulting function always has _ENV as its only upvalue, -even if it does not use that variable. - - -

      -A chunk can be stored in a file or in a string inside the host program. -To execute a chunk, -Lua first loads it, -precompiling the chunk's code into instructions for a virtual machine, -and then Lua executes the compiled code -with an interpreter for the virtual machine. - - -

      -Chunks can also be precompiled into binary form; -see program luac and function string.dump for details. -Programs in source and compiled forms are interchangeable; -Lua automatically detects the file type and acts accordingly (see load). - - - - - -

      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: - -

      -	stat ::= varlist ‘=’ explist
      -	varlist ::= var {‘,’ var}
      -	explist ::= exp {‘,’ exp}
      -

      -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 the assignments are 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, -and - -

      -     x, y, z = y, z, x
      -

      -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.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.) - - -

      -An assignment to a global name x = val -is equivalent to the assignment -_ENV.x = val (see §2.2). - - - - - -

      3.3.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 §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. - - -

      -The goto statement transfers the program control to a label. -For syntactical reasons, -labels in Lua are considered statements too: - - - -

      -	stat ::= goto Name
      -	stat ::= label
      -	label ::= ‘::’ 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. - - -

      -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
      -

      -A break ends the innermost enclosing loop. - - -

      -The return statement is used to return values -from a function or a chunk -(which is an anonymous function). - -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 idiom do return end, -because now return is the last statement in its (inner) block. - - - - - -

      3.3.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 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
      -       var = var - step
      -       while true do
      -         var = var + step
      -         if (step >= 0 and var > limit) or (step < 0 and var < limit) then
      -           break
      -         end
      -         local v = var
      -         block
      -       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. -
      • - -
      • -You can use break and goto to exit a for loop. -
      • - -
      • -The loop variable v is local to the loop body. -If you need its value after the loop, -assign it to another variable before exiting the loop. -
      • - -
      - -

      -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}
      -

      -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)
      -         if var_1 == nil then break end
      -         var = var_1
      -         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. -
      • - -
      - - - - -

      3.3.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 §3.4.10. - - - - - -

      3.3.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 §3.3.3). -Otherwise, all variables are initialized with nil. - - -

      -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 visibility rules for local variables are explained in §3.5. - - - - - - - -

      3.4 – Expressions

      - -

      -The basic expressions in Lua are the following: - -

      -	exp ::= prefixexp
      -	exp ::= nil | false | true
      -	exp ::= Numeral
      -	exp ::= LiteralString
      -	exp ::= functiondef
      -	exp ::= tableconstructor
      -	exp ::= ‘...’
      -	exp ::= exp binop exp
      -	exp ::= unop exp
      -	prefixexp ::= var | functioncall | ‘(’ exp ‘)’
      -
      - -

      -Numerals and literal strings are explained in §3.1; -variables are explained in §3.2; -function definitions are explained in §3.4.11; -function calls are explained in §3.4.10; -table constructors are explained in §3.4.9. -Vararg expressions, -denoted by three dots ('...'), can only be used when -directly inside a vararg function; -they are explained in §3.4.11. - - -

      -Binary operators comprise arithmetic operators (see §3.4.1), -bitwise operators (see §3.4.2), -relational operators (see §3.4.4), logical operators (see §3.4.5), -and the concatenation operator (see §3.4.6). -Unary operators comprise the unary minus (see §3.4.1), -the unary bitwise not (see §3.4.2), -the unary logical not (see §3.4.5), -and the unary length operator (see §3.4.7). - - -

      -Both function calls and vararg expressions can result in multiple values. -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 expression is enclosed in parentheses). -In all other contexts, -Lua adjusts the result list to one element, -either discarding all values except the first one -or adding a single nil if there are no values. - - -

      -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 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.) - - - -

      3.4.1 – Arithmetic Operators

      -Lua supports the following arithmetic operators: - -

        -
      • +: addition
      • -
      • -: subtraction
      • -
      • *: multiplication
      • -
      • /: float division
      • -
      • //: floor division
      • -
      • %: modulo
      • -
      • ^: exponentiation
      • -
      • -: unary minus
      • -
      - -

      -With the exception of float 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.3), -then they are converted to floats, -the operation is performed following the usual rules -for floating-point arithmetic -(usually the IEEE 754 standard), -and the result is a float. - - -

      -Float division (/) and exponentiation -always convert their operands to floats -and the result is always a float. -Exponentiation uses the ISO C function pow, -so that it works for non-integer exponents too. - - -

      -Floor division (//) is a division -that rounds the quotient towards minus infinite, -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). - - -

      -In case of overflows in integer arithmetic, -all operations wrap around, -according to the usual rules of two-complement arithmetic. -(In other words, -they return the unique representable integer -that is equal modulo 264 to the mathematical result.) - - - -

      3.4.2 – Bitwise Operators

      -Lua supports the following bitwise operators: - -

        -
      • &: bitwise and
      • -
      • |: bitwise or
      • -
      • ~: bitwise exclusive or
      • -
      • >>: right shift
      • -
      • <<: left shift
      • -
      • ~: unary bitwise not
      • -
      - -

      -All bitwise operations convert its operands to integers -(see §3.4.3), -operate on all bits of those integers, -and result in an integer. - - -

      -Both right and left shifts fill the vacant bits with zeros. -Negative displacements shift to the other direction; -displacements with absolute values equal to or higher than -the number of bits in an integer -result in zero (as all bits are shifted out). - - - - - -

      3.4.3 – Coercions and Conversions

      -Lua provides some automatic conversions between some -types and representations at run time. -Bitwise operators always convert float operands to integers. -Float division and exponentiation -always convert integer operands to floats. -All other arithmetic operations applied to mixed numbers -(integers and floats) convert the integer operand to a float; -this is called the usual rule. -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. - - -

      -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 -the nearest lower representable value. -This kind of conversion never fails. - - -

      -The conversion from float to integer -checks whether the float has an exact representation as an integer -(that is, the float has an integral value and -it is in the range of integer representation). -If it does, that representation is the result. -Otherwise, the conversion fails. - - -

      -The conversion from strings to numbers goes as follows: -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. - - -

      -The conversion from numbers to strings uses a -non-specified human-readable format. -For complete control over how numbers are converted to strings, -use the format function from the string library -(see string.format). - - - - - -

      3.4.4 – Relational Operators

      -Lua supports the following relational operators: - -

        -
      • ==: equality
      • -
      • ~=: inequality
      • -
      • <: less than
      • -
      • >: greater than
      • -
      • <=: less or equal
      • -
      • >=: greater or equal
      • -

      -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. -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. - - -

      -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, 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. - - -

      -You can change the way that Lua compares tables and userdata -by using the "eq" metamethod (see §2.4). - - -

      -Equality comparisons do not 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. - - -

      -The operator ~= is exactly the negation of equality (==). - - -

      -The order operators work as follows. -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" -metamethod (see §2.4). -A comparison a > b is translated to b < a -and a >= b is translated to b <= a. - - - - - -

      3.4.5 – 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-circuit evaluation; -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
      -

      -(In this manual, ---> indicates the result of the preceding expression.) - - - - - -

      3.4.6 – 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 described in §3.4.3. -Otherwise, the __concat metamethod is called (see §2.4). - - - - - -

      3.4.7 – The Length Operator

      - -

      -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). - - -

      -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, -the set of its positive numeric keys is equal to {1..n} -for some non-negative 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 positive numeric keys of that table.) -Note, however, that non-numeric keys do not interfere -with whether a table is a sequence. - - - - - -

      3.4.8 – Precedence

      -Operator precedence in Lua follows the table below, -from lower to higher priority: - -

      -     or
      -     and
      -     <     >     <=    >=    ~=    ==
      -     |
      -     ~
      -     &
      -     <<    >>
      -     ..
      -     +     -
      -     *     /     //    %
      -     unary operators (not   #     -     ~)
      -     ^
      -

      -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.4.9 – 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 ::= ‘,’ | ‘;’
      -
      - -

      -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 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
      -
      - -

      -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.10). - - -

      -The field list can have an optional trailing separator, -as a convenience for machine-generated code. - - - - - -

      3.4.10 – 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). - - -

      -The form - -

      -	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. - - -

      -Arguments have the following syntax: - -

      -	args ::= ‘(’ [explist] ‘)’
      -	args ::= tableconstructor
      -	args ::= LiteralString
      -

      -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. - - -

      -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.11 – Function Definitions

      - -

      -The syntax for function definition is - -

      -	functiondef ::= function funcbody
      -	funcbody ::= ‘(’ [parlist] ‘)’ 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 () body end
      -

      -translates to - -

      -     f = function () body end
      -

      -The statement - -

      -     function t.a.b.c.f () body end
      -

      -translates to - -

      -     t.a.b.c.f = function () body end
      -

      -The statement - -

      -     local function f () body end
      -

      -translates to - -

      -     local f; f = function () body end
      -

      -not to - -

      -     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, -whose value has type function. -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) -is the final value of the expression. - - -

      -Parameters act as local variables that are -initialized with the argument values: - -

      -	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 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
      -
      - -

      -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. - - -

      - -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, -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 - -

      -     t.a.b.c.f = function (self, params) body end
      -
      - - - - - - -

      3.5 – Visibility Rules

      - -

      - -Lua is a lexically scoped language. -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: - -

      -     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. -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. - - - - - -

      4 – 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. -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. - - -

      -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 the macro LUA_USE_APICHECK defined. - - - -

      4.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. -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, -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 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) -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. - - - - - -

      4.2 – Stack Size

      - -

      -When you interact with the 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 ensure that the stack has enough space for pushing new elements. - - -

      -Whenever Lua calls C, -it ensures that the stack has space for -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. - - -

      -When you call a Lua function -without a fixed number of results (see lua_call), -Lua ensures that the stack has enough space for all results, -but it does not ensure any extra space. -So, before pushing anything in the stack after such a call -you should use lua_checkstack. - - - - - -

      4.3 – Valid and Acceptable Indices

      - -

      -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 -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 -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 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. -(Note that 0 is never an acceptable index.) -Except when noted otherwise, -functions in the API work with acceptable indices. - - -

      -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, -which behaves like a nil value. - - - - - -

      4.4 – C Closures

      - -

      -When a C function is created, -it is possible to associate some values with it, -thus creating a C closure -(see lua_pushcclosure); -these values are called upvalues and are -accessible to the function whenever it 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. -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. - - - - - -

      4.5 – Registry

      - -

      -Lua provides a 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. -Any C library can store data into this table, -but it must 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, -or any Lua object created by your code. -As with variable names, -string keys starting with an underscore followed by -uppercase letters are reserved for Lua. - - -

      -The integer keys in the registry are used -by the reference mechanism (see luaL_ref) -and by some predefined values. -Therefore, integer keys must not be used for other purposes. - - -

      -When you create a new Lua state, -its registry comes with some predefined values. -These predefined values are indexed with integer keys -defined as constants in lua.h. -The following constants are defined: - -

        -
      • 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 -the global environment. -
      • -
      - - - - -

      4.6 – Error Handling in C

      - -

      -Internally, Lua uses the C longjmp facility to handle errors. -(Lua will use exceptions if you compile it as C++; -search for LUAI_THROW in the source code for details.) -When Lua faces any error -(such as a memory allocation error, 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 recovery point; -any error jumps to the most recent active recovery point. - - -

      -If an error happens outside any protected environment, -Lua calls a panic function (see lua_atpanic) -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 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 must first check the available space (see §4.2). - - -

      -Most functions in the API can raise an error, -for instance due to a memory allocation error. -The documentation for each function indicates whether -it can raise errors. - - -

      -Inside a C function you can raise an error by calling lua_error. - - - - - -

      4.7 – Handling Yields in C

      - -

      -Internally, Lua uses the C longjmp facility to yield a coroutine. -Therefore, if a C function foo calls an API function -and this API function yields -(directly or indirectly by calling another function that yields), -Lua cannot return to foo any more, -because the longjmp removes its frame from the C stack. - - -

      -To avoid this kind of problem, -Lua raises an error whenever it tries to yield across an API call, -except for three functions: -lua_yieldk, lua_callk, and lua_pcallk. -All those functions receive a continuation function -(as a parameter named k) to continue execution after a yield. - - -

      -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, -which we will call the callee function, -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.) - - -

      -Suppose the running thread yields while executing the callee function. -After the thread resumes, -it eventually will finish running the callee function. -However, -the callee function cannot return to the original function, -because its frame in the C stack was destroyed by the yield. -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 -of the original function. - - -

      -As an illustration, consider the following function: - -

      -     int original_function (lua_State *L) {
      -       ...     /* code 1 */
      -       status = lua_pcall(L, n, m, h);  /* calls Lua */
      -       ...     /* code 2 */
      -     }
      -

      -Now we want to allow -the Lua code being ran by lua_pcall to yield. -First, we can rewrite our function like here: - -

      -     int k (lua_State *L, int status, lua_KContext ctx) {
      -       ...  /* code 2 */
      -     }
      -     
      -     int original_function (lua_State *L) {
      -       ...     /* code 1 */
      -       return k(L, lua_pcall(L, n, m, h), ctx);
      -     }
      -

      -In the above code, -the new function k is a -continuation function (with type lua_KFunction), -which should do all the work that the original function -was doing after calling lua_pcall. -Now, we must inform Lua that it must call k if the Lua code -begin running by lua_pcall gets interrupted in some way -(errors or yielding), -so we rewrite the code as here, -replacing lua_pcall by lua_pcallk: - -

      -     int original_function (lua_State *L) {
      -       ...     /* code 1 */
      -       return k(L, lua_pcallk(L, n, m, h, ctx2, k), ctx1);
      -     }
      -

      -Note the external, explicit call to the continuation: -Lua will call the continuation only if needed, that is, -in case of errors or resuming after an yield. -If the called function returns normally without ever yielding, -lua_pcallk (and lua_callk) will also return normally. -(Of course, instead of calling the continuation in that case, -you can do the equivalent work directly inside the original function.) - - -

      -Besides the Lua state, -the continuation function has two other parameters: -the final status of the call plus the context value (ctx) that -was passed originally to lua_pcallk. -(Lua does not use this context value; -it only passes this value from the original function to the -continuation function.) -For lua_pcallk, -the status is the same value that would be returned by lua_pcallk, -except that it is LUA_YIELD when being executed after an yield -(instead of LUA_OK). -For lua_yieldk and lua_callk, -the status is always LUA_YIELD when Lua calls the continuation. -(For these two functions, -Lua will not call the continuation in case of errors, -because they do not handle errors.) -Similarly, when using lua_callk, -you should call the continuation function -with LUA_OK as the status. -(For lua_yieldk, there is not much point in calling -directly the continuation function, -because lua_yieldk usually does not return.) - - -

      -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. -(For instance, -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 were the return -of the original function. - - - - - -

      4.8 – 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 can 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 raise errors: -'-' means the function never raises any error; -'e' means the function may raise errors; -'v' means the function may raise an error on purpose. - - - -


      lua_absindex

      -[-0, +0, –] -

      int 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,
      -                             size_t osize,
      -                             size_t nsize);
      - -

      -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, an opaque pointer passed to lua_newstate; -ptr, a pointer to the block being allocated/reallocated/freed; -osize, the original size of the block or some code about what -is being allocated; -and nsize, the new size of the block. - - -

      -When ptr is not NULL, -osize is the size of the block pointed by ptr, -that is, the size given when it was allocated or reallocated. - - -

      -When ptr is NULL, -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) -Lua is creating a new object of that type. -When osize is some other value, -Lua is allocating memory for something else. - - -

      -Lua assumes the following behavior from the allocator function: - - -

      -When nsize is zero, -the allocator must behave like free -and return NULL. - - -

      -When nsize is not zero, -the allocator must behave like realloc. -The allocator returns NULL -if and only if it cannot fulfill the request. -Lua assumes that the allocator never fails when -osize >= nsize. - - -

      -Here is a simple implementation for the allocator function. -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;  (void)osize;  /* not used */
      -       if (nsize == 0) {
      -         free(ptr);
      -         return NULL;
      -       }
      -       else
      -         return realloc(ptr, nsize);
      -     }
      -

      -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. -(Although Standard C does not ensure this behavior, -it seems to be a safe assumption.) - - - - - -


      lua_arith

      -[-(2|1), +1, e] -

      void lua_arith (lua_State *L, int op);
      - -

      -Performs an arithmetic or bitwise operation over the two values -(or one, in the case of negations) -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: - -

      - - - - -

      lua_atpanic

      -[-0, +0, –] -

      lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
      - -

      -Sets a new panic function and returns the old one (see §4.6). - - - - - -


      lua_call

      -[-(nargs+1), +nresults, e] -

      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 -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 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 -(with a longjmp). - - -

      -The following example shows how the host program can do the -equivalent to this Lua code: - -

      -     a = f("how", t.x, 14)
      -

      -Here it is in C: - -

      -     lua_getglobal(L, "f");                  /* function to be called */
      -     lua_pushliteral(L, "how");                       /* 1st argument */
      -     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_setglobal(L, "a");                         /* set global '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_callk

      -[-(nargs + 1), +nresults, e] -

      void lua_callk (lua_State *L,
      -                int nargs,
      -                int nresults,
      -                lua_KContext ctx,
      -                lua_KFunction k);
      - -

      -This function behaves exactly like lua_call, -but allows the called function to yield (see §4.7). - - - - - -


      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 -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. -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 -discarded 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 their sum: - -

      -     static int foo (lua_State *L) {
      -       int n = lua_gettop(L);    /* number of arguments */
      -       lua_Number sum = 0.0;
      -       int i;
      -       for (i = 1; i <= n; i++) {
      -         if (!lua_isnumber(L, i)) {
      -           lua_pushliteral(L, "incorrect argument");
      -           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

      -[-0, +0, –] -

      int lua_checkstack (lua_State *L, int n);
      - -

      -Ensures that the stack has space for at least n extra slots. -It returns false if it cannot fulfill the request, -either because it would cause the stack -to be larger than a fixed maximum size -(typically at least several thousand elements) or -because it cannot allocate memory for the extra space. -This function never shrinks the stack; -if the stack is already larger than the new size, -it is left unchanged. - - - - - -


      lua_close

      -[-0, +0, –] -

      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, -because all resources are naturally released when the host program ends. -On the other hand, long-running programs that create multiple states, -such as daemons or web servers, -will probably need to close states as soon as they are not needed. - - - - - -


      lua_compare

      -[-0, +0, e] -

      int lua_compare (lua_State *L, int index1, int index2, int op);
      - -

      -Compares two Lua values. -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. -Also returns 0 if any of the indices is not valid. - - -

      -The value of op must be one of the following constants: - -

        - -
      • LUA_OPEQ: compares for equality (==)
      • -
      • LUA_OPLT: compares for less than (<)
      • -
      • LUA_OPLE: compares for less or equal (<=)
      • - -
      - - - - -

      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 value on the stack -(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 §3.4.6). - - - - - -


      lua_copy

      -[-0, +0, –] -

      void lua_copy (lua_State *L, int fromidx, int toidx);
      - -

      -Copies the element at index fromidx -into the valid index toidx, -replacing the value at that position. -Values at other positions are not affected. - - - - - -


      lua_createtable

      -[-0, +1, e] -

      void lua_createtable (lua_State *L, int narr, int nrec);
      - -

      -Creates a new empty table and pushes it onto the stack. -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. - - - - - -


      lua_dump

      -[-0, +0, e] -

      int lua_dump (lua_State *L,
      -                        lua_Writer writer,
      -                        void *data,
      -                        int strip);
      - -

      -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, -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. - - -

      -If strip is true, -the binary representation is created without debug information -about the function. - - -

      -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_error

      -[-1, +0, v] -

      int lua_error (lua_State *L);
      - -

      -Generates a Lua error, -using the value at the top of the stack as the error object. -This function does a long jump, -and therefore never returns -(see luaL_error). - - - - - -


      lua_gc

      -[-0, +0, e] -

      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_GCSETPAUSE: -sets data as the new value -for the pause of the collector (see §2.5) -and returns the previous value of the pause. -
      • - -
      • LUA_GCSETSTEPMUL: -sets data as the new value for the step multiplier of -the collector (see §2.5) -and returns the previous value of the step multiplier. -
      • - -
      • LUA_GCISRUNNING: -returns a boolean that tells whether the collector is running -(i.e., not stopped). -
      • - -
      - -

      -For more details about these options, -see collectgarbage. - - - - - -


      lua_getallocf

      -[-0, +0, –] -

      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 given when the memory-allocator function was set. - - - - - -


      lua_getfield

      -[-0, +1, e] -

      int 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 index. -As in Lua, this function may trigger a metamethod -for the "index" event (see §2.4). - - -

      -Returns the type of the pushed value. - - - - - -


      lua_getextraspace

      -[-0, +0, –] -

      void *lua_getextraspace (lua_State *L);
      - -

      -Returns a pointer to a raw memory area associated with the -given Lua state. -The application can use this area for any purpose; -Lua does not use it for anything. - - -

      -Each new thread has this area initialized with a copy -of the area of the main thread. - - -

      -By default, this area has the size of a pointer to void, -but you can recompile Lua with a different size for this area. -(See LUA_EXTRASPACE in luaconf.h.) - - - - - -


      lua_getglobal

      -[-0, +1, e] -

      int lua_getglobal (lua_State *L, const char *name);
      - -

      -Pushes onto the stack the value of the global name. -Returns the type of that value. - - - - - -


      lua_geti

      -[-0, +1, e] -

      int lua_geti (lua_State *L, int index, lua_Integer i);
      - -

      -Pushes onto the stack the value t[i], -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). - - -

      -Returns the type of the pushed value. - - - - - -


      lua_getmetatable

      -[-0, +(0|1), –] -

      int lua_getmetatable (lua_State *L, int index);
      - -

      -If the value at the given index has a metatable, -the function pushes that metatable onto the stack and returns 1. -Otherwise, -the function returns 0 and pushes nothing on the stack. - - - - - -


      lua_gettable

      -[-1, +1, e] -

      int lua_gettable (lua_State *L, int index);
      - -

      -Pushes onto the stack the value t[k], -where t is the value at the given index -and k is the value at the top of the stack. - - -

      -This function pops the key from the stack, -pushing the resulting value in its place. -As in Lua, this function may trigger a metamethod -for the "index" event (see §2.4). - - -

      -Returns the type of the pushed value. - - - - - -


      lua_gettop

      -[-0, +0, –] -

      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; -in particular, 0 means an empty stack. - - - - - -


      lua_getuservalue

      -[-0, +1, –] -

      int lua_getuservalue (lua_State *L, int index);
      - -

      -Pushes onto the stack the Lua value associated with the userdata -at the given index. - - -

      -Returns the type of the pushed value. - - - - - -


      lua_insert

      -[-1, +1, –] -

      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. -This function cannot be called with a pseudo-index, -because a pseudo-index is not an actual stack position. - - - - - -


      lua_Integer

      -
      typedef ... lua_Integer;
      - -

      -The type of integers in Lua. - - -

      -By default this type is long long, -(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.) - - -

      -Lua also defines the constants -LUA_MININTEGER and LUA_MAXINTEGER, -with the minimum and the maximum values that fit in this type. - - - - - -


      lua_isboolean

      -[-0, +0, –] -

      int lua_isboolean (lua_State *L, int index);
      - -

      -Returns 1 if the value at the given index is a boolean, -and 0 otherwise. - - - - - -


      lua_iscfunction

      -[-0, +0, –] -

      int lua_iscfunction (lua_State *L, int index);
      - -

      -Returns 1 if the value at the given index is a C function, -and 0 otherwise. - - - - - -


      lua_isfunction

      -[-0, +0, –] -

      int lua_isfunction (lua_State *L, int index);
      - -

      -Returns 1 if the value at the given index is a function -(either C or Lua), and 0 otherwise. - - - - - -


      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);
      - -

      -Returns 1 if the value at the given index is a light userdata, -and 0 otherwise. - - - - - -


      lua_isnil

      -[-0, +0, –] -

      int lua_isnil (lua_State *L, int index);
      - -

      -Returns 1 if the value at the given index is nil, -and 0 otherwise. - - - - - -


      lua_isnone

      -[-0, +0, –] -

      int lua_isnone (lua_State *L, int index);
      - -

      -Returns 1 if the given index is not valid, -and 0 otherwise. - - - - - -


      lua_isnoneornil

      -[-0, +0, –] -

      int lua_isnoneornil (lua_State *L, int index);
      - -

      -Returns 1 if the given index is not valid -or if the value at this index is nil, -and 0 otherwise. - - - - - -


      lua_isnumber

      -[-0, +0, –] -

      int lua_isnumber (lua_State *L, int index);
      - -

      -Returns 1 if the value at the given index is a number -or a string convertible to a number, -and 0 otherwise. - - - - - -


      lua_isstring

      -[-0, +0, –] -

      int lua_isstring (lua_State *L, int index);
      - -

      -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. - - - - - -


      lua_istable

      -[-0, +0, –] -

      int lua_istable (lua_State *L, int index);
      - -

      -Returns 1 if the value at the given index is a table, -and 0 otherwise. - - - - - -


      lua_isthread

      -[-0, +0, –] -

      int lua_isthread (lua_State *L, int index);
      - -

      -Returns 1 if the value at the given index is a thread, -and 0 otherwise. - - - - - -


      lua_isuserdata

      -[-0, +0, –] -

      int lua_isuserdata (lua_State *L, int index);
      - -

      -Returns 1 if the value at the given index is a userdata -(either full or light), and 0 otherwise. - - - - - -


      lua_isyieldable

      -[-0, +0, –] -

      int lua_isyieldable (lua_State *L);
      - -

      -Returns 1 if the given coroutine can yield, -and 0 otherwise. - - - - - -


      lua_KContext

      -
      typedef ... lua_KContext;
      - -

      -The type for continuation-function contexts. -It must be a numerical type. -This type is defined as intptr_t -when intptr_t is available, -so that it can store pointers too. -Otherwise, it is defined as ptrdiff_t. - - - - - -


      lua_KFunction

      -
      typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);
      - -

      -Type for continuation functions (see §4.7). - - - - - -


      lua_len

      -[-0, +1, e] -

      void lua_len (lua_State *L, int index);
      - -

      -Returns the length of the value at the given index. -It is equivalent to the '#' operator in Lua (see §3.4.7) and -may trigger a metamethod for the "length" event (see §2.4). -The result is pushed on the stack. - - - - - -


      lua_load

      -[-0, +1, –] -

      int lua_load (lua_State *L,
      -              lua_Reader reader,
      -              void *data,
      -              const char *chunkname,
      -              const char *mode);
      - -

      -Loads a Lua chunk without running it. -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: - -

        - -
      • LUA_OK: no errors;
      • - -
      • LUA_ERRSYNTAX: -syntax error during precompilation;
      • - -
      • LUA_ERRMEM: -memory allocation error;
      • - -
      • 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.) -
      • - -
      - -

      -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. - - -

      -The chunkname argument gives a name to the chunk, -which is used for error messages and in debug information (see §4.9). - - -

      -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". - - -

      -lua_load uses the stack internally, -so the reader function must always leave the stack -unmodified when returning. - - -

      -If the resulting function has upvalues, -its 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). -Other upvalues are initialized with nil. - - - - - -


      lua_newstate

      -[-0, +0, –] -

      lua_State *lua_newstate (lua_Alloc f, void *ud);
      - -

      -Creates a new thread running in a new, independent 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. -The second argument, ud, is an opaque pointer that Lua -passes to the allocator in every call. - - - - - -


      lua_newtable

      -[-0, +1, e] -

      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). - - - - - -


      lua_newthread

      -[-0, +1, e] -

      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 thread returned by this function shares with the original thread -its global environment, -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

      -[-0, +1, e] -

      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. -The host program can freely use this memory. - - - - - -


      lua_next

      -[-1, +(2|0), e] -

      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: - -

      -     /* table is in the stack at index 't' */
      -     lua_pushnil(L);  /* first key */
      -     while (lua_next(L, t) != 0) {
      -       /* 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)));
      -       /* removes 'value'; keeps 'key' for next iteration */
      -       lua_pop(L, 1);
      -     }
      -
      - -

      -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 may change -the value at the given index; -this confuses the next call to lua_next. - - -

      -See function next for the caveats of modifying -the table during its traversal. - - - - - -


      lua_Number

      -
      typedef double lua_Number;
      - -

      -The type of floats in Lua. - - -

      -By default this type is double, -but that can be changed to a single float. -(See LUA_REAL in luaconf.h.) - - - - - -


      lua_numbertointeger

      -
      int lua_numbertointeger (lua_Number n, lua_Integer *p);
      - -

      -Converts a Lua float to a Lua integer. -This macro assumes that n has an integral value. -If that value is within the range of Lua integers, -it is converted to an integer and assigned to *p. -The macro results in a boolean indicating whether the -conversion was successful. -(Note that this range test can be tricky to do -correctly without this macro, -due to roundings.) - - -

      -This macro may evaluate its arguments more than once. - - - - - -


      lua_pcall

      -[-(nargs + 1), +(nresults|1), –] -

      int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);
      - -

      -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 msgh is 0, -then the error message returned on the stack -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.) -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. - - -

      -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. - - -

      -The lua_pcall function returns one of the following constants -(defined in lua.h): - -

        - -
      • LUA_OK (0): -success.
      • - -
      • LUA_ERRRUN: -a runtime error. -
      • - -
      • LUA_ERRMEM: -memory allocation error. -For such errors, Lua does not call the message handler. -
      • - -
      • LUA_ERRERR: -error while running the message handler. -
      • - -
      • LUA_ERRGCMM: -error while running a __gc metamethod. -(This error typically has no relation with the function being called.) -
      • - -
      - - - - -

      lua_pcallk

      -[-(nargs + 1), +(nresults|1), –] -

      int lua_pcallk (lua_State *L,
      -                int nargs,
      -                int nresults,
      -                int errfunc,
      -                lua_KContext ctx,
      -                lua_KFunction k);
      - -

      -This function behaves exactly like lua_pcall, -but allows the called function to yield (see §4.7). - - - - - -


      lua_pop

      -[-n, +0, –] -

      void lua_pop (lua_State *L, int n);
      - -

      -Pops n elements from the stack. - - - - - -


      lua_pushboolean

      -[-0, +1, –] -

      void lua_pushboolean (lua_State *L, int b);
      - -

      -Pushes a boolean value with value b onto the stack. - - - - - -


      lua_pushcclosure

      -[-n, +1, e] -

      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 §4.4); -these values are then accessible to the function whenever it is called. -To associate values with a C function, -first these values must 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, -with the argument n telling how many values will be -associated with the function. -lua_pushcclosure also pops these values from the stack. - - -

      -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 never raises a memory error. - - - - - -


      lua_pushcfunction

      -[-0, +1, –] -

      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 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 -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. - - - - - -


      lua_pushfstring

      -[-0, +1, e] -

      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 ISO 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 -(and deallocation, through garbage collection). -
      • - -
      • -The conversion specifiers are quite restricted. -There are no flags, widths, or precisions. -The conversion specifiers can only be -'%%' (inserts the character '%'), -'%s' (inserts a zero-terminated string, with no size restrictions), -'%f' (inserts a lua_Number), -'%L' (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 -'%U' (inserts a long int as a UTF-8 byte sequence). -
      • - -
      - - - - -

      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);
      - -

      -Pushes an integer with value n onto the stack. - - - - - -


      lua_pushlightuserdata

      -[-0, +1, –] -

      void lua_pushlightuserdata (lua_State *L, void *p);
      - -

      -Pushes a light userdata onto the stack. - - -

      -Userdata represent C values in Lua. -A light userdata represents a pointer, a void*. -It is a value (like a number): -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. - - - - - -


      lua_pushliteral

      -[-0, +1, e] -

      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. - - - - - -


      lua_pushlstring

      -[-0, +1, e] -

      const char *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 any binary data, -including embedded zeros. - - -

      -Returns a pointer to the internal copy of the string. - - - - - -


      lua_pushnil

      -[-0, +1, –] -

      void lua_pushnil (lua_State *L);
      - -

      -Pushes a nil value onto the stack. - - - - - -


      lua_pushnumber

      -[-0, +1, –] -

      void lua_pushnumber (lua_State *L, lua_Number n);
      - -

      -Pushes a float with value n onto the stack. - - - - - -


      lua_pushstring

      -[-0, +1, e] -

      const char *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. - - -

      -Returns a pointer to the internal copy of the string. - - -

      -If s is NULL, pushes nil and returns NULL. - - - - - -


      lua_pushthread

      -[-0, +1, –] -

      int lua_pushthread (lua_State *L);
      - -

      -Pushes the thread represented by L onto the stack. -Returns 1 if this thread is the main thread of its state. - - - - - -


      lua_pushvalue

      -[-0, +1, –] -

      void lua_pushvalue (lua_State *L, int index);
      - -

      -Pushes a copy of the element at the given index -onto the stack. - - - - - -


      lua_pushvfstring

      -[-0, +1, e] -

      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

      -[-0, +0, –] -

      int lua_rawequal (lua_State *L, int index1, int index2);
      - -

      -Returns 1 if the two values in indices index1 and -index2 are primitively equal -(that is, without calling metamethods). -Otherwise returns 0. -Also returns 0 if any of the indices are not valid. - - - - - -


      lua_rawget

      -[-1, +1, –] -

      int lua_rawget (lua_State *L, int index);
      - -

      -Similar to lua_gettable, but does a raw access -(i.e., without metamethods). - - - - - -


      lua_rawgeti

      -[-0, +1, –] -

      int lua_rawgeti (lua_State *L, int index, lua_Integer n);
      - -

      -Pushes onto the stack the value t[n], -where t is the table at the given index. -The access is raw; -that is, it does not invoke metamethods. - - -

      -Returns the type of the pushed value. - - - - - -


      lua_rawgetp

      -[-0, +1, –] -

      int 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 index and -k is the pointer p represented as a light userdata. -The access is raw; -that is, it does not invoke metamethods. - - -

      -Returns the type of the pushed value. - - - - - -


      lua_rawlen

      -[-0, +0, –] -

      size_t lua_rawlen (lua_State *L, int 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; -for userdata, this is the size of the block of memory allocated -for the userdata; -for other values, it is 0. - - - - - -


      lua_rawset

      -[-2, +0, e] -

      void lua_rawset (lua_State *L, int index);
      - -

      -Similar to lua_settable, but does a raw assignment -(i.e., without metamethods). - - - - - -


      lua_rawseti

      -[-1, +0, e] -

      void lua_rawseti (lua_State *L, int index, lua_Integer i);
      - -

      -Does the equivalent of t[i] = v, -where t is the table at the given 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_rawsetp

      -[-1, +0, e] -

      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 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,
      -                                    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. -The block must exist until the reader function is called again. -To signal the end of the chunk, -the reader must return NULL or set size to zero. -The reader function may return pieces of any size greater than zero. - - - - - -


      lua_register

      -[-0, +0, e] -

      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

      -[-1, +0, –] -

      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. -This function cannot be called with a pseudo-index, -because a pseudo-index is not an actual stack position. - - - - - -


      lua_replace

      -[-1, +0, –] -

      void lua_replace (lua_State *L, int index);
      - -

      -Moves the top element into the given valid index -without shifting any element -(therefore replacing the value at the given index), -and then pops the top element. - - - - - -


      lua_resume

      -[-?, +?, –] -

      int lua_resume (lua_State *L, lua_State *from, int nargs);
      - -

      -Starts and resumes a coroutine in a given thread. - - -

      -To start a coroutine, -you push onto the thread stack the main function plus any arguments; -then you call lua_resume, -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. -lua_resume returns -LUA_YIELD if the coroutine yields, -LUA_OK 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. -The error message is on the top of the stack. - - -

      -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. - - -

      -The parameter from represents the coroutine that is resuming L. -If there is no such coroutine, -this parameter can be NULL. - - - - - -


      lua_rotate

      -[-0, +0, –] -

      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, -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. - - - - - -


      lua_setallocf

      -[-0, +0, –] -

      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_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 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.4). - - - - - -


      lua_setglobal

      -[-1, +0, e] -

      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. - - - - - -


      lua_seti

      -[-1, +0, e] -

      void lua_seti (lua_State *L, int index, lua_Integer n);
      - -

      -Does the equivalent to t[n] = v, -where t is the value at the given 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.4). - - - - - -


      lua_setmetatable

      -[-1, +0, –] -

      void 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 index. - - - - - -


      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 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.4). - - - - - -


      lua_settop

      -[-?, +?, –] -

      void lua_settop (lua_State *L, int index);
      - -

      -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. -If index is 0, then all stack elements are removed. - - - - - -


      lua_setuservalue

      -[-1, +0, –] -

      void lua_setuservalue (lua_State *L, int index);
      - -

      -Pops a value 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;
      - -

      -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 accessible through this structure. - - -

      -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. - - - - - -


      lua_status

      -[-0, +0, –] -

      int lua_status (lua_State *L);
      - -

      -Returns the status of the thread L. - - -

      -The status can be 0 (LUA_OK) for a normal thread, -an error code if the thread finished the execution -of a lua_resume with an error, -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 coroutine). - - - - - -


      lua_stringtonumber

      -[-0, +1, –] -

      size_t lua_stringtonumber (lua_State *L, const char *s);
      - -

      -Converts the zero-terminated string s to a number, -pushes that number into the stack, -and returns the total size of the string, -that is, its length plus one. -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. -(Note that the result can be used as a boolean, -true if the conversion succeeds.) - - - - - -


      lua_toboolean

      -[-0, +0, –] -

      int lua_toboolean (lua_State *L, int index);
      - -

      -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. -(If you want to accept only actual boolean values, -use lua_isboolean to test the value's type.) - - - - - -


      lua_tocfunction

      -[-0, +0, –] -

      lua_CFunction lua_tocfunction (lua_State *L, int index);
      - -

      -Converts a value at the given index to a C function. -That value must be a C function; -otherwise, returns NULL. - - - - - -


      lua_tointeger

      -[-0, +0, –] -

      lua_Integer lua_tointeger (lua_State *L, int index);
      - -

      -Equivalent to lua_tointegerx with isnum equal to NULL. - - - - - -


      lua_tointegerx

      -[-0, +0, –] -

      lua_Integer lua_tointegerx (lua_State *L, int index, int *isnum);
      - -

      -Converts the Lua value at the given index -to the signed integral type lua_Integer. -The Lua value must be an integer, -or a number or string convertible to an integer (see §3.4.3); -otherwise, lua_tointegerx returns 0. - - -

      -If isnum is not NULL, -its referent is assigned a boolean value that -indicates whether the operation succeeded. - - - - - -


      lua_tolstring

      -[-0, +0, e] -

      const char *lua_tolstring (lua_State *L, int index, size_t *len);
      - -

      -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; -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 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') -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 -will be valid after the corresponding Lua value is removed from the stack. - - - - - -


      lua_tonumber

      -[-0, +0, –] -

      lua_Number lua_tonumber (lua_State *L, int index);
      - -

      -Equivalent to lua_tonumberx with isnum equal to NULL. - - - - - -


      lua_tonumberx

      -[-0, +0, –] -

      lua_Number lua_tonumberx (lua_State *L, int index, int *isnum);
      - -

      -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.3); -otherwise, lua_tonumberx returns 0. - - -

      -If isnum is not NULL, -its referent is assigned a boolean value that -indicates whether the operation succeeded. - - - - - -


      lua_topointer

      -[-0, +0, –] -

      const void *lua_topointer (lua_State *L, int index);
      - -

      -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. -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

      -[-0, +0, e] -

      const char *lua_tostring (lua_State *L, int index);
      - -

      -Equivalent to lua_tolstring with len equal to NULL. - - - - - -


      lua_tothread

      -[-0, +0, –] -

      lua_State *lua_tothread (lua_State *L, int index);
      - -

      -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. - - - - - -


      lua_touserdata

      -[-0, +0, –] -

      void *lua_touserdata (lua_State *L, int index);
      - -

      -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. -Otherwise, returns NULL. - - - - - -


      lua_type

      -[-0, +0, –] -

      int lua_type (lua_State *L, int 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, -LUA_TNUMBER, -LUA_TBOOLEAN, -LUA_TSTRING, -LUA_TTABLE, -LUA_TFUNCTION, -LUA_TUSERDATA, -LUA_TTHREAD, -and -LUA_TLIGHTUSERDATA. - - - - - -


      lua_typename

      -[-0, +0, –] -

      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_Unsigned

      -
      typedef ... lua_Unsigned;
      - -

      -The unsigned version of lua_Integer. - - - - - -


      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);
      - -

      -Returns the address of the version number stored in the Lua core. -When called with a valid lua_State, -returns the address of the version used to create that state. -When called with NULL, -returns the address of the version running the call. - - - - - -


      lua_Writer

      -
      typedef int (*lua_Writer) (lua_State *L,
      -                           const void* p,
      -                           size_t sz,
      -                           void* ud);
      - -

      -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), -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 state. - - -

      -This function pops n values from the stack from, -and pushes them onto the stack to. - - - - - -


      lua_yield

      -[-?, +?, e] -

      int lua_yield (lua_State *L, int nresults);
      - -

      -This function is equivalent to lua_yieldk, -but it has no continuation (see §4.7). -Therefore, when the thread resumes, -it continues the function that called -the function calling lua_yield. - - - - - -


      lua_yieldk

      -[-?, +?, e] -

      int lua_yieldk (lua_State *L,
      -                int nresults,
      -                lua_KContext ctx,
      -                lua_KFunction k);
      - -

      -Yields a coroutine (thread). - - -

      -When a C function calls lua_yieldk, -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 will be passed as results to lua_resume. - - -

      -When the coroutine is resumed again, -Lua calls the given continuation function k to continue -the execution of the C function that yielded (see §4.7). -This continuation function receives the same stack -from the previous function, -with the n results removed and -replaced by the arguments passed to lua_resume. -Moreover, -the continuation function receives the value ctx -that was passed to lua_yieldk. - - -

      -Usually, this function does not return; -when the coroutine eventually resumes, -it continues executing the continuation function. -However, there is one special case, -which is when this function is called -from inside a line hook (see §4.9). -In that case, lua_yieldk should be called with no continuation -(probably in the form of lua_yield), -and the hook should return immediately after the call. -Lua will yield and, -when the coroutine resumes again, -it will continue the normal execution -of the (Lua) function that triggered the hook. - - -

      -This function can raise an error if it is called from a thread -with a pending C call with no continuation function, -or it is called from a thread that is not running inside a resume -(e.g., the main thread). - - - - - - - -

      4.9 – 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 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 */
      -  other fields
      -} lua_Debug;
      - -

      -A structure used to carry different pieces of -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, -call lua_getinfo. - - -

      -The fields of lua_Debug have the following meaning: - -

        - -
      • source: -the name of the chunk that created the function. -If source starts with a '@', -it means that the function was defined in a file where -the file name follows the '@'. -If source starts with a '=', -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. -
      • - -
      • 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 the function is a Lua function, -"C" if it is a C function, -"main" if it 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. -
      • - -
      • 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 can be the value of multiple global variables, -while others can 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.) -
      • - -
      • 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: -the number of upvalues of the function. -
      • - -
      • nparams: -the number of fixed parameters of the function -(always 0 for C functions). -
      • - -
      • isvararg: -true if the function is a vararg function -(always true for C functions). -
      • - -
      - - - - -

      lua_gethook

      -[-0, +0, –] -

      lua_Hook lua_gethook (lua_State *L);
      - -

      -Returns the current hook function. - - - - - -


      lua_gethookcount

      -[-0, +0, –] -

      int lua_gethookcount (lua_State *L);
      - -

      -Returns the current hook count. - - - - - -


      lua_gethookmask

      -[-0, +0, –] -

      int lua_gethookmask (lua_State *L);
      - -

      -Returns the current hook mask. - - - - - -


      lua_getinfo

      -[-(0|1), +(0|1|2), e] -

      int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
      - -

      -Gets 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 from 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_getglobal(L, "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, short_src, -linedefined, lastlinedefined, and what; -
      • - -
      • 'l': fills in the field currentline; -
      • - -
      • 't': fills in the field istailcall; -
      • - -
      • 'u': fills in the fields -nups, nparams, and isvararg; -
      • - -
      • '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.) - - -

        -If this option is given together with option 'f', -its table is pushed after the function. -

      • - -
      - -

      -This function returns 0 on error -(for instance, an invalid option in what). - - - - - -


      lua_getlocal

      -[-0, +(0|1), –] -

      const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
      - -

      -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; -see debug.getlocal for details about variable indices -and names. - - -

      -lua_getlocal pushes the variable's value onto the stack -and returns its name. - - -

      -In the second case, ar must 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 -the number of active local variables. - - - - - -


      lua_getstack

      -[-0, +0, –] -

      int lua_getstack (lua_State *L, int level, lua_Debug *ar);
      - -

      -Gets 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 -(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. - - - - - -


      lua_getupvalue

      -[-0, +(0|1), –] -

      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, -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 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_HOOKTAILCALL, 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 call events, event can be LUA_HOOKCALL, -the normal value, or LUA_HOOKTAILCALL, for a tail call; -in this case, there will be no corresponding return event. - - -

      -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. - - -

      -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. - - - - - -


      lua_sethook

      -[-0, +0, –] -

      void lua_sethook (lua_State *L, lua_Hook f, int mask, int count);
      - -

      -Sets the debugging 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, -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, -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. -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 -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

      -[-(0|1), +0, –] -

      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) -when the index is greater than -the number of active local variables. - - - - - -


      lua_setupvalue

      -[-(0|1), +0, –] -

      const char *lua_setupvalue (lua_State *L, int funcindex, int n);
      - -

      -Sets the value of a closure's upvalue. -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. - - - - - -


      lua_upvalueid

      -[-0, +0, –] -

      void *lua_upvalueid (lua_State *L, int funcindex, int n);
      - -

      -Returns an 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). - - -

      -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. - - - - - -


      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 funcindex1 -refer to the n2-th upvalue of the Lua closure at index funcindex2. - - - - - - - -

      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 -interactions between C and Lua, -the auxiliary library provides higher-level functions for some -common tasks. - - -

      -All functions and types 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 -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. - - -

      -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. -Because the error message is formatted for arguments -(e.g., "bad argument #1"), -you should not use these functions for other stack values. - - -

      -Functions called luaL_check* -always raise an error if the check is not satisfied. - - - -

      5.1 – Functions and Types

      - -

      -Here we list all functions and types from the auxiliary library -in alphabetical order. - - - -


      luaL_addchar

      -[-?, +?, e] -

      void luaL_addchar (luaL_Buffer *B, char c);
      - -

      -Adds the byte c to the buffer B -(see luaL_Buffer). - - - - - -


      luaL_addlstring

      -[-?, +?, e] -

      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 can contain embedded zeros. - - - - - -


      luaL_addsize

      -[-?, +?, e] -

      void luaL_addsize (luaL_Buffer *B, size_t n);
      - -

      -Adds to the buffer B (see luaL_Buffer) -a string of length n previously copied to the -buffer area (see luaL_prepbuffer). - - - - - -


      luaL_addstring

      -[-?, +?, e] -

      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). - - - - - -


      luaL_addvalue

      -[-1, +?, e] -

      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

      -[-0, +0, v] -

      void luaL_argcheck (lua_State *L,
      -                    int cond,
      -                    int arg,
      -                    const char *extramsg);
      - -

      -Checks whether cond is true. -If it is not, raises an error with a standard message (see luaL_argerror). - - - - - -


      luaL_argerror

      -[-0, +0, v] -

      int luaL_argerror (lua_State *L, int arg, const char *extramsg);
      - -

      -Raises an error reporting a problem with argument arg -of the C function that called it, -using a standard message -that includes extramsg as a comment: - -

      -     bad argument #arg to 'funcname' (extramsg)
      -

      -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: - -

        - -
      • First declare a variable b of type luaL_Buffer.
      • - -
      • Then initialize it with a call luaL_buffinit(L, &b).
      • - -
      • -Then add string pieces to the buffer calling any of -the luaL_add* functions. -
      • - -
      • -Finish by calling luaL_pushresult(&b). -This call leaves the final string on the top of the stack. -
      • - -
      - -

      -If you know beforehand the total size of the resulting string, -you can use the buffer like this: - -

        - -
      • First declare a variable b of type luaL_Buffer.
      • - -
      • Then initialize it and preallocate a space of -size sz with a call luaL_buffinitsize(L, &b, sz).
      • - -
      • Then copy the string into that space.
      • - -
      • -Finish by calling luaL_pushresultsize(&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. -So, while using a buffer, you cannot assume that you know where -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 -level when the buffer was initialized, -plus the final string on its top. - - - - - -


      luaL_buffinit

      -[-0, +0, –] -

      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_buffinitsize

      -[-?, +?, e] -

      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);
      - -

      -Calls a metamethod. - - -

      -If the object at index obj has a metatable and this -metatable has a field e, -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, -this function returns false (without pushing any value on the stack). - - - - - -


      luaL_checkany

      -[-0, +0, v] -

      void luaL_checkany (lua_State *L, int arg);
      - -

      -Checks whether the function has an argument -of any type (including nil) at position arg. - - - - - -


      luaL_checkinteger

      -[-0, +0, v] -

      lua_Integer luaL_checkinteger (lua_State *L, int arg);
      - -

      -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. - - - - - -


      luaL_checklstring

      -[-0, +0, v] -

      const char *luaL_checklstring (lua_State *L, int arg, size_t *l);
      - -

      -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. - - -

      -This function uses lua_tolstring to get its result, -so all conversions and caveats of that function apply here. - - - - - -


      luaL_checknumber

      -[-0, +0, v] -

      lua_Number luaL_checknumber (lua_State *L, int arg);
      - -

      -Checks whether the function argument arg is a number -and returns this number. - - - - - -


      luaL_checkoption

      -[-0, +0, v] -

      int luaL_checkoption (lua_State *L,
      -                      int arg,
      -                      const char *def,
      -                      const char *const lst[]);
      - -

      -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. -Raises an error if the argument is not a string or -if the string cannot be found. - - -

      -If def is not NULL, -the function uses def as a default value when -there is no argument arg or when this argument is nil. - - -

      -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

      -[-0, +0, v] -

      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 -(or NULL for no additional text). - - - - - -


      luaL_checkstring

      -[-0, +0, v] -

      const char *luaL_checkstring (lua_State *L, int arg);
      - -

      -Checks whether the function argument arg is a string -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

      -[-0, +0, v] -

      void luaL_checktype (lua_State *L, int arg, int t);
      - -

      -Checks whether the function argument arg has type t. -See lua_type for the encoding of types for t. - - - - - -


      luaL_checkudata

      -[-0, +0, v] -

      void *luaL_checkudata (lua_State *L, int arg, const char *tname);
      - -

      -Checks whether the function argument arg is a userdata -of the type tname (see luaL_newmetatable) and -returns the userdata address (see lua_touserdata). - - - - - -


      luaL_checkversion

      -[-0, +0, –] -

      void luaL_checkversion (lua_State *L);
      - -

      -Checks whether the core running the call, -the core that created the Lua state, -and the code making the call are all using the same version of Lua. -Also checks whether the core running the call -and the core that created the Lua state -are using the same address space. - - - - - -


      luaL_dofile

      -[-0, +?, e] -

      int luaL_dofile (lua_State *L, const char *filename);
      - -

      -Loads and runs the given file. -It is defined as the following macro: - -

      -     (luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))
      -

      -It returns false if there are no errors -or true in case of errors. - - - - - -


      luaL_dostring

      -[-0, +?, –] -

      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 false if there are no errors -or true in case of errors. - - - - - -


      luaL_error

      -[-0, +0, v] -

      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. -It also adds at the beginning of the message the file name and -the line number where the error occurred, -if this information is available. - - -

      -This function never returns, -but it is an idiom to use it in C functions -as return luaL_error(args). - - - - - -


      luaL_execresult

      -[-0, +3, e] -

      int luaL_execresult (lua_State *L, int stat);
      - -

      -This function produces the return values for -process-related functions in the standard library -(os.execute and io.close). - - - - - -


      luaL_fileresult

      -[-0, +(1|3), e] -

      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.). - - - - - -


      luaL_getmetafield

      -[-0, +(0|1), e] -

      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 and returns the type of pushed value. -If the object does not have a metatable, -or if the metatable does not have this field, -pushes nothing and returns LUA_TNIL. - - - - - -


      luaL_getmetatable

      -[-0, +1, –] -

      int luaL_getmetatable (lua_State *L, const char *tname);
      - -

      -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. - - - - - -


      luaL_getsubtable

      -[-0, +1, e] -

      int luaL_getsubtable (lua_State *L, int idx, const char *fname);
      - -

      -Ensures that the value t[fname], -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 -and false if it creates a new table. - - - - - -


      luaL_gsub

      -[-0, +1, e] -

      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_len

      -[-0, +0, e] -

      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.7). -Raises an error if the result of the operation is not an integer. -(This case only can happen through metamethods.) - - - - - -


      luaL_loadbuffer

      -[-0, +1, –] -

      int luaL_loadbuffer (lua_State *L,
      -                     const char *buff,
      -                     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 -buffer pointed to 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. -The string mode works as in function lua_load. - - - - - -


      luaL_loadfile

      -[-0, +1, e] -

      int luaL_loadfile (lua_State *L, const char *filename);
      - -

      -Equivalent to luaL_loadfilex with mode equal to NULL. - - - - - -


      luaL_loadfilex

      -[-0, +1, e] -

      int luaL_loadfilex (lua_State *L, const char *filename,
      -                                            const char *mode);
      - -

      -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 #. - - -

      -The string mode works as in function lua_load. - - -

      -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 or the file has a wrong mode. - - -

      -As lua_load, this function only loads the chunk; -it does not run it. - - - - - -


      luaL_loadstring

      -[-0, +1, –] -

      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. - - -

      -Also as lua_load, this function only loads the chunk; -it does not run it. - - - - - -


      luaL_newlib

      -[-0, +1, e] -

      void luaL_newlib (lua_State *L, const luaL_Reg 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))
      -

      -The array l must be the actual array, -not a pointer to it. - - - - - -


      luaL_newlibtable

      -[-0, +1, e] -

      void luaL_newlibtable (lua_State *L, const luaL_Reg l[]);
      - -

      -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). - - -

      -It is implemented as a macro. -The array l must be the actual array, -not a pointer to it. - - - - - -


      luaL_newmetatable

      -[-0, +1, e] -

      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 to this new table the pair __name = tname, -adds to the registry the pair [tname] = new table, -and returns 1. - - -

      -In both cases pushes onto the stack the final value associated -with tname in the registry. - - - - - -


      luaL_newstate

      -[-0, +0, –] -

      lua_State *luaL_newstate (void);
      - -

      -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 §4.6) 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_openlibs

      -[-0, +0, e] -

      void luaL_openlibs (lua_State *L);
      - -

      -Opens all standard Lua libraries into the given state. - - - - - -


      luaL_optinteger

      -[-0, +0, v] -

      lua_Integer luaL_optinteger (lua_State *L,
      -                             int arg,
      -                             lua_Integer d);
      - -

      -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. - - - - - -


      luaL_optlstring

      -[-0, +0, v] -

      const char *luaL_optlstring (lua_State *L,
      -                             int arg,
      -                             const char *d,
      -                             size_t *l);
      - -

      -If the function argument arg 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, -fills the position *l with the result's length. - - - - - -


      luaL_optnumber

      -[-0, +0, v] -

      lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number d);
      - -

      -If the function argument arg is a number, -returns this number. -If this argument is absent or is nil, -returns d. -Otherwise, raises an error. - - - - - -


      luaL_optstring

      -[-0, +0, v] -

      const char *luaL_optstring (lua_State *L,
      -                            int arg,
      -                            const char *d);
      - -

      -If the function argument arg is a string, -returns this string. -If this argument is absent or is nil, -returns d. -Otherwise, raises an error. - - - - - -


      luaL_prepbuffer

      -[-?, +?, e] -

      char *luaL_prepbuffer (luaL_Buffer *B);
      - -

      -Equivalent to luaL_prepbuffsize -with the predefined size LUAL_BUFFERSIZE. - - - - - -


      luaL_prepbuffsize

      -[-?, +?, e] -

      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 -luaL_addsize with the size of the string to actually add -it to the buffer. - - - - - -


      luaL_pushresult

      -[-?, +1, e] -

      void luaL_pushresult (luaL_Buffer *B);
      - -

      -Finishes the use of buffer B leaving the final string on -the top of the stack. - - - - - -


      luaL_pushresultsize

      -[-?, +1, e] -

      void luaL_pushresultsize (luaL_Buffer *B, size_t sz);
      - -

      -Equivalent to the sequence luaL_addsize, luaL_pushresult. - - - - - -


      luaL_ref

      -[-1, +0, e] -

      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 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 -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_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 -in which both name and func are NULL. - - - - - -


      luaL_requiref

      -[-0, +1, e] -

      void luaL_requiref (lua_State *L, const char *modname,
      -                    lua_CFunction openf, int glb);
      - -

      -If modname is not already present in package.loaded, -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 module into global modname. - - -

      -Leaves a copy of the module on the stack. - - - - - -


      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). - - -

      -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_Stream

      -
      typedef struct luaL_Stream {
      -  FILE *f;
      -  lua_CFunction closef;
      -} luaL_Stream;
      - -

      -The standard representation for file handles, -which is used by the standard I/O library. - - -

      -A file handle is implemented as a full userdata, -with a metatable called LUA_FILEHANDLE -(where LUA_FILEHANDLE is a macro with the actual metatable's name). -The metatable is created by the I/O library -(see luaL_newmetatable). - - -

      -This userdata must start with the structure luaL_Stream; -it can contain other data after this initial structure. -Field f points to the corresponding C stream -(or it can be NULL to indicate an incompletely created handle). -Field closef points to a Lua function -that will be called to close the stream -when the handle is closed or collected; -this function receives the file handle as its sole argument and -must return either true (in case of success) -or nil plus an error message (in case of error). -Once Lua calls this field, -the field value is changed to NULL -to signal that the handle is closed. - - - - - -


      luaL_testudata

      -[-0, +0, e] -

      void *luaL_testudata (lua_State *L, int arg, const char *tname);
      - -

      -This function works like luaL_checkudata, -except that, when the test fails, -it returns NULL instead of raising an error. - - - - - -


      luaL_tolstring

      -[-0, +1, e] -

      const char *luaL_tolstring (lua_State *L, int idx, size_t *len);
      - -

      -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. -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, e] -

      void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
      -                     int level);
      - -

      -Creates and pushes a traceback of the stack L1. -If msg is not NULL it is appended -at the beginning of the traceback. -The level parameter tells at which level -to start the traceback. - - - - - -


      luaL_typename

      -[-0, +0, –] -

      const char *luaL_typename (lua_State *L, int index);
      - -

      -Returns the name of the type of the value at the given index. - - - - - -


      luaL_unref

      -[-0, +0, –] -

      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

      -[-0, +1, e] -

      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 following 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. - - - - - - - -

      6 – Standard Libraries

      - -

      -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 requirements that -deserve an implementation in C (e.g., table.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 (§6.1);
      • - -
      • coroutine library (§6.2);
      • - -
      • package library (§6.3);
      • - -
      • string manipulation (§6.4);
      • - -
      • basic UTF-8 support (§6.5);
      • - -
      • table manipulation (§6.6);
      • - -
      • mathematical functions (§6.7) (sin, log, etc.);
      • - -
      • input and output (§6.8);
      • - -
      • operating system facilities (§6.9);
      • - -
      • debug facilities (§6.10).
      • - -

      -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. - - -

      -To have access to these libraries, -the C host program should call the luaL_openlibs function, -which opens all standard libraries. -Alternatively, -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), -luaopen_string (for the string library), -luaopen_utf8 (for the UTF8 library), -luaopen_table (for the table library), -luaopen_math (for the mathematical library), -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. - - - -

      6.1 – Basic Functions

      - -

      -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. - - -

      -


      assert (v [, message])

      - - -

      -Calls error if -the value of its argument v is false (i.e., nil or false); -otherwise, returns all its arguments. -In case of error, -message is the error object; -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: - -

        - -
      • "collect": -performs a full garbage-collection cycle. -This is the default option. -
      • - -
      • "stop": -stops automatic execution of the garbage collector. -The collector will run only when explicitly invoked, -until a call to restart it. -
      • - -
      • "restart": -restarts automatic execution of the garbage collector. -
      • - -
      • "count": -returns the total memory in use by Lua in Kbytes. -The value has a fractional part, -so that it multiplied by 1024 -gives the exact number of bytes in use by Lua -(except for overflows). -
      • - -
      • "step": -performs a garbage-collection step. -The step "size" is controlled by arg. -With a zero value, -the collector will perform one basic (indivisible) step. -For non-zero values, -the collector will perform as if that amount of memory -(in KBytes) had been allocated by Lua. -Returns true if the step finished a collection cycle. -
      • - -
      • "setpause": -sets arg as the new value for the pause of -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.5). -Returns the previous value for step. -
      • - -
      • "isrunning": -returns a boolean that tells whether the collector is running -(i.e., not stopped). -
      • - -
      - - - -

      -


      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 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])

      -Terminates the last protected function called -and returns message as the error object. -Function error never returns. - - -

      -Usually, error adds some information about the error position -at the beginning of the message, if the message is a string. -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 (see §2.2). -Lua itself does not use this variable; -changing its value does not affect any environment, -nor vice versa. - - - - -

      -


      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) -so that the construction - -

      -     for i,v in ipairs(t) do body end
      -

      -will iterate over the key–value pairs -(1,t[1]), (2,t[2]), ..., -up to the first nil value. - - - - -

      -


      load (chunk [, chunkname [, mode [, env]]])

      - - -

      -Loads a chunk. - - -

      -If chunk is a string, the chunk is this string. -If chunk is a function, -load calls it repeatedly to get the chunk pieces. -Each call to chunk 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 there are no syntactic 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 env, -if that parameter is given, -or to the value of the global environment. -Other upvalues are initialized with nil. -(When you load a main chunk, -the resulting function will always have exactly one upvalue, -the _ENV variable (see §2.2). -However, -when you load a binary chunk created from a function (see string.dump), -the resulting function can have an arbitrary number of upvalues.) -All upvalues are fresh, that is, -they are not shared with any other function. - - -

      -chunkname is used as the name of the chunk for error messages -and debug information (see §4.9). -When absent, -it defaults to chunk, if chunk is a string, -or to "=(load)" otherwise. - - -

      -The string mode controls whether the chunk can be text or binary -(that is, a precompiled chunk). -It may be the string "b" (only binary chunks), -"t" (only text chunks), -or "bt" (both binary and text). -The default is "bt". - - -

      -Lua does not check the consistency of binary chunks. -Maliciously crafted binary chunks can crash -the interpreter. - - - - -

      -


      loadfile ([filename [, mode [, env]]])

      - - -

      -Similar to load, -but gets the chunk from file filename -or from the standard input, -if no file name is given. - - - - -

      -


      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 its associated value. -When called with nil as its second argument, -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. -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. - - -

      -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.) - - -

      -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)

      - - -

      -If t has a metamethod __pairs, -calls it with t as argument and returns the first three -results from the call. - - -

      -Otherwise, -returns three values: the next function, the table t, and nil, -so that the construction - -

      -     for k,v in pairs(t) do body end
      -

      -will iterate over all key–value pairs of table t. - - -

      -See function next for the caveats of modifying -the table during its traversal. - - - - -

      -


      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), -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 (···)

      -Receives any number of arguments -and prints their values to stdout, -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, -for instance for debugging. -For complete control over the output, -use string.format and io.write. - - - - -

      -


      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 may be any value. - - - - -

      -


      rawlen (v)

      -Returns the length of the object v, -which must be a table or a string, -without invoking any metamethod. -Returns an integer. - - - - -

      -


      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 NaN, -and value any Lua value. - - -

      -This function returns table. - - - - -

      -


      select (index, ···)

      - - -

      -If index is a number, -returns all arguments after argument number index; -a negative number indexes from the end (-1 is the last argument). -Otherwise, index must be the string "#", -and select returns the total number of extra arguments it received. - - - - -

      -


      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])

      - - -

      -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, -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 must 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. -If the string e is not a valid numeral in the given base, -the function returns nil. - - - - -

      -


      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.) - - -

      -If the metatable of v has a "__tostring" field, -then tostring calls the corresponding value -with v 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". - - - - -

      -


      _VERSION

      -A global variable (not a function) that -holds a string containing the current interpreter version. -The current value of this variable is "Lua 5.3". - - - - -

      -


      xpcall (f, msgh [, arg1, ···])

      - - -

      -This function is similar to pcall, -except that it sets a new message handler msgh. - - - - - - - -

      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.6 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.isyieldable ()

      - - -

      -Returns true when the running coroutine can yield. - - -

      -A running coroutine is yieldable if it is not the main thread and -it is not inside a non-yieldable C function. - - - - -

      -


      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, ... are passed -as the arguments to the body function. -If the coroutine has yielded, -resume restarts it; -the values val1, ... are passed -as the results from the yield. - - -

      -If the coroutine runs without any errors, -resume returns true plus any values passed to yield -(when the coroutine yields) or any values returned by the body function -(when the coroutine terminates). -If there is any error, -resume returns false plus the error message. - - - - -

      -


      coroutine.running ()

      - - -

      -Returns the running coroutine plus a boolean, -true when the running coroutine is the main one. - - - - -

      -


      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 (···)

      - - -

      -Suspends the execution of the calling coroutine. -Any arguments to yield are passed as extra results to resume. - - - - - - - -

      6.3 – Modules

      - -

      -The package library provides basic -facilities for loading modules in Lua. -It exports one function directly in the global environment: -require. -Everything else is exported in a table package. - - -

      -


      require (modname)

      - - -

      -Loads the given module. -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]. -Otherwise, it tries to find a loader for the module. - - -

      -To find a loader, -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.searchers. - - -

      -First require queries package.preload[modname]. -If it has a value, -this value (which must 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 (see package.searchers). - - -

      -Once a loader is found, -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 -has not assigned any value to package.loaded[modname], -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 the module, -then require raises an error. - - - - -

      -


      package.config

      - - -

      -A string describing some compile-time configurations for packages. -This string is a sequence of lines: - -

        - -
      • The first line is the directory separator string. -Default is '\' for Windows and '/' for all other systems.
      • - -
      • The second line is the character that separates templates in a path. -Default is ';'.
      • - -
      • The third line is the string that marks the -substitution points in a template. -Default is '?'.
      • - -
      • The fourth line is a string that, in a path in Windows, -is replaced by the executable's directory. -Default is '!'.
      • - -
      • The fifth line is a mark to ignore all text after it -when building the luaopen_ function name. -Default is '-'.
      • - -
      - - - -

      -


      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_5_3 -or the environment variable LUA_CPATH -or a default path defined in luaconf.h. - - - - -

      -


      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. - - -

      -This variable is only a reference to the real table; -assignments to this variable do not change the -table used by require. - - - - -

      -


      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 lua_CFunction prototype -(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_3 or -the environment variable LUA_PATH or -with a default path defined in luaconf.h, -if those environment variables are 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

      - - -

      -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 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 searcher 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. -The search is done as described in function package.searchpath. - - -

      -The third searcher looks for a loader as a C library, -using the path given by the variable package.cpath. -Again, -the search is done as described in function package.searchpath. -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 suffix after (and including) the first hyphen is removed. -For instance, if the module name is a.b.c-v2.1, -the function name will be luaopen_a_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. - - -

      -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. - - - - -

      -


      package.searchpath (name, path [, sep [, rep]])

      - - -

      -Searches for the given name in the given path. - - -

      -A path is a string containing a sequence of -templates separated by semicolons. -For each template, -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 rep -(the system's directory separator, by default), -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 the name foo.a -will try to open the files -./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 the file), -or nil plus an error message if none succeeds. -(This error message lists all file names it tried to open.) - - - - - - - -

      6.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 -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). - - -

      -The string library assumes one-byte character encodings. - - -

      -


      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. -These indices are corrected -following the same rules of function string.sub. - - -

      -Numerical codes are not necessarily portable across platforms. - - - - -

      -


      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. - - -

      -Numerical codes are not necessarily portable across platforms. - - - - -

      -


      string.dump (function [, strip])

      - - -

      -Returns a string containing a binary representation -(a binary chunk) -of the given function, -so that a later load on this string returns -a copy of the function (but with new upvalues). -If strip is a true value, -the binary representation is created without debug information -about the function -(local variable names, lines, etc.). - - -

      -Functions with upvalues have only their number of upvalues saved. -When (re)loaded, -those upvalues receive fresh instances containing nil. -(You can use the debug library to serialize -and reload the upvalues of a function -in a way adequate to your needs.) - - - - -

      -


      string.find (s, pattern [, init [, plain]])

      - - -

      -Looks for the first match of -pattern (see §6.4.1) in the string 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 can 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, -then in a successful match -the captured values are also returned, -after the two indices. - - - - -

      -


      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 ISO C function sprintf. -The only differences are that the options/modifiers -*, h, L, l, n, -and p are not supported -and that there is an extra option, q. -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')
      -

      -may produce the string: - -

      -     "a string with \"quotes\" and \
      -      new line"
      -
      - -

      -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. -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. - - - - -

      -


      string.gmatch (s, pattern)

      -Returns an iterator function that, -each time it is called, -returns the next captures from pattern (see §6.4.1) -over the string s. -If pattern specifies no captures, -then the whole match is produced in each call. - - -

      -As an example, the following loop -will iterate over all the words from string s, -printing one per line: - -

      -     s = "hello world from Lua"
      -     for w in string.gmatch(s, "%a+") do
      -       print(w)
      -     end
      -

      -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
      -
      - -

      -For this function, a caret '^' at the start of a pattern does not -work as an anchor, as this would prevent the iteration. - - - - -

      -


      string.gsub (s, pattern, repl [, n])

      -Returns a copy of s -in which all (or the first n, if given) -occurrences of the pattern (see §6.4.1) have been -replaced by a replacement string specified by repl, -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. - - -

      -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 %d, -with d between 1 and 9, -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 repl is a function, then this function is called every time a -match occurs, with all captured substrings passed as arguments, -in order. - - -

      -In any case, -if the pattern specifies no captures, -then it behaves as if the whole pattern was inside a capture. - - -

      -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). - - -

      -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 load(s)()
      -         end)
      -     --> x="4+5 = 9"
      -     
      -     local t = {name="lua", version="5.3"}
      -     x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t)
      -     --> x="lua-5.3.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 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])

      -Looks for the first match of -pattern (see §6.4.1) 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 can be negative. - - - - -

      -


      string.pack (fmt, v1, v2, ...)

      - - -

      -Returns a binary string containing the values v1, v2, etc. -packed (that is, serialized in binary form) -according to the format string fmt (see §6.4.2). - - - - -

      -


      string.packsize (fmt)

      - - -

      -Returns the size of a string resulting from string.pack -with the given format. -The format string cannot have the variable-length options -'s' or 'z' (see §6.4.2). - - - - -

      -


      string.rep (s, n [, sep])

      -Returns a string that is the concatenation of n copies of -the string s separated by the string sep. -The default value for sep is the empty string -(that is, no separator). -Returns the empty string if n is not positive. - - - - -

      -


      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 can 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. - - -

      -If, after the translation of negative indices, -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, -i is greater than j, -the function returns the empty string. - - - - -

      -


      string.unpack (fmt, s [, pos])

      - - -

      -Returns the values packed in string s (see string.pack) -according to the format string fmt (see §6.4.2). -An optional pos marks where -to start reading in s (default is 1). -After the read values, -this function also returns the index of the first unread byte in 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. - - - - - -

      6.4.1 – Patterns

      - -

      -Patterns in Lua are described by regular strings, -which are interpreted as patterns by the pattern-matching functions -string.find, -string.gmatch, -string.gsub, -and string.match. -This section describes the syntax and the meaning -(that is, what they match) of these strings. - - - -

      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 -^$()%.[]*+-?) -represents the character x itself. -
      • - -
      • .: (a dot) represents all characters.
      • - -
      • %a: represents all letters.
      • - -
      • %c: represents all control characters.
      • - -
      • %d: represents all digits.
      • - -
      • %g: represents all printable characters except space.
      • - -
      • %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.
      • - -
      • %x: (where x is any non-alphanumeric character) -represents the character x. -This is the standard way to escape the magic characters. -Any non-alphanumeric character -(including all punctuations, even the non-magical) -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 can be specified by -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. -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. - - - - - -

      Pattern Item:

      -A pattern item can 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. -
      • - -
      • -%f[set], a frontier pattern; -such item matches an empty string at any position such that -the next character belongs to set -and the previous character does not belong to set. -The set set is interpreted as previously described. -The beginning and the end of the subject are handled as if -they were the character '\0'. -
      • - -
      - - - - -

      Pattern:

      -A pattern is a sequence of pattern items. -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. -At other positions, -'^' and '$' have no special meaning and represent themselves. - - - - - -

      Captures:

      -A pattern can 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. - - - - - - - -

      6.4.2 – Format Strings for Pack and Unpack

      - -

      -The first argument to string.pack, -string.packsize, and string.unpack -is a format string, -which describes the layout of the structure being created or read. - - -

      -A format string is a sequence of conversion options. -The conversion options are as follows: - -

        -
      • <: sets little endian
      • -
      • >: sets big endian
      • -
      • =: sets native endian
      • -
      • ![n]: sets maximum alignment to n -(default is native alignment)
      • -
      • b: a signed byte (char)
      • -
      • B: an unsigned byte (char)
      • -
      • h: a signed short (native size)
      • -
      • H: an unsigned short (native size)
      • -
      • l: a signed long (native size)
      • -
      • L: an unsigned long (native size)
      • -
      • j: a lua_Integer
      • -
      • J: a lua_Unsigned
      • -
      • T: a size_t (native size)
      • -
      • i[n]: a signed int with n bytes -(default is native size)
      • -
      • I[n]: an unsigned int with n bytes -(default is native size)
      • -
      • f: a float (native size)
      • -
      • d: a double (native size)
      • -
      • n: a lua_Number
      • -
      • cn: a fixed-sized string with n bytes
      • -
      • z: a zero-terminated string
      • -
      • s[n]: a string preceded by its length -coded as an unsigned integer with n bytes -(default is a size_t)
      • -
      • x: one byte of padding
      • -
      • Xop: an empty item that aligns -according to option op -(which is otherwise ignored)
      • -
      • ' ': (empty space) ignored
      • -

      -(A "[n]" means an optional integral numeral.) -Except for padding, spaces, and configurations -(options "xX <=>!"), -each option corresponds to an argument (in string.pack) -or a result (in string.unpack). - - -

      -For options "!n", "sn", "in", and "In", -n can be any integer between 1 and 16. -All integral options check overflows; -string.pack checks whether the given value fits in the given size; -string.unpack checks whether the read value fits in a Lua integer. - - -

      -Any format string starts as if prefixed by "!1=", -that is, -with maximum alignment of 1 (no alignment) -and native endianness. - - -

      -Alignment works as follows: -For each option, -the format gets extra padding until the data starts -at an offset that is a multiple of the minimum between the -option size and the maximum alignment; -this minimum must be a power of 2. -Options "c" and "z" are not aligned; -option "s" follows the alignment of its starting integer. - - -

      -All padding is filled with zeros by string.pack -(and ignored by string.unpack). - - - - - - - -

      6.5 – UTF-8 Support

      - -

      -This library provides basic support for UTF-8 encoding. -It provides all its functions inside the table utf8. -This library does not provide any support for Unicode other -than the handling of the encoding. -Any operation that needs the meaning of a character, -such as character classification, is outside its scope. - - -

      -Unless stated otherwise, -all functions that expect a byte position as a parameter -assume that the given position is either the start of a byte sequence -or one plus the length of the subject string. -As in the string library, -negative indices count from the end of the string. - - -

      -


      utf8.char (···)

      -Receives zero or more integers, -converts each one to its corresponding UTF-8 byte sequence -and returns a string with the concatenation of all these sequences. - - - - -

      -


      utf8.charpattern

      -The pattern (a string, not a function) "[\0-\x7F\xC2-\xF4][\x80-\xBF]*" -(see §6.4.1), -which matches exactly one UTF-8 byte sequence, -assuming that the subject is a valid UTF-8 string. - - - - -

      -


      utf8.codes (s)

      - - -

      -Returns values so that the construction - -

      -     for p, c in utf8.codes(s) do body end
      -

      -will iterate over all characters in string s, -with p being the position (in bytes) and c the code point -of each character. -It raises an error if it meets any invalid byte sequence. - - - - -

      -


      utf8.codepoint (s [, i [, j]])

      -Returns the codepoints (as integers) from all characters in s -that start between byte position i and j (both included). -The default for i is 1 and for j is i. -It raises an error if it meets any invalid byte sequence. - - - - -

      -


      utf8.len (s [, i [, j]])

      -Returns the number of UTF-8 characters in string s -that start between positions i and @{j} (both inclusive). -The default for i is 1 and for j is -1. -If it finds any invalid byte sequence, -returns a false value plus the position of the first invalid byte. - - - - -

      -


      utf8.offset (s, n [, i])

      -Returns the position (in bytes) where the encoding of the -n-th character of s -(counting from position i) starts. -A negative n gets characters before position i. -The default for i is 1 when n is non-negative -and #s + 1 otherwise, -so that utf8.offset(s, -n) gets the offset of the -n-th character from the end of the string. -If the specified character is neither in the subject -nor right after its end, -the function returns nil. - - -

      -As a special case, -when n is 0 the function returns the start of the encoding -of the character that contains the i-th byte of s. - - -

      -This function assumes that s is a valid UTF-8 string. - - - - - - - -

      6.6 – Table Manipulation

      - -

      -This library provides generic functions for table manipulation. -It provides all its functions inside the table table. - - -

      -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 -in the tables given as arguments. - - -

      -


      table.concat (list [, sep [, i [, j]]])

      - - -

      -Given a list where all elements are strings or numbers, -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. -If i is greater than j, returns the empty string. - - - - -

      -


      table.insert (list, [pos,] value)

      - - -

      -Inserts element value at position pos in list, -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. - - - - -

      -


      table.move (a1, f, e, t [,a2])

      - - -

      -Moves elements from table a1 to table a2. -This function performs the equivalent to the following -multiple assignment: -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. - - - - -

      -


      table.pack (···)

      - - -

      -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 resulting table may not be a sequence. - - - - -

      -


      table.remove (list [, pos])

      - - -

      -Removes from list the element at position pos, -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 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(l) removes the last element -of list l. - - - - -

      -


      table.sort (list [, comp])

      - - -

      -Sorts list elements in a given order, in-place, -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(list[i+1],list[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.unpack (list [, i [, j]])

      - - -

      -Returns the elements from the given list. -This function is equivalent to - -

      -     return list[i], list[i+1], ···, list[j]
      -

      -By default, i is 1 and j is #list. - - - - - - - -

      6.7 – Mathematical Functions

      - -

      -This library provides basic mathematical functions. -It provides all its functions and constants inside the table math. -Functions with the annotation "integer/float" give -integer results for integer arguments -and float results for float (or mixed) arguments. -Rounding functions -(math.ceil, math.floor, and math.modf) -return an integer when the result fits in the range of an integer, -or a float otherwise. - - -

      -


      math.abs (x)

      - - -

      -Returns the absolute value of x. (integer/float) - - - - -

      -


      math.acos (x)

      - - -

      -Returns the arc cosine of x (in radians). - - - - -

      -


      math.asin (x)

      - - -

      -Returns the arc sine of x (in radians). - - - - -

      -


      math.atan (y [, x])

      - - -

      - -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 x being zero.) - - -

      -The default value for x is 1, -so that the call math.atan(y) -returns the arc tangent of y. - - - - -

      -


      math.ceil (x)

      - - -

      -Returns the smallest integral value larger than or equal to x. - - - - -

      -


      math.cos (x)

      - - -

      -Returns the cosine of x (assumed to be in radians). - - - - -

      -


      math.deg (x)

      - - -

      -Converts the angle x from radians to degrees. - - - - -

      -


      math.exp (x)

      - - -

      -Returns the value ex -(where e is the base of natural logarithms). - - - - -

      -


      math.floor (x)

      - - -

      -Returns the largest integral value smaller than or equal to x. - - - - -

      -


      math.fmod (x, y)

      - - -

      -Returns the remainder of the division of x by y -that rounds the quotient towards zero. (integer/float) - - - - -

      -


      math.huge

      - - -

      -The float value HUGE_VAL, -a value larger than any other numerical value. - - - - -

      -


      math.log (x [, base])

      - - -

      -Returns the logarithm of x in the given base. -The default for base is e -(so that the function returns the natural logarithm of x). - - - - -

      -


      math.max (x, ···)

      - - -

      -Returns the argument with the maximum value, -according to the Lua operator <. (integer/float) - - - - -

      -


      math.maxinteger

      -An integer with the maximum value for an integer. - - - - -

      -


      math.min (x, ···)

      - - -

      -Returns the argument with the minimum value, -according to the Lua operator <. (integer/float) - - - - -

      -


      math.mininteger

      -An integer with the minimum value for an integer. - - - - -

      -


      math.modf (x)

      - - -

      -Returns the integral part of x and the fractional part of x. -Its second result is always a float. - - - - -

      -


      math.pi

      - - -

      -The value of π. - - - - -

      -


      math.rad (x)

      - - -

      -Converts the angle x from degrees to radians. - - - - -

      -


      math.random ([m [, n]])

      - - -

      -When called without arguments, -returns a pseudo-random float with uniform distribution -in the range [0,1). -When called with two integers m and n, -math.random returns a pseudo-random integer -with uniform distribution in the range [m, n]. -(The value m-n cannot be negative and must fit in a Lua integer.) -The call math.random(n) is equivalent to math.random(1,n). - - -

      -This function is an interface to the underling -pseudo-random generator function provided by C. -No guarantees can be given for its statistical properties. - - - - -

      -


      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.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.tointeger (x)

      - - -

      -If the value x is convertible to an integer, -returns that integer. -Otherwise, returns nil. - - - - -

      -


      math.type (x)

      - - -

      -Returns "integer" if x is an integer, -"float" if it is a float, -or nil if x is not a number. - - - - -

      -


      math.ult (m, n)

      - - -

      -Returns a boolean, -true if integer m is below integer n when -they are compared as unsigned integers. - - - - - - - -

      6.8 – Input and Output Facilities

      - -

      -The I/O library provides two different styles for file manipulation. -The first one uses implicit file handles; -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 handles. - - -

      -When using implicit file handles, -all operations are supplied by table io. -When using explicit file handles, -the operation io.open returns a file handle -and then all operations are supplied as methods of the file handle. - - -

      -The table io also provides -three predefined file handles with their usual meanings from C: -io.stdin, io.stdout, and io.stderr. -The I/O library never closes these files. - - -

      -Unless otherwise stated, -all I/O functions return nil on failure -(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. - - -

      -


      io.close ([file])

      - - -

      -Equivalent to file:close(). -Without a file, closes the default output file. - - - - -

      -


      io.flush ()

      - - -

      -Equivalent to io.output():flush(). - - - - -

      -


      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, -instead of returning an error code. - - - - -

      -


      io.lines ([filename ···])

      - - -

      -Opens the given file name in read mode -and returns an iterator function that -works like file:lines(···) over the opened file. -When the iterator function detects the end of file, -it returns no values (to finish the loop) and automatically closes the file. - - -

      -The call io.lines() (with no file name) is equivalent -to io.input():lines("*l"); -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. - - -

      -In case of errors this function raises the error, -instead of returning an error code. - - - - -

      -


      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 can also have a 'b' at the end, -which is needed in some systems to open the file in binary mode. - - - - -

      -


      io.output ([file])

      - - -

      -Similar to io.input, but operates over the default output file. - - - - -

      -


      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 -(if mode is "r", the default) -or to write data to this program -(if mode is "w"). - - - - -

      -


      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. -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 (···)

      - - -

      -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. - - -

      -When closing a file handle created with io.popen, -file:close returns the same values -returned by os.execute. - - - - -

      -


      file:flush ()

      - - -

      -Saves any written data to file. - - - - -

      -


      file:lines (···)

      - - -

      -Returns an iterator function that, -each time it is called, -reads the file according to the given formats. -When no format is given, -uses "l" as a default. -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. - - -

      -In case of errors this function raises the error, -instead of returning an error code. - - - - -

      -


      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, -or nil if it cannot read data with the specified format. -(In this latter case, -the function does not read subsequent formats.) -When called without formats, -it uses a default format that reads the next line -(see below). - - -

      -The available formats are - -

        - -
      • "n": -reads a numeral and returns it as a float or an integer, -following the lexical conventions of Lua. -(The numeral may have leading spaces and a sign.) -This format always reads the longest input sequence that -is a valid prefix for a number; -if that prefix does not form a valid number -(e.g., an empty string, "0x", or "3.4e-"), -it is discarded and the function returns nil. -
      • - -
      • "i": -reads an integral number and returns it as an integer. -
      • - -
      • "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. -
      • - -
      • "L": -reads the next line keeping the end-of-line character (if present), -returning nil on end of file. -
      • - -
      • number: -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, -or nil on end of file. -
      • - -

      -The formats "l" and "L" should be used only for text files. - - - - -

      -


      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, seek returns the final file position, -measured in bytes from the beginning of the file. -If seek 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; 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 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, size -specifies the size of the buffer, in bytes. -The default is an appropriate size. - - - - -

      -


      file:write (···)

      - - -

      -Writes the value of each of its arguments to file. -The arguments must be strings or numbers. - - -

      -In case of success, this function returns file. -Otherwise it returns nil plus a string describing the error. - - - - - - - -

      6.9 – 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, -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 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), -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. - - -

      -If format is not "*t", -then date returns the date as a string, -formatted according to the same rules as the ISO 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")). - - -

      -On non-POSIX systems, -this function may be not thread safe -because of its reliance on C function gmtime and C function localtime. - - - - -

      -


      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 ISO C function system. -It passes command to be executed by an operating system shell. -Its first result is true -if the command terminated successfully, -or nil otherwise. -After this first result -the function returns a string plus 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. - - - - -

      -


      os.exit ([code [, close]])

      - - -

      -Calls the ISO 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 true. - - -

      -If the optional second argument close is true, -closes the Lua state before exiting. - - - - -

      -


      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 empty directory, on POSIX systems) -with the given name. -If this function fails, it returns nil, -plus a string describing the error and the error code. - - - - -

      -


      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 and the error code. - - - - -

      -


      os.setlocale (locale [, category])

      - - -

      -Sets the current locale of the program. -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"; -the default category is "all". -The function returns the name of the new locale, -or nil if the request cannot be honored. - - -

      -If locale is the empty string, -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. - - -

      -When called with nil as the first argument, -this function only returns the name of the current locale -for the given category. - - -

      -This function may be not thread safe -because of its reliance on C function setlocale. - - - - -

      -


      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 (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. - - -

      -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 -os.date and os.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 explicitly removed when no longer needed. - - -

      -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 -in the time between getting the name and creating the file.) -You still have to open the file to use it -and to remove it (even if you do not use it). - - -

      -When possible, -you may prefer to use io.tmpfile, -which automatically removes the file when the program ends. - - - - - - - -

      6.10 – The Debug Library

      - -

      -This library provides -the functionality of the debug interface (§4.9) to Lua programs. -You should exert care when using this library. -Several of its functions -violate basic assumptions about Lua code -(e.g., that variables local to a function -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. - - -

      -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, -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 -within any function and so have no direct access to local variables. - - - - -

      -


      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 ([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 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 f is a number larger than the number of active functions, -then getinfo returns nil. - - -

      -The returned table can 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. -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. - - -

      -For instance, the expression debug.getinfo(1,"n").name returns -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. - - - - -

      -


      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 f of the stack. -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.) - - -

      -Variable names starting with '(' (open parenthesis) -represent variables with no known names -(internal variables like loop control variables, -and variables from chunks saved without debug information). - - -

      -The parameter f may also be a function. -In that case, getlocal returns only the name of function parameters. - - - - -

      -


      debug.getmetatable (value)

      - - -

      -Returns the metatable of the given value -or nil if it does not have a metatable. - - - - -

      -


      debug.getregistry ()

      - - -

      -Returns the registry table (see §4.5). - - - - -

      -


      debug.getupvalue (f, up)

      - - -

      -This function returns the name and the value of the upvalue -with index up of the function f. -The function returns nil if there is no upvalue with the given index. - - -

      -Variable names starting with '(' (open parenthesis) -represent variables with no known names -(variables from chunks saved without debug information). - - - - -

      -


      debug.getuservalue (u)

      - - -

      -Returns the Lua value associated to u. -If u is not a userdata, -returns nil. - - - - -

      -


      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 any combination of 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.
      • -

      -Moreover, -with a count different from zero, -the hook is called also after every count instructions. - - -

      -When called without arguments, -debug.sethook turns off the hook. - - -

      -When the hook is called, its first parameter is a string -describing the event that has triggered its call: -"call" (or "tail call"), -"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 -the running function -(level 0 is the getinfo function, -and level 1 is the hook function). - - - - -

      -


      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, -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. - - -

      -See debug.getlocal for more information about -variable indices and names. - - - - -

      -


      debug.setmetatable (value, table)

      - - -

      -Sets the metatable for the given value to the given table -(which can be nil). -Returns value. - - - - -

      -


      debug.setupvalue (f, up, value)

      - - -

      -This function assigns the value value to the upvalue -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. - - - - -

      -


      debug.setuservalue (udata, value)

      - - -

      -Sets the given value as -the Lua value associated to the given udata. -udata must be a full userdata. - - -

      -Returns udata. - - - - -

      -


      debug.traceback ([thread,] [message [, level]])

      - - -

      -If message is present but is neither a string nor nil, -this function returns message without further processing. -Otherwise, -it returns a string with a traceback of the call stack. -The optional message string is appended -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). - - - - -

      -


      debug.upvalueid (f, 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 (f1, n1, f2, n2)

      - - -

      -Make the n1-th upvalue of the Lua closure f1 -refer to the n2-th upvalue of the Lua closure f2. - - - - - - - -

      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 standalone language. -An interpreter for Lua as a standalone language, -called simply lua, -is provided with the standard distribution. -The standalone interpreter includes -all standard libraries, including the debug library. -Its usage is: - -

      -     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;
      • -
      • -E: ignores environment variables;
      • -
      • --: stops handling options;
      • -
      • -: executes stdin as a file and stops handling options.
      • -

      -After handling its options, lua runs the given script. -When called without arguments, -lua behaves as lua -v -i -when the standard input (stdin) is a terminal, -and as lua - otherwise. - - -

      -When called without option -E, -the interpreter checks for an environment variable LUA_INIT_5_3 -(or LUA_INIT if the versioned name 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. - - -

      -When called with option -E, -besides ignoring LUA_INIT, -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. - - -

      -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, -and finally run the file script.lua with no arguments. -(Here $ is the shell prompt. Your prompt may be different.) - - -

      -Before running any code, -lua collects all command-line arguments -in a global table called arg. -The script name goes to 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 its options) -go to negative indices. -For instance, in the call - -

      -     $ lua -la b.lua t1 t2
      -

      -the table is like this: - -

      -     arg = { [-2] = "lua", [-1] = "-la",
      -             [0] = "b.lua",
      -             [1] = "t1", [2] = "t2" }
      -

      -If there is no script in the call, -the interpreter name goes to index 0, -followed by the other arguments. -For instance, the call - -

      -     $ lua -e "print(arg[1])"
      -

      -will print "-e". -If there is a script, -the script is called with parameters -arg[1], ···, arg[#arg]. -(Like all chunks in Lua, -the script is compiled as a vararg function.) - - -

      -In interactive mode, -Lua repeatedly prompts and waits for a line. -After reading a line, -Lua first try to interpret the line as an expression. -If it succeeds, it prints its value. -Otherwise, it interprets the line as a statement. -If you write an incomplete statement, -the interpreter waits for its completion -by issuing a different prompt. - - -

      -In case of unprotected errors in the script, -the interpreter reports the error to the standard error stream. -If the error object is not a string but -has a metamethod __tostring, -the interpreter calls this metamethod to produce the final message. -Otherwise, the interpreter converts the error object to a string -and adds a stack traceback to it. - - -

      -When finishing normally, -the interpreter closes its main Lua state -(see lua_close). -The script can avoid this step by -calling os.exit to terminate. - - -

      -To allow the use of Lua as a -script interpreter in Unix systems, -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, -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.) - - - -

      8 – Incompatibilities with the Previous Version

      - -

      -Here we list the incompatibilities that you may find when moving a program -from Lua 5.2 to Lua 5.3. -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 future. - - -

      -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 -or the implementation of functions as macros. -Therefore, -you should not assume that binaries are compatible between -different Lua versions. -Always recompile clients of the Lua API when -using a new version. - - -

      -Similarly, Lua versions can always change the internal representation -of precompiled chunks; -precompiled chunks are not compatible between different Lua versions. - - -

      -The standard paths in the official distribution may -change between versions. - - - -

      8.1 – Changes in the Language

      -
        - -
      • -The main difference between Lua 5.2 and Lua 5.3 is the -introduction of an integer subtype for numbers. -Although this change should not affect "normal" computations, -some computations -(mainly those that involve some kind of overflow) -can give different results. - - -

        -You can fix these differences by forcing a number to be a float -(in Lua 5.2 all numbers were float), -in particular writing constants with an ending .0 -or using x = x + 0.0 to convert a variable. -(This recommendation is only for a quick fix -for an occasional incompatibility; -it is not a general guideline for good programming. -For good programming, -use floats where you need floats -and integers where you need integers.) -

      • - -
      • -The conversion of a float to a string now adds a .0 suffix -to the result if it looks like an integer. -(For instance, the float 2.0 will be printed as 2.0, -not as 2.) -You should always use an explicit format -when you need a specific format for numbers. - - -

        -(Formally this is not an incompatibility, -because Lua does not specify how numbers are formatted as strings, -but some programs assumed a specific format.) -

      • - -
      • -The generational mode for the garbage collector was removed. -(It was an experimental feature in Lua 5.2.) -
      • - -
      - - - - -

      8.2 – Changes in the Libraries

      -
        - -
      • -The bit32 library has been deprecated. -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.) -
      • - -
      • -The Table library now respects metamethods -for setting and getting elements. -
      • - -
      • -The ipairs iterator now respects metamethods and -its __ipairs metamethod has been deprecated. -
      • - -
      • -Option names in io.read do not have a starting '*' anymore. -For compatibility, Lua will continue to ignore this character. -
      • - -
      • -The following functions were deprecated in the mathematical library: -atan2, cosh, sinh, tanh, pow, -frexp, and ldexp. -You can replace math.pow(x,y) with x^y; -you can replace math.atan2 with math.atan, -which now accepts one or two parameters; -you can replace math.ldexp(x,exp) with x * 2.0^exp. -For the other operations, -you can either use an external library or -implement them in Lua. -
      • - -
      • -The searcher for C loaders used by require -changed the way it handles versioned names. -Now, the version should come after the module name -(as is usual in most other tools). -For compatibility, that searcher still tries the old format -if it cannot find an open function according to the new style. -(Lua 5.2 already worked that way, -but it did not document the change.) -
      • - -
      - - - - -

      8.3 – Changes in the API

      - - -
        - -
      • -Continuation functions now receive as parameters what they needed -to get through lua_getctx, -so lua_getctx has been removed. -Adapt your code accordingly. -
      • - -
      • -Function lua_dump has an extra parameter, strip. -Use 0 as the value of this parameter to get the old behavior. -
      • - -
      • -Functions to inject/project unsigned integers -(lua_pushunsigned, lua_tounsigned, lua_tounsignedx, -luaL_checkunsigned, luaL_optunsigned) -were deprecated. -Use their signed equivalents with a type cast. -
      • - -
      • -Macros to project non-default integer types -(luaL_checkint, luaL_optint, luaL_checklong, luaL_optlong) -were deprecated. -Use their equivalent over lua_Integer with a type cast -(or, when possible, use lua_Integer in your code). -
      • - -
      - - - - -

      9 – The Complete Syntax of Lua

      - -

      -Here is the complete syntax of Lua in extended BNF. -As usual in extended BNF, -{A} means 0 or more As, -and [A] means an optional A. -(For operator precedences, see §3.4.8; -for a description of the terminals -Name, Numeral, -and LiteralString, see §3.1.) - - - - -

      -
      -	chunk ::= block
      -
      -	block ::= {stat} [retstat]
      -
      -	stat ::=  ‘;’ | 
      -		 varlist ‘=’ explist | 
      -		 functioncall | 
      -		 label | 
      -		 break | 
      -		 goto Name | 
      -		 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 explist do block end | 
      -		 function funcname funcbody | 
      -		 local function Name funcbody | 
      -		 local namelist [‘=’ explist] 
      -
      -	retstat ::= return [explist] [‘;’]
      -
      -	label ::= ‘::’ Name ‘::’
      -
      -	funcname ::= Name {‘.’ Name} [‘:’ Name]
      -
      -	varlist ::= var {‘,’ var}
      -
      -	var ::=  Name | prefixexp ‘[’ exp ‘]’ | prefixexp ‘.’ Name 
      -
      -	namelist ::= Name {‘,’ Name}
      -
      -	explist ::= exp {‘,’ exp}
      -
      -	exp ::=  nil | false | true | Numeral | LiteralString | ‘...’ | functiondef | 
      -		 prefixexp | tableconstructor | exp binop exp | unop exp 
      -
      -	prefixexp ::= var | functioncall | ‘(’ exp ‘)’
      -
      -	functioncall ::=  prefixexp args | prefixexp ‘:’ Name args 
      -
      -	args ::=  ‘(’ [explist] ‘)’ | tableconstructor | LiteralString 
      -
      -	functiondef ::= function funcbody
      -
      -	funcbody ::= ‘(’ [parlist] ‘)’ block end
      -
      -	parlist ::= namelist [‘,’ ‘...’] | ‘...’
      -
      -	tableconstructor ::= ‘{’ [fieldlist] ‘}’
      -
      -	fieldlist ::= field {fieldsep field} [fieldsep]
      -
      -	field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp
      -
      -	fieldsep ::= ‘,’ | ‘;’
      -
      -	binop ::=  ‘+’ | ‘-’ | ‘*’ | ‘/’ | ‘//’ | ‘^’ | ‘%’ | 
      -		 ‘&’ | ‘~’ | ‘|’ | ‘>>’ | ‘<<’ | ‘..’ | 
      -		 ‘<’ | ‘<=’ | ‘>’ | ‘>=’ | ‘==’ | ‘~=’ | 
      -		 and | or
      -
      -	unop ::= ‘-’ | not | ‘#’ | ‘~’
      -
      -
      - -

      - - - - - - - - -


      - -Last update: -Tue Dec 16 14:45:50 BRST 2014 - - - - - diff --git a/doc/osi-certified-72x60.png b/doc/osi-certified-72x60.png deleted file mode 100644 index 07df5f6ee7a7a8b2108025dcd815f73f145a83af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3774 zcmV;v4ngsWP)$kl5 zqcT7g&?zu8?ezWYz4zUB-|zR9d+&Qy2xAN{qY(ew0A7^*gV^7jytKqPFV3{hZfovn zs%x!l>(m&Gdb8C+5XeR7>h0kj=o=X3A39;2KLYfEMt>p1YMW~dt`rpAC{lN~P>5pq zH1L4nAdCT17}*hN=LnEsvMl=5Ij^QArAa&_V~zoht-Ei~)E~(Ivhe0#jik{t$isEK znCH$TxCB8EKmcF>3@pRaHpbR%Gqm*dsZA4H{j(NjZFp^iNFW+RBx6R*X19J*`0XG5 z^Y>cR=^Hi9#ovYGlbFSr#Q*^PgCGC^gb*SC5TcBfzQLe-r2m!Quik&_g9XzTj0qSR zD`FkG_RYWDa^+#UUxL&t+!K+&(ion@Fd`5l5p7{Qsva9vegC|4^NzJUMvn)^gqWsF zvu^j=%FfCVg^cgbXDRl1DE$lsfe;BjjmFmRHER~E-MeWoNsyyNHCpG%Y}igd_(Md;&9La8_B075NDRX9gTD zIHY`}9E~aGi9Kk1@P~rmPna=*=gz~UTdTpsQmjX)J23%v9NliQS)8`xJh6Qz_nE~e z&tP|!dcJdo;JMNa3>afSx$lko8>fp-I}OiCVz(dOF1u6e8$IrsSP?=5mp~lkaFqm? zAUMxRq%ecIu3WE)Uf=%p8g z+RSY?G=VO%wAfdICj?Uzb+5jr{8m|)i#{M}JjaDIoXf#1=DYLwX;1EW&sijPvm6EkBGuOx6r~lKv`g`yH?)|&PRUr$5Ibw2HBM7C74XvE@gaPjN+@;j$J)AgYhnT-U5m+wj|Wz8K630AfO8PUoGD^^Mcq zY9C<~%wUm^u%ox5P21)KNN0$(v^OI$A~?iwsS_fRu1+`EH|CRdpA4zsk8Z#|?x@^vVEAL+2JxH%&^{JUU%B=?EU7`Ar*Q|JvqPofcBt765(*f5JI$>=3{<%K)4ei zogo$)5XP}_X$y^pIYyWTt}EAnhTq}u4sAdBvC(WC{I#x4^>$vCvQ0UDs^18sAQG9o zEaP0qjrSSv1W0FyO%9&y$@em~n@8}}EXBG6x%ew49J_q%l@As_XnNpi|MTTPr~ca_ zW%uon6dBKL*pvzYFvf<~p6K8hK9BDNNN0$7xp^hWC3n^7FoQ?P(=m(6!Pj&S2f1fqH=`(w)KcPl5aEi2}~4hF*f*g}vaS-=c7v>N8c z{yNM*%+azq=@prWtgpi~^3?^AsJqS(>=pb=6PrGH#=O{Hcho$_F#MtsK$$3e2fZvg zy}!-V%`+uFMOW87LIgu3vKuMgqwY0}*Sd;aokQp(F#-{}Ss(Iy1iekY1ZQX?1WEL? z7=zq`lH-#Hw=bHRio3yPun%`c5rI1Hb|wTSWTs|12Mg#QkkwTmy zAYul0H*_b(BnkP#!R_&p@d54uz0JKthGv3C^fdKS%~alookE`QX@%#MQN2=SFWrOha7Ij7ImStNaWsy~? zsylUeT02_-z-G4s0L!v=+Wx|cxr$tmY&$a1by8z#6HBp!*9{@mU9XQ0h@L%V_R}4g z&s#2{MCOj4`5ux-SUautC5@{U895o-biKMWWoQ09{|jx8wz}@_(ep%Yk4{90C#s6-sa}fU5{}m>#>VtE_b#5bn8O+3k{&6GoEkB;yGie;A_5Uy zqPN*tU()pE+_&~``5XX({el-xT_}%`%fsc>_0@m5{+FhXru>rpyLESe31R>cK^FFrCm+#WL$-D{Z3*9>Lg{wi}xEYn_`@Hy`-d z1N}kIY%@Eu&Bpe|Rr6N;%Yk>6&RI$lgpIO26BYT%C!dU-o4bqqQpGY?p6lPru6Hzc z@WuSDI^BYaDH*>R)~)$V1J0Edn4r(9vo>E<2XjOJr2*G124;t^U+p{iUnZN5oapCpCk(F}}<#3ZZli!Nk z^UWT;Q9qm-i`i$kJS}5P%puBJ<&krTO;*#$Y7d$o96EbQ{aF1XFpTj}wf}eI|IOba z%w}_CWu?JjkV>U-ad9L$@Mu$CU;pUQBZgt5QmI@n=W@9K(A(SF-rnxzy|_!5ekKqCQTad`sa|&&Q6jfy}iAEst?|mH*emIjg9SB zRVWlHl?r3bvh2qnf6V6(+>4TulB%kzFveeh{k1?K*t&J=m>dk9P8SjqQdn4sF;*&- z(b3VFnVH$y*$Rb%rs zefJ#z#KpyZ_0?C$jvY%)O?7a?7#}%u1OT>d*)keF*REZ=c=4j6tkr5MilS*cB_$;< zFArmEv)Oby-7}4>TD9uE_ulKT4s6Bp@^Y0*rBEo&o;?cy8#Zi^%jH+DTv4f1SFc_L zfc5LwXJ=;vKt@K!?%liR&!6Almmq$2R@G|tg$oyGnpP+jQBhF<(9qCOR8%AuiBtJCSc zyu1LQw6wIQre^Zw$^E0N)#}R1%J}$rkw`Qc#z0A{)dIkjDN`I(PfyS2=x9f~R4N64 zPe1*1=gytQ#l=RWao4V0bLY-=?Bpl*dQDA@LZMJ9l{Gar$;rvzfB$`Tb#+==T0=ua zSy@?1N{UXWyL9Q&#*G`Zv$GE#JXljxBauj2T3VD!rO9N<%F3#*uP-Sn(P%W=w{Jgx z{(NC!VNOmC0OaN6ZQHg@tJQw^;fGtdZUulVSFX&NGv~~iGoO9-nNq0~2n78w23E{L zmth7T3|W>10ISuSm6cUgRCMXmr5!tV0D!x@`?6)rcI?<8lgZ#IIehqVOiYYpi@x#3 z8xau^+1c4ER;th&( zVHk--A`l3|!os9dsYatANm8TH96x@%qM{-&FmUtc&2qVX-MV%A_U(J~%{TY#*<&ym zX3Ur|c$No?u%e>k#EBDaZEY7XUVLH`0zh|n zw_~XRz;RH!y1MS)zn_X$Km70mNs@ZKo~G$z$BuD09F}FpVzEY}F&d2ug#rLPJUpgPpKh}a^y$-i zJl@%}XHT6vRaaNHckf=MQYn>6Fk&*D<+ja0B z5C{a#&CQN-V`HPyXe3EeAP~gH#>U3RayT5ZSd1}tbaaSNDAZ^)j%n&QHMoE=7KubA zlWEeVNpiV7Dk=&gzM|0Dz(>0HA5Q-_F}_znz(xxqbU~E|+`a#EH|V zPjA|^DJLg~rs?+f_6rv-T)upnAP7fChoq;cFJHcV=gyt)zWXjs(+gZ<%kMDTlOd1+TFW%&z(D`)oKF*0@Bmd zLqkIy?RvewprGK+ojWv5%Ve?@D^>&r1p$CcrMhuv}x1&joiO~|IC>)G) - - -Lua 5.3 readme - - - - - - - -
      -

      -Lua -Welcome to Lua 5.3.0 -

      - -

      -about -· -installation -· -changes -· -license -· -reference manual - -

      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 -provides complete information -about Lua, -including -an -executive summary -and -updated -documentation, -especially the -reference manual, -which may differ slightly from the -local copy -distributed in this package. - -

      Installing Lua

      - -

      -Lua is distributed in -source -form. -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 -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. -See also -instructions for other systems -and -customization options. - -

      -If you don't have the time or the inclination to compile Lua yourself, -get a binary from -LuaBinaries. -Try also -LuaDist, -a multi-platform distribution of Lua that includes batteries. - -

      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.3.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 bsd c89 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, - c89, 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. - To check that Lua has been built correctly, do "make test" - after building Lua. This will run the interpreter and print its version. -
      -

      -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

      -

      - 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 the Makefile. You'll - probably need the right permissions to install files. - -

      - To build and install Lua in one step, do "make xxx install", - where xxx is your platform name. - -

      - To install Lua locally, do "make local". - This will create a directory install with subdirectories - bin, include, lib, man, share, - 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. - The installation starts in the src and doc directories, - so take care if INSTALL_TOP is not an absolute path. - -

      -
      - bin: -
      - lua luac -
      - include: -
      - lauxlib.h lua.h lua.hpp luaconf.h lualib.h -
      - lib: -
      - liblua.a -
      - man/man1: -
      - lua.1 luac.1 -
      - -

      - 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've made. - -

      - 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 available to experts by editing the Lua sources. - -

      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 lbitlib.c lcorolib.c ldblib.c liolib.c -lmathlib.c loslib.c lstrlib.c ltablib.c lutf8lib.c loadlib.c linit.c -
      -interpreter: -
      - library, lua.c -
      -compiler: -
      - library, luac.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 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. - For Windows, we recommend that the Lua library be a DLL. - In all cases, the compiler luac should be linked statically. - -

      - As mentioned above, you may edit src/luaconf.h to customize - some features before building Lua. - -

      Changes since Lua 5.2

      - -

      -Here are the main changes introduced in Lua 5.3. -The -reference manual -lists the -incompatibilities that had to be introduced. - -

      Main changes

      -
        -
      • integers (64-bit by default) -
      • official support for 32-bit numbers -
      • bitwise operators -
      • basic utf-8 support -
      • functions for packing and unpacking values - -
      - -Here are the other changes introduced in Lua 5.3: -

      Language

      -
        -
      • userdata can have any Lua value as uservalue -
      • integer division -
      • more flexible rules for some metamethods -
      - -

      Libraries

      -
        -
      • ipairs and the table library respect metamethods -
      • strip option in string.dump -
      • table library respects metamethods -
      • new function table.move -
      • new function string.pack -
      • new function string.unpack -
      • new function string.packsize -
      - -

      C API

      -
        -
      • simpler API for continuation functions in C -
      • lua_gettable and similar functions return type of resulted value -
      • strip option in lua_dump -
      • new function: lua_geti -
      • new function: lua_seti -
      • new function: lua_isyieldable -
      • new function: lua_numbertointeger -
      • new function: lua_rotate -
      • new function: lua_stringtonumber -
      - -

      Lua standalone interpreter

      -
        -
      • can be used as calculator; no need to prefix with '=' -
      • arg table available to all code -
      - -

      License

      - -[osi certified] - - -

      -Lua is free software distributed under the terms of the -MIT license -reproduced below; -it may 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, see -this. - -

      -Copyright © 1994–2014 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: -Fri Dec 12 09:58:42 BRST 2014 - - - - - diff --git a/src/Makefile b/src/Makefile deleted file mode 100644 index 7d1b02c6f4..0000000000 --- a/src/Makefile +++ /dev/null @@ -1,197 +0,0 @@ -# Makefile for building Lua -# See ../doc/readme.html for installation and customization instructions. - -# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= - -# Your platform. See PLATS for possible values. -PLAT= none - -CC= gcc -CFLAGS= -O2 -Wall -Wextra -DLUA_COMPAT_5_2 $(SYSCFLAGS) $(MYCFLAGS) -LDFLAGS= $(SYSLDFLAGS) $(MYLDFLAGS) -LIBS= -lm $(SYSLIBS) $(MYLIBS) - -AR= ar rcu -RANLIB= ranlib -RM= rm -f - -SYSCFLAGS= -SYSLDFLAGS= -SYSLIBS= - -MYCFLAGS= -MYLDFLAGS= -MYLIBS= -MYOBJS= - -# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE ======= - -PLATS= aix bsd c89 freebsd generic linux macosx mingw posix solaris - -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 lcorolib.o ldblib.o liolib.o \ - lmathlib.o loslib.o lstrlib.o ltablib.o lutf8lib.o loadlib.o linit.o -BASE_O= $(CORE_O) $(LIB_O) $(MYOBJS) - -LUA_T= lua -LUA_O= lua.o - -LUAC_T= luac -LUAC_O= luac.o - -ALL_O= $(BASE_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) - -o: $(ALL_O) - -a: $(ALL_A) - -$(LUA_A): $(BASE_O) - $(AR) $@ $(BASE_O) - $(RANLIB) $@ - -$(LUA_T): $(LUA_O) $(LUA_A) - $(CC) -o $@ $(LDFLAGS) $(LUA_O) $(LUA_A) $(LIBS) - -$(LUAC_T): $(LUAC_O) $(LUA_A) - $(CC) -o $@ $(LDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS) - -clean: - $(RM) $(ALL_T) $(ALL_O) - -depend: - @$(CC) $(CFLAGS) -MM l*.c - -echo: - @echo "PLAT= $(PLAT)" - @echo "CC= $(CC)" - @echo "CFLAGS= $(CFLAGS)" - @echo "LDFLAGS= $(SYSLDFLAGS)" - @echo "LIBS= $(LIBS)" - @echo "AR= $(AR)" - @echo "RANLIB= $(RANLIB)" - @echo "RM= $(RM)" - -# Convenience targets for popular platforms -ALL= all - -none: - @echo "Please do 'make PLATFORM' where PLATFORM is one of these:" - @echo " $(PLATS)" - -aix: - $(MAKE) $(ALL) CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-ldl" SYSLDFLAGS="-brtl -bexpall" - -bsd: - $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-Wl,-E" - -c89: - $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_C89" CC="gcc -std=c89" - @echo '' - @echo '*** C89 does not guarantee 64-bit integers for Lua.' - @echo '' - - -freebsd: - $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -lreadline" - -generic: $(ALL) - -linux: - $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline" - -macosx: - $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX" SYSLIBS="-lreadline" CC=cc - -mingw: - $(MAKE) "LUA_A=lua53.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" - -solaris: - $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN -D_REENTRANT" SYSLIBS="-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 lprefix.h 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 lprefix.h lua.h luaconf.h lauxlib.h -lbaselib.o: lbaselib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h -lbitlib.o: lbitlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h -lcode.o: lcode.c lprefix.h 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 lvm.h -lcorolib.o: lcorolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h -lctype.o: lctype.c lprefix.h lctype.h lua.h luaconf.h llimits.h -ldblib.o: ldblib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h -ldebug.o: ldebug.c lprefix.h 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 lprefix.h 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 lprefix.h lua.h luaconf.h lobject.h llimits.h lstate.h \ - ltm.h lzio.h lmem.h lundump.h -lfunc.o: lfunc.c lprefix.h lua.h luaconf.h lfunc.h lobject.h llimits.h \ - lgc.h lstate.h ltm.h lzio.h lmem.h -lgc.o: lgc.c lprefix.h 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 lprefix.h lua.h luaconf.h lualib.h lauxlib.h -liolib.o: liolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h -llex.o: llex.c lprefix.h lua.h luaconf.h lctype.h llimits.h ldo.h \ - lobject.h lstate.h ltm.h lzio.h lmem.h lgc.h llex.h lparser.h lstring.h \ - ltable.h -lmathlib.o: lmathlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h -lmem.o: lmem.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \ - llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h -loadlib.o: loadlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h -lobject.o: lobject.c lprefix.h 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 lprefix.h lopcodes.h llimits.h lua.h luaconf.h -loslib.o: loslib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h -lparser.o: lparser.c lprefix.h 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 lprefix.h 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 lprefix.h lua.h luaconf.h ldebug.h lstate.h \ - lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h -lstrlib.o: lstrlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h -ltable.o: ltable.c lprefix.h 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 lvm.h -ltablib.o: ltablib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h -ltm.o: ltm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \ - llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h ltable.h lvm.h -lua.o: lua.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h -luac.o: luac.c lprefix.h 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 lprefix.h 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 -lutf8lib.o: lutf8lib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h -lvm.o: lvm.c lprefix.h 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 lprefix.h lua.h luaconf.h llimits.h lmem.h lstate.h \ - lobject.h ltm.h lzio.h - -# (end of Makefile) diff --git a/src/lapi.c b/src/lapi.c deleted file mode 100644 index 92ef0782af..0000000000 --- a/src/lapi.c +++ /dev/null @@ -1,1270 +0,0 @@ -/* -** $Id: lapi.c,v 2.243 2014/11/12 13:28:54 roberto Exp $ -** Lua API -** See Copyright Notice in lua.h -*/ - -#define lapi_c -#define LUA_CORE - -#include "lprefix.h" - - -#include -#include - -#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 "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "ltm.h" -#include "lundump.h" -#include "lvm.h" - - - -const char lua_ident[] = - "$LuaVersion: " LUA_COPYRIGHT " $" - "$LuaAuthors: " LUA_AUTHORS " $"; - - -/* value at a non-valid index */ -#define NONVALIDVALUE cast(TValue *, luaO_nilobject) - -/* corresponding test */ -#define isvalid(o) ((o) != luaO_nilobject) - -/* test for pseudo index */ -#define ispseudo(i) ((i) <= LUA_REGISTRYINDEX) - -/* test for upvalue */ -#define isupvalue(i) ((i) < LUA_REGISTRYINDEX) - -/* test for valid but not pseudo index */ -#define isstackindex(i, o) (isvalid(o) && !ispseudo(i)) - -#define api_checkvalidindex(o) api_check(isvalid(o), "invalid index") - -#define api_checkstackindex(i, o) \ - api_check(isstackindex(i, o), "index not in the stack") - - -static TValue *index2addr (lua_State *L, int idx) { - CallInfo *ci = L->ci; - if (idx > 0) { - TValue *o = ci->func + idx; - api_check(idx <= ci->top - (ci->func + 1), "unacceptable index"); - if (o >= L->top) return NONVALIDVALUE; - else return o; - } - else if (!ispseudo(idx)) { /* negative index */ - api_check(idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); - return L->top + idx; - } - else if (idx == LUA_REGISTRYINDEX) - return &G(L)->l_registry; - else { /* upvalues */ - idx = LUA_REGISTRYINDEX - idx; - api_check(idx <= MAXUPVAL + 1, "upvalue index too large"); - if (ttislcf(ci->func)) /* light C function? */ - return NONVALIDVALUE; /* it has no upvalues */ - else { - CClosure *func = clCvalue(ci->func); - return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : NONVALIDVALUE; - } - } -} - - -/* -** to be called 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 n) { - int res; - CallInfo *ci = L->ci; - lua_lock(L); - api_check(n >= 0, "negative 'n'"); - if (L->stack_last - L->top > n) /* stack large enough? */ - res = 1; /* yes; check is OK */ - else { /* no; need to grow stack */ - int inuse = cast_int(L->top - L->stack) + EXTRA_STACK; - if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */ - res = 0; /* no */ - else /* try to grow stack */ - res = (luaD_rawrunprotected(L, &growstack, &n) == LUA_OK); - } - if (res && ci->top < L->top + n) - ci->top = L->top + n; /* adjust frame top */ - lua_unlock(L); - return res; -} - - -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); - api_check(G(from) == G(to), "moving among independent states"); - api_check(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); - } - 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 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; -} - - - -/* -** basic stack manipulation -*/ - - -/* -** convert an acceptable stack index into an absolute index -*/ -LUA_API int lua_absindex (lua_State *L, int idx) { - return (idx > 0 || ispseudo(idx)) - ? 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)); -} - - -LUA_API void lua_settop (lua_State *L, int idx) { - StkId func = L->ci->func; - lua_lock(L); - if (idx >= 0) { - api_check(idx <= L->stack_last - (func + 1), "new top too large"); - while (L->top < (func + 1) + idx) - setnilvalue(L->top++); - L->top = (func + 1) + idx; - } - else { - api_check(-(idx+1) <= (L->top - (func + 1)), "invalid new top"); - L->top += idx+1; /* 'subtract' index (index is negative) */ - } - lua_unlock(L); -} - - -/* -** Reverse the stack segment from 'from' to 'to' -** (auxiliary to 'lua_rotate') -*/ -static void reverse (lua_State *L, StkId from, StkId to) { - for (; from < to; from++, to--) { - TValue temp; - setobj(L, &temp, from); - setobjs2s(L, from, to); - setobj2s(L, to, &temp); - } -} - - -/* -** Let x = AB, where A is a prefix of length 'n'. Then, -** rotate x n == BA. But BA == (A^r . B^r)^r. -*/ -LUA_API void lua_rotate (lua_State *L, int idx, int n) { - StkId p, t, m; - lua_lock(L); - t = L->top - 1; /* end of stack segment being rotated */ - p = index2addr(L, idx); /* start of segment */ - api_checkstackindex(idx, p); - api_check((n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'"); - m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */ - reverse(L, p, m); /* reverse the prefix with length 'n' */ - reverse(L, m + 1, t); /* reverse the suffix */ - reverse(L, p, t); /* reverse the entire segment */ - lua_unlock(L); -} - - -LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) { - TValue *fr, *to; - lua_lock(L); - fr = index2addr(L, fromidx); - to = index2addr(L, toidx); - api_checkvalidindex(to); - setobj(L, to, fr); - if (isupvalue(toidx)) /* function upvalue? */ - luaC_barrier(L, clCvalue(L->ci->func), fr); - /* LUA_REGISTRYINDEX does not need gc barrier - (collector revisits it before finishing collection) */ - lua_unlock(L); -} - - -LUA_API void lua_pushvalue (lua_State *L, int idx) { - lua_lock(L); - setobj2s(L, L->top, index2addr(L, idx)); - api_incr_top(L); - lua_unlock(L); -} - - - -/* -** access functions (stack -> C) -*/ - - -LUA_API int lua_type (lua_State *L, int idx) { - StkId o = index2addr(L, idx); - return (isvalid(o) ? ttnov(o) : LUA_TNONE); -} - - -LUA_API const char *lua_typename (lua_State *L, int t) { - UNUSED(L); - api_check(LUA_TNONE <= t && t < LUA_NUMTAGS, "invalid tag"); - return ttypename(t); -} - - -LUA_API int lua_iscfunction (lua_State *L, int idx) { - StkId o = index2addr(L, idx); - return (ttislcf(o) || (ttisCclosure(o))); -} - - -LUA_API int lua_isinteger (lua_State *L, int idx) { - StkId o = index2addr(L, idx); - return ttisinteger(o); -} - - -LUA_API int lua_isnumber (lua_State *L, int idx) { - lua_Number n; - const TValue *o = index2addr(L, idx); - return tonumber(o, &n); -} - - -LUA_API int lua_isstring (lua_State *L, int idx) { - const TValue *o = index2addr(L, idx); - return (ttisstring(o) || cvt2str(o)); -} - - -LUA_API int lua_isuserdata (lua_State *L, int idx) { - const TValue *o = index2addr(L, idx); - return (ttisfulluserdata(o) || ttislightuserdata(o)); -} - - -LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { - StkId o1 = index2addr(L, index1); - StkId o2 = index2addr(L, index2); - return (isvalid(o1) && isvalid(o2)) ? luaV_rawequalobj(o1, o2) : 0; -} - - -LUA_API void lua_arith (lua_State *L, int op) { - lua_lock(L); - if (op != LUA_OPUNM && op != LUA_OPBNOT) - api_checknelems(L, 2); /* all other operations expect two operands */ - else { /* for unary operations, add fake 2nd operand */ - api_checknelems(L, 1); - setobjs2s(L, L->top, L->top - 1); - L->top++; - } - /* first operand at top - 2, second at top - 1; result go to top - 2 */ - luaO_arith(L, op, L->top - 2, L->top - 1, L->top - 2); - L->top--; /* remove second operand */ - lua_unlock(L); -} - - -LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) { - StkId o1, o2; - int i = 0; - lua_lock(L); /* may call tag method */ - o1 = index2addr(L, index1); - o2 = index2addr(L, index2); - if (isvalid(o1) && isvalid(o2)) { - switch (op) { - case LUA_OPEQ: i = luaV_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(0, "invalid option"); - } - } - lua_unlock(L); - return i; -} - - -LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) { - size_t sz = luaO_str2num(s, L->top); - if (sz != 0) - api_incr_top(L); - return sz; -} - - -LUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *pisnum) { - lua_Number n; - const TValue *o = index2addr(L, idx); - int isnum = tonumber(o, &n); - if (!isnum) - n = 0; /* call to 'tonumber' may change 'n' even if it fails */ - if (pisnum) *pisnum = isnum; - return n; -} - - -LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *pisnum) { - lua_Integer res; - const TValue *o = index2addr(L, idx); - int isnum = tointeger(o, &res); - if (!isnum) - res = 0; /* call to 'tointeger' may change 'n' even if it fails */ - if (pisnum) *pisnum = isnum; - return res; -} - - -LUA_API int lua_toboolean (lua_State *L, int 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 = index2addr(L, idx); - if (!ttisstring(o)) { - if (!cvt2str(o)) { /* not convertible? */ - if (len != NULL) *len = 0; - return NULL; - } - lua_lock(L); /* 'luaO_tostring' may create a new string */ - luaC_checkGC(L); - o = index2addr(L, idx); /* previous call may reallocate the stack */ - luaO_tostring(L, o); - lua_unlock(L); - } - if (len != NULL) *len = tsvalue(o)->len; - return svalue(o); -} - - -LUA_API size_t lua_rawlen (lua_State *L, int idx) { - StkId o = index2addr(L, idx); - switch (ttnov(o)) { - case LUA_TSTRING: return tsvalue(o)->len; - case LUA_TUSERDATA: return uvalue(o)->len; - case LUA_TTABLE: return luaH_getn(hvalue(o)); - default: return 0; - } -} - - -LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { - StkId o = index2addr(L, idx); - if (ttislcf(o)) return fvalue(o); - 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 (ttnov(o)) { - case LUA_TUSERDATA: return getudatamem(uvalue(o)); - case LUA_TLIGHTUSERDATA: return pvalue(o); - default: return NULL; - } -} - - -LUA_API lua_State *lua_tothread (lua_State *L, int 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 = index2addr(L, idx); - switch (ttype(o)) { - case LUA_TTABLE: return hvalue(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: - case LUA_TLIGHTUSERDATA: - return lua_touserdata(L, idx); - default: return NULL; - } -} - - - -/* -** push functions (C -> stack) -*/ - - -LUA_API void lua_pushnil (lua_State *L) { - lua_lock(L); - setnilvalue(L->top); - api_incr_top(L); - lua_unlock(L); -} - - -LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { - lua_lock(L); - setfltvalue(L->top, n); - api_incr_top(L); - lua_unlock(L); -} - - -LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { - lua_lock(L); - setivalue(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); - luaC_checkGC(L); - ts = luaS_newlstr(L, s, len); - setsvalue2s(L, L->top, ts); - api_incr_top(L); - lua_unlock(L); - return getstr(ts); -} - - -LUA_API const char *lua_pushstring (lua_State *L, const char *s) { - if (s == NULL) { - lua_pushnil(L); - return NULL; - } - 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); - } -} - - -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 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; -} - - -LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { - lua_lock(L); - if (n == 0) { - setfvalue(L->top, fn); - } - else { - CClosure *cl; - api_checknelems(L, n); - api_check(n <= MAXUPVAL, "upvalue index too large"); - luaC_checkGC(L); - cl = luaF_newCclosure(L, n); - cl->f = fn; - L->top -= n; - while (n--) { - setobj2n(L, &cl->upvalue[n], L->top + n); - /* does not need barrier because closure is white */ - } - setclCvalue(L, L->top, cl); - } - api_incr_top(L); - lua_unlock(L); -} - - -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_pushlightuserdata (lua_State *L, void *p) { - lua_lock(L); - setpvalue(L->top, p); - api_incr_top(L); - lua_unlock(L); -} - - -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) -*/ - - -LUA_API int lua_getglobal (lua_State *L, const char *name) { - 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, name)); - luaV_gettable(L, gt, L->top - 1, L->top - 1); - lua_unlock(L); - return ttnov(L->top - 1); -} - - -LUA_API int lua_gettable (lua_State *L, int idx) { - StkId t; - lua_lock(L); - t = index2addr(L, idx); - luaV_gettable(L, t, L->top - 1, L->top - 1); - lua_unlock(L); - return ttnov(L->top - 1); -} - - -LUA_API int lua_getfield (lua_State *L, int idx, const char *k) { - StkId t; - lua_lock(L); - t = index2addr(L, idx); - 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); - return ttnov(L->top - 1); -} - - -LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { - StkId t; - lua_lock(L); - t = index2addr(L, idx); - setivalue(L->top, n); - api_incr_top(L); - luaV_gettable(L, t, L->top - 1, L->top - 1); - lua_unlock(L); - return ttnov(L->top - 1); -} - - -LUA_API int lua_rawget (lua_State *L, int idx) { - StkId t; - lua_lock(L); - t = index2addr(L, idx); - api_check(ttistable(t), "table expected"); - setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); - lua_unlock(L); - return ttnov(L->top - 1); -} - - -LUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) { - StkId t; - lua_lock(L); - t = index2addr(L, idx); - api_check(ttistable(t), "table expected"); - setobj2s(L, L->top, luaH_getint(hvalue(t), n)); - api_incr_top(L); - lua_unlock(L); - return ttnov(L->top - 1); -} - - -LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) { - StkId t; - TValue k; - lua_lock(L); - t = index2addr(L, idx); - api_check(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); - return ttnov(L->top - 1); -} - - -LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { - Table *t; - lua_lock(L); - luaC_checkGC(L); - 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); -} - - -LUA_API int lua_getmetatable (lua_State *L, int objindex) { - const TValue *obj; - Table *mt = NULL; - int res = 0; - lua_lock(L); - obj = index2addr(L, objindex); - switch (ttnov(obj)) { - case LUA_TTABLE: - mt = hvalue(obj)->metatable; - break; - case LUA_TUSERDATA: - mt = uvalue(obj)->metatable; - break; - default: - mt = G(L)->mt[ttnov(obj)]; - break; - } - if (mt != NULL) { - sethvalue(L, L->top, mt); - api_incr_top(L); - res = 1; - } - lua_unlock(L); - return res; -} - - -LUA_API int lua_getuservalue (lua_State *L, int idx) { - StkId o; - lua_lock(L); - o = index2addr(L, idx); - api_check(ttisfulluserdata(o), "full userdata expected"); - getuservalue(L, uvalue(o), L->top); - api_incr_top(L); - lua_unlock(L); - return ttnov(L->top - 1); -} - - -/* -** set functions (stack -> Lua) -*/ - - -LUA_API void lua_setglobal (lua_State *L, const char *name) { - 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, name)); - 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); - api_checknelems(L, 2); - t = index2addr(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_setfield (lua_State *L, int idx, const char *k) { - StkId t; - lua_lock(L); - api_checknelems(L, 1); - t = index2addr(L, idx); - 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); -} - - -LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { - StkId t; - lua_lock(L); - api_checknelems(L, 1); - t = index2addr(L, idx); - setivalue(L->top++, n); - luaV_settable(L, t, L->top - 1, L->top - 2); - L->top -= 2; /* pop value and key */ - lua_unlock(L); -} - - -LUA_API void lua_rawset (lua_State *L, int idx) { - StkId o; - Table *t; - lua_lock(L); - api_checknelems(L, 2); - o = index2addr(L, idx); - api_check(ttistable(o), "table expected"); - t = hvalue(o); - setobj2t(L, luaH_set(L, t, L->top-2), L->top-1); - invalidateTMcache(t); - luaC_barrierback(L, t, L->top-1); - L->top -= 2; - lua_unlock(L); -} - - -LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) { - StkId o; - Table *t; - lua_lock(L); - api_checknelems(L, 1); - o = index2addr(L, idx); - api_check(ttistable(o), "table expected"); - t = hvalue(o); - luaH_setint(L, t, n, L->top - 1); - luaC_barrierback(L, t, L->top-1); - L->top--; - lua_unlock(L); -} - - -LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) { - StkId o; - Table *t; - TValue k; - lua_lock(L); - api_checknelems(L, 1); - o = index2addr(L, idx); - api_check(ttistable(o), "table expected"); - t = hvalue(o); - setpvalue(&k, cast(void *, p)); - setobj2t(L, luaH_set(L, t, &k), L->top - 1); - luaC_barrierback(L, t, L->top - 1); - L->top--; - lua_unlock(L); -} - - -LUA_API int lua_setmetatable (lua_State *L, int objindex) { - TValue *obj; - Table *mt; - lua_lock(L); - api_checknelems(L, 1); - obj = index2addr(L, objindex); - if (ttisnil(L->top - 1)) - mt = NULL; - else { - api_check(ttistable(L->top - 1), "table expected"); - mt = hvalue(L->top - 1); - } - switch (ttnov(obj)) { - case LUA_TTABLE: { - hvalue(obj)->metatable = mt; - if (mt) { - luaC_objbarrier(L, gcvalue(obj), mt); - luaC_checkfinalizer(L, gcvalue(obj), mt); - } - break; - } - case LUA_TUSERDATA: { - uvalue(obj)->metatable = mt; - if (mt) { - luaC_objbarrier(L, uvalue(obj), mt); - luaC_checkfinalizer(L, gcvalue(obj), mt); - } - break; - } - default: { - G(L)->mt[ttnov(obj)] = mt; - break; - } - } - L->top--; - lua_unlock(L); - return 1; -} - - -LUA_API void lua_setuservalue (lua_State *L, int idx) { - StkId o; - lua_lock(L); - api_checknelems(L, 1); - o = index2addr(L, idx); - api_check(ttisfulluserdata(o), "full userdata expected"); - setuservalue(L, uvalue(o), L->top - 1); - luaC_barrier(L, gcvalue(o), L->top - 1); - L->top--; - lua_unlock(L); -} - - -/* -** 'load' and 'call' functions (run Lua code) -*/ - - -#define checkresults(L,na,nr) \ - api_check((nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \ - "results from function overflow current stack size") - - -LUA_API void lua_callk (lua_State *L, int nargs, int nresults, - lua_KContext ctx, lua_KFunction k) { - StkId func; - lua_lock(L); - api_check(k == NULL || !isLua(L->ci), - "cannot use continuations inside hooks"); - api_checknelems(L, nargs+1); - api_check(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? */ - 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); -} - - - -/* -** 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 = cast(struct CallS *, ud); - luaD_call(L, c->func, c->nresults, 0); -} - - - -LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, - lua_KContext ctx, lua_KFunction k) { - struct CallS c; - int status; - ptrdiff_t func; - lua_lock(L); - api_check(k == NULL || !isLua(L->ci), - "cannot use continuations inside hooks"); - api_checknelems(L, nargs+1); - api_check(L->status == LUA_OK, "cannot do calls on non-normal thread"); - checkresults(L, nargs, nresults); - if (errfunc == 0) - func = 0; - else { - StkId o = index2addr(L, errfunc); - api_checkstackindex(errfunc, o); - func = savestack(L, o); - } - c.func = L->top - (nargs+1); /* function to be called */ - 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->extra = savestack(L, c.func); - ci->u.c.old_errfunc = L->errfunc; - L->errfunc = func; - setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */ - ci->callstatus |= CIST_YPCALL; /* function can do error recovery */ - 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; -} - - -LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, - const char *chunkname, const char *mode) { - ZIO z; - int status; - lua_lock(L); - if (!chunkname) chunkname = "?"; - luaZ_init(L, &z, reader, data); - status = luaD_protectedparser(L, &z, chunkname, mode); - if (status == LUA_OK) { /* no errors? */ - LClosure *f = clLvalue(L->top - 1); /* get newly created function */ - if (f->nupvalues >= 1) { /* does it have an 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->upvals[0]->v, gt); - luaC_upvalbarrier(L, f->upvals[0]); - } - } - lua_unlock(L); - return status; -} - - -LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) { - int status; - TValue *o; - lua_lock(L); - api_checknelems(L, 1); - o = L->top - 1; - if (isLfunction(o)) - status = luaU_dump(L, getproto(o), writer, data, strip); - else - status = 1; - lua_unlock(L); - return status; -} - - -LUA_API int lua_status (lua_State *L) { - return L->status; -} - - -/* -** Garbage-collection function -*/ - -LUA_API int lua_gc (lua_State *L, int what, int data) { - int res = 0; - global_State *g; - lua_lock(L); - g = G(L); - switch (what) { - case LUA_GCSTOP: { - g->gcrunning = 0; - break; - } - case LUA_GCRESTART: { - luaE_setdebt(g, 0); - g->gcrunning = 1; - break; - } - case LUA_GCCOLLECT: { - luaC_fullgc(L, 0); - break; - } - case LUA_GCCOUNT: { - /* GC values are expressed in Kbytes: #bytes/2^10 */ - res = cast_int(gettotalbytes(g) >> 10); - break; - } - case LUA_GCCOUNTB: { - res = cast_int(gettotalbytes(g) & 0x3ff); - break; - } - case LUA_GCSTEP: { - l_mem debt = 1; /* =1 to signal that it did an actual step */ - int oldrunning = g->gcrunning; - g->gcrunning = 1; /* allow GC to run */ - if (data == 0) { - luaE_setdebt(g, -GCSTEPSIZE); /* to do a "small" step */ - luaC_step(L); - } - else { /* add 'data' to total debt */ - debt = cast(l_mem, data) * 1024 + g->GCdebt; - luaE_setdebt(g, debt); - luaC_checkGC(L); - } - g->gcrunning = oldrunning; /* restore previous state */ - if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */ - res = 1; /* signal it */ - break; - } - case LUA_GCSETPAUSE: { - res = g->gcpause; - g->gcpause = data; - break; - } - case LUA_GCSETSTEPMUL: { - res = g->gcstepmul; - if (data < 40) data = 40; /* avoid ridiculous low values (and 0) */ - g->gcstepmul = data; - break; - } - case LUA_GCISRUNNING: { - res = g->gcrunning; - break; - } - default: res = -1; /* invalid option */ - } - lua_unlock(L); - return res; -} - - - -/* -** miscellaneous functions -*/ - - -LUA_API int lua_error (lua_State *L) { - lua_lock(L); - api_checknelems(L, 1); - luaG_errormsg(L); - /* code unreachable; will unlock when control actually leaves the kernel */ - return 0; /* to avoid warnings */ -} - - -LUA_API int lua_next (lua_State *L, int idx) { - StkId t; - int more; - lua_lock(L); - t = index2addr(L, idx); - api_check(ttistable(t), "table expected"); - more = luaH_next(L, hvalue(t), L->top - 1); - if (more) { - api_incr_top(L); - } - else /* no more elements */ - L->top -= 1; /* remove key */ - lua_unlock(L); - return more; -} - - -LUA_API void lua_concat (lua_State *L, int n) { - lua_lock(L); - api_checknelems(L, n); - if (n >= 2) { - luaC_checkGC(L); - luaV_concat(L, n); - } - else if (n == 0) { /* push empty string */ - setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); - api_incr_top(L); - } - /* else n == 1; nothing to do */ - lua_unlock(L); -} - - -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); - if (ud) *ud = G(L)->ud; - 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); -} - - -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, L->top, u); - api_incr_top(L); - lua_unlock(L); - return getudatamem(u); -} - - - -static const char *aux_upvalue (StkId fi, int n, TValue **val, - CClosure **owner, UpVal **uv) { - 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 = f; - return ""; - } - case LUA_TLCL: { /* Lua closure */ - LClosure *f = clLvalue(fi); - TString *name; - Proto *p = f->p; - if (!(1 <= n && n <= p->sizeupvalues)) return NULL; - *val = f->upvals[n-1]->v; - if (uv) *uv = f->upvals[n - 1]; - name = p->upvalues[n-1].name; - return (name == NULL) ? "(*no name)" : getstr(name); - } - default: return NULL; /* not a closure */ - } -} - - -LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { - const char *name; - TValue *val = NULL; /* to avoid warnings */ - lua_lock(L); - name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL, NULL); - if (name) { - setobj2s(L, L->top, val); - api_incr_top(L); - } - lua_unlock(L); - return name; -} - - -LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { - const char *name; - TValue *val = NULL; /* to avoid warnings */ - CClosure *owner = NULL; - UpVal *uv = NULL; - StkId fi; - lua_lock(L); - fi = index2addr(L, funcindex); - api_checknelems(L, 1); - name = aux_upvalue(fi, n, &val, &owner, &uv); - if (name) { - L->top--; - setobj(L, val, L->top); - if (owner) { luaC_barrier(L, owner, L->top); } - else if (uv) { luaC_upvalbarrier(L, uv); } - } - lua_unlock(L); - return name; -} - - -static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) { - LClosure *f; - StkId fi = index2addr(L, fidx); - api_check(ttisLclosure(fi), "Lua function expected"); - f = clLvalue(fi); - api_check((1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index"); - if (pf) *pf = f; - return &f->upvals[n - 1]; /* get its upvalue pointer */ -} - - -LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) { - StkId fi = index2addr(L, fidx); - 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(1 <= n && n <= f->nupvalues, "invalid upvalue index"); - return &f->upvalue[n - 1]; - } - default: { - api_check(0, "closure expected"); - return NULL; - } - } -} - - -LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1, - int fidx2, int n2) { - LClosure *f1; - UpVal **up1 = getupvalref(L, fidx1, n1, &f1); - UpVal **up2 = getupvalref(L, fidx2, n2, NULL); - luaC_upvdeccount(L, *up1); - *up1 = *up2; - (*up1)->refcount++; - if (upisopen(*up1)) (*up1)->u.open.touched = 1; - luaC_upvalbarrier(L, *up1); -} - - diff --git a/src/lapi.h b/src/lapi.h deleted file mode 100644 index 092f5e974c..0000000000 --- a/src/lapi.h +++ /dev/null @@ -1,24 +0,0 @@ -/* -** $Id: lapi.h,v 2.8 2014/07/15 21:26:50 roberto Exp $ -** Auxiliary functions from Lua API -** See Copyright Notice in lua.h -*/ - -#ifndef lapi_h -#define lapi_h - - -#include "llimits.h" -#include "lstate.h" - -#define api_incr_top(L) {L->top++; api_check(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((n) < (L->top - L->ci->func), \ - "not enough elements in the stack") - - -#endif diff --git a/src/lauxlib.c b/src/lauxlib.c deleted file mode 100644 index 1c41d6a8ea..0000000000 --- a/src/lauxlib.c +++ /dev/null @@ -1,972 +0,0 @@ -/* -** $Id: lauxlib.c,v 1.279 2014/12/14 18:32:26 roberto Exp $ -** Auxiliary functions for building Lua libraries -** See Copyright Notice in lua.h -*/ - -#define lauxlib_c -#define LUA_LIB - -#include "lprefix.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. -*/ - -#include "lua.h" - -#include "lauxlib.h" - - -/* -** {====================================================== -** 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) { - if (level == 0 || !lua_istable(L, -1)) - return 0; /* not found */ - lua_pushnil(L); /* start 'next' loop */ - 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) */ - 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 */ -} - - -/* -** Search for a name for a function in all loaded modules -** (registry._LOADED). -*/ -static int pushglobalfuncname (lua_State *L, lua_Debug *ar) { - int top = lua_gettop(L); - lua_getinfo(L, "f", ar); /* push function */ - lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); - if (findfield(L, top + 1, 2)) { - const char *name = lua_tostring(L, -1); - if (strncmp(name, "_G.", 3) == 0) { /* name start with '_G.'? */ - lua_pushstring(L, name + 3); /* push name without prefix */ - lua_remove(L, -2); /* remove original name */ - } - 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 (pushglobalfuncname(L, ar)) { /* try first a global name */ - lua_pushfstring(L, "function '%s'", lua_tostring(L, -1)); - lua_remove(L, -2); /* remove name */ - } - else if (*ar->namewhat != '\0') /* is there a name from code? */ - lua_pushfstring(L, "%s '%s'", ar->namewhat, ar->name); /* use it */ - else if (*ar->what == 'm') /* main? */ - lua_pushliteral(L, "main chunk"); - else if (*ar->what != 'C') /* for Lua functions, use */ - lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); - else /* nothing left... */ - lua_pushliteral(L, "?"); -} - - -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 arg, const char *extramsg) { - lua_Debug ar; - if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ - return luaL_error(L, "bad argument #%d (%s)", arg, extramsg); - lua_getinfo(L, "n", &ar); - if (strcmp(ar.namewhat, "method") == 0) { - arg--; /* do not count 'self' */ - if (arg == 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 = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?"; - return luaL_error(L, "bad argument #%d to '%s' (%s)", - arg, ar.name, extramsg); -} - - -static int typeerror (lua_State *L, int arg, const char *tname) { - const char *msg; - const char *typearg; /* name for the type of the actual argument */ - if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING) - typearg = lua_tostring(L, -1); /* use the given type name */ - else if (lua_type(L, arg) == LUA_TLIGHTUSERDATA) - typearg = "light userdata"; /* special name for messages */ - else - typearg = luaL_typename(L, arg); /* standard name */ - msg = lua_pushfstring(L, "%s expected, got %s", tname, typearg); - return luaL_argerror(L, arg, msg); -} - - -static void tag_error (lua_State *L, int arg, int tag) { - typeerror(L, arg, 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, "Sl", &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_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_pushstring(L, strerror(en)); - lua_pushinteger(L, en); - return 3; - } -} - - -#if !defined(l_inspectstat) /* { */ - -#if defined(LUA_USE_POSIX) - -#include - -/* -** use appropriate macros to interpret 'pclose' return status -*/ -#define l_inspectstat(stat,what) \ - if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \ - else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; } - -#else - -#define l_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 { - l_inspectstat(stat, what); /* interpret result */ - if (*what == 'e' && stat == 0) /* successful termination? */ - lua_pushboolean(L, 1); - else - lua_pushnil(L); - lua_pushstring(L, what); - lua_pushinteger(L, stat); - return 3; /* return true/nil,what,code */ - } -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Userdata's metatable manipulation -** ======================================================= -*/ - -LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { - if (luaL_getmetatable(L, tname)) /* 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_setfield(L, -2, "__name"); /* metatable.__name = tname */ - lua_pushvalue(L, -1); - lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ - return 1; -} - - -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? */ - if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ - luaL_getmetatable(L, tname); /* get correct metatable */ - 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; - } - } - 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) typeerror(L, ud, tname); - return p; -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Argument check functions -** ======================================================= -*/ - -LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def, - const char *const lst[]) { - const char *name = (def) ? luaL_optstring(L, arg, def) : - luaL_checkstring(L, arg); - int i; - for (i=0; lst[i]; i++) - if (strcmp(lst[i], name) == 0) - return i; - return luaL_argerror(L, arg, - lua_pushfstring(L, "invalid option '%s'", name)); -} - - -LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { - /* 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 - luaL_error(L, "stack overflow"); - } -} - - -LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) { - if (lua_type(L, arg) != t) - tag_error(L, arg, t); -} - - -LUALIB_API void luaL_checkany (lua_State *L, int arg) { - if (lua_type(L, arg) == LUA_TNONE) - luaL_argerror(L, arg, "value expected"); -} - - -LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) { - const char *s = lua_tolstring(L, arg, len); - if (!s) tag_error(L, arg, LUA_TSTRING); - return s; -} - - -LUALIB_API const char *luaL_optlstring (lua_State *L, int arg, - const char *def, size_t *len) { - if (lua_isnoneornil(L, arg)) { - if (len) - *len = (def ? strlen(def) : 0); - return def; - } - else return luaL_checklstring(L, arg, len); -} - - -LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) { - int isnum; - lua_Number d = lua_tonumberx(L, arg, &isnum); - if (!isnum) - tag_error(L, arg, LUA_TNUMBER); - return d; -} - - -LUALIB_API lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number def) { - return luaL_opt(L, luaL_checknumber, arg, def); -} - - -static void interror (lua_State *L, int arg) { - if (lua_isnumber(L, arg)) - luaL_argerror(L, arg, "number has no integer representation"); - else - tag_error(L, arg, LUA_TNUMBER); -} - - -LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) { - int isnum; - lua_Integer d = lua_tointegerx(L, arg, &isnum); - if (!isnum) { - interror(L, arg); - } - return d; -} - - -LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg, - lua_Integer def) { - return luaL_opt(L, luaL_checkinteger, arg, def); -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Generic Buffer manipulation -** ======================================================= -*/ - -/* -** check whether buffer is using a userdata on the stack as a temporary -** buffer -*/ -#define buffonstack(B) ((B)->b != (B)->initb) - - -/* -** 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 big enough? */ - newsize = B->n + sz; - if (newsize < B->n || newsize - B->n < sz) - luaL_error(L, "buffer too large"); - /* 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; - B->size = newsize; - } - return &B->b[B->n]; -} - - -LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { - char *b = luaL_prepbuffsize(B, l); - memcpy(b, s, l * sizeof(char)); - luaL_addsize(B, l); -} - - -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) { - 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 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) { - B->L = L; - 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); -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Reference system -** ======================================================= -*/ - -/* index of free-list header */ -#define freelist 0 - - -LUALIB_API int luaL_ref (lua_State *L, int t) { - int ref; - if (lua_isnil(L, -1)) { - lua_pop(L, 1); /* remove from stack */ - return LUA_REFNIL; /* 'nil' has a unique fixed reference */ - } - t = lua_absindex(L, t); - 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_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */ - } - else /* no free elements */ - ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */ - lua_rawseti(L, t, ref); - return ref; -} - - -LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { - if (ref >= 0) { - t = lua_absindex(L, t); - lua_rawgeti(L, t, freelist); - lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */ - lua_pushinteger(L, ref); - lua_rawseti(L, t, freelist); /* t[freelist] = ref */ - } -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Load functions -** ======================================================= -*/ - -typedef struct LoadF { - int n; /* number of pre-read characters */ - FILE *f; /* file being read */ - char buff[BUFSIZ]; /* area for reading file */ -} LoadF; - - -static const char *getF (lua_State *L, void *ud, size_t *size) { - LoadF *lf = (LoadF *)ud; - (void)L; /* not used */ - 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 { /* 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); /* read block */ - } - return lf->buff; -} - - -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 %s %s: %s", what, filename, serr); - lua_remove(L, fnameindex); - return LUA_ERRFILE; -} - - -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 != *(const 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 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 (LoadF *lf, int *cp) { - int c = *cp = skipBOM(lf); - if (c == '#') { /* first line is a comment (Unix exec. file)? */ - do { /* skip first line */ - c = getc(lf->f); - } while (c != EOF && c != '\n') ; - *cp = getc(lf->f); /* skip end-of-line, if present */ - return 1; /* there was a comment */ - } - else return 0; /* no comment */ -} - - -LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, - const char *mode) { - 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, "open", fnameindex); - } - 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 != EOF) - lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ - status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode); - readstatus = ferror(lf.f); - if (filename) fclose(lf.f); /* close file (even in case of errors) */ - if (readstatus) { - lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ - return errfile(L, "read", 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; /* not used */ - if (ls->size == 0) return NULL; - *size = ls->size; - ls->size = 0; - return ls->s; -} - - -LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size, - const char *name, const char *mode) { - LoadS ls; - ls.s = buff; - ls.size = size; - return lua_load(L, getS, &ls, name, mode); -} - - -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 LUA_TNIL; - else { - int tt; - lua_pushstring(L, event); - tt = lua_rawget(L, -2); - if (tt == LUA_TNIL) /* is metafield nil? */ - lua_pop(L, 2); /* remove metatable and metafield */ - else - lua_remove(L, -2); /* remove only metatable */ - return tt; /* return metafield type */ - } -} - - -LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { - obj = lua_absindex(L, obj); - if (luaL_getmetafield(L, obj, event) == LUA_TNIL) /* no metafield? */ - return 0; - lua_pushvalue(L, obj); - lua_call(L, 1, 1); - return 1; -} - - -LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) { - lua_Integer l; - int isnum; - lua_len(L, idx); - l = lua_tointegerx(L, -1, &isnum); - if (!isnum) - luaL_error(L, "object length is not an integer"); - 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: { - if (lua_isinteger(L, idx)) - lua_pushfstring(L, "%I", lua_tointeger(L, idx)); - else - lua_pushfstring(L, "%f", lua_tonumber(L, idx)); - break; - } - 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); -} - - -/* -** {====================================================== -** Compatibility with 5.1 module functions -** ======================================================= -*/ -#if defined(LUA_COMPAT_MODULE) - -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 { - e = strchr(fname, '.'); - if (e == NULL) e = fname + strlen(fname); - lua_pushlstring(L, fname, e - fname); - if (lua_rawget(L, -2) == LUA_TNIL) { /* 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++; - return size; -} - - -/* -** 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_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); /* get _LOADED table */ - if (lua_getfield(L, -1, modname) != LUA_TTABLE) { /* no _LOADED[modname]? */ - 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, sizehint) != NULL) - luaL_error(L, "name conflict for module '%s'", 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) { - luaL_pushmodule(L, libname, libsize(l)); /* get/create library table */ - lua_insert(L, -(nup + 1)); /* move library table to below upvalues */ - } - if (l) - luaL_setfuncs(L, l, nup); - else - lua_pop(L, nup); /* remove upvalues */ -} - -#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->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); - 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 int luaL_getsubtable (lua_State *L, int idx, const char *fname) { - if (lua_getfield(L, idx, fname) == LUA_TTABLE) - return 1; /* table already there */ - else { - lua_pop(L, 1); /* remove previous result */ - idx = lua_absindex(L, idx); - 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 */ - } -} - - -/* -** Stripped-down 'require': After checking "loaded" table, 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) { - luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); - lua_getfield(L, -1, modname); /* _LOADED[modname] */ - if (!lua_toboolean(L, -1)) { /* package not already loaded? */ - lua_pop(L, 1); /* remove field */ - lua_pushcfunction(L, openf); - lua_pushstring(L, modname); /* argument to open function */ - lua_call(L, 1, 1); /* call 'openf' to open module */ - lua_pushvalue(L, -1); /* make copy of module (call result) */ - lua_setfield(L, -3, modname); /* _LOADED[modname] = module */ - } - lua_remove(L, -2); /* remove _LOADED table */ - if (glb) { - lua_pushvalue(L, -1); /* copy of module */ - lua_setglobal(L, modname); /* _G[modname] = module */ - } -} - - -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); -} - - -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); - return NULL; - } - else - return realloc(ptr, nsize); -} - - -static int panic (lua_State *L) { - lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", - lua_tostring(L, -1)); - return 0; /* return to Lua to abort */ -} - - -LUALIB_API lua_State *luaL_newstate (void) { - lua_State *L = lua_newstate(l_alloc, NULL); - if (L) lua_atpanic(L, &panic); - return L; -} - - -LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) { - const lua_Number *v = lua_version(L); - if (sz != LUAL_NUMSIZES) /* check numeric types */ - luaL_error(L, "core and library have incompatible numeric types"); - if (v != lua_version(NULL)) - luaL_error(L, "multiple Lua VMs detected"); - else if (*v != ver) - luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f", - ver, *v); -} - diff --git a/src/lauxlib.h b/src/lauxlib.h deleted file mode 100644 index 0bac2467ec..0000000000 --- a/src/lauxlib.h +++ /dev/null @@ -1,256 +0,0 @@ -/* -** $Id: lauxlib.h,v 1.128 2014/10/29 16:11:17 roberto Exp $ -** Auxiliary functions for building Lua libraries -** See Copyright Notice in lua.h -*/ - - -#ifndef lauxlib_h -#define lauxlib_h - - -#include -#include - -#include "lua.h" - - - -/* extra error code for 'luaL_load' */ -#define LUA_ERRFILE (LUA_ERRERR+1) - - -typedef struct luaL_Reg { - const char *name; - lua_CFunction func; -} luaL_Reg; - - -#define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number)) - -LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz); -#define luaL_checkversion(L) \ - luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES) - -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_argerror) (lua_State *L, int arg, const char *extramsg); -LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg, - size_t *l); -LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg, - const char *def, size_t *l); -LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg); -LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def); - -LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg); -LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg, - 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 arg, int t); -LUALIB_API void (luaL_checkany) (lua_State *L, int arg); - -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); - -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_checkoption) (lua_State *L, int arg, 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) - -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_loadfilex) (lua_State *L, const char *filename, - const char *mode); - -#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL) - -LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, - const char *name, const char *mode); -LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); - -LUALIB_API lua_State *(luaL_newstate) (void); - -LUALIB_API lua_Integer (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 void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); - -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); - -LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, - lua_CFunction openf, int glb); - -/* -** =============================================================== -** some useful macros -** =============================================================== -*/ - - -#define luaL_newlibtable(L,l) \ - lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1) - -#define luaL_newlib(L,l) \ - (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) - -#define luaL_argcheck(L, cond,arg,extramsg) \ - ((void)((cond) || luaL_argerror(L, (arg), (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_typename(L,i) lua_typename(L, lua_type(L,(i))) - -#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, LUA_MULTRET, 0)) - -#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))) - -#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL) - - -/* -** {====================================================== -** Generic Buffer manipulation -** ======================================================= -*/ - -typedef struct luaL_Buffer { - char *b; /* buffer address */ - size_t size; /* buffer size */ - size_t n; /* number of characters in buffer */ - lua_State *L; - char initb[LUAL_BUFFERSIZE]; /* initial buffer */ -} luaL_Buffer; - - -#define luaL_addchar(B,c) \ - ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \ - ((B)->b[(B)->n++] = (c))) - -#define luaL_addsize(B,s) ((B)->n += (s)) - -LUALIB_API void (luaL_buffinit) (lua_State *L, 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) - -/* }====================================================== */ - - - -/* -** {====================================================== -** 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) - -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); - -#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0)) - -#endif - - -/* -** {================================================================== -** "Abstraction Layer" for basic report of messages and errors -** =================================================================== -*/ - -/* print a string */ -#if !defined(lua_writestring) -#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) -#endif - -/* print a newline and flush the output */ -#if !defined(lua_writeline) -#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout)) -#endif - -/* print an error message */ -#if !defined(lua_writestringerror) -#define lua_writestringerror(s,p) \ - (fprintf(stderr, (s), (p)), fflush(stderr)) -#endif - -/* }================================================================== */ - - -/* -** {============================================================ -** Compatibility with deprecated conversions -** ============================================================= -*/ -#if defined(LUA_COMPAT_APIINTCASTS) - -#define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a)) -#define luaL_optunsigned(L,a,d) \ - ((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(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))) - -#endif -/* }============================================================ */ - - - -#endif - - diff --git a/src/lbaselib.c b/src/lbaselib.c deleted file mode 100644 index a2403952f0..0000000000 --- a/src/lbaselib.c +++ /dev/null @@ -1,520 +0,0 @@ -/* -** $Id: lbaselib.c,v 1.309 2014/12/10 12:26:42 roberto Exp $ -** Basic library -** See Copyright Notice in lua.h -*/ - -#define lbaselib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -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; - 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_tolstring(L, -1, &l); /* get result */ - if (s == NULL) - return luaL_error(L, "'tostring' must return a string to 'print'"); - if (i>1) lua_writestring("\t", 1); - lua_writestring(s, l); - lua_pop(L, 1); /* pop result */ - } - lua_writeline(); - return 0; -} - - -#define SPACECHARS " \f\n\r\t\v" - -static const char *b_str2int (const char *s, int base, lua_Integer *pn) { - lua_Unsigned n = 0; - int neg = 0; - s += strspn(s, SPACECHARS); /* skip initial spaces */ - if (*s == '-') { s++; neg = 1; } /* handle signal */ - else if (*s == '+') s++; - if (!isalnum((unsigned char)*s)) /* no digit? */ - return NULL; - do { - int digit = (isdigit((unsigned char)*s)) ? *s - '0' - : toupper((unsigned char)*s) - 'A' + 10; - if (digit >= base) return NULL; /* invalid numeral */ - n = n * base + digit; - s++; - } while (isalnum((unsigned char)*s)); - s += strspn(s, SPACECHARS); /* skip trailing spaces */ - *pn = (lua_Integer)((neg) ? (0u - n) : n); - return s; -} - - -static int luaB_tonumber (lua_State *L) { - if (lua_isnoneornil(L, 2)) { /* standard conversion? */ - luaL_checkany(L, 1); - if (lua_type(L, 1) == LUA_TNUMBER) { /* already a number? */ - lua_settop(L, 1); /* yes; return it */ - return 1; - } - else { - size_t l; - const char *s = lua_tolstring(L, 1, &l); - if (s != NULL && lua_stringtonumber(L, s) == l + 1) - return 1; /* successful conversion to number */ - /* else not a number */ - } - } - else { - size_t l; - const char *s; - lua_Integer n = 0; /* to avoid warnings */ - lua_Integer base = luaL_checkinteger(L, 2); - luaL_checktype(L, 1, LUA_TSTRING); /* before 'luaL_checklstring'! */ - s = luaL_checklstring(L, 1, &l); - luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); - if (b_str2int(s, (int)base, &n) == s + l) { - lua_pushinteger(L, n); - return 1; - } /* else not a number */ - } /* else not a number */ - lua_pushnil(L); /* not a number */ - return 1; -} - - -static int luaB_error (lua_State *L) { - int level = (int)luaL_optinteger(L, 2, 1); - 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); - } - return lua_error(L); -} - - -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_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") != LUA_TNIL) - return luaL_error(L, "cannot change a protected metatable"); - lua_settop(L, 2); - lua_setmetatable(L, 1); - return 1; -} - - -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_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); - lua_settop(L, 2); - lua_rawget(L, 1); - return 1; -} - -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; -} - - -static int luaB_collectgarbage (lua_State *L) { - static const char *const opts[] = {"stop", "restart", "collect", - "count", "step", "setpause", "setstepmul", - "isrunning", NULL}; - static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, - LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, - LUA_GCISRUNNING}; - int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; - int ex = (int)luaL_optinteger(L, 2, 0); - int res = lua_gc(L, o, ex); - switch (o) { - case LUA_GCCOUNT: { - int b = lua_gc(L, LUA_GCCOUNTB, 0); - lua_pushnumber(L, (lua_Number)res + ((lua_Number)b/1024)); - return 1; - } - case LUA_GCSTEP: case LUA_GCISRUNNING: { - lua_pushboolean(L, res); - return 1; - } - default: { - lua_pushinteger(L, res); - return 1; - } - } -} - - -/* -** This function has all type names as upvalues, to maximize performance. -*/ -static int luaB_type (lua_State *L) { - luaL_checkany(L, 1); - lua_pushvalue(L, lua_upvalueindex(lua_type(L, 1) + 1)); - return 1; -} - - -static int pairsmeta (lua_State *L, const char *method, int iszero, - lua_CFunction iter) { - if (luaL_getmetafield(L, 1, method) == LUA_TNIL) { /* no metamethod? */ - luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */ - 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); - } - 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 */ - if (lua_next(L, 1)) - return 2; - else { - lua_pushnil(L); - return 1; - } -} - - -static int luaB_pairs (lua_State *L) { - return pairsmeta(L, "__pairs", 0, luaB_next); -} - - -/* -** Traversal function for 'ipairs' for raw tables -*/ -static int ipairsaux_raw (lua_State *L) { - lua_Integer i = luaL_checkinteger(L, 2) + 1; - luaL_checktype(L, 1, LUA_TTABLE); - lua_pushinteger(L, i); - return (lua_rawgeti(L, 1, i) == LUA_TNIL) ? 1 : 2; -} - - -/* -** Traversal function for 'ipairs' for tables with metamethods -*/ -static int ipairsaux (lua_State *L) { - lua_Integer i = luaL_checkinteger(L, 2) + 1; - lua_pushinteger(L, i); - return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2; -} - - -/* -** This function will use either 'ipairsaux' or 'ipairsaux_raw' to -** traverse a table, depending on whether the table has metamethods -** that can affect the traversal. -*/ -static int luaB_ipairs (lua_State *L) { - lua_CFunction iter = (luaL_getmetafield(L, 1, "__index") != LUA_TNIL) - ? ipairsaux : ipairsaux_raw; -#if defined(LUA_COMPAT_IPAIRS) - return pairsmeta(L, "__ipairs", 1, iter); -#else - luaL_checkany(L, 1); - lua_pushcfunction(L, iter); /* iteration function */ - lua_pushvalue(L, 1); /* state */ - lua_pushinteger(L, 0); /* initial value */ - return 3; -#endif -} - - -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 { /* 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 */ - } -} - - -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) ? 3 : 0); /* 'env' index or 0 if no 'env' */ - int status = luaL_loadfilex(L, fname, mode); - return load_aux(L, status, env); -} - - -/* -** {====================================================== -** Generic Read function -** ======================================================= -*/ - - -/* -** 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 5 - - -/* -** 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) { - (void)(ud); /* not used */ - 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)) { - lua_pop(L, 1); /* pop result */ - *size = 0; - return NULL; - } - else if (!lua_isstring(L, -1)) - luaL_error(L, "reader function must return a string"); - lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ - return lua_tolstring(L, RESERVEDSLOT, size); -} - - -static int luaB_load (lua_State *L) { - int status; - size_t 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); - } - else { /* loading from a reader function */ - 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, NULL, chunkname, mode); - } - return load_aux(L, status, env); -} - -/* }====================================================== */ - - -static int dofilecont (lua_State *L, int d1, lua_KContext d2) { - (void)d1; (void)d2; /* only to match 'lua_Kfunction' prototype */ - return lua_gettop(L) - 1; -} - - -static int luaB_dofile (lua_State *L) { - const char *fname = luaL_optstring(L, 1, NULL); - lua_settop(L, 1); - if (luaL_loadfile(L, fname) != LUA_OK) - return lua_error(L); - lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); - return dofilecont(L, 0, 0); -} - - -static int luaB_assert (lua_State *L) { - if (lua_toboolean(L, 1)) /* condition is true? */ - return lua_gettop(L); /* return all arguments */ - else { /* error */ - luaL_checkany(L, 1); /* there must be a condition */ - lua_remove(L, 1); /* remove it */ - lua_pushliteral(L, "assertion failed!"); /* default message */ - lua_settop(L, 1); /* leave only message (default if no other one) */ - return luaB_error(L); /* call 'error' */ - } -} - - -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 { - lua_Integer i = luaL_checkinteger(L, 1); - if (i < 0) i = n + i; - else if (i > n) i = n; - luaL_argcheck(L, 1 <= i, 1, "index out of range"); - return n - (int)i; - } -} - - -/* -** Continuation function for 'pcall' and 'xpcall'. Both functions -** already pushed a 'true' before doing the call, so in case of success -** 'finishpcall' only has to return everything in the stack minus -** 'extra' values (where 'extra' is exactly the number of items to be -** ignored). -*/ -static int finishpcall (lua_State *L, int status, lua_KContext extra) { - if (status != LUA_OK && status != LUA_YIELD) { /* error? */ - lua_pushboolean(L, 0); /* first result (false) */ - lua_pushvalue(L, -2); /* error message */ - return 2; /* return false, msg */ - } - else - return lua_gettop(L) - (int)extra; /* return all results */ -} - - -static int luaB_pcall (lua_State *L) { - int status; - luaL_checkany(L, 1); - lua_pushboolean(L, 1); /* first result if no errors */ - lua_insert(L, 1); /* put it in place */ - status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall); - return finishpcall(L, status, 0); -} - - -/* -** Do a protected call with error handling. After 'lua_rotate', the -** stack will have ; so, the function passes -** 2 to 'finishpcall' to skip the 2 first values when returning results. -*/ -static int luaB_xpcall (lua_State *L) { - int status; - int n = lua_gettop(L); - luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */ - lua_pushboolean(L, 1); /* first result */ - lua_pushvalue(L, 1); /* function */ - lua_rotate(L, 3, 2); /* move them below function's arguments */ - status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall); - return finishpcall(L, status, 2); -} - - -static int luaB_tostring (lua_State *L) { - luaL_checkany(L, 1); - luaL_tolstring(L, 1, NULL); - return 1; -} - - -static const luaL_Reg base_funcs[] = { - {"assert", luaB_assert}, - {"collectgarbage", luaB_collectgarbage}, - {"dofile", luaB_dofile}, - {"error", luaB_error}, - {"getmetatable", luaB_getmetatable}, - {"ipairs", luaB_ipairs}, - {"loadfile", luaB_loadfile}, - {"load", luaB_load}, -#if defined(LUA_COMPAT_LOADSTRING) - {"loadstring", luaB_load}, -#endif - {"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}, - {"setmetatable", luaB_setmetatable}, - {"tonumber", luaB_tonumber}, - {"tostring", luaB_tostring}, - {"xpcall", luaB_xpcall}, - /* placeholders */ - {"type", NULL}, - {"_G", NULL}, - {"_VERSION", NULL}, - {NULL, NULL} -}; - - -LUAMOD_API int luaopen_base (lua_State *L) { - int i; - /* open lib into global table */ - lua_pushglobaltable(L); - luaL_setfuncs(L, base_funcs, 0); - /* set global _G */ - lua_pushvalue(L, -1); - lua_setfield(L, -2, "_G"); - /* set global _VERSION */ - lua_pushliteral(L, LUA_VERSION); - lua_setfield(L, -2, "_VERSION"); - /* set function 'type' with proper upvalues */ - for (i = 0; i < LUA_NUMTAGS; i++) /* push all type names as upvalues */ - lua_pushstring(L, lua_typename(L, i)); - lua_pushcclosure(L, luaB_type, LUA_NUMTAGS); - lua_setfield(L, -2, "type"); - return 1; -} - diff --git a/src/lbitlib.c b/src/lbitlib.c deleted file mode 100644 index 15d5f0cdfc..0000000000 --- a/src/lbitlib.c +++ /dev/null @@ -1,230 +0,0 @@ -/* -** $Id: lbitlib.c,v 1.28 2014/11/02 19:19:04 roberto Exp $ -** Standard library for bitwise operations -** See Copyright Notice in lua.h -*/ - -#define lbitlib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -#if defined(LUA_COMPAT_BITLIB) /* { */ - - -/* number of bits to consider in a number */ -#if !defined(LUA_NBITS) -#define LUA_NBITS 32 -#endif - - -/* -** a lua_Unsigned with its first LUA_NBITS bits equal to 1. (Shift must -** be made in two parts to avoid problems when LUA_NBITS is equal to the -** number of bits in a lua_Unsigned.) -*/ -#define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1)) - - -/* macro to trim extra bits */ -#define trim(x) ((x) & ALLONES) - - -/* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */ -#define mask(n) (~((ALLONES << 1) << ((n) - 1))) - - - -static lua_Unsigned andaux (lua_State *L) { - int i, n = lua_gettop(L); - lua_Unsigned r = ~(lua_Unsigned)0; - for (i = 1; i <= n; i++) - r &= luaL_checkunsigned(L, i); - return trim(r); -} - - -static int b_and (lua_State *L) { - lua_Unsigned r = andaux(L); - lua_pushunsigned(L, r); - return 1; -} - - -static int b_test (lua_State *L) { - lua_Unsigned r = andaux(L); - lua_pushboolean(L, r != 0); - return 1; -} - - -static int b_or (lua_State *L) { - int i, n = lua_gettop(L); - lua_Unsigned r = 0; - for (i = 1; i <= n; i++) - r |= luaL_checkunsigned(L, i); - lua_pushunsigned(L, trim(r)); - return 1; -} - - -static int b_xor (lua_State *L) { - int i, n = lua_gettop(L); - lua_Unsigned r = 0; - for (i = 1; i <= n; i++) - r ^= luaL_checkunsigned(L, i); - lua_pushunsigned(L, trim(r)); - return 1; -} - - -static int b_not (lua_State *L) { - lua_Unsigned r = ~luaL_checkunsigned(L, 1); - lua_pushunsigned(L, trim(r)); - return 1; -} - - -static int b_shift (lua_State *L, lua_Unsigned r, lua_Integer i) { - if (i < 0) { /* shift right? */ - i = -i; - r = trim(r); - if (i >= LUA_NBITS) r = 0; - else r >>= i; - } - else { /* shift left */ - if (i >= LUA_NBITS) r = 0; - else r <<= i; - r = trim(r); - } - lua_pushunsigned(L, r); - return 1; -} - - -static int b_lshift (lua_State *L) { - return b_shift(L, luaL_checkunsigned(L, 1), luaL_checkinteger(L, 2)); -} - - -static int b_rshift (lua_State *L) { - return b_shift(L, luaL_checkunsigned(L, 1), -luaL_checkinteger(L, 2)); -} - - -static int b_arshift (lua_State *L) { - lua_Unsigned r = luaL_checkunsigned(L, 1); - lua_Integer i = luaL_checkinteger(L, 2); - if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1)))) - return b_shift(L, r, -i); - else { /* arithmetic shift for 'negative' number */ - if (i >= LUA_NBITS) r = ALLONES; - else - r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */ - lua_pushunsigned(L, r); - return 1; - } -} - - -static int b_rot (lua_State *L, lua_Integer d) { - lua_Unsigned r = luaL_checkunsigned(L, 1); - int i = d & (LUA_NBITS - 1); /* i = d % NBITS */ - r = trim(r); - if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */ - r = (r << i) | (r >> (LUA_NBITS - i)); - lua_pushunsigned(L, trim(r)); - return 1; -} - - -static int b_lrot (lua_State *L) { - return b_rot(L, luaL_checkinteger(L, 2)); -} - - -static int b_rrot (lua_State *L) { - return b_rot(L, -luaL_checkinteger(L, 2)); -} - - -/* -** get field and width arguments for field-manipulation functions, -** checking whether they are valid. -** ('luaL_error' called without 'return' to avoid later warnings about -** 'width' being used uninitialized.) -*/ -static int fieldargs (lua_State *L, int farg, int *width) { - lua_Integer f = luaL_checkinteger(L, farg); - lua_Integer w = luaL_optinteger(L, farg + 1, 1); - luaL_argcheck(L, 0 <= f, farg, "field cannot be negative"); - 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 = (int)w; - return (int)f; -} - - -static int b_extract (lua_State *L) { - int w; - lua_Unsigned r = trim(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; - lua_Unsigned r = trim(luaL_checkunsigned(L, 1)); - lua_Unsigned 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}, - {NULL, NULL} -}; - - - -LUAMOD_API int luaopen_bit32 (lua_State *L) { - luaL_newlib(L, bitlib); - return 1; -} - - -#else /* }{ */ - - -LUAMOD_API int luaopen_bit32 (lua_State *L) { - return luaL_error(L, "library 'bit32' has been deprecated"); -} - -#endif /* } */ diff --git a/src/lcode.c b/src/lcode.c deleted file mode 100644 index cfe4a21047..0000000000 --- a/src/lcode.c +++ /dev/null @@ -1,972 +0,0 @@ -/* -** $Id: lcode.c,v 2.97 2014/11/24 14:59:22 roberto Exp $ -** Code generator for Lua -** See Copyright Notice in lua.h -*/ - -#define lcode_c -#define LUA_CORE - -#include "lprefix.h" - - -#include -#include - -#include "lua.h" - -#include "lcode.h" -#include "ldebug.h" -#include "ldo.h" -#include "lgc.h" -#include "llex.h" -#include "lmem.h" -#include "lobject.h" -#include "lopcodes.h" -#include "lparser.h" -#include "lstring.h" -#include "ltable.h" -#include "lvm.h" - - -/* Maximum number of registers in a Lua function */ -#define MAXREGS 250 - - -/* test for x == -0 ('signbit' needs 'math.h') */ -#if defined(signbit) -#define isminuszero(x) ((x) == 0.0 && signbit(x)) -#else -#define isminuszero(x) ((x) == 0.0 && 1.0/(x) < 0.0) -#endif - - -#define hasjumps(e) ((e)->t != (e)->f) - - -static int tonumeral(expdesc *e, TValue *v) { - if (e->t != NO_JUMP || e->f != NO_JUMP) - return 0; /* not a numeral */ - switch (e->k) { - case VKINT: - if (v) setivalue(v, e->u.ival); - return 1; - case VKFLT: - if (v) setfltvalue(v, e->u.nval); - return 1; - default: return 0; - } -} - - -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 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, n - 1, 0); /* else no optimization */ -} - - -int luaK_jump (FuncState *fs) { - 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; -} - - -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); -} - - -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); - 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 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 */ - else - return (pc+1)+offset; /* turn offset into absolute position */ -} - - -static Instruction *getjumpcontrol (FuncState *fs, int pc) { - Instruction *pi = &fs->f->code[pc]; - if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) - return pi-1; - else - return pi; -} - - -/* -** 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) { - for (; list != NO_JUMP; list = getjump(fs, list)) { - Instruction i = *getjumpcontrol(fs, list); - if (GET_OPCODE(i) != OP_TESTSET) return 1; - } - return 0; /* not found */ -} - - -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 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)) - patchtestreg(fs, list, NO_REG); -} - - -static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, - int dtarget) { - while (list != NO_JUMP) { - int next = getjump(fs, list); - if (patchtestreg(fs, list, 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); - fs->jpc = NO_JUMP; -} - - -void luaK_patchlist (FuncState *fs, int list, int target) { - if (target == fs->pc) - luaK_patchtohere(fs, list); - else { - lua_assert(target < fs->pc); - patchlistaux(fs, list, target, NO_REG, target); - } -} - - -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); -} - - -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 = getjump(fs, list)) != NO_JUMP) /* find last element */ - list = next; - fixjump(fs, list, 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->ls->L, f->code, fs->pc, f->sizecode, Instruction, - MAX_INT, "opcodes"); - f->code[fs->pc] = i; - /* save corresponding line information */ - 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++; -} - - -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_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, OP_LOADKX, reg, 0); - codeextraarg(fs, k); - return p; - } -} - - -void luaK_checkstack (FuncState *fs, int n) { - int newstack = fs->freereg + n; - if (newstack > fs->f->maxstacksize) { - if (newstack >= MAXREGS) - luaX_syntaxerror(fs->ls, "function or expression too complex"); - fs->f->maxstacksize = cast_byte(newstack); - } -} - - -void luaK_reserveregs (FuncState *fs, int n) { - luaK_checkstack(fs, n); - fs->freereg += n; -} - - -static void freereg (FuncState *fs, int reg) { - if (!ISK(reg) && reg >= fs->nactvar) { - fs->freereg--; - lua_assert(reg == fs->freereg); - } -} - - -static void freeexp (FuncState *fs, expdesc *e) { - if (e->k == VNONRELOC) - freereg(fs, e->u.info); -} - - -/* -** Use scanner's table to cache position of constants in constant list -** and try to reuse constants -*/ -static int addk (FuncState *fs, TValue *key, TValue *v) { - lua_State *L = fs->ls->L; - Proto *f = fs->f; - TValue *idx = luaH_set(L, fs->ls->h, key); /* index scanner table */ - int k, oldsize; - if (ttisinteger(idx)) { /* is there an index there? */ - k = cast_int(ivalue(idx)); - /* correct value? (warning: must distinguish floats from integers!) */ - if (k < fs->nk && ttype(&f->k[k]) == ttype(v) && - luaV_rawequalobj(&f->k[k], v)) - return k; /* reuse index */ - } - /* 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 */ - setivalue(idx, 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; -} - - -int luaK_stringK (FuncState *fs, TString *s) { - TValue o; - setsvalue(fs->ls->L, &o, s); - return addk(fs, &o, &o); -} - - -/* -** Integers use userdata as keys to avoid collision with floats with same -** value; conversion to 'void*' used only for hashing, no "precision" -** problems -*/ -int luaK_intK (FuncState *fs, lua_Integer n) { - TValue k, o; - setpvalue(&k, cast(void*, cast(size_t, n))); - setivalue(&o, n); - return addk(fs, &k, &o); -} - - -/* -** Both NaN and -0.0 should not go to the constant table, as they have -** problems with the hashing. (NaN is not a valid key, -0.0 collides -** with +0.0.) -*/ -static int luaK_numberK (FuncState *fs, lua_Number r) { - TValue o; - lua_assert(!luai_numisnan(r) && !isminuszero(r)); - setfltvalue(&o, r); - return addk(fs, &o, &o); -} - - -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 */ - sethvalue(fs->ls->L, &k, fs->ls->h); - return addk(fs, &k, &v); -} - - -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); - } - 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->u.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 */ - } -} - - -void luaK_dischargevars (FuncState *fs, expdesc *e) { - switch (e->k) { - case VLOCAL: { - e->k = VNONRELOC; - break; - } - case VUPVAL: { - e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); - e->k = VRELOCABLE; - break; - } - case VINDEXED: { - 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; - } - case VVARARG: - case VCALL: { - luaK_setoneret(fs, e); - break; - } - default: break; /* there is one value available (somewhere) */ - } -} - - -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 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_codek(fs, reg, e->u.info); - break; - } - case VKFLT: { - luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval)); - break; - } - case VKINT: { - luaK_codek(fs, reg, luaK_intK(fs, e->u.ival)); - break; - } - case VRELOCABLE: { - Instruction *pc = &getcode(fs, e); - SETARG_A(*pc, reg); - break; - } - case VNONRELOC: { - if (reg != e->u.info) - luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0); - break; - } - default: { - lua_assert(e->k == VVOID || e->k == VJMP); - return; /* nothing to do... */ - } - } - e->u.info = reg; - e->k = VNONRELOC; -} - - -static void discharge2anyreg (FuncState *fs, expdesc *e) { - if (e->k != VNONRELOC) { - luaK_reserveregs(fs, 1); - discharge2reg(fs, e, fs->freereg-1); - } -} - - -static void exp2reg (FuncState *fs, expdesc *e, int reg) { - discharge2reg(fs, e, reg); - if (e->k == VJMP) - 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 */ - int p_t = NO_JUMP; /* position of an eventual LOAD true */ - if (need_value(fs, e->t) || need_value(fs, e->f)) { - 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); - } - final = luaK_getlabel(fs); - patchlistaux(fs, e->f, final, reg, p_f); - patchlistaux(fs, e->t, final, reg, p_t); - } - e->f = e->t = NO_JUMP; - e->u.info = reg; - e->k = VNONRELOC; -} - - -void luaK_exp2nextreg (FuncState *fs, expdesc *e) { - luaK_dischargevars(fs, e); - freeexp(fs, e); - luaK_reserveregs(fs, 1); - 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->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.info; -} - - -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); - else - luaK_dischargevars(fs, 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 fits in RK operand? */ - e->u.info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE)); - e->k = VK; - return RKASK(e->u.info); - } - else break; - } - case VKINT: { - e->u.info = luaK_intK(fs, e->u.ival); - e->k = VK; - goto vk; - } - case VKFLT: { - e->u.info = luaK_numberK(fs, e->u.nval); - e->k = VK; - /* go through */ - } - case VK: { - vk: - if (e->u.info <= MAXINDEXRK) /* constant fits in 'argC'? */ - return RKASK(e->u.info); - else break; - } - default: break; - } - /* not a constant in the right range: put it in a register */ - return luaK_exp2anyreg(fs, e); -} - - -void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { - switch (var->k) { - case VLOCAL: { - freeexp(fs, ex); - exp2reg(fs, ex, var->u.info); - return; - } - case VUPVAL: { - int e = luaK_exp2anyreg(fs, ex); - 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, var->u.ind.t, var->u.ind.idx, e); - break; - } - default: { - lua_assert(0); /* invalid var kind to store */ - break; - } - } - freeexp(fs, ex); -} - - -void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { - int ereg; - luaK_exp2anyreg(fs, e); - ereg = e->u.info; /* register where 'e' was placed */ - freeexp(fs, e); - 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); -} - - -static void invertjump (FuncState *fs, expdesc *e) { - 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))); -} - - -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 condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); - } - /* else go through */ - } - discharge2anyreg(fs, e); - freeexp(fs, e); - return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond); -} - - -void luaK_goiftrue (FuncState *fs, expdesc *e) { - int pc; /* pc of last jump */ - luaK_dischargevars(fs, e); - switch (e->k) { - case VJMP: { - invertjump(fs, e); - pc = e->u.info; - break; - } - case VK: case VKFLT: case VKINT: case VTRUE: { - pc = NO_JUMP; /* always true; do nothing */ - break; - } - default: { - pc = jumponcond(fs, e, 0); - break; - } - } - luaK_concat(fs, &e->f, pc); /* insert last jump in 'f' list */ - luaK_patchtohere(fs, e->t); - e->t = NO_JUMP; -} - - -void luaK_goiffalse (FuncState *fs, expdesc *e) { - int pc; /* pc of last jump */ - luaK_dischargevars(fs, e); - switch (e->k) { - case VJMP: { - pc = e->u.info; - break; - } - case VNIL: case VFALSE: { - pc = NO_JUMP; /* always false; do nothing */ - break; - } - default: { - pc = jumponcond(fs, e, 1); - break; - } - } - luaK_concat(fs, &e->t, pc); /* insert last jump in 't' list */ - luaK_patchtohere(fs, e->f); - e->f = NO_JUMP; -} - - -static void codenot (FuncState *fs, expdesc *e) { - luaK_dischargevars(fs, e); - switch (e->k) { - case VNIL: case VFALSE: { - e->k = VTRUE; - break; - } - case VK: case VKFLT: case VKINT: case VTRUE: { - e->k = VFALSE; - break; - } - case VJMP: { - invertjump(fs, e); - break; - } - case VRELOCABLE: - case VNONRELOC: { - discharge2anyreg(fs, e); - freeexp(fs, e); - e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0); - e->k = VRELOCABLE; - break; - } - default: { - lua_assert(0); /* cannot happen */ - break; - } - } - /* interchange true and false lists */ - { int temp = e->f; e->f = e->t; e->t = temp; } - removevalues(fs, e->f); - removevalues(fs, e->t); -} - - -void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { - lua_assert(!hasjumps(t)); - 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; -} - - -/* -** return false if folding can raise an error -*/ -static int validop (int op, TValue *v1, TValue *v2) { - lua_Number a, b; - lua_Integer i; - cast_void(a); cast_void(b); /* macro may not use its arguments */ - if (luai_numinvalidop(op, (cast_void(tonumber(v1, &a)), a), - (cast_void(tonumber(v2, &b)), b))) - return 0; - switch (op) { - case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: - case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: /* conversion errors */ - return (tointeger(v1, &i) && tointeger(v2, &i)); - case LUA_OPIDIV: case LUA_OPMOD: /* integer division by 0 */ - return !(ttisinteger(v1) && ttisinteger(v2) && ivalue(v2) == 0); - default: return 1; /* everything else is valid */ - } -} - - -/* -** Try to "constant-fold" an operation; return 1 iff successful -*/ -static int constfolding (FuncState *fs, int op, expdesc *e1, expdesc *e2) { - TValue v1, v2, res; - if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2)) - return 0; /* non-numeric operands or not safe to fold */ - luaO_arith(fs->ls->L, op, &v1, &v2, &res); - if (ttisinteger(&res)) { - e1->k = VKINT; - e1->u.ival = ivalue(&res); - } - else { - lua_Number n = fltvalue(&res); - if (luai_numisnan(n) || isminuszero(n)) - return 0; /* folds neither NaN nor -0 */ - e1->k = VKFLT; - e1->u.nval = n; - } - return 1; -} - - -/* -** Code for binary and unary expressions that "produce values" -** (arithmetic operations, bitwise operations, concat, length). First -** try to do constant folding (only for numeric [arithmetic and -** bitwise] operations, which is what 'lua_arith' accepts). -** Expression to produce final result will be encoded in 'e1'. -*/ -static void codeexpval (FuncState *fs, OpCode op, - expdesc *e1, expdesc *e2, int line) { - lua_assert(op >= OP_ADD); - if (op <= OP_BNOT && constfolding(fs, op - OP_ADD + LUA_OPADD, e1, e2)) - return; /* result has been folded */ - else { - int o1, o2; - /* move operands to registers (if needed) */ - if (op == OP_UNM || op == OP_BNOT || op == OP_LEN) { /* unary op? */ - o2 = 0; /* no second expression */ - o1 = luaK_exp2anyreg(fs, e1); /* cannot operate on constants */ - } - else { /* regular case (binary operators) */ - o2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */ - o1 = luaK_exp2RK(fs, e1); - } - if (o1 > o2) { /* free registers in proper order */ - freeexp(fs, e1); - freeexp(fs, e2); - } - else { - freeexp(fs, e2); - freeexp(fs, e1); - } - e1->u.info = luaK_codeABC(fs, op, 0, o1, o2); /* generate opcode */ - e1->k = VRELOCABLE; /* all those operations are relocable */ - luaK_fixline(fs, line); - } -} - - -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.info = condjump(fs, op, cond, o1, o2); - e1->k = VJMP; -} - - -void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { - expdesc e2; - e2.t = e2.f = NO_JUMP; e2.k = VKINT; e2.u.ival = 0; - switch (op) { - case OPR_MINUS: case OPR_BNOT: case OPR_LEN: { - codeexpval(fs, cast(OpCode, (op - OPR_MINUS) + OP_UNM), e, &e2, line); - break; - } - case OPR_NOT: codenot(fs, e); break; - default: lua_assert(0); - } -} - - -void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { - switch (op) { - case OPR_AND: { - luaK_goiftrue(fs, v); - break; - } - case OPR_OR: { - luaK_goiffalse(fs, v); - break; - } - case OPR_CONCAT: { - luaK_exp2nextreg(fs, v); /* operand must be on the 'stack' */ - break; - } - case OPR_ADD: case OPR_SUB: - case OPR_MUL: case OPR_DIV: case OPR_IDIV: - case OPR_MOD: case OPR_POW: - case OPR_BAND: case OPR_BOR: case OPR_BXOR: - case OPR_SHL: case OPR_SHR: { - if (!tonumeral(v, NULL)) luaK_exp2RK(fs, v); - break; - } - default: { - luaK_exp2RK(fs, v); - break; - } - } -} - - -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 */ - luaK_dischargevars(fs, e2); - 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, &e2->t, e1->t); - *e1 = *e2; - break; - } - case OPR_CONCAT: { - luaK_exp2val(fs, e2); - if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) { - lua_assert(e1->u.info == GETARG_B(getcode(fs, e2))-1); - freeexp(fs, e1); - 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' */ - codeexpval(fs, OP_CONCAT, e1, e2, line); - } - break; - } - case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: - case OPR_IDIV: case OPR_MOD: case OPR_POW: - case OPR_BAND: case OPR_BOR: case OPR_BXOR: - case OPR_SHL: case OPR_SHR: { - codeexpval(fs, cast(OpCode, (op - OPR_ADD) + OP_ADD), e1, e2, line); - break; - } - case OPR_EQ: case OPR_LT: case OPR_LE: { - codecomp(fs, cast(OpCode, op - OPR_EQ + OP_EQ), 1, e1, e2); - break; - } - case OPR_NE: case OPR_GT: case OPR_GE: { - codecomp(fs, cast(OpCode, op - OPR_NE + OP_EQ), 0, e1, e2); - break; - } - default: lua_assert(0); - } -} - - -void luaK_fixline (FuncState *fs, int line) { - fs->f->lineinfo[fs->pc - 1] = line; -} - - -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 if (c <= MAXARG_Ax) { - luaK_codeABC(fs, OP_SETLIST, base, b, 0); - 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 deleted file mode 100644 index 43ab86db77..0000000000 --- a/src/lcode.h +++ /dev/null @@ -1,87 +0,0 @@ -/* -** $Id: lcode.h,v 1.63 2013/12/30 20:47:58 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 (ORDER OP) -*/ -typedef enum BinOpr { - OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW, - OPR_DIV, - OPR_IDIV, - OPR_BAND, OPR_BOR, OPR_BXOR, - OPR_SHL, OPR_SHR, - OPR_CONCAT, - OPR_EQ, OPR_LT, OPR_LE, - OPR_NE, OPR_GT, OPR_GE, - OPR_AND, OPR_OR, - OPR_NOBINOPR -} BinOpr; - - -typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; - - -#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) - -#define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) - -#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) - -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_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); -LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); -LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s); -LUAI_FUNC int luaK_intK (FuncState *fs, lua_Integer n); -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); -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_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); -LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); -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); - - -#endif diff --git a/src/lcorolib.c b/src/lcorolib.c deleted file mode 100644 index 0c0b7fa6b3..0000000000 --- a/src/lcorolib.c +++ /dev/null @@ -1,168 +0,0 @@ -/* -** $Id: lcorolib.c,v 1.9 2014/11/02 19:19:04 roberto Exp $ -** Coroutine Library -** See Copyright Notice in lua.h -*/ - -#define lcorolib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -static lua_State *getco (lua_State *L) { - lua_State *co = lua_tothread(L, 1); - luaL_argcheck(L, co, 1, "thread expected"); - return co; -} - - -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, L, 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 = getco(L); - int r; - 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); - } - return lua_error(L); /* propagate error */ - } - return r; -} - - -static int luaB_cocreate (lua_State *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; -} - - -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 = getco(L); - 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_yieldable (lua_State *L) { - lua_pushboolean(L, lua_isyieldable(L)); - 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}, - {"isyieldable", luaB_yieldable}, - {NULL, NULL} -}; - - - -LUAMOD_API int luaopen_coroutine (lua_State *L) { - luaL_newlib(L, co_funcs); - return 1; -} - diff --git a/src/lctype.c b/src/lctype.c deleted file mode 100644 index ae9367e691..0000000000 --- a/src/lctype.c +++ /dev/null @@ -1,55 +0,0 @@ -/* -** $Id: lctype.c,v 1.12 2014/11/02 19:19:04 roberto Exp $ -** 'ctype' functions for Lua -** See Copyright Notice in lua.h -*/ - -#define lctype_c -#define LUA_CORE - -#include "lprefix.h" - - -#include "lctype.h" - -#if !LUA_USE_CTYPE /* { */ - -#include - -LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = { - 0x00, /* EOZ */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */ - 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */ - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */ - 0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */ - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */ - 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05, - 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */ - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */ - 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* e. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* f. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -#endif /* } */ diff --git a/src/lctype.h b/src/lctype.h deleted file mode 100644 index 99c7d12237..0000000000 --- a/src/lctype.h +++ /dev/null @@ -1,95 +0,0 @@ -/* -** $Id: lctype.h,v 1.12 2011/07/15 12:50:29 roberto Exp $ -** 'ctype' functions for Lua -** See Copyright Notice in lua.h -*/ - -#ifndef lctype_h -#define lctype_h - -#include "lua.h" - - -/* -** 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 -*/ - -#if !defined(LUA_USE_CTYPE) - -#if 'A' == 65 && '0' == 48 -/* ASCII case: can use its own tables; faster and fixed */ -#define LUA_USE_CTYPE 0 -#else -/* must use standard C ctype */ -#define LUA_USE_CTYPE 1 -#endif - -#endif - - -#if !LUA_USE_CTYPE /* { */ - -#include - -#include "llimits.h" - - -#define ALPHABIT 0 -#define DIGITBIT 1 -#define PRINTBIT 2 -#define SPACEBIT 3 -#define XDIGITBIT 4 - - -#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 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)) - -/* -** this 'ltolower' only works for alphabetic characters -*/ -#define ltolower(c) ((c) | ('A' ^ 'a')) - - -/* two more entries for 0 and -1 (EOZ) */ -LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2]; - - -#else /* }{ */ - -/* -** use standard C ctypes -*/ - -#include - - -#define lislalpha(c) (isalpha(c) || (c) == '_') -#define lislalnum(c) (isalnum(c) || (c) == '_') -#define lisdigit(c) (isdigit(c)) -#define lisspace(c) (isspace(c)) -#define lisprint(c) (isprint(c)) -#define lisxdigit(c) (isxdigit(c)) - -#define ltolower(c) (tolower(c)) - -#endif /* } */ - -#endif - diff --git a/src/ldblib.c b/src/ldblib.c deleted file mode 100644 index c7aa7bb674..0000000000 --- a/src/ldblib.c +++ /dev/null @@ -1,432 +0,0 @@ -/* -** $Id: ldblib.c,v 1.147 2014/12/08 15:47:25 roberto Exp $ -** Interface from Lua to its debug API -** See Copyright Notice in lua.h -*/ - -#define ldblib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -/* -** The hook table at registry[&HOOKKEY] maps threads to their current -** hook function. (We only need the unique address of 'HOOKKEY'.) -*/ -static const int HOOKKEY = 0; - - -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)) { - lua_pushnil(L); /* no metatable */ - } - return 1; -} - - -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"); - lua_settop(L, 2); - lua_setmetatable(L, 1); - return 1; /* return 1st argument */ -} - - -static int db_getuservalue (lua_State *L) { - if (lua_type(L, 1) != LUA_TUSERDATA) - lua_pushnil(L); - else - lua_getuservalue(L, 1); - return 1; -} - - -static int db_setuservalue (lua_State *L) { - luaL_checktype(L, 1, LUA_TUSERDATA); - luaL_checkany(L, 2); - lua_settop(L, 2); - lua_setuservalue(L, 1); - return 1; -} - - -/* -** Auxiliary function used by several library functions: check for -** an optional thread as function's first argument and set 'arg' with -** 1 if this argument is present (so that functions can skip it to -** access their other arguments) -*/ -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; /* function will operate over current thread */ - } -} - - -/* -** Variations of 'lua_settable', used by 'db_getinfo' to put results -** from 'lua_getinfo' into result table. Key is always a string; -** value can be a string, an int, or a boolean. -*/ -static void settabss (lua_State *L, const char *k, const char *v) { - lua_pushstring(L, v); - lua_setfield(L, -2, k); -} - -static void settabsi (lua_State *L, const char *k, int v) { - lua_pushinteger(L, v); - lua_setfield(L, -2, k); -} - -static void settabsb (lua_State *L, const char *k, int v) { - lua_pushboolean(L, v); - lua_setfield(L, -2, k); -} - - -/* -** In function 'db_getinfo', the call to 'lua_getinfo' may push -** results on the stack; later it creates the result table to put -** these objects. Function 'treatstackoption' puts the result from -** 'lua_getinfo' on top of the result table so that it can call -** 'lua_setfield'. -*/ -static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { - if (L == L1) - lua_rotate(L, -2, 1); /* exchange object and table */ - else - lua_xmove(L1, L, 1); /* move object to the "main" stack */ - lua_setfield(L, -2, fname); /* put object into table */ -} - - -/* -** Calls 'lua_getinfo' and collects all results in a new table. -*/ -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, "flnStu"); - if (lua_isfunction(L, arg + 1)) { /* info about a function? */ - options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */ - lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */ - lua_xmove(L, L1, 1); - } - else { /* stack level */ - if (!lua_getstack(L1, (int)luaL_checkinteger(L, arg + 1), &ar)) { - lua_pushnil(L); /* level out of range */ - return 1; - } - } - if (!lua_getinfo(L1, options, &ar)) - return luaL_argerror(L, arg+2, "invalid option"); - lua_newtable(L); /* table to collect results */ - 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); - 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; - lua_State *L1 = getthread(L, &arg); - lua_Debug ar; - const char *name; - int nvar = (int)luaL_checkinteger(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; /* return only name (there is no value) */ - } - else { /* stack-level argument */ - int level = (int)luaL_checkinteger(L, arg + 1); - if (!lua_getstack(L1, level, &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); /* move local value */ - lua_pushstring(L, name); /* push name */ - lua_rotate(L, -2, 1); /* re-order */ - return 2; - } - else { - lua_pushnil(L); /* no name (nor value) */ - return 1; - } - } -} - - -static int db_setlocal (lua_State *L) { - int arg; - lua_State *L1 = getthread(L, &arg); - lua_Debug ar; - int level = (int)luaL_checkinteger(L, arg + 1); - if (!lua_getstack(L1, level, &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, (int)luaL_checkinteger(L, arg+2))); - return 1; -} - - -/* -** get (if 'get' is true) or set an upvalue from a closure -*/ -static int auxupvalue (lua_State *L, int get) { - const char *name; - int n = (int)luaL_checkinteger(L, 2); /* upvalue index */ - luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */ - 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)); /* no-op if get is false */ - return get + 1; -} - - -static int db_getupvalue (lua_State *L) { - return auxupvalue(L, 1); -} - - -static int db_setupvalue (lua_State *L) { - luaL_checkany(L, 3); - return auxupvalue(L, 0); -} - - -/* -** Check whether a given upvalue from a given closure exists and -** returns its index -*/ -static int checkupval (lua_State *L, int argf, int argnup) { - int nup = (int)luaL_checkinteger(L, argnup); /* upvalue index */ - luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */ - luaL_argcheck(L, (lua_getupvalue(L, argf, nup) != NULL), 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; -} - - -/* -** Call hook function registered at hook table for the current -** thread (if there is one) -*/ -static void hookf (lua_State *L, lua_Debug *ar) { - static const char *const hooknames[] = - {"call", "return", "line", "count", "tail call"}; - lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY); - lua_pushthread(L); - if (lua_rawget(L, -2) == LUA_TFUNCTION) { /* is there a hook function? */ - lua_pushstring(L, hooknames[(int)ar->event]); /* push event name */ - if (ar->currentline >= 0) - lua_pushinteger(L, ar->currentline); /* push current line */ - else lua_pushnil(L); - lua_assert(lua_getinfo(L, "lS", ar)); - lua_call(L, 2, 0); /* call hook function */ - } -} - - -/* -** Convert a string mask (for 'sethook') into a bit mask -*/ -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; -} - - -/* -** Convert a bit mask (for 'gethook') into a string mask -*/ -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 int db_sethook (lua_State *L) { - int arg, mask, count; - lua_Hook func; - lua_State *L1 = getthread(L, &arg); - if (lua_isnoneornil(L, arg+1)) { /* no hook? */ - lua_settop(L, arg+1); - func = NULL; mask = 0; count = 0; /* turn off hooks */ - } - else { - const char *smask = luaL_checkstring(L, arg+2); - luaL_checktype(L, arg+1, LUA_TFUNCTION); - count = (int)luaL_optinteger(L, arg + 3, 0); - func = hookf; mask = makemask(smask, count); - } - if (lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY) == LUA_TNIL) { - lua_createtable(L, 0, 2); /* create a hook table */ - lua_pushvalue(L, -1); - lua_rawsetp(L, LUA_REGISTRYINDEX, &HOOKKEY); /* set it in position */ - lua_pushstring(L, "k"); - lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */ - lua_pushvalue(L, -1); - lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */ - } - lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */ - lua_pushvalue(L, arg + 1); /* value (hook function) */ - lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */ - lua_sethook(L1, func, mask, count); - return 0; -} - - -static int db_gethook (lua_State *L) { - int arg; - lua_State *L1 = getthread(L, &arg); - char buff[5]; - int mask = lua_gethookmask(L1); - lua_Hook hook = lua_gethook(L1); - if (hook == NULL) /* no hook? */ - lua_pushnil(L); - else if (hook != hookf) /* external hook? */ - lua_pushliteral(L, "external hook"); - else { /* hook table must exist */ - lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY); - lua_pushthread(L1); lua_xmove(L1, L, 1); - lua_rawget(L, -2); /* 1st result = hooktable[L1] */ - lua_remove(L, -2); /* remove hook table */ - } - lua_pushstring(L, unmakemask(mask, buff)); /* 2nd result = mask */ - lua_pushinteger(L, lua_gethookcount(L1)); /* 3rd result = count */ - return 3; -} - - -static int db_debug (lua_State *L) { - for (;;) { - char buffer[250]; - lua_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)) - lua_writestringerror("%s\n", lua_tostring(L, -1)); - lua_settop(L, 0); /* remove eventual returns */ - } -} - - -static int db_traceback (lua_State *L) { - int arg; - lua_State *L1 = getthread(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 = (int)luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0); - luaL_traceback(L, L1, msg, level); - } - return 1; -} - - -static const luaL_Reg dblib[] = { - {"debug", db_debug}, - {"getuservalue", db_getuservalue}, - {"gethook", db_gethook}, - {"getinfo", db_getinfo}, - {"getlocal", db_getlocal}, - {"getregistry", db_getregistry}, - {"getmetatable", db_getmetatable}, - {"getupvalue", db_getupvalue}, - {"upvaluejoin", db_upvaluejoin}, - {"upvalueid", db_upvalueid}, - {"setuservalue", db_setuservalue}, - {"sethook", db_sethook}, - {"setlocal", db_setlocal}, - {"setmetatable", db_setmetatable}, - {"setupvalue", db_setupvalue}, - {"traceback", db_traceback}, - {NULL, NULL} -}; - - -LUAMOD_API int luaopen_debug (lua_State *L) { - luaL_newlib(L, dblib); - return 1; -} - diff --git a/src/ldebug.c b/src/ldebug.c deleted file mode 100644 index 5ca62ebfcf..0000000000 --- a/src/ldebug.c +++ /dev/null @@ -1,642 +0,0 @@ -/* -** $Id: ldebug.c,v 2.109 2014/12/10 11:30:09 roberto Exp $ -** Debug Interface -** See Copyright Notice in lua.h -*/ - -#define ldebug_c -#define LUA_CORE - -#include "lprefix.h" - - -#include -#include -#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 "lvm.h" - - - -#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL) - - -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)->p); -} - - -static int currentline (CallInfo *ci) { - return getfuncline(ci_func(ci)->p, currentpc(ci)); -} - - -/* -** this function can be called asynchronous (e.g. during a signal) -*/ -LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { - if (func == NULL || mask == 0) { /* turn off hooks? */ - mask = 0; - func = NULL; - } - if (isLua(L->ci)) - L->oldpc = L->ci->u.l.savedpc; - L->hook = func; - L->basehookcount = count; - resethookcount(L); - L->hookmask = cast_byte(mask); -} - - -LUA_API lua_Hook lua_gethook (lua_State *L) { - return L->hook; -} - - -LUA_API int lua_gethookmask (lua_State *L) { - return L->hookmask; -} - - -LUA_API int lua_gethookcount (lua_State *L) { - return L->basehookcount; -} - - -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 = ci->previous) - level--; - if (level == 0 && ci != &L->base_ci) { /* level found? */ - status = 1; - ar->i_ci = ci; - } - else status = 0; /* no such level */ - lua_unlock(L); - return status; -} - - -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) - 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)) { - 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; - 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 - 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) { - const char *name; - lua_lock(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(clLvalue(L->top - 1)->p, n, 0); - } - else { /* active function; get information through 'ar' */ - StkId pos = 0; /* to avoid warnings */ - name = findlocal(L, ar->i_ci, n, &pos); - 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) { - 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); - L->top--; /* pop value */ - lua_unlock(L); - return name; -} - - -static void funcinfo (lua_Debug *ar, Closure *cl) { - if (noLuaClosure(cl)) { - ar->source = "=[C]"; - ar->linedefined = -1; - ar->lastlinedefined = -1; - ar->what = "C"; - } - else { - 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); -} - - -static void collectvalidlines (lua_State *L, Closure *f) { - if (noLuaClosure(f)) { - setnilvalue(L->top); - api_incr_top(L); - } - else { - int i; - TValue v; - 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 */ - 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 */ - } -} - - -static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, - Closure *f, CallInfo *ci) { - int status = 1; - for (; *what; what++) { - switch (*what) { - case 'S': { - funcinfo(ar, f); - break; - } - case 'l': { - ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1; - break; - } - case 'u': { - ar->nups = (f == NULL) ? 0 : f->c.nupvalues; - if (noLuaClosure(f)) { - 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': { - /* 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; - } - break; - } - case 'L': - case 'f': /* handled by lua_getinfo */ - break; - default: status = 0; /* invalid option */ - } - } - return status; -} - - -LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { - int status; - Closure *cl; - CallInfo *ci; - StkId func; - lua_lock(L); - if (*what == '>') { - ci = NULL; - func = L->top - 1; - api_check(ttisfunction(func), "function expected"); - what++; /* skip the '>' */ - L->top--; /* pop function */ - } - else { - ci = ar->i_ci; - func = ci->func; - lua_assert(ttisfunction(ci->func)); - } - cl = ttisclosure(func) ? clvalue(func) : NULL; - status = auxgetinfo(L, what, ar, cl, ci); - if (strchr(what, 'f')) { - setobjs2s(L, L->top, func); - api_incr_top(L); - } - if (strchr(what, 'L')) - collectvalidlines(L, cl); - lua_unlock(L); - return status; -} - - -/* -** {====================================================== -** Symbolic Execution -** ======================================================= -*/ - -static const char *getobjname (Proto *p, int lastpc, int reg, - const char **name); - - -/* -** find a "name" for the RK value 'c' -*/ -static void kname (Proto *p, int pc, int c, const char **name) { - if (ISK(c)) { /* is 'c' a constant? */ - TValue *kvalue = &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 */ - const char *what = getobjname(p, pc, 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 int filterpc (int pc, int jmptarget) { - if (pc < jmptarget) /* is code conditional (inside a jump)? */ - return -1; /* cannot know who sets that register */ - else return pc; /* current position sets that register */ -} - - -/* -** try to find last instruction before 'lastpc' that modified register 'reg' -*/ -static int findsetreg (Proto *p, int lastpc, int reg) { - int pc; - int setreg = -1; /* keep last instruction that changed 'reg' */ - int jmptarget = 0; /* any code before this address is conditional */ - 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_LOADNIL: { - int b = GETARG_B(i); - if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */ - setreg = filterpc(pc, jmptarget); - break; - } - case OP_TFORCALL: { - if (reg >= a + 2) /* affect all regs above its base */ - setreg = filterpc(pc, jmptarget); - break; - } - case OP_CALL: - case OP_TAILCALL: { - if (reg >= a) /* affect all registers above base */ - setreg = filterpc(pc, jmptarget); - break; - } - 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) { - if (dest > jmptarget) - jmptarget = dest; /* update 'jmptarget' */ - } - break; - } - default: - if (testAMode(op) && reg == a) /* any instruction that set A */ - setreg = filterpc(pc, jmptarget); - break; - } - } - 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 = (TMS)0; /* to avoid warnings */ - Proto *p = ci_func(ci)->p; /* calling function */ - int pc = currentpc(ci); /* calling instruction index */ - Instruction i = p->code[pc]; /* calling instruction */ - if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */ - *name = "?"; - return "hook"; - } - switch (GET_OPCODE(i)) { - case OP_CALL: - 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; - case OP_SETTABUP: case OP_SETTABLE: - tm = TM_NEWINDEX; - break; - case OP_ADD: case OP_SUB: case OP_MUL: case OP_MOD: - case OP_POW: case OP_DIV: case OP_IDIV: case OP_BAND: - case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: { - int offset = cast_int(GET_OPCODE(i)) - cast_int(OP_ADD); /* ORDER OP */ - tm = cast(TMS, offset + cast_int(TM_ADD)); /* ORDER TM */ - break; - } - case OP_UNM: tm = TM_UNM; break; - case OP_BNOT: tm = TM_BNOT; break; - case OP_LEN: tm = TM_LEN; break; - case OP_CONCAT: tm = TM_CONCAT; break; - case OP_EQ: tm = TM_EQ; break; - case OP_LT: tm = TM_LT; break; - case OP_LE: tm = TM_LE; break; - default: lua_assert(0); /* other instructions cannot call a function */ - } - *name = getstr(G(L)->tmname[tm]); - return "metamethod"; -} - -/* }====================================================== */ - - - -/* -** The subtraction of two potentially unrelated pointers is -** not ISO C, but it should not crash a program; the subsequent -** checks are ISO C and ensure a correct result. -*/ -static int isinstack (CallInfo *ci, const TValue *o) { - ptrdiff_t i = o - ci->u.l.base; - return (0 <= i && i < (ci->top - ci->u.l.base) && ci->u.l.base + i == o); -} - - -/* -** Checks whether value 'o' came from an upvalue. (That can only happen -** with instructions OP_GETTABUP/OP_SETTABUP, which operate directly on -** upvalues.) -*/ -static const char *getupvalname (CallInfo *ci, const TValue *o, - const char **name) { - LClosure *c = ci_func(ci); - int i; - for (i = 0; i < c->nupvalues; i++) { - if (c->upvals[i]->v == o) { - *name = upvalname(c->p, i); - return "upvalue"; - } - } - return NULL; -} - - -static const char *varinfo (lua_State *L, const TValue *o) { - const char *name = NULL; /* to avoid warnings */ - CallInfo *ci = L->ci; - 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(ci_func(ci)->p, currentpc(ci), - cast_int(o - ci->u.l.base), &name); - } - return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, name) : ""; -} - - -l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { - const char *t = objtypename(o); - luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o)); -} - - -l_noret luaG_concaterror (lua_State *L, const TValue *p1, const TValue *p2) { - if (ttisstring(p1) || cvt2str(p1)) p1 = p2; - luaG_typeerror(L, p1, "concatenate"); -} - - -l_noret luaG_opinterror (lua_State *L, const TValue *p1, - const TValue *p2, const char *msg) { - lua_Number temp; - if (!tonumber(p1, &temp)) /* first operand is wrong? */ - p2 = p1; /* now second is wrong */ - luaG_typeerror(L, p2, msg); -} - - -/* -** Error when both values are convertible to numbers, but not to integers -*/ -l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) { - lua_Integer temp; - if (!tointeger(p1, &temp)) - p2 = p1; - luaG_runerror(L, "number%s has no integer representation", varinfo(L, 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); -} - - -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); - TString *src = ci_func(ci)->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); - } -} - - -l_noret luaG_errormsg (lua_State *L) { - if (L->errfunc != 0) { /* is there an error handling function? */ - StkId errfunc = restorestack(L, L->errfunc); - setobjs2s(L, L->top, L->top - 1); /* move argument */ - setobjs2s(L, L->top - 1, errfunc); /* push function */ - L->top++; /* assume EXTRA_STACK */ - luaD_call(L, L->top - 2, 1, 0); /* call it */ - } - luaD_throw(L, LUA_ERRRUN); -} - - -l_noret 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); -} - - -void luaG_traceexec (lua_State *L) { - CallInfo *ci = L->ci; - lu_byte mask = L->hookmask; - int counthook = ((mask & LUA_MASKCOUNT) && L->hookcount == 0); - if (counthook) - resethookcount(L); /* reset count */ - if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ - ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ - return; /* do not call hook again (VM yielded, so it did not move) */ - } - if (counthook) - luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ - if (mask & LUA_MASKLINE) { - 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, */ - 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); /* call line hook */ - } - L->oldpc = ci->u.l.savedpc; - if (L->status == LUA_YIELD) { /* did hook yield? */ - if (counthook) - L->hookcount = 1; /* undo decrement to zero */ - ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ - ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ - ci->func = L->top - 1; /* protect stack below results */ - luaD_throw(L, LUA_YIELD); - } -} - diff --git a/src/ldebug.h b/src/ldebug.h deleted file mode 100644 index 0d8966ca9a..0000000000 --- a/src/ldebug.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -** $Id: ldebug.h,v 2.12 2014/11/10 14:46:05 roberto Exp $ -** Auxiliary functions from Debug Interface module -** See Copyright Notice in lua.h -*/ - -#ifndef ldebug_h -#define ldebug_h - - -#include "lstate.h" - - -#define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1) - -#define getfuncline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : -1) - -#define resethookcount(L) (L->hookcount = L->basehookcount) - -/* Active Lua function (given call info) */ -#define ci_func(ci) (clLvalue((ci)->func)) - - -LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o, - const char *opname); -LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1, - const TValue *p2); -LUAI_FUNC l_noret luaG_opinterror (lua_State *L, const TValue *p1, - const TValue *p2, - const char *msg); -LUAI_FUNC l_noret luaG_tointerror (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); -LUAI_FUNC void luaG_traceexec (lua_State *L); - - -#endif diff --git a/src/ldo.c b/src/ldo.c deleted file mode 100644 index 6159e51da2..0000000000 --- a/src/ldo.c +++ /dev/null @@ -1,717 +0,0 @@ -/* -** $Id: ldo.c,v 2.135 2014/11/11 17:13:39 roberto Exp $ -** Stack and Call structure of Lua -** See Copyright Notice in lua.h -*/ - -#define ldo_c -#define LUA_CORE - -#include "lprefix.h" - - -#include -#include -#include - -#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 "lparser.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "ltm.h" -#include "lundump.h" -#include "lvm.h" -#include "lzio.h" - - - -#define errorstatus(s) ((s) > LUA_YIELD) - - -/* -** {====================================================== -** Error-recovery functions -** ======================================================= -*/ - -/* -** 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) && !defined(LUA_USE_LONGJMP) /* { */ - -/* 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_POSIX) /* }{ */ - -/* in POSIX, 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 /* }{ */ - -/* ISO C 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 { - struct lua_longjmp *previous; - luai_jmpbuf b; - volatile int status; /* error code */ -}; - - -static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { - switch (errcode) { - case LUA_ERRMEM: { /* memory error? */ - setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ - break; - } - case LUA_ERRERR: { - setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); - break; - } - default: { - setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ - break; - } - } - L->top = oldtop + 1; -} - - -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 */ - } - else { /* thread has no error handler */ - global_State *g = G(L); - L->status = cast_byte(errcode); /* mark it as dead */ - if (g->mainthread->errorJmp) { /* main thread has a handler? */ - setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ - luaD_throw(g->mainthread, errcode); /* re-throw in main thread */ - } - else { /* no handler at all; abort */ - if (g->panic) { /* panic function? */ - seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */ - if (L->ci->top < L->top) - L->ci->top = L->top; /* pushing msg. can break this invariant */ - lua_unlock(L); - g->panic(L); /* call panic function (last chance to jump out) */ - } - abort(); - } - } -} - - -int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { - unsigned short oldnCcalls = L->nCcalls; - struct lua_longjmp lj; - 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 */ - L->nCcalls = oldnCcalls; - return lj.status; -} - -/* }====================================================== */ - - -static void correctstack (lua_State *L, TValue *oldstack) { - CallInfo *ci; - UpVal *up; - L->top = (L->top - oldstack) + L->stack; - for (up = L->openupval; up != NULL; up = up->u.open.next) - up->v = (up->v - oldstack) + L->stack; - for (ci = L->ci; ci != NULL; ci = ci->previous) { - ci->top = (ci->top - oldstack) + L->stack; - ci->func = (ci->func - oldstack) + L->stack; - if (isLua(ci)) - ci->u.l.base = (ci->u.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 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_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 = 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; - if (newsize > LUAI_MAXSTACK) { /* stack overflow? */ - luaD_reallocstack(L, ERRORSTACKSIZE); - luaG_runerror(L, "stack overflow"); - } - else - luaD_reallocstack(L, newsize); - } -} - - -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 */ -} - - -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 (L->stacksize > LUAI_MAXSTACK) /* was handling stack overflow? */ - luaE_freeCI(L); /* free all CIs (list grew because of an error) */ - else - luaE_shrinkCI(L); /* shrink list */ - if (inuse > LUAI_MAXSTACK || /* still 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_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, ci->top); - lua_Debug ar; - ar.event = event; - ar.currentline = line; - ar.i_ci = ci; - luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - 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; - 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; - StkId base, fixed; - lua_assert(actual >= nfixargs); - /* move fixed parameters to final position */ - luaD_checkstack(L, p->maxstacksize); /* check again for new 'base' */ - fixed = L->top - actual; /* first fixed argument */ - base = L->top; /* final position of first argument */ - for (i=0; itop++, fixed + i); - setnilvalue(fixed + i); - } - return base; -} - - -/* -** Check whether __call metafield of 'func' is a function. If so, put -** it in stack below original 'func' so that 'luaD_precall' can call -** it. Raise an error if __call metafield is not a function. -*/ -static void tryfuncTM (lua_State *L, StkId func) { - const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL); - StkId p; - if (!ttisfunction(tm)) - luaG_typeerror(L, func, "call"); - /* Open a hole inside the stack at 'func' */ - for (p = L->top; p > func; p--) - setobjs2s(L, p, p-1); - L->top++; /* slot ensured by caller */ - setobj2s(L, func, tm); /* tag method is the new function to be called */ -} - - - -#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) { - lua_CFunction f; - 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; - luaC_checkGC(L); /* stack grow uses memory */ - 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; - n = cast_int(L->top - func) - 1; /* number of real arguments */ - luaD_checkstack(L, p->maxstacksize); - for (; n < p->numparams; n++) - setnilvalue(L->top++); /* complete missing arguments */ - if (!p->is_vararg) { - func = restorestack(L, funcr); - base = func + 1; - } - else { - base = adjust_varargs(L, p, n); - func = restorestack(L, funcr); /* previous call can change stack */ - } - 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; - luaC_checkGC(L); /* stack grow uses memory */ - if (L->hookmask & LUA_MASKCALL) - callhook(L, ci); - return 0; - } - default: { /* not a function */ - luaD_checkstack(L, 1); /* ensure space for metamethod */ - func = restorestack(L, funcr); /* previous call may change stack */ - tryfuncTM(L, func); /* try to get '__call' metamethod */ - return luaD_precall(L, func, nresults); /* now it must be a function */ - } - } -} - - -int luaD_poscall (lua_State *L, StkId firstResult) { - StkId res; - int wanted, i; - 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 */ - 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++); - while (i-- > 0) - setnilvalue(res++); - L->top = res; - return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */ -} - - -/* -** 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, int allowyield) { - if (++L->nCcalls >= LUAI_MAXCCALLS) { - if (L->nCcalls == LUAI_MAXCCALLS) - luaG_runerror(L, "C stack overflow"); - 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--; - L->nCcalls--; -} - - -/* -** Completes the execution of an interrupted C function, calling its -** continuation function. -*/ -static void finishCcall (lua_State *L, int status) { - CallInfo *ci = L->ci; - int n; - /* must have a continuation and must be able to call it */ - lua_assert(ci->u.c.k != NULL && L->nny == 0); - /* error status can only happen in a protected call */ - lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD); - 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'; CIST_YPCALL and 'errfunc' already - handled */ - adjustresults(L, ci->nresults); - /* call continuation function */ - lua_unlock(L); - n = (*ci->u.c.k)(L, status, ci->u.c.ctx); - lua_lock(L); - api_checknelems(L, n); - /* finish 'luaD_precall' */ - luaD_poscall(L, L->top - n); -} - - -/* -** Executes "full continuation" (everything in the stack) of a -** previously interrupted coroutine until the stack is empty (or another -** interruption long-jumps out of the loop). If the coroutine is -** recovering from an error, 'ud' points to the error status, which must -** be passed to the first continuation function (otherwise the default -** status is LUA_YIELD). -*/ -static void unroll (lua_State *L, void *ud) { - if (ud != NULL) /* error status? */ - finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */ - while (L->ci != &L->base_ci) { /* something in the stack */ - if (!isLua(L->ci)) /* C function? */ - finishCcall(L, LUA_YIELD); /* complete its execution */ - else { /* Lua function */ - luaV_finishOp(L); /* finish interrupted instruction */ - luaV_execute(L); /* execute down to higher C 'boundary' */ - } - } -} - - -/* -** Try to find a suspended protected call (a "recover point") for the -** given thread. -*/ -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 */ -} - - -/* -** Recovers from an error in a coroutine. Finds a recover point (if -** there is one) and completes the execution of the interrupted -** 'luaD_pcall'. If there is no recover point, returns zero. -*/ -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->extra); - luaF_close(L, oldtop); - seterrorobj(L, status, oldtop); - L->ci = ci; - L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ - L->nny = 0; /* should be zero to be yieldable */ - luaD_shrinkstack(L); - L->errfunc = ci->u.c.old_errfunc; - 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 handler and should not kill the coroutine.) -*/ -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 */ - api_incr_top(L); - luaD_throw(L, -1); /* jump back to 'lua_resume' */ -} - - -/* -** Do the work for 'lua_resume' in protected mode. Most of the work -** depends on the status of the coroutine: initial state, suspended -** inside a hook, or regularly suspended (optionally with a continuation -** function), plus erroneous cases: non-suspended coroutine or dead -** coroutine. -*/ -static void resume (lua_State *L, void *ud) { - int nCcalls = L->nCcalls; - StkId firstArg = cast(StkId, ud); - CallInfo *ci = L->ci; - 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? */ - 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; /* mark that it is running (again) */ - ci->func = restorestack(L, ci->extra); - 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 function? */ - int n; - lua_unlock(L); - n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */ - lua_lock(L); - api_checknelems(L, n); - firstArg = L->top - n; /* yield results come from continuation */ - } - luaD_poscall(L, firstArg); /* finish 'luaD_precall' */ - } - unroll(L, NULL); /* run continuation */ - } - lua_assert(nCcalls == L->nCcalls); -} - - -LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) { - int status; - int oldnny = L->nny; /* save "number of non-yieldable" calls */ - lua_lock(L); - luai_userstateresume(L, nargs); - 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); - if (status == -1) /* error calling 'lua_resume'? */ - status = LUA_ERRRUN; - else { /* continue running after recoverable errors */ - while (errorstatus(status) && recover(L, status)) { - /* unroll continuation */ - status = luaD_rawrunprotected(L, unroll, &status); - } - if (errorstatus(status)) { /* unrecoverable error? */ - L->status = cast_byte(status); /* mark thread as 'dead' */ - seterrorobj(L, status, L->top); /* push error message */ - L->ci->top = L->top; - } - else lua_assert(status == L->status); /* normal end or yield */ - } - L->nny = oldnny; /* restore 'nny' */ - L->nCcalls--; - lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0)); - lua_unlock(L); - return status; -} - - -LUA_API int lua_isyieldable (lua_State *L) { - return (L->nny == 0); -} - - -LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, - lua_KFunction k) { - CallInfo *ci = L->ci; - luai_userstateyield(L, nresults); - lua_lock(L); - api_checknelems(L, nresults); - if (L->nny > 0) { - if (L != G(L)->mainthread) - luaG_runerror(L, "attempt to yield across a C-call boundary"); - else - luaG_runerror(L, "attempt to yield from outside a coroutine"); - } - L->status = LUA_YIELD; - ci->extra = savestack(L, ci->func); /* save current 'func' */ - if (isLua(ci)) { /* inside a hook? */ - api_check(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->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 */ - lua_unlock(L); - 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; - 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 != LUA_OK) { /* an error occurred? */ - StkId oldtop = restorestack(L, old_top); - luaF_close(L, oldtop); /* close possible pending closures */ - seterrorobj(L, status, oldtop); - L->ci = old_ci; - L->allowhook = old_allowhooks; - L->nny = old_nny; - luaD_shrinkstack(L); - } - L->errfunc = old_errfunc; - return status; -} - - - -/* -** Execute a protected parser. -*/ -struct SParser { /* data to 'f_parser' */ - ZIO *z; - Mbuffer buff; /* dynamic structure used by the scanner */ - Dyndata dyd; /* dynamic structures used by the parser */ - const char *mode; - const char *name; -}; - - -static void checkmode (lua_State *L, const char *mode, const char *x) { - if (mode && strchr(mode, x[0]) == NULL) { - luaO_pushfstring(L, - "attempt to load a %s chunk (mode is '%s')", x, mode); - luaD_throw(L, LUA_ERRSYNTAX); - } -} - - -static void f_parser (lua_State *L, void *ud) { - LClosure *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"); - cl = luaU_undump(L, p->z, &p->buff, p->name); - } - else { - checkmode(L, p->mode, "text"); - cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); - } - lua_assert(cl->nupvalues == cl->p->sizeupvalues); - luaF_initupvals(L, cl); -} - - -int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, - const char *mode) { - struct SParser p; - int status; - L->nny++; /* cannot yield during parsing */ - p.z = z; p.name = name; p.mode = mode; - 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.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/ldo.h b/src/ldo.h deleted file mode 100644 index 05745c8ad8..0000000000 --- a/src/ldo.h +++ /dev/null @@ -1,46 +0,0 @@ -/* -** $Id: ldo.h,v 2.21 2014/10/25 11:50:46 roberto Exp $ -** Stack and Call structure of Lua -** See Copyright Notice in lua.h -*/ - -#ifndef ldo_h -#define ldo_h - - -#include "lobject.h" -#include "lstate.h" -#include "lzio.h" - - -#define luaD_checkstack(L,n) if (L->stack_last - L->top <= (n)) \ - luaD_growstack(L, n); else condmovestack(L); - - -#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))) - - -/* 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, - const char *mode); -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, - 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_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 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 deleted file mode 100644 index b6c7114f5d..0000000000 --- a/src/ldump.c +++ /dev/null @@ -1,214 +0,0 @@ -/* -** $Id: ldump.c,v 2.34 2014/11/02 19:19:04 roberto Exp $ -** save precompiled Lua chunks -** See Copyright Notice in lua.h -*/ - -#define ldump_c -#define LUA_CORE - -#include "lprefix.h" - - -#include - -#include "lua.h" - -#include "lobject.h" -#include "lstate.h" -#include "lundump.h" - - -typedef struct { - lua_State *L; - lua_Writer writer; - void *data; - int strip; - int status; -} DumpState; - - -/* -** All high-level dumps go through DumpVector; you can change it to -** change the endianness of the result -*/ -#define DumpVector(v,n,D) DumpBlock(v,(n)*sizeof((v)[0]),D) - -#define DumpLiteral(s,D) DumpBlock(s, sizeof(s) - sizeof(char), D) - - -static void DumpBlock (const void *b, size_t size, DumpState *D) { - if (D->status == 0) { - lua_unlock(D->L); - D->status = (*D->writer)(D->L, b, size, D->data); - lua_lock(D->L); - } -} - - -#define DumpVar(x,D) DumpVector(&x,1,D) - - -static void DumpByte (int y, DumpState *D) { - lu_byte x = (lu_byte)y; - DumpVar(x, D); -} - - -static void DumpInt (int x, DumpState *D) { - DumpVar(x, D); -} - - -static void DumpNumber (lua_Number x, DumpState *D) { - DumpVar(x, D); -} - - -static void DumpInteger (lua_Integer x, DumpState *D) { - DumpVar(x, D); -} - - -static void DumpString (const TString *s, DumpState *D) { - if (s == NULL) - DumpByte(0, D); - else { - size_t size = s->len + 1; /* include trailing '\0' */ - if (size < 0xFF) - DumpByte(cast_int(size), D); - else { - DumpByte(0xFF, D); - DumpVar(size, D); - } - DumpVector(getstr(s), size - 1, D); /* no need to save '\0' */ - } -} - - -static void DumpCode (const Proto *f, DumpState *D) { - DumpInt(f->sizecode, D); - DumpVector(f->code, f->sizecode, D); -} - - -static void DumpFunction(const Proto *f, TString *psource, DumpState *D); - -static void DumpConstants (const Proto *f, DumpState *D) { - int i; - int n = f->sizek; - DumpInt(n, D); - for (i = 0; i < n; i++) { - const TValue *o = &f->k[i]; - DumpByte(ttype(o), D); - switch (ttype(o)) { - case LUA_TNIL: - break; - case LUA_TBOOLEAN: - DumpByte(bvalue(o), D); - break; - case LUA_TNUMFLT: - DumpNumber(fltvalue(o), D); - break; - case LUA_TNUMINT: - DumpInteger(ivalue(o), D); - break; - case LUA_TSHRSTR: - case LUA_TLNGSTR: - DumpString(tsvalue(o), D); - break; - default: - lua_assert(0); - } - } -} - - -static void DumpProtos (const Proto *f, DumpState *D) { - int i; - int n = f->sizep; - DumpInt(n, D); - for (i = 0; i < n; i++) - DumpFunction(f->p[i], f->source, D); -} - - -static void DumpUpvalues (const Proto *f, DumpState *D) { - int i, n = f->sizeupvalues; - DumpInt(n, D); - for (i = 0; i < n; i++) { - DumpByte(f->upvalues[i].instack, D); - DumpByte(f->upvalues[i].idx, D); - } -} - - -static void DumpDebug (const Proto *f, DumpState *D) { - int i, n; - n = (D->strip) ? 0 : f->sizelineinfo; - DumpInt(n, D); - DumpVector(f->lineinfo, n, D); - n = (D->strip) ? 0 : f->sizelocvars; - DumpInt(n, D); - for (i = 0; i < n; i++) { - DumpString(f->locvars[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; i < n; i++) - DumpString(f->upvalues[i].name, D); -} - - -static void DumpFunction (const Proto *f, TString *psource, DumpState *D) { - if (D->strip || f->source == psource) - DumpString(NULL, D); /* no debug info or same source as its parent */ - else - DumpString(f->source, D); - DumpInt(f->linedefined, D); - DumpInt(f->lastlinedefined, D); - DumpByte(f->numparams, D); - DumpByte(f->is_vararg, D); - DumpByte(f->maxstacksize, D); - DumpCode(f, D); - DumpConstants(f, D); - DumpUpvalues(f, D); - DumpProtos(f, D); - DumpDebug(f, D); -} - - -static void DumpHeader (DumpState *D) { - DumpLiteral(LUA_SIGNATURE, D); - DumpByte(LUAC_VERSION, D); - DumpByte(LUAC_FORMAT, D); - DumpLiteral(LUAC_DATA, D); - DumpByte(sizeof(int), D); - DumpByte(sizeof(size_t), D); - DumpByte(sizeof(Instruction), D); - DumpByte(sizeof(lua_Integer), D); - DumpByte(sizeof(lua_Number), D); - DumpInteger(LUAC_INT, D); - DumpNumber(LUAC_NUM, D); -} - - -/* -** dump Lua function as precompiled chunk -*/ -int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, - int strip) { - DumpState D; - D.L = L; - D.writer = w; - D.data = data; - D.strip = strip; - D.status = 0; - DumpHeader(&D); - DumpByte(f->sizeupvalues, &D); - DumpFunction(f, NULL, &D); - return D.status; -} - diff --git a/src/lfunc.c b/src/lfunc.c deleted file mode 100644 index 67967dab3f..0000000000 --- a/src/lfunc.c +++ /dev/null @@ -1,151 +0,0 @@ -/* -** $Id: lfunc.c,v 2.45 2014/11/02 19:19:04 roberto Exp $ -** Auxiliary functions to manipulate prototypes and closures -** See Copyright Notice in lua.h -*/ - -#define lfunc_c -#define LUA_CORE - -#include "lprefix.h" - - -#include - -#include "lua.h" - -#include "lfunc.h" -#include "lgc.h" -#include "lmem.h" -#include "lobject.h" -#include "lstate.h" - - - -CClosure *luaF_newCclosure (lua_State *L, int n) { - GCObject *o = luaC_newobj(L, LUA_TCCL, sizeCclosure(n)); - CClosure *c = gco2ccl(o); - c->nupvalues = cast_byte(n); - return c; -} - - -LClosure *luaF_newLclosure (lua_State *L, int n) { - GCObject *o = luaC_newobj(L, LUA_TLCL, sizeLclosure(n)); - LClosure *c = gco2lcl(o); - c->p = NULL; - c->nupvalues = cast_byte(n); - while (n--) c->upvals[n] = NULL; - return c; -} - -/* -** fill a closure with new closed upvalues -*/ -void luaF_initupvals (lua_State *L, LClosure *cl) { - int i; - for (i = 0; i < cl->nupvalues; i++) { - UpVal *uv = luaM_new(L, UpVal); - uv->refcount = 1; - uv->v = &uv->u.value; /* make it closed */ - setnilvalue(uv->v); - cl->upvals[i] = uv; - } -} - - -UpVal *luaF_findupval (lua_State *L, StkId level) { - UpVal **pp = &L->openupval; - UpVal *p; - UpVal *uv; - lua_assert(isintwups(L) || L->openupval == NULL); - while (*pp != NULL && (p = *pp)->v >= level) { - lua_assert(upisopen(p)); - if (p->v == level) /* found a corresponding upvalue? */ - return p; /* return it */ - pp = &p->u.open.next; - } - /* not found: create a new upvalue */ - uv = luaM_new(L, UpVal); - uv->refcount = 0; - uv->u.open.next = *pp; /* link it to list of open upvalues */ - uv->u.open.touched = 1; - *pp = uv; - uv->v = level; /* current value lives in the stack */ - if (!isintwups(L)) { /* thread not in list of threads with upvalues? */ - L->twups = G(L)->twups; /* link it to the list */ - G(L)->twups = L; - } - return uv; -} - - -void luaF_close (lua_State *L, StkId level) { - UpVal *uv; - while (L->openupval != NULL && (uv = L->openupval)->v >= level) { - lua_assert(upisopen(uv)); - L->openupval = uv->u.open.next; /* remove from 'open' list */ - if (uv->refcount == 0) /* no references? */ - luaM_free(L, uv); /* free upvalue */ - else { - setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */ - uv->v = &uv->u.value; /* now current value lives here */ - luaC_upvalbarrier(L, uv); - } - } -} - - -Proto *luaF_newproto (lua_State *L) { - GCObject *o = luaC_newobj(L, LUA_TPROTO, sizeof(Proto)); - Proto *f = gco2p(o); - f->k = NULL; - f->sizek = 0; - f->p = NULL; - f->sizep = 0; - f->code = NULL; - f->cache = NULL; - f->sizecode = 0; - f->lineinfo = NULL; - f->sizelineinfo = 0; - f->upvalues = NULL; - f->sizeupvalues = 0; - f->numparams = 0; - f->is_vararg = 0; - f->maxstacksize = 0; - f->locvars = NULL; - f->sizelocvars = 0; - f->linedefined = 0; - f->lastlinedefined = 0; - f->source = NULL; - return f; -} - - -void luaF_freeproto (lua_State *L, Proto *f) { - 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); -} - - -/* -** Look for n-th local variable at line 'line' in function 'func'. -** Returns NULL if not found. -*/ -const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { - int 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 getstr(f->locvars[i].varname); - } - } - return NULL; /* not found */ -} - diff --git a/src/lfunc.h b/src/lfunc.h deleted file mode 100644 index 256d3cf90b..0000000000 --- a/src/lfunc.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -** $Id: lfunc.h,v 2.14 2014/06/19 18:27:20 roberto Exp $ -** Auxiliary functions to manipulate prototypes and closures -** See Copyright Notice in lua.h -*/ - -#ifndef lfunc_h -#define lfunc_h - - -#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))) - - -/* test whether thread is in 'twups' list */ -#define isintwups(L) (L->twups != L) - - -/* -** Upvalues for Lua closures -*/ -struct UpVal { - TValue *v; /* points to stack or to its own value */ - lu_mem refcount; /* reference counter */ - union { - struct { /* (when open) */ - UpVal *next; /* linked list */ - int touched; /* mark to avoid cycles with dead threads */ - } open; - TValue value; /* the value (when closed) */ - } u; -}; - -#define upisopen(up) ((up)->v != &(up)->u.value) - - -LUAI_FUNC Proto *luaF_newproto (lua_State *L); -LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems); -LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems); -LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); -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 const char *luaF_getlocalname (const Proto *func, int local_number, - int pc); - - -#endif diff --git a/src/lgc.c b/src/lgc.c deleted file mode 100644 index 7e37c0c3b0..0000000000 --- a/src/lgc.c +++ /dev/null @@ -1,1159 +0,0 @@ -/* -** $Id: lgc.c,v 2.200 2014/11/02 19:19:04 roberto Exp $ -** Garbage Collector -** See Copyright Notice in lua.h -*/ - -#define lgc_c -#define LUA_CORE - -#include "lprefix.h" - - -#include - -#include "lua.h" - -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "lgc.h" -#include "lmem.h" -#include "lobject.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "ltm.h" - - -/* -** internal state for collector while inside the atomic phase. The -** collector should never be in this state while running regular code. -*/ -#define GCSinsideatomic (GCSpause + 1) - -/* -** cost of sweeping one element (the size of a small object divided -** by some adjust for the sweep speed) -*/ -#define GCSWEEPCOST ((sizeof(TString) + 4) / 4) - -/* maximum number of elements to sweep in each single step */ -#define GCSWEEPMAX (cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4)) - -/* cost of calling one finalizer */ -#define GCFINALIZECOST GCSWEEPCOST - - -/* -** macro to adjust 'stepmul': 'stepmul' is actually used like -** 'stepmul / STEPMULADJ' (value chosen by tests) -*/ -#define STEPMULADJ 200 - - -/* -** macro to adjust 'pause': 'pause' is actually used like -** 'pause / PAUSEADJ' (value chosen by tests) -*/ -#define PAUSEADJ 100 - - -/* -** 'makewhite' erases all color bits then sets only the current white -** bit -*/ -#define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS)) -#define makewhite(g,x) \ - (x->marked = cast_byte((x->marked & maskcolors) | luaC_white(g))) - -#define white2gray(x) resetbits(x->marked, WHITEBITS) -#define black2gray(x) resetbit(x->marked, BLACKBIT) - - -#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) - -#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)); } - -#define markobject(g,t) \ - { if ((t) && iswhite(t)) reallymarkobject(g, obj2gco(t)); } - -static void reallymarkobject (global_State *g, GCObject *o); - - -/* -** {====================================================== -** Generic functions -** ======================================================= -*/ - - -/* -** one after last element in a hash array -*/ -#define gnodelast(h) gnode(h, cast(size_t, sizenode(h))) - - -/* -** link collectable object 'o' into list pointed by 'p' -*/ -#define linkgclist(o,p) ((o)->gclist = (p), (p) = obj2gco(o)) - - -/* -** 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 (valiswhite(gkey(n))) - setdeadvalue(wgkey(n)); /* unused and unmarked key; remove it */ -} - - -/* -** 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 (global_State *g, const TValue *o) { - if (!iscollectable(o)) return 0; - else if (ttisstring(o)) { - markobject(g, tsvalue(o)); /* strings are 'values', so are never weak */ - return 0; - } - else return iswhite(gcvalue(o)); -} - - -/* -** barrier that moves collector forward, that is, mark the white object -** being pointed by a black object. (If in sweep phase, clear the black -** object to white [sweep it] to avoid other barrier calls for this -** same object.) -*/ -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)); - if (keepinvariant(g)) /* must keep invariant? */ - reallymarkobject(g, v); /* restore invariant */ - 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); - lua_assert(isblack(t) && !isdead(g, t)); - black2gray(t); /* make table gray (again) */ - linkgclist(t, g->grayagain); -} - - -/* -** barrier for assignments to closed upvalues. Because upvalues are -** shared among closures, it is impossible to know the color of all -** closures pointing to it. So, we assume that the object being assigned -** must be marked. -*/ -void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) { - global_State *g = G(L); - GCObject *o = gcvalue(uv->v); - lua_assert(!upisopen(uv)); /* ensured by macro luaC_upvalbarrier */ - if (keepinvariant(g)) - markobject(g, o); -} - - -void luaC_fix (lua_State *L, GCObject *o) { - global_State *g = G(L); - lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ - white2gray(o); /* they will be gray forever */ - g->allgc = o->next; /* remove object from 'allgc' list */ - o->next = g->fixedgc; /* link it to 'fixedgc' list */ - g->fixedgc = o; -} - - -/* -** create a new collectable object (with given type and size) and link -** it to 'allgc' list. -*/ -GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { - global_State *g = G(L); - GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz)); - o->marked = luaC_white(g); - o->tt = tt; - o->next = g->allgc; - g->allgc = o; - return o; -} - -/* }====================================================== */ - - - -/* -** {====================================================== -** Mark functions -** ======================================================= -*/ - - -/* -** mark an object. Userdata, strings, and closed upvalues are visited -** and turned black here. 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) { - reentry: - white2gray(o); - switch (o->tt) { - case LUA_TSHRSTR: - case LUA_TLNGSTR: { - gray2black(o); - g->GCmemtrav += sizestring(gco2ts(o)); - break; - } - case LUA_TUSERDATA: { - TValue uvalue; - markobject(g, gco2u(o)->metatable); /* mark its metatable */ - gray2black(o); - g->GCmemtrav += sizeudata(gco2u(o)); - getuservalue(g->mainthread, gco2u(o), &uvalue); - if (valiswhite(&uvalue)) { /* markvalue(g, &uvalue); */ - o = gcvalue(&uvalue); - goto reentry; - } - break; - } - case LUA_TLCL: { - linkgclist(gco2lcl(o), g->gray); - break; - } - case LUA_TCCL: { - linkgclist(gco2ccl(o), g->gray); - break; - } - case LUA_TTABLE: { - linkgclist(gco2t(o), g->gray); - break; - } - case LUA_TTHREAD: { - linkgclist(gco2th(o), g->gray); - break; - } - case LUA_TPROTO: { - linkgclist(gco2p(o), g->gray); - break; - } - default: lua_assert(0); break; - } -} - - -/* -** mark metamethods for basic types -*/ -static void markmt (global_State *g) { - int i; - for (i=0; i < LUA_NUMTAGS; i++) - markobject(g, g->mt[i]); -} - - -/* -** mark all objects in list of being-finalized -*/ -static void markbeingfnz (global_State *g) { - GCObject *o; - for (o = g->tobefnz; o != NULL; o = o->next) - markobject(g, o); -} - - -/* -** Mark all values stored in marked open upvalues from non-marked threads. -** (Values from marked threads were already marked when traversing the -** thread.) Remove from the list threads that no longer have upvalues and -** not-marked threads. -*/ -static void remarkupvals (global_State *g) { - lua_State *thread; - lua_State **p = &g->twups; - while ((thread = *p) != NULL) { - lua_assert(!isblack(thread)); /* threads are never black */ - if (isgray(thread) && thread->openupval != NULL) - p = &thread->twups; /* keep marked thread with upvalues in the list */ - else { /* thread is not marked or without upvalues */ - UpVal *uv; - *p = thread->twups; /* remove thread from the list */ - thread->twups = thread; /* mark that it is out of list */ - for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { - if (uv->u.open.touched) { - markvalue(g, uv->v); /* remark upvalue's value */ - uv->u.open.touched = 0; - } - } - } - } -} - - -/* -** mark root set and reset all gray lists, to start a new collection -*/ -static void restartcollection (global_State *g) { - 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 */ -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Traverse functions -** ======================================================= -*/ - -/* -** Traverse a table with weak values and link it to proper list. During -** propagate phase, keep it in 'grayagain' list, to be revisited in the -** atomic phase. In the atomic phase, if table has any white value, -** put it in 'weak' list, to be cleared. -*/ -static void traverseweakvalue (global_State *g, Table *h) { - Node *n, *limit = gnodelast(h); - /* if there is array part, assume it may have white values (it is not - worth traversing it now just to check) */ - int hasclears = (h->sizearray > 0); - for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ - checkdeadkey(n); - if (ttisnil(gval(n))) /* entry is empty? */ - removeentry(n); /* remove it */ - else { - lua_assert(!ttisnil(gkey(n))); - markvalue(g, gkey(n)); /* mark key */ - if (!hasclears && iscleared(g, gval(n))) /* is there a white value? */ - hasclears = 1; /* table will have to be cleared */ - } - } - if (g->gcstate == GCSpropagate) - linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ - else if (hasclears) - linkgclist(h, g->weak); /* has to be cleared later */ -} - - -/* -** Traverse an ephemeron table and link it to proper list. Returns true -** iff any object was marked during this traversal (which implies that -** convergence has to continue). During propagation phase, keep table -** in 'grayagain' list, to be visited again in the atomic phase. In -** the atomic phase, if table has any white->white entry, it has to -** be revisited during ephemeron convergence (as that key may turn -** black). Otherwise, if it has any white key, table has to be cleared -** (in the atomic phase). -*/ -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 white keys */ - int hasww = 0; /* true if table has entry "white-key -> white-value" */ - Node *n, *limit = gnodelast(h); - unsigned int i; - /* traverse array part */ - for (i = 0; i < h->sizearray; i++) { - if (valiswhite(&h->array[i])) { - marked = 1; - reallymarkobject(g, gcvalue(&h->array[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 (iscleared(g, gkey(n))) { /* key is not marked (yet)? */ - hasclears = 1; /* table must be cleared */ - if (valiswhite(gval(n))) /* value not marked yet? */ - hasww = 1; /* white-white entry */ - } - else if (valiswhite(gval(n))) { /* value not marked yet? */ - marked = 1; - reallymarkobject(g, gcvalue(gval(n))); /* mark it now */ - } - } - /* link table into proper list */ - if (g->gcstate == GCSpropagate) - linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ - else if (hasww) /* table has white->white entries? */ - linkgclist(h, g->ephemeron); /* have to propagate again */ - else if (hasclears) /* table has white keys? */ - linkgclist(h, g->allweak); /* may have to clean white keys */ - return marked; -} - - -static void traversestrongtable (global_State *g, Table *h) { - Node *n, *limit = gnodelast(h); - unsigned int i; - for (i = 0; i < h->sizearray; i++) /* traverse array part */ - markvalue(g, &h->array[i]); - for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ - checkdeadkey(n); - if (ttisnil(gval(n))) /* entry is empty? */ - removeentry(n); /* remove it */ - else { - lua_assert(!ttisnil(gkey(n))); - markvalue(g, gkey(n)); /* mark key */ - markvalue(g, gval(n)); /* mark value */ - } - } -} - - -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? */ - ((weakkey = strchr(svalue(mode), 'k')), - (weakvalue = strchr(svalue(mode), 'v')), - (weakkey || weakvalue))) { /* is really weak? */ - black2gray(h); /* keep table gray */ - if (!weakkey) /* strong keys? */ - traverseweakvalue(g, h); - else if (!weakvalue) /* strong values? */ - traverseephemeron(g, h); - else /* all weak */ - linkgclist(h, g->allweak); /* nothing to traverse now */ - } - else /* not weak */ - traversestrongtable(g, h); - return sizeof(Table) + sizeof(TValue) * h->sizearray + - sizeof(Node) * cast(size_t, sizenode(h)); -} - - -static int traverseproto (global_State *g, Proto *f) { - int i; - if (f->cache && iswhite(f->cache)) - f->cache = NULL; /* allow cache to be collected */ - 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 */ - 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 */ - 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 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 sizeCclosure(cl->nupvalues); -} - -/* -** open upvalues point to values in a thread, so those values should -** be marked when the thread is traversed except in the atomic phase -** (because then the value cannot be changed by the thread and the -** thread may not be traversed again) -*/ -static lu_mem traverseLclosure (global_State *g, LClosure *cl) { - int i; - markobject(g, cl->p); /* mark its prototype */ - for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */ - UpVal *uv = cl->upvals[i]; - if (uv != NULL) { - if (upisopen(uv) && g->gcstate != GCSinsideatomic) - uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */ - else - markvalue(g, uv->v); - } - } - return sizeLclosure(cl->nupvalues); -} - - -static lu_mem traversethread (global_State *g, lua_State *th) { - StkId o = th->stack; - if (o == NULL) - return 1; /* stack not completely built yet */ - lua_assert(g->gcstate == GCSinsideatomic || - th->openupval == NULL || isintwups(th)); - for (; o < th->top; o++) /* mark live elements in the stack */ - markvalue(g, o); - if (g->gcstate == GCSinsideatomic) { /* final traversal? */ - StkId lim = th->stack + th->stacksize; /* real end of stack */ - for (; o < lim; o++) /* clear not-marked stack slice */ - setnilvalue(o); - /* 'remarkupvals' may have removed thread from 'twups' list */ - if (!isintwups(th) && th->openupval != NULL) { - th->twups = g->twups; /* link it back to the list */ - g->twups = th; - } - } - else if (g->gckind != KGC_EMERGENCY) - luaD_shrinkstack(th); /* do not change stack in emergency cycle */ - return (sizeof(lua_State) + sizeof(TValue) * th->stacksize); -} - - -/* -** traverse one gray object, turning it to black (except for threads, -** which are always gray). -*/ -static void propagatemark (global_State *g) { - lu_mem size; - GCObject *o = g->gray; - lua_assert(isgray(o)); - gray2black(o); - switch (o->tt) { - case LUA_TTABLE: { - Table *h = gco2t(o); - g->gray = h->gclist; /* remove from 'gray' list */ - size = traversetable(g, h); - break; - } - case LUA_TLCL: { - LClosure *cl = gco2lcl(o); - g->gray = cl->gclist; /* remove from 'gray' list */ - size = traverseLclosure(g, cl); - break; - } - case LUA_TCCL: { - CClosure *cl = gco2ccl(o); - 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; /* remove from 'gray' list */ - linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ - black2gray(o); - size = traversethread(g, th); - break; - } - case LUA_TPROTO: { - Proto *p = gco2p(o); - g->gray = p->gclist; /* remove from 'gray' list */ - size = traverseproto(g, p); - break; - } - default: lua_assert(0); return; - } - g->GCmemtrav += size; -} - - -static void propagateall (global_State *g) { - while (g->gray) propagatemark(g); -} - - -static void convergeephemerons (global_State *g) { - int changed; - do { - GCObject *w; - GCObject *next = g->ephemeron; /* get ephemeron list */ - g->ephemeron = NULL; /* tables may return to this list when traversed */ - changed = 0; - while ((w = next) != NULL) { - next = gco2t(w)->gclist; - if (traverseephemeron(g, gco2t(w))) { /* traverse marked some value? */ - propagateall(g); /* propagate changes */ - changed = 1; /* will have to revisit all ephemeron tables */ - } - } - } while (changed); -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Sweep Functions -** ======================================================= -*/ - - -/* -** clear entries with unmarked keys from all weaktables in list 'l' up -** to element '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(g, 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 clearvalues (global_State *g, GCObject *l, GCObject *f) { - for (; l != f; l = gco2t(l)->gclist) { - Table *h = gco2t(l); - Node *n, *limit = gnodelast(h); - unsigned int i; - for (i = 0; i < h->sizearray; i++) { - TValue *o = &h->array[i]; - if (iscleared(g, o)) /* value was collected? */ - setnilvalue(o); /* remove value */ - } - for (n = gnode(h, 0); n < limit; n++) { - if (!ttisnil(gval(n)) && iscleared(g, gval(n))) { - setnilvalue(gval(n)); /* remove value ... */ - removeentry(n); /* and remove entry from table */ - } - } - } -} - - -void luaC_upvdeccount (lua_State *L, UpVal *uv) { - lua_assert(uv->refcount > 0); - uv->refcount--; - if (uv->refcount == 0 && !upisopen(uv)) - luaM_free(L, uv); -} - - -static void freeLclosure (lua_State *L, LClosure *cl) { - int i; - for (i = 0; i < cl->nupvalues; i++) { - UpVal *uv = cl->upvals[i]; - if (uv) - luaC_upvdeccount(L, uv); - } - luaM_freemem(L, cl, sizeLclosure(cl->nupvalues)); -} - - -static void freeobj (lua_State *L, GCObject *o) { - switch (o->tt) { - case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; - case LUA_TLCL: { - freeLclosure(L, gco2lcl(o)); - break; - } - case LUA_TCCL: { - luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); - 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_TSHRSTR: - luaS_remove(L, gco2ts(o)); /* remove it from hash table */ - /* go through */ - case LUA_TLNGSTR: { - luaM_freemem(L, o, sizestring(gco2ts(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); - - -/* -** 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; change all non-dead objects back -** to white, preparing for next collection cycle. -** When object is a thread, sweep its list of open upvalues too. -*/ -static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { - global_State *g = G(L); - int ow = otherwhite(g); - int white = luaC_white(g); /* current white */ - while (*p != NULL && count-- > 0) { - GCObject *curr = *p; - int marked = curr->marked; - if (isdeadm(ow, marked)) { /* is 'curr' dead? */ - *p = curr->next; /* remove 'curr' from list */ - freeobj(L, curr); /* erase 'curr' */ - } - else { /* update marks */ - curr->marked = cast_byte((marked & maskcolors) | white); - p = &curr->next; /* go to next element */ - } - } - return (*p == NULL) ? NULL : p; -} - - -/* -** sweep a list until a live object (or end of list) -*/ -static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) { - GCObject **old = p; - int i = 0; - do { - i++; - p = sweeplist(L, p, 1); - } while (p == old); - if (n) *n += i; - return p; -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Finalization -** ======================================================= -*/ - -/* -** If possible, free concatenation buffer and shrink string table -*/ -static void checkSizes (lua_State *L, global_State *g) { - if (g->gckind != KGC_EMERGENCY) { - l_mem olddebt = g->GCdebt; - luaZ_freebuffer(L, &g->buff); /* free concatenation buffer */ - if (g->strt.nuse < g->strt.size / 4) /* string table too big? */ - luaS_resize(L, g->strt.size / 2); /* shrink it a little */ - g->GCestimate += g->GCdebt - olddebt; /* update estimate */ - } -} - - -static GCObject *udata2finalize (global_State *g) { - GCObject *o = g->tobefnz; /* get first element */ - lua_assert(tofinalize(o)); - g->tobefnz = o->next; /* remove it from 'tobefnz' list */ - o->next = g->allgc; /* return it to 'allgc' list */ - g->allgc = o; - resetbit(o->marked, FINALIZEDBIT); /* object is "normal" again */ - if (issweepphase(g)) - makewhite(g, o); /* "sweep" object */ - return 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); - 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; - int running = g->gcrunning; - L->allowhook = 0; /* stop debug hooks during GC metamethod */ - g->gcrunning = 0; /* avoid GC steps */ - setobj2s(L, L->top, tm); /* push finalizer... */ - 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->gcrunning = running; /* restore state */ - if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ - if (status == LUA_ERRRUN) { /* is there an error object? */ - const char *msg = (ttisstring(L->top - 1)) - ? svalue(L->top - 1) - : "no message"; - luaO_pushfstring(L, "error in __gc metamethod (%s)", msg); - status = LUA_ERRGCMM; /* error in __gc metamethod */ - } - luaD_throw(L, status); /* re-throw error */ - } - } -} - - -/* -** call a few (up to 'g->gcfinnum') finalizers -*/ -static int runafewfinalizers (lua_State *L) { - global_State *g = G(L); - unsigned int i; - lua_assert(!g->tobefnz || g->gcfinnum > 0); - for (i = 0; g->tobefnz && i < g->gcfinnum; i++) - GCTM(L, 1); /* call one finalizer */ - g->gcfinnum = (!g->tobefnz) ? 0 /* nothing more to finalize? */ - : g->gcfinnum * 2; /* else call a few more next time */ - return i; -} - - -/* -** call all pending finalizers -*/ -static void callallpendingfinalizers (lua_State *L, int propagateerrors) { - global_State *g = G(L); - while (g->tobefnz) - GCTM(L, propagateerrors); -} - - -/* -** find last 'next' field in list 'p' list (to add elements in its end) -*/ -static GCObject **findlast (GCObject **p) { - while (*p != NULL) - p = &(*p)->next; - return p; -} - - -/* -** move all unreachable objects (or 'all' objects) that need -** finalization from list 'finobj' to list 'tobefnz' (to be finalized) -*/ -static void separatetobefnz (global_State *g, int all) { - GCObject *curr; - GCObject **p = &g->finobj; - GCObject **lastnext = findlast(&g->tobefnz); - while ((curr = *p) != NULL) { /* traverse all finalizable objects */ - lua_assert(tofinalize(curr)); - if (!(iswhite(curr) || all)) /* not being collected? */ - p = &curr->next; /* don't bother with it */ - else { - *p = curr->next; /* remove 'curr' from 'finobj' list */ - curr->next = *lastnext; /* link at the end of 'tobefnz' list */ - *lastnext = curr; - lastnext = &curr->next; - } - } -} - - -/* -** 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, GCObject *o, Table *mt) { - global_State *g = G(L); - if (tofinalize(o) || /* obj. is already marked... */ - gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */ - return; /* nothing to be done */ - else { /* move 'o' to 'finobj' list */ - GCObject **p; - if (issweepphase(g)) { - makewhite(g, o); /* "sweep" object 'o' */ - if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */ - g->sweepgc = sweeptolive(L, g->sweepgc, NULL); /* change 'sweepgc' */ - } - /* search for pointer pointing to 'o' */ - for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ } - *p = o->next; /* remove 'o' from 'allgc' list */ - o->next = g->finobj; /* link it in 'finobj' list */ - g->finobj = o; - l_setbit(o->marked, FINALIZEDBIT); /* mark it as such */ - } -} - -/* }====================================================== */ - - - -/* -** {====================================================== -** GC control -** ======================================================= -*/ - - -/* -** Set a reasonable "time" to wait before starting a new GC cycle; cycle -** will start when memory use hits threshold. (Division by 'estimate' -** should be OK: it cannot be zero (because Lua cannot even start with -** less than PAUSEADJ bytes). -*/ -static void setpause (global_State *g) { - l_mem threshold, debt; - l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */ - lua_assert(estimate > 0); - threshold = (g->gcpause < MAX_LMEM / estimate) /* overflow? */ - ? estimate * g->gcpause /* no overflow */ - : MAX_LMEM; /* overflow; truncate to maximum */ - debt = gettotalbytes(g) - threshold; - luaE_setdebt(g, debt); -} - - -/* -** Enter first sweep phase. -** The call to 'sweeptolive' makes pointer 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. -** Returns how many objects it swept. -*/ -static int entersweep (lua_State *L) { - global_State *g = G(L); - int n = 0; - g->gcstate = GCSswpallgc; - lua_assert(g->sweepgc == NULL); - g->sweepgc = sweeptolive(L, &g->allgc, &n); - return n; -} - - -void luaC_freeallobjects (lua_State *L) { - global_State *g = G(L); - separatetobefnz(g, 1); /* separate all objects with finalizers */ - lua_assert(g->finobj == NULL); - callallpendingfinalizers(L, 0); - lua_assert(g->tobefnz == NULL); - g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ - g->gckind = KGC_NORMAL; - sweepwholelist(L, &g->finobj); - sweepwholelist(L, &g->allgc); - sweepwholelist(L, &g->fixedgc); /* collect fixed objects */ - lua_assert(g->strt.nuse == 0); -} - - -static l_mem atomic (lua_State *L) { - global_State *g = G(L); - l_mem work; - GCObject *origweak, *origall; - GCObject *grayagain = g->grayagain; /* save original list */ - lua_assert(g->ephemeron == NULL && g->weak == NULL); - lua_assert(!iswhite(g->mainthread)); - g->gcstate = GCSinsideatomic; - g->GCmemtrav = 0; /* start counting work */ - markobject(g, L); /* mark running thread */ - /* registry and global metatables may be changed by API */ - markvalue(g, &g->l_registry); - markmt(g); /* mark global metatables */ - /* remark occasional upvalues of (maybe) dead threads */ - remarkupvals(g); - propagateall(g); /* propagate changes */ - work = g->GCmemtrav; /* stop counting (do not recount 'grayagain') */ - g->gray = grayagain; - propagateall(g); /* traverse 'grayagain' list */ - g->GCmemtrav = 0; /* restart counting */ - convergeephemerons(g); - /* at this point, all strongly accessible objects are marked. */ - /* Clear values from weak tables, before checking finalizers */ - clearvalues(g, g->weak, NULL); - clearvalues(g, g->allweak, NULL); - origweak = g->weak; origall = g->allweak; - work += g->GCmemtrav; /* stop counting (objects being finalized) */ - separatetobefnz(g, 0); /* separate objects to be finalized */ - g->gcfinnum = 1; /* there may be objects to be finalized */ - markbeingfnz(g); /* mark objects that will be finalized */ - propagateall(g); /* remark, to propagate 'resurrection' */ - g->GCmemtrav = 0; /* restart counting */ - convergeephemerons(g); - /* at this point, all resurrected objects are marked. */ - /* remove dead objects from weak 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, g->weak, origweak); - clearvalues(g, g->allweak, origall); - g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ - work += g->GCmemtrav; /* complete counting */ - return work; /* estimate of memory marked by 'atomic' */ -} - - -static lu_mem sweepstep (lua_State *L, global_State *g, - int nextstate, GCObject **nextlist) { - if (g->sweepgc) { - l_mem olddebt = g->GCdebt; - g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); - g->GCestimate += g->GCdebt - olddebt; /* update estimate */ - if (g->sweepgc) /* is there still something to sweep? */ - return (GCSWEEPMAX * GCSWEEPCOST); - } - /* else enter next state */ - g->gcstate = nextstate; - g->sweepgc = nextlist; - return 0; -} - - -static lu_mem singlestep (lua_State *L) { - global_State *g = G(L); - switch (g->gcstate) { - case GCSpause: { - g->GCmemtrav = g->strt.size * sizeof(GCObject*); - restartcollection(g); - g->gcstate = GCSpropagate; - return g->GCmemtrav; - } - case GCSpropagate: { - g->GCmemtrav = 0; - lua_assert(g->gray); - propagatemark(g); - if (g->gray == NULL) /* no more gray objects? */ - g->gcstate = GCSatomic; /* finish propagate phase */ - return g->GCmemtrav; /* memory traversed in this step */ - } - case GCSatomic: { - lu_mem work; - int sw; - propagateall(g); /* make sure gray list is empty */ - work = atomic(L); /* work is what was traversed by 'atomic' */ - sw = entersweep(L); - g->GCestimate = gettotalbytes(g); /* first estimate */; - return work + sw * GCSWEEPCOST; - } - case GCSswpallgc: { /* sweep "regular" objects */ - return sweepstep(L, g, GCSswpfinobj, &g->finobj); - } - case GCSswpfinobj: { /* sweep objects with finalizers */ - return sweepstep(L, g, GCSswptobefnz, &g->tobefnz); - } - case GCSswptobefnz: { /* sweep objects to be finalized */ - return sweepstep(L, g, GCSswpend, NULL); - } - case GCSswpend: { /* finish sweeps */ - makewhite(g, g->mainthread); /* sweep main thread */ - checkSizes(L, g); - g->gcstate = GCScallfin; - return 0; - } - case GCScallfin: { /* call remaining finalizers */ - if (g->tobefnz && g->gckind != KGC_EMERGENCY) { - int n = runafewfinalizers(L); - return (n * GCFINALIZECOST); - } - else { /* emergency mode or no more finalizers */ - g->gcstate = GCSpause; /* finish collection */ - return 0; - } - } - default: lua_assert(0); return 0; - } -} - - -/* -** 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); - while (!testbit(statesmask, g->gcstate)) - singlestep(L); -} - - -/* -** get GC debt and convert it from Kb to 'work units' (avoid zero debt -** and overflows) -*/ -static l_mem getdebt (global_State *g) { - l_mem debt = g->GCdebt; - int stepmul = g->gcstepmul; - debt = (debt / STEPMULADJ) + 1; - debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM; - return debt; -} - -/* -** performs a basic GC step when collector is running -*/ -void luaC_step (lua_State *L) { - global_State *g = G(L); - l_mem debt = getdebt(g); /* GC deficit (be paid now) */ - if (!g->gcrunning) { /* not running? */ - luaE_setdebt(g, -GCSTEPSIZE * 10); /* avoid being called too often */ - return; - } - do { /* repeat until pause or enough "credit" (negative debt) */ - lu_mem work = singlestep(L); /* perform one single step */ - debt -= work; - } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause); - if (g->gcstate == GCSpause) - setpause(g); /* pause until next cycle */ - else { - debt = (debt / g->gcstepmul) * STEPMULADJ; /* convert 'work units' to Kb */ - luaE_setdebt(g, debt); - runafewfinalizers(L); - } -} - - -/* -** Performs a full GC cycle; if 'isemergency', set a flag to avoid -** some operations which could change the interpreter state in some -** unexpected ways (running finalizers and shrinking some structures). -** Before running the collection, check 'keepinvariant'; if it is true, -** there may be some objects marked as black, so the collector has -** to sweep all objects to turn them back to white (as white has not -** changed, nothing will be collected). -*/ -void luaC_fullgc (lua_State *L, int isemergency) { - global_State *g = G(L); - lua_assert(g->gckind == KGC_NORMAL); - if (isemergency) g->gckind = KGC_EMERGENCY; /* set flag */ - if (keepinvariant(g)) { /* black objects? */ - entersweep(L); /* sweep everything to turn them back to white */ - } - /* finish any pending sweep phase to start a new cycle */ - luaC_runtilstate(L, bitmask(GCSpause)); - luaC_runtilstate(L, ~bitmask(GCSpause)); /* start new collection */ - luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ - /* estimate must be correct after a full GC cycle */ - lua_assert(g->GCestimate == gettotalbytes(g)); - luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ - g->gckind = KGC_NORMAL; - setpause(g); -} - -/* }====================================================== */ - - diff --git a/src/lgc.h b/src/lgc.h deleted file mode 100644 index 0eedf84204..0000000000 --- a/src/lgc.h +++ /dev/null @@ -1,138 +0,0 @@ -/* -** $Id: lgc.h,v 2.86 2014/10/25 11:50:46 roberto Exp $ -** Garbage Collector -** See Copyright Notice in lua.h -*/ - -#ifndef lgc_h -#define lgc_h - - -#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). -*/ - - - -/* 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 -*/ -#define GCSpropagate 0 -#define GCSatomic 1 -#define GCSswpallgc 2 -#define GCSswpfinobj 3 -#define GCSswptobefnz 4 -#define GCSswpend 5 -#define GCScallfin 6 -#define GCSpause 7 - - -#define issweepphase(g) \ - (GCSswpallgc <= (g)->gcstate && (g)->gcstate <= GCSswpend) - - -/* -** macro to tell when main invariant (white objects cannot point to black -** ones) must be kept. During a 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. -*/ - -#define keepinvariant(g) ((g)->gcstate <= GCSatomic) - - -/* -** 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)) - - -/* 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 /* object has been marked for finalization */ -/* bit 7 is currently used by tests (luaL_checkmemory) */ - -#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) - - -#define iswhite(x) testbits((x)->marked, WHITEBITS) -#define isblack(x) testbit((x)->marked, BLACKBIT) -#define isgray(x) /* neither white nor black */ \ - (!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT))) - -#define tofinalize(x) testbit((x)->marked, FINALIZEDBIT) - -#define otherwhite(g) ((g)->currentwhite ^ WHITEBITS) -#define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow))) -#define isdead(g,v) isdeadm(otherwhite(g), (v)->marked) - -#define changewhite(x) ((x)->marked ^= WHITEBITS) -#define gray2black(x) l_setbit((x)->marked, BLACKBIT) - -#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) - - -#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 (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) \ - luaC_barrier_(L,obj2gco(p),gcvalue(v)); } - -#define luaC_barrierback(L,p,v) { \ - if (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) \ - luaC_barrierback_(L,p); } - -#define luaC_objbarrier(L,p,o) { \ - if (isblack(p) && iswhite(o)) \ - luaC_barrier_(L,obj2gco(p),obj2gco(o)); } - -#define luaC_upvalbarrier(L,uv) \ - { if (iscollectable((uv)->v) && !upisopen(uv)) \ - luaC_upvalbarrier_(L,uv); } - -LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); -LUAI_FUNC void luaC_freeallobjects (lua_State *L); -LUAI_FUNC void luaC_step (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); -LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); -LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o); -LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv); -LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); -LUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv); - - -#endif diff --git a/src/linit.c b/src/linit.c deleted file mode 100644 index ca9d100d33..0000000000 --- a/src/linit.c +++ /dev/null @@ -1,66 +0,0 @@ -/* -** $Id: linit.c,v 1.37 2014/12/09 15:00:17 roberto Exp $ -** Initialization of libraries for lua.c and other clients -** See Copyright Notice in lua.h -*/ - - -#define linit_c -#define LUA_LIB - -#include "lprefix.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. -** -** You can also *preload* libraries, so that a later 'require' can -** open the library, which is already linked to the application. -** For that, do the following code: -** -** luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); -** lua_pushcfunction(L, luaopen_modname); -** lua_setfield(L, -2, modname); -** lua_pop(L, 1); // remove _PRELOAD table -*/ - -#include "lua.h" - -#include "lualib.h" -#include "lauxlib.h" - - -/* -** 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_COLIBNAME, luaopen_coroutine}, - {LUA_TABLIBNAME, luaopen_table}, - {LUA_IOLIBNAME, luaopen_io}, - {LUA_OSLIBNAME, luaopen_os}, - {LUA_STRLIBNAME, luaopen_string}, - {LUA_MATHLIBNAME, luaopen_math}, - {LUA_UTF8LIBNAME, luaopen_utf8}, - {LUA_DBLIBNAME, luaopen_debug}, -#if defined(LUA_COMPAT_BITLIB) - {LUA_BITLIBNAME, luaopen_bit32}, -#endif - {NULL, NULL} -}; - - -LUALIB_API void luaL_openlibs (lua_State *L) { - const luaL_Reg *lib; - /* "require" functions from 'loadedlibs' and set results to global table */ - for (lib = loadedlibs; lib->func; lib++) { - luaL_requiref(L, lib->name, lib->func, 1); - lua_pop(L, 1); /* remove lib */ - } -} - diff --git a/src/liolib.c b/src/liolib.c deleted file mode 100644 index 245036bd00..0000000000 --- a/src/liolib.c +++ /dev/null @@ -1,759 +0,0 @@ -/* -** $Id: liolib.c,v 2.141 2014/11/21 12:17:33 roberto Exp $ -** Standard I/O (and system) library -** See Copyright Notice in lua.h -*/ - -#define liolib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include -#include -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -#if !defined(l_checkmode) - -/* -** Check whether 'mode' matches '[rwa]%+?b?'. -** Change this macro to accept other modes for 'fopen' besides -** the standard ones. -*/ -#define l_checkmode(mode) \ - (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \ - (*mode != '+' || ++mode) && /* skip if char is '+' */ \ - (*mode != 'b' || ++mode) && /* skip if char is 'b' */ \ - (*mode == '\0')) - -#endif - -/* -** {====================================================== -** l_popen spawns a new process connected to the current -** one through the file streams. -** ======================================================= -*/ - -#if !defined(l_popen) /* { */ - -#if defined(LUA_USE_POSIX) /* { */ - -#define l_popen(L,c,m) (fflush(NULL), popen(c,m)) -#define l_pclose(L,file) (pclose(file)) - -#elif defined(LUA_USE_WINDOWS) /* }{ */ - -#define l_popen(L,c,m) (_popen(c,m)) -#define l_pclose(L,file) (_pclose(file)) - -#else /* }{ */ - -/* ISO C definitions */ -#define l_popen(L,c,m) \ - ((void)((void)c, m), \ - luaL_error(L, "'popen' not supported"), \ - (FILE*)0) -#define l_pclose(L,file) ((void)L, (void)file, -1) - -#endif /* } */ - -#endif /* } */ - -/* }====================================================== */ - - -#if !defined(l_getc) /* { */ - -#if defined(LUA_USE_POSIX) -#define l_getc(f) getc_unlocked(f) -#define l_lockfile(f) flockfile(f) -#define l_unlockfile(f) funlockfile(f) -#else -#define l_getc(f) getc(f) -#define l_lockfile(f) ((void)0) -#define l_unlockfile(f) ((void)0) -#endif - -#endif /* } */ - - -/* -** {====================================================== -** l_fseek: configuration for longer offsets -** ======================================================= -*/ - -#if !defined(l_fseek) /* { */ - -#if defined(LUA_USE_POSIX) /* { */ - -#include - -#define l_fseek(f,o,w) fseeko(f,o,w) -#define l_ftell(f) ftello(f) -#define l_seeknum off_t - -#elif defined(LUA_USE_WINDOWS) && !defined(_CRTIMP_TYPEINFO) \ - && defined(_MSC_VER) && (_MSC_VER >= 1400) /* }{ */ - -/* Windows (but not DDK) and Visual C++ 2005 or higher */ -#define l_fseek(f,o,w) _fseeki64(f,o,w) -#define l_ftell(f) _ftelli64(f) -#define l_seeknum __int64 - -#else /* }{ */ - -/* ISO C definitions */ -#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 IOPREF_LEN (sizeof(IO_PREFIX)/sizeof(char) - 1) -#define IO_INPUT (IO_PREFIX "input") -#define IO_OUTPUT (IO_PREFIX "output") - - -typedef luaL_Stream LStream; - - -#define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE)) - -#define isclosed(p) ((p)->closef == NULL) - - -static int io_type (lua_State *L) { - LStream *p; - luaL_checkany(L, 1); - p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE); - if (p == NULL) - lua_pushnil(L); /* not a file */ - else if (isclosed(p)) - lua_pushliteral(L, "closed file"); - else - lua_pushliteral(L, "file"); - return 1; -} - - -static int f_tostring (lua_State *L) { - LStream *p = tolstream(L); - if (isclosed(p)) - lua_pushliteral(L, "file (closed)"); - else - lua_pushfstring(L, "file (%p)", p->f); - return 1; -} - - -static FILE *tofile (lua_State *L) { - LStream *p = tolstream(L); - if (isclosed(p)) - luaL_error(L, "attempt to use a closed file"); - lua_assert(p->f); - return p->f; -} - - -/* -** 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 LStream *newprefile (lua_State *L) { - LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream)); - p->closef = NULL; /* mark file handle as 'closed' */ - luaL_setmetatable(L, LUA_FILEHANDLE); - return p; -} - - -/* -** Calls the 'close' function from a file handle. The 'volatile' avoids -** a bug in some versions of the Clang compiler (e.g., clang 3.0 for -** 32 bits). -*/ -static int aux_close (lua_State *L) { - LStream *p = tolstream(L); - volatile lua_CFunction cf = p->closef; - p->closef = NULL; /* mark stream as closed */ - return (*cf)(L); /* close it */ -} - - -static int io_close (lua_State *L) { - if (lua_isnone(L, 1)) /* no argument? */ - lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */ - tofile(L); /* make sure argument is an open stream */ - return aux_close(L); -} - - -static int f_gc (lua_State *L) { - LStream *p = tolstream(L); - if (!isclosed(p) && p->f != NULL) - aux_close(L); /* ignore closed and incompletely open files */ - return 0; -} - - -/* -** function to close regular files -*/ -static int io_fclose (lua_State *L) { - LStream *p = tolstream(L); - int res = fclose(p->f); - return luaL_fileresult(L, (res == 0), NULL); -} - - -static LStream *newfile (lua_State *L) { - LStream *p = newprefile(L); - p->f = NULL; - p->closef = &io_fclose; - return p; -} - - -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 '%s' (%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"); - LStream *p = newfile(L); - const char *md = mode; /* to traverse/check mode */ - luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); - p->f = fopen(filename, mode); - return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; -} - - -/* -** function to close 'popen' files -*/ -static int io_pclose (lua_State *L) { - LStream *p = tolstream(L); - return luaL_execresult(L, l_pclose(L, p->f)); -} - - -static int io_popen (lua_State *L) { - const char *filename = luaL_checkstring(L, 1); - const char *mode = luaL_optstring(L, 2, "r"); - LStream *p = newprefile(L); - p->f = l_popen(L, filename, mode); - p->closef = &io_pclose; - return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; -} - - -static int io_tmpfile (lua_State *L) { - LStream *p = newfile(L); - p->f = tmpfile(); - return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; -} - - -static FILE *getiofile (lua_State *L, const char *findex) { - LStream *p; - lua_getfield(L, LUA_REGISTRYINDEX, findex); - p = (LStream *)lua_touserdata(L, -1); - if (isclosed(p)) - luaL_error(L, "standard %s file is closed", findex + IOPREF_LEN); - return p->f; -} - - -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) - opencheck(L, filename, mode); - else { - tofile(L); /* check that it's a valid file handle */ - lua_pushvalue(L, 1); - } - lua_setfield(L, LUA_REGISTRYINDEX, f); - } - /* return current value */ - lua_getfield(L, LUA_REGISTRYINDEX, f); - return 1; -} - - -static int io_input (lua_State *L) { - return g_iofile(L, IO_INPUT, "r"); -} - - -static int io_output (lua_State *L) { - return g_iofile(L, IO_OUTPUT, "w"); -} - - -static int io_readline (lua_State *L); - - -static void aux_lines (lua_State *L, int toclose) { - int n = lua_gettop(L) - 1; /* number of arguments to read */ - lua_pushinteger(L, n); /* number of arguments to read */ - lua_pushboolean(L, toclose); /* close/not close file when finished */ - lua_rotate(L, 2, 2); /* move 'n' and 'toclose' to their positions */ - 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, 0); - return 1; -} - - -static int io_lines (lua_State *L) { - int toclose; - if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ - if (lua_isnil(L, 1)) { /* no file name? */ - lua_getfield(L, LUA_REGISTRYINDEX, 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 { /* open a new file */ - const char *filename = luaL_checkstring(L, 1); - opencheck(L, filename, "r"); - lua_replace(L, 1); /* put file at index 1 */ - toclose = 1; /* close it after iteration */ - } - aux_lines(L, toclose); - return 1; -} - - -/* -** {====================================================== -** READ -** ======================================================= -*/ - - -/* maximum length of a numeral */ -#define MAXRN 200 - -/* auxiliary structure used by 'read_number' */ -typedef struct { - FILE *f; /* file being read */ - int c; /* current character (look ahead) */ - int n; /* number of elements in buffer 'buff' */ - char buff[MAXRN + 1]; /* +1 for ending '\0' */ -} RN; - - -/* -** Add current char to buffer (if not out of space) and read next one -*/ -static int nextc (RN *rn) { - if (rn->n >= MAXRN) { /* buffer overflow? */ - rn->buff[0] = '\0'; /* invalidate result */ - return 0; /* fail */ - } - else { - rn->buff[rn->n++] = rn->c; /* save current char */ - rn->c = l_getc(rn->f); /* read next one */ - return 1; - } -} - - -/* -** Accept current char if it is in 'set' (of size 1 or 2) -*/ -static int test2 (RN *rn, const char *set) { - if (rn->c == set[0] || (rn->c == set[1] && rn->c != '\0')) - return nextc(rn); - else return 0; -} - - -/* -** Read a sequence of (hex)digits -*/ -static int readdigits (RN *rn, int hex) { - int count = 0; - while ((hex ? isxdigit(rn->c) : isdigit(rn->c)) && nextc(rn)) - count++; - return count; -} - - -/* access to locale "radix character" (decimal point) */ -#if !defined(l_getlocaledecpoint) -#define l_getlocaledecpoint() (localeconv()->decimal_point[0]) -#endif - - -/* -** Read a number: first reads a valid prefix of a numeral into a buffer. -** Then it calls 'lua_stringtonumber' to check whether the format is -** correct and to convert it to a Lua number -*/ -static int read_number (lua_State *L, FILE *f) { - RN rn; - int count = 0; - int hex = 0; - char decp[2] = "."; - rn.f = f; rn.n = 0; - decp[0] = l_getlocaledecpoint(); /* get decimal point from locale */ - l_lockfile(rn.f); - do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */ - test2(&rn, "-+"); /* optional signal */ - if (test2(&rn, "0")) { - if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */ - else count = 1; /* count initial '0' as a valid digit */ - } - count += readdigits(&rn, hex); /* integral part */ - if (test2(&rn, decp)) /* decimal point? */ - count += readdigits(&rn, hex); /* fractional part */ - if (count > 0 && test2(&rn, (hex ? "pP" : "eE"))) { /* exponent mark? */ - test2(&rn, "-+"); /* exponent signal */ - readdigits(&rn, 0); /* exponent digits */ - } - ungetc(rn.c, rn.f); /* unread look-ahead char */ - l_unlockfile(rn.f); - rn.buff[rn.n] = '\0'; /* finish string */ - if (lua_stringtonumber(L, rn.buff)) /* is this a valid number? */ - return 1; /* ok */ - else { /* invalid format */ - lua_pushnil(L); /* "result" to be removed */ - return 0; /* read fails */ - } -} - - -static int test_eof (lua_State *L, FILE *f) { - int c = getc(f); - ungetc(c, f); /* no-op when c == EOF */ - lua_pushlstring(L, NULL, 0); - return (c != EOF); -} - - -static int read_line (lua_State *L, FILE *f, int chop) { - luaL_Buffer b; - int c; - luaL_buffinit(L, &b); - for (;;) { - char *buff = luaL_prepbuffer(&b); /* pre-allocate buffer */ - int i = 0; - l_lockfile(f); /* no memory errors can happen inside the lock */ - while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n') - buff[i++] = c; - l_unlockfile(f); - luaL_addsize(&b, i); - if (i < LUAL_BUFFERSIZE) - break; - } - if (!chop && c == '\n') /* want a newline and have one? */ - luaL_addchar(&b, c); /* add ending newline to result */ - luaL_pushresult(&b); /* close buffer */ - /* return ok if read something (either a newline or something else) */ - return (c == '\n' || lua_rawlen(L, -1) > 0); -} - - -static void read_all (lua_State *L, FILE *f) { - size_t nr; - luaL_Buffer b; - luaL_buffinit(L, &b); - do { /* read file in chunks of LUAL_BUFFERSIZE bytes */ - char *p = luaL_prepbuffsize(&b, LUAL_BUFFERSIZE); - nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f); - luaL_addsize(&b, nr); - } while (nr == LUAL_BUFFERSIZE); - 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 (nr > 0); /* true iff read something */ -} - - -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, 1); - n = first+1; /* to return 1 result */ - } - 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)luaL_checkinteger(L, n); - success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); - } - else { - const char *p = luaL_checkstring(L, n); - if (*p == '*') p++; /* skip optional '*' (for compatibility) */ - switch (*p) { - case 'n': /* number */ - success = read_number(L, f); - break; - case 'l': /* line */ - 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_all(L, f); /* read entire file */ - success = 1; /* always success */ - break; - default: - return luaL_argerror(L, n, "invalid format"); - } - } - } - } - if (ferror(f)) - return luaL_fileresult(L, 0, NULL); - 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), 2); -} - - -static int io_readline (lua_State *L) { - LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1)); - int i; - int n = (int)lua_tointeger(L, lua_upvalueindex(2)); - if (isclosed(p)) /* file is already closed? */ - return luaL_error(L, "file is already closed"); - lua_settop(L , 1); - luaL_checkstack(L, n, "too many arguments"); - for (i = 1; i <= n; i++) /* push arguments to 'g_read' */ - lua_pushvalue(L, lua_upvalueindex(3 + i)); - n = g_read(L, p->f, 2); /* 'n' is number of results */ - lua_assert(n > 0); /* should return at least a nil */ - if (lua_toboolean(L, -n)) /* read at least one value? */ - return n; /* return them */ - else { /* first result is nil: EOF or error */ - 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)); - aux_close(L); /* close it */ - } - return 0; - } -} - -/* }====================================================== */ - - -static int g_write (lua_State *L, FILE *f, int arg) { - int nargs = lua_gettop(L) - arg; - int status = 1; - for (; nargs--; arg++) { - if (lua_type(L, arg) == LUA_TNUMBER) { - /* optimization: could be done exactly as for strings */ - int len = lua_isinteger(L, arg) - ? fprintf(f, LUA_INTEGER_FMT, lua_tointeger(L, arg)) - : fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)); - status = status && (len > 0); - } - else { - size_t l; - const char *s = luaL_checklstring(L, arg, &l); - status = status && (fwrite(s, sizeof(char), l, f) == l); - } - } - if (status) return 1; /* file handle already on stack top */ - else return luaL_fileresult(L, status, NULL); -} - - -static int io_write (lua_State *L) { - return g_write(L, getiofile(L, IO_OUTPUT), 1); -} - - -static int f_write (lua_State *L) { - FILE *f = tofile(L); - lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ - return g_write(L, f, 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); - int op = luaL_checkoption(L, 2, "cur", modenames); - lua_Integer p3 = luaL_optinteger(L, 3, 0); - l_seeknum offset = (l_seeknum)p3; - luaL_argcheck(L, (lua_Integer)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, (lua_Integer)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); - int op = luaL_checkoption(L, 2, NULL, modenames); - lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); - int res = setvbuf(f, NULL, mode[op], (size_t)sz); - return luaL_fileresult(L, res == 0, NULL); -} - - - -static int io_flush (lua_State *L) { - return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); -} - - -static int f_flush (lua_State *L) { - return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL); -} - - -/* -** functions for 'io' library -*/ -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}, - {"write", io_write}, - {NULL, NULL} -}; - - -/* -** methods for file handles -*/ -static const luaL_Reg flib[] = { - {"close", io_close}, - {"flush", f_flush}, - {"lines", f_lines}, - {"read", f_read}, - {"seek", f_seek}, - {"setvbuf", f_setvbuf}, - {"write", f_write}, - {"__gc", f_gc}, - {"__tostring", f_tostring}, - {NULL, NULL} -}; - - -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_setfuncs(L, flib, 0); /* add file methods to new metatable */ - lua_pop(L, 1); /* pop new metatable */ -} - - -/* -** function to (not) close the standard files stdin, stdout, and stderr -*/ -static int io_noclose (lua_State *L) { - LStream *p = tolstream(L); - p->closef = &io_noclose; /* keep file opened */ - lua_pushnil(L); - lua_pushliteral(L, "cannot close standard file"); - return 2; -} - - -static void createstdfile (lua_State *L, FILE *f, const char *k, - const char *fname) { - LStream *p = newprefile(L); - p->f = f; - p->closef = &io_noclose; - if (k != NULL) { - lua_pushvalue(L, -1); - lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */ - } - lua_setfield(L, -2, fname); /* add file to module */ -} - - -LUAMOD_API int luaopen_io (lua_State *L) { - luaL_newlib(L, iolib); /* new module */ - createmeta(L); - /* create (and set) default files */ - createstdfile(L, stdin, IO_INPUT, "stdin"); - createstdfile(L, stdout, IO_OUTPUT, "stdout"); - createstdfile(L, stderr, NULL, "stderr"); - return 1; -} - diff --git a/src/llex.c b/src/llex.c deleted file mode 100644 index 6e4a457ad6..0000000000 --- a/src/llex.c +++ /dev/null @@ -1,602 +0,0 @@ -/* -** $Id: llex.c,v 2.89 2014/11/14 16:06:09 roberto Exp $ -** Lexical Analyzer -** See Copyright Notice in lua.h -*/ - -#define llex_c -#define LUA_CORE - -#include "lprefix.h" - - -#include -#include - -#include "lua.h" - -#include "lctype.h" -#include "ldo.h" -#include "lgc.h" -#include "llex.h" -#include "lobject.h" -#include "lparser.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "lzio.h" - - - -#define next(ls) (ls->current = zgetc(ls->z)) - - - -#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') - - -/* ORDER RESERVED */ -static const char *const luaX_tokens [] = { - "and", "break", "do", "else", "elseif", - "end", "false", "for", "function", "goto", "if", - "in", "local", "nil", "not", "or", "repeat", - "return", "then", "true", "until", "while", - "//", "..", "...", "==", ">=", "<=", "~=", - "<<", ">>", "::", "", - "", "", "", "" -}; - - -#define save_and_next(ls) (save(ls, ls->current), next(ls)) - - -static l_noret lexerror (LexState *ls, const char *msg, int token); - - -static void save (LexState *ls, int c) { - Mbuffer *b = ls->buff; - if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) { - size_t newsize; - if (luaZ_sizebuffer(b) >= MAX_SIZE/2) - lexerror(ls, "lexical element too long", 0); - newsize = luaZ_sizebuffer(b) * 2; - luaZ_resizebuffer(ls->L, b, newsize); - } - b->buffer[luaZ_bufflen(b)++] = cast(char, c); -} - - -void luaX_init (lua_State *L) { - int i; - TString *e = luaS_new(L, LUA_ENV); /* create env name */ - luaC_fix(L, obj2gco(e)); /* never collect this name */ - for (i=0; iextra = cast_byte(i+1); /* reserved word */ - } -} - - -const char *luaX_token2str (LexState *ls, int token) { - if (token < FIRST_RESERVED) { /* single-byte symbols? */ - lua_assert(token == cast_uchar(token)); - return luaO_pushfstring(ls->L, "'%c'", token); - } - else { - const char *s = luaX_tokens[token - FIRST_RESERVED]; - if (token < TK_EOS) /* fixed format (symbols and reserved words)? */ - return luaO_pushfstring(ls->L, "'%s'", s); - else /* names, strings, and numerals */ - return s; - } -} - - -static const char *txtToken (LexState *ls, int token) { - switch (token) { - case TK_NAME: case TK_STRING: - case TK_FLT: case TK_INT: - save(ls, '\0'); - return luaO_pushfstring(ls->L, "'%s'", luaZ_buffer(ls->buff)); - default: - return luaX_token2str(ls, token); - } -} - - -static l_noret 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 %s", msg, txtToken(ls, token)); - luaD_throw(ls->L, LUA_ERRSYNTAX); -} - - -l_noret luaX_syntaxerror (LexState *ls, const char *msg) { - lexerror(ls, msg, ls->t.token); -} - - -/* -** creates a new string and anchors it in scanner's table so that -** it will not be collected until the end of the compilation -** (by that time it should be anchored somewhere) -*/ -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); /* create new string */ - setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ - o = luaH_set(L, ls->h, L->top - 1); - if (ttisnil(o)) { /* not in use yet? */ - /* 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); - } - else { /* string already present */ - ts = tsvalue(keyfromval(o)); /* re-use value previously stored */ - } - 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)); - 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) - lexerror(ls, "chunk has too many lines", 0); -} - - -void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, - int firstchar) { - ls->t.token = 0; - ls->decpoint = '.'; - ls->L = L; - ls->current = firstchar; - ls->lookahead.token = TK_EOS; /* no look-ahead token */ - ls->z = z; - ls->fs = NULL; - ls->linenumber = 1; - ls->lastline = 1; - ls->source = source; - ls->envn = luaS_new(L, LUA_ENV); /* get env name */ - luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ -} - - - -/* -** ======================================================= -** LEXICAL ANALYZER -** ======================================================= -*/ - - -static int check_next1 (LexState *ls, int c) { - if (ls->current == c) { - next(ls); - return 1; - } - else return 0; -} - - -/* -** Check whether current char is in set 'set' (with two chars) and -** saves it -*/ -static int check_next2 (LexState *ls, const char *set) { - lua_assert(set[2] == '\0'); - if (ls->current == set[0] || ls->current == set[1]) { - save_and_next(ls); - return 1; - } - else return 0; -} - - -/* -** change all characters 'from' in buffer to 'to' -*/ -static void buffreplace (LexState *ls, char from, char to) { - if (from != to) { - size_t n = luaZ_bufflen(ls->buff); - char *p = luaZ_buffer(ls->buff); - while (n--) - if (p[n] == from) p[n] = to; - } -} - - -#if !defined(l_getlocaledecpoint) -#define l_getlocaledecpoint() (localeconv()->decimal_point[0]) -#endif - - -#define buff2num(b,o) (luaO_str2num(luaZ_buffer(b), o) != 0) - -/* -** 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, TValue *o) { - char old = ls->decpoint; - ls->decpoint = l_getlocaledecpoint(); - buffreplace(ls, old, ls->decpoint); /* try new decimal separator */ - if (!buff2num(ls->buff, o)) { - /* format error with correct decimal point: no more options */ - buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */ - lexerror(ls, "malformed number", TK_FLT); - } -} - - -/* LUA_NUMBER */ -/* -** this function is quite liberal in what it accepts, as 'luaO_str2num' -** will reject ill-formed numerals. -*/ -static int read_numeral (LexState *ls, SemInfo *seminfo) { - TValue obj; - const char *expo = "Ee"; - int first = ls->current; - lua_assert(lisdigit(ls->current)); - save_and_next(ls); - if (first == '0' && check_next2(ls, "xX")) /* hexadecimal? */ - expo = "Pp"; - for (;;) { - if (check_next2(ls, expo)) /* exponent part? */ - check_next2(ls, "-+"); /* optional exponent sign */ - if (lisxdigit(ls->current)) - save_and_next(ls); - else if (ls->current == '.') - save_and_next(ls); - else break; - } - save(ls, '\0'); - buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ - if (!buff2num(ls->buff, &obj)) /* format error? */ - trydecpoint(ls, &obj); /* try to update decimal point separator */ - if (ttisinteger(&obj)) { - seminfo->i = ivalue(&obj); - return TK_INT; - } - else { - lua_assert(ttisfloat(&obj)); - seminfo->r = fltvalue(&obj); - return TK_FLT; - } -} - - -/* -** 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; - 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 sep) { - int line = ls->linenumber; /* initial line (for error message) */ - save_and_next(ls); /* skip 2nd '[' */ - if (currIsNewline(ls)) /* string starts with a newline? */ - inclinenumber(ls); /* skip it */ - for (;;) { - switch (ls->current) { - case EOZ: { /* error */ - const char *what = (seminfo ? "string" : "comment"); - const char *msg = luaO_pushfstring(ls->L, - "unfinished long %s (starting at line %d)", what, line); - lexerror(ls, msg, TK_EOS); - break; /* to avoid warnings */ - } - case ']': { - if (skip_sep(ls) == sep) { - save_and_next(ls); /* skip 2nd ']' */ - goto endloop; - } - break; - } - case '\n': case '\r': { - save(ls, '\n'); - inclinenumber(ls); - if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ - break; - } - default: { - if (seminfo) save_and_next(ls); - else next(ls); - } - } - } endloop: - if (seminfo) - seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep), - luaZ_bufflen(ls->buff) - 2*(2 + sep)); -} - - -static void esccheck (LexState *ls, int c, const char *msg) { - if (!c) { - if (ls->current != EOZ) - save_and_next(ls); /* add current to buffer for error message */ - lexerror(ls, msg, TK_STRING); - } -} - - -static int gethexa (LexState *ls) { - save_and_next(ls); - esccheck (ls, lisxdigit(ls->current), "hexadecimal digit expected"); - return luaO_hexavalue(ls->current); -} - - -static int readhexaesc (LexState *ls) { - int r = gethexa(ls); - r = (r << 4) + gethexa(ls); - luaZ_buffremove(ls->buff, 2); /* remove saved chars from buffer */ - return r; -} - - -static unsigned long readutf8esc (LexState *ls) { - unsigned long r; - int i = 4; /* chars to be removed: '\', 'u', '{', and first digit */ - save_and_next(ls); /* skip 'u' */ - esccheck(ls, ls->current == '{', "missing '{'"); - r = gethexa(ls); /* must have at least one digit */ - while ((save_and_next(ls), lisxdigit(ls->current))) { - i++; - r = (r << 4) + luaO_hexavalue(ls->current); - esccheck(ls, r <= 0x10FFFF, "UTF-8 value too large"); - } - esccheck(ls, ls->current == '}', "missing '}'"); - next(ls); /* skip '}' */ - luaZ_buffremove(ls->buff, i); /* remove saved chars from buffer */ - return r; -} - - -static void utf8esc (LexState *ls) { - char buff[UTF8BUFFSZ]; - int n = luaO_utf8esc(buff, readutf8esc(ls)); - for (; n > 0; n--) /* add 'buff' to string */ - save(ls, buff[UTF8BUFFSZ - n]); -} - - -static int readdecesc (LexState *ls) { - int i; - int r = 0; /* result accumulator */ - for (i = 0; i < 3 && lisdigit(ls->current); i++) { /* read up to 3 digits */ - r = 10*r + ls->current - '0'; - save_and_next(ls); - } - esccheck(ls, r <= UCHAR_MAX, "decimal escape too large"); - luaZ_buffremove(ls->buff, i); /* remove read digits from buffer */ - return r; -} - - -static void read_string (LexState *ls, int del, SemInfo *seminfo) { - save_and_next(ls); /* keep delimiter (for error messages) */ - while (ls->current != del) { - switch (ls->current) { - case EOZ: - lexerror(ls, "unfinished string", TK_EOS); - break; /* to avoid warnings */ - case '\n': - case '\r': - lexerror(ls, "unfinished string", TK_STRING); - break; /* to avoid warnings */ - case '\\': { /* escape sequences */ - int c; /* final character to be saved */ - save_and_next(ls); /* keep '\\' for error messages */ - switch (ls->current) { - 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 'u': utf8esc(ls); goto no_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 */ - luaZ_buffremove(ls->buff, 1); /* remove '\\' */ - next(ls); /* skip the 'z' */ - while (lisspace(ls->current)) { - if (currIsNewline(ls)) inclinenumber(ls); - else next(ls); - } - goto no_save; - } - default: { - esccheck(ls, lisdigit(ls->current), "invalid escape sequence"); - c = readdecesc(ls); /* digital escape '\ddd' */ - goto only_save; - } - } - read_save: - next(ls); - /* go through */ - only_save: - luaZ_buffremove(ls->buff, 1); /* remove '\\' */ - save(ls, c); - /* go through */ - no_save: break; - } - default: - save_and_next(ls); - } - } - save_and_next(ls); /* skip delimiter */ - seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, - luaZ_bufflen(ls->buff) - 2); -} - - -static int llex (LexState *ls, SemInfo *seminfo) { - luaZ_resetbuffer(ls->buff); - for (;;) { - switch (ls->current) { - case '\n': case '\r': { /* line breaks */ - inclinenumber(ls); - break; - } - 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 == '[') { /* 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); /* 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); /* skip until end of line (or end of file) */ - break; - } - case '[': { /* long string or simply '[' */ - int sep = skip_sep(ls); - if (sep >= 0) { - read_long_string(ls, seminfo, sep); - return TK_STRING; - } - else if (sep == -1) return '['; - else lexerror(ls, "invalid long string delimiter", TK_STRING); - } - case '=': { - next(ls); - if (check_next1(ls, '=')) return TK_EQ; - else return '='; - } - case '<': { - next(ls); - if (check_next1(ls, '=')) return TK_LE; - else if (check_next1(ls, '<')) return TK_SHL; - else return '<'; - } - case '>': { - next(ls); - if (check_next1(ls, '=')) return TK_GE; - else if (check_next1(ls, '>')) return TK_SHR; - else return '>'; - } - case '/': { - next(ls); - if (check_next1(ls, '/')) return TK_IDIV; - else return '/'; - } - case '~': { - next(ls); - if (check_next1(ls, '=')) return TK_NE; - else return '~'; - } - case ':': { - next(ls); - if (check_next1(ls, ':')) return TK_DBCOLON; - else return ':'; - } - case '"': case '\'': { /* short literal strings */ - read_string(ls, ls->current, seminfo); - return TK_STRING; - } - case '.': { /* '.', '..', '...', or number */ - save_and_next(ls); - if (check_next1(ls, '.')) { - if (check_next1(ls, '.')) - return TK_DOTS; /* '...' */ - else return TK_CONCAT; /* '..' */ - } - else if (!lisdigit(ls->current)) return '.'; - else return read_numeral(ls, seminfo); - } - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': { - return read_numeral(ls, seminfo); - } - case EOZ: { - return TK_EOS; - } - default: { - if (lislalpha(ls->current)) { /* identifier or reserved word? */ - TString *ts; - do { - save_and_next(ls); - } while (lislalnum(ls->current)); - ts = luaX_newstring(ls, luaZ_buffer(ls->buff), - luaZ_bufflen(ls->buff)); - seminfo->ts = ts; - if (isreserved(ts)) /* reserved word? */ - return ts->extra - 1 + FIRST_RESERVED; - else { - return TK_NAME; - } - } - else { /* single-char tokens (+ - / ...) */ - int c = ls->current; - next(ls); - return c; - } - } - } - } -} - - -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 */ -} - - -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 deleted file mode 100644 index afb40b5622..0000000000 --- a/src/llex.h +++ /dev/null @@ -1,86 +0,0 @@ -/* -** $Id: llex.h,v 1.78 2014/10/29 15:38:24 roberto Exp $ -** Lexical Analyzer -** See Copyright Notice in lua.h -*/ - -#ifndef llex_h -#define llex_h - -#include "lobject.h" -#include "lzio.h" - - -#define FIRST_RESERVED 257 - - -#if !defined(LUA_ENV) -#define LUA_ENV "_ENV" -#endif - - -/* -* WARNING: if you change the order of this enumeration, -* grep "ORDER RESERVED" -*/ -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_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_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, - TK_SHL, TK_SHR, - TK_DBCOLON, TK_EOS, - TK_FLT, TK_INT, TK_NAME, TK_STRING -}; - -/* number of reserved words */ -#define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1)) - - -typedef union { - lua_Number r; - lua_Integer i; - TString *ts; -} SemInfo; /* semantics information */ - - -typedef struct Token { - int token; - SemInfo seminfo; -} 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; /* current function (parser) */ - struct lua_State *L; - ZIO *z; /* input stream */ - Mbuffer *buff; /* buffer for tokens */ - Table *h; /* to avoid collection/reuse strings */ - struct Dyndata *dyd; /* dynamic structures used by the parser */ - TString *source; /* current source name */ - TString *envn; /* environment variable name */ - char decpoint; /* locale decimal point */ -} LexState; - - -LUAI_FUNC void luaX_init (lua_State *L); -LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, - 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); -LUAI_FUNC l_noret 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 deleted file mode 100644 index 59f342dcf9..0000000000 --- a/src/llimits.h +++ /dev/null @@ -1,242 +0,0 @@ -/* -** $Id: llimits.h,v 1.124 2014/11/02 19:33:33 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 - - -#include "lua.h" - -/* -** 'lu_mem' and 'l_mem' are unsigned/signed integers big enough to count -** the total memory used by Lua (in bytes). Usually, 'size_t' and -** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines. -*/ -#if defined(LUAI_MEM) /* { external definitions? */ -typedef LUAI_UMEM lu_mem; -typedef LUAI_MEM l_mem; -#elif LUAI_BITSINT >= 32 /* }{ */ -typedef size_t lu_mem; -typedef ptrdiff_t l_mem; -#else /* 16-bit ints */ /* }{ */ -typedef unsigned long lu_mem; -typedef long l_mem; -#endif /* } */ - - -/* chars used as small naturals (so that 'char' is reserved for characters) */ -typedef unsigned char lu_byte; - - -/* maximum value for size_t */ -#define MAX_SIZET ((size_t)(~(size_t)0)) - -/* maximum size visible for Lua (must be representable in a lua_Integer */ -#define MAX_SIZE (sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \ - : (size_t)(LUA_MAXINTEGER)) - - -#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)) - -#define MAX_LMEM ((l_mem)(MAX_LUMEM >> 1)) - - -#define MAX_INT INT_MAX /* maximum value of an int */ - - -/* -** conversion of pointer to integer: -** this is for hashing only; there is no problem if the integer -** cannot hold the whole pointer value -*/ -#define point2int(p) ((unsigned int)((size_t)(p) & UINT_MAX)) - - - -/* type to ensure maximum alignment */ -#if defined(LUAI_USER_ALIGNMENT_T) -typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; -#else -typedef union { double u; void *s; lua_Integer i; long l; } L_Umaxalign; -#endif - - - -/* types of 'usual argument conversions' for lua_Number and lua_Integer */ -typedef LUAI_UACNUMBER l_uacNumber; -typedef LUAI_UACINT l_uacInt; - - -/* 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) ((void)0) -#define check_exp(c,e) (e) -#define lua_longassert(c) ((void)0) -#endif - -/* -** assertion for checking API calls -*/ -#if defined(LUA_USE_APICHECK) -#include -#define luai_apicheck(e) assert(e) -#else -#define luai_apicheck(e) lua_assert(e) -#endif - - -#define api_check(e,msg) luai_apicheck((e) && msg) - - -#if !defined(UNUSED) -#define UNUSED(x) ((void)(x)) /* to avoid warnings */ -#endif - - -#define cast(t, exp) ((t)(exp)) - -#define cast_void(i) cast(void, (i)) -#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)) - - -/* cast a signed lua_Integer to lua_Unsigned */ -#if !defined(l_castS2U) -#define l_castS2U(i) ((lua_Unsigned)(i)) -#endif - -/* -** cast a lua_Unsigned to a signed lua_Integer; this cast is -** not strict ISO C, but two-complement architectures should -** work fine. -*/ -#if !defined(l_castU2S) -#define l_castU2S(i) ((lua_Integer)(i)) -#endif - - -/* -** 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.) -*/ -#if !defined(LUAI_MAXCCALLS) -#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 - - -/* -** type for virtual-machine instructions; -** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) -*/ -#if LUAI_BITSINT >= 32 -typedef unsigned int Instruction; -#else -typedef unsigned long Instruction; -#endif - - - - -/* minimum size for the string table (must be power of 2) */ -#if !defined(MINSTRTABSIZE) -#define MINSTRTABSIZE 64 /* minimum size for "predefined" strings */ -#endif - - -/* minimum size for string buffer */ -#if !defined(LUA_MINBUFFER) -#define LUA_MINBUFFER 32 -#endif - - -#if !defined(lua_lock) -#define lua_lock(L) ((void) 0) -#define lua_unlock(L) ((void) 0) -#endif - -#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,L1) ((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 -*/ -#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 condchangemem(L) \ - ((void)(!(G(L)->gcrunning) || (luaC_fullgc(L, 0), 1))) -#endif - -#endif diff --git a/src/lmathlib.c b/src/lmathlib.c deleted file mode 100644 index 158f2337b1..0000000000 --- a/src/lmathlib.c +++ /dev/null @@ -1,402 +0,0 @@ -/* -** $Id: lmathlib.c,v 1.113 2014/11/07 11:31:58 roberto Exp $ -** Standard mathematical library -** See Copyright Notice in lua.h -*/ - -#define lmathlib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -#undef PI -#define PI (l_mathop(3.141592653589793238462643383279502884)) - - -#if !defined(l_rand) /* { */ -#if defined(LUA_USE_POSIX) -#define l_rand() random() -#define l_srand(x) srandom(x) -#else -#define l_rand() rand() -#define l_srand(x) srand(x) -#endif -#endif /* } */ - - -static int math_abs (lua_State *L) { - if (lua_isinteger(L, 1)) { - lua_Integer n = lua_tointeger(L, 1); - if (n < 0) n = (lua_Integer)(0u - n); - lua_pushinteger(L, n); - } - else - lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1))); - return 1; -} - -static int math_sin (lua_State *L) { - lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1))); - return 1; -} - -static int math_cos (lua_State *L) { - lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1))); - return 1; -} - -static int math_tan (lua_State *L) { - lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1))); - return 1; -} - -static int math_asin (lua_State *L) { - lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1))); - return 1; -} - -static int math_acos (lua_State *L) { - lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1))); - return 1; -} - -static int math_atan (lua_State *L) { - lua_Number y = luaL_checknumber(L, 1); - lua_Number x = luaL_optnumber(L, 2, 1); - lua_pushnumber(L, l_mathop(atan2)(y, x)); - return 1; -} - - -static int math_toint (lua_State *L) { - int valid; - lua_Integer n = lua_tointegerx(L, 1, &valid); - if (valid) - lua_pushinteger(L, n); - else { - luaL_checkany(L, 1); - lua_pushnil(L); /* value is not convertible to integer */ - } - return 1; -} - - -static void pushnumint (lua_State *L, lua_Number d) { - lua_Integer n; - if (lua_numbertointeger(d, &n)) /* does 'd' fit in an integer? */ - lua_pushinteger(L, n); /* result is integer */ - else - lua_pushnumber(L, d); /* result is float */ -} - - -static int math_floor (lua_State *L) { - if (lua_isinteger(L, 1)) - lua_settop(L, 1); /* integer is its own floor */ - else { - lua_Number d = l_mathop(floor)(luaL_checknumber(L, 1)); - pushnumint(L, d); - } - return 1; -} - - -static int math_ceil (lua_State *L) { - if (lua_isinteger(L, 1)) - lua_settop(L, 1); /* integer is its own ceil */ - else { - lua_Number d = l_mathop(ceil)(luaL_checknumber(L, 1)); - pushnumint(L, d); - } - return 1; -} - - -static int math_fmod (lua_State *L) { - if (lua_isinteger(L, 1) && lua_isinteger(L, 2)) { - lua_Integer d = lua_tointeger(L, 2); - if ((lua_Unsigned)d + 1u <= 1u) { /* special cases: -1 or 0 */ - luaL_argcheck(L, d != 0, 2, "zero"); - lua_pushinteger(L, 0); /* avoid overflow with 0x80000... / -1 */ - } - else - lua_pushinteger(L, lua_tointeger(L, 1) % d); - } - else - lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1), - luaL_checknumber(L, 2))); - return 1; -} - - -/* -** next function does not use 'modf', avoiding problems with 'double*' -** (which is not compatible with 'float*') when lua_Number is not -** 'double'. -*/ -static int math_modf (lua_State *L) { - if (lua_isinteger(L ,1)) { - lua_settop(L, 1); /* number is its own integer part */ - lua_pushnumber(L, 0); /* no fractional part */ - } - else { - lua_Number n = luaL_checknumber(L, 1); - /* integer part (rounds toward zero) */ - lua_Number ip = (n < 0) ? l_mathop(ceil)(n) : l_mathop(floor)(n); - pushnumint(L, ip); - /* fractional part (test needed for inf/-inf) */ - lua_pushnumber(L, (n == ip) ? l_mathop(0.0) : (n - ip)); - } - return 2; -} - - -static int math_sqrt (lua_State *L) { - lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1))); - return 1; -} - - -static int math_ult (lua_State *L) { - lua_Integer a = luaL_checkinteger(L, 1); - lua_Integer b = luaL_checkinteger(L, 2); - lua_pushboolean(L, (lua_Unsigned)a < (lua_Unsigned)b); - return 1; -} - -static int math_log (lua_State *L) { - lua_Number x = luaL_checknumber(L, 1); - lua_Number res; - if (lua_isnoneornil(L, 2)) - res = l_mathop(log)(x); - else { - lua_Number base = luaL_checknumber(L, 2); - if (base == 10.0) res = l_mathop(log10)(x); - else res = l_mathop(log)(x)/l_mathop(log)(base); - } - lua_pushnumber(L, res); - return 1; -} - -static int math_exp (lua_State *L) { - lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1))); - return 1; -} - -static int math_deg (lua_State *L) { - lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI)); - return 1; -} - -static int math_rad (lua_State *L) { - lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0))); - return 1; -} - - -static int math_min (lua_State *L) { - int n = lua_gettop(L); /* number of arguments */ - int imin = 1; /* index of current minimum value */ - int i; - luaL_argcheck(L, n >= 1, 1, "value expected"); - for (i = 2; i <= n; i++) { - if (lua_compare(L, i, imin, LUA_OPLT)) - imin = i; - } - lua_pushvalue(L, imin); - return 1; -} - - -static int math_max (lua_State *L) { - int n = lua_gettop(L); /* number of arguments */ - int imax = 1; /* index of current maximum value */ - int i; - luaL_argcheck(L, n >= 1, 1, "value expected"); - for (i = 2; i <= n; i++) { - if (lua_compare(L, imax, i, LUA_OPLT)) - imax = i; - } - lua_pushvalue(L, imax); - return 1; -} - -/* -** This function uses 'double' (instead of 'lua_Number') to ensure that -** all bits from 'l_rand' can be represented, and that 'RAND_MAX + 1.0' -** will keep full precision (ensuring that 'r' is always less than 1.0.) -*/ -static int math_random (lua_State *L) { - lua_Integer low, up; - double r = (double)l_rand() * (1.0 / ((double)RAND_MAX + 1.0)); - switch (lua_gettop(L)) { /* check number of arguments */ - case 0: { /* no arguments */ - lua_pushnumber(L, (lua_Number)r); /* Number between 0 and 1 */ - return 1; - } - case 1: { /* only upper limit */ - low = 1; - up = luaL_checkinteger(L, 1); - break; - } - case 2: { /* lower and upper limits */ - low = luaL_checkinteger(L, 1); - up = luaL_checkinteger(L, 2); - break; - } - default: return luaL_error(L, "wrong number of arguments"); - } - /* random integer in the interval [low, up] */ - luaL_argcheck(L, low <= up, 1, "interval is empty"); - luaL_argcheck(L, low >= 0 || up <= LUA_MAXINTEGER + low, 1, - "interval too large"); - r *= (double)(up - low) + 1.0; - lua_pushinteger(L, (lua_Integer)r + low); - return 1; -} - - -static int math_randomseed (lua_State *L) { - l_srand((unsigned int)(lua_Integer)luaL_checknumber(L, 1)); - (void)rand(); /* discard first value to avoid undesirable correlations */ - return 0; -} - - -static int math_type (lua_State *L) { - if (lua_type(L, 1) == LUA_TNUMBER) { - if (lua_isinteger(L, 1)) - lua_pushliteral(L, "integer"); - else - lua_pushliteral(L, "float"); - } - else { - luaL_checkany(L, 1); - lua_pushnil(L); - } - return 1; -} - - -/* -** {================================================================== -** Deprecated functions (for compatibility only) -** =================================================================== -*/ -#if defined(LUA_COMPAT_MATHLIB) - -static int math_cosh (lua_State *L) { - lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1))); - return 1; -} - -static int math_sinh (lua_State *L) { - lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1))); - return 1; -} - -static int math_tanh (lua_State *L) { - lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1))); - return 1; -} - -static int math_pow (lua_State *L) { - lua_Number x = luaL_checknumber(L, 1); - lua_Number y = luaL_checknumber(L, 2); - lua_pushnumber(L, l_mathop(pow)(x, y)); - return 1; -} - -static int math_frexp (lua_State *L) { - int 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_Number x = luaL_checknumber(L, 1); - int ep = (int)luaL_checkinteger(L, 2); - lua_pushnumber(L, l_mathop(ldexp)(x, ep)); - return 1; -} - -static int math_log10 (lua_State *L) { - lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1))); - return 1; -} - -#endif -/* }================================================================== */ - - - -static const luaL_Reg mathlib[] = { - {"abs", math_abs}, - {"acos", math_acos}, - {"asin", math_asin}, - {"atan", math_atan}, - {"ceil", math_ceil}, - {"cos", math_cos}, - {"deg", math_deg}, - {"exp", math_exp}, - {"tointeger", math_toint}, - {"floor", math_floor}, - {"fmod", math_fmod}, - {"ult", math_ult}, - {"log", math_log}, - {"max", math_max}, - {"min", math_min}, - {"modf", math_modf}, - {"rad", math_rad}, - {"random", math_random}, - {"randomseed", math_randomseed}, - {"sin", math_sin}, - {"sqrt", math_sqrt}, - {"tan", math_tan}, - {"type", math_type}, -#if defined(LUA_COMPAT_MATHLIB) - {"atan2", math_atan}, - {"cosh", math_cosh}, - {"sinh", math_sinh}, - {"tanh", math_tanh}, - {"pow", math_pow}, - {"frexp", math_frexp}, - {"ldexp", math_ldexp}, - {"log10", math_log10}, -#endif - /* placeholders */ - {"pi", NULL}, - {"huge", NULL}, - {"maxinteger", NULL}, - {"mininteger", NULL}, - {NULL, NULL} -}; - - -/* -** Open math library -*/ -LUAMOD_API int luaopen_math (lua_State *L) { - luaL_newlib(L, mathlib); - lua_pushnumber(L, PI); - lua_setfield(L, -2, "pi"); - lua_pushnumber(L, (lua_Number)HUGE_VAL); - lua_setfield(L, -2, "huge"); - lua_pushinteger(L, LUA_MAXINTEGER); - lua_setfield(L, -2, "maxinteger"); - lua_pushinteger(L, LUA_MININTEGER); - lua_setfield(L, -2, "mininteger"); - return 1; -} - diff --git a/src/lmem.c b/src/lmem.c deleted file mode 100644 index 4feaf036c7..0000000000 --- a/src/lmem.c +++ /dev/null @@ -1,99 +0,0 @@ -/* -** $Id: lmem.c,v 1.89 2014/11/02 19:33:33 roberto Exp $ -** Interface to Memory Manager -** See Copyright Notice in lua.h -*/ - -#define lmem_c -#define LUA_CORE - -#include "lprefix.h" - - -#include - -#include "lua.h" - -#include "ldebug.h" -#include "ldo.h" -#include "lgc.h" -#include "lmem.h" -#include "lobject.h" -#include "lstate.h" - - - -/* -** About the realloc function: -** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); -** ('osize' is the old size, 'nsize' is the new size) -** -** * 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); -** particularly, frealloc(ud, NULL, 0, 0) does nothing -** (which is equivalent to free(NULL) in ISO C) -** -** frealloc returns NULL if it cannot create or reallocate the area -** (any reallocation to an equal or smaller size cannot fail!) -*/ - - - -#define MINSIZEARRAY 4 - - -void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems, - 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, "too many %s (limit is %d)", what, limit); - newsize = limit; /* still have at least one free place */ - } - else { - newsize = (*size)*2; - if (newsize < MINSIZEARRAY) - newsize = MINSIZEARRAY; /* minimum size */ - } - newblock = luaM_reallocv(L, block, *size, newsize, size_elems); - *size = newsize; /* update only when everything else is OK */ - return newblock; -} - - -l_noret luaM_toobig (lua_State *L) { - luaG_runerror(L, "memory allocation error: block too big"); -} - - - -/* -** generic allocation routine. -*/ -void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { - void *newblock; - global_State *g = G(L); - size_t realosize = (block) ? osize : 0; - lua_assert((realosize == 0) == (block == NULL)); -#if defined(HARDMEMTESTS) - 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( nsize > realosize, - "realloc cannot fail when shrinking a block"); - 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->GCdebt = (g->GCdebt + nsize) - realosize; - return newblock; -} - diff --git a/src/lmem.h b/src/lmem.h deleted file mode 100644 index f701ae0f87..0000000000 --- a/src/lmem.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -** $Id: lmem.h,v 1.41 2014/10/08 20:25:51 roberto Exp $ -** Interface to Memory Manager -** See Copyright Notice in lua.h -*/ - -#ifndef lmem_h -#define lmem_h - - -#include - -#include "llimits.h" -#include "lua.h" - - -/* -** This macro reallocs a vector 'b' from 'on' to 'n' elements, where -** each element has size 'e'. In case of arithmetic overflow of the -** product 'n'*'e', it raises an error (calling 'luaM_toobig'). Because -** 'e' is always constant, it avoids the runtime division MAX_SIZET/(e). -** -** (The macro is somewhat complex to avoid warnings: The 'sizeof' -** comparison avoids a runtime comparison when overflow cannot occur. -** The compiler should be able to optimize the real test by itself, but -** when it does it, it may give a warning about "comparison is always -** false due to limited range of data type"; the +1 tricks the compiler, -** avoiding this warning but also this optimization.) -*/ -#define luaM_reallocv(L,b,on,n,e) \ - (((sizeof(n) >= sizeof(size_t) && cast(size_t, (n)) + 1 > MAX_SIZET/(e)) \ - ? luaM_toobig(L) : cast_void(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) -#define luaM_freearray(L, b, n) luaM_realloc_(L, (b), (n)*sizeof(*(b)), 0) - -#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))) - -#define luaM_reallocvector(L, v,oldn,n,t) \ - ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t)))) - -LUAI_FUNC l_noret 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_growaux_ (lua_State *L, void *block, int *size, - size_t size_elem, int limit, - const char *what); - -#endif - diff --git a/src/loadlib.c b/src/loadlib.c deleted file mode 100644 index 1dab9bd0f1..0000000000 --- a/src/loadlib.c +++ /dev/null @@ -1,774 +0,0 @@ -/* -** $Id: loadlib.c,v 1.123 2014/11/12 13:31:51 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 Windows, and a stub for other -** systems. -*/ - -#define loadlib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#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 - -#define LUA_PATHSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR - -#define LUA_PATHVARVERSION LUA_PATH_VAR LUA_PATHSUFFIX -#define LUA_CPATHVARVERSION LUA_CPATH_VAR LUA_PATHSUFFIX - -/* -** 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 - - -/* -** 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_" - -/* separator for open functions in C libraries */ -#define LUA_OFSEP "_" - - -/* -** unique key for table in the registry that keeps handles -** for all loaded C libraries -*/ -static const int CLIBS = 0; - -#define LIB_FAIL "open" - -#define setprogdir(L) ((void)0) - - -/* -** system-dependent functions -*/ - -/* -** unload library 'lib' -*/ -static void lsys_unloadlib (void *lib); - -/* -** load C library in file 'path'. If 'seeglb', load with all names in -** the library global. -** Returns the library; in case of error, returns NULL plus an -** error string in the stack. -*/ -static void *lsys_load (lua_State *L, const char *path, int seeglb); - -/* -** Try to find a function named 'sym' in library 'lib'. -** Returns the function; in case of error, returns NULL plus an -** error string in the stack. -*/ -static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym); - - - - -#if defined(LUA_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 lsys_unloadlib (void *lib) { - dlclose(lib); -} - - -static void *lsys_load (lua_State *L, const char *path, int seeglb) { - void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL)); - if (lib == NULL) lua_pushstring(L, dlerror()); - return lib; -} - - -static lua_CFunction lsys_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(LUA_DL_DLL) /* }{ */ -/* -** {====================================================================== -** This is an implementation of loadlib for Windows using native functions. -** ======================================================================= -*/ - -#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; - DWORD nsize = sizeof(buff)/sizeof(char); - DWORD n = GetModuleFileNameA(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_EXEC_DIR, buff); - lua_remove(L, -2); /* remove original string */ - } -} - - -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)/sizeof(char), NULL)) - lua_pushstring(L, buffer); - else - lua_pushfstring(L, "system error %d\n", error); -} - -static void lsys_unloadlib (void *lib) { - FreeLibrary((HMODULE)lib); -} - - -static void *lsys_load (lua_State *L, const char *path, int seeglb) { - HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS); - (void)(seeglb); /* not used: symbols are 'global' by default */ - if (lib == NULL) pusherror(L); - return lib; -} - - -static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { - lua_CFunction f = (lua_CFunction)GetProcAddress((HMODULE)lib, sym); - if (f == NULL) pusherror(L); - return f; -} - -/* }====================================================== */ - - -#else /* }{ */ -/* -** {====================================================== -** Fallback for other systems -** ======================================================= -*/ - -#undef LIB_FAIL -#define LIB_FAIL "absent" - - -#define DLMSG "dynamic libraries not enabled; check your Lua installation" - - -static void lsys_unloadlib (void *lib) { - (void)(lib); /* not used */ -} - - -static void *lsys_load (lua_State *L, const char *path, int seeglb) { - (void)(path); (void)(seeglb); /* not used */ - lua_pushliteral(L, DLMSG); - return NULL; -} - - -static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { - (void)(lib); (void)(sym); /* not used */ - lua_pushliteral(L, DLMSG); - return NULL; -} - -/* }====================================================== */ -#endif /* } */ - - -/* -** return registry.CLIBS[path] -*/ -static void *checkclib (lua_State *L, const char *path) { - void *plib; - lua_rawgetp(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; -} - - -/* -** registry.CLIBS[path] = plib -- for queries -** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries -*/ -static void addtoclib (lua_State *L, const char *path, void *plib) { - lua_rawgetp(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 for CLIBS table: calls 'lsys_unloadlib' for all lib -** handles in list CLIBS -*/ -static int gctm (lua_State *L) { - lua_Integer n = luaL_len(L, 1); - for (; n >= 1; n--) { /* for each handle, in reverse order */ - lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ - lsys_unloadlib(lua_touserdata(L, -1)); - lua_pop(L, 1); /* pop handle */ - } - return 0; -} - - - -/* error codes for 'lookforfunc' */ -#define ERRLIB 1 -#define ERRFUNC 2 - -/* -** Look for a C function named 'sym' in a dynamically loaded library -** 'path'. -** First, check whether the library is already loaded; if not, try -** to load it. -** Then, if 'sym' is '*', return true (as library has been loaded). -** Otherwise, look for symbol 'sym' in the library and push a -** C function with that symbol. -** Return 0 and 'true' or a function in the stack; in case of -** errors, return an error code and an error message in the stack. -*/ -static int lookforfunc (lua_State *L, const char *path, const char *sym) { - void *reg = checkclib(L, path); /* check loaded C libraries */ - if (reg == NULL) { /* must load library? */ - reg = lsys_load(L, path, *sym == '*'); /* global symbols if 'sym'=='*' */ - if (reg == NULL) return ERRLIB; /* unable to load library */ - 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 = lsys_sym(L, reg, sym); - if (f == NULL) - return ERRFUNC; /* unable to find function */ - lua_pushcfunction(L, f); /* else create new function */ - return 0; /* no errors */ - } -} - - -static int ll_loadlib (lua_State *L) { - const char *path = luaL_checkstring(L, 1); - const char *init = luaL_checkstring(L, 2); - int stat = lookforfunc(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' function -** ======================================================= -*/ - - -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_PATH_SEP) path++; /* skip separators */ - if (*path == '\0') return NULL; /* no more templates */ - 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 *searchpath (lua_State *L, const char *name, - const char *path, - 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, 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); - lua_remove(L, -2); /* remove path template */ - if (readable(filename)) /* does file exist and is readable? */ - return filename; /* return that file name */ - lua_pushfstring(L, "\n\tno file '%s'", filename); - lua_remove(L, -2); /* remove file name */ - luaL_addvalue(&msg); /* concatenate error msg. entry */ - } - luaL_pushresult(&msg); /* create error message */ - return NULL; /* not found */ -} - - -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, 4, LUA_DIRSEP)); - 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 *dirsep) { - const char *path; - lua_getfield(L, lua_upvalueindex(1), pname); - path = lua_tostring(L, -1); - if (path == NULL) - luaL_error(L, "'package.%s' must be a string", pname); - return searchpath(L, name, path, ".", dirsep); -} - - -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 '%s' from file '%s':\n\t%s", - lua_tostring(L, 1), filename, lua_tostring(L, -1)); -} - - -static int searcher_Lua (lua_State *L) { - const char *filename; - const char *name = luaL_checkstring(L, 1); - 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); -} - - -/* -** Try to find a load function for module 'modname' at file 'filename'. -** First, change '.' to '_' in 'modname'; then, if 'modname' has -** the form X-Y (that is, it has an "ignore mark"), build a function -** name "luaopen_X" and look for it. (For compatibility, if that -** fails, it also tries "luaopen_Y".) If there is no ignore mark, -** look for a function named "luaopen_modname". -*/ -static int loadfunc (lua_State *L, const char *filename, const char *modname) { - const char *openfunc; - const char *mark; - modname = luaL_gsub(L, modname, ".", LUA_OFSEP); - mark = strchr(modname, *LUA_IGMARK); - if (mark) { - int stat; - openfunc = lua_pushlstring(L, modname, mark - modname); - openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc); - stat = lookforfunc(L, filename, openfunc); - if (stat != ERRFUNC) return stat; - modname = mark + 1; /* else go ahead and try old-style name */ - } - openfunc = lua_pushfstring(L, LUA_POF"%s", modname); - return lookforfunc(L, filename, openfunc); -} - - -static int searcher_C (lua_State *L) { - const char *name = luaL_checkstring(L, 1); - 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); -} - - -static int searcher_Croot (lua_State *L) { - 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", LUA_CSUBSEP); - if (filename == NULL) return 1; /* root not found */ - if ((stat = loadfunc(L, filename, name)) != 0) { - if (stat != ERRFUNC) - return checkload(L, 0, filename); /* real error */ - else { /* open function not found */ - lua_pushfstring(L, "\n\tno module '%s' in file '%s'", name, filename); - return 1; - } - } - lua_pushstring(L, filename); /* will be 2nd argument to module */ - return 2; -} - - -static int searcher_preload (lua_State *L) { - const char *name = luaL_checkstring(L, 1); - lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD"); - if (lua_getfield(L, -1, name) == LUA_TNIL) /* not found? */ - lua_pushfstring(L, "\n\tno field package.preload['%s']", name); - return 1; -} - - -static void findloader (lua_State *L, const char *name) { - int i; - luaL_Buffer msg; /* to build error message */ - luaL_buffinit(L, &msg); - /* push 'package.searchers' to index 3 in the stack */ - if (lua_getfield(L, lua_upvalueindex(1), "searchers") != LUA_TTABLE) - luaL_error(L, "'package.searchers' must be a table"); - /* iterate over available searchers to find a loader */ - for (i = 1; ; i++) { - if (lua_rawgeti(L, 3, i) == LUA_TNIL) { /* no more searchers? */ - lua_pop(L, 1); /* remove nil */ - luaL_pushresult(&msg); /* create error message */ - luaL_error(L, "module '%s' not found:%s", 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? */ - return; /* module loader found */ - else if (lua_isstring(L, -2)) { /* searcher returned error message? */ - lua_pop(L, 1); /* remove extra return */ - 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 */ - if (!lua_isnil(L, -1)) /* non-nil return? */ - lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ - if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no 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 -** ======================================================= -*/ -#if defined(LUA_COMPAT_MODULE) - -/* -** changes the environment 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, "'module' not called from a Lua function"); - lua_pushvalue(L, -2); /* copy new environment table to top */ - lua_setupvalue(L, -2, 1); - lua_pop(L, 1); /* remove function */ -} - - -static void dooptions (lua_State *L, int n) { - int i; - for (i = 2; i <= n; i++) { - 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); - } - } -} - - -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); - int lastarg = lua_gettop(L); /* last parameter */ - luaL_pushmodule(L, modname, 1); /* get/create module table */ - /* check whether table already has a _NAME field */ - if (lua_getfield(L, -1, "_NAME") != LUA_TNIL) - lua_pop(L, 1); /* table is an initialized module */ - else { /* no; initialize it */ - lua_pop(L, 1); - modinit(L, modname); - } - lua_pushvalue(L, -1); - set_env(L); - dooptions(L, lastarg); - return 1; -} - - -static int ll_seeall (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - if (!lua_getmetatable(L, 1)) { - lua_createtable(L, 0, 1); /* create new metatable */ - lua_pushvalue(L, -1); - lua_setmetatable(L, 1); - } - lua_pushglobaltable(L); - lua_setfield(L, -2, "__index"); /* mt.__index = _G */ - return 0; -} - -#endif -/* }====================================================== */ - - - -/* auxiliary mark (for internal use) */ -#define AUXMARK "\1" - - -/* -** return registry.LUA_NOENV as a boolean -*/ -static int noenv (lua_State *L) { - int b; - lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); - b = lua_toboolean(L, -1); - lua_pop(L, 1); /* remove value */ - return b; -} - - -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 || noenv(L)) /* 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_PATH_SEP LUA_PATH_SEP, - LUA_PATH_SEP AUXMARK LUA_PATH_SEP); - 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}, - {"searchpath", ll_searchpath}, -#if defined(LUA_COMPAT_MODULE) - {"seeall", ll_seeall}, -#endif - /* placeholders */ - {"preload", NULL}, - {"cpath", NULL}, - {"path", NULL}, - {"searchers", NULL}, - {"loaded", NULL}, - {NULL, NULL} -}; - - -static const luaL_Reg ll_funcs[] = { -#if defined(LUA_COMPAT_MODULE) - {"module", ll_module}, -#endif - {"require", ll_require}, - {NULL, NULL} -}; - - -static void createsearcherstable (lua_State *L) { - static const lua_CFunction searchers[] = - {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL}; - int i; - /* create 'searchers' table */ - lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); - /* fill it with pre-defined searchers */ - for (i=0; searchers[i] != NULL; i++) { - lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */ - lua_pushcclosure(L, searchers[i], 1); - lua_rawseti(L, -2, i+1); - } -#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' */ -#endif - lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */ -} - - -/* -** create table CLIBS to keep track of loaded C libraries, -** setting a finalizer to close all libraries when closing state. -*/ -static void createclibstable (lua_State *L) { - lua_newtable(L); /* create CLIBS table */ - lua_createtable(L, 0, 1); /* create metatable for CLIBS */ - lua_pushcfunction(L, gctm); - lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */ - lua_setmetatable(L, -2); - lua_rawsetp(L, LUA_REGISTRYINDEX, &CLIBS); /* set CLIBS table in registry */ -} - - -LUAMOD_API int luaopen_package (lua_State *L) { - createclibstable(L); - luaL_newlib(L, pk_funcs); /* create 'package' table */ - createsearcherstable(L); - /* set field 'path' */ - setpath(L, "path", LUA_PATHVARVERSION, LUA_PATH_VAR, LUA_PATH_DEFAULT); - /* set field 'cpath' */ - setpath(L, "cpath", LUA_CPATHVARVERSION, LUA_CPATH_VAR, 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_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); - lua_setfield(L, -2, "loaded"); - /* set field '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 */ - 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.c b/src/lobject.c deleted file mode 100644 index ceb4b98396..0000000000 --- a/src/lobject.c +++ /dev/null @@ -1,470 +0,0 @@ -/* -** $Id: lobject.c,v 2.100 2014/11/21 12:15:57 roberto Exp $ -** Some generic functions over Lua objects -** See Copyright Notice in lua.h -*/ - -#define lobject_c -#define LUA_CORE - -#include "lprefix.h" - - -#include -#include -#include -#include - -#include "lua.h" - -#include "lctype.h" -#include "ldebug.h" -#include "ldo.h" -#include "lmem.h" -#include "lobject.h" -#include "lstate.h" -#include "lstring.h" -#include "lvm.h" - - - -LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT}; - - -/* -** converts an integer to a "floating point byte", represented as -** (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; /* exponent */ - if (x < 8) return x; - while (x >= 0x10) { - x = (x+1) >> 1; - e++; - } - return ((e+1) << 3) | (cast_int(x) - 8); -} - - -/* converts back */ -int luaO_fb2int (int x) { - int e = (x >> 3) & 0x1f; - if (e == 0) return x; - else return ((x & 7) + 8) << (e - 1); -} - - -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, - 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 - }; - int l = 0; - x--; - while (x >= 256) { l += 8; x >>= 8; } - return l + log_2[x]; -} - - -static lua_Integer intarith (lua_State *L, int op, lua_Integer v1, - lua_Integer v2) { - switch (op) { - case LUA_OPADD: return intop(+, v1, v2); - case LUA_OPSUB:return intop(-, v1, v2); - case LUA_OPMUL:return intop(*, v1, v2); - case LUA_OPMOD: return luaV_mod(L, v1, v2); - case LUA_OPIDIV: return luaV_div(L, v1, v2); - case LUA_OPBAND: return intop(&, v1, v2); - case LUA_OPBOR: return intop(|, v1, v2); - case LUA_OPBXOR: return intop(^, v1, v2); - case LUA_OPSHL: return luaV_shiftl(v1, v2); - case LUA_OPSHR: return luaV_shiftl(v1, -v2); - case LUA_OPUNM: return intop(-, 0, v1); - case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1); - default: lua_assert(0); return 0; - } -} - - -static lua_Number numarith (lua_State *L, int op, lua_Number v1, - lua_Number v2) { - switch (op) { - case LUA_OPADD: return luai_numadd(L, v1, v2); - case LUA_OPSUB: return luai_numsub(L, v1, v2); - case LUA_OPMUL: return luai_nummul(L, v1, v2); - case LUA_OPDIV: return luai_numdiv(L, v1, v2); - case LUA_OPPOW: return luai_numpow(L, v1, v2); - case LUA_OPIDIV: return luai_numidiv(L, v1, v2); - case LUA_OPUNM: return luai_numunm(L, v1); - case LUA_OPMOD: { - lua_Number m; - luai_nummod(L, v1, v2, m); - return m; - } - default: lua_assert(0); return 0; - } -} - - -void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2, - TValue *res) { - switch (op) { - case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: - case LUA_OPSHL: case LUA_OPSHR: - case LUA_OPBNOT: { /* operate only on integers */ - lua_Integer i1; lua_Integer i2; - if (tointeger(p1, &i1) && tointeger(p2, &i2)) { - setivalue(res, intarith(L, op, i1, i2)); - return; - } - else break; /* go to the end */ - } - case LUA_OPDIV: case LUA_OPPOW: { /* operate only on floats */ - lua_Number n1; lua_Number n2; - if (tonumber(p1, &n1) && tonumber(p2, &n2)) { - setfltvalue(res, numarith(L, op, n1, n2)); - return; - } - else break; /* go to the end */ - } - default: { /* other operations */ - lua_Number n1; lua_Number n2; - if (ttisinteger(p1) && ttisinteger(p2)) { - setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2))); - return; - } - else if (tonumber(p1, &n1) && tonumber(p2, &n2)) { - setfltvalue(res, numarith(L, op, n1, n2)); - return; - } - else break; /* go to the end */ - } - } - /* could not perform raw operation; try metamethod */ - lua_assert(L != NULL); /* should not fail when folding (compile time) */ - luaT_trybinTM(L, p1, p2, res, cast(TMS, op - LUA_OPADD + TM_ADD)); -} - - -int luaO_hexavalue (int c) { - if (lisdigit(c)) return c - '0'; - else return ltolower(c) - 'a' + 10; -} - - -static int isneg (const char **s) { - if (**s == '-') { (*s)++; return 1; } - else if (**s == '+') (*s)++; - return 0; -} - - - -/* -** {================================================================== -** Lua's implementation for 'lua_strx2number' -** =================================================================== -*/ -#if !defined(lua_strx2number) - -#include - -/* maximum number of significant digits to read (to avoid overflows - even with single floats) */ -#define MAXSIGDIG 30 - -/* -** 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; /* result (accumulator) */ - int sigdig = 0; /* number of significant digits */ - int nosigdig = 0; /* number of non-significant digits */ - int e = 0; /* exponent correction */ - int neg = 0; /* 1 if number is negative */ - int dot = 0; /* true after seen a dot */ - *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') */ - for (s += 2; ; s++) { /* skip '0x' and read numeral */ - if (*s == '.') { - if (dot) break; /* second dot? stop loop */ - else dot = 1; - } - else if (lisxdigit(cast_uchar(*s))) { - if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */ - nosigdig++; - else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */ - r = (r * cast_num(16.0)) + luaO_hexavalue(*s); - else e++; /* too many digits; ignore, but still count for exponent */ - if (dot) e--; /* decimal digit? correct exponent */ - } - else break; /* neither a dot nor a digit */ - } - if (nosigdig + sigdig == 0) /* no digits? */ - return 0.0; /* invalid format */ - *endptr = cast(char *, s); /* valid up to here */ - e *= 4; /* each digit multiplies/divides value by 2^4 */ - if (*s == 'p' || *s == 'P') { /* exponent part? */ - int exp1 = 0; /* exponent value */ - int neg1; /* exponent signal */ - s++; /* skip 'p' */ - neg1 = isneg(&s); /* signal */ - if (!lisdigit(cast_uchar(*s))) - return 0.0; /* invalid; 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 */ - } - if (neg) r = -r; - return l_mathop(ldexp)(r, e); -} - -#endif -/* }====================================================== */ - - -static const char *l_str2d (const char *s, lua_Number *result) { - char *endptr; - if (strpbrk(s, "nN")) /* reject 'inf' and 'nan' */ - return NULL; - else if (strpbrk(s, "xX")) /* hex? */ - *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 == '\0' ? endptr : NULL); /* OK if no trailing characters */ -} - - -static const char *l_str2int (const char *s, lua_Integer *result) { - lua_Unsigned a = 0; - int empty = 1; - int neg; - while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ - neg = isneg(&s); - if (s[0] == '0' && - (s[1] == 'x' || s[1] == 'X')) { /* hex? */ - s += 2; /* skip '0x' */ - for (; lisxdigit(cast_uchar(*s)); s++) { - a = a * 16 + luaO_hexavalue(*s); - empty = 0; - } - } - else { /* decimal */ - for (; lisdigit(cast_uchar(*s)); s++) { - a = a * 10 + *s - '0'; - empty = 0; - } - } - while (lisspace(cast_uchar(*s))) s++; /* skip trailing spaces */ - if (empty || *s != '\0') return NULL; /* something wrong in the numeral */ - else { - *result = l_castU2S((neg) ? 0u - a : a); - return s; - } -} - - -size_t luaO_str2num (const char *s, TValue *o) { - lua_Integer i; lua_Number n; - const char *e; - if ((e = l_str2int(s, &i)) != NULL) { /* try as an integer */ - setivalue(o, i); - } - else if ((e = l_str2d(s, &n)) != NULL) { /* else try as a float */ - setfltvalue(o, n); - } - else - return 0; /* conversion failed */ - return (e - s + 1); /* success; return string size */ -} - - -int luaO_utf8esc (char *buff, unsigned long x) { - int n = 1; /* number of bytes put in buffer (backwards) */ - lua_assert(x <= 0x10FFFF); - if (x < 0x80) /* ascii? */ - buff[UTF8BUFFSZ - 1] = cast(char, x); - else { /* need continuation bytes */ - unsigned int mfb = 0x3f; /* maximum that fits in first byte */ - do { /* add continuation bytes */ - buff[UTF8BUFFSZ - (n++)] = cast(char, 0x80 | (x & 0x3f)); - x >>= 6; /* remove added bits */ - mfb >>= 1; /* now there is one less bit available in first byte */ - } while (x > mfb); /* still needs continuation byte? */ - buff[UTF8BUFFSZ - n] = cast(char, (~mfb << 1) | x); /* add first byte */ - } - return n; -} - - -/* maximum length of the conversion of a number to a string */ -#define MAXNUMBER2STR 50 - - -/* -** Convert a number object to a string -*/ -void luaO_tostring (lua_State *L, StkId obj) { - char buff[MAXNUMBER2STR]; - size_t len; - lua_assert(ttisnumber(obj)); - if (ttisinteger(obj)) - len = lua_integer2str(buff, ivalue(obj)); - else { - len = lua_number2str(buff, fltvalue(obj)); -#if !defined(LUA_COMPAT_FLOATSTRING) - if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */ - buff[len++] = '.'; - buff[len++] = '0'; /* adds '.0' to result */ - } -#endif - } - setsvalue2s(L, obj, luaS_newlstr(L, buff, len)); -} - - -static void pushstr (lua_State *L, const char *str, size_t l) { - setsvalue2s(L, L->top++, luaS_newlstr(L, str, l)); -} - - -/* this function handles only '%d', '%c', '%f', '%p', and '%s' - conventional formats, plus Lua-specific '%I' and '%U' */ -const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { - int n = 0; - for (;;) { - const char *e = strchr(fmt, '%'); - if (e == NULL) break; - luaD_checkstack(L, 2); /* fmt + item */ - pushstr(L, fmt, e - fmt); - switch (*(e+1)) { - case 's': { - const char *s = va_arg(argp, char *); - if (s == NULL) s = "(null)"; - pushstr(L, s, strlen(s)); - break; - } - case 'c': { - char buff = cast(char, va_arg(argp, int)); - if (lisprint(cast_uchar(buff))) - pushstr(L, &buff, 1); - else /* non-printable character; print its code */ - luaO_pushfstring(L, "<\\%d>", cast_uchar(buff)); - break; - } - case 'd': { - setivalue(L->top++, va_arg(argp, int)); - luaO_tostring(L, L->top - 1); - break; - } - case 'I': { - setivalue(L->top++, cast(lua_Integer, va_arg(argp, l_uacInt))); - luaO_tostring(L, L->top - 1); - break; - } - case 'f': { - setfltvalue(L->top++, cast_num(va_arg(argp, l_uacNumber))); - luaO_tostring(L, L->top - 1); - break; - } - case 'p': { - char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */ - int l = sprintf(buff, "%p", va_arg(argp, void *)); - pushstr(L, buff, l); - break; - } - case 'U': { - char buff[UTF8BUFFSZ]; - int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long))); - pushstr(L, buff + UTF8BUFFSZ - l, l); - break; - } - case '%': { - pushstr(L, "%", 1); - break; - } - default: { - luaG_runerror(L, "invalid option '%%%c' to 'lua_pushfstring'", - *(e + 1)); - } - } - 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); -} - - -const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { - const char *msg; - va_list argp; - va_start(argp, fmt); - msg = luaO_pushvfstring(L, fmt, argp); - va_end(argp); - return msg; -} - - -/* number of chars of a literal string without the ending \0 */ -#define LL(x) (sizeof(x)/sizeof(char) - 1) - -#define RETS "..." -#define PRE "[string \"" -#define POS "\"]" - -#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 * sizeof(char)); - else { /* truncate it */ - addstr(out, source + 1, bufflen - 1); - *out = '\0'; - } - } - else if (*source == '@') { /* file name */ - if (l <= bufflen) /* small enough? */ - 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 * sizeof(char)); - } - } - 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) + 1; /* save space for prefix+suffix+'\0' */ - 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) * sizeof(char)); - } -} - diff --git a/src/lobject.h b/src/lobject.h deleted file mode 100644 index abe6e7aff0..0000000000 --- a/src/lobject.h +++ /dev/null @@ -1,538 +0,0 @@ -/* -** $Id: lobject.h,v 2.104 2014/10/25 11:50:46 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" - - -/* -** Extra tags for non-values -*/ -#define LUA_TPROTO LUA_NUMTAGS -#define LUA_TDEADKEY (LUA_NUMTAGS+1) - -/* -** number of all possible tags (including LUA_TNONE but excluding DEADKEY) -*/ -#define LUA_TOTALTAGS (LUA_TPROTO + 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 -*/ - -#define VARBITS (3 << 4) - - -/* -** LUA_TFUNCTION variants: -** 0 - Lua function -** 1 - light C function -** 2 - regular C function (closure) -*/ - -/* 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 */ - - -/* Variant tags for strings */ -#define LUA_TSHRSTR (LUA_TSTRING | (0 << 4)) /* short strings */ -#define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) /* long strings */ - - -/* Variant tags for numbers */ -#define LUA_TNUMFLT (LUA_TNUMBER | (0 << 4)) /* float numbers */ -#define LUA_TNUMINT (LUA_TNUMBER | (1 << 4)) /* integer numbers */ - - -/* Bit mark for collectable types */ -#define BIT_ISCOLLECTABLE (1 << 6) - -/* mark a tag as collectable */ -#define ctb(t) ((t) | BIT_ISCOLLECTABLE) - - -/* -** Common type for all collectable objects -*/ -typedef struct GCObject GCObject; - - -/* -** 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 - - -/* -** Common type has only the common header -*/ -struct GCObject { - CommonHeader; -}; - - - -/* -** Union of all Lua values -*/ -typedef union Value Value; - - - - -/* -** 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_ - -typedef struct lua_TValue TValue; - - -/* macro defining a nil value */ -#define NILCONSTANT {NULL}, LUA_TNIL - - -#define val_(o) ((o)->value_) - - -/* raw type tag of a TValue */ -#define rttype(o) ((o)->tt_) - -/* tag with no variants (bits 0-3) */ -#define novariant(x) ((x) & 0x0F) - -/* 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 ttnov(o) (novariant(rttype(o))) - - -/* Macros to test type */ -#define checktag(o,t) (rttype(o) == (t)) -#define checktype(o,t) (ttnov(o) == (t)) -#define ttisnumber(o) checktype((o), LUA_TNUMBER) -#define ttisfloat(o) checktag((o), LUA_TNUMFLT) -#define ttisinteger(o) checktag((o), LUA_TNUMINT) -#define ttisnil(o) checktag((o), LUA_TNIL) -#define ttisboolean(o) checktag((o), LUA_TBOOLEAN) -#define ttislightuserdata(o) checktag((o), LUA_TLIGHTUSERDATA) -#define ttisstring(o) checktype((o), LUA_TSTRING) -#define ttisshrstring(o) checktag((o), ctb(LUA_TSHRSTR)) -#define ttislngstring(o) checktag((o), ctb(LUA_TLNGSTR)) -#define ttistable(o) checktag((o), ctb(LUA_TTABLE)) -#define ttisfunction(o) checktype(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 ttisfulluserdata(o) checktag((o), ctb(LUA_TUSERDATA)) -#define ttisthread(o) checktag((o), ctb(LUA_TTHREAD)) -#define ttisdeadkey(o) checktag((o), LUA_TDEADKEY) - - -/* Macros to access values */ -#define ivalue(o) check_exp(ttisinteger(o), val_(o).i) -#define fltvalue(o) check_exp(ttisfloat(o), val_(o).n) -#define gcvalue(o) check_exp(iscollectable(o), val_(o).gc) -#define pvalue(o) check_exp(ttislightuserdata(o), val_(o).p) -#define tsvalue(o) check_exp(ttisstring(o), gco2ts(val_(o).gc)) -#define uvalue(o) check_exp(ttisfulluserdata(o), gco2u(val_(o).gc)) -#define clvalue(o) check_exp(ttisclosure(o), gco2cl(val_(o).gc)) -#define clLvalue(o) check_exp(ttisLclosure(o), gco2lcl(val_(o).gc)) -#define clCvalue(o) check_exp(ttisCclosure(o), gco2ccl(val_(o).gc)) -#define fvalue(o) check_exp(ttislcf(o), val_(o).f) -#define hvalue(o) check_exp(ttistable(o), gco2t(val_(o).gc)) -#define bvalue(o) check_exp(ttisboolean(o), val_(o).b) -#define thvalue(o) check_exp(ttisthread(o), gco2th(val_(o).gc)) -/* 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)) - - -#define iscollectable(o) (rttype(o) & BIT_ISCOLLECTABLE) - - -/* Macros for internal tests */ -#define righttt(obj) (ttype(obj) == gcvalue(obj)->tt) - -#define checkliveness(g,obj) \ - lua_longassert(!iscollectable(obj) || \ - (righttt(obj) && !isdead(g,gcvalue(obj)))) - - -/* Macros to set values */ -#define settt_(o,t) ((o)->tt_=(t)) - -#define setfltvalue(obj,x) \ - { TValue *io=(obj); val_(io).n=(x); settt_(io, LUA_TNUMFLT); } - -#define setivalue(obj,x) \ - { TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_TNUMINT); } - -#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 *io=(obj); val_(io).p=(x); settt_(io, LUA_TLIGHTUSERDATA); } - -#define setbvalue(obj,x) \ - { 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(i_g->tt)); } - -#define setsvalue(L,obj,x) \ - { TValue *io = (obj); TString *x_ = (x); \ - val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \ - checkliveness(G(L),io); } - -#define setuvalue(L,obj,x) \ - { TValue *io = (obj); Udata *x_ = (x); \ - val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TUSERDATA)); \ - checkliveness(G(L),io); } - -#define setthvalue(L,obj,x) \ - { TValue *io = (obj); lua_State *x_ = (x); \ - val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTHREAD)); \ - checkliveness(G(L),io); } - -#define setclLvalue(L,obj,x) \ - { TValue *io = (obj); LClosure *x_ = (x); \ - val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TLCL)); \ - checkliveness(G(L),io); } - -#define setclCvalue(L,obj,x) \ - { TValue *io = (obj); CClosure *x_ = (x); \ - val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TCCL)); \ - checkliveness(G(L),io); } - -#define sethvalue(L,obj,x) \ - { TValue *io = (obj); Table *x_ = (x); \ - val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \ - checkliveness(G(L),io); } - -#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY) - - - -#define setobj(L,obj1,obj2) \ - { TValue *io1=(obj1); *io1 = *(obj2); \ - (void)L; checkliveness(G(L),io1); } - - -/* -** different types of assignments, according to destination -*/ - -/* from stack to (same) stack */ -#define setobjs2s setobj -/* 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 */ -#define setobj2t setobj -/* to new object */ -#define setobj2n setobj -#define setsvalue2n setsvalue - - - - -/* -** {====================================================== -** types and prototypes -** ======================================================= -*/ - - -union Value { - GCObject *gc; /* collectable objects */ - void *p; /* light userdata */ - int b; /* booleans */ - lua_CFunction f; /* light C functions */ - lua_Integer i; /* integer numbers */ - lua_Number n; /* float numbers */ -}; - - -struct lua_TValue { - TValuefields; -}; - - -typedef TValue *StkId; /* index to stack elements */ - - - - -/* -** Header for string value; string bytes follow the end of this structure -** (aligned according to 'UTString'; see next). -*/ -typedef struct TString { - CommonHeader; - lu_byte extra; /* reserved words for short strings; "has hash" for longs */ - unsigned int hash; - size_t len; /* number of characters in string */ - struct TString *hnext; /* linked list for hash table */ -} TString; - - -/* -** Ensures that address after this type is always fully aligned. -*/ -typedef union UTString { - L_Umaxalign dummy; /* ensures maximum alignment for strings */ - TString tsv; -} UTString; - - -/* -** Get the actual string (array of bytes) from a 'TString'. -** (Access to 'extra' ensures that value is really a 'TString'.) -*/ -#define getaddrstr(ts) (cast(char *, (ts)) + sizeof(UTString)) -#define getstr(ts) \ - check_exp(sizeof((ts)->extra), cast(const char*, getaddrstr(ts))) - -/* get the actual string (array of bytes) from a Lua value */ -#define svalue(o) getstr(tsvalue(o)) - - -/* -** Header for userdata; memory area follows the end of this structure -** (aligned according to 'UUdata'; see next). -*/ -typedef struct Udata { - CommonHeader; - lu_byte ttuv_; /* user value's tag */ - struct Table *metatable; - size_t len; /* number of bytes */ - union Value user_; /* user value */ -} Udata; - - -/* -** Ensures that address after this type is always fully aligned. -*/ -typedef union UUdata { - L_Umaxalign dummy; /* ensures maximum alignment for 'local' udata */ - Udata uv; -} UUdata; - - -/* -** Get the address of memory block inside 'Udata'. -** (Access to 'ttuv_' ensures that value is really a 'Udata'.) -*/ -#define getudatamem(u) \ - check_exp(sizeof((u)->ttuv_), (cast(char*, (u)) + sizeof(UUdata))) - -#define setuservalue(L,u,o) \ - { const TValue *io=(o); Udata *iu = (u); \ - iu->user_ = io->value_; iu->ttuv_ = io->tt_; \ - checkliveness(G(L),io); } - - -#define getuservalue(L,u,o) \ - { TValue *io=(o); const Udata *iu = (u); \ - io->value_ = iu->user_; io->tt_ = iu->ttuv_; \ - checkliveness(G(L),io); } - - -/* -** Description of an upvalue for function prototypes -*/ -typedef struct Upvaldesc { - TString *name; /* upvalue name (for debug information) */ - 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 -*/ -typedef struct Proto { - CommonHeader; - lu_byte numparams; /* number of fixed parameters */ - lu_byte is_vararg; - lu_byte maxstacksize; /* maximum stack used by this function */ - int sizeupvalues; /* size of 'upvalues' */ - int sizek; /* size of 'k' */ - int sizecode; - int sizelineinfo; - int sizep; /* size of 'p' */ - int sizelocvars; - int linedefined; - int lastlinedefined; - 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 (debug information) */ - LocVar *locvars; /* information about local variables (debug information) */ - Upvaldesc *upvalues; /* upvalue information */ - struct LClosure *cache; /* last created closure with this prototype */ - TString *source; /* used for debug information */ - GCObject *gclist; -} Proto; - - - -/* -** Lua Upvalues -*/ -typedef struct UpVal UpVal; - - -/* -** Closures -*/ - -#define ClosureHeader \ - CommonHeader; lu_byte nupvalues; GCObject *gclist - -typedef struct CClosure { - ClosureHeader; - lua_CFunction f; - TValue upvalue[1]; /* list of upvalues */ -} CClosure; - - -typedef struct LClosure { - ClosureHeader; - struct Proto *p; - UpVal *upvals[1]; /* list of upvalues */ -} LClosure; - - -typedef union Closure { - CClosure c; - LClosure l; -} Closure; - - -#define isLfunction(o) ttisLclosure(o) - -#define getproto(o) (clLvalue(o)->p) - - -/* -** Tables -*/ - -typedef union TKey { - struct { - TValuefields; - int next; /* for chaining (offset for next node) */ - } nk; - TValue tvk; -} TKey; - - -/* copy a value into a key without messing up field 'next' */ -#define setkey(L,key,obj) \ - { TKey *k_=(key); const TValue *io_=(obj); \ - k_->nk.value_ = io_->value_; k_->nk.tt_ = io_->tt_; \ - (void)L; checkliveness(G(L),io_); } - - -typedef struct Node { - TValue i_val; - TKey i_key; -} Node; - - -typedef struct Table { - CommonHeader; - lu_byte flags; /* 1<

      lsizenode)) - - -/* -** (address of) a fixed nil value -*/ -#define luaO_nilobject (&luaO_nilobject_) - - -LUAI_DDEC const TValue luaO_nilobject_; - -/* size of buffer for 'luaO_utf8esc' function */ -#define UTF8BUFFSZ 8 - -LUAI_FUNC int luaO_int2fb (unsigned int x); -LUAI_FUNC int luaO_fb2int (int x); -LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x); -LUAI_FUNC int luaO_ceillog2 (unsigned int x); -LUAI_FUNC void luaO_arith (lua_State *L, int op, const TValue *p1, - const TValue *p2, TValue *res); -LUAI_FUNC size_t luaO_str2num (const char *s, TValue *o); -LUAI_FUNC int luaO_hexavalue (int c); -LUAI_FUNC void luaO_tostring (lua_State *L, StkId obj); -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, size_t len); - - -#endif - diff --git a/src/lopcodes.c b/src/lopcodes.c deleted file mode 100644 index 8e2e6da3d5..0000000000 --- a/src/lopcodes.c +++ /dev/null @@ -1,122 +0,0 @@ -/* -** $Id: lopcodes.c,v 1.54 2014/11/02 19:19:04 roberto Exp $ -** Opcodes for Lua virtual machine -** See Copyright Notice in lua.h -*/ - -#define lopcodes_c -#define LUA_CORE - -#include "lprefix.h" - - -#include "lopcodes.h" - - -/* ORDER OP */ - -LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { - "MOVE", - "LOADK", - "LOADKX", - "LOADBOOL", - "LOADNIL", - "GETUPVAL", - "GETTABUP", - "GETTABLE", - "SETTABUP", - "SETUPVAL", - "SETTABLE", - "NEWTABLE", - "SELF", - "ADD", - "SUB", - "MUL", - "MOD", - "POW", - "DIV", - "IDIV", - "BAND", - "BOR", - "BXOR", - "SHL", - "SHR", - "UNM", - "BNOT", - "NOT", - "LEN", - "CONCAT", - "JMP", - "EQ", - "LT", - "LE", - "TEST", - "TESTSET", - "CALL", - "TAILCALL", - "RETURN", - "FORLOOP", - "FORPREP", - "TFORCALL", - "TFORLOOP", - "SETLIST", - "CLOSURE", - "VARARG", - "EXTRAARG", - NULL -}; - - -#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) - -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, 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 */ - ,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 */ - ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_IDIV */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BAND */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BOR */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BXOR */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHL */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHR */ - ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */ - ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_BNOT */ - ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ - ,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, 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 */ - ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */ - ,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, 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 deleted file mode 100644 index 864b8e4bb5..0000000000 --- a/src/lopcodes.h +++ /dev/null @@ -1,295 +0,0 @@ -/* -** $Id: lopcodes.h,v 1.148 2014/10/25 11:50:46 roberto Exp $ -** Opcodes for Lua virtual machine -** See Copyright Notice in lua.h -*/ - -#ifndef lopcodes_h -#define lopcodes_h - -#include "llimits.h" - - -/*=========================================================================== - We assume that instructions are unsigned numbers. - All instructions have an opcode in the first 6 bits. - Instructions can have the following fields: - '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 - - 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. -===========================================================================*/ - - -enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */ - - -/* -** size and position of opcode arguments. -*/ -#define SIZE_C 9 -#define SIZE_B 9 -#define SIZE_Bx (SIZE_C + SIZE_B) -#define SIZE_A 8 -#define SIZE_Ax (SIZE_C + SIZE_B + SIZE_A) - -#define SIZE_OP 6 - -#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_Ax POS_A - - -/* -** limits for opcode arguments. -** we use (signed) int to manipulate most arguments, -** so they must fit in LUAI_BITSINT-1 bits (-1 for sign) -*/ -#if SIZE_Bx < LUAI_BITSINT-1 -#define MAXARG_Bx ((1<>1) /* 'sBx' is signed */ -#else -#define MAXARG_Bx MAX_INT -#define MAXARG_sBx MAX_INT -#endif - -#if SIZE_Ax < LUAI_BITSINT-1 -#define MAXARG_Ax ((1<>POS_OP) & MASK1(SIZE_OP,0))) -#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \ - ((cast(Instruction, o)<>pos) & MASK1(size,0))) -#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \ - ((cast(Instruction, v)<> RK(C) */ -OP_UNM,/* A B R(A) := -R(B) */ -OP_BNOT,/* A B R(A) := ~R(B) */ -OP_NOT,/* A B R(A) := not R(B) */ -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_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 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)) */ -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) > 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)) - - -LUAI_DDEC const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */ - - -/* number of list items to accumulate before a SETLIST instruction */ -#define LFIELDS_PER_FLUSH 50 - - -#endif diff --git a/src/loslib.c b/src/loslib.c deleted file mode 100644 index b72ce961af..0000000000 --- a/src/loslib.c +++ /dev/null @@ -1,356 +0,0 @@ -/* -** $Id: loslib.c,v 1.53 2014/12/10 15:42:42 roberto Exp $ -** Standard Operating System library -** See Copyright Notice in lua.h -*/ - -#define loslib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -#if !defined(LUA_STRFTIMEOPTIONS) /* { */ -/* -** list of valid conversion specifiers for the 'strftime' function -*/ - -#if defined(LUA_USE_C89) -#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" } -#else /* C99 specification */ -#define LUA_STRFTIMEOPTIONS \ - { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "", \ - "E", "cCxXyY", \ - "O", "deHImMSuUVwWy" } -#endif - -#endif /* } */ - - - -#if !defined(l_time_t) /* { */ -/* -** type to represent time_t in Lua -*/ -#define l_timet lua_Integer -#define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t)) -#define l_checktime(L,a) ((time_t)luaL_checkinteger(L,a)) - -#endif /* } */ - - - -#if !defined(lua_tmpnam) /* { */ -/* -** By default, Lua uses tmpnam except when POSIX is available, where it -** uses mkstemp. -*/ - -#if defined(LUA_USE_POSIX) /* { */ - -#include - -#define LUA_TMPNAMBUFSIZE 32 - -#if !defined(LUA_TMPNAMTEMPLATE) -#define LUA_TMPNAMTEMPLATE "/tmp/lua_XXXXXX" -#endif - -#define lua_tmpnam(b,e) { \ - strcpy(b, LUA_TMPNAMTEMPLATE); \ - e = mkstemp(b); \ - if (e != -1) close(e); \ - e = (e == -1); } - -#else /* }{ */ - -/* ISO C definitions */ -#define LUA_TMPNAMBUFSIZE L_tmpnam -#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } - -#endif /* } */ - -#endif /* } */ - - - -#if !defined(l_gmtime) /* { */ -/* -** By default, Lua uses gmtime/localtime, except when POSIX is available, -** where it uses gmtime_r/localtime_r -*/ - -#if defined(LUA_USE_POSIX) /* { */ - -#define l_gmtime(t,r) gmtime_r(t,r) -#define l_localtime(t,r) localtime_r(t,r) - -#else /* }{ */ - -/* ISO C definitions */ -#define l_gmtime(t,r) ((void)r, gmtime(t)) -#define l_localtime(t,r) ((void)r, localtime(t)) - -#endif /* } */ - -#endif /* } */ - - - -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_pushboolean(L, stat); /* true if there is a shell */ - return 1; - } -} - - -static int os_remove (lua_State *L) { - const char *filename = luaL_checkstring(L, 1); - 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 luaL_fileresult(L, rename(fromname, toname) == 0, NULL); -} - - -static int os_tmpname (lua_State *L) { - 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; -} - - -static int os_getenv (lua_State *L) { - lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ - return 1; -} - - -static int os_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_pushinteger(L, value); - lua_setfield(L, -2, key); -} - -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); -} - -static int getboolfield (lua_State *L, const char *key) { - int res; - res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1); - lua_pop(L, 1); - return res; -} - - -static int getfield (lua_State *L, const char *key, int d) { - int res, isnum; - lua_getfield(L, -1, key); - res = (int)lua_tointegerx(L, -1, &isnum); - if (!isnum) { - if (d < 0) - return luaL_error(L, "field '%s' missing in date table", key); - res = d; - } - lua_pop(L, 1); - return res; -} - - -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, l_checktime, 2, time(NULL)); - struct tm tmr, *stm; - if (*s == '!') { /* UTC? */ - stm = l_gmtime(&t, &tmr); - s++; /* skip '!' */ - } - else - stm = l_localtime(&t, &tmr); - 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 cc[4]; - luaL_Buffer b; - cc[0] = '%'; - luaL_buffinit(L, &b); - 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 */ - s = checkoption(L, s + 1, cc); - reslen = strftime(buff, sizeof(buff), cc, stm); - luaL_addlstring(&b, buff, reslen); - } - } - luaL_pushresult(&b); - } - return 1; -} - - -static int os_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)(l_timet)t) - luaL_error(L, "time result cannot be represented in this Lua instalation"); - else if (t == (time_t)(-1)) - lua_pushnil(L); - else - l_pushtime(L, t); - return 1; -} - - -static int os_difftime (lua_State *L) { - double res = difftime((l_checktime(L, 1)), (l_checktime(L, 2))); - lua_pushnumber(L, (lua_Number)res); - return 1; -} - -/* }====================================================== */ - - -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", - "numeric", "time", NULL}; - const char *l = luaL_optstring(L, 1, NULL); - int op = luaL_checkoption(L, 2, "all", catnames); - lua_pushstring(L, setlocale(cat[op], l)); - return 1; -} - - -static int os_exit (lua_State *L) { - int status; - if (lua_isboolean(L, 1)) - status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE); - else - status = (int)luaL_optinteger(L, 1, EXIT_SUCCESS); - if (lua_toboolean(L, 2)) - lua_close(L); - if (L) exit(status); /* 'if' to avoid warnings for unreachable 'return' */ - return 0; -} - - -static const luaL_Reg syslib[] = { - {"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} -}; - -/* }====================================================== */ - - - -LUAMOD_API int luaopen_os (lua_State *L) { - luaL_newlib(L, syslib); - return 1; -} - diff --git a/src/lparser.c b/src/lparser.c deleted file mode 100644 index 98b92c2218..0000000000 --- a/src/lparser.c +++ /dev/null @@ -1,1647 +0,0 @@ -/* -** $Id: lparser.c,v 2.146 2014/11/27 18:41:43 roberto Exp $ -** Lua Parser -** See Copyright Notice in lua.h -*/ - -#define lparser_c -#define LUA_CORE - -#include "lprefix.h" - - -#include - -#include "lua.h" - -#include "lcode.h" -#include "ldebug.h" -#include "ldo.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 "ltable.h" - - - -/* maximum number of local variables per function (must be smaller - than 250, due to the bytecode format) */ -#define MAXVARS 200 - - -#define hasmultret(k) ((k) == VCALL || (k) == VVARARG) - - -/* because all strings are unified by the scanner, the parser - can use pointer equality for string equality */ -#define eqstr(a,b) ((a) == (b)) - - -/* -** nodes for block list (list of active blocks) -*/ -typedef struct BlockCnt { - struct BlockCnt *previous; /* chain */ - 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 */ -} BlockCnt; - - - -/* -** prototypes for recursive non-terminal functions -*/ -static void statement (LexState *ls); -static void expr (LexState *ls, expdesc *v); - - -/* semantic error */ -static l_noret semerror (LexState *ls, const char *msg) { - ls->t.token = 0; /* remove "near " from final message */ - luaX_syntaxerror(ls, msg); -} - - -static l_noret error_expected (LexState *ls, int token) { - luaX_syntaxerror(ls, - luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token))); -} - - -static l_noret 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(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); -} - - -static void checklimit (FuncState *fs, int v, int l, const char *what) { - if (v > l) errorlimit(fs, l, what); -} - - -static int testnext (LexState *ls, int c) { - if (ls->t.token == c) { - luaX_next(ls); - return 1; - } - else return 0; -} - - -static void check (LexState *ls, int c) { - if (ls->t.token != c) - error_expected(ls, c); -} - - -static void checknext (LexState *ls, int c) { - check(ls, c); - luaX_next(ls); -} - - -#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 (!testnext(ls, what)) { - if (where == ls->linenumber) - error_expected(ls, what); - else { - luaX_syntaxerror(ls, luaO_pushfstring(ls->L, - "%s expected (to close %s at line %d)", - luaX_token2str(ls, what), luaX_token2str(ls, who), where)); - } - } -} - - -static TString *str_checkname (LexState *ls) { - TString *ts; - check(ls, TK_NAME); - ts = ls->t.seminfo.ts; - luaX_next(ls); - return ts; -} - - -static void init_exp (expdesc *e, expkind k, int i) { - e->f = e->t = NO_JUMP; - e->k = k; - e->u.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 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, 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); - return fs->nlocvars++; -} - - -static void new_localvar (LexState *ls, TString *name) { - FuncState *fs = ls->fs; - Dyndata *dyd = ls->dyd; - int reg = registerlocalvar(ls, name); - checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, - 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(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 LocVar *getlocvar (FuncState *fs, int i) { - int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx; - lua_assert(idx < fs->nlocvars); - return &fs->f->locvars[idx]; -} - - -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; - } -} - - -static void removevars (FuncState *fs, int tolevel) { - fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel); - while (fs->nactvar > tolevel) - getlocvar(fs, --fs->nactvar)->endpc = fs->pc; -} - - -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; - checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); - 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->ls->L, f, name); - return fs->nups++; -} - - -static int searchvar (FuncState *fs, TString *n) { - int i; - for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) { - if (eqstr(n, getlocvar(fs, i)->varname)) - return i; - } - return -1; /* not found */ -} - - -/* - Mark block where variable at given level was defined - (to emit close instructions later). -*/ -static void markupval (FuncState *fs, int level) { - BlockCnt *bl = fs->bl; - while (bl->nactvar > level) bl = bl->previous; - bl->upval = 1; -} - - -/* - 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 VVOID; /* default is global */ - else { - 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 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; - } - } -} - - -static void singlevar (LexState *ls, expdesc *var) { - TString *varname = str_checkname(ls); - FuncState *fs = ls->fs; - if (singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */ - expdesc key; - 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] */ - } -} - - -static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { - FuncState *fs = ls->fs; - int extra = nvars - nexps; - if (hasmultret(e->k)) { - extra++; /* includes call itself */ - 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 */ - if (extra > 0) { - int reg = fs->freereg; - luaK_reserveregs(fs, extra); - luaK_nil(fs, reg, extra); - } - } -} - - -static void enterlevel (LexState *ls) { - lua_State *L = ls->L; - ++L->nCcalls; - checklimit(ls->fs, L->nCcalls, LUAI_MAXCCALLS, "C levels"); -} - - -#define leavelevel(ls) ((ls)->L->nCcalls--) - - -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) { - TString *vname = getlocvar(fs, gt->nactvar)->varname; - const char *msg = luaO_pushfstring(ls->L, - " at line %d jumps into the scope of local '%s'", - getstr(gt->name), gt->line, getstr(vname)); - 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, SHRT_MAX, "labels/gotos"); - 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 exits 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; - lua_assert(fs->freereg == fs->nactvar); -} - - -/* -** 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 l_noret undefgoto (LexState *ls, Labeldesc *gt) { - const char *msg = isreserved(gt->name) - ? "<%s> at line %d not inside a loop" - : "no visible label '%s' for at line %d"; - 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); - lua_assert(bl->nactvar == fs->nactvar); - fs->freereg = fs->nactvar; /* free registers */ - 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 */ -} - - -/* -** adds a new prototype into list of prototypes -*/ -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(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions"); - while (oldsize < f->sizep) f->p[oldsize++] = NULL; - } - f->p[fs->np++] = clp = luaF_newproto(L); - luaC_objbarrier(L, f, clp); - return clp; -} - - -/* -** 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 the last register */ -} - - -static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { - Proto *f; - fs->prev = ls->fs; /* linked list of funcstates */ - fs->ls = ls; - ls->fs = fs; - fs->pc = 0; - 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->dyd->actvar.n; - fs->bl = NULL; - f = fs->f; - f->source = ls->source; - f->maxstacksize = 2; /* registers 0/1 are always valid */ - enterblock(fs, bl, 0); -} - - -static void close_func (LexState *ls) { - lua_State *L = ls->L; - FuncState *fs = ls->fs; - Proto *f = fs->f; - luaK_ret(fs, 0, 0); /* final return */ - 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); - f->sizelineinfo = fs->pc; - 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; - luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar); - f->sizelocvars = fs->nlocvars; - luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc); - f->sizeupvalues = fs->nups; - lua_assert(fs->bl == NULL); - ls->fs = fs->prev; - luaC_checkGC(L); -} - - - -/*============================================================*/ -/* 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 is 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; - expdesc key; - luaK_exp2anyregup(fs, v); - luaX_next(ls); /* skip the dot or colon */ - checkname(ls, &key); - luaK_indexed(fs, v, &key); -} - - -static void yindex (LexState *ls, expdesc *v) { - /* index -> '[' expr ']' */ - luaX_next(ls); /* skip the '[' */ - expr(ls, v); - luaK_exp2val(ls->fs, v); - checknext(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 reg = ls->fs->freereg; - expdesc key, val; - int rkkey; - if (ls->t.token == TK_NAME) { - checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); - checkname(ls, &key); - } - else /* ls->t.token == '[' */ - yindex(ls, &key); - cc->nh++; - checknext(ls, '='); - rkkey = luaK_exp2RK(fs, &key); - expr(ls, &val); - luaK_codeABC(fs, OP_SETTABLE, cc->t->u.info, rkkey, 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_setlist(fs, cc->t->u.info, cc->na, cc->tostore); /* flush */ - cc->tostore = 0; /* no more items pending */ - } -} - - -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.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.info, cc->na, cc->tostore); - } -} - - -static void listfield (LexState *ls, struct ConsControl *cc) { - /* listfield -> exp */ - expr(ls, &cc->v); - 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 -> '{' [ field { sep field } [sep] ] '}' - sep -> ',' | ';' */ - 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 */ - checknext(ls, '{'); - do { - lua_assert(cc.v.k == VVOID || cc.tostore > 0); - if (ls->t.token == '}') break; - closelistfield(fs, &cc); - field(ls, &cc); - } 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_int2fb(cc.nh)); /* set initial table size */ -} - -/* }====================================================================== */ - - - -static void parlist (LexState *ls) { - /* parlist -> [ param { ',' param } ] */ - FuncState *fs = ls->fs; - Proto *f = fs->f; - int nparams = 0; - f->is_vararg = 0; - if (ls->t.token != ')') { /* is 'parlist' not empty? */ - do { - switch (ls->t.token) { - case TK_NAME: { /* param -> NAME */ - new_localvar(ls, str_checkname(ls)); - nparams++; - break; - } - case TK_DOTS: { /* param -> '...' */ - luaX_next(ls); - f->is_vararg = 1; - break; - } - default: luaX_syntaxerror(ls, " or '...' expected"); - } - } while (!f->is_vararg && testnext(ls, ',')); - } - adjustlocalvars(ls, nparams); - f->numparams = cast_byte(fs->nactvar); - luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ -} - - -static void body (LexState *ls, expdesc *e, int ismethod, int line) { - /* body -> '(' parlist ')' block END */ - FuncState new_fs; - BlockCnt 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 */ - adjustlocalvars(ls, 1); - } - parlist(ls); - checknext(ls, ')'); - statlist(ls); - new_fs.f->lastlinedefined = ls->linenumber; - check_match(ls, TK_END, TK_FUNCTION, line); - codeclosure(ls, e); - close_func(ls); -} - - -static int explist (LexState *ls, expdesc *v) { - /* explist -> expr { ',' expr } */ - int n = 1; /* at least one expression */ - expr(ls, v); - while (testnext(ls, ',')) { - luaK_exp2nextreg(ls->fs, v); - expr(ls, v); - n++; - } - return n; -} - - -static void funcargs (LexState *ls, expdesc *f, int line) { - FuncState *fs = ls->fs; - expdesc args; - int base, nparams; - switch (ls->t.token) { - case '(': { /* funcargs -> '(' [ explist ] ')' */ - luaX_next(ls); - if (ls->t.token == ')') /* arg list is empty? */ - args.k = VVOID; - else { - explist(ls, &args); - luaK_setmultret(fs, &args); - } - check_match(ls, ')', '(', line); - break; - } - case '{': { /* funcargs -> constructor */ - constructor(ls, &args); - break; - } - case TK_STRING: { /* funcargs -> STRING */ - codestring(ls, &args, ls->t.seminfo.ts); - luaX_next(ls); /* must use 'seminfo' before 'next' */ - break; - } - default: { - luaX_syntaxerror(ls, "function arguments expected"); - } - } - lua_assert(f->k == VNONRELOC); - base = f->u.info; /* base register for call */ - if (hasmultret(args.k)) - nparams = LUA_MULTRET; /* open call */ - else { - if (args.k != VVOID) - luaK_exp2nextreg(fs, &args); /* close last argument */ - nparams = fs->freereg - (base+1); - } - 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 */ -} - - - - -/* -** {====================================================================== -** Expression parsing -** ======================================================================= -*/ - - -static void primaryexp (LexState *ls, expdesc *v) { - /* primaryexp -> NAME | '(' expr ')' */ - switch (ls->t.token) { - case '(': { - int line = ls->linenumber; - luaX_next(ls); - expr(ls, v); - check_match(ls, ')', '(', line); - luaK_dischargevars(ls->fs, v); - return; - } - case TK_NAME: { - singlevar(ls, v); - return; - } - default: { - luaX_syntaxerror(ls, "unexpected symbol"); - } - } -} - - -static void suffixedexp (LexState *ls, expdesc *v) { - /* suffixedexp -> - primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ - FuncState *fs = ls->fs; - int line = ls->linenumber; - primaryexp(ls, v); - for (;;) { - switch (ls->t.token) { - case '.': { /* fieldsel */ - fieldsel(ls, v); - break; - } - case '[': { /* '[' exp1 ']' */ - expdesc key; - luaK_exp2anyregup(fs, v); - yindex(ls, &key); - luaK_indexed(fs, v, &key); - break; - } - case ':': { /* ':' NAME funcargs */ - expdesc key; - luaX_next(ls); - checkname(ls, &key); - luaK_self(fs, v, &key); - funcargs(ls, v, line); - break; - } - case '(': case TK_STRING: case '{': { /* funcargs */ - luaK_exp2nextreg(fs, v); - funcargs(ls, v, line); - break; - } - default: return; - } - } -} - - -static void simpleexp (LexState *ls, expdesc *v) { - /* simpleexp -> FLT | INT | STRING | NIL | TRUE | FALSE | ... | - constructor | FUNCTION body | suffixedexp */ - switch (ls->t.token) { - case TK_FLT: { - init_exp(v, VKFLT, 0); - v->u.nval = ls->t.seminfo.r; - break; - } - case TK_INT: { - init_exp(v, VKINT, 0); - v->u.ival = ls->t.seminfo.i; - break; - } - case TK_STRING: { - codestring(ls, v, ls->t.seminfo.ts); - break; - } - case TK_NIL: { - init_exp(v, VNIL, 0); - break; - } - case TK_TRUE: { - init_exp(v, VTRUE, 0); - break; - } - case TK_FALSE: { - init_exp(v, VFALSE, 0); - break; - } - case TK_DOTS: { /* vararg */ - FuncState *fs = ls->fs; - check_condition(ls, fs->f->is_vararg, - "cannot use '...' outside a vararg function"); - init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); - break; - } - case '{': { /* constructor */ - constructor(ls, v); - return; - } - case TK_FUNCTION: { - luaX_next(ls); - body(ls, v, 0, ls->linenumber); - return; - } - default: { - suffixedexp(ls, v); - return; - } - } - luaX_next(ls); -} - - -static UnOpr getunopr (int op) { - switch (op) { - case TK_NOT: return OPR_NOT; - case '-': return OPR_MINUS; - case '~': return OPR_BNOT; - case '#': return OPR_LEN; - default: return OPR_NOUNOPR; - } -} - - -static BinOpr getbinopr (int op) { - switch (op) { - case '+': return OPR_ADD; - case '-': return OPR_SUB; - case '*': return OPR_MUL; - case '%': return OPR_MOD; - case '^': return OPR_POW; - case '/': return OPR_DIV; - case TK_IDIV: return OPR_IDIV; - case '&': return OPR_BAND; - case '|': return OPR_BOR; - case '~': return OPR_BXOR; - case TK_SHL: return OPR_SHL; - case TK_SHR: return OPR_SHR; - 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; - } -} - - -static const struct { - lu_byte left; /* left priority for each binary operator */ - lu_byte right; /* right priority */ -} priority[] = { /* ORDER OPR */ - {10, 10}, {10, 10}, /* '+' '-' */ - {11, 11}, {11, 11}, /* '*' '%' */ - {14, 13}, /* '^' (right associative) */ - {11, 11}, {11, 11}, /* '/' '//' */ - {6, 6}, {4, 4}, {5, 5}, /* '&' '|' '~' */ - {7, 7}, {7, 7}, /* '<<' '>>' */ - {9, 8}, /* '..' (right associative) */ - {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */ - {3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */ - {2, 2}, {1, 1} /* and, or */ -}; - -#define UNARY_PRIORITY 12 /* priority for unary operators */ - - -/* -** 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, int limit) { - BinOpr op; - UnOpr uop; - 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, line); - } - 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; - 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, line); - op = nextop; - } - leavelevel(ls); - return op; /* return first untreated operator */ -} - - -static void expr (LexState *ls, expdesc *v) { - subexpr(ls, v, 0); -} - -/* }==================================================================== */ - - - -/* -** {====================================================================== -** Rules for Statements -** ======================================================================= -*/ - - -static void block (LexState *ls) { - /* block -> statlist */ - FuncState *fs = ls->fs; - BlockCnt bl; - enterblock(fs, &bl, 0); - statlist(ls); - leaveblock(fs); -} - - -/* -** 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 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) { /* 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, extra, v->u.info, 0); - luaK_reserveregs(fs, 1); - } -} - - -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 -> ',' suffixedexp assignment */ - struct LHS_assign nv; - nv.prev = lh; - suffixedexp(ls, &nv.v); - if (nv.v.k != VINDEXED) - check_conflict(ls, lh, &nv.v); - checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS, - "C levels"); - assignment(ls, &nv, nvars+1); - } - else { /* assignment -> '=' explist */ - int nexps; - checknext(ls, '='); - nexps = explist(ls, &e); - if (nexps != nvars) { - adjust_assign(ls, nvars, nexps, &e); - if (nexps > nvars) - ls->fs->freereg -= nexps - nvars; /* remove extra values */ - } - else { - luaK_setoneret(ls->fs, &e); /* close last expression */ - luaK_storevar(ls->fs, &lh->v, &e); - return; /* avoid default */ - } - } - init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ - luaK_storevar(ls->fs, &lh->v, &e); -} - - -static int cond (LexState *ls) { - /* cond -> exp */ - expdesc v; - expr(ls, &v); /* read condition */ - if (v.k == VNIL) v.k = VFALSE; /* 'falses' are all equal here */ - luaK_goiftrue(ls->fs, &v); - return v.f; -} - - -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 */ -} - - -/* check for repeated labels on the same block */ -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, - "label '%s' already defined on line %d", - getstr(label), ll->arr[i].line); - semerror(fs->ls, msg); - } - } -} - - -/* 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; - Labellist *ll = &ls->dyd->label; - int l; /* index of new label being created */ - checkrepeated(fs, ll, label); /* check for repeated labels */ - checknext(ls, TK_DBCOLON); /* skip double colon */ - /* create new entry for this label */ - l = newlabelentry(ls, ll, label, line, fs->pc); - 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; - } - findgotos(ls, &ll->arr[l]); -} - - -static void whilestat (LexState *ls, int line) { - /* whilestat -> WHILE cond DO block END */ - FuncState *fs = ls->fs; - int whileinit; - int condexit; - BlockCnt bl; - luaX_next(ls); /* skip WHILE */ - whileinit = luaK_getlabel(fs); - condexit = cond(ls); - enterblock(fs, &bl, 1); - checknext(ls, TK_DO); - block(ls); - luaK_jumpto(fs, whileinit); - check_match(ls, TK_END, TK_WHILE, line); - leaveblock(fs); - luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ -} - - -static void repeatstat (LexState *ls, int line) { - /* repeatstat -> REPEAT block UNTIL cond */ - int condexit; - FuncState *fs = ls->fs; - int repeat_init = luaK_getlabel(fs); - BlockCnt bl1, bl2; - enterblock(fs, &bl1, 1); /* loop block */ - enterblock(fs, &bl2, 0); /* scope block */ - luaX_next(ls); /* skip REPEAT */ - statlist(ls); - check_match(ls, TK_UNTIL, TK_REPEAT, line); - condexit = cond(ls); /* read condition (inside scope block) */ - 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 */ -} - - -static int exp1 (LexState *ls) { - expdesc e; - int reg; - expr(ls, &e); - luaK_exp2nextreg(ls->fs, &e); - lua_assert(e.k == VNONRELOC); - reg = e.u.info; - return reg; -} - - -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, 3); /* control variables */ - checknext(ls, TK_DO); - 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); - block(ls); - leaveblock(fs); /* end of scope for declared variables */ - luaK_patchtohere(fs, prep); - 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); -} - - -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)"); - new_localvarliteral(ls, "(for limit)"); - new_localvarliteral(ls, "(for step)"); - new_localvar(ls, varname); - checknext(ls, '='); - exp1(ls); /* initial value */ - checknext(ls, ','); - exp1(ls); /* limit */ - if (testnext(ls, ',')) - exp1(ls); /* optional step */ - else { /* default step = 1 */ - luaK_codek(fs, fs->freereg, luaK_intK(fs, 1)); - luaK_reserveregs(fs, 1); - } - forbody(ls, base, line, 1, 1); -} - - -static void forlist (LexState *ls, TString *indexname) { - /* forlist -> NAME {,NAME} IN explist forbody */ - FuncState *fs = ls->fs; - expdesc e; - 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)"); - new_localvarliteral(ls, "(for state)"); - new_localvarliteral(ls, "(for control)"); - /* create declared variables */ - 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, explist(ls, &e), &e); - luaK_checkstack(fs, 3); /* extra space to call generator */ - forbody(ls, base, line, nvars - 3, 0); -} - - -static void forstat (LexState *ls, int line) { - /* forstat -> FOR (fornum | forlist) END */ - FuncState *fs = ls->fs; - TString *varname; - BlockCnt bl; - enterblock(fs, &bl, 1); /* scope for loop and control variables */ - luaX_next(ls); /* skip 'for' */ - varname = str_checkname(ls); /* first variable name */ - 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"); - } - check_match(ls, TK_END, TK_FOR, line); - leaveblock(fs); /* loop scope ('break' jumps to this point) */ -} - - -static void test_then_block (LexState *ls, int *escapelist) { - /* test_then_block -> [IF | ELSEIF] cond THEN block */ - 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 */ - expr(ls, &v); /* read condition */ - checknext(ls, TK_THEN); - 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 */ - skipnoopstat(ls); /* skip other no-op statements */ - 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 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 */ - check_match(ls, TK_END, TK_IF, line); - luaK_patchtohere(fs, escapelist); /* patch escape list to 'if' end */ -} - - -static void localfunc (LexState *ls) { - expdesc b; - FuncState *fs = ls->fs; - 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 */ - /* debug information will only see the variable after this point! */ - getlocvar(fs, b.u.info)->startpc = fs->pc; -} - - -static void localstat (LexState *ls) { - /* stat -> LOCAL NAME {',' NAME} ['=' explist] */ - int nvars = 0; - int nexps; - expdesc e; - do { - new_localvar(ls, str_checkname(ls)); - nvars++; - } while (testnext(ls, ',')); - if (testnext(ls, '=')) - nexps = explist(ls, &e); - else { - e.k = VVOID; - nexps = 0; - } - adjust_assign(ls, nvars, nexps, &e); - adjustlocalvars(ls, nvars); -} - - -static int funcname (LexState *ls, expdesc *v) { - /* funcname -> NAME {fieldsel} [':' NAME] */ - int ismethod = 0; - singlevar(ls, v); - while (ls->t.token == '.') - fieldsel(ls, v); - if (ls->t.token == ':') { - ismethod = 1; - fieldsel(ls, v); - } - return ismethod; -} - - -static void funcstat (LexState *ls, int line) { - /* funcstat -> FUNCTION funcname body */ - int ismethod; - expdesc v, b; - luaX_next(ls); /* skip FUNCTION */ - 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 */ -} - - -static void exprstat (LexState *ls) { - /* stat -> func | assignment */ - FuncState *fs = ls->fs; - struct LHS_assign v; - 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 */ - } -} - - -static void retstat (LexState *ls) { - /* stat -> RETURN [explist] [';'] */ - FuncState *fs = ls->fs; - expdesc e; - int first, nret; /* registers with returned values */ - if (block_follow(ls, 1) || ls->t.token == ';') - first = nret = 0; /* return no values */ - else { - nret = explist(ls, &e); /* optional return values */ - 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); - } - 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_ret(fs, first, nret); - testnext(ls, ';'); /* skip optional semicolon */ -} - - -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 ';' */ - break; - } - case TK_IF: { /* stat -> ifstat */ - ifstat(ls, line); - break; - } - case TK_WHILE: { /* stat -> whilestat */ - whilestat(ls, line); - break; - } - case TK_DO: { /* stat -> DO block END */ - luaX_next(ls); /* skip DO */ - block(ls); - check_match(ls, TK_END, TK_DO, line); - break; - } - case TK_FOR: { /* stat -> forstat */ - forstat(ls, line); - break; - } - case TK_REPEAT: { /* stat -> repeatstat */ - repeatstat(ls, line); - break; - } - case TK_FUNCTION: { /* stat -> funcstat */ - funcstat(ls, line); - break; - } - case TK_LOCAL: { /* stat -> localstat */ - luaX_next(ls); /* skip LOCAL */ - if (testnext(ls, TK_FUNCTION)) /* local function? */ - localfunc(ls); - else - localstat(ls); - break; - } - case TK_DBCOLON: { /* stat -> label */ - luaX_next(ls); /* skip double colon */ - labelstat(ls, str_checkname(ls), line); - break; - } - case TK_RETURN: { /* stat -> retstat */ - luaX_next(ls); /* skip RETURN */ - retstat(ls); - break; - } - case TK_BREAK: /* stat -> breakstat */ - case TK_GOTO: { /* stat -> 'goto' NAME */ - gotostat(ls, luaK_jump(ls->fs)); - break; - } - default: { /* stat -> func | assignment */ - exprstat(ls); - 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); -} - -/* }====================================================================== */ - - -/* -** 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); -} - - -LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, - Dyndata *dyd, const char *name, int firstchar) { - LexState lexstate; - FuncState funcstate; - LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */ - setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */ - incr_top(L); - lexstate.h = luaH_new(L); /* create table for scanner */ - sethvalue(L, L->top, lexstate.h); /* anchor it */ - incr_top(L); - funcstate.f = cl->p = luaF_newproto(L); - funcstate.f->source = luaS_new(L, name); /* create and anchor TString */ - lua_assert(iswhite(funcstate.f)); /* do not need barrier here */ - lexstate.buff = buff; - lexstate.dyd = dyd; - dyd->actvar.n = dyd->gt.n = dyd->label.n = 0; - 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); - L->top--; /* remove scanner's table */ - return cl; /* closure is on the stack, too */ -} - diff --git a/src/lparser.h b/src/lparser.h deleted file mode 100644 index 62c50cac7c..0000000000 --- a/src/lparser.h +++ /dev/null @@ -1,120 +0,0 @@ -/* -** $Id: lparser.h,v 1.74 2014/10/25 11:50:46 roberto Exp $ -** Lua Parser -** See Copyright Notice in lua.h -*/ - -#ifndef lparser_h -#define lparser_h - -#include "llimits.h" -#include "lobject.h" -#include "lzio.h" - - -/* -** Expression descriptor -*/ - -typedef enum { - VVOID, /* no value */ - VNIL, - VTRUE, - VFALSE, - VK, /* info = index of constant in 'k' */ - VKFLT, /* nval = numerical float value */ - VKINT, /* nval = numerical integer value */ - VNONRELOC, /* info = result register */ - VLOCAL, /* info = local register */ - VUPVAL, /* info = index of upvalue in 'upvalues' */ - VINDEXED, /* t = table register/upvalue; idx = index R/K */ - VJMP, /* info = instruction pc */ - VRELOCABLE, /* info = instruction pc */ - 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 { /* 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 VKFLT */ - lua_Integer ival; /* for VKINT */ - } u; - int t; /* patch list of 'exit when true' */ - int f; /* patch list of 'exit when false' */ -} expdesc; - - -/* description of active local variable */ -typedef struct Vardesc { - short idx; /* variable index in stack */ -} Vardesc; - - -/* 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 */ - - -/* 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 BlockCnt *bl; /* chain of current blocks */ - int pc; /* next position to code (equivalent to 'ncode') */ - int lasttarget; /* 'label' of last 'jump label' */ - int jpc; /* list of pending jumps to 'pc' */ - int nk; /* number of elements in 'k' */ - int np; /* number of elements in 'p' */ - 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; - - -LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, - Dyndata *dyd, const char *name, int firstchar); - - -#endif diff --git a/src/lprefix.h b/src/lprefix.h deleted file mode 100644 index c2a78cd701..0000000000 --- a/src/lprefix.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -** $Id: lprefix.h,v 1.1 2014/11/03 15:12:44 roberto Exp $ -** Definitions for Lua code that must come before any other header file -** See Copyright Notice in lua.h -*/ - -#ifndef lprefix_h -#define lprefix_h - - -/* -** Allows POSIX/XSI stuff -*/ -#if !defined(_XOPEN_SOURCE) -#define _XOPEN_SOURCE 600 -#endif - -/* -** Allows manipulation of large files in gcc and some other compilers -*/ -#if !defined(_FILE_OFFSET_BITS) -#define _LARGEFILE_SOURCE 1 -#define _FILE_OFFSET_BITS 64 -#endif - - -/* -** Windows stuff -*/ -#if defined(_WIN32) /* { */ - -#if !defined(_CRT_SECURE_NO_WARNINGS) -#define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */ -#endif - -#endif /* } */ - -#endif - diff --git a/src/lstate.c b/src/lstate.c deleted file mode 100644 index ff6b02d36a..0000000000 --- a/src/lstate.c +++ /dev/null @@ -1,346 +0,0 @@ -/* -** $Id: lstate.c,v 2.127 2014/11/02 19:33:33 roberto Exp $ -** Global State -** See Copyright Notice in lua.h -*/ - -#define lstate_c -#define LUA_CORE - -#include "lprefix.h" - - -#include -#include - -#include "lua.h" - -#include "lapi.h" -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "lgc.h" -#include "llex.h" -#include "lmem.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "ltm.h" - - -#if !defined(LUAI_GCPAUSE) -#define LUAI_GCPAUSE 200 /* 200% */ -#endif - -#if !defined(LUAI_GCMUL) -#define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */ -#endif - - -#define MEMERRMSG "not enough memory" - - -/* -** a macro to help the creation of a unique random seed when a state is -** created; the seed is used to randomize hashes. -*/ -#if !defined(luai_makeseed) -#include -#define luai_makeseed() cast(unsigned int, time(NULL)) -#endif - - - -/* -** thread state + extra space -*/ -typedef struct LX { - lu_byte extra_[LUA_EXTRASPACE]; - lua_State l; -} LX; - - -/* -** Main thread combines a thread state and the global state -*/ -typedef struct LG { - LX l; - global_State g; -} LG; - - - -#define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l))) - - -/* -** Compute an initial seed as random as possible. Rely on Address Space -** Layout Randomization (if present) to increase randomness.. -*/ -#define addbuff(b,p,e) \ - { size_t t = cast(size_t, e); \ - memcpy(buff + p, &t, sizeof(t)); p += sizeof(t); } - -static unsigned int makeseed (lua_State *L) { - char buff[4 * sizeof(size_t)]; - unsigned int h = luai_makeseed(); - int p = 0; - addbuff(buff, p, L); /* heap variable */ - addbuff(buff, p, &h); /* local variable */ - addbuff(buff, p, luaO_nilobject); /* global variable */ - addbuff(buff, p, &lua_newstate); /* public function */ - lua_assert(p == sizeof(buff)); - return luaS_hash(buff, p, h); -} - - -/* -** set GCdebt to a new value keeping the value (totalbytes + GCdebt) -** invariant -*/ -void luaE_setdebt (global_State *g, l_mem debt) { - g->totalbytes -= (debt - g->GCdebt); - g->GCdebt = debt; -} - - -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; -} - - -/* -** free all CallInfo structures not in use by a thread -*/ -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); - } -} - - -/* -** free half of the CallInfo structures not in use by a thread -*/ -void luaE_shrinkCI (lua_State *L) { - CallInfo *ci = L->ci; - while (ci->next != NULL) { /* while there is 'next' */ - CallInfo *next2 = ci->next->next; /* next's next */ - if (next2 == NULL) break; - luaM_free(L, ci->next); /* remove next */ - ci->next = next2; /* remove 'next' from the list */ - next2->previous = ci; - ci = next2; - } -} - - -static void stack_init (lua_State *L1, lua_State *L) { - int i; CallInfo *ci; - /* initialize stack array */ - 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; - /* initialize first ci */ - ci = &L1->base_ci; - ci->next = ci->previous = NULL; - ci->callstatus = 0; - ci->func = L1->top; - setnilvalue(L1->top++); /* 'function' entry for this 'ci' */ - ci->top = L1->top + LUA_MINSTACK; - L1->ci = ci; -} - - -static void freestack (lua_State *L) { - 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); /* free stack array */ -} - - -/* -** Create registry table and its predefined values -*/ -static void init_registry (lua_State *L, global_State *g) { - TValue temp; - /* 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, &temp, L); /* temp = L */ - luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp); - /* registry[LUA_RIDX_GLOBALS] = table of globals */ - sethvalue(L, &temp, luaH_new(L)); /* temp = new table (global table) */ - luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp); -} - - -/* -** open parts of the state that may cause memory-allocation errors. -** ('g->version' != NULL flags that the state was completely build) -*/ -static void f_luaopen (lua_State *L, void *ud) { - global_State *g = G(L); - UNUSED(ud); - stack_init(L, L); /* init stack */ - init_registry(L, g); - luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ - luaT_init(L); - luaX_init(L); - /* pre-create memory-error message */ - g->memerrmsg = luaS_newliteral(L, MEMERRMSG); - luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */ - g->gcrunning = 1; /* allow gc */ - g->version = lua_version(NULL); - luai_userstateopen(L); -} - - -/* -** preinitialize a thread with consistent values without allocating -** any memory (to avoid errors) -*/ -static void preinit_thread (lua_State *L, global_State *g) { - G(L) = g; - L->stack = NULL; - L->ci = NULL; - L->stacksize = 0; - L->twups = L; /* thread has no upvalues */ - L->errorJmp = NULL; - L->nCcalls = 0; - L->hook = NULL; - L->hookmask = 0; - L->basehookcount = 0; - L->allowhook = 1; - resethookcount(L); - L->openupval = NULL; - L->nny = 1; - L->status = LUA_OK; - L->errfunc = 0; -} - - -static void close_state (lua_State *L) { - global_State *g = G(L); - luaF_close(L, L->stack); /* close all upvalues for this thread */ - luaC_freeallobjects(L); /* collect all objects */ - if (g->version) /* closing a fully built state? */ - luai_userstateclose(L); - luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); - luaZ_freebuffer(L, &g->buff); - freestack(L); - lua_assert(gettotalbytes(g) == sizeof(LG)); - (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ -} - - -LUA_API lua_State *lua_newthread (lua_State *L) { - global_State *g = G(L); - lua_State *L1; - lua_lock(L); - luaC_checkGC(L); - /* create new thread */ - L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l; - L1->marked = luaC_white(g); - L1->tt = LUA_TTHREAD; - /* link it on list 'allgc' */ - L1->next = g->allgc; - g->allgc = obj2gco(L1); - /* anchor it on L stack */ - setthvalue(L, L->top, L1); - api_incr_top(L); - preinit_thread(L1, g); - L1->hookmask = L->hookmask; - L1->basehookcount = L->basehookcount; - L1->hook = L->hook; - resethookcount(L1); - /* initialize L1 extra space */ - memcpy(lua_getextraspace(L1), lua_getextraspace(g->mainthread), - LUA_EXTRASPACE); - luai_userstatethread(L, L1); - stack_init(L1, L); /* init stack */ - lua_unlock(L); - 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(L, L1); - freestack(L1); - luaM_free(L, l); -} - - -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, LUA_TTHREAD, sizeof(LG))); - if (l == NULL) return NULL; - L = &l->l.l; - g = &l->g; - L->next = NULL; - L->tt = LUA_TTHREAD; - g->currentwhite = bitmask(WHITE0BIT); - L->marked = luaC_white(g); - preinit_thread(L, g); - g->frealloc = f; - g->ud = ud; - g->mainthread = L; - g->seed = makeseed(L); - g->gcrunning = 0; /* no GC while building state */ - g->GCestimate = 0; - g->strt.size = g->strt.nuse = 0; - g->strt.hash = NULL; - setnilvalue(&g->l_registry); - luaZ_initbuffer(L, &g->buff); - g->panic = NULL; - g->version = NULL; - g->gcstate = GCSpause; - g->gckind = KGC_NORMAL; - g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL; - g->sweepgc = NULL; - g->gray = g->grayagain = NULL; - g->weak = g->ephemeron = g->allweak = NULL; - g->twups = NULL; - g->totalbytes = sizeof(LG); - g->GCdebt = 0; - g->gcfinnum = 0; - g->gcpause = LUAI_GCPAUSE; - g->gcstepmul = LUAI_GCMUL; - 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); - L = NULL; - } - return L; -} - - -LUA_API void lua_close (lua_State *L) { - L = G(L)->mainthread; /* only the main thread can be closed */ - lua_lock(L); - close_state(L); -} - - diff --git a/src/lstate.h b/src/lstate.h deleted file mode 100644 index 81e12c40db..0000000000 --- a/src/lstate.h +++ /dev/null @@ -1,223 +0,0 @@ -/* -** $Id: lstate.h,v 2.119 2014/10/30 18:53:28 roberto Exp $ -** Global State -** See Copyright Notice in lua.h -*/ - -#ifndef lstate_h -#define lstate_h - -#include "lua.h" - -#include "lobject.h" -#include "ltm.h" -#include "lzio.h" - - -/* - -** Some notes about garbage-collected objects: All objects in Lua must -** be kept somehow accessible until being freed, so all objects always -** belong to one (and only one) of these lists, using field 'next' of -** the 'CommonHeader' for the link: -** -** 'allgc': all objects not marked for finalization; -** 'finobj': all objects marked for finalization; -** 'tobefnz': all objects ready to be finalized; -** 'fixedgc': all objects that are not to be collected (currently -** only small strings, such as reserved words). - -*/ - - -struct lua_longjmp; /* defined in ldo.c */ - - - -/* extra stack space to handle TM calls and some other extras */ -#define EXTRA_STACK 5 - - -#define BASIC_STACK_SIZE (2*LUA_MINSTACK) - - -/* kinds of Garbage Collection */ -#define KGC_NORMAL 0 -#define KGC_EMERGENCY 1 /* gc was forced by an allocation failure */ - - -typedef struct stringtable { - TString **hash; - int nuse; /* number of elements */ - int size; -} stringtable; - - -/* -** Information about a call. -** When a thread yields, 'func' is adjusted to pretend that the -** top function has only the yielded values in its stack; in that -** case, the actual 'func' value is saved in field 'extra'. -** When a function calls another with a continuation, 'extra' keeps -** the function index so that, in case of errors, the continuation -** function can be called with the correct top. -*/ -typedef struct CallInfo { - StkId func; /* function index in the stack */ - StkId top; /* top for this function */ - struct CallInfo *previous, *next; /* dynamic call link */ - union { - struct { /* only for Lua functions */ - StkId base; /* base for this function */ - const Instruction *savedpc; - } l; - struct { /* only for C functions */ - lua_KFunction k; /* continuation in case of yields */ - ptrdiff_t old_errfunc; - lua_KContext ctx; /* context info. in case of yields */ - } c; - } u; - ptrdiff_t extra; - short nresults; /* expected number of results from this function */ - lu_byte callstatus; -} CallInfo; - - -/* -** Bits in CallInfo status -*/ -#define CIST_OAH (1<<0) /* original value of 'allowhook' */ -#define CIST_LUA (1<<1) /* call is running a Lua function */ -#define CIST_HOOKED (1<<2) /* call is running a debug hook */ -#define CIST_REENTRY (1<<3) /* call is running on same invocation of - luaV_execute of previous call */ -#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */ -#define CIST_TAIL (1<<5) /* call was tail called */ -#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ - -#define isLua(ci) ((ci)->callstatus & CIST_LUA) - -/* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */ -#define setoah(st,v) ((st) = ((st) & ~CIST_OAH) | (v)) -#define getoah(st) ((st) & CIST_OAH) - - -/* -** 'global state', shared by all threads of this state -*/ -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 - GCdebt */ - l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ - 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 */ - 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 */ - GCObject *allgc; /* list of all collectable objects */ - GCObject **sweepgc; /* current position of sweep in list */ - GCObject *finobj; /* list of collectable objects with finalizers */ - GCObject *gray; /* list of gray objects */ - GCObject *grayagain; /* list of objects to be traversed atomically */ - 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 */ - GCObject *fixedgc; /* list of objects not to be collected */ - struct lua_State *twups; /* list of threads with open upvalues */ - Mbuffer buff; /* temporary buffer for string concatenation */ - unsigned int gcfinnum; /* number of finalizers to call in each GC step */ - int gcpause; /* size of pause between successive GCs */ - int gcstepmul; /* GC 'granularity' */ - lua_CFunction panic; /* to be called in unprotected errors */ - struct lua_State *mainthread; - const lua_Number *version; /* pointer to version number */ - 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; - - -/* -** 'per thread' state -*/ -struct lua_State { - CommonHeader; - lu_byte status; - StkId top; /* first free slot in the stack */ - global_State *l_G; - CallInfo *ci; /* call info for current function */ - const Instruction *oldpc; /* last pc traced */ - StkId stack_last; /* last free slot in the stack */ - StkId stack; /* stack base */ - UpVal *openupval; /* list of open upvalues in this stack */ - GCObject *gclist; - struct lua_State *twups; /* list of threads with open upvalues */ - struct lua_longjmp *errorJmp; /* current error recover point */ - CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ - lua_Hook hook; - ptrdiff_t errfunc; /* current error handling function (stack index) */ - int stacksize; - int basehookcount; - int hookcount; - unsigned short nny; /* number of non-yieldable calls in stack */ - unsigned short nCcalls; /* number of nested C calls */ - lu_byte hookmask; - lu_byte allowhook; -}; - - -#define G(L) (L->l_G) - - -/* -** Union of all collectable objects (only for conversions) -*/ -union GCUnion { - GCObject gc; /* common header */ - struct TString ts; - struct Udata u; - union Closure cl; - struct Table h; - struct Proto p; - struct lua_State th; /* thread */ -}; - - -#define cast_u(o) cast(union GCUnion *, (o)) - -/* macros to convert a GCObject into a specific value */ -#define gco2ts(o) \ - check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts)) -#define gco2u(o) check_exp((o)->tt == LUA_TUSERDATA, &((cast_u(o))->u)) -#define gco2lcl(o) check_exp((o)->tt == LUA_TLCL, &((cast_u(o))->cl.l)) -#define gco2ccl(o) check_exp((o)->tt == LUA_TCCL, &((cast_u(o))->cl.c)) -#define gco2cl(o) \ - check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl)) -#define gco2t(o) check_exp((o)->tt == LUA_TTABLE, &((cast_u(o))->h)) -#define gco2p(o) check_exp((o)->tt == LUA_TPROTO, &((cast_u(o))->p)) -#define gco2th(o) check_exp((o)->tt == LUA_TTHREAD, &((cast_u(o))->th)) - - -/* macro to convert a Lua object into a GCObject */ -#define obj2gco(v) \ - check_exp(novariant((v)->tt) < LUA_TDEADKEY, (&(cast_u(v)->gc))) - - -/* 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); -LUAI_FUNC void luaE_shrinkCI (lua_State *L); - - -#endif - diff --git a/src/lstring.c b/src/lstring.c deleted file mode 100644 index 2947113c3c..0000000000 --- a/src/lstring.c +++ /dev/null @@ -1,182 +0,0 @@ -/* -** $Id: lstring.c,v 2.45 2014/11/02 19:19:04 roberto Exp $ -** String table (keeps all strings handled by Lua) -** See Copyright Notice in lua.h -*/ - -#define lstring_c -#define LUA_CORE - -#include "lprefix.h" - - -#include - -#include "lua.h" - -#include "ldebug.h" -#include "ldo.h" -#include "lmem.h" -#include "lobject.h" -#include "lstate.h" -#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->len; - lua_assert(a->tt == LUA_TLNGSTR && b->tt == LUA_TLNGSTR); - return (a == b) || /* same instance or... */ - ((len == b->len) && /* equal length and ... */ - (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ -} - - -unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) { - 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) - h = h ^ ((h<<5) + (h>>2) + cast_byte(str[l1 - 1])); - return h; -} - - -/* -** resizes the string table -*/ -void luaS_resize (lua_State *L, int newsize) { - int i; - stringtable *tb = &G(L)->strt; - if (newsize > tb->size) { /* grow table if needed */ - luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *); - for (i = tb->size; i < newsize; i++) - tb->hash[i] = NULL; - } - for (i = 0; i < tb->size; i++) { /* rehash */ - TString *p = tb->hash[i]; - tb->hash[i] = NULL; - while (p) { /* for each node in the list */ - TString *hnext = p->hnext; /* save next */ - unsigned int h = lmod(p->hash, newsize); /* new position */ - p->hnext = tb->hash[h]; /* chain it */ - tb->hash[h] = p; - p = hnext; - } - } - if (newsize < tb->size) { /* shrink table if needed */ - /* vanishing slice should be empty */ - lua_assert(tb->hash[newsize] == NULL && tb->hash[tb->size - 1] == NULL); - luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *); - } - tb->size = newsize; -} - - - -/* -** creates a new string object -*/ -static TString *createstrobj (lua_State *L, const char *str, size_t l, - int tag, unsigned int h) { - TString *ts; - GCObject *o; - size_t totalsize; /* total size of TString object */ - totalsize = sizelstring(l); - o = luaC_newobj(L, tag, totalsize); - ts = gco2ts(o); - ts->len = l; - ts->hash = h; - ts->extra = 0; - memcpy(getaddrstr(ts), str, l * sizeof(char)); - getaddrstr(ts)[l] = '\0'; /* ending 0 */ - return ts; -} - - -void luaS_remove (lua_State *L, TString *ts) { - stringtable *tb = &G(L)->strt; - TString **p = &tb->hash[lmod(ts->hash, tb->size)]; - while (*p != ts) /* find previous element */ - p = &(*p)->hnext; - *p = (*p)->hnext; /* remove element from its list */ - tb->nuse--; -} - - -/* -** checks whether short string exists and reuses it or creates a new one -*/ -static TString *internshrstr (lua_State *L, const char *str, size_t l) { - TString *ts; - global_State *g = G(L); - unsigned int h = luaS_hash(str, l, g->seed); - TString **list = &g->strt.hash[lmod(h, g->strt.size)]; - for (ts = *list; ts != NULL; ts = ts->hnext) { - if (l == ts->len && - (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { - /* found! */ - if (isdead(g, ts)) /* dead (but not collected yet)? */ - changewhite(ts); /* resurrect it */ - return ts; - } - } - if (g->strt.nuse >= g->strt.size && g->strt.size <= MAX_INT/2) { - luaS_resize(L, g->strt.size * 2); - list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */ - } - ts = createstrobj(L, str, l, LUA_TSHRSTR, h); - ts->hnext = *list; - *list = ts; - g->strt.nuse++; - return ts; -} - - -/* -** new string (with explicit length) -*/ -TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { - if (l <= LUAI_MAXSHORTLEN) /* short string? */ - return internshrstr(L, str, l); - else { - if (l + 1 > (MAX_SIZE - sizeof(TString))/sizeof(char)) - luaM_toobig(L); - return createstrobj(L, str, l, LUA_TLNGSTR, G(L)->seed); - } -} - - -/* -** new zero-terminated string -*/ -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) { - Udata *u; - GCObject *o; - if (s > MAX_SIZE - sizeof(Udata)) - luaM_toobig(L); - o = luaC_newobj(L, LUA_TUSERDATA, sizeludata(s)); - u = gco2u(o); - u->len = s; - u->metatable = NULL; - setuservalue(L, u, luaO_nilobject); - return u; -} - diff --git a/src/lstring.h b/src/lstring.h deleted file mode 100644 index d3f04caf72..0000000000 --- a/src/lstring.h +++ /dev/null @@ -1,46 +0,0 @@ -/* -** $Id: lstring.h,v 1.56 2014/07/18 14:46:47 roberto Exp $ -** String table (keep all strings handled by Lua) -** See Copyright Notice in lua.h -*/ - -#ifndef lstring_h -#define lstring_h - -#include "lgc.h" -#include "lobject.h" -#include "lstate.h" - - -#define sizelstring(l) (sizeof(union UTString) + ((l) + 1) * sizeof(char)) -#define sizestring(s) sizelstring((s)->len) - -#define sizeludata(l) (sizeof(union UUdata) + (l)) -#define sizeudata(u) sizeludata((u)->len) - -#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ - (sizeof(s)/sizeof(char))-1)) - - -/* -** test whether a string is a reserved word -*/ -#define isreserved(s) ((s)->tt == LUA_TSHRSTR && (s)->extra > 0) - - -/* -** equality for short strings, which are always internalized -*/ -#define eqshrstr(a,b) check_exp((a)->tt == LUA_TSHRSTR, (a) == (b)) - - -LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed); -LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); -LUAI_FUNC void luaS_resize (lua_State *L, int newsize); -LUAI_FUNC void luaS_remove (lua_State *L, TString *ts); -LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s); -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 deleted file mode 100644 index a650b768d5..0000000000 --- a/src/lstrlib.c +++ /dev/null @@ -1,1430 +0,0 @@ -/* -** $Id: lstrlib.c,v 1.221 2014/12/11 14:03:07 roberto Exp $ -** Standard library for string operations and pattern-matching -** See Copyright Notice in lua.h -*/ - -#define lstrlib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include -#include -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#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)) - - -/* -** Some sizes are better limited to fit in 'int', but must also fit in -** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.) -*/ -#define MAXSIZE \ - (sizeof(size_t) < sizeof(int) ? (~(size_t)0) : (size_t)(INT_MAX)) - - - - -static int str_len (lua_State *L) { - size_t l; - luaL_checklstring(L, 1, &l); - lua_pushinteger(L, (lua_Integer)l); - return 1; -} - - -/* translate a relative string position: negative means back from end */ -static lua_Integer posrelat (lua_Integer pos, size_t len) { - if (pos >= 0) return pos; - else if (0u - (size_t)pos > len) return 0; - else return (lua_Integer)len + pos + 1; -} - - -static int str_sub (lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - lua_Integer start = posrelat(luaL_checkinteger(L, 2), l); - lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l); - if (start < 1) start = 1; - if (end > (lua_Integer)l) end = l; - if (start <= end) - lua_pushlstring(L, s + start - 1, (size_t)(end - start + 1)); - else lua_pushliteral(L, ""); - return 1; -} - - -static int str_reverse (lua_State *L) { - size_t l, i; - luaL_Buffer b; - const char *s = luaL_checklstring(L, 1, &l); - 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; -} - - -static int str_lower (lua_State *L) { - size_t l; - size_t i; - luaL_Buffer b; - const char *s = luaL_checklstring(L, 1, &l); - char *p = luaL_buffinitsize(L, &b, l); - for (i=0; i MAXSIZE / n) /* may overflow? */ - return luaL_error(L, "resulting string too large"); - else { - size_t totallen = (size_t)n * l + (size_t)(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; - if (lsep > 0) { /* empty 'memcpy' is not that cheap */ - 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; -} - - -static int str_byte (lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l); - lua_Integer pose = posrelat(luaL_optinteger(L, 3, posi), l); - int n, i; - if (posi < 1) posi = 1; - if (pose > (lua_Integer)l) pose = l; - if (posi > pose) return 0; /* empty interval; return no values */ - n = (int)(pose - posi + 1); - if (posi + n <= pose) /* arithmetic overflow? */ - return luaL_error(L, "string slice too long"); - luaL_checkstack(L, n, "string slice too long"); - for (i=0; i= ms->level || ms->capture[l].len == CAP_UNFINISHED) - return luaL_error(ms->L, "invalid capture index %%%d", l + 1); - return l; -} - - -static int capture_to_close (MatchState *ms) { - int level = ms->level; - for (level--; level>=0; level--) - if (ms->capture[level].len == CAP_UNFINISHED) return level; - return luaL_error(ms->L, "invalid pattern capture"); -} - - -static const char *classend (MatchState *ms, const char *p) { - switch (*p++) { - case L_ESC: { - if (p == ms->p_end) - luaL_error(ms->L, "malformed pattern (ends with '%%')"); - return p+1; - } - case '[': { - if (*p == '^') p++; - do { /* look for a ']' */ - if (p == ms->p_end) - luaL_error(ms->L, "malformed pattern (missing ']')"); - if (*(p++) == L_ESC && p < ms->p_end) - p++; /* skip escapes (e.g. '%]') */ - } while (*p != ']'); - return p+1; - } - default: { - return p; - } - } -} - - -static int match_class (int c, int cl) { - int res; - switch (tolower(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; - case 'u' : res = isupper(c); break; - case 'w' : res = isalnum(c); break; - case 'x' : res = isxdigit(c); break; - case 'z' : res = (c == 0); break; /* deprecated option */ - default: return (cl == c); - } - return (islower(cl) ? res : !res); -} - - -static int matchbracketclass (int c, const char *p, const char *ec) { - int sig = 1; - if (*(p+1) == '^') { - sig = 0; - p++; /* skip the '^' */ - } - while (++p < ec) { - if (*p == L_ESC) { - p++; - if (match_class(c, uchar(*p))) - return sig; - } - else if ((*(p+1) == '-') && (p+2 < ec)) { - p+=2; - if (uchar(*(p-2)) <= c && c <= uchar(*p)) - return sig; - } - else if (uchar(*p) == c) return sig; - } - return !sig; -} - - -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 *matchbalance (MatchState *ms, const char *s, - const char *p) { - if (p >= ms->p_end - 1) - luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')"); - if (*s != *p) return NULL; - else { - int b = *p; - int e = *(p+1); - int cont = 1; - while (++s < ms->src_end) { - if (*s == e) { - if (--cont == 0) return s+1; - } - else if (*s == b) cont++; - } - } - return NULL; /* string ends out of balance */ -} - - -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 (singlematch(ms, s + i, p, ep)) - i++; - /* keeps trying to match with the maximum repetitions */ - while (i>=0) { - const char *res = match(ms, (s+i), ep+1); - if (res) return res; - i--; /* else didn't match; reduce 1 repetition to try again */ - } - return NULL; -} - - -static const char *min_expand (MatchState *ms, const char *s, - const char *p, const char *ep) { - for (;;) { - const char *res = match(ms, s, ep+1); - if (res != NULL) - return res; - else if (singlematch(ms, s, p, ep)) - s++; /* try with one more repetition */ - else return NULL; - } -} - - -static const char *start_capture (MatchState *ms, const char *s, - const char *p, int what) { - const char *res; - int level = ms->level; - 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; - if ((res=match(ms, s, p)) == NULL) /* match failed? */ - ms->level--; /* undo capture */ - return res; -} - - -static const char *end_capture (MatchState *ms, const char *s, - const char *p) { - int l = capture_to_close(ms); - const char *res; - 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 (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 (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? */ - 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; - } - 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 '[' after '%%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; - } - 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 */ - } - 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; -} - - - -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 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 %%%d", i + 1); - } - 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; - 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 */ -} - - -/* check whether pattern has no special characters */ -static int nospecials (const char *p, size_t l) { - size_t upto = 0; - do { - if (strpbrk(p + upto, SPECIALS)) - return 0; /* pattern has a special character */ - upto += strlen(p + upto) + 1; /* may have more after \0 */ - } while (upto <= l); - return 1; /* no special chars found */ -} - - -static int str_find_aux (lua_State *L, int find) { - size_t ls, lp; - const char *s = luaL_checklstring(L, 1, &ls); - const char *p = luaL_checklstring(L, 2, &lp); - lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls); - if (init < 1) init = 1; - else if (init > (lua_Integer)ls + 1) { /* start after string's end? */ - lua_pushnil(L); /* cannot find anything */ - return 1; - } - /* explicit request or no special characters? */ - if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { - /* do a plain search */ - const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp); - if (s2) { - lua_pushinteger(L, s2 - s + 1); - lua_pushinteger(L, s2 - s + lp); - return 2; - } - } - else { - MatchState ms; - const char *s1 = s + init - 1; - int anchor = (*p == '^'); - if (anchor) { - 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 */ - lua_pushinteger(L, res - s); /* end */ - return push_captures(&ms, NULL, 0) + 2; - } - else - return push_captures(&ms, s1, res); - } - } while (s1++ < ms.src_end && !anchor); - } - lua_pushnil(L); /* not found */ - return 1; -} - - -static int str_find (lua_State *L) { - return str_find_aux(L, 1); -} - - -static int str_match (lua_State *L) { - return str_find_aux(L, 0); -} - - -static int gmatch_aux (lua_State *L) { - MatchState ms; - size_t ls, lp; - const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); - 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; - for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); - src <= ms.src_end; - 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 */ - lua_pushinteger(L, newstart); - lua_replace(L, lua_upvalueindex(3)); - return push_captures(&ms, src, e); - } - } - return 0; /* not found */ -} - - -static int gmatch (lua_State *L) { - luaL_checkstring(L, 1); - luaL_checkstring(L, 2); - lua_settop(L, 2); - lua_pushinteger(L, 0); - lua_pushcclosure(L, gmatch_aux, 3); - return 1; -} - - -static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, - const char *e) { - size_t l, i; - lua_State *L = ms->L; - const char *news = lua_tolstring(L, 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]))) { - if (news[i] != L_ESC) - luaL_error(L, "invalid use of '%c' in replacement string", L_ESC); - luaL_addchar(b, news[i]); - } - else if (news[i] == '0') - luaL_addlstring(b, s, e - s); - else { - push_onecapture(ms, news[i] - '1', s, e); - luaL_tolstring(L, -1, NULL); /* if number, convert it to string */ - lua_remove(L, -2); /* remove original value */ - luaL_addvalue(b); /* add capture to accumulated result */ - } - } - } -} - - -static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, - const char *e, int tr) { - lua_State *L = ms->L; - switch (tr) { - 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: { /* 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_addvalue(b); /* add result to accumulator */ -} - - -static int str_gsub (lua_State *L) { - size_t srcl, lp; - const char *src = luaL_checklstring(L, 1, &srcl); - const char *p = luaL_checklstring(L, 2, &lp); - int tr = lua_type(L, 3); - lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); - int anchor = (*p == '^'); - lua_Integer 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); - if (anchor) { - 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++; - add_value(&ms, &b, src, e, tr); - } - if (e && e>src) /* non empty match? */ - src = e; /* skip it */ - else if (src < ms.src_end) - luaL_addchar(&b, *src++); - else break; - if (anchor) break; - } - luaL_addlstring(&b, src, ms.src_end-src); - luaL_pushresult(&b); - lua_pushinteger(L, n); /* number of substitutions */ - return 2; -} - -/* }====================================================== */ - - - -/* -** {====================================================== -** STRING FORMAT -** ======================================================= -*/ - -/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ -#define MAX_ITEM 512 - -/* valid flags in a format specification */ -#define FLAGS "-+ #0" - -/* -** maximum size of each format specification (such as "%-099.99d") -** (+2 for length modifiers; +10 accounts for %99.99x plus margin of error) -*/ -#define MAX_FORMAT (sizeof(FLAGS) + 2 + 10) - - -static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { - size_t l; - const char *s = luaL_checklstring(L, arg, &l); - luaL_addchar(b, '"'); - while (l--) { - if (*s == '"' || *s == '\\' || *s == '\n') { - luaL_addchar(b, '\\'); - luaL_addchar(b, *s); - } - else if (*s == '\0' || iscntrl(uchar(*s))) { - char buff[10]; - if (!isdigit(uchar(*(s+1)))) - sprintf(buff, "\\%d", (int)uchar(*s)); - else - sprintf(buff, "\\%03d", (int)uchar(*s)); - luaL_addstring(b, buff); - } - else - luaL_addchar(b, *s); - s++; - } - luaL_addchar(b, '"'); -} - -static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { - const char *p = strfrmt; - while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip 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) */ - if (*p == '.') { - p++; - 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)"); - *(form++) = '%'; - memcpy(form, strfrmt, (p - strfrmt + 1) * sizeof(char)); - form += p - strfrmt + 1; - *form = '\0'; - return p; -} - - -/* -** add length modifier into formats -*/ -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, lenmod); - form[l + lm - 1] = spec; - form[l + lm] = '\0'; -} - - -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); - const char *strfrmt_end = strfrmt+sfl; - luaL_Buffer b; - luaL_buffinit(L, &b); - while (strfrmt < strfrmt_end) { - if (*strfrmt != L_ESC) - luaL_addchar(&b, *strfrmt++); - else if (*++strfrmt == L_ESC) - luaL_addchar(&b, *strfrmt++); /* %% */ - else { /* format item */ - char form[MAX_FORMAT]; /* to store the format ('%...') */ - 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': { - nb = sprintf(buff, form, (int)luaL_checkinteger(L, arg)); - break; - } - case 'd': case 'i': - case 'o': case 'u': case 'x': case 'X': { - lua_Integer n = luaL_checkinteger(L, arg); - addlenmod(form, LUA_INTEGER_FRMLEN); - nb = sprintf(buff, form, n); - break; - } -#if defined(LUA_USE_AFORMAT) - case 'a': case 'A': -#endif - case 'e': case 'E': case 'f': - case 'g': case 'G': { - addlenmod(form, LUA_NUMBER_FRMLEN); - nb = sprintf(buff, form, luaL_checknumber(L, arg)); - break; - } - case 'q': { - addquoted(L, &b, arg); - break; - } - case 's': { - size_t 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 */ - luaL_addvalue(&b); - break; - } - else { - nb = sprintf(buff, form, s); - lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ - break; - } - } - default: { /* also treat cases 'pnLlh' */ - return luaL_error(L, "invalid option '%%%c' to 'format'", - *(strfrmt - 1)); - } - } - luaL_addsize(&b, nb); - } - } - luaL_pushresult(&b); - return 1; -} - -/* }====================================================== */ - - -/* -** {====================================================== -** PACK/UNPACK -** ======================================================= -*/ - - -/* value used for padding */ -#if !defined(LUA_PACKPADBYTE) -#define LUA_PACKPADBYTE 0x00 -#endif - -/* maximum size for the binary representation of an integer */ -#define MAXINTSIZE 16 - -/* number of bits in a character */ -#define NB CHAR_BIT - -/* mask for one character (NB 1's) */ -#define MC ((1 << NB) - 1) - -/* size of a lua_Integer */ -#define SZINT ((int)sizeof(lua_Integer)) - - -/* dummy union to get native endianness */ -static const union { - int dummy; - char little; /* true iff machine is little endian */ -} nativeendian = {1}; - - -/* dummy structure to get native alignment requirements */ -struct cD { - char c; - union { double d; void *p; lua_Integer i; lua_Number n; } u; -}; - -#define MAXALIGN (offsetof(struct cD, u)) - - -/* -** Union for serializing floats -*/ -typedef union Ftypes { - float f; - double d; - lua_Number n; - char buff[5 * sizeof(lua_Number)]; /* enough for any float type */ -} Ftypes; - - -/* -** information to pack/unpack stuff -*/ -typedef struct Header { - lua_State *L; - int islittle; - int maxalign; -} Header; - - -/* -** options for pack/unpack -*/ -typedef enum KOption { - Kint, /* signed integers */ - Kuint, /* unsigned integers */ - Kfloat, /* floating-point numbers */ - Kchar, /* fixed-length strings */ - Kstring, /* strings with prefixed length */ - Kzstr, /* zero-terminated strings */ - Kpadding, /* padding */ - Kpaddalign, /* padding for alignment */ - Knop /* no-op (configuration or spaces) */ -} KOption; - - -/* -** Read an integer numeral from string 'fmt' or return 'df' if -** there is no numeral -*/ -static int digit (int c) { return '0' <= c && c <= '9'; } - -static int getnum (const char **fmt, int df) { - if (!digit(**fmt)) /* no number? */ - return df; /* return default value */ - else { - int a = 0; - do { - a = a*10 + (*((*fmt)++) - '0'); - } while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10); - return a; - } -} - - -/* -** Read an integer numeral and raises an error if it is larger -** than the maximum size for integers. -*/ -static int getnumlimit (Header *h, const char **fmt, int df) { - int sz = getnum(fmt, df); - if (sz > MAXINTSIZE || sz <= 0) - luaL_error(h->L, "integral size (%d) out of limits [1,%d]", - sz, MAXINTSIZE); - return sz; -} - - -/* -** Initialize Header -*/ -static void initheader (lua_State *L, Header *h) { - h->L = L; - h->islittle = nativeendian.little; - h->maxalign = 1; -} - - -/* -** Read and classify next option. 'size' is filled with option's size. -*/ -static KOption getoption (Header *h, const char **fmt, int *size) { - int opt = *((*fmt)++); - *size = 0; /* default */ - switch (opt) { - case 'b': *size = sizeof(char); return Kint; - case 'B': *size = sizeof(char); return Kuint; - case 'h': *size = sizeof(short); return Kint; - case 'H': *size = sizeof(short); return Kuint; - case 'l': *size = sizeof(long); return Kint; - case 'L': *size = sizeof(long); return Kuint; - case 'j': *size = sizeof(lua_Integer); return Kint; - case 'J': *size = sizeof(lua_Integer); return Kuint; - case 'T': *size = sizeof(size_t); return Kuint; - case 'f': *size = sizeof(float); return Kfloat; - case 'd': *size = sizeof(double); return Kfloat; - case 'n': *size = sizeof(lua_Number); return Kfloat; - case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint; - case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; - case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; - case 'c': - *size = getnum(fmt, -1); - if (*size == -1) - luaL_error(h->L, "missing size for format option 'c'"); - return Kchar; - case 'z': return Kzstr; - case 'x': *size = 1; return Kpadding; - case 'X': return Kpaddalign; - case ' ': break; - case '<': h->islittle = 1; break; - case '>': h->islittle = 0; break; - case '=': h->islittle = nativeendian.little; break; - case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break; - default: luaL_error(h->L, "invalid format option '%c'", opt); - } - return Knop; -} - - -/* -** Read, classify, and fill other details about the next option. -** 'psize' is filled with option's size, 'notoalign' with its -** alignment requirements. -** Local variable 'size' gets the size to be aligned. (Kpadal option -** always gets its full alignment, other options are limited by -** the maximum alignment ('maxalign'). Kchar option needs no alignment -** despite its size. -*/ -static KOption getdetails (Header *h, size_t totalsize, - const char **fmt, int *psize, int *ntoalign) { - KOption opt = getoption(h, fmt, psize); - int align = *psize; /* usually, alignment follows size */ - if (opt == Kpaddalign) { /* 'X' gets alignment from following option */ - if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0) - luaL_argerror(h->L, 1, "invalid next option for option 'X'"); - } - if (align <= 1 || opt == Kchar) /* need no alignment? */ - *ntoalign = 0; - else { - if (align > h->maxalign) /* enforce maximum alignment */ - align = h->maxalign; - if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */ - luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); - *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1); - } - return opt; -} - - -/* -** Pack integer 'n' with 'size' bytes and 'islittle' endianness. -** The final 'if' handles the case when 'size' is larger than -** the size of a Lua integer, correcting the extra sign-extension -** bytes if necessary (by default they would be zeros). -*/ -static void packint (luaL_Buffer *b, lua_Unsigned n, - int islittle, int size, int neg) { - char *buff = luaL_prepbuffsize(b, size); - int i; - buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */ - for (i = 1; i < size; i++) { - n >>= NB; - buff[islittle ? i : size - 1 - i] = (char)(n & MC); - } - if (neg && size > SZINT) { /* negative number need sign extension? */ - for (i = SZINT; i < size; i++) /* correct extra bytes */ - buff[islittle ? i : size - 1 - i] = (char)MC; - } - luaL_addsize(b, size); /* add result to buffer */ -} - - -/* -** Copy 'size' bytes from 'src' to 'dest', correcting endianness if -** given 'islittle' is different from native endianness. -*/ -static void copywithendian (volatile char *dest, volatile const char *src, - int size, int islittle) { - if (islittle == nativeendian.little) { - while (size-- != 0) - *(dest++) = *(src++); - } - else { - dest += size - 1; - while (size-- != 0) - *(dest--) = *(src++); - } -} - - -static int str_pack (lua_State *L) { - luaL_Buffer b; - Header h; - const char *fmt = luaL_checkstring(L, 1); /* format string */ - int arg = 1; /* current argument to pack */ - size_t totalsize = 0; /* accumulate total size of result */ - initheader(L, &h); - lua_pushnil(L); /* mark to separate arguments from string buffer */ - luaL_buffinit(L, &b); - while (*fmt != '\0') { - int size, ntoalign; - KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); - totalsize += ntoalign + size; - while (ntoalign-- > 0) - luaL_addchar(&b, LUA_PACKPADBYTE); /* fill alignment */ - arg++; - switch (opt) { - case Kint: { /* signed integers */ - lua_Integer n = luaL_checkinteger(L, arg); - if (size < SZINT) { /* need overflow check? */ - lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1); - luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow"); - } - packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0)); - break; - } - case Kuint: { /* unsigned integers */ - lua_Integer n = luaL_checkinteger(L, arg); - if (size < SZINT) /* need overflow check? */ - luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)), - arg, "unsigned overflow"); - packint(&b, (lua_Unsigned)n, h.islittle, size, 0); - break; - } - case Kfloat: { /* floating-point options */ - volatile Ftypes u; - char *buff = luaL_prepbuffsize(&b, size); - lua_Number n = luaL_checknumber(L, arg); /* get argument */ - if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */ - else if (size == sizeof(u.d)) u.d = (double)n; - else u.n = n; - /* move 'u' to final result, correcting endianness if needed */ - copywithendian(buff, u.buff, size, h.islittle); - luaL_addsize(&b, size); - break; - } - case Kchar: { /* fixed-size string */ - size_t len; - const char *s = luaL_checklstring(L, arg, &len); - luaL_argcheck(L, len == (size_t)size, arg, "wrong length"); - luaL_addlstring(&b, s, size); - break; - } - case Kstring: { /* strings with length count */ - size_t len; - const char *s = luaL_checklstring(L, arg, &len); - luaL_argcheck(L, size >= (int)sizeof(size_t) || - len < ((size_t)1 << (size * NB)), - arg, "string length does not fit in given size"); - packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */ - luaL_addlstring(&b, s, len); - totalsize += len; - break; - } - case Kzstr: { /* zero-terminated string */ - size_t len; - const char *s = luaL_checklstring(L, arg, &len); - luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros"); - luaL_addlstring(&b, s, len); - luaL_addchar(&b, '\0'); /* add zero at the end */ - totalsize += len + 1; - break; - } - case Kpadding: luaL_addchar(&b, LUA_PACKPADBYTE); /* go through */ - case Kpaddalign: case Knop: - arg--; /* undo increment */ - break; - } - } - luaL_pushresult(&b); - return 1; -} - - -static int str_packsize (lua_State *L) { - Header h; - const char *fmt = luaL_checkstring(L, 1); /* format string */ - size_t totalsize = 0; /* accumulate total size of result */ - initheader(L, &h); - while (*fmt != '\0') { - int size, ntoalign; - KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); - size += ntoalign; /* total space used by option */ - luaL_argcheck(L, totalsize <= MAXSIZE - size, 1, - "format result too large"); - totalsize += size; - switch (opt) { - case Kstring: /* strings with length count */ - case Kzstr: /* zero-terminated string */ - luaL_argerror(L, 1, "variable-length format"); - break; - default: break; - } - } - lua_pushinteger(L, (lua_Integer)totalsize); - return 1; -} - - -/* -** Unpack an integer with 'size' bytes and 'islittle' endianness. -** If size is smaller than the size of a Lua integer and integer -** is signed, must do sign extension (propagating the sign to the -** higher bits); if size is larger than the size of a Lua integer, -** it must check the unread bytes to see whether they do not cause an -** overflow. -*/ -static lua_Integer unpackint (lua_State *L, const char *str, - int islittle, int size, int issigned) { - lua_Unsigned res = 0; - int i; - int limit = (size <= SZINT) ? size : SZINT; - for (i = limit - 1; i >= 0; i--) { - res <<= NB; - res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i]; - } - if (size < SZINT) { /* real size smaller than lua_Integer? */ - if (issigned) { /* needs sign extension? */ - lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1); - res = ((res ^ mask) - mask); /* do sign extension */ - } - } - else if (size > SZINT) { /* must check unread bytes */ - int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; - for (i = limit; i < size; i++) { - if ((unsigned char)str[islittle ? i : size - 1 - i] != mask) - luaL_error(L, "%d-byte integer does not fit into Lua Integer", size); - } - } - return (lua_Integer)res; -} - - -static int str_unpack (lua_State *L) { - Header h; - const char *fmt = luaL_checkstring(L, 1); - size_t ld; - const char *data = luaL_checklstring(L, 2, &ld); - size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; - int n = 0; /* number of results */ - luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); - initheader(L, &h); - while (*fmt != '\0') { - int size, ntoalign; - KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); - if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld) - luaL_argerror(L, 2, "data string too short"); - pos += ntoalign; /* skip alignment */ - /* stack space for item + next position */ - luaL_checkstack(L, 2, "too many results"); - n++; - switch (opt) { - case Kint: - case Kuint: { - lua_Integer res = unpackint(L, data + pos, h.islittle, size, - (opt == Kint)); - lua_pushinteger(L, res); - break; - } - case Kfloat: { - volatile Ftypes u; - lua_Number num; - copywithendian(u.buff, data + pos, size, h.islittle); - if (size == sizeof(u.f)) num = (lua_Number)u.f; - else if (size == sizeof(u.d)) num = (lua_Number)u.d; - else num = u.n; - lua_pushnumber(L, num); - break; - } - case Kchar: { - lua_pushlstring(L, data + pos, size); - break; - } - case Kstring: { - size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0); - luaL_argcheck(L, pos + len + size <= ld, 2, "data string too short"); - lua_pushlstring(L, data + pos + size, len); - pos += len; /* skip string */ - break; - } - case Kzstr: { - size_t len = (int)strlen(data + pos); - lua_pushlstring(L, data + pos, len); - pos += len + 1; /* skip string plus final '\0' */ - break; - } - case Kpaddalign: case Kpadding: case Knop: - n--; /* undo increment */ - break; - } - pos += size; - } - lua_pushinteger(L, pos + 1); /* next position */ - return n + 1; -} - -/* }====================================================== */ - - -static const luaL_Reg strlib[] = { - {"byte", str_byte}, - {"char", str_char}, - {"dump", str_dump}, - {"find", str_find}, - {"format", str_format}, - {"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}, - {"pack", str_pack}, - {"packsize", str_packsize}, - {"unpack", str_unpack}, - {NULL, NULL} -}; - - -static void createmetatable (lua_State *L) { - lua_createtable(L, 0, 1); /* table to be metatable for strings */ - lua_pushliteral(L, ""); /* dummy string */ - lua_pushvalue(L, -2); /* copy table */ - lua_setmetatable(L, -2); /* set table as metatable for strings */ - lua_pop(L, 1); /* pop dummy string */ - lua_pushvalue(L, -2); /* get string library */ - lua_setfield(L, -2, "__index"); /* metatable.__index = string */ - lua_pop(L, 1); /* pop metatable */ -} - - -/* -** Open string library -*/ -LUAMOD_API int luaopen_string (lua_State *L) { - luaL_newlib(L, strlib); - createmetatable(L); - return 1; -} - diff --git a/src/ltable.c b/src/ltable.c deleted file mode 100644 index e8ef146cea..0000000000 --- a/src/ltable.c +++ /dev/null @@ -1,650 +0,0 @@ -/* -** $Id: ltable.c,v 2.99 2014/11/02 19:19:04 roberto Exp $ -** Lua tables (hash) -** See Copyright Notice in lua.h -*/ - -#define ltable_c -#define LUA_CORE - -#include "lprefix.h" - - -/* -** 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. -** Hence even when the load factor reaches 100%, performance remains good. -*/ - -#include -#include -#include -#include - -#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" -#include "lvm.h" - - -/* -** Maximum size of array part (MAXASIZE) is 2^MAXABITS. MAXABITS is -** the largest integer such that MAXASIZE fits in an unsigned int. -*/ -#define MAXABITS cast_int(sizeof(int) * CHAR_BIT - 1) -#define MAXASIZE (1u << MAXABITS) - -/* -** Maximum size of hash part is 2^MAXHBITS. MAXHBITS is the largest -** integer such that 2^MAXHBITS fits in a signed int. (Note that the -** maximum number of elements in a table, 2^MAXABITS + 2^MAXHBITS, still -** fits comfortably in an unsigned int.) -*/ -#define MAXHBITS (MAXABITS - 1) - - -#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) - -#define hashstr(t,str) hashpow2(t, (str)->hash) -#define hashboolean(t,p) hashpow2(t, p) -#define hashint(t,i) hashpow2(t, i) - - -/* -** 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, point2int(p)) - - -#define dummynode (&dummynode_) - -#define isdummy(n) ((n) == dummynode) - -static const Node dummynode_ = { - {NILCONSTANT}, /* value */ - {{NILCONSTANT, 0}} /* key */ -}; - - -/* -** Checks whether a float has a value representable as a lua_Integer -** (and does the conversion if so) -*/ -static int numisinteger (lua_Number x, lua_Integer *p) { - if ((x) == l_floor(x)) /* integral value? */ - return lua_numbertointeger(x, p); /* try as an integer */ - else return 0; -} - - -/* -** hash for floating-point numbers -*/ -static Node *hashfloat (const Table *t, lua_Number n) { - int i; - n = l_mathop(frexp)(n, &i) * cast_num(INT_MAX - DBL_MAX_EXP); - i += cast_int(n); - if (i < 0) { - if (cast(unsigned int, i) == 0u - i) /* use unsigned to avoid overflows */ - i = 0; /* handle INT_MIN */ - i = -i; /* must be a positive value */ - } - return hashmod(t, i); -} - - - -/* -** returns the 'main' position of an element in a table (that is, the index -** of its hash value) -*/ -static Node *mainposition (const Table *t, const TValue *key) { - switch (ttype(key)) { - case LUA_TNUMINT: - return hashint(t, ivalue(key)); - case LUA_TNUMFLT: - return hashfloat(t, fltvalue(key)); - case LUA_TSHRSTR: - return hashstr(t, tsvalue(key)); - case LUA_TLNGSTR: { - TString *s = tsvalue(key); - if (s->extra == 0) { /* no hash? */ - s->hash = luaS_hash(getstr(s), s->len, s->hash); - s->extra = 1; /* now it has its hash */ - } - return hashstr(t, tsvalue(key)); - } - case LUA_TBOOLEAN: - 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)); - } -} - - -/* -** returns the index for 'key' if 'key' is an appropriate key to live in -** the array part of the table, 0 otherwise. -*/ -static unsigned int arrayindex (const TValue *key) { - if (ttisinteger(key)) { - lua_Integer k = ivalue(key); - if (0 < k && (lua_Unsigned)k <= MAXASIZE) - return cast(unsigned int, k); /* 'key' is an appropriate array index */ - } - return 0; /* 'key' did not match some condition */ -} - - -/* -** 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 signaled by 0. -*/ -static unsigned int findindex (lua_State *L, Table *t, StkId key) { - unsigned int i; - if (ttisnil(key)) return 0; /* first iteration */ - i = arrayindex(key); - if (i != 0 && i <= t->sizearray) /* is 'key' inside array part? */ - return i; /* yes; that's the index */ - else { - int nx; - Node *n = mainposition(t, key); - for (;;) { /* check whether 'key' is somewhere in the chain */ - /* key may be dead already, but it is ok to use it in 'next' */ - if (luaV_rawequalobj(gkey(n), key) || - (ttisdeadkey(gkey(n)) && iscollectable(key) && - deadvalue(gkey(n)) == gcvalue(key))) { - i = cast_int(n - gnode(t, 0)); /* key index in hash table */ - /* hash elements are numbered after array ones */ - return (i + 1) + t->sizearray; - } - nx = gnext(n); - if (nx == 0) - luaG_runerror(L, "invalid key to 'next'"); /* key not found */ - else n += nx; - } - } -} - - -int luaH_next (lua_State *L, Table *t, StkId key) { - unsigned int i = findindex(L, t, key); /* find original element */ - for (; i < t->sizearray; i++) { /* try first array part */ - if (!ttisnil(&t->array[i])) { /* a non-nil value? */ - setivalue(key, i + 1); - setobj2s(L, key+1, &t->array[i]); - return 1; - } - } - for (i -= t->sizearray; cast_int(i) < sizenode(t); i++) { /* hash part */ - if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ - setobj2s(L, key, gkey(gnode(t, i))); - setobj2s(L, key+1, gval(gnode(t, i))); - return 1; - } - } - return 0; /* no more elements */ -} - - -/* -** {============================================================= -** Rehash -** ============================================================== -*/ - -/* -** Compute the optimal size for the array part of table 't'. 'nums' is a -** "count array" where 'nums[i]' is the number of integers in the table -** between 2^(i - 1) + 1 and 2^i. Put in '*narray' the optimal size, and -** return the number of elements that will go to that part. -*/ -static unsigned int computesizes (unsigned int nums[], unsigned int *narray) { - int i; - unsigned int twotoi; /* 2^i */ - unsigned int a = 0; /* number of elements smaller than 2^i */ - unsigned int na = 0; /* number of elements to go to array part */ - unsigned 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 > twotoi/2) { /* more than half elements present? */ - n = twotoi; /* optimal size (till now) */ - na = a; /* all elements up to '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, unsigned int *nums) { - unsigned int k = arrayindex(key); - if (k != 0) { /* is 'key' an appropriate array index? */ - nums[luaO_ceillog2(k)]++; /* count as such */ - return 1; - } - else - return 0; -} - - -static unsigned int numusearray (const Table *t, unsigned int *nums) { - int lg; - unsigned int ttlg; /* 2^lg */ - unsigned int ause = 0; /* summation of 'nums' */ - unsigned int i = 1; /* count to traverse all array keys */ - /* traverse each slice */ - for (lg = 0, ttlg = 1; lg <= MAXABITS; lg++, ttlg *= 2) { - unsigned int lc = 0; /* counter */ - unsigned int lim = ttlg; - if (lim > t->sizearray) { - lim = t->sizearray; /* adjust upper limit */ - if (i > lim) - break; /* no more elements to count */ - } - /* 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; - } - return ause; -} - - -static int numusehash (const Table *t, unsigned int *nums, - unsigned int *pnasize) { - int totaluse = 0; /* total number of elements */ - int ause = 0; /* elements added to 'nums' (can go to array part) */ - int i = sizenode(t); - while (i--) { - Node *n = &t->node[i]; - if (!ttisnil(gval(n))) { - ause += countint(gkey(n), nums); - totaluse++; - } - } - *pnasize += ause; - return totaluse; -} - - -static void setarrayvector (lua_State *L, Table *t, unsigned int size) { - unsigned int i; - luaM_reallocvector(L, t->array, t->sizearray, size, TValue); - for (i=t->sizearray; iarray[i]); - t->sizearray = size; -} - - -static void setnodevector (lua_State *L, Table *t, unsigned int size) { - int lsize; - if (size == 0) { /* no elements to hash part? */ - t->node = cast(Node *, dummynode); /* use common 'dummynode' */ - lsize = 0; - } - else { - int i; - lsize = luaO_ceillog2(size); - if (lsize > MAXHBITS) - luaG_runerror(L, "table overflow"); - size = twoto(lsize); - t->node = luaM_newvector(L, size, Node); - for (i = 0; i < (int)size; i++) { - Node *n = gnode(t, i); - gnext(n) = 0; - setnilvalue(wgkey(n)); - setnilvalue(gval(n)); - } - } - t->lsizenode = cast_byte(lsize); - t->lastfree = gnode(t, size); /* all positions are free */ -} - - -void luaH_resize (lua_State *L, Table *t, unsigned int nasize, - unsigned int nhsize) { - unsigned int i; - int j; - unsigned int oldasize = t->sizearray; - int oldhsize = t->lsizenode; - 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); - if (nasize < oldasize) { /* array part must shrink? */ - t->sizearray = nasize; - /* re-insert elements from vanishing slice */ - for (i=nasize; iarray[i])) - luaH_setint(L, t, i + 1, &t->array[i]); - } - /* shrink array */ - luaM_reallocvector(L, t->array, oldasize, nasize, TValue); - } - /* re-insert elements from hash part */ - for (j = twoto(oldhsize) - 1; j >= 0; j--) { - Node *old = nold + j; - 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, cast(size_t, twoto(oldhsize))); /* free old array */ -} - - -void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) { - int nsize = isdummy(t->node) ? 0 : sizenode(t); - luaH_resize(L, t, nasize, nsize); -} - -/* -** nums[i] = number of keys 'k' where 2^(i - 1) < k <= 2^i -*/ -static void rehash (lua_State *L, Table *t, const TValue *ek) { - unsigned int nasize, na; - unsigned int nums[MAXABITS + 1]; - int i; - int totaluse; - for (i = 0; i <= MAXABITS; 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 */ - luaH_resize(L, t, nasize, totaluse - na); -} - - - -/* -** }============================================================= -*/ - - -Table *luaH_new (lua_State *L) { - GCObject *o = luaC_newobj(L, LUA_TTABLE, sizeof(Table)); - Table *t = gco2t(o); - t->metatable = NULL; - t->flags = cast_byte(~0); - t->array = NULL; - t->sizearray = 0; - setnodevector(L, t, 0); - return t; -} - - -void luaH_free (lua_State *L, Table *t) { - if (!isdummy(t->node)) - luaM_freearray(L, t->node, cast(size_t, sizenode(t))); - luaM_freearray(L, t->array, t->sizearray); - luaM_free(L, t); -} - - -static Node *getfreepos (Table *t) { - while (t->lastfree > t->node) { - t->lastfree--; - 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 -** 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. -*/ -TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { - Node *mp; - TValue aux; - if (ttisnil(key)) luaG_runerror(L, "table index is nil"); - else if (ttisfloat(key)) { - lua_Number n = fltvalue(key); - lua_Integer k; - if (luai_numisnan(n)) - luaG_runerror(L, "table index is NaN"); - if (numisinteger(n, &k)) { /* index is int? */ - setivalue(&aux, k); - key = &aux; /* insert it as an integer */ - } - } - mp = mainposition(t, key); - if (!ttisnil(gval(mp)) || isdummy(mp)) { /* main position is taken? */ - Node *othern; - Node *f = getfreepos(t); /* get a free place */ - if (f == NULL) { /* cannot find a free place? */ - rehash(L, t, key); /* grow table */ - /* whatever called 'newkey' takes care of TM cache and GC barrier */ - return luaH_set(L, t, key); /* insert key into grown table */ - } - lua_assert(!isdummy(f)); - othern = mainposition(t, gkey(mp)); - if (othern != mp) { /* is colliding node out of its main position? */ - /* yes; move colliding node into free position */ - while (othern + gnext(othern) != mp) /* find previous */ - othern += gnext(othern); - gnext(othern) = cast_int(f - othern); /* rechain to point to 'f' */ - *f = *mp; /* copy colliding node into free pos. (mp->next also goes) */ - if (gnext(mp) != 0) { - gnext(f) += cast_int(mp - f); /* correct 'next' */ - gnext(mp) = 0; /* now 'mp' is free */ - } - setnilvalue(gval(mp)); - } - else { /* colliding node is in its own main position */ - /* new node will go into free position */ - if (gnext(mp) != 0) - gnext(f) = cast_int((mp + gnext(mp)) - f); /* chain new position */ - else lua_assert(gnext(f) == 0); - gnext(mp) = cast_int(f - mp); - mp = f; - } - } - setkey(L, &mp->i_key, key); - luaC_barrierback(L, t, key); - lua_assert(ttisnil(gval(mp))); - return gval(mp); -} - - -/* -** search function for integers -*/ -const TValue *luaH_getint (Table *t, lua_Integer key) { - /* (1 <= key && key <= t->sizearray) */ - if (l_castS2U(key - 1) < t->sizearray) - return &t->array[key - 1]; - else { - Node *n = hashint(t, key); - for (;;) { /* check whether 'key' is somewhere in the chain */ - if (ttisinteger(gkey(n)) && ivalue(gkey(n)) == key) - return gval(n); /* that's it */ - else { - int nx = gnext(n); - if (nx == 0) break; - n += nx; - } - }; - return luaO_nilobject; - } -} - - -/* -** search function for short strings -*/ -const TValue *luaH_getstr (Table *t, TString *key) { - Node *n = hashstr(t, key); - lua_assert(key->tt == LUA_TSHRSTR); - for (;;) { /* check whether 'key' is somewhere in the chain */ - const TValue *k = gkey(n); - if (ttisshrstring(k) && eqshrstr(tsvalue(k), key)) - return gval(n); /* that's it */ - else { - int nx = gnext(n); - if (nx == 0) break; - n += nx; - } - }; - return luaO_nilobject; -} - - -/* -** main search function -*/ -const TValue *luaH_get (Table *t, const TValue *key) { - switch (ttype(key)) { - case LUA_TSHRSTR: return luaH_getstr(t, tsvalue(key)); - case LUA_TNUMINT: return luaH_getint(t, ivalue(key)); - case LUA_TNIL: return luaO_nilobject; - case LUA_TNUMFLT: { - lua_Integer k; - if (numisinteger(fltvalue(key), &k)) /* index is int? */ - return luaH_getint(t, k); /* use specialized version */ - /* else go through */ - } - default: { - Node *n = mainposition(t, key); - for (;;) { /* check whether 'key' is somewhere in the chain */ - if (luaV_rawequalobj(gkey(n), key)) - return gval(n); /* that's it */ - else { - int nx = gnext(n); - if (nx == 0) break; - n += nx; - } - }; - return luaO_nilobject; - } - } -} - - -/* -** 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); - if (p != luaO_nilobject) - return cast(TValue *, p); - else return luaH_newkey(L, t, key); -} - - -void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) { - const TValue *p = luaH_getint(t, key); - TValue *cell; - if (p != luaO_nilobject) - cell = cast(TValue *, p); - else { - TValue k; - setivalue(&k, key); - cell = luaH_newkey(L, t, &k); - } - setobj2t(L, cell, value); -} - - -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_getint(t, j))) { - i = j; - if (j > cast(unsigned int, MAX_INT)/2) { /* overflow? */ - /* table was built with bad purposes: resort to linear search */ - i = 1; - while (!ttisnil(luaH_getint(t, i))) i++; - return i - 1; - } - j *= 2; - } - /* now do a binary search between them */ - while (j - i > 1) { - unsigned int m = (i+j)/2; - if (ttisnil(luaH_getint(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 (isdummy(t->node)) /* 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 isdummy(n); } - -#endif diff --git a/src/ltable.h b/src/ltable.h deleted file mode 100644 index 53d25511ad..0000000000 --- a/src/ltable.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -** $Id: ltable.h,v 2.20 2014/09/04 18:15:29 roberto Exp $ -** Lua tables (hash) -** See Copyright Notice in lua.h -*/ - -#ifndef ltable_h -#define ltable_h - -#include "lobject.h" - - -#define gnode(t,i) (&(t)->node[i]) -#define gval(n) (&(n)->i_val) -#define gnext(n) ((n)->i_key.nk.next) - - -/* 'const' to avoid wrong writings that can mess up field 'next' */ -#define gkey(n) cast(const TValue*, (&(n)->i_key.tvk)) - -#define wgkey(n) (&(n)->i_key.nk) - -#define invalidateTMcache(t) ((t)->flags = 0) - - -/* returns the key, given the value of a table entry */ -#define keyfromval(v) \ - (gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val)))) - - -LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); -LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, - TValue *value); -LUAI_FUNC const TValue *luaH_getstr (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, unsigned int nasize, - unsigned int nhsize); -LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned 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); - - -#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/ltablib.c b/src/ltablib.c deleted file mode 100644 index 8f78afb7f2..0000000000 --- a/src/ltablib.c +++ /dev/null @@ -1,357 +0,0 @@ -/* -** $Id: ltablib.c,v 1.79 2014/11/02 19:19:04 roberto Exp $ -** Library for Table Manipulation -** See Copyright Notice in lua.h -*/ - -#define ltablib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - - -/* -** Structure with table-access functions -*/ -typedef struct { - int (*geti) (lua_State *L, int idx, lua_Integer n); - void (*seti) (lua_State *L, int idx, lua_Integer n); -} TabA; - - -/* -** Check that 'arg' has a table and set access functions in 'ta' to raw -** or non-raw according to the presence of corresponding metamethods. -*/ -static void checktab (lua_State *L, int arg, TabA *ta) { - ta->geti = NULL; ta->seti = NULL; - if (lua_getmetatable(L, arg)) { - lua_pushliteral(L, "__index"); /* 'index' metamethod */ - if (lua_rawget(L, -2) != LUA_TNIL) - ta->geti = lua_geti; - lua_pushliteral(L, "__newindex"); /* 'newindex' metamethod */ - if (lua_rawget(L, -3) != LUA_TNIL) - ta->seti = lua_seti; - lua_pop(L, 3); /* pop metatable plus both metamethods */ - } - if (ta->geti == NULL || ta->seti == NULL) { - luaL_checktype(L, arg, LUA_TTABLE); /* must be table for raw methods */ - if (ta->geti == NULL) ta->geti = lua_rawgeti; - if (ta->seti == NULL) ta->seti = lua_rawseti; - } -} - - -#define aux_getn(L,n,ta) (checktab(L, n, ta), luaL_len(L, n)) - - -#if defined(LUA_COMPAT_MAXN) -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; -} -#endif - - -static int tinsert (lua_State *L) { - TabA ta; - lua_Integer e = aux_getn(L, 1, &ta) + 1; /* first empty element */ - lua_Integer pos; /* where to insert new element */ - switch (lua_gettop(L)) { - case 2: { /* called with only 2 arguments */ - pos = e; /* insert new element at the end */ - break; - } - case 3: { - lua_Integer i; - pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */ - luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds"); - for (i = e; i > pos; i--) { /* move up elements */ - (*ta.geti)(L, 1, i - 1); - (*ta.seti)(L, 1, i); /* t[i] = t[i - 1] */ - } - break; - } - default: { - return luaL_error(L, "wrong number of arguments to 'insert'"); - } - } - (*ta.seti)(L, 1, pos); /* t[pos] = v */ - return 0; -} - - -static int tremove (lua_State *L) { - TabA ta; - lua_Integer size = aux_getn(L, 1, &ta); - lua_Integer pos = luaL_optinteger(L, 2, size); - if (pos != size) /* validate 'pos' if given */ - luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds"); - (*ta.geti)(L, 1, pos); /* result = t[pos] */ - for ( ; pos < size; pos++) { - (*ta.geti)(L, 1, pos + 1); - (*ta.seti)(L, 1, pos); /* t[pos] = t[pos + 1] */ - } - lua_pushnil(L); - (*ta.seti)(L, 1, pos); /* t[pos] = nil */ - return 1; -} - - -static int tmove (lua_State *L) { - TabA ta; - lua_Integer f = luaL_checkinteger(L, 2); - lua_Integer e = luaL_checkinteger(L, 3); - lua_Integer t = luaL_checkinteger(L, 4); - int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ - /* the following restriction avoids several problems with overflows */ - luaL_argcheck(L, f > 0, 2, "initial position must be positive"); - if (e >= f) { /* otherwise, nothing to move */ - lua_Integer n, i; - ta.geti = (luaL_getmetafield(L, 1, "__index") == LUA_TNIL) - ? (luaL_checktype(L, 1, LUA_TTABLE), lua_rawgeti) - : lua_geti; - ta.seti = (luaL_getmetafield(L, tt, "__newindex") == LUA_TNIL) - ? (luaL_checktype(L, tt, LUA_TTABLE), lua_rawseti) - : lua_seti; - n = e - f + 1; /* number of elements to move */ - if (t > f) { - for (i = n - 1; i >= 0; i--) { - (*ta.geti)(L, 1, f + i); - (*ta.seti)(L, tt, t + i); - } - } - else { - for (i = 0; i < n; i++) { - (*ta.geti)(L, 1, f + i); - (*ta.seti)(L, tt, t + i); - } - } - } - lua_pushvalue(L, tt); /* return "to table" */ - return 1; -} - - -static void addfield (lua_State *L, luaL_Buffer *b, TabA *ta, lua_Integer i) { - (*ta->geti)(L, 1, i); - if (!lua_isstring(L, -1)) - luaL_error(L, "invalid value (%s) at index %d in table for 'concat'", - luaL_typename(L, -1), i); - luaL_addvalue(b); -} - - -static int tconcat (lua_State *L) { - TabA ta; - luaL_Buffer b; - size_t lsep; - lua_Integer i, last; - const char *sep = luaL_optlstring(L, 2, "", &lsep); - checktab(L, 1, &ta); - i = luaL_optinteger(L, 3, 1); - last = luaL_opt(L, luaL_checkinteger, 4, luaL_len(L, 1)); - luaL_buffinit(L, &b); - for (; i < last; i++) { - addfield(L, &b, &ta, i); - luaL_addlstring(&b, sep, lsep); - } - if (i == last) /* add last value (if interval was not empty) */ - addfield(L, &b, &ta, i); - luaL_pushresult(&b); - return 1; -} - - -/* -** {====================================================== -** Pack/unpack -** ======================================================= -*/ - -static int pack (lua_State *L) { - int i; - int n = lua_gettop(L); /* number of elements to pack */ - lua_createtable(L, n, 1); /* create result table */ - lua_insert(L, 1); /* put it at index 1 */ - for (i = n; i >= 1; i--) /* assign elements */ - lua_rawseti(L, 1, i); - lua_pushinteger(L, n); - lua_setfield(L, 1, "n"); /* t.n = number of elements */ - return 1; /* return table */ -} - - -static int unpack (lua_State *L) { - TabA ta; - lua_Integer i, e; - lua_Unsigned n; - checktab(L, 1, &ta); - i = luaL_optinteger(L, 2, 1); - e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); - if (i > e) return 0; /* empty range */ - n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ - if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n))) - return luaL_error(L, "too many results to unpack"); - do { /* must have at least one element */ - (*ta.geti)(L, 1, i); /* push arg[i..e] */ - } while (i++ < e); - - return (int)n; -} - -/* }====================================================== */ - - - -/* -** {====================================================== -** Quicksort -** (based on 'Algorithms in MODULA-3', Robert Sedgewick; -** Addison-Wesley, 1993.) -** ======================================================= -*/ - - -static void set2 (lua_State *L, TabA *ta, int i, int j) { - (*ta->seti)(L, 1, i); - (*ta->seti)(L, 1, j); -} - -static int sort_comp (lua_State *L, int a, int b) { - if (!lua_isnil(L, 2)) { /* function? */ - int res; - lua_pushvalue(L, 2); - lua_pushvalue(L, a-1); /* -1 to compensate function */ - lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */ - lua_call(L, 2, 1); - res = lua_toboolean(L, -1); - lua_pop(L, 1); - return res; - } - else /* a < b? */ - return lua_compare(L, a, b, LUA_OPLT); -} - -static void auxsort (lua_State *L, TabA *ta, int l, int u) { - while (l < u) { /* for tail recursion */ - int i, j; - /* sort elements a[l], a[(l+u)/2] and a[u] */ - (*ta->geti)(L, 1, l); - (*ta->geti)(L, 1, u); - if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */ - set2(L, ta, l, u); /* swap a[l] - a[u] */ - else - lua_pop(L, 2); - if (u-l == 1) break; /* only 2 elements */ - i = (l+u)/2; - (*ta->geti)(L, 1, i); - (*ta->geti)(L, 1, l); - if (sort_comp(L, -2, -1)) /* a[i]geti)(L, 1, u); - if (sort_comp(L, -1, -2)) /* a[u]geti)(L, 1, i); /* Pivot */ - lua_pushvalue(L, -1); - (*ta->geti)(L, 1, u-1); - set2(L, ta, i, u-1); - /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */ - i = l; j = u-1; - for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */ - /* repeat ++i until a[i] >= P */ - while ((*ta->geti)(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 ((*ta->geti)(L, 1, --j), sort_comp(L, -3, -1)) { - if (j<=l) luaL_error(L, "invalid order function for sorting"); - lua_pop(L, 1); /* remove a[j] */ - } - if (jgeti)(L, 1, u-1); - (*ta->geti)(L, 1, i); - set2(L, ta, u-1, i); /* swap pivot (a[u-1]) with a[i] */ - /* 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(L, ta, j, i); /* call recursively the smaller one */ - } /* repeat the routine for the larger one */ -} - -static int sort (lua_State *L) { - TabA ta; - int n = (int)aux_getn(L, 1, &ta); - luaL_checkstack(L, 50, ""); /* assume array is smaller than 2^50 */ - if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ - luaL_checktype(L, 2, LUA_TFUNCTION); - lua_settop(L, 2); /* make sure there are two arguments */ - auxsort(L, &ta, 1, n); - return 0; -} - -/* }====================================================== */ - - -static const luaL_Reg tab_funcs[] = { - {"concat", tconcat}, -#if defined(LUA_COMPAT_MAXN) - {"maxn", maxn}, -#endif - {"insert", tinsert}, - {"pack", pack}, - {"unpack", unpack}, - {"remove", tremove}, - {"move", tmove}, - {"sort", sort}, - {NULL, NULL} -}; - - -LUAMOD_API int luaopen_table (lua_State *L) { - luaL_newlib(L, tab_funcs); -#if defined(LUA_COMPAT_UNPACK) - /* _G.unpack = table.unpack */ - lua_getfield(L, -1, "unpack"); - lua_setglobal(L, "unpack"); -#endif - return 1; -} - diff --git a/src/ltm.c b/src/ltm.c deleted file mode 100644 index 25b46b17f9..0000000000 --- a/src/ltm.c +++ /dev/null @@ -1,143 +0,0 @@ -/* -** $Id: ltm.c,v 2.33 2014/11/21 12:15:57 roberto Exp $ -** Tag methods -** See Copyright Notice in lua.h -*/ - -#define ltm_c -#define LUA_CORE - -#include "lprefix.h" - - -#include - -#include "lua.h" - -#include "ldebug.h" -#include "ldo.h" -#include "lobject.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "ltm.h" -#include "lvm.h" - - -static const char udatatypename[] = "userdata"; - -LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = { - "no value", - "nil", "boolean", udatatypename, "number", - "string", "table", "function", udatatypename, "thread", - "proto" /* this last case is used for tests only */ -}; - - -void luaT_init (lua_State *L) { - static const char *const luaT_eventname[] = { /* ORDER TM */ - "__index", "__newindex", - "__gc", "__mode", "__len", "__eq", - "__add", "__sub", "__mul", "__mod", "__pow", - "__div", "__idiv", - "__band", "__bor", "__bxor", "__shl", "__shr", - "__unm", "__bnot", "__lt", "__le", - "__concat", "__call" - }; - int i; - for (i=0; itmname[i] = luaS_new(L, luaT_eventname[i]); - luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */ - } -} - - -/* -** function to be used with macro "fasttm": optimized for absence of -** tag methods -*/ -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_byte(1u<metatable; - break; - case LUA_TUSERDATA: - mt = uvalue(o)->metatable; - break; - default: - mt = G(L)->mt[ttnov(o)]; - } - return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject); -} - - -void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, - const TValue *p2, TValue *p3, int hasres) { - ptrdiff_t result = savestack(L, p3); - setobj2s(L, L->top++, f); /* push function (assume EXTRA_STACK) */ - 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); /* 3rd argument */ - /* 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); - } -} - - -int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2, - StkId res, TMS event) { - const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ - if (ttisnil(tm)) - tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ - if (ttisnil(tm)) return 0; - luaT_callTM(L, tm, p1, p2, res, 1); - return 1; -} - - -void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, - StkId res, TMS event) { - if (!luaT_callbinTM(L, p1, p2, res, event)) { - switch (event) { - case TM_CONCAT: - luaG_concaterror(L, p1, p2); - case TM_BAND: case TM_BOR: case TM_BXOR: - case TM_SHL: case TM_SHR: case TM_BNOT: { - lua_Number dummy; - if (tonumber(p1, &dummy) && tonumber(p2, &dummy)) - luaG_tointerror(L, p1, p2); - else - luaG_opinterror(L, p1, p2, "perform bitwise operation on"); - /* else go through */ - } - default: - luaG_opinterror(L, p1, p2, "perform arithmetic on"); - } - } -} - - -int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, - TMS event) { - if (!luaT_callbinTM(L, p1, p2, L->top, event)) - return -1; /* no metamethod */ - else - return !l_isfalse(L->top); -} - diff --git a/src/ltm.h b/src/ltm.h deleted file mode 100644 index 180179ce03..0000000000 --- a/src/ltm.h +++ /dev/null @@ -1,75 +0,0 @@ -/* -** $Id: ltm.h,v 2.21 2014/10/25 11:50:46 roberto Exp $ -** Tag methods -** See Copyright Notice in lua.h -*/ - -#ifndef ltm_h -#define ltm_h - - -#include "lobject.h" - - -/* -* WARNING: if you change the order of this enumeration, -* grep "ORDER TM" and "ORDER OP" -*/ -typedef enum { - TM_INDEX, - TM_NEWINDEX, - TM_GC, - TM_MODE, - TM_LEN, - TM_EQ, /* last tag method with fast access */ - TM_ADD, - TM_SUB, - TM_MUL, - TM_MOD, - TM_POW, - TM_DIV, - TM_IDIV, - TM_BAND, - TM_BOR, - TM_BXOR, - TM_SHL, - TM_SHR, - TM_UNM, - TM_BNOT, - TM_LT, - TM_LE, - TM_CONCAT, - TM_CALL, - TM_N /* number of elements in the enum */ -} TMS; - - - -#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) - -#define ttypename(x) luaT_typenames_[(x) + 1] -#define objtypename(x) ttypename(ttnov(x)) - -LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS]; - - -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); - -LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, - const TValue *p2, TValue *p3, int hasres); -LUAI_FUNC int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2, - StkId res, TMS event); -LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, - StkId res, TMS event); -LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1, - const TValue *p2, TMS event); - - - -#endif diff --git a/src/lua.c b/src/lua.c deleted file mode 100644 index 34a3900a79..0000000000 --- a/src/lua.c +++ /dev/null @@ -1,611 +0,0 @@ -/* -** $Id: lua.c,v 1.222 2014/11/11 19:41:27 roberto Exp $ -** Lua stand-alone interpreter -** See Copyright Notice in lua.h -*/ - -#define lua_c - -#include "lprefix.h" - - -#include -#include -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -#if !defined(LUA_PROMPT) -#define LUA_PROMPT "> " -#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 - -#define LUA_INITVARVERSION \ - LUA_INIT_VAR "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR - - -/* -** lua_stdin_is_tty detects whether the standard input is a 'tty' (that -** is, whether we're running lua interactively). -*/ -#if !defined(lua_stdin_is_tty) /* { */ - -#if defined(LUA_USE_POSIX) /* { */ - -#include -#define lua_stdin_is_tty() isatty(0) - -#elif defined(LUA_USE_WINDOWS) /* }{ */ - -#include -#define lua_stdin_is_tty() _isatty(_fileno(stdin)) - -#else /* }{ */ - -/* ISO C definition */ -#define lua_stdin_is_tty() 1 /* assume stdin is a tty */ - -#endif /* } */ - -#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_readline) /* { */ - -#if defined(LUA_USE_READLINE) /* { */ - -#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)) - -#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 /* } */ - - - - -static lua_State *globalL = NULL; - -static const char *progname = LUA_PROGNAME; - - -/* -** Hook set by signal function to stop the interpreter. -*/ -static void lstop (lua_State *L, lua_Debug *ar) { - (void)ar; /* unused arg. */ - lua_sethook(L, NULL, 0, 0); /* reset hook */ - luaL_error(L, "interrupted!"); -} - - -/* -** Function to be called at a C signal. Because a C signal cannot -** just change a Lua state (as there is no proper synchronization), -** this function only sets a hook that, when called, will stop the -** interpreter. -*/ -static void laction (int i) { - signal(i, SIG_DFL); /* if another SIGINT happens, terminate process */ - lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); -} - - -static void print_usage (const char *badoption) { - lua_writestringerror("%s: ", progname); - if (badoption[1] == 'e' || badoption[1] == 'l') - lua_writestringerror("'%s' needs argument\n", badoption); - else - lua_writestringerror("unrecognized option '%s'\n", badoption); - lua_writestringerror( - "usage: %s [options] [script [args]]\n" - "Available options are:\n" - " -e stat execute string 'stat'\n" - " -i enter interactive mode after executing 'script'\n" - " -l name require library 'name'\n" - " -v show version information\n" - " -E ignore environment variables\n" - " -- stop handling options\n" - " - stop handling options and execute stdin\n" - , - progname); -} - - -/* -** Prints an error message, adding the program name in front of it -** (if present) -*/ -static void l_message (const char *pname, const char *msg) { - if (pname) lua_writestringerror("%s: ", pname); - lua_writestringerror("%s\n", msg); -} - - -/* -** Check whether 'status' is not OK and, if so, prints the error -** message on the top of the stack. It assumes that the error object -** is a string, as it was either generated by Lua or by 'msghandler'. -*/ -static int report (lua_State *L, int status) { - if (status != LUA_OK) { - const char *msg = lua_tostring(L, -1); - l_message(progname, msg); - lua_pop(L, 1); /* remove message */ - } - return status; -} - - -/* -** Message handler used to run all chunks -*/ -static int msghandler (lua_State *L) { - const char *msg = lua_tostring(L, 1); - if (msg == NULL) { /* is error object not a string? */ - if (luaL_callmeta(L, 1, "__tostring") && /* does it have a metamethod */ - lua_type(L, -1) == LUA_TSTRING) /* that produces a string? */ - return 1; /* that is the message */ - else - msg = lua_pushfstring(L, "(error object is a %s value)", - luaL_typename(L, 1)); - } - luaL_traceback(L, L, msg, 1); /* append a standard traceback */ - return 1; /* return the traceback */ -} - - -/* -** Interface to 'lua_pcall', which sets appropriate message function -** and C-signal handler. Used to run all chunks. -*/ -static int docall (lua_State *L, int narg, int nres) { - int status; - int base = lua_gettop(L) - narg; /* function index */ - lua_pushcfunction(L, msghandler); /* push message handler */ - lua_insert(L, base); /* put it under function and args */ - globalL = L; /* to be available to 'laction' */ - signal(SIGINT, laction); /* set C-signal handler */ - status = lua_pcall(L, narg, nres, base); - signal(SIGINT, SIG_DFL); /* reset C-signal handler */ - lua_remove(L, base); /* remove message handler from the stack */ - return status; -} - - -static void print_version (void) { - lua_writestring(LUA_COPYRIGHT, strlen(LUA_COPYRIGHT)); - lua_writeline(); -} - - -/* -** Create the 'arg' table, which stores all arguments from the -** command line ('argv'). It should be aligned so that, at index 0, -** it has 'argv[script]', which is the script name. The arguments -** to the script (everything after 'script') go to positive indices; -** other arguments (before the script name) go to negative indices. -** If there is no script name, assume interpreter's name as base. -*/ -static void createargtable (lua_State *L, char **argv, int argc, int script) { - int i, narg; - if (script == argc) script = 0; /* no script name? */ - narg = argc - (script + 1); /* number of positive indices */ - lua_createtable(L, narg, script + 1); - for (i = 0; i < argc; i++) { - lua_pushstring(L, argv[i]); - lua_rawseti(L, -2, i - script); - } - lua_setglobal(L, "arg"); -} - - -static int dochunk (lua_State *L, int status) { - if (status == LUA_OK) status = docall(L, 0, 0); - return report(L, status); -} - - -static int dofile (lua_State *L, const char *name) { - return dochunk(L, luaL_loadfile(L, name)); -} - - -static int dostring (lua_State *L, const char *s, const char *name) { - return dochunk(L, luaL_loadbuffer(L, s, strlen(s), name)); -} - - -/* -** Calls 'require(name)' and stores the result in a global variable -** with the given name. -*/ -static int dolibrary (lua_State *L, const char *name) { - int status; - lua_getglobal(L, "require"); - lua_pushstring(L, name); - status = docall(L, 1, 1); /* call 'require(name)' */ - if (status == LUA_OK) - lua_setglobal(L, name); /* global[name] = require return */ - return report(L, status); -} - - -/* -** Returns the string to be used as a prompt by the interpreter. -*/ -static const char *get_prompt (lua_State *L, int firstline) { - const char *p; - lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2"); - p = lua_tostring(L, -1); - if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); - return p; -} - -/* mark in error messages for incomplete statements */ -#define EOFMARK "" -#define marklen (sizeof(EOFMARK)/sizeof(char) - 1) - - -/* -** Check whether 'status' signals a syntax error and the error -** message at the top of the stack ends with the above mark for -** incomplete statements. -*/ -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, EOFMARK) == 0) { - lua_pop(L, 1); - return 1; - } - } - return 0; /* else... */ -} - - -/* -** Prompt the user, read a line, and push it into the Lua stack. -*/ -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); - int readstatus = lua_readline(L, b, prmt); - if (readstatus == 0) - return 0; /* no input (prompt will be popped by caller) */ - lua_pop(L, 1); /* remove prompt */ - l = strlen(b); - if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ - b[l-1] = '\0'; /* remove it */ - if (firstline && b[0] == '=') /* for compatibility with 5.2, ... */ - lua_pushfstring(L, "return %s", b + 1); /* change '=' to 'return' */ - else - lua_pushstring(L, b); - lua_freeline(L, b); - return 1; -} - - -/* -** Try to compile line on the stack as 'return '; on return, stack -** has either compiled chunk or original line (if compilation failed). -*/ -static int addreturn (lua_State *L) { - int status; - size_t len; const char *line; - lua_pushliteral(L, "return "); - lua_pushvalue(L, -2); /* duplicate line */ - lua_concat(L, 2); /* new line is "return ..." */ - line = lua_tolstring(L, -1, &len); - if ((status = luaL_loadbuffer(L, line, len, "=stdin")) == LUA_OK) - lua_remove(L, -3); /* remove original line */ - else - lua_pop(L, 2); /* remove result from 'luaL_loadbuffer' and new line */ - return status; -} - - -/* -** Read multiple lines until a complete Lua statement -*/ -static int multiline (lua_State *L) { - for (;;) { /* repeat until gets a complete statement */ - size_t len; - const char *line = lua_tolstring(L, 1, &len); /* get what it has */ - int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */ - if (!incomplete(L, status) || !pushline(L, 0)) - return status; /* cannot or should not try to add continuation line */ - lua_pushliteral(L, "\n"); /* add newline... */ - lua_insert(L, -2); /* ...between the two lines */ - lua_concat(L, 3); /* join them */ - } -} - - -/* -** Read a line and try to load (compile) it first as an expression (by -** adding "return " in front of it) and second as a statement. Return -** the final status of load/call with the resulting function (if any) -** in the top of the stack. -*/ -static int loadline (lua_State *L) { - int status; - lua_settop(L, 0); - if (!pushline(L, 1)) - return -1; /* no input */ - if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */ - status = multiline(L); /* try as command, maybe with continuation lines */ - lua_saveline(L, 1); /* keep history */ - lua_remove(L, 1); /* remove line from the stack */ - lua_assert(lua_gettop(L) == 1); - return status; -} - - -/* -** Prints (calling the Lua 'print' function) any values on the stack -*/ -static void l_print (lua_State *L) { - int n = lua_gettop(L); - if (n > 0) { /* any result to be printed? */ - luaL_checkstack(L, LUA_MINSTACK, "too many results to print"); - lua_getglobal(L, "print"); - lua_insert(L, 1); - if (lua_pcall(L, n, 0, 0) != LUA_OK) - l_message(progname, lua_pushfstring(L, "error calling 'print' (%s)", - lua_tostring(L, -1))); - } -} - - -/* -** Do the REPL: repeatedly read (load) a line, evaluate (call) it, and -** print any results. -*/ -static void doREPL (lua_State *L) { - int status; - const char *oldprogname = progname; - progname = NULL; /* no 'progname' on errors in interactive mode */ - while ((status = loadline(L)) != -1) { - if (status == LUA_OK) - status = docall(L, 0, LUA_MULTRET); - if (status == LUA_OK) l_print(L); - else report(L, status); - } - lua_settop(L, 0); /* clear stack */ - lua_writeline(); - progname = oldprogname; -} - - -/* -** Push on the stack the contents of table 'arg' from 1 to #arg -*/ -static int pushargs (lua_State *L) { - int i, n; - if (lua_getglobal(L, "arg") != LUA_TTABLE) - luaL_error(L, "'arg' is not a table"); - n = (int)luaL_len(L, -1); - luaL_checkstack(L, n + 3, "too many arguments to script"); - for (i = 1; i <= n; i++) - lua_rawgeti(L, -i, i); - lua_remove(L, -i); /* remove table from the stack */ - return n; -} - - -static int handle_script (lua_State *L, char **argv) { - int status; - const char *fname = argv[0]; - if (strcmp(fname, "-") == 0 && strcmp(argv[-1], "--") != 0) - fname = NULL; /* stdin */ - status = luaL_loadfile(L, fname); - if (status == LUA_OK) { - int n = pushargs(L); /* push arguments to script */ - status = docall(L, n, LUA_MULTRET); - } - return report(L, status); -} - - - -/* bits of various argument indicators in 'args' */ -#define has_error 1 /* bad option */ -#define has_i 2 /* -i */ -#define has_v 4 /* -v */ -#define has_e 8 /* -e */ -#define has_E 16 /* -E */ - -/* -** Traverses all arguments from 'argv', returning a mask with those -** needed before running any Lua code (or an error code if it finds -** any invalid argument). 'first' returns the first not-handled argument -** (either the script name or a bad argument in case of error). -*/ -static int collectargs (char **argv, int *first) { - int args = 0; - int i; - for (i = 1; argv[i] != NULL; i++) { - *first = i; - if (argv[i][0] != '-') /* not an option? */ - return args; /* stop handling options */ - switch (argv[i][1]) { /* else check option */ - case '-': /* '--' */ - if (argv[i][2] != '\0') /* extra characters after '--'? */ - return has_error; /* invalid option */ - *first = i + 1; - return args; - case '\0': /* '-' */ - return args; /* script "name" is '-' */ - case 'E': - if (argv[i][2] != '\0') /* extra characters after 1st? */ - return has_error; /* invalid option */ - args |= has_E; - break; - case 'i': - args |= has_i; /* goes through (-i implies -v) */ - case 'v': - if (argv[i][2] != '\0') /* extra characters after 1st? */ - return has_error; /* invalid option */ - args |= has_v; - break; - case 'e': - args |= has_e; /* go through */ - 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 has_error; /* no next argument or it is another option */ - } - break; - default: /* invalid option */ - return has_error; - } - } - *first = i; /* no script name */ - return args; -} - - -/* -** Processes options 'e' and 'l', which involve running Lua code. -** Returns 0 if some code raises an error. -*/ -static int runargs (lua_State *L, char **argv, int n) { - int i; - for (i = 1; i < n; i++) { - int status; - int option = argv[i][1]; - lua_assert(argv[i][0] == '-'); /* already checked */ - if (option == 'e' || option == 'l') { - const char *extra = argv[i] + 2; /* both options need an argument */ - if (*extra == '\0') extra = argv[++i]; - lua_assert(extra != NULL); - if (option == 'e') - status = dostring(L, extra, "=(command line)"); - else - status = dolibrary(L, extra); - if (status != LUA_OK) return 0; - } - } - return 1; -} - - -static int handle_luainit (lua_State *L) { - const char *name = "=" LUA_INITVARVERSION; - const char *init = getenv(name + 1); - if (init == NULL) { - name = "=" LUA_INIT_VAR; - 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, name); -} - - -/* -** Main body of stand-alone interpreter (to be called in protected mode). -** Reads the options and handles them all. -*/ -static int pmain (lua_State *L) { - int argc = (int)lua_tointeger(L, 1); - char **argv = (char **)lua_touserdata(L, 2); - int script; - int args = collectargs(argv, &script); - luaL_checkversion(L); /* check that interpreter has correct version */ - if (argv[0] && argv[0][0]) progname = argv[0]; - if (args == has_error) { /* bad arg? */ - print_usage(argv[script]); /* 'script' has index of bad arg. */ - return 0; - } - if (args & has_v) /* option '-v'? */ - print_version(); - if (args & has_E) { /* option '-E'? */ - lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */ - lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); - } - luaL_openlibs(L); /* open standard libraries */ - createargtable(L, argv, argc, script); /* create table 'arg' */ - if (!(args & has_E)) { /* no option '-E'? */ - if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */ - return 0; /* error running LUA_INIT */ - } - if (!runargs(L, argv, script)) /* execute arguments -e and -l */ - return 0; /* something failed */ - if (script < argc && /* execute main script (if there is one) */ - handle_script(L, argv + script) != LUA_OK) - return 0; - if (args & has_i) /* -i option? */ - doREPL(L); /* do read-eval-print loop */ - else if (script == argc && !(args & (has_e | has_v))) { /* no arguments? */ - if (lua_stdin_is_tty()) { /* running in interactive mode? */ - print_version(); - doREPL(L); /* do read-eval-print loop */ - } - else dofile(L, NULL); /* executes stdin as a file */ - } - lua_pushboolean(L, 1); /* signal no errors */ - return 1; -} - - -int main (int argc, char **argv) { - 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; - } - lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */ - lua_pushinteger(L, argc); /* 1st argument */ - lua_pushlightuserdata(L, argv); /* 2nd argument */ - status = lua_pcall(L, 2, 1, 0); /* do the call */ - result = lua_toboolean(L, -1); /* get result */ - report(L, status); - lua_close(L); - return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE; -} - diff --git a/src/lua.h b/src/lua.h deleted file mode 100644 index 2f8d3edd35..0000000000 --- a/src/lua.h +++ /dev/null @@ -1,485 +0,0 @@ -/* -** $Id: lua.h,v 1.324 2014/12/08 15:12:07 roberto Exp $ -** Lua - A Scripting Language -** Lua.org, PUC-Rio, Brazil (http://www.lua.org) -** See Copyright Notice at the end of this file -*/ - - -#ifndef lua_h -#define lua_h - -#include -#include - - -#include "luaconf.h" - - -#define LUA_VERSION_MAJOR "5" -#define LUA_VERSION_MINOR "3" -#define LUA_VERSION_NUM 503 -#define LUA_VERSION_RELEASE "0" - -#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-2014 Lua.org, PUC-Rio" -#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" - - -/* mark for precompiled code ('Lua') */ -#define LUA_SIGNATURE "\x1bLua" - -/* option for multiple returns in 'lua_pcall' and 'lua_call' */ -#define LUA_MULTRET (-1) - - -/* -** pseudo-indices -*/ -#define LUA_REGISTRYINDEX LUAI_FIRSTPSEUDOIDX -#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i)) - - -/* thread status */ -#define LUA_OK 0 -#define LUA_YIELD 1 -#define LUA_ERRRUN 2 -#define LUA_ERRSYNTAX 3 -#define LUA_ERRMEM 4 -#define LUA_ERRGCMM 5 -#define LUA_ERRERR 6 - - -typedef struct lua_State lua_State; - - -/* -** basic types -*/ -#define LUA_TNONE (-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_NUMTAGS 9 - - - -/* minimum Lua stack available to a C function */ -#define LUA_MINSTACK 20 - - -/* predefined values in the registry */ -#define LUA_RIDX_MAINTHREAD 1 -#define LUA_RIDX_GLOBALS 2 -#define LUA_RIDX_LAST LUA_RIDX_GLOBALS - - -/* type of numbers in Lua */ -typedef LUA_NUMBER lua_Number; - - -/* type for integer functions */ -typedef LUA_INTEGER lua_Integer; - -/* unsigned integer type */ -typedef LUA_UNSIGNED lua_Unsigned; - -/* type for continuation-function contexts */ -typedef LUA_KCONTEXT lua_KContext; - - -/* -** Type for C functions registered with Lua -*/ -typedef int (*lua_CFunction) (lua_State *L); - -/* -** Type for continuation functions -*/ -typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx); - - -/* -** Type for functions that read/write blocks when loading/dumping Lua chunks -*/ -typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); - -typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud); - - -/* -** Type for memory-allocation functions -*/ -typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); - - - -/* -** generic extra include file -*/ -#if defined(LUA_USER_H) -#include LUA_USER_H -#endif - - -/* -** RCS ident string -*/ -extern const char lua_ident[]; - - -/* -** 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_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); - - -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); -LUA_API void (lua_rotate) (lua_State *L, int idx, int n); -LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx); -LUA_API int (lua_checkstack) (lua_State *L, 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_isinteger) (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 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); -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, ORDER OP */ -#define LUA_OPSUB 1 -#define LUA_OPMUL 2 -#define LUA_OPMOD 3 -#define LUA_OPPOW 4 -#define LUA_OPDIV 5 -#define LUA_OPIDIV 6 -#define LUA_OPBAND 7 -#define LUA_OPBOR 8 -#define LUA_OPBXOR 9 -#define LUA_OPSHL 10 -#define LUA_OPSHR 11 -#define LUA_OPUNM 12 -#define LUA_OPBNOT 13 - -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 const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len); -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, ...); -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 int (lua_getglobal) (lua_State *L, const char *name); -LUA_API int (lua_gettable) (lua_State *L, int idx); -LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k); -LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n); -LUA_API int (lua_rawget) (lua_State *L, int idx); -LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n); -LUA_API int (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); -LUA_API int (lua_getuservalue) (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 idx); -LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); -LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n); -LUA_API void (lua_rawset) (lua_State *L, int idx); -LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer 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); - - -/* -** 'load' and 'call' functions (load and run Lua code) -*/ -LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, - lua_KContext ctx, lua_KFunction k); -#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL) - -LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, - lua_KContext ctx, lua_KFunction 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, const char *mode); - -LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip); - - -/* -** coroutine functions -*/ -LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx, - lua_KFunction k); -LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg); -LUA_API int (lua_status) (lua_State *L); -LUA_API int (lua_isyieldable) (lua_State *L); - -#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL) - - -/* -** garbage-collection function and options -*/ - -#define LUA_GCSTOP 0 -#define LUA_GCRESTART 1 -#define LUA_GCCOLLECT 2 -#define LUA_GCCOUNT 3 -#define LUA_GCCOUNTB 4 -#define LUA_GCSTEP 5 -#define LUA_GCSETPAUSE 6 -#define LUA_GCSETSTEPMUL 7 -#define LUA_GCISRUNNING 9 - -LUA_API int (lua_gc) (lua_State *L, int what, int data); - - -/* -** miscellaneous functions -*/ - -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 size_t (lua_stringtonumber) (lua_State *L, const char *s); - -LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); -LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); - - - -/* -** {============================================================== -** some useful macros -** =============================================================== -*/ - -#define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE)) - -#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) - -#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_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_pushglobaltable(L) \ - lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS) - -#define lua_tostring(L,i) lua_tolstring(L, (i), NULL) - - -#define lua_insert(L,idx) lua_rotate(L, (idx), 1) - -#define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1)) - -#define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1)) - -/* }============================================================== */ - - -/* -** {============================================================== -** compatibility macros for unsigned conversions -** =============================================================== -*/ -#if defined(LUA_COMPAT_APIINTCASTS) - -#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) -#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is)) -#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL) - -#endif -/* }============================================================== */ - -/* -** {====================================================================== -** Debug API -** ======================================================================= -*/ - - -/* -** Event codes -*/ -#define LUA_HOOKCALL 0 -#define LUA_HOOKRET 1 -#define LUA_HOOKLINE 2 -#define LUA_HOOKCOUNT 3 -#define LUA_HOOKTAILCALL 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 */ - - -/* 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 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 void (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 *source; /* (S) */ - int currentline; /* (l) */ - 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 */ - struct CallInfo *i_ci; /* active function */ -}; - -/* }====================================================================== */ - - -/****************************************************************************** -* Copyright (C) 1994-2014 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. -******************************************************************************/ - - -#endif diff --git a/src/lua.hpp b/src/lua.hpp deleted file mode 100644 index ec417f5946..0000000000 --- a/src/lua.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// lua.hpp -// Lua header files for C++ -// <> not supplied automatically because Lua also compiles as C++ - -extern "C" { -#include "lua.h" -#include "lualib.h" -#include "lauxlib.h" -} diff --git a/src/luac.c b/src/luac.c deleted file mode 100644 index a8d2a31bce..0000000000 --- a/src/luac.c +++ /dev/null @@ -1,444 +0,0 @@ -/* -** $Id: luac.c,v 1.71 2014/11/26 12:08:59 lhf Exp $ -** Lua compiler (saves bytecodes to files; also lists bytecodes) -** See Copyright Notice in lua.h -*/ - -#define luac_c -#define LUA_CORE - -#include "lprefix.h" - -#include -#include -#include -#include -#include - -#include "lua.h" -#include "lauxlib.h" - -#include "lobject.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 */ - -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; /* actual output file name */ -static const char* progname=PROGNAME; /* actual program name */ - -static void fatal(const char* message) -{ - fprintf(stderr,"%s: %s\n",progname,message); - exit(EXIT_FAILURE); -} - -static void cannot(const char* what) -{ - fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno)); - exit(EXIT_FAILURE); -} - -static void usage(const char* message) -{ - if (*message=='-') - fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message); - else - fprintf(stderr,"%s: %s\n",progname,message); - fprintf(stderr, - "usage: %s [options] [filenames]\n" - "Available options are:\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" - " -v show version information\n" - " -- stop handling options\n" - " - stop handling options and process stdin\n" - ,progname,Output); - exit(EXIT_FAILURE); -} - -#define IS(s) (strcmp(argv[i],s)==0) - -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)) - -static const Proto* combine(lua_State* L, int n) -{ - if (n==1) - return toproto(L,-1); - else - { - Proto* f; - int i=n; - if (lua_load(L,reader,&i,"=(" PROGNAME ")",NULL)!=LUA_OK) fatal(lua_tostring(L,-1)); - f=toproto(L,-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; - return f; - } -} - -static int writer(lua_State* L, const void* p, size_t size, void* u) -{ - UNUSED(L); - return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0); -} - -static int pmain(lua_State* L) -{ - int argc=(int)lua_tointeger(L,1); - char** argv=(char**)lua_touserdata(L,2); - const Proto* f; - int i; - if (!lua_checkstack(L,argc)) fatal("too many input files"); - for (i=0; i1); - if (dumping) - { - FILE* D= (output==NULL) ? stdout : fopen(output,"wb"); - if (D==NULL) cannot("open"); - lua_lock(L); - luaU_dump(L,f,writer,D,stripping); - lua_unlock(L); - if (ferror(D)) cannot("write"); - if (fclose(D)) cannot("close"); - } - return 0; -} - -int main(int argc, char* argv[]) -{ - lua_State* L; - int i=doargs(argc,argv); - argc-=i; argv+=i; - if (argc<=0) usage("no input files given"); - L=luaL_newstate(); - if (L==NULL) fatal("cannot create state: not enough memory"); - lua_pushcfunction(L,&pmain); - lua_pushinteger(L,argc); - lua_pushlightuserdata(L,argv); - 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.74 2014/07/21 01:41:45 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 VOID(p) ((const void*)(p)) - -static void PrintString(const TString* ts) -{ - const char* s=getstr(ts); - size_t i,n=ts->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_TNUMFLT: - printf(LUA_NUMBER_FMT,fltvalue(o)); - break; - case LUA_TNUMINT: - printf(LUA_INTEGER_FMT,ivalue(o)); - break; - case LUA_TSHRSTR: case LUA_TLNGSTR: - PrintString(tsvalue(o)); - break; - default: /* cannot happen */ - printf("? type=%d",ttype(o)); - break; - } -} - -#define UPVALNAME(x) ((f->upvalues[x].name) ? getstr(f->upvalues[x].name) : "-") -#define MYK(x) (-1-(x)) - -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) ? (MYK(INDEXK(b))) : b); - if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (MYK(INDEXK(c))) : c); - break; - case iABx: - printf("%d",a); - if (getBMode(o)==OpArgK) printf(" %d",MYK(bx)); - if (getBMode(o)==OpArgU) printf(" %d",bx); - break; - case iAsBx: - printf("%d %d",a,sbx); - break; - case iAx: - printf("%d",MYK(ax)); - break; - } - switch (o) - { - case OP_LOADK: - printf("\t; "); PrintConstant(f,bx); - 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_POW: - case OP_DIV: - case OP_IDIV: - case OP_BAND: - case OP_BOR: - case OP_BXOR: - case OP_SHL: - case OP_SHR: - 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 deleted file mode 100644 index f470f0eb27..0000000000 --- a/src/luaconf.h +++ /dev/null @@ -1,743 +0,0 @@ -/* -** $Id: luaconf.h,v 1.235 2014/12/16 17:17:30 roberto Exp $ -** Configuration file for Lua -** See Copyright Notice in lua.h -*/ - - -#ifndef luaconf_h -#define luaconf_h - -#include -#include - - -/* -** =================================================================== -** Search for "@@" to find all configurable definitions. -** =================================================================== -*/ - - -/* -** {==================================================================== -** System Configuration: macros to adapt (if needed) Lua to some -** particular platform, for instance compiling it with 32-bit numbers or -** restricting it to C89. -** ===================================================================== -*/ - -/* -@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. You -** can also define LUA_32BITS in the make file, but changing here you -** ensure that all software connected to Lua will be compiled with the -** same configuration. -*/ -/* #define LUA_32BITS */ - - -/* -@@ LUA_USE_C89 controls the use of non-ISO-C89 features. -** Define it if you want Lua to avoid the use of a few C99 features -** or Windows-specific features on Windows. -*/ -/* #define LUA_USE_C89 */ - - -/* -** By default, Lua on Windows use (some) specific Windows features -*/ -#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE) -#define LUA_USE_WINDOWS /* enable goodies for regular Windows */ -#endif - - -#if defined(LUA_USE_WINDOWS) -#define LUA_DL_DLL /* enable support for DLL */ -#define LUA_USE_C89 /* broadly, Windows is C89 */ -#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_USE_DLOPEN /* MacOS does not need -ldl */ -#define LUA_USE_READLINE /* needs an extra library: -lreadline */ -#endif - - -/* -@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for -** C89 ('long' and 'double'); Windows always has '__int64', so it does -** not need to use this case. -*/ -#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS) -#define LUA_C89_NUMBERS -#endif - - - -/* -@@ LUAI_BITSINT defines the (minimum) number of bits in an 'int'. -*/ -/* avoid undefined shifts */ -#if ((INT_MAX >> 15) >> 15) >= 1 -#define LUAI_BITSINT 32 -#else -/* 'int' always must have at least 16 bits */ -#define LUAI_BITSINT 16 -#endif - - -/* -@@ LUA_INT_INT / LUA_INT_LONG / LUA_INT_LONGLONG defines the type for -** Lua integers. -@@ LUA_REAL_FLOAT / LUA_REAL_DOUBLE / LUA_REAL_LONGDOUBLE defines -** the type for Lua floats. -** Lua should work fine with any mix of these options (if supported -** by your C compiler). The usual configurations are 64-bit integers -** and 'double' (the default), 32-bit integers and 'float' (for -** restricted platforms), and 'long'/'double' (for C compilers not -** compliant with C99, which may not have support for 'long long'). -*/ - -#if defined(LUA_32BITS) /* { */ -/* -** Small Lua (32-bit integers and 'float') -*/ -#if LUAI_BITSINT >= 32 /* use 'int' if big enough */ -#define LUA_INT_INT -#else /* otherwise use 'long' */ -#define LUA_INT_LONG -#endif -#define LUA_REAL_FLOAT - -#elif defined(LUA_C89_NUMBERS) /* }{ */ -/* -** largest types available for C89 ('long' and 'double') -*/ -#define LUA_INT_LONG -#define LUA_REAL_DOUBLE - -#else /* }{ */ -/* -** default configuration for 64-bit Lua ('long long' and 'double') -*/ -#define LUA_INT_LONGLONG -#define LUA_REAL_DOUBLE - -#endif /* } */ - -/* }================================================================== */ - - - - -/* -** {================================================================== -** Configuration for Paths. -** =================================================================== -*/ - -/* -@@ 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. -*/ -#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR -#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. -*/ -#define LUA_LDIR "!\\lua\\" -#define LUA_CDIR "!\\" -#define LUA_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\" -#define LUA_PATH_DEFAULT \ - LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ - LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \ - LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \ - ".\\?.lua;" ".\\?\\init.lua" -#define LUA_CPATH_DEFAULT \ - LUA_CDIR"?.dll;" \ - LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \ - LUA_CDIR"loadall.dll;" ".\\?.dll" - -#else /* }{ */ - -#define LUA_ROOT "/usr/local/" -#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;" "./?/init.lua" -#define LUA_CPATH_DEFAULT \ - LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.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 - -/* }================================================================== */ - - -/* -** {================================================================== -** Marks for exported symbols in the C code -** =================================================================== -*/ - -/* -@@ LUA_API is a mark for all core API 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 -** 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 - -#endif /* } */ - - -/* 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_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. 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(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ - defined(__ELF__) /* { */ -#define LUAI_FUNC __attribute__((visibility("hidden"))) extern -#else /* }{ */ -#define LUAI_FUNC extern -#endif /* } */ - -#define LUAI_DDEC LUAI_FUNC -#define LUAI_DDEF /* empty */ - -/* }================================================================== */ - - -/* -** {================================================================== -** Compatibility with previous versions -** =================================================================== -*/ - -/* -@@ LUA_COMPAT_5_2 controls other macros for compatibility with Lua 5.2. -@@ LUA_COMPAT_5_1 controls other macros for compatibility with Lua 5.1. -** You can define it to get all options, or change specific options -** to fit your specific needs. -*/ -#if defined(LUA_COMPAT_5_2) /* { */ - -/* -@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated -** functions in the mathematical library. -*/ -#define LUA_COMPAT_MATHLIB - -/* -@@ LUA_COMPAT_BITLIB controls the presence of library 'bit32'. -*/ -#define LUA_COMPAT_BITLIB - -/* -@@ LUA_COMPAT_IPAIRS controls the effectiveness of the __ipairs metamethod. -*/ -#define LUA_COMPAT_IPAIRS - -/* -@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for -** manipulating other integer types (lua_pushunsigned, lua_tounsigned, -** luaL_checkint, luaL_checklong, etc.) -*/ -#define LUA_COMPAT_APIINTCASTS - - -/* -@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a -@@ a float mark ('.0'). -** This macro is not on by default even in compatibility mode, -** because this is not really an incompatibility. -*/ -/* #define LUA_COMPAT_FLOATSTRING */ - -#endif /* } */ - - -#if defined(LUA_COMPAT_5_1) /* { */ - -/* -@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'. -** You can replace it with 'table.unpack'. -*/ -#define LUA_COMPAT_UNPACK - -/* -@@ LUA_COMPAT_LOADERS controls the presence of table 'package.loaders'. -** You can replace it with 'package.searchers'. -*/ -#define LUA_COMPAT_LOADERS - -/* -@@ 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)), \ - lua_pushlightuserdata(L,(u)), \ - lua_pcall(L,1,0,0)) - - -/* -@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library. -** You can rewrite 'log10(x)' as 'log(x, 10)'. -*/ -#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. -*/ -#define LUA_COMPAT_MAXN - -/* -@@ 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_strlen(L,i) lua_rawlen(L, (i)) - -#define lua_objlen(L,i) lua_rawlen(L, (i)) - -#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_MODULE controls compatibility with previous -** module functions 'module' (Lua) and 'luaL_register' (C). -*/ -#define LUA_COMPAT_MODULE - -#endif /* } */ - -/* }================================================================== */ - - - -/* -** {================================================================== -** Configuration for Numbers. -** Change these definitions if no predefined LUA_REAL_* / LUA_INT_* -** satisfy your needs. -** =================================================================== -*/ - -/* -@@ LUA_NUMBER is the floating-point type used by Lua. -** -@@ LUAI_UACNUMBER is the result of an 'usual argument conversion' -@@ over a floating number. -** -@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats. -@@ LUA_NUMBER_FMT is the format for writing floats. -@@ lua_number2str converts a float to a string. -** -@@ l_mathop allows the addition of an 'l' or 'f' to all math operations. -** -@@ lua_str2number converts a decimal numeric string to a number. -*/ - -#if defined(LUA_REAL_FLOAT) /* { single float */ - -#define LUA_NUMBER float - -#define LUAI_UACNUMBER double - -#define LUA_NUMBER_FRMLEN "" -#define LUA_NUMBER_FMT "%.7g" - -#define l_mathop(op) op##f - -#define lua_str2number(s,p) strtof((s), (p)) - - -#elif defined(LUA_REAL_LONGDOUBLE) /* }{ long double */ - -#define LUA_NUMBER long double - -#define LUAI_UACNUMBER long double - -#define LUA_NUMBER_FRMLEN "L" -#define LUA_NUMBER_FMT "%.19Lg" - -#define l_mathop(op) op##l - -#define lua_str2number(s,p) strtold((s), (p)) - -#elif defined(LUA_REAL_DOUBLE) /* }{ double */ - -#define LUA_NUMBER double - -#define LUAI_UACNUMBER double - -#define LUA_NUMBER_FRMLEN "" -#define LUA_NUMBER_FMT "%.14g" - -#define l_mathop(op) op - -#define lua_str2number(s,p) strtod((s), (p)) - -#else /* }{ */ - -#error "numeric real type not defined" - -#endif /* } */ - - -#define l_floor(x) (l_mathop(floor)(x)) - -#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n)) - - -/* -@@ lua_numbertointeger converts a float number to an integer, or -** returns 0 if float is not within the range of a lua_Integer. -** (The range comparisons are tricky because of rounding. The tests -** here assume a two-complement representation, where MININTEGER always -** has an exact representation as a float; MAXINTEGER may not have one, -** and therefore its conversion to float may have an ill-defined value.) -*/ -#define lua_numbertointeger(n,p) \ - ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \ - (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \ - (*(p) = (LUA_INTEGER)(n), 1)) - - -/* -@@ The luai_num* macros define the primitive operations over numbers. -** They should work for any size of floating numbers. -*/ - -/* the following operations need the math library */ -#if defined(lobject_c) || defined(lvm_c) -#include - -/* floor division (defined as 'floor(a/b)') */ -#define luai_numidiv(L,a,b) ((void)L, l_mathop(floor)((a)/(b))) - -/* -** module: defined as 'a - floor(a/b)*b'; the previous definition gives -** NaN when 'b' is huge, but the result should be 'a'. 'fmod' gives the -** result of 'a - trunc(a/b)*b', and therefore must be corrected when -** 'trunc(a/b) ~= floor(a/b)'. That happens when the division has a -** non-integer negative result, which is equivalent to the test below -*/ -#define luai_nummod(L,a,b,m) \ - { (m) = l_mathop(fmod)(a,b); if ((m)*(b) < 0) (m) += (b); } - -/* exponentiation */ -#define luai_numpow(L,a,b) ((void)L, l_mathop(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))) -#endif - - -/* -** The following macro checks whether an operation is not safe to be -** performed by the constant folder. It should result in zero only if -** the operation is safe. -*/ -#define luai_numinvalidop(op,a,b) 0 - - -/* -@@ LUA_INTEGER is the integer type used by Lua. -** -@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER. -** -@@ LUAI_UACINT is the result of an 'usual argument conversion' -@@ over a lUA_INTEGER. -@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers. -@@ LUA_INTEGER_FMT is the format for writing integers. -@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER. -@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER. -@@ lua_integer2str converts an integer to a string. -*/ - - -/* The following definitions are good for most cases here */ - -#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d" -#define lua_integer2str(s,n) sprintf((s), LUA_INTEGER_FMT, (n)) - -#define LUAI_UACINT LUA_INTEGER - -/* -** use LUAI_UACINT here to avoid problems with promotions (which -** can turn a comparison between unsigneds into a signed comparison) -*/ -#define LUA_UNSIGNED unsigned LUAI_UACINT - - -/* now the variable definitions */ - -#if defined(LUA_INT_INT) /* { int */ - -#define LUA_INTEGER int -#define LUA_INTEGER_FRMLEN "" - -#define LUA_MAXINTEGER INT_MAX -#define LUA_MININTEGER INT_MIN - -#elif defined(LUA_INT_LONG) /* }{ long */ - -#define LUA_INTEGER long -#define LUA_INTEGER_FRMLEN "l" - -#define LUA_MAXINTEGER LONG_MAX -#define LUA_MININTEGER LONG_MIN - -#elif defined(LUA_INT_LONGLONG) /* }{ long long */ - -#if defined(LLONG_MAX) /* { */ -/* use ISO C99 stuff */ - -#define LUA_INTEGER long long -#define LUA_INTEGER_FRMLEN "ll" - -#define LUA_MAXINTEGER LLONG_MAX -#define LUA_MININTEGER LLONG_MIN - -#elif defined(LUA_USE_WINDOWS) /* }{ */ -/* in Windows, can use specific Windows types */ - -#define LUA_INTEGER __int64 -#define LUA_INTEGER_FRMLEN "I64" - -#define LUA_MAXINTEGER _I64_MAX -#define LUA_MININTEGER _I64_MIN - -#else /* }{ */ - -#error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \ - or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)" - -#endif /* } */ - -#else /* }{ */ - -#error "numeric integer type not defined" - -#endif /* } */ - -/* }================================================================== */ - - -/* -** {================================================================== -** Dependencies with C99 -** =================================================================== -*/ - -/* -@@ lua_strx2number converts an hexadecimal numeric string to a number. -** In C99, 'strtod' does both conversions. Otherwise, you can -** leave 'lua_strx2number' undefined and Lua will provide its own -** implementation. -*/ -#if !defined(LUA_USE_C89) -#define lua_strx2number(s,p) lua_str2number(s,p) -#endif - - -/* -@@ LUA_USE_AFORMAT allows '%a'/'%A' specifiers in 'string.format' -** Enable it if the C function 'printf' supports these specifiers. -** (C99 demands it and Windows also supports it.) -*/ -#if !defined(LUA_USE_C89) || defined(LUA_USE_WINDOWS) -#define LUA_USE_AFORMAT -#endif - - -/* -** 'strtof' and 'opf' variants for math functions are not valid in -** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the -** availability of these variants. ('math.h' is already included in -** all files that use these macros.) -*/ -#if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF)) -#undef l_mathop /* variants not available */ -#undef lua_str2number -#define l_mathop(op) (lua_Number)op /* no variant */ -#define lua_str2number(s,p) ((lua_Number)strtod((s), (p))) -#endif - - -/* -@@ LUA_KCONTEXT is the type of the context ('ctx') for continuation -** functions. It must be a numerical type; Lua will use 'intptr_t' if -** available, otherwise it will use 'ptrdiff_t' (the nearest thing to -** 'intptr_t' in C89) -*/ -#define LUA_KCONTEXT ptrdiff_t - -#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \ - __STDC_VERSION__ >= 199901L -#include -#if defined (INTPTR_MAX) /* even in C99 this type is optional */ -#undef LUA_KCONTEXT -#define LUA_KCONTEXT intptr_t -#endif -#endif - -/* }================================================================== */ - - -/* -** {================================================================== -** Macros that affect the API and must be stable (that is, must be the -** same when you compile Lua and when you compile code that links to -** Lua). You probably do not want/need to change them. -** ===================================================================== -*/ - -/* -@@ 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 from consuming unlimited stack -** space (and to reserve some numbers for pseudo-indices). -*/ -#if LUAI_BITSINT >= 32 -#define LUAI_MAXSTACK 1000000 -#else -#define LUAI_MAXSTACK 15000 -#endif - -/* reserve some space for error handling */ -#define LUAI_FIRSTPSEUDOIDX (-LUAI_MAXSTACK - 1000) - - -/* -@@ LUA_EXTRASPACE defines the size of a raw memory area associated with -** a Lua state with very fast access. -** CHANGE it if you need a different size. -*/ -#define LUA_EXTRASPACE (sizeof(void *)) - - -/* -@@ LUA_IDSIZE gives the maximum size for the description of the source -@@ of a function in debug information. -** CHANGE it if you want a different size. -*/ -#define LUA_IDSIZE 60 - - -/* -@@ 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 - - -/* -@@ 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 ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer))) - -/* }================================================================== */ - - -/* -@@ LUA_QL describes how error messages quote program elements. -** Lua does not use these macros anymore; they are here for -** compatibility only. -*/ -#define LUA_QL(x) "'" x "'" -#define LUA_QS LUA_QL("%s") - - - - -/* =================================================================== */ - -/* -** Local configuration. You can use this space to add your redefinitions -** without modifying the main part of the file. -*/ - - - - - -#endif - diff --git a/src/lualib.h b/src/lualib.h deleted file mode 100644 index 5165c0fb3f..0000000000 --- a/src/lualib.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -** $Id: lualib.h,v 1.44 2014/02/06 17:32:33 roberto Exp $ -** Lua standard libraries -** See Copyright Notice in lua.h -*/ - - -#ifndef lualib_h -#define lualib_h - -#include "lua.h" - - - -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); - -#define LUA_IOLIBNAME "io" -LUAMOD_API int (luaopen_io) (lua_State *L); - -#define LUA_OSLIBNAME "os" -LUAMOD_API int (luaopen_os) (lua_State *L); - -#define LUA_STRLIBNAME "string" -LUAMOD_API int (luaopen_string) (lua_State *L); - -#define LUA_UTF8LIBNAME "utf8" -LUAMOD_API int (luaopen_utf8) (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); - -#define LUA_DBLIBNAME "debug" -LUAMOD_API int (luaopen_debug) (lua_State *L); - -#define LUA_LOADLIBNAME "package" -LUAMOD_API int (luaopen_package) (lua_State *L); - - -/* open all previous libraries */ -LUALIB_API void (luaL_openlibs) (lua_State *L); - - - -#if !defined(lua_assert) -#define lua_assert(x) ((void)0) -#endif - - -#endif diff --git a/src/lundump.c b/src/lundump.c deleted file mode 100644 index 510f325827..0000000000 --- a/src/lundump.c +++ /dev/null @@ -1,277 +0,0 @@ -/* -** $Id: lundump.c,v 2.41 2014/11/02 19:19:04 roberto Exp $ -** load precompiled Lua chunks -** See Copyright Notice in lua.h -*/ - -#define lundump_c -#define LUA_CORE - -#include "lprefix.h" - - -#include - -#include "lua.h" - -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "lmem.h" -#include "lobject.h" -#include "lstring.h" -#include "lundump.h" -#include "lzio.h" - - -#if !defined(luai_verifycode) -#define luai_verifycode(L,b,f) /* empty */ -#endif - - -typedef struct { - lua_State *L; - ZIO *Z; - Mbuffer *b; - const char *name; -} LoadState; - - -static l_noret error(LoadState *S, const char *why) { - luaO_pushfstring(S->L, "%s: %s precompiled chunk", S->name, why); - luaD_throw(S->L, LUA_ERRSYNTAX); -} - - -/* -** All high-level loads go through LoadVector; you can change it to -** adapt to the endianness of the input -*/ -#define LoadVector(S,b,n) LoadBlock(S,b,(n)*sizeof((b)[0])) - -static void LoadBlock (LoadState *S, void *b, size_t size) { - if (luaZ_read(S->Z, b, size) != 0) - error(S, "truncated"); -} - - -#define LoadVar(S,x) LoadVector(S,&x,1) - - -static lu_byte LoadByte (LoadState *S) { - lu_byte x; - LoadVar(S, x); - return x; -} - - -static int LoadInt (LoadState *S) { - int x; - LoadVar(S, x); - return x; -} - - -static lua_Number LoadNumber (LoadState *S) { - lua_Number x; - LoadVar(S, x); - return x; -} - - -static lua_Integer LoadInteger (LoadState *S) { - lua_Integer x; - LoadVar(S, x); - return x; -} - - -static TString *LoadString (LoadState *S) { - size_t size = LoadByte(S); - if (size == 0xFF) - LoadVar(S, size); - if (size == 0) - return NULL; - else { - char *s = luaZ_openspace(S->L, S->b, --size); - LoadVector(S, s, size); - return luaS_newlstr(S->L, s, size); - } -} - - -static void LoadCode (LoadState *S, Proto *f) { - int n = LoadInt(S); - f->code = luaM_newvector(S->L, n, Instruction); - f->sizecode = n; - LoadVector(S, f->code, n); -} - - -static void LoadFunction(LoadState *S, Proto *f, TString *psource); - - -static void LoadConstants (LoadState *S, Proto *f) { - int i; - int n = LoadInt(S); - f->k = luaM_newvector(S->L, n, TValue); - f->sizek = n; - for (i = 0; i < n; i++) - setnilvalue(&f->k[i]); - for (i = 0; i < n; i++) { - TValue *o = &f->k[i]; - int t = LoadByte(S); - switch (t) { - case LUA_TNIL: - setnilvalue(o); - break; - case LUA_TBOOLEAN: - setbvalue(o, LoadByte(S)); - break; - case LUA_TNUMFLT: - setfltvalue(o, LoadNumber(S)); - break; - case LUA_TNUMINT: - setivalue(o, LoadInteger(S)); - break; - case LUA_TSHRSTR: - case LUA_TLNGSTR: - setsvalue2n(S->L, o, LoadString(S)); - break; - default: - lua_assert(0); - } - } -} - - -static void LoadProtos (LoadState *S, Proto *f) { - int i; - int n = LoadInt(S); - f->p = luaM_newvector(S->L, n, Proto *); - f->sizep = n; - for (i = 0; i < n; i++) - f->p[i] = NULL; - for (i = 0; i < n; i++) { - f->p[i] = luaF_newproto(S->L); - LoadFunction(S, f->p[i], 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; i < n; i++) - f->upvalues[i].name = NULL; - for (i = 0; i < n; i++) { - f->upvalues[i].instack = LoadByte(S); - f->upvalues[i].idx = LoadByte(S); - } -} - - -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); - n = LoadInt(S); - f->locvars = luaM_newvector(S->L, n, LocVar); - f->sizelocvars = n; - for (i = 0; i < n; i++) - f->locvars[i].varname = NULL; - for (i = 0; i < n; i++) { - f->locvars[i].varname = LoadString(S); - f->locvars[i].startpc = LoadInt(S); - f->locvars[i].endpc = LoadInt(S); - } - n = LoadInt(S); - for (i = 0; i < n; i++) - f->upvalues[i].name = LoadString(S); -} - - -static void LoadFunction (LoadState *S, Proto *f, TString *psource) { - f->source = LoadString(S); - if (f->source == NULL) /* no source in dump? */ - f->source = psource; /* reuse parent's source */ - f->linedefined = LoadInt(S); - f->lastlinedefined = LoadInt(S); - f->numparams = LoadByte(S); - f->is_vararg = LoadByte(S); - f->maxstacksize = LoadByte(S); - LoadCode(S, f); - LoadConstants(S, f); - LoadUpvalues(S, f); - LoadProtos(S, f); - LoadDebug(S, f); -} - - -static void checkliteral (LoadState *S, const char *s, const char *msg) { - char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */ - size_t len = strlen(s); - LoadVector(S, buff, len); - if (memcmp(s, buff, len) != 0) - error(S, msg); -} - - -static void fchecksize (LoadState *S, size_t size, const char *tname) { - if (LoadByte(S) != size) - error(S, luaO_pushfstring(S->L, "%s size mismatch in", tname)); -} - - -#define checksize(S,t) fchecksize(S,sizeof(t),#t) - -static void checkHeader (LoadState *S) { - checkliteral(S, LUA_SIGNATURE + 1, "not a"); /* 1st char already checked */ - if (LoadByte(S) != LUAC_VERSION) - error(S, "version mismatch in"); - if (LoadByte(S) != LUAC_FORMAT) - error(S, "format mismatch in"); - checkliteral(S, LUAC_DATA, "corrupted"); - checksize(S, int); - checksize(S, size_t); - checksize(S, Instruction); - checksize(S, lua_Integer); - checksize(S, lua_Number); - if (LoadInteger(S) != LUAC_INT) - error(S, "endianness mismatch in"); - if (LoadNumber(S) != LUAC_NUM) - error(S, "float format mismatch in"); -} - - -/* -** load precompiled chunk -*/ -LClosure *luaU_undump(lua_State *L, ZIO *Z, Mbuffer *buff, - const char *name) { - LoadState S; - LClosure *cl; - if (*name == '@' || *name == '=') - S.name = name + 1; - else if (*name == LUA_SIGNATURE[0]) - S.name = "binary string"; - else - S.name = name; - S.L = L; - S.Z = Z; - S.b = buff; - checkHeader(&S); - cl = luaF_newLclosure(L, LoadByte(&S)); - setclLvalue(L, L->top, cl); - incr_top(L); - cl->p = luaF_newproto(L); - LoadFunction(&S, cl->p, NULL); - lua_assert(cl->nupvalues == cl->p->sizeupvalues); - luai_verifycode(L, buff, cl->p); - return cl; -} - diff --git a/src/lundump.h b/src/lundump.h deleted file mode 100644 index ef43d51264..0000000000 --- a/src/lundump.h +++ /dev/null @@ -1,33 +0,0 @@ -/* -** $Id: lundump.h,v 1.44 2014/06/19 18:27:20 roberto Exp $ -** load precompiled Lua chunks -** See Copyright Notice in lua.h -*/ - -#ifndef lundump_h -#define lundump_h - -#include "llimits.h" -#include "lobject.h" -#include "lzio.h" - - -/* data to catch conversion errors */ -#define LUAC_DATA "\x19\x93\r\n\x1a\n" - -#define LUAC_INT 0x5678 -#define LUAC_NUM cast_num(370.5) - -#define MYINT(s) (s[0]-'0') -#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR)) -#define LUAC_FORMAT 0 /* this is the official format */ - -/* load one chunk; from lundump.c */ -LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, - const char* name); - -/* dump one chunk; from ldump.c */ -LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, - void* data, int strip); - -#endif diff --git a/src/lutf8lib.c b/src/lutf8lib.c deleted file mode 100644 index be4f087f76..0000000000 --- a/src/lutf8lib.c +++ /dev/null @@ -1,255 +0,0 @@ -/* -** $Id: lutf8lib.c,v 1.13 2014/11/02 19:19:04 roberto Exp $ -** Standard library for UTF-8 manipulation -** See Copyright Notice in lua.h -*/ - -#define lutf8lib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - -#define MAXUNICODE 0x10FFFF - -#define iscont(p) ((*(p) & 0xC0) == 0x80) - - -/* from strlib */ -/* translate a relative string position: negative means back from end */ -static lua_Integer u_posrelat (lua_Integer pos, size_t len) { - if (pos >= 0) return pos; - else if (0u - (size_t)pos > len) return 0; - else return (lua_Integer)len + pos + 1; -} - - -/* -** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid. -*/ -static const char *utf8_decode (const char *o, int *val) { - static unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF}; - const unsigned char *s = (const unsigned char *)o; - unsigned int c = s[0]; - unsigned int res = 0; /* final result */ - if (c < 0x80) /* ascii? */ - res = c; - else { - int count = 0; /* to count number of continuation bytes */ - while (c & 0x40) { /* still have continuation bytes? */ - int cc = s[++count]; /* read next byte */ - if ((cc & 0xC0) != 0x80) /* not a continuation byte? */ - return NULL; /* invalid byte sequence */ - res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ - c <<= 1; /* to test next bit */ - } - res |= ((c & 0x7F) << (count * 5)); /* add first byte */ - if (count > 3 || res > MAXUNICODE || res <= limits[count]) - return NULL; /* invalid byte sequence */ - s += count; /* skip continuation bytes read */ - } - if (val) *val = res; - return (const char *)s + 1; /* +1 to include first byte */ -} - - -/* -** utf8len(s [, i [, j]]) --> number of characters that start in the -** range [i,j], or nil + current position if 's' is not well formed in -** that interval -*/ -static int utflen (lua_State *L) { - int n = 0; - size_t len; - const char *s = luaL_checklstring(L, 1, &len); - lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); - lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len); - luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2, - "initial position out of string"); - luaL_argcheck(L, --posj < (lua_Integer)len, 3, - "final position out of string"); - while (posi <= posj) { - const char *s1 = utf8_decode(s + posi, NULL); - if (s1 == NULL) { /* conversion error? */ - lua_pushnil(L); /* return nil ... */ - lua_pushinteger(L, posi + 1); /* ... and current position */ - return 2; - } - posi = s1 - s; - n++; - } - lua_pushinteger(L, n); - return 1; -} - - -/* -** codepoint(s, [i, [j]]) -> returns codepoints for all characters -** that start in the range [i,j] -*/ -static int codepoint (lua_State *L) { - size_t len; - const char *s = luaL_checklstring(L, 1, &len); - lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); - lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len); - int n; - const char *se; - luaL_argcheck(L, posi >= 1, 2, "out of range"); - luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range"); - if (posi > pose) return 0; /* empty interval; return no values */ - n = (int)(pose - posi + 1); - if (posi + n <= pose) /* (lua_Integer -> int) overflow? */ - return luaL_error(L, "string slice too long"); - luaL_checkstack(L, n, "string slice too long"); - n = 0; - se = s + pose; - for (s += posi - 1; s < se;) { - int code; - s = utf8_decode(s, &code); - if (s == NULL) - return luaL_error(L, "invalid UTF-8 code"); - lua_pushinteger(L, code); - n++; - } - return n; -} - - -static void pushutfchar (lua_State *L, int arg) { - lua_Integer code = luaL_checkinteger(L, arg); - luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, "value out of range"); - lua_pushfstring(L, "%U", (long)code); -} - - -/* -** utfchar(n1, n2, ...) -> char(n1)..char(n2)... -*/ -static int utfchar (lua_State *L) { - int n = lua_gettop(L); /* number of arguments */ - if (n == 1) /* optimize common case of single char */ - pushutfchar(L, 1); - else { - int i; - luaL_Buffer b; - luaL_buffinit(L, &b); - for (i = 1; i <= n; i++) { - pushutfchar(L, i); - luaL_addvalue(&b); - } - luaL_pushresult(&b); - } - return 1; -} - - -/* -** offset(s, n, [i]) -> index where n-th character counting from -** position 'i' starts; 0 means character at 'i'. -*/ -static int byteoffset (lua_State *L) { - size_t len; - const char *s = luaL_checklstring(L, 1, &len); - lua_Integer n = luaL_checkinteger(L, 2); - lua_Integer posi = (n >= 0) ? 1 : len + 1; - posi = u_posrelat(luaL_optinteger(L, 3, posi), len); - luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3, - "position out of range"); - if (n == 0) { - /* find beginning of current byte sequence */ - while (posi > 0 && iscont(s + posi)) posi--; - } - else { - if (iscont(s + posi)) - luaL_error(L, "initial position is a continuation byte"); - if (n < 0) { - while (n < 0 && posi > 0) { /* move back */ - do { /* find beginning of previous character */ - posi--; - } while (posi > 0 && iscont(s + posi)); - n++; - } - } - else { - n--; /* do not move for 1st character */ - while (n > 0 && posi < (lua_Integer)len) { - do { /* find beginning of next character */ - posi++; - } while (iscont(s + posi)); /* (cannot pass final '\0') */ - n--; - } - } - } - if (n == 0) /* did it find given character? */ - lua_pushinteger(L, posi + 1); - else /* no such character */ - lua_pushnil(L); - return 1; -} - - -static int iter_aux (lua_State *L) { - size_t len; - const char *s = luaL_checklstring(L, 1, &len); - lua_Integer n = lua_tointeger(L, 2) - 1; - if (n < 0) /* first iteration? */ - n = 0; /* start from here */ - else if (n < (lua_Integer)len) { - n++; /* skip current byte */ - while (iscont(s + n)) n++; /* and its continuations */ - } - if (n >= (lua_Integer)len) - return 0; /* no more codepoints */ - else { - int code; - const char *next = utf8_decode(s + n, &code); - if (next == NULL || iscont(next)) - return luaL_error(L, "invalid UTF-8 code"); - lua_pushinteger(L, n + 1); - lua_pushinteger(L, code); - return 2; - } -} - - -static int iter_codes (lua_State *L) { - luaL_checkstring(L, 1); - lua_pushcfunction(L, iter_aux); - lua_pushvalue(L, 1); - lua_pushinteger(L, 0); - return 3; -} - - -/* pattern to match a single UTF-8 character */ -#define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*" - - -static struct luaL_Reg funcs[] = { - {"offset", byteoffset}, - {"codepoint", codepoint}, - {"char", utfchar}, - {"len", utflen}, - {"codes", iter_codes}, - /* placeholders */ - {"charpattern", NULL}, - {NULL, NULL} -}; - - -LUAMOD_API int luaopen_utf8 (lua_State *L) { - luaL_newlib(L, funcs); - lua_pushliteral(L, UTF8PATT); - lua_setfield(L, -2, "charpattern"); - return 1; -} - diff --git a/src/lvm.c b/src/lvm.c deleted file mode 100644 index 09a9afa3ad..0000000000 --- a/src/lvm.c +++ /dev/null @@ -1,1138 +0,0 @@ -/* -** $Id: lvm.c,v 2.230 2014/11/21 12:15:00 roberto Exp $ -** Lua virtual machine -** See Copyright Notice in lua.h -*/ - -#define lvm_c -#define LUA_CORE - -#include "lprefix.h" - - -#include -#include -#include -#include - -#include "lua.h" - -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "lgc.h" -#include "lobject.h" -#include "lopcodes.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "ltm.h" -#include "lvm.h" - - -/* -** You can define LUA_FLOORN2I if you want to convert floats to integers -** by flooring them (instead of raising an error if they are not -** integral values) -*/ -#if !defined(LUA_FLOORN2I) -#define LUA_FLOORN2I 0 -#endif - - -/* limit for table tag-method chains (to avoid loops) */ -#define MAXTAGLOOP 2000 - - -/* -** Similar to 'tonumber', but does not attempt to convert strings and -** ensure correct precision (no extra bits). Used in comparisons. -*/ -static int tofloat (const TValue *obj, lua_Number *n) { - if (ttisfloat(obj)) *n = fltvalue(obj); - else if (ttisinteger(obj)) { - volatile lua_Number x = cast_num(ivalue(obj)); /* avoid extra precision */ - *n = x; - } - else { - *n = 0; /* to avoid warnings */ - return 0; - } - return 1; -} - - -/* -** Try to convert a value to a float. The float case is already handled -** by the macro 'tonumber'. -*/ -int luaV_tonumber_ (const TValue *obj, lua_Number *n) { - TValue v; - if (ttisinteger(obj)) { - *n = cast_num(ivalue(obj)); - return 1; - } - else if (cvt2num(obj) && /* string convertible to number? */ - luaO_str2num(svalue(obj), &v) == tsvalue(obj)->len + 1) { - /* convert result of 'luaO_str2num' to a float */ - *n = (ttisinteger(&v)) ? cast_num(ivalue(&v)) : fltvalue(&v); - return 1; - } - else - return 0; /* conversion failed */ -} - - -/* -** try to convert a value to an integer, rounding according to 'mode': -** mode == 0: accepts only integral values -** mode == 1: takes the floor of the number -** mode == 2: takes the ceil of the number -*/ -static int tointeger_aux (const TValue *obj, lua_Integer *p, int mode) { - TValue v; - again: - if (ttisfloat(obj)) { - lua_Number n = fltvalue(obj); - lua_Number f = l_floor(n); - if (n != f) { /* not an integral value? */ - if (mode == 0) return 0; /* fails if mode demands integral value */ - else if (mode > 1) /* needs ceil? */ - f += 1; /* convert floor to ceil (remember: n != f) */ - } - return lua_numbertointeger(f, p); - } - else if (ttisinteger(obj)) { - *p = ivalue(obj); - return 1; - } - else if (cvt2num(obj) && - luaO_str2num(svalue(obj), &v) == tsvalue(obj)->len + 1) { - obj = &v; - goto again; /* convert result from 'luaO_str2num' to an integer */ - } - return 0; /* conversion failed */ -} - - -/* -** try to convert a value to an integer -*/ -int luaV_tointeger_ (const TValue *obj, lua_Integer *p) { - return tointeger_aux(obj, p, LUA_FLOORN2I); -} - - -/* -** Try to convert a 'for' limit to an integer, preserving the -** semantics of the loop. -** (The following explanation assumes a non-negative step; it is valid -** for negative steps mutatis mutandis.) -** If the limit can be converted to an integer, rounding down, that is -** it. -** Otherwise, check whether the limit can be converted to a number. If -** the number is too large, it is OK to set the limit as LUA_MAXINTEGER, -** which means no limit. If the number is too negative, the loop -** should not run, because any initial integer value is larger than the -** limit. So, it sets the limit to LUA_MININTEGER. 'stopnow' corrects -** the extreme case when the initial value is LUA_MININTEGER, in which -** case the LUA_MININTEGER limit would still run the loop once. -*/ -static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step, - int *stopnow) { - *stopnow = 0; /* usually, let loops run */ - if (!tointeger_aux(obj, p, (step < 0 ? 2 : 1))) { /* not fit in integer? */ - lua_Number n; /* try to convert to float */ - if (!tonumber(obj, &n)) /* cannot convert to float? */ - return 0; /* not a number */ - if (n > 0) { /* if true, float is larger than max integer */ - *p = LUA_MAXINTEGER; - if (step < 0) *stopnow = 1; - } - else { /* float is smaller than min integer */ - *p = LUA_MININTEGER; - if (step >= 0) *stopnow = 1; - } - } - return 1; -} - - -/* -** Main function for table access (invoking metamethods if needed). -** Compute 'val = t[key]' -*/ -void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { - int loop; /* counter to avoid infinite loops */ - 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 get */ - if (!ttisnil(res) || /* result is not nil? */ - (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ - setobj2s(L, val, res); /* result is the raw get */ - return; - } - /* else will try metamethod */ - } - else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) - luaG_typeerror(L, t, "index"); /* no metamethod */ - if (ttisfunction(tm)) { /* metamethod is a function */ - luaT_callTM(L, tm, t, key, val, 1); - return; - } - t = tm; /* else repeat access over 'tm' */ - } - luaG_runerror(L, "gettable chain too long; possible loop"); -} - - -/* -** Main function for table assignment (invoking metamethods if needed). -** Compute 't[key] = val' -*/ -void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { - int loop; /* counter to avoid infinite loops */ - for (loop = 0; loop < MAXTAGLOOP; loop++) { - const TValue *tm; - if (ttistable(t)) { /* 't' is a table? */ - Table *h = hvalue(t); - TValue *oldval = cast(TValue *, luaH_get(h, key)); - /* if previous value is not nil, there must be a previous entry - in the table; 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, h, val); - return; - } - /* else will try the metamethod */ - } - else /* not a table; check metamethod */ - if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) - luaG_typeerror(L, t, "index"); - /* try the metamethod */ - if (ttisfunction(tm)) { - luaT_callTM(L, tm, t, key, val, 0); - return; - } - t = tm; /* else repeat assignment over 'tm' */ - } - luaG_runerror(L, "settable chain too long; possible loop"); -} - - -/* -** Compare two strings 'ls' x 'rs', returning an integer smaller-equal- -** -larger than zero if 'ls' is smaller-equal-larger than 'rs'. -** The code is a little tricky because it allows '\0' in the strings -** and it uses 'strcoll' (to respect locales) for each segments -** of the strings. -*/ -static int l_strcmp (const TString *ls, const TString *rs) { - const char *l = getstr(ls); - size_t ll = ls->len; - const char *r = getstr(rs); - size_t lr = rs->len; - for (;;) { /* for each segment */ - int temp = strcoll(l, r); - if (temp != 0) /* not equal? */ - return temp; /* done */ - else { /* strings are equal up to a '\0' */ - size_t len = strlen(l); /* index of first '\0' in both strings */ - if (len == lr) /* 'rs' is finished? */ - return (len == ll) ? 0 : 1; /* check 'ls' */ - else if (len == ll) /* 'ls' is finished? */ - return -1; /* 'ls' is smaller than 'rs' ('rs' is not finished) */ - /* both strings longer than 'len'; go on comparing after the '\0' */ - len++; - l += len; ll -= len; r += len; lr -= len; - } - } -} - - -/* -** Main operation less than; return 'l < r'. -*/ -int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { - int res; - lua_Number nl, nr; - if (ttisinteger(l) && ttisinteger(r)) /* both operands are integers? */ - return (ivalue(l) < ivalue(r)); - else if (tofloat(l, &nl) && tofloat(r, &nr)) /* both are numbers? */ - return luai_numlt(nl, nr); - else if (ttisstring(l) && ttisstring(r)) /* both are strings? */ - return l_strcmp(tsvalue(l), tsvalue(r)) < 0; - else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0) /* no metamethod? */ - luaG_ordererror(L, l, r); /* error */ - return res; -} - - -/* -** Main operation less than or equal to; return 'l <= r'. -*/ -int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { - int res; - lua_Number nl, nr; - if (ttisinteger(l) && ttisinteger(r)) /* both operands are integers? */ - return (ivalue(l) <= ivalue(r)); - else if (tofloat(l, &nl) && tofloat(r, &nr)) /* both are numbers? */ - return luai_numle(nl, nr); - else if (ttisstring(l) && ttisstring(r)) /* both are strings? */ - return l_strcmp(tsvalue(l), tsvalue(r)) <= 0; - else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* first try 'le' */ - return res; - else if ((res = luaT_callorderTM(L, r, l, TM_LT)) < 0) /* else try 'lt' */ - luaG_ordererror(L, l, r); - return !res; -} - - -/* -** Main operation for equality of Lua values; return 't1 == t2'. -** L == NULL means raw equality (no metamethods) -*/ -int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { - const TValue *tm; - if (ttype(t1) != ttype(t2)) { /* not the same variant? */ - if (ttnov(t1) != ttnov(t2) || ttnov(t1) != LUA_TNUMBER) - return 0; /* only numbers can be equal with different variants */ - else { /* two numbers with different variants */ - lua_Number n1, n2; /* compare them as floats */ - lua_assert(ttisnumber(t1) && ttisnumber(t2)); - cast_void(tofloat(t1, &n1)); cast_void(tofloat(t2, &n2)); - return luai_numeq(n1, n2); - } - } - /* values have same type and same variant */ - switch (ttype(t1)) { - case LUA_TNIL: return 1; - case LUA_TNUMINT: return (ivalue(t1) == ivalue(t2)); - case LUA_TNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(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_TSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2)); - case LUA_TLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2)); - case LUA_TUSERDATA: { - if (uvalue(t1) == uvalue(t2)) return 1; - else if (L == NULL) return 0; - tm = fasttm(L, uvalue(t1)->metatable, TM_EQ); - if (tm == NULL) - tm = fasttm(L, 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 = fasttm(L, hvalue(t1)->metatable, TM_EQ); - if (tm == NULL) - tm = fasttm(L, hvalue(t2)->metatable, TM_EQ); - break; /* will try TM */ - } - default: - return gcvalue(t1) == gcvalue(t2); - } - if (tm == NULL) /* no TM? */ - return 0; /* objects are different */ - luaT_callTM(L, tm, t1, t2, L->top, 1); /* call TM */ - return !l_isfalse(L->top); -} - - -/* macro used by 'luaV_concat' to ensure that element at 'o' is a string */ -#define tostring(L,o) \ - (ttisstring(o) || (cvt2str(o) && (luaO_tostring(L, o), 1))) - -/* -** Main operation for concatenation: concat 'total' values in the stack, -** from 'L->top - total' up to 'L->top - 1'. -*/ -void luaV_concat (lua_State *L, int total) { - lua_assert(total >= 2); - do { - StkId top = L->top; - int n = 2; /* number of elements handled in this pass (at least 2) */ - if (!(ttisstring(top-2) || cvt2str(top-2)) || !tostring(L, top-1)) - luaT_trybinTM(L, top-2, top-1, top-2, TM_CONCAT); - else if (tsvalue(top-1)->len == 0) /* second operand is empty? */ - cast_void(tostring(L, top - 2)); /* result is first operand */ - else if (ttisstring(top-2) && tsvalue(top-2)->len == 0) { - setobjs2s(L, top - 2, top - 1); /* result is second op. */ - } - else { - /* at least two non-empty string values; get as many as possible */ - size_t tl = tsvalue(top-1)->len; - char *buffer; - int i; - /* collect total length */ - for (i = 1; i < total && tostring(L, top-i-1); i++) { - size_t l = tsvalue(top-i-1)->len; - if (l >= (MAX_SIZE/sizeof(char)) - tl) - luaG_runerror(L, "string length overflow"); - tl += l; - } - buffer = luaZ_openspace(L, &G(L)->buff, tl); - tl = 0; - n = i; - do { /* copy all strings to buffer */ - size_t l = tsvalue(top-i)->len; - memcpy(buffer+tl, svalue(top-i), l * sizeof(char)); - tl += l; - } while (--i > 0); - setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); /* create result */ - } - total -= n-1; /* got 'n' strings to create 1 new */ - L->top -= n-1; /* popped 'n' strings and pushed one */ - } while (total > 1); /* repeat until only 1 result left */ -} - - -/* -** Main operation 'ra' = #rb'. -*/ -void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { - const TValue *tm; - switch (ttnov(rb)) { - case LUA_TTABLE: { - Table *h = hvalue(rb); - tm = fasttm(L, h->metatable, TM_LEN); - if (tm) break; /* metamethod? break switch to call it */ - setivalue(ra, luaH_getn(h)); /* else primitive len */ - return; - } - case LUA_TSTRING: { - setivalue(ra, 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; - } - } - luaT_callTM(L, tm, rb, rb, ra, 1); -} - - -/* -** Integer division; return 'm // n', that is, floor(m/n). -** C division truncates its result (rounds towards zero). -** 'floor(q) == trunc(q)' when 'q >= 0' or when 'q' is integer, -** otherwise 'floor(q) == trunc(q) - 1'. -*/ -lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) { - if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ - if (n == 0) - luaG_runerror(L, "attempt to divide by zero"); - return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */ - } - else { - lua_Integer q = m / n; /* perform C division */ - if ((m ^ n) < 0 && m % n != 0) /* 'm/n' would be negative non-integer? */ - q -= 1; /* correct result for different rounding */ - return q; - } -} - - -/* -** Integer modulus; return 'm % n'. (Assume that C '%' with -** negative operands follows C99 behavior. See previous comment -** about luaV_div.) -*/ -lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) { - if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ - if (n == 0) - luaG_runerror(L, "attempt to perform 'n%%0'"); - return 0; /* m % -1 == 0; avoid overflow with 0x80000...%-1 */ - } - else { - lua_Integer r = m % n; - if (r != 0 && (m ^ n) < 0) /* 'm/n' would be non-integer negative? */ - r += n; /* correct result for different rounding */ - return r; - } -} - - -/* number of bits in an integer */ -#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT) - -/* -** Shift left operation. (Shift right just negates 'y'.) -*/ -lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) { - if (y < 0) { /* shift right? */ - if (y <= -NBITS) return 0; - else return intop(>>, x, -y); - } - else { /* shift left */ - if (y >= NBITS) return 0; - else return intop(<<, x, y); - } -} - - -/* -** 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 LClosure *getcached (Proto *p, UpVal **encup, StkId base) { - LClosure *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->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 closure is not cached if prototype is -** already black (which means that 'cache' was already cleared by the -** GC). -*/ -static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, - StkId ra) { - int nup = p->sizeupvalues; - Upvaldesc *uv = p->upvalues; - int i; - LClosure *ncl = luaF_newLclosure(L, nup); - ncl->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? */ - ncl->upvals[i] = luaF_findupval(L, base + uv[i].idx); - else /* get upvalue from enclosing function */ - ncl->upvals[i] = encup[uv[i].idx]; - ncl->upvals[i]->refcount++; - /* new closure is white, so we do not need a barrier here */ - } - if (!isblack(p)) /* cache will not break GC invariant? */ - p->cache = ncl; /* save it on cache for reuse */ -} - - -/* -** 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); - switch (op) { /* finish its execution */ - case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_IDIV: - case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: - case OP_MOD: case OP_POW: - case OP_UNM: case OP_BNOT: case OP_LEN: - case OP_GETTABUP: 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 'luaT_trybinTM' was called */ - int b = GETARG_B(inst); /* first element 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) */ - 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_SETTABUP: case OP_SETTABLE: - break; - default: lua_assert(0); - } -} - - - - -/* -** {================================================================== -** Function 'luaV_execute': main interpreter loop -** =================================================================== -*/ - - -/* -** 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)) -#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i)) -#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \ - 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) \ - (k + (GETARG_Bx(i) != 0 ? GETARG_Bx(i) - 1 : GETARG_Ax(*ci->u.l.savedpc++))) - - -/* 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,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 vmdispatch(o) switch(o) -#define vmcase(l,b) case l: {b} break; -#define vmcasenb(l,b) case l: {b} /* nb = no break */ - -void luaV_execute (lua_State *L) { - CallInfo *ci = L->ci; - LClosure *cl; - TValue *k; - StkId base; - newframe: /* reentry point when frame changes (call/return) */ - lua_assert(ci == L->ci); - cl = clLvalue(ci->func); - 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)) { - Protect(luaG_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); - vmdispatch (GET_OPCODE(i)) { - vmcase(OP_MOVE, - setobjs2s(L, ra, RB(i)); - ) - vmcase(OP_LOADK, - 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, - setbvalue(ra, GETARG_B(i)); - if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */ - ) - vmcase(OP_LOADNIL, - int b = GETARG_B(i); - do { - setnilvalue(ra++); - } while (b--); - ) - vmcase(OP_GETUPVAL, - int b = GETARG_B(i); - setobj2s(L, ra, cl->upvals[b]->v); - ) - 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)); - ) - 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_upvalbarrier(L, uv); - ) - vmcase(OP_SETTABLE, - Protect(luaV_settable(L, ra, RKB(i), RKC(i))); - ) - 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)); - checkGC(L, ra + 1); - ) - vmcase(OP_SELF, - StkId rb = RB(i); - setobjs2s(L, ra+1, rb); - Protect(luaV_gettable(L, rb, RKC(i), ra)); - ) - vmcase(OP_ADD, - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Number nb; lua_Number nc; - if (ttisinteger(rb) && ttisinteger(rc)) { - lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - setivalue(ra, intop(+, ib, ic)); - } - else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - setfltvalue(ra, luai_numadd(L, nb, nc)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD)); } - ) - vmcase(OP_SUB, - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Number nb; lua_Number nc; - if (ttisinteger(rb) && ttisinteger(rc)) { - lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - setivalue(ra, intop(-, ib, ic)); - } - else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - setfltvalue(ra, luai_numsub(L, nb, nc)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SUB)); } - ) - vmcase(OP_MUL, - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Number nb; lua_Number nc; - if (ttisinteger(rb) && ttisinteger(rc)) { - lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - setivalue(ra, intop(*, ib, ic)); - } - else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - setfltvalue(ra, luai_nummul(L, nb, nc)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MUL)); } - ) - vmcase(OP_DIV, /* float division (always with floats) */ - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Number nb; lua_Number nc; - if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - setfltvalue(ra, luai_numdiv(L, nb, nc)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_DIV)); } - ) - vmcase(OP_BAND, - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Integer ib; lua_Integer ic; - if (tointeger(rb, &ib) && tointeger(rc, &ic)) { - setivalue(ra, intop(&, ib, ic)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BAND)); } - ) - vmcase(OP_BOR, - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Integer ib; lua_Integer ic; - if (tointeger(rb, &ib) && tointeger(rc, &ic)) { - setivalue(ra, intop(|, ib, ic)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BOR)); } - ) - vmcase(OP_BXOR, - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Integer ib; lua_Integer ic; - if (tointeger(rb, &ib) && tointeger(rc, &ic)) { - setivalue(ra, intop(^, ib, ic)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BXOR)); } - ) - vmcase(OP_SHL, - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Integer ib; lua_Integer ic; - if (tointeger(rb, &ib) && tointeger(rc, &ic)) { - setivalue(ra, luaV_shiftl(ib, ic)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHL)); } - ) - vmcase(OP_SHR, - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Integer ib; lua_Integer ic; - if (tointeger(rb, &ib) && tointeger(rc, &ic)) { - setivalue(ra, luaV_shiftl(ib, -ic)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHR)); } - ) - vmcase(OP_MOD, - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Number nb; lua_Number nc; - if (ttisinteger(rb) && ttisinteger(rc)) { - lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - setivalue(ra, luaV_mod(L, ib, ic)); - } - else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - lua_Number m; - luai_nummod(L, nb, nc, m); - setfltvalue(ra, m); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MOD)); } - ) - vmcase(OP_IDIV, /* floor division */ - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Number nb; lua_Number nc; - if (ttisinteger(rb) && ttisinteger(rc)) { - lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - setivalue(ra, luaV_div(L, ib, ic)); - } - else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - setfltvalue(ra, luai_numidiv(L, nb, nc)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); } - ) - vmcase(OP_POW, - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Number nb; lua_Number nc; - if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - setfltvalue(ra, luai_numpow(L, nb, nc)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_POW)); } - ) - vmcase(OP_UNM, - TValue *rb = RB(i); - lua_Number nb; - if (ttisinteger(rb)) { - lua_Integer ib = ivalue(rb); - setivalue(ra, intop(-, 0, ib)); - } - else if (tonumber(rb, &nb)) { - setfltvalue(ra, luai_numunm(L, nb)); - } - else { - Protect(luaT_trybinTM(L, rb, rb, ra, TM_UNM)); - } - ) - vmcase(OP_BNOT, - TValue *rb = RB(i); - lua_Integer ib; - if (tointeger(rb, &ib)) { - setivalue(ra, intop(^, ~l_castS2U(0), ib)); - } - else { - Protect(luaT_trybinTM(L, rb, rb, ra, TM_BNOT)); - } - ) - vmcase(OP_NOT, - TValue *rb = RB(i); - int res = l_isfalse(rb); /* next assignment may change this value */ - setbvalue(ra, res); - ) - vmcase(OP_LEN, - Protect(luaV_objlen(L, ra, RB(i))); - ) - 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)); - ra = RA(i); /* 'luav_concat' may invoke TMs and move the stack */ - rb = b + base; - setobjs2s(L, ra, rb); - checkGC(L, (ra >= rb ? ra + 1 : rb)); - L->top = ci->top; /* restore top */ - ) - vmcase(OP_JMP, - dojump(ci, i, 0); - ) - vmcase(OP_EQ, - TValue *rb = RKB(i); - TValue *rc = RKC(i); - Protect( - if (cast_int(luaV_equalobj(L, rb, rc)) != GETARG_A(i)) - ci->u.l.savedpc++; - else - donextjump(ci); - ) - ) - vmcase(OP_LT, - Protect( - if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) - ci->u.l.savedpc++; - else - donextjump(ci); - ) - ) - vmcase(OP_LE, - Protect( - if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) - ci->u.l.savedpc++; - else - donextjump(ci); - ) - ) - vmcase(OP_TEST, - 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)) - ci->u.l.savedpc++; - else { - setobjs2s(L, ra, rb); - donextjump(ci); - } - ) - 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; - } - else { /* Lua function */ - ci = L->ci; - ci->callstatus |= CIST_REENTRY; - goto newframe; /* restart luaV_execute over new Lua function */ - } - ) - 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? */ - base = ci->u.l.base; - 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); - goto newframe; /* restart luaV_execute over new Lua function */ - } - ) - vmcasenb(OP_RETURN, - int b = GETARG_B(i); - if (b != 0) L->top = ra+b-1; - if (cl->p->sizep > 0) luaF_close(L, base); - b = luaD_poscall(L, ra); - 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); - goto newframe; /* restart luaV_execute over new Lua function */ - } - ) - vmcase(OP_FORLOOP, - if (ttisinteger(ra)) { /* integer loop? */ - lua_Integer step = ivalue(ra + 2); - lua_Integer idx = ivalue(ra) + step; /* increment index */ - lua_Integer limit = ivalue(ra + 1); - if ((0 < step) ? (idx <= limit) : (limit <= idx)) { - ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - setivalue(ra, idx); /* update internal index... */ - setivalue(ra + 3, idx); /* ...and external index */ - } - } - else { /* floating loop */ - lua_Number step = fltvalue(ra + 2); - lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */ - lua_Number limit = fltvalue(ra + 1); - if (luai_numlt(0, step) ? luai_numle(idx, limit) - : luai_numle(limit, idx)) { - ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - setfltvalue(ra, idx); /* update internal index... */ - setfltvalue(ra + 3, idx); /* ...and external index */ - } - } - ) - vmcase(OP_FORPREP, - TValue *init = ra; - TValue *plimit = ra + 1; - TValue *pstep = ra + 2; - lua_Integer ilimit; - int stopnow; - if (ttisinteger(init) && ttisinteger(pstep) && - forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) { - /* all values are integer */ - lua_Integer initv = (stopnow ? 0 : ivalue(init)); - setivalue(plimit, ilimit); - setivalue(init, initv - ivalue(pstep)); - } - else { /* try making all values floats */ - lua_Number ninit; lua_Number nlimit; lua_Number nstep; - if (!tonumber(plimit, &nlimit)) - luaG_runerror(L, "'for' limit must be a number"); - setfltvalue(plimit, nlimit); - if (!tonumber(pstep, &nstep)) - luaG_runerror(L, "'for' step must be a number"); - setfltvalue(pstep, nstep); - if (!tonumber(init, &ninit)) - luaG_runerror(L, "'for' initial value must be a number"); - setfltvalue(init, luai_numsub(L, ninit, nstep)); - } - ci->u.l.savedpc += GETARG_sBx(i); - ) - vmcasenb(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), 1)); - L->top = ci->top; - i = *(ci->u.l.savedpc++); /* go to next instruction */ - ra = RA(i); - lua_assert(GET_OPCODE(i) == OP_TFORLOOP); - goto l_tforloop; - ) - vmcase(OP_TFORLOOP, - l_tforloop: - if (!ttisnil(ra + 1)) { /* continue loop? */ - setobjs2s(L, ra, ra + 1); /* save control variable */ - ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - } - ) - vmcase(OP_SETLIST, - int n = GETARG_B(i); - int c = GETARG_C(i); - unsigned int last; - Table *h; - 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++); - } - luai_runtimecheck(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-allocate it at once */ - for (; n > 0; n--) { - TValue *val = ra+n; - luaH_setint(L, h, last--, val); - luaC_barrierback(L, h, val); - } - L->top = ci->top; /* correct top (in case of previous open call) */ - ) - vmcase(OP_CLOSURE, - Proto *p = cl->p->p[GETARG_Bx(i)]; - LClosure *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 - setclLvalue(L, ra, ncl); /* push cashed closure */ - checkGC(L, ra + 1); - ) - vmcase(OP_VARARG, - int b = GETARG_B(i) - 1; - int j; - 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 */ - L->top = ra + n; - } - for (j = 0; j < b; j++) { - if (j < n) { - setobjs2s(L, ra + j, base - n + j); - } - else { - setnilvalue(ra + j); - } - } - ) - vmcase(OP_EXTRAARG, - lua_assert(0); - ) - } - } -} - -/* }================================================================== */ - diff --git a/src/lvm.h b/src/lvm.h deleted file mode 100644 index 5c5e18c3ac..0000000000 --- a/src/lvm.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -** $Id: lvm.h,v 2.34 2014/08/01 17:24:02 roberto Exp $ -** Lua virtual machine -** See Copyright Notice in lua.h -*/ - -#ifndef lvm_h -#define lvm_h - - -#include "ldo.h" -#include "lobject.h" -#include "ltm.h" - - -#if !defined(LUA_NOCVTN2S) -#define cvt2str(o) ttisnumber(o) -#else -#define cvt2str(o) 0 /* no conversion from numbers to strings */ -#endif - - -#if !defined(LUA_NOCVTS2N) -#define cvt2num(o) ttisstring(o) -#else -#define cvt2num(o) 0 /* no conversion from strings to numbers */ -#endif - - -#define tonumber(o,n) \ - (ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n)) - -#define tointeger(o,i) \ - (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger_(o,i)) - -#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2)) - -#define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,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); -LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n); -LUAI_FUNC int luaV_tointeger_ (const TValue *obj, lua_Integer *p); -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_finishOp (lua_State *L); -LUAI_FUNC void luaV_execute (lua_State *L); -LUAI_FUNC void luaV_concat (lua_State *L, int total); -LUAI_FUNC lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y); -LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y); -LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y); -LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb); - -#endif diff --git a/src/lzio.c b/src/lzio.c deleted file mode 100644 index 46493920f4..0000000000 --- a/src/lzio.c +++ /dev/null @@ -1,78 +0,0 @@ -/* -** $Id: lzio.c,v 1.36 2014/11/02 19:19:04 roberto Exp $ -** Buffered streams -** See Copyright Notice in lua.h -*/ - -#define lzio_c -#define LUA_CORE - -#include "lprefix.h" - - -#include - -#include "lua.h" - -#include "llimits.h" -#include "lmem.h" -#include "lstate.h" -#include "lzio.h" - - -int luaZ_fill (ZIO *z) { - size_t 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; /* discount char being returned */ - z->p = buff; - return cast_uchar(*(z->p++)); -} - - -void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { - z->L = L; - z->reader = reader; - z->data = data; - z->n = 0; - z->p = NULL; -} - - -/* --------------------------------------------------------------- read --- */ -size_t luaZ_read (ZIO *z, void *b, size_t n) { - while (n) { - size_t m; - 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; - z->p += m; - b = (char *)b + m; - n -= m; - } - return 0; -} - -/* ------------------------------------------------------------------------ */ -char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) { - if (n > buff->buffsize) { - if (n < LUA_MINBUFFER) n = LUA_MINBUFFER; - luaZ_resizebuffer(L, buff, n); - } - return buff->buffer; -} - - diff --git a/src/lzio.h b/src/lzio.h deleted file mode 100644 index 2ad163a6dc..0000000000 --- a/src/lzio.h +++ /dev/null @@ -1,66 +0,0 @@ -/* -** $Id: lzio.h,v 1.28 2014/01/31 15:14:22 roberto Exp $ -** Buffered streams -** See Copyright Notice in lua.h -*/ - - -#ifndef lzio_h -#define lzio_h - -#include "lua.h" - -#include "lmem.h" - - -#define EOZ (-1) /* end of stream */ - -typedef struct Zio ZIO; - -#define zgetc(z) (((z)->n--)>0 ? cast_uchar(*(z)->p++) : luaZ_fill(z)) - - -typedef struct Mbuffer { - char *buffer; - size_t n; - size_t buffsize; -} Mbuffer; - -#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) - -#define luaZ_buffer(buff) ((buff)->buffer) -#define luaZ_sizebuffer(buff) ((buff)->buffsize) -#define luaZ_bufflen(buff) ((buff)->n) - -#define luaZ_buffremove(buff,i) ((buff)->n -= (i)) -#define luaZ_resetbuffer(buff) ((buff)->n = 0) - - -#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) - - -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 */ - - - -/* --------- Private Part ------------------ */ - -struct Zio { - size_t n; /* bytes still unread */ - const char *p; /* current position in buffer */ - lua_Reader reader; /* reader function */ - void *data; /* additional data */ - lua_State *L; /* Lua state (for reader) */ -}; - - -LUAI_FUNC int luaZ_fill (ZIO *z); - -#endif From e2c82b2b7dd59a08de60eee78cde1f4ca83e85d3 Mon Sep 17 00:00:00 2001 From: Kate Adams Date: Sun, 4 Jan 2015 08:19:23 +0000 Subject: [PATCH 10/40] Imported Lua 1.0 --- src/Makefile | 29 + src/README | 22 + src/array.lua | 15 + src/fixed/iolib.c | 402 +++++++++++ src/fixed/lex_yy.c | 923 ++++++++++++++++++++++++ src/fixed/lua.c | 55 ++ src/floatingpoint.h | 1 + src/globals.lua | 5 + src/hash.c | 259 +++++++ src/hash.h | 35 + src/inout.c | 188 +++++ src/inout.h | 24 + src/iolib.c | 401 +++++++++++ src/lex_yy.c | 923 ++++++++++++++++++++++++ src/lua.c | 54 ++ src/lua.h | 54 ++ src/lualib.h | 15 + src/mathlib.c | 234 ++++++ src/opcode.c | 933 ++++++++++++++++++++++++ src/opcode.h | 144 ++++ src/save.lua | 47 ++ src/sort.lua | 56 ++ src/strlib.c | 131 ++++ src/table.c | 351 +++++++++ src/table.h | 39 + src/test.lua | 15 + src/type.lua | 35 + src/y_tab.c | 1639 +++++++++++++++++++++++++++++++++++++++++++ src/y_tab.h | 35 + 29 files changed, 7064 insertions(+) create mode 100644 src/Makefile create mode 100644 src/README create mode 100644 src/array.lua create mode 100644 src/fixed/iolib.c create mode 100644 src/fixed/lex_yy.c create mode 100644 src/fixed/lua.c create mode 100644 src/floatingpoint.h create mode 100644 src/globals.lua create mode 100644 src/hash.c create mode 100644 src/hash.h create mode 100644 src/inout.c create mode 100644 src/inout.h create mode 100644 src/iolib.c create mode 100644 src/lex_yy.c create mode 100644 src/lua.c create mode 100644 src/lua.h create mode 100644 src/lualib.h create mode 100644 src/mathlib.c create mode 100644 src/opcode.c create mode 100644 src/opcode.h create mode 100644 src/save.lua create mode 100644 src/sort.lua create mode 100644 src/strlib.c create mode 100644 src/table.c create mode 100644 src/table.h create mode 100644 src/test.lua create mode 100644 src/type.lua create mode 100644 src/y_tab.c create mode 100644 src/y_tab.h diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000000..8ed18bb5dd --- /dev/null +++ b/src/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/src/README b/src/README new file mode 100644 index 0000000000..29ad01d58f --- /dev/null +++ b/src/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/src/array.lua b/src/array.lua new file mode 100644 index 0000000000..349fb81821 --- /dev/null +++ b/src/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/src/fixed/iolib.c b/src/fixed/iolib.c new file mode 100644 index 0000000000..dce91f9dbe --- /dev/null +++ b/src/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/src/fixed/lua.c b/src/fixed/lua.c new file mode 100644 index 0000000000..f2cfc0b633 --- /dev/null +++ b/src/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/src/hash.h b/src/hash.h new file mode 100644 index 0000000000..28c50317b6 --- /dev/null +++ b/src/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/src/inout.c b/src/inout.c new file mode 100644 index 0000000000..3ba32ba7e7 --- /dev/null +++ b/src/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/src/inout.h b/src/inout.h new file mode 100644 index 0000000000..5a72261c70 --- /dev/null +++ b/src/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/src/iolib.c b/src/iolib.c new file mode 100644 index 0000000000..174dd5018e --- /dev/null +++ b/src/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/src/lua.c b/src/lua.c new file mode 100644 index 0000000000..be01b70f02 --- /dev/null +++ b/src/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/src/opcode.c b/src/opcode.c new file mode 100644 index 0000000000..97975ba1b8 --- /dev/null +++ b/src/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/src/opcode.h b/src/opcode.h new file mode 100644 index 0000000000..b32969d5f4 --- /dev/null +++ b/src/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/src/save.lua b/src/save.lua new file mode 100644 index 0000000000..1a4ba04d8c --- /dev/null +++ b/src/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/src/sort.lua b/src/sort.lua new file mode 100644 index 0000000000..f749c12248 --- /dev/null +++ b/src/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/src/table.c b/src/table.c new file mode 100644 index 0000000000..3bae7ebd54 --- /dev/null +++ b/src/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/src/y_tab.h b/src/y_tab.h new file mode 100644 index 0000000000..b973d540c5 --- /dev/null +++ b/src/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 a59341ea3b96a0b26fa3d6982b97020abef4c045 Mon Sep 17 00:00:00 2001 From: Kate Adams Date: Sun, 4 Jan 2015 08:20:31 +0000 Subject: [PATCH 11/40] Imported Lua 1.1 --- Makefile | 11 + README | 47 ++ clients/lib/Makefile | 23 + {src => clients/lib}/iolib.c | 122 +++- {src => clients/lib}/mathlib.c | 23 +- clients/lib/mathlib.h | 13 + {src => 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 + {src => include}/lua.h | 2 +- {src => include}/lualib.h | 5 +- include/mm.h | 0 src/Makefile | 39 +- src/README | 22 - src/fixed/iolib.c | 402 ----------- src/fixed/lex_yy.c | 923 ------------------------ src/fixed/lua.c | 55 -- src/floatingpoint.h | 1 - src/globals.lua | 5 - src/hash.c | 146 +++- src/hash.h | 11 +- src/inout.c | 33 +- src/inout.h | 7 +- src/lex.c | 238 ++++++ src/lex_yy.c | 923 ------------------------ src/lua.c | 54 -- src/opcode.c | 230 ++++-- src/opcode.h | 36 +- src/table.c | 270 ++++--- src/table.h | 27 +- src/test.lua | 15 - src/type.lua | 35 - src/{y_tab.c => y.tab.c} | 1242 ++++++++++++++++++-------------- src/y.tab.h | 37 + src/y_tab.h | 35 - src/yacc/Makefile | 27 + src/yacc/exscript | 3 + src/yacc/lua.lex | 85 +++ src/yacc/lua.stx | 953 ++++++++++++++++++++++++ {src => test}/array.lua | 0 test/dump | 37 + test/loop.lua | 6 + {src => test}/save.lua | 1 - {src => 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 + 56 files changed, 3053 insertions(+), 3379 deletions(-) create mode 100644 Makefile create mode 100644 README create mode 100644 clients/lib/Makefile rename {src => clients/lib}/iolib.c (77%) rename {src => clients/lib}/mathlib.c (92%) create mode 100644 clients/lib/mathlib.h rename {src => 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 rename {src => include}/lua.h (97%) rename {src => include}/lualib.h (66%) create mode 100644 include/mm.h delete mode 100644 src/README delete mode 100644 src/fixed/iolib.c delete mode 100644 src/fixed/lex_yy.c delete mode 100644 src/fixed/lua.c delete mode 100644 src/floatingpoint.h delete mode 100644 src/globals.lua create mode 100644 src/lex.c delete mode 100644 src/lex_yy.c delete mode 100644 src/lua.c delete mode 100644 src/test.lua delete mode 100644 src/type.lua rename src/{y_tab.c => y.tab.c} (57%) create mode 100644 src/y.tab.h delete 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 rename {src => test}/array.lua (100%) create mode 100644 test/dump create mode 100644 test/loop.lua rename {src => test}/save.lua (99%) rename {src => 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 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..10640e0d02 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +# makefile for lua hierarchy + +all: + (cd src; make) + (cd clients/lib; make) + (cd clients/lua; make) + +clean: + (cd src; make clean) + (cd clients/lib; make clean) + (cd clients/lua; make clean) diff --git a/README b/README new file mode 100644 index 0000000000..3b8ad6aab9 --- /dev/null +++ b/README @@ -0,0 +1,47 @@ +* 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. + +* 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. + +* Coming soon + Object-oriented extensions. + Lazy evaluation. + +* 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. + +* 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. + +* 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. + +-- +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/src/iolib.c b/clients/lib/iolib.c similarity index 77% rename from src/iolib.c rename to clients/lib/iolib.c index 174dd5018e..b972124b44 100644 --- a/src/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/src/mathlib.c b/clients/lib/mathlib.c similarity index 92% rename from src/mathlib.c rename to clients/lib/mathlib.c index b07c8c4754..c84af8cb81 100644 --- a/src/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/src/strlib.c b/clients/lib/strlib.c similarity index 83% rename from src/strlib.c rename to clients/lib/strlib.c index efd01e9b23..037b84beaf 100644 --- a/src/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

    3. 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(


      + 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/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 6cd4124a787ef1f3eb99e8ef18b7e810bb0ad6f3 Mon Sep 17 00:00:00 2001 From: Kate Adams Date: Sun, 4 Jan 2015 08:25:49 +0000 Subject: [PATCH 17/40] Imported 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 57de8d56dedf3984915be73a059fe0bd6e5df110 Mon Sep 17 00:00:00 2001 From: Kate Adams Date: Sun, 4 Jan 2015 08:26:40 +0000 Subject: [PATCH 18/40] Imported 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 ab33cc922b51e5e067e1ca202472d82084044cba Mon Sep 17 00:00:00 2001 From: Kate Adams Date: Sun, 4 Jan 2015 08:27:11 +0000 Subject: [PATCH 19/40] Imported Lua 4.0.1 --- COPYRIGHT | 29 +- DIFFS | 97 + HISTORY | 32 +- INSTALL | 57 +- MANIFEST | 41 +- Makefile | 36 +- README | 60 +- UPDATE | 19 + 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 | 547 ++--- src/ldo.h | 33 +- src/lfunc.c | 121 +- src/lfunc.h | 15 +- src/lgc.c | 442 ++-- src/lgc.h | 10 +- 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/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 + 104 files changed, 12180 insertions(+), 8780 deletions(-) create mode 100644 DIFFS create mode 100644 UPDATE 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 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/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/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/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/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;
    4. %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);
    5. %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..660ecd80a1 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.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 @@ -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.1" +#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..54c2cba411 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.110a 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==0) ? 1 : 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..8a779bbe03 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.109a 2000/10/30 12:38:50 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -10,378 +10,379 @@ #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; + /* 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); } + 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); + 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; } -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..f1eee9ab09 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; +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..09b66a2bd3 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.9 2001/02/02 16:23:20 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -11,11 +11,9 @@ #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_collectgarbage (lua_State *L); +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..29bad6a8f2 --- /dev/null +++ b/src/lib/lbaselib.c @@ -0,0 +1,651 @@ +/* +** $Id: lbaselib.c,v 1.17a 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, 1); + 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, 1); + 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 == '\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); +} + + +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..67161c868e 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.117 2000/11/29 11:57:42 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) && 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..a415a7d3fd 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.45a 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 = (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)); 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/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..2a00b6a532 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.146a 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-1, 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 02150a497480a15e79de4336f5defb6ac187ec38 Mon Sep 17 00:00:00 2001 From: Kate Adams Date: Sun, 4 Jan 2015 08:27:47 +0000 Subject: [PATCH 20/40] Imported 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/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 + 126 files changed, 15536 insertions(+), 11405 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 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/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 456bda8d38cfe5eb60e1e2c3d2ea8e4c146d7aca Mon Sep 17 00:00:00 2001 From: Kate Adams Date: Sun, 4 Jan 2015 08:28:32 +0000 Subject: [PATCH 21/40] Imported Lua 5.0.2 --- COPYRIGHT | 2 +- DIFFS | 224 +++++++++++++++++++++++++++++++++++++++ MANIFEST | 259 +++++++++++++++++++++++---------------------- Makefile | 3 + UPDATE | 23 ++++ doc/contents.html | 123 +++++++++++++++++++++ doc/manual.html | 231 ++++++++++++++++++++-------------------- doc/readme.html | 4 +- etc/.exrc | 1 - include/lua.h | 8 +- src/ldo.c | 25 +++-- src/lgc.c | 23 ++-- src/lgc.h | 4 +- src/lib/lbaselib.c | 7 +- src/lib/liolib.c | 6 +- src/lparser.c | 10 +- src/lvm.c | 15 +-- test/compat.lua | 192 --------------------------------- test/luac.lua | 6 +- test/table.lua | 2 +- 20 files changed, 686 insertions(+), 482 deletions(-) create mode 100644 DIFFS create mode 100644 UPDATE create mode 100644 doc/contents.html delete mode 120000 etc/.exrc 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 new file mode 100644 index 0000000000..f7d5ba27eb --- /dev/null +++ b/DIFFS @@ -0,0 +1,224 @@ +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/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 new file mode 100644 index 0000000000..f0921887dd --- /dev/null +++ b/UPDATE @@ -0,0 +1,23 @@ +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/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/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/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/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..88b0191e9a 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.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" -#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/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..b6a4baedc2 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.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; } @@ -324,7 +325,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/lvm.c b/src/lvm.c index eaa5c700b0..94e2802d86 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.284b 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,12 @@ 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) + 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 || L->ci->state == (CI_SAVEDPC | CI_CALLING)); L->ci->state = CI_HASFRAME; /* activate frame */ @@ -673,9 +675,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); @@ -778,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/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) 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 0f23361ed6f9dc2dbb82a09a88c591b83569b2bc Mon Sep 17 00:00:00 2001 From: Kate Adams Date: Sun, 4 Jan 2015 08:28:59 +0000 Subject: [PATCH 22/40] Imported Lua 5.0.3 --- COPYRIGHT | 2 +- DIFFS | 480 ++++++++++++++++++++++++++------------------- MANIFEST | 260 ++++++++++++------------ include/lua.h | 8 +- src/lapi.c | 6 +- src/lcode.c | 52 ++--- src/lfunc.c | 10 +- src/lfunc.h | 9 +- src/lgc.c | 23 ++- src/lib/lbaselib.c | 4 +- src/lib/liolib.c | 66 ++++--- src/lvm.c | 14 +- 12 files changed, 514 insertions(+), 420 deletions(-) diff --git a/COPYRIGHT b/COPYRIGHT index 16321abf6b..2cd57d3b46 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) 2003-2006 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 f7d5ba27eb..c236ff8b9a 100644 --- a/DIFFS +++ b/DIFFS @@ -1,224 +1,294 @@ -diff -r lua-5.0/COPYRIGHT lua-5.0.2/COPYRIGHT +diff -r lua-5.0.2/COPYRIGHT lua-5.0.3/COPYRIGHT 12c12 -< Copyright (C) 2003 Tecgraf, PUC-Rio. +< Copyright (C) 2003-2004 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 +> Copyright (C) 2003-2006 Tecgraf, PUC-Rio. +diff -r lua-5.0.2/include/lua.h lua-5.0.3/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 $ --- -> ** $Id: lua.h,v 1.175b 2003/03/18 12:31:39 roberto Exp $ +> ** $Id: lua.h,v 1.175c 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" --- -> #define LUA_VERSION "Lua 5.0.2" -> #define LUA_COPYRIGHT "Copyright (C) 1994-2004 Tecgraf, PUC-Rio" +> #define LUA_VERSION "Lua 5.0.3" +> #define LUA_COPYRIGHT "Copyright (C) 1994-2006 Tecgraf, PUC-Rio" 368c368 -< * Copyright (C) 1994-2003 Tecgraf, PUC-Rio. All rights reserved. +< * Copyright (C) 1994-2004 Tecgraf, PUC-Rio. All rights reserved. +--- +> * Copyright (C) 1994-2006 Tecgraf, PUC-Rio. All rights reserved. +diff -r lua-5.0.2/src/lapi.c lua-5.0.3/src/lapi.c +2c2 +< ** $Id: lapi.c,v 1.235 2003/04/07 14:36:08 roberto Exp $ +--- +> ** $Id: lapi.c,v 1.235a 2003/04/07 14:36:08 roberto Exp $ +882c882 +< if (n > f->c.nupvalues) return NULL; --- -> * 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 +> if (!(1 <= n && n <= f->c.nupvalues)) return NULL; +888c888 +< if (n > p->sizeupvalues) return NULL; +--- +> if (!(1 <= n && n <= p->sizeupvalues)) return NULL; +diff -r lua-5.0.2/src/lcode.c lua-5.0.3/src/lcode.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; +< ** $Id: lcode.c,v 1.117 2003/04/03 13:35:34 roberto Exp $ +--- +> ** $Id: lcode.c,v 1.117a 2003/04/03 13:35:34 roberto Exp $ +105c105,108 +< if (GET_OPCODE(i) != OP_TEST || GETARG_C(i) != cond) return 1; +--- +> if (GET_OPCODE(i) != OP_TEST || +> GETARG_A(i) != NO_REG || +> GETARG_C(i) != cond) +> return 1; +117,118c120,130 +< static void luaK_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 = luaK_getjump(fs, list)) { +> Instruction *i = getjumpcontrol(fs, list); +> if (GET_OPCODE(*i) == OP_TEST) +> patchtestreg(i, NO_REG); +> } > } > > -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 +> static void luaK_patchlistaux (FuncState *fs, int list, int vtarget, int reg, +> int dtarget) { +122,136c134,136 +< 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); +< } +--- +> if (GET_OPCODE(*i) == OP_TEST && GETARG_A(*i) == NO_REG) { +> patchtestreg(i, reg); +> luaK_fixjump(fs, list, vtarget); +137a138,139 +> else +> luaK_fixjump(fs, list, dtarget); /* jump to default target */ +144c146 +< luaK_patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc, NO_REG, fs->pc); +--- +> luaK_patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); +154c156 +< luaK_patchlistaux(fs, list, target, NO_REG, target, NO_REG, target); +--- +> luaK_patchlistaux(fs, list, target, NO_REG, target); +357,358c359,360 +< 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); +--- +> luaK_patchlistaux(fs, e->f, final, reg, p_f); +> luaK_patchlistaux(fs, e->t, final, reg, p_t); +476c478 +< return luaK_condjump(fs, OP_TEST, NO_REG, GETARG_B(ie), !cond); +--- +> return luaK_condjump(fs, OP_TEST, GETARG_B(ie), GETARG_B(ie), !cond); +566a569,570 +> removevalues(fs, e->f); +> removevalues(fs, e->t); +diff -r lua-5.0.2/src/lfunc.c lua-5.0.3/src/lfunc.c 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 +< ** $Id: lfunc.c,v 1.67 2003/03/18 12:50:04 roberto Exp $ +--- +> ** $Id: lfunc.c,v 1.67a 2003/03/18 12:50:04 roberto Exp $ +19,26d18 +< +< +< #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))) +< +diff -r lua-5.0.2/src/lfunc.h lua-5.0.3/src/lfunc.h 2c2 -< ** $Id: lbaselib.c,v 1.130 2003/04/03 13:35:34 roberto Exp $ +< ** $Id: lfunc.h,v 1.21 2003/03/18 12:50:04 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 +> ** $Id: lfunc.h,v 1.21a 2003/03/18 12:50:04 roberto Exp $ +11a12,18 +> +> +> #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))) +diff -r lua-5.0.2/src/lgc.c lua-5.0.3/src/lgc.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 +< ** $Id: lgc.c,v 1.171a 2003/04/03 13:35:34 roberto Exp $ +--- +> ** $Id: lgc.c,v 1.171b 2003/04/03 13:35:34 roberto Exp $ +221,224c221,222 +< if (!u->marked) { +< markobject(st, &u->value); +< u->marked = 1; +< } +--- +> markobject(st, u->v); +> u->marked = 1; +261c259,260 +< static void propagatemarks (GCState *st) { +--- +> static lu_mem propagatemarks (GCState *st) { +> lu_mem mf = 0; +267a267,268 +> mf += sizeof(Table) + sizeof(TObject) * h->sizearray + +> sizeof(Node) * sizenode(h); +273a275,276 +> mf += (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : +> sizeLclosure(cl->l.nupvalues); +279a283,284 +> mf += sizeof(lua_State) + sizeof(TObject) * th->stacksize + +> sizeof(CallInfo) * th->size_ci; +285a291 +> /* do not need 'mf' for this case (cannot happen inside a udata) */ +290a297 +> return mf; +371c378 +< if (curr->gch.marked > limit) { +--- +> if ((curr->gch.marked & ~(KEYWEAK | VALUEWEAK)) > limit) { +473c480 +< propagatemarks(&st); /* remark, to propagate `preserveness' */ +--- +> deadmem += propagatemarks(&st); /* remark, to propagate `preserveness' */ +diff -r lua-5.0.2/src/lib/lbaselib.c lua-5.0.3/src/lib/lbaselib.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 +< ** $Id: lbaselib.c,v 1.130b 2003/04/03 13:35:34 roberto Exp $ +--- +> ** $Id: lbaselib.c,v 1.130c 2003/04/03 13:35:34 roberto Exp $ +175a176 +> lua_settop(L, 2); +183a185 +> lua_settop(L, 3); +diff -r lua-5.0.2/src/lib/liolib.c lua-5.0.3/src/lib/liolib.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 +< ** $Id: liolib.c,v 2.39a 2003/03/19 21:16:12 roberto Exp $ +--- +> ** $Id: liolib.c,v 2.39b 2003/03/19 21:16:12 roberto Exp $ +22a23,28 +> typedef struct FileHandle { +> FILE *f; +> int ispipe; +> } FileHandle; +> > -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*(.*)$') +89,92c95,98 +< 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 FileHandle *topfile (lua_State *L, int findex) { +> FileHandle *fh = (FileHandle *)luaL_checkudata(L, findex, FILEHANDLE); +> if (fh == NULL) luaL_argerror(L, findex, "bad file"); +> return fh; +97,99c103,105 +< FILE **f = (FILE **)luaL_checkudata(L, 1, FILEHANDLE); +< if (f == NULL) lua_pushnil(L); +< else if (*f == NULL) +--- +> FileHandle *fh = (FileHandle *)luaL_checkudata(L, 1, FILEHANDLE); +> if (fh == NULL) lua_pushnil(L); +> else if (fh->f == NULL) +107,109c113,117 +< static FILE *tofile (lua_State *L, int findex) { +< FILE **f = topfile(L, findex); +< if (*f == NULL) +--- +> #define tofile(L,i) (tofileh(L,i)->f) +> +> static FileHandle *tofileh (lua_State *L, int findex) { +> FileHandle *fh = topfile(L, findex); +> if (fh->f == NULL) +111c119 +< return *f; +--- +> return fh; +115a124,125 +> #define newfile(L) (&(newfileh(L)->f)) +> +121,123c131,134 +< static FILE **newfile (lua_State *L) { +< FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); +< *pf = NULL; /* file handle is currently `closed' */ +--- +> static FileHandle *newfileh (lua_State *L) { +> FileHandle *fh = (FileHandle *)lua_newuserdata(L, sizeof(FileHandle)); +> fh->f = NULL; /* file handle is currently `closed' */ +> fh->ispipe = 0; +126c137 +< return pf; +--- +> return fh; +148c159,160 +< FILE *f = tofile(L, 1); +--- +> FileHandle *fh = tofileh(L, 1); +> FILE *f = fh->f; +152,154c164,165 +< int ok = (pclose(f) != -1) || (fclose(f) == 0); +< if (ok) +< *(FILE **)lua_touserdata(L, 1) = NULL; /* mark file as closed */ +--- +> int ok = fh->ispipe ? (pclose(f) != -1) : (fclose(f) == 0); +> fh->f = NULL; /* mark file as closed */ +170,171c181,182 +< FILE **f = topfile(L, 1); +< if (*f != NULL) /* ignore closed files */ +--- +> FileHandle *fh = topfile(L, 1); +> if (fh->f != NULL) /* ignore closed files */ +179,180c190,191 +< FILE **f = topfile(L, 1); +< if (*f == NULL) +--- +> FileHandle *fh = topfile(L, 1); +> if (fh->f == NULL) +205,207c216,219 +< FILE **pf = newfile(L); +< *pf = popen(filename, mode); +< return (*pf == NULL) ? pushresult(L, 0, filename) : 1; +--- +> FileHandle *fh = newfileh(L); +> fh->f = popen(filename, mode); +> fh->ispipe = 1; +> return (fh->f == NULL) ? pushresult(L, 0, filename) : 1; +diff -r lua-5.0.2/src/lvm.c lua-5.0.3/src/lvm.c +2c2 +< ** $Id: lvm.c,v 1.284b 2003/04/03 13:35:34 roberto Exp $ +--- +> ** $Id: lvm.c,v 1.284c 2003/04/03 13:35:34 roberto Exp $ +324,325c324 +< lu_mem tl = cast(lu_mem, tsvalue(top-1)->tsv.len) + +< cast(lu_mem, tsvalue(top-2)->tsv.len); +--- +> size_t tl = tsvalue(top-1)->tsv.len; +328,330c327,331 +< while (n < total && tostring(L, top-n-1)) { /* collect total length */ +< tl += tsvalue(top-n-1)->tsv.len; +< n++; +--- +> /* collect total length */ +> for (n = 1; n < total && tostring(L, top-n-1); n++) { +> size_t l = tsvalue(top-n-1)->tsv.len; +> if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); +> tl += l; +332d332 +< if (tl > MAX_SIZET) luaG_runerror(L, "string size overflow"); diff --git a/MANIFEST b/MANIFEST index 0c7b8dce0b..9692b6aa3d 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,131 +1,131 @@ -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 +MANIFEST contents of Lua 5.0.3 distribution on Mon Jun 19 11:04:48 BRT 2006 +lua-5.0.3 +lua-5.0.3/COPYRIGHT +lua-5.0.3/DIFFS +lua-5.0.3/HISTORY +lua-5.0.3/INSTALL +lua-5.0.3/MANIFEST +lua-5.0.3/Makefile +lua-5.0.3/README +lua-5.0.3/UPDATE +lua-5.0.3/bin +lua-5.0.3/build +lua-5.0.3/config +lua-5.0.3/configure +lua-5.0.3/doc +lua-5.0.3/doc/contents.html +lua-5.0.3/doc/logo.gif +lua-5.0.3/doc/lua.1 +lua-5.0.3/doc/lua.html +lua-5.0.3/doc/luac.1 +lua-5.0.3/doc/luac.html +lua-5.0.3/doc/manual.html +lua-5.0.3/doc/readme.html +lua-5.0.3/etc +lua-5.0.3/etc/Makefile +lua-5.0.3/etc/README +lua-5.0.3/etc/bin2c.c +lua-5.0.3/etc/compat.lua +lua-5.0.3/etc/doall.lua +lua-5.0.3/etc/lua.ico +lua-5.0.3/etc/lua.magic +lua-5.0.3/etc/lua.xpm +lua-5.0.3/etc/luser_number.h +lua-5.0.3/etc/luser_tests.h +lua-5.0.3/etc/min.c +lua-5.0.3/etc/noparser.c +lua-5.0.3/etc/saconfig.c +lua-5.0.3/etc/trace.c +lua-5.0.3/include +lua-5.0.3/include/Makefile +lua-5.0.3/include/lauxlib.h +lua-5.0.3/include/lua.h +lua-5.0.3/include/lualib.h +lua-5.0.3/lib +lua-5.0.3/src +lua-5.0.3/src/Makefile +lua-5.0.3/src/README +lua-5.0.3/src/lapi.c +lua-5.0.3/src/lapi.h +lua-5.0.3/src/lcode.c +lua-5.0.3/src/lcode.h +lua-5.0.3/src/ldebug.c +lua-5.0.3/src/ldebug.h +lua-5.0.3/src/ldo.c +lua-5.0.3/src/ldo.h +lua-5.0.3/src/ldump.c +lua-5.0.3/src/lfunc.c +lua-5.0.3/src/lfunc.h +lua-5.0.3/src/lgc.c +lua-5.0.3/src/lgc.h +lua-5.0.3/src/lib +lua-5.0.3/src/lib/Makefile +lua-5.0.3/src/lib/README +lua-5.0.3/src/lib/lauxlib.c +lua-5.0.3/src/lib/lbaselib.c +lua-5.0.3/src/lib/ldblib.c +lua-5.0.3/src/lib/liolib.c +lua-5.0.3/src/lib/lmathlib.c +lua-5.0.3/src/lib/loadlib.c +lua-5.0.3/src/lib/lstrlib.c +lua-5.0.3/src/lib/ltablib.c +lua-5.0.3/src/llex.c +lua-5.0.3/src/llex.h +lua-5.0.3/src/llimits.h +lua-5.0.3/src/lmem.c +lua-5.0.3/src/lmem.h +lua-5.0.3/src/lobject.c +lua-5.0.3/src/lobject.h +lua-5.0.3/src/lopcodes.c +lua-5.0.3/src/lopcodes.h +lua-5.0.3/src/lparser.c +lua-5.0.3/src/lparser.h +lua-5.0.3/src/lstate.c +lua-5.0.3/src/lstate.h +lua-5.0.3/src/lstring.c +lua-5.0.3/src/lstring.h +lua-5.0.3/src/ltable.c +lua-5.0.3/src/ltable.h +lua-5.0.3/src/ltests.c +lua-5.0.3/src/ltm.c +lua-5.0.3/src/ltm.h +lua-5.0.3/src/lua +lua-5.0.3/src/lua/Makefile +lua-5.0.3/src/lua/README +lua-5.0.3/src/lua/lua.c +lua-5.0.3/src/luac +lua-5.0.3/src/luac/Makefile +lua-5.0.3/src/luac/README +lua-5.0.3/src/luac/luac.c +lua-5.0.3/src/luac/print.c +lua-5.0.3/src/lundump.c +lua-5.0.3/src/lundump.h +lua-5.0.3/src/lvm.c +lua-5.0.3/src/lvm.h +lua-5.0.3/src/lzio.c +lua-5.0.3/src/lzio.h +lua-5.0.3/test +lua-5.0.3/test/README +lua-5.0.3/test/bisect.lua +lua-5.0.3/test/cf.lua +lua-5.0.3/test/echo.lua +lua-5.0.3/test/env.lua +lua-5.0.3/test/factorial.lua +lua-5.0.3/test/fib.lua +lua-5.0.3/test/fibfor.lua +lua-5.0.3/test/globals.lua +lua-5.0.3/test/hello.lua +lua-5.0.3/test/life.lua +lua-5.0.3/test/lua +lua-5.0.3/test/luac +lua-5.0.3/test/luac.lua +lua-5.0.3/test/printf.lua +lua-5.0.3/test/readonly.lua +lua-5.0.3/test/sieve.lua +lua-5.0.3/test/sort.lua +lua-5.0.3/test/table.lua +lua-5.0.3/test/trace-calls.lua +lua-5.0.3/test/trace-globals.lua +lua-5.0.3/test/undefined.lua +lua-5.0.3/test/xd.lua END OF MANIFEST diff --git a/include/lua.h b/include/lua.h index 88b0191e9a..bd4acc9a88 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.175c 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.2" -#define LUA_COPYRIGHT "Copyright (C) 1994-2004 Tecgraf, PUC-Rio" +#define LUA_VERSION "Lua 5.0.3" +#define LUA_COPYRIGHT "Copyright (C) 1994-2006 Tecgraf, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" @@ -365,7 +365,7 @@ struct lua_Debug { /****************************************************************************** -* Copyright (C) 1994-2004 Tecgraf, PUC-Rio. All rights reserved. +* Copyright (C) 1994-2006 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/lapi.c b/src/lapi.c index d5dd9ca465..2ed4c63482 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 1.235 2003/04/07 14:36:08 roberto Exp $ +** $Id: lapi.c,v 1.235a 2003/04/07 14:36:08 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -879,13 +879,13 @@ static const char *aux_upvalue (lua_State *L, int funcindex, int n, 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 d626ecd60e..3925c976c8 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 1.117a 2003/04/03 13:35:34 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -102,7 +102,10 @@ static Instruction *getjumpcontrol (FuncState *fs, int pc) { 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; + if (GET_OPCODE(i) != OP_TEST || + GETARG_A(i) != NO_REG || + GETARG_C(i) != cond) + return 1; } return 0; /* not found */ } @@ -114,34 +117,33 @@ static void patchtestreg (Instruction *i, int reg) { } -static void luaK_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 = luaK_getjump(fs, list)) { + Instruction *i = getjumpcontrol(fs, list); + if (GET_OPCODE(*i) == OP_TEST) + patchtestreg(i, NO_REG); + } +} + + +static void luaK_patchlistaux (FuncState *fs, int list, int vtarget, int reg, + 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); - } + if (GET_OPCODE(*i) == OP_TEST && GETARG_A(*i) == NO_REG) { + patchtestreg(i, reg); + luaK_fixjump(fs, list, vtarget); } + else + luaK_fixjump(fs, list, dtarget); /* jump to default target */ list = next; } } static void luaK_dischargejpc (FuncState *fs) { - luaK_patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc, NO_REG, fs->pc); + luaK_patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); fs->jpc = NO_JUMP; } @@ -151,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); + luaK_patchlistaux(fs, list, target, NO_REG, target); } } @@ -354,8 +356,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); + luaK_patchlistaux(fs, e->f, final, reg, p_f); + luaK_patchlistaux(fs, e->t, final, reg, p_t); } e->f = e->t = NO_JUMP; e->info = reg; @@ -473,7 +475,7 @@ 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 luaK_condjump(fs, OP_TEST, GETARG_B(ie), GETARG_B(ie), !cond); } /* else go through */ } @@ -564,6 +566,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); } diff --git a/src/lfunc.c b/src/lfunc.c index 31044fa56b..97c5d9bbdc 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -1,5 +1,5 @@ /* -** $Id: lfunc.c,v 1.67 2003/03/18 12:50:04 roberto Exp $ +** $Id: lfunc.c,v 1.67a 2003/03/18 12:50:04 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -18,14 +18,6 @@ #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); diff --git a/src/lfunc.h b/src/lfunc.h index 5d5325076b..dc61e2ed43 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 1.21a 2003/03/18 12:50:04 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -11,6 +11,13 @@ #include "lobject.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))) + + Proto *luaF_newproto (lua_State *L); Closure *luaF_newCclosure (lua_State *L, int nelems); Closure *luaF_newLclosure (lua_State *L, int nelems, TObject *e); diff --git a/src/lgc.c b/src/lgc.c index 5e036d387a..b44f201701 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 1.171b 2003/04/03 13:35:34 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -218,10 +218,8 @@ static void traverseclosure (GCState *st, Closure *cl) { 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(st, u->v); + u->marked = 1; } } } @@ -258,36 +256,45 @@ static void traversestack (GCState *st, lua_State *L1) { } -static void propagatemarks (GCState *st) { +static lu_mem propagatemarks (GCState *st) { + lu_mem mf = 0; 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); + mf += sizeof(Table) + sizeof(TObject) * h->sizearray + + sizeof(Node) * sizenode(h); break; } case LUA_TFUNCTION: { Closure *cl = gcotocl(st->tmark); st->tmark = cl->c.gclist; traverseclosure(st, cl); + mf += (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); + mf += sizeof(lua_State) + sizeof(TObject) * th->stacksize + + sizeof(CallInfo) * th->size_ci; break; } case LUA_TPROTO: { Proto *p = gcotop(st->tmark); st->tmark = p->gclist; traverseproto(st, p); + /* do not need 'mf' for this case (cannot happen inside a udata) */ break; } default: lua_assert(0); } } + return mf; } @@ -368,7 +375,7 @@ 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) { + if ((curr->gch.marked & ~(KEYWEAK | VALUEWEAK)) > limit) { unmark(curr); p = &curr->gch.next; } @@ -470,7 +477,7 @@ static size_t mark (lua_State *L) { st.wv = NULL; deadmem = luaC_separateudata(L); /* separate userdata to be preserved */ marktmu(&st); /* mark `preserved' userdata */ - propagatemarks(&st); /* remark, to propagate `preserveness' */ + deadmem += propagatemarks(&st); /* remark, to propagate `preserveness' */ cleartablekeys(wkv); /* `propagatemarks' may resuscitate some weak tables; clear them too */ cleartablekeys(st.wk); diff --git a/src/lib/lbaselib.c b/src/lib/lbaselib.c index b6a4baedc2..fb26a54a94 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.130c 2003/04/03 13:35:34 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -173,6 +173,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; } @@ -181,6 +182,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; } diff --git a/src/lib/liolib.c b/src/lib/liolib.c index 96b38831d2..bcadcdfdec 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.39b 2003/03/19 21:16:12 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -20,6 +20,12 @@ #include "lualib.h" +typedef struct FileHandle { + FILE *f; + int ispipe; +} FileHandle; + + /* ** by default, gcc does not get `tmpname' @@ -86,17 +92,17 @@ 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"); - return f; +static FileHandle *topfile (lua_State *L, int findex) { + FileHandle *fh = (FileHandle *)luaL_checkudata(L, findex, FILEHANDLE); + if (fh == NULL) luaL_argerror(L, findex, "bad file"); + return fh; } 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) + FileHandle *fh = (FileHandle *)luaL_checkudata(L, 1, FILEHANDLE); + if (fh == NULL) lua_pushnil(L); + else if (fh->f == NULL) lua_pushliteral(L, "closed file"); else lua_pushliteral(L, "file"); @@ -104,26 +110,31 @@ static int io_type (lua_State *L) { } -static FILE *tofile (lua_State *L, int findex) { - FILE **f = topfile(L, findex); - if (*f == NULL) +#define tofile(L,i) (tofileh(L,i)->f) + +static FileHandle *tofileh (lua_State *L, int findex) { + FileHandle *fh = topfile(L, findex); + if (fh->f == NULL) luaL_error(L, "attempt to use a closed file"); - return *f; + return fh; } +#define newfile(L) (&(newfileh(L)->f)) + /* ** 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' */ +static FileHandle *newfileh (lua_State *L) { + FileHandle *fh = (FileHandle *)lua_newuserdata(L, sizeof(FileHandle)); + fh->f = NULL; /* file handle is currently `closed' */ + fh->ispipe = 0; luaL_getmetatable(L, FILEHANDLE); lua_setmetatable(L, -2); - return pf; + return fh; } @@ -145,13 +156,13 @@ static void registerfile (lua_State *L, FILE *f, const char *name, static int aux_close (lua_State *L) { - FILE *f = tofile(L, 1); + FileHandle *fh = tofileh(L, 1); + FILE *f = fh->f; if (f == stdin || f == stdout || f == stderr) return 0; /* file cannot be closed */ else { - int ok = (pclose(f) != -1) || (fclose(f) == 0); - if (ok) - *(FILE **)lua_touserdata(L, 1) = NULL; /* mark file as closed */ + int ok = fh->ispipe ? (pclose(f) != -1) : (fclose(f) == 0); + fh->f = NULL; /* mark file as closed */ return ok; } } @@ -167,8 +178,8 @@ static int io_close (lua_State *L) { static int io_gc (lua_State *L) { - FILE **f = topfile(L, 1); - if (*f != NULL) /* ignore closed files */ + FileHandle *fh = topfile(L, 1); + if (fh->f != NULL) /* ignore closed files */ aux_close(L); return 0; } @@ -176,8 +187,8 @@ static int io_gc (lua_State *L) { static int io_tostring (lua_State *L) { char buff[128]; - FILE **f = topfile(L, 1); - if (*f == NULL) + FileHandle *fh = topfile(L, 1); + if (fh->f == NULL) strcpy(buff, "closed"); else sprintf(buff, "%p", lua_touserdata(L, 1)); @@ -202,9 +213,10 @@ static int io_popen (lua_State *L) { #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; + FileHandle *fh = newfileh(L); + fh->f = popen(filename, mode); + fh->ispipe = 1; + return (fh->f == NULL) ? pushresult(L, 0, filename) : 1; #endif } diff --git a/src/lvm.c b/src/lvm.c index 94e2802d86..951329315c 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 1.284b 2003/04/03 13:35:34 roberto Exp $ +** $Id: lvm.c,v 1.284c 2003/04/03 13:35:34 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -321,15 +321,15 @@ void luaV_concat (lua_State *L, int total, int last) { 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 */ - lu_mem tl = cast(lu_mem, tsvalue(top-1)->tsv.len) + - cast(lu_mem, tsvalue(top-2)->tsv.len); + size_t tl = tsvalue(top-1)->tsv.len; char *buffer; int i; - while (n < total && tostring(L, top-n-1)) { /* collect total length */ - tl += tsvalue(top-n-1)->tsv.len; - n++; + /* collect total length */ + for (n = 1; n < total && tostring(L, top-n-1); n++) { + size_t l = tsvalue(top-n-1)->tsv.len; + if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); + tl += l; } - 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 */ From 8cc1344d3f8533bc4062f1a501db568ccf6252ef Mon Sep 17 00:00:00 2001 From: Kate Adams Date: Sun, 4 Jan 2015 08:29:42 +0000 Subject: [PATCH 23/40] Imported Lua 5.1 --- COPYRIGHT | 2 +- DIFFS | 294 -- HISTORY | 26 +- INSTALL | 130 +- MANIFEST | 237 +- Makefile | 184 +- README | 23 +- UPDATE | 23 - build | 33 - config | 178 -- configure | 9 - doc/contents.html | 392 ++- doc/lua.1 | 38 +- doc/lua.css | 15 + doc/lua.html | 53 +- doc/luac.1 | 44 +- doc/luac.html | 67 +- doc/manual.html | 6495 ++++++++++++++++++++++++-------------- doc/readme.html | 7 +- etc/Makefile | 76 +- etc/README | 56 +- etc/all.c | 38 + etc/bin2c.c | 67 - etc/compat.lua | 192 -- etc/doall.lua | 6 - etc/lua.hpp | 9 + etc/lua.magic | 12 - etc/lua.pc | 27 + etc/lua.xpm | 44 - etc/luavs.bat | 7 + etc/luser_number.h | 34 - etc/luser_tests.h | 68 - etc/min.c | 19 +- etc/noparser.c | 36 +- etc/saconfig.c | 87 - etc/strict.lua | 34 + etc/trace.c | 55 - include/Makefile | 17 - include/lauxlib.h | 145 - include/lua.h | 391 --- include/lualib.h | 56 - src/Makefile | 253 +- src/README | 5 - src/lapi.c | 643 ++-- src/lapi.h | 4 +- src/{lib => }/lauxlib.c | 312 +- src/lauxlib.h | 172 + src/{lib => }/lbaselib.c | 428 ++- src/lcode.c | 453 ++- src/lcode.h | 67 +- src/ldblib.c | 397 +++ src/ldebug.c | 327 +- src/ldebug.h | 22 +- src/ldo.c | 366 ++- src/ldo.h | 51 +- src/ldump.c | 164 +- src/lfunc.c | 105 +- src/lfunc.h | 30 +- src/lgc.c | 774 +++-- src/lgc.h | 101 +- src/lib/Makefile | 27 - src/lib/README | 8 - src/lib/ldblib.c | 299 -- src/lib/liolib.c | 762 ----- src/lib/loadlib.c | 205 -- src/linit.c | 38 + src/liolib.c | 532 ++++ src/llex.c | 531 ++-- src/llex.h | 28 +- src/llimits.h | 139 +- src/{lib => }/lmathlib.c | 105 +- src/lmem.c | 97 +- src/lmem.h | 39 +- src/loadlib.c | 667 ++++ src/lobject.c | 127 +- src/lobject.h | 191 +- src/lopcodes.c | 102 +- src/lopcodes.h | 124 +- src/loslib.c | 238 ++ src/lparser.c | 619 ++-- src/lparser.h | 28 +- src/lstate.c | 202 +- src/lstate.h | 129 +- src/lstring.c | 63 +- src/lstring.h | 18 +- src/{lib => }/lstrlib.c | 415 ++- src/ltable.c | 493 +-- src/ltable.h | 33 +- src/{lib => }/ltablib.c | 130 +- src/ltests.c | 852 ----- src/ltm.c | 29 +- src/ltm.h | 17 +- src/lua.c | 377 +++ src/lua.h | 384 +++ src/luac.c | 196 ++ src/luaconf.h | 736 +++++ src/lualib.h | 53 + src/lundump.c | 287 +- src/lundump.h | 30 +- src/lvm.c | 795 +++-- src/lvm.h | 21 +- src/lzio.c | 37 +- src/lzio.h | 37 +- src/print.c | 224 ++ test/README | 1 - test/fibfor.lua | 2 +- test/lua | 1 - test/luac | 1 - test/luac.lua | 4 +- test/printf.lua | 2 +- test/trace-calls.lua | 4 +- test/undefined.lua | 9 - test/xd.lua | 6 +- 113 files changed, 14061 insertions(+), 10833 deletions(-) delete mode 100644 DIFFS delete mode 100644 UPDATE delete mode 100755 build delete mode 100644 config delete mode 100755 configure create mode 100644 doc/lua.css create mode 100644 etc/all.c delete mode 100644 etc/bin2c.c delete mode 100644 etc/compat.lua delete mode 100644 etc/doall.lua create mode 100644 etc/lua.hpp delete mode 100644 etc/lua.magic create mode 100644 etc/lua.pc delete mode 100644 etc/lua.xpm create mode 100644 etc/luavs.bat delete mode 100644 etc/luser_number.h delete mode 100644 etc/luser_tests.h delete mode 100644 etc/saconfig.c create mode 100644 etc/strict.lua delete mode 100644 etc/trace.c delete mode 100644 include/Makefile delete mode 100644 include/lauxlib.h delete mode 100644 include/lua.h delete mode 100644 include/lualib.h delete mode 100644 src/README rename src/{lib => }/lauxlib.c (60%) create mode 100644 src/lauxlib.h rename src/{lib => }/lbaselib.c (61%) create mode 100644 src/ldblib.c delete mode 100644 src/lib/Makefile delete mode 100644 src/lib/README delete mode 100644 src/lib/ldblib.c delete mode 100644 src/lib/liolib.c delete mode 100644 src/lib/loadlib.c create mode 100644 src/linit.c create mode 100644 src/liolib.c rename src/{lib => }/lmathlib.c (73%) create mode 100644 src/loadlib.c create mode 100644 src/loslib.c rename src/{lib => }/lstrlib.c (62%) rename src/{lib => }/ltablib.c (67%) delete mode 100644 src/ltests.c create mode 100644 src/lua.c create mode 100644 src/lua.h create mode 100644 src/luac.c create mode 100644 src/luaconf.h create mode 100644 src/lualib.h create mode 100644 src/print.c delete mode 120000 test/lua delete mode 120000 test/luac delete mode 100644 test/undefined.lua diff --git a/COPYRIGHT b/COPYRIGHT index 2cd57d3b46..84d401b1e4 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -9,7 +9,7 @@ For details and rationale, see http://www.lua.org/license.html . =============================================================================== -Copyright (C) 2003-2006 Tecgraf, 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/DIFFS b/DIFFS deleted file mode 100644 index c236ff8b9a..0000000000 --- a/DIFFS +++ /dev/null @@ -1,294 +0,0 @@ -diff -r lua-5.0.2/COPYRIGHT lua-5.0.3/COPYRIGHT -12c12 -< Copyright (C) 2003-2004 Tecgraf, PUC-Rio. ---- -> Copyright (C) 2003-2006 Tecgraf, PUC-Rio. -diff -r lua-5.0.2/include/lua.h lua-5.0.3/include/lua.h -2c2 -< ** $Id: lua.h,v 1.175b 2003/03/18 12:31:39 roberto Exp $ ---- -> ** $Id: lua.h,v 1.175c 2003/03/18 12:31:39 roberto Exp $ -17,18c17,18 -< #define LUA_VERSION "Lua 5.0.2" -< #define LUA_COPYRIGHT "Copyright (C) 1994-2004 Tecgraf, PUC-Rio" ---- -> #define LUA_VERSION "Lua 5.0.3" -> #define LUA_COPYRIGHT "Copyright (C) 1994-2006 Tecgraf, PUC-Rio" -368c368 -< * Copyright (C) 1994-2004 Tecgraf, PUC-Rio. All rights reserved. ---- -> * Copyright (C) 1994-2006 Tecgraf, PUC-Rio. All rights reserved. -diff -r lua-5.0.2/src/lapi.c lua-5.0.3/src/lapi.c -2c2 -< ** $Id: lapi.c,v 1.235 2003/04/07 14:36:08 roberto Exp $ ---- -> ** $Id: lapi.c,v 1.235a 2003/04/07 14:36:08 roberto Exp $ -882c882 -< if (n > f->c.nupvalues) return NULL; ---- -> if (!(1 <= n && n <= f->c.nupvalues)) return NULL; -888c888 -< if (n > p->sizeupvalues) return NULL; ---- -> if (!(1 <= n && n <= p->sizeupvalues)) return NULL; -diff -r lua-5.0.2/src/lcode.c lua-5.0.3/src/lcode.c -2c2 -< ** $Id: lcode.c,v 1.117 2003/04/03 13:35:34 roberto Exp $ ---- -> ** $Id: lcode.c,v 1.117a 2003/04/03 13:35:34 roberto Exp $ -105c105,108 -< if (GET_OPCODE(i) != OP_TEST || GETARG_C(i) != cond) return 1; ---- -> if (GET_OPCODE(i) != OP_TEST || -> GETARG_A(i) != NO_REG || -> GETARG_C(i) != cond) -> return 1; -117,118c120,130 -< static void luaK_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 = luaK_getjump(fs, list)) { -> Instruction *i = getjumpcontrol(fs, list); -> if (GET_OPCODE(*i) == OP_TEST) -> patchtestreg(i, NO_REG); -> } -> } -> -> -> static void luaK_patchlistaux (FuncState *fs, int list, int vtarget, int reg, -> int dtarget) { -122,136c134,136 -< 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); -< } ---- -> if (GET_OPCODE(*i) == OP_TEST && GETARG_A(*i) == NO_REG) { -> patchtestreg(i, reg); -> luaK_fixjump(fs, list, vtarget); -137a138,139 -> else -> luaK_fixjump(fs, list, dtarget); /* jump to default target */ -144c146 -< luaK_patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc, NO_REG, fs->pc); ---- -> luaK_patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); -154c156 -< luaK_patchlistaux(fs, list, target, NO_REG, target, NO_REG, target); ---- -> luaK_patchlistaux(fs, list, target, NO_REG, target); -357,358c359,360 -< 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); ---- -> luaK_patchlistaux(fs, e->f, final, reg, p_f); -> luaK_patchlistaux(fs, e->t, final, reg, p_t); -476c478 -< return luaK_condjump(fs, OP_TEST, NO_REG, GETARG_B(ie), !cond); ---- -> return luaK_condjump(fs, OP_TEST, GETARG_B(ie), GETARG_B(ie), !cond); -566a569,570 -> removevalues(fs, e->f); -> removevalues(fs, e->t); -diff -r lua-5.0.2/src/lfunc.c lua-5.0.3/src/lfunc.c -2c2 -< ** $Id: lfunc.c,v 1.67 2003/03/18 12:50:04 roberto Exp $ ---- -> ** $Id: lfunc.c,v 1.67a 2003/03/18 12:50:04 roberto Exp $ -19,26d18 -< -< -< #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))) -< -diff -r lua-5.0.2/src/lfunc.h lua-5.0.3/src/lfunc.h -2c2 -< ** $Id: lfunc.h,v 1.21 2003/03/18 12:50:04 roberto Exp $ ---- -> ** $Id: lfunc.h,v 1.21a 2003/03/18 12:50:04 roberto Exp $ -11a12,18 -> -> -> #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))) -diff -r lua-5.0.2/src/lgc.c lua-5.0.3/src/lgc.c -2c2 -< ** $Id: lgc.c,v 1.171a 2003/04/03 13:35:34 roberto Exp $ ---- -> ** $Id: lgc.c,v 1.171b 2003/04/03 13:35:34 roberto Exp $ -221,224c221,222 -< if (!u->marked) { -< markobject(st, &u->value); -< u->marked = 1; -< } ---- -> markobject(st, u->v); -> u->marked = 1; -261c259,260 -< static void propagatemarks (GCState *st) { ---- -> static lu_mem propagatemarks (GCState *st) { -> lu_mem mf = 0; -267a267,268 -> mf += sizeof(Table) + sizeof(TObject) * h->sizearray + -> sizeof(Node) * sizenode(h); -273a275,276 -> mf += (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : -> sizeLclosure(cl->l.nupvalues); -279a283,284 -> mf += sizeof(lua_State) + sizeof(TObject) * th->stacksize + -> sizeof(CallInfo) * th->size_ci; -285a291 -> /* do not need 'mf' for this case (cannot happen inside a udata) */ -290a297 -> return mf; -371c378 -< if (curr->gch.marked > limit) { ---- -> if ((curr->gch.marked & ~(KEYWEAK | VALUEWEAK)) > limit) { -473c480 -< propagatemarks(&st); /* remark, to propagate `preserveness' */ ---- -> deadmem += propagatemarks(&st); /* remark, to propagate `preserveness' */ -diff -r lua-5.0.2/src/lib/lbaselib.c lua-5.0.3/src/lib/lbaselib.c -2c2 -< ** $Id: lbaselib.c,v 1.130b 2003/04/03 13:35:34 roberto Exp $ ---- -> ** $Id: lbaselib.c,v 1.130c 2003/04/03 13:35:34 roberto Exp $ -175a176 -> lua_settop(L, 2); -183a185 -> lua_settop(L, 3); -diff -r lua-5.0.2/src/lib/liolib.c lua-5.0.3/src/lib/liolib.c -2c2 -< ** $Id: liolib.c,v 2.39a 2003/03/19 21:16:12 roberto Exp $ ---- -> ** $Id: liolib.c,v 2.39b 2003/03/19 21:16:12 roberto Exp $ -22a23,28 -> typedef struct FileHandle { -> FILE *f; -> int ispipe; -> } FileHandle; -> -> -89,92c95,98 -< 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 FileHandle *topfile (lua_State *L, int findex) { -> FileHandle *fh = (FileHandle *)luaL_checkudata(L, findex, FILEHANDLE); -> if (fh == NULL) luaL_argerror(L, findex, "bad file"); -> return fh; -97,99c103,105 -< FILE **f = (FILE **)luaL_checkudata(L, 1, FILEHANDLE); -< if (f == NULL) lua_pushnil(L); -< else if (*f == NULL) ---- -> FileHandle *fh = (FileHandle *)luaL_checkudata(L, 1, FILEHANDLE); -> if (fh == NULL) lua_pushnil(L); -> else if (fh->f == NULL) -107,109c113,117 -< static FILE *tofile (lua_State *L, int findex) { -< FILE **f = topfile(L, findex); -< if (*f == NULL) ---- -> #define tofile(L,i) (tofileh(L,i)->f) -> -> static FileHandle *tofileh (lua_State *L, int findex) { -> FileHandle *fh = topfile(L, findex); -> if (fh->f == NULL) -111c119 -< return *f; ---- -> return fh; -115a124,125 -> #define newfile(L) (&(newfileh(L)->f)) -> -121,123c131,134 -< static FILE **newfile (lua_State *L) { -< FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); -< *pf = NULL; /* file handle is currently `closed' */ ---- -> static FileHandle *newfileh (lua_State *L) { -> FileHandle *fh = (FileHandle *)lua_newuserdata(L, sizeof(FileHandle)); -> fh->f = NULL; /* file handle is currently `closed' */ -> fh->ispipe = 0; -126c137 -< return pf; ---- -> return fh; -148c159,160 -< FILE *f = tofile(L, 1); ---- -> FileHandle *fh = tofileh(L, 1); -> FILE *f = fh->f; -152,154c164,165 -< int ok = (pclose(f) != -1) || (fclose(f) == 0); -< if (ok) -< *(FILE **)lua_touserdata(L, 1) = NULL; /* mark file as closed */ ---- -> int ok = fh->ispipe ? (pclose(f) != -1) : (fclose(f) == 0); -> fh->f = NULL; /* mark file as closed */ -170,171c181,182 -< FILE **f = topfile(L, 1); -< if (*f != NULL) /* ignore closed files */ ---- -> FileHandle *fh = topfile(L, 1); -> if (fh->f != NULL) /* ignore closed files */ -179,180c190,191 -< FILE **f = topfile(L, 1); -< if (*f == NULL) ---- -> FileHandle *fh = topfile(L, 1); -> if (fh->f == NULL) -205,207c216,219 -< FILE **pf = newfile(L); -< *pf = popen(filename, mode); -< return (*pf == NULL) ? pushresult(L, 0, filename) : 1; ---- -> FileHandle *fh = newfileh(L); -> fh->f = popen(filename, mode); -> fh->ispipe = 1; -> return (fh->f == NULL) ? pushresult(L, 0, filename) : 1; -diff -r lua-5.0.2/src/lvm.c lua-5.0.3/src/lvm.c -2c2 -< ** $Id: lvm.c,v 1.284b 2003/04/03 13:35:34 roberto Exp $ ---- -> ** $Id: lvm.c,v 1.284c 2003/04/03 13:35:34 roberto Exp $ -324,325c324 -< lu_mem tl = cast(lu_mem, tsvalue(top-1)->tsv.len) + -< cast(lu_mem, tsvalue(top-2)->tsv.len); ---- -> size_t tl = tsvalue(top-1)->tsv.len; -328,330c327,331 -< while (n < total && tostring(L, top-n-1)) { /* collect total length */ -< tl += tsvalue(top-n-1)->tsv.len; -< n++; ---- -> /* collect total length */ -> for (n = 1; n < total && tostring(L, top-n-1); n++) { -> size_t l = tsvalue(top-n-1)->tsv.len; -> if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); -> tl += l; -332d332 -< if (tl > MAX_SIZET) luaG_runerror(L, "string size overflow"); diff --git a/HISTORY b/HISTORY index cf6e1c019d..d807a53383 100644 --- a/HISTORY +++ b/HISTORY @@ -1,4 +1,28 @@ -This is Lua 5.0. +HISTORY for Lua 5.1 + +* 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 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). + + luaopen_* functionst must be called through Lua. + Implementation: + + new configuration scheme via luaconf.h. + + 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. + + 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/INSTALL b/INSTALL index 748c6861d0..65f6f1eb07 100644 --- a/INSTALL +++ b/INSTALL @@ -1,80 +1,96 @@ -This is Lua 5.0. +INSTALL for Lua 5.1 -* Installation +* Building Lua ------------ - Building Lua on a Unix system should be very easy: + Lua is built in the src directory, but the build process can be + controlled from the top-level Makefile. - 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. + 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 - See below for instructions for Windows and other systems. + See below for customization instructions and for instructions on how + to build with other Windows compilers. + + 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 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: + + bin: lua luac + include: lua.h luaconf.h lualib.h lauxlib.h lua.hpp + lib: liblua.a + man/man1: lua.1 luac.1 -* 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. - 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. + 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. - See also the README files in the various subdirectories. - A convenient starting point is ./doc/readme.html. + If you want to install Lua locally, but in some other directory, do + "make install INSTALL_TOP=xxx", where xxx is your chosen directory. -* If you have problems (and solutions!) - ------------------------------------- - If "make" fails, please let us know (lua@tecgraf.puc-rio.br). - If you make changes to "config" or to the Makefiles, please send them to us. + See below for instructions for Windows and other systems. -* 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". +* 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. - 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". + You don't actually need to edit the Makefiles because you may set the + relevant variables when invoking make. - 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. + 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 + it will be used by any Lua clients that you build, to ensure consistency. - 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.) + 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. - Building shared libraries in other systems is similar but details differ; - you may need to fix a few details in the top-level Makefile. +* Building Lua on Windows and 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: -* 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: + 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 - 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 + interpreter: library, lua.c - standard lib: lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c ltablib.c - lstrlib.c loadlib.c + compiler: library, luac.c print.c - interpreter: core lib, standard lib, lua.c + If you use Visual Studio .NET, you can use etc/luavs.bat + in its "Command Prompt". - compiler: core lib, standard lib, luac.c print.c - and also lopcodes.c (with LUA_OPNAMES defined) from core. + 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. - Of course, to use Lua as a library, you'll have to know how to create - and use libraries with your compiler. + 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 9692b6aa3d..fd18c8bb9e 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,131 +1,108 @@ -MANIFEST contents of Lua 5.0.3 distribution on Mon Jun 19 11:04:48 BRT 2006 -lua-5.0.3 -lua-5.0.3/COPYRIGHT -lua-5.0.3/DIFFS -lua-5.0.3/HISTORY -lua-5.0.3/INSTALL -lua-5.0.3/MANIFEST -lua-5.0.3/Makefile -lua-5.0.3/README -lua-5.0.3/UPDATE -lua-5.0.3/bin -lua-5.0.3/build -lua-5.0.3/config -lua-5.0.3/configure -lua-5.0.3/doc -lua-5.0.3/doc/contents.html -lua-5.0.3/doc/logo.gif -lua-5.0.3/doc/lua.1 -lua-5.0.3/doc/lua.html -lua-5.0.3/doc/luac.1 -lua-5.0.3/doc/luac.html -lua-5.0.3/doc/manual.html -lua-5.0.3/doc/readme.html -lua-5.0.3/etc -lua-5.0.3/etc/Makefile -lua-5.0.3/etc/README -lua-5.0.3/etc/bin2c.c -lua-5.0.3/etc/compat.lua -lua-5.0.3/etc/doall.lua -lua-5.0.3/etc/lua.ico -lua-5.0.3/etc/lua.magic -lua-5.0.3/etc/lua.xpm -lua-5.0.3/etc/luser_number.h -lua-5.0.3/etc/luser_tests.h -lua-5.0.3/etc/min.c -lua-5.0.3/etc/noparser.c -lua-5.0.3/etc/saconfig.c -lua-5.0.3/etc/trace.c -lua-5.0.3/include -lua-5.0.3/include/Makefile -lua-5.0.3/include/lauxlib.h -lua-5.0.3/include/lua.h -lua-5.0.3/include/lualib.h -lua-5.0.3/lib -lua-5.0.3/src -lua-5.0.3/src/Makefile -lua-5.0.3/src/README -lua-5.0.3/src/lapi.c -lua-5.0.3/src/lapi.h -lua-5.0.3/src/lcode.c -lua-5.0.3/src/lcode.h -lua-5.0.3/src/ldebug.c -lua-5.0.3/src/ldebug.h -lua-5.0.3/src/ldo.c -lua-5.0.3/src/ldo.h -lua-5.0.3/src/ldump.c -lua-5.0.3/src/lfunc.c -lua-5.0.3/src/lfunc.h -lua-5.0.3/src/lgc.c -lua-5.0.3/src/lgc.h -lua-5.0.3/src/lib -lua-5.0.3/src/lib/Makefile -lua-5.0.3/src/lib/README -lua-5.0.3/src/lib/lauxlib.c -lua-5.0.3/src/lib/lbaselib.c -lua-5.0.3/src/lib/ldblib.c -lua-5.0.3/src/lib/liolib.c -lua-5.0.3/src/lib/lmathlib.c -lua-5.0.3/src/lib/loadlib.c -lua-5.0.3/src/lib/lstrlib.c -lua-5.0.3/src/lib/ltablib.c -lua-5.0.3/src/llex.c -lua-5.0.3/src/llex.h -lua-5.0.3/src/llimits.h -lua-5.0.3/src/lmem.c -lua-5.0.3/src/lmem.h -lua-5.0.3/src/lobject.c -lua-5.0.3/src/lobject.h -lua-5.0.3/src/lopcodes.c -lua-5.0.3/src/lopcodes.h -lua-5.0.3/src/lparser.c -lua-5.0.3/src/lparser.h -lua-5.0.3/src/lstate.c -lua-5.0.3/src/lstate.h -lua-5.0.3/src/lstring.c -lua-5.0.3/src/lstring.h -lua-5.0.3/src/ltable.c -lua-5.0.3/src/ltable.h -lua-5.0.3/src/ltests.c -lua-5.0.3/src/ltm.c -lua-5.0.3/src/ltm.h -lua-5.0.3/src/lua -lua-5.0.3/src/lua/Makefile -lua-5.0.3/src/lua/README -lua-5.0.3/src/lua/lua.c -lua-5.0.3/src/luac -lua-5.0.3/src/luac/Makefile -lua-5.0.3/src/luac/README -lua-5.0.3/src/luac/luac.c -lua-5.0.3/src/luac/print.c -lua-5.0.3/src/lundump.c -lua-5.0.3/src/lundump.h -lua-5.0.3/src/lvm.c -lua-5.0.3/src/lvm.h -lua-5.0.3/src/lzio.c -lua-5.0.3/src/lzio.h -lua-5.0.3/test -lua-5.0.3/test/README -lua-5.0.3/test/bisect.lua -lua-5.0.3/test/cf.lua -lua-5.0.3/test/echo.lua -lua-5.0.3/test/env.lua -lua-5.0.3/test/factorial.lua -lua-5.0.3/test/fib.lua -lua-5.0.3/test/fibfor.lua -lua-5.0.3/test/globals.lua -lua-5.0.3/test/hello.lua -lua-5.0.3/test/life.lua -lua-5.0.3/test/lua -lua-5.0.3/test/luac -lua-5.0.3/test/luac.lua -lua-5.0.3/test/printf.lua -lua-5.0.3/test/readonly.lua -lua-5.0.3/test/sieve.lua -lua-5.0.3/test/sort.lua -lua-5.0.3/test/table.lua -lua-5.0.3/test/trace-calls.lua -lua-5.0.3/test/trace-globals.lua -lua-5.0.3/test/undefined.lua -lua-5.0.3/test/xd.lua +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 9ab901d4da..56a9b665dd 100644 --- a/Makefile +++ b/Makefile @@ -1,102 +1,126 @@ -# makefile for Lua hierarchy +# makefile for installing Lua # see INSTALL for installation instructions -# see config for customization instructions - -LUA= . - -include $(LUA)/config - -# primary targets ("co" and "klean" are used for making the distribution) -all clean co klean: dirs - cd include; $(MAKE) $@ - cd src; $(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/* - -# 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) - -# 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/* - 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/* +# see src/Makefile and src/luaconf.h for further customization + +# == 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.) +# +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 + +# 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 + +# Utilities. +CP= cp +FIND= find +INSTALL= install +MKDIR= mkdir +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 + +# What to install. +TO_BIN= lua luac +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. +V= 5.1 + +all: $(PLAT) + +$(PLATS) clean: + 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) +# $(RANLIB) $(INSTALL_LIB)/$(TO_LIB) + +local: + $(MAKE) install INSTALL_TOP=.. INSTALL_EXEC="cp -p" INSTALL_DATA="cp -p" + +none: + @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: # 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 "" - @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)" + @cd src && $(MAKE) -s 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)" @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 "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 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: - @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 + @$(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/README b/README index 4aaaba5286..f082d40460 100644 --- a/README +++ b/README @@ -1,4 +1,6 @@ -This is Lua 5.0. +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? @@ -17,9 +19,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,18 +27,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@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 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. + 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/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/build b/build deleted file mode 100755 index 6faed3710c..0000000000 --- a/build +++ /dev/null @@ -1,33 +0,0 @@ -# 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 deleted file mode 100644 index 34c77ea372..0000000000 --- a/config +++ /dev/null @@ -1,178 +0,0 @@ -# configuration file for making Lua 5.0 -# 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 ======================= - -# --------------------------------------------------------------- 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 - -# 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 -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. 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 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 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.0 - -BIN= $(LUA)/bin -INC= $(LUA)/include -LIB= $(LUA)/lib - -INCS= -I$(INC) $(EXTRA_INCS) -DEFS= $(NUMBER) $(EXTRA_DEFS) - -CFLAGS= $(MYCFLAGS) $(WARN) $(INCS) $(DEFS) - -# (end of config) 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/doc/contents.html b/doc/contents.html index 06bd6fb4c7..564377c942 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -1,32 +1,28 @@ -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. +© 2006 Lua.org, PUC-Rio. All rights reserved. +


        +

        Contents

        -
      • 3 - The Application Program Interface -
      • 4 - The Debug Interface +
      • 4 - The Auxiliary Library
      • 5 - Standard Libraries
      • 6 - Lua Stand-alone +
      • Incompatibilities with the Previous Version
      • The Complete Syntax of Lua +
      +

      Quick index

      + + + + + + +
      +

      Functions

      +_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
      +math.abs
      +math.acos
      +math.asin
      +math.atan2
      +math.atan
      +math.ceil
      +math.cosh
      +math.cos
      +math.deg
      +math.exp
      +math.floor
      +math.fmod
      +math.frexp
      +math.ldexp
      +math.log10
      +math.log
      +math.max
      +math.min
      +math.modf
      +math.pow
      +math.rad
      +math.random
      +math.randomseed
      +math.sinh
      +math.sin
      +math.sqrt
      +math.tanh
      +math.tan
      +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
      +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_getglobal
      +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_pushthread
      +lua_pushvalue
      +lua_pushvfstring
      +lua_rawequal
      +lua_rawget
      +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
      +lua_settable
      +lua_settop
      +lua_setupvalue
      +lua_status
      +lua_toboolean
      +lua_tocfunction
      +lua_tointeger
      +lua_tolstring
      +lua_tonumber
      +lua_topointer
      +lua_tostring
      +lua_tothread
      +lua_touserdata
      +lua_type
      +lua_typename
      +lua_xmove
      +lua_yield
      + +
      +

      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_openlibs
      +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: -Wed May 7 18:34:34 EST 2003 +Fri Feb 10 17:15:37 BRST 2006 diff --git a/doc/lua.1 b/doc/lua.1 index c9bba7d700..24809cc6c1 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.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 " file" +.BI \-l " name" call -.BI require( file ) +.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. @@ -163,5 +160,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..1d435ab029 100644 --- a/doc/lua.html +++ b/doc/lua.html @@ -1,14 +1,15 @@ - + LUA man page + -

      NAME

      +

      NAME

      lua - Lua interpreter -

      SYNOPSIS

      +

      SYNOPSIS

      lua [ options @@ -19,7 +20,7 @@

      SYNOPSIS

      args ] ] -

      DESCRIPTION

      +

      DESCRIPTION

      lua is the stand-alone Lua interpreter. It loads and executes Lua programs, @@ -51,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, @@ -69,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, @@ -102,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 @@ -121,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, @@ -134,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 @@ -147,29 +147,26 @@

      OPTIONS

      script is executed.

      --l "file" +-l name call -require( file) +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 W. Celes -(lua AT tecgraf.puc-rio.br) diff --git a/doc/luac.1 b/doc/luac.1 index c6523060f8..d8146782df 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.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 @@ -13,11 +13,11 @@ 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, -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,17 +43,6 @@ 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 @@ -56,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 @@ -88,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. @@ -112,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. @@ -132,5 +133,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..179ffe8288 100644 --- a/doc/luac.html +++ b/doc/luac.html @@ -1,37 +1,45 @@ - + LUAC man page + -

      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 -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, -protecting source code from user changes, +protecting source code from accidental user changes, 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.

      +Precompiled chunks are not necessarily smaller than the corresponding source. +The main goal in precompiling 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. @@ -42,34 +50,23 @@

      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 (``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, +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 -"-" +'-' 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 @@ -77,7 +74,7 @@

      DESCRIPTION

      So, save the source files of all Lua programs that you precompile.

      -

      OPTIONS

      +

      OPTIONS

      Options must be separate.

      -l @@ -89,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. @@ -118,27 +119,27 @@

      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 -(lua AT tecgraf.puc-rio.br) diff --git a/doc/manual.html b/doc/manual.html index 2a92d2aaf4..a44d2e8ea3 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1,33 +1,33 @@ - + -Lua: 5.0 reference manual +Lua 5.1 Reference Manual + - + -
      +

      -Lua -Lua 5.0 Reference Manual +[Lua logo] +Lua 5.1 Reference Manual

      by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes

      -Copyright -© 2003 Tecgraf, PUC-Rio. All rights reserved. +Copyright +© 2006 Lua.org, PUC-Rio. All rights reserved. -


      +

      - -

      1 - Introduction

      +

      1 - Introduction

      Lua is an extension programming language designed to support general procedural programming with data description @@ -35,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++). @@ -44,48 +44,28 @@

      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 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

      +

      2 - The Language

      This section describes the lexis, the syntax, and the semantics of Lua. In other words, @@ -94,49 +74,53 @@

      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. +{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. +The complete syntax of Lua can be found at the end of this manual. -

      2.1 - Lexical Conventions

      +

      2.1 - Lexical Conventions

      -

      Identifiers 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 identifiers in most languages. +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 identifiers: +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 identifiers. -As a convention, identifiers starting with an underscore followed by -uppercase letters (such as _VERSION) -are reserved for internal variables used by Lua. +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, @@ -150,10 +134,8 @@

    • \t --- horizontal tab
    • \v --- vertical tab
    • \\ --- backslash -
    • \" --- quotation mark -
    • \' --- apostrophe -
    • \[ --- left square bracket -
    • \] --- right square bracket +
    • \" --- quotation mark (double quote) +
    • \' --- apostrophe (single quote)
    Moreover, a `\newline´ (that is, a backslash followed by a real newline) @@ -161,86 +143,109 @@

    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´. -

    Literal strings can also be delimited by matching double square brackets -[[ · · · ]]. +

    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 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. 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. +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. + +

    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), +(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"]]
    -
    + 123"]==] +

    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 anywhere outside a string with a -double hyphen (--). -If the text immediately after -- is different from [[, +

    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 ]]. -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). +which runs until the corresponding closing long bracket. +Long comments are frequently used to disable code temporarily. -

    2.2 - Values and Types

    +

    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. +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: nil, boolean, number, -string, function, userdata, thread, and table. -Nil is the type of the value nil, +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; +it usually represents the absence of a useful value. +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. (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 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). +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.7). +(see 2.5.8).

    The type userdata is provided to allow arbitrary C data to be stored in Lua variables. @@ -251,18 +256,20 @@

    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. +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. +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, -that is, they can contain values of all types (except nil). +but with any value (except nil). +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. @@ -270,37 +277,38 @@

    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). +(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, +because functions are first-class values, table fields may contain functions. -Thus tables may also carry methods (see 2.5.8). +Thus tables may also carry methods (see 2.5.9). -

    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 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). +

    The library function type returns a string describing the type +of a given value. -

    2.2.1 - Coercion

    +

    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. +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 of how numbers are converted to strings, -use the format function from the string library (see 5.3). +For complete control over how numbers are converted to strings, +use the format function from the string library +(see string.format). -

    2.3 - Variables

    +

    2.3 - Variables

    Variables are places that store values. @@ -308,31 +316,33 @@

    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's 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 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:

     	var ::= prefixexp `[´ exp `]´
     
    -The first expression (prefixexp)should result in a table value; +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 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"]: +

    The syntax var.Name is just syntactic sugar for +var["Name"] and is used to denote table fields:

     	var ::= prefixexp `.´ Name
     
    @@ -347,37 +357,42 @@

    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. +called environment tables or simply +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. 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). +To get the environment table of a Lua function, +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).)

    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.) +(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

    +

    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, +assignment, control structures, function 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, @@ -386,12 +401,16 @@

     	chunk ::= {stat [`;´]}
     
    +There are no empty statements and thus `;;´ is not legal. -

    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. +

    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 +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. @@ -402,9 +421,9 @@

    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: +syntactically, a block is the same as a chunk:
     	block ::= chunk
     
    @@ -420,7 +439,7 @@

    of another block (see 2.4.4). -

    2.4.3 - Assignment

    +

    2.4.3 - Assignment

    Lua allows multiple assignment. Therefore, the syntax for assignment @@ -440,26 +459,26 @@

    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, +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).

    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. +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 @@ -475,14 +494,14 @@

    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

    +

    2.4.4 - Control Structures

    The control structures if, while, and repeat have the usual meaning and familiar syntax: @@ -496,14 +515,20 @@

    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 +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, +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 -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 @@ -511,7 +536,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: @@ -520,7 +545,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, @@ -530,10 +555,8 @@

    `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

    +

    2.4.5 - For Statement

    The for statement has two forms: one numeric and one generic. @@ -549,32 +572,32 @@

    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, _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
    +           _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. +
    • _var, _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. +
    • 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; +
    • 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. @@ -582,139 +605,183 @@

      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 -
      +
              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
      +         local _f, _s, _var = explist
                while true do
      -           var_1, ..., var_n = _f(_s, var_1)
      -           if var_1 == nil then break end
      +           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 and _s are invisible variables. +
      • _f, _s, and _var 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; +
      • 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.7. +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]
      -	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. +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. +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

      +

      2.5 - Expressions

      The basic expressions in Lua are the following:

       	exp ::= prefixexp
      -	exp ::= nil | false | true
      +	exp ::= nil  |  false  |  true
       	exp ::= Number
      -	exp ::= Literal
      +	exp ::= String
       	exp ::= function
       	exp ::= tableconstructor
      -	prefixexp ::= var | functioncall | `(´ exp `)´
      +	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.8; -function calls are explained in 2.5.7; -table constructors are explained in 2.5.6. +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.) +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

      +

      2.5.1 - Arithmetic Operators

      Lua supports the usual arithmetic operators: the binary + (addition), - (subtraction), * (multiplication), -/ (division), 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 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

      +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 remainder 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) 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. -Thus, "0"==0 evaluates to false, +Thus, "0"==0 evaluates to false, and t[0] and t["0"] denote different entries in a table. @@ -728,65 +795,89 @@

      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 -
      +
              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 return false or true. - -

      The conjunction operator and returns its first argument -if this value is false or nil; +

      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; +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, -

      -       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

      +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
      +
      +(In this manual, +`-->´ indicates the result of the preceding expression.) + +

      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 - 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 +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 +directly precedes 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)
      +       *     /     %
      +       not   #     - (unary)
              ^
      -
      -You can use parentheses to change the precedences in 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. -

      2.5.6 - 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, @@ -795,8 +886,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 @@ -808,35 +899,36 @@

      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 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
      -
      +

      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). +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 in parentheses (see 2.5). +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.7 - Function Calls

      +

      2.5.8 - Function Calls

      A function call in Lua has the following syntax:
       	functioncall ::= prefixexp args
      @@ -844,9 +936,9 @@ 

      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, 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). @@ -864,61 +956,24 @@

       	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. - -

      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
      -
      +(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. +This 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). +
      +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). @@ -935,18 +990,18 @@

      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 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
      -
      +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
      +
      -

      2.5.8 - Function Definitions

      +

      2.5.9 - Function Definitions

      The syntax for function definition is

      @@ -961,29 +1016,35 @@ 

      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
      -
      +
      +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. @@ -1000,8 +1061,7 @@

      Parameters act as local variables that are initialized with the argument values:

      -	parlist1 ::= namelist [`,´ `...´]
      -	parlist1 ::= `...´
      +	parlist1 ::= namelist [`,´ `...´]  |  `...´
       
      When a function is called, the list of arguments is adjusted to @@ -1010,20 +1070,27 @@

      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. +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: -
      +
      +Then, we have the following mapping from arguments to parameters and +to the vararg expression: +
              CALL            PARAMETERS
       
              f(3)             a=3, b=nil
      @@ -1032,11 +1099,11 @@ 

      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) 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 @@ -1047,51 +1114,44 @@

      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

      +

      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, +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, 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. @@ -1099,98 +1159,110 @@

      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

      +

      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). +

      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 print an error message). +(such as printing an error message).

      Lua code can explicitly generate an error by calling the -error function (see 5.1). +error function. If you need to catch errors in Lua, -you can use the pcall function (see 5.1). +you can use the pcall function. -

      2.8 - Metatables

      +

      2.8 - Metatables

      -

      Every table and userdata object in Lua may have a metatable. +

      Every value in Lua may have a metatable. This metatable is an ordinary Lua table -that defines the behavior of the original table and userdata +that defines the behavior of the original value 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, +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. +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 and change the metatable of an object -through the set/getmetatable -functions (see 5.1). +

      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. +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 table or a userdata, -it checks whether that object 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.

      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 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 and it is much more efficient than this simulation. All functions used in these descriptions -(rawget, tonumber, etc.) +(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]
      -
      +
      +       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 -(it simply results in nil). +(it simply results in nil).

        - -

      • "add": +
      • "add": the + operation.

        The function getbinhandler below defines how Lua chooses a handler @@ -1198,14 +1270,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, +
        +Using 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?
        @@ -1220,7 +1292,7 @@ 

        end end end -

        +

      • "sub": the - operation. @@ -1234,28 +1306,21 @@

        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. -
        - 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
        -
        +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?
        @@ -1264,18 +1329,18 @@ 

        -- 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) + -- 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
        @@ -1289,7 +1354,28 @@ 

        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. @@ -1298,16 +1384,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
        @@ -1323,12 +1409,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
        @@ -1343,12 +1429,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
        @@ -1368,7 +1454,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 @@ -1376,7 +1462,7 @@

      • "index": The indexing access table[key]. -
        +
          function gettable_event (table, key)
            local h
            if type(table) == "table" then
        @@ -1393,12 +1479,13 @@ 

        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
        @@ -1415,62 +1502,113 @@ 

        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
        +     return func(...)   -- primitive call
            else
              local h = metatable(func).__call
              if h then
        -       return h(func, unpack(arg))
        +       return h(func, ...)
              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. +

      2.9 - Environments

      + +

      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 +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 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 the function. + +

      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 +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. + +

      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, 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. -

      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, +

      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 +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 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 +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 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 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). These metamethods are also called finalizers. Finalizers allow you to coordinate Lua's garbage collection @@ -1478,20 +1616,20 @@

      (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, 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 @@ -1500,14 +1638,14 @@

      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.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. +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, @@ -1518,7 +1656,7 @@

      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. @@ -1528,11 +1666,10 @@

      Otherwise, the weak behavior of the tables controlled by this metatable is undefined. -

      2.10 - Coroutines

      +

      2.11 - Coroutines

      Lua supports coroutines, -also called semi-coroutines -or collaborative multithreading. +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 @@ -1546,11 +1683,12 @@

      it does not start the coroutine execution.

      When you first call coroutine.resume, -passing as its first 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 -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. @@ -1558,64 +1696,60 @@

      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. When a coroutine yields, -the corresponding coroutine.resume returns immediately, +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. +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. +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, +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, -this function does not catch errors; +Unlike coroutine.resume, +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: -
      +
       co-body 1       10
       foo     2
       main    true    4
      @@ -1624,1330 +1758,2635 @@ 

      co-body x y main true 10 end main false cannot resume dead coroutine -

      +

      -

      3 - The Application Program Interface

      +

      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 +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. +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);
      -
      +and so do not generate any hidden side-effects. -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. +

      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. -

      3.2 - The Stack and Indices

      +

      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.). +(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. +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, 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: +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. +(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 +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). +

      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. -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. +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 in lua.h as 20, +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. +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, 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). +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 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 Lua value must be a number or a string convertible to number -(see 2.2.1); otherwise, lua_tonumber returns 0. +

      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_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). +

      3.4 - C Closures

      -

      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. +

      When a C function is created, +it is possible to associate some values with it, +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, +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 +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. -

      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. +

      3.5 - Registry

      -

      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 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, +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. -

      lua_touserdata is explained in 3.8. +

      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 - Pushing Values onto the Stack

      +

      3.6 - Error Handling in C

      -

      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);
      -
      +

      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, +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. -

      +

      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 by calling lua_error. -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). -
      +

      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 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, 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. +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 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, +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. + +

      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);
      +
      + + +

      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);
      +
      + + +

      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 +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 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 +(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, "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, +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, +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 +discarded 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);
      +
      + + +

      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);
      +
      -

      The function -

      -       void lua_concat (lua_State *L, int n);
      -
      -concatenates the n values at the top of the stack, +

      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, +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 +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). -

      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. +

      +


      lua_cpcall

      +
      +          int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);
      +
      -

      3.8 - Userdata

      -

      Userdata represents C values in Lua. -Lua supports two types of userdata: -full userdata and light userdata. +

      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. +All values returned by func are discarded. -

      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). +

      +


      lua_createtable

      +
      +          void lua_createtable (lua_State *L, int narr, int nrec);
      +
      -

      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. +

      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. -

      You can create a new full userdata with the following function: -

      -       void *lua_newuserdata (lua_State *L, size_t size);
      -
      +

      +


      lua_dump

      +
      +          int lua_dump (lua_State *L, lua_Writer writer, void *data);
      +
      -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). +

      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, +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 +call to the writer; +0 means no errors. -

      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. +

      This function does not pop the Lua function from the stack. -

      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_equal

      +
      +          int lua_equal (lua_State *L, int index1, int index2);
      +
      -

      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);
      -
      +

      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. + +

      +


      lua_error

      +
      +          int lua_error (lua_State *L);
      +
      -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. +

      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). -

      3.10 - Loading Lua Chunks

      +

      +


      lua_gc

      +
      +          int lua_gc (lua_State *L, int what, int data);
      +
      -

      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);
      -
      +

      Controls the garbage collector. -The return values of lua_load are: +

      This function performs several tasks, +according to the value of the parameter what:

        -
      • 0 --- no errors; -
      • LUA_ERRSYNTAX --- -syntax error during pre-compilation. -
      • LUA_ERRMEM --- -memory allocation error. +
      • 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. +The function returns 1 if the step finished a +garbage-collection cycle. +
      • LUA_GCSETPAUSE--- +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 +the collector (see 2.10). +The function returns the previous value of the step multiplier.
      -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. +

      +


      lua_getallocf

      +
      +          lua_Alloc lua_getallocf (lua_State *L, void **ud);
      +
      -

      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). +

      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. -

      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. +

      +


      lua_getfenv

      +
      +          void lua_getfenv (lua_State *L, int index);
      +
      -

      3.11 - Manipulating Tables

      -

      Tables are created by calling -the function -

      -       void lua_newtable (lua_State *L);
      -
      +

      Pushes on the stack the environment table of +the value at the given index. -This function creates a new, empty table and pushes it onto the stack. +

      +


      lua_getfield

      +
      +          void lua_getfield (lua_State *L, int index, const char *k);
      +
      -

      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. +

      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). -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 */
      -       }
      -
      +

      +


      lua_getglobal

      +
      +          void lua_getglobal (lua_State *L, const char *name);
      +
      -

      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

      +

      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)
      +
      -

      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. +

      +


      lua_getmetatable

      +
      +          int lua_getmetatable (lua_State *L, int index);
      +
      -

      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);
      -
      +

      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. +

      +


      lua_gettable

      +
      +          void lua_gettable (lua_State *L, int index);
      +
      -

      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

      +

      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. -

      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);
      -
      +

      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). -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. +

      +


      lua_gettop

      +
      +          int lua_gettop (lua_State *L);
      +
      -

      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.) +

      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). -

      3.15 - Protected Calls

      +

      +


      lua_insert

      +
      +          void lua_insert (lua_State *L, int index);
      +
      -

      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. +

      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, +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, +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 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 is 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 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);
      +
      + + +

      Creates a new, independent state. +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 this state through this 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 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

      +
      +          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 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, +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: +

      +       /* 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. +By default, it is double, but that can be changed in luaconf.h. + +

      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: +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 userdata; +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. + +

      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 on the stack +is exactly the original error message. +Otherwise, errfunc is the stack index of an +error handler function. +(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. + +

      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 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

      +
      +          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. + +

      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

      +
      +          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, +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 +(and deallocation, through garbage collection). +
      • 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). +
      + +

      +


      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 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);
      +
      + + +

      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 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);
      +
      + + +

      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 +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 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], +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 +(i.e., without metamethods). + +

      +


      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. +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. +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_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);
      +
      + + +

      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), +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 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. +When it returns, the stack contains all values passed to lua_yield, +or all values returned by the body function. +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. +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

      +
      +          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 +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, +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_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

      +
      +          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 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. + +

      +


      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_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. + +

      +


      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 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; +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 a 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 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´) +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 a 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 only 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 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 +defined in lua.h: +LUA_TNIL, +LUA_TNUMBER, +LUA_TBOOLEAN, +LUA_TSTRING, +LUA_TTABLE, +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

      +
      +          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 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: +

      +       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 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 the 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. + +

      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

      +
      +          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 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. +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 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, +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. +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. +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, +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). +(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 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) +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 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

      + +

      +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 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. +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"), +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 +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 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 +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 +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 +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, raises 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, +but it is an idiom to use it as return luaL_argerror ... +in C functions. + +

      +


      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 +the luaL_add* functions. +
      • You finish by calling luaL_pushresult(&b). +This 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 +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 +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 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 +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 +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 +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 +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 +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 +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[]);
      +
      + + +

      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. +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);
      +
      + + +

      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 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);
      +
      + + +

      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 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, +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);
      +
      + + +

      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 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 +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 +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. +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. +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 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/read 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. -

      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. +

      +


      luaL_newmetatable

      +
      +          int luaL_newmetatable (lua_State *L, const char *tname);
      +
      -

      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

      +

      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. -

      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);
      -
      +

      In both cases pushes on the stack the final value associated +with tname in the registry. -A C function receives a Lua state and returns an integer, -the number of values it wants to return to Lua. +

      +


      luaL_newstate

      +
      +          lua_State *luaL_newstate (void);
      +
      -

      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);
      -
      +

      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. -

      3.17 - Defining C Closures

      +

      Returns the new state, +or NULL if there is a memory allocation error. -

      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);
      -
      +

      +


      luaL_openlibs

      +
      +          void luaL_openlibs (lua_State *L);
      +
      -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). +

      Opens all standard Lua libraries into the given state. -

      3.18 - Registry

      +

      +


      luaL_optint

      +
      +          int luaL_optint (lua_State *L, int narg, int d);
      +
      -

      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. +

      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. -

      3.19 - Error Handling in C

      +

      +


      luaL_optinteger

      +
      +          lua_Integer luaL_optinteger (lua_State *L, int narg, lua_Integer d);
      +
      -

      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. +

      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. -

      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. +

      +


      luaL_optlong

      +
      +          long luaL_optlong (lua_State *L, int narg, long d);
      +
      -

      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. +

      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. -

      C code can generate a Lua error calling the function -

      -       void lua_error (lua_State *L);
      -
      +

      +


      luaL_optlstring

      +
      +          const char *luaL_optlstring (lua_State *L, int narg,
      +                                       const char *d, size_t *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

      +

      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. -

      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);
      -
      +

      If l is not NULL, +fills the position *l with the results's length. -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. +

      +


      luaL_optnumber

      +
      +          lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number d);
      +
      -

      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. +

      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. -

      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);
      -
      +

      +


      luaL_optstring

      +
      +          const char *luaL_optstring (lua_State *L, int narg, const char *d);
      +
      -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. +

      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. -

      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. +

      +


      luaL_prepbuffer

      +
      +          char *luaL_prepbuffer (luaL_Buffer *B);
      +
      -

      -

      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. +

      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. -

      4.1 - Stack and Function Information

      +

      +


      luaL_pushresult

      +
      +          void luaL_pushresult (luaL_Buffer *B);
      +
      -

      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. +

      Finishes the use of buffer B leaving the final string on +the top of the stack. -

      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);
      -
      +

      +


      luaL_ref

      +
      +          int luaL_ref (lua_State *L, int t);
      +
      -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: -
        +

        Creates and returns a reference, +in the table at index t, +for the object at the top of the stack (and pops the object). -

      • 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. +

        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. -

      • short_src -A "printable" version of source, to be used in error messages. +

        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. -

      • linedefined -the line number where the definition of the function starts. +

        +


        luaL_Reg

        +
        +          typedef struct luaL_Reg {
        +            const char *name;
        +            lua_CFunction func;
        +          } luaL_Reg;
         
        -

      • 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. +

        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. -

      • 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.) +

        +


        luaL_register

        +
        +          void luaL_register (lua_State *L, const char *libname,
        +                              const luaL_Reg *l);
        +
        -

      • nups -The number of upvalues of the function. -

      +

      Opens a library. -

      4.2 - Manipulating Local Variables and Upvalues

      +

      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. -

      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. +

      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], +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. -

      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);
      -
      +

      In any case the function leaves the table +on the top of the stack. -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. +

      +


      luaL_typename

      +
      +          const char *luaL_typename (lua_State *L, int idx);
      +
      -

      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;
      -       }
      -
      +

      Returns the name of the type of the value at index idx. -

      4.3 - Hooks

      +

      +


      luaL_typerror

      +
      +          int luaL_typerror (lua_State *L, int narg, const char *tname);
      +
      -

      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);
      -
      +

      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. -You can set the hook with the following function: -
      -       int lua_sethook (lua_State *L, lua_Hook func, int mask, int count);
      -
      +

      +


      luaL_unref

      +
      +          void luaL_unref (lua_State *L, int t, int ref);
      +
      -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. +

      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. -

      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);
      -
      +

      If ref is LUA_NOREF or LUA_REFNIL, +luaL_unref does nothing. +

      +


      luaL_where

      +
      +          void luaL_where (lua_State *L, int lvl);
      +
      -

      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. +

      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, +etc. + +

      This function is used to build a prefix for error messages.

      -

      5 - Standard Libraries

      +

      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); +(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 -and are provided as separate C modules. +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.); @@ -2955,330 +4394,301 @@

      • operating system facilities;
      • debug facilities.
      -Except for the basic library, +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 functions +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. - +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

      +

      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; -otherwise, returns this value. +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 ([limit])

      +


      collectgarbage (opt [, arg])

      -

      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). +

      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. +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). +
      • "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. +Returns all values 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])

      +to its caller (that is, dofile 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. +

      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

      +


      _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.) +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: +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. The default for f is 1. -

      If the environment has a "__fenv" field, -returns the associated value, instead of the environment. +


      getmetatable (object)

      -

      getmetatable (object)

      - - -

      If the 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. -

      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)

      +


      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
      -
      +
      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. +

      See next for the caveats of modifying the table during its traversal. -

      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). +


      load (func [, chunkname])

      -

      loadstring (string [, chunkname])

      -Loads a string as a Lua chunk (without running it). -If there are no errors, +

      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. +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. +

      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 +or from the standard input, +if no file name is given. + +


      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. +

      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. +next returns the next index of the table +and its associated value. +When called with nil as its second argument, +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. -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. +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. +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.) +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. +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. +
      +will iterate over all key--value pairs of table t. + +

      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. -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), -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. +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, +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, typically for debugging. -For formatted output, use format (see 5.3). +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. - -

      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. +index any value different from nil, +and value any Lua value. -

      While running a file, -require defines the global variable _REQUIREDNAME -with the package name. -The package being loaded always runs within the global environment. +


      select (index, ...)

      -

      setfenv (f, table)

      +

      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. -

      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: +


      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. +setfenv returns the given function.

      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. +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 a userdata from Lua.) -If metatable is nil, removes the metatable of 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. -

      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 that number; -otherwise, it returns nil. +to a number, then tonumber returns this 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, +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). +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 format (see 5.3). +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), +"nil" (a string, not the value nil), "number", "string", "boolean, @@ -3287,22 +4697,23 @@

      "thread", and "userdata". -

      unpack (list)

      -Returns all elements from the given list. +


      unpack (list [, i [, j]])

      +Returns the elements from the given table. 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

      +
      +  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). + +


      _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". +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. @@ -3315,52 +4726,61 @@

      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

      +

      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. +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 +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.status (co)

      +


      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)

      +


      coroutine.wrap (f)

      Creates a new coroutine, with body f. f must be a Lua function. @@ -3371,197 +4791,356 @@

      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, -nor a metamethod, nor an iterator. -Any arguments to yield go as extra results to resume. +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 +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 [, ...])

      + +

      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, +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 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 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 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 the module. + +

      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. +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. + +

      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]. +If the loader returns no value and +has not assigned any value to package.loaded[modname], +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 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 +it initializes the Lua path package.path, +using the environment variable LUA_CPATH +(plus another default path defined in luaconf.h). + +


      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. +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)). + +

      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 extension. +funcname must be the exact name exported by the C library +(which may depend on the C compiler and linker used). -

      5.3 - String Manipulation

      -This library provides generic functions for string manipulation, +

      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 +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. + +

      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. + +


      package.preload

      + +

      A table to store loaders for specific modules +(see require). + +


      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, 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.

      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. +It also sets a metatable for strings +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]])

      +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, ...)

      +


      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, -so that a later loadstring on that string returns +

      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]])

      -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. -If the pattern specifies captures (see string.gsub below), -the captured strings are returned as extra results. +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 +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. +Note that if plain is given, then init must be given as well. -

      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 -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. +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 -
      +
              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. +

      This function does not accept string values +containing embedded zeros. -

      string.gfind (s, pat)

      - -

      Returns an iterator function that, +


      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 -

      +
         s = "hello world from Lua"
      -  for w in string.gfind(s, "%a+") do
      +  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.gfind(s, "(%w+)=(%w+)") do
      +  for k, v in string.gmatch(s, "(%w+)=(%w+)") do
           t[k] = v
         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. +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 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; 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 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, 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. For instance, when n is 1 only the first occurrence of -pat is replaced. +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+)", "%1 %1", 1)
      +   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")
      @@ -3575,20 +5154,67 @@ 

      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" -

      + 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)

      +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 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])

      +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. -

      Patterns

      +


      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

      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. @@ -3638,7 +5264,6 @@

        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 @@ -3663,12 +5288,12 @@

        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, @@ -3694,9 +5319,9 @@

        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 the current string position (a number). @@ -3705,147 +5330,91 @@

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

        5.4 - Table Manipulation

        +

        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, 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]]])

        +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]. 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. +and the default for j is the length 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)

        +


        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), +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. -This function also updates the size of the table by -calling table.setn(table, n+1). -

        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. +(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, 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), +where n is the length of the table, 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)

        +


        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. -

        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. +

        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.5 - Mathematical Functions

        +

        5.6 - Mathematical Functions

        -

        This library is an interface to most of the functions of the -standard C math library. -(Some have slightly different names.) +

        This library is an interface to the standard C math library. 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). + 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. @@ -3854,161 +5423,183 @@

        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. +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]. +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

        +

        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. +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 explicit file descriptors, -the operation io.open returns a file descriptor -and then all operations are supplied as methods by the file descriptor. +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. -

        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 +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. 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.

        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. +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])

        +


        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:

          -
        • "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. +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. -

        Similar to io.input, but operates over the default output file. +


        io.popen ([prog [, mode]])

        -

        io.read (format1, ...)

        +

        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 +on all platforms. + +


        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. +or 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 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, 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 +(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). @@ -4020,29 +5611,29 @@

      • "*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. +
      • 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. +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. -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", @@ -4054,90 +5645,112 @@

      and the call file:seek("end") sets the position to the end of the file, and returns its size. -

      file:write (value1, ...)

      +


      file:setvbuf (mode [, size])

      + +

      Sets the buffering mode for an output file. +There are three available modes: +

        +
      • "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, ...)

      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. +use tostring or string.format before write. -

      5.7 - Operating System Facilities

      +

      5.8 - Operating System Facilities

      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.

      If the time argument is present, this is the time to be formatted -(see the os.time function for a description of this value). +(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, +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, then date returns the date as a string, -formatted according with the same rules as the C function strftime. +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)

      +


      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. +

      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, +

      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, +

      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. -If this function fails, it returns nil, +

      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; @@ -4146,40 +5759,33 @@

      "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. 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). +(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. The file must be explicitly opened before its use -and removed when no longer needed. +and explicitly 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.9 - The Debug Library

      -

      5.8 - The Reflexive Debug Interface

      - -

      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 @@ -4187,14 +5793,17 @@

      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. +Moreover, several of its functions +violate some 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) +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. @@ -4205,17 +5814,21 @@

      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. +within any function, and so have no direct access to local variables. + +


      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). +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: @@ -4223,9 +5836,9 @@

      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, +

      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, @@ -4233,45 +5846,45 @@

      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. +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, +(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.) +(You can call debug.getinfo to check whether the level is valid.) -

      debug.getupvalue (func, up)

      +

      Variable names starting with `(´ (open parentheses) +represent internal variables +(loop control variables, temporaries, and C function locals). -

      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.getmetatable (object)

      -

      debug.setlocal (level, local, value)

      +

      Returns the metatable of the given object +or nil if it does not have a metatable. -

      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.getregistry ()

      -

      debug.setupvalue (func, up, value)

      +

      Returns the registry table (see 3.5). -

      This function assigns the value value to the upvalue +


      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 (object, table)

      -

      debug.sethook (hook, mask [, count])

      +

      Sets the environment of the given object to the given table. +


      debug.sethook (hook, mask [, count])

      Sets the given function as a hook. The string mask and the number count describe @@ -4279,224 +5892,202 @@

      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 -(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.traceback ([message])

      +


      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 (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 +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 +This function is typically used with xpcall to produce 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, +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. +all standard libraries, including the debug library. Its usage is: -

      +
             lua [options] [script [args]]
      -
      +
      The options are:
        -
      • - executes stdin as a file;
      • -e stat executes string stat; -
      • -l file "requires" file; +
      • -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. +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. -(Here, $ is the shell prompt. Your prompt may be different.) +
      +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. -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
      -
      +
      +       $ 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",
      -               [1] = "t1", [2] = "t2"; n = 2 }
      -
      +
      +       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 also access these 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,
      +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. - -

      In Unix systems, Lua scripts can be made into executable programs -by using chmod +x and the #! form, +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, +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.) -

      -

      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. +

        Incompatibilities with the Previous Version

        -

      • -The precedence of or is smaller than the precedence of and. -

      • -in, false, and true are reserved words. +

        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. -

      • -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. +

        Incompatibilities with version 5.0

        -

      • -When a literal string of the form [[...]] starts with a newline, -this newline is ignored. +

        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. -

        • Upvalues in the form %var are obsolete; -use external local variables instead. +

        • +The long string/long comment syntax ([[...]]) does not allow nesting. +You can use the new syntax ([=[...]=]) in these cases. +(Option LUA_COMPAT_LSTR in luaconf.h.)

        @@ -4504,32 +6095,46 @@

        Acknowledgments

        • -Most library functions now are defined inside tables. -There is a compatibility script (compat.lua) that -redefine most of them as global names. +Function string.gfind was renamed string.gmatch. +(Option LUA_COMPAT_GFIND) -

        • -In the math library, angles are expressed in radians. -With the compatibility script (compat.lua), -functions still work in degrees. +

        • +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)

        • -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. +Function loadlib was renamed package.loadlib. +(Option LUA_COMPAT_LOADLIB)

        • -dofile do not handle errors, but simply propagates them. +Function math.mod was renamed math.fmod. +(Option LUA_COMPAT_MOD)

        • -dostring is deprecated. Use loadstring instead. +Functions table.foreach and table.foreachi are deprecated. +You can use a for loop with pairs or ipairs instead. -

        • -The read option *w is obsolete. +

        • +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. -

        • -The format option %n$ is obsolete. +

        • +Function collectgarbage has different arguments. +Function gcinfo is deprecated; +use collectgarbage("count") instead.

        @@ -4537,76 +6142,106 @@

        Acknowledgments

        • -lua_open does not have a stack size as its argument -(stacks are dynamic). +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. -

        • -lua_pushuserdata is deprecated. -Use lua_newuserdata or lua_pushlightuserdata instead. +

        • +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 +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

        +

        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 [`;´]} + 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 [`=´ explist1] -

        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] + 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 + explist1 ::= {exp `,´} exp -

        explist1 ::= {exp `,´} exp + exp ::= nil | false | true | Number | String | `...´ | + 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 | String -

        args ::= `(´ [explist1] `)´ | tableconstructor | Literal + function ::= function funcbody -

        function ::= function funcbody + funcbody ::= `(´ [parlist1] `)´ block end -

        funcbody ::= `(´ [parlist1] `)´ block end + parlist1 ::= namelist [`,´ `...´] | `...´ -

        parlist1 ::= Name {`,´ Name} [`,´ `...´] | `...´ + 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 + + fieldsep ::= `,´ | `;´ -

        unop ::= `-´ | not + 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 index baa7cc8a07..db20a69a00 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -1,6 +1,7 @@ Lua documentation + @@ -17,10 +18,6 @@

    • lua man page
    • luac man page
    • lua/README -
    • lua/src/README -
    • lua/src/lib/README -
    • lua/src/lua/README -
    • lua/src/luac/README
    • lua/etc/README
    • lua/test/README
    @@ -28,7 +25,7 @@


    Last update: -Thu Mar 11 23:08:56 BRT 2004 +Wed Sep 7 12:57:50 BRST 2005 diff --git a/etc/Makefile b/etc/Makefile index 1286c6403a..6d00008d98 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -1,42 +1,44 @@ # makefile for Lua etc -LUA= .. - -include $(LUA)/config - -LIBLUA=$(LIB)/liblua.a -ALL= bin2c min trace noparser luab - -all: - @echo 'choose a target:' $(ALL) - -bin2c: bin2c.c - $(CC) $(CFLAGS) -o $@ $@.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) - $(BIN)/luac $(LUA)/test/hello.lua - $@ luac.out - -$@ -e'a=1' - -flat: - cd ..; mkdir flat; mv include/*.h src/*.[ch] src/*/*.[ch] flat - -$(LIBLUA): - cd ../src; $(MAKE) +TOP= .. +LIB= $(TOP)/src +INC= $(TOP)/src +BIN= $(TOP)/src +SRC= $(TOP)/src +TST= $(TOP)/test + +CC= gcc +CFLAGS= -O2 -Wall -I$(INC) $(MYCFLAGS) +MYCFLAGS= +MYLDFLAGS= -Wl,-E +MYLIBS= -lm +#MYLIBS= -lm -Wl,-E -ldl -lreadline -lhistory -lncurses +RM= rm -f + +default: + @echo 'Please choose a target: min noparser one strict clean' + +min: min.c + $(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) + $(BIN)/luac $(TST)/hello.lua + -./a.out luac.out + -./a.out -e'a=1' + +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 -f $(ALL) a.out core *.o luac.out + $(RM) a.out core core.* *.o luac.out -luser_tests.h: RCS/ltests.h,v - co -q -M ltests.h - mv -f ltests.h $@ +.PHONY: default min noparser one strict clean diff --git a/etc/README b/etc/README index c838a7fe19..ad9ca6ab87 100644 --- a/etc/README +++ b/etc/README @@ -1,54 +1,36 @@ 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 +If any of the makes fail, you're probably not using the same libraries +used to build Lua. Set MYLIBS in Makefile accordingly. -lua.ico - A Lua icon for Windows. - Drawn by hand by Markus Gritsch . +all.c + Full Lua interpreter in a single file. + Do "make one" for a demo. -lua.magic - Data for teaching file(1) about Lua precompiled chunks. +lua.hpp + Lua header files for C++ using 'extern "C"'. -lua.xpm - The same icon as lua.ico, but in XPM format. - It was converted with ImageMagick by Andy Tai . +lua.ico + A Lua icon for Windows (and web sites: save as favicon.ico). + Drawn by hand by Markus Gritsch . -luser_number.h - Number type configuration for Lua core. +lua.pc + pkg-config data for Lua -luser_tests.h - Self-test configuration for Lua core. +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. + Do "make min" for a demo. 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" for a demo. -saconfig.c - Configuration for Lua interpreter. +strict.lua + Traps uses of undeclared global variables. + Do "make strict" for a demo. -trace.c - A simple execution tracer. - An example of how to use the debug hooks in C. diff --git a/etc/all.c b/etc/all.c new file mode 100644 index 0000000000..dab68fac58 --- /dev/null +++ b/etc/all.c @@ -0,0 +1,38 @@ +/* +* all.c -- Lua core, libraries and interpreter in a single file +*/ + +#define luaall_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" +#include "loslib.c" +#include "lstrlib.c" +#include "ltablib.c" + +#include "lua.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.hpp b/etc/lua.hpp new file mode 100644 index 0000000000..ec417f5946 --- /dev/null +++ b/etc/lua.hpp @@ -0,0 +1,9 @@ +// lua.hpp +// Lua header files for C++ +// <> not supplied automatically because Lua also compiles as C++ + +extern "C" { +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" +} 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.pc b/etc/lua.pc new file mode 100644 index 0000000000..5fd2b1ed1f --- /dev/null +++ b/etc/lua.pc @@ -0,0 +1,27 @@ +# lua.pc -- pkg-config data for Lua + +# vars from install Makefile + +# grep '^V=' ../Makefile +V= 5.1 + +# 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 + +Name: Lua +Description: An Extensible Extension Language +Version: ${V} +Requires: +Libs: -L${libdir} -llua -lm +Cflags: -I${includedir} + 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/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/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..404bd50385 100644 --- a/etc/min.c +++ b/etc/min.c @@ -5,7 +5,9 @@ */ #include + #include "lua.h" +#include "lauxlib.h" static int print(lua_State *L) { @@ -16,31 +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/etc/noparser.c b/etc/noparser.c index 00c2b12625..13ba546239 100644 --- a/etc/noparser.c +++ b/etc/noparser.c @@ -4,23 +4,47 @@ * 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 + #include "llex.h" #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) { +LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { UNUSED(z); UNUSED(buff); - lua_pushstring(L,"parser not loaded"); + UNUSED(name); + lua_pushliteral(L,"parser not loaded"); lua_error(L); return NULL; } + +#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); +#if 1 + UNUSED(L); + return 0; +#else + lua_pushliteral(L,"dumper not loaded"); + lua_error(L); +#endif +} +#endif diff --git a/etc/saconfig.c b/etc/saconfig.c deleted file mode 100644 index bf3c64b701..0000000000 --- a/etc/saconfig.c +++ /dev/null @@ -1,87 +0,0 @@ -/* 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/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/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/Makefile b/include/Makefile deleted file mode 100644 index d75997d9f0..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 - -all: - -clean: - -co: - co -q -f -M $(SRCS) - -klean: clean - rm -f $(SRCS) diff --git a/include/lauxlib.h b/include/lauxlib.h deleted file mode 100644 index 450e16c720..0000000000 --- a/include/lauxlib.h +++ /dev/null @@ -1,145 +0,0 @@ -/* -** $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 -*/ - - -#ifndef lauxlib_h -#define lauxlib_h - - -#include -#include - -#include "lua.h" - - -#ifndef LUALIB_API -#define LUALIB_API LUA_API -#endif - - - -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_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_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); - - - -/* -** =============================================================== -** some useful macros -** =============================================================== -*/ - -#define luaL_argcheck(L, cond,numarg,extramsg) if (!(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))) - - -/* -** {====================================================== -** Generic Buffer manipulation -** ======================================================= -*/ - - -#ifndef LUAL_BUFFERSIZE -#define LUAL_BUFFERSIZE BUFSIZ -#endif - - -typedef struct luaL_Buffer { - char *p; /* current position in buffer */ - 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)), \ - (*(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); - - -/* }====================================================== */ - - - -/* -** 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 deleted file mode 100644 index bd4acc9a88..0000000000 --- a/include/lua.h +++ /dev/null @@ -1,391 +0,0 @@ -/* -** $Id: lua.h,v 1.175c 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 -** See Copyright Notice at the end of this file -*/ - - -#ifndef lua_h -#define lua_h - -#include -#include - - -#define LUA_VERSION "Lua 5.0.3" -#define LUA_COPYRIGHT "Copyright (C) 1994-2006 Tecgraf, PUC-Rio" -#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" - - - -/* option for multiple returns in `lua_pcall' and `lua_call' */ -#define LUA_MULTRET (-1) - - -/* -** pseudo-indices -*/ -#define LUA_REGISTRYINDEX (-10000) -#define LUA_GLOBALSINDEX (-10001) -#define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i)) - - -/* error codes for `lua_load' and `lua_pcall' */ -#define LUA_ERRRUN 1 -#define LUA_ERRFILE 2 -#define LUA_ERRSYNTAX 3 -#define LUA_ERRMEM 4 -#define LUA_ERRERR 5 - - -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); - - -/* -** basic types -*/ -#define LUA_TNONE (-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 - - -/* 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 (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 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_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 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, 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_pushboolean (lua_State *L, int b); -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_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_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); - - -/* -** coroutine functions -*/ -LUA_API int lua_yield (lua_State *L, int nresults); -LUA_API int lua_resume (lua_State *L, int narg); - -/* -** 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); - -/* -** miscellaneous functions -*/ - -LUA_API const char *lua_version (void); - -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); - - - -/* -** =============================================================== -** some useful macros -** =============================================================== -*/ - -#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_pushstring(L, n), \ - lua_pushcfunction(L, f), \ - lua_settable(L, LUA_GLOBALSINDEX)) - -#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) -#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_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) - - - -/* -** 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-2006 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 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/lualib.h b/include/lualib.h deleted file mode 100644 index e22c4c3063..0000000000 --- a/include/lualib.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -** $Id: lualib.h,v 1.28 2003/03/18 12:24:26 roberto Exp $ -** Lua standard libraries -** See Copyright Notice in lua.h -*/ - - -#ifndef lualib_h -#define lualib_h - -#include "lua.h" - - -#ifndef LUALIB_API -#define LUALIB_API LUA_API -#endif - - -#define LUA_COLIBNAME "coroutine" -LUALIB_API int luaopen_base (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); - -#define LUA_MATHLIBNAME "math" -LUALIB_API int luaopen_math (lua_State *L); - -#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 bf64c03f08..1d46d3423a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,85 +1,178 @@ -# 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 \ - ltests.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 \ - ltests.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 ======================= + +# Your platform. See PLATS for possible values. +PLAT= none + +CC= gcc +CFLAGS= -O2 -Wall $(MYCFLAGS) +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 ========= + +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 \ + 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 + +LUA_T= lua +LUA_O= lua.o + +LUAC_T= luac +LUAC_O= luac.o print.o + +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) + +a: $(ALL_A) + +$(LUA_A): $(CORE_O) $(LIB_O) + $(AR) $@ $? $(RANLIB) $@ +$(LUA_T): $(LUA_O) $(LUA_A) + $(CC) -o $@ $(MYLDFLAGS) $(LUA_O) $(LUA_A) $(LIBS) + +$(LUAC_T): $(LUAC_O) $(LUA_A) + $(CC) -o $@ $(MYLDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS) + clean: - rm -f $(OBJS) $T + $(RM) $(ALL_T) $(ALL_O) + +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 + +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 + +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 +# 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=$(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" + +# 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 -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 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 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 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 +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 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 e5375981f6..0000000000 --- a/src/README +++ /dev/null @@ -1,5 +0,0 @@ -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 2ed4c63482..ce7bcf6f3a 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,14 +1,17 @@ /* -** $Id: lapi.c,v 1.235a 2003/04/07 14:36:08 roberto Exp $ +** $Id: lapi.c,v 2.53 2006/01/10 12:50:00 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ #include +#include +#include #include #define lapi_c +#define LUA_CORE #include "lua.h" @@ -27,6 +30,7 @@ #include "lvm.h" + const char lua_ident[] = "$Lua: " LUA_VERSION " " LUA_COPYRIGHT " $\n" "$Authors: " LUA_AUTHORS " $\n" @@ -34,72 +38,64 @@ const char lua_ident[] = -#ifndef api_check -#define api_check(L, o) /*{ 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 *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); + 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_ENVIRONINDEX: { + Closure *func = curr_func(L); + sethvalue(L, &L->env, func->c.env); + return &L->env; + } 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; - } +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 { - TObject *o = negindex(L, idx); - api_check(L, o != NULL); - return o; + Closure *func = curr_func(L); + return func->c.env; } } -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); - incr_top(L); +void luaA_pushobject (lua_State *L, const TValue *o) { + setobj2s(L, L->top, o); + 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) > LUA_MAXCSTACK) + if ((L->top - L->base + size) > LUAI_MAXCSTACK) res = 0; /* stack overflow */ else { luaD_checkstack(L, size); @@ -114,12 +110,14 @@ 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); + 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->top, from->top + i); - api_incr_top(to); + setobj2s(to, to->top++, from->top + i); } lua_unlock(to); } @@ -140,10 +138,10 @@ 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); + luai_userstatethread(L, L1); return L1; } @@ -155,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); } @@ -178,8 +176,9 @@ 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); - while (++p < L->top) setobjs2s(p-1, p); + p = index2adr(L, idx); + api_checkvalidindex(L, p); + while (++p < L->top) setobjs2s(L, p-1, p); L->top--; lua_unlock(L); } @@ -189,17 +188,31 @@ LUA_API void lua_insert (lua_State *L, int idx) { StkId p; 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); + 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); 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 = index2adr(L, idx); + api_checkvalidindex(L, o); + 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); } @@ -207,7 +220,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, index2adr(L, idx)); api_incr_top(L); lua_unlock(L); } @@ -220,8 +233,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 = index2adr(L, idx); + return (o == luaO_nilobject) ? LUA_TNONE : ttype(o); } @@ -232,15 +245,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 = index2adr(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 = index2adr(L, idx); + return tonumber(o, &n); } @@ -251,16 +264,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 = index2adr(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 = index2adr(L, index1); + StkId o2 = index2adr(L, index2); + return (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 + : luaO_rawequalObj(o1, o2); } @@ -268,10 +281,9 @@ 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 = index2adr(L, index1); + o2 = index2adr(L, index2); + i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : equalobj(L, o1, o2); lua_unlock(L); return i; } @@ -281,10 +293,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 = index2adr(L, index1); + o2 = index2adr(L, index2); + i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 + : luaV_lessthan(L, o1, o2); lua_unlock(L); return i; } @@ -292,65 +304,81 @@ 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 = index2adr(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 = index2adr(L, idx); + if (tonumber(o, &n)) { + lua_Integer res; + lua_Number num = nvalue(o); + lua_number2integer(res, num); + 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 = index2adr(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)) - return svalue(o); - else { - const char *s; +LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { + StkId o = index2adr(L, idx); + 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); + o = index2adr(L, idx); /* previous call may reallocate the stack */ lua_unlock(L); - return s; } + if (len != NULL) *len = tsvalue(o)->len; + return svalue(o); } -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 size_t lua_objlen (lua_State *L, int idx) { + StkId o = index2adr(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 = luaA_indexAcceptable(L, idx); - return (o == NULL || !iscfunction(o)) ? NULL : clvalue(o)->c.f; + 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_indexAcceptable(L, idx); - if (o == NULL) return NULL; + StkId o = index2adr(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 +386,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 = index2adr(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 = index2adr(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 +427,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_num(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); } @@ -448,12 +481,13 @@ 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--) - 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); } @@ -475,6 +509,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) @@ -484,8 +527,22 @@ LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { 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)); + t = index2adr(L, idx); + 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 = index2adr(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); } @@ -493,9 +550,9 @@ LUA_API void lua_gettable (lua_State *L, int idx) { 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->top - 1, luaH_get(hvalue(t), L->top - 1)); + setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); lua_unlock(L); } @@ -503,43 +560,44 @@ 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->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, nrec)); 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 = index2adr(L, objindex); + switch (ttype(obj)) { + case LUA_TTABLE: + mt = hvalue(obj)->metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(obj)->metatable; + break; + default: + mt = G(L)->mt[ttype(obj)]; + 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; } @@ -551,8 +609,22 @@ 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); - setobj2s(L->top, isLfunction(o) ? &clvalue(o)->l.g : gt(L)); + o = index2adr(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; + case LUA_TTHREAD: + setobj2s(L, L->top, gt(thvalue(o))); + break; + default: + setnilvalue(L->top); + break; + } api_incr_top(L); lua_unlock(L); } @@ -567,20 +639,36 @@ 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); 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 = index2adr(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); + t = index2adr(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_barriert(L, hvalue(t), L->top-1); L->top -= 2; lua_unlock(L); } @@ -590,54 +678,76 @@ 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(luaH_setnum(L, hvalue(o), n), L->top-1); /* write barrier */ + setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1); + luaC_barriert(L, hvalue(o), L->top-1); L->top--; lua_unlock(L); } LUA_API int lua_setmetatable (lua_State *L, int objindex) { - TObject *obj, *mt; - int res = 1; + TValue *obj; + Table *mt; 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)); + obj = index2adr(L, objindex); + 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_objbarriert(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: { - res = 0; /* cannot set */ + G(L)->mt[ttype(obj)] = mt; break; } } L->top--; lua_unlock(L); - return res; + return 1; } 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 = luaA_index(L, idx); - L->top--; - api_check(L, ttistable(L->top)); - if (isLfunction(o)) { - res = 1; - clvalue(o)->l.g = *(L->top); + o = index2adr(L, idx); + api_checkvalidindex(L, o); + api_check(L, ttistable(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; + case LUA_TTHREAD: + sethvalue(L, gt(thvalue(o)), 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; } @@ -647,12 +757,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); } @@ -679,10 +800,19 @@ 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)); + api_checknelems(L, nargs+1); + checkresults(L, nargs, nresults); + if (errfunc == 0) + func = 0; + else { + StkId o = index2adr(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); + adjustresults(L, nresults); lua_unlock(L); return status; } @@ -700,12 +830,12 @@ 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->top, cl); /* push function */ - incr_top(L); + setclvalue(L, L->top, cl); /* push function */ + 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); } @@ -722,72 +852,98 @@ 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; - 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; } -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; - 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; + status = 1; lua_unlock(L); return status; } -/* -** Garbage-collection functions -*/ +LUA_API int lua_status (lua_State *L) { + return L->status; +} -/* 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; -} +/* +** Garbage-collection function +*/ -LUA_API int lua_getgccount (lua_State *L) { - int count; +LUA_API int lua_gc (lua_State *L, int what, int data) { + int res = 0; + global_State *g; lua_lock(L); - count = GCscale(G(L)->nblocks); + g = G(L); + switch (what) { + case LUA_GCSTOP: { + g->GCthreshold = MAX_LUMEM; + break; + } + case LUA_GCRESTART: { + g->GCthreshold = g->totalbytes; + break; + } + case LUA_GCCOLLECT: { + luaC_fullgc(L); + break; + } + case LUA_GCCOUNT: { + /* GC values are expressed in Kbytes: #bytes/2^10 */ + 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) + g->GCthreshold = g->totalbytes - a; + else + g->GCthreshold = 0; + while (g->GCthreshold <= g->totalbytes) + luaC_step(L); + if (g->gcstate == GCSpause) /* end of cycle? */ + res = 1; /* signal it */ + break; + } + case LUA_GCSETPAUSE: { + res = g->gcpause; + g->gcpause = data; + break; + } + case LUA_GCSETSTEPMUL: { + res = g->gcstepmul; + g->gcstepmul = data; + break; + } + default: res = -1; /* invalid option */ + } lua_unlock(L); - return count; + return res; } -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); -} /* @@ -795,11 +951,6 @@ LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold) { */ -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); @@ -813,7 +964,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) { @@ -828,14 +979,14 @@ 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 */ - 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 +994,40 @@ 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; + 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); +} + + 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); + u = luaS_newudata(L, size, getcurrenv(L)); + 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 (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 +1046,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(index2adr(L, funcindex), n, &val); if (name) { - setobj2s(L->top, val); + setobj2s(L, L->top, val); api_incr_top(L); } lua_unlock(L); @@ -908,13 +1060,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 = index2adr(L, funcindex); api_checknelems(L, 1); - name = aux_upvalue(L, funcindex, n, &val); + name = aux_upvalue(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..9d1d435649 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.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 TObject *o); +LUAI_FUNC void luaA_pushobject (lua_State *L, const TValue *o); #endif diff --git a/src/lib/lauxlib.c b/src/lauxlib.c similarity index 60% rename from src/lib/lauxlib.c rename to src/lauxlib.c index ee2d1339b0..317a48d108 100644 --- a/src/lib/lauxlib.c +++ b/src/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.158 2006/01/16 12:42:21 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -17,18 +18,14 @@ */ #define lauxlib_c +#define LUA_LIB #include "lua.h" #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 */ @@ -45,36 +42,38 @@ 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' */ 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); } 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); } 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)); } 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; @@ -97,51 +96,38 @@ 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)); } 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_pushstring(L, tname); - lua_rawset(L, LUA_REGISTRYINDEX); /* registry[metatable] = name */ + lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ return 1; } -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; - } + 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; } @@ -164,9 +150,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; } @@ -191,8 +176,21 @@ 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); +} + + +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) { + return luaL_opt(L, luaL_checkinteger, narg, def); } @@ -222,27 +220,43 @@ 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); +} + + +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) { - lua_pushstring(L, libname); - lua_gettable(L, LUA_GLOBALSINDEX); /* check whether lib already exists */ - 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 */ + int size = libsize(l); + /* check whether lib already exists */ + 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, 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; - 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 */ } @@ -255,50 +269,50 @@ LUALIB_API void luaL_openlib (lua_State *L, const char *libname, ** ======================================================= */ +#if defined(LUA_COMPAT_GETN) + 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; } 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 */ 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 */ + lua_setfield(L, LUA_REGISTRYINDEX, "LUA_SIZES"); /* store in register */ } } -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); 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_pushinteger(L, n); lua_rawset(L, t); } else { /* use `sizes' */ getsizes(L); lua_pushvalue(L, t); - lua_pushnumber(L, (lua_Number)n); + 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) { +LUALIB_API int luaL_getn (lua_State *L, int t) { int n; t = abs_index(L, t); lua_pushliteral(L, "n"); /* try t.n */ @@ -308,19 +322,60 @@ int luaL_getn (lua_State *L, int 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; + 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 @@ -374,7 +429,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++); } @@ -392,9 +447,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 */ } @@ -424,18 +480,15 @@ 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 */ 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 = (int)lua_objlen(L, t); ref++; /* create new reference */ - luaL_setn(L, t, ref); } lua_rawseti(L, t, ref); return ref; @@ -447,7 +500,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 +514,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,15 +523,21 @@ 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; } -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; } @@ -488,6 +548,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,20 +556,29 @@ 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, "open", fnameindex); } - 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 */ + if (lf.f == NULL) return errfile(L, "reopen", fnameindex); + /* 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) */ 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; @@ -539,53 +609,39 @@ LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size, return lua_load(L, getS, &ls, name); } -/* }====================================================== */ +LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s) { + return luaL_loadbuffer(L, s, strlen(s), s); +} -/* -** {====================================================== -** 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 */ +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; } - callalert(L, status); - return status; -} - - -LUALIB_API int lua_dofile (lua_State *L, const char *filename) { - return aux_do(L, luaL_loadfile(L, filename)); + else + return realloc(ptr, nsize); } -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)); +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; } -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); + if (L) lua_atpanic(L, &panic); + return L; } -/* }====================================================== */ diff --git a/src/lauxlib.h b/src/lauxlib.h new file mode 100644 index 0000000000..1bba1c04f8 --- /dev/null +++ b/src/lauxlib.h @@ -0,0 +1,172 @@ +/* +** $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 +*/ + + +#ifndef lauxlib_h +#define lauxlib_h + + +#include +#include + +#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) + + +typedef struct luaL_Reg { + const char *name; + lua_CFunction func; +} luaL_Reg; + + + +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); +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 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_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_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_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_findtable) (lua_State *L, int idx, + const char *fname, int szhint); + + + + +/* +** =============================================================== +** some useful macros +** =============================================================== +*/ + +#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_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_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))) + +#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) + +/* +** {====================================================== +** Generic Buffer manipulation +** ======================================================= +*/ + + + +typedef struct luaL_Buffer { + char *p; /* current position in buffer */ + int lvl; /* number of strings in the stack (level) */ + lua_State *L; + char buffer[LUAL_BUFFERSIZE]; +} luaL_Buffer; + +#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); +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); + + +/* }====================================================== */ + + +/* 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)) + + +#define luaL_reg luaL_Reg + +#endif + + diff --git a/src/lib/lbaselib.c b/src/lbaselib.c similarity index 61% rename from src/lib/lbaselib.c rename to src/lbaselib.c index fb26a54a94..1d922a8105 100644 --- a/src/lib/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.130c 2003/04/03 13:35:34 roberto Exp $ +** $Id: lbaselib.c,v 1.189 2006/01/18 11:49:12 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -12,6 +12,7 @@ #include #define lbaselib_c +#define LUA_LIB #include "lua.h" @@ -38,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 */ @@ -78,10 +80,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); @@ -130,18 +130,12 @@ 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 */ + if (lua_iscfunction(L, -1)) /* is a C function? */ + lua_pushvalue(L, LUA_GLOBALSINDEX); /* return the thread's global env. */ + else + lua_getfenv(L, -1); return 1; } @@ -149,16 +143,18 @@ 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) - lua_replace(L, LUA_GLOBALSINDEX); - else if (lua_setfenv(L, -2) == 0) - luaL_error(L, "`setfenv' cannot change environment of given function"); - return 0; + 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"); + return 1; } @@ -189,21 +185,40 @@ 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", "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_checkoption(L, 1, "collect", opts); + 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, res + ((lua_Number)b/1024)); + return 1; + } + case LUA_GCSTEP: { + lua_pushboolean(L, res); + return 1; + } + default: { + lua_pushnumber(L, res); + return 1; + } + } } 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; } @@ -222,30 +237,29 @@ 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_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) { - 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; - } + lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ + lua_pushvalue(L, 1); /* state, */ + lua_pushinteger(L, 0); /* and initial value */ + return 3; } @@ -274,11 +288,44 @@ static int luaB_loadfile (lua_State *L) { } +/* +** 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) { + (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 */ + 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 luaL_error(L, "reader function must return a string"); + return NULL; /* to avoid warnings */ +} + + +static int luaB_load (lua_State *L) { + 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); + 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; } @@ -288,22 +335,40 @@ 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, e, n; luaL_checktype(L, 1, LUA_TTABLE); - n = 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"); - 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 = n + i; + else if (i > n) i = n; + luaL_argcheck(L, 1 <= i, 1, "index out of range"); + return n - i; + } +} + + static int luaB_pcall (lua_State *L) { int status; luaL_checkany(L, 1); @@ -327,38 +392,26 @@ static int luaB_xpcall (lua_State *L) { static int luaB_tostring (lua_State *L) { - char buff[128]; 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; - case LUA_TTABLE: - sprintf(buff, "table: %p", lua_topointer(L, 1)); - break; - case LUA_TFUNCTION: - sprintf(buff, "function: %p", lua_topointer(L, 1)); - break; - case LUA_TUSERDATA: - case LUA_TLIGHTUSERDATA: - sprintf(buff, "userdata: %p", lua_touserdata(L, 1)); - break; - case LUA_TTHREAD: - sprintf(buff, "thread: %p", (void *)lua_tothread(L, 1)); break; case LUA_TNIL: lua_pushliteral(L, "nil"); - return 1; + break; + default: + lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1)); + break; } - lua_pushstring(L, buff); return 1; } @@ -389,150 +442,31 @@ static int luaB_newproxy (lua_State *L) { } -/* -** {====================================================== -** `require' function -** ======================================================= -*/ - - -/* 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 sufix? */ - 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_concat(L, n); -} - - -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); - 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)); - } - } -} - -/* }====================================================== */ - - -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}, - {"ipairs", luaB_ipairs}, - {"pairs", luaB_pairs}, + {"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}, {"unpack", luaB_unpack}, - {"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}, - {"require", luaB_require}, {NULL, NULL} }; @@ -547,9 +481,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_status(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"); @@ -623,55 +561,83 @@ 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_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 const luaL_reg co_funcs[] = { +static int luaB_corunning (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}, + {"running", luaB_corunning}, {"status", luaB_costatus}, + {"wrap", luaB_cowrap}, + {"yield", luaB_yield}, {NULL, NULL} }; /* }====================================================== */ +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) { - lua_pushliteral(L, "_G"); + /* set global _G */ lua_pushvalue(L, LUA_GLOBALSINDEX); - luaL_openlib(L, NULL, base_funcs, 0); /* open lib into global table */ - lua_pushliteral(L, "_VERSION"); + lua_setglobal(L, "_G"); + /* open lib into global table */ + luaL_register(L, "_G", base_funcs); lua_pushliteral(L, LUA_VERSION); - lua_rawset(L, -3); /* 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); /* `newproxy' needs a weaktable as upvalue */ - lua_pushliteral(L, "newproxy"); - 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, "__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_setglobal(L, "newproxy"); /* set global `newproxy' */ } 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 0; + luaL_register(L, LUA_COLIBNAME, co_funcs); + return 2; } diff --git a/src/lcode.c b/src/lcode.c index 3925c976c8..dd3e37e78c 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 1.117a 2003/04/03 13:35:34 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 */ @@ -8,12 +8,14 @@ #include #define lcode_c +#define LUA_CORE #include "lua.h" #include "lcode.h" #include "ldebug.h" #include "ldo.h" +#include "lgc.h" #include "llex.h" #include "lmem.h" #include "lobject.h" @@ -25,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 */ @@ -51,13 +61,18 @@ int luaK_jump (FuncState *fs) { } -static int luaK_condjump (FuncState *fs, OpCode op, int A, int B, int C) { +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); } -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); @@ -77,7 +92,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 */ @@ -88,7 +103,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; @@ -99,51 +114,49 @@ 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) { - for (; list != NO_JUMP; list = luaK_getjump(fs, list)) { +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_A(i) != NO_REG || - 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); +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 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 = luaK_getjump(fs, list)) { - Instruction *i = getjumpcontrol(fs, list); - if (GET_OPCODE(*i) == OP_TEST) - patchtestreg(i, NO_REG); - } + for (; list != NO_JUMP; list = getjump(fs, list)) + patchtestreg(fs, list, NO_REG); } -static void luaK_patchlistaux (FuncState *fs, int list, int vtarget, int reg, - int dtarget) { +static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, + int dtarget) { while (list != NO_JUMP) { - int next = luaK_getjump(fs, list); - Instruction *i = getjumpcontrol(fs, list); - if (GET_OPCODE(*i) == OP_TEST && GETARG_A(*i) == NO_REG) { - patchtestreg(i, reg); - luaK_fixjump(fs, list, vtarget); - } + int next = getjump(fs, list); + if (patchtestreg(fs, list, reg)) + fixjump(fs, list, vtarget); else - luaK_fixjump(fs, list, dtarget); /* jump to default target */ + fixjump(fs, list, dtarget); /* jump to default target */ list = next; } } -static void luaK_dischargejpc (FuncState *fs) { - luaK_patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); +static void dischargejpc (FuncState *fs) { + patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); fs->jpc = NO_JUMP; } @@ -153,7 +166,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); + patchlistaux(fs, list, target, NO_REG, target); } } @@ -171,9 +184,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); } } @@ -183,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); } } @@ -195,7 +208,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); } @@ -204,56 +217,81 @@ 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); } -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)); + 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_num(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; +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); - 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); } -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->u.s.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 */ } } @@ -265,24 +303,25 @@ 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; } + case VVARARG: case VCALL: { - luaK_setcallreturns(fs, e, 1); + luaK_setoneret(fs, e); break; } default: break; /* there is one value available (somewhere) */ @@ -308,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: { @@ -317,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: { @@ -326,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; } @@ -339,28 +382,26 @@ 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 */ + 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, 1) || need_value(fs, e->f, 0)) { - int fj = NO_JUMP; /* first jump (over LOAD ops.) */ - if (e->k != VJMP) - fj = luaK_jump(fs); + if (need_value(fs, e->t) || need_value(fs, e->f)) { + 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); } final = luaK_getlabel(fs); - luaK_patchlistaux(fs, e->f, final, reg, p_f); - luaK_patchlistaux(fs, e->t, final, 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; + e->u.s.info = reg; e->k = VNONRELOC; } @@ -369,21 +410,21 @@ 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); } 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; + 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; } @@ -398,17 +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 + MAXSTACK <= MAXARG_C) { /* constant fit in argC? */ - e->info = nil_constant(fs); + 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->k = VK; - return e->info + MAXSTACK; + return RKASK(e->u.s.info); } else break; } case VK: { - if (e->info + MAXSTACK <= MAXARG_C) /* constant fit in argC? */ - return e->info + MAXSTACK; + if (e->u.s.info <= MAXINDEXRK) /* constant fit in argC? */ + return RKASK(e->u.s.info); else break; } default: break; @@ -418,26 +464,26 @@ 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); + exp2reg(fs, ex, var->u.s.info); return; } case VUPVAL: { - int e = luaK_exp2anyreg(fs, exp); - luaK_codeABC(fs, OP_SETUPVAL, e, var->info, 0); + int e = luaK_exp2anyreg(fs, ex); + luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0); break; } case VGLOBAL: { - int e = luaK_exp2anyreg(fs, exp); - luaK_codeABx(fs, OP_SETGLOBAL, e, var->info); + int e = luaK_exp2anyreg(fs, ex); + luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info); break; } case VINDEXED: { - int e = luaK_exp2RK(fs, exp); - luaK_codeABC(fs, OP_SETTABLE, var->info, var->aux, e); + int e = luaK_exp2RK(fs, ex); + luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e); break; } default: { @@ -445,7 +491,7 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *exp) { break; } } - freeexp(fs, exp); + freeexp(fs, ex); } @@ -455,17 +501,17 @@ 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); - lua_assert(testOpMode(GET_OPCODE(*pc), OpModeT) && - GET_OPCODE(*pc) != OP_TEST); + 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))); } @@ -475,13 +521,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, GETARG_B(ie), GETARG_B(ie), !cond); + return condjump(fs, OP_TEST, GETARG_B(ie), 0, !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_TESTSET, NO_REG, e->u.s.info, cond); } @@ -489,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; } @@ -499,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: { @@ -508,10 +554,12 @@ 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; } -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) { @@ -524,7 +572,7 @@ void luaK_goiffalse (FuncState *fs, expdesc *e) { break; } case VJMP: { - pc = e->info; + pc = e->u.s.info; break; } default: { @@ -533,6 +581,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; } @@ -543,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; } @@ -555,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; } @@ -572,25 +622,85 @@ 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 (luai_numisnan(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) { - 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; + expdesc e2; + e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; + switch (op) { + case OPR_MINUS: { + 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); /* cannot operate on constants */ + codearith(fs, OP_LEN, e, &e2); + break; + } + default: lua_assert(0); } - else /* op == NOT */ - codenot(fs, e); } @@ -598,14 +708,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: { @@ -613,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 = luaK_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); } } @@ -690,9 +780,9 @@ 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; - 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"); @@ -707,12 +797,29 @@ 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); } + +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 74908c6580..b5668f22a6 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.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_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, @@ -34,41 +34,44 @@ 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_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) -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); -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); +#define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) + +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_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); +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 new file mode 100644 index 0000000000..26a19b6a6f --- /dev/null +++ b/src/ldblib.c @@ -0,0 +1,397 @@ +/* +** $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 +*/ + + +#include +#include +#include + +#define ldblib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + + +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)) { + lua_pushnil(L); /* no metatable */ + } + return 1; +} + + +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"); + lua_settop(L, 2); + lua_pushboolean(L, lua_setmetatable(L, 1)); + return 1; +} + + +static int db_getfenv (lua_State *L) { + lua_getfenv(L, 1); + return 1; +} + + +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, LUA_QL("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); +} + + +static void settabsi (lua_State *L, const char *i, int v) { + 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 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); + 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, arg+1)) { + lua_pushfstring(L, ">%s", options); + options = lua_tostring(L, -1); + lua_pushvalue(L, arg+1); + lua_xmove(L, L1, 1); + } + else + 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_createtable(L, 0, 2); + 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 db_getlocal (lua_State *L) { + int arg; + 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); + return 1; + } +} + + +static int db_setlocal (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + lua_Debug ar; + 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; +} + + +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 db_getupvalue (lua_State *L) { + return auxupvalue(L, 1); +} + + +static int db_setupvalue (lua_State *L) { + luaL_checkany(L, 3); + return auxupvalue(L, 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"}; + 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_pushinteger(L, ar->currentline); + else lua_pushnil(L); + lua_assert(lua_getinfo(L, "lS", ar)); + lua_call(L, 2, 0); + } +} + + +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 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 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; + 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, 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); + } + 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 db_gethook (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + char buff[5]; + int mask = lua_gethookmask(L1); + lua_Hook hook = lua_gethook(L1); + if (hook != NULL && hook != hookf) /* external hook? */ + lua_pushliteral(L, "external hook"); + else { + 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_pushinteger(L, lua_gethookcount(L1)); + return 3; +} + + +static int db_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; + 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 */ + } +} + + +#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 `...' */ + 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); + } + lua_concat(L, lua_gettop(L) - arg); + return 1; +} + + +static const luaL_Reg dblib[] = { + {"debug", db_debug}, + {"getfenv", db_getfenv}, + {"gethook", db_gethook}, + {"getinfo", db_getinfo}, + {"getlocal", db_getlocal}, + {"getregistry", db_getregistry}, + {"getmetatable", db_getmetatable}, + {"getupvalue", db_getupvalue}, + {"setfenv", db_setfenv}, + {"sethook", db_sethook}, + {"setlocal", db_setlocal}, + {"setmetatable", db_setmetatable}, + {"setupvalue", db_setupvalue}, + {"traceback", db_errorfb}, + {NULL, NULL} +}; + + +LUALIB_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 8e511e3bd9..8919a01739 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,14 +1,17 @@ /* -** $Id: ldebug.c,v 1.150 2003/03/19 21:24:04 roberto Exp $ +** $Id: ldebug.c,v 2.29 2005/12/22 16:19:56 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ -#include +#include +#include #include + #define ldebug_c +#define LUA_CORE #include "lua.h" @@ -27,23 +30,19 @@ -static const char *getfuncname (CallInfo *ci, const char **name); - +static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name); -#define isLua(ci) (!((ci)->state & CI_C)) - -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->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); + 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 @@ -51,14 +50,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) */ @@ -70,8 +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->hookinit = 0; + L->hookmask = cast_byte(mask); return 1; } @@ -97,18 +87,18 @@ 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? */ - level -= ci->u.l.tailcalls; /* skip lost tail calls */ + 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 = cast_int(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; } @@ -119,87 +109,94 @@ 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(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(ci)); - if (!name || name[0] == '(') /* `(' starts private locals */ - name = NULL; - else - setobjs2s(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; } -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; + ar->lastlinedefined = -1; ar->what = "C"; } 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); } -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) { +static void info_tailcall (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(ar); + return status; + } for (; *what; what++) { switch (*what) { case 'S': { @@ -207,27 +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) { - /* 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); + case 'L': + case 'f': /* handled by lua_getinfo */ break; - } default: status = 0; /* invalid option */ } } @@ -236,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; - lua_assert(ttisfunction(ci->base - 1)); - status = auxgetinfo(L, what, ar, ci->base - 1, ci); + ci = L->base_ci + ar->i_ci; + lua_assert(ttisfunction(ci->func)); + 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; } @@ -274,72 +275,89 @@ 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; } -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: - 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 */ } } -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(ISK(r) ? INDEXK(r) < pt->sizek : r < pt->maxstacksize); + break; + } + return 1; } -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) */ 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; 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); + if (dest > 0) { + /* cannot jump to a setlist count */ + Instruction d = pt->code[dest-1]; + check(!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)); + } + } 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 +387,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: { + 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 */ break; } - 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); + 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 */ @@ -408,7 +427,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: { @@ -422,6 +442,14 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { } 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); + break; + } default: break; } } @@ -436,28 +464,28 @@ 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 (symbexec(pt, pt->sizecode, NO_REG) != 0); } 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 "?"; } -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? */ 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: { @@ -470,7 +498,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: { @@ -478,6 +506,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 = p->upvalues ? getstr(p->upvalues[u]) : "?"; + return "upvalue"; + } case OP_SELF: { int k = GETARG_C(i); /* key index */ *name = kname(p, k); @@ -490,21 +523,22 @@ 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->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) - return getobjname(ci, GETARG_A(i), name); + 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 */ } /* 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,13 +546,14 @@ 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)) ? - getobjname(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 `%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); @@ -532,15 +567,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]) @@ -555,7 +590,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); } @@ -566,8 +601,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..9c76aa10f0 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.3 2005/04/25 19:24:10 roberto Exp $ ** Auxiliary functions from Debug Interface module ** See Copyright Notice in lua.h */ @@ -18,14 +18,16 @@ #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); - +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 a6d344cd57..b8eb1a8a59 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.37 2005/12/22 16:19:56 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -10,6 +10,7 @@ #include #define ldo_c +#define LUA_CORE #include "lua.h" @@ -34,7 +35,7 @@ /* ** {====================================================== -** Error-recovery functions (based on long jumps) +** Error-recovery functions ** ======================================================= */ @@ -42,24 +43,24 @@ /* chain list of long jump buffers */ struct lua_longjmp { struct lua_longjmp *previous; - jmp_buf b; + luai_jmpbuf b; volatile int status; /* error code */ }; -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(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; } } @@ -67,13 +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; - longjmp(L->errorJmp->b, 1); + LUAI_THROW(L, L->errorJmp); } else { - G(L)->panic(L); + L->status = cast_byte(errcode); + if (G(L)->panic) { + resetstack(L, errcode); + lua_unlock(L); + G(L)->panic(L); + } exit(EXIT_FAILURE); } } @@ -84,44 +113,38 @@ 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) + LUAI_TRY(L, &lj, (*f)(L, ud); + ); L->errorJmp = lj.previous; /* restore old error handler */ return lj.status; } - -static void restore_stack_limit (lua_State *L) { - 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); - } -} - /* }====================================================== */ -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; + ci->func = (ci->func - oldstack) + L->stack; } - L->base = L->ci->base; + L->base = (L->base - oldstack) + L->stack; } 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; + 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; correctstack(L, oldstack); } @@ -129,9 +152,9 @@ 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; + L->end_ci = L->base_ci + L->size_ci - 1; } @@ -139,18 +162,19 @@ 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) { - if (L->size_ci > LUA_MAXCALLS) /* overflow while handling overflow? */ +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 > LUA_MAXCALLS) + if (L->size_ci > LUAI_MAXCALLS) luaG_runerror(L, "stack overflow"); } + return ++L->ci; } @@ -165,9 +189,10 @@ 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); L->allowhook = 0; /* cannot call hooks inside a hook */ lua_unlock(L); (*hook)(L, &ar); @@ -180,86 +205,125 @@ 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, Proto *p, int actual) { 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++); + 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)); } - 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); +#endif + /* 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; } 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; } -StkId luaD_precall (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)) + + +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 */ - if (L->ci + 1 == L->end_ci) luaD_growCI(L); - else condhardstacktests(luaD_reallocCI(L, L->size_ci)); + 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; 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; + func = restorestack(L, funcr); + 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); + func = restorestack(L, funcr); /* previous call may change the stack */ + } + ci = inc_ci(L); /* now `enter' new function */ + 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->state = CI_SAVEDPC; - while (L->top < ci->top) - setnilvalue(L->top++); + 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); L->top = ci->top; - return NULL; + 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 */ 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 = 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; - ci->state = CI_C; /* a C function */ + lua_assert(ci->top <= L->stack_last); + ci->nresults = nresults; 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; + if (n < 0) /* yielding? */ + return PCRYIELD; + else { + luaD_poscall(L, L->top - n); + return PCRC; + } } } @@ -267,29 +331,32 @@ 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? */ - while (L->ci->u.l.tailcalls--) /* call hook for eventual tail calls */ + if (f_isLua(L->ci)) { /* Lua function? */ + while (L->ci->tailcalls--) /* call hook for eventual tail calls */ luaD_callhook(L, LUA_HOOKTAILRET, -1); } return restorestack(L, fr); } -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->base - 1; /* res == final position of 1st result */ - L->ci--; - L->base = L->ci->base; /* restore base */ + 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) { - setobjs2s(res++, firstResult++); - wanted--; - } - while (wanted-- > 0) + for (i = wanted; i != 0 && firstResult < L->top; i--) + setobjs2s(L, res++, firstResult++); + while (i-- > 0) setnilvalue(res++); L->top = res; + return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */ } @@ -300,56 +367,46 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { ** 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) + 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 */ } - firstResult = luaD_precall(L, func); - if (firstResult == NULL) /* is a Lua function? */ - firstResult = luaV_execute(L); /* 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 (ci == L->base_ci) { /* no activation record? */ - lua_assert(nargs < L->top - L->base); - luaD_precall(L, L->top - (nargs + 1)); /* 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 { /* 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; + 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 */ } + else /* yielded inside a hook: just continue its execution */ + L->base = L->ci->base; } - firstResult = luaV_execute(L); - if (firstResult != NULL) /* return? */ - luaD_poscall(L, LUA_MULTRET, firstResult); /* finalize this coroutine */ + L->status = 0; + 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->top, luaS_new(L, msg)); + setsvalue2s(L, L->top, luaS_new(L, msg)); incr_top(L); lua_unlock(L); return LUA_ERRRUN; @@ -358,48 +415,35 @@ 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); - if (L->ci == L->base_ci) { - if (nargs >= L->top - L->base) + 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"); } - else if (!(L->ci->state & CI_YIELD)) /* not inside a yield? */ - return resume_error(L, "cannot resume non-suspended coroutine"); - old_allowhooks = L->allowhook; + luai_userstateresume(L, nargs); lua_assert(L->errfunc == 0 && L->nCcalls == 0); - status = luaD_rawrunprotected(L, resume, &nargs); + status = luaD_rawrunprotected(L, resume, L->top - 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 = cast_byte(status); /* mark thread as `dead' */ + luaD_seterrorobj(L, status, L->top); + L->ci->top = L->top; } + else + status = L->status; lua_unlock(L); return status; } 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 (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; + L->base = L->top - nresults; /* protect stack slots below */ + L->status = LUA_YIELD; lua_unlock(L); return -1; } @@ -417,10 +461,11 @@ 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; + L->savedpc = L->ci->savedpc; L->allowhook = old_allowhooks; restore_stack_limit(L); } @@ -436,35 +481,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, hvalue(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..b2de92bb80 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.7 2005/08/24 16:15:49 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -13,48 +13,45 @@ #include "lzio.h" -/* -** macro to control inclusion of some hard tests on stack reallocation -*/ -#ifndef HARDSTACKTESTS -#define condhardstacktests(x) { /* empty */ } -#else -#define condhardstacktests(x) x -#endif - - #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)); + else condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); #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))) +/* 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, 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); +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 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); -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); +LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop); #endif + diff --git a/src/ldump.c b/src/ldump.c index 234b011f5f..f08277d3ac 100644 --- a/src/ldump.c +++ b/src/ldump.c @@ -1,170 +1,164 @@ /* -** $Id: ldump.c,v 1.4 2003/02/11 23:52:12 lhf Exp $ -** save bytecodes +** $Id: ldump.c,v 1.15 2006/02/16 15:53:49 lhf Exp $ +** save precompiled Lua chunks ** See Copyright Notice in lua.h */ #include #define ldump_c +#define LUA_CORE #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; + lua_Writer writer; void* data; + int strip; + int status; } DumpState; +#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) { - 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) +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(TString* s, DumpState* 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; - 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); -} +#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 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); + const TValue* o=&f->k[i]; + DumpChar(ttype(o),D); switch (ttype(o)) { + case LUA_TNIL: + break; + case LUA_TBOOLEAN: + DumpChar(bvalue(o),D); + break; case LUA_TNUMBER: DumpNumber(nvalue(o),D); break; case LUA_TSTRING: - DumpString(tsvalue(o),D); - break; - case LUA_TNIL: + DumpString(rawtsvalue(o),D); break; default: lua_assert(0); /* cannot happen */ break; } } - DumpInt(n=f->sizep,D); + n=f->sizep; + DumpInt(n,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); - 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); + 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); DumpCode(f,D); + DumpConstants(f,D); + DumpDebug(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); + char h[LUAC_HEADERSIZE]; + luaU_header(h); + DumpBlock(h,LUAC_HEADERSIZE,D); } /* -** dump function as precompiled chunk +** dump Lua 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* f, lua_Writer 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); + DumpFunction(f,NULL,&D); + return D.status; } - diff --git a/src/lfunc.c b/src/lfunc.c index 97c5d9bbdc..b8cd67b267 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -1,13 +1,14 @@ /* -** $Id: lfunc.c,v 1.67a 2003/03/18 12:50:04 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 */ -#include +#include #define lfunc_c +#define LUA_CORE #include "lua.h" @@ -18,57 +19,102 @@ #include "lstate.h" -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, valtogco(c), LUA_TFUNCTION); + luaC_link(L, obj2gco(c), LUA_TFUNCTION); c->c.isC = 1; - c->c.nupvalues = cast(lu_byte, nelems); + c->c.env = e; + c->c.nupvalues = cast_byte(nelems); return c; } -Closure *luaF_newLclosure (lua_State *L, int nelems, TObject *e) { +Closure *luaF_newLclosure (lua_State *L, int nelems, Table *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); + c->l.env = e; + c->l.nupvalues = cast_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->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 *v; + 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; } - 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); + 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 *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) && uv->v != &uv->u.value); + L->openupval = uv->next; /* remove from `open' list */ + if (isdead(g, o)) + luaF_freeupval(L, uv); /* free upvalue */ + else { + unlinkupval(uv); + setobj(L, &uv->u.value, uv->v); + uv->v = &uv->u.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; @@ -85,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; } @@ -94,18 +141,18 @@ 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 *); - 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/lfunc.h b/src/lfunc.h index dc61e2ed43..2e02419bd6 100644 --- a/src/lfunc.h +++ b/src/lfunc.h @@ -1,5 +1,5 @@ /* -** $Id: lfunc.h,v 1.21a 2003/03/18 12:50:04 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 */ @@ -12,21 +12,23 @@ #define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \ - cast(int, sizeof(TObject)*((n)-1))) + cast(int, sizeof(TValue)*((n)-1))) #define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \ - cast(int, sizeof(TObject *)*((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); -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); - -const char *luaF_getlocalname (const Proto *func, int local_number, int pc); + cast(int, sizeof(TValue *)*((n)-1))) + + +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 b44f201701..691565db49 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 1.171b 2003/04/03 13:35:34 roberto Exp $ +** $Id: lgc.c,v 2.37 2005/12/22 16:19:56 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,325 +23,350 @@ #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 1024u +#define GCSWEEPMAX 40 +#define GCSWEEPCOST 10 +#define GCFINALIZECOST 100 -/* -** 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 maskmarks cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) + +#define makewhite(g,x) \ + ((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) -#define unmark(x) resetbit((x)->gch.marked, 0) -#define ismarked(x) ((x)->gch.marked & ((1<<4)|1)) +#define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) -#define stringmark(s) setbit((s)->tsv.marked, 0) +#define isfinalized(u) testbit((u)->marked, FINALIZEDBIT) +#define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT) -#define isfinalized(u) (!testbit((u)->uv.marked, 1)) -#define markfinalized(u) resetbit((u)->uv.marked, 1) +#define KEYWEAK bitmask(KEYWEAKBIT) +#define VALUEWEAK bitmask(VALUEWEAKBIT) -#define KEYWEAKBIT 1 -#define VALUEWEAKBIT 2 -#define KEYWEAK (1<GCthreshold = (g->estimate/100) * g->gcpause) +static void removeentry (Node *n) { + lua_assert(ttisnil(gval(n))); + if (iscollectable(gkey(n))) + setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */ +} + -static void reallymarkobject (GCState *st, GCObject *o) { - lua_assert(!ismarked(o)); - setbit(o->gch.marked, 0); /* mark object */ +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); + markobject(g, gco2u(o)->env); + 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 */ + 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) { - 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 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); } } /* 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) { + global_State *g = G(L); size_t deadmem = 0; - GCObject **p = &G(L)->rootudata; + GCObject **p = &g->mainthread->next; 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))) + 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)); + 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; + } } } - /* insert collected udata with gc event into `tmudata' list */ - *lastcollected = G(L)->tmudata; - G(L)->tmudata = collected; return deadmem; } -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); + 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->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 */ } } + 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))) { + lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || 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) { + markobject(g, cl->c.env); 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]; - markobject(st, u->v); - u->marked = 1; - } + markobject(g, cl->l.p); + for (i=0; il.nupvalues; i++) /* mark its upvalues */ + markobject(g, cl->l.upvals[i]); } } 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 = 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... */ - 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)); } -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 lu_mem propagatemarks (GCState *st) { - lu_mem mf = 0; - 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); - mf += sizeof(Table) + sizeof(TObject) * h->sizearray + - sizeof(Node) * sizenode(h); - break; - } - case LUA_TFUNCTION: { - Closure *cl = gcotocl(st->tmark); - st->tmark = cl->c.gclist; - traverseclosure(st, cl); - mf += (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); - mf += sizeof(lua_State) + sizeof(TObject) * th->stacksize + - sizeof(CallInfo) * th->size_ci; - break; - } - case LUA_TPROTO: { - Proto *p = gcotop(st->tmark); - st->tmark = p->gclist; - traverseproto(st, p); - /* do not need 'mf' for this case (cannot happen inside a udata) */ - break; - } - default: lua_assert(0); +/* +** traverse one gray object, turning it to black. +** Returns `quantity' traversed. +*/ +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); + } + 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); } + 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; + } + 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; + } + default: lua_assert(0); return 0; } - return mf; } -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); +static void propagateall (global_State *g) { + while (g->gray) propagatemark(g); } /* -** 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(key2tval(n), 1) || iscleared(gval(n), 0))) { + setnilvalue(gval(n)); /* remove value ... */ + removeentry(n); /* remove entry from table */ + } } l = h->gclist; } @@ -349,21 +375,22 @@ 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: luaF_freeupval(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)); + G(L)->strt.nuse--; + luaM_freemem(L, o, sizestring(gco2ts(o))); break; } case LUA_TUSERDATA: { - luaM_free(L, o, sizeudata(gcotou(o)->uv.len)); + luaM_freemem(L, o, sizeudata(gco2u(o))); break; } default: lua_assert(0); @@ -371,135 +398,310 @@ static void freeobj (lua_State *L, GCObject *o) { } -static int sweeplist (lua_State *L, GCObject **p, int limit) { + +#define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) + + +static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { GCObject *curr; - int count = 0; /* number of collected items */ - while ((curr = *p) != NULL) { - if ((curr->gch.marked & ~(KEYWEAK | VALUEWEAK)) > limit) { - unmark(curr); + 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)); + makewhite(g, curr); /* make it white (for next cycle) */ p = &curr->gch.next; } - else { - count++; + 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 */ freeobj(L, curr); } } - return count; -} - - -static void sweepstrings (lua_State *L, int all) { - int i; - for (i=0; istrt.size; i++) { /* for each list */ - G(L)->strt.nuse -= sweeplist(L, &G(L)->strt.hash[i], all); - } + return p; } -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->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->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; + 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; + 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 */ } } +/* +** 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_freeall (lua_State *L) { + 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]); } -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); +static void markmt (global_State *g) { + int i; + for (i=0; imt[i]) markobject(g, g->mt[i]); } /* 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); + 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 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 */ - deadmem += 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) { + 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); + } } -void luaC_collectgarbage (lua_State *L) { - size_t deadmem = mark(L); - luaC_sweep(L, 0); - checkSizes(L, deadmem); - luaC_callGCTM(L); +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; + 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; + propagateall(g); + 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 */ + /* flip current white */ + g->currentwhite = cast_byte(otherwhite(g)); + g->sweepstrgc = 0; + g->sweepgc = &g->rootgc; + g->gcstate = GCSsweepstring; + g->estimate = g->totalbytes - udsize; /* first estimate */ +} + + +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; + } + case GCSpropagate: { + if (g->gray) + return propagatemark(g); + else { /* no more `gray' objects */ + atomic(L); /* finish mark phase */ + return 0; + } + } + 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; + 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); + 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); + return GCFINALIZECOST; + } + else { + g->gcstate = GCSpause; /* end collection */ + g->gcdept = 0; + return 0; + } + } + default: lua_assert(0); return 0; + } +} + + +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 { + 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); + } +} + + +void luaC_fullgc (lua_State *L) { + 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); + 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) { - 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 && g->gcstate != GCSpause); + } + } +} + diff --git a/src/lgc.h b/src/lgc.h index 3f4d7486e9..5f69acb1e3 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.15 2005/08/24 16:15:49 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -11,15 +11,100 @@ #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 GCSpause 0 +#define GCSpropagate 1 +#define GCSsweepstring 2 +#define GCSsweep 3 +#define GCSfinalize 4 + + +/* +** 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 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))) + + + +/* +** 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 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 +#define FINALIZEDBIT 3 +#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 ^ WHITEBITS) +#define isdead(g,v) ((v)->gch.marked & otherwhite(g) & WHITEBITS) + +#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 & 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_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ + luaC_barrierf(L,obj2gco(p),gcvalue(v)); } + +#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,t,o) \ + { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); } -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); -void luaC_link (lua_State *L, GCObject *o, lu_byte tt); +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, Table *t); #endif diff --git a/src/lib/Makefile b/src/lib/Makefile deleted file mode 100644 index 3c6c07ab2f..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 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 - -$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/ldblib.c b/src/lib/ldblib.c deleted file mode 100644 index 6dc9b64cfc..0000000000 --- a/src/lib/ldblib.c +++ /dev/null @@ -1,299 +0,0 @@ -/* -** $Id: ldblib.c,v 1.80 2003/04/03 13:35:34 roberto Exp $ -** Interface from Lua to its debug API -** See Copyright Notice in lua.h -*/ - - -#include -#include -#include - -#define ldblib_c - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - - -static void settabss (lua_State *L, const char *i, const char *v) { - lua_pushstring(L, i); - lua_pushstring(L, v); - lua_rawset(L, -3); -} - - -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); -} - - -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)) { - 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); - } - else - return luaL_argerror(L, 1, "function or level expected"); - if (!lua_getinfo(L, options, &ar)) - return luaL_argerror(L, 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': - lua_pushliteral(L, "func"); - lua_pushvalue(L, -3); - lua_rawset(L, -3); - break; - } - } - return 1; /* return table */ -} - - -static int getlocal (lua_State *L) { - 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 (name) { - lua_pushstring(L, name); - lua_pushvalue(L, -2); - return 2; - } - else { - lua_pushnil(L); - return 1; - } -} - - -static int setlocal (lua_State *L) { - 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))); - 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); -} - - - -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"}; - lua_pushlightuserdata(L, (void *)&KEY_HOOK); - lua_rawget(L, LUA_REGISTRYINDEX); - if (lua_isfunction(L, -1)) { - 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 */ -} - - -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 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 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_rawset(L, LUA_REGISTRYINDEX); /* set new hook */ - return 0; -} - - -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 */ - } -} - - -#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 luaL_reg dblib[] = { - {"getlocal", getlocal}, - {"getinfo", getinfo}, - {"gethook", gethook}, - {"getupvalue", getupvalue}, - {"sethook", sethook}, - {"setlocal", setlocal}, - {"setupvalue", setupvalue}, - {"debug", debug}, - {"traceback", errorfb}, - {NULL, NULL} -}; - - -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 deleted file mode 100644 index bcadcdfdec..0000000000 --- a/src/lib/liolib.c +++ /dev/null @@ -1,762 +0,0 @@ -/* -** $Id: liolib.c,v 2.39b 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 - -#define liolib_c - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -typedef struct FileHandle { - FILE *f; - int ispipe; -} FileHandle; - - - -/* -** 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 -#ifdef _POSIX_C_SOURCE -#if _POSIX_C_SOURCE >= 2 -#define USE_POPEN 1 -#endif -#endif -#endif - -#ifndef USE_POPEN -#define USE_POPEN 0 -#endif - - - - -/* -** {====================================================== -** FILE Operations -** ======================================================= -*/ - - -#if !USE_POPEN -#define pclose(f) (-1) -#endif - - -#define FILEHANDLE "FILE*" - -#define IO_INPUT "_input" -#define IO_OUTPUT "_output" - - -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_pushnumber(L, errno); - return 3; - } -} - - -static FileHandle *topfile (lua_State *L, int findex) { - FileHandle *fh = (FileHandle *)luaL_checkudata(L, findex, FILEHANDLE); - if (fh == NULL) luaL_argerror(L, findex, "bad file"); - return fh; -} - - -static int io_type (lua_State *L) { - FileHandle *fh = (FileHandle *)luaL_checkudata(L, 1, FILEHANDLE); - if (fh == NULL) lua_pushnil(L); - else if (fh->f == NULL) - lua_pushliteral(L, "closed file"); - else - lua_pushliteral(L, "file"); - return 1; -} - - -#define tofile(L,i) (tofileh(L,i)->f) - -static FileHandle *tofileh (lua_State *L, int findex) { - FileHandle *fh = topfile(L, findex); - if (fh->f == NULL) - luaL_error(L, "attempt to use a closed file"); - return fh; -} - - - -#define newfile(L) (&(newfileh(L)->f)) - -/* -** 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 FileHandle *newfileh (lua_State *L) { - FileHandle *fh = (FileHandle *)lua_newuserdata(L, sizeof(FileHandle)); - fh->f = NULL; /* file handle is currently `closed' */ - fh->ispipe = 0; - luaL_getmetatable(L, FILEHANDLE); - lua_setmetatable(L, -2); - return fh; -} - - -/* -** 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) { - FileHandle *fh = tofileh(L, 1); - FILE *f = fh->f; - if (f == stdin || f == stdout || f == stderr) - return 0; /* file cannot be closed */ - else { - int ok = fh->ispipe ? (pclose(f) != -1) : (fclose(f) == 0); - fh->f = NULL; /* mark file as closed */ - return ok; - } -} - - -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)); - } - return pushresult(L, aux_close(L), NULL); -} - - -static int io_gc (lua_State *L) { - FileHandle *fh = topfile(L, 1); - if (fh->f != NULL) /* ignore closed files */ - aux_close(L); - return 0; -} - - -static int io_tostring (lua_State *L) { - char buff[128]; - FileHandle *fh = topfile(L, 1); - if (fh->f == NULL) - strcpy(buff, "closed"); - else - 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_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"); - FileHandle *fh = newfileh(L); - fh->f = popen(filename, mode); - fh->ispipe = 1; - return (fh->f == NULL) ? pushresult(L, 0, filename) : 1; -#endif -} - - -static int io_tmpfile (lua_State *L) { - FILE **pf = newfile(L); - *pf = tmpfile(); - return (*pf == NULL) ? pushresult(L, 0, NULL) : 1; -} - - -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 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"); -} - - -static int io_output (lua_State *L) { - return g_iofile(L, IO_OUTPUT, "w"); -} - - -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_pushvalue(L, idx); - lua_pushboolean(L, close); /* close/not close file when finished */ - lua_pushcclosure(L, io_readline, 3); -} - - -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; -} - - -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; - } -} - - -/* -** {====================================================== -** READ -** ======================================================= -*/ - - -static int read_number (lua_State *L, FILE *f) { - lua_Number d; - if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) { - lua_pushnumber(L, d); - return 1; - } - else return 0; /* read fails */ -} - - -static int test_eof (lua_State *L, FILE *f) { - int c = getc(f); - ungetc(c, f); - lua_pushlstring(L, NULL, 0); - return (c != EOF); -} - - -static int read_line (lua_State *L, FILE *f) { - luaL_Buffer b; - luaL_buffinit(L, &b); - for (;;) { - size_t l; - char *p = luaL_prepbuffer(&b); - if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */ - luaL_pushresult(&b); /* close buffer */ - return (lua_strlen(L, -1) > 0); /* check whether read something */ - } - 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' */ - } - } -} - - -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 */ - 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 g_read (lua_State *L, FILE *f, int first) { - int nargs = lua_gettop(L) - 1; - int success; - int n; - 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, 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 */ - success = read_number(L, f); - break; - case 'l': /* line */ - success = read_line(L, f); - break; - case 'a': /* file */ - 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"); - } - } - } - } - 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 */ - } - return 0; - } -} - -/* }====================================================== */ - - -static int g_write (lua_State *L, FILE *f, int arg) { - int nargs = lua_gettop(L) - 1; - int status = 1; - for (; nargs--; arg++) { - if (lua_type(L, arg) == LUA_TNUMBER) { - /* optimization: could be done exactly as for strings */ - status = status && - fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; - } - else { - size_t l; - const char *s = luaL_checklstring(L, arg, &l); - status = status && (fwrite(s, sizeof(char), l, f) == l); - } - } - return pushresult(L, status, NULL); -} - - -static int io_write (lua_State *L) { - return g_write(L, getiofile(L, IO_OUTPUT), 1); -} - - -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}; - 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, NULL); /* error */ - else { - lua_pushnumber(L, ftell(f)); - return 1; - } -} - - -static int io_flush (lua_State *L) { - 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); -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Other O.S. Operations -** ======================================================= -*/ - -static int io_execute (lua_State *L) { - lua_pushnumber(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 -} - - -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_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) { - const char *s = luaL_optstring(L, 1, "%c"); - time_t t = (time_t)(luaL_optnumber(L, 2, -1)); - 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 `!' */ - } - else - 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 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_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_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/loadlib.c b/src/lib/loadlib.c deleted file mode 100644 index ac4d697a68..0000000000 --- a/src/lib/loadlib.c +++ /dev/null @@ -1,205 +0,0 @@ -/* -** $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/linit.c b/src/linit.c new file mode 100644 index 0000000000..483d9c8c28 --- /dev/null +++ b/src/linit.c @@ -0,0 +1,38 @@ +/* +** $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 +*/ + + +#define linit_c +#define LUA_LIB + +#include "lua.h" + +#include "lualib.h" +#include "lauxlib.h" + + +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}, + {NULL, NULL} +}; + + +LUALIB_API void luaL_openlibs (lua_State *L) { + const luaL_Reg *lib = lualibs; + for (; lib->func; lib++) { + lua_pushcfunction(L, lib->func); + lua_pushstring(L, lib->name); + lua_call(L, 1, 0); + } +} + diff --git a/src/liolib.c b/src/liolib.c new file mode 100644 index 0000000000..bb3b5194d9 --- /dev/null +++ b/src/liolib.c @@ -0,0 +1,532 @@ +/* +** $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 +*/ + + +#include +#include +#include +#include + +#define liolib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + + +#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) { + 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)); +} + + +#define topfile(L) ((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE)) + + +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)) + lua_pushnil(L); /* not a file */ + else if (*((FILE **)ud) == NULL) + lua_pushliteral(L, "closed file"); + else + lua_pushliteral(L, "file"); + return 1; +} + + +static FILE *tofile (lua_State *L) { + FILE **f = topfile(L); + if (*f == NULL) + luaL_error(L, "attempt to use a closed file"); + return *f; +} + + + +/* +** 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, LUA_FILEHANDLE); + lua_setmetatable(L, -2); + return pf; +} + + +/* +** 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) { + 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); + tofile(L); /* make sure argument is a file */ + return aux_close(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) + aux_close(L); + return 0; +} + + +static int io_tostring (lua_State *L) { + FILE *f = *topfile(L); + if (f == NULL) + lua_pushstring(L, "file (closed)"); + else + lua_pushfstring(L, "file (%p)", f); + 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_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(); + return (*pf == NULL) ? pushresult(L, 0, NULL) : 1; +} + + +static FILE *getiofile (lua_State *L, int findex) { + FILE *f; + lua_rawgeti(L, LUA_ENVIRONINDEX, findex); + f = *(FILE **)lua_touserdata(L, -1); + if (f == NULL) + luaL_error(L, "standard %s file is closed", fnames[findex - 1]); + return f; +} + + +static int g_iofile (lua_State *L, int f, const char *mode) { + if (!lua_isnoneornil(L, 1)) { + const char *filename = lua_tostring(L, 1); + if (filename) { + FILE **pf = newfile(L); + *pf = fopen(filename, mode); + if (*pf == NULL) + fileerror(L, 1, filename); + } + else { + tofile(L); /* check that it's a valid file handle */ + lua_pushvalue(L, 1); + } + lua_rawseti(L, LUA_ENVIRONINDEX, f); + } + /* return current value */ + lua_rawgeti(L, LUA_ENVIRONINDEX, f); + return 1; +} + + +static int io_input (lua_State *L) { + return g_iofile(L, IO_INPUT, "r"); +} + + +static int io_output (lua_State *L) { + return g_iofile(L, IO_OUTPUT, "w"); +} + + +static int io_readline (lua_State *L); + + +static void aux_lines (lua_State *L, int idx, int toclose) { + lua_pushvalue(L, idx); + lua_pushboolean(L, toclose); /* close/not close file when finished */ + lua_pushcclosure(L, io_readline, 2); +} + + +static int f_lines (lua_State *L) { + tofile(L); /* check that it's a valid file handle */ + aux_lines(L, 1, 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); + } + else { + 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; + } +} + + +/* +** {====================================================== +** READ +** ======================================================= +*/ + + +static int read_number (lua_State *L, FILE *f) { + lua_Number d; + if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) { + lua_pushnumber(L, d); + return 1; + } + else return 0; /* read fails */ +} + + +static int test_eof (lua_State *L, FILE *f) { + int c = getc(f); + ungetc(c, f); + lua_pushlstring(L, NULL, 0); + return (c != EOF); +} + + +static int read_line (lua_State *L, FILE *f) { + luaL_Buffer b; + luaL_buffinit(L, &b); + for (;;) { + size_t l; + char *p = luaL_prepbuffer(&b); + if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */ + luaL_pushresult(&b); /* close buffer */ + return (lua_strlen(L, -1) > 0); /* check whether read something */ + } + l = strlen(p); + if (l == 0 || 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' */ + } + } +} + + +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 */ + 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 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 */ + } + 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_tointeger(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 */ + success = read_number(L, f); + break; + case 'l': /* line */ + success = read_line(L, f); + break; + case 'a': /* file */ + read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */ + success = 1; /* always success */ + break; + default: + return luaL_argerror(L, n, "invalid format"); + } + } + } + } + if (ferror(f)) + return pushresult(L, 0, NULL); + 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), 2); +} + + +static int io_readline (lua_State *L) { + 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"); + sucess = read_line(L, f); + if (ferror(f)) + return luaL_error(L, "%s", strerror(errno)); + if (sucess) return 1; + else { /* EOF */ + if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */ + lua_settop(L, 0); + lua_pushvalue(L, lua_upvalueindex(1)); + aux_close(L); /* close it */ + } + return 0; + } +} + +/* }====================================================== */ + + +static int g_write (lua_State *L, FILE *f, int arg) { + int nargs = lua_gettop(L) - 1; + int status = 1; + for (; nargs--; arg++) { + if (lua_type(L, arg) == LUA_TNUMBER) { + /* optimization: could be done exactly as for strings */ + status = status && + fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; + } + else { + size_t l; + const char *s = luaL_checklstring(L, arg, &l); + status = status && (fwrite(s, sizeof(char), l, f) == l); + } + } + return pushresult(L, status, NULL); +} + + +static int io_write (lua_State *L) { + return g_write(L, getiofile(L, IO_OUTPUT), 1); +} + + +static int f_write (lua_State *L) { + 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); + int op = luaL_checkoption(L, 2, "cur", modenames); + long offset = luaL_optlong(L, 3, 0); + op = fseek(f, offset, mode[op]); + if (op) + return pushresult(L, 0, NULL); /* error */ + else { + 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); + 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); +} + + + +static int io_flush (lua_State *L) { + return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); +} + + +static int f_flush (lua_State *L) { + return pushresult(L, fflush(tofile(L)) == 0, NULL); +} + + +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}, + {"write", io_write}, + {NULL, NULL} +}; + + +static const luaL_Reg flib[] = { + {"close", io_close}, + {"flush", f_flush}, + {"lines", f_lines}, + {"read", f_read}, + {"seek", f_seek}, + {"setvbuf", f_setvbuf}, + {"write", f_write}, + {"__gc", io_gc}, + {"__tostring", io_tostring}, + {NULL, NULL} +}; + + +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 */ +} + + +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); + /* 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); + /* 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_createtable(L, 0, 1); + 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.c b/src/llex.c index 045e999443..f3022df596 100644 --- a/src/llex.c +++ b/src/llex.c @@ -1,14 +1,16 @@ /* -** $Id: llex.c,v 1.119 2003/03/24 12:39:34 roberto Exp $ +** $Id: llex.c,v 2.19 2006/02/06 18:28:16 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ #include +#include #include #define llex_c +#define LUA_CORE #include "lua.h" @@ -22,28 +24,49 @@ -#define next(LS) (LS->current = zgetc(LS->z)) +#define next(ls) (ls->current = zgetc(ls->z)) + +#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 */ + lua_assert(strlen(luaX_tokens[i])+1 <= TOKEN_LEN); + ts->tsv.reserved = cast_byte(i+1); /* reserved word */ } } @@ -51,85 +74,77 @@ 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 == cast(unsigned char, token)); + return (iscntrl(token)) ? luaO_pushfstring(ls->L, "char(%d)", token) : + luaO_pushfstring(ls->L, "%c", token); } + else + return luaX_tokens[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 " LUA_QS, 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->decpoint = '.'; + 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; + luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ + next(ls); /* read first char */ } @@ -141,242 +156,250 @@ 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 +static int check_next (LexState *ls, const char *set) { + if (!strchr(set, ls->current)) + return 0; + save_and_next(ls); + return 1; +} + -/* maximum number of chars that can be read without checking buffer size */ -#define MAXNOCHECK 5 +static void buffreplace (LexState *ls, char from, char to) { + size_t n = luaZ_bufflen(ls->buff); + char *p = luaZ_buffer(ls->buff); + while (n--) + if (p[n] == from) p[n] = to; +} -#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 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); + } +} -static size_t readname (LexState *LS) { - size_t l = 0; - checkbuffer(LS, l); +/* LUA_NUMBER */ +static void read_numeral (LexState *ls, SemInfo *seminfo) { + lua_assert(isdigit(ls->current)); do { - checkbuffer(LS, l); - save_and_next(LS, l); - } while (isalnum(LS->current) || LS->current == '_'); - save(LS, '\0', l); - return l-1; + save_and_next(ls); + } while (isdigit(ls->current) || ls->current == '.'); + if (check_next(ls, "Ee")) /* `E'? */ + check_next(ls, "+-"); /* optional exponent sign */ + 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? */ + trydecpoint(ls, seminfo); /* try to update decimal point separator */ } -/* 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); - } - if (LS->current == '.') { - save_and_next(LS, l); - if (LS->current == '.') { - 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(LS, l); - save_and_next(LS, l); +static int skip_sep (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++; } - 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); - } - } - save(LS, '\0', l); - if (!luaO_str2d(luaZ_buffer(LS->buff), &seminfo->r)) - luaX_lexerror(LS, "malformed number", TK_NUMBER); + return (ls->current == s) ? count : (-count) - 1; } -static void read_long_string (LexState *LS, SemInfo *seminfo) { +static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { 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 */ + (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 (;;) { - 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 defined(LUA_COMPAT_LSTR) + case '[': { + if (skip_sep(ls) == sep) { + save_and_next(ls); /* skip 2nd `[' */ cont++; - save_and_next(LS, l); +#if LUA_COMPAT_LSTR == 1 + if (sep == 0) + luaX_lexerror(ls, "nesting of [[...]] is deprecated", '['); +#endif } - continue; - case ']': - save_and_next(LS, l); - if (LS->current == ']') { - if (cont == 0) goto endloop; + break; + } +#endif + case ']': { + if (skip_sep(ls) == sep) { + save_and_next(ls); /* skip 2nd `]' */ +#if defined(LUA_COMPAT_LSTR) && LUA_COMPAT_LSTR == 2 cont--; - save_and_next(LS, l); + if (sep == 0 && cont >= 0) break; +#endif + goto endloop; } - continue; + break; + } case '\n': - save(LS, '\n', l); - inclinenumber(LS); - if (!seminfo) l = 0; /* reset buffer to avoid wasting space */ - continue; - default: - save_and_next(LS, l); + case '\r': { + save(ls, '\n'); + inclinenumber(ls); + if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ + break; + } + default: { + 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 + sep), + luaZ_bufflen(ls->buff) - 2*(2 + sep)); } -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) { +static int llex (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 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; + } + } + /* 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 sep = skip_sep(ls); + if (sep >= 0) { + read_long_string(ls, seminfo, sep); return TK_STRING; } + else if (sep == -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 (check_next(ls, ".")) { + if (check_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 +407,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 (+ - / ...) */ } } @@ -414,4 +441,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 740e3f6b31..d4ca7f20e1 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.57 2005/12/07 15:43:05 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' */ +LUAI_DATA const char *const luaX_tokens []; + + typedef union { lua_Number r; TString *ts; @@ -59,17 +63,19 @@ typedef struct LexState { ZIO *z; /* input stream */ Mbuffer *buff; /* buffer for tokens */ TString *source; /* current source name */ - int nestlevel; /* level of nested non-terminals */ + char decpoint; /* locale decimal point */ } LexState; -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); -void luaX_errorline (LexState *ls, const char *s, const char *token, int line); -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 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); #endif diff --git a/src/llimits.h b/src/llimits.h index 343c922612..b03221aeec 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.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,45 +15,13 @@ #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 -#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 +typedef LUAI_UINT32 lu_int32; +typedef LUAI_UMEM lu_mem; -/* -** 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 to hold hash values */ -typedef unsigned int lu_hash; -/* its signed equivalent */ -typedef int ls_hash; +typedef LUAI_MEM l_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 unsigned long lu_mem; -#define MAX_LUMEM ULONG_MAX - - -/* 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; @@ -61,6 +29,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) */ @@ -69,33 +39,30 @@ 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)(lu_mem)(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 +typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; -/* result of `usual argument conversion' over lua_Number */ -#ifndef LUA_UACNUMBER -typedef double l_uacNumber; -#else -typedef LUA_UACNUMBER l_uacNumber; -#endif +/* result of a `usual argument conversion' over lua_Number */ +typedef LUAI_UACNUMBER l_uacNumber; -#ifndef lua_assert -#define lua_assert(c) /* empty */ -#endif +/* 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 -#ifndef check_exp -#define check_exp(c,e) (e) #endif @@ -108,58 +75,24 @@ typedef LUA_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)) + /* ** 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) */ -#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 C stack */ -#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 /* arbitrary limit ( #define lmathlib_c +#define LUA_LIB #include "lua.h" @@ -22,56 +23,58 @@ -/* -** 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_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(TORAD(luaL_checknumber(L, 1)))); + 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(TORAD(luaL_checknumber(L, 1)))); + 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, 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; } @@ -85,11 +88,19 @@ 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; } +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; @@ -128,7 +139,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 +190,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"); @@ -201,31 +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}, - {"cos", math_cos}, - {"tan", math_tan}, - {"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}, + {"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} }; @@ -234,13 +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); - lua_pushliteral(L, "pi"); + luaL_register(L, LUA_MATHLIBNAME, mathlib); lua_pushnumber(L, PI); - lua_settable(L, -3); - lua_pushliteral(L, "__pow"); - lua_pushcfunction(L, math_pow); - lua_settable(L, LUA_GLOBALSINDEX); + 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 f977770af0..cef2bc5f85 100644 --- a/src/lmem.c +++ b/src/lmem.c @@ -1,13 +1,14 @@ /* -** $Id: lmem.c,v 1.61 2002/12/04 17:38:31 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 */ -#include +#include #define lmem_c +#define LUA_CORE #include "lua.h" @@ -20,72 +21,66 @@ /* -** 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 * 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, 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) +** +** frealloc 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 -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 = (*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) /* cannot grow even a little? */ + luaG_runerror(L, errormsg); + 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 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) - 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; - } +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->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; } diff --git a/src/lmem.h b/src/lmem.h index 1bb4fde0b2..19df1fbb6c 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.31 2005/04/25 19:24:10 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -16,29 +16,34 @@ #define MEMERRMSG "not enough memory" -void *luaM_realloc (lua_State *L, void *oldblock, lu_mem oldsize, lu_mem size); +#define luaM_reallocv(L,b,on,n,e) \ + ((cast(size_t, (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, int 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_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_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_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)))) + +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 new file mode 100644 index 0000000000..19edaca0fd --- /dev/null +++ b/src/loadlib.c @@ -0,0 +1,667 @@ +/* +** $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 +** +** 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 "lauxlib.h" +#include "lobject.h" +#include "lua.h" +#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 +#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); + + + +#if defined(LUA_DL_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(LUA_DL_DLL) +/* +** {====================================================================== +** This is an implementation of loadlib for Windows using native functions. +** ======================================================================= +*/ + +#include + + +#undef setprogdir + +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"); + else { + *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]; + 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(LUA_DL_DYLD) +/* +** {====================================================================== +** Native Mac OS X / Darwin Implementation +** ======================================================================= +*/ + +#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) { + 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 " LUA_QS " not found", sym); + return NULL; + } + return (lua_CFunction)NSAddressOfSymbol(nss); +} + +/* }====================================================== */ + + + +#else +/* +** {====================================================== +** Fallback for other systems +** ======================================================= +*/ + +#undef LIB_FAIL +#define LIB_FAIL "absent" + + +#define DLMSG "dynamic libraries not enabled; check your Lua installation" + + +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, 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, DLMSG); + 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) ll_unloadlib(*lib); + *lib = NULL; /* mark library as closed */ + 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); + if (*reg == NULL) + return ERRLIB; /* unable to load library */ + 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 */ + } +} + + +static int ll_loadlib (lua_State *L) { + const char *path = luaL_checkstring(L, 1); + const char *init = luaL_checkstring(L, 2); + 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' function +** ======================================================= +*/ + + +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); + 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, 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 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) != 0) + loaderror(L, filename); + 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 *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) + 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, '.'); + 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 1; /* root not found */ + funcname = mkfuncname(L, name); + if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { + 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, name); + if (lua_isnil(L, -1)) /* not found? */ + luaO_pushfstring(L, "\n\tno field package.preload['%s']", name); + return 1; +} + + +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); + 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"); + lua_pushstring(L, ""); /* error message accumulator */ + for (i=1; ; i++) { + lua_rawgeti(L, -2, i); /* get a loader */ + if (lua_isnil(L, -1)) + 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? */ + 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 */ + 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? */ + 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; + lua_getstack(L, 1, &ar); + 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); + 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) */ + 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 */ + } + /* 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); + modinit(L, modname); + } + lua_pushvalue(L, -1); + 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_createtable(L, 0, 1); /* 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; +} + + +/* }====================================================== */ + + + +/* 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_Lua, loader_C, loader_Croot, NULL}; + + +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 */ + 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); + /* create `loaders' table */ + 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]); + 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' */ + /* 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' */ + luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2); + lua_setfield(L, -2, "loaded"); + /* set field `preload' */ + lua_newtable(L); + lua_setfield(L, -2, "preload"); + lua_pushvalue(L, LUA_GLOBALSINDEX); + 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 9522b6e812..acde82ccdf 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,15 +1,17 @@ /* -** $Id: lobject.c,v 1.97 2003/04/03 13:35:34 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 */ #include #include +#include #include #include #define lobject_c +#define LUA_CORE #include "lua.h" @@ -21,63 +23,59 @@ #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 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 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); } 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, + 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, 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: return 1; case LUA_TNUMBER: - return 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: @@ -91,35 +89,40 @@ int luaO_rawequalObj (const TObject *t1, const TObject *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 */ - while (isspace((unsigned char)(*endptr))) 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? */ - *result = res; return 1; } 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); } -/* 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, ""); 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': - pushstr(L, va_arg(argp, char *)); + case 's': { + const char *s = va_arg(argp, char *); + if (s == NULL) s = "(null)"; + pushstr(L, s); break; + } case 'c': { char buff[2]; buff[0] = cast(char, va_arg(argp, int)); @@ -127,24 +130,40 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { pushstr(L, buff); break; } - case 'd': - setnvalue(L->top, cast(lua_Number, va_arg(argp, int))); + case 'd': { + 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))); + } + case 'f': { + setnvalue(L->top, cast_num(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: 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; } 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); } @@ -160,26 +179,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(" `...' "); + 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"); /* 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 321a7e06c1..8ce4405b6a 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,26 +1,33 @@ /* -** $Id: lobject.h,v 1.159 2003/03/18 12:50:04 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 */ + #ifndef lobject_h #define lobject_h +#include + + #include "llimits.h" #include "lua.h" /* 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_TPROTO (LAST_TAG+1) +#define LUA_TUPVAL (LAST_TAG+2) +#define LUA_TDEADKEY (LAST_TAG+3) /* @@ -58,12 +65,14 @@ typedef union { /* -** Lua values (or `tagged objects') +** Tagged Values */ -typedef struct lua_TObject { - int tt; - Value value; -} TObject; + +#define TValuefields Value value; int tt + +typedef struct lua_TValue { + TValuefields; +} TValue; /* Macros to test type */ @@ -82,8 +91,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 +102,66 @@ 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 setnvalue(obj,x) \ - { TObject *i_o=(obj); i_o->tt=LUA_TNUMBER; i_o->value.n=(x); } +#define setnilvalue(obj) ((obj)->tt=LUA_TNIL) -#define chgnvalue(obj,x) \ - check_exp(ttype(obj)==LUA_TNUMBER, (obj)->value.n=(x)) +#define setnvalue(obj,x) \ + { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; } #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); } - -#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); } + { TValue *i_o=(obj); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; } -#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 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 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 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 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 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 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 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 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->value = o2->value; o1->tt=o2->tt; \ + checkliveness(G(L),o1); } /* @@ -155,6 +173,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 +190,7 @@ typedef struct lua_TObject { -typedef TObject *StkId; /* index to stack elements */ +typedef TValue *StkId; /* index to stack elements */ /* @@ -181,7 +201,7 @@ typedef union TString { struct { CommonHeader; lu_byte reserved; - lu_hash hash; + unsigned int hash; size_t len; } tsv; } TString; @@ -197,6 +217,7 @@ typedef union Udata { struct { CommonHeader; struct Table *metatable; + struct Table *env; size_t len; } uv; } Udata; @@ -209,7 +230,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 */ @@ -222,7 +243,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; @@ -231,6 +253,12 @@ typedef struct Proto { } 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 */ @@ -245,8 +273,14 @@ 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 */ + union { + TValue value; /* the value (when closed) */ + struct { /* double linked list (when open) */ + struct UpVal *prev; + struct UpVal *next; + } l; + } u; } UpVal; @@ -255,19 +289,19 @@ 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; lua_CFunction f; - TObject upvalue[1]; + TValue upvalue[1]; } CClosure; typedef struct LClosure { ClosureHeader; struct Proto *p; - TObject g; /* global table for this closure */ UpVal *upvals[1]; } LClosure; @@ -286,10 +320,18 @@ typedef union Closure { ** Tables */ +typedef union TKey { + struct { + TValuefields; + struct Node *next; /* for chaining */ + } nk; + TValue tvk; +} TKey; + + typedef struct Node { - TObject i_key; - TObject i_val; - struct Node *next; /* for chaining */ + TValue i_val; + TKey i_key; } Node; @@ -298,9 +340,9 @@ typedef struct Table { lu_byte flags; /* 1<

    lsizenode)) +#define luaO_nilobject (&luaO_nilobject_) -extern const TObject luaO_nilobject; - -int luaO_log2 (unsigned int x); -int luaO_int2fb (unsigned int x); -#define fb2int(x) (((x) & 7) << ((x) >> 3)) +LUAI_DATA const TValue luaO_nilobject_; -int luaO_rawequalObj (const TObject *t1, const TObject *t2); -int luaO_str2d (const char *s, lua_Number *result); +#define ceillog2(x) (luaO_log2((x)-1) + 1) -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, size_t len); #endif + diff --git a/src/lopcodes.c b/src/lopcodes.c index 993e426d35..bf9cd522c2 100644 --- a/src/lopcodes.c +++ b/src/lopcodes.c @@ -1,22 +1,19 @@ /* -** $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.37 2005/11/08 19:45:36 roberto Exp $ ** See Copyright Notice in lua.h */ #define lopcodes_c +#define LUA_CORE -#include "lua.h" -#include "lobject.h" #include "lopcodes.h" -#ifdef LUA_OPNAMES +/* ORDER OP */ -const char *const luaP_opnames[] = { +const char *const luaP_opnames[NUM_OPCODES+1] = { "MOVE", "LOADK", "LOADBOOL", @@ -33,70 +30,73 @@ const char *const luaP_opnames[] = { "SUB", "MUL", "DIV", + "MOD", "POW", "UNM", "NOT", + "LEN", "CONCAT", "JMP", "EQ", "LT", "LE", "TEST", + "TESTSET", "CALL", "TAILCALL", "RETURN", "FORLOOP", + "FORPREP", "TFORLOOP", - "TFORPREP", "SETLIST", - "SETLISTO", "CLOSE", - "CLOSURE" + "CLOSURE", + "VARARG", + NULL }; -#endif - -#define opmode(t,b,bk,ck,sa,k,m) (((t)<>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)< 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)) */ 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)*/ -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 with C == 0). + + (*) In OP_RETURN, if (B == 0) then return up to `top' - (3) 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 - (4) All `skips' (pc++) assume that next instruction is a jump + (*) For comparisons, A specifies what condition the test should accept + (true or false). + + (*) All `skips' (pc++) assume that next instruction is a jump ===========================================================================*/ /* -** masks for instruction properties +** masks for instruction properties. The format is: +** bits 0-1: op mode +** bits 2-3: C arg mode +** bits 4-5: B arg mode +** bit 6: instruction set register A +** bit 7: operator is a test */ -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 */ - -}; +enum OpArgMask { + OpArgN, /* argument is not used */ + OpArgU, /* argument is used */ + OpArgR, /* argument is a register or a jump offset */ + OpArgK /* argument is a constant or register/constant */ +}; -extern const lu_byte luaP_opmodes[NUM_OPCODES]; - -#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 3)) -#define testOpMode(m, b) (luaP_opmodes[m] & (1 << (b))) +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)) +#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 +LUAI_DATA 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/loslib.c b/src/loslib.c new file mode 100644 index 0000000000..509d7b72e4 --- /dev/null +++ b/src/loslib.c @@ -0,0 +1,238 @@ +/* +** $Id: loslib.c,v 1.17 2006/01/27 13:54:31 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 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; + } + 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 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); +} + + +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 os_tmpname (lua_State *L) { + 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; +} + + +static int os_getenv (lua_State *L) { + lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ + return 1; +} + + +static int os_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_pushinteger(L, value); + lua_setfield(L, -2, key); +} + +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); +} + +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 " LUA_QS " missing in date table", key); + res = d; + } + lua_pop(L, 1); + return res; +} + + +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); + 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, LUA_QL("date") " format too long"); + } + return 1; +} + + +static int os_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, (lua_Number)t); + return 1; +} + + +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; +} + +/* }====================================================== */ + + +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", + "numeric", "time", NULL}; + const char *l = lua_tostring(L, 1); + 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; +} + + +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", 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} +}; + +/* }====================================================== */ + + + +LUALIB_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 99bd3020e7..b40ee794fe 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.40 2005/12/22 16:19:56 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -8,11 +8,13 @@ #include #define lparser_c +#define LUA_CORE #include "lua.h" #include "lcode.h" #include "ldebug.h" +#include "ldo.h" #include "lfunc.h" #include "llex.h" #include "lmem.h" @@ -25,12 +27,11 @@ -#define getlocvar(fs, i) ((fs)->f->locvars[(fs)->actvar[i]]) +#define hasmultret(k) ((k) == VCALL || (k) == VVARARG) +#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--) +#define luaY_checklimit(fs,v,l,m) if ((v)>(l)) errorlimit(fs,l,m) /* @@ -39,9 +40,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; @@ -53,33 +54,32 @@ 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 */ +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); } - 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 error_expected (LexState *ls, int token) { + luaX_syntaxerror(ls, + luaO_pushfstring(ls->L, LUA_QS " expected", luaX_token2str(ls, token))); } -static void error_expected (LexState *ls, int token) { - luaX_syntaxerror(ls, - 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); } static int testnext (LexState *ls, int c) { if (ls->t.token == c) { - next(ls); + luaX_next(ls); return 1; } else return 0; @@ -87,10 +87,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); + luaX_next(ls); +} + #define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); } @@ -102,7 +107,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)); } } @@ -111,9 +116,9 @@ 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"); + check(ls, TK_NAME); ts = ls->t.seminfo.ts; - next(ls); + luaX_next(ls); return ts; } @@ -121,7 +126,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; } @@ -135,26 +140,33 @@ 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; luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, - LocVar, MAX_INT, ""); + 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); 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, LUAI_MAXVARS, "local variables"); + fs->actvar[fs->nactvar+n] = cast(unsigned short, registerlocalvar(ls, name)); } static void adjustlocalvars (LexState *ls, int nvars) { FuncState *fs = ls->fs; - fs->nactvar += nvars; + fs->nactvar = cast_byte(fs->nactvar + nvars); for (; nvars; nvars--) { getlocvar(fs, fs->nactvar - nvars).startpc = fs->pc; } @@ -168,32 +180,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); + if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->u.s.info) { + 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, LUAI_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_byte(v->k); + fs->upvalues[f->nups].info = cast_byte(v->u.s.info); return f->nups++; } @@ -215,46 +221,46 @@ 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->u.s.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->u.s.info = luaK_stringK(fs, varname); /* info points to global name */ } 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 */ @@ -267,19 +273,16 @@ 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 enterlevel (LexState *ls) { + if (++ls->L->nCcalls > LUAI_MAXCCALLS) + luaX_lexerror(ls, "chunk has too many syntax levels", 0); } -static void enterblock (FuncState *fs, BlockCnt *bl, int isbreakable) { +#define leavelevel(ls) ((ls)->L->nCcalls--) + + +static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) { bl->breaklist = NO_JUMP; bl->isbreakable = isbreakable; bl->nactvar = fs->nactvar; @@ -296,6 +299,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); @@ -305,10 +309,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 +325,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->lasttarget = -1; 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); } @@ -344,12 +357,12 @@ 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); 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,23 +373,26 @@ 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 */ + funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */ + luaX_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); - lua_assert(lexstate.nestlevel == 0); + lua_assert(lexstate.fs == NULL); return funcstate.f; } @@ -387,23 +403,23 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff) { /*============================================================*/ -static void luaY_field (LexState *ls, expdesc *v) { +static void field (LexState *ls, expdesc *v) { /* field -> ['.' | ':'] NAME */ 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); } -static void luaY_index (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); - check(ls, ']'); + checknext(ls, ']'); } @@ -429,17 +445,17 @@ 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"); - cc->nh++; + luaY_checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); checkname(ls, &key); } else /* ls->t.token == '[' */ - luaY_index(ls, &key); - check(ls, '='); + yindex(ls, &key); + cc->nh++; + 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 */ } @@ -449,31 +465,30 @@ 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->u.s.info, cc->na, cc->tostore); /* flush */ cc->tostore = 0; /* no more items pending */ - fs->freereg = cc->t->info + 1; /* free registers */ } } 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); + if (hasmultret(cc->v.k)) { + luaK_setmultret(fs, &cc->v); + 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_codeABx(fs, OP_SETLIST, cc->t->info, cc->na-1); + luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore); } - 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"); + luaY_checklimit(ls->fs, cc->na, MAXARG_Bx, "items in a constructor"); cc->na++; cc->tostore++; } @@ -490,15 +505,14 @@ 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 */ if (ls->t.token == '}') break; 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 @@ -518,7 +532,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 */ } /* }====================================================================== */ @@ -527,18 +541,34 @@ 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; - default: luaX_syntaxerror(ls, " or `...' expected"); + case TK_NAME: { /* param -> NAME */ + 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; + break; + } + default: luaX_syntaxerror(ls, " or " LUA_QL("...") " expected"); } - } while (!dots && testnext(ls, ',')); + } while (!f->is_vararg && testnext(ls, ',')); } - code_params(ls, nparams, dots); + adjustlocalvars(ls, nparams); + f->numparams = cast_byte(fs->nactvar - (f->is_vararg & VARARG_HASARG)); + luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ } @@ -546,13 +576,16 @@ 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"); + new_fs.f->linedefined = line; + checknext(ls, '('); + if (needself) { + new_localvarliteral(ls, "self", 0); + adjustlocalvars(ls, 1); + } parlist(ls); - check(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); @@ -581,12 +614,12 @@ 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 { explist1(ls, &args); - luaK_setcallreturns(fs, &args, LUA_MULTRET); + luaK_setmultret(fs, &args); } check_match(ls, ')', '(', line); break; @@ -597,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: { @@ -606,8 +639,8 @@ static void funcargs (LexState *ls, expdesc *f) { } } lua_assert(f->k == VNONRELOC); - base = f->info; /* base register for call */ - if (args.k == VCALL) + base = f->u.s.info; /* base register for call */ + if (hasmultret(args.k)) nparams = LUA_MULTRET; /* open call */ else { if (args.k != VVOID) @@ -635,28 +668,16 @@ 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); 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); + singlevar(ls, v); return; } -#endif default: { luaX_syntaxerror(ls, "unexpected symbol"); return; @@ -673,19 +694,19 @@ 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; } case ':': { /* `:' NAME funcargs */ expdesc key; - next(ls); + luaX_next(ls); checkname(ls, &key); luaK_self(fs, v, &key); funcargs(ls, v); @@ -703,48 +724,53 @@ 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)); - next(ls); /* must use `seminfo' before `next' */ + init_exp(v, VKNUM, 0); + v->u.nval = ls->t.seminfo.r; 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 " 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; } case '{': { /* constructor */ constructor(ls, v); - break; + return; } case TK_FUNCTION: { - next(ls); + luaX_next(ls); body(ls, v, 0, ls->linenumber); - break; + return; } default: { primaryexp(ls, v); - break; + return; } } + luaX_next(ls); } @@ -752,6 +778,7 @@ static UnOpr getunopr (int op) { switch (op) { case TK_NOT: return OPR_NOT; case '-': return OPR_MINUS; + case '#': return OPR_LEN; default: return OPR_NOUNOPR; } } @@ -761,8 +788,9 @@ 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; case TK_CONCAT: return OPR_CONCAT; case TK_NE: return OPR_NE; @@ -782,9 +810,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) */ }; @@ -793,29 +821,29 @@ 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, int limit) { +static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) { BinOpr op; UnOpr uop; 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); } 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); + luaX_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 +853,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); } /* }==================================================================== */ @@ -882,18 +910,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); } } @@ -913,7 +941,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); @@ -921,7 +949,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 */ } @@ -931,88 +959,74 @@ 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); + return v.f; } -/* -** 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 +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[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 > 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 */ + luaX_next(ls); /* skip WHILE */ + whileinit = luaK_getlabel(fs); + condexit = cond(ls); enterblock(fs, &bl, 1); - check(ls, TK_DO); - blockinit = luaK_getlabel(fs); + checknext(ls, TK_DO); 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); - expdesc v; - 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 */ + luaX_next(ls); /* skip REPEAT */ + chunk(ls); check_match(ls, TK_UNTIL, TK_REPEAT, line); - cond(ls, &v); - luaK_patchlist(fs, v.f, 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 */ } @@ -1027,33 +1041,37 @@ 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 */ - check(ls, TK_DO); - enterblock(fs, &bl, 1); /* loop block */ - prep = luaK_getlabel(fs); + adjustlocalvars(ls, 3); /* control variables */ + checknext(ls, TK_DO); + 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); 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); - check(ls, '='); + new_localvarliteral(ls, "(for index)", 0); + new_localvarliteral(ls, "(for limit)", 1); + new_localvarliteral(ls, "(for step)", 2); + new_localvar(ls, varname, 3); + checknext(ls, '='); exp1(ls); /* initial value */ - check(ls, ','); + checknext(ls, ','); exp1(ls); /* limit */ if (testnext(ls, ',')) exp1(ls); /* optional step */ @@ -1061,79 +1079,81 @@ 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); + checknext(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 */ - next(ls); /* skip `for' */ + enterblock(fs, &bl, 1); /* scope for loop and control variables */ + luaX_next(ls); /* skip `for' */ varname = str_checkname(ls); /* first variable name */ 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); + 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 */ - next(ls); /* skip IF or ELSEIF */ - cond(ls, v); - check(ls, TK_THEN); + int condexit; + luaX_next(ls); /* skip IF or ELSEIF */ + condexit = cond(ls); + checknext(ls, TK_THEN); block(ls); /* `then' part */ + return condexit; } 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); - next(ls); /* skip ELSE (after patch, for correct line info) */ + luaK_patchtohere(fs, flist); + luaX_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); } @@ -1175,12 +1195,12 @@ 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 == '.') - luaY_field(ls, v); + field(ls, v); if (ls->t.token == ':') { needself = 1; - luaY_field(ls, v); + field(ls, v); } return needself; } @@ -1190,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); @@ -1203,9 +1223,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); @@ -1218,14 +1237,14 @@ 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 { 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); } @@ -1242,25 +1261,7 @@ static void retstat (LexState *ls) { } } } - luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); -} - - -static void breakstat (LexState *ls) { - /* stat -> BREAK [NAME] */ - 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); } @@ -1276,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; @@ -1294,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 @@ -1306,6 +1307,7 @@ static int statement (LexState *ls) { return 1; /* must be last statement */ } case TK_BREAK: { /* stat -> breakstat */ + luaX_next(ls); /* skip BREAK */ breakstat(ls); return 1; /* must be last statement */ } @@ -1324,7 +1326,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..d5e6e81d0d 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.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' */ @@ -30,17 +31,27 @@ 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 { 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; +typedef struct upvaldesc { + lu_byte k; + lu_byte info; +} upvaldesc; + + struct BlockCnt; /* defined in lparser.c */ @@ -58,14 +69,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' */ - int nactvar; /* number of active local variables */ - expdesc upvalues[MAXUPVALUES]; /* upvalues */ - int actvar[MAXVARS]; /* declared-variable stack */ + 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 */ } FuncState; -Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff); +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 b593658def..77e93fbdfa 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,13 +1,14 @@ /* -** $Id: lstate.c,v 1.123 2003/04/03 13:35:34 roberto Exp $ +** $Id: lstate.c,v 2.35 2005/10/06 20:46:25 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ -#include +#include #define lstate_c +#define LUA_CORE #include "lua.h" @@ -23,63 +24,43 @@ #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) + LUAI_EXTRASPACE) +#define fromstate(l) (cast(lu_byte *, (l)) - LUAI_EXTRASPACE) +#define tostate(l) (cast(lua_State *, cast(lu_byte *, l) + LUAI_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); + /* 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; - L1->ci->state = CI_C; /* not a Lua function */ + /* 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; } 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,85 +68,65 @@ 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); + global_State *g = G(L); 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 */ + 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); luaS_fix(luaS_newliteral(L, MEMERRMSG)); - g->GCthreshold = 4*G(L)->nblocks; + g->GCthreshold = 4*g->totalbytes; } -static void preinit_state (lua_State *L) { +static void preinit_state (lua_State *L, global_State *g) { + G(L) = 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->status = 0; L->base_ci = L->ci = NULL; + L->savedpc = NULL; 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 */ - 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_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 *); + 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->totalbytes == sizeof(LG)); + (*g->frealloc)(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))); + luaC_link(L, obj2gco(L1), LUA_TTHREAD); + 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 */ + L1->hookmask = L->hookmask; + L1->basehookcount = L->basehookcount; + L1->hook = L->hook; + resethookcount(L1); + lua_assert(iswhite(obj2gco(L1))); return L1; } @@ -173,26 +134,58 @@ 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); - freestate(L, L1); + luaM_freemem(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) { + int i; + 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; + L->tt = LUA_TTHREAD; + g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT); + L->marked = luaC_white(g); + 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 = 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 = 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->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) { + /* memory allocation error: free partial state */ + close_state(L); + L = NULL; } - lua_userstateopen(L); + else + luai_userstateopen(L); return L; } @@ -204,10 +197,11 @@ 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); /* 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..d296a4cab9 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.24 2006/02/06 18:27:59 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -14,42 +14,15 @@ #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 */ -/* default meta table (both for tables and udata) */ -#define defaultmeta(L) (&G(L)->_defaultmeta) - /* 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 */ @@ -64,7 +37,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; @@ -73,36 +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 */ - 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; + const Instruction *savedpc; + int nresults; /* expected number of results from this function */ + int tailcalls; /* number of tail calls lost under this entry */ } 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)) +#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)) /* @@ -110,17 +67,29 @@ 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 */ - GCObject *tmudata; /* list of userdata to be GC */ + lua_Alloc frealloc; /* function to reallocate memory */ + 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' */ + 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; - 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 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 */ - TObject _registry; - TObject _defaultmeta; + TValue l_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 */ + struct Table *mt[NUM_TAGS]; /* metatables for basic types */ TString *tmname[TM_N]; /* array with tag-method names */ } global_State; @@ -130,24 +99,26 @@ 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; 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 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 hookinit; int basehookcount; int hookcount; lua_Hook hook; - TObject _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; struct lua_longjmp *errorJmp; /* current error recover point */ @@ -174,22 +145,24 @@ 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); -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.c b/src/lstring.c index 8cbddbd218..4319930c96 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.8 2005/12/22 16:19:56 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,25 +19,23 @@ -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 = luaM_newvector(L, newsize, GCObject *); - stringtable *tb = &G(L)->strt; + 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; 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)); + lua_assert(cast_int(h%newsize) == lmod(h, newsize)); p->gch.next = newhash[h1]; /* chain it */ newhash[h1] = p; p = next; @@ -48,12 +47,16 @@ void luaS_resize (lua_State *L, int newsize) { } -static TString *newlstr (lua_State *L, const char *str, size_t l, lu_hash h) { - TString *ts = cast(TString *, luaM_malloc(L, sizestring(l))); +static TString *newlstr (lua_State *L, const char *str, size_t l, + unsigned int h) { + 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 = 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 +64,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,32 +74,38 @@ 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 */ - 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) { - 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 */ } -Udata *luaS_newudata (lua_State *L, size_t s) { +Udata *luaS_newudata (lua_State *L, size_t s, Table *e) { Udata *u; - u = cast(Udata *, luaM_malloc(L, sizeudata(s))); - u->uv.marked = (1<<1); /* is not finalized */ + 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; - u->uv.metatable = hvalue(defaultmeta(L)); - /* chain it on udata list */ - u->uv.next = G(L)->rootudata; - G(L)->rootudata = valtogco(u); + 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 be5a1e3767..1d2e91ea13 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.43 2005/04/25 19:24:10 roberto Exp $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -8,26 +8,24 @@ #define lstring_h +#include "lgc.h" #include "lobject.h" #include "lstate.h" +#define sizestring(s) (sizeof(union TString)+((s)->len+1)*sizeof(char)) -#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 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) ((s)->tsv.marked |= (1<<4)) +#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); -void luaS_freeall (lua_State *L); -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/lib/lstrlib.c b/src/lstrlib.c similarity index 62% rename from src/lib/lstrlib.c rename to src/lstrlib.c index 8752e3aba3..84478fd106 100644 --- a/src/lib/lstrlib.c +++ b/src/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.130 2005/12/29 15:32:11 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,35 +21,31 @@ /* 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_checklstring(L, 1, &l); - lua_pushnumber(L, (lua_Number)l); + lua_pushinteger(L, l); return 1; } -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_checklong(L, 2), l); - sint32 end = posrelat(luaL_optlong(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, ""); @@ -56,6 +53,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_addchar(&b, s[l]); + luaL_pushresult(&b); + return 1; +} + + static int str_lower (lua_State *L) { size_t l; size_t i; @@ -63,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; i l) /* index out of range? */ - return 0; /* no answer */ - lua_pushnumber(L, uchar(s[pos-1])); - return 1; + 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; + 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"); + luaL_checkstack(L, n, "string slice too long"); + for (i=0; iL, "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; @@ -235,9 +248,9 @@ 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, *p)) + if (match_class(c, uchar(*p))) return sig; } else if ((*(p+1) == '-') && (p+2 < ec)) { @@ -251,10 +264,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 L_ESC: return match_class(c, uchar(*(p+1))); case '[': return matchbracketclass(c, p, ep-1); default: return (uchar(*p) == c); } @@ -286,8 +299,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) { @@ -305,7 +318,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; } @@ -316,7 +329,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; @@ -360,7 +373,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); @@ -371,8 +384,9 @@ 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"); - ep = luaI_classend(ms, p); /* points to what is next */ + 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; @@ -380,7 +394,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) */ } @@ -397,8 +411,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; @@ -448,45 +462,49 @@ static const char *lmemfind (const char *s1, size_t l1, } -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 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 */ } -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); - sint32 init = posrelat(luaL_optlong(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; - if (lua_toboolean(L, 4) || /* explicit request? */ - strpbrk(p, SPECIALS) == NULL) { /* or no special characters? */ + else if ((size_t)(init) > l1) init = (ptrdiff_t)l1; + 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) { - 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,35 +519,49 @@ 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 */ - return push_captures(&ms, NULL, 0) + 2; + if (find) { + lua_pushinteger(L, s1-s+1); /* start */ + lua_pushinteger(L, res-s); /* end */ + return push_captures(&ms, NULL, 0) + 2; + } + else + return push_captures(&ms, s1, res); } - } while (s1++L; - if (lua_isstring(L, 3)) { - const char *news = lua_tostring(L, 3); - size_t l = lua_strlen(L, 3); - 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_putchar(b, news[i]); - 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 */ } @@ -592,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; @@ -605,18 +663,18 @@ 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 */ else if (src < ms.src_end) - luaL_putchar(&b, *src++); + luaL_addchar(&b, *src++); else break; if (anchor) break; } luaL_addlstring(&b, src, ms.src_end-src); luaL_pushresult(&b); - lua_pushnumber(L, (lua_Number)n); /* number of substitutions */ + lua_pushinteger(L, n); /* number of substitutions */ return 2; } @@ -625,19 +683,24 @@ 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 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, '"'); + 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': { @@ -645,39 +708,46 @@ static void luaI_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, '"'); } - -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] = '%'; - 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; @@ -686,40 +756,43 @@ static int str_format (lua_State *L) { luaL_Buffer b; luaL_buffinit(L, &b); while (strfrmt < strfrmt_end) { - if (*strfrmt != '%') - luaL_putchar(&b, *strfrmt++); - else if (*++strfrmt == '%') - luaL_putchar(&b, *strfrmt++); /* %% */ + if (*strfrmt != L_ESC) + luaL_addchar(&b, *strfrmt++); + else if (*++strfrmt == L_ESC) + luaL_addchar(&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); + 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': { - luaI_addquoted(L, &b, arg); - continue; /* skip the `addsize' at the end */ + addquoted(L, &b, arg); + continue; /* skip the 'addsize' at the end */ } 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); @@ -732,7 +805,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)); @@ -743,28 +816,48 @@ static int str_format (lua_State *L) { } -static const luaL_reg strlib[] = { - {"len", str_len}, - {"sub", str_sub}, - {"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} }; +static void createmetatable (lua_State *L) { + 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 */ + 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 */ +} + + /* ** 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 0c64adb10a..bc91cacd63 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.32 2006/01/18 11:49:02 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -15,15 +15,14 @@ ** 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 #include #define ltable_c +#define LUA_CORE #include "lua.h" @@ -39,20 +38,13 @@ /* ** max size of array part is 2^MAXBITS */ -#if BITS_INT > 26 -#define MAXBITS 24 +#if LUAI_BITSINT > 26 +#define MAXBITS 26 #else -#define MAXBITS (BITS_INT-2) +#define MAXBITS (LUAI_BITSINT-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 MAXASIZE (1 << MAXBITS) #define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) @@ -74,7 +66,16 @@ /* ** 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)) + + + +#define dummynode (&dummynode_) + +static const Node dummynode_ = { + {{NULL}, LUA_TNIL}, /* value */ + {{{NULL}, LUA_TNIL, NULL}} /* key */ +}; /* @@ -87,7 +88,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 +97,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) { +static Node *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 +117,12 @@ 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) { 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)) + lua_number2int(k, n); + if (luai_numeq(cast_num(k), n)) return k; } return -1; /* `key' did not match some condition */ @@ -130,39 +132,46 @@ static int arrayindex (const TObject *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 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); - if (0 <= i && i <= t->sizearray) { /* is `key' inside array part? */ + 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 */ + 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 */ + /* hash elements are numbered after array ones */ + return i + t->sizearray; + } + else n = gnext(n); + } while (n); + luaG_runerror(L, "invalid key to " LUA_QL("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)); - setobj2s(key+1, &t->array[i]); + setnvalue(key, cast_num(i+1)); + 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, key2tval(gnode(t, i))); + setobj2s(L, key+1, gval(gnode(t, i))); return 1; } } @@ -177,95 +186,111 @@ 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 */ } - lua_assert(na <= *narray && *narray <= ntotal); - *nhash = ntotal - na; - *narray = (n == -1) ? 0 : twoto(n); - lua_assert(na <= *narray && na >= *narray/2); + *narray = n; + lua_assert(*narray/2 <= na && na <= *narray); + return na; } -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 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; + } + else + return 0; +} + + +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(gkey(n)); - if (k >= 0) { /* 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; } 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; } -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) */ +static void setnodevector (lua_State *L, Table *t, int size) { + int lsize; + if (size == 0) { /* no elements to hash part? */ + t->node = cast(Node *, 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].next = 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->firstfree = gnode(t, size-1); /* first free position to be used */ + t->lsizenode = cast_byte(lsize); + t->lastfree = gnode(t, size); /* all positions are free */ } @@ -273,48 +298,54 @@ 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(G(L)->dummynode->next == 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 */ 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 */ + /* re-insert elements from 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, key2tval(old)), gval(old)); } - if (oldhsize) + if (nold != 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 */ - resize(L, t, nasize, luaO_log2(nhsize)+1); +void luaH_resizearray (lua_State *L, Table *t, int nasize) { + int nsize = (t->node == 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); } @@ -324,49 +355,38 @@ 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, valtogco(t), LUA_TTABLE); - t->metatable = hvalue(defaultmeta(L)); - t->flags = cast(lu_byte, ~0); + luaC_link(L, obj2gco(t), LUA_TTABLE); + 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 = NULL; + t->node = cast(Node *, 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 != dummynode) luaM_freearray(L, t->node, sizenode(t), Node); - luaM_freearray(L, t->array, t->sizearray, TObject); - luaM_freelem(L, t); + luaM_freearray(L, t->array, t->sizearray, TValue); + luaM_free(L, 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) ?? +static Node *getfreepos (Table *t) { + while (t->lastfree-- > t->node) { + if (ttisnil(gkey(t->lastfree))) + return t->lastfree; } - lua_assert(ttisnil(gval(node))); - setnilvalue(gkey(e)); /* clear node `e' */ - e->next = NULL; + return NULL; /* could not find a free place */ } -#endif + /* @@ -376,76 +396,55 @@ 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; - 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 */ - Node *n = t->firstfree; /* get a free place */ +static TValue *newkey (lua_State *L, Table *t, const TValue *key) { + 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 != 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 (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(gkey(mp), key); /* write barrier */ + 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(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; - } + return gval(mp); } /* ** search function for integers */ -const TObject *luaH_getnum (Table *t, int key) { - if (1 <= key && key <= t->sizearray) +const TValue *luaH_getnum (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]; 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)) && nvalue(gkey(n)) == nk) + if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk)) return gval(n); /* that's it */ - else n = n->next; + else n = gnext(n); } while (n); - return &luaO_nilobject; + return luaO_nilobject; } } @@ -453,57 +452,137 @@ 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; + else n = gnext(n); } while (n); - return &luaO_nilobject; + return luaO_nilobject; } /* ** 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_TNIL: return luaO_nilobject; + case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key)); case LUA_TNUMBER: { int k; - lua_number2int(k, (nvalue(key))); - if (cast(lua_Number, k) == nvalue(key)) /* is an integer index? */ + 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 */ /* else go through */ } - default: return luaH_getany(t, key); + default: { + 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; + } } } -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); + if (p != luaO_nilobject) + 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) && luai_numisnan(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); +TValue *luaH_setnum (lua_State *L, Table *t, int key) { + const TValue *p = luaH_getnum(t, key); + if (p != luaO_nilobject) + return cast(TValue *, p); else { - TObject k; - setnvalue(&k, cast(lua_Number, key)); + 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); + } +} + + +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))) { + 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++; + 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; + 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 == 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 3d4d753c3c..09193cdbe0 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.10 2006/01/10 13:13:06 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -11,21 +11,30 @@ #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.nk.next) +#define key2tval(n) (&(n)->i_key.tvk) -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 Table *t, const TObject *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); + + +#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/lib/ltablib.c b/src/ltablib.c similarity index 67% rename from src/lib/ltablib.c rename to src/ltablib.c index c9bb2d1b7e..453b23b378 100644 --- a/src/lib/ltablib.c +++ b/src/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.38 2005/10/23 17:38:15 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -8,6 +8,7 @@ #include #define ltablib_c +#define LUA_LIB #include "lua.h" @@ -18,13 +19,13 @@ #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); - for (i=1; i<=n; i++) { + 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)) @@ -35,13 +36,11 @@ 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 */ - 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 */ @@ -50,74 +49,102 @@ static int luaB_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; } -static int luaB_getn (lua_State *L) { - lua_pushnumber(L, (lua_Number)aux_getn(L, 1)); +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); +#ifndef luaL_setn luaL_setn(L, 1, luaL_checkint(L, 2)); - return 0; +#else + luaL_error(L, LUA_QL("setn") " is obsolete"); +#endif + 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; +static int tinsert (lua_State *L) { + 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 */ - 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] */ + 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")); + } } - lua_pushvalue(L, v); + luaL_setn(L, 1, e); /* new size */ 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 */ +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' */ + luaL_setn(L, 1, e - 1); /* t.n = n-1 */ lua_rawgeti(L, 1, pos); /* result = t[pos] */ - for ( ;pos -#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 1b3e515e57..097b815ad3 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.8 2006/01/10 12:50:00 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -8,6 +8,7 @@ #include #define ltm_c +#define LUA_CORE #include "lua.h" @@ -21,7 +22,8 @@ const char *const luaT_typenames[] = { "nil", "boolean", "userdata", "number", - "string", "table", "function", "userdata", "thread" + "string", "table", "function", "userdata", "thread", + "proto", "upval" }; @@ -29,8 +31,8 @@ void luaT_init (lua_State *L) { static const char *const luaT_eventname[] = { /* ORDER TM */ "__index", "__newindex", "__gc", "__mode", "__eq", - "__add", "__sub", "__mul", "__div", - "__pow", "__unm", "__lt", "__le", + "__add", "__sub", "__mul", "__div", "__mod", + "__pow", "__unm", "__len", "__lt", "__le", "__concat", "__call" }; int i; @@ -45,26 +47,29 @@ 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<flags |= cast_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 = G(L)->mt[ttype(o)]; } + return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject); } diff --git a/src/ltm.h b/src/ltm.h index 8eebfd3dc3..866c79668d 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.6 2005/06/06 13:30:25 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_LEN, TM_LT, TM_LE, TM_CONCAT, @@ -36,16 +38,17 @@ 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) +LUAI_DATA const char *const luaT_typenames[]; -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); -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 new file mode 100644 index 0000000000..6df527db30 --- /dev/null +++ b/src/lua.c @@ -0,0 +1,377 @@ +/* +** $Id: lua.c,v 1.157 2005/12/29 16:23:32 roberto Exp $ +** Lua stand-alone interpreter +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include + +#define lua_c + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + + +static lua_State *globalL = NULL; + +static const char *progname = LUA_PROGNAME; + + + +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) { + signal(i, SIG_DFL); /* if another SIGINT happens before lstop, + terminate process (default action) */ + lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); +} + + +static void print_usage (void) { + fprintf(stderr, + "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" + " -v show version information\n" + " -- stop handling options\n" + " - execute stdin and 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); +} + + +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)"; + l_message(progname, msg); + lua_pop(L, 1); + } + return status; +} + + +static int traceback (lua_State *L) { + lua_getfield(L, LUA_GLOBALSINDEX, "debug"); + if (!lua_istable(L, -1)) { + lua_pop(L, 1); + 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; +} + + +static int docall (lua_State *L, int narg, int clear) { + 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 */ + 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_VERSION " " LUA_COPYRIGHT); +} + + +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]); + lua_createtable(L, narg, n + 1); + for (i=0; i < argc; i++) { + lua_pushstring(L, argv[i]); + lua_rawseti(L, -2, i - n); + } + return narg; +} + + +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 (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 dolibrary (lua_State *L, const char *name) { + lua_getglobal(L, "require"); + lua_pushstring(L, name); + return report(L, lua_pcall(L, 1, 0, 0)); +} + + +static const char *get_prompt (lua_State *L, int firstline) { + const char *p; + 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 */ + return p; +} + + +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) { + lua_pop(L, 1); + return 1; + } + } + return 0; /* else... */ +} + + +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 (!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 (!pushline(L, 0)) /* no more input? */ + return -1; + 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, 1); + lua_remove(L, 1); /* remove line */ + return status; +} + + +static void dotty (lua_State *L) { + int status; + const char *oldprogname = progname; + progname = NULL; + 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); + if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) + 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); + fflush(stdout); + progname = oldprogname; +} + + +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 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 'l': + if (argv[i][2] == '\0') { + i++; + if (argv[i] == NULL) return -1; + } + 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; + } + 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; +} + + +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 dofile(L, init+1); + else + return dostring(L, init, "=LUA_INIT"); +} + + +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 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) + dotty(L); + else if (script == 0 && !has_e && !has_v) { + if (lua_stdin_is_tty()) { + print_version(); + dotty(L); + } + else dofile(L, NULL); /* executes stdin as a file */ + } + return 0; +} + + +int main (int argc, char **argv) { + int 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(L, status); + lua_close(L); + return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS; +} + diff --git a/src/lua.h b/src/lua.h new file mode 100644 index 0000000000..881f834555 --- /dev/null +++ b/src/lua.h @@ -0,0 +1,384 @@ +/* +** $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 +*/ + + +#ifndef lua_h +#define lua_h + +#include +#include + + +#include "luaconf.h" + + +#define LUA_VERSION "Lua 5.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" + + +/* mark for precompiled code (`Lua') */ +#define LUA_SIGNATURE "\033Lua" + +/* 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)) + + +/* thread status; 0 is OK */ +#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; + +typedef int (*lua_CFunction) (lua_State *L); + + +/* +** functions that read/write blocks when loading/dumping Lua chunks +*/ +typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); + +typedef int (*lua_Writer) (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 +*/ +#define LUA_TNONE (-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 + + + +/* minimum Lua stack available to a C function */ +#define LUA_MINSTACK 20 + + +/* +** generic extra include file +*/ +#if defined(LUA_USER_H) +#include LUA_USER_H +#endif + + +/* type of numbers in Lua */ +typedef LUA_NUMBER lua_Number; + + +/* type for integer functions */ +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_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 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_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 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); + + +/* +** 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); + + +/* +** 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); + + +/* +** `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_Reader reader, void *dt, + const char *chunkname); + +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_resume) (lua_State *L, int narg); +LUA_API int (lua_status) (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_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); + + +/* +** miscellaneous functions +*/ + +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 lua_Alloc (lua_getallocf) (lua_State *L, void **ud); +LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud); + + + +/* +** =============================================================== +** some useful macros +** =============================================================== +*/ + +#define lua_pop(L,n) lua_settop(L, -(n)-1) + +#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) + +#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) +#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_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 + + + +/* +** {====================================================================== +** 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 */ + + +/* Functions to be called by the debuger 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_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 *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 */ + int i_ci; /* active function */ +}; + +/* }====================================================================== */ + + +/****************************************************************************** +* 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 +* "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. +******************************************************************************/ + + +#endif diff --git a/src/luac.c b/src/luac.c new file mode 100644 index 0000000000..2dd76b7653 --- /dev/null +++ b/src/luac.c @@ -0,0 +1,196 @@ +/* +** $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 +*/ + +#include +#include +#include +#include + +#define luac_c +#define LUA_CORE + +#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 "lundump.h" + +#define PROGNAME "luac" /* default program name */ +#define OUTPUT PROGNAME ".out" /* default output file */ + +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; /* actual output file name */ +static const char* progname=PROGNAME; /* actual program name */ + +static void fatal(const char* message) +{ + fprintf(stderr,"%s: %s\n",progname,message); + exit(EXIT_FAILURE); +} + +static void cannot(const char* what) +{ + fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno)); + exit(EXIT_FAILURE); +} + +static void usage(const char* message) +{ + if (*message=='-') + fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message); + else + fprintf(stderr,"%s: %s\n",progname,message); + fprintf(stderr, + "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); + exit(EXIT_FAILURE); +} + +#define IS(s) (strcmp(argv[i],s)==0) + +static int doargs(int argc, char* argv[]) +{ + int i; + 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) +{ + if (n==1) + 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); + return f; + } +} + +static int writer(lua_State* L, const void* p, size_t size, void* u) +{ + UNUSED(L); + 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; + Proto* f; + int i; + if (!lua_checkstack(L,argc)) fatal("too many input files"); + for (i=0; i1); + if (dumping) + { + FILE* D= (output==NULL) ? stdout : fopen(output,"wb"); + if (D==NULL) cannot("open"); + lua_lock(L); + luaU_dump(L,f,writer,D,stripping); + lua_unlock(L); + 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/luaconf.h b/src/luaconf.h new file mode 100644 index 0000000000..97a3e30c0e --- /dev/null +++ b/src/luaconf.h @@ -0,0 +1,736 @@ +/* +** $Id: luaconf.h,v 1.81 2006/02/10 17:44:06 roberto Exp $ +** Configuration file for Lua +** See Copyright Notice in lua.h +*/ + + +#ifndef lconfig_h +#define lconfig_h + +#include +#include + + +/* +** ================================================================== +** Search for "@@" to find all configurable definitions. +** =================================================================== +*/ + + +/* +@@ 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 + + +#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 */ +#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 +@* 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. +*/ +#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. +*/ +#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" +#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_PATH_DEFAULT \ + "./?.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 + + +/* +@@ 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 + + +/* +@@ 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. +** 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 + +#endif + +/* more often than not the libs go together with the core */ +#define LUALIB_API LUA_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. +** 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 +#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_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 want a different size. +*/ +#define LUA_IDSIZE 60 + + +/* +** {================================================================== +** Stand-alone configuration +** =================================================================== +*/ + +#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. +*/ +#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. +*/ +#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(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 + +/* }================================================================== */ + + +/* +@@ 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. +*/ +#define LUAI_GCPAUSE 200 /* 200% (wait memory to double before next GC) */ + + +/* +@@ 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. +*/ +#define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */ + + + +/* +@@ 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. +*/ +#undef LUA_COMPAT_GETN + +/* +@@ 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'). +*/ +#undef LUA_COMPAT_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_VARARG + +/* +@@ 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_MOD + +/* +@@ 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 + +/* +@@ 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 +** 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 + + +/* +@@ 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 LUAI_BITSINT 16 +#elif INT_MAX > 2147483640L +/* 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 + + +/* +@@ 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 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 LUAI_UINT32 unsigned long +#define LUAI_INT32 long +#define LUAI_MAXINT32 LONG_MAX +#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. +*/ +#define LUAI_MAXCALLS 20000 + + +/* +@@ 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 LUAI_MAXCSTACK 2048 + + + +/* +** {================================================================== +** 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. +** =================================================================== +*/ + + +/* +@@ 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. +*/ +#define LUAL_BUFFERSIZE BUFSIZ + +/* }================================================================== */ + + + + +/* +** {================================================================== +@@ 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_NUMBER_DOUBLE +#define LUA_NUMBER double + +/* +@@ LUAI_UACNUMBER is the result of an 'usual argument conversion' +@* over a number. +*/ +#define LUAI_UACNUMBER double + + +/* +@@ 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)) + + +/* +@@ The luai_num* macros define the primitive operations over numbers. +*/ +#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)) +#define luai_numisnan(a) (!luai_numeq((a), (a))) +#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_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) \ + { 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 + +/* }================================================================== */ + + +/* +@@ 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 + + +/* +@@ 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_USE_POPEN) + +#define lua_popen(L,c,m) ((void)L, 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)) + +#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), 0) + +#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 + + + +/* =================================================================== */ + +/* +** Local configuration. You can use this space to add your redefinitions +** without modifying the main part of the file. +*/ + + + +#endif + diff --git a/src/lualib.h b/src/lualib.h new file mode 100644 index 0000000000..0c76232c0d --- /dev/null +++ b/src/lualib.h @@ -0,0 +1,53 @@ +/* +** $Id: lualib.h,v 1.36 2005/12/27 17:12:00 roberto Exp $ +** Lua standard libraries +** See Copyright Notice in lua.h +*/ + + +#ifndef lualib_h +#define lualib_h + +#include "lua.h" + + +/* Key to file-handle type */ +#define LUA_FILEHANDLE "FILE*" + + +#define LUA_COLIBNAME "coroutine" +LUALIB_API int (luaopen_base) (lua_State *L); + +#define LUA_TABLIBNAME "table" +LUALIB_API int (luaopen_table) (lua_State *L); + +#define LUA_IOLIBNAME "io" +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); + +#define LUA_MATHLIBNAME "math" +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_package) (lua_State *L); + + +/* open all previous libraries */ +LUALIB_API void (luaL_openlibs) (lua_State *L); + + + +#ifndef lua_assert +#define lua_assert(x) ((void)0) +#endif + + +#endif diff --git a/src/lundump.c b/src/lundump.c index 151a8507cc..7fc635eeb7 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,286 +1,223 @@ /* -** $Id: lundump.c,v 1.49 2003/04/07 20:34:20 lhf Exp $ -** load pre-compiled Lua chunks +** $Id: lundump.c,v 1.60 2006/02/16 15:53:49 lhf Exp $ +** load precompiled Lua chunks ** See Copyright Notice in lua.h */ +#include + #define lundump_c +#define LUA_CORE #include "lua.h" #include "ldebug.h" +#include "ldo.h" #include "lfunc.h" #include "lmem.h" -#include "lopcodes.h" +#include "lobject.h" #include "lstring.h" #include "lundump.h" #include "lzio.h" -#define LoadByte (lu_byte) ezgetc - typedef struct { lua_State* L; ZIO* Z; Mbuffer* b; - int swap; const char* name; } LoadState; -static void unexpectedEOZ (LoadState* S) -{ - luaG_runerror(S->L,"unexpected end of file in %s",S->name); -} +#ifdef LUAC_TRUST_BINARIES +#define IF(c,s) +#else +#define IF(c,s) if (c) error(S,s) -static int ezgetc (LoadState* S) +static void error(LoadState* S, const char* why) { - int c=zgetc(S->Z); - if (c==EOZ) unexpectedEOZ(S); - return c; + luaO_pushfstring(S->L,"%s: %s in precompiled chunk",S->name,why); + luaD_throw(S->L,LUA_ERRSYNTAX); } +#endif -static void ezread (LoadState* S, void* b, int n) -{ - int r=luaZ_read(S->Z,b,n); - if (r!=0) unexpectedEOZ(S); -} +#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) +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) luaG_runerror(S->L,"bad integer in %s",S->name); + 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(*f->code)); -} - -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=LoadString(S); - f->locvars[i].startpc=LoadInt(S); - f->locvars[i].endpc=LoadInt(S); - } -} - -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)); -} - -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); + int n=LoadInt(S); + f->code=luaM_newvector(S->L,n,Instruction); + f->sizecode=n; + LoadVector(S,f->code,n,sizeof(Instruction)); } -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); - 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]; - int t=LoadByte(S); + TValue* o=&f->k[i]; + int t=LoadChar(S); switch (t) { + case LUA_TNIL: + setnilvalue(o); + break; + case LUA_TBOOLEAN: + setbvalue(o,LoadChar(S)); + break; case LUA_TNUMBER: setnvalue(o,LoadNumber(S)); break; case LUA_TSTRING: - setsvalue2n(o,LoadString(S)); - break; - case LUA_TNIL: - setnilvalue(o); + setsvalue2n(S->L,o,LoadString(S)); break; default: - luaG_runerror(S->L,"bad constant type (%d) in %s",t,S->name); + 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); } -static Proto* LoadFunction (LoadState* S, TString* p) +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); + 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); 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 + LoadConstants(S,f); + LoadDebug(S,f); + 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) luaG_runerror(S->L,"bad signature in %s",S->name); -} - -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); -} - -#define TESTSIZE(s,w) TestSize(S,s,w) -#define V(v) v/16,v%16 - -static void LoadHeader (LoadState* S) -{ - int version; - lua_Number x,tx=TEST_NUMBER; - 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)); - 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) +static void LoadHeader(LoadState* S) { - LoadHeader(S); - return LoadFunction(S,NULL); + 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"); } /* ** 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* name) { LoadState S; - const char* s=zname(Z); - 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; - return LoadChunk(&S); + LoadHeader(&S); + return LoadFunction(&S,luaS_newliteral(L,"=?")); } /* -** 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; /* 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? */ } diff --git a/src/lundump.h b/src/lundump.h index c7e6959b30..58cca5d190 100644 --- a/src/lundump.h +++ b/src/lundump.h @@ -1,6 +1,6 @@ /* -** $Id: lundump.h,v 1.30 2003/04/07 20:34:20 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 */ @@ -11,24 +11,26 @@ #include "lzio.h" /* load one chunk; from lundump.c */ -Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff); +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); +/* make header; from lundump.c */ +LUAI_FUNC void luaU_header (char* h); /* dump one chunk; from ldump.c */ -void luaU_dump (lua_State* L, const Proto* Main, lua_Chunkwriter w, void* data); +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 */ -void luaU_print (const Proto* Main); +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 -/* 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 */ +/* for header of binary files -- this is the official format */ +#define LUAC_FORMAT 0 -/* a multiple of PI for testing native format */ -/* multiplying by 1E7 gives non-trivial integer values */ -#define TEST_NUMBER ((lua_Number)3.14159265358979323846E7) +/* size of header of binary files */ +#define LUAC_HEADERSIZE 12 #endif diff --git a/src/lvm.c b/src/lvm.c index 951329315c..6f4c0291c9 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,18 +1,16 @@ /* -** $Id: lvm.c,v 1.284c 2003/04/03 13:35:34 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 */ -#include +#include #include #include -/* needed only when `lua_number2str' uses `sprintf' */ -#include - #define lvm_c +#define LUA_CORE #include "lua.h" @@ -30,17 +28,11 @@ -/* 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 -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)) { @@ -56,126 +48,102 @@ 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)); - setsvalue2s(obj, luaS_new(L, s)); + char s[LUAI_MAXNUMBER2STR]; + lua_Number n = nvalue(obj); + lua_number2str(s, n); + 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? */ + 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); - return; } } 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))) { + 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); - 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 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); - 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, 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); } -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 get */ + 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)) { + callTMres(L, val, tm, t, key); + 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_barriert(L, h, val); return; } /* else will try the tag method */ @@ -187,29 +155,26 @@ void luaV_settable (lua_State *L, const TObject *t, TObject *key, StkId val) { 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); + callTMres(L, res, tm, p1, p2); 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,20 +185,20 @@ 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); + callTMres(L, L->top, tm1, p1, p2); return !l_isfalse(L->top); } -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); @@ -255,28 +220,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); + return luai_numlt(nvalue(l), nvalue(r)); else if (ttisstring(l)) - return luaV_strcmp(tsvalue(l), tsvalue(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 TObject *l, const TObject *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); + return luai_numle(nvalue(l), nvalue(r)); else if (ttisstring(l)) - return luaV_strcmp(tsvalue(l), tsvalue(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' */ @@ -285,17 +250,17 @@ 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; - case LUA_TNUMBER: return 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: { 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 +272,7 @@ 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 */ + callTMres(L, L->top, tm, t1, t2); /* call TM */ return !l_isfalse(L->top); } @@ -319,25 +284,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 */ - size_t tl = tsvalue(top-1)->tsv.len; + size_t tl = tsvalue(top-1)->len; 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)->tsv.len; + size_t l = tsvalue(top-n-1)->len; if (l >= MAX_SIZET - 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 */ - 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,27 +310,21 @@ 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 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, 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; - } + 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; } } @@ -379,380 +338,382 @@ static void Arith (lua_State *L, StkId ra, ** 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 */ -#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, \ + 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 dojump(L,pc,i) {(pc) += (i); luai_threadyield(L);} + + +#define Protect(x) { L->savedpc = pc; {x;}; base = L->base; } -#define dojump(pc, i) ((pc) += (i)) +#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)); \ + } + -StkId luaV_execute (lua_State *L) { +void luaV_execute (lua_State *L, int nexeccalls) { LClosure *cl; - TObject *k; + StkId base; + TValue *k; const Instruction *pc; - callentry: /* entry point when calling new functions */ - 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 || - 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; + reentry: /* entry point */ + pc = L->savedpc; + cl = &clvalue(L->ci->func)->l; + base = L->base; 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? */ - L->ci->u.l.savedpc = pc - 1; - L->ci->state = CI_YIELD | CI_SAVEDPC; - return NULL; + traceexec(L, pc); + if (L->status == LUA_YIELD) { /* did hook yield? */ + L->savedpc = pc - 1; + return; } + 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(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->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)) { case OP_MOVE: { - setobjs2s(ra, RB(i)); - break; + setobjs2s(L, ra, RB(i)); + continue; } case OP_LOADK: { - setobj2s(ra, KBx(i)); - break; + setobj2s(L, ra, KBx(i)); + continue; } case OP_LOADBOOL: { setbvalue(ra, GETARG_B(i)); if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ - break; + continue; } case OP_LOADNIL: { - TObject *rb = RB(i); + TValue *rb = RB(i); do { setnilvalue(rb--); } while (rb >= ra); - break; + continue; } case OP_GETUPVAL: { int b = GETARG_B(i); - setobj2s(ra, cl->upvals[b]->v); - break; + setobj2s(L, ra, cl->upvals[b]->v); + continue; } case OP_GETGLOBAL: { - 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; + 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: { - 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; + Protect(luaV_gettable(L, RB(i), RKC(i), ra)); + continue; } case OP_SETGLOBAL: { - lua_assert(ttisstring(KBx(i)) && ttistable(&cl->g)); - luaV_settable(L, &cl->g, KBx(i), ra); - break; + TValue g; + sethvalue(L, &g, cl->env); + lua_assert(ttisstring(KBx(i))); + Protect(luaV_settable(L, &g, KBx(i), ra)); + continue; } case OP_SETUPVAL: { - int b = GETARG_B(i); - setobj(cl->upvals[b]->v, ra); /* write barrier */ - break; + UpVal *uv = cl->upvals[GETARG_B(i)]; + setobj(L, uv->v, ra); + luaC_barrier(L, uv, ra); + continue; } case OP_SETTABLE: { - luaV_settable(L, ra, RKB(i), RKC(i)); - break; + Protect(luaV_settable(L, ra, RKB(i), RKC(i))); + continue; } case OP_NEWTABLE: { int b = GETARG_B(i); - b = fb2int(b); - sethvalue(ra, luaH_new(L, b, GETARG_C(i))); - luaC_checkGC(L); - break; + int c = GETARG_C(i); + sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); + Protect(luaC_checkGC(L)); + continue; } 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)); - break; + setobjs2s(L, ra+1, rb); + Protect(luaV_gettable(L, rb, RKC(i), ra)); + continue; } case OP_ADD: { - TObject *rb = RKB(i); - TObject *rc = RKC(i); - if (ttisnumber(rb) && ttisnumber(rc)) { - setnvalue(ra, nvalue(rb) + nvalue(rc)); - } - else - Arith(L, ra, rb, rc, TM_ADD); - break; + arith_op(luai_numadd, TM_ADD); + continue; } case OP_SUB: { - TObject *rb = RKB(i); - TObject *rc = RKC(i); - if (ttisnumber(rb) && ttisnumber(rc)) { - setnvalue(ra, nvalue(rb) - nvalue(rc)); - } - else - Arith(L, ra, rb, rc, TM_SUB); - break; + arith_op(luai_numsub, TM_SUB); + continue; } case OP_MUL: { - TObject *rb = RKB(i); - TObject *rc = RKC(i); - if (ttisnumber(rb) && ttisnumber(rc)) { - setnvalue(ra, nvalue(rb) * nvalue(rc)); - } - else - Arith(L, ra, rb, rc, TM_MUL); - break; + arith_op(luai_nummul, TM_MUL); + continue; } case OP_DIV: { - TObject *rb = RKB(i); - TObject *rc = RKC(i); - if (ttisnumber(rb) && ttisnumber(rc)) { - setnvalue(ra, nvalue(rb) / nvalue(rc)); - } - else - Arith(L, ra, rb, rc, TM_DIV); - break; + arith_op(luai_numdiv, TM_DIV); + continue; + } + case OP_MOD: { + arith_op(luai_nummod, TM_MOD); + continue; } case OP_POW: { - Arith(L, ra, RKB(i), RKC(i), TM_POW); - break; + arith_op(luai_numpow, TM_POW); + continue; } case OP_UNM: { - const TObject *rb = RB(i); - TObject temp; - if (tonumber(rb, &temp)) { - setnvalue(ra, -nvalue(rb)); + TValue *rb = RB(i); + if (ttisnumber(rb)) { + lua_Number nb = nvalue(rb); + setnvalue(ra, luai_numunm(nb)); } else { - setnilvalue(&temp); - if (!call_binTM(L, RB(i), &temp, ra, TM_UNM)) - luaG_aritherror(L, RB(i), &temp); + Protect(Arith(L, ra, rb, rb, TM_UNM)); } - break; + continue; } case OP_NOT: { int res = l_isfalse(RB(i)); /* next assignment may change this value */ setbvalue(ra, res); - break; + 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"); + ) + } + } + continue; } 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; + Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L)); + setobjs2s(L, RA(i), base+b); + continue; } case OP_JMP: { - dojump(pc, GETARG_sBx(i)); - break; + dojump(L, pc, GETARG_sBx(i)); + continue; } case OP_EQ: { - if (equalobj(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; - else dojump(pc, GETARG_sBx(*pc) + 1); - break; + TValue *rb = RKB(i); + TValue *rc = RKC(i); + Protect( + if (equalobj(L, rb, rc) == GETARG_A(i)) + dojump(L, pc, GETARG_sBx(*pc)); + ) + pc++; + continue; } case OP_LT: { - if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; - else dojump(pc, GETARG_sBx(*pc) + 1); - break; + Protect( + if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) + dojump(L, pc, GETARG_sBx(*pc)); + ) + pc++; + continue; } case OP_LE: { - if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; - else dojump(pc, GETARG_sBx(*pc) + 1); - break; + Protect( + if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) + dojump(L, pc, GETARG_sBx(*pc)); + ) + pc++; + continue; } case OP_TEST: { - TObject *rb = RB(i); - if (l_isfalse(rb) == GETARG_C(i)) pc++; - else { - setobjs2s(ra, rb); - dojump(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)) { + setobjs2s(L, ra, rb); + dojump(L, pc, GETARG_sBx(*pc)); } - break; + pc++; + continue; } - case OP_CALL: - case OP_TAILCALL: { - StkId firstResult; + case OP_CALL: { int b = GETARG_B(i); - int nresults; + int nresults = GETARG_C(i) - 1; if (b != 0) L->top = 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; + L->savedpc = pc; + switch (luaD_precall(L, ra, nresults)) { + case PCRLUA: { + nexeccalls++; + goto reentry; /* restart luaV_execute over new Lua function */ } - /* 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); + case PCRC: { + /* it was a C function (`precall' called it); adjust results */ + if (nresults >= 0) L->top = L->ci->top; + base = L->base; + continue; } - else { /* tail call: put new frame in place of previous one */ + default: { + return; /* yield */ + } + } + } + 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; - 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; + 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 */ - L->base = L->ci->base; + goto reentry; + } + case PCRC: { /* it was a C function (`precall' called it) */ + base = L->base; + continue; + } + default: { + return; /* yield */ } - goto callentry; } - 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 */ - } + L->savedpc = pc; + b = luaD_poscall(L, ra); + if (--nexeccalls == 0) /* was previous function running `here'? */ + return; /* no: return */ else { /* yes: continue its execution */ - int nresults; - 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); - 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, 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 */ + lua_Number step = nvalue(ra+2); + lua_Number idx = luai_numadd(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 */ + 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->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)); + continue; } 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); + Protect(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? */ - pc++; /* skip jump (break loop) */ - else - 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"))); + 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 */ } - dojump(pc, GETARG_sBx(i)); - break; + pc++; + continue; } - case OP_SETLIST: - case OP_SETLISTO: { - int bc; - int n; + case OP_SETLIST: { + int n = GETARG_B(i); + 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 (c == 0) c = cast_int(*pc++); 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 { - n = L->top - ra - 1; - L->top = L->ci->top; + 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); + luaC_barriert(L, h, val); } - 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; + continue; } case OP_CLOSE: { luaF_close(L, ra); - break; + continue; } case OP_CLOSURE: { Proto *p; @@ -760,7 +721,7 @@ StkId luaV_execute (lua_State *L) { 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; jl.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc)); } } - setclvalue(ra, ncl); - luaC_checkGC(L); - break; + 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) { + 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); + } + else { + setnilvalue(ra + j); + } + } + continue; } } } } - diff --git a/src/lvm.h b/src/lvm.h index 19cce200b6..788423f8e3 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.5 2005/08/22 18:54:49 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -22,14 +22,15 @@ (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); +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 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 3aeca1c588..5121ada846 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.31 2005/06/03 20:15:29 roberto Exp $ ** a generic input stream interface ** See Copyright Notice in lua.h */ @@ -8,17 +8,23 @@ #include #define lzio_c +#define LUA_CORE #include "lua.h" #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; @@ -28,19 +34,21 @@ 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); } -void luaZ_init (ZIO *z, lua_Chunkreader reader, void *data, const char *name) { +void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { + z->L = L; z->reader = reader; z->data = data; - z->name = name; z->n = 0; z->p = NULL; } @@ -50,14 +58,8 @@ void luaZ_init (ZIO *z, lua_Chunkreader reader, void *data, const char *name) { 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; @@ -72,8 +74,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..8f403b8e74 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.21 2005/05/17 19:49:15 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ @@ -10,36 +10,31 @@ #include "lua.h" +#include "lmem.h" + #define EOZ (-1) /* end of stream */ 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 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); - - - 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_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,17 +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 */ - const char *name; + 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 new file mode 100644 index 0000000000..1c3a4457c4 --- /dev/null +++ b/src/print.c @@ -0,0 +1,224 @@ +/* +** $Id: print.c,v 1.54 2006/01/11 22:49:27 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 Proto* f, int n) +{ + const char* s=svalue(&f->k[n]); + putchar('"'); + for (; *s; s++) + { + switch (*s) + { + 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: if (isprint((unsigned char)*s)) + printf("%c",*s); + else + printf("\\%03u",(unsigned char)*s); + } + } + putchar('"'); +} + +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; + default: /* cannot happen */ + printf("? type=%d",ttype(o)); + break; + } +} + +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,-1-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,bx); + 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[bx])); + 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->nups)); + 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) +{ + int i,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); + } +} + +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])); + } +} + +void PrintFunction(const Proto* f, int full) +{ + int i,n=f->sizep; + PrintHeader(f); + PrintCode(f); + if (full) + { + PrintConstants(f); + PrintLocals(f); + PrintUpvalues(f); + } + for (i=0; ip[i],full); +} 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/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/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/luac.lua b/test/luac.lua index b009ae9da5..96a0a97ce7 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(f:close()) 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/trace-calls.lua b/test/trace-calls.lua index 63c8b8f3eb..6d7a7b3b43 100644 --- a/test/trace-calls.lua +++ b/test/trace-calls.lua @@ -1,9 +1,9 @@ -- trace calls --- example: lua -ltrace-calls.lua bisect.lua +-- example: lua -ltrace-calls bisect.lua 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 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 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 37cb1b7c058ed5bd73d54514f946228a313b13c1 Mon Sep 17 00:00:00 2001 From: Kate Adams Date: Sun, 4 Jan 2015 08:30:18 +0000 Subject: [PATCH 24/40] Imported Lua 5.1.1 --- MANIFEST | 108 - Makefile | 11 +- doc/contents.html | 112 +- doc/lua.css | 7 + doc/manual.html | 7535 +++++++++++++++++++++++++++++---------------- etc/lua.pc | 6 +- src/Makefile | 20 +- src/lapi.c | 7 +- src/lauxlib.c | 18 +- src/lauxlib.h | 8 +- src/lbaselib.c | 2 +- src/lcode.c | 14 +- src/lcode.h | 3 +- src/ldo.c | 7 +- 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 | 13 +- src/lparser.h | 3 +- src/lstate.c | 4 +- src/lstrlib.c | 9 +- src/lua.c | 31 +- src/lua.h | 3 +- src/luac.c | 18 +- src/luaconf.h | 28 +- src/lvm.c | 3 +- src/print.c | 21 +- 31 files changed, 5120 insertions(+), 2923 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..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. Currently used only for messages. +# 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/contents.html b/doc/contents.html index 564377c942..c1e4a99ddb 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -2,26 +2,30 @@ Lua 5.1 reference manual - contents + - +


    Lua -Lua 5.1 Reference Manual +Reference manual for Lua 5.1

    - -Copyright -© 2006 Lua.org, PUC-Rio. All rights reserved. - +contents +· +index
    - -

    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
    @@ -127,8 +168,6 @@

    Functions

    debug.setmetatable
    debug.setupvalue
    debug.traceback
    -dofile
    -error
    file:close
    file:flush
    file:lines
    @@ -136,8 +175,6 @@

    Functions

    file:seek
    file:setvbuf
    file:write
    -getfenv
    -getmetatable
    io.close
    io.flush
    io.input
    @@ -149,10 +186,6 @@

    Functions

    io.tmpfile
    io.type
    io.write
    -ipairs
    -load
    -loadfile
    -loadstring
    math.abs
    math.acos
    math.asin
    @@ -166,12 +199,14 @@

    Functions

    math.floor
    math.fmod
    math.frexp
    +math.huge
    math.ldexp
    math.log10
    math.log
    math.max
    math.min
    math.modf
    +math.pi
    math.pow
    math.rad
    math.random
    @@ -181,8 +216,6 @@

    Functions

    math.sqrt
    math.tanh
    math.tan
    -module
    -next
    os.clock
    os.date
    os.difftime
    @@ -200,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
    @@ -229,15 +252,10 @@

    Functions

    table.maxn
    table.remove
    table.sort
    -tonumber
    -tostring
    -type
    -unpack
    -xpcall
    -

    API

    +
    +

    C API

    lua_Alloc
    lua_CFunction
    lua_Debug
    @@ -337,12 +355,13 @@

    API

    lua_touserdata
    lua_type
    lua_typename
    +lua_upvalueindex
    lua_xmove
    lua_yield
    -

    Auxiliary library

    +

    auxiliary library

    luaL_Buffer
    luaL_Reg
    luaL_addchar
    @@ -365,6 +384,8 @@

    Auxiliary library

    luaL_checkstring
    luaL_checktype
    luaL_checkudata
    +luaL_dofile
    +luaL_dostring
    luaL_error
    luaL_getmetafield
    luaL_getmetatable
    @@ -398,8 +419,11 @@

    Auxiliary library


    Last update: -Fri Feb 10 17:15:37 BRST 2006 +Tue Jun 6 14:55:31 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..16fbb36ef0 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,72 @@

    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. - -

    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, + +

    +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 -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 +438,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 +565,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 +872,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 +910,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 -do not apply to equality comparisons. +

    +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 +1036,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 +1089,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 +1141,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 +1258,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 +1340,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 +1367,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 +1519,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 +1559,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 using 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 +1977,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 +1994,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 +2079,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 +2128,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 +2139,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 +2154,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, -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. -

    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 +2372,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 +2415,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 +2425,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 +2468,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 +2534,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 +2653,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 +2686,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 +2719,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 +3138,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 +3289,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 +3301,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_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 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);
    -
    -

    Pushes the thread represented by L onto the stack. -

    -


    lua_pushvalue

    -
    -          void lua_pushvalue (lua_State *L, int index);
    -
    +

    lua_pushthread

    +
    int lua_pushthread (lua_State *L);
    -

    Pushes a copy of the element at the given valid index +

    +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 + + +


    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 +3637,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 +3709,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);
    -
    -

    Pops a value from the stack and + +


    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

    -          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);
    -
    -

    Accepts any acceptable index, or 0, + +


    lua_settop

    +
    void lua_settop (lua_State *L, int index);
    + +

    +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;
    -
    +

    lua_State

    +
    typedef struct lua_State lua_State;
    -

    Opaque structure that keeps the whole state of a Lua interpreter. +

    +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);
    -
    +

    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). +

    +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 +3866,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 +3917,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);
    -
    -

    Converts the value at the given acceptable index to a generic -C pointer (void*). + +


    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. +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. + + + + + +


    lua_tostring

    +
    const char *lua_tostring (lua_State *L, int index);
    + +

    +Equivalent to lua_tolstring with len equal to NULL. + -

    Equivalent to lua_tolstring with len equal to NULL. -

    -


    lua_tothread

    -
    -          lua_State *lua_tothread (lua_State *L, int index);
    -
    +

    lua_tothread

    +
    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 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 +4022,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 -by means of functions and hooks. -This interface allows the construction of different + + + + + +

    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_gethookcount

    -
    -          int lua_gethookcount (lua_State *L);
    -
    +

    lua_gethook

    +
    lua_Hook lua_gethook (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_getinfo

    -
    -          int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
    -
    +

    lua_gethookcount

    +
    int lua_gethookcount (lua_State *L);
    + +

    +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). + + + + + +


    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. +

    +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 +4326,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 +4379,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 +4413,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 +4528,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 +4711,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 +


    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). -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. +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 +4936,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 +5293,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 +5381,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 +5510,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 +5543,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 +5671,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 +5725,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 +5738,185 @@

    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, +

    +This function returns table. + + + + +

    +


    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)

    -


    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, @@ -4731,46 +5929,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 +6009,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 +6026,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 [, ···])

    -


    module (name [, ...])

    -

    Creates a module. +

    +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 +6076,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 +6086,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 -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, -first require queries package.preload[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 +at package.loaded[modname]. +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, 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 +6135,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 +6163,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. -


    string.char (i1, i2, ...)

    -Receives 0 or more integers. +

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

    +


    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 +6476,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 +6577,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 +6610,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 +6679,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 +6785,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. -

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

    5.5 - Table Manipulation

    + + + + + + + + + +

    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,8 +6874,12 @@

    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, + + + +

    +


    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, @@ -5382,220 +6888,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.) + + + + + + +

    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, -math.random returns a pseudo-random real number +returns a pseudo-random real number in the range [0,1). -When called with a number n, +When called with a number m, math.random returns -a pseudo-random integer in the range [1,n]. -When called with two arguments, -l and u, +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 [l,u]. -The math.randomseed function sets a "seed" +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. +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. + +

    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])

    + -


    io.popen ([prog [, mode]])

    +

    +Similar to io.input, but operates over the default output file. -

    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 +7501,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 +7566,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 + + + +

    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, + + +

    +


    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 +7770,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 +7836,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 +7859,191 @@

    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 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. +The default for what is to get all information available, +except the table of valid lines. If present, -the option `f´ +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. -

    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. +Returns object. + + + + +

    +


    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 +8051,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 +8108,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 +8129,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 +8161,296 @@

    (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. -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. +

    8 - The Complete Syntax of Lua

    +Here is the complete syntax of Lua in extended BNF. +(It does not describe operator precedences.) + + -

     
    -	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: +Mon Jun 5 17:05:27 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/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/lapi.c b/src/lapi.c index ce7bcf6f3a..7c532b8b1b 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.55 2006/06/07 12:37:17 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"; @@ -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); 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..2df437b018 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.191 2006/06/02 15:34:00 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ 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/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/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..a9be740e99 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.42 2006/06/05 15:57:59 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" @@ -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/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..5cee7fa9f0 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.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); } @@ -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..064ff6fb35 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.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 @@ -17,6 +17,7 @@ #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 2dd76b7653..d07017391b 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.54 2006/06/02 17:37:11 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; ici)); pc = L->savedpc; cl = &clvalue(L->ci->func)->l; base = L->base; diff --git a/src/print.c b/src/print.c index 1c3a4457c4..2a4fb3ed32 100644 --- a/src/print.c +++ b/src/print.c @@ -1,5 +1,5 @@ /* -** $Id: print.c,v 1.54 2006/01/11 22:49:27 lhf Exp $ +** $Id: print.c,v 1.55 2006/05/31 13:30:05 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ @@ -20,13 +20,16 @@ #define Sizeof(x) ((int)sizeof(x)) #define VOID(p) ((const void*)(p)) -static void PrintString(const Proto* f, int n) +static void PrintString(const TString* ts) { - const char* s=svalue(&f->k[n]); + const char* s=getstr(ts); + int n=ts->tsv.len; + int i; putchar('"'); - for (; *s; s++) + for (i=0; i Date: Sun, 4 Jan 2015 08:30:50 +0000 Subject: [PATCH 25/40] Imported Lua 5.1.2 --- COPYRIGHT | 2 +- HISTORY | 2 +- INSTALL | 9 +- Makefile | 13 +- README | 4 +- 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 | 379 +++++++++++++++++++++++++++------------------- doc/readme.html | 14 +- etc/README | 1 + etc/lua.pc | 2 +- etc/luavs.bat | 22 ++- etc/strict.lua | 9 +- src/Makefile | 9 +- src/lbaselib.c | 10 +- src/lcode.c | 44 ++++-- src/ldebug.c | 10 +- src/lfunc.c | 6 +- src/loadlib.c | 33 ++-- src/loslib.c | 23 ++- src/lparser.c | 4 +- src/lstrlib.c | 4 +- src/lua.h | 8 +- src/luaconf.h | 4 +- src/lvm.c | 10 +- src/print.c | 6 +- 29 files changed, 443 insertions(+), 266 deletions(-) create mode 100644 doc/amazon.gif create mode 100644 doc/cover.png create mode 100644 doc/manual.css 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/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/README b/README index f082d40460..11b4dff70e 100644 --- a/README +++ b/README @@ -24,8 +24,8 @@ See HISTORY for a summary of changes since the last released version. * Installation ------------ 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. + platforms that have an ANSI C compiler. In most Unix-like platforms, simply + do "make" with a suitable target. See INSTALL for detailed instructions. * Origin ------ 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..6b137ff6e6 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. @@ -882,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. @@ -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. @@ -3183,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, @@ -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)
      +
      @@ -3455,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, @@ -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 +Mon Mar 26 12:59:26 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/etc/README b/etc/README index ad9ca6ab87..5149fc91d4 100644 --- a/etc/README +++ b/etc/README @@ -20,6 +20,7 @@ lua.pc 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. 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/luavs.bat b/etc/luavs.bat index eea175e3e0..6b1120b881 100644 --- a/etc/luavs.bat +++ b/etc/luavs.bat @@ -1,7 +1,15 @@ -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 .. +rem script to build Lua under "Visual Studio .NET Command Prompt". +rem do not run it 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. + +cd src +cl /MD /O2 /W3 /c /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE /DLUA_BUILD_AS_DLL l*.c +del lua.obj luac.obj +link /DLL /out:lua51.dll l*.obj +cl /MD /O2 /W3 /c /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE /DLUA_BUILD_AS_DLL lua.c +link /out:lua.exe lua.obj lua51.lib +cl /MD /O2 /W3 /c /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE 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 +link /out:luac.exe *.obj +del *.obj +cd .. 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/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/lfunc.c b/src/lfunc.c index b8cd67b267..05bd5ff50f 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -1,5 +1,5 @@ /* -** $Id: lfunc.c,v 2.12 2005/12/22 16:19:56 roberto Exp $ +** $Id: lfunc.c,v 2.12a 2005/12/22 16:19:56 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -55,7 +55,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { GCObject **pp = &L->openupval; UpVal *p; UpVal *uv; - while ((p = ngcotouv(*pp)) != NULL && p->v >= level) { + while (*pp != NULL && (p = ngcotouv(*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? */ @@ -96,7 +96,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 ((uv = ngcotouv(L->openupval)) != NULL && uv->v >= level) { + while (L->openupval != NULL && (uv = ngcotouv(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 */ diff --git a/src/loadlib.c b/src/loadlib.c index 08722e1855..808368ba43 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.52 2006/04/10 18:27:23 roberto Exp $ +** $Id: loadlib.c,v 1.54a 2006/07/03 20:16:49 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -16,9 +16,9 @@ #define loadlib_c #define LUA_LIB -#include "lauxlib.h" -#include "lobject.h" #include "lua.h" + +#include "lauxlib.h" #include "lualib.h" @@ -98,7 +98,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 { @@ -112,7 +112,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 @@ -125,7 +125,7 @@ static void ll_unloadlib (void *lib) { static void *ll_load (lua_State *L, const char *path) { - HINSTANCE lib = LoadLibrary(path); + HINSTANCE lib = LoadLibraryA(path); if (lib == NULL) pusherror(L); return lib; } @@ -356,15 +356,16 @@ 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 */ + 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); + lua_remove(L, -2); /* remove path template */ 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); + 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 */ } return NULL; /* not found */ } @@ -423,8 +424,8 @@ static int loader_Croot (lua_State *L) { funcname = mkfuncname(L, name); if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { if (stat != ERRFUNC) loaderror(L, filename); /* real error */ - luaO_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, - name, filename); + lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, + name, filename); return 1; /* function not found */ } return 1; @@ -438,7 +439,7 @@ static int loader_preload (lua_State *L) { luaL_error(L, LUA_QL("package.preload") " must be a table"); lua_getfield(L, -1, name); if (lua_isnil(L, -1)) /* not found? */ - luaO_pushfstring(L, "\n\tno field package.preload['%s']", name); + lua_pushfstring(L, "\n\tno field package.preload['%s']", name); return 1; } @@ -462,7 +463,7 @@ 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 */ + lua_pushliteral(L, ""); /* error message accumulator */ for (i=1; ; i++) { lua_rawgeti(L, -2, i); /* get a loader */ if (lua_isnil(L, -1)) @@ -646,8 +647,8 @@ LUALIB_API int luaopen_package (lua_State *L) { 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_pushliteral(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" + LUA_EXECDIR "\n" LUA_IGMARK); lua_setfield(L, -2, "config"); /* set field `loaded' */ luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2); 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/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..08802f440f 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 */ @@ -165,7 +165,7 @@ static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, 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; + if (ttisnil(tm)) return 0; callTMres(L, res, tm, p1, p2); return 1; } @@ -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? */ + (void)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; diff --git a/src/print.c b/src/print.c index 2a4fb3ed32..e240cfc3c6 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 */ @@ -23,8 +23,7 @@ static void PrintString(const TString* ts) { const char* s=getstr(ts); - int n=ts->tsv.len; - int i; + size_t i,n=ts->tsv.len; putchar('"'); for (i=0; i Date: Sun, 4 Jan 2015 08:31:25 +0000 Subject: [PATCH 26/40] Imported Lua 5.1.3 --- COPYRIGHT | 2 +- Makefile | 20 +- doc/contents.html | 73 ++++- doc/manual.css | 6 + doc/manual.html | 815 ++++++++++++++++++++++++++++++---------------- doc/readme.html | 4 +- etc/lua.pc | 2 +- etc/luavs.bat | 35 +- etc/min.c | 2 +- etc/strict.lua | 4 +- src/Makefile | 9 +- src/lapi.c | 9 +- src/lapi.h | 2 +- src/lauxlib.c | 13 +- src/lauxlib.h | 2 +- src/lbaselib.c | 78 +++-- src/lcode.c | 4 +- src/lcode.h | 2 +- src/ldblib.c | 30 +- src/ldebug.c | 6 +- src/ldebug.h | 2 +- src/ldo.c | 24 +- src/ldo.h | 2 +- src/ldump.c | 2 +- src/lfunc.c | 2 +- src/lfunc.h | 2 +- src/lgc.c | 2 +- src/lgc.h | 2 +- src/linit.c | 2 +- src/liolib.c | 69 ++-- src/llex.c | 2 +- src/llex.h | 2 +- src/llimits.h | 2 +- src/lmathlib.c | 2 +- src/lmem.c | 2 +- src/lmem.h | 2 +- src/loadlib.c | 2 +- src/lobject.c | 2 +- src/lobject.h | 2 +- src/lopcodes.c | 2 +- src/lopcodes.h | 2 +- src/loslib.c | 3 +- src/lparser.c | 4 +- src/lparser.h | 2 +- src/lstate.c | 6 +- src/lstate.h | 3 +- src/lstring.c | 2 +- src/lstring.h | 2 +- src/lstrlib.c | 10 +- src/ltable.c | 6 +- src/ltable.h | 2 +- src/ltablib.c | 5 +- src/ltm.c | 2 +- src/ltm.h | 2 +- src/lua.c | 6 +- src/lua.h | 11 +- src/luaconf.h | 7 +- src/lualib.h | 2 +- src/lundump.c | 6 +- src/lundump.h | 2 +- src/lvm.c | 10 +- src/lvm.h | 2 +- src/lzio.c | 2 +- src/lzio.h | 2 +- 64 files changed, 846 insertions(+), 502 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/Makefile b/Makefile index c5ec666af7..fec201156a 100644 --- a/Makefile +++ b/Makefile @@ -20,20 +20,15 @@ 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. -# -INSTALL_EXEC= $(CP) -INSTALL_DATA= $(CP) -#INSTALL_EXEC= $(INSTALL) -m 0755 -#INSTALL_DATA= $(INSTALL) -m 0644 +# How to install. If you don't have "install" (unlikely) then get install-sh at +# http://dev.w3.org/cvsweb/libwww/config/install-sh +# or use cp instead. +INSTALL_EXEC= $(INSTALL) -p -m 0755 +INSTALL_DATA= $(INSTALL) -p -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 ========= @@ -48,7 +43,7 @@ TO_MAN= lua.1 luac.1 # Lua version and release. V= 5.1 -R= 5.1.2 +R= 5.1.3 all: $(PLAT) @@ -64,10 +59,9 @@ install: dummy 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" + $(MAKE) install INSTALL_TOP=.. none: @echo "Please do" diff --git a/doc/contents.html b/doc/contents.html index 01b069f7ac..8e58e18ca9 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -1,7 +1,9 @@ + -Lua 5.1 reference manual - contents +Lua 5.1 Reference Manual - contents + @@ -20,7 +19,13 @@

    Lua 5.1 Reference Manual

    -This is an online version of +

    +The reference manual is the official definition of the Lua language. +For a complete introduction to Lua programming, see the book +Programming in Lua. + +

    +This manual is also available as a book:

    @@ -29,128 +34,119 @@


    by R. Ierusalimschy, L. H. de Figueiredo, W. Celes
    Lua.org, August 2006
    ISBN 85-903798-3-3 -
    -[Buy from Amazon]

    -

    -Buy a copy of this book and +

    +Buy a copy +of this book and help to support the Lua project. -

    -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 · index · -português -· -español +other versions


    -Copyright © 2006-2008 Lua.org, PUC-Rio. +Copyright © 2006–2012 Lua.org, PUC-Rio. Freely available under the terms of the -Lua license. +Lua license. -

    Contents

    Index

    @@ -160,6 +156,8 @@

    Index

    Lua functions

    _G
    _VERSION
    +

    + assert
    collectgarbage
    dofile
    @@ -487,12 +485,12 @@

    auxiliary library


    - + Last update: -Sat Jan 19 13:24:29 BRST 2008 +Mon Feb 13 18:53:32 BRST 2012 diff --git a/doc/lua.css b/doc/lua.css index 039cf11698..7fafbb1bb6 100644 --- a/doc/lua.css +++ b/doc/lua.css @@ -1,17 +1,37 @@ body { color: #000000 ; background-color: #FFFFFF ; - font-family: sans-serif ; + 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 { + font-family: Verdana, Geneva, sans-serif ; font-weight: normal ; font-style: italic ; } +h2 { + padding-top: 0.4em ; + padding-bottom: 0.4em ; + padding-left: 30px ; + padding-right: 30px ; + margin-left: -30px ; + background-color: #E0E0FF ; +} + +h3 { + padding-left: 0.5em ; + border-left: solid #E0E0FF 1em ; +} + +table h3 { + padding-left: 0px ; + border-left: none ; +} + a:link { color: #000080 ; background-color: inherit ; @@ -39,3 +59,25 @@ hr { background-color: #a0a0a0 ; } +:target { + background-color: #F8F8F8 ; + 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: 4px center ; + padding-left: 20px ; + height: 2em ; +} + diff --git a/doc/manual.css b/doc/manual.css index eed5afd9ee..b49b362937 100644 --- a/doc/manual.css +++ b/doc/manual.css @@ -1,13 +1,24 @@ h3 code { font-family: inherit ; + font-size: 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 { + padding-top: 0.4em ; + padding-bottom: 0.4em ; + padding-left: 30px ; + margin-left: -30px ; + background-color: #E0E0FF ; +} diff --git a/doc/manual.html b/doc/manual.html index b125c13d88..4e41683d02 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -3,8 +3,8 @@ Lua 5.1 Reference Manual - - + + @@ -19,9 +19,9 @@

    by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes

    -Copyright © 2006-2008 Lua.org, PUC-Rio. +Copyright © 2006–2012 Lua.org, PUC-Rio. Freely available under the terms of the -Lua license. +Lua license.


    @@ -29,11 +29,13 @@

    contents · index +· +other versions

    - + @@ -103,7 +105,8 @@

    2 - The Language

    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. +The complete syntax of Lua can be found in §8 +at the end of this manual. @@ -139,7 +142,7 @@

    2.1 - Lexical Conventions

    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. @@ -169,26 +172,15 @@

    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 may also be specified by its numerical value +A character in a string can 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, +Strings in Lua can contain any 8-bit value, including embedded zeros, which can be specified as '\0'. -

    -To put a double (single) quote, a newline, a backslash, -a carriage return, -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 long brackets. @@ -202,10 +194,10 @@

    2.1 - Lexical Conventions

    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, +Literals in this bracketed form can 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. +They can contain anything except a closing bracket of the proper level.

    @@ -215,7 +207,7 @@

    2.1 - Lexical Conventions

    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 literals below denote the same string: +the five literal strings below denote the same string:
          a = 'alo\n123"'
    @@ -229,7 +221,7 @@ 

    2.1 - Lexical Conventions

    -A numerical constant may be written with an optional decimal part +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. @@ -288,7 +280,7 @@

    2.2 - Values and Types

    String represents arrays of characters. Lua is 8-bit clean: -strings may contain any 8-bit character, +strings can contain any 8-bit character, including embedded zeros ('\0') (see §2.1). @@ -327,7 +319,7 @@

    2.2 - Values and Types

    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, +they can 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 @@ -341,8 +333,8 @@

    2.2 - Values and Types

    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). +table fields can contain functions. +Thus tables can also carry methods (see §2.5.9).

    @@ -477,7 +469,7 @@

    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, +assignments, control structures, function calls, and variable declarations. @@ -505,15 +497,15 @@

    2.4.1 - Chunks

    -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. +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.

    -Chunks may also be pre-compiled into binary form; +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. @@ -532,7 +524,7 @@

    2.4.2 - Blocks

    -A block may be explicitly delimited to produce a single statement: +A block can be explicitly delimited to produce a single statement:

     	stat ::= do block end
    @@ -550,7 +542,7 @@ 

    2.4.2 - Blocks

    2.4.3 - Assignment

    -Lua allows multiple 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. @@ -573,7 +565,7 @@

    2.4.3 - Assignment

    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 this call enter in the list of values, +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). @@ -595,7 +587,13 @@

    2.4.3 - Assignment

          x, y = y, x
     

    -exchanges the values of x and y. +exchanges the values of x and y, +and + +

    +     x, y, z = y, z, x
    +

    +cyclically permutes the values of x, y, and z.

    @@ -644,7 +642,7 @@

    2.4.4 - Control Structures

    The condition expression of a -control structure may return any value. +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). @@ -662,8 +660,8 @@

    2.4.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 may return more than one value, -so the syntax for the return statement is +Functions and chunks can return more than one value, +and so the syntax for the return statement is

     	stat ::= return [explist]
    @@ -745,7 +743,7 @@ 

    2.4.5 - For Statement

  • var, limit, and step are invisible variables. -The names are here for explanatory purposes only. +The names shown here are for explanatory purposes only.
  • @@ -842,8 +840,8 @@

    2.4.6 - Function Calls as Statements

    2.4.7 - Local Declarations

    -Local variables may be declared anywhere inside a block. -The declaration may include an initial assignment: +Local variables can be declared anywhere inside a block. +The declaration can include an initial assignment:

     	stat ::= local namelist [`=´ explist]
    @@ -908,12 +906,12 @@ 

    2.5 - Expressions

    -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), +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 the expression is used as the last (or the only) element +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). @@ -931,7 +929,7 @@

    2.5 - Expressions

    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 + -- 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 @@ -945,7 +943,7 @@

    2.5 - Expressions

    -An expression enclosed in parentheses always results in only one value. +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. @@ -1023,6 +1021,8 @@

    2.5.2 - Relational Operators

    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. @@ -1060,7 +1060,7 @@

    2.5.3 - Logical Operators

    10 and 20 --> 20

  • (In this manual, ---> indicates the result of the preceding expression.) +--> indicates the result of the preceding expression.) @@ -1090,13 +1090,13 @@

    2.5.5 - The Length Operator

    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. +moreover, if t[1] is nil, n can 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 +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). @@ -1132,7 +1132,7 @@

    2.5.6 - Precedence

    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, +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 @@ -1179,12 +1179,12 @@

    2.5.7 - Table Constructors

    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) +enclose the function call or the vararg expression in parentheses (see §2.5).

    -The field list may have an optional trailing separator, +The field list can have an optional trailing separator, as a convenience for machine-generated code. @@ -1349,8 +1349,8 @@

    2.5.9 - Function Definitions

    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. +can refer to different external local variables +and can have different environment tables.

    @@ -1377,7 +1377,7 @@

    2.5.9 - Function Definitions

    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). +(unless that last expression is enclosed in parentheses).

    @@ -1520,7 +1520,7 @@

    2.7 - Error Handling

    2.8 - Metatables

    -Every value in Lua may have a metatable. +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. @@ -1549,22 +1549,22 @@

    2.8 - Metatables

    through the setmetatable function. You cannot change the metatable of other types from Lua -(except using the debug library); +(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. -So, there is one single metatable for all numbers, +(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.

    -A metatable may control how an object behaves in arithmetic operations, +A metatable controls 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 +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. @@ -1806,7 +1806,7 @@

    2.8 - Metatables

    if h then return (h(op1, op2)) else - error(···); + error(···) end end end @@ -1833,7 +1833,7 @@

    2.8 - Metatables

    if h then return not h(op2, op1) else - error(···); + error(···) end end end @@ -1860,7 +1860,7 @@

    2.8 - Metatables

    else h = metatable(table).__index if h == nil then - error(···); + error(···) end end if type(h) == "function" then @@ -1886,7 +1886,7 @@

    2.8 - Metatables

    else h = metatable(table).__newindex if h == nil then - error(···); + error(···) end end if type(h) == "function" then @@ -1933,6 +1933,17 @@

    2.9 - Environments

    multiple objects can share the same environment. +

    +Threads are created sharing the environment of the creating thread. +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 environment of the creating thread. +Nested Lua functions are created sharing the environment of +the creating Lua function. + +

    Environments associated with userdata have no meaning for Lua. It is only a convenience feature for programmers to associate a table to @@ -1942,23 +1953,22 @@

    2.9 - Environments

    Environments associated with threads are called global environments. -They are used as the default environment for their threads and -non-nested functions created by the thread -(through loadfile, loadstring or load) +They are used as the default environment for threads and +non-nested Lua functions created by the thread and can be directly accessed by C code (see §3.3).

    -Environments associated with C functions can be directly +The environment associated with a C function 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. +It is used as the default environment for other C functions +and userdata created by the function.

    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 +They are used as the default environment for nested Lua functions created by the function. @@ -1985,9 +1995,9 @@

    2.10 - Garbage Collection

    Lua manages memory automatically by running a garbage collector from time to time to collect all dead objects -(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. +(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.

    @@ -1995,15 +2005,17 @@

    2.10 - Garbage Collection

    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).

    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 +Values smaller than 100 mean the collector will not wait to start a new cycle. -A value of 2 means that the collector waits for the total memory in use +A value of 200 means that the collector waits for the total memory in use to double before starting a new cycle. @@ -2013,17 +2025,15 @@

    2.10 - Garbage Collection

    memory allocation. 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" +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.

    You can change these numbers by calling lua_gc in C or collectgarbage in Lua. -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). @@ -2100,7 +2110,7 @@

    2.10.2 - Weak Tables

    After you use a table as a metatable, -you should not change the value of its field __mode. +you should not change the value of its __mode field. Otherwise, the weak behavior of the tables controlled by this metatable is undefined. @@ -2133,7 +2143,7 @@

    2.11 - Coroutines

    When you first call coroutine.resume, passing as its first argument -the thread returned by coroutine.create, +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 @@ -2383,7 +2393,7 @@

    3.4 - C Closures

    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, +current function (but not greater than 256), produces an acceptable (but invalid) index. @@ -2431,7 +2441,7 @@

    3.6 - Error Handling in C

    -Most functions in the API may throw an error, +Most functions in the API can throw an error, for instance due to a memory allocation error. The documentation for each function indicates whether it can throw errors. @@ -2459,7 +2469,7 @@

    3.7 - Functions and Types

    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) +A field in the form x|y means the function can push (or pop) x or y elements, depending on the situation; an interrogation mark '?' means that @@ -2544,7 +2554,7 @@

    3.7 - Functions and Types

    Lua calls a panic function and then calls exit(EXIT_FAILURE), thus exiting the host application. -Your panic function may avoid this exit by +Your panic function can avoid this exit by never returning (e.g., doing a long jump). @@ -2589,7 +2599,7 @@

    3.7 - Functions and Types

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

    @@ -2858,13 +2868,13 @@ 

    3.7 - Functions and Types

  • LUA_GCSETPAUSE: -sets data/100 as the new value +sets data 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 data/100 as the new value for the step multiplier of +sets data as the new value for the step multiplier of the collector (see §2.10). The function returns the previous value of the step multiplier.
  • @@ -3485,6 +3495,10 @@

    3.7 - Functions and Types

    lua_pushcclosure also pops these values from the stack. +

    +The maximum value for n is 255. + + @@ -3774,7 +3788,8 @@

    3.7 - Functions and Types

    with a new piece of the chunk and set size to the block size. The block must exist until the reader function is called again. -To signal the end of the chunk, the reader must return NULL. +To signal the end of the chunk, +the reader must return NULL or set size to zero. The reader function may return pieces of any size greater than zero. @@ -4081,7 +4096,7 @@

    3.7 - Functions and Types

    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. +but can 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. @@ -4112,7 +4127,7 @@

    3.7 - Functions and Types

    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; +The value can be a userdata, a table, a thread, or a function; otherwise, lua_topointer returns NULL. Different objects will give different pointers. There is no way to convert the pointer back to its original value. @@ -4350,8 +4365,8 @@

    3.8 - The Debug Interface

    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. +some functions can be the value of multiple global variables, +while others can 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, @@ -4581,7 +4596,7 @@

    3.8 - The Debug Interface

    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, +For return events, event can 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; @@ -5632,7 +5647,7 @@

    5 - Standard Libraries

      -
    • basic library;
    • +
    • basic library, which includes the coroutine sub-library;
    • package library;
    • @@ -5696,7 +5711,7 @@

      5.1 - Basic Functions

      -


      collectgarbage (opt [, arg])

      +

      collectgarbage ([opt [, arg]])

      @@ -5705,6 +5720,11 @@

      5.1 - Basic Functions

        +
      • "collect": +performs a full garbage-collection cycle. +This is the default option. +
      • +
      • "stop": stops the garbage collector.
      • @@ -5713,10 +5733,6 @@

        5.1 - Basic Functions

        restarts the garbage collector. -
      • "collect": -performs a full garbage-collection cycle. -
      • -
      • "count": returns the total memory in use by Lua (in Kbytes).
      • @@ -5731,13 +5747,15 @@

        5.1 - Basic Functions

      • "setpause": -sets arg/100 as the new value for the pause of +sets arg as the new value for the pause of the collector (see §2.10). +Returns the previous value for pause.
      • "setstepmul": -sets arg/100 as the new value for the step multiplier of +sets arg as the new value for the step multiplier of the collector (see §2.10). +Returns the previous value for step.
      @@ -5745,7 +5763,7 @@

      5.1 - Basic Functions

      -


      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). @@ -5842,7 +5860,7 @@

      5.1 - Basic Functions

      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 an empty string, nil, or no value signals the end of the chunk.

      @@ -6088,7 +6106,7 @@

      5.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 may have a decimal part, +In base 10 (the default), the number can have a decimal part, as well as an optional exponent part (see §2.1). In other bases, only unsigned integers are accepted. @@ -6335,7 +6353,7 @@

      5.3 - Modules

      -This function may receive optional options after +This function can receive optional options after the module name, where each option is a function to be applied over the module. @@ -6442,7 +6460,7 @@

      5.3 - Modules

      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) +The function can 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. @@ -6617,6 +6635,10 @@

      5.4 - String Manipulation

      can be written as s:byte(i). +

      +The string library assumes one-byte character encodings. + +


      string.byte (s [, i [, j]])

      Returns the internal numerical codes of the characters s[i], @@ -6667,7 +6689,7 @@

      5.4 - String Manipulation

      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 can 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, @@ -6771,7 +6793,7 @@

      5.4 - String Manipulation

      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. +which can be a string, a table, or a function. gsub also returns, as its second value, the total number of matches that occurred. @@ -6869,7 +6891,7 @@

      5.4 - String Manipulation

      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 can be negative. @@ -6893,7 +6915,7 @@

      5.4 - String Manipulation


      string.sub (s, i [, j])

      Returns the substring of s that starts at i and continues until j; -i and j may be negative. +i and j can 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, @@ -6962,9 +6984,9 @@

      Character Class:

    • [set]: represents the class which is the union of all characters in set. -A range of characters may be specified by +A range of characters can be specified by separating the end characters of the range with a '-'. -All classes %x described above may also be used as +All classes %x described above can also be used as components in set. All other characters in set represent themselves. For example, [%w_] (or [_%w]) @@ -7001,7 +7023,7 @@

      Character Class:

      Pattern Item:

      -A pattern item may be +A pattern item can be

        @@ -7070,7 +7092,7 @@

        Pattern:

        Captures:

        -A pattern may contain sub-patterns enclosed in parentheses; +A pattern can 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. @@ -7320,7 +7342,8 @@

        5.6 - Mathematical Functions

        -Returns the remainder of the division of x by y. +Returns the remainder of the division of x by y +that rounds the quotient towards zero. @@ -7657,7 +7680,7 @@

        5.7 - Input and Output Facilities

      • "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 can 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. @@ -8115,6 +8138,22 @@

      5.8 - Operating System Facilities

      and explicitly removed when no longer needed. +

      +On some systems (POSIX), +this function also creates a file with that name, +to avoid security risks. +(Someone else might create the file with wrong permissions +in the time between getting the name and creating the file.) +You still have to open the file to use it +and to remove it (even if you do not use it). + + +

      +When possible, +you may prefer to use io.tmpfile, +which automatically removes the file when the program ends. + + @@ -8207,7 +8246,7 @@

      5.9 - The Debug Library

      -The returned table may contain all the fields returned by lua_getinfo, +The returned table can 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. @@ -8326,7 +8365,8 @@

      5.9 - The Debug Library

      When the hook is called, its first parameter is a string describing the event that has triggered its call: -"call", "return" (or "tail return"), +"call", "return" (or "tail return", +when simulating a return from a tail call), "line", and "count". For line events, the hook also gets the new line number as its second parameter. @@ -8384,7 +8424,7 @@

      5.9 - The Debug Library

      -


      debug.traceback ([thread,] [message] [, level])

      +

      debug.traceback ([thread,] [message [, level]])

      @@ -8752,12 +8792,12 @@

      8 - The Complete Syntax of Lua


      - + Last update: -Fri Jan 18 22:32:24 BRST 2008 +Mon Feb 13 18:54:19 BRST 2012 diff --git a/doc/readme.html b/doc/readme.html index 972faddd97..3ed6a81895 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.3. +This is the documentation included in the source distribution of Lua 5.1.5.
      • Reference manual @@ -33,7 +33,7 @@


        Last update: -Wed Dec 19 13:59:14 BRST 2007 +Fri Feb 3 09:44:42 BRST 2012 diff --git a/etc/lua.pc b/etc/lua.pc index 19a5c91532..07e2852b0a 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.3 +R= 5.1.5 # grep '^INSTALL_.*=' ../Makefile | sed 's/INSTALL_TOP/prefix/' prefix= /usr/local diff --git a/src/Makefile b/src/Makefile index e4a3cd6108..e0d4c9fa64 100644 --- a/src/Makefile +++ b/src/Makefile @@ -48,7 +48,7 @@ o: $(ALL_O) a: $(ALL_A) $(LUA_A): $(CORE_O) $(LIB_O) - $(AR) $@ $? + $(AR) $@ $(CORE_O) $(LIB_O) # DLL needs all object files $(RANLIB) $@ $(LUA_T): $(LUA_O) $(LUA_A) diff --git a/src/lapi.c b/src/lapi.c index d7e8931e45..5d5145d2eb 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.55.1.3 2008/01/03 15:20:39 roberto Exp $ +** $Id: lapi.c,v 2.55.1.5 2008/07/04 18:41:18 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -93,15 +93,14 @@ void luaA_pushobject (lua_State *L, const TValue *o) { LUA_API int lua_checkstack (lua_State *L, int size) { - int res; + int res = 1; lua_lock(L); - if ((L->top - L->base + size) > LUAI_MAXCSTACK) + if (size > LUAI_MAXCSTACK || (L->top - L->base + size) > LUAI_MAXCSTACK) res = 0; /* stack overflow */ - else { + else if (size > 0) { luaD_checkstack(L, size); if (L->ci->top < L->top + size) L->ci->top = L->top + size; - res = 1; } lua_unlock(L); return res; @@ -930,10 +929,13 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { g->GCthreshold = g->totalbytes - a; else g->GCthreshold = 0; - while (g->GCthreshold <= g->totalbytes) + while (g->GCthreshold <= g->totalbytes) { luaC_step(L); - if (g->gcstate == GCSpause) /* end of cycle? */ - res = 1; /* signal it */ + if (g->gcstate == GCSpause) { /* end of cycle? */ + res = 1; /* signal it */ + break; + } + } break; } case LUA_GCSETPAUSE: { diff --git a/src/lbaselib.c b/src/lbaselib.c index eb06bcef86..2ab550bd48 100644 --- a/src/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.191.1.4 2008/01/20 13:53:22 roberto Exp $ +** $Id: lbaselib.c,v 1.191.1.6 2008/02/14 16:46:22 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -344,10 +344,12 @@ static int luaB_unpack (lua_State *L) { 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) return 0; /* empty range */ - luaL_checkstack(L, n, "table too big to unpack"); - for (; i<=e; i++) /* push arg[i...e] */ + 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; } @@ -526,7 +528,7 @@ static int auxresume (lua_State *L, lua_State *co, int narg) { status = lua_resume(co, narg); if (status == 0 || status == LUA_YIELD) { int nres = lua_gettop(co); - if (!lua_checkstack(L, nres)) + if (!lua_checkstack(L, nres + 1)) luaL_error(L, "too many results to resume"); lua_xmove(co, L, nres); /* move yielded values */ return nres; @@ -629,7 +631,7 @@ static void base_open (lua_State *L) { 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 */ + /* `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 */ diff --git a/src/lcode.c b/src/lcode.c index cff626b7fa..679cb9cfd9 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.25.1.5 2011/01/31 14:53:16 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -544,10 +544,6 @@ 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; @@ -572,10 +568,6 @@ 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; diff --git a/src/ldblib.c b/src/ldblib.c index 67de1222a9..2027eda598 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.104.1.4 2009/08/04 18:50:18 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; } diff --git a/src/ldebug.c b/src/ldebug.c index 9eac4a9b41..50ad3d3803 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.29.1.3 2007/12/28 15:32:23 roberto Exp $ +** $Id: ldebug.c,v 2.29.1.6 2008/05/08 16:56:26 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -275,12 +275,12 @@ 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) || + 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(GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); + check(pt->sizecode > 0 && GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); return 1; } @@ -346,9 +346,18 @@ static Instruction symbexec (const Proto *pt, int lastpc, int reg) { int dest = pc+1+b; check(0 <= dest && dest < pt->sizecode); if (dest > 0) { - /* cannot jump to a setlist count */ - Instruction d = pt->code[dest-1]; - check(!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 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); } } break; @@ -363,7 +372,11 @@ static Instruction symbexec (const Proto *pt, int lastpc, int reg) { } switch (op) { case OP_LOADBOOL: { - check(c == 0 || pc+2 < pt->sizecode); /* check its jump */ + 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); + } break; } case OP_LOADNIL: { @@ -428,7 +441,10 @@ static Instruction symbexec (const Proto *pt, int lastpc, int reg) { } case OP_SETLIST: { if (b > 0) checkreg(pt, a + b); - if (c == 0) pc++; + if (c == 0) { + pc++; + check(pc < pt->sizecode - 1); + } break; } case OP_CLOSURE: { diff --git a/src/ldo.c b/src/ldo.c index 8de05f728e..d1bf786cb7 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.38.1.4 2012/01/18 02:27:10 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -217,6 +217,7 @@ static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { int nvar = actual - nfixargs; /* number of extra arguments */ lua_assert(p->is_vararg & VARARG_HASARG); luaC_checkGC(L); + luaD_checkstack(L, p->maxstacksize); htab = luaH_new(L, nvar, 1); /* create `arg' table */ for (i=0; itop - nvar + i); diff --git a/src/lgc.c b/src/lgc.c index d9e0b78294..e909c79a96 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.38.1.2 2011/03/18 18:05:38 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -627,7 +627,6 @@ void luaC_step (lua_State *L) { } } else { - lua_assert(g->totalbytes >= g->estimate); setthreshold(g); } } diff --git a/src/liolib.c b/src/liolib.c index e79ed1cb2e..649f9a5951 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.73.1.4 2010/05/14 15:33:51 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -276,7 +276,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 */ + } } diff --git a/src/llex.c b/src/llex.c index 6dc319358c..88c6790c07 100644 --- a/src/llex.c +++ b/src/llex.c @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: llex.c,v 2.20.1.2 2009/11/23 14:58:22 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -118,8 +118,10 @@ 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)) + if (ttisnil(o)) { setbvalue(o, 1); /* make sure `str' will not be collected */ + luaC_checkGC(L); + } return ts; } diff --git a/src/loadlib.c b/src/loadlib.c index d955f3ef41..6158c5353d 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.52.1.2 2007/12/28 14:58:43 roberto Exp $ +** $Id: loadlib.c,v 1.52.1.4 2009/09/09 13:17:16 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -506,8 +506,10 @@ static int ll_require (lua_State *L) { static void setfenv (lua_State *L) { lua_Debug ar; - lua_getstack(L, 1, &ar); - lua_getinfo(L, "f", &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); lua_setfenv(L, -2); lua_pop(L, 1); @@ -637,7 +639,7 @@ LUALIB_API int luaopen_package (lua_State *L) { lua_pushvalue(L, -1); lua_replace(L, 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]); diff --git a/src/lobject.h b/src/lobject.h index e7199dfc68..f1e447ef3b 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lobject.h,v 2.20.1.2 2008/08/06 13:29:48 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -208,7 +208,7 @@ typedef union TString { #define getstr(ts) cast(const char *, (ts) + 1) -#define svalue(o) getstr(tsvalue(o)) +#define svalue(o) getstr(rawtsvalue(o)) diff --git a/src/lparser.c b/src/lparser.c index 1e2a9a88b7..dda7488dca 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.42.1.4 2011/10/21 19:31:42 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -374,9 +374,9 @@ 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); + L->top -= 2; /* remove table and prototype from the stack */ } diff --git a/src/lstrlib.c b/src/lstrlib.c index ca333ba168..7a03489beb 100644 --- a/src/lstrlib.c +++ b/src/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.132.1.3 2007/12/28 15:32:23 roberto Exp $ +** $Id: lstrlib.c,v 1.132.1.5 2010/05/14 15:34:19 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -35,7 +35,8 @@ static int str_len (lua_State *L) { static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) { /* relative string position: negative means back from end */ - return (pos>=0) ? pos : (ptrdiff_t)len+pos+1; + if (pos < 0) pos += (ptrdiff_t)len + 1; + return (pos >= 0) ? pos : 0; } @@ -753,6 +754,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); @@ -767,7 +769,8 @@ 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 */ - arg++; + if (++arg > top) + luaL_argerror(L, arg, "no value"); strfrmt = scanformat(L, strfrmt, form); switch (*strfrmt++) { case 'c': { diff --git a/src/ltablib.c b/src/ltablib.c index 06f1c37be1..b6d9cb4ac7 100644 --- a/src/ltablib.c +++ b/src/ltablib.c @@ -1,5 +1,5 @@ /* -** $Id: ltablib.c,v 1.38.1.2 2007/12/28 15:32:23 roberto Exp $ +** $Id: ltablib.c,v 1.38.1.3 2008/02/14 16:46:58 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -132,6 +132,15 @@ static int tremove (lua_State *L) { } +static void addfield (lua_State *L, luaL_Buffer *b, int i) { + lua_rawgeti(L, 1, 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); +} + + static int tconcat (lua_State *L) { luaL_Buffer b; size_t lsep; @@ -141,13 +150,12 @@ static int tconcat (lua_State *L) { 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); - luaL_argcheck(L, lua_isstring(L, -1), 1, "table contains non-strings"); - luaL_addvalue(&b); - if (i != last) - luaL_addlstring(&b, sep, lsep); + for (; i < last; i++) { + addfield(L, &b, i); + luaL_addlstring(&b, sep, lsep); } + if (i == last) /* add last value (if interval was not empty) */ + addfield(L, &b, i); luaL_pushresult(&b); return 1; } diff --git a/src/lua.h b/src/lua.h index 5bc97b746f..a4b73e743e 100644 --- a/src/lua.h +++ b/src/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.218.1.4 2008/01/03 15:41:15 roberto Exp $ +** $Id: lua.h,v 1.218.1.7 2012/01/13 20:36:20 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.3" +#define LUA_RELEASE "Lua 5.1.5" #define LUA_VERSION_NUM 501 -#define LUA_COPYRIGHT "Copyright (C) 1994-2008 Lua.org, PUC-Rio" +#define LUA_COPYRIGHT "Copyright (C) 1994-2012 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" @@ -362,7 +362,7 @@ struct lua_Debug { /****************************************************************************** -* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved. +* Copyright (C) 1994-2012 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 eb2f5a1f71..e2cb26163a 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.82.1.6 2008/01/18 17:07:48 roberto Exp $ +** $Id: luaconf.h,v 1.82.1.7 2008/02/11 16:25:08 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -440,10 +440,10 @@ @* 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. +** functions to consume unlimited stack space. (must be smaller than +** -LUA_REGISTRYINDEX) */ -#define LUAI_MCS_AUX ((int)(INT_MAX / (4*sizeof(LUA_NUMBER)))) -#define LUAI_MAXCSTACK (LUAI_MCS_AUX > SHRT_MAX ? SHRT_MAX : LUAI_MCS_AUX) +#define LUAI_MAXCSTACK 8000 diff --git a/src/lundump.c b/src/lundump.c index 731c064553..8010a45795 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,5 +1,5 @@ /* -** $Id: lundump.c,v 2.7.1.2 2008/01/18 16:39:11 roberto Exp $ +** $Id: lundump.c,v 2.7.1.4 2008/04/04 19:51:41 roberto Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -48,7 +48,6 @@ static void error(LoadState* S, const char* why) static void LoadBlock(LoadState* S, void* b, size_t size) { size_t r=luaZ_read(S->Z,b,size); - UNUSED(r); IF (r!=0, "unexpected end"); } @@ -115,7 +114,7 @@ static void LoadConstants(LoadState* S, Proto* f) setnilvalue(o); break; case LUA_TBOOLEAN: - setbvalue(o,LoadChar(S)); + setbvalue(o,LoadChar(S)!=0); break; case LUA_TNUMBER: setnvalue(o,LoadNumber(S)); @@ -161,7 +160,9 @@ static void LoadDebug(LoadState* S, Proto* f) static Proto* LoadFunction(LoadState* S, TString* p) { - Proto* f=luaF_newproto(S->L); + Proto* f; + if (++S->L->nCcalls > LUAI_MAXCCALLS) error(S,"code 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); @@ -175,6 +176,7 @@ static Proto* LoadFunction(LoadState* S, TString* p) LoadDebug(S,f); IF (!luaG_checkcode(f), "bad code"); S->L->top--; + S->L->nCcalls--; return f; } diff --git a/src/lvm.c b/src/lvm.c index ee3256ab94..e0a0cd8521 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.63.1.5 2011/08/17 20:43:11 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -133,6 +133,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? */ @@ -141,6 +142,7 @@ 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); + h->flags = 0; luaC_barriert(L, h, val); return; } @@ -152,7 +154,9 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { callTM(L, tm, t, key, val); 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"); } From 124c2a87beb06b8200f8a692b0fea6a665a9350d Mon Sep 17 00:00:00 2001 From: Kate Adams Date: Sun, 4 Jan 2015 08:32:32 +0000 Subject: [PATCH 28/40] Import Lua 5.2.1 --- COPYRIGHT | 34 - HISTORY | 183 - INSTALL | 99 - Makefile | 110 +- README | 37 +- doc/contents.html | 282 +- doc/cover.png | Bin 3305 -> 0 bytes doc/lua.1 | 121 +- doc/lua.html | 172 - doc/luac.1 | 86 +- doc/luac.html | 145 - doc/manual.html | 7309 +++++++++++++++++++++-------------- doc/osi-certified-72x60.png | Bin 0 -> 3774 bytes doc/readme.html | 400 +- etc/Makefile | 44 - etc/README | 37 - etc/all.c | 38 - etc/lua.ico | Bin 1078 -> 0 bytes etc/lua.pc | 31 - etc/luavs.bat | 28 - etc/min.c | 39 - etc/noparser.c | 50 - etc/strict.lua | 41 - src/Makefile | 165 +- src/lapi.c | 838 ++-- src/lapi.h | 14 +- src/lauxlib.c | 948 +++-- src/lauxlib.h | 126 +- src/lbaselib.c | 562 +-- src/lbitlib.c | 209 + src/lcode.c | 391 +- src/lcode.h | 21 +- src/lcorolib.c | 155 + src/lctype.c | 52 + src/lctype.h | 95 + src/ldblib.c | 214 +- src/ldebug.c | 616 ++- src/ldebug.h | 27 +- src/ldo.c | 655 ++-- src/ldo.h | 33 +- src/ldump.c | 43 +- src/lfunc.c | 81 +- src/lfunc.h | 7 +- src/lgc.c | 1401 ++++--- src/lgc.h | 153 +- src/linit.c | 45 +- src/liolib.c | 495 ++- src/llex.c | 360 +- src/llex.h | 27 +- src/llimits.h | 221 +- src/lmathlib.c | 98 +- src/lmem.c | 45 +- src/lmem.h | 21 +- src/loadlib.c | 609 +-- src/lobject.c | 239 +- src/lobject.h | 463 ++- src/lopcodes.c | 31 +- src/lopcodes.h | 106 +- src/loslib.c | 148 +- src/lparser.c | 1010 +++-- src/lparser.h | 75 +- src/lstate.c | 266 +- src/lstate.h | 149 +- src/lstring.c | 174 +- src/lstring.h | 21 +- src/lstrlib.c | 407 +- src/ltable.c | 212 +- src/ltable.h | 15 +- src/ltablib.c | 130 +- src/ltm.c | 20 +- src/ltm.h | 9 +- src/lua.c | 310 +- src/lua.h | 219 +- {etc => src}/lua.hpp | 0 src/luac.c | 332 +- src/luaconf.h | 675 ++-- src/lualib.h | 28 +- src/lundump.c | 141 +- src/lundump.h | 22 +- src/lvm.c | 919 +++-- src/lvm.h | 27 +- src/lzio.c | 34 +- src/lzio.h | 8 +- src/print.c | 227 -- 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/hello.lua | 3 - 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 | 14 - 104 files changed, 14287 insertions(+), 10653 deletions(-) delete mode 100644 COPYRIGHT delete mode 100644 HISTORY delete mode 100644 INSTALL delete mode 100644 doc/cover.png delete mode 100644 doc/lua.html delete mode 100644 doc/luac.html create mode 100644 doc/osi-certified-72x60.png delete mode 100644 etc/Makefile delete mode 100644 etc/README delete mode 100644 etc/all.c delete mode 100644 etc/lua.ico delete mode 100644 etc/lua.pc delete mode 100644 etc/luavs.bat delete mode 100644 etc/min.c delete mode 100644 etc/noparser.c delete mode 100644 etc/strict.lua create mode 100644 src/lbitlib.c create mode 100644 src/lcorolib.c create mode 100644 src/lctype.c create mode 100644 src/lctype.h rename {etc => src}/lua.hpp (100%) delete mode 100644 src/print.c 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/hello.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/COPYRIGHT b/COPYRIGHT deleted file mode 100644 index a86026803a..0000000000 --- a/COPYRIGHT +++ /dev/null @@ -1,34 +0,0 @@ -Lua License ------------ - -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. - -For details and rationale, see http://www.lua.org/license.html . - -=============================================================================== - -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 "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. - -=============================================================================== - -(end of COPYRIGHT) diff --git a/HISTORY b/HISTORY deleted file mode 100644 index ce0c95bc69..0000000000 --- a/HISTORY +++ /dev/null @@ -1,183 +0,0 @@ -HISTORY for Lua 5.1 - -* 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 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). - + luaopen_* functions must be called through Lua. - Implementation: - + new configuration scheme via luaconf.h. - + 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. - + 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 - ------------------------------- - 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 - ------------------------------- - 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: - + 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. - + 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 - ------------------------------- - + redirected all output in Lua's core to _ERRORMESSAGE and _ALERT. - + increased limit on the number of constants and globals per function - (from 2^16 to 2^24). - + debugging info (lua_debug and hooks) moved into lua_state and new API - functions provided to get and set this info. - + new debug lib gives full debugging access within Lua. - + new table functions "foreachi", "sort", "tinsert", "tremove", "getn". - + new io functions "flush", "seek". - -* Changes from version 3.0 to 3.1 - ------------------------------- - + NEW FEATURE: anonymous functions with closures (via "upvalues"). - + new syntax: - - local variables in chunks. - - better scope control with DO block END. - - constructors can now be also written: { record-part; list-part }. - - more general syntax for function calls and lvalues, e.g.: - f(x).y=1 - o:f(x,y):g(z) - f"string" is sugar for f("string") - + strings may now contain arbitrary binary data (e.g., embedded zeros). - + major code re-organization and clean-up; reduced module interdependecies. - + no arbitrary limits on the total number of constants and globals. - + support for multiple global contexts. - + better syntax error messages. - + new traversal functions "foreach" and "foreachvar". - + the default for numbers is now double. - changing it to use floats or longs is easy. - + complete debug information stored in pre-compiled chunks. - + sample interpreter now prompts user when run interactively, and also - handles control-C interruptions gracefully. - -* Changes from version 2.5 to 3.0 - ------------------------------- - + NEW CONCEPT: "tag methods". - Tag methods replace fallbacks as the meta-mechanism for extending the - semantics of Lua. Whereas fallbacks had a global nature, tag methods - work on objects having the same tag (e.g., groups of tables). - Existing code that uses fallbacks should work without change. - + new, general syntax for constructors {[exp] = exp, ... }. - + support for handling variable number of arguments in functions (varargs). - + support for conditional compilation ($if ... $else ... $end). - + cleaner semantics in API simplifies host code. - + better support for writing libraries (auxlib.h). - + better type checking and error messages in the standard library. - + luac can now also undump. - -* Changes from version 2.4 to 2.5 - ------------------------------- - + io and string libraries are now based on pattern matching; - the old libraries are still available for compatibility - + dofile and dostring can now return values (via return statement) - + better support for 16- and 64-bit machines - + expanded documentation, with more examples - -* Changes from version 2.2 to 2.4 - ------------------------------- - + external compiler creates portable binary files that can be loaded faster - + interface for debugging and profiling - + new "getglobal" fallback - + new functions for handling references to Lua objects - + new functions in standard lib - + only one copy of each string is stored - + expanded documentation, with more examples - -* Changes from version 2.1 to 2.2 - ------------------------------- - + functions now may be declared with any "lvalue" as a name - + garbage collection of functions - + support for pipes - -* Changes from version 1.1 to 2.1 - ------------------------------- - + object-oriented support - + fallbacks - + simplified syntax for tables - + many internal improvements - -(end of HISTORY) diff --git a/INSTALL b/INSTALL deleted file mode 100644 index 17eb8aee8c..0000000000 --- a/INSTALL +++ /dev/null @@ -1,99 +0,0 @@ -INSTALL for Lua 5.1 - -* Building Lua - ------------ - Lua is built in the src directory, but the build process can be - controlled from the top-level Makefile. - - 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: - 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. - - 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 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: - - 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. - - See below for instructions for Windows and other systems. - -* 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 don't actually need to edit the Makefiles because you may set the - relevant variables when invoking make. - - 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 - 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 Windows). See src/luaconf.h and also src/Makefile. - -* Building Lua on Windows and 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 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. - - As mentioned above, you may edit luaconf.h to select some features before - building Lua. - -(end of INSTALL) diff --git a/Makefile b/Makefile index 209a132441..bd9515fd84 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,5 @@ -# makefile for installing Lua -# see INSTALL for installation instructions -# see src/Makefile and src/luaconf.h for further customization +# Makefile for installing Lua +# See doc/readme.html for installation and customization instructions. # == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= @@ -8,55 +7,55 @@ 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 probably want to make INSTALL_LMOD and INSTALL_CMOD consistent with -# LUA_ROOT, LUA_LDIR, and LUA_CDIR in luaconf.h (and also with etc/lua.pc). 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 (do "make ranlib"). +# 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 # -# If you don't have install you can use cp instead. +# If you don't have "install" you can use "cp" instead. # INSTALL= cp -p # INSTALL_EXEC= $(INSTALL) # INSTALL_DATA= $(INSTALL) -# Utilities. +# Other utilities. MKDIR= mkdir -p -RANLIB= ranlib +RM= rm -f -# == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= +# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE ======= # Convenience platforms targets. PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris # What to install. TO_BIN= lua luac -TO_INC= lua.h luaconf.h lualib.h lauxlib.h ../etc/lua.hpp +TO_INC= lua.h luaconf.h lualib.h lauxlib.h lua.hpp TO_LIB= liblua.a TO_MAN= lua.1 luac.1 # Lua version and release. -V= 5.1 -R= 5.1.5 +V= 5.2 +R= $V.1 +# Targets start here. all: $(PLAT) $(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) @@ -65,62 +64,49 @@ install: dummy cd src && $(INSTALL_DATA) $(TO_LIB) $(INSTALL_LIB) cd doc && $(INSTALL_DATA) $(TO_MAN) $(INSTALL_MAN) -ranlib: - cd src && cd $(INSTALL_LIB) && $(RANLIB) $(TO_LIB) +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) local: - $(MAKE) install INSTALL_TOP=.. + $(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 INSTALL for complete instructions." + @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 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 11b4dff70e..253d110692 100644 --- a/README +++ b/README @@ -1,37 +1,6 @@ -README for Lua 5.1 -See INSTALL for installation instructions. -See HISTORY for a summary of changes since the last released version. +This is Lua 5.2.1, released on 08 Jun 2012. -* 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. Lua is free software. +For installation instructions, license details, and +further information about Lua, see doc/readme.html. - 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.lua.org/uses.html . - -* Availability - ------------ - 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 at http://www.lua.org/download.html . - -* Installation - ------------ - Lua is implemented in pure ANSI C, and compiles unmodified in all known - platforms that have an ANSI C compiler. In most Unix-like platforms, simply - do "make" with a suitable target. See INSTALL for detailed instructions. - -* Origin - ------ - 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 3d83da98a6..9f5060519f 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -1,12 +1,13 @@ -Lua 5.1 Reference Manual - contents +Lua 5.2 Reference Manual - contents - + @@ -16,32 +17,13 @@

        -Lua 5.1 Reference Manual +Lua 5.2 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. - -

        -This manual is also available as a book: -

        - - - -Lua 5.1 Reference Manual -
        by R. Ierusalimschy, L. H. de Figueiredo, W. Celes -
        Lua.org, August 2006 -
        ISBN 85-903798-3-3 -
        -
        - -

        -Buy a copy -of this book and -help to support -the Lua project. +Programming in Lua.

        start @@ -49,11 +31,9 @@

        contents · index -· -other versions
        -Copyright © 2006–2012 Lua.org, PUC-Rio. +Copyright © 2011–2012 Lua.org, PUC-Rio. Freely available under the terms of the Lua license. @@ -62,91 +42,95 @@

        Contents

    Lua functions

    +

    _G
    _VERSION
    -

    +

    assert
    collectgarbage
    dofile
    error
    -getfenv
    getmetatable
    ipairs
    -load
    loadfile
    -loadstring
    -module
    +load
    next
    pairs
    pcall
    print
    rawequal
    rawget
    +rawlen
    rawset
    require
    select
    -setfenv
    setmetatable
    tonumber
    tostring
    type
    -unpack
    xpcall
    +

    +bit32.arshift
    +bit32.band
    +bit32.bnot
    +bit32.bor
    +bit32.btest
    +bit32.bxor
    +bit32.extract
    +bit32.lrotate
    +bit32.lshift
    +bit32.replace
    +bit32.rrotate
    +bit32.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
    debug.setupvalue
    debug.traceback
    +debug.upvalueid
    +debug.upvaluejoin
    -

    -

     

    +

    file:close
    file:flush
    file:lines
    @@ -220,8 +215,8 @@

     

    file:seek
    file:setvbuf
    file:write
    -

    +

    io.close
    io.flush
    io.input
    @@ -236,8 +231,11 @@

     

    io.tmpfile
    io.type
    io.write
    -

    +

    +

     

    +

    math.abs
    math.acos
    math.asin
    @@ -254,7 +252,6 @@

     

    math.huge
    math.ldexp
    math.log
    -math.log10
    math.max
    math.min
    math.modf
    @@ -268,8 +265,8 @@

     

    math.sqrt
    math.tan
    math.tanh
    -

    +

    os.clock
    os.date
    os.difftime
    @@ -281,17 +278,18 @@

     

    os.setlocale
    os.time
    os.tmpname
    -

    +

    +package.config
    package.cpath
    package.loaded
    -package.loaders
    package.loadlib
    package.path
    package.preload
    -package.seeall
    -

    +package.searchers
    +package.searchpath
    +

    string.byte
    string.char
    string.dump
    @@ -306,17 +304,19 @@

     

    string.reverse
    string.sub
    string.upper
    -

    +

    table.concat
    table.insert
    -table.maxn
    +table.pack
    table.remove
    table.sort
    +table.unpack

    C API

    +

    lua_Alloc
    lua_CFunction
    lua_Debug
    @@ -325,22 +325,26 @@

    C API

    lua_Number
    lua_Reader
    lua_State
    +lua_Unsigned
    lua_Writer
    -

    +

    +lua_absindex
    +lua_arith
    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_getfenv
    +lua_getctx
    lua_getfield
    lua_getglobal
    lua_gethook
    @@ -353,6 +357,7 @@

    C API

    lua_gettable
    lua_gettop
    lua_getupvalue
    +lua_getuservalue
    lua_insert
    lua_isboolean
    lua_iscfunction
    @@ -366,15 +371,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
    @@ -393,14 +398,16 @@

    C API

    lua_rawequal
    lua_rawget
    lua_rawgeti
    +lua_rawlen
    lua_rawset
    lua_rawseti
    +lua_rawgetp
    +lua_rawsetp
    lua_register
    lua_remove
    lua_replace
    lua_resume
    lua_setallocf
    -lua_setfenv
    lua_setfield
    lua_setglobal
    lua_sethook
    @@ -409,29 +416,39 @@

    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
    +lua_tounsigned
    +lua_tounsignedx
    lua_touserdata
    lua_type
    lua_typename
    +lua_upvalueid
    lua_upvalueindex
    +lua_upvaluejoin
    +lua_version
    lua_xmove
    lua_yield
    +lua_yieldk

    auxiliary library

    +

    luaL_Buffer
    luaL_Reg
    -

    +

    luaL_addchar
    luaL_addlstring
    luaL_addsize
    @@ -440,10 +457,11 @@

    auxiliary library

    luaL_argcheck
    luaL_argerror
    luaL_buffinit
    +luaL_buffinitsize
    luaL_callmeta
    luaL_checkany
    -luaL_checkint
    luaL_checkinteger
    +luaL_checkint
    luaL_checklong
    luaL_checklstring
    luaL_checknumber
    @@ -452,45 +470,61 @@

    auxiliary library

    luaL_checkstring
    luaL_checktype
    luaL_checkudata
    +luaL_checkunsigned
    +luaL_checkversion
    luaL_dofile
    luaL_dostring
    luaL_error
    +luaL_execresult
    +luaL_fileresult
    luaL_getmetafield
    luaL_getmetatable
    +luaL_getsubtable
    luaL_gsub
    +luaL_len
    luaL_loadbuffer
    +luaL_loadbufferx
    luaL_loadfile
    +luaL_loadfilex
    luaL_loadstring
    +luaL_newlib
    +luaL_newlibtable
    luaL_newmetatable
    luaL_newstate
    luaL_openlibs
    -luaL_optint
    luaL_optinteger
    +luaL_optint
    luaL_optlong
    luaL_optlstring
    luaL_optnumber
    luaL_optstring
    +luaL_optunsigned
    luaL_prepbuffer
    +luaL_prepbuffsize
    luaL_pushresult
    +luaL_pushresultsize
    luaL_ref
    -luaL_register
    +luaL_requiref
    +luaL_setfuncs
    +luaL_setmetatable
    +luaL_testudata
    +luaL_tolstring
    +luaL_traceback
    luaL_typename
    -luaL_typerror
    luaL_unref
    luaL_where
    -


    Last update: -Mon Feb 13 18:53:32 BRST 2012 +Sat May 26 08:52:25 BRT 2012 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/lua.1 b/doc/lua.1 index 24809cc6c1..1dbf04366c 100644 --- a/doc/lua.1 +++ b/doc/lua.1 @@ -1,5 +1,5 @@ -.\" $Id: lua.man,v 1.11 2006/01/06 16:03:34 lhf Exp $ -.TH LUA 1 "$Date: 2006/01/06 16:03:34 $" +.\" $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 @@ -15,7 +15,7 @@ lua \- Lua interpreter ] .SH DESCRIPTION .B lua -is the stand-alone Lua interpreter. +is the standalone Lua interpreter. It loads and executes Lua programs, either in textual source form or in precompiled binary form. @@ -27,8 +27,7 @@ can be used as a batch interpreter and also interactively. .LP The given .I options -(see below) -are executed and then +are handled in order and then the Lua program in file .I script is loaded and executed. @@ -38,45 +37,7 @@ 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, +If no options or arguments are given, then .B "\-v \-i" is assumed when the standard input is a terminal; @@ -93,71 +54,63 @@ 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 -(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 ">> ". +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 -.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. +enter interactive mode after executing +.IR script . .TP .BI \-l " name" -call -.BI require(' name ') +execute the equivalent of +.IB name =require(' name ') before executing .IR script . -Typically used to load libraries. .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 -http://www.lua.org/ +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, -and W. Celes .\" EOF diff --git a/doc/lua.html b/doc/lua.html deleted file mode 100644 index 1d435ab029..0000000000 --- a/doc/lua.html +++ /dev/null @@ -1,172 +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 -(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, -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 name -call -require('name') -before executing -script. -Typically used to load libraries. -

    --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 - - - diff --git a/doc/luac.1 b/doc/luac.1 index d8146782df..33a4ed00ac 100644 --- a/doc/luac.1 +++ b/doc/luac.1 @@ -1,5 +1,5 @@ -.\" $Id: luac.man,v 1.28 2006/01/06 16:03:34 lhf Exp $ -.TH LUAC 1 "$Date: 2006/01/06 16:03:34 $" +.\" $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 @@ -13,29 +13,29 @@ luac \- Lua compiler .B luac is the Lua compiler. It translates programs written in the Lua programming language -into binary files that can be later loaded and executed. +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. -.LP -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. .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 -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 +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 bytecodes -for all source files given. +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 , @@ -43,32 +43,15 @@ but you can change this with the .B \-o option. .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 +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. -So, -save the source files of all Lua programs that you precompile. +Make sure you 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. @@ -78,6 +61,9 @@ If no files are given, then loads .B luac.out and lists its contents. +Use +.B \-l \-l +for a full listing. .TP .BI \-o " file" output to @@ -88,7 +74,7 @@ instead of the default .B "'\-'" for standard output, but not on platforms that open standard output in text mode.) -The output file may be a source file because +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 @@ -96,41 +82,37 @@ Be careful not to overwrite precious files. 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. +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. -For instance, +In particular, line numbers and names of local variables are lost. .TP .B \-v show version information. -.SH FILES -.TP 15 -.B luac.out -default output file +.TP +.B \-\- +stop handling options. +.TP +.B \- +stop handling options and process standard input. .SH "SEE ALSO" .BR lua (1) .br -http://www.lua.org/ +The documentation at lua.org. .SH DIAGNOSTICS Error messages should be self explanatory. .SH AUTHORS +R. Ierusalimschy, L. H. de Figueiredo, -R. Ierusalimschy and W. Celes .\" EOF diff --git a/doc/luac.html b/doc/luac.html deleted file mode 100644 index 179ffe8288..0000000000 --- a/doc/luac.html +++ /dev/null @@ -1,145 +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 later loaded and executed. -

    -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. -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. -

    -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. -By default, -the output file is named -luac.out, -but you can change this with the --o -option. -

    -In the command line, -you can mix -text files containing Lua source and -binary files containing precompiled chunks. -This is useful because several precompiled chunks, -even from different (but compatible) platforms, -can be combined 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. -(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. -

    --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 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

    -

    -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 - - - diff --git a/doc/manual.html b/doc/manual.html index 4e41683d02..4ba084dfc8 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -2,7 +2,7 @@ -Lua 5.1 Reference Manual +Lua 5.2 Reference Manual @@ -13,13 +13,13 @@

    -Lua 5.1 Reference Manual +Lua 5.2 Reference Manual

    by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes

    -Copyright © 2006–2012 Lua.org, PUC-Rio. +Copyright © 2011–2012 Lua.org, PUC-Rio. Freely available under the terms of the Lua license. @@ -29,18 +29,16 @@

    contents · index -· -other versions

    - + -

    1 - Introduction

    +

    1 – Introduction

    Lua is an extension programming language designed to support @@ -48,24 +46,25 @@

    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 implemented as a library, written in clean C -(that is, in the common subset of ANSI C and C++). +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++.

    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, stand-alone Lua interpreter. +which uses the Lua library to offer a complete, standalone Lua interpreter, +for interactive or batch use.

    @@ -82,170 +81,18 @@

    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). - - - -

    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

    - -

    -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: - - -

    -     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 -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 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. -Literals in this bracketed form can run for several lines, -do not interpret any escape sequences, -and ignore long brackets of any other level. -They can contain anything except a closing bracket of the proper level. - - -

    -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: +see Roberto's book, Programming in Lua. -

    -     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 the basic concepts of the language. -

    2.2 - Values and Types

    +

    2.1 – Values and Types

    Lua is a dynamically typed language. @@ -273,32 +120,38 @@

    2.2 - 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 float or long integers; +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 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).

    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 -(see §2.8). +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. This guarantees the integrity of data owned by the host program. @@ -306,7 +159,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. @@ -315,26 +168,50 @@

    2.2 - 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 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). + + +

    +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).

    Like indices, -the value of a table field can be of any type (except nil). +the values of table fields 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 §2.5.9). +Thus tables can also carry methods (see §3.4.10). + + +

    +The indexing of tables follows +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 and j are raw equal +(that is, equal without metamethods).

    @@ -348,1892 +225,2235 @@

    2.2 - Values and Types

    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 -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). +of a given value (see §6.1). +

    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 local variable called _ENV (see §3.3.2), +so _ENV itself is never a global name in a chunk. -

    2.3 - Variables

    -Variables are places that store values. - -There are three kinds of variables in Lua: -global variables, local variables, and table fields. +Despite the existence of this external _ENV variable and +the translation of global names, +_ENV is a completely regular name. +In particular, +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 (see §3.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 §2.1. +Any table used as the value of _ENV is called an environment.

    -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). +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.

    -Before the first assignment to a variable, its value is nil. +When Lua compiles a chunk, +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 +and several functions there operate on that 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.)

    -Square brackets are used to index a table: +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 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. -

    -	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.3 – Error Handling

    -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 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 getfenv. -To replace it, -you call setfenv. -(You can only manipulate the environment of C functions -through the debug library; (see §5.9).) +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 +the compilation or execution of a Lua chunk, +control returns to the host, +which can take appropriate measures +(such as printing an error message).

    -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.) +Lua code can explicitly generate an error by calling the +error function. +If you need to catch errors in Lua, +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 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. +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; +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. -

    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. -

    2.4.1 - Chunks

    +

    2.4 – Metatables and Metamethods

    -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. +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" of the value's metatable. +If it finds one, +Lua calls this function to perform the addition.

    -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. +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.

    -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. +You can query the metatable of any value +using the getmetatable function.

    -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. +You can replace the metatable of tables +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. +

    +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). +

    +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 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) +controls how Lua will perform the operation. -

    2.4.2 - Blocks

    -A block is a list of statements; -syntactically, a block is the same as a chunk: +

    +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". -

    -	block ::= chunk
    -

    -A block can be explicitly delimited to produce a single statement: - -

    -	stat ::= do block end
    +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.
    +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
    +
    +
    +     metatable(obj)[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). +This should be read as +

    +     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). +

    +For the unary - and # operators, +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. +(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). - - -

      -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). +

    • +
    • "concat": +the .. (concatenation) 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 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 return statement is used to return values -from a function or a chunk (which is just a function). +

    • "len": +the # operation. -Functions and chunks can return more than one value, -and so the syntax for the return statement is
      -	stat ::= return [explist]
      -
      + 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 break statement is used to terminate the execution of a -while, repeat, or for loop, -skipping to the next statement after the loop: +

  • "eq": +the == operation. +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, +and the values are either tables or full userdata.
    -	stat ::= break
    +     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
     

    -A break ends the innermost enclosing loop. +The "eq" event is defined as follows: + +

    +     function eq_event (op1, op2)
    +       if op1 == op2 then   -- primitive equal?
    +         return true   -- values are equal
    +       end
    +       -- try metamethod
    +       local h = getequalhandler(op1, op2)
    +       if h then
    +         return not not h(op1, op2)
    +       else
    +         return false
    +       end
    +     end
    +

    +Note that the result is always a boolean. +

  • +
  • "lt": +the < operation. -

    -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. +

    +     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 not not h(op1, op2)
    +         else
    +           error(···)
    +         end
    +       end
    +     end
    +

    +Note that the result is always a boolean. +

  • +
  • "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 = getbinhandler(op1, op2, "__le")
    +         if h then
    +           return not not 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). -

    2.4.5 - For Statement

    +As with the other comparison operators, +the result is always a boolean. +

  • -The for statement has two forms: -one numeric and one generic. +
  • "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.) -

    -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
    +     function gettable_event (table, key)
    +       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
    +       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
     

    -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 +

  • + +
  • "newindex": +The indexing assignment table[key] = value. +Note that the metamethod is tried only +when key is not present in table. +
    -     for v = e1, e2, e3 do block end
    +     function settable_event (table, key, value)
    +       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
    +       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
     

    -is equivalent to the code: +

  • + +
  • "call": +called when Lua calls a value. +
    -     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 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
     

    -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. -
  • -
  • -You can use break to exit a for loop. -
  • +

    2.5 – Garbage Collection

    -
  • -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. -
  • +

    +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: +strings, tables, userdata, functions, threads, internal structures, etc. -

    -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: +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 +(e.g., a value of 100 means an internal value of 1). -

    -	stat ::= for namelist in explist do block end
    -	namelist ::= Name {`,´ Name}
    -

    -A for statement like -

    -     for var_1, ···, var_n in explist do block end
    -

    -is equivalent to the code: +

    +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. -

    -     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: -

      +

      +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 is 200, +which means that the collector runs at "twice" +the speed of memory allocation. -

    • -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. -
    • +

      +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 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. -
    • +

      +You can change these numbers by calling lua_gc in C +or collectgarbage in Lua. +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.4.6 - Function Calls as Statements

    -To allow possible side-effects, -function calls can be executed as statements: +

    2.5.1 – Garbage-Collection Metamethods

    -
    -	stat ::= functioncall
    -

    -In this case, all returned values are thrown away. -Function calls are explained in §2.5.8. +

    +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 +(such as closing files, network or database connections, +or freeing your own memory). +

    +For an object (table or userdata) to be finalized when collected, +you must mark it for finalization. +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 object will not be marked for finalization. +However, after an object is marked, +you can freely change the __gc field of its metatable. -

    2.4.7 - Local Declarations

    -Local variables can be declared anywhere inside a block. -The declaration can include an initial assignment: +

    +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 object in that list:

    -	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. + function gc_event (obj) + local h = metatable(obj).__gc + if type(h) == "function" then + h(obj) + end + end +

    + +

    +At the end of each garbage-collection cycle, +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 object marked last in the program. +The execution of each finalizer may occur at any point during +the execution of the regular code.

    -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. +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.

    -The visibility rules for local variables are explained in §2.6. +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. +

    2.5.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. -

    2.5 - Expressions

    -The basic expressions in Lua are the following: +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. -

    -	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 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 through its value, +the pair is removed.

    -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). +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.

    -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. +Only objects that have an explicit construction +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). +Although strings are subject to garbage collection, +they do not have an explicit construction, +and therefore are not removed from weak tables.

    -Here are some examples: +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. -

    -     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.) - - - -

    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. +If a weak table is among the resurrected objects in a collection cycle, +it may not be properly cleared until the next cycle. -

    2.5.2 - Relational Operators

    -The relational operators in Lua are -

    -     ==    ~=    <     >     <=    >=
    -

    -These operators always result in false or true. +

    2.6 – Coroutines

    -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. +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 can change the way that Lua compares tables and userdata -by using the "eq" metamethod (see §2.8). +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.

    -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. +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, +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.

    -The operator ~= is exactly the negation of equality (==). +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 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. - - - +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. -

    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. +

    +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 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: +As an example of how coroutines work, +consider the following code:

    -     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
    +     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"))
     

    -(In this manual, ---> indicates the result of the preceding expression.) - - - +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.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). +

    +You can also create and manipulate coroutines through the C API: +see functions lua_newthread, lua_resume, +and lua_yield. -

    2.5.5 - The Length Operator

    +

    3 – The Language

    -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). +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 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, 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 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). - - +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 §9 +at the end of this manual. -

    2.5.6 - Precedence

    -Operator precedence in Lua follows the table below, -from lower to higher priority: +

    3.1 – Lexical Conventions

    -
    -     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. +

    +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. +Identifiers are used to name variables, table fields, and labels. +

    +The following keywords are reserved +and cannot be used as names: -

    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 ::= `,´ | `;´
    +     and       break     do        else      elseif    end
    +     false     for       function  goto      if        in
    +     local     nil       not       or        repeat    return
    +     then      true      until     while
     

    -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, +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. -

    -     a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }
    -

    -is equivalent to + +

    +The following strings denote other tokens:

    -     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). +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 '\z' skips the following span +of white-space characters, +including line breaks; +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.

    -The field list can have an optional trailing separator, -as a convenience for machine-generated code. +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, +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 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, +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. +

    +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. -

    2.5.8 - Function Calls

    -A function call in Lua has the following syntax: +

    +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:

    -	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.8). - + a = 'alo\n123"' + a = "alo\n123\"" + a = '\97lo\10\04923"' + a = [[alo + 123"]] + a = [==[ + alo + 123"]==] +

    -The form +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 'p' or 'P'. +Examples of valid numerical constants are

    -	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. + 3 3.0 3.1416 314.16e-2 0.31416E1 + 0xff 0x0.1E 0xA23p-4 0X1.921FB54442D18P+1 + + +

    +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. + + + +

    3.2 – Variables

    +

    -Arguments have the following syntax: +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 function's formal parameter, +which is a particular kind of local variable):

    -	args ::= `(´ [explist] `)´
    -	args ::= tableconstructor
    -	args ::= String
    +	var ::= Name
     

    -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. +Name denotes identifiers, as defined in §3.1. + + +

    +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.

    -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 +Square brackets are used to index a table:

    -     a = f
    -     (g).x(a)
    +	var ::= prefixexp ‘[’ exp ‘]

    -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). +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.)

    -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 syntax var.Name is just syntactic sugar for +var["Name"]:

    -     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
    +	var ::= prefixexp ‘.’ Name
     
    +

    +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). -

    2.5.9 - Function Definitions

    -

    -The syntax for function definition is -

    -	function ::= function funcbody
    -	funcbody ::= `(´ [parlist] `)´ block end
    -
    +

    3.3 – Statements

    -The following syntactic sugar simplifies function definitions: +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. -

    -	stat ::= function funcname funcbody
    -	stat ::= local function Name funcbody
    -	funcname ::= Name {`.´ Name} [`:´ Name]
    -

    -The statement -

    -     function f () body end
    -

    -translates to -

    -     f = function () body end
    -

    -The statement +

    3.3.1 – Blocks

    -
    -     function t.a.b.c.f () body end
    -

    -translates to +

    +A block is a list of statements, +which are executed sequentially:

    -     t.a.b.c.f = function () body end
    +	block ::= {stat}
     

    -The statement +Lua has empty statements +that allow you to separate statements with semicolons, +start a block with a semicolon +or write two semicolons in sequence:

    -     local function f () body end
    -

    -translates to + stat ::= ‘;’ + -

    -     local f; f = function () body end
    -

    -not to +

    +A block can be explicitly delimited to produce a single statement:

    -     local f = function () body end
    +	stat ::= do block end
     

    -(This only makes a difference when the body of the function -contains references to f.) - +Explicit blocks are useful +to control the scope of variable declarations. +Explicit blocks are also sometimes used to +add a return statement in the middle +of another block (see §3.3.4). -

    -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. -

    -Parameters act as local variables that are -initialized with the argument values: -

    -	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). +

    3.3.2 – Chunks

    -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: +The unit of execution of Lua is called a chunk. +Syntactically, +a chunk is simply a block:

    -     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
    +	chunk ::= block
     

    -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. +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). +The resulting function always has _ENV as its only upvalue, +even if it does not use that variable.

    -The colon syntax -is used for defining methods, -that is, functions that have an implicit extra parameter self. -Thus, the statement +A chunk can be stored in a file or in a string inside the host program. +To execute a chunk, +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. -

    -     function t.a.b.c:f (params) body end
    -

    -is syntactic sugar for -

    -     t.a.b.c.f = function (self, params) body end
    -
    +

    +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. -

    2.6 - Visibility Rules

    +

    3.3.3 – Assignment

    - -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: +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:

    -     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. + stat ::= varlist ‘=’ explist + varlist ::= var {‘,’ var} + explist ::= exp {‘,’ exp} +

    +Expressions are discussed in §3.4.

    -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. +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).

    -Notice that each execution of a local statement -defines new local variables. -Consider the following example: +The assignment statement first evaluates all its expressions +and only then are the assignments performed. +Thus the code

    -     a = {}
    -     local x = 20
    -     for i=1,10 do
    -       local y = 0
    -       a[i] = function () y=y+1; return x+y end
    -     end
    +     i = 3
    +     i, a[i] = i+1, 20
     

    -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. +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, +and +

    +     x, y, z = y, z, x
    +

    +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.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.) -

    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). +An assignment to a global variable x = val +is equivalent to the assignment +_ENV.x = val (see §2.2). -

    -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. +

    3.3.4 – Control Structures

    +The control structures +if, while, and repeat have the usual meaning and +familiar syntax: -

    2.8 - Metatables

    -

    -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. + +

    +	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 §3.3.5).

    -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 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).

    -You can query the metatable of any value -through the getmetatable function. +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.

    -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. +The goto statement transfers the program control to a label. +For syntactical reasons, +labels in Lua are considered statements too: -

    -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. +

    +	stat ::= goto Name
    +	stat ::= label
    +	label ::= ‘::’ Name ‘::’
    +

    -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 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.

    -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. +Labels and empty statements are called void statements, +as they perform no actions.

    -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 break statement terminates the execution of a +while, repeat, or for loop, +skipping to the next statement after the loop: +

    -     metatable(obj)[event]
    +	stat ::= break
     

    -This should be read as +A break ends the innermost enclosing loop. + + +

    +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

    -     rawget(getmetatable(obj) or {}, event)
    -

    + stat ::= return [explist] [‘;’] + -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). +

    +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 idiom do return end, +because now return is the last statement in its (inner) block. -

      -
    • "add": -the + operation. +

      3.3.5 – For Statement

      + +

      + +The for statement has two forms: +one numeric and one generic.

      -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. +The numeric for loop repeats a block of code while a +control variable runs through an arithmetic progression. +It has the following syntax:

      -     function getbinhandler (op1, op2, event)
      -       return metatable(op1)[event] or metatable(op2)[event]
      -     end
      +	stat ::= for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end
       

      -By using this function, -the behavior of the op1 + op2 is +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

      -     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
      +     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: -
    • "sub": -the - operation. +
        -Behavior similar to the "add" operation. +
      • +All three control expressions are evaluated only once, +before the loop starts. +They must all result in numbers.
      • -
      • "mul": -the * operation. - -Behavior similar to the "add" operation. +
      • +var, limit, and step are invisible variables. +The names shown here are for explanatory purposes only.
      • -
      • "div": -the / operation. - -Behavior similar to the "add" operation. +
      • +If the third expression (the step) is absent, +then a step of 1 is used.
      • -
      • "mod": -the % operation. - -Behavior similar to the "add" operation, -with the operation -o1 - floor(o1/o2)*o2 as the primitive operation. +
      • +You can use break to exit a for loop.
      • -
      • "pow": -the ^ (exponentiation) operation. - -Behavior similar to the "add" operation, -with the function pow (from the C math library) -as the primitive 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.
      • -
      • "unm": -the unary - operation. +
      +

      +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:

      -     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
      +	stat ::= for namelist in explist do block end
      +	namelist ::= Name {‘,’ Name}
       

      -

    • - -
    • "concat": -the .. (concatenation) operation. - +A for statement like
      -     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
      +     for var_1, ···, var_n in explist do block end
       

      -

    • - -
    • "len": -the # operation. - +is equivalent to the code:
      -     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
      +     do
      +       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
      +         block
              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. +Note the following: -
      -     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). +

      • +explist is evaluated only once. +Its results are an iterator function, +a state, +and an initial value for the first iterator variable.
      • -
      • "lt": -the < operation. +
      • +f, s, and var are invisible variables. +The names are here for explanatory purposes only. +
      • +
      • +You can use break to exit a for loop. +
      • -
        -     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. +

      • +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.
      • -
      • "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]. +

      3.3.6 – Function Calls as Statements

      +To allow possible side-effects, +function calls can be executed as statements:

      -     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
      +	stat ::= functioncall
       

      -

    • +In this case, all returned values are thrown away. +Function calls are explained in §3.4.9. -
    • "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
      -         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. +

      3.3.7 – Local Declarations

      +Local variables can be declared anywhere inside a block. +The declaration can include an initial assignment:

      -     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
      +	stat ::= local namelist [‘=’ 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. -

    2.9 - Environments

    -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. +A chunk is also a block (see §3.3.2), +and so local variables can be declared in a chunk outside any explicit block.

    -Threads are created sharing the environment of the creating thread. -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 environment of the creating thread. -Nested Lua functions are created sharing the environment of -the creating Lua function. +The visibility rules for local variables are explained in §3.5. -

    -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 -global environments. -They are used as the default environment for threads and -non-nested Lua functions created by the thread -and can be directly accessed by C code (see §3.3). -

    -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. +

    3.4 – Expressions

    -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 nested Lua functions -created by the function. +The basic expressions in Lua are the following: +

    +	exp ::= prefixexp
    +	exp ::= nil | false | true
    +	exp ::= Number
    +	exp ::= String
    +	exp ::= functiondef
    +	exp ::= tableconstructor
    +	exp ::= ‘...’
    +	exp ::= exp binop exp
    +	exp ::= unop exp
    +	prefixexp ::= var | functioncall | ‘(’ exp ‘)’
    +

    -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. +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. +

    +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 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 expression is enclosed in parentheses). +In all other contexts, +Lua adjusts the result list to one element, +discarding all values except the first one. -

    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. +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 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
    +

    -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). +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.) + +

    3.4.1 – Arithmetic Operators

    +Lua supports the usual arithmetic operators: +the binary + (addition), +- (subtraction), * (multiplication), +/ (division), % (modulo), and ^ (exponentiation); +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. +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. + + + + + +

    3.4.2 – Coercion

    +

    -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. +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. +(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, +use the format function from the string library +(see string.format). + + + + + +

    3.4.3 – Relational Operators

    +The relational operators in Lua are + +

    +     ==    ~=    <     >     <=    >=
    +

    +These operators always result in false or true.

    -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. +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 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, 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.

    -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). +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. -

    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). +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. + + + + + +

    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: + +

    +     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.) + + + + + +

    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). + + + + + +

    3.4.6 – The Length Operator

    + +

    +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). + + +

    +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, +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 + +

    +     {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 positive numeric keys of that table.) +Note, however, that non-numeric keys do not interfere +with whether a table is a sequence. + + + + + +

    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. + + + + + +

    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 ::= ‘{’ [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 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 §3.4.9). + + +

    +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). + + +

    +The form + +

    +	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. + + +

    +Arguments have the following syntax: + +

    +	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. + + +

    +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

    + +

    +The syntax for function definition is + +

    +	functiondef ::= function funcbody
    +	funcbody ::= ‘(’ [parlist] ‘)’ 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 () body end
    +

    +translates to + +

    +     f = function () body end
    +

    +The statement + +

    +     function t.a.b.c.f () body end
    +

    +translates to + +

    +     t.a.b.c.f = function () body end
    +

    +The statement + +

    +     local function f () body end
    +

    +translates to + +

    +     local f; f = function () body end
    +

    +not to + +

    +     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, +whose value has type function. +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) +is the final value of the expression. + + +

    +Parameters act as local variables that are +initialized with the argument values: + +

    +	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 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).

    -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: +As an example, consider the following definitions:

    -     function gc_event (udata)
    -       local h = metatable(udata).__gc
    -       if h then
    -         h(udata)
    -       end
    -     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
     

    -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. - - - - +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. -

    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 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. +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.

    -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. - - - +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 +

    +     t.a.b.c.f = function (self, params) body end
    +
    -

    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. +

    3.5 – Visibility Rules

    -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. - -

    -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 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: +

    +     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

    @@ -2247,7 +2467,8 @@

    3 - 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. @@ -2256,12 +2477,11 @@

    3 - 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. -

    3.1 - The Stack

    +

    4.1 – The Stack

    Lua uses a virtual stack to pass values to and from C. @@ -2283,9 +2503,9 @@

    3.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) @@ -2294,94 +2514,114 @@

    3.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). - -

    3.2 - Stack Size

    +

    4.2 – Stack Size

    -When you interact with Lua API, +When you interact with the 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. +to ensure that the stack has extra slots when pushing new elements.

    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.

    -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 +When you call a Lua function +without a fixed number of results (see lua_call), +Lua ensures that the stack has enough size for all results, +but it does not ensure any extra space. +So, before pushing anything in the stack after such a call +you should use lua_checkstack. + + + + + +

    4.3 – Valid and Acceptable Indices

    + +

    +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. -

    3.3 - Pseudo-Indices

    Unless otherwise noted, -any function that accepts valid indices can also be called with -pseudo-indices, +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 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. +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_GLOBALSINDEX, varname);
    -
    - -

    3.4 - C Closures

    +

    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.

    @@ -2400,61 +2640,170 @@

    3.4 - C Closures

    -

    3.5 - Registry

    +

    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. +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 any Lua object created by your code. +As with global names, +string keys starting with an underscore followed by +uppercase letters are reserved for Lua.

    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. +and by some predefined values. +Therefore, integer keys should not be used for other purposes. + + +

    +When you create a new Lua state, +its registry comes with some predefined values. +These predefined values are indexed with integer keys +defined as constants in lua.h. +The following constants are defined: +

      +
    • 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 +the global environment. +
    • +
    -

    3.6 - Error Handling in C

    +

    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.) When Lua faces any error -(such as memory allocation errors, type errors, syntax errors, +(such as a memory allocation error, 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. +to set a recovery point; +any error jumps to the most recent active recovery point. + + +

    +If an error happens outside any protected environment, +Lua calls a panic function (see lua_atpanic) +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 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. +The documentation for each function indicates whether +it can throw errors. + + +

    +Inside a C function you can throw an error by calling lua_error. + + + + + +

    4.7 – Handling Yields in C

    + +

    +Internally, Lua uses the C longjmp facility to yield a coroutine. +Therefore, if a function foo calls an API function +and this API function yields +(directly or indirectly by calling another function that yields), +Lua cannot return to foo any more, +because the longjmp removes its frame from the C stack. + + +

    +To avoid this kind of problem, +Lua raises an error whenever it tries to yield across an API call, +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 a yield. + + +

    +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, +which we will call the callee function, +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.)

    -Most functions in the API can throw an error, -for instance due to a memory allocation error. -The documentation for each function indicates whether -it can throw errors. +Suppose the running thread yields while executing the callee function. +After the thread resumes, +it eventually will finish running the callee function. +However, +the callee function cannot return to the original function, +because its frame in the C stack was destroyed by the yield. +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 +of the original function.

    -Inside a C function you can throw an error by calling lua_error. +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. +(For instance, +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 were the return +of the original function. +

    +The only difference in the Lua state between the original function +and its continuation is the result of a call to lua_getctx. + -

    3.7 - Functions and Types

    + +

    4.8 – Functions and Types

    Here we list all functions and types from the C API in @@ -2479,13 +2828,23 @@

    3.7 - 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; -'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. +

    lua_absindex

    +[-0, +0, –] +

    int 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,
    @@ -2500,18 +2859,43 @@ 

    3.7 - Functions and Types

    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; +osize, the original size of the block or some code about what +is being allocated; 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 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, -the allocator should behave like malloc. -When nsize and osize are not zero, -the allocator behaves like realloc. + + +

    +When ptr is not NULL, +osize is the size of the block pointed by ptr, +that is, the size given when it was allocated or reallocated. + + +

    +When ptr is NULL, +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) +Lua is creating a new object of that type. +When osize is some other value, +Lua is allocating memory for something else. + + +

    +Lua assumes the following behavior from the allocator function: + + +

    +When nsize is zero, +the allocator should behave like free +and return NULL. + + +

    +When nsize is not zero, +the allocator should behave like realloc. +The allocator returns NULL +if and only if it cannot fulfill the request. Lua assumes that the allocator never fails when osize >= nsize. @@ -2532,41 +2916,62 @@

    3.7 - Functions and Types

    return realloc(ptr, nsize); }

    -This code assumes +Note that Standard C ensures that free(NULL) has no effect and that realloc(NULL, size) is equivalent to malloc(size). -ANSI C ensures both behaviors. +This code assumes that realloc does not fail when shrinking a block. +(Although Standard C does not ensure this behavior, +it seems to be a safe assumption.) -


    lua_atpanic

    -[-0, +0, -] -

    lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
    +

    lua_arith

    +[-(2|1), +1, e] +

    void lua_arith (lua_State *L, int op);

    -Sets a new panic function and returns the old one. +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).

    -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 can avoid this exit by -never returning (e.g., doing a long jump). +The value of op must be one of the following constants: + +

    + + + + +

    lua_atpanic

    +[-0, +0, –] +

    lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);

    -The panic function can access the error message at the top of the stack. +Sets a new panic function and returns the old one (see §4.6).


    lua_call

    -[-(nargs + 1), +nresults, e] +[-(nargs+1), +nresults, e]

    void lua_call (lua_State *L, int nargs, int nresults);

    @@ -2586,7 +2991,7 @@

    3.7 - 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), @@ -2608,14 +3013,14 @@

    3.7 - Functions and Types

    Here it is in C:
    -     lua_getfield(L, LUA_GLOBALSINDEX, "f"); /* function to be called */
    +     lua_getglobal(L, "f");                  /* function to be called */
          lua_pushstring(L, "how");                        /* 1st argument */
    -     lua_getfield(L, LUA_GLOBALSINDEX, "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_GLOBALSINDEX, "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. @@ -2625,6 +3030,19 @@

    3.7 - Functions and Types

    +

    lua_callk

    +[-(nargs + 1), +nresults, e] +

    void lua_callk (lua_State *L, int nargs, int nresults, int ctx,
    +                lua_CFunction k);
    + +

    +This function behaves exactly like lua_call, +but allows the called function to yield (see §4.7). + + + + +


    lua_CFunction

    typedef int (*lua_CFunction) (lua_State *L);
    @@ -2677,12 +3095,15 @@

    3.7 - Functions and Types


    lua_checkstack

    -[-0, +0, m] +[-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 grow the stack to that size. +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. This function never shrinks the stack; if the stack is already larger than the new size, it is left unchanged. @@ -2692,7 +3113,7 @@

    3.7 - Functions and Types


    lua_close

    -[-0, +0, -] +[-0, +0, –]

    void lua_close (lua_State *L);

    @@ -2701,11 +3122,38 @@

    3.7 - 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. + + + + + +

    lua_compare

    +[-0, +0, e] +

    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 +(that is, it may call metamethods). +Otherwise returns 0. +Also returns 0 if any of the indices is non valid. + + +

    +The value of op must be one of the following constants: + +

      +
    • LUA_OPEQ: compares for equality (==)
    • +
    • LUA_OPLT: compares for less than (<)
    • +
    • LUA_OPLE: compares for less or equal (<=)
    • + +
    @@ -2721,40 +3169,39 @@

    3.7 - 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). -

    lua_cpcall

    -[-0, +(0|1), -] -

    int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);
    +

    lua_copy

    +[-0, +0, –] +

    void lua_copy (lua_State *L, int fromidx, int toidx);

    -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. -All values returned by func are discarded. +Moves the element at the valid index fromidx +into the valid index toidx +without shifting any element +(therefore replacing the value at that position).


    lua_createtable

    -[-0, +1, m] +[-0, +1, e]

    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 +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. @@ -2762,7 +3209,7 @@

    3.7 - Functions and Types


    lua_dump

    -[-0, +0, m] +[-0, +0, e]

    int lua_dump (lua_State *L, lua_Writer writer, void *data);

    @@ -2790,22 +3237,6 @@

    3.7 - Functions and Types

    -

    lua_equal

    -[-0, +0, e] -

    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. - - - - -


    lua_error

    [-1, +0, v]

    int lua_error (lua_State *L);
    @@ -2815,7 +3246,7 @@

    3.7 - 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). @@ -2836,28 +3267,28 @@

    3.7 - 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. @@ -2867,25 +3298,45 @@

      3.7 - Functions and Types

      garbage-collection cycle.
    • -
    • LUA_GCSETPAUSE: +
    • 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: +
    • 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.
    • +
    • LUA_GCISRUNNING: +returns a boolean that tells whether the collector is running +(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 these options, +see collectgarbage. + +


    lua_getallocf

    -[-0, +0, -] +[-0, +0, –]

    lua_Alloc lua_getallocf (lua_State *L, void **ud);

    @@ -2897,13 +3348,37 @@

    3.7 - Functions and Types

    -

    lua_getfenv

    -[-0, +1, -] -

    void lua_getfenv (lua_State *L, int index);
    +

    lua_getctx

    +[-0, +0, –] +

    int lua_getctx (lua_State *L, int *ctx);
    + +

    +This function is called by a continuation function (see §4.7) +to retrieve the status of the thread and a context information. + + +

    +When called in the original function, +lua_getctx always returns LUA_OK +and does not change the value of its argument ctx. +When called inside a continuation function, +lua_getctx returns LUA_YIELD and sets +the value of ctx to be the context information +(the value passed as the ctx argument +to the callee together with the continuation function). +

    -Pushes onto the stack the environment table of -the value at the given index. +When the callee is lua_pcallk, +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 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); +the value of ctx will be set to the context information, +as in the case of a yield. @@ -2917,7 +3392,7 @@

    3.7 - 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). @@ -2929,24 +3404,19 @@

    3.7 - Functions and Types

    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

    -[-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. @@ -2967,14 +3437,14 @@

    3.7 - 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).

    lua_gettop

    -[-0, +0, -] +[-0, +0, –]

    int lua_gettop (lua_State *L);

    @@ -2987,8 +3457,21 @@

    3.7 - 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, -] +[-1, +1, –]

    void lua_insert (lua_State *L, int index);

    @@ -3005,7 +3488,7 @@

    3.7 - 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.

    @@ -3018,11 +3501,11 @@

    3.7 - 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. @@ -3030,7 +3513,7 @@

    3.7 - Functions and Types


    lua_iscfunction

    -[-0, +0, -] +[-0, +0, –]

    int lua_iscfunction (lua_State *L, int index);

    @@ -3042,7 +3525,7 @@

    3.7 - Functions and Types


    lua_isfunction

    -[-0, +0, -] +[-0, +0, –]

    int lua_isfunction (lua_State *L, int index);

    @@ -3054,7 +3537,7 @@

    3.7 - Functions and Types


    lua_islightuserdata

    -[-0, +0, -] +[-0, +0, –]

    int lua_islightuserdata (lua_State *L, int index);

    @@ -3066,7 +3549,7 @@

    3.7 - Functions and Types


    lua_isnil

    -[-0, +0, -] +[-0, +0, –]

    int lua_isnil (lua_State *L, int index);

    @@ -3078,7 +3561,7 @@

    3.7 - Functions and Types


    lua_isnone

    -[-0, +0, -] +[-0, +0, –]

    int lua_isnone (lua_State *L, int index);

    @@ -3091,7 +3574,7 @@

    3.7 - Functions and Types


    lua_isnoneornil

    -[-0, +0, -] +[-0, +0, –]

    int lua_isnoneornil (lua_State *L, int index);

    @@ -3105,7 +3588,7 @@

    3.7 - Functions and Types


    lua_isnumber

    -[-0, +0, -] +[-0, +0, –]

    int lua_isnumber (lua_State *L, int index);

    @@ -3118,7 +3601,7 @@

    3.7 - Functions and Types


    lua_isstring

    -[-0, +0, -] +[-0, +0, –]

    int lua_isstring (lua_State *L, int index);

    @@ -3131,7 +3614,7 @@

    3.7 - Functions and Types


    lua_istable

    -[-0, +0, -] +[-0, +0, –]

    int lua_istable (lua_State *L, int index);

    @@ -3143,7 +3626,7 @@

    3.7 - Functions and Types


    lua_isthread

    -[-0, +0, -] +[-0, +0, –]

    int lua_isthread (lua_State *L, int index);

    @@ -3155,7 +3638,7 @@

    3.7 - Functions and Types


    lua_isuserdata

    -[-0, +0, -] +[-0, +0, –]

    int lua_isuserdata (lua_State *L, int index);

    @@ -3166,92 +3649,105 @@

    3.7 - Functions and Types

    -

    lua_lessthan

    -[-0, +0, e] -

    int lua_lessthan (lua_State *L, int index1, int index2);
    +

    lua_len

    +[-0, +1, e] +

    void lua_len (lua_State *L, int index);

    -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 is non valid. +Returns the "length" of the value at the given acceptable index; +it is equivalent to the '#' operator in Lua (see §3.4.6). +The result is pushed on the stack.


    lua_load

    -[-0, +1, -] +[-0, +1, –]

    int lua_load (lua_State *L,
                   lua_Reader reader,
                   void *data,
    -              const char *chunkname);
    + 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:

      -
    • 0: no errors;
    • +
    • LUA_OK: no errors;
    • + +
    • LUA_ERRSYNTAX: +syntax error during precompilation;
    • -
    • LUA_ERRSYNTAX: -syntax error during pre-compilation;
    • +
    • LUA_ERRMEM: +memory allocation error;
    • -
    • LUA_ERRMEM: -memory allocation error.
    • +
    • 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.) +

    -This function only loads a chunk; -it does not run it. +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.

    -lua_load automatically detects whether the chunk is text or binary, -and loads it accordingly (see program luac). +The source argument gives a name to the chunk, +which is used for error messages and in debug information (see §4.9).

    -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. +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".

    -The chunkname argument gives a name to the chunk, -which is used for error messages and in debug information (see §3.8). +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).


    lua_newstate

    -[-0, +0, -] +[-0, +0, –]

    lua_State *lua_newstate (lua_Alloc f, void *ud);

    -Creates a new, independent state. -Returns NULL if cannot create the state +Creates a new thread running in a new, independent 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.


    lua_newtable

    -[-0, +1, m] +[-0, +1, e]

    void lua_newtable (lua_State *L);

    @@ -3263,14 +3759,14 @@

    3.7 - Functions and Types


    lua_newthread

    -[-0, +1, m] +[-0, +1, e]

    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), +The new thread returned by this function shares with the original thread +its global environment, but has an independent execution stack. @@ -3284,29 +3780,14 @@

    3.7 - Functions and Types


    lua_newuserdata

    -[-0, +1, m] +[-0, +1, e]

    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 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). - - -

    -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. +The host program can freely use this memory. @@ -3318,7 +3799,7 @@

    3.7 - Functions and Types

    Pops a key from the stack, -and pushes a key-value pair from the table at the given index +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). @@ -3344,11 +3825,16 @@

    3.7 - 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. +

    +See function next for the caveats of modifying +the table during its traversal. + + @@ -3358,35 +3844,16 @@

    3.7 - Functions and Types

    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 this configuration file you can change Lua to operate with another type for numbers (e.g., float or long). -


    lua_objlen

    -[-0, +0, -] -

    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 userdata; -for other values, it is 0. - - - - -


    lua_pcall

    -[-(nargs + 1), +(nresults|1), -] -

    int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
    +[-(nargs + 1), +(nresults|1), –] +
    int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);

    Calls a function in protected mode. @@ -3407,42 +3874,51 @@

    3.7 - 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.

    -The lua_pcall function returns 0 in case of success -or one of the following error codes +The lua_pcall function returns one of the following codes (defined in lua.h):

      -
    • LUA_ERRRUN: +
    • LUA_OK (0): +success.
    • + +
    • LUA_ERRRUN: a runtime error.
    • -
    • LUA_ERRMEM: +
    • 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. +
    • LUA_ERRERR: +error while running the message handler. +
    • + +
    • 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.)
    @@ -3450,8 +3926,25 @@

    3.7 - 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);
    + +

    +This function behaves exactly like lua_pcall, +but allows the called function to yield (see §4.7). + + + + +


    lua_pop

    -[-n, +0, -] +[-n, +0, –]

    void lua_pop (lua_State *L, int n);

    @@ -3462,7 +3955,7 @@

    3.7 - Functions and Types


    lua_pushboolean

    -[-0, +1, -] +[-0, +1, –]

    void lua_pushboolean (lua_State *L, int b);

    @@ -3473,7 +3966,7 @@

    3.7 - Functions and Types


    lua_pushcclosure

    -[-n, +1, m] +[-n, +1, e]

    void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);

    @@ -3483,7 +3976,7 @@

    3.7 - 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 @@ -3499,11 +3992,18 @@

    3.7 - 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 never throws a memory error. + +


    lua_pushcfunction

    -[-0, +1, m] +[-0, +1, –]

    void lua_pushcfunction (lua_State *L, lua_CFunction f);

    @@ -3524,13 +4024,15 @@

    3.7 - Functions and Types

          #define lua_pushcfunction(L,f)  lua_pushcclosure(L,f,0)
    -
    +

    +Note that f is used twice. +


    lua_pushfstring

    -[-0, +1, m] +[-0, +1, e]

    const char *lua_pushfstring (lua_State *L, const char *fmt, ...);

    @@ -3556,7 +4058,7 @@

    3.7 - 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). @@ -3565,7 +4067,7 @@

    3.7 - Functions and Types


    lua_pushinteger

    -[-0, +1, -] +[-0, +1, –]

    void lua_pushinteger (lua_State *L, lua_Integer n);

    @@ -3576,7 +4078,7 @@

    3.7 - Functions and Types


    lua_pushlightuserdata

    -[-0, +1, -] +[-0, +1, –]

    void lua_pushlightuserdata (lua_State *L, void *p);

    @@ -3585,7 +4087,7 @@

    3.7 - Functions and Types

    Userdata represent C values in Lua. -A light userdata represents a pointer. +A light userdata represents a pointer, a void*. It is a value (like a number): you do not create it, it has no individual metatable, and it is not collected (as it was never created). @@ -3597,21 +4099,21 @@

    3.7 - Functions and Types


    lua_pushliteral

    -[-0, +1, m] -

    void lua_pushliteral (lua_State *L, const char *s);
    +[-0, +1, e] +
    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. -In these cases, it automatically provides the string length. +It automatically provides the string length.


    lua_pushlstring

    -[-0, +1, m] -

    void lua_pushlstring (lua_State *L, const char *s, size_t len);
    +[-0, +1, e] +
    const char *lua_pushlstring (lua_State *L, const char *s, size_t len);

    Pushes the string pointed to by s with size len @@ -3619,14 +4121,19 @@

    3.7 - 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. + + +

    +Returns a pointer to the internal copy of the string.


    lua_pushnil

    -[-0, +1, -] +[-0, +1, –]

    void lua_pushnil (lua_State *L);

    @@ -3637,7 +4144,7 @@

    3.7 - Functions and Types


    lua_pushnumber

    -[-0, +1, -] +[-0, +1, –]

    void lua_pushnumber (lua_State *L, lua_Number n);

    @@ -3648,8 +4155,8 @@

    3.7 - Functions and Types


    lua_pushstring

    -[-0, +1, m] -

    void lua_pushstring (lua_State *L, const char *s);
    +[-0, +1, e] +
    const char *lua_pushstring (lua_State *L, const char *s);

    Pushes the zero-terminated string pointed to by s @@ -3657,15 +4164,21 @@

    3.7 - 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; -it is assumed to end at the first zero. + + +

    +Returns a pointer to the internal copy of the string. + + +

    +If s is NULL, pushes nil and returns NULL.


    lua_pushthread

    -[-0, +1, -] +[-0, +1, –]

    int lua_pushthread (lua_State *L);

    @@ -3677,7 +4190,7 @@

    3.7 - Functions and Types


    lua_pushvalue

    -[-0, +1, -] +[-0, +1, –]

    void lua_pushvalue (lua_State *L, int index);

    @@ -3689,7 +4202,7 @@

    3.7 - Functions and Types


    lua_pushvfstring

    -[-0, +1, m] +[-0, +1, e]

    const char *lua_pushvfstring (lua_State *L,
                                   const char *fmt,
                                   va_list argp);
    @@ -3703,7 +4216,7 @@

    3.7 - Functions and Types


    lua_rawequal

    -[-0, +0, -] +[-0, +0, –]

    int lua_rawequal (lua_State *L, int index1, int index2);

    @@ -3718,7 +4231,7 @@

    3.7 - Functions and Types


    lua_rawget

    -[-1, +1, -] +[-1, +1, –]

    void lua_rawget (lua_State *L, int index);

    @@ -3730,12 +4243,12 @@

    3.7 - Functions and Types


    lua_rawgeti

    -[-0, +1, -] +[-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. +where t is the table at the given valid index. The access is raw; that is, it does not invoke metamethods. @@ -3743,8 +4256,40 @@

    3.7 - 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, –] +

    size_t lua_rawlen (lua_State *L, int index);
    + +

    +Returns the raw "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 ('#') +with no metamethods; +for userdata, this is the size of the block of memory allocated +for the userdata; +for other values, it is 0. + + + + +


    lua_rawset

    -[-2, +0, m] +[-2, +0, e]

    void lua_rawset (lua_State *L, int index);

    @@ -3756,12 +4301,32 @@

    3.7 - Functions and Types


    lua_rawseti

    -[-1, +0, m] +[-1, +0, e]

    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 +where t is the table at the given valid 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_rawsetp

    +[-1, +0, e] +

    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. @@ -3798,9 +4363,7 @@

    3.7 - 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. @@ -3815,7 +4378,7 @@

    3.7 - Functions and Types


    lua_remove

    -[-1, +0, -] +[-1, +0, –]

    void lua_remove (lua_State *L, int index);

    @@ -3829,54 +4392,66 @@

    3.7 - Functions and Types


    lua_replace

    -[-1, +0, -] +[-1, +0, –]

    void lua_replace (lua_State *L, int index);

    -Moves the top element into the given position (and pops it), +Moves the top element into the given position without shifting any element -(therefore replacing the value at the given position). +(therefore replacing the value at the given position), +and then pops the top element.


    lua_resume

    -[-?, +?, -] -

    int lua_resume (lua_State *L, int narg);
    +[-?, +?, –] +
    int lua_resume (lua_State *L, lua_State *from, int nargs);

    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 onto its stack the main function plus any arguments; +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. lua_resume returns LUA_YIELD if the coroutine yields, -0 if the coroutine finishes its execution +LUA_OK 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. The error message is on the top of the stack. -To restart a coroutine, you put on its stack only the values to + + +

    +To resume a coroutine, you put on its stack only the values to be passed as results from yield, 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);

    @@ -3887,22 +4462,6 @@

    3.7 - Functions and Types

    -

    lua_setfenv

    -[-1, +0, -] -

    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

    [-1, +0, e]

    void lua_setfield (lua_State *L, int index, const char *k);
    @@ -3916,7 +4475,7 @@

    3.7 - 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). @@ -3929,18 +4488,14 @@

    3.7 - 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: -

    -     #define lua_setglobal(L,s)   lua_setfield(L, LUA_GLOBALSINDEX, s)
    -

    lua_setmetatable

    -[-1, +0, -] -

    int lua_setmetatable (lua_State *L, int index);
    +[-1, +0, –] +
    void lua_setmetatable (lua_State *L, int index);

    Pops a table from the stack and @@ -3965,14 +4520,14 @@

    3.7 - 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).


    lua_settop

    -[-?, +?, -] +[-?, +?, –]

    void lua_settop (lua_State *L, int index);

    @@ -3986,18 +4541,31 @@

    3.7 - 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;

    -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. @@ -4006,7 +4574,7 @@

    3.7 - Functions and Types


    lua_status

    -[-0, +0, -] +[-0, +0, –]

    int lua_status (lua_State *L);

    @@ -4014,26 +4582,34 @@

    3.7 - Functions and Types

    -The status can be 0 for a normal thread, -an error code if the thread finished its execution with an error, +The status can be 0 (LUA_OK) for a normal thread, +an error code if the thread finished the execution +of a lua_resume with an error, 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 coroutine). + +


    lua_toboolean

    -[-0, +0, -] +[-0, +0, –]

    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 +lua_toboolean returns true for any Lua value different from false and nil; -otherwise it returns 0. -It also returns 0 when called with a non-valid index. +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.) @@ -4042,7 +4618,7 @@

    3.7 - Functions and Types


    lua_tocfunction

    -[-0, +0, -] +[-0, +0, –]

    lua_CFunction lua_tocfunction (lua_State *L, int index);

    @@ -4055,15 +4631,26 @@

    3.7 - Functions and Types


    lua_tointeger

    -[-0, +0, -] +[-0, +0, –]

    lua_Integer lua_tointeger (lua_State *L, int index);
    +

    +Equivalent to lua_tointegerx with isnum equal to 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 §2.2.1); -otherwise, lua_tointeger returns 0. +(see §3.4.2); +otherwise, lua_tointegerx returns 0.

    @@ -4071,11 +4658,17 @@

    3.7 - Functions and Types

    it is truncated in some non-specified way. +

    +If isnum is not NULL, +its referent is assigned a boolean value that +indicates whether the operation succeeded. + +


    lua_tolstring

    -[-0, +0, m] +[-0, +0, e]

    const char *lua_tolstring (lua_State *L, int index, size_t *len);

    @@ -4085,20 +4678,20 @@

    3.7 - 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. @@ -4106,29 +4699,46 @@

    3.7 - Functions and Types


    lua_tonumber

    -[-0, +0, -] +[-0, +0, –]

    lua_Number lua_tonumber (lua_State *L, int index);
    +

    +Equivalent to lua_tonumberx with isnum equal to 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 §2.2.1); -otherwise, lua_tonumber returns 0. +(see §3.4.2); +otherwise, lua_tonumberx returns 0. + + +

    +If isnum is not NULL, +its referent is assigned a boolean value that +indicates whether the operation succeeded.


    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. @@ -4141,7 +4751,7 @@

    3.7 - Functions and Types


    lua_tostring

    -[-0, +0, m] +[-0, +0, e]

    const char *lua_tostring (lua_State *L, int index);

    @@ -4152,7 +4762,7 @@

    3.7 - Functions and Types


    lua_tothread

    -[-0, +0, -] +[-0, +0, –]

    lua_State *lua_tothread (lua_State *L, int index);

    @@ -4165,8 +4775,48 @@

    3.7 - Functions and Types

    +

    lua_tounsigned

    +[-0, +0, –] +

    lua_Unsigned lua_tounsigned (lua_State *L, int index);
    + +

    +Equivalent to lua_tounsignedx with isnum equal to 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 not NULL, +its referent is assigned a boolean value that +indicates whether the operation succeeded. + + + + +


    lua_touserdata

    -[-0, +0, -] +[-0, +0, –]

    void *lua_touserdata (lua_State *L, int index);

    @@ -4181,33 +4831,32 @@

    3.7 - 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, -LUA_TNUMBER, -LUA_TBOOLEAN, -LUA_TSTRING, -LUA_TTABLE, -LUA_TFUNCTION, -LUA_TUSERDATA, -LUA_TTHREAD, +LUA_TNIL, +LUA_TNUMBER, +LUA_TBOOLEAN, +LUA_TSTRING, +LUA_TTABLE, +LUA_TFUNCTION, +LUA_TUSERDATA, +LUA_TTHREAD, and -LUA_TLIGHTUSERDATA. +LUA_TLIGHTUSERDATA.


    lua_typename

    -[-0, +0, -] -

    const char *lua_typename  (lua_State *L, int tp);
    +[-0, +0, –] +
    const char *lua_typename (lua_State *L, int tp);

    Returns the name of the type encoded by the value tp, @@ -4217,6 +4866,37 @@

    3.7 - 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);
    + +

    +Returns the address of the version number stored in the Lua core. +When called with a valid lua_State, +returns the address of the version used to create that state. +When called with NULL, +returns the address of the version running the call. + + + + +


    lua_Writer

    typedef int (*lua_Writer) (lua_State *L,
                                const void* p,
    @@ -4243,11 +4923,11 @@ 

    3.7 - 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.

    @@ -4259,8 +4939,23 @@

    3.7 - 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, +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. + + + + + +


    lua_yieldk

    +[-?, +?, –] +

    int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k);

    Yields a coroutine. @@ -4271,21 +4966,34 @@

    3.7 - Functions and Types

    return expression of a C function, as follows:
    -     return lua_yield (L, nresults);
    +     return lua_yieldk (L, n, i, k);
     

    -When a C function calls lua_yield in that way, +When a C function calls lua_yieldk 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. +

    +When the coroutine is resumed again, +Lua calls the given continuation function k to continue +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 +replaced by the arguments passed to lua_resume. +Moreover, +the continuation function may access the value ctx +by calling lua_getctx. + + -

    3.8 - The Debug Interface

    +

    4.9 – The Debug Interface

    Lua has no built-in debugging facilities. @@ -4305,9 +5013,12 @@

    3.8 - The Debug Interface

    const char *what; /* (S) */ 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 */ other fields @@ -4315,7 +5026,7 @@

    3.8 - 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, @@ -4327,41 +5038,43 @@

    3.8 - The Debug Interface

      -
    • 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. +
    • 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 +the file name follows the '@'. +If source starts with a '=', +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.
    • -
    • 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, -and "tail" if it was a function that did a tail call. -In the latter case, -Lua has no other information about the 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: @@ -4373,7 +5086,7 @@

      3.8 - The Debug Interface

      then name is set to NULL.
    • -
    • namewhat: +
    • namewhat: explains the name field. The value of namewhat can be "global", "local", "method", @@ -4382,17 +5095,32 @@

      3.8 - The Debug Interface

      (Lua uses the empty string when no other option seems to apply.)
    • -
    • nups: +
    • 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: the number of upvalues of the function.
    • +
    • nparams: +the number of fixed parameters of the function +(always 0 for C functions). +
    • + +
    • isvararg: +true if the function is a vararg function +(always true for C functions). +
    • +

    lua_gethook

    -[-0, +0, -] +[-0, +0, –]

    lua_Hook lua_gethook (lua_State *L);

    @@ -4403,7 +5131,7 @@

    3.8 - The Debug Interface


    lua_gethookcount

    -[-0, +0, -] +[-0, +0, –]

    int lua_gethookcount (lua_State *L);

    @@ -4414,7 +5142,7 @@

    3.8 - The Debug Interface


    lua_gethookmask

    -[-0, +0, -] +[-0, +0, –]

    int lua_gethookmask (lua_State *L);

    @@ -4425,11 +5153,11 @@

    3.8 - 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);

    -Returns information about a specific function or function invocation. +Gets information about a specific function or function invocation.

    @@ -4443,13 +5171,13 @@

    3.8 - The Debug Interface

    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.) +lua_getinfo pops the function from 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_getglobal(L, "f");  /* get global 'f' */
          lua_getinfo(L, ">S", &ar);
          printf("%d\n", ar.linedefined);
     
    @@ -4461,26 +5189,30 @@

    3.8 - 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;
    • -
    • '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, @@ -4499,25 +5231,35 @@

      3.8 - The Debug Interface


      lua_getlocal

      -[-0, +(0|1), -] +[-0, +(0|1), –]

      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 -(1 is the first parameter or active local variable, and so on, -until the last active local variable). +The index n selects which local variable to inspect; +see debug.getlocal for details about variable indices +and names. + + +

      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). +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.

      @@ -4530,11 +5272,11 @@

      3.8 - The Debug Interface


      lua_getstack

      -[-0, +0, -] +[-0, +0, –]

      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.

      @@ -4542,7 +5284,8 @@

      3.8 - 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. @@ -4552,7 +5295,7 @@

      3.8 - The Debug Interface


      lua_getupvalue

      -[-0, +(0|1), -] +[-0, +(0|1), –]

      const char *lua_getupvalue (lua_State *L, int funcindex, int n);

      @@ -4591,16 +5334,17 @@

      3.8 - The Debug Interface

      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, +LUA_HOOKTAILCALL, 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 can 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. + + +

      +For call events, event can be LUA_HOOKCALL, +the normal value, or LUA_HOOKTAILCALL, for a tail call; +in this case, there will be no corresponding return event.

      @@ -4609,11 +5353,25 @@

      3.8 - The Debug Interface

      this execution occurs without any calls to hooks. +

      +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. + +


      lua_sethook

      -[-0, +0, -] +[-0, +0, –]

      int lua_sethook (lua_State *L, lua_Hook f, int mask, int count);

      @@ -4634,23 +5392,24 @@

      3.8 - 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. -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 +
      • 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.)
      • @@ -4665,7 +5424,7 @@

        3.8 - The Debug Interface


        lua_setlocal

        -[-(0|1), +0, -] +[-(0|1), +0, –]

        const char *lua_setlocal (lua_State *L, lua_Debug *ar, int n);

        @@ -4687,7 +5446,7 @@

        3.8 - The Debug Interface


        lua_setupvalue

        -[-(0|1), +0, -] +[-(0|1), +0, –]

        const char *lua_setupvalue (lua_State *L, int funcindex, int n);

        @@ -4707,22 +5466,58 @@

        3.8 - The Debug Interface

        +

        lua_upvalueid

        +[-0, +0, –] +

        void *lua_upvalueid (lua_State *L, int funcindex, int n);
        + +

        +Returns an 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). + + +

        +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. + + + + + +


        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 funcindex1 +refer to the n2-th upvalue of the Lua closure at index funcindex2. + + + + -

        4 - The Auxiliary Library

        + +

        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.

        -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_. @@ -4730,21 +5525,34 @@

        4 - 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 this 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. + + +

        +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. -Their names are always luaL_check* or luaL_opt*. -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. +

        +Functions called luaL_check* +always throw an error if the check is not satisfied. + + -

        4.1 - Functions and Types

        +

        5.1 – Functions and Types

        Here we list all functions and types from the auxiliary library @@ -4753,11 +5561,11 @@

        4.1 - Functions and Types


        luaL_addchar

        -[-0, +0, m] +[-?, +?, e]

        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). @@ -4765,21 +5573,21 @@

        4.1 - Functions and Types


        luaL_addlstring

        -[-0, +0, m] +[-?, +?, e]

        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. +The string can contain embedded zeros.


        luaL_addsize

        -[-0, +0, m] +[-?, +?, e]

        void luaL_addsize (luaL_Buffer *B, size_t n);

        @@ -4792,21 +5600,21 @@

        4.1 - Functions and Types


        luaL_addstring

        -[-0, +0, m] +[-?, +?, e]

        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. +The string cannot contain embedded zeros.


        luaL_addvalue

        -[-1, +0, m] +[-1, +?, e]

        void luaL_addvalue (luaL_Buffer *B);

        @@ -4829,32 +5637,25 @@

        4.1 - Functions and Types

        [-0, +0, v]
        void luaL_argcheck (lua_State *L,
                             int cond,
        -                    int narg,
        +                    int arg,
                             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: +If not, raises an error with a standard message. -

        -     bad argument #<narg> to <func> (<extramsg>)
        -

        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 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, @@ -4878,22 +5679,43 @@

        4.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.
        +

        +If you know beforehand the total size of the resulting string, +you can use the buffer like this: + +

          + +
        • First declare a variable b of type luaL_Buffer.
        • + +
        • Then initialize it and preallocate a space of +size sz with a call luaL_buffinitsize(L, &b, sz).
        • + +
        • Then copy the string into that space.
        • + +
        • +Finish by calling luaL_pushresultsize(&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. @@ -4915,7 +5737,7 @@

        4.1 - Functions and Types


        luaL_buffinit

        -[-0, +0, -] +[-0, +0, –]

        void luaL_buffinit (lua_State *L, luaL_Buffer *B);

        @@ -4928,6 +5750,18 @@

        4.1 - Functions and Types

        +

        luaL_buffinitsize

        +[-?, +?, e] +

        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);
        @@ -4939,11 +5773,11 @@

        4.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. -In this case this function returns 1 and pushes onto the +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, -this function returns 0 (without pushing any value on the stack). +this function returns false (without pushing any value on the stack). @@ -4951,11 +5785,11 @@

        4.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. @@ -4963,10 +5797,10 @@

        4.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. @@ -4975,10 +5809,10 @@

        4.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. @@ -4987,10 +5821,10 @@

        4.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. @@ -4999,10 +5833,10 @@

        4.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. @@ -5018,10 +5852,10 @@

        4.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. @@ -5031,12 +5865,12 @@

        4.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. @@ -5047,7 +5881,7 @@

        4.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 arg or when this argument is nil.

        @@ -5066,7 +5900,8 @@

        4.1 - Functions and Types

        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. +msg is an additional text to go into the error message +(or NULL for no additional text). @@ -5074,10 +5909,10 @@

        4.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. @@ -5091,10 +5926,10 @@

        4.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. @@ -5103,18 +5938,47 @@

        4.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 arg is a userdata +of the type tname (see luaL_newmetatable) and +returns the userdata address (see lua_touserdata). + + + + + +


        luaL_checkunsigned

        +[-0, +0, v] +

        lua_Unsigned luaL_checkunsigned (lua_State *L, int arg);
        + +

        +Checks whether the function argument arg is a number +and returns this number cast to a lua_Unsigned. + + + + + +


        luaL_checkversion

        +[-0, +0, –] +

        void luaL_checkversion (lua_State *L);

        -Checks whether the function argument narg is a userdata -of the type tname (see luaL_newmetatable). +Checks whether the core running the call, +the core that created the Lua state, +and the code making the call are all using the same version of Lua. +Also checks whether the core running the call +and the core that created the Lua state +are using the same address space.


        luaL_dofile

        -[-0, +?, m] +[-0, +?, e]

        int luaL_dofile (lua_State *L, const char *filename);

        @@ -5124,15 +5988,15 @@

        4.1 - Functions and Types

              (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. +It returns false if there are no errors +or true in case of errors.


        luaL_dostring

        -[-0, +?, m] +[-0, +?, –]

        int luaL_dostring (lua_State *L, const char *str);

        @@ -5142,8 +6006,8 @@

        4.1 - Functions and Types

              (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. +It returns false if there are no errors +or true in case of errors. @@ -5172,8 +6036,34 @@

        4.1 - Functions and Types

        +

        luaL_execresult

        +[-0, +3, e] +

        int luaL_execresult (lua_State *L, int stat);
        + +

        +This function produces the return values for +process-related functions in the standard library +(os.execute and io.close). + + + + + +


        luaL_fileresult

        +[-0, +(1|3), e] +

        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.). + + + + +


        luaL_getmetafield

        -[-0, +(0|1), m] +[-0, +(0|1), e]

        int luaL_getmetafield (lua_State *L, int obj, const char *e);

        @@ -5181,14 +6071,14 @@

        4.1 - Functions and Types

        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. +returns false and pushes nothing.

        luaL_getmetatable

        -[-0, +1, -] +[-0, +1, –]

        void luaL_getmetatable (lua_State *L, const char *tname);

        @@ -5199,8 +6089,24 @@

        4.1 - Functions and Types

        +

        luaL_getsubtable

        +[-0, +1, e] +

        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] +[-0, +1, e]

        const char *luaL_gsub (lua_State *L,
                                const char *s,
                                const char *p,
        @@ -5216,13 +6122,43 @@ 

        4.1 - Functions and Types

        +

        luaL_len

        +[-0, +0, e] +

        int luaL_len (lua_State *L, int index);
        + +

        +Returns the "length" of the value at the given acceptable 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. +(This case only can happen through metamethods.) + + + + +


        luaL_loadbuffer

        -[-0, +1, m] +[-0, +1, –]

        int luaL_loadbuffer (lua_State *L,
                              const char *buff,
                              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 @@ -5233,15 +6169,28 @@

        4.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.

        luaL_loadfile

        -[-0, +1, m] +[-0, +1, e]

        int luaL_loadfile (lua_State *L, const char *filename);
        +

        +Equivalent to luaL_loadfilex with mode equal to NULL. + + + + + +


        luaL_loadfilex

        +[-0, +1, e] +

        int luaL_loadfilex (lua_State *L, const char *filename,
        +                                            const char *mode);
        +

        Loads a file as a Lua chunk. This function uses lua_load to load the chunk in the file @@ -5251,10 +6200,14 @@

        4.1 - Functions and Types

        The first line in the file is ignored if it starts with a #. +

        +The string mode works as in function lua_load. + +

        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.

        @@ -5266,7 +6219,7 @@

        4.1 - Functions and Types


        luaL_loadstring

        -[-0, +1, m] +[-0, +1, –]

        int luaL_loadstring (lua_State *L, const char *s);

        @@ -5287,8 +6240,45 @@

        4.1 - Functions and Types

        +

        luaL_newlib

        +[-0, +1, e] +

        int luaL_newlib (lua_State *L, const luaL_Reg *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, e] +

        int luaL_newlibtable (lua_State *L, const luaL_Reg l[]);
        + +

        +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). + + +

        +It is implemented as a macro. +The array l must be the actual array, +not a pointer to it. + + + + +


        luaL_newmetatable

        -[-0, +1, m] +[-0, +1, e]

        int luaL_newmetatable (lua_State *L, const char *tname);

        @@ -5309,14 +6299,14 @@

        4.1 - Functions and Types


        luaL_newstate

        -[-0, +0, -] +[-0, +0, –]

        lua_State *luaL_newstate (void);

        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 +and then sets a panic function (see §4.6) that prints an error message to the standard error output in case of fatal errors. @@ -5330,7 +6320,7 @@

        4.1 - Functions and Types


        luaL_openlibs

        -[-0, +0, m] +[-0, +0, e]

        void luaL_openlibs (lua_State *L);

        @@ -5342,10 +6332,10 @@

        4.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. @@ -5358,11 +6348,11 @@

        4.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. @@ -5374,10 +6364,10 @@

        4.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. @@ -5390,12 +6380,12 @@

        4.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. @@ -5404,7 +6394,7 @@

        4.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. @@ -5412,10 +6402,10 @@

        4.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. @@ -5425,17 +6415,34 @@

        4.1 - Functions and Types

        -

        luaL_optstring

        +


        luaL_optstring

        +[-0, +0, v] +

        const char *luaL_optstring (lua_State *L,
        +                            int arg,
        +                            const char *d);
        + +

        +If the function argument arg is a string, +returns this string. +If this argument is absent or is nil, +returns d. +Otherwise, raises an error. + + + + + +


        luaL_optunsigned

        [-0, +0, v] -

        const char *luaL_optstring (lua_State *L,
        -                            int narg,
        -                            const char *d);
        +
        lua_Unsigned luaL_optunsigned (lua_State *L,
        +                               int arg,
        +                               lua_Unsigned u);

        -If the function argument narg is a string, -returns this string. +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 d. +returns u. Otherwise, raises an error. @@ -5443,15 +6450,27 @@

        4.1 - Functions and Types


        luaL_prepbuffer

        -[-0, +0, -] +[-?, +?, e]

        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

        +[-?, +?, e] +

        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 -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. @@ -5459,7 +6478,7 @@

        4.1 - Functions and Types


        luaL_pushresult

        -[-?, +1, m] +[-?, +1, e]

        void luaL_pushresult (luaL_Buffer *B);

        @@ -5470,8 +6489,19 @@

        4.1 - Functions and Types

        +

        luaL_pushresultsize

        +[-?, +1, e] +

        void luaL_pushresultsize (luaL_Buffer *B, size_t sz);
        + +

        +Equivalent to the sequence luaL_addsize, luaL_pushresult. + + + + +


        luaL_ref

        -[-1, +0, m] +[-1, +0, e]

        int luaL_ref (lua_State *L, int t);

        @@ -5507,7 +6537,7 @@

        4.1 - Functions and Types

        Type for arrays of functions to be registered by -luaL_register. +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 @@ -5517,72 +6547,128 @@

        4.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. +

        -Opens a library. +If glb is true, +also stores the result into global modname.

        -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. +Leaves a copy of that result on the stack. + + + +


        luaL_setfuncs

        +[-nup, +0, e] +

        void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);
        +

        -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. +Registers all functions in the array l +(see luaL_Reg) into the table on the top of the stack +(below optional upvalues, see next).

        -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. +These values are popped from the stack after the registration. -


        luaL_typename

        -[-0, +0, -] -

        const char *luaL_typename (lua_State *L, int index);
        +

        luaL_setmetatable

        +[-0, +0, –] +

        void luaL_setmetatable (lua_State *L, const char *tname);

        -Returns the name of the type of the value at the given index. +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_typerror

        -[-0, +0, v] -

        int luaL_typerror (lua_State *L, int narg, const char *tname);
        +

        luaL_testudata

        +[-0, +0, e] +

        void *luaL_testudata (lua_State *L, int arg, const char *tname);

        -Generates an error with a message like the following: +This function works like luaL_checkudata, +except that, when the test fails, +it returns NULL instead of throwing an error. -

        -     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_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, e] +

        void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
        +                     int level);
        + +

        +Creates and pushes a traceback of the stack L1. +If msg is not NULL it is appended +at the beginning of the traceback. +The level parameter tells at which level +to start the traceback. + + + + + +


        luaL_typename

        +[-0, +0, –] +

        const char *luaL_typename (lua_State *L, int index);
        + +

        +Returns the name of the type of the value at the given index.


        luaL_unref

        -[-0, +0, -] +[-0, +0, –]

        void luaL_unref (lua_State *L, int t, int ref);

        @@ -5602,7 +6688,7 @@

        4.1 - Functions and Types


        luaL_where

        -[-0, +1, m] +[-0, +1, e]

        void luaL_where (lua_State *L, int lvl);

        @@ -5627,7 +6713,7 @@

        4.1 - Functions and Types

        -

        5 - Standard Libraries

        +

        6 – Standard Libraries

        The standard Lua libraries provide useful functions @@ -5647,24 +6733,28 @@

        5 - Standard Libraries

          -
        • basic library, which includes the coroutine sub-library;
        • +
        • basic library (§6.1);
        • + +
        • coroutine library (§6.2);
        • -
        • package 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.);
        • -
        • input and output;
        • +
        • bitwise operations (§6.7);
        • -
        • operating system facilities;
        • +
        • input and output (§6.8);
        • -
        • debug facilities.
        • +
        • operating system facilities (§6.9);
        • + +
        • 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. @@ -5674,28 +6764,28 @@

        5 - 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), luaopen_string (for the string library), luaopen_table (for the table library), luaopen_math (for the mathematical 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). -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. -

        5.1 - Basic Functions

        +

        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 +you should check carefully whether you need to provide implementations for some of its facilities. @@ -5720,24 +6810,36 @@

        5.1 - Basic Functions

          -
        • "collect": +
        • "collect": performs a full garbage-collection cycle. This is the default option.
        • -
        • "stop": -stops the garbage collector. +
        • "stop": +stops automatic execution of the garbage collector. +The collector will run only when explicitly invoked, +until a call to restart it.
        • -
        • "restart": -restarts the garbage collector. +
        • "restart": +restarts automatic execution of the garbage collector.
        • -
        • "count": -returns the total memory in use by Lua (in Kbytes). +
        • "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, +so the following equality is always true: + +
          +     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": +
        • "step": performs a garbage-collection step. The step "size" is controlled by arg (larger values mean more steps) in a non-specified way. @@ -5746,18 +6848,33 @@

          5.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.10). +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.10). +the collector (see §2.5). Returns the previous value for step.
        • +
        • "isrunning": +returns a boolean that tells whether the collector is running +(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. +
        • +
        @@ -5783,7 +6900,7 @@

        5.1 - Basic Functions

        Usually, error adds some information about the error position -at the beginning of the message. +at the beginning of the message, if the message is a string. 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. @@ -5798,25 +6915,10 @@

        5.1 - Basic Functions


        _G

        A global variable (not a function) that -holds the global environment (that is, _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. -(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 -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. -The default for f is 1. @@ -5840,77 +6942,85 @@

        5.1 - Basic Functions

        -Returns three values: an iterator function, the table t, and 0, +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]), ···, +will iterate over the pairs (1,t[1]), (2,t[2]), ..., up to the first integer key absent from the table.

        -


        load (func [, chunkname])

        +

        load (ld [, source [, mode [, env]]])

        + + +

        +Loads a chunk.

        -Loads a chunk using function func to get its pieces. -Each call to func must return a string that concatenates +If ld is a string, the chunk is this string. +If ld is a function, +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 there are no errors, +If there are no syntactic 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. -When absent, -it defaults to "=(load)". - - +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).

        -


        loadfile ([filename])

        +source is used as the source of the chunk for error messages +and debug information (see §4.9). +When absent, +it defaults to ld, if ld is a string, +or to "=(load)" otherwise.

        -Similar to load, -but gets the chunk from file filename -or from the standard input, -if no file name is given. +The string mode controls whether the chunk can be text or binary +(that is, a precompiled chunk). +It may be the string "b" (only binary chunks), +"t" (only text chunks), +or "bt" (both binary and text). +The default is "bt".

        -


        loadstring (string [, chunkname])

        +

        loadfile ([filename [, mode [, env]]])

        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. +but gets the chunk from file filename +or from the standard input, +if no file name is given. @@ -5940,11 +7050,11 @@

        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.)

        -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. @@ -5958,7 +7068,14 @@

        5.1 - Basic Functions

        -Returns three values: the next function, the table t, and nil, +If t has a metamethod __pairs, +calls it with t as argument and returns the first three +results from the call. + + +

        +Otherwise, +returns three values: the next function, the table t, and nil, so that the construction

        @@ -5975,7 +7092,7 @@ 

        5.1 - Basic Functions

        -


        pcall (f, arg1, ···)

        +

        pcall (f [, arg1, ···])

        @@ -5995,13 +7112,14 @@

        5.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. @@ -6025,12 +7143,22 @@

        5.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, 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. @@ -6046,33 +7174,14 @@

        5.1 - Basic Functions

        If index is a number, -returns all arguments after argument number index. +returns all arguments after argument number index; +a negative number indexes from the end (-1 is the last argument). 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 -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 -the environment of the running thread. -In this case, setfenv returns no values. - - - -


        setmetatable (table, metatable)

        @@ -6094,37 +7203,43 @@

        5.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 number can have a decimal part, -as well as an optional exponent part (see §2.1). -In other bases, only unsigned 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. @@ -6146,53 +7261,22 @@

        5.1 - Basic Functions

        -

        -


        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 §2.5.5). - - - -


        _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".

        -


        xpcall (f, err)

        +

        xpcall (f, msgh [, arg1, ···])

        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 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. +except that it sets a new message handler msgh. @@ -6200,12 +7284,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.

        @@ -6229,11 +7313,11 @@

        5.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. @@ -6253,8 +7337,8 @@

        5.2 - Coroutine Manipulation

        -Returns the running coroutine, -or nil when called by the main thread. +Returns the running coroutine plus a boolean, +true when the running coroutine is the main one. @@ -6300,8 +7384,6 @@

        5.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. @@ -6310,56 +7392,16 @@

        5.2 - Coroutine Manipulation

        -

        5.3 - Modules

        +

        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 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 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 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. - - - -


        require (modname)

        @@ -6375,11 +7417,11 @@

        5.3 - Modules

        To find a loader, -require is guided by the package.loaders array. -By changing this array, +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.

        @@ -6391,15 +7433,18 @@

        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 package.loaders). +it tries an all-in-one loader (see package.searchers).

        Once a loader is found, -require calls the loader with a single argument, modname. -If the loader returns any value, +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 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 @@ -6409,8 +7454,40 @@

        5.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. + + + + +

        +


        package.config

        + +

        +A string describing some compile-time configurations for packages. +This string is a sequence of lines: + +

          + +
        • The first line is the directory separator string. +Default is '\' for Windows and '/' for all other systems.
        • + +
        • The second line is the character that separates templates in a path. +Default is ';'.
        • + +
        • The third line is the string that marks the +substitution points in a template. +Default is '?'.
        • + +
        • The fourth line is a string that, in a path in Windows, +is replaced by the executable's directory. +Default is '!'.
        • + +
        • The fifth line is a mark to ignore all text before it +when building the luaopen_ function name. +Default is '-'.
        • + +
        @@ -6425,7 +7502,8 @@

        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 +using the environment variable LUA_CPATH_5_2 +or the environment variable LUA_CPATH or a default path defined in luaconf.h. @@ -6437,17 +7515,100 @@

        5.3 - Modules

        -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. +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. + + +

        +This variable is only a reference to the real table; +assignments to this variable do not change the +table used by require. + + + + +

        +


        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 prototype 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 those environment variables are 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.loaders

        +

        package.searchers

        @@ -6461,9 +7622,13 @@

        5.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.

        @@ -6474,27 +7639,14 @@

        5.3 - Modules

        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 search is done as described in function package.searchpath.

        The third searcher looks for a loader as a C library, using the path given by the variable package.cpath. +Again, +the search is done as described in function package.searchpath. For instance, if the C path is the string @@ -6532,80 +7684,53 @@

        5.3 - Modules

        with each submodule keeping its original open function. - - -

        -


        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. -(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 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, Mac OS X, Solaris, BSD, -plus other Unix systems that support the dlfcn standard). +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.

        -


        package.path

        - - -

        -The path used by require to search for a Lua loader. +


        package.searchpath (name, path [, sep [, rep]])

        -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 -is replaced by the default path. - - +Searches for the given name in the given path.

        -


        package.preload

        +A path is a string containing a sequence of +templates separated by semicolons. +For each template, +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 rep +(the system's directory separator, by default), +and then tries to open the resulting file name.

        -A table to store loaders for specific modules -(see require). - +For instance, if the path is the string +

        +     "./?.lua;./?.lc;/usr/local/?/init.lua"
        +

        +the search for the name foo.a +will try to open the files +./foo/a.lua, ./foo/a.lc, and +/usr/local/foo/a/init.lua, in that order.

        -


        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. +Returns the resulting name of the first file that it can +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.) @@ -6613,7 +7738,7 @@

        5.3 - Modules

        -

        5.4 - String Manipulation

        +

        6.4 – String Manipulation

        This library provides generic functions for string manipulation, @@ -6631,7 +7756,7 @@

        5.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). @@ -6642,13 +7767,15 @@

        5.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. @@ -6662,7 +7789,7 @@

        5.4 - String Manipulation

        -Note that numerical codes are not necessarily portable across platforms. +Numerical codes are not necessarily portable across platforms. @@ -6673,15 +7800,17 @@

        5.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).


        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 @@ -6693,7 +7822,7 @@

        5.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. @@ -6708,26 +7837,25 @@

        5.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 +*, 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 \
        @@ -6735,16 +7863,21 @@ 

        5.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 +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, +it is converted to one following the same rules of tostring. @@ -6753,13 +7886,15 @@

        5.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.

        As an example, the following loop +will iterate over all the words from string s, +printing one per line:

              s = "hello world from Lua"
        @@ -6767,8 +7902,6 @@ 

        5.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: @@ -6781,7 +7914,7 @@

        5.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. @@ -6796,31 +7929,34 @@

        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.

        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. 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.

        @@ -6849,13 +7985,13 @@

        5.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" - 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"
        @@ -6897,9 +8033,11 @@

        5.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). @@ -6925,6 +8063,17 @@

        5.4 - String Manipulation

        with length i. +

        +If, after the translation of negative indices, +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, +i is greater than j, +the function returns the empty string. + +

        @@ -6936,7 +8085,7 @@

        5.4 - String Manipulation

        -

        5.4.1 - Patterns

        +

        6.4.1 – Patterns

        Character Class:

        @@ -6945,35 +8094,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.
        • -
        • %l: represents all lowercase letters.
        • +
        • %g: represents all printable characters except space.
        • -
        • %p: represents all punctuation characters.
        • +
        • %l: represents all lowercase letters.
        • -
        • %s: represents all space characters.
        • +
        • %p: represents all punctuation characters.
        • -
        • %u: represents all uppercase letters.
        • +
        • %s: represents all space characters.
        • -
        • %w: represents all alphanumeric characters.
        • +
        • %u: represents all uppercase letters.
        • -
        • %x: represents all hexadecimal digits.
        • +
        • %w: represents all alphanumeric characters.
        • -
        • %z: represents the character with representation 0.
        • +
        • %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) @@ -6981,11 +8130,12 @@

          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 -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. @@ -7002,7 +8152,7 @@

          Character Class:

          have no meaning.

        • -
        • [^set]: +
        • [^set]: represents the complement of set, where set is interpreted as above.
        • @@ -7048,7 +8198,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;

        • @@ -7073,6 +8223,16 @@

          Pattern Item:

          balanced parentheses.

        • +
        • +%f[set], a frontier pattern; +such item matches an empty string at any position such that +the next character belongs to set +and the previous character does not belong to set. +The set set is interpreted as previously described. +The beginning and the end of the subject are handled as if +they were the character '\0'. +
        • +
        @@ -7080,7 +8240,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. @@ -7111,9 +8271,6 @@

        Captures:

        string "flaaap", there will be two captures: 3 and 5. -

        -A pattern cannot contain embedded zeros. Use %z instead. - @@ -7123,85 +8280,97 @@

        Captures:

        +

        6.5 – Table Manipulation

        -

        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 these functions, when we talk about the "length" of a table -we mean the result of the length operator. +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. + + +

        +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, -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), +Inserts element value at position pos in list, +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 table t. +of list t.

        -


        table.maxn (table)

        +

        table.pack (···)

        -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.) +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 resulting table may not be a sequence.

        -


        table.remove (table [, pos])

        +

        table.remove (list [, pos])

        -Removes from table the element at position pos, -shifting down other elements to close the space, if necessary. +Removes from list the element at position pos, +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 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 (list [, 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. +Sorts list elements in a given order, in-place, +from list[1] to list[#list]. 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). +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(list[i+1],list[i]) will be true after the sort). If comp is not given, then the standard Lua operator < is used instead. @@ -7214,10 +8383,26 @@

        5.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]
        +

        +By default, i is 1 and j is #list. + + -

        5.6 - Mathematical Functions

        + + +

        6.6 – Mathematical Functions

        This library is an interface to the standard C math library. @@ -7328,225 +8513,444 @@

        5.6 - Mathematical Functions

        -


        math.floor (x)

        +

        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 +that rounds the quotient towards zero. + + + + +

        +


        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 [, base])

        + + +

        +Returns the logarithm of x in the given base. +The default for base is e +(so that the function returns the natural 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 of π. + + + + +

        +


        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 Standard C. +(No guarantees can be given for its statistical properties.) + + +

        +When called without arguments, +returns a uniform pseudo-random real 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, +math.random returns a uniform pseudo-random +integer in the range [m, n]. + + + + +

        +


        math.randomseed (x)

        -Returns the largest integer smaller than or equal to x. +Sets x as the "seed" +for the pseudo-random generator: +equal seeds produce equal sequences of numbers.

        -


        math.fmod (x, y)

        +

        math.sin (x)

        -Returns the remainder of the division of x by y -that rounds the quotient towards zero. +Returns the sine of x (assumed to be in radians).

        -


        math.frexp (x)

        +

        math.sinh (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). +Returns the hyperbolic sine of x.

        -


        math.huge

        +

        math.sqrt (x)

        -The value HUGE_VAL, -a value larger than or equal to any other numerical value. +Returns the square root of x. +(You can also use the expression x^0.5 to compute this value.)

        -


        math.ldexp (m, e)

        +

        math.tan (x)

        -Returns m2e (e should be an integer). +Returns the tangent of x (assumed to be in radians).

        -


        math.log (x)

        +

        math.tanh (x)

        -Returns the natural logarithm of x. +Returns the hyperbolic tangent of x. + + + +

        6.7 – Bitwise Operations

        +

        -


        math.log10 (x)

        +This library provides bitwise operations. +It provides all its functions inside the table bit32.

        -Returns the base-10 logarithm of x. +Unless otherwise stated, +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.bnot(0) is 0xFFFFFFFF, +which is different from -1. +

        +


        bit32.arshift (x, disp)

        -


        math.max (x, ···)

        +Returns the number x shifted disp bits to the right. +The number disp may be any representable integer. +Negative displacements shift to the left.

        -Returns the maximum value among its arguments. +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).

        -


        math.min (x, ···)

        +

        bit32.band (···)

        -Returns the minimum value among its arguments. +Returns the bitwise and of its operands.

        -


        math.modf (x)

        +

        bit32.bnot (x)

        -Returns two numbers, -the integral part of x and the fractional part of x. +Returns the bitwise negation of x. +For any integer x, +the following identity holds: +

        +     assert(bit32.bnot(x) == (-1 - x) % 2^32)
        +

        -


        math.pi

        +

        bit32.bor (···)

        -The value of pi. +Returns the bitwise or of its operands.

        -


        math.pow (x, y)

        +

        bit32.btest (···)

        -Returns xy. -(You can also use the expression x^y to compute this value.) +Returns a boolean signaling +whether the bitwise and of its operands is different from zero.

        -


        math.rad (x)

        +

        bit32.bxor (···)

        -Returns the angle x (given in degrees) in radians. +Returns the bitwise exclusive or of its operands.

        -


        math.random ([m [, n]])

        +

        bit32.extract (n, field [, width])

        -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.) +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].

        -When called without arguments, -returns a uniform pseudo-random real 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, -math.random returns a uniform pseudo-random -integer in the range [m, n]. +The default for width is 1.

        -


        math.randomseed (x)

        +

        bit32.replace (n, v, field [, width])

        -Sets x as the "seed" -for the pseudo-random generator: -equal seeds produce equal sequences of numbers. +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.

        -


        math.sin (x)

        +

        bit32.lrotate (x, disp)

        -Returns the sine of x (assumed to be in radians). +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(bit32.lrotate(x, disp) == bit32.lrotate(x, disp % 32))
        +

        +In particular, +negative displacements rotate to the right. -

        -


        math.sinh (x)

        -Returns the hyperbolic sine of x. +


        bit32.lshift (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, +displacements with absolute values higher than 31 +result in zero (all bits are shifted out).

        -


        math.sqrt (x)

        +For positive displacements, +the following equality holds: + +
        +     assert(bit32.lshift(b, disp) == (b * 2^disp) % 2^32)
        +
        +

        -Returns the square root of x. -(You can also use the expression x^0.5 to compute this value.) +


        bit32.rrotate (x, disp)

        +

        +Returns the number x rotated disp bits to the right. +The number disp may be any representable integer.

        -


        math.tan (x)

        +For any valid displacement, +the following identity holds: + +
        +     assert(bit32.rrotate(x, disp) == bit32.rrotate(x, disp % 32))
        +

        +In particular, +negative displacements rotate to the left. + +

        -Returns the tangent of x (assumed to be in radians). +


        bit32.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 31 +result in zero (all bits are shifted out).

        -


        math.tanh (x)

        +For positive displacements, +the following equality holds: +
        +     assert(bit32.rshift(b, disp) == math.floor(b % 2^32 / 2^disp))
        +

        -Returns the hyperbolic tangent of x. +This shift operation is what is called logical shift. @@ -7554,7 +8958,7 @@

        5.6 - Mathematical Functions

        -

        5.7 - Input and Output Facilities

        +

        6.8 – Input and Output Facilities

        The I/O library provides two different styles for file manipulation. @@ -7604,7 +9008,7 @@

        5.7 - Input and Output Facilities

        -Equivalent to file:flush over the default output file. +Equivalent to io.output():flush(). @@ -7630,20 +9034,13 @@

        5.7 - Input and Output Facilities

        -


        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 body end
        -

        -will iterate over all lines of the file. +and returns an iterator function that +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. @@ -7655,6 +9052,11 @@

        5.7 - 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. + +

        @@ -7672,18 +9074,16 @@

        5.7 - 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, 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. @@ -7702,6 +9102,11 @@

        5.7 - 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 @@ -7710,11 +9115,6 @@

        5.7 - Input and Output Facilities

        (if mode is "w"). -

        -This function is system dependent and is not available -on all platforms. - -

        @@ -7722,7 +9122,7 @@

        5.7 - Input and Output Facilities

        -Equivalent to io.input():read. +Equivalent to io.input():read(···). @@ -7757,7 +9157,7 @@

        5.7 - Input and Output Facilities

        -Equivalent to io.output():write. +Equivalent to io.output():write(···). @@ -7773,6 +9173,12 @@

        5.7 - Input and Output Facilities

        but that takes an unpredictable amount of time to happen. +

        +When closing a file handle created with io.popen, +file:close returns the same values +returned by os.execute. + +

        @@ -7786,21 +9192,29 @@

        5.7 - Input and Output Facilities

        -


        file:lines ()

        +

        file:lines (···)

        Returns an iterator function that, each time it is called, -returns a new line from the file. -Therefore, the construction +reads the file according to the given formats. +When no format is given, +uses "*l" as a default. +As an example, 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. -(Unlike io.lines, this function does not close the file -when the loop ends.) +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. + + +

        +In case of errors this function raises the error, +instead of returning an error code. @@ -7816,7 +9230,7 @@

        5.7 - 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). @@ -7825,24 +9239,29 @@

        5.7 - 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": -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, +
        • "*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 bytes, returning nil on end of file. If number is zero, it reads nothing and returns an empty string, @@ -7854,7 +9273,7 @@

          5.7 - Input and Output Facilities

          -


          file:seek ([whence] [, offset])

          +

          file:seek ([whence [, offset]])

          @@ -7864,13 +9283,13 @@

          5.7 - 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, +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. @@ -7897,17 +9316,17 @@

          5.7 - 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)). +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). @@ -7926,11 +9345,13 @@

            5.7 - 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. + + +

            +In case of success, this function returns file. +Otherwise it returns nil plus a string describing the error. @@ -7938,7 +9359,7 @@

            5.7 - Input and Output Facilities

            -

            5.8 - Operating System Facilities

            +

            6.9 – Operating System Facilities

            This library is implemented through table os. @@ -7977,11 +9398,13 @@

            5.8 - 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). +This last field may be absent +if the information is not available.

            @@ -7997,6 +9420,11 @@

            5.8 - Operating System Facilities

            (that is, os.date() is equivalent to os.date("%c")). +

            +On some systems, +this function may be not thread safe. + +

            @@ -8018,22 +9446,52 @@

            5.8 - 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. +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: + +

              + +
            • "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. + +

            +


            os.exit ([code [, close])

            +

            -


            os.exit ([code])

            +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 true.

            -Calls the C function exit, -with an optional code, -to terminate the host program. -The default value for code is the success code. +If the optional second argument close is true, +closes the Lua state before exiting. @@ -8054,10 +9512,10 @@

            5.8 - 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. +plus a string describing the error and the error code. @@ -8069,7 +9527,7 @@

            5.8 - 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. @@ -8080,7 +9538,7 @@

            5.8 - 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"; @@ -8112,17 +9570,22 @@

            5.8 - 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.

            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.date and os.difftime. @@ -8139,7 +9602,7 @@

            5.8 - 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 @@ -8159,23 +9622,20 @@

            5.8 - Operating System Facilities

            -

            5.9 - The Debug Library

            +

            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. -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 its 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.

            @@ -8203,14 +9663,7 @@

            5.9 - 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. - - - - -

            -


            debug.getfenv (o)

            -Returns the environment of object o. +within any function and so have no direct access to local variables. @@ -8229,19 +9682,20 @@

            5.9 - 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; +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. @@ -8271,34 +9725,45 @@

            5.9 - 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. -(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. +with index local of the function at level f of the stack. +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.)

            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). + + +

            +The parameter f may also be a function. +In that case, getlocal returns only the name of function parameters.

            -


            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. @@ -8309,30 +9774,31 @@

            5.9 - The Debug Library

            -Returns the registry table (see §3.5). +Returns the registry table (see §4.5).

            -


            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.

            -


            debug.setfenv (object, table)

            +

            debug.getuservalue (u)

            -Sets the environment of the given object to the given table. -Returns object. +Returns the Lua value associated to u. +If u is not a userdata, +returns nil. @@ -8349,9 +9815,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. @@ -8365,8 +9831,8 @@

            5.9 - The Debug Library

            When the hook is called, its first parameter is a string describing the event that has triggered its call: -"call", "return" (or "tail return", -when simulating a return from a tail call), +"call" (or "tail call"), +"return", "line", and "count". For line events, the hook also gets the new line number as its second parameter. @@ -8374,10 +9840,7 @@

            5.9 - The Debug Library

            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. +and level 1 is the hook function). @@ -8396,26 +9859,32 @@

            5.9 - The Debug Library

            Otherwise, it returns the name of the local variable. +

            +See debug.getlocal for more information about +variable indices and names. + +

            -


            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 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. @@ -8423,12 +9892,32 @@

            5.9 - 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]])

            -Returns a string with a traceback of the call stack. +If message is present but is neither a string nor nil, +this function returns message without further processing. +Otherwise, +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 @@ -8438,19 +9927,50 @@

            5.9 - The Debug Library

            +

            +


            debug.upvalueid (f, 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 (f1, n1, f2, n2)

            + + +

            +Make the n1-th upvalue of the Lua closure f1 +refer to the n2-th upvalue of the Lua closure f2. + + -

            6 - 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: @@ -8460,12 +9980,13 @@

            6 - Lua Stand-alone

            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;
            • +
            • -E: ignores environment variables;
            • +
            • --: 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. @@ -8476,21 +9997,33 @@

            6 - Lua Stand-alone

            -Before running any argument, -the interpreter checks for an environment variable LUA_INIT. -If its format is @filename, +When called without option -E, +the interpreter checks for an environment variable LUA_INIT_5_2 +(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, +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. + + +

            +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 may be different.) @@ -8519,7 +10052,7 @@

            6 - Lua Stand-alone

            [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 '...'. @@ -8532,30 +10065,28 @@

    6 - Lua Stand-alone

    -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: +In case of unprotected errors in the script, +the interpreter reports the error to the standard error stream. +If the error object is a string, +the interpreter adds a stack traceback to it. +Otherwise, if the error object has a metamethod __tostring, +the interpreter calls this metamethod to produce the final message. +Finally, if the error object is nil, +the interpreter does not report the error. -

    -     $ 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. + +

    +When finishing normally, +the interpreter closes its main Lua state +(see lua_close). +The script can avoid this step by +calling os.exit to terminate.

    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, @@ -8567,46 +10098,80 @@

    6 - Lua Stand-alone

    (Of course, the location of the Lua interpreter may 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.) -

    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 -from Lua 5.0 to Lua 5.1. -You can avoid most of the incompatibilities compiling Lua with +from Lua 5.1 to Lua 5.2. +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. +Similarly, +all features marked as deprecated in Lua 5.1 +have been removed in Lua 5.2. -

    7.1 - Changes in the Language

    +

    8.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. -(See compile-time option LUA_COMPAT_VARARG in luaconf.h.) +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 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 +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. +

    • + +
    • +Lua identifiers cannot use locale-dependent letters. +
    • + +
    • +Doing a step or a full collection in the garbage collector +does not restart the collector if it has been stopped. +
    • + +
    • +Weak tables with weak keys now perform like ephemeron tables.
    • -There was a subtle change in the scope of the implicit -variables of the for statement and for the repeat statement. +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 that +there will not be a corresponding return event.
    • -The long string/long comment syntax ([[string]]) -does not allow nesting. -You can use the new syntax ([=[string]=]) in these cases. -(See compile-time option LUA_COMPAT_LSTR in luaconf.h.) +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.
    @@ -8614,57 +10179,71 @@

    7.1 - Changes in the Language

    -

    7.2 - Changes in the Libraries

    +

    8.2 – Changes in the Libraries

    • -Function string.gfind was renamed string.gmatch. -(See compile-time option LUA_COMPAT_GFIND in luaconf.h.) +Function module is deprecated. +It is easy to set up a module with regular Lua code. +Modules are not expected to set global variables. +
    • + +
    • +Functions setfenv and getfenv were removed, +because of the changes in environments. +
    • + +
    • +Function math.log10 is deprecated. +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.
    • -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.maxn is deprecated. +Write it in Lua if you really need it.
    • -Function table.setn was deprecated. -Function table.getn corresponds -to the new length operator (#); -use the operator instead of the function. -(See compile-time option LUA_COMPAT_GETN in luaconf.h.) +Function os.execute now returns true when command +terminates successfully and nil plus error information +otherwise.
    • -Function loadlib was renamed package.loadlib. -(See compile-time option LUA_COMPAT_LOADLIB in luaconf.h.) +Function unpack was moved into the table library +and therefore must be called as table.unpack.
    • -Function math.mod was renamed math.fmod. -(See compile-time option LUA_COMPAT_MOD in luaconf.h.) +Character class %z in patterns is deprecated, +as now patterns may contain '\0' as a regular character.
    • -Functions table.foreach and table.foreachi are deprecated. -You can use a for loop with pairs or ipairs instead. +The table package.loaders was renamed package.searchers.
    • -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. +Lua does not have bytecode verification anymore. +So, all functions that load code +(load and loadfile) +are potentially insecure when loading untrusted binary data. +(Actually, those functions were already insecure because +of flaws in the verification algorithm.) +When in doubt, +use the mode argument of those functions +to restrict them to loading textual chunks.
    • -Function collectgarbage has different arguments. -Function gcinfo is deprecated; -use collectgarbage("count") instead. +The standard paths in the official distribution may +change between versions.
    @@ -8672,40 +10251,76 @@

    7.2 - Changes in the Libraries

    -

    7.3 - Changes in the API

    +

    8.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. +Pseudoindex LUA_GLOBALSINDEX was removed. +You must get the global environment from the registry +(see §4.5). +
    • + +
    • +Pseudoindex LUA_ENVIRONINDEX +and functions lua_getfenv/lua_setfenv +were removed, +as C functions no longer have environments.
    • -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 -create a state with a standard allocation function -(based on realloc). +Function luaL_register is deprecated. +Use luaL_setfuncs so that your module does not create globals. +(Modules are not expected to set global variables anymore.)
    • -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. +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.
    • -Function luaL_openlib was replaced by luaL_register. +Finalizers (__gc metamethods) for userdata are called in the +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, +if the metatable does not have a __gc field when set, +the finalizer will not be called, +even if it is set later.
    • -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.) +luaL_typerror was removed. +Write your own version if you need it. +
    • + +
    • +Function lua_cpcall is deprecated. +You can simply push the function with lua_pushcfunction +and call it with lua_pcall. +
    • + +
    • +Functions lua_equal and lua_lessthan are deprecated. +Use the new lua_compare with appropriate options instead. +
    • + +
    • +Function lua_objlen was renamed lua_rawlen. +
    • + +
    • +Function lua_load has an extra parameter, mode. +Pass NULL to simulate the old behavior. +
    • + +
    • +Function lua_resume has an extra parameter, from. +Pass NULL or the thread doing the call.
    @@ -8713,7 +10328,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. @@ -8724,62 +10339,68 @@

    8 - The Complete Syntax of Lua

     
    -	chunk ::= {stat [`;´]} [laststat [`;´]]
    +	chunk ::= block
     
    -	block ::= chunk
    +	block ::= {stat} [retstat]
     
    -	stat ::=  varlist `=´ explist | 
    +	stat ::=  ‘;’ | 
    +		 varlist ‘=’ explist | 
     		 functioncall | 
    +		 label | 
    +		 break | 
    +		 goto Name | 
     		 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 ‘=’ exp ‘,’ exp [‘,’ exp] do block end | 
     		 for namelist in explist do block end | 
     		 function funcname funcbody | 
     		 local function Name funcbody | 
    -		 local namelist [`=´ explist] 
    +		 local namelist [‘=’ explist] 
    +
    +	retstat ::= return [explist] [‘;’]
     
    -	laststat ::= return [explist] | break
    +	label ::= ‘::’ Name ‘::’
     
    -	funcname ::= Name {`.´ Name} [`:´ Name]
    +	funcname ::= Name {‘.’ Name} [‘:’ Name]
     
    -	varlist ::= var {`,´ var}
    +	varlist ::= var {‘,’ var}
     
    -	var ::=  Name | prefixexp `[´ exp `]´ | prefixexp `.´ Name 
    +	var ::=  Name | prefixexp ‘[’ exp ‘]’ | prefixexp ‘.’ Name 
     
    -	namelist ::= Name {`,´ Name}
    +	namelist ::= Name {‘,’ Name}
     
    -	explist ::= {exp `,´} exp
    +	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 `)´
    +	prefixexp ::= var | functioncall | ‘(’ exp ‘)’
     
    -	functioncall ::=  prefixexp args | prefixexp `:´ Name args 
    +	functioncall ::=  prefixexp args | prefixexp ‘:’ Name args 
     
    -	args ::=  `(´ [explist] `)´ | tableconstructor | String 
    +	args ::=  ‘(’ [explist] ‘)’ | tableconstructor | String 
     
    -	function ::= function funcbody
    +	functiondef ::= function funcbody
     
    -	funcbody ::= `(´ [parlist] `)´ block end
    +	funcbody ::= ‘(’ [parlist] ‘)’ block end
     
    -	parlist ::= namelist [`,´ `...´] | `...´
    +	parlist ::= namelist [‘,’ ‘...’] | ‘...’
     
    -	tableconstructor ::= `{´ [fieldlist] `}´
    +	tableconstructor ::= ‘{’ [fieldlist] ‘}’
     
     	fieldlist ::= field {fieldsep field} [fieldsep]
     
    -	field ::= `[´ exp `]´ `=´ exp | Name `=´ exp | exp
    +	field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp
     
    -	fieldsep ::= `,´ | `;´
    +	fieldsep ::= ‘,’ | ‘;’
     
    -	binop ::= `+´ | `-´ | `*´ | `/´ | `^´ | `%´ | `..´ | 
    -		 `<´ | `<=´ | `>´ | `>=´ | `==´ | `~=´ | 
    +	binop ::= ‘+’ | ‘-’ | ‘*’ | ‘/’ | ‘^’ | ‘%’ | ‘..’ | 
    +		 ‘<’ | ‘<=’ | ‘>’ | ‘>=’ | ‘==’ | ‘~=’ | 
     		 and | or
     
    -	unop ::= `-´ | not | `#´
    +	unop ::= ‘-’ | not | ‘#
    @@ -8794,10 +10415,10 @@

    8 - The Complete Syntax of Lua


    Last update: -Mon Feb 13 18:54:19 BRST 2012 +Fri Jun 8 16:13:40 BRT 2012 diff --git a/doc/osi-certified-72x60.png b/doc/osi-certified-72x60.png new file mode 100644 index 0000000000000000000000000000000000000000..07df5f6ee7a7a8b2108025dcd815f73f145a83af GIT binary patch literal 3774 zcmV;v4ngsWP)$kl5 zqcT7g&?zu8?ezWYz4zUB-|zR9d+&Qy2xAN{qY(ew0A7^*gV^7jytKqPFV3{hZfovn zs%x!l>(m&Gdb8C+5XeR7>h0kj=o=X3A39;2KLYfEMt>p1YMW~dt`rpAC{lN~P>5pq zH1L4nAdCT17}*hN=LnEsvMl=5Ij^QArAa&_V~zoht-Ei~)E~(Ivhe0#jik{t$isEK znCH$TxCB8EKmcF>3@pRaHpbR%Gqm*dsZA4H{j(NjZFp^iNFW+RBx6R*X19J*`0XG5 z^Y>cR=^Hi9#ovYGlbFSr#Q*^PgCGC^gb*SC5TcBfzQLe-r2m!Quik&_g9XzTj0qSR zD`FkG_RYWDa^+#UUxL&t+!K+&(ion@Fd`5l5p7{Qsva9vegC|4^NzJUMvn)^gqWsF zvu^j=%FfCVg^cgbXDRl1DE$lsfe;BjjmFmRHER~E-MeWoNsyyNHCpG%Y}igd_(Md;&9La8_B075NDRX9gTD zIHY`}9E~aGi9Kk1@P~rmPna=*=gz~UTdTpsQmjX)J23%v9NliQS)8`xJh6Qz_nE~e z&tP|!dcJdo;JMNa3>afSx$lko8>fp-I}OiCVz(dOF1u6e8$IrsSP?=5mp~lkaFqm? zAUMxRq%ecIu3WE)Uf=%p8g z+RSY?G=VO%wAfdICj?Uzb+5jr{8m|)i#{M}JjaDIoXf#1=DYLwX;1EW&sijPvm6EkBGuOx6r~lKv`g`yH?)|&PRUr$5Ibw2HBM7C74XvE@gaPjN+@;j$J)AgYhnT-U5m+wj|Wz8K630AfO8PUoGD^^Mcq zY9C<~%wUm^u%ox5P21)KNN0$(v^OI$A~?iwsS_fRu1+`EH|CRdpA4zsk8Z#|?x@^vVEAL+2JxH%&^{JUU%B=?EU7`Ar*Q|JvqPofcBt765(*f5JI$>=3{<%K)4ei zogo$)5XP}_X$y^pIYyWTt}EAnhTq}u4sAdBvC(WC{I#x4^>$vCvQ0UDs^18sAQG9o zEaP0qjrSSv1W0FyO%9&y$@em~n@8}}EXBG6x%ew49J_q%l@As_XnNpi|MTTPr~ca_ zW%uon6dBKL*pvzYFvf<~p6K8hK9BDNNN0$7xp^hWC3n^7FoQ?P(=m(6!Pj&S2f1fqH=`(w)KcPl5aEi2}~4hF*f*g}vaS-=c7v>N8c z{yNM*%+azq=@prWtgpi~^3?^AsJqS(>=pb=6PrGH#=O{Hcho$_F#MtsK$$3e2fZvg zy}!-V%`+uFMOW87LIgu3vKuMgqwY0}*Sd;aokQp(F#-{}Ss(Iy1iekY1ZQX?1WEL? z7=zq`lH-#Hw=bHRio3yPun%`c5rI1Hb|wTSWTs|12Mg#QkkwTmy zAYul0H*_b(BnkP#!R_&p@d54uz0JKthGv3C^fdKS%~alookE`QX@%#MQN2=SFWrOha7Ij7ImStNaWsy~? zsylUeT02_-z-G4s0L!v=+Wx|cxr$tmY&$a1by8z#6HBp!*9{@mU9XQ0h@L%V_R}4g z&s#2{MCOj4`5ux-SUautC5@{U895o-biKMWWoQ09{|jx8wz}@_(ep%Yk4{90C#s6-sa}fU5{}m>#>VtE_b#5bn8O+3k{&6GoEkB;yGie;A_5Uy zqPN*tU()pE+_&~``5XX({el-xT_}%`%fsc>_0@m5{+FhXru>rpyLESe31R>cK^FFrCm+#WL$-D{Z3*9>Lg{wi}xEYn_`@Hy`-d z1N}kIY%@Eu&Bpe|Rr6N;%Yk>6&RI$lgpIO26BYT%C!dU-o4bqqQpGY?p6lPru6Hzc z@WuSDI^BYaDH*>R)~)$V1J0Edn4r(9vo>E<2XjOJr2*G124;t^U+p{iUnZN5oapCpCk(F}}<#3ZZli!Nk z^UWT;Q9qm-i`i$kJS}5P%puBJ<&krTO;*#$Y7d$o96EbQ{aF1XFpTj}wf}eI|IOba z%w}_CWu?JjkV>U-ad9L$@Mu$CU;pUQBZgt5QmI@n=W@9K(A(SF-rnxzy|_!5ekKqCQTad`sa|&&Q6jfy}iAEst?|mH*emIjg9SB zRVWlHl?r3bvh2qnf6V6(+>4TulB%kzFveeh{k1?K*t&J=m>dk9P8SjqQdn4sF;*&- z(b3VFnVH$y*$Rb%rs zefJ#z#KpyZ_0?C$jvY%)O?7a?7#}%u1OT>d*)keF*REZ=c=4j6tkr5MilS*cB_$;< zFArmEv)Oby-7}4>TD9uE_ulKT4s6Bp@^Y0*rBEo&o;?cy8#Zi^%jH+DTv4f1SFc_L zfc5LwXJ=;vKt@K!?%liR&!6Almmq$2R@G|tg$oyGnpP+jQBhF<(9qCOR8%AuiBtJCSc zyu1LQw6wIQre^Zw$^E0N)#}R1%J}$rkw`Qc#z0A{)dIkjDN`I(PfyS2=x9f~R4N64 zPe1*1=gytQ#l=RWao4V0bLY-=?Bpl*dQDA@LZMJ9l{Gar$;rvzfB$`Tb#+==T0=ua zSy@?1N{UXWyL9Q&#*G`Zv$GE#JXljxBauj2T3VD!rO9N<%F3#*uP-Sn(P%W=w{Jgx z{(NC!VNOmC0OaN6ZQHg@tJQw^;fGtdZUulVSFX&NGv~~iGoO9-nNq0~2n78w23E{L zmth7T3|W>10ISuSm6cUgRCMXmr5!tV0D!x@`?6)rcI?<8lgZ#IIehqVOiYYpi@x#3 z8xau^+1c4ER;th&( zVHk--A`l3|!os9dsYatANm8TH96x@%qM{-&FmUtc&2qVX-MV%A_U(J~%{TY#*<&ym zX3Ur|c$No?u%e>k#EBDaZEY7XUVLH`0zh|n zw_~XRz;RH!y1MS)zn_X$Km70mNs@ZKo~G$z$BuD09F}FpVzEY}F&d2ug#rLPJUpgPpKh}a^y$-i zJl@%}XHT6vRaaNHckf=MQYn>6Fk&*D<+ja0B z5C{a#&CQN-V`HPyXe3EeAP~gH#>U3RayT5ZSd1}tbaaSNDAZ^)j%n&QHMoE=7KubA zlWEeVNpiV7Dk=&gzM|0Dz(>0HA5Q-_F}_znz(xxqbU~E|+`a#EH|V zPjA|^DJLg~rs?+f_6rv-T)upnAP7fChoq;cFJHcV=gyt)zWXjs(+gZ<%kMDTlOd1+TFW%&z(D`)oKF*0@Bmd zLqkIy?RvewprGK+ojWv5%Ve?@D^>&r1p$CcrMhuv}x1&joiO~|IC>)G) -Lua documentation +Lua 5.2 readme + + @@ -9,32 +30,381 @@

    Lua -Documentation +Welcome to Lua 5.2

    -This is the documentation included in the source distribution of Lua 5.1.5. +

    +about +· +installation +· +changes +· +license +· +reference manual -

    +

    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

    + +

    +Lua is distributed in +source +form. +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 +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. +See also +instructions for other systems +and +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.1. +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. + 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 the Makefile. You'll + probably need the right permissions to install files. + +

    + To build and install Lua in one step, do "make xxx install", + where xxx is your platform name. + +

    + To install Lua locally, do "make local". + This will create a directory install with subdirectories + bin, include, lib, man, + 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. + +

    +
    + 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. + 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 available to experts by editing the Lua sources. + +

    + 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: +
    +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 lcorolib.c ldblib.c liolib.c +lmathlib.c loslib.c lstrlib.c ltablib.c loadlib.c linit.c +
    +interpreter: +
    + library, lua.c +
    +compiler: +
    + library, luac.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 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. + 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

    + +

    +Here are the main changes introduced in Lua 5.2. +The +reference manual +lists the +incompatibilities that had to be introduced. + +

    Main changes

    +
      +
    • yieldable pcall and metamethods +
    • 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: +

    Language

    +
      +
    • no more fenv for threads or functions +
    • tables honor the __len metamethod +
    • hex and \z 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

    +
      +
    • arguments for function called through xpcall +
    • 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 +
    • 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

    +
      +
    • main thread predefined in the registry +
    • 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 +
    • nparams and isvararg available in debug API +
    • new lua_Unsigned +
    + +

    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 +
    • parser uses much less C-stack space (no more auto arrays) +
    + +

    Lua standalone interpreter

    +
      +
    • new -E option to avoid environment variables +
    • handling of non-string error messages +
    + +

    License

    + +[osi certified] + + +

    +Lua is free software distributed under the terms of the +MIT license +reproduced below; +it may 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, see +this. + +

    +Copyright © 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 "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: -Fri Feb 3 09:44:42 BRST 2012 +Tue May 29 21:57:51 BRT 2012 + diff --git a/etc/Makefile b/etc/Makefile deleted file mode 100644 index 6d00008d98..0000000000 --- a/etc/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -# makefile for Lua etc - -TOP= .. -LIB= $(TOP)/src -INC= $(TOP)/src -BIN= $(TOP)/src -SRC= $(TOP)/src -TST= $(TOP)/test - -CC= gcc -CFLAGS= -O2 -Wall -I$(INC) $(MYCFLAGS) -MYCFLAGS= -MYLDFLAGS= -Wl,-E -MYLIBS= -lm -#MYLIBS= -lm -Wl,-E -ldl -lreadline -lhistory -lncurses -RM= rm -f - -default: - @echo 'Please choose a target: min noparser one strict clean' - -min: min.c - $(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) - $(BIN)/luac $(TST)/hello.lua - -./a.out luac.out - -./a.out -e'a=1' - -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) a.out core core.* *.o luac.out - -.PHONY: default min noparser one strict clean diff --git a/etc/README b/etc/README deleted file mode 100644 index 5149fc91d4..0000000000 --- a/etc/README +++ /dev/null @@ -1,37 +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 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. - -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" for a demo. - -strict.lua - Traps uses of undeclared global variables. - Do "make strict" for a demo. - diff --git a/etc/all.c b/etc/all.c deleted file mode 100644 index dab68fac58..0000000000 --- a/etc/all.c +++ /dev/null @@ -1,38 +0,0 @@ -/* -* all.c -- Lua core, libraries and interpreter in a single file -*/ - -#define luaall_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" -#include "loslib.c" -#include "lstrlib.c" -#include "ltablib.c" - -#include "lua.c" 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 07e2852b0a..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.5 - -# 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/luavs.bat b/etc/luavs.bat deleted file mode 100644 index 08c2beddf6..0000000000 --- a/etc/luavs.bat +++ /dev/null @@ -1,28 +0,0 @@ -@rem Script to build Lua 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 (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:lua51.dll l*.obj -if exist lua51.dll.manifest^ - %MYMT% -manifest lua51.dll.manifest -outputresource:lua51.dll;2 -%MYCOMPILE% /DLUA_BUILD_AS_DLL lua.c -%MYLINK% /out:lua.exe lua.obj lua51.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 6a85a4d10e..0000000000 --- a/etc/min.c +++ /dev/null @@ -1,39 +0,0 @@ -/* -* 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" -#include "lauxlib.h" - -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 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("\n"); - return 0; -} - -int main(void) -{ - lua_State *L=lua_open(); - lua_register(L,"print",print); - if (luaL_dofile(L,NULL)!=0) fprintf(stderr,"%s\n",lua_tostring(L,-1)); - lua_close(L); - return 0; -} diff --git a/etc/noparser.c b/etc/noparser.c deleted file mode 100644 index 13ba546239..0000000000 --- a/etc/noparser.c +++ /dev/null @@ -1,50 +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 ("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 - -#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, const char *name) { - UNUSED(z); - UNUSED(buff); - UNUSED(name); - lua_pushliteral(L,"parser not loaded"); - lua_error(L); - return NULL; -} - -#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); -#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 deleted file mode 100644 index 604619dd2e..0000000000 --- a/etc/strict.lua +++ /dev/null @@ -1,41 +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. --- - -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 e0d4c9fa64..8c9ee677ee 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 ======================= @@ -8,37 +7,46 @@ PLAT= none CC= gcc -CFLAGS= -O2 -Wall $(MYCFLAGS) +CFLAGS= -O2 -Wall -DLUA_COMPAT_ALL $(SYSCFLAGS) $(MYCFLAGS) +LDFLAGS= $(SYSLDFLAGS) $(MYLDFLAGS) +LIBS= -lm $(SYSLIBS) $(MYLIBS) + AR= ar rcu RANLIB= ranlib RM= rm -f -LIBS= -lm $(MYLIBS) + +SYSCFLAGS= +SYSLDFLAGS= +SYSLIBS= MYCFLAGS= MYLDFLAGS= MYLIBS= +MYOBJS= -# == 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 lcorolib.o ldblib.o liolib.o \ + lmathlib.o loslib.o lstrlib.o ltablib.o loadlib.o linit.o +BASE_O= $(CORE_O) $(LIB_O) $(MYOBJS) 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_O= $(BASE_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) @@ -47,136 +55,133 @@ o: $(ALL_O) a: $(ALL_A) -$(LUA_A): $(CORE_O) $(LIB_O) - $(AR) $@ $(CORE_O) $(LIB_O) # DLL needs all object files +$(LUA_A): $(BASE_O) + $(AR) $@ $(BASE_O) $(RANLIB) $@ $(LUA_T): $(LUA_O) $(LUA_A) - $(CC) -o $@ $(MYLDFLAGS) $(LUA_O) $(LUA_A) $(LIBS) + $(CC) -o $@ $(LDFLAGS) $(LUA_O) $(LUA_A) $(LIBS) $(LUAC_T): $(LUAC_O) $(LUA_A) - $(CC) -o $@ $(MYLDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS) + $(CC) -o $@ $(LDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS) clean: $(RM) $(ALL_T) $(ALL_O) depend: - @$(CC) $(CFLAGS) -MM l*.c print.c + @$(CC) $(CFLAGS) -MM l*.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 "LDFLAGS= $(SYSLDFLAGS)" + @echo "LIBS= $(LIBS)" + @echo "AR= $(AR)" + @echo "RANLIB= $(RANLIB)" + @echo "RM= $(RM)" + +# 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: - $(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" SYSLIBS="-ldl" SYSLDFLAGS="-brtl -bexpall" ansi: - $(MAKE) all MYCFLAGS=-DLUA_ANSI + $(MAKE) $(ALL) SYSCFLAGS="-DLUA_ANSI" bsd: - $(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-Wl,-E" + $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-Wl,-E" freebsd: - $(MAKE) all MYCFLAGS="-DLUA_USE_LINUX" MYLIBS="-Wl,-E -lreadline" + $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -lreadline" -generic: - $(MAKE) all MYCFLAGS= +generic: $(ALL) linux: - $(MAKE) all MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-Wl,-E -ldl -lreadline -lhistory -lncurses" + $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-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) SYSCFLAGS="-DLUA_USE_MACOSX" SYSLIBS="-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 + "SYSCFLAGS=-DLUA_BUILD_AS_DLL" "SYSLIBS=" "SYSLDFLAGS=-s" lua.exe $(MAKE) "LUAC_T=luac.exe" luac.exe posix: - $(MAKE) all MYCFLAGS=-DLUA_USE_POSIX + $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX" solaris: - $(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" + $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-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 + lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lgc.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 -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 \ - 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 +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 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 + 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 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 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 + 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 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 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 + 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 + 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 -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 + lzio.h -# (end of Makefile) diff --git a/src/lapi.c b/src/lapi.c index 5d5145d2eb..1854fe6159 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.164 2012/06/08 15:14:04 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ -#include -#include #include #include @@ -32,76 +30,71 @@ 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 " $"; +/* value at a non-valid index */ +#define NONVALIDVALUE cast(TValue *, luaO_nilobject) -#define api_checknelems(L, n) api_check(L, (n) <= (L->top - L->base)) +/* corresponding test */ +#define isvalid(o) ((o) != luaO_nilobject) -#define api_checkvalidindex(L, i) api_check(L, (i) != luaO_nilobject) +#define api_checkvalidindex(L, i) api_check(L, isvalid(i), "invalid index") -#define api_incr_top(L) {api_check(L, L->top < L->ci->top); L->top++;} - - -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); - if (o >= L->top) return cast(TValue *, luaO_nilobject); + TValue *o = ci->func + idx; + api_check(L, idx <= ci->top - (ci->func + 1), "unacceptable index"); + if (o >= L->top) return NONVALIDVALUE; 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_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); - idx = LUA_GLOBALSINDEX - idx; - return (idx <= func->c.nupvalues) - ? &func->c.upvalue[idx-1] - : cast(TValue *, luaO_nilobject); + else if (idx == LUA_REGISTRYINDEX) + return &G(L)->l_registry; + else { /* upvalues */ + idx = LUA_REGISTRYINDEX - idx; + api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); + if (ttislcf(ci->func)) /* light C function? */ + return NONVALIDVALUE; /* it has no upvalues */ + else { + CClosure *func = clCvalue(ci->func); + return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : NONVALIDVALUE; } } } -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 called 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 = 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 */ + 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 +105,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 +115,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 +125,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; } @@ -156,21 +138,32 @@ LUA_API lua_State *lua_newthread (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->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 +173,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 +185,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 +193,39 @@ 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); + setobj(L, to, 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) */ +} + + 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); - 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); - } + 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,26 +238,26 @@ 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); + StkId o = index2addr(L, idx); + return (isvalid(o) ? ttypenv(o) : LUA_TNONE); } LUA_API const char *lua_typename (lua_State *L, int t) { UNUSED(L); - return (t == LUA_TNONE) ? "no value" : luaT_typenames[t]; + return ttypename(t); } LUA_API int lua_iscfunction (lua_State *L, int idx) { - StkId o = index2adr(L, idx); - return iscfunction(o); + StkId o = index2addr(L, idx); + return (ttislcf(o) || (ttisCclosure(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,77 +269,116 @@ 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); - return (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 - : luaO_rawequalObj(o1, o2); + StkId o1 = index2addr(L, index1); + StkId o2 = index2addr(L, index2); + return (isvalid(o1) && isvalid(o2)) ? luaV_rawequalobj(o1, o2) : 0; } -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) { + StkId o1; /* 1st operand */ + StkId o2; /* 2nd operand */ + lua_lock(L); + 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, o1, o1, o2, cast(TMS, 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; + int i = 0; 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 (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; } - -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 = index2adr(L, idx); - if (tonumber(o, &n)) + const TValue *o = index2addr(L, idx); + 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 = index2adr(L, idx); + 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; + } +} + + +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_number2unsigned(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 = 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 +387,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,33 +395,29 @@ 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); - switch (ttype(o)) { +LUA_API size_t lua_rawlen (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + 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)); - 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); - return (!iscfunction(o)) ? NULL : clvalue(o)->c.f; + StkId o = index2addr(L, idx); + if (ttislcf(o)) return fvalue(o); + 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 = index2adr(L, idx); - switch (ttype(o)) { + StkId o = index2addr(L, idx); + switch (ttypenv(o)) { case LUA_TUSERDATA: return (rawuvalue(o) + 1); case LUA_TLIGHTUSERDATA: return pvalue(o); default: return NULL; @@ -393,16 +426,18 @@ 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); + 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: case LUA_TLIGHTUSERDATA: @@ -429,6 +464,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); } @@ -442,20 +479,43 @@ 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 void lua_pushunsigned (lua_State *L, lua_Unsigned u) { + lua_Number n; + lua_lock(L); + n = lua_unsigned2number(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); 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); - else - lua_pushlstring(L, s, strlen(s)); + return NULL; + } + 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); + } } @@ -484,17 +544,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); - luaC_checkGC(L); - api_checknelems(L, n); - 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 <= MAXUPVAL, "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); + setclCvalue(L, L->top, cl); + } api_incr_top(L); lua_unlock(L); } @@ -531,10 +596,21 @@ 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); - 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 +619,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,29 +632,46 @@ 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); } LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { - StkId o; + StkId t; + lua_lock(L); + 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); - o = index2adr(L, idx); - api_check(L, ttistable(o)); - setobj2s(L, L->top, luaH_getnum(hvalue(o), n)); + 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); } 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,8 +681,8 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) { Table *mt = NULL; int res; lua_lock(L); - obj = index2adr(L, objindex); - switch (ttype(obj)) { + obj = index2addr(L, objindex); + switch (ttypenv(obj)) { case LUA_TTABLE: mt = hvalue(obj)->metatable; break; @@ -598,7 +690,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) @@ -613,25 +705,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_getuservalue (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: - sethvalue(L, L->top, clvalue(o)->c.env); - break; - 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; - } + 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); } @@ -642,11 +725,24 @@ LUA_API void lua_getfenv (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); 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 +752,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,23 +767,39 @@ 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); + invalidateTMcache(hvalue(t)); + luaC_barrierback(L, gcvalue(t), L->top-1); L->top -= 2; lua_unlock(L); } LUA_API void lua_rawseti (lua_State *L, int idx, int n) { - StkId o; + StkId t; + lua_lock(L); + api_checknelems(L, 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); - 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); + 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); } @@ -699,29 +810,32 @@ 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)) { + switch (ttypenv(obj)) { case LUA_TTABLE: { hvalue(obj)->metatable = mt; if (mt) - luaC_objbarriert(L, hvalue(obj), mt); + luaC_objbarrierback(L, gcvalue(obj), mt); + luaC_checkfinalizer(L, gcvalue(obj), mt); break; } case LUA_TUSERDATA: { uvalue(obj)->metatable = mt; - if (mt) + if (mt) { luaC_objbarrier(L, rawuvalue(obj), mt); + luaC_checkfinalizer(L, gcvalue(obj), mt); + } break; } default: { - G(L)->mt[ttype(obj)] = mt; + G(L)->mt[ttypenv(obj)] = mt; break; } } @@ -731,32 +845,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_setuservalue (lua_State *L, int idx) { StkId o; - 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)); - 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; - case LUA_TTHREAD: - sethvalue(L, gt(thvalue(o)), 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; } @@ -765,21 +869,37 @@ 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") -#define checkresults(L,na,nr) \ - api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na))) - +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; +} + -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); + api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); 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,76 +917,75 @@ 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); + api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); 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->extra = 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) { + const char *chunkname, const char *mode) { ZIO z; int status; lua_lock(L); if (!chunkname) chunkname = "?"; luaZ_init(L, &z, reader, data); - status = luaD_protectedparser(L, &z, chunkname); + status = luaD_protectedparser(L, &z, chunkname, mode); + if (status == LUA_OK) { /* no errors? */ + 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->upvals[0]->v, gt); + luaC_barrier(L, f->upvals[0], gt); + } + } lua_unlock(L); return status; } @@ -879,7 +998,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); @@ -903,38 +1022,40 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { g = G(L); switch (what) { case LUA_GCSTOP: { - g->GCthreshold = MAX_LUMEM; + g->gcrunning = 0; break; } case LUA_GCRESTART: { - g->GCthreshold = g->totalbytes; + luaE_setdebt(g, 0); + g->gcrunning = 1; break; } case LUA_GCCOLLECT: { - luaC_fullgc(L); + luaC_fullgc(L, 0); break; } 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: { - lu_mem a = (cast(lu_mem, data) << 10); - if (a <= g->totalbytes) - g->GCthreshold = g->totalbytes - a; - else - g->GCthreshold = 0; - while (g->GCthreshold <= g->totalbytes) { - luaC_step(L); - if (g->gcstate == GCSpause) { /* end of cycle? */ - res = 1; /* signal it */ - break; - } + if (g->gckind == KGC_GEN) { /* generational mode? */ + res = (g->GCestimate == 0); /* true if it will do major collection */ + luaC_forcestep(L); /* do a single step */ + } + else { + 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; } @@ -943,11 +1064,28 @@ 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; break; } + case LUA_GCISRUNNING: { + res = g->gcrunning; + 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 */ } lua_unlock(L); @@ -974,8 +1112,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 +1130,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 +1141,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); @@ -1026,7 +1173,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); @@ -1035,30 +1182,36 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) { - -static const char *aux_upvalue (StkId fi, int n, TValue **val) { - Closure *f; - if (!ttisfunction(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]; - return ""; - } - else { - 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]); +static const char *aux_upvalue (StkId fi, int n, TValue **val, + GCObject **owner) { + 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); + 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 = p->upvalues[n-1].name; + return (name == NULL) ? "" : getstr(name); + } + default: return NULL; /* not a closure */ } } LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { const char *name; - TValue *val; + TValue *val = NULL; /* to avoid warnings */ lua_lock(L); - name = aux_upvalue(index2adr(L, funcindex), n, &val); + name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL); if (name) { setobj2s(L, L->top, val); api_incr_top(L); @@ -1070,18 +1223,59 @@ 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; + TValue *val = NULL; /* to avoid warnings */ + GCObject *owner = NULL; /* to avoid warnings */ StkId fi; lua_lock(L); - fi = index2adr(L, funcindex); + 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; } + +static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) { + LClosure *f; + StkId fi = index2addr(L, fidx); + 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->upvals[n - 1]; /* get its upvalue pointer */ +} + + +LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) { + StkId fi = index2addr(L, fidx); + 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; + } + } +} + + +LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1, + int fidx2, int n2) { + LClosure *f1; + UpVal **up1 = getupvalref(L, fidx1, n1, &f1); + UpVal **up2 = getupvalref(L, fidx2, n2, NULL); + *up1 = *up2; + luaC_objbarrier(L, f1, *up2); +} + 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..36ae7e629f 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.244 2012/05/31 20:28:45 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ -#include #include #include #include @@ -25,12 +24,124 @@ #include "lauxlib.h" -#define FREELIST_REF 0 /* free list of references */ +/* +** {====================================================== +** 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) { + if (level == 0 || !lua_istable(L, -1)) + return 0; /* not found */ + lua_pushnil(L); /* start 'next' loop */ + 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) */ + 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') { + 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); +} -/* convert a stack index to positive */ -#define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \ - lua_gettop(L) + (i) + 1) + +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); +} + +/* }====================================================== */ /* @@ -39,7 +150,6 @@ ** ======================================================= */ - 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 +158,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) { +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); @@ -66,7 +175,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)); + typeerror(L, narg, lua_typename(L, tag)); } @@ -93,24 +202,74 @@ 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; + } +} -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)); + +#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? */ + lua_pushboolean(L, 1); + else + lua_pushnil(L); + lua_pushstring(L, what); + lua_pushinteger(L, stat); + return 3; /* return true/nil,what,code */ + } } +/* }====================================================== */ + + +/* +** {====================================================== +** Userdata's metatable manipulation +** ======================================================= +*/ LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { - lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get registry.name */ + luaL_getmetatable(L, tname); /* try to get metatable */ if (!lua_isnil(L, -1)) /* name already in use? */ return 0; /* leave previous value on top, but return 0 */ lua_pop(L, 1); @@ -121,25 +280,64 @@ 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_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? */ 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_getmetatable(L, tname); /* get correct metatable */ + 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) 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) { + /* 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 + luaL_error(L, "stack overflow"); + } } @@ -174,8 +372,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; } @@ -187,255 +386,79 @@ 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; } -LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int 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_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 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 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 lua_Integer luaL_optinteger (lua_State *L, int narg, + lua_Integer def) { + return luaL_opt(L, luaL_checkinteger, narg, def); } -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); +LUALIB_API lua_Unsigned luaL_optunsigned (lua_State *L, int narg, + lua_Unsigned def) { + return luaL_opt(L, luaL_checkunsigned, narg, def); } -#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 ** ======================================================= */ - -#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_strlen(L, -1); - do { - size_t l = lua_strlen(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, "buffer too large"); + /* 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; + 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 * sizeof(char)); + luaL_addsize(B, l); } @@ -445,57 +468,72 @@ 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) { 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); } /* }====================================================== */ +/* +** {====================================================== +** Reference system +** ======================================================= +*/ + +/* index of free-list header */ +#define freelist 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_tointeger(L, -1); /* ref = t[FREELIST_REF] */ + t = lua_absindex(L, t); + 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_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */ - } - else { /* no free elements */ - ref = (int)lua_objlen(L, t); - ref++; /* create new reference */ + lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */ } + else /* no free elements */ + ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */ lua_rawseti(L, t, ref); return ref; } @@ -503,14 +541,15 @@ 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_rawgeti(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_rawseti(L, t, freelist); /* t[freelist] = ref */ } } +/* }====================================================== */ /* @@ -520,23 +559,27 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { */ typedef struct LoadF { - int extraline; - 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->extraline) { - lf->extraline = 0; - *size = 1; - return "\n"; + (void)L; /* not used */ + 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 */ } - if (feof(lf->f)) return NULL; - *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); - return (*size > 0) ? lf->buff : NULL; + 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); /* read block */ + } + return lf->buff; } @@ -549,12 +592,46 @@ static int errfile (lua_State *L, const char *what, int fnameindex) { } -LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { +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 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 (LoadF *lf, int *cp) { + int c = *cp = skipBOM(lf); + if (c == '#') { /* first line is a comment (Unix exec. file)? */ + do { /* skip first line */ + c = getc(lf->f); + } while (c != EOF && c != '\n') ; + *cp = getc(lf->f); /* skip end-of-line, if present */ + return 1; /* there was a comment */ + } + else return 0; /* no comment */ +} + + +LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, + const char *mode) { LoadF lf; 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; @@ -564,21 +641,16 @@ 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? */ - lf.extraline = 1; - while ((c = getc(lf.f)) != EOF && c != '\n') ; /* skip first line */ - if (c == '\n') c = getc(lf.f); - } + 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); - /* skip eventual `#!...' */ - while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ; - lf.extraline = 0; + skipcomment(&lf, &c); /* re-read initial portion */ } - ungetc(c, lf.f); - status = lua_load(L, getF, &lf, lua_tostring(L, -1)); + 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), mode); readstatus = ferror(lf.f); if (filename) fclose(lf.f); /* close file (even in case of errors) */ if (readstatus) { @@ -598,7 +670,7 @@ typedef struct LoadS { static const char *getS (lua_State *L, void *ud, size_t *size) { LoadS *ls = (LoadS *)ud; - (void)L; + (void)L; /* not used */ if (ls->size == 0) return NULL; *size = ls->size; ls->size = 0; @@ -606,27 +678,245 @@ static const char *getS (lua_State *L, void *ud, size_t *size) { } -LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size, - const char *name) { +LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size, + const char *name, const char *mode) { LoadS ls; ls.s = buff; ls.size = size; - return lua_load(L, getS, &ls, name); + return lua_load(L, getS, &ls, name, mode); } -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 = lua_absindex(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; + int isnum; + lua_len(L, idx); + l = (int)lua_tointegerx(L, -1, &isnum); + if (!isnum) + 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); +} + + +/* +** {====================================================== +** Compatibility with 5.1 module functions +** ======================================================= +*/ +#if defined(LUA_COMPAT_MODULE) + +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 { + 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++; + return size; +} + + +/* +** 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_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_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 */ + } + 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) { + luaL_pushmodule(L, libname, libsize(l)); /* get/create library table */ + lua_insert(L, -(nup + 1)); /* move library table to below upvalues */ + } + if (l) + luaL_setfuncs(L, l, nup); + else + lua_pop(L, nup); /* remove upvalues */ +} +#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_checkversion(L); + luaL_checkstack(L, nup, "too many upvalues"); + 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); + 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 int luaL_getsubtable (lua_State *L, int idx, const char *fname) { + lua_getfield(L, idx, fname); + if (lua_istable(L, -1)) return 1; /* table already there */ + else { + lua_pop(L, 1); /* remove previous result */ + idx = lua_absindex(L, idx); + 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 */ + } +} + + +/* +** 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_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 */ + if (glb) { + lua_pushvalue(L, -1); /* copy of 'mod' */ + lua_setglobal(L, modname); /* _G[modname] = module */ + } +} + + +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); +} + static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { - (void)ud; - (void)osize; + (void)ud; (void)osize; /* not used */ if (nsize == 0) { free(ptr); return NULL; @@ -637,10 +927,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", + luai_writestringerror("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 +939,20 @@ 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 %f, 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 34258235db..ac4d15fbb9 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.120 2011/11/29 15:55:08 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,14 +26,12 @@ 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); -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_argerror) (lua_State *L, int numarg, const char *extramsg); LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg, size_t *l); @@ -57,12 +43,17 @@ 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); 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); LUALIB_API void (luaL_where) (lua_State *L, int lvl); @@ -71,25 +62,41 @@ 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) + 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_loadbuffer) (lua_State *L, const char *buff, size_t sz, - const char *name); +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_loadbufferx) (lua_State *L, const char *buff, size_t sz, + const char *name, const char *mode); 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); -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 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); +LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, + lua_CFunction openf, int glb); /* ** =============================================================== @@ -97,6 +104,12 @@ LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, ** =============================================================== */ + +#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)) @@ -118,56 +131,81 @@ LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, #define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) +#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL) + + /* ** {====================================================== ** 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))) -/* compatibility only */ -#define luaL_putchar(B,c) luaL_addchar(B,c) +#define luaL_addchar(B,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) /* }====================================================== */ -/* compatibility with ref system */ -/* pre-defined references */ -#define LUA_NOREF (-2) -#define LUA_REFNIL (-1) +/* +** {====================================================== +** 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; + +/* }====================================================== */ + -#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)) +/* compatibility with old module system */ +#if defined(LUA_COMPAT_MODULE) -#define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, (ref)) +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); +#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0)) + +#endif -#define luaL_reg luaL_Reg #endif diff --git a/src/lbaselib.c b/src/lbaselib.c index 2ab550bd48..dbfcb02cfc 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.274 2012/04/27 14:13:19 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -20,60 +20,68 @@ #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"); 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); + 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 */ } - fputs("\n", stdout); + 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); - 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; must be something */ + luaL_checkany(L, 1); } 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 base = luaL_checkint(L, 2); + int neg = 0; 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 */ - if (*s2 == '\0') { /* no invalid trailing characters? */ - lua_pushnumber(L, (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; } @@ -107,57 +115,13 @@ 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; } -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); - 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. */ - 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"); - return 1; -} - - static int luaB_rawequal (lua_State *L) { luaL_checkany(L, 1); luaL_checkany(L, 2); @@ -166,6 +130,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); @@ -184,32 +157,29 @@ static int luaB_rawset (lua_State *L) { } -static int luaB_gcinfo (lua_State *L) { - lua_pushinteger(L, lua_getgccount(L)); - 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", + "setmajorinc", "isrunning", "generational", "incremental", 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_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, 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 +193,23 @@ static int luaB_type (lua_State *L) { } +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_pushcfunction(L, iter); /* 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 +223,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, luaB_next); } @@ -250,21 +233,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)) ? 1 : 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, ipairsaux); } static int load_aux (lua_State *L, int status) { - if (status == 0) /* OK? */ + if (status == LUA_OK) return 1; else { lua_pushnil(L); @@ -274,20 +253,34 @@ 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)); + 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); } +/* +** {====================================================== +** Generic Read function +** ======================================================= +*/ + + +/* +** 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 5 + + /* ** Reader for generic `load' function: `lua_load' uses the ** stack for internal stuff, so the reader cannot change the @@ -295,66 +288,69 @@ 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 */ + (void)(ud); /* not used */ 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)) { + lua_pop(L, 1); /* pop result */ *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 luaL_error(L, "reader function must return a string"); - return NULL; /* to avoid warnings */ + else if (!lua_isstring(L, -1)) + luaL_error(L, "reader function must return a string"); + lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ + return lua_tolstring(L, RESERVEDSLOT, size); } static int luaB_load (lua_State *L) { 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); + size_t l; + 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, 2, s); + status = luaL_loadbufferx(L, s, l, chunkname, mode); + } + else { /* loading from a reader function */ + 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, 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); } +/* }====================================================== */ + + +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,75 +367,50 @@ static int luaB_select (lua_State *L) { } +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_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0); - lua_pushboolean(L, (status == 0)); - 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)); } 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)); - lua_replace(L, 1); - return lua_gettop(L); /* return status + all results */ + 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, 0, pcallcont); + return finishpcall(L, (status == LUA_OK)); } 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; - } - return 1; -} - - -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_newtable(L); /* create a new metatable `m' ... */ - 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); + luaL_tolstring(L, 1, NULL); return 1; } @@ -449,205 +420,40 @@ 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}, - {"loadstring", luaB_loadstring}, +#if defined(LUA_COMPAT_LOADSTRING) + {"loadstring", luaB_load}, +#endif {"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}, {"setmetatable", luaB_setmetatable}, {"tonumber", luaB_tonumber}, {"tostring", luaB_tostring}, {"type", luaB_type}, - {"unpack", luaB_unpack}, {"xpcall", luaB_xpcall}, {NULL, NULL} }; -/* -** {====================================================== -** Coroutine library -** ======================================================= -*/ - -#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]); - 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); - if (!lua_checkstack(L, nres + 1)) - luaL_error(L, "too many results to resume"); - 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_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, - "Lua function expected"); - 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_corunning (lua_State *L) { - if (lua_pushthread(L)) - lua_pushnil(L); /* main thread is not a coroutine */ - return 1; -} - - -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 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) { +LUAMOD_API int luaopen_base (lua_State *L) { /* set global _G */ - lua_pushvalue(L, LUA_GLOBALSINDEX); - lua_setglobal(L, "_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_setglobal(L, "_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 */ - 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_setglobal(L, "newproxy"); /* set global `newproxy' */ -} - - -LUALIB_API int luaopen_base (lua_State *L) { - base_open(L); - luaL_register(L, LUA_COLIBNAME, co_funcs); - return 2; + lua_setfield(L, -2, "_VERSION"); /* set global _VERSION */ + return 1; } diff --git a/src/lbitlib.c b/src/lbitlib.c new file mode 100644 index 0000000000..7533b85c5a --- /dev/null +++ b/src/lbitlib.c @@ -0,0 +1,209 @@ +/* +** $Id: lbitlib.c,v 1.16 2011/06/20 16:35:23 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" +#include "lualib.h" + + +/* number of bits to consider in a number */ +#if !defined(LUA_NBITS) +#define LUA_NBITS 32 +#endif + + +#define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1)) + +/* macro to trim extra bits */ +#define trim(x) ((x) & ALLONES) + + +/* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */ +#define mask(n) (~((ALLONES << 1) << ((n) - 1))) + + +typedef lua_Unsigned b_uint; + + + +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 &= luaL_checkunsigned(L, i); + return trim(r); +} + + +static int b_and (lua_State *L) { + b_uint r = andaux(L); + lua_pushunsigned(L, 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 |= luaL_checkunsigned(L, i); + lua_pushunsigned(L, trim(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 ^= luaL_checkunsigned(L, i); + lua_pushunsigned(L, trim(r)); + return 1; +} + + +static int b_not (lua_State *L) { + b_uint r = ~luaL_checkunsigned(L, 1); + lua_pushunsigned(L, trim(r)); + return 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 >= LUA_NBITS) r = 0; + else r >>= i; + } + else { /* shift left */ + if (i >= LUA_NBITS) r = 0; + else r <<= i; + r = trim(r); + } + lua_pushunsigned(L, r); + return 1; +} + + +static int b_lshift (lua_State *L) { + return b_shift(L, luaL_checkunsigned(L, 1), luaL_checkint(L, 2)); +} + + +static int b_rshift (lua_State *L) { + return b_shift(L, luaL_checkunsigned(L, 1), -luaL_checkint(L, 2)); +} + + +static int b_arshift (lua_State *L) { + b_uint r = luaL_checkunsigned(L, 1); + int i = luaL_checkint(L, 2); + if (i < 0 || !(r & ((b_uint)1 << (LUA_NBITS - 1)))) + return b_shift(L, r, -i); + else { /* arithmetic shift for 'negative' number */ + if (i >= LUA_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 = luaL_checkunsigned(L, 1); + i &= (LUA_NBITS - 1); /* i = i % NBITS */ + r = trim(r); + r = (r << i) | (r >> (LUA_NBITS - i)); + lua_pushunsigned(L, trim(r)); + return 1; +} + + +static int b_lrot (lua_State *L) { + return b_rot(L, luaL_checkint(L, 2)); +} + + +static int b_rrot (lua_State *L) { + return b_rot(L, -luaL_checkint(L, 2)); +} + + +/* +** 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 negative"); + 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}, + {NULL, NULL} +}; + + + +LUAMOD_API int luaopen_bit32 (lua_State *L) { + luaL_newlib(L, bitlib); + return 1; +} + diff --git a/src/lcode.c b/src/lcode.c index 679cb9cfd9..614e452f9c 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.25.1.5 2011/01/31 14:53:16 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 */ @@ -21,7 +21,9 @@ #include "lobject.h" #include "lopcodes.h" #include "lparser.h" +#include "lstring.h" #include "ltable.h" +#include "lvm.h" #define hasjumps(e) ((e)->t != (e)->f) @@ -34,25 +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? */ - 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 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 */ } @@ -176,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); @@ -196,6 +209,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->ls->L, f->code, fs->pc, f->sizecode, Instruction, + MAX_INT, "opcodes"); + f->code[fs->pc] = i; + /* save corresponding line information */ + 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++; +} + + +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_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, OP_LOADKX, reg, 0); + codeextraarg(fs, k); + return p; + } +} + + void luaK_checkstack (FuncState *fs, int n) { int newstack = fs->freereg + n; if (newstack > fs->f->maxstacksize) { @@ -222,42 +284,60 @@ 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); } -static int addk (FuncState *fs, TValue *k, TValue *v) { - lua_State *L = fs->L; - TValue *idx = luaH_set(L, fs->h, k); +static int addk (FuncState *fs, TValue *key, TValue *v) { + lua_State *L = fs->ls->L; + 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 (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 */ } + /* 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++]); + setobj(L, &f->k[k], v); + fs->nk++; + luaC_barrier(L, f, v); + return k; } 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->ls->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; } @@ -272,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); } @@ -292,7 +372,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); @@ -308,19 +388,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->k = VRELOCABLE; - break; - } - case VGLOBAL: { - e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info); + 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); + 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; } @@ -352,11 +431,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.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: { @@ -365,8 +444,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: { @@ -374,7 +453,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; } @@ -390,7 +469,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 */ @@ -406,7 +485,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; } @@ -422,14 +501,20 @@ 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; +} + + +void luaK_exp2anyregup (FuncState *fs, expdesc *e) { + if (e->k != VUPVAL || hasjumps(e)) + luaK_exp2anyreg(fs, e); } @@ -444,22 +529,24 @@ 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)); + 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.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; @@ -473,22 +560,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); - break; - } - case VGLOBAL: { - int e = luaK_exp2anyreg(fs, ex); - luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info); + 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); + luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e); break; } default: { @@ -501,20 +584,20 @@ 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_reserveregs(fs, 2); - luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key)); - freeexp(fs, key); - e->u.s.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); } 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))); @@ -532,7 +615,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); } @@ -540,13 +623,13 @@ 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.s.info; + pc = e->u.info; + break; + } + case VK: case VKNUM: case VTRUE: { + pc = NO_JUMP; /* always true; do nothing */ break; } default: { @@ -560,16 +643,16 @@ 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) { - case VNIL: case VFALSE: { - pc = NO_JUMP; /* always false; do nothing */ + case VJMP: { + pc = e->u.info; break; } - case VJMP: { - pc = e->u.s.info; + case VNIL: case VFALSE: { + pc = NO_JUMP; /* always false; do nothing */ break; } default: { @@ -602,7 +685,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; } @@ -619,38 +702,28 @@ static void codenot (FuncState *fs, expdesc *e) { void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { - t->u.s.aux = luaK_exp2RK(fs, k); + lua_assert(!hasjumps(t)); + 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; } 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; } -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 { @@ -664,8 +737,9 @@ static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { 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); } } @@ -681,25 +755,28 @@ 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; } -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) { 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, 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); @@ -734,7 +811,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 */ @@ -753,29 +831,30 @@ void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { 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' */ - codearith(fs, OP_CONCAT, e1, e2); + codearith(fs, OP_CONCAT, e1, e2, line); } 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, cast(OpCode, op - OPR_ADD + OP_ADD), e1, e2, line); + break; + } + case OPR_EQ: case OPR_LT: case OPR_LE: { + codecomp(fs, cast(OpCode, op - OPR_EQ + OP_EQ), 1, e1, e2); + break; + } + case OPR_NE: case OPR_GT: case OPR_GE: { + codecomp(fs, cast(OpCode, op - OPR_NE + OP_EQ), 0, e1, e2); + break; + } default: lua_assert(0); } } @@ -786,46 +865,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..5a1fa9feac 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.58 2011/08/30 16:26:41 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; @@ -36,14 +36,17 @@ 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) #define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) +#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) + 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_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); @@ -52,12 +55,14 @@ 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); 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); @@ -65,11 +70,13 @@ 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); +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/lcorolib.c b/src/lcorolib.c new file mode 100644 index 0000000000..c7932d90f2 --- /dev/null +++ b/src/lcorolib.c @@ -0,0 +1,155 @@ +/* +** $Id: lcorolib.c,v 1.4 2012/04/27 18:59:04 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, L, 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; + 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; +} + + +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/lctype.c b/src/lctype.c new file mode 100644 index 0000000000..55e433a5dd --- /dev/null +++ b/src/lctype.c @@ -0,0 +1,52 @@ +/* +** $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 /* { */ + +#include + +LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = { + 0x00, /* EOZ */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */ + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */ + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */ + 0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */ + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */ + 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05, + 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */ + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */ + 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* e. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* f. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +#endif /* } */ diff --git a/src/lctype.h b/src/lctype.h new file mode 100644 index 0000000000..99c7d12237 --- /dev/null +++ b/src/lctype.h @@ -0,0 +1,95 @@ +/* +** $Id: lctype.h,v 1.12 2011/07/15 12:50:29 roberto Exp $ +** 'ctype' functions for Lua +** See Copyright Notice in lua.h +*/ + +#ifndef lctype_h +#define lctype_h + +#include "lua.h" + + +/* +** 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 +*/ + +#if !defined(LUA_USE_CTYPE) + +#if 'A' == 65 && '0' == 48 +/* ASCII case: can use its own tables; faster and fixed */ +#define LUA_USE_CTYPE 0 +#else +/* must use standard C ctype */ +#define LUA_USE_CTYPE 1 +#endif + +#endif + + +#if !LUA_USE_CTYPE /* { */ + +#include + +#include "llimits.h" + + +#define ALPHABIT 0 +#define DIGITBIT 1 +#define PRINTBIT 2 +#define SPACEBIT 3 +#define XDIGITBIT 4 + + +#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 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)) + +/* +** this 'ltolower' only works for alphabetic characters +*/ +#define ltolower(c) ((c) | ('A' ^ 'a')) + + +/* two more entries for 0 and -1 (EOZ) */ +LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2]; + + +#else /* }{ */ + +/* +** use standard C ctypes +*/ + +#include + + +#define lislalpha(c) (isalpha(c) || (c) == '_') +#define lislalnum(c) (isalnum(c) || (c) == '_') +#define lisdigit(c) (isdigit(c)) +#define lisspace(c) (isspace(c)) +#define lisprint(c) (isprint(c)) +#define lisxdigit(c) (isxdigit(c)) + +#define ltolower(c) (tolower(c)) + +#endif /* } */ + +#endif + diff --git a/src/ldblib.c b/src/ldblib.c index 2027eda598..c022694573 100644 --- a/src/ldblib.c +++ b/src/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.104.1.4 2009/08/04 18:50:18 roberto Exp $ +** $Id: ldblib.c,v 1.132 2012/01/19 20:14:44 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,24 +42,28 @@ 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 */ } -static int db_getfenv (lua_State *L) { - luaL_checkany(L, 1); - lua_getfenv(L, 1); +static int db_getuservalue (lua_State *L) { + if (lua_type(L, 1) != LUA_TUSERDATA) + lua_pushnil(L); + else + lua_getuservalue(L, 1); return 1; } -static int db_setfenv (lua_State *L) { - luaL_checktype(L, 2, LUA_TTABLE); +static int db_setuservalue (lua_State *L) { + if (lua_type(L, 1) == LUA_TLIGHTUSERDATA) + luaL_argerror(L, 1, "full userdata expected, got light userdata"); + 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_setuservalue(L, 1); return 1; } @@ -73,6 +80,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; @@ -100,7 +113,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 */ @@ -127,38 +140,51 @@ 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; 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; + } + } } @@ -180,7 +206,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); @@ -200,16 +225,42 @@ 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 const char KEY_HOOK = 'h'; + +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; +} + + +#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 return"}; - lua_pushlightuserdata(L, (void *)&KEY_HOOK); - lua_rawget(L, LUA_REGISTRYINDEX); - lua_pushlightuserdata(L, L); + {"call", "return", "line", "count", "tail call"}; + gethooktable(L); + lua_pushthread(L); lua_rawget(L, -2); if (lua_isfunction(L, -1)) { lua_pushstring(L, hooknames[(int)ar->event]); @@ -242,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; @@ -269,11 +307,15 @@ static int db_sethook (lua_State *L) { count = luaL_optint(L, arg+3, 0); func = hookf; mask = makemask(smask, count); } - gethooktable(L); - lua_pushlightuserdata(L, L1); + if (gethooktable(L) == 0) { /* creating hook table? */ + lua_pushstring(L, "k"); + lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */ + lua_pushvalue(L, -1); + lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */ + } + lua_pushthread(L1); lua_xmove(L1, L, 1); lua_pushvalue(L, arg+1); lua_rawset(L, -3); /* set new hook */ - lua_pop(L, 1); /* remove hook table */ lua_sethook(L1, func, mask, count); /* set hooks */ return 0; } @@ -289,7 +331,7 @@ static int db_gethook (lua_State *L) { lua_pushliteral(L, "external hook"); else { gethooktable(L); - lua_pushlightuserdata(L, L1); + lua_pushthread(L1); lua_xmove(L1, L, 1); lua_rawget(L, -2); /* get hook */ lua_remove(L, -2); /* remove hook table */ } @@ -302,97 +344,55 @@ 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 */ } } -#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; } static const luaL_Reg dblib[] = { {"debug", db_debug}, - {"getfenv", db_getfenv}, + {"getuservalue", db_getuservalue}, {"gethook", db_gethook}, {"getinfo", db_getinfo}, {"getlocal", db_getlocal}, {"getregistry", db_getregistry}, {"getmetatable", db_getmetatable}, {"getupvalue", db_getupvalue}, - {"setfenv", db_setfenv}, + {"upvaluejoin", db_upvaluejoin}, + {"upvalueid", db_upvalueid}, + {"setuservalue", db_setuservalue}, {"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) { - luaL_register(L, LUA_DBLIBNAME, dblib); +LUAMOD_API int luaopen_debug (lua_State *L) { + luaL_newlib(L, dblib); return 1; } diff --git a/src/ldebug.c b/src/ldebug.c index 50ad3d3803..43f8f046ff 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.89 2012/01/20 22:05:50 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -30,23 +30,20 @@ +#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL) + + 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)->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)->p, currentpc(ci)); } @@ -58,6 +55,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 +83,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? */ + 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? */ - status = 1; - ar->i_ci = 0; + ar->i_ci = ci; } else status = 0; /* no such level */ lua_unlock(L); @@ -104,43 +97,78 @@ 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 *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 *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 */ +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 { - StkId limit = (ci == L->ci) ? L->top : (ci+1)->func; - if (limit - ci->base >= n && n > 0) /* is 'n' inside 'ci' stack? */ - return "(*temporary)"; + *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)) { + 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; + 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 - return NULL; + 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); + const char *name; lua_lock(L); - if (name) - luaA_pushobject(L, ci->base + (n - 1)); + 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(clLvalue(L->top - 1)->p, n, 0); + } + else { /* active function; get information through 'ar' */ + StkId pos = 0; /* to avoid warnings */ + name = findlocal(L, ar->i_ci, n, &pos); + 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 = 0; /* to avoid warnings */ + 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; @@ -148,55 +176,45 @@ 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 (noLuaClosure(cl)) { ar->source = "=[C]"; ar->linedefined = -1; ar->lastlinedefined = -1; 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); } -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) { + if (noLuaClosure(f)) { setnilvalue(L->top); + incr_top(L); } 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); + TValue v; + 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); + 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 */ } - incr_top(L); } static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, - Closure *f, CallInfo *ci) { + Closure *f, CallInfo *ci) { int status = 1; - if (f == NULL) { - info_tailcall(ar); - return status; - } for (; *what; what++) { switch (*what) { case 'S': { @@ -204,15 +222,31 @@ 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; + ar->nups = (f == NULL) ? 0 : f->c.nupvalues; + if (noLuaClosure(f)) { + 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': { - 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; @@ -231,29 +265,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; - luai_apicheck(L, ttisfunction(func)); + ci = NULL; + func = L->top - 1; + api_check(L, ttisfunction(func), "function expected"); what++; /* skip the '>' */ - 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; + 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')) { - if (f == NULL) setnilvalue(L->top); - else 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; } @@ -261,315 +296,218 @@ 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 const char *getobjname (Proto *p, int lastpc, int reg, + const char **name); -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; +/* +** find a "name" for the RK value 'c' +*/ +static void kname (Proto *p, int pc, int c, const char **name) { + if (ISK(c)) { /* is 'c' a constant? */ + TValue *kvalue = &p->k[INDEXK(c)]; + if (ttisstring(kvalue)) { /* literal constant? */ + *name = svalue(kvalue); /* it is its own name */ + return; } - default: return 0; /* invalid instruction after an open call */ + /* else no reasonable name found */ } -} - - -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; + else { /* 'c' is a register */ + const char *what = getobjname(p, pc, c, name); /* search for 'c' */ + if (what && *what == 'c') { /* found a constant name? */ + return; /* 'name' already filled */ + } + /* else no reasonable name found */ } - return 1; + *name = "?"; /* no reasonable name found */ } -static Instruction symbexec (const Proto *pt, int lastpc, int reg) { +/* +** try to find last instruction before 'lastpc' that modified register 'reg' +*/ +static int findsetreg (Proto *p, 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)); + int setreg = -1; /* keep last instruction that changed 'reg' */ 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))); - break; - } - case iABx: { - b = GETARG_Bx(i); - 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); - 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); - } - } - 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); - } - 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])); - 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 */ + int b = GETARG_B(i); + if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */ + setreg = pc; 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) setreg = pc; /* 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 */ + if (reg >= a) setreg = pc; /* affect all registers above base */ break; } - case OP_RETURN: { - b--; /* b = num. returns */ - if (b > 0) checkreg(pt, a+b-1); - break; - } - case OP_SETLIST: { - if (b > 0) checkreg(pt, a + b); - if (c == 0) { - pc++; - check(pc < pt->sizecode - 1); - } + 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_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_TEST: { + if (reg == a) setreg = pc; /* jumped code can change 'a' */ 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) /* any instruction that set A */ + setreg = pc; break; - } - default: break; } } - return pt->code[last]; + return setreg; } -#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, +static const char *getobjname (Proto *p, int lastpc, int reg, 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"; - } + 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 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' */ + 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 */ - *name = kname(p, k); - return "field"; + 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: { - int u = GETARG_B(i); /* upvalue index */ - *name = p->upvalues ? getstr(p->upvalues[u]) : "?"; + *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 */ - *name = kname(p, k); + kname(p, pc, k, name); return "method"; } - default: break; + default: break; /* go through to return NULL */ } } - return NULL; /* no useful name found */ + return NULL; /* could not find reasonable 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(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 */ + TMS tm; + 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: /* 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; + case OP_SETTABUP: + 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 */ +/* +** 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->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) { +static const char *getupvalname (CallInfo *ci, const TValue *o, + const char **name) { + LClosure *c = ci_func(ci); + int i; + for (i = 0; i < c->nupvalues; i++) { + if (c->upvals[i]->v == o) { + *name = upvalname(c->p, i); + return "upvalue"; + } + } + return NULL; +} + + +l_noret 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) : - 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(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)", op, kind, name, t); @@ -578,14 +516,14 @@ void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { } -void luaG_concaterror (lua_State *L, StkId p1, StkId p2) { +l_noret 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"); } -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 */ @@ -593,14 +531,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) { - const char *t1 = luaT_typenames[ttype(p1)]; - const char *t2 = luaT_typenames[ttype(p2)]; - if (t1[2] == t2[2]) +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; } @@ -608,27 +545,32 @@ 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); + TString *src = ci_func(ci)->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); } } -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); 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); } -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 ba28a97248..fe39556b06 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.7 2011/10/07 20:45:19 roberto Exp $ ** Auxiliary functions from Debug Interface module ** See Copyright Notice in lua.h */ @@ -13,21 +13,22 @@ #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) +/* 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); -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); + +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 d1bf786cb7..d18e33cd41 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.38.1.4 2012/01/18 02:27:10 roberto Exp $ +** $Id: ldo.c,v 2.105 2012/06/08 15:14:04 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) && !defined(LUA_USE_LONGJMP) +/* 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,18 +81,17 @@ 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)); + case LUA_ERRMEM: { /* memory error? */ + setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ break; } case LUA_ERRERR: { 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); +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 */ } -} - - -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); - } - 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 = 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 */ + L->nCcalls = oldnCcalls; return lj.status; } @@ -129,113 +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 = 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; + 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); - luaD_checkstack(L, p->maxstacksize); - 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; } @@ -257,100 +286,85 @@ 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; - 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->savedpc = L->savedpc; - 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) { /* 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); - func = restorestack(L, funcr); /* previous call may change the stack */ + lua_CFunction f; + 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; } - 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); - L->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; - if (L->hookmask & LUA_MASKCALL) { - L->savedpc++; /* hooks assume 'pc' is already incremented */ - luaD_callhook(L, LUA_HOOKCALL, -1); - L->savedpc--; /* correct 'pc' */ + 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; } - return PCRLUA; - } - 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->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; - 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) /* yielding? */ - return PCRYIELD; - else { - luaD_poscall(L, L->top - n); - return PCRC; + default: { /* not a function */ + func = tryfuncTM(L, func); /* retry with 'function' tag method */ + return luaD_precall(L, func, nresults); /* now it must be a function */ } } } -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 */ wanted = ci->nresults; - L->base = (ci - 1)->base; /* restore base */ - L->savedpc = (ci - 1)->savedpc; /* restore savedpc */ + 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++); @@ -366,112 +380,222 @@ 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) { +*/ +void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) { if (++L->nCcalls >= LUAI_MAXCCALLS) { if (L->nCcalls == LUAI_MAXCCALLS) luaG_runerror(L, "C stack overflow"); 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? */ - luaV_execute(L, 1); /* call it */ + if (!allowyield) L->nny++; + if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ + luaV_execute(L); /* call it */ + if (!allowyield) L->nny--; L->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 '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->extra); + 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 handler and should not kill the coroutine.) +*/ +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); - 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) { + int nCcalls = L->nCcalls; + StkId firstArg = cast(StkId, ud); + CallInfo *ci = L->ci; + 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? */ + 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; + ci->func = restorestack(L, ci->extra); + 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; + 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 */ + } + luaD_poscall(L, firstArg); /* finish 'luaD_precall' */ + } + unroll(L, NULL); + } + lua_assert(nCcalls == L->nCcalls); } -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); - 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; + 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); - 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 */ + L->nCcalls--; + lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0)); 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) - luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); - L->base = L->top - nresults; /* protect stack slots below */ + api_checknelems(L, nresults); + 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; + ci->extra = savestack(L, ci->func); /* save current 'func' */ + 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->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 */ 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,35 +608,60 @@ 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 */ + Mbuffer buff; /* dynamic structure used by the scanner */ + Dyndata dyd; /* dynamic structures used by the parser */ + const char *mode; const char *name; }; + +static void checkmode (lua_State *L, const char *mode, const char *x) { + if (mode && strchr(mode, x[0]) == NULL) { + luaO_pushfstring(L, + "attempt to load a %s chunk (mode is " LUA_QS ")", x, mode); + luaD_throw(L, LUA_ERRSYNTAX); + } +} + + static void f_parser (lua_State *L, void *ud) { int i; - Proto *tf; 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))); - cl->l.p = tf; - 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 c = zgetc(p->z); /* read first character */ + if (c == LUA_SIGNATURE[0]) { + checkmode(L, p->mode, "binary"); + cl = luaU_undump(L, p->z, &p->buff, p->name); + } + else { + checkmode(L, p->mode, "text"); + 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); + } } -int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) { +int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, + const char *mode) { struct SParser p; int status; - p.z = z; p.name = name; + L->nny++; /* cannot yield during parsing */ + p.z = z; p.name = name; p.mode = mode; + 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.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/ldo.h b/src/ldo.h index 98fddac59f..27b837d999 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.20 2011/11/29 15:55:08 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -13,45 +13,34 @@ #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 int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, + const char *mode); +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 l_noret 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..d5e6a47cb3 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.17 2012/01/23 23:02:10 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); @@ -69,13 +69,13 @@ 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); } } #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) { @@ -84,8 +84,8 @@ static void DumpConstants(const Proto* f, DumpState* D) for (i=0; ik[i]; - DumpChar(ttype(o),D); - switch (ttype(o)) + DumpChar(ttypenv(o),D); + switch (ttypenv(o)) { case LUA_TNIL: break; @@ -98,19 +98,29 @@ static void DumpConstants(const Proto* f, DumpState* D) case LUA_TSTRING: DumpString(rawtsvalue(o),D); break; - default: - lua_assert(0); /* cannot happen */ - break; + default: lua_assert(0); } } 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) +{ + 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; + 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; @@ -123,26 +133,25 @@ 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) +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->nups,D); DumpChar(f->numparams,D); DumpChar(f->is_vararg,D); DumpChar(f->maxstacksize,D); DumpCode(f,D); DumpConstants(f,D); + DumpUpvalues(f,D); DumpDebug(f,D); } static void DumpHeader(DumpState* D) { - char h[LUAC_HEADERSIZE]; + lu_byte h[LUAC_HEADERSIZE]; luaU_header(h); DumpBlock(h,LUAC_HEADERSIZE,D); } @@ -159,6 +168,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/lfunc.c b/src/lfunc.c index 813e88f583..4fd27fe5eb 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.29 2012/05/08 13:53:33 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -20,30 +20,24 @@ -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_byte(nelems); +Closure *luaF_newCclosure (lua_State *L, int n) { + Closure *c = &luaC_newobj(L, LUA_TCCL, sizeCclosure(n), NULL, 0)->cl; + 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); - c->l.isC = 0; - c->l.env = e; - c->l.nupvalues = cast_byte(nelems); - while (nelems--) c->l.upvals[nelems] = NULL; +Closure *luaF_newLclosure (lua_State *L, int n) { + Closure *c = &luaC_newobj(L, LUA_TLCL, sizeLclosure(n), NULL, 0)->cl; + c->l.p = 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 +49,20 @@ 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) { + 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)); /* ressurect it */ + 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; } - 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,41 +89,42 @@ 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 */ 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); } } } 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->cache = 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; @@ -139,23 +133,16 @@ 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, 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); } -void luaF_freeclosure (lua_State *L, Closure *c) { - int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) : - sizeLclosure(c->l.nupvalues); - luaM_freemem(L, c, size); -} - - /* ** Look for n-th local variable at line `line' in function `func'. ** Returns NULL if not found. diff --git a/src/lfunc.h b/src/lfunc.h index a68cf5151c..e236a717c6 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.8 2012/05/08 13:53:33 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -19,13 +19,12 @@ 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); 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); diff --git a/src/lgc.c b/src/lgc.c index e909c79a96..06f972a725 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.38.1.2 2011/03/18 18:05:38 roberto Exp $ +** $Id: lgc.c,v 2.133 2012/05/31 21:28:59 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -23,376 +23,665 @@ #include "ltm.h" -#define GCSTEPSIZE 1024u -#define GCSWEEPMAX 40 -#define GCSWEEPCOST 10 -#define GCFINALIZECOST 100 +/* +** cost of sweeping one element (the size of a small object divided +** by some adjust for the sweep speed) +*/ +#define GCSWEEPCOST ((sizeof(TString) + 4) / 4) -#define maskmarks cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) +/* maximum number of elements to sweep in each single step */ +#define GCSWEEPMAX (cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4)) + +/* maximum number of finalizers to call in each GC step */ +#define GCFINALIZENUM 4 + + +/* +** macro to adjust 'stepmul': 'stepmul' is actually used like +** 'stepmul / STEPMULADJ' (value chosen by tests) +*/ +#define STEPMULADJ 200 + +/* +** macro to adjust 'pause': 'pause' is actually used like +** 'pause / PAUSEADJ' (value chosen by tests) +*/ +#define PAUSEADJ 200 -#define makewhite(g,x) \ - ((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) -#define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) + +/* +** 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 isfinalized(u) testbit((u)->marked, FINALIZEDBIT) -#define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT) +/* +** '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 KEYWEAK bitmask(KEYWEAKBIT) -#define VALUEWEAK bitmask(VALUEWEAKBIT) +#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 (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)); } +static void reallymarkobject (global_State *g, GCObject *o); + + +/* +** {====================================================== +** Generic functions +** ======================================================= +*/ + -#define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause) +/* +** one after last element in a hash array +*/ +#define gnodelast(h) gnode(h, cast(size_t, sizenode(h))) +/* +** link table 'h' into list pointed by 'p' +*/ +#define linktable(h,p) ((h)->gclist = *(p), *(p) = obj2gco(h)) + + +/* +** 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))) - setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */ + if (valiswhite(gkey(n))) + setdeadvalue(gkey(n)); /* unused and unmarked key; remove it */ } +/* +** 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 (global_State *g, const TValue *o) { + if (!iscollectable(o)) return 0; + else if (ttisstring(o)) { + markobject(g, rawtsvalue(o)); /* strings are `values', so are never weak */ + return 0; + } + else return iswhite(gcvalue(o)); +} + + +/* +** barrier that moves collector forward, that is, mark the white object +** being pointed by a black object. +*/ +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(gch(o)->tt != LUA_TTABLE); + if (keepinvariant(g)) /* must keep invariant? */ + reallymarkobject(g, v); /* restore invariant */ + 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. (Current implementation +** only works for tables; access to 'gclist' is not uniform across +** different types.) +*/ +void luaC_barrierback_ (lua_State *L, GCObject *o) { + global_State *g = G(L); + 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; +} + + +/* +** 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 +*/ +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); + char *raw = cast(char *, luaM_newobject(L, novariant(tt), sz)); + GCObject *o = obj2gco(raw + offset); + if (list == NULL) + list = &g->allgc; /* standard list for collectable objects */ + gch(o)->marked = luaC_white(g); + gch(o)->tt = tt; + gch(o)->next = *list; + *list = o; + return o; +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** Mark functions +** ======================================================= +*/ + + +/* +** mark an object. Userdata, strings, and closed upvalues are visited +** and turned black here. 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)); + lu_mem size; white2gray(o); - switch (o->gch.tt) { - case LUA_TSTRING: { - return; + switch (gch(o)->tt) { + case LUA_TSHRSTR: + case LUA_TLNGSTR: { + size = sizestring(gco2ts(o)); + break; /* nothing else to mark; make it black */ } 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; + size = sizeudata(gco2u(o)); + break; } 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) /* open? */ + return; /* open upvalues remain gray */ + size = sizeof(UpVal); + break; + } + case LUA_TLCL: { + gco2lcl(o)->gclist = g->gray; + g->gray = o; return; } - case LUA_TFUNCTION: { - gco2cl(o)->c.gclist = g->gray; + case LUA_TCCL: { + gco2ccl(o)->gclist = g->gray; g->gray = o; - break; + return; } case LUA_TTABLE: { - gco2h(o)->gclist = g->gray; - g->gray = o; - break; + linktable(gco2t(o), &g->gray); + 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; } -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); +/* +** mark metamethods for basic types +*/ +static void markmt (global_State *g) { + int i; + for (i=0; i < LUA_NUMTAGS; i++) + markobject(g, g->mt[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) { + makewhite(g, o); + reallymarkobject(g, o); } } -/* 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->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; - } - } +/* +** 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) { + if (isgray(obj2gco(uv))) + markvalue(g, uv->v); } - return deadmem; } -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 */ - } - } - 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); - lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); - if (ttisnil(gval(n))) - removeentry(n); /* remove empty entries */ +/* +** mark root set and reset all gray lists, to start a new +** incremental (or full) collection +*/ +static void markroot (global_State *g) { + 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 */ +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Traverse functions +** ======================================================= +*/ + +static void traverseweakvalue (global_State *g, Table *h) { + Node *n, *limit = gnodelast(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? */ + removeentry(n); /* remove it */ else { lua_assert(!ttisnil(gkey(n))); - if (!weakkey) markvalue(g, gkey(n)); - if (!weakvalue) markvalue(g, gval(n)); + markvalue(g, gkey(n)); /* mark key */ + if (!hasclears && iscleared(g, gval(n))) /* is there a white value? */ + hasclears = 1; /* table will have to be cleared */ } } - return weakkey || weakvalue; + if (hasclears) + linktable(h, &g->weak); /* has to be cleared later */ + else /* no white values */ + linktable(h, &g->grayagain); /* no need to clean */ } -/* -** 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 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 white keys */ + int prop = 0; /* true if table has entry "white-key -> white-value" */ + Node *n, *limit = gnodelast(h); int 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]); + /* 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])); + } } - for (i=0; isizelocvars; i++) { /* mark local-variable names */ - if (f->locvars[i].varname) - stringmark(f->locvars[i].varname); + /* 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 (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 */ + } + else if (valiswhite(gval(n))) { /* value not marked yet? */ + marked = 1; + reallymarkobject(g, gcvalue(gval(n))); /* mark it now */ + } } + 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; } - -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 */ - markvalue(g, &cl->c.upvalue[i]); +static void traversestrongtable (global_State *g, Table *h) { + Node *n, *limit = gnodelast(h); + int i; + for (i = 0; i < h->sizearray; i++) /* traverse array part */ + markvalue(g, &h->array[i]); + for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ + checkdeadkey(n); + if (ttisnil(gval(n))) /* entry is empty? */ + removeentry(n); /* remove it */ + else { + lua_assert(!ttisnil(gkey(n))); + markvalue(g, gkey(n)); /* mark key */ + markvalue(g, gval(n)); /* mark value */ + } } - else { - int i; - lua_assert(cl->l.nupvalues == cl->l.p->nups); - markobject(g, cl->l.p); - for (i=0; il.nupvalues; i++) /* mark its upvalues */ - markobject(g, cl->l.upvals[i]); +} + + +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? */ + ((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 */ } + else /* not weak */ + traversestrongtable(g, h); + return sizeof(Table) + sizeof(TValue) * h->sizearray + + sizeof(Node) * sizenode(h); } -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 int traverseproto (global_State *g, Proto *f) { + int i; + if (f->cache && iswhite(obj2gco(f->cache))) + f->cache = NULL; /* allow cache to be collected */ + 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 */ + 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 */ + 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 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 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 sizeCclosure(cl->nupvalues); +} + +static lu_mem traverseLclosure (global_State *g, LClosure *cl) { + int i; + markobject(g, cl->p); /* mark its prototype */ + for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ + markobject(g, cl->upvals[i]); + return sizeLclosure(cl->nupvalues); +} + + +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 < th->top; o++) markvalue(g, o); - for (; o <= lim; o++) - setnilvalue(o); - checkstacksizes(l, lim); + if (g->gcstate == GCSatomic) { /* final traversal? */ + StkId lim = th->stack + th->stacksize; /* real end of stack */ + for (; o < lim; o++) /* clear not-marked stack slice */ + setnilvalue(o); + } + return sizeof(lua_State) + sizeof(TValue) * th->stacksize; } /* -** 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). */ -static l_mem propagatemark (global_State *g) { +static void propagatemark (global_State *g) { + lu_mem size; 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); - 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); - } - 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); + Table *h = gco2t(o); + g->gray = h->gclist; /* remove from 'gray' list */ + size = traversetable(g, h); + break; + } + case LUA_TLCL: { + LClosure *cl = gco2lcl(o); + g->gray = cl->gclist; /* remove from 'gray' list */ + size = traverseLclosure(g, cl); + break; + } + case LUA_TCCL: { + CClosure *cl = gco2ccl(o); + 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); - traversestack(g, th); - return sizeof(lua_State) + sizeof(TValue) * th->stacksize + - sizeof(CallInfo) * th->size_ci; + size = traversestack(g, th); + 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; + 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; } -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); } +static void propagatelist (global_State *g, GCObject *l) { + lua_assert(g->gray == NULL); /* no grays left */ + g->gray = l; + propagateall(g); /* traverse all elements from 'l' */ +} + /* -** 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 +** 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 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 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); } +static void convergeephemerons (global_State *g) { + int changed; + do { + GCObject *w; + 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))) { /* traverse marked some value? */ + propagateall(g); /* propagate changes */ + changed = 1; /* will have to revisit all ephemeron tables */ + } + } + } while (changed); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Sweep Functions +** ======================================================= +*/ + + /* -** clear collected entries from weaktables +** clear entries with unmarked keys from all weaktables in list 'l' up +** to element 'f' */ -static void cleartable (GCObject *l) { - while (l) { - Table *h = gco2h(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 */ +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(g, gkey(n)))) { + setnilvalue(gval(n)); /* remove value ... */ + removeentry(n); /* and remove entry from table */ } } - i = sizenode(h); - while (i--) { - Node *n = gnode(h, i); - if (!ttisnil(gval(n)) && /* non-empty entry? */ - (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) { + } +} + + +/* +** clear entries with unmarked values from all weaktables in list 'l' up +** to element '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(g, o)) /* value was collected? */ + setnilvalue(o); /* remove value */ + } + for (n = gnode(h, 0); n < limit; n++) { + if (!ttisnil(gval(n)) && iscleared(g, gval(n))) { setnilvalue(gval(n)); /* remove value ... */ - removeentry(n); /* remove entry from table */ + removeentry(n); /* and remove entry from table */ } } - l = h->gclist; } } 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)); + case LUA_TLCL: { + luaM_freemem(L, o, sizeLclosure(gco2lcl(o)->nupvalues)); break; } - case LUA_TSTRING: { - G(L)->strt.nuse--; - luaM_freemem(L, o, sizestring(gco2ts(o))); + case LUA_TCCL: { + luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); break; } - case LUA_TUSERDATA: { - luaM_freemem(L, o, sizeudata(gco2u(o))); + case LUA_TUPVAL: luaF_freeupval(L, gco2uv(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_TSHRSTR: + G(L)->strt.nuse--; + /* go through */ + case LUA_TLNGSTR: { + luaM_freemem(L, o, sizestring(gco2ts(o))); break; } default: lua_assert(0); @@ -400,311 +689,517 @@ static void freeobj (lua_State *L, GCObject *o) { } - #define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) +static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count); +/* +** 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 (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) { - 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)); - makewhite(g, curr); /* make it white (for next cycle) */ - p = &curr->gch.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 */ - freeobj(L, curr); + 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); /* 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 */ + /* update marks */ + gch(curr)->marked = cast_byte((marked & toclear) | toset); + p = &gch(curr)->next; /* go to next element */ } } + return (*p == NULL) ? NULL : p; +} + + +/* +** sweep a list until a live object (or end of list) +*/ +static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) { + GCObject ** old = p; + int i = 0; + do { + i++; + p = sweeplist(L, p, 1); + } while (p == old); + if (n) *n += i; 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->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 */ } } -static void GCTM (lua_State *L) { +static GCObject *udata2finalize (global_State *g) { + GCObject *o = g->tobefnz; /* get first element */ + 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(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 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); - 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; - makewhite(g, o); - tm = fasttm(L, udata->uv.metatable, TM_GC); - if (tm != NULL) { + 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 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); + int running = g->gcrunning; + L->allowhook = 0; /* stop debug hooks during GC metamethod */ + g->gcrunning = 0; /* avoid GC steps */ + setobj2s(L, L->top, tm); /* push finalizer... */ + 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->GCthreshold = oldt; /* restore threshold */ + g->gcrunning = running; /* restore state */ + if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ + if (status == LUA_ERRRUN) { /* is there an error object? */ + const char *msg = (ttisstring(L->top - 1)) + ? svalue(L->top - 1) + : "no message"; + luaO_pushfstring(L, "error in __gc metamethod (%s)", msg); + status = LUA_ERRGCMM; /* error in __gc metamethod */ + } + luaD_throw(L, status); /* re-throw error */ + } } } /* -** Call all GC tag methods +** move all unreachable objects (or 'all' objects) that need +** finalization from list 'finobj' to list 'tobefnz' (to be finalized) */ -void luaC_callGCTM (lua_State *L) { - while (G(L)->tmudata) - GCTM(L); +static void separatetobefnz (lua_State *L, int all) { + global_State *g = G(L); + 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(!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 'finobj' list */ + gch(curr)->next = *lastnext; /* link at the end of 'tobefnz' list */ + *lastnext = curr; + lastnext = &gch(curr)->next; + } + } } -void luaC_freeall (lua_State *L) { +/* +** 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, GCObject *o, Table *mt) { 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(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 'o' to 'finobj' list */ + GCObject **p; + GCheader *ho = gch(o); + if (g->sweepgc == &ho->next) { /* avoid removing current sweep object */ + lua_assert(issweepphase(g)); + g->sweepgc = sweeptolive(L, g->sweepgc, NULL); + } + /* 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(ho->marked, SEPARATED); /* mark it as such */ + if (!keepinvariant(g)) /* not keeping invariant? */ + makewhite(g, o); /* "sweep" object */ + else + resetoldbit(o); /* see MOVE OLD rule */ + } } +/* }====================================================== */ -static void markmt (global_State *g) { - int i; - for (i=0; imt[i]) markobject(g, g->mt[i]); + +/* +** {====================================================== +** GC control +** ======================================================= +*/ + + +#define sweepphases \ + (bitmask(GCSsweepstring) | bitmask(GCSsweepudata) | bitmask(GCSsweep)) + + +/* +** enter first sweep phase (strings) and prepare pointers for other +** sweep phases. The calls to 'sweeptolive' 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. +** Returns how many objects it sweeped. +*/ +static int entersweep (lua_State *L) { + global_State *g = G(L); + int n = 0; + g->gcstate = GCSsweepstring; + lua_assert(g->sweepgc == NULL && g->sweepfin == NULL); + /* prepare to sweep strings, finalizable objects, and regular objects */ + g->sweepstrgc = 0; + g->sweepfin = sweeptolive(L, &g->finobj, &n); + g->sweepgc = sweeptolive(L, &g->allgc, &n); + return n; } -/* mark root set */ -static void markroot (lua_State *L) { +/* +** change GC mode +*/ +void luaC_changemode (lua_State *L, int mode) { 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; + 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->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->gckind = KGC_NORMAL; + entersweep(L); + luaC_runtilstate(L, ~sweepphases); + } } -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); +/* +** call all pending finalizers +*/ +static void callallpendingfinalizers (lua_State *L, int propagateerrors) { + global_State *g = G(L); + while (g->tobefnz) { + resetoldbit(g->tobefnz); + GCTM(L, propagateerrors); } } -static void atomic (lua_State *L) { +void luaC_freeallobjects (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; + int i; + separatetobefnz(L, 1); /* separate all objects with finalizers */ + lua_assert(g->finobj == NULL); + callallpendingfinalizers(L, 0); + g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ + g->gckind = KGC_NORMAL; + sweepwholelist(L, &g->finobj); /* finalizers can create objs. in 'finobj' */ + sweepwholelist(L, &g->allgc); + 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 l_mem atomic (lua_State *L) { + global_State *g = G(L); + l_mem work = -g->GCmemtrav; /* start counting work */ + GCObject *origweak, *origall; 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; - 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; - g->gcstate = GCSsweepstring; - g->estimate = g->totalbytes - udsize; /* first estimate */ + /* 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); + propagateall(g); /* propagate changes */ + work += g->GCmemtrav; /* stop counting (do not (re)count grays) */ + /* traverse objects caught by write barrier and by 'remarkupvals' */ + retraversegrays(g); + work -= g->GCmemtrav; /* restart counting */ + convergeephemerons(g); + /* at this point, all strongly accessible objects are marked. */ + /* clear values from weak tables, before checking finalizers */ + clearvalues(g, g->weak, NULL); + clearvalues(g, g->allweak, NULL); + origweak = g->weak; origall = g->allweak; + work += g->GCmemtrav; /* stop counting (objects being finalized) */ + separatetobefnz(L, 0); /* separate objects to be finalized */ + markbeingfnz(g); /* mark objects that will be finalized */ + propagateall(g); /* remark, to propagate `preserveness' */ + work -= g->GCmemtrav; /* restart counting */ + convergeephemerons(g); + /* at this point, all resurrected objects are marked. */ + /* remove dead objects from weak 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, g->weak, origweak); + clearvalues(g, g->allweak, origall); + g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ + work += g->GCmemtrav; /* complete counting */ + return work; /* estimate of memory marked by 'atomic' */ } -static l_mem singlestep (lua_State *L) { +static lu_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; + 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))); + g->gcstate = GCSpropagate; + 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 */ - atomic(L); /* finish mark phase */ - return 0; + lu_mem work; + int sw; + g->gcstate = GCSatomic; /* finish mark phase */ + g->GCestimate = g->GCmemtrav; /* save what was counted */; + work = atomic(L); /* add what was traversed by 'atomic' */ + g->GCestimate += work; /* estimate of total memory traversed */ + sw = entersweep(L); + return work + sw * GCSWEEPCOST; } } 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; - return GCSWEEPCOST; + 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 i * 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); - 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; - return GCFINALIZECOST; + case GCSsweepudata: { + if (g->sweepfin) { + g->sweepfin = sweeplist(L, g->sweepfin, GCSWEEPMAX); + return GCSWEEPMAX*GCSWEEPCOST; } else { - g->gcstate = GCSpause; /* end collection */ - g->gcdept = 0; + g->gcstate = GCSsweep; return 0; } } + 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; /* finish collection */ + return GCSWEEPCOST; + } + } default: lua_assert(0); return 0; } } -void luaC_step (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); - 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); - 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 { - setthreshold(g); - } + while (!testbit(statesmask, g->gcstate)) + singlestep(L); } -void luaC_fullgc (lua_State *L) { +static void generationalcollection (lua_State *L) { 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); - singlestep(L); + if (g->GCestimate == 0) { /* signal for another major collection? */ + luaC_fullgc(L, 0); /* perform a full regular collection */ + g->GCestimate = gettotalbytes(g); /* update control */ } - markroot(L); - while (g->gcstate != GCSpause) { - singlestep(L); + else { + lu_mem estimate = g->GCestimate; + luaC_runtilstate(L, ~bitmask(GCSpause)); /* run complete cycle */ + luaC_runtilstate(L, bitmask(GCSpause)); + if (gettotalbytes(g) > (estimate / 100) * g->gcmajorinc) + g->GCestimate = 0; /* signal for a major collection */ } - setthreshold(g); + luaE_setdebt(g, stddebt(g)); } -void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { +static void incstep (lua_State *L) { 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 */ + l_mem debt = g->GCdebt; + int stepmul = g->gcstepmul; + if (stepmul < 40) stepmul = 40; /* avoid ridiculous low values */ + /* 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; + do { /* always perform at least one single step */ + lu_mem work = singlestep(L); /* do some work */ + debt -= work; + } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause); + if (g->gcstate == GCSpause) + debt = stddebtest(g, g->GCestimate); /* pause until next cycle */ + else + debt = (debt / stepmul) * STEPMULADJ; /* convert 'work units' to Kb */ + luaE_setdebt(g, debt); } -void luaC_barrierback (lua_State *L, Table *t) { +/* +** performs a basic GC step +*/ +void luaC_forcestep (lua_State *L) { 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; + int i; + if (isgenerational(g)) generationalcollection(L); + else incstep(L); + /* 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 */ } -void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { +/* +** performs a basic GC step only if collector is running +*/ +void luaC_step (lua_State *L) { global_State *g = G(L); - o->gch.next = g->rootgc; - g->rootgc = o; - o->gch.marked = luaC_white(g); - o->gch.tt = tt; + if (g->gcrunning) luaC_forcestep(L); + else luaE_setdebt(g, -GCSTEPSIZE); /* avoid being called too often */ } -void luaC_linkupval (lua_State *L, UpVal *uv) { + +/* +** 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); - 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); - } + 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; + else { + g->gckind = KGC_NORMAL; + callallpendingfinalizers(L, 1); + } + 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) */ + 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)); + if (origkind == KGC_GEN) { /* generational mode? */ + /* generational mode must always start in propagate phase */ + luaC_runtilstate(L, bitmask(GCSpropagate)); } + g->gckind = origkind; + 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 5a8dc605b3..bdd5cce6cf 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.56 2012/05/23 15:43:14 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -9,65 +9,97 @@ #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). +*/ + + + +/* 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 */ -#define GCSpause 0 -#define GCSpropagate 1 +#define GCSpropagate 0 +#define GCSatomic 1 #define GCSsweepstring 2 -#define GCSsweep 3 -#define GCSfinalize 4 +#define GCSsweepudata 3 +#define GCSsweep 4 +#define GCSpause 5 + +#define issweepphase(g) \ + (GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep) + +#define isgenerational(g) ((g)->gckind == KGC_GEN) /* -** some userful bit tricks +** 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 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 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))) - +#define keepinvariant(g) (isgenerational(g) || g->gcstate <= GCSatomic) /* -** 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 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) +** 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)) + + +/* 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 /* 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) */ - -#define WHITE0BIT 0 -#define WHITE1BIT 1 -#define BLACKBIT 2 -#define FINALIZEDBIT 3 -#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 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) @@ -77,34 +109,39 @@ #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_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))) \ - 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); } -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, Table *t); +#define luaC_barrierproto(L,p,c) \ + { if (isblack(obj2gco(p))) luaC_barrierproto_(L,p,c); } +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, + GCObject **list, int offset); +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, GCObject *o, Table *mt); +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 c1f90dfab7..8d3aa6576f 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.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 #define LUA_LIB @@ -14,25 +22,46 @@ #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_COLIBNAME, luaopen_coroutine}, {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, + {LUA_BITLIBNAME, luaopen_bit32}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_DBLIBNAME, luaopen_debug}, {NULL, NULL} }; +/* +** these libs are preloaded and must be required before used +*/ +static const luaL_Reg preloadedlibs[] = { + {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' and set results to global table */ + for (lib = loadedlibs; lib->func; lib++) { + luaL_requiref(L, lib->name, lib->func, 1); + lua_pop(L, 1); /* remove lib */ + } + /* add open functions from 'preloadedlibs' into 'package.preload' table */ + luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); + for (lib = preloadedlibs; lib->func; lib++) { lua_pushcfunction(L, lib->func); - lua_pushstring(L, lib->name); - lua_call(L, 1, 0); + lua_setfield(L, -2, lib->name); } + lua_pop(L, 1); /* remove _PRELOAD table */ } diff --git a/src/liolib.c b/src/liolib.c index 649f9a5951..4814aa2c2a 100644 --- a/src/liolib.c +++ b/src/liolib.c @@ -1,10 +1,20 @@ /* -** $Id: liolib.c,v 2.73.1.4 2010/05/14 15:33:51 roberto Exp $ +** $Id: liolib.c,v 2.108 2011/11/25 12:50:03 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 @@ -20,48 +30,95 @@ -#define IO_INPUT 1 -#define IO_OUTPUT 2 +/* +** {====================================================== +** lua_popen spawns a new process connected to the current +** one through the file streams. +** ======================================================= +*/ + +#if !defined(lua_popen) /* { */ +#if defined(LUA_USE_POPEN) /* { */ -static const char *const fnames[] = {"input", "output"}; +#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) /* }{ */ -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; - } -} +#define lua_popen(L,c,m) ((void)L, _popen(c,m)) +#define lua_pclose(L,file) ((void)L, _pclose(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)); -} +#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 /* } */ + +/* }====================================================== */ + + +/* +** {====================================================== +** 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) && !defined(_CRTIMP_TYPEINFO) \ + && defined(_MSC_VER) && (_MSC_VER >= 1400) +/* Windows (but not DDK) and Visual C++ 2005 or higher */ -#define tofilep(L) ((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE)) +#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 luaL_Stream LStream; + + +#define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE)) + +#define isclosed(p) ((p)->closef == NULL) static int io_type (lua_State *L) { - void *ud; + LStream *p; 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)) + p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE); + if (p == NULL) lua_pushnil(L); /* not a file */ - else if (*((FILE **)ud) == NULL) + else if (isclosed(p)) lua_pushliteral(L, "closed file"); else lua_pushliteral(L, "file"); @@ -69,47 +126,59 @@ static int io_type (lua_State *L) { } +static int f_tostring (lua_State *L) { + LStream *p = tolstream(L); + if (isclosed(p)) + lua_pushliteral(L, "file (closed)"); + else + lua_pushfstring(L, "file (%p)", p->f); + return 1; +} + + static FILE *tofile (lua_State *L) { - FILE **f = tofilep(L); - if (*f == NULL) + LStream *p = tolstream(L); + if (isclosed(p)) luaL_error(L, "attempt to use a closed file"); - return *f; + lua_assert(p->f); + return p->f; } - /* ** 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, LUA_FILEHANDLE); - lua_setmetatable(L, -2); - return pf; +static LStream *newprefile (lua_State *L) { + LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream)); + p->closef = NULL; /* mark file handle as 'closed' */ + luaL_setmetatable(L, LUA_FILEHANDLE); + return p; } -/* -** function to (not) close the standard files stdin, stdout, and stderr -*/ -static int io_noclose (lua_State *L) { - lua_pushnil(L); - lua_pushliteral(L, "cannot close standard file"); - return 2; +static int aux_close (lua_State *L) { + LStream *p = tolstream(L); + lua_CFunction cf = p->closef; + p->closef = NULL; /* mark stream as closed */ + return (*cf)(L); /* close it */ } -/* -** function to close 'popen' files -*/ -static int io_pclose (lua_State *L) { - FILE **p = tofilep(L); - int ok = lua_pclose(L, *p); - *p = NULL; - return pushresult(L, ok, NULL); +static int io_close (lua_State *L) { + if (lua_isnone(L, 1)) /* no argument? */ + lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */ + tofile(L); /* make sure argument is an open stream */ + return aux_close(L); +} + + +static int f_gc (lua_State *L) { + LStream *p = tolstream(L); + if (!isclosed(p) && p->f != NULL) + aux_close(L); /* ignore closed and incompletely open files */ + return 0; } @@ -117,103 +186,94 @@ static int io_pclose (lua_State *L) { ** function to close regular files */ static int io_fclose (lua_State *L) { - FILE **p = tofilep(L); - int ok = (fclose(*p) == 0); - *p = NULL; - return pushresult(L, ok, NULL); -} - - -static int aux_close (lua_State *L) { - lua_getfenv(L, 1); - lua_getfield(L, -1, "__close"); - return (lua_tocfunction(L, -1))(L); + LStream *p = tolstream(L); + int res = fclose(p->f); + return luaL_fileresult(L, (res == 0), NULL); } -static int io_close (lua_State *L) { - if (lua_isnone(L, 1)) - lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT); - tofile(L); /* make sure argument is a file */ - return aux_close(L); +static LStream *newfile (lua_State *L) { + LStream *p = newprefile(L); + p->f = NULL; + p->closef = &io_fclose; + return p; } -static int io_gc (lua_State *L) { - FILE *f = *tofilep(L); - /* ignore closed files */ - if (f != NULL) - aux_close(L); - return 0; -} - - -static int io_tostring (lua_State *L) { - FILE *f = *tofilep(L); - if (f == NULL) - lua_pushliteral(L, "file (closed)"); - else - lua_pushfstring(L, "file (%p)", f); - return 1; +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"); - FILE **pf = newfile(L); - *pf = fopen(filename, mode); - return (*pf == NULL) ? pushresult(L, 0, filename) : 1; + LStream *p = newfile(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] == '\0'))) + 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; } /* -** this function has a separated environment, which defines the -** correct __close for 'popen' files +** function to close 'popen' files */ +static int io_pclose (lua_State *L) { + LStream *p = tolstream(L); + return luaL_execresult(L, lua_pclose(L, p->f)); +} + + 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; + LStream *p = newprefile(L); + p->f = lua_popen(L, filename, mode); + p->closef = &io_pclose; + return (p->f == 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; + LStream *p = newfile(L); + p->f = tmpfile(); + return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; } -static FILE *getiofile (lua_State *L, int findex) { - FILE *f; - lua_rawgeti(L, LUA_ENVIRONINDEX, findex); - f = *(FILE **)lua_touserdata(L, -1); - if (f == NULL) - luaL_error(L, "standard %s file is closed", fnames[findex - 1]); - return f; +static FILE *getiofile (lua_State *L, const char *findex) { + LStream *p; + lua_getfield(L, LUA_REGISTRYINDEX, findex); + p = (LStream *)lua_touserdata(L, -1); + if (isclosed(p)) + luaL_error(L, "standard %s file is closed", findex + strlen(IO_PREFIX)); + return p->f; } -static int g_iofile (lua_State *L, int f, const char *mode) { +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) { - FILE **pf = newfile(L); - *pf = fopen(filename, mode); - if (*pf == 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); } - lua_rawseti(L, LUA_ENVIRONINDEX, f); + lua_setfield(L, LUA_REGISTRYINDEX, f); } /* return current value */ - lua_rawgeti(L, LUA_ENVIRONINDEX, f); + lua_getfield(L, LUA_REGISTRYINDEX, f); return 1; } @@ -231,35 +291,43 @@ 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_getfield(L, LUA_REGISTRYINDEX, 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; + opencheck(L, filename, "r"); + lua_replace(L, 1); /* put file at index 1 */ + toclose = 1; /* close it after iteration */ } + aux_lines(L, toclose); + return 1; } @@ -277,8 +345,8 @@ static int read_number (lua_State *L, FILE *f) { return 1; } else { - lua_pushnil(L); /* "result" to be removed */ - return 0; /* read fails */ + lua_pushnil(L); /* "result" to be removed */ + return 0; /* read fails */ } } @@ -291,7 +359,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 (;;) { @@ -299,13 +367,13 @@ 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') 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' */ } @@ -313,21 +381,34 @@ static int read_line (lua_State *L, FILE *f) { } +#define MAX_SIZE_T (~(size_t)0) + +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); + for (;;) { + char *p = luaL_prepbuffsize(&b, rlen); + size_t nr = fread(p, sizeof(char), rlen, f); + luaL_addsize(&b, nr); + 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 rlen; /* how much to read */ size_t nr; /* number of chars actually read */ + char *p; 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 */ + 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 (n == 0 || lua_objlen(L, -1) > 0); + return (nr > 0); /* true iff read something */ } @@ -337,7 +418,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 */ @@ -356,10 +437,13 @@ 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 */ + read_all(L, f); /* read entire file */ success = 1; /* always success */ break; default: @@ -369,7 +453,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 */ @@ -389,16 +473,24 @@ 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; - if (f == NULL) /* file is already closed? */ - luaL_error(L, "file is already closed"); - sucess = read_line(L, f); - if (ferror(f)) - return luaL_error(L, "%s", strerror(errno)); - if (sucess) return 1; - else { /* EOF */ - if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */ + LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1)); + int i; + int n = (int)lua_tointeger(L, lua_upvalueindex(2)); + if (isclosed(p)) /* file is already closed? */ + return luaL_error(L, "file is already closed"); + 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, p->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 (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)); aux_close(L); /* close it */ @@ -411,7 +503,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) { @@ -425,7 +517,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 luaL_fileresult(L, status, NULL); } @@ -435,7 +528,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); } @@ -444,12 +539,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 pushresult(L, 0, NULL); /* error */ + return luaL_fileresult(L, 0, NULL); /* error */ else { - lua_pushinteger(L, ftell(f)); + lua_pushnumber(L, (lua_Number)l_ftell(f)); return 1; } } @@ -462,21 +560,24 @@ 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); } +/* +** functions for 'io' library +*/ static const luaL_Reg iolib[] = { {"close", io_close}, {"flush", io_flush}, @@ -493,6 +594,9 @@ static const luaL_Reg iolib[] = { }; +/* +** methods for file handles +*/ static const luaL_Reg flib[] = { {"close", io_close}, {"flush", f_flush}, @@ -501,8 +605,8 @@ static const luaL_Reg flib[] = { {"seek", f_seek}, {"setvbuf", f_setvbuf}, {"write", f_write}, - {"__gc", io_gc}, - {"__tostring", io_tostring}, + {"__gc", f_gc}, + {"__tostring", f_tostring}, {NULL, NULL} }; @@ -511,46 +615,43 @@ 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_setfuncs(L, flib, 0); /* 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; - if (k > 0) { - lua_pushvalue(L, -1); - lua_rawseti(L, LUA_ENVIRONINDEX, k); - } - lua_pushvalue(L, -2); /* copy environment */ - lua_setfenv(L, -2); /* set it */ - lua_setfield(L, -3, fname); +/* +** function to (not) close the standard files stdin, stdout, and stderr +*/ +static int io_noclose (lua_State *L) { + LStream *p = tolstream(L); + p->closef = &io_noclose; /* keep file opened */ + lua_pushnil(L); + lua_pushliteral(L, "cannot close standard file"); + return 2; } -static void newfenv (lua_State *L, lua_CFunction cls) { - lua_createtable(L, 0, 1); - lua_pushcfunction(L, cls); - lua_setfield(L, -2, "__close"); +static void createstdfile (lua_State *L, FILE *f, const char *k, + const char *fname) { + LStream *p = newprefile(L); + p->f = f; + p->closef = &io_noclose; + if (k != NULL) { + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */ + } + lua_setfield(L, -2, fname); /* add file to module */ } -LUALIB_API int luaopen_io (lua_State *L) { +LUAMOD_API int luaopen_io (lua_State *L) { + luaL_newlib(L, iolib); /* new module */ 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); /* create (and set) default files */ - newfenv(L, io_noclose); /* close function for default files */ 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_pop(L, 1); /* pop 'popen' */ + createstdfile(L, stderr, NULL, "stderr"); return 1; } diff --git a/src/llex.c b/src/llex.c index 88c6790c07..c4d8c65b6f 100644 --- a/src/llex.c +++ b/src/llex.c @@ -1,11 +1,10 @@ /* -** $Id: llex.c,v 2.20.1.2 2009/11/23 14:58:22 roberto Exp $ +** $Id: llex.c,v 2.61 2012/01/23 23:05:51 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", + "end", "false", "for", "function", "goto", "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 l_noret 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); } @@ -66,23 +67,24 @@ void luaX_init (lua_State *L) { for (i=0; itsv.reserved = cast_byte(i+1); /* reserved word */ + ts->tsv.extra = cast_byte(i+1); /* reserved word */ } } -#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,40 +94,54 @@ 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 l_noret 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); +l_noret luaX_syntaxerror (LexState *ls, const char *msg) { + lexerror(ls, msg, ls->t.token); } +/* +** 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; - 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 */ + 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_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); } + 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)); @@ -137,17 +153,20 @@ 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; ls->linenumber = 1; ls->lastline = 1; ls->source = 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 */ } @@ -161,13 +180,16 @@ 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; } +/* +** 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); @@ -176,37 +198,59 @@ static void buffreplace (LexState *ls, char from, char to) { } +#if !defined(getlocaledecpoint) +#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 +*/ 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)) { + ls->decpoint = getlocaledecpoint(); + buffreplace(ls, old, ls->decpoint); /* try new decimal separator */ + if (!buff2d(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 */ +/* +** this function is quite liberal in what it accepts, as 'luaO_str2d' +** will reject ill-formed numerals. +*/ static void read_numeral (LexState *ls, SemInfo *seminfo) { - lua_assert(isdigit(ls->current)); - do { - save_and_next(ls); - } while (isdigit(ls->current) || ls->current == '.'); - if (check_next(ls, "Ee")) /* `E'? */ - check_next(ls, "+-"); /* optional exponent sign */ - while (isalnum(ls->current) || ls->current == '_') - save_and_next(ls); + const char *expo = "Ee"; + int first = ls->current; + lua_assert(lisdigit(ls->current)); + save_and_next(ls); + if (first == '0' && check_next(ls, "Xx")) /* hexadecimal? */ + expo = "Pp"; + for (;;) { + if (check_next(ls, expo)) /* exponent part? */ + check_next(ls, "+-"); /* optional exponent sign */ + if (lisxdigit(ls->current) || ls->current == '.') + save_and_next(ls); + else break; + } 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 */ } +/* +** 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; @@ -221,43 +265,23 @@ 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; } - case '\n': - case '\r': { + case '\n': case '\r': { save(ls, '\n'); inclinenumber(ls); if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ @@ -275,51 +299,91 @@ static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { } +static void escerror (LexState *ls, int *c, int n, const char *msg) { + int i; + luaZ_resetbuffer(ls->buff); /* prepare error message */ + save(ls, '\\'); + for (i = 0; i < n && c[i] != EOZ; i++) + save(ls, c[i]); + lexerror(ls, msg, TK_STRING); +} + + +static int readhexaesc (LexState *ls) { + 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]); + } + return r; +} + + +static int readdecesc (LexState *ls) { + 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); + } + if (r > UCHAR_MAX) + escerror(ls, c, i, "decimal escape too large"); + return r; +} + + 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: - luaX_lexerror(ls, "unfinished string", TK_EOS); - continue; /* to avoid warnings */ + lexerror(ls, "unfinished string", TK_EOS); + break; /* to avoid warnings */ case '\n': case '\r': - luaX_lexerror(ls, "unfinished string", TK_STRING); - continue; /* to avoid warnings */ - case '\\': { - int c; + lexerror(ls, "unfinished string", TK_STRING); + break; /* to avoid warnings */ + case '\\': { /* escape sequences */ + 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 '\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); /* 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); + 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; + goto no_save; + } + default: { + if (!lisdigit(ls->current)) + escerror(ls, &ls->current, 1, "invalid escape sequence"); + /* digital escape \ddd */ + c = readdecesc(ls); + goto only_save; } } - save(ls, c); - next(ls); - continue; + read_save: next(ls); /* read next character */ + only_save: save(ls, c); /* save 'c' */ + no_save: break; } default: save_and_next(ls); @@ -335,38 +399,41 @@ 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); 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); @@ -388,56 +455,52 @@ static int llex (LexState *ls, SemInfo *seminfo) { if (ls->current != '=') return '~'; else { next(ls); return TK_NE; } } - case '"': - case '\'': { + case ':': { + next(ls); + if (ls->current != ':') return ':'; + else { next(ls); return TK_DBCOLON; } + } + 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; /* .. */ - } - else if (!isdigit(ls->current)) return '.'; - else { - read_numeral(ls, seminfo); - return TK_NUMBER; + return TK_DOTS; /* '...' */ + else return TK_CONCAT; /* '..' */ } + else if (!lisdigit(ls->current)) return '.'; + /* 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 (isspace(ls->current)) { - lua_assert(!currIsNewline(ls)); - next(ls); - continue; - } - else if (isdigit(ls->current)) { - read_numeral(ls, seminfo); - return TK_NUMBER; - } - else if (isalpha(ls->current) || ls->current == '_') { - /* identifier or reserved word */ + 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? */ - return ts->tsv.reserved - 1 + FIRST_RESERVED; + seminfo->ts = ts; + if (isreserved(ts)) /* reserved word? */ + return ts->tsv.extra - 1 + FIRST_RESERVED; else { - seminfo->ts = ts; return TK_NAME; } } - else { + else { /* single-char tokens (+ - / ...) */ int c = ls->current; next(ls); - return c; /* single-char tokens (+ - / ...) */ + return c; } } } @@ -456,8 +519,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..9ca8a29948 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.72 2011/11/30 12:43:51 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,21 +23,17 @@ 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_NUMBER, - TK_NAME, TK_STRING, TK_EOS + TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_DBCOLON, 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; @@ -52,29 +46,32 @@ 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 Dyndata *dyd; /* dynamic structures used by the parser */ TString *source; /* current source name */ + TString *envn; /* environment variable name */ char decpoint; /* locale decimal point */ } 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 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 int luaX_lookahead (LexState *ls); +LUAI_FUNC l_noret 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..fc9de1a11b 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.99 2012/05/28 20:32:28 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; @@ -31,6 +31,8 @@ typedef unsigned char lu_byte; #define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2) +#define MAX_LMEM ((l_mem) ((MAX_LUMEM >> 1) - 2)) + #define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */ @@ -44,6 +46,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,35 +58,74 @@ 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) - +/* to avoid problems with conditions too long */ +#define lua_longassert(c) { if (!(c)) lua_assert(0); } #else - #define lua_assert(c) ((void)0) #define check_exp(c,e) (e) -#define api_check luai_apicheck +#define lua_longassert(c) ((void)0) +#endif +/* +** assertion for checking API calls +*/ +#if !defined(luai_apicheck) + +#if defined(LUA_USE_APICHECK) +#include +#define luai_apicheck(L,e) assert(e) +#else +#define luai_apicheck(L,e) lua_assert(e) #endif +#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)) +#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.) +*/ +#if !defined(LUAI_MAXCCALLS) +#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 + + /* ** type for virtual-machine instructions ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) @@ -95,34 +140,170 @@ 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,L1) ((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 + +/* +** 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. +** 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) /* { */ +/* 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 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_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_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_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 /* } */ + + +/* 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 + + + +#if defined(ltable_c) && !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 + + + /* ** 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) \ + ((void)(!(G(L)->gcrunning) || (luaC_fullgc(L, 0), 1))) #endif #endif diff --git a/src/lmathlib.c b/src/lmathlib.c index 441fbf736c..c3c605e86b 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.81 2012/05/18 17:47:53 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ @@ -17,112 +17,132 @@ #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 (3.14159265358979323846) +#define PI (l_tg(3.1415926535897932384626433832795)) #define RADIANS_PER_DEGREE (PI/180.0) 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; } 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 = l_tg(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); + } + lua_pushnumber(L, res); return 1; } +#if defined(LUA_COMPAT_LOG10) static int math_log10 (lua_State *L) { - lua_pushnumber(L, log10(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_tg(log10)(luaL_checknumber(L, 1))); return 1; } +#endif 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; } @@ -138,13 +158,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; } @@ -188,16 +209,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, l_tg(floor)(r*u) + 1.0); /* int in [1, 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, l_tg(floor)(r*(u-l+1)) + l); /* int in [l, u] */ break; } default: return luaL_error(L, "wrong number of arguments"); @@ -207,7 +228,8 @@ 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; } @@ -227,7 +249,9 @@ static const luaL_Reg mathlib[] = { {"fmod", math_fmod}, {"frexp", math_frexp}, {"ldexp", math_ldexp}, +#if defined(LUA_COMPAT_LOG10) {"log10", math_log10}, +#endif {"log", math_log}, {"max", math_max}, {"min", math_min}, @@ -248,16 +272,12 @@ static const luaL_Reg mathlib[] = { /* ** Open math library */ -LUALIB_API int luaopen_math (lua_State *L) { - luaL_register(L, LUA_MATHLIBNAME, mathlib); +LUAMOD_API int luaopen_math (lua_State *L) { + luaL_newlib(L, 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..3f88496e09 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.84 2012/05/23 15:41:53 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 { @@ -63,9 +63,8 @@ void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems, } -void *luaM_toobig (lua_State *L) { +l_noret luaM_toobig (lua_State *L) { luaG_runerror(L, "memory allocation error: block too big"); - return NULL; /* to avoid warnings */ } @@ -74,13 +73,27 @@ 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->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 (g->gcrunning) { + 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->GCdebt = (g->GCdebt + nsize) - realosize; + return newblock; } diff --git a/src/lmem.h b/src/lmem.h index 7c2dcb3220..535dfe07f3 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.38 2011/12/02 13:26:54 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -13,23 +13,23 @@ #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 */ \ - luaM_realloc_(L, (b), (on)*(e), (n)*(e)) : \ - luaM_toobig(L)) + ((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))) #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 +37,14 @@ #define luaM_reallocvector(L, v,oldn,n,t) \ ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t)))) +LUAI_FUNC l_noret 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 6158c5353d..a9959277bd 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -1,14 +1,22 @@ /* -** $Id: loadlib.c,v 1.52.1.4 2009/09/09 13:17:16 roberto Exp $ +** $Id: loadlib.c,v 1.111 2012/05/30 12:33:44 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. */ +/* +** if needed, includes windows header before everything else +*/ +#if defined(_WIN32) +#include +#endif + + #include #include @@ -22,6 +30,61 @@ #include "lualib.h" +/* +** LUA_PATH and LUA_CPATH are the names of the environment +** variables that Lua check to set its paths. +*/ +#if !defined(LUA_PATH) +#define LUA_PATH "LUA_PATH" +#endif + +#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. +** 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 + + +/* +** 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_" @@ -29,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" @@ -42,13 +105,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 +131,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 : RTLD_LOCAL)); if (lib == NULL) lua_pushstring(L, dlerror()); return lib; } @@ -89,10 +155,15 @@ 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 -#undef setprogdir static void setprogdir (lua_State *L) { char buff[MAX_PATH + 1]; @@ -103,7 +174,7 @@ static void setprogdir (lua_State *L) { 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 */ } } @@ -113,26 +184,27 @@ 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); } static void ll_unloadlib (void *lib) { - FreeLibrary((HINSTANCE)lib); + FreeLibrary((HMODULE)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) { + HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS); + (void)(seeglb); /* not used: symbols are 'global' by default */ 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); + lua_CFunction f = (lua_CFunction)GetProcAddress((HMODULE)lib, sym); if (f == NULL) pusherror(L); return f; } @@ -140,88 +212,6 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { /* }====================================================== */ - -#elif defined(LUA_DL_DYLD) -/* -** {====================================================================== -** Native Mac OS X / Darwin Implementation -** ======================================================================= -*/ - -#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) { - 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 " LUA_QS " not found", sym); - return NULL; - } - return (lua_CFunction)NSAddressOfSymbol(nss); -} - -/* }====================================================== */ - - - #else /* ** {====================================================== @@ -237,19 +227,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); /* not used */ } -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); (void)(seeglb); /* not used */ 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); /* not used */ lua_pushliteral(L, DLMSG); return NULL; } @@ -258,50 +248,58 @@ 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); - 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); - } +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); - 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); - return 0; /* return function */ + lua_pushcfunction(L, f); /* else create new function */ + return 0; /* no errors */ } } @@ -339,104 +337,137 @@ 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); - lua_pushliteral(L, ""); /* error accumulator */ +static const char *searchpath (lua_State *L, const char *name, + const char *path, + 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, dirsep); /* replace it by 'dirsep' */ 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 */ 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 */ } -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 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, 4, LUA_DIRSEP)); + 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 *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, ".", dirsep); +} + + +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)); } -static int loader_Lua (lua_State *L) { +static int searcher_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) != 0) - loaderror(L, filename); - return 1; /* library loaded successfully */ + 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); } -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; + 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, 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, LUA_POF"%s", modname); + return ll_loadfunc(L, filename, funcname); } -static int loader_C (lua_State *L) { - const char *funcname; +static int searcher_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 */ - funcname = mkfuncname(L, name); - if (ll_loadfunc(L, filename, funcname) != 0) - loaderror(L, filename); - return 1; /* library loaded successfully */ + 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); } -static int loader_Croot (lua_State *L) { - const char *funcname; +static int searcher_Croot (lua_State *L) { 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"); + filename = findfile(L, lua_tostring(L, -1), "cpath", LUA_CSUBSEP); if (filename == NULL) return 1; /* root not found */ - funcname = mkfuncname(L, name); - if ((stat = ll_loadfunc(L, filename, funcname)) != 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 = loadfunc(L, filename, name)) != 0) { + 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; } -static int loader_preload (lua_State *L) { +static int searcher_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, LUA_REGISTRYINDEX, "_PRELOAD"); lua_getfield(L, -1, name); if (lua_isnil(L, -1)) /* not found? */ lua_pushfstring(L, "\n\tno field package.preload['%s']", name); @@ -444,48 +475,53 @@ static int loader_preload (lua_State *L) { } -static const int sentinel_ = 0; -#define sentinel ((void *)&sentinel_) +static void findloader (lua_State *L, const char *name) { + int i; + 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"); + /* iterate over available searchers to find a loader */ + for (i = 1; ; i++) { + lua_rawgeti(L, 3, i); /* get a searcher */ + 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, -1)); + } + lua_pushstring(L, name); + lua_call(L, 1, 2); /* call it */ + if (lua_isfunction(L, -2)) /* did it find a loader? */ + return; /* module loader found */ + else if (lua_isstring(L, -2)) { /* searcher returned error message? */ + lua_pop(L, 1); /* remove extra return */ + 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); - 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); + lua_getfield(L, 2, name); /* _LOADED[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_ENVIRONINDEX, "loaders"); - if (!lua_istable(L, -1)) - luaL_error(L, LUA_QL("package.loaders") " must be a table"); - lua_pushliteral(L, ""); /* error message accumulator */ - for (i=1; ; i++) { - lua_rawgeti(L, -2, i); /* get a loader */ - if (lua_isnil(L, -1)) - 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? */ - 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 */ - lua_pushstring(L, name); /* pass name as argument to module */ - lua_call(L, 1, 1); /* run loaded module */ + /* 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 */ 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 */ @@ -502,26 +538,31 @@ static int ll_require (lua_State *L) { ** 'module' function ** ======================================================= */ - +#if defined(LUA_COMPAT_MODULE) -static void setfenv (lua_State *L) { +/* +** changes the environment 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); - lua_setfenv(L, -2); - lua_pop(L, 1); + lua_pushvalue(L, -2); /* copy new environment table to top */ + lua_setupvalue(L, -2, 1); + lua_pop(L, 1); /* remove function */ } 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); + } } } @@ -543,17 +584,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) */ - 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 */ - } + 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? */ @@ -563,9 +595,9 @@ static int ll_module (lua_State *L) { modinit(L, modname); } lua_pushvalue(L, -1); - setfenv(L); - dooptions(L, loaded - 1); - return 0; + set_env(L); + dooptions(L, lastarg); + return 1; } @@ -576,12 +608,12 @@ 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; } - +#endif /* }====================================================== */ @@ -589,15 +621,30 @@ 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); + +/* +** return registry.LUA_NOENV as a boolean +*/ +static int noenv (lua_State *L) { + int b; + lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); + b = lua_toboolean(L, -1); + lua_pop(L, 1); /* remove value */ + return b; +} + + +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 || noenv(L)) /* 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); + 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,59 +655,71 @@ static void setpath (lua_State *L, const char *fieldname, const char *envname, static const luaL_Reg pk_funcs[] = { {"loadlib", ll_loadlib}, + {"searchpath", ll_searchpath}, +#if defined(LUA_COMPAT_MODULE) {"seeall", ll_seeall}, +#endif {NULL, NULL} }; static const luaL_Reg ll_funcs[] = { +#if defined(LUA_COMPAT_MODULE) {"module", ll_module}, +#endif {"require", ll_require}, {NULL, NULL} }; -static const lua_CFunction loaders[] = - {loader_preload, loader_Lua, loader_C, loader_Croot, NULL}; +static void createsearcherstable (lua_State *L) { + static const lua_CFunction searchers[] = + {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL}; + int i; + /* create 'searchers' table */ + lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); + /* fill it with pre-defined searchers */ + for (i=0; searchers[i] != NULL; i++) { + lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */ + lua_pushcclosure(L, searchers[i], 1); + lua_rawseti(L, -2, i+1); + } +} -LUALIB_API int luaopen_package (lua_State *L) { - int i; - /* create new type _LOADLIB */ - luaL_newmetatable(L, "_LOADLIB"); +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"); + lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */ + lua_setmetatable(L, -2); /* 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"); + 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' */ #endif - lua_pushvalue(L, -1); - lua_replace(L, 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_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' */ + lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */ + /* 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_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); + luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); lua_setfield(L, -2, "loaded"); /* set field `preload' */ - lua_newtable(L); + luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); lua_setfield(L, -2, "preload"); - lua_pushvalue(L, LUA_GLOBALSINDEX); - luaL_register(L, NULL, ll_funcs); /* open lib into global table */ - lua_pop(L, 1); + lua_pushglobaltable(L); + lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ + 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.c b/src/lobject.c index 4ff50732a4..cf0f75446d 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.55 2011/11/30 19:30:16 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}; /* @@ -33,25 +34,25 @@ const TValue luaO_nilobject_ = {{NULL}, LUA_TNIL}; ** eeeee != 0 and (xxx) otherwise. */ int luaO_int2fb (unsigned int x) { - int e = 0; /* expoent */ - while (x >= 16) { + 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,55 +63,122 @@ 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]; +} + + +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(NULL, v1); + default: lua_assert(0); return 0; + } +} + + +int luaO_hexavalue (int c) { + if (lisdigit(c)) return c - '0'; + else return ltolower(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; +} + +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))); + (*count)++; + } + return r; } -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); - default: - lua_assert(iscollectable(t1)); - return gcvalue(t1) == gcvalue(t2); +/* +** 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, lua_Number *result) { +int luaO_str2d (const char *s, size_t len, 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? */ - return 1; + 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); + if (endptr == s) return 0; /* nothing recognized */ + while (lisspace(cast_uchar(*endptr))) endptr++; + return (endptr == s + len); /* 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; @@ -120,14 +188,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': { @@ -142,29 +209,25 @@ 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: { - char buff[3]; - buff[0] = '%'; - buff[1] = *(e+1); - buff[2] = '\0'; - pushstr(L, buff); - break; + luaG_runerror(L, + "invalid option " LUA_QL("%%%c") " to " LUA_QL("lua_pushfstring"), + *(e + 1)); } } n += 2; fmt = e+2; } - pushstr(L, fmt); - luaV_concat(L, n+1, cast_int(L->top - L->base) - 1); - L->top -= n; + pushstr(L, fmt, strlen(fmt)); + if (n > 0) luaV_concat(L, n + 1); return svalue(L->top - 1); } @@ -179,36 +242,48 @@ 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 RETS "..." +#define PRE "[string \"" +#define POS "\"]" + +#define addstr(a,b,l) ( memcpy(a,b,(l) * sizeof(char)), 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 * sizeof(char)); + 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 * sizeof(char)); + else { /* add '...' before rest of name */ + addstr(out, RETS, LL(RETS)); + bufflen -= LL(RETS); + memcpy(out, source + 1 + l - bufflen, bufflen * sizeof(char)); } - 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) + 1; /* save space for prefix+suffix+'\0' */ + 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) * sizeof(char)); } } + diff --git a/src/lobject.h b/src/lobject.h index f1e447ef3b..ca75a028c2 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.70 2012/05/11 14:10:50 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -16,18 +16,53 @@ #include "lua.h" -/* tags for values visible from Lua */ -#define LAST_TAG LUA_TTHREAD +/* +** Extra tags for non-values +*/ +#define LUA_TPROTO LUA_NUMTAGS +#define LUA_TUPVAL (LUA_NUMTAGS+1) +#define LUA_TDEADKEY (LUA_NUMTAGS+2) -#define NUM_TAGS (LAST_TAG+1) +/* +** number of all possible tags (including LUA_TNONE but excluding DEADKEY) +*/ +#define LUA_TOTALTAGS (LUA_TUPVAL+2) /* -** Extra tags for non-values +** 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 +*/ + +#define VARBITS (3 << 4) + + +/* +** LUA_TFUNCTION variants: +** 0 - Lua function +** 1 - light C function +** 2 - regular C function (closure) */ -#define LUA_TPROTO (LAST_TAG+1) -#define LUA_TUPVAL (LAST_TAG+2) -#define LUA_TDEADKEY (LAST_TAG+3) + +/* 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 */ + + +/* +** LUA_TSTRING variants */ +#define LUA_TSHRSTR (LUA_TSTRING | (0 << 4)) /* short strings */ +#define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) /* long strings */ + + +/* Bit mark for collectable types */ +#define BIT_ISCOLLECTABLE (1 << 6) + +/* mark a tag as collectable */ +#define ctb(t) ((t) | BIT_ISCOLLECTABLE) /* @@ -52,120 +87,167 @@ typedef struct GCheader { - /* ** Union of all Lua values */ -typedef union { - GCObject *gc; - void *p; - lua_Number n; - int b; -} Value; +typedef union Value Value; + + +#define numfield lua_Number n; /* numbers */ + /* -** 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 +#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 val_(o) ((o)->value_) +#define num_(o) (val_(o).n) + + +/* raw type tag of a TValue */ +#define rttype(o) ((o)->tt_) + +/* tag with no variants (bits 0-3) */ +#define novariant(x) ((x) & 0x0F) + +/* 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) (novariant(rttype(o))) /* 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) +#define checktag(o,t) (rttype(o) == (t)) +#define checktype(o,t) (ttypenv(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) checktype((o), LUA_TSTRING) +#define ttisshrstring(o) checktag((o), ctb(LUA_TSHRSTR)) +#define ttislngstring(o) checktag((o), ctb(LUA_TLNGSTR)) +#define ttistable(o) checktag((o), ctb(LUA_TTABLE)) +#define ttisfunction(o) checktype(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), LUA_TDEADKEY) + +#define ttisequal(o1,o2) (rttype(o1) == rttype(o2)) /* 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 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(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(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) +/* 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)) -/* -** for internal debug only -*/ -#define checkconsistency(obj) \ - lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt)) + +#define iscollectable(o) (rttype(o) & BIT_ISCOLLECTABLE) + + +/* Macros for internal tests */ +#define righttt(obj) (ttype(obj) == gcvalue(obj)->gch.tt) #define checkliveness(g,obj) \ - lua_assert(!iscollectable(obj) || \ - ((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(g, (obj)->value.gc))) + 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 changenvalue(o,x) check_exp(ttisnumber(o), num_(o)=(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); \ + TString *x_ = (x); \ + val_(io).gc=cast(GCObject *, x_); settt_(io, ctb(x_->tsv.tt)); \ + 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 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 setclLvalue(L,obj,x) \ + { TValue *io=(obj); \ + val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TLCL)); \ + 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); } +#define setclCvalue(L,obj,x) \ + { TValue *io=(obj); \ + val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TCCL)); \ + 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); } +#define sethvalue(L,obj,x) \ + { TValue *io=(obj); \ + val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TTABLE)); \ + checkliveness(G(L),io); } +#define setdeadvalue(obj) settt_(obj, 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); } /* -** different types of sets, according to destination +** different types of assignments, according to destination */ /* from stack to (same) stack */ @@ -183,47 +265,204 @@ typedef struct lua_TValue { #define setobj2n setobj #define setsvalue2n setsvalue -#define setttype(obj, tt) (ttype(obj) = (tt)) +/* check whether a number is valid (useful only for NaN trick) */ +#define luai_checknum(L,o,c) { /* empty */ } + + +/* +** {====================================================== +** NaN Trick +** ======================================================= +*/ +#if defined(LUA_NANTRICK) + +/* +** 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') +*/ + +/* 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 + +#undef TValuefields +#undef NILCONSTANT + +#if (LUA_IEEEENDIAN == 0) /* { */ + +/* little endian */ +#define TValuefields \ + union { struct { Value v__; int tt__; } i; double d__; } u +#define NILCONSTANT {{{NULL}, tag2tt(LUA_TNIL)}} +/* field-access macros */ +#define v_(o) ((o)->u.i.v__) +#define d_(o) ((o)->u.d__) +#define tt_(o) ((o)->u.i.tt__) + +#else /* }{ */ + +/* big endian */ +#define TValuefields \ + 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__) + +#endif /* } */ + +#endif /* } */ -#define iscollectable(o) (ttype(o) >= LUA_TSTRING) +/* 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) ((tt_(o) & NNMASK) != NNMARK) + +#define tag2tt(t) (NNMARK | (t)) + +#undef rttype +#define rttype(o) (ttisnumber(o) ? LUA_TNUMBER : tt_(o) & 0xff) + +#undef settt_ +#define settt_(o,t) (tt_(o) = 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 +#undef checktype +#define checktag(o,t) (tt_(o) == tag2tt(t)) +#define checktype(o,t) (ctb(tt_(o) | VARBITS) == ctb(tag2tt(t) | VARBITS)) + +#undef ttisequal +#define ttisequal(o1,o2) \ + (ttisnumber(o1) ? ttisnumber(o2) : (tt_(o1) == tt_(o2))) + + +#undef luai_checknum +#define luai_checknum(L,o,c) { if (!ttisnumber(o)) c; } + +#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 */ + + /* -** 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 */ struct { CommonHeader; - lu_byte reserved; + lu_byte extra; /* reserved words for short strings; "has hash" for longs */ unsigned int hash; - size_t len; + size_t len; /* number of characters in string */ } tsv; } 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 { CommonHeader; struct Table *metatable; struct Table *env; - size_t len; + size_t len; /* number of bytes */ } uv; } Udata; +/* +** Description of an upvalue for function prototypes +*/ +typedef struct Upvaldesc { + TString *name; /* upvalue name (for debug information) */ + 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 @@ -233,11 +472,12 @@ 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 */ - struct LocVar *locvars; /* information about local variables */ - TString **upvalues; /* upvalue names */ - TString *source; - int sizeupvalues; + 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; /* used for debug information */ + int sizeupvalues; /* size of 'upvalues' */ int sizek; /* size of `k' */ int sizecode; int sizelineinfo; @@ -246,31 +486,16 @@ typedef struct Proto { int linedefined; int lastlinedefined; GCObject *gclist; - lu_byte nups; /* number of upvalues */ - 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; -/* 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 */ - 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 */ @@ -289,20 +514,19 @@ typedef struct UpVal { */ #define ClosureHeader \ - CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist; \ - struct Table *env + CommonHeader; lu_byte nupvalues; GCObject *gclist 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; @@ -312,8 +536,9 @@ 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 isLfunction(o) ttisLclosure(o) + +#define getproto(o) (clLvalue(o)->p) /* @@ -337,7 +562,7 @@ typedef struct Node { typedef struct Table { CommonHeader; - lu_byte flags; /* 1<

    lsizenode)) +/* +** (address of) a fixed nil value +*/ #define luaO_nilobject (&luaO_nilobject_) -LUAI_DATA const TValue luaO_nilobject_; -#define ceillog2(x) (luaO_log2((x)-1) + 1) +LUAI_DDEC const TValue luaO_nilobject_; + -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 int luaO_ceillog2 (unsigned int x); +LUAI_FUNC lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2); +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 4cc745230b..ef73692754 100644 --- a/src/lopcodes.c +++ b/src/lopcodes.c @@ -1,5 +1,6 @@ /* -** $Id: lopcodes.c,v 1.37.1.1 2007/12/27 13:02:25 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 */ @@ -13,15 +14,16 @@ /* ORDER OP */ -const char *const luaP_opnames[NUM_OPCODES+1] = { +LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { "MOVE", "LOADK", + "LOADKX", "LOADBOOL", "LOADNIL", "GETUPVAL", - "GETGLOBAL", + "GETTABUP", "GETTABLE", - "SETGLOBAL", + "SETTABUP", "SETUPVAL", "SETTABLE", "NEWTABLE", @@ -47,27 +49,29 @@ const char *const luaP_opnames[NUM_OPCODES+1] = { "RETURN", "FORLOOP", "FORPREP", + "TFORCALL", "TFORLOOP", "SETLIST", - "CLOSE", "CLOSURE", "VARARG", + "EXTRAARG", NULL }; #define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) -const lu_byte luaP_opmodes[NUM_OPCODES] = { +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, 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, 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 */ @@ -86,17 +90,18 @@ 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 */ ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */ ,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, 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 41224d6ee1..07d2b3f39a 100644 --- a/src/lopcodes.h +++ b/src/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.125.1.1 2007/12/27 13:02:25 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 */ @@ -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 @@ -28,7 +29,7 @@ ===========================================================================*/ -enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ +enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */ /* @@ -38,6 +39,7 @@ enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ #define SIZE_B 9 #define SIZE_Bx (SIZE_C + SIZE_B) #define SIZE_A 8 +#define SIZE_Ax (SIZE_C + SIZE_B + SIZE_A) #define SIZE_OP 6 @@ -46,6 +48,7 @@ enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ #define POS_C (POS_A + SIZE_A) #define POS_B (POS_C + SIZE_C) #define POS_Bx POS_C +#define POS_Ax POS_A /* @@ -61,6 +64,12 @@ enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ #define MAXARG_sBx MAX_INT #endif +#if SIZE_Ax < LUAI_BITSINT-1 +#define MAXARG_Ax ((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)<= 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++ */ +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 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_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 +212,44 @@ 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_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx]) */ + +OP_VARARG,/* A B R(A), R(A+1), ..., R(A+B-2) = vararg */ -OP_VARARG/* A B R(A), R(A+1), ..., R(A+B-1) = vararg */ +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 real C + (*) In OP_SETLIST, if (B == 0) then B = `top'; if (C == 0) then next + 'instruction' is EXTRAARG(real C). + + (*) In OP_LOADKX, the next 'instruction' is always EXTRAARG. (*) 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 +259,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 +269,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 +278,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..489755b6f5 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.39 2012/05/23 15:37:09 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ @@ -20,37 +20,85 @@ #include "lualib.h" -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; - } - else { - lua_pushnil(L); - lua_pushfstring(L, "%s: %s", filename, strerror(en)); - lua_pushinteger(L, en); - return 3; - } -} +/* +** 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 + + +/* +** By default, Lua uses gmtime/localtime, except when POSIX is available, +** where it uses gmtime_r/localtime_r +*/ +#if defined(LUA_USE_GMTIME_R) + +#define l_gmtime(t,r) gmtime_r(t,r) +#define l_localtime(t,r) localtime_r(t,r) + +#elif !defined(l_gmtime) + +#define l_gmtime(t,r) ((void)r, gmtime(t)) +#define l_localtime(t,r) ((void)r, localtime(t)) + +#endif + static int os_execute (lua_State *L) { - lua_pushinteger(L, system(luaL_optstring(L, 1, NULL))); - return 1; + const char *cmd = luaL_optstring(L, 1, NULL); + int stat = system(cmd); + if (cmd != NULL) + return luaL_execresult(L, stat); + else { + lua_pushboolean(L, stat); /* true if there is a shell */ + 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); } @@ -107,11 +155,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; @@ -121,16 +168,40 @@ 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)); - struct tm *stm; + struct tm tmr, *stm; if (*s == '!') { /* UTC? */ - stm = gmtime(&t); + stm = l_gmtime(&t, &tmr); s++; /* skip `!' */ } else - stm = localtime(&t); + stm = l_localtime(&t, &tmr); if (stm == NULL) /* invalid date? */ lua_pushnil(L); else if (strcmp(s, "*t") == 0) { @@ -146,17 +217,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 +285,18 @@ static int os_setlocale (lua_State *L) { static int os_exit (lua_State *L) { - exit(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); + if (L) exit(status); /* 'if' to avoid warnings for unreachable 'return' */ + return 0; } + static const luaL_Reg syslib[] = { {"clock", os_clock}, {"date", os_date}, @@ -236,8 +316,8 @@ static const luaL_Reg syslib[] = { -LUALIB_API int luaopen_os (lua_State *L) { - luaL_register(L, LUA_OSLIBNAME, syslib); +LUAMOD_API int luaopen_os (lua_State *L) { + luaL_newlib(L, syslib); return 1; } diff --git a/src/lparser.c b/src/lparser.c index dda7488dca..b3eb3ca923 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.42.1.4 2011/10/21 19:31:42 roberto Exp $ +** $Id: lparser.c,v 2.128 2012/05/20 14:51:23 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) /* @@ -39,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 */ + 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 isbreakable; /* true if `block' is a loop */ + lu_byte isloop; /* true if `block' is a loop */ } BlockCnt; @@ -50,11 +53,13 @@ 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); 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); @@ -62,18 +67,34 @@ static void anchor_token (LexState *ls) { } -static void error_expected (LexState *ls, int token) { +/* semantic error */ +static l_noret semerror (LexState *ls, const char *msg) { + ls->t.token = 0; /* remove 'near to' from final message */ + luaX_syntaxerror(ls, msg); +} + + +static l_noret 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 l_noret 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(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); } -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); +static void checklimit (FuncState *fs, int v, int l, const char *what) { + if (v > l) errorlimit(fs, l, what); } @@ -91,6 +112,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); @@ -107,7 +129,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)); } } @@ -126,7 +148,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; } @@ -135,7 +157,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 +167,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 +175,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; + Dyndata *dyd = ls->dyd; + int reg = registerlocalvar(ls, name); + checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, + 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(short, reg); +} -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 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 LocVar *getlocvar (FuncState *fs, int i) { + int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx; + lua_assert(idx < fs->nlocvars); + return &fs->f->locvars[idx]; } @@ -168,77 +206,88 @@ 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->dyd->actvar.n -= (fs->nactvar - tolevel); while (fs->nactvar > tolevel) - getlocvar(fs, --fs->nactvar).endpc = fs->pc; + getlocvar(fs, --fs->nactvar)->endpc = fs->pc; } -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 (luaS_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; - 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); - 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; - 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++; + checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); + 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->ls->L, f, name); + 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 (luaS_eqstr(n, getlocvar(fs, i)->varname)) return i; } return -1; /* not found */ } +/* + Mark block where variable at given level was defined + (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; } +/* + 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? */ - init_exp(var, VGLOBAL, NO_REG); /* default is global variable */ - return VGLOBAL; - } + if (fs == NULL) /* no more levels? */ + 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; } } @@ -248,8 +297,13 @@ 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) == VVOID) { /* global name? */ + expdesc key; + 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] */ + } } @@ -274,18 +328,118 @@ 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); + lua_State *L = ls->L; + ++L->nCcalls; + checklimit(ls->fs, L->nCcalls, LUAI_MAXCCALLS, "C levels"); } #define leavelevel(ls) ((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(luaS_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(vname)); + 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 (luaS_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, SHRT_MAX, "labels/gotos"); + 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 (luaS_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 exits 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; @@ -293,63 +447,105 @@ 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 l_noret undefgoto (LexState *ls, Labeldesc *gt) { + const char *msg = isreserved(gt->name) + ? "<%s> at line %d not inside a loop" + : "no visible label " LUA_QS " for at line %d"; + 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->ls, 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); + removevars(fs, bl->nactvar); 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 */ } -static void pushclosure (LexState *ls, FuncState *func, expdesc *v) { +/* +** adds a new prototype into list of prototypes +*/ +static Proto *addprototype (LexState *ls) { + Proto *clp; + lua_State *L = ls->L; 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; - luaK_codeABC(fs, o, 0, func->upvalues[i].info, 0); + Proto *f = fs->f; /* prototype of current function */ + if (fs->np >= f->sizep) { + int oldsize = f->sizep; + 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 = luaF_newproto(L); + luaC_objbarrier(L, f, clp); + return clp; } -static void open_func (LexState *ls, FuncState *fs) { +/* +** 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) */ +} + + +static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { 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->dyd->actvar.n; fs->bl = NULL; + f = fs->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) */ + fs->h = luaH_new(L); + /* anchor table of constants (to avoid being collected) */ sethvalue2s(L, L->top, fs->h); incr_top(L); - setptvalue2s(L, L->top, f); - incr_top(L); + enterblock(fs, bl, 0); } @@ -357,8 +553,8 @@ static void close_func (LexState *ls) { lua_State *L = ls->L; FuncState *fs = ls->fs; Proto *f = fs->f; - removevars(ls, 0); luaK_ret(fs, 0, 0); /* final return */ + 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); @@ -369,32 +565,14 @@ 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; - /* last token read was anchored in defunct function; must reanchor it */ - if (fs) anchor_token(ls); - L->top -= 2; /* remove table and prototype from the stack */ -} - - -Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { - struct LexState lexstate; - struct FuncState funcstate; - lexstate.buff = buff; - luaX_setinput(L, &lexstate, z, luaS_new(L, name)); - open_func(&lexstate, &funcstate); - funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */ - luaX_next(&lexstate); /* read first token */ - chunk(&lexstate); - check(&lexstate, TK_EOS); - close_func(&lexstate); - lua_assert(funcstate.prev == NULL); - lua_assert(funcstate.f->nups == 0); - lua_assert(lexstate.fs == NULL); - return funcstate.f; + /* last token read was anchored in defunct function; must re-anchor it */ + anchor_token(ls); + L->top--; /* pop table of constants */ + luaC_checkGC(L); } @@ -404,11 +582,39 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { /*============================================================*/ -static void field (LexState *ls, expdesc *v) { - /* field -> ['.' | ':'] NAME */ +/* +** 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; 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); @@ -447,7 +653,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 == '[' */ @@ -456,7 +662,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 */ } @@ -466,7 +672,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 */ } } @@ -476,27 +682,51 @@ 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); } } 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); @@ -505,30 +735,13 @@ 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); 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 +763,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,33 +777,35 @@ 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 */ } -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; + new_fs.f = addprototype(ls); new_fs.f->linedefined = line; + open_func(ls, &new_fs, &bl); checknext(ls, '('); - if (needself) { - new_localvarliteral(ls, "self", 0); + 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, e); close_func(ls); - pushclosure(ls, &new_fs, e); } -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, ',')) { @@ -606,20 +817,17 @@ 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)"); + 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); @@ -636,11 +844,10 @@ static void funcargs (LexState *ls, expdesc *f) { } default: { luaX_syntaxerror(ls, "function arguments expected"); - return; } } 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 { @@ -664,8 +871,8 @@ static void funcargs (LexState *ls, expdesc *f) { */ -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; @@ -681,26 +888,26 @@ static void prefixexp (LexState *ls, expdesc *v) { } default: { luaX_syntaxerror(ls, "unexpected symbol"); - return; } } } -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; - prefixexp(ls, v); + int line = ls->linenumber; + primaryexp(ls, v); for (;;) { switch (ls->t.token) { - case '.': { /* field */ - field(ls, v); + case '.': { /* fieldsel */ + fieldsel(ls, v); break; } case '[': { /* `[' exp1 `]' */ expdesc key; - luaK_exp2anyreg(fs, v); + luaK_exp2anyregup(fs, v); yindex(ls, &key); luaK_indexed(fs, v, &key); break; @@ -710,12 +917,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; @@ -725,8 +932,8 @@ static void primaryexp (LexState *ls, expdesc *v) { static void simpleexp (LexState *ls, expdesc *v) { - /* simpleexp -> NUMBER | STRING | NIL | true | false | ... | - constructor | FUNCTION body | primaryexp */ + /* simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... | + constructor | FUNCTION body | suffixedexp */ switch (ls->t.token) { case TK_NUMBER: { init_exp(v, VKNUM, 0); @@ -753,7 +960,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; } @@ -767,7 +973,7 @@ static void simpleexp (LexState *ls, expdesc *v) { return; } default: { - primaryexp(ls, v); + suffixedexp(ls, v); return; } } @@ -811,11 +1017,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 */ @@ -825,15 +1031,16 @@ 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); 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' */ @@ -841,11 +1048,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); @@ -868,23 +1076,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); } @@ -900,29 +1097,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) { - if (lh->v.k == VINDEXED) { - if (lh->v.u.s.info == v->u.s.info) { /* conflict? */ + 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.s.info = extra; /* previous assignment will use safe copy */ + lh->v.u.ind.vt = VLOCAL; + lh->v.u.ind.t = extra; /* previous assignment will use safe copy */ } - if (lh->v.u.s.aux == v->u.s.info) { /* conflict? */ + /* 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.s.aux = extra; /* previous assignment will use safe copy */ + lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ } } } if (conflict) { - luaK_codeABC(fs, OP_MOVE, fs->freereg, v->u.s.info, 0); /* make copy */ + /* copy upvalue/local value to a temporary (in position 'extra') */ + OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; + luaK_codeABC(fs, op, extra, v->u.info, 0); luaK_reserveregs(fs, 1); } } @@ -930,22 +1132,21 @@ 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, - "syntax error"); - if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */ + check_condition(ls, vkisvar(lh->v.k), "syntax error"); + if (testnext(ls, ',')) { /* assignment -> ',' suffixedexp assignment */ struct LHS_assign nv; nv.prev = lh; - primaryexp(ls, &nv.v); - if (nv.v.k == VLOCAL) + suffixedexp(ls, &nv.v); + if (nv.v.k != VINDEXED) check_conflict(ls, lh, &nv.v); - luaY_checklimit(ls->fs, nvars, LUAI_MAXCCALLS - ls->L->nCcalls, - "variables in assignment"); + checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS, + "C levels"); 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) @@ -972,19 +1173,57 @@ static int cond (LexState *ls) { } -static void breakstat (LexState *ls) { +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 */ +} + + +/* check for repeated labels on the same block */ +static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) { + int i; + for (i = fs->bl->firstlabel; i < ll->n; i++) { + if (luaS_eqstr(label, ll->arr[i].name)) { + 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); + } + } +} + + +/* 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; - BlockCnt *bl = fs->bl; - int upval = 0; - while (bl && !bl->isbreakable) { - upval |= bl->upval; - bl = bl->previous; + Labellist *ll = &ls->dyd->label; + int l; /* index of new label being created */ + checkrepeated(fs, ll, label); /* check for repeated labels */ + checknext(ls, TK_DBCOLON); /* skip double colon */ + /* create new entry for this label */ + l = newlabelentry(ls, ll, label, line, fs->pc); + 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; } - 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)); + findgotos(ls, &ll->arr[l]); } @@ -1000,7 +1239,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 */ @@ -1016,30 +1255,25 @@ 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(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 */ - } + 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 */ } 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.info; + return reg; } @@ -1057,10 +1291,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 +1307,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 +1318,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); @@ -1087,23 +1326,25 @@ 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 = 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); + adjust_assign(ls, 3, explist(ls, &e), &e); luaK_checkstack(fs, 3); /* extra space to call generator */ forbody(ls, base, line, nvars - 3, 0); } @@ -1127,65 +1368,77 @@ 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 */ + skipnoopstat(ls); /* skip other no-op statements */ + 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 */ } static void localfunc (LexState *ls) { - expdesc v, b; + expdesc b; FuncState *fs = ls->fs; - new_localvar(ls, str_checkname(ls), 0); - init_exp(&v, VLOCAL, fs->freereg); - luaK_reserveregs(fs, 1); - adjustlocalvars(ls, 1); - body(ls, &b, 0, ls->linenumber); - luaK_storevar(fs, &v, &b); + 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 */ /* debug information will only see the variable after this point! */ - getlocvar(fs, fs->nactvar - 1).startpc = fs->pc; + getlocvar(fs, b.u.info)->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; 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); + nexps = explist(ls, &e); else { e.k = VVOID; nexps = 0; @@ -1196,26 +1449,26 @@ static void localstat (LexState *ls) { static int funcname (LexState *ls, expdesc *v) { - /* funcname -> NAME {field} [`:' NAME] */ - int needself = 0; + /* funcname -> NAME {fieldsel} [`:' NAME] */ + int ismethod = 0; singlevar(ls, v); while (ls->t.token == '.') - field(ls, v); + fieldsel(ls, v); if (ls->t.token == ':') { - needself = 1; - field(ls, v); + 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 */ } @@ -1225,26 +1478,27 @@ 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 */ + } } static void retstat (LexState *ls) { - /* stat -> RETURN explist */ + /* stat -> RETURN [explist] [';'] */ 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 == ';') + 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? */ @@ -1265,37 +1519,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 ';' */ + 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: { - funcstat(ls, line); /* stat -> funcstat */ - return 0; + case TK_FUNCTION: { /* stat -> funcstat */ + funcstat(ls, line); + break; } case TK_LOCAL: { /* stat -> localstat */ luaX_next(ls); /* skip LOCAL */ @@ -1303,37 +1563,73 @@ static int statement (LexState *ls) { localfunc(ls); else localstat(ls); - return 0; + break; + } + case TK_DBCOLON: { /* stat -> label */ + luaX_next(ls); /* skip double colon */ + 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 */ + case TK_BREAK: /* stat -> breakstat */ + case TK_GOTO: { /* stat -> 'goto' NAME */ + gotostat(ls, luaK_jump(ls->fs)); + break; } - default: { + default: { /* stat -> func | assignment */ exprstat(ls); - return 0; /* to avoid warnings */ + 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); - 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); + +/* +** 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; + 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, 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 cl; /* it's on the stack too */ } -/* }====================================================================== */ diff --git a/src/lparser.h b/src/lparser.h index 18836afd1c..301167d4f5 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.70 2012/05/08 13:53:33 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -23,34 +23,72 @@ 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' */ - VGLOBAL, /* info = index of table; aux = index of global name in `k' */ - VINDEXED, /* info = table register; aux = index register (or `k') */ + VUPVAL, /* info = index of upvalue in 'upvalues' */ + 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' */ } expdesc; -typedef struct upvaldesc { - lu_byte k; - lu_byte info; -} upvaldesc; +/* description of active local variable */ +typedef struct Vardesc { + short idx; /* variable index in stack */ +} Vardesc; + + +/* 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 */ @@ -60,23 +98,22 @@ 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' */ - 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 */ - upvaldesc upvalues[LUAI_MAXUPVALUES]; /* upvalues */ - unsigned short actvar[LUAI_MAXVARS]; /* declared-variable stack */ + lu_byte nups; /* number of upvalues */ + lu_byte freereg; /* first free register */ } FuncState; -LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, - const char *name); +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 4313b83a0c..3c00c28559 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,17 +1,19 @@ /* -** $Id: lstate.c,v 2.36.1.2 2008/01/03 15:20:39 roberto Exp $ +** $Id: lstate.c,v 2.98 2012/05/30 12:33:44 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ #include +#include #define lstate_c #define LUA_CORE #include "lua.h" +#include "lapi.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" @@ -24,119 +26,236 @@ #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 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 + + +#define MEMERRMSG "not enough memory" + + +/* +** a macro to help the creation of a unique random seed when a state is +** created; the seed is used to randomize hashes. +*/ +#if !defined(luai_makeseed) +#include +#define luai_makeseed() cast(size_t, time(NULL)) +#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))) + + +/* +** Compute an initial seed as random as possible. In ANSI, rely on +** Address Space Layout Randomization (if present) to increase +** randomness.. +*/ +#define addbuff(b,p,e) \ + { size_t t = cast(size_t, e); \ + memcpy(buff + p, &t, sizeof(t)); p += sizeof(t); } + +static unsigned int makeseed (lua_State *L) { + char buff[4 * sizeof(size_t)]; + unsigned int h = luai_makeseed(); + int p = 0; + addbuff(buff, p, L); /* heap variable */ + addbuff(buff, p, &h); /* local variable */ + addbuff(buff, p, luaO_nilobject); /* global variable */ + addbuff(buff, p, &lua_newstate); /* public function */ + lua_assert(p == sizeof(buff)); + return luaS_hash(buff, p, h); +} + + +/* +** set GCdebt to a new value keeping the value (totalbytes + GCdebt) +** invariant +*/ +void luaE_setdebt (global_State *g, l_mem debt) { + g->totalbytes -= (debt - g->GCdebt); + g->GCdebt = debt; +} + + +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; CallInfo *ci; /* 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; - L1->ci->top = L1->top + LUA_MINSTACK; + ci = &L1->base_ci; + ci->next = ci->previous = NULL; + ci->callstatus = 0; + ci->func = L1->top; + setnilvalue(L1->top++); /* 'function' entry for this 'ci' */ + ci->top = L1->top + LUA_MINSTACK; + L1->ci = ci; +} + + +static void freestack (lua_State *L) { + 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); /* free stack array */ } -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) { + 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); + luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &mt); + /* registry[LUA_RIDX_GLOBALS] = table of globals */ + sethvalue(L, &mt, luaH_new(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 */ + 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->gcrunning = 1; /* allow gc */ } +/* +** 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; + L->ci = NULL; L->stacksize = 0; L->errorJmp = NULL; + L->nCcalls = 0; L->hook = NULL; L->hookmask = 0; L->basehookcount = 0; 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->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); - lua_assert(g->totalbytes == sizeof(LG)); - (*g->frealloc)(g->ud, fromstate(L), state_size(LG), 0); + freestack(L); + lua_assert(gettotalbytes(g) == sizeof(LG)); + (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ } -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))); + luai_userstatethread(L, L1); + stack_init(L1, L); /* init stack */ + lua_unlock(L); 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)); + luai_userstatefree(L, L1); + freestack(L1); + luaM_free(L, l); } @@ -144,42 +263,45 @@ 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, LUA_TTHREAD, 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); - set2bits(L->marked, FIXEDBIT, SFIXEDBIT); + g->gckind = KGC_NORMAL; preinit_state(L, g); g->frealloc = f; g->ud = ud; g->mainthread = L; + g->seed = makeseed(L); g->uvhead.u.l.prev = &g->uvhead; g->uvhead.u.l.next = &g->uvhead; - g->GCthreshold = 0; /* mark it as unfinished state */ + g->gcrunning = 0; /* no GC while building state */ + g->GCestimate = 0; g->strt.size = 0; g->strt.nuse = 0; g->strt.hash = NULL; - setnilvalue(registry(L)); + setnilvalue(&g->l_registry); 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->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); + g->GCdebt = 0; g->gcpause = LUAI_GCPAUSE; + g->gcmajorinc = LUAI_GCMAJOR; g->gcstepmul = LUAI_GCMUL; - g->gcdept = 0; - for (i=0; imt[i] = NULL; - if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { + 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); L = NULL; @@ -190,25 +312,11 @@ 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); luai_userstateclose(L); close_state(L); } + diff --git a/src/lstate.h b/src/lstate.h index 3bc575b6bc..29f810ba04 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.81 2012/06/08 15:14:04 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -14,26 +14,47 @@ #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->allgc. 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.) +** +** Objects with finalizers are kept in the list g->finobj. +** +** The list g->tobefnz links all objects 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 */ #define EXTRA_STACK 5 -#define BASIC_CI_SIZE 8 - #define BASIC_STACK_SIZE (2*LUA_MINSTACK) +/* kinds of Garbage Collection */ +#define KGC_NORMAL 0 +#define KGC_EMERGENCY 1 /* gc was forced by an allocation failure */ +#define KGC_GEN 2 /* generational collection */ + typedef struct stringtable { GCObject **hash; @@ -43,54 +64,87 @@ typedef struct stringtable { /* -** informations about a call +** information 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 this function */ + lu_byte callstatus; + ptrdiff_t extra; + 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; + 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 CIST_HOOKYIELD (1<<7) /* last hook called yielded */ + -#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) /* ** `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 - GCdebt */ + l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ + 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 */ 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 *rootgc; /* list of all collectable objects */ - GCObject **sweepgc; /* position of sweep in `rootgc' */ + GCObject *allgc; /* list of all collectable objects */ + GCObject *finobj; /* list of collectable objects with finalizers */ + 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 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; - 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' */ + 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 */ + 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 */ - 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 */ + const lua_Number *version; /* pointer to version number */ + 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; @@ -101,29 +155,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 nny; /* number of non-yieldable calls in stack */ 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; 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 +183,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 +194,35 @@ 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 rawgco2ts(o) \ + check_exp(novariant((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 gco2lcl(o) check_exp((o)->gch.tt == LUA_TLCL, &((o)->cl.l)) +#define gco2ccl(o) check_exp((o)->gch.tt == LUA_TCCL, &((o)->cl.c)) +#define gco2cl(o) \ + check_exp(novariant((o)->gch.tt) == LUA_TFUNCTION, &((o)->cl)) +#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); +/* 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); + #endif diff --git a/src/lstring.c b/src/lstring.c index 49113151cc..8b959f19d0 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.24 2012/05/11 14:14:42 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -18,78 +18,157 @@ #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 (a == b) || /* same instance or... */ + ((len == b->tsv.len) && /* equal length and ... */ + (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ +} + + +/* +** equality for strings +*/ +int luaS_eqstr (TString *a, TString *b) { + return (a->tsv.tt == b->tsv.tt) && + (a->tsv.tt == LUA_TSHRSTR ? eqshrstr(a, b) : luaS_eqlngstr(a, b)); +} + +unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) { + unsigned int h = seed ^ l; + size_t 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; +} + + +/* +** resizes the string table +*/ 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; + resetoldbit(p); /* see MOVE OLD rule */ 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) { +/* +** creates a new string object +*/ +static TString *createstrobj (lua_State *L, const char *str, size_t l, + int tag, unsigned int h, GCObject **list) { 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))); + size_t totalsize; /* total size of TString object */ + totalsize = sizeof(TString) + ((l + 1) * sizeof(char)); + ts = &luaC_newobj(L, tag, 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; + ts->tsv.extra = 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; } -TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { +/* +** creates a new short string, inserting it into string table +*/ +static TString *newshrstr (lua_State *L, const char *str, size_t l, + unsigned int h) { + GCObject **list; /* (pointer to) list where it will be inserted */ + stringtable *tb = &G(L)->strt; + TString *s; + if (tb->nuse >= cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) + luaS_resize(L, tb->size*2); /* too crowded */ + list = &tb->hash[lmod(h, tb->size)]; + s = createstrobj(L, str, l, LUA_TSHRSTR, h, list); + tb->nuse++; + return s; +} + + +/* +** checks whether short string exists and reuses it or creates a new one +*/ +static TString *internshrstr (lua_State *L, const char *str, size_t l) { GCObject *o; - 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 */ - h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1])); - for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; + global_State *g = G(L); + unsigned int h = luaS_hash(str, l, g->seed); + for (o = g->strt.hash[lmod(h, g->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 * sizeof(char)) == 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 newshrstr(L, str, l, h); /* not found; create a new string */ +} + + +/* +** new string (with explicit length) +*/ +TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { + if (l <= LUAI_MAXSHORTLEN) /* short string? */ + return internshrstr(L, str, l); + else { + if (l + 1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) + luaM_toobig(L); + return createstrobj(L, str, l, LUA_TLNGSTR, G(L)->seed, NULL); + } +} + + +/* +** new zero-terminated string +*/ +TString *luaS_new (lua_State *L, const char *str) { + return luaS_newlstr(L, str, strlen(str)); } @@ -97,15 +176,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..d312ff3d2b 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.49 2012/02/01 21:57:15 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,31 @@ #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) + +/* +** test whether a string is a reserved word +*/ +#define isreserved(s) ((s)->tsv.tt == LUA_TSHRSTR && (s)->tsv.extra > 0) + + +/* +** equality for short strings, which are always internalized +*/ +#define eqshrstr(a,b) check_exp((a)->tsv.tt == LUA_TSHRSTR, (a) == (b)) + + +LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed); +LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); +LUAI_FUNC int luaS_eqstr (TString *a, TString *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 7a03489beb..e13098bb6e 100644 --- a/src/lstrlib.c +++ b/src/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.132.1.5 2010/05/14 15:34:19 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 */ @@ -20,47 +20,58 @@ #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)) +#define uchar(c) ((unsigned char)(c)) 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 (0u - (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; } 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; } @@ -70,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; i> 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; + 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); + } return 1; } @@ -106,15 +133,15 @@ 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? */ - luaL_error(L, "string slice too long"); + 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; i= 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; } @@ -202,16 +230,16 @@ static int capture_to_close (MatchState *ms) { static const char *classend (MatchState *ms, const char *p) { switch (*p++) { case L_ESC: { - if (*p == '\0') + if (p == ms->p_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; @@ -229,13 +257,14 @@ 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; 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); @@ -280,8 +309,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; @@ -364,6 +394,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? */ @@ -374,7 +406,12 @@ 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 '$': { + 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); @@ -393,27 +430,19 @@ 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: goto 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 suffix */ 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; @@ -492,37 +521,56 @@ static int push_captures (MatchState *ms, const char *s, const char *e) { } +/* check whether pattern has no special characters */ +static int nospecials (const char *p, size_t l) { + size_t upto = 0; + do { + if (strpbrk(p + upto, SPECIALS)) + return 0; /* pattern has a special character */ + upto += strlen(p + upto) + 1; /* may have more after \0 */ + } while (upto <= l); + return 1; /* no special chars found */ +} + + 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 (find && (lua_toboolean(L, 4) || /* explicit request? */ - strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */ + 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 > ls + 1) { /* start after string's end? */ + lua_pushnil(L); /* cannot find anything */ + return 1; + } + /* explicit request or no special characters? */ + if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { /* do a plain search */ - const char *s2 = lmemfind(s+init, l1-init, 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 + 1); + lua_pushinteger(L, s2 - s + lp); return 2; } } else { MatchState ms; - int anchor = (*p == '^') ? (p++, 1) : 0; - const char *s1=s+init; + 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; 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 @@ -547,13 +595,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++) { @@ -581,12 +630,6 @@ static int gmatch (lua_State *L) { } -static int gfind_nodef (lua_State *L) { - return luaL_error(L, LUA_QL("string.gfind") " was renamed to " - LUA_QL("string.gmatch")); -} - - static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, const char *e) { size_t l, i; @@ -596,8 +639,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 +657,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,41 +672,49 @@ 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 */ } 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); - int tr = lua_type(L, 3); - int max_s = luaL_optint(L, 4, srcl+1); - int anchor = (*p == '^') ? (p++, 1) : 0; - int n = 0; + 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 == '^'); + size_t 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); + 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; 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 +732,46 @@ static int str_gsub (lua_State *L) { /* }====================================================== */ + +/* +** {====================================================== +** 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_INTFRMLEN) /* { */ +#if defined(LUA_USE_LONGLONG) + +#define LUA_INTFRMLEN "ll" +#define LUA_INTFRM_T long long + +#else + +#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 + + /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ #define MAX_ITEM 512 /* valid flags in a format specification */ @@ -698,25 +788,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 (!isdigit(uchar(*(s+1)))) + sprintf(buff, "\\%d", (int)uchar(*s)); + else + sprintf(buff, "\\%03d", (int)uchar(*s)); + luaL_addstring(b, buff); + } + else + luaL_addchar(b, *s); s++; } luaL_addchar(b, '"'); @@ -725,7 +810,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 (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ - if ((size_t)(p - strfrmt) >= 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) */ @@ -737,19 +822,23 @@ 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) * sizeof(char)); form += p - strfrmt + 1; *form = '\0'; return p; } -static void addintlen (char *form) { +/* +** add length modifier into formats +*/ +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'; } @@ -768,46 +857,61 @@ 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 */ + 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, (int)luaL_checknumber(L, arg)); + nb = sprintf(buff, form, luaL_checkint(L, arg)); break; } case 'd': case 'i': { - addintlen(form); - sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg)); + lua_Number n = luaL_checknumber(L, 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, ni); break; } case 'o': case 'u': case 'x': case 'X': { - addintlen(form); - sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg)); + lua_Number n = luaL_checknumber(L, 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, ni); break; } case 'e': case 'E': case 'f': +#if defined(LUA_USE_AFORMAT) + case 'a': case 'A': +#endif case 'g': case 'G': { - 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': { addquoted(L, &b, arg); - continue; /* skip the 'addsize' at the end */ + break; } 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); - continue; /* skip the `addsize' at the end */ + break; } else { - sprintf(buff, form, s); + nb = sprintf(buff, form, s); + lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ break; } } @@ -816,13 +920,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}, @@ -830,7 +936,6 @@ static const luaL_Reg strlib[] = { {"dump", str_dump}, {"find", str_find}, {"format", str_format}, - {"gfind", gfind_nodef}, {"gmatch", gmatch}, {"gsub", str_gsub}, {"len", str_len}, @@ -845,13 +950,13 @@ static const luaL_Reg strlib[] = { static void createmetatable (lua_State *L) { - lua_createtable(L, 0, 1); /* create metatable for strings */ + lua_createtable(L, 0, 1); /* table to be metatable for strings */ lua_pushliteral(L, ""); /* dummy string */ - lua_pushvalue(L, -2); - lua_setmetatable(L, -2); /* set string metatable */ + lua_pushvalue(L, -2); /* copy table */ + lua_setmetatable(L, -2); /* set table as 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_pushvalue(L, -2); /* get string library */ + lua_setfield(L, -2, "__index"); /* metatable.__index = string */ lua_pop(L, 1); /* pop metatable */ } @@ -859,12 +964,8 @@ static void createmetatable (lua_State *L) { /* ** Open string library */ -LUALIB_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 +LUAMOD_API int luaopen_string (lua_State *L) { + luaL_newlib(L, strlib); createmetatable(L); return 1; } diff --git a/src/ltable.c b/src/ltable.c index ec84f4fabc..ffa5ecb36a 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.71 2012/05/23 15:37:09 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 @@ -32,14 +31,16 @@ #include "lmem.h" #include "lobject.h" #include "lstate.h" +#include "lstring.h" #include "ltable.h" +#include "lvm.h" /* ** 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 @@ -47,10 +48,10 @@ #define MAXASIZE (1 << MAXBITS) -#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 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) /* @@ -63,18 +64,13 @@ #define hashpointer(t,p) hashmod(t, IntPoint(p)) -/* -** number of ints inside a lua_Number -*/ -#define numints cast_int(sizeof(lua_Number)/sizeof(int)) - - - #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 +78,14 @@ 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) { + if (cast(unsigned int, i) == 0u - i) /* use unsigned to avoid overflows */ + i = 0; /* handle INT_MIN */ + i = -i; /* must be a positive value */ + } + return hashmod(t, i); } @@ -101,12 +98,22 @@ static Node *mainposition (const Table *t, const TValue *key) { switch (ttype(key)) { case LUA_TNUMBER: return hashnum(t, nvalue(key)); - case LUA_TSTRING: + case LUA_TLNGSTR: { + TString *s = rawtsvalue(key); + if (s->tsv.extra == 0) { /* no hash? */ + s->tsv.hash = luaS_hash(getstr(s), s->tsv.len, s->tsv.hash); + s->tsv.extra = 1; /* now it has its hash */ + } + return hashstr(t, rawtsvalue(key)); + } + case LUA_TSHRSTR: return hashstr(t, rawtsvalue(key)); case LUA_TBOOLEAN: 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)); } @@ -132,7 +139,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; @@ -142,19 +149,19 @@ static int findindex (lua_State *L, Table *t, StkId key) { return i-1; /* yes; that's the index (corrected to C) */ else { Node *n = mainposition(t, key); - do { /* check whether `key' is somewhere in the chain */ + for (;;) { /* 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))) { + if (luaV_rawequalobj(gkey(n), key) || + (ttisdeadkey(gkey(n)) && iscollectable(key) && + deadvalue(gkey(n)) == gcvalue(key))) { i = cast_int(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 to " LUA_QL("next")); /* key not found */ - return 0; /* to avoid warnings */ + if (n == NULL) + luaG_runerror(L, "invalid key to " LUA_QL("next")); /* key not found */ + } } } @@ -170,7 +177,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; } @@ -211,7 +218,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 @@ -251,7 +258,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++; } } @@ -277,7 +284,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 +301,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 +309,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]); + luaH_setint(L, t, i + 1, &t->array[i]); } /* shrink array */ luaM_reallocvector(L, t->array, oldasize, nasize, TValue); @@ -316,23 +323,26 @@ static void 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))) - setobjt2t(L, luaH_set(L, t, key2tval(old)), 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 (nold != dummynode) - luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */ + if (!isdummy(nold)) + luaM_freearray(L, nold, cast(size_t, 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); } 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 */ @@ -345,7 +355,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 +365,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, cast(size_t, 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,23 +396,28 @@ 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) { +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(n != dummynode); - othern = mainposition(t, key2tval(mp)); + lua_assert(!isdummy(n)); + 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 */ @@ -422,8 +433,8 @@ static TValue *newkey (lua_State *L, Table *t, const TValue *key) { mp = n; } } - gkey(mp)->value = key->value; gkey(mp)->tt = key->tt; - luaC_barriert(L, t, key); + setobj2t(L, gkey(mp), key); + luaC_barrierback(L, obj2gco(t), key); lua_assert(ttisnil(gval(mp))); return gval(mp); } @@ -432,7 +443,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]; @@ -450,12 +461,13 @@ const TValue *luaH_getnum (Table *t, int key) { /* -** search function for strings +** search function for short strings */ const TValue *luaH_getstr (Table *t, TString *key) { Node *n = hashstr(t, key); + lua_assert(key->tsv.tt == LUA_TSHRSTR); do { /* check whether `key' is somewhere in the chain */ - if (ttisstring(gkey(n)) && rawtsvalue(gkey(n)) == key) + if (ttisshrstring(gkey(n)) && eqshrstr(rawtsvalue(gkey(n)), key)) return gval(n); /* that's it */ else n = gnext(n); } while (n); @@ -469,19 +481,19 @@ 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_TSHRSTR: return luaH_getstr(t, rawtsvalue(key)); 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? */ - return luaH_getnum(t, k); /* use specialized version */ + return luaH_getint(t, k); /* use specialized version */ /* else go through */ } default: { Node *n = mainposition(t, key); do { /* check whether `key' is somewhere in the chain */ - if (luaO_rawequalObj(key2tval(n), key)) + if (luaV_rawequalobj(gkey(n), key)) return gval(n); /* that's it */ else n = gnext(n); } while (n); @@ -491,41 +503,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(nvalue(key))) - luaG_runerror(L, "table index is NaN"); - return newkey(L, t, key); - } + else return luaH_newkey(L, t, key); } -TValue *luaH_setnum (lua_State *L, Table *t, int key) { - const TValue *p = luaH_getnum(t, 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); } @@ -533,20 +533,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 +570,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 +583,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..2f6f5c2dc8 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.16 2011/08/17 20:26:47 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) +#define invalidateTMcache(t) ((t)->flags = 0) -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 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, 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..a52add03da 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.63 2011/11/28 17:26:30 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -16,43 +16,11 @@ #include "lualib.h" -#define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n)) - - -static int 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_pushinteger(L, 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 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); - if (!lua_isnil(L, -1)) - return 1; - lua_pop(L, 2); /* remove value and result */ - } - return 0; -} +#define aux_getn(L,n) \ + (luaL_checktype(L, n, LUA_TTABLE), luaL_len(L, n)) +#if defined(LUA_COMPAT_MAXN) static int maxn (lua_State *L) { lua_Number max = 0; luaL_checktype(L, 1, LUA_TTABLE); @@ -67,24 +35,7 @@ static int maxn (lua_State *L) { lua_pushnumber(L, max); return 1; } - - -static int getn (lua_State *L) { - lua_pushinteger(L, aux_getn(L, 1)); - return 1; -} - - -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) { @@ -109,7 +60,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 +69,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 0) { /* at least one element? */ + int i; + lua_pushvalue(L, 1); + lua_rawseti(L, -2, 1); /* insert first element */ + lua_replace(L, 1); /* move table into index 1 */ + for (i = n; i >= 2; i--) /* assign other elements */ + lua_rawseti(L, 1, i); + } + return 1; /* return table */ +} + + +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, 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 */ + 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 +178,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 +215,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 (jmetatable; break; @@ -68,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 64343b781b..89bdc19a1e 100644 --- a/src/ltm.h +++ b/src/ltm.h @@ -1,5 +1,5 @@ /* -** $Id: ltm.h,v 2.6.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: ltm.h,v 2.11 2011/02/28 17:32:10 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -20,6 +20,7 @@ typedef enum { TM_NEWINDEX, TM_GC, TM_MODE, + TM_LEN, TM_EQ, /* last tag method with `fast' access */ TM_ADD, TM_SUB, @@ -28,7 +29,6 @@ typedef enum { TM_MOD, TM_POW, TM_UNM, - TM_LEN, TM_LT, TM_LE, TM_CONCAT, @@ -43,7 +43,10 @@ typedef enum { #define fasttm(l,et,e) gfasttm(G(l), et, e) -LUAI_DATA const char *const luaT_typenames[]; +#define ttypename(x) luaT_typenames_[(x) + 1] +#define objtypename(x) ttypename(ttypenv(x)) + +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 3a46609328..7614c7030b 100644 --- a/src/lua.c +++ b/src/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.160.1.2 2007/12/28 15:32:23 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 */ @@ -18,6 +18,72 @@ #include "lualib.h" +#if !defined(LUA_PROMPT) +#define LUA_PROMPT "> " +#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) +#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 +** 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; @@ -39,77 +105,87 @@ static void laction (int i) { } -static void print_usage (void) { - fprintf(stderr, - "usage: %s [options] [script [args]].\n" +static void print_usage (const char *badoption) { + luai_writestringerror("%s: ", progname); + if (badoption[1] == 'e' || badoption[1] == 'l') + luai_writestringerror("'%s' needs argument\n", badoption); + else + 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" + " -E ignore environment variables\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); } 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; } -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 */ - /* 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); + luai_writestring(LUA_COPYRIGHT, strlen(LUA_COPYRIGHT)); + luai_writeline(); } @@ -132,40 +208,48 @@ 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, 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) || docall(L, 0, 1); + int status = luaL_loadbuffer(L, s, strlen(s), name); + if (status == LUA_OK) status = docall(L, 0, 0); return report(L, status); } static int dolibrary (lua_State *L, const char *name) { + int status; lua_getglobal(L, "require"); lua_pushstring(L, name); - return report(L, docall(L, 1, 1)); + status = docall(L, 1, 1); /* call 'require(name)' */ + if (status == LUA_OK) + lua_setglobal(L, name); /* global[name] = require return */ + return report(L, status); } static const char *get_prompt (lua_State *L, int firstline) { const char *p; - lua_getfield(L, LUA_GLOBALSINDEX, 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 */ return p; } +/* mark in error messages for incomplete statements */ +#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); - const char *tp = msg + lmsg - (sizeof(LUA_QL("")) - 1); - if (strstr(msg, LUA_QL("")) == tp) { + if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0) { lua_pop(L, 1); return 1; } @@ -199,7 +283,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,20 +304,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, LUA_MULTRET); report(L, status); - if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ + if (status == LUA_OK && lua_gettop(L) > 0) { /* any result to print? */ + luaL_checkstack(L, LUA_MINSTACK, "too many results to print"); lua_getglobal(L, "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); - fflush(stdout); + luai_writeline(); progname = oldprogname; } @@ -242,49 +328,63 @@ static int handle_script (lua_State *L, char **argv, int n) { int narg = getargs(L, argv, n); /* collect arguments */ lua_setglobal(L, "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) - status = docall(L, narg, 0); + if (status == LUA_OK) + status = docall(L, narg, LUA_MULTRET); 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) { +/* 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? */ 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 'E': + args[has_E] = 1; + break; case 'i': - notail(argv[i]); - *pi = 1; /* go through */ + noextrachars(argv[i]); + args[has_i] = 1; /* go through */ case 'v': - notail(argv[i]); - *pv = 1; + noextrachars(argv[i]); + args[has_v] = 1; break; case 'e': - *pe = 1; /* go through */ - case 'l': - if (argv[i][2] == '\0') { - i++; - if (argv[i] == NULL) return -1; + 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' */ + if (argv[i] == NULL || argv[i][0] == '-') + return -(i - 1); /* no next argument or it is another option */ } break; - default: return -1; /* invalid option */ + default: /* invalid option; return its index... */ + return -i; /* ...as a negative value */ } } return 0; @@ -294,99 +394,103 @@ 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': { 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 *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); + return dostring(L, init, name); } -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 = (int)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; + 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, args); + if (script < 0) { /* invalid arg? */ + print_usage(argv[-script]); + return 0; + } + if (args[has_v]) print_version(); + if (args[has_E]) { /* option '-E'? */ + lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */ + lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); + } + /* 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); - 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) + if (!args[has_E] && handle_luainit(L) != LUA_OK) + return 0; /* error running LUA_INIT */ + /* 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 (args[has_i]) /* -i option? */ dotty(L); - else if (script == 0 && !has_e && !has_v) { + else if (script == 0 && !args[has_e] && !args[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 */ + 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_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); - 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 a4b73e743e..a3a3a70c69 100644 --- a/src/lua.h +++ b/src/lua.h @@ -1,6 +1,6 @@ /* -** $Id: lua.h,v 1.218.1.7 2012/01/13 20:36:20 roberto Exp $ -** Lua - An Extensible Extension Language +** $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 */ @@ -16,35 +16,39 @@ #include "luaconf.h" -#define LUA_VERSION "Lua 5.1" -#define LUA_RELEASE "Lua 5.1.5" -#define LUA_VERSION_NUM 501 -#define LUA_COPYRIGHT "Copyright (C) 1994-2012 Lua.org, PUC-Rio" -#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" +#define LUA_VERSION_MAJOR "5" +#define LUA_VERSION_MINOR "2" +#define LUA_VERSION_NUM 502 +#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-2012 Lua.org, 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' */ +/* mark for precompiled code ('Lua') */ +#define LUA_SIGNATURE "\033Lua" + +/* 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_upvalueindex(i) (LUA_REGISTRYINDEX - (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; @@ -81,18 +85,18 @@ 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 */ #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_GLOBALS 2 +#define LUA_RIDX_LAST LUA_RIDX_GLOBALS /* type of numbers in Lua */ @@ -102,6 +106,18 @@ typedef LUA_NUMBER lua_Number; /* type for integer functions */ typedef LUA_INTEGER lua_Integer; +/* unsigned integer type */ +typedef LUA_UNSIGNED lua_Unsigned; + + + +/* +** generic extra include file +*/ +#if defined(LUA_USER_H) +#include LUA_USER_H +#endif + /* @@ -114,15 +130,20 @@ 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 */ +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); 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 +160,49 @@ 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 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_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 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, va_list argp); LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); @@ -174,35 +215,47 @@ 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); -LUA_API void (lua_getfenv) (lua_State *L, int idx); +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 int (lua_setfenv) (lua_State *L, int idx); +LUA_API void (lua_setuservalue) (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); + const char *chunkname, + const char *mode); LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data); @@ -210,8 +263,10 @@ 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_resume) (lua_State *L, int narg); +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, lua_State *from, int narg); LUA_API int (lua_status) (lua_State *L); /* @@ -226,6 +281,10 @@ LUA_API int (lua_status) (lua_State *L); #define LUA_GCSTEP 5 #define LUA_GCSETPAUSE 6 #define LUA_GCSETSTEPMUL 7 +#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); @@ -239,18 +298,23 @@ 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 ** =============================================================== */ +#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) #define lua_newtable(L) lua_createtable(L, 0, 0) @@ -259,8 +323,6 @@ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud); #define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) -#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) #define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) @@ -273,31 +335,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 +356,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,43 +370,50 @@ 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 */ }; /* }====================================================================== */ /****************************************************************************** -* Copyright (C) 1994-2012 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/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..5081836d4c 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.69 2011/11/29 17:46:33 lhf Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ @@ -15,16 +15,15 @@ #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 */ +#define OUTPUT PROGNAME ".out" /* default output file */ static int listing=0; /* list bytecodes? */ static int dumping=1; /* dump bytecodes? */ @@ -52,20 +51,20 @@ 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" - " - 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); + "usage: %s [options] [filenames]\n" + "Available options are:\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" + " -v show version information\n" + " -- stop handling options\n" + " - stop handling options and process stdin\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[]) { @@ -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) 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 */ @@ -108,13 +108,30 @@ 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; } -#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,16 @@ 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; + Proto* f; + int i=n; + if (lua_load(L,reader,&i,"=(" PROGNAME ")",NULL)!=LUA_OK) fatal(lua_tostring(L,-1)); + f=toproto(L,-1); 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); + if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0; } - f->code[pc++]=CREATE_ABC(OP_RETURN,0,1,0); + f->sizelineinfo=0; return f; } } @@ -150,23 +159,17 @@ 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=(int)lua_tointeger(L,1); + char** argv=(char**)lua_touserdata(L,2); const Proto* f; int i; if (!lua_checkstack(L,argc)) fatal("too many input files"); for (i=0; i1); @@ -186,15 +189,244 @@ static int pmain(lua_State* L) 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)); + L=luaL_newstate(); + if (L==NULL) fatal("cannot create state: not enough memory"); + lua_pushcfunction(L,&pmain); + lua_pushinteger(L,argc); + lua_pushlightuserdata(L,argv); + 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.68 2011/09/30 10:21:20 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 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) : "-") +#define MYK(x) (-1-(x)) + +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) ? (MYK(INDEXK(b))) : b); + if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (MYK(INDEXK(c))) : c); + break; + case iABx: + printf("%d",a); + if (getBMode(o)==OpArgK) printf(" %d",MYK(bx)); + if (getBMode(o)==OpArgU) printf(" %d",bx); + break; + case iAsBx: + printf("%d %d",a,sbx); + break; + case iAx: + printf("%d",MYK(ax)); + break; + } + switch (o) + { + case OP_LOADK: + printf("\t; "); PrintConstant(f,bx); + 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 e2cb26163a..e4335df904 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.172 2012/05/11 14:14:42 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -24,30 +24,44 @@ ** 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 -#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) +#define LUA_DL_DLL +#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ +#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 */ +#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_DL_DYLD /* does not need extra library */ +#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 /* -@@ 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. */ @@ -56,20 +70,10 @@ #define LUA_USE_ISATTY #define LUA_USE_POPEN #define LUA_USE_ULONGJMP +#define LUA_USE_GMTIME_R #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 @@ -80,7 +84,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. @@ -88,21 +92,23 @@ #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 +#else /* }{ */ + +#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR "/" #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/" LUA_VDIR +#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR #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" -#endif + LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so" +#endif /* } */ /* @@ -118,79 +124,67 @@ /* -@@ 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. +@@ 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_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 +#define LUA_ENV "_ENV" /* @@ 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 ** 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 +#else /* }{ */ #define LUA_API extern -#endif +#endif /* } */ + /* 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. -*/ -#if defined(luaall_c) -#define LUAI_FUNC static -#define LUAI_DATA /* empty */ - -#elif defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ - defined(__ELF__) +** 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(__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 +#else /* }{ */ #define LUAI_FUNC extern -#define LUAI_DATA extern -#endif +#define LUAI_DDEC extern +#define LUAI_DDEF /* empty */ +#endif /* } */ @@ -211,175 +205,108 @@ /* -** {================================================================== -** Stand-alone configuration -** =================================================================== +@@ 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_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 +#if defined(LUA_LIB) || defined(lua_c) #include -#define lua_stdin_is_tty() _isatty(_fileno(stdin)) -#else -#define lua_stdin_is_tty() 1 /* assume stdin is a tty */ +#define luai_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) +#define luai_writeline() (luai_writestring("\n", 1), fflush(stdout)) #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.) +@@ luai_writestringerror defines how to print error messages. +** (A format string with one argument is enough for Lua...) */ -#define LUA_PROMPT "> " -#define LUA_PROMPT2 ">> " +#define luai_writestringerror(s,p) \ + (fprintf(stderr, (s), (p)), fflush(stderr)) /* -@@ 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. +@@ 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 LUA_PROGNAME "lua" +#define LUAI_MAXSHORTLEN 40 -/* -@@ LUA_MAXINPUT is the maximum length for an input line in the -@* stand-alone interpreter. -** CHANGE it if you need longer lines. -*/ -#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). +** {================================================================== +** Compatibility with previous versions +** =================================================================== */ -#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 - -/* }================================================================== */ - /* -@@ 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_ALL controls all compatibility options. +** You can define it to get all options, or change specific options +** to fit your specific needs. */ -#define LUAI_GCPAUSE 200 /* 200% (wait memory to double before next GC) */ - +#if defined(LUA_COMPAT_ALL) /* { */ /* -@@ 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_UNPACK controls the presence of global 'unpack'. +** You can replace it with 'table.unpack'. */ -#define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */ - - +#define LUA_COMPAT_UNPACK /* -@@ 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_LOADERS controls the presence of table 'package.loaders'. +** You can replace it with 'package.searchers'. */ -#undef LUA_COMPAT_GETN +#define LUA_COMPAT_LOADERS /* -@@ 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'). +@@ macro 'lua_cpcall' emulates deprecated function lua_cpcall. +** You can call your C function directly (with light C functions). */ -#undef LUA_COMPAT_LOADLIB +#define lua_cpcall(L,f,u) \ + (lua_pushcfunction(L, (f)), \ + lua_pushlightuserdata(L,(u)), \ + lua_pcall(L,1,0,0)) -/* -@@ 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_VARARG /* -@@ 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'. +@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library. +** You can rewrite 'log10(x)' as 'log(x, 10)'. */ -#define LUA_COMPAT_MOD +#define LUA_COMPAT_LOG10 /* -@@ 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 [[...]]. +@@ LUA_COMPAT_LOADSTRING defines the function 'loadstring' in the base +** library. You can rewrite 'loadstring(s)' as 'load(s)'. */ -#define LUA_COMPAT_LSTR 1 +#define LUA_COMPAT_LOADSTRING /* -@@ LUA_COMPAT_GFIND controls compatibility with old 'string.gfind' name. -** CHANGE it to undefined as soon as you rename 'string.gfind' to -** 'string.gmatch'. +@@ LUA_COMPAT_MAXN defines the function 'maxn' in the table library. */ -#define LUA_COMPAT_GFIND +#define LUA_COMPAT_MAXN /* -@@ 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' +@@ 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_OPENLIB +#define lua_strlen(L,i) lua_rawlen(L, (i)) +#define lua_objlen(L,i) lua_rawlen(L, (i)) +#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) /* -@@ 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. +@@ LUA_COMPAT_MODULE controls compatibility with previous +** module functions 'module' (Lua) and 'luaL_register' (C). */ -#if defined(LUA_USE_APICHECK) -#include -#define luai_apicheck(L,o) { (void)L; assert(o); } -#else -#define luai_apicheck(L,o) { (void)L; } -#endif +#define LUA_COMPAT_MODULE + +#endif /* } */ + +/* }================================================================== */ + /* @@ -388,107 +315,62 @@ ** 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 /* } */ /* -@@ 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 +#if LUAI_BITSINT >= 32 /* { */ +#define LUA_INT32 int #define LUAI_UMEM size_t #define LUAI_MEM ptrdiff_t -#else +#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 +#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 - - -/* -@@ 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 - - - -/* -** {================================================================== -** 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. -** =================================================================== -*/ - +#if LUAI_BITSINT >= 32 +#define LUAI_MAXSTACK 1000000 +#else +#define LUAI_MAXSTACK 15000 +#endif -/* -@@ LUAI_MAXCCALLS is the maximum depth for nested C calls (short) and -@* syntactical nested non-terminals in a program. -*/ -#define LUAI_MAXCCALLS 200 +/* reserve some space for error handling */ +#define LUAI_FIRSTPSEUDOIDX (-LUAI_MAXSTACK - 1000) -/* -@@ 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. +** CHANGE it if it uses too much C-stack space. */ #define LUAL_BUFFERSIZE BUFSIZ -/* }================================================================== */ - @@ -516,237 +398,138 @@ @@ 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)) /* -@@ The luai_num* macros define the primitive operations over numbers. +@@ 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. */ -#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)) -#define luai_numisnan(a) (!luai_numeq((a), (a))) +#define lua_str2number(s,p) strtod((s), (p)) + +#if defined(LUA_USE_STRTODHEX) +#define lua_strx2number(s,p) strtod((s), (p)) #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. +@@ The luai_num* macros define the primitive operations over numbers. */ -/* On a Pentium, resort to a trick */ -#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \ - (defined(__i386) || defined (_M_IX86) || defined(__i386__)) - -/* On a Microsoft compiler, use assembler */ -#if defined(_MSC_VER) - -#define lua_number2int(i,d) __asm fld d __asm fistp i -#define lua_number2integer(i,n) lua_number2int(i, n) - -/* 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) - +/* 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)) #endif - -/* 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)) - +/* 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(L,a,b) ((a)<(b)) +#define luai_numle(L,a,b) ((a)<=(b)) +#define luai_numisnan(L,a) (!luai_numeq((a), (a))) #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. +@@ 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 LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; } - +#define LUA_INTEGER ptrdiff_t /* -@@ 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. +@@ LUA_UNSIGNED is the integral type used by lua_pushunsigned/lua_tounsigned. +** It must have at least 32 bits. */ -#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 +#define LUA_UNSIGNED unsigned LUA_INT32 -#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. +** Some tricks with doubles */ -#define LUA_MAXCAPTURES 32 - +#if defined(LUA_CORE) && \ + defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */ /* -@@ 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. +** 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). */ -#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 - - -/* -@@ 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_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) +/* Microsoft compiler on a Pentium (32 bit) ? */ +#if defined(LUA_WIN) && defined(_MSC_VER) && defined(_M_IX86) /* { */ -#define lua_popen(L,c,m) ((void)L, _popen(c,m)) -#define lua_pclose(L,file) ((void)L, (_pclose(file) != -1)) +#define MS_ASMTRICK +#define LUA_IEEEENDIAN 0 +#define LUA_NANTRICK -#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), 0) +/* pentium 32 bits? */ +#elif defined(__i386__) || defined(__i386) || defined(__X86__) /* }{ */ -#endif +#define LUA_IEEE754TRICK +#define LUA_IEEELL +#define LUA_IEEEENDIAN 0 +#define LUA_NANTRICK -/* -@@ 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 +/* pentium 64 bits? */ +#elif defined(__x86_64) /* }{ */ -#if defined(LUA_WIN) -#define LUA_DL_DLL -#endif +#define LUA_IEEE754TRICK +#define LUA_IEEEENDIAN 0 +#elif defined(__POWERPC__) || defined(__ppc__) /* }{ */ -/* -@@ 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 +#define LUA_IEEE754TRICK +#define LUA_IEEEENDIAN 1 +#else /* }{ */ -/* -@@ 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. -*/ +/* assume IEEE754 and a 32-bit integer type */ +#define LUA_IEEE754TRICK -#if defined(LUA_USELONGLONG) +#endif /* } */ -#define LUA_INTFRMLEN "ll" -#define LUA_INTFRM_T long long +#endif /* } */ -#else - -#define LUA_INTFRMLEN "l" -#define LUA_INTFRM_T long +/* }================================================================== */ -#endif diff --git a/src/lualib.h b/src/lualib.h index 469417f670..9fd126bf78 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.43 2011/12/08 12:11:37 roberto Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ @@ -11,41 +11,43 @@ #include "lua.h" -/* Key to file-handle type */ -#define LUA_FILEHANDLE "FILE*" +LUAMOD_API int (luaopen_base) (lua_State *L); #define LUA_COLIBNAME "coroutine" -LUALIB_API int (luaopen_base) (lua_State *L); +LUAMOD_API int (luaopen_coroutine) (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 "bit32" +LUAMOD_API int (luaopen_bit32) (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); -#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 8010a45795..54de011a45 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.22 2012/05/08 13:53:33 roberto Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -27,28 +27,24 @@ typedef struct { const char* name; } LoadState; -#ifdef LUAC_TRUST_BINARIES -#define IF(c,s) -#define error(S,s) -#else -#define IF(c,s) if (c) error(S,s) - -static void error(LoadState* S, const char* why) +static l_noret 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) +#if !defined(luai_verifycode) +#define luai_verifycode(L,b,f) /* empty */ +#endif + 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,"truncated"); } static int LoadChar(LoadState* S) @@ -62,7 +58,7 @@ static int LoadInt(LoadState* S) { int x; LoadVar(S,x); - IF (x<0, "bad integer"); + if (x<0) error(S,"corrupted"); return x; } @@ -82,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' */ } } @@ -95,7 +91,7 @@ static void LoadCode(LoadState* S, Proto* f) LoadVector(S,f->code,n,sizeof(Instruction)); } -static Proto* LoadFunction(LoadState* S, TString* p); +static void LoadFunction(LoadState* S, Proto* f); static void LoadConstants(LoadState* S, Proto* f) { @@ -111,10 +107,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)); break; case LUA_TNUMBER: setnvalue(o,LoadNumber(S)); @@ -122,21 +118,38 @@ static void LoadConstants(LoadState* S, Proto* f) case LUA_TSTRING: setsvalue2n(S->L,o,LoadString(S)); break; - default: - error(S,"bad constant"); - break; + default: lua_assert(0); } } 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]=luaF_newproto(S->L); + LoadFunction(S,f->p[i]); + } +} + +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=LoadByte(S); + f->upvalues[i].idx=LoadByte(S); + } } 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; @@ -152,49 +165,48 @@ 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) +static void LoadFunction(LoadState* S, Proto* f) { - Proto* f; - if (++S->L->nCcalls > LUAI_MAXCCALLS) error(S,"code 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); LoadCode(S,f); LoadConstants(S,f); + LoadUpvalues(S,f); LoadDebug(S,f); - IF (!luaG_checkcode(f), "bad code"); - S->L->top--; - 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)-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); - IF (memcmp(h,s,LUAC_HEADERSIZE)!=0, "bad header"); + 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"); + if (memcmp(h,s,N3)!=0) error(S,"incompatible"); else error(S,"corrupted"); } /* ** 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]) @@ -205,23 +217,42 @@ 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,"=?")); + 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') +#define VERSION MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR) +#define FORMAT 0 /* this is the official format */ + /* -* make header +* make header for precompiled chunks +* 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)LUAC_VERSION; - *h++=(char)LUAC_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,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 c80189dbff..2b8accecb8 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.39 2012/05/08 13:53:33 roberto Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -11,26 +11,18 @@ #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 (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); -#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 +/* data to catch conversion errors */ +#define LUAC_TAIL "\x19\x93\r\n\x1a\n" -/* size of header of binary files */ -#define LUAC_HEADERSIZE 12 +/* 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 e0a0cd8521..b77eac26d0 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.63.1.5 2011/08/17 20:43:11 roberto Exp $ +** $Id: lvm.c,v 2.152 2012/06/08 15:14:04 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; } @@ -50,58 +50,61 @@ 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; } } -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); + int counthook = ((mask & LUA_MASKCOUNT) && L->hookcount == 0); + if (counthook) + resethookcount(L); /* reset count */ + if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ + ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ + return; /* do not call hook again (VM yielded, so it did not move) */ } + if (counthook) + luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ 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)->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); /* call line hook */ + } + L->oldpc = ci->u.l.savedpc; + if (L->status == LUA_YIELD) { /* did hook yield? */ + if (counthook) + L->hookcount = 1; /* undo decrement to zero */ + ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ + ci->callstatus |= CIST_HOOKYIELD; /* mark that it yieled */ + ci->func = L->top - 1; /* protect stack below results */ + luaD_throw(L, LUA_YIELD); } } -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); /* 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 */ + p3 = restorestack(L, result); + setobjs2s(L, p3, --L->top); + } } @@ -112,7 +115,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; @@ -122,10 +125,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,30 +136,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 no nil? */ - (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ - setobj2t(L, oldval, val); - h->flags = 0; - luaC_barriert(L, h, 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); + 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"); } @@ -168,12 +179,12 @@ 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; } -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; @@ -181,7 +192,7 @@ static const TValue *get_compTM (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; } @@ -189,14 +200,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; - callTMres(L, L->top, tm1, p1, p2); - return !l_isfalse(L->top); + if (!call_binTM(L, p1, p2, L->top, event)) + return -1; /* no metamethod */ + else + return !l_isfalse(L->top); } @@ -224,125 +231,261 @@ 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)) - return luai_numlt(nvalue(l), nvalue(r)); - else if (ttisstring(l)) + if (ttisnumber(l) && ttisnumber(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; } -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)); - else if (ttisstring(l)) + if (ttisnumber(l) && ttisnumber(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; } -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)); 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_TSHRSTR: return eqshrstr(rawtsvalue(t1), rawtsvalue(t2)); + case LUA_TLNGSTR: return luaS_eqlngstr(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); + 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; - tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); + 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? */ - 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) { + setobjs2s(L, top - 2, 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; /* 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 */ - last -= n-1; + total -= n-1; /* got 'n' strings to create 1 new */ + L->top -= n-1; /* popped '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 (ttypenv(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, rb, 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); } +/* +** 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, 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? */ + 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 +*/ +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); + 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_GETTABUP: 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 = 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) */ + 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_SETTABUP: case OP_SETTABLE: + break; + default: lua_assert(0); + } +} + + /* ** some macros for common tasks in `luaV_execute' */ -#define runtime_check(L, c) { if (!(c)) break; } +#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 */ @@ -352,13 +495,27 @@ 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++))) + +/* 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; } -#define dojump(L,pc,i) {(pc) += (i); luai_threadyield(L);} +/* 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) { L->savedpc = pc; {x;}; base = L->base; } +#define Protect(x) { {x;}; base = ci->u.l.base; } + +#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) { \ @@ -366,401 +523,345 @@ 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)); \ - } + else { Protect(luaV_arith(L, ra, rb, rc, tm)); } } +#define vmdispatch(o) switch(o) +#define vmcase(l,b) case l: {b} break; +#define vmcasenb(l,b) case l: {b} /* nb = no break */ -void luaV_execute (lua_State *L, int nexeccalls) { +void luaV_execute (lua_State *L) { + CallInfo *ci = L->ci; 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; + StkId base; + newframe: /* reentry point when frame changes (call/return) */ + lua_assert(ci == L->ci); + cl = clLvalue(ci->func); k = cl->p->k; + base = ci->u.l.base; /* 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); - if (L->status == LUA_YIELD) { /* did hook yield? */ - L->savedpc = pc - 1; - return; - } - base = L->base; + Protect(traceexec(L)); } - /* warning!! several calls may realloc the stack and invalidate `ra' */ + /* 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)); - switch (GET_OPCODE(i)) { - case OP_MOVE: { + lua_assert(base == ci->u.l.base); + lua_assert(base <= L->top && L->top < L->stack + L->stacksize); + vmdispatch (GET_OPCODE(i)) { + vmcase(OP_MOVE, setobjs2s(L, ra, RB(i)); - continue; - } - case OP_LOADK: { - setobj2s(L, ra, KBx(i)); - continue; - } - case OP_LOADBOOL: { + ) + vmcase(OP_LOADK, + 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, setbvalue(ra, GETARG_B(i)); - if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ - continue; - } - case OP_LOADNIL: { - TValue *rb = RB(i); + if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */ + ) + vmcase(OP_LOADNIL, + int b = GETARG_B(i); do { - setnilvalue(rb--); - } while (rb >= ra); - continue; - } - case OP_GETUPVAL: { + setnilvalue(ra++); + } while (b--); + ) + 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; - sethvalue(L, &g, cl->env); - lua_assert(ttisstring(KBx(i))); - Protect(luaV_settable(L, &g, KBx(i), 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); - sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); - Protect(luaC_checkGC(L)); - continue; - } - case OP_SELF: { + Table *t = luaH_new(L); + sethvalue(L, ra, t); + if (b != 0 || c != 0) + luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); + checkGC(L, ra + 1); + ) + 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); - 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; - } - case OP_NOT: { - int res = l_isfalse(RB(i)); /* next assignment may change this value */ + ) + vmcase(OP_NOT, + TValue *rb = RB(i); + int res = l_isfalse(rb); /* next assignment may change this value */ setbvalue(ra, res); - 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"); - ) - } - } - continue; - } - case OP_CONCAT: { + ) + vmcase(OP_LEN, + Protect(luaV_objlen(L, ra, RB(i))); + ) + vmcase(OP_CONCAT, int b = GETARG_B(i); int c = GETARG_C(i); - Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L)); - setobjs2s(L, RA(i), base+b); - continue; - } - case OP_JMP: { - dojump(L, pc, GETARG_sBx(i)); - continue; - } - case OP_EQ: { + StkId rb; + L->top = base + c + 1; /* mark the end of concat operands */ + 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, (ra >= rb ? ra + 1 : rb)); + L->top = ci->top; /* restore top */ + ) + vmcase(OP_JMP, + 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(L, pc, GETARG_sBx(*pc)); + if (cast_int(equalobj(L, rb, rc)) != GETARG_A(i)) + ci->u.l.savedpc++; + else + donextjump(ci); ) - pc++; - continue; - } - case OP_LT: { + ) + vmcase(OP_LT, Protect( - if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) - dojump(L, pc, GETARG_sBx(*pc)); + if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) + ci->u.l.savedpc++; + else + donextjump(ci); ) - pc++; - continue; - } - case OP_LE: { + ) + vmcase(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)) + ci->u.l.savedpc++; + else + donextjump(ci); ) - pc++; - continue; - } - case OP_TEST: { - if (l_isfalse(ra) != GETARG_C(i)) - dojump(L, pc, GETARG_sBx(*pc)); - pc++; - continue; - } - case OP_TESTSET: { + ) + vmcase(OP_TEST, + 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 (l_isfalse(rb) != GETARG_C(i)) { + if (GETARG_C(i) ? l_isfalse(rb) : !l_isfalse(rb)) + ci->u.l.savedpc++; + else { setobjs2s(L, ra, rb); - dojump(L, pc, GETARG_sBx(*pc)); + donextjump(ci); } - pc++; - 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 */ - 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; } - } - case OP_TAILCALL: { + else { /* Lua function */ + ci = L->ci; + ci->callstatus |= CIST_REENTRY; + goto newframe; /* restart luaV_execute over new Lua function */ + } + ) + vmcase(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; + 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); + goto newframe; /* restart luaV_execute over new Lua function */ } - } - case OP_RETURN: { + ) + vmcasenb(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); + 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(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)) { + ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ 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; - 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)); - continue; - } - case OP_TFORLOOP: { + setnvalue(ra, luai_numsub(L, nvalue(ra), nvalue(pstep))); + ci->u.l.savedpc += GETARG_sBx(i); + ) + vmcasenb(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); + goto l_tforloop; + ) + vmcase(OP_TFORLOOP, + l_tforloop: + if (!ttisnil(ra + 1)) { /* continue loop? */ + setobjs2s(L, ra, ra + 1); /* save control variable */ + ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ } - pc++; - continue; - } - case OP_SETLIST: { + ) + vmcase(OP_SETLIST, int n = GETARG_B(i); 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)); + luai_runtimecheck(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 */ + luaH_resizearray(L, h, last); /* pre-allocate it at once */ for (; n > 0; n--) { TValue *val = ra+n; - setobj2t(L, luaH_setnum(L, h, last--), val); - luaC_barriert(L, h, val); + luaH_setint(L, h, last--, val); + luaC_barrierback(L, obj2gco(h), val); } - continue; - } - case OP_CLOSE: { - luaF_close(L, ra); - 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); - 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); - Protect(luaC_checkGC(L)); - continue; - } - case OP_VARARG: { + L->top = ci->top; /* correct top (in case of previous open call) */ + ) + 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 + setclLvalue(L, ra, ncl); /* push cashed closure */ + checkGC(L, ra + 1); + ) + vmcase(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); } } - continue; - } + ) + vmcase(OP_EXTRAARG, + lua_assert(0); + ) } } } diff --git a/src/lvm.h b/src/lvm.h index bfe4f5678d..ec35822406 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.17 2011/05/31 18:27:56 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -13,24 +13,33 @@ #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)) +#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_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_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..8b77054e0b 100644 --- a/src/lzio.c +++ b/src/lzio.c @@ -1,6 +1,6 @@ /* -** $Id: lzio.c,v 1.31.1.1 2007/12/27 13:02:25 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 */ @@ -25,23 +25,11 @@ 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); + return cast_uchar(*(z->p++)); } @@ -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 51d695d8c1..08682301e8 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.26 2011/07/15 12:48:03 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ @@ -17,9 +17,8 @@ typedef struct Zio ZIO; -#define char2int(c) cast(int, cast(unsigned char, (c))) +#define zgetc(z) (((z)->n--)>0 ? cast_uchar(*(z)->p++) : luaZ_fill(z)) -#define zgetc(z) (((z)->n--)>0 ? char2int(*(z)->p++) : luaZ_fill(z)) typedef struct Mbuffer { char *buffer; @@ -47,7 +46,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); @@ -56,7 +54,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) */ }; diff --git a/src/print.c b/src/print.c deleted file mode 100644 index e240cfc3c6..0000000000 --- a/src/print.c +++ /dev/null @@ -1,227 +0,0 @@ -/* -** $Id: print.c,v 1.55a 2006/05/31 13:30:05 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; - } -} - -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,-1-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,bx); - 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[bx])); - 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->nups)); - 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) -{ - int i,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); - } -} - -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])); - } -} - -void PrintFunction(const Proto* f, int full) -{ - int i,n=f->sizep; - PrintHeader(f); - PrintCode(f); - if (full) - { - PrintConstants(f); - PrintLocals(f); - PrintUpvalues(f); - } - for (i=0; ip[i],full); -} 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 0871bb2125..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 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 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 ebc3effc06..0000000000 --- a/test/xd.lua +++ /dev/null @@ -1,14 +0,0 @@ --- hex dump --- usage: lua xd.lua < file - -local offset=0 -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) - io.write(string.rep(" ",3*(16-string.len(s)))) - io.write(" ",string.gsub(s,"%c","."),"\n") - offset=offset+16 -end From 3a270501c505b77298f7a5419509f40596424da8 Mon Sep 17 00:00:00 2001 From: Kate Adams Date: Sun, 4 Jan 2015 08:32:59 +0000 Subject: [PATCH 29/40] Import Lua 5.2.2 --- README | 2 +- doc/contents.html | 18 +-- doc/lua.css | 6 +- doc/manual.css | 6 +- doc/manual.html | 314 +++++++++++++++++++++++++++++----------------- doc/readme.html | 10 +- src/Makefile | 2 +- src/lapi.c | 45 +++---- src/lauxlib.c | 13 +- src/lbaselib.c | 33 +++-- src/lbitlib.c | 6 +- src/lcode.c | 11 +- src/lcorolib.c | 4 +- src/ldebug.c | 10 +- src/ldo.c | 15 ++- src/lfunc.c | 4 +- src/lgc.c | 90 +++++++------ src/lgc.h | 16 ++- src/liolib.c | 26 ++-- src/llex.c | 10 +- src/llimits.h | 8 +- src/lmathlib.c | 72 +++++------ src/lmem.h | 15 ++- src/lobject.c | 20 ++- src/lobject.h | 7 +- src/loslib.c | 4 +- src/lparser.c | 11 +- src/lstate.c | 4 +- src/lstate.h | 4 +- src/lstring.c | 6 +- src/lstrlib.c | 207 ++++++++++++++++++------------ src/ltable.c | 6 +- src/ltablib.c | 20 +-- src/lua.c | 7 +- src/lua.h | 13 +- src/luaconf.h | 25 ++-- src/lvm.c | 7 +- src/lvm.h | 5 +- 38 files changed, 631 insertions(+), 451 deletions(-) diff --git a/README b/README index 253d110692..6e2aee6ce3 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ -This is Lua 5.2.1, released on 08 Jun 2012. +This is Lua 5.2.2, released on 21 Mar 2013. 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 9f5060519f..0ce297da19 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -23,7 +23,7 @@

    The reference manual is the official definition of the Lua language. For a complete introduction to Lua programming, see the book -Programming in Lua. +Programming in Lua.

    start @@ -33,7 +33,7 @@

    index
    -Copyright © 2011–2012 Lua.org, PUC-Rio. +Copyright © 2011–2013 Lua.org, PUC-Rio. Freely available under the terms of the Lua license. @@ -149,8 +149,8 @@

    Lua functions

    error
    getmetatable
    ipairs
    -loadfile
    load
    +loadfile
    next
    pairs
    pcall
    @@ -385,6 +385,7 @@

    C API

    lua_pushcclosure
    lua_pushcfunction
    lua_pushfstring
    +lua_pushglobaltable
    lua_pushinteger
    lua_pushlightuserdata
    lua_pushliteral
    @@ -393,15 +394,16 @@

    C API

    lua_pushnumber
    lua_pushstring
    lua_pushthread
    +lua_pushunsigned
    lua_pushvalue
    lua_pushvfstring
    lua_rawequal
    lua_rawget
    lua_rawgeti
    +lua_rawgetp
    lua_rawlen
    lua_rawset
    lua_rawseti
    -lua_rawgetp
    lua_rawsetp
    lua_register
    lua_remove
    @@ -460,8 +462,8 @@

    auxiliary library

    luaL_buffinitsize
    luaL_callmeta
    luaL_checkany
    -luaL_checkinteger
    luaL_checkint
    +luaL_checkinteger
    luaL_checklong
    luaL_checklstring
    luaL_checknumber
    @@ -492,8 +494,8 @@

    auxiliary library

    luaL_newmetatable
    luaL_newstate
    luaL_openlibs
    -luaL_optinteger
    luaL_optint
    +luaL_optinteger
    luaL_optlong
    luaL_optlstring
    luaL_optnumber
    @@ -521,10 +523,10 @@

    auxiliary library


    Last update: -Sat May 26 08:52:25 BRT 2012 +Tue Mar 12 11:22:18 BRT 2013 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..85365363fb 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. @@ -8348,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. @@ -8990,6 +9061,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 +9486,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 +9497,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 +9521,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 +9556,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 +9637,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 +9828,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 +10497,10 @@

      9 – The Complete Syntax of Lua


      Last update: -Fri Jun 8 16:13:40 BRT 2012 +Thu Mar 21 12:58:59 BRT 2013 diff --git a/doc/readme.html b/doc/readme.html index 2ff294ec37..5b9e47ecba 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. @@ -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

        @@ -372,7 +374,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 +402,10 @@

        License


        Last update: -Tue May 29 21:57:51 BRT 2012 +Fri Feb 22 09:24:20 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..791d85454f 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.171 2013/03/16 21:10:18 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 unreachable; 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..2e989d661b 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.248 2013/03/21 13:54:57 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"); @@ -598,7 +599,7 @@ static int skipBOM (LoadF *lf) { lf->n = 0; do { c = getc(lf->f); - if (c == EOF || c != *(unsigned char *)p++) return c; + if (c == EOF || c != *(const 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 */ diff --git a/src/lbaselib.c b/src/lbaselib.c index dbfcb02cfc..540e9a5cc0 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.276 2013/02/21 13:44:53 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); } /* }====================================================== */ @@ -338,7 +336,8 @@ static int dofilecont (lua_State *L) { static int luaB_dofile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); lua_settop(L, 1); - if (luaL_loadfile(L, fname) != LUA_OK) lua_error(L); + if (luaL_loadfile(L, fname) != LUA_OK) + return lua_error(L); lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); return dofilecont(L); } diff --git a/src/lbitlib.c b/src/lbitlib.c index 7533b85c5a..9637532e3d 100644 --- a/src/lbitlib.c +++ b/src/lbitlib.c @@ -1,5 +1,5 @@ /* -** $Id: lbitlib.c,v 1.16 2011/06/20 16:35:23 roberto Exp $ +** $Id: lbitlib.c,v 1.18 2013/03/19 13:19:12 roberto Exp $ ** Standard library for bitwise operations ** See Copyright Notice in lua.h */ @@ -147,7 +147,9 @@ static int b_rrot (lua_State *L) { /* ** get field and width arguments for field-manipulation functions, -** checking whether they are valid +** checking whether they are valid. +** ('luaL_error' called without 'return' to avoid later warnings about +** 'width' being used uninitialized.) */ static int fieldargs (lua_State *L, int farg, int *width) { int f = luaL_checkint(L, farg); 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/lcorolib.c b/src/lcorolib.c index c7932d90f2..1326c8146c 100644 --- a/src/lcorolib.c +++ b/src/lcorolib.c @@ -1,5 +1,5 @@ /* -** $Id: lcorolib.c,v 1.4 2012/04/27 18:59:04 roberto Exp $ +** $Id: lcorolib.c,v 1.5 2013/02/21 13:44:53 roberto Exp $ ** Coroutine Library ** See Copyright Notice in lua.h */ @@ -73,7 +73,7 @@ static int luaB_auxwrap (lua_State *L) { lua_insert(L, -2); lua_concat(L, 2); } - lua_error(L); /* propagate error */ + return lua_error(L); /* propagate error */ } return r; } 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..535e988ae0 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.140 2013/03/16 21:10:18 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); @@ -459,7 +450,7 @@ static lu_mem traversetable (global_State *g, Table *h) { else /* not weak */ traversestrongtable(g, h); return sizeof(Table) + sizeof(TValue) * h->sizearray + - sizeof(Node) * sizenode(h); + sizeof(Node) * cast(size_t, sizenode(h)); } @@ -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)) @@ -918,7 +924,7 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { ** 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. -** Returns how many objects it sweeped. +** Returns how many objects it swept. */ static int entersweep (lua_State *L) { global_State *g = G(L); @@ -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/liolib.c b/src/liolib.c index 4814aa2c2a..3f80db1927 100644 --- a/src/liolib.c +++ b/src/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.108 2011/11/25 12:50:03 roberto Exp $ +** $Id: liolib.c,v 2.111 2013/03/21 13:57:27 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -29,6 +29,20 @@ #include "lualib.h" +#if !defined(lua_checkmode) + +/* +** Check whether 'mode' matches '[rwa]%+?b?'. +** Change this macro to accept other modes for 'fopen' besides +** the standard ones. +*/ +#define lua_checkmode(mode) \ + (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \ + (*mode != '+' || ++mode) && /* skip if char is '+' */ \ + (*mode != 'b' || ++mode) && /* skip if char is 'b' */ \ + (*mode == '\0')) + +#endif /* ** {====================================================== @@ -212,14 +226,8 @@ static int io_open (lua_State *L) { const char *filename = luaL_checkstring(L, 1); const char *mode = luaL_optstring(L, 2, "r"); LStream *p = newfile(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] == '\0'))) - return luaL_error(L, "invalid mode " LUA_QS - " (should match " LUA_QL("[rwa]%%+?b?") ")", mode); + const char *md = mode; /* to traverse/check mode */ + luaL_argcheck(L, lua_checkmode(md), 2, "invalid mode"); p->f = fopen(filename, mode); return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; } diff --git a/src/llex.c b/src/llex.c index c4d8c65b6f..1a32e348b0 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.63 2013/03/16 21:10:18 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; } } @@ -313,7 +313,7 @@ static int readhexaesc (LexState *ls) { 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 */ + for (i = 1; i < 3; i++) { /* read two hexadecimal digits */ c[i] = next(ls); if (!lisxdigit(c[i])) escerror(ls, c, i + 1, "hexadecimal digit expected"); diff --git a/src/llimits.h b/src/llimits.h index fc9de1a11b..1b8c79bda2 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.103 2013/02/20 14:08:56 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_mathop(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..a49f1fd25a 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.83 2013/03/07 18:21:32 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); + int ep = luaL_checkint(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..5f850999a9 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.40 2013/02/20 14:08:21 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 "comparison 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..c152785a5a 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.58 2013/02/20 14:08:56 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_mathop(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..ad798b4e2a 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.65 2013/03/07 18:17:24 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,17 @@ 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"); 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..eb0482b8f4 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.285 2013/03/15 13:04:22 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" @@ -119,6 +119,11 @@ typedef LUA_UNSIGNED lua_Unsigned; #endif +/* +** RCS ident string +*/ +extern const char lua_ident[]; + /* ** state manipulation @@ -413,7 +418,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..df802c9526 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.176 2013/03/16 21:10:18 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -44,7 +44,7 @@ #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_STRTODHEX /* assume 'strtod' handles hex formats */ #define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ #define LUA_USE_LONGLONG /* assume support for long long */ #endif @@ -53,7 +53,7 @@ #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_STRTODHEX /* assume 'strtod' handles hex formats */ #define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ #define LUA_USE_LONGLONG /* assume support for long long */ #endif @@ -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..657d5c456a 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.155 2013/03/16 21:10:18 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -83,7 +83,7 @@ static void traceexec (lua_State *L) { if (counthook) L->hookcount = 1; /* undo decrement to zero */ ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ - ci->callstatus |= CIST_HOOKYIELD; /* mark that it yieled */ + ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ ci->func = L->top - 1; /* protect stack below results */ luaD_throw(L, LUA_YIELD); } @@ -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 449465e35c085846cbcc41241e99c4ee0a7cdc9e Mon Sep 17 00:00:00 2001 From: Kate Adams Date: Sun, 4 Jan 2015 08:33:20 +0000 Subject: [PATCH 30/40] Import Lua 5.2.3 --- Makefile | 2 +- README | 2 +- doc/lua.css | 31 ++++++++++++++++++++++--------- doc/manual.css | 9 +++++---- doc/readme.html | 7 ++++--- src/Makefile | 2 +- src/lapi.c | 2 +- src/lapi.h | 2 +- src/lauxlib.c | 2 +- src/lauxlib.h | 2 +- src/lbaselib.c | 2 +- src/lbitlib.c | 5 +++-- src/lcode.c | 2 +- src/lcode.h | 2 +- src/lcorolib.c | 2 +- src/lctype.c | 2 +- src/lctype.h | 2 +- src/ldblib.c | 2 +- src/ldebug.c | 31 ++++++++++++++++++++++--------- src/ldebug.h | 2 +- src/ldo.c | 18 +++++++++++++----- src/ldo.h | 2 +- src/ldump.c | 2 +- src/lfunc.c | 2 +- src/lfunc.h | 2 +- src/lgc.c | 13 ++++++++++--- src/lgc.h | 2 +- src/linit.c | 2 +- src/liolib.c | 23 ++++++++++++----------- src/llex.c | 5 ++++- src/llex.h | 2 +- src/llimits.h | 2 +- src/lmathlib.c | 2 +- src/lmem.c | 2 +- src/lmem.h | 2 +- src/loadlib.c | 2 +- src/lobject.c | 2 +- src/lobject.h | 2 +- src/lopcodes.c | 2 +- src/lopcodes.h | 2 +- src/loslib.c | 2 +- src/lparser.c | 2 +- src/lparser.h | 2 +- src/lstate.c | 11 ++++++----- src/lstate.h | 2 +- src/lstring.c | 2 +- src/lstring.h | 2 +- src/lstrlib.c | 2 +- src/ltable.c | 2 +- src/ltable.h | 6 +++++- src/ltablib.c | 2 +- src/ltm.c | 2 +- src/ltm.h | 2 +- src/lua.c | 2 +- src/lua.h | 4 ++-- src/luac.c | 4 ++-- src/luaconf.h | 2 +- src/lualib.h | 2 +- src/lundump.c | 2 +- src/lundump.h | 2 +- src/lvm.c | 2 +- src/lvm.h | 2 +- src/lzio.c | 2 +- src/lzio.h | 2 +- 64 files changed, 161 insertions(+), 108 deletions(-) diff --git a/Makefile b/Makefile index bd9515fd84..d2c7db4a2d 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,7 @@ TO_MAN= lua.1 luac.1 # Lua version and release. V= 5.2 -R= $V.1 +R= $V.3 # Targets start here. all: $(PLAT) diff --git a/README b/README index 6e2aee6ce3..49033adb5b 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ -This is Lua 5.2.2, released on 21 Mar 2013. +This is Lua 5.2.3, released on 11 Nov 2013. For installation instructions, license details, and further information about Lua, see doc/readme.html. diff --git a/doc/lua.css b/doc/lua.css index 240e85eb8b..3d2443acff 100644 --- a/doc/lua.css +++ b/doc/lua.css @@ -1,30 +1,37 @@ +html { + background-color: #F8F8F8 ; +} + body { + border: solid #a0a0a0 1px ; + border-radius: 20px ; + padding: 26px ; + margin: 16px ; color: #000000 ; background-color: #FFFFFF ; font-family: Helvetica, Arial, sans-serif ; text-align: justify ; - margin-right: 30px ; - margin-left: 30px ; } h1, h2, h3, h4 { font-family: Verdana, Geneva, sans-serif ; font-weight: normal ; - font-style: italic ; + font-style: normal ; } h2 { padding-top: 0.4em ; padding-bottom: 0.4em ; - padding-left: 1em ; - padding-right: 1em ; - background-color: #E0E0FF ; + padding-left: 0.8em ; + padding-right: 0.8em ; + background-color: #D0D0FF ; border-radius: 8px ; + border: solid #a0a0a0 1px ; } h3 { padding-left: 0.5em ; - border-left: solid #E0E0FF 1em ; + border-left: solid #D0D0FF 1em ; } table h3 { @@ -45,7 +52,7 @@ a:visited { a:link:hover, a:visited:hover { color: #000080 ; - background-color: #E0E0FF ; + background-color: #D0D0FF ; } a:link:active, a:visited:active { @@ -57,17 +64,23 @@ hr { height: 1px ; color: #a0a0a0 ; background-color: #a0a0a0 ; + display: none ; +} + +table hr { + display: block ; } :target { background-color: #F8F8F8 ; padding: 8px ; border: solid #a0a0a0 2px ; + border-radius: 8px ; } .footer { color: gray ; - font-size: small ; + font-size: x-small ; } input[type=text] { diff --git a/doc/manual.css b/doc/manual.css index 269bd4358e..ca613cd9fb 100644 --- a/doc/manual.css +++ b/doc/manual.css @@ -16,11 +16,12 @@ span.apii { } p+h1, ul+h1 { + font-style: normal ; padding-top: 0.4em ; padding-bottom: 0.4em ; - padding-left: 24px ; - margin-left: -24px ; - background-color: #E0E0FF ; + padding-left: 16px ; + margin-left: -16px ; + background-color: #D0D0FF ; border-radius: 8px ; + border: solid #000080 1px ; } - diff --git a/doc/readme.html b/doc/readme.html index 5b9e47ecba..8acec874ca 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -7,6 +7,7 @@