Commit 17df207a authored by Johny Mattsson's avatar Johny Mattsson
Browse files

Port Terry's Lua 5.1 + 5.3 work from the esp8266 branch.

Changes have been kept to a minimum, but a serious chunk of work was
needed to move from 8266isms to IDFisms.

Some things got refactored into components/lua/common, in particular
the LFS location awareness.

As part of this work I also evicted our partition table manipulation
code, as with the current IDF it kept breaking checksums and rendering
things unbootable, which is the opposite of helpful (which was the
original intent behind it).

The uart module got relocated from base_nodemcu to the modules component
properly, after I worked out how to force its inclusion using Kconfig alone.
parent f123d462
/*
** $Id: luaconf.h,v 1.259.1.1 2017/04/19 17:29:57 roberto Exp $
** Configuration file for Lua
** See Copyright Notice in lua.h
*/
#ifndef luaconf_h
#define luaconf_h
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "sdkconfig.h"
/*
** ===================================================================
** The NodeMCU Lua environment support 2 compilation targets:
**
** * The ESP8266 ans ESP32 embedded runtimes which are compiled using
** the GCC XTENSA cross-compiler toolchain.
**
** * An extend version of the luac build for cross-compiling Lua
** sources for downloading to the ESP hardware. This is command
** line only and does not support any interactive dialogue or
** dynamically loaded libraries.
**
** Note that we've removd the "how to fill this in comments so you
** can now see the actual content more easily. Also the two big
** boilerplate conditional sections "Configuration for Numbers" and
** "Dependencies with C99 and other C details" have been moved to
** the end of the include file to keep the information dense content
** at the front.
** ===================================================================
*/
#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE)
# define LUA_USE_WINDOWS /* enable goodies for regular Windows */
//# define LUA_USE_C89 /* We only support the VS2013 C or later */
#elif defined(__APPLE__)
# define LUA_USE_MACOSX
# define LUA_USE_POSIX
#else
# define LUA_USE_LINUX
//# define LUA_USE_POSIX
#endif
#define LUA_NODEMCU_NOCLOADERS
//#define LUA_C89_NUMBERS
#define LUAI_BITSINT 32
/* predefined options for LUA_INT_TYPE */
#define LUA_INT_INT 1
#define LUA_INT_LONG 2
#define LUA_INT_LONGLONG 3L
/* predefined options for LUA_FLOAT_TYPE */
#define LUA_FLOAT_FLOAT 1
#define LUA_FLOAT_DOUBLE 2
#define LUA_FLOAT_LONGDOUBLE 3
/* 32 vs 64 bit decisions controlled via Kconfig options */
#if defined(CONFIG_LUA_NUMBER_INT64)
# define LUA_INT_TYPE LUA_INT_LONGLONG
#else
# define LUA_INT_TYPE LUA_INT_INT
#endif
#if defined(CONFIG_LUA_NUMBER_DOUBLE)
# define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
#else
# define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT
#endif
/*
** Configuration for Paths.
**
** LUA_CPATH_DEFAULT is the default path that Lua uses to look for
** Dynamic C libraries are not used and ditto LUA_CPATH_DEFAULT
*/
#define LUA_PATH_SEP ";"
#define LUA_PATH_MARK "?"
#define LUA_EXEC_DIR "!"
#define LUA_PATH_DEFAULT "?.lc;?.lua"
#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.
*/
#define LUA_API extern
#define LUALIB_API LUA_API
#define LUAMOD_API LUALIB_API
/*
@@ LUAI_FUNC, LUAI_DDEF and LUAI_DDEC are used to mark visibilty when
** building lua as a shared library. Used to tag private inter-module
** Lua internal functions.
*/
//#define LUAI_FUNC __attribute__((visibility("hidden"))) extern
#define LUAI_FUNC extern
#define LUAI_DDEC LUAI_FUNC
#define LUAI_DDEF
/*
** {==================================================================
** Compatibility with previous versions
** ===================================================================
*/
//#define LUA_COMPAT_MATHLIB // retains several deprecated functions in math.
//#define LUA_COMPAT_BITLIB // bit32 is separately implemented as a NodeMCU lib
//#define LUA_COMPAT_IPAIRS // enables __ipairs meta which isn't used in NodeMCU
#define LUA_NODEMCU_COMPAT_MATHLIB /* retains NodeMCU subset of mathlib */
#define LUA_COMPAT_APIINTCASTS /* needed to enable NodeMCU modules to work on */
/* both Lua 5.1 and Lua 5.3 */
#define LUA_COMPAT_UNPACK /* needed to support a global 'unpack' */
#define LUA_COMPAT_LOADERS /* keeps 'package.loaders' as a synonym for */
/* 'package.searchers'. Used in our libraries */
#define LUA_COMPAT_LOADSTRING /* keeps loadstring(s) as synonym for load(s) */
#if 0
#define lua_cpcall(L,f,u) \ // Not used in our module code
(lua_pushcfunction(L, (f)), \
lua_pushlightuserdata(L,(u)), \
lua_pcall(L,1,0,0))
#endif
//#define LUA_COMPAT_LOG10 // math.log10 not used in NodeMCU
//#define LUA_COMPAT_MAXN // math.maxn not used
/* Compatbililty for some API calls withdrawn in Lua53 */
#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)
// #define LUA_COMPAT_MODULE // drop support for legacy module() format not used in our modules
/**** May need to revisit this one *****/
// #define LUA_COMPAT_FLOATSTRING // makes Lua format integral floats without a float mark
#define LUA_KCONTEXT ptrdiff_t
#define lua_getlocaledecpoint() '.'
// #define LUA_NOCVTN2S // enable automatic coercion between
// #define LUA_NOCVTS2N // strings and numbers
#if defined(LUA_USE_APICHECK)
#include <assert.h>
#define luai_apicheck(l,e) assert(e)
#endif
#define LUA_EXTRASPACE (sizeof(void *)) // raw memory area associated with a Lua state
#define LUAI_MAXSTACK 12000 // Maximum Lua stack size
#define LUA_IDSIZE 60 // Maximum size for the description of the source
/*
@@ lua_getlocaledecpoint gets the locale "radix character" (decimal point).
** Change that if you do not want to use C locales. (Code using this
** macro must include header 'locale.h'.)
*/
// of a function in debug information.
#define LUAL_BUFFERSIZE 256 // NodeMCU setting because of stack limits
#define LUA_QL(x) "'" x "'" // No longer used in lua53, but still used
#define LUA_QS LUA_QL("%s") // in some of our apllication modules
/*
** {==================================================================
** Other NodeMCU configuration.
** ===================================================================
*/
#ifdef LUA_USE_ESP
#define LUAI_USER_ALIGNMENT_T size_t
#endif
#define LUAI_GCPAUSE 110 /* 110% (wait memory to grow 10% before next gc) */
/* }================================================================== */
/*
** {==================================================================
** Configuration for Numbers.
** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_*
** satisfy your needs.
** ===================================================================
**
@@ LUA_NUMBER is the floating-point type used by Lua.
@@ LUAI_UACNUMBER is the result of a 'default argument promotion' over a floating number.
@@ l_mathlim(x) corrects limit name 'x' to the proper float type by prefixing it with one of FLT/DBL/LDBL.
@@ 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.
@@ l_floor takes the floor of a float.
@@ lua_str2number converts a decimal numeric string to a number.
*/
/* The following definitions are good for most cases here */
#define l_floor(x) (l_mathop(floor)(x))
#define lua_number2str(s,sz,n) \
l_sprintf((s), sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)(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))
/* now the variable definitions */
#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */
#define LUA_NUMBER float
#define l_mathlim(n) (FLT_##n)
#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 LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */
#define LUA_NUMBER long double
#define l_mathlim(n) (LDBL_##n)
#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 LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */
#define LUA_NUMBER double
#define l_mathlim(n) (DBL_##n)
#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 float type not defined"
#endif /* } */
#define LUA_FLOAT LUA_NUMBER
/*
@@ LUA_INTEGER is the integer type used by Lua.
**
@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER.
**
@@ LUAI_UACINT is the result of a 'default argument promotion'
@@ 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 LUAI_UACINT LUA_INTEGER
#define lua_integer2str(s,sz,n) \
l_sprintf((s), sz, LUA_INTEGER_FMT, (LUAI_UACINT)(n))
/*
** 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 LUA_INT_TYPE == LUA_INT_INT /* { int */
#define LUA_INTEGER int
#define LUA_INTEGER_FRMLEN ""
#define LUA_MAXINTEGER INT_MAX
#define LUA_MININTEGER INT_MIN
#elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */
#define LUA_INTEGER long
#define LUA_INTEGER_FRMLEN "l"
#define LUA_MAXINTEGER LONG_MAX
#define LUA_MININTEGER LONG_MIN
#elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */
/* use presence of macro LLONG_MAX as proxy for C99 compliance */
#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 and other C details
** ===================================================================
*/
/*
@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89.
** (All uses in Lua have only one format item.)
*/
#if !defined(LUA_USE_C89)
#define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i)
#else
#define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i))
#endif
/*
@@ lua_strx2number converts an hexadecimal numeric string to a number.
** In C99, 'strtod' does that conversion. 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_pointer2str converts a pointer to a readable string in a
** non-specified way.
*/
#define lua_pointer2str(buff,sz,p) l_sprintf(buff,sz,"%p",p)
/*
@@ lua_number2strx converts a float to an hexadecimal numeric string.
** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that.
** Otherwise, you can leave 'lua_number2strx' undefined and Lua will
** provide its own implementation.
*/
#if !defined(LUA_USE_C89)
#define lua_number2strx(L,b,sz,f,n) \
((void)L, l_sprintf(b,sz,f,(LUAI_UACNUMBER)(n)))
#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
#undef lua_str2number
#define lua_str2number(s,p) ((lua_Number)strtod((s), (p)))
#define LUA_DEBUG_HOOK lua_debugbreak
#endif
/*
** $Id: lualib.h,v 1.45.1.1 2017/04/19 17:20:42 roberto Exp $
** Lua standard libraries
** See Copyright Notice in lua.h
*/
#ifndef lualib_h
#define lualib_h
#include "lua.h"
/* version suffix for environment variable names */
#define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
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
/*---
** $Id: lundump.c,v 2.44.1.1 2017/04/19 17:20:42 roberto Exp $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
#define lundump_c
#define LUA_CORE
#include "lprefix.h"
#include <string.h>
#include "lua.h"
#include "ldebug.h"
#include "ldo.h"
#include "lfunc.h"
#include "llex.h"
#include "lmem.h"
#include "lnodemcu.h"
#include "lobject.h"
#include "lstring.h"
#include "lundump.h"
#include "lzio.h"
/*
** Unlike the standard Lua version of lundump.c, this NodeMCU version must be
** able to store the dumped Protos into one of two targets:
**
** (A) RAM-based heap. This in the same way as standard Lua, where the
** Proto data structures can be created by direct in memory addressing,
** with any references complying with Lua GC assumptions, so that all
** storage can be collected in the case of a thrown error.
**
** (B) Flash programmable ROM memory. This can only be written to serially,
** using a write API, it can be subsequently but accessed and directly
** addressable through a memory-mapped address window after cache flush.
**
** Mode (B) also know as LFS (Lua FLash Store) enables running Lua apps
** on small-memory IoT devices which support programmable flash storage such
** as the ESP8266 SoC. In the case of this chip, the usable RAM heap is
** roughly 45Kb, so the ability to store an extra 128Kb, say, of program into
** LFS can materially increase the size of application that can be executed
** and leave most of the heap for true R/W application data.
**
** The changes to this source file enable the addition of LFS mode. In mode B,
** the resources aren't allocated in RAM but are written to Flash using the
** write API which returns the corresponding Flash read address is returned;
** also data can't be immediately read back using these addresses because of
** cache staleness.
**
** Handling the Proto record has been reordered to avoid interleaved resource
** writes in mode (B), with the f->k being cached in RAM and the Proto
** hierarchies walked bottom-up in a way that still maintains GC compliance
** conformance for mode (A). This no-interleave constraint also complicates
** the writing of TString resources into flash, so the flashing process
** circumvents this issue for LFS loads by header by taking two passes to dump
** the hierarchy. The first dumps all strings that needed to load the Protos,
** with the subsequent Proto loads use an index to any TString references.
** This enables all strings to be loaded into an LFS-based ROstrt before
** starting to load the Protos.
**
** Note that this module and ldump.c are compiled into both the ESP firmware
** and a host-based luac cross compiler. LFS dump is currently only supported
** in the compiler, but both the LFS and standard loads are supported in both
** the target (lua.c) and the host (luac.cross -e)environments. Both
** environments are built with the same integer and float formats (e.g. 32 bit,
** 32-bit IEEE).
**
** Dumps can either be loaded into RAM or LFS depending on the load format. An
** extra complication is that luac.cross supports two LFS modes, with the
** first loading into an host process address space and using host 32 or 64
** bit address references. The second uses shadow ESP 32 bit addresses to
** create an absolute binary image for direct provisioning of ESP images.
*/
#define MODE_RAM 0 /* Loading into RAM */
#define MODE_LFS 1 /* Loading into a locally executable LFS */
#define MODE_LFSA 2 /* (Host only) Loading into a shadow ESP image */
typedef struct {
lua_State *L; /* cache L to drop parameter list */
ZIO *Z; /* ZIO context */
const char *name; /* Filename of the LFS image being loaded */
LFSHeader *fh; /* LFS flash header block */
void *startLFS; /* Start address of LFS region */
TString **TS; /* List of TStrings being used in the image */
lu_int32 TSlen; /* Length of the same */
lu_int32 TSndx; /* Index into the same */
lu_int32 TSnFixed; /* Number of "fixed" TS */
char *buff; /* Working buffer for assembling a TString */
lu_int32 buffLen; /* Maximum length of TS used in the image */
TString **list; /* TS list used to index the ROstrt */
lu_int32 listLen; /* Length of the same */
Proto **pv; /* List of Protos in LFS */
lu_int32 pvLen; /* Length of the same */
GCObject *protogc; /* LFS proto linked list */
lu_byte useStrRefs; /* Flag if set then TStings are a index into TS */
lu_byte mode; /* Either LFS or RAM */
} 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 wordptr(p) cast(lu_int32 *, p)
#define byteptr(p) cast(lu_byte *, p)
#define wordoffset(p,q) (wordptr(p) - wordptr(q))
#define FHaddr(S,t,f) cast(t, wordptr(S->startLFS) + (f))
#define FHoffset(S,o) wordoffset((o), S->startLFS)
#define NewVector(S, n, t) cast(t *,NewVector_(S, n, sizeof(t)))
#define StoreGetPos(S) luaN_writeFlash((S)->Z->data, NULL, 0)
static void *NewVector_(LoadState *S, int n, size_t s) {
void *v;
if (S->mode == MODE_RAM) {
v = luaM_reallocv(S->L, NULL, 0, n, s);
memset (v, 0, n*s);
} else {
v = StoreGetPos(S);
}
return v;
}
static void *Store_(LoadState *S, void *a, int ndx, const void *e, size_t s
#ifdef LUA_USE_HOST
, const char *format
#endif
) {
if (S->mode == MODE_RAM) {
lu_byte *p = byteptr(a) + ndx*s;
if (p != byteptr(e))
memcpy(p, e, s);
return p;
}
#ifdef LUA_USE_HOST
else if (S->mode == MODE_LFSA && format) { /* do a repack move */
void *p = StoreGetPos(S);
const char *f = format;
int o;
for (o = 0; *f; o++, f++ ) {
luaN_writeFlash(S->Z->data, wordptr(e)+o, sizeof(lu_int32));
if (*f == 'A' || *f == 'W') /* Addr or word followed by alignment fill */
o++;
}
lua_assert(o*sizeof(lu_int32) == s);
return p;
}
#endif
/* mode == LFS or 32bit build */
return luaN_writeFlash(S->Z->data, e, s);
}
#ifdef LUA_USE_HOST
#include <stdio.h>
/* These compression maps must match the definitions in lobject.h etc. */
# define OFFSET_TSTRING (2*(sizeof(lu_int32)-sizeof(size_t)))
# define FMT_TSTRING "AwwA"
# define FMT_TVALUE "WA"
# define FMT_PROTO "AwwwwwwwwwwAAAAAAAA"
# define FMT_UPVALUE "AW"
# define FMT_LOCVAR "Aww"
# define FMT_ROTENTRY "AWA"
# define FMT_ROTABLE "AWAA"
# define StoreR(S,a, i, v, f) Store_(S, (a), i, &(v), sizeof(v), f)
# define Store(S, a, i, v) StoreR(S, (a), i, v, NULL)
# define StoreN(S, v, n) Store_(S, NULL, 0, (v), (n)*sizeof(*(v)), NULL)
static void *StoreAV (LoadState *S, void *a, int n) {
void **av = cast(void**, a);
if (S->mode == MODE_LFSA) {
void *p = StoreGetPos(S);
int i; for (i = 0; i < n; i ++)
luaN_writeFlash(S->Z->data, wordptr(av++), sizeof(lu_int32));
return p;
} else {
return Store_(S, NULL, 0, av, n*sizeof(*av), NULL);
}
}
#else // LUA_USE_ESP
# define OFFSET_TSTRING (0)
# define Store(S, a, i, v) Store_(S, (a), i, &(v), sizeof(v))
# define StoreN(S, v, n) Store_(S, NULL, 0, (v), (n)*sizeof(*(v)))
# define StoreR(S, a, i, v, f) Store(S, a, i, v)
# define StoreAV(S, p, n) StoreN(S, p, n)
# define OPT_FMT
#endif
#define StoreFlush(S) luaN_flushFlash((S)->Z->data);
#define LoadVector(S,b,n) LoadBlock(S,b,(n)*sizeof((b)[0]))
static void LoadBlock (LoadState *S, void *b, size_t size) {
lu_int32 left = luaZ_read(S->Z, b, size);
if ( left != 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 lua_Integer LoadInt (LoadState *S) {
lu_byte b;
lua_Integer x = 0;
do { b = LoadByte(S); x = (x<<7) + (b & 0x7f); } while (b & 0x80);
return x;
}
static lua_Number LoadNumber (LoadState *S) {
lua_Number x;
LoadVar(S, x);
return x;
}
static lua_Integer LoadInteger (LoadState *S, lu_byte tt_data) {
lu_byte b;
lua_Integer x = tt_data & LUAU_DMASK;
if (tt_data & 0x80) {
do { b = LoadByte(S); x = (x<<7) + (b & 0x7f); } while (b & 0x80);
}
return (tt_data & LUAU_TMASK) == LUAU_TNUMNINT ? -x-1 : x;
}
static TString *LoadString_ (LoadState *S, int prelen) {
TString *ts;
char buff[LUAI_MAXSHORTLEN];
int n = LoadInteger(S, (prelen < 0 ? LoadByte(S) : prelen)) - 1;
if (n < 0)
return NULL;
if (S->useStrRefs)
ts = S->TS[n];
else if (n <= LUAI_MAXSHORTLEN) { /* short string? */
LoadVector(S, buff, n);
ts = luaS_newlstr(S->L, buff, n);
} else { /* long string */
ts = luaS_createlngstrobj(S->L, n);
LoadVector(S, getstr(ts), n); /* load directly in final place */
}
return ts;
}
#define LoadString(S) LoadString_(S,-1)
#define LoadString2(S,pl) LoadString_(S,(pl))
static void LoadCode (LoadState *S, Proto *f) {
Instruction *p;
f->sizecode = LoadInt(S);
f->code = luaM_newvector(S->L, f->sizecode, Instruction);
LoadVector(S, f->code, f->sizecode);
if (S->mode != MODE_RAM) {
p = StoreN(S, f->code, f->sizecode);
luaM_freearray(S->L, f->code, f->sizecode);
f->code = p;
}
}
static void *LoadFunction(LoadState *S, Proto *f, TString *psource);
static void LoadConstants (LoadState *S, Proto *f) {
int i;
f->sizek = LoadInt(S);
f->k = NewVector(S, f->sizek, TValue);
for (i = 0; i < f->sizek; i++) {
TValue o;
/*
* tt is formatted 0bFTTTDDDD where TTT is the type; the F and the DDDD
* fields are used by the integer decoder as this often saves a byte in
* the endcoding.
*/
lu_byte tt = LoadByte(S);
switch (tt & LUAU_TMASK) {
case LUAU_TNIL:
setnilvalue(&o);
break;
case LUAU_TBOOLEAN:
setbvalue(&o, !(tt == LUAU_TBOOLEAN));
break;
case LUAU_TNUMFLT:
setfltvalue(&o, LoadNumber(S));
break;
case LUAU_TNUMPINT:
case LUAU_TNUMNINT:
setivalue(&o, LoadInteger(S, tt));
break;
case LUAU_TSSTRING:
o.value_.gc = cast(GCObject *, LoadString2(S, tt));
o.tt_ = ctb(LUA_TSHRSTR);
break;
case LUAU_TLSTRING:
o.value_.gc = cast(GCObject *, LoadString2(S, tt));
o.tt_ = ctb(LUA_TLNGSTR);
break;
default:
lua_assert(0);
}
StoreR(S, f->k, i, o, FMT_TVALUE);
}
}
/*
** The handling of Protos has support both modes, and in the case of flash
** mode, this requires some care as any writes to a Proto f must be deferred
** until after all of the writes to its sub Protos have been completed; so
** the Proto record and its p vector must be retained in RAM until stored to
** flash.
**
** Recovery of dead resources on error handled by the Lua GC as standard in
** the case of RAM loading. In the case of loading an LFS image into flash,
** the error recovery could be done through the S->protogc list, but given
** that the immediate action is to restart the CPU, there is little point
** in adding the extra functionality to recover these dangling resources.
*/
static void LoadProtos (LoadState *S, Proto *f) {
int i, n = LoadInt(S);
Proto **p = luaM_newvector(S->L, n, Proto *);
f->p = p;
f->sizep = n;
memset (p, 0, n * sizeof(*p));
for (i = 0; i < n; i++)
p[i] = LoadFunction(S, luaF_newproto(S->L), f->source);
if (S->mode != MODE_RAM) {
f->p = StoreAV(S, cast(void **, p), n);
luaM_freearray(S->L, p, n);
}
}
static void LoadUpvalues (LoadState *S, Proto *f) {
int i, nostripnames = LoadByte(S);
f->sizeupvalues = LoadInt(S);
if (f->sizeupvalues) {
f->upvalues = NewVector(S, f->sizeupvalues, Upvaldesc);
for (i = 0; i < f->sizeupvalues ; i++) {
TString *name = nostripnames ? LoadString(S) : NULL;
Upvaldesc uv = {name, LoadByte(S), LoadByte(S)};
StoreR(S, f->upvalues, i, uv, FMT_UPVALUE);
}
}
}
static void LoadDebug (LoadState *S, Proto *f) {
int i;
f->sizelineinfo = LoadInt(S);
if (f->sizelineinfo) {
lu_byte *li = luaM_newvector(S->L, f->sizelineinfo, lu_byte);
LoadVector(S, li, f->sizelineinfo);
if (S->mode == MODE_RAM) {
f->lineinfo = li;
} else {
f->lineinfo = StoreN(S, li, f->sizelineinfo);
luaM_freearray(S->L, li, f->sizelineinfo);
}
}
f->sizelocvars = LoadInt(S);
f->locvars = NewVector(S, f->sizelocvars, LocVar);
for (i = 0; i < f->sizelocvars; i++) {
LocVar lv = {LoadString(S), LoadInt(S), LoadInt(S)};
StoreR(S, f->locvars, i, lv, FMT_LOCVAR);
}
}
static void *LoadFunction (LoadState *S, Proto *f, TString *psource) {
/*
* Main protos have f->source naming the file used to create the hierarchy;
* subordinate protos set f->source != NULL to inherit this name from the
* parent. In LFS mode, the Protos are moved from the GC to a local list
* in S, but no error GC is attempted as discussed in LoadProtos.
*/
Proto *p;
global_State *g = G(S->L);
if (S->mode != MODE_RAM) {
lua_assert(g->allgc == obj2gco(f));
g->allgc = f->next; /* remove object from 'allgc' list */
f->next = S->protogc; /* push f into the head of the protogc list */
S->protogc = obj2gco(f);
}
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);
LoadProtos(S, f);
LoadCode(S, f);
LoadConstants(S, f);
LoadUpvalues(S, f);
LoadDebug(S, f);
if (S->mode != MODE_RAM) {
GCObject *save = f->next;
if (f->source != NULL) {
setLFSbit(f);
/* cache the RAM next and set up the next for the LFS proto chain */
f->next = FHaddr(S, GCObject *, S->fh->protoHead);
p = StoreR(S, NULL, 0, *f, FMT_PROTO);
S->fh->protoHead = FHoffset(S, p);
} else {
p = StoreR(S, NULL, 0, *f, FMT_PROTO);
}
S->protogc = save; /* pop f from the head of the protogc list */
luaM_free(S->L, f); /* and collect the dead resource */
f = p;
}
return 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, int format) {
checkliteral(S, LUA_SIGNATURE + 1, "not a"); /* 1st char already checked */
if (LoadByte(S) != LUAC_VERSION)
error(S, "version mismatch in");
if (LoadByte(S) != format)
error(S, "format mismatch in");
checkliteral(S, LUAC_DATA, "corrupted");
checksize(S, int);
/*
* The standard Lua VM does a check on the sizeof size_t and endian check on
* integer; both are dropped as the former prevents dump files being shared
* across 32 and 64 bit machines, and we use multi-byte coding of ints.
*/
checksize(S, Instruction);
checksize(S, lua_Integer);
checksize(S, lua_Number);
LoadByte(S); /* skip number tt field */
if (LoadNumber(S) != LUAC_NUM)
error(S, "float format mismatch in");
}
/*
** Load precompiled chunk to support standard LUA_API load functions. The
** extra LFS functionality is effectively NO-OPed out on this MODE_RAM path.
*/
LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
LoadState S = {0};
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.mode = MODE_RAM;
S.fh = NULL;
S.useStrRefs = 0;
checkHeader(&S, LUAC_FORMAT);
cl = luaF_newLclosure(L, LoadByte(&S));
setclLvalue(L, L->top, cl);
luaD_inctop(L);
cl->p = luaF_newproto(L);
LoadFunction(&S, cl->p, NULL);
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
return cl;
}
/*============================================================================**
** NodeMCU extensions for LFS support and Loading. Note that this funtionality
** is called from a hook in the lua startup within a lua_lock() (as with
** LuaU_undump), so luaU_undumpLFS() cannot use the external Lua API. It does
** uses the Lua stack, but staying within LUA_MINSTACK limits.
**
** The in-RAM Protos used to assemble proto content prior to writing to LFS
** need special treatment since these hold LFS references rather than RAM ones
** and will cause the Lua GC to error if swept. Rather than adding complexity
** to lgc.c for this one-off process, these Protos are removed from the allgc
** list and fixed in a local one, and collected inline.
**============================================================================*/
/*
** Write a TString to the LFS. This parallels the lstring.c algo but writes
** directly to the LFS buffer and also append the LFS address in S->TS. Seeding
** is based on the seed defined in the LFS image, rather than g->seed.
*/
static void addTS(LoadState *S, int l, int extra) {
LFSHeader *fh = S->fh;
TString *ts = cast(TString *, S->buff);
char *s = getstr(ts);
lua_assert (sizelstring(l) <= S->buffLen);
s[l] = '\0';
/* The collectable and LFS bits must be set; all others inc the whitebits clear */
ts->marked = bitmask(LFSBIT) | BIT_ISCOLLECTABLE;
ts->extra = extra;
if (l <= LUAI_MAXSHORTLEN) { /* short string */
TString **p;
ts->tt = LUA_TSHRSTR;
ts->shrlen = cast_byte(l);
ts->hash = luaS_hash(s, l, fh->seed);
p = S->list + lmod(ts->hash, S->listLen);
ts->u.hnext = *p;
ts->next = FHaddr(S, GCObject *, fh->shortTShead);
S->TS[S->TSndx] = *p = StoreR(S, NULL, 0, *ts, FMT_TSTRING);
fh->shortTShead = FHoffset(S, *p);
} else { /* long string */
TString *p;
ts->tt = LUA_TLNGSTR;
ts->shrlen = 0;
ts->u.lnglen = l;
ts->hash = fh->seed;
luaS_hashlongstr(ts); /* sets hash and extra fields */
ts->next = FHaddr(S, GCObject *, fh->longTShead);
S->TS[S->TSndx] = p = StoreR(S, NULL, 0, *ts, FMT_TSTRING);
fh->longTShead = FHoffset(S, p);
}
// printf("%04u(%u): %s\n", S->TSndx, l, S->buff + sizeof(union UTString));
StoreN(S,S->buff + sizeof(union UTString), l+1);
S->TSndx++;
}
/*
** The runtime (in ltm.c and llex.c) declares ~100 fixed strings and so these
** are moved into LFS to free up an extra ~2Kb RAM. Extra get token access
** functions have been added to these modules. These tokens aren't unique as
** ("nil" and "function" are both tokens and typenames), hardwiring this
** duplication debounce as a wrapper around addTS() is the simplest way of
** voiding the need for extra lookup resources.
*/
static void addTSnodup(LoadState *S, const char *s, int extra) {
int i, l = strlen(s);
static struct {const char *k; int found; } t[] = {{"nil", 0},{"function", 0}};
for (i = 0; i < sizeof(t)/sizeof(*t); i++) {
if (!strcmp(t[i].k, s)) {
if (t[i].found) return; /* ignore the duplicate copy */
t[i].found = 1; /* flag that this constant is already loaded */
break;
}
}
memcpy(getstr(cast(TString *, S->buff)), s, l);
addTS(S, l, extra);
}
/*
** Load TStrings in dump format. ALl TStrings used in an LFS image excepting
** any fixed strings are dumped as a unique collated set. Any strings in the
** following Proto streams use an index reference into this list rather than an
** inline copy. This function loads and stores them into LFS, constructing the
** ROstrt for the shorter interned strings.
*/
static void LoadAllStrings (LoadState *S) {
lua_State *L = S->L;
global_State *g = G(L);
int nb = sizelstring(LoadInt(S));
int ns = LoadInt(S);
int nl = LoadInt(S);
int nstrings = LoadInt(S);
int n = ns + nl;
int nlist = 1<<luaO_ceillog2(ns);
int i, extra;
const char *p;
/* allocate dynamic resources and save in S for error path collection */
S->TS = luaM_newvector(L, n+1, TString *);
S->TSlen = n+1;
S->buff = luaM_newvector(L, nb, char);
S->buffLen = nb;
S->list = luaM_newvector(L, nlist, TString *);
S->listLen = nlist;
memset (S->list, 0, nlist*sizeof(TString *));
/* add the strings in the image file to LFS */
for (i = 1; i <= nstrings; i++) {
int tt = LoadByte(S);
lua_assert((tt&LUAU_TMASK)==LUAU_TSSTRING || (tt&LUAU_TMASK)==LUAU_TLSTRING);
int l = LoadInteger(S, tt) - 1; /* No NULL entry in list of TSs */
LoadVector(S, getstr(cast(TString *, S->buff)), l);
addTS(S, l, 0);
}
/* add the fixed strings to LFS */
for (i = 0; (p = luaX_getstr(i, &extra))!=NULL; i++) {
addTSnodup(S, p, extra);
}
addTSnodup(S, getstr(g->memerrmsg), 0);
addTSnodup(S, LUA_ENV, 0);
for (i = 0; (p = luaT_getstr(i))!=NULL; i++) {
addTSnodup(S, p, 0);
}
/* check that the actual size is the same as the predicted */
lua_assert(n == S->TSndx-1);
S->fh->oROhash = FHoffset(S, StoreAV(S, S->list, nlist));
S->fh->nROuse = ns;
S->fh->nROsize = nlist;
StoreFlush(S);
S->buff = luaM_freearray(L, S->buff, nb);
S->buffLen = 0;
S->list = luaM_freearray(L, S->list, nlist);
S->listLen = 0;
}
static void LoadAllProtos (LoadState *S) {
lua_State *L = S->L;
ROTable_entry eol = {NULL, LRO_NILVAL};
int i, n = LoadInt(S);
S->pv = luaM_newvector(L, n, Proto *);
S->pvLen = n;
/* Load Protos and store addresses in the Proto vector */
for (i = 0; i < n; i++) {
S->pv[i] = LoadFunction(S, luaF_newproto(L), NULL);
}
/* generate the ROTable entries from first N constants; the last is a timestamp */
lua_assert(n+1 == LoadInt(S));
ROTable_entry *entry_list = cast(ROTable_entry *, StoreGetPos(S));
for (i = 0; i < n; i++) {
lu_byte tt_data = LoadByte(S);
TString *Tname = LoadString2(S, tt_data);
const char *name = getstr(Tname) + OFFSET_TSTRING;
lua_assert((tt_data & LUAU_TMASK) == LUAU_TSSTRING);
ROTable_entry me = {name, LRO_LUDATA(S->pv[i])};
StoreR(S, NULL, 0, me, FMT_ROTENTRY);
}
StoreR(S, NULL, 0, eol, FMT_ROTENTRY);
/* terminate the ROTable entry list and store the ROTable header */
ROTable ev = { (GCObject *)1, LUA_TTBLROF, LROT_MARKED,
(lu_byte) ~0, n, NULL, entry_list};
S->fh->protoROTable = FHoffset(S, StoreR(S, NULL, 0, ev, FMT_ROTABLE));
/* last const is timestamp */
S->fh->timestamp = LoadInteger(S, LoadByte(S));
}
static void undumpLFS(lua_State *L, void *ud) {
LoadState *S = cast(LoadState *, ud);
void *F = S->Z->data;
S->startLFS = StoreGetPos(S);
luaN_setFlash(F, sizeof(LFSHeader));
S->fh->flash_sig = FLASH_SIG;
if (LoadByte(S) != LUA_SIGNATURE[0])
error(S, "invalid header in");
checkHeader(S, LUAC_LFS_IMAGE_FORMAT);
S->fh->seed = LoadInteger(S, LoadByte(S));
checkliteral(S, LUA_STRING_SIG,"no string vector");
LoadAllStrings (S);
checkliteral(S, LUA_PROTO_SIG,"no Proto vector");
LoadAllProtos(S);
S->fh->flash_size = byteptr(StoreGetPos(S)) - byteptr(S->startLFS);
luaN_setFlash(F, 0);
StoreN(S, S->fh, 1);
luaN_setFlash(F, 0);
S->TS = luaM_freearray(L, S->TS, S->TSlen);
}
/*
** Load precompiled LFS image. This is called from a hook in the firmware
** startup if LFS reload is required.
*/
LUAI_FUNC int luaU_undumpLFS(lua_State *L, ZIO *Z, int isabs) {
LFSHeader fh = {0};
LoadState S = {0};
int status;
S.L = L;
S.Z = Z;
S.mode = isabs && sizeof(size_t) != sizeof(lu_int32) ? MODE_LFSA : MODE_LFS;
S.useStrRefs = 1;
S.fh = &fh;
L->nny++; /* do not yield during undump LFS */
status = luaD_pcall(L, undumpLFS, &S, savestack(L, L->top), L->errfunc);
luaM_freearray(L, S.TS, S.TSlen);
luaM_freearray(L, S.buff, S.buffLen);
luaM_freearray(L, S.list, S.listLen);
luaM_freearray(L, S.pv, S.pvLen);
L->nny--;
return status;
}
/*
** $Id: lundump.h,v 1.45.1.1 2017/04/19 17:20:42 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"
/* These allow a multi=byte flag:1,type:3,data:4 packing in the tt byte */
#define LUAU_TNIL (0<<4)
#define LUAU_TBOOLEAN (1<<4)
#define LUAU_TNUMFLT (2<<4)
#define LUAU_TNUMPINT (3<<4)
#define LUAU_TNUMNINT (4<<4)
#define LUAU_TSSTRING (5<<4)
#define LUAU_TLSTRING (6<<4)
#define LUAU_TMASK (7<<4)
#define LUAU_DMASK 0x0f
/* 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 LUAC_FUNC_MARKER 0xFE
#define LUA_TNUMNINT (LUA_TNUMBER | (2 << 4)) /* negative integer numbers */
#define MYINT(s) (s[0]-'0')
#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR))
#define LUAC_FORMAT 10 /* this is the NodeMCU format */
#define LUAC_LFS_IMAGE_FORMAT 11
#define LUA_STRING_SIG "\x19ss"
#define LUA_PROTO_SIG "\x19pr"
#define LUA_HDR_BYTE '\x19'
/* load one chunk; from lundump.c */
LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, 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);
LUAI_FUNC int luaU_DumpAllProtos(lua_State *L, const Proto *m, lua_Writer w,
void *data, int strip);
LUAI_FUNC int luaU_undumpLFS(lua_State *L, ZIO *Z, int isabs);
LUAI_FUNC int luaU_stripdebug (lua_State *L, Proto *f, int level, int recv);
typedef struct FlashHeader LFSHeader;
/*
** The LFSHeader uses offsets rather than pointers to avoid 32 vs 64 bit issues
** during host compilation. The offsets are in units of lu_int32's and NOT
** size_t, though clearly any internal pointers are of the size_t for the
** executing architectures: 4 or 8 byte. Likewise recources are size_t aligned
** so LFS regions built for 64-bit execution will have 4-byte alignment packing
** between resources.
*/
struct FlashHeader{
lu_int32 flash_sig; /* a standard fingerprint identifying an LFS image */
lu_int32 flash_size; /* Size of LFS image in bytes */
lu_int32 seed; /* random number seed used in LFS */
lu_int32 timestamp; /* timestamp of LFS build */
lu_int32 nROuse; /* number of elements in ROstrt */
lu_int32 nROsize; /* size of ROstrt */
lu_int32 oROhash; /* offset of TString ** ROstrt hash */
lu_int32 protoROTable; /* offset of master ROTable for proto lookup */
lu_int32 protoHead; /* offset of linked list of Protos in LFS */
lu_int32 shortTShead; /* offset of linked list of short TStrings in LFS */
lu_int32 longTShead; /* offset of linked list of long TStrings in LFS */
lu_int32 reserved;
};
#ifdef LUA_USE_HOST
extern void *LFSregion;
LUAI_FUNC void luaN_setabsolute(lu_int32 addr);
#endif
#define FLASH_FORMAT_VERSION ( 2 << 8)
#define FLASH_SIG_B1 0x06
#define FLASH_SIG_B2 0x02
#define FLASH_SIG_PASS2 0x0F
#define FLASH_FORMAT_MASK 0xF00
#define FLASH_SIG_B2_MASK 0x04
#define FLASH_SIG_ABSOLUTE 0x01
#define FLASH_SIG_IN_PROGRESS 0x08
#define FLASH_SIG (0xfafaa050 | FLASH_FORMAT_VERSION)
#define FLASH_FORMAT_MASK 0xF00
#endif
/*
** $Id: lutf8lib.c,v 1.16.1.1 2017/04/19 17:29:57 roberto Exp $
** Standard library for UTF-8 manipulation
** See Copyright Notice in lua.h
*/
#define lutf8lib_c
#define LUA_LIB
#include "lprefix.h"
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#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 const 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 */
if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */
return luaL_error(L, "string slice too long");
n = (int)(pose - posi) + 1;
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))
return 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 int utf8_lookup (lua_State *L) {
const char *key = lua_tostring(L,2);
if (strcmp(key,"charpattern"))
lua_pushnil(L);
else
lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1);
return 1;
}
LROT_BEGIN(utf8_meta, NULL, LROT_MASK_INDEX)
LROT_FUNCENTRY( __index, utf8_lookup )
LROT_END(utf8_meta, NULL, LROT_MASK_INDEX)
LROT_BEGIN(utf8, LROT_TABLEREF(utf8_meta), 0)
LROT_FUNCENTRY( offset, byteoffset )
LROT_FUNCENTRY( codepoint, codepoint )
LROT_FUNCENTRY( char, utfchar )
LROT_FUNCENTRY( len, utflen )
LROT_FUNCENTRY( codes, iter_codes )
LROT_END(utf8, LROT_TABLEREF(utf8_meta), 0)
LUAMOD_API int luaopen_utf8 (lua_State *L) {
(void)L;
return 0;
}
/*
** $Id: lvm.c,v 2.268.1.1 2017/04/19 17:39:34 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
#define lvm_c
#define LUA_CORE
#include "lprefix.h"
#include <float.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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 2000
/*
** 'l_intfitsf' checks whether a given integer can be converted to a
** float without rounding. Used in comparisons. Left undefined if
** all integers fit in a float precisely.
*/
#if !defined(l_intfitsf)
/* number of bits in the mantissa of a float */
#define NBM (l_mathlim(MANT_DIG))
/*
** Check whether some integers may not fit in a float, that is, whether
** (maxinteger >> NBM) > 0 (that implies (1 << NBM) <= maxinteger).
** (The shifts are done in parts to avoid shifting by more than the size
** of an integer. In a worst case, NBM == 113 for long double and
** sizeof(integer) == 32.)
*/
#if ((((LUA_MAXINTEGER >> (NBM / 4)) >> (NBM / 4)) >> (NBM / 4)) \
>> (NBM - (3 * (NBM / 4)))) > 0
#define l_intfitsf(i) \
(-((lua_Integer)1 << NBM) <= (i) && (i) <= ((lua_Integer)1 << NBM))
#endif
#endif
/*
** 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) == vslen(obj) + 1) {
*n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */
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
*/
int luaV_tointeger (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) == vslen(obj) + 1) {
obj = &v;
goto again; /* convert result from 'luaO_str2num' to an integer */
}
return 0; /* conversion failed */
}
/*
** 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 (!luaV_tointeger(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 (luai_numlt(0, n)) { /* 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;
}
/*
** Finish the table access 'val = t[key]'.
** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to
** t[k] entry (which must be nil).
*/
void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,
const TValue *slot) {
int loop; /* counter to avoid infinite loops */
const TValue *tm; /* metamethod */
for (loop = 0; loop < MAXTAGLOOP; loop++) {
if (slot == NULL) { /* 't' is not a table? */
lua_assert(!ttistable(t));
tm = luaT_gettmbyobj(L, t, TM_INDEX);
if (ttisnil(tm))
luaG_typeerror(L, t, "index"); /* no metamethod */
/* else will try the metamethod */
}
else { /* 't' is a table */
lua_assert(ttisnil(slot));
tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */
if (tm == NULL) { /* no metamethod? */
setnilvalue(val); /* result is nil */
return;
}
/* else will try the metamethod */
}
if (ttisfunction(tm)) { /* is metamethod a function? */
luaT_callTM(L, tm, t, key, val, 1); /* call it */
return;
}
t = tm; /* else try to access 'tm[key]' */
if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */
setobj2s(L, val, slot); /* done */
return;
}
/* else repeat (tail call 'luaV_finishget') */
}
luaG_runerror(L, "'__index' chain too long; possible loop");
}
/*
** Finish a table assignment 't[key] = val'.
** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points
** to the entry 't[key]', or to 'luaO_nilobject' if there is no such
** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset'
** would have done the job.)
*/
void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *slot) {
int loop; /* counter to avoid infinite loops */
for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm; /* '__newindex' metamethod */
if (slot != NULL) { /* is 't' a table? */
Table *h = hvalue(t); /* save 't' table */
lua_assert(ttisnil(slot)); /* old value must be nil */
tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */
if (tm == NULL) { /* no metamethod? */
if (slot == luaO_nilobject) /* no previous entry? */
slot = luaH_newkey(L, h, key); /* create one */
/* no metamethod and (now) there is an entry with given key */
setobj2t(L, cast(TValue *, slot), val); /* set its new value */
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' */
if (luaV_fastset(L, t, key, slot, luaH_get, val))
return; /* done */
/* else loop */
}
luaG_runerror(L, "'__newindex' 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'.
** Stripped down version for NodeMCU without locales support
*/
static int l_strcmp (const TString *ls, const TString *rs) {
const char *l = getstr(ls);
const char *r = getstr(rs);
if (l == r) {
return 0;
} else {
size_t ll = tsslen(ls);
size_t lr = tsslen(rs);
size_t lm = ll<lr ? ll : lr;
int s = memcmp(l, r, lm);
return s ? s : (lr == lm ? (ll == lm ? 0 : 1) : -1);
}
}
/*
** Check whether integer 'i' is less than float 'f'. If 'i' has an
** exact representation as a float ('l_intfitsf'), compare numbers as
** floats. Otherwise, if 'f' is outside the range for integers, result
** is trivial. Otherwise, compare them as integers. (When 'i' has no
** float representation, either 'f' is "far away" from 'i' or 'f' has
** no precision left for a fractional part; either way, how 'f' is
** truncated is irrelevant.) When 'f' is NaN, comparisons must result
** in false.
*/
static int LTintfloat (lua_Integer i, lua_Number f) {
#if defined(l_intfitsf)
if (!l_intfitsf(i)) {
if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */
return 1; /* f >= maxint + 1 > i */
else if (f > cast_num(LUA_MININTEGER)) /* minint < f <= maxint ? */
return (i < cast(lua_Integer, f)); /* compare them as integers */
else /* f <= minint <= i (or 'f' is NaN) --> not(i < f) */
return 0;
}
#endif
return luai_numlt(cast_num(i), f); /* compare them as floats */
}
/*
** Check whether integer 'i' is less than or equal to float 'f'.
** See comments on previous function.
*/
static int LEintfloat (lua_Integer i, lua_Number f) {
#if defined(l_intfitsf)
if (!l_intfitsf(i)) {
if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */
return 1; /* f >= maxint + 1 > i */
else if (f >= cast_num(LUA_MININTEGER)) /* minint <= f <= maxint ? */
return (i <= cast(lua_Integer, f)); /* compare them as integers */
else /* f < minint <= i (or 'f' is NaN) --> not(i <= f) */
return 0;
}
#endif
return luai_numle(cast_num(i), f); /* compare them as floats */
}
/*
** Return 'l < r', for numbers.
*/
static int LTnum (const TValue *l, const TValue *r) {
if (ttisinteger(l)) {
lua_Integer li = ivalue(l);
if (ttisinteger(r))
return li < ivalue(r); /* both are integers */
else /* 'l' is int and 'r' is float */
return LTintfloat(li, fltvalue(r)); /* l < r ? */
}
else {
lua_Number lf = fltvalue(l); /* 'l' must be float */
if (ttisfloat(r))
return luai_numlt(lf, fltvalue(r)); /* both are float */
else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */
return 0; /* NaN < i is always false */
else /* without NaN, (l < r) <--> not(r <= l) */
return !LEintfloat(ivalue(r), lf); /* not (r <= l) ? */
}
}
/*
** Return 'l <= r', for numbers.
*/
static int LEnum (const TValue *l, const TValue *r) {
if (ttisinteger(l)) {
lua_Integer li = ivalue(l);
if (ttisinteger(r))
return li <= ivalue(r); /* both are integers */
else /* 'l' is int and 'r' is float */
return LEintfloat(li, fltvalue(r)); /* l <= r ? */
}
else {
lua_Number lf = fltvalue(l); /* 'l' must be float */
if (ttisfloat(r))
return luai_numle(lf, fltvalue(r)); /* both are float */
else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */
return 0; /* NaN <= i is always false */
else /* without NaN, (l <= r) <--> not(r < l) */
return !LTintfloat(ivalue(r), lf); /* not (r < l) ? */
}
}
/*
** Main operation less than; return 'l < r'.
*/
int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
int res;
if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */
return LTnum(l, r);
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'. If it needs
** a metamethod and there is no '__le', try '__lt', based on
** l <= r iff !(r < l) (assuming a total order). If the metamethod
** yields during this substitution, the continuation has to know
** about it (to negate the result of r<l); bit CIST_LEQ in the call
** status keeps that information.
*/
int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {
int res;
if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */
return LEnum(l, r);
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) /* try 'le' */
return res;
else { /* try 'lt': */
L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */
res = luaT_callorderTM(L, r, l, TM_LT);
L->ci->callstatus ^= CIST_LEQ; /* clear mark */
if (res < 0)
luaG_ordererror(L, l, r);
return !res; /* result is negated */
}
}
/*
** 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_Integer i1, i2; /* compare them as integers */
return (tointeger(t1, &i1) && tointeger(t2, &i2) && i1 == i2);
}
}
/* 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_TTBLRAM:
case LUA_TTBLROF: {
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)))
#define isemptystr(o) (ttisshrstring(o) && getshrlen(tsvalue(o)) == 0)
/* copy strings in stack from top - n up to top - 1 to buffer */
static void copy2buff (StkId top, int n, char *buff) {
size_t tl = 0; /* size already copied */
do {
size_t l = vslen(top - n); /* length of string being copied */
memcpy(buff + tl, svalue(top - n), l * sizeof(char));
tl += l;
} while (--n > 0);
}
/*
** 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 (isemptystr(top - 1)) /* second operand is empty? */
cast_void(tostring(L, top - 2)); /* result is first operand */
else if (isemptystr(top - 2)) { /* first operand is an empty string? */
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 = vslen(top - 1);
TString *ts;
/* collect total length and number of strings */
for (n = 1; n < total && tostring(L, top - n - 1); n++) {
size_t l = vslen(top - n - 1);
if (l >= (MAX_SIZE/sizeof(char)) - tl)
luaG_runerror(L, "string length overflow");
tl += l;
}
if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */
char buff[LUAI_MAXSHORTLEN];
copy2buff(top, n, buff); /* copy strings to buffer */
ts = luaS_newlstr(L, buff, tl);
}
else { /* long string; copy strings directly to final result */
ts = luaS_createlngstrobj(L, tl);
copy2buff(top, n, getstr(ts));
}
setsvalue2s(L, top - n, ts); /* 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 (ttype(rb)) {
case LUA_TTABLE: {
Table *h = hvalue(rb);
tm = fasttm(L, h->metatable, TM_LEN);
if (tm) break; /* metamethod? break switch to call it */
setivalue(ra, luaH_getn(h)); /* else primitive len */
return;
}
case LUA_TSHRSTR: {
setivalue(ra, getshrlen(tsvalue(rb)));
return;
}
case LUA_TLNGSTR: {
setivalue(ra, tsvalue(rb)->u.lnglen);
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);
}
}
/*
** 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 */
}
}
/*
** 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--;
if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */
lua_assert(op == OP_LE);
ci->callstatus ^= CIST_LEQ; /* clear mark */
res = !res; /* negate 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'
*/
#define RA(i) (base+GETARG_A(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))
/* 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) \
{ luaC_condGC(L, L->top = (c), /* limit of live values */ \
Protect(L->top = ci->top)); /* restore top */ \
luai_threadyield(L); }
/* fetch an instruction and prepare its execution */
#define vmfetch() { \
i = *(ci->u.l.savedpc++); \
if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) \
Protect(luaG_traceexec(L)); \
ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
lua_assert(base == ci->u.l.base); \
lua_assert(base <= L->top && L->top < L->stack + L->stacksize); \
}
#define vmdispatch(o) switch(o)
#define vmcase(l) case l:
#define vmbreak break
/*
** copy of 'luaV_gettable', but protecting the call to potential
** metamethod (which can reallocate the stack)
*/
#define gettableProtected(L,t,k,v) { const TValue *slot; \
if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
else Protect(luaV_finishget(L,t,k,v,slot)); }
/* same for 'luaV_settable' */
#define settableProtected(L,t,k,v) { const TValue *slot; \
if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \
Protect(luaV_finishset(L,t,k,v,slot)); }
void luaV_execute (lua_State *L) {
CallInfo *ci = L->ci;
LClosure *cl;
TValue *k;
StkId base;
ci->callstatus |= CIST_FRESH; /* fresh invocation of 'luaV_execute" */
newframe: /* reentry point when frame changes (call/return) */
lua_assert(ci == L->ci);
cl = clLvalue(ci->func); /* local reference to function's closure */
k = cl->p->k; /* local reference to function's constant table */
base = ci->u.l.base; /* local copy of function's base */
/* main loop of interpreter */
for (;;) {
Instruction i;
StkId ra;
vmfetch();
vmdispatch (GET_OPCODE(i)) {
vmcase(OP_MOVE) {
setobjs2s(L, ra, RB(i));
vmbreak;
}
vmcase(OP_LOADK) {
TValue *rb = k + GETARG_Bx(i);
setobj2s(L, ra, rb);
vmbreak;
}
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);
vmbreak;
}
vmcase(OP_LOADBOOL) {
setbvalue(ra, GETARG_B(i));
if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */
vmbreak;
}
vmcase(OP_LOADNIL) {
int b = GETARG_B(i);
do {
setnilvalue(ra++);
} while (b--);
vmbreak;
}
vmcase(OP_GETUPVAL) {
int b = GETARG_B(i);
setobj2s(L, ra, cl->upvals[b]->v);
vmbreak;
}
vmcase(OP_GETTABUP) {
TValue *upval = cl->upvals[GETARG_B(i)]->v;
TValue *rc = RKC(i);
gettableProtected(L, upval, rc, ra);
vmbreak;
}
vmcase(OP_GETTABLE) {
StkId rb = RB(i);
TValue *rc = RKC(i);
gettableProtected(L, rb, rc, ra);
vmbreak;
}
vmcase(OP_SETTABUP) {
TValue *upval = cl->upvals[GETARG_A(i)]->v;
TValue *rb = RKB(i);
TValue *rc = RKC(i);
settableProtected(L, upval, rb, rc);
vmbreak;
}
vmcase(OP_SETUPVAL) {
UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, ra);
luaC_upvalbarrier(L, uv);
vmbreak;
}
vmcase(OP_SETTABLE) {
TValue *rb = RKB(i);
TValue *rc = RKC(i);
settableProtected(L, ra, rb, rc);
vmbreak;
}
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);
vmbreak;
}
vmcase(OP_SELF) {
const TValue *aux;
StkId rb = RB(i);
TValue *rc = RKC(i);
TString *key = tsvalue(rc); /* key must be a string */
setobjs2s(L, ra + 1, rb);
if (luaV_fastget(L, rb, key, aux, luaH_getstr)) {
setobj2s(L, ra, aux);
}
else Protect(luaV_finishget(L, rb, rc, ra, aux));
vmbreak;
}
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)); }
vmbreak;
}
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)); }
vmbreak;
}
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)); }
vmbreak;
}
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)); }
vmbreak;
}
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)); }
vmbreak;
}
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)); }
vmbreak;
}
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)); }
vmbreak;
}
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)); }
vmbreak;
}
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)); }
vmbreak;
}
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)); }
vmbreak;
}
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)); }
vmbreak;
}
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)); }
vmbreak;
}
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));
}
vmbreak;
}
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));
}
vmbreak;
}
vmcase(OP_NOT) {
TValue *rb = RB(i);
int res = l_isfalse(rb); /* next assignment may change this value */
setbvalue(ra, res);
vmbreak;
}
vmcase(OP_LEN) {
Protect(luaV_objlen(L, ra, RB(i)));
vmbreak;
}
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 = base + b;
setobjs2s(L, ra, rb);
checkGC(L, (ra >= rb ? ra + 1 : rb));
L->top = ci->top; /* restore top */
vmbreak;
}
vmcase(OP_JMP) {
dojump(ci, i, 0);
vmbreak;
}
vmcase(OP_EQ) {
TValue *rb = RKB(i);
TValue *rc = RKC(i);
Protect(
if (luaV_equalobj(L, rb, rc) != GETARG_A(i))
ci->u.l.savedpc++;
else
donextjump(ci);
)
vmbreak;
}
vmcase(OP_LT) {
Protect(
if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i))
ci->u.l.savedpc++;
else
donextjump(ci);
)
vmbreak;
}
vmcase(OP_LE) {
Protect(
if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i))
ci->u.l.savedpc++;
else
donextjump(ci);
)
vmbreak;
}
vmcase(OP_TEST) {
if (GETARG_C(i) ? l_isfalse(ra) : !l_isfalse(ra))
ci->u.l.savedpc++;
else
donextjump(ci);
vmbreak;
}
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);
}
vmbreak;
}
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 */
Protect((void)0); /* update 'base' */
}
else { /* Lua function */
ci = L->ci;
goto newframe; /* restart luaV_execute over new Lua function */
}
vmbreak;
}
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? */
Protect((void)0); /* update '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 + getnumparams(getproto(nfunc));
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 + getmaxstacksize(getproto(ofunc)));
goto newframe; /* restart luaV_execute over new Lua function */
}
vmbreak;
}
vmcase(OP_RETURN) {
int b = GETARG_B(i);
if (cl->p->sizep > 0) luaF_close(L, base);
b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra)));
if (ci->callstatus & CIST_FRESH) /* local 'ci' still from callee */
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 = intop(+, 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 */
chgivalue(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 */
chgfltvalue(ra, idx); /* update internal index... */
setfltvalue(ra + 3, idx); /* ...and external index */
}
}
vmbreak;
}
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, intop(-, 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);
vmbreak;
}
vmcase(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 = 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 */
}
vmbreak;
}
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++);
}
h = hvalue(ra);
last = ((c-1)*LFIELDS_PER_FLUSH) + n;
if (last > h->sizearray) /* needs more space? */
luaH_resizearray(L, h, last); /* preallocate 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) */
vmbreak;
}
vmcase(OP_CLOSURE) {
Proto *p = cl->p->p[GETARG_Bx(i)];
pushclosure(L, p, cl->upvals, base, ra); /* create a new Closure */
checkGC(L, ra + 1);
vmbreak;
}
vmcase(OP_VARARG) {
int b = GETARG_B(i) - 1; /* required results */
int j;
int n = cast_int(base - ci->func) - getnumparams(cl->p) - 1;
if (n < 0) /* less arguments than parameters? */
n = 0; /* no vararg arguments */
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 < n; j++)
setobjs2s(L, ra + j, base - n + j);
for (; j < b; j++) /* complete required results with nil */
setnilvalue(ra + j);
vmbreak;
}
vmcase(OP_EXTRAARG) {
lua_assert(0);
vmbreak;
}
}
}
}
/* }================================================================== */
/*
** $Id: lvm.h,v 2.41.1.1 2017/04/19 17:20:42 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
/*
** 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
#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,LUA_FLOORN2I))
#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2))
#define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2)
/*
** fast track for 'gettable': if 't' is a table and 't[k]' is not nil,
** return 1 with 'slot' pointing to 't[k]' (final result). Otherwise,
** return 0 (meaning it will have to check metamethod) with 'slot'
** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise).
** 'f' is the raw get function to use.
*/
#define luaV_fastget(L,t,k,slot,f) \
(!ttistable(t) \
? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
: (slot = f(hvalue(t), k), /* else, do raw access */ \
!ttisnil(slot))) /* result not nil? */
/*
** standard implementation for 'gettable'
*/
#define luaV_gettable(L,t,k,v) { const TValue *slot; \
if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
else luaV_finishget(L,t,k,v,slot); }
/*
** Fast track for set table. If 't' is a table and 't[k]' is not nil,
** call GC barrier, do a raw 't[k]=v', and return true; otherwise,
** return false with 'slot' equal to NULL (if 't' is not a table) or
** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro
** returns true, there is no need to 'invalidateTMcache', because the
** call is not creating a new entry.
*/
#define luaV_fastset(L,t,k,slot,f,v) \
(!ttistable(t) \
? (slot = NULL, 0) \
: (slot = f(hvalue(t), k), \
ttisnil(slot) ? 0 \
: (luaC_barrierback(L, hvalue(t), v), \
setobj2t(L, cast(TValue *,slot), v), \
1)))
#define luaV_settable(L,t,k,v) { const TValue *slot; \
if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \
luaV_finishset(L,t,k,v,slot); }
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, int mode);
LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *slot);
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
/*
** $Id: lzio.c,v 1.37.1.1 2017/04/19 17:20:42 roberto Exp $
** Buffered streams
** See Copyright Notice in lua.h
*/
#define lzio_c
#define LUA_CORE
#include "lprefix.h"
#include <string.h>
#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;
}
/*
** $Id: lzio.h,v 1.31.1.1 2017/04/19 17:20:42 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) \
((buff)->buffer = luaM_reallocvchar(L, (buff)->buffer, \
(buff)->buffsize, size), \
(buff)->buffsize = size)
#define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0)
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
/*
** $Id: lua.c,v 1.160.1.2 2007/12/28 15:32:23 roberto Exp $
** Lua stand-alone interpreter
** See Copyright Notice in lua.h
*/
// #include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "user_version.h"
#include "driver/console.h"
#include "esp_system.h"
#include "platform.h"
#define lua_c
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "legc.h"
#include "lflash.h"
lua_State *globalL = NULL;
lua_Load gLoad;
static const char *progname = LUA_PROGNAME;
static void l_message (const char *pname, const char *msg) {
#if defined(LUA_USE_STDIO)
if (pname) fprintf(stderr, "%s: ", pname);
fprintf(stderr, "%s\n", msg);
fflush(stderr);
#else
if (pname) luai_writestringerror("%s: ", pname);
luai_writestringerror("%s\n", msg);
#endif
}
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) {
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) && !lua_isrotable(L, -1)) {
lua_pop(L, 1);
return 1;
}
lua_getfield(L, -1, "traceback");
if (!lua_isfunction(L, -1) && !lua_islightfunction(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 (lua_State *L) {
lua_pushliteral (L, "\n" NODE_VERSION " build " BUILD_DATE " powered by " LUA_RELEASE " on SDK ");
lua_pushstring (L, SDK_VERSION);
lua_concat (L, 2);
const char *msg = lua_tostring (L, -1);
l_message (NULL, msg);
lua_pop (L, 1);
}
#if 0
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;
}
#endif
static int dofsfile (lua_State *L, const char *name) {
int status = luaL_loadfsfile(L, name) || docall(L, 0, 1);
return report(L, status);
}
static int dolfsfile (lua_State *L, const char *name) {
int status = 1;
const char *code_fmt = "if node.flashindex('%s') then node.flashindex('%s')() end";
char *module_name = strdup(name);
unsigned name_len = strlen(name);
unsigned code_length = strlen(code_fmt) + name_len*2 + 1;
char *code_buf = malloc(code_length);
if (code_buf && module_name) {
char *dot = strrchr(module_name, '.');
if (dot) {
if (strstr(module_name, ".lua") == dot)
*dot = 0;
}
snprintf(code_buf, code_length, code_fmt, module_name, module_name);
status = luaL_dostring(L, code_buf);
if (status)
lua_pushfstring(L, "Failed to load %s from LFS", module_name);
} else {
lua_pushstring(L, "Failed to allocate memory");
}
if (module_name)
free(module_name);
if (code_buf)
free(code_buf);
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, docall(L, 1, 1));
}
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("<eof>")) - 1);
if (strstr(msg, LUA_QL("<eof>")) == tp) {
lua_pop(L, 1);
return 1;
}
}
return 0; /* else... */
}
/* 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 '-':
notail(argv[i]);
return (argv[i+1] != NULL ? i+1 : 0);
case '\0':
return i;
case 'i':
notail(argv[i]);
*pi = 1; /* fall-through */
case 'v':
notail(argv[i]);
*pv = 1;
break;
case 'e':
*pe = 1; /* fall-through */
case 'm': /* fall-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 'm': {
const char *limit = argv[i] + 2;
int memlimit=0;
if (*limit == '\0') limit = argv[++i];
lua_assert(limit != NULL);
memlimit = atoi(limit);
lua_gc(L, LUA_GCSETMEMLIMIT, memlimit);
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;
}
#ifndef LUA_INIT_STRING
#define LUA_INIT_STRING "@init.lua"
#endif
static int handle_luainit (lua_State *L) {
(void)dolfsfile; // silence warning about potentially unused function
const char *init = LUA_INIT_STRING;
if (init[0] == '@') {
#if CONFIG_NODEMCU_EMBEDDED_LFS_SIZE > 0
int status = dolfsfile(L, init+1);
if (status == 0)
return status;
#endif
return dofsfile(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);
print_version(L);
s->status = handle_luainit(L);
script = collectargs(argv, &has_i, &has_v, &has_e);
if (script < 0) { /* invalid args? */
s->status = 1;
return 0;
}
s->status = runargs(L, argv, (script > 0) ? script : s->argc);
if (s->status != 0) return 0;
return 0;
}
static void dojob(lua_Load *load);
static bool readline(lua_Load *load);
#ifdef LUA_RPC
int main (int argc, char **argv) {
#else
int lua_main (int argc, char **argv) {
#endif
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);
gLoad.L = L;
gLoad.firstline = 1;
gLoad.done = 0;
gLoad.line = malloc(LUA_MAXINPUT);
gLoad.len = LUA_MAXINPUT;
gLoad.line_position = 0;
gLoad.prmt = get_prompt(L, 1);
dojob(&gLoad);
NODE_DBG("Heap size:%d.\n",system_get_free_heap_size());
legc_set_mode( L, EGC_ALWAYS, 4096 );
// legc_set_mode( L, EGC_ON_MEM_LIMIT, 4096 );
// lua_close(L);
return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
}
int lua_put_line(const char *s, size_t l) {
if (s == NULL || ++l > LUA_MAXINPUT || gLoad.line_position > 0)
return 0;
memcpy(gLoad.line, s, l);
gLoad.line[l] = '\0';
gLoad.line_position = l;
gLoad.done = 1;
NODE_DBG("Get command: %s\n", gLoad.line);
return 1;
}
void lua_handle_input (bool force)
{
while (gLoad.L && (force || readline (&gLoad))) {
NODE_DBG("Handle Input: first=%u, pos=%u, len=%u, actual=%u, line=%s\n", gLoad.firstline,
gLoad.line_position, gLoad.len, strlen(gLoad.line), gLoad.line);
dojob (&gLoad);
force = false;
}
}
void donejob(lua_Load *load){
lua_close(load->L);
}
static void dojob(lua_Load *load){
size_t l;
int status;
char *b = load->line;
lua_State *L = load->L;
const char *oldprogname = progname;
progname = NULL;
do{
if(load->done == 1){
l = strlen(b);
if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
b[l-1] = '\0'; /* remove it */
if (load->firstline && b[0] == '=') /* first line starts with `=' ? */
lua_pushfstring(L, "return %s", b+1); /* change it to `return' */
else
lua_pushstring(L, b);
if(load->firstline != 1){
lua_pushliteral(L, "\n"); /* add a new line... */
lua_insert(L, -2); /* ...between the two lines */
lua_concat(L, 3); /* join them */
}
status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
if (!incomplete(L, status)) { /* cannot try to add lines? */
lua_remove(L, 1); /* remove line */
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)));
}
load->firstline = 1;
load->prmt = get_prompt(L, 1);
lua_settop(L, 0);
/* force a complete garbage collection in case of errors */
if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0);
} else {
load->firstline = 0;
load->prmt = get_prompt(L, 0);
}
}
}while(0);
progname = oldprogname;
load->done = 0;
load->line_position = 0;
memset(load->line, 0, load->len);
printf(load->prmt);
fflush (stdout);
}
extern bool uart_on_data_cb(unsigned id, const char *buf, size_t len);
extern bool uart0_echo;
extern bool run_input;
extern uart_status_t uart_status[];
static char last_nl_char = '\0';
static bool readline(lua_Load *load){
// NODE_DBG("readline() is called.\n");
bool need_dojob = false;
char ch;
uart_status_t *us = & uart_status[CONSOLE_UART];
while (console_getc(&ch))
{
if(run_input)
{
char tmp_last_nl_char = last_nl_char;
// reset marker, will be finally set below when newline is processed
last_nl_char = '\0';
/* handle CR & LF characters
filters second char of LF&CR (\n\r) or CR&LF (\r\n) sequences */
if ((ch == '\r' && tmp_last_nl_char == '\n') || // \n\r sequence -> skip \r
(ch == '\n' && tmp_last_nl_char == '\r')) // \r\n sequence -> skip \n
{
continue;
}
/* backspace key */
else if (ch == 0x7f || ch == 0x08)
{
if (load->line_position > 0)
{
if(uart0_echo) putchar(0x08);
if(uart0_echo) putchar(' ');
if(uart0_echo) putchar(0x08);
load->line_position--;
}
load->line[load->line_position] = 0;
continue;
}
/* EOT(ctrl+d) */
// else if (ch == 0x04)
// {
// if (load->line_position == 0)
// // No input which makes lua interpreter close
// donejob(load);
// else
// continue;
// }
/* end of line */
if (ch == '\r' || ch == '\n')
{
last_nl_char = ch;
load->line[load->line_position] = 0;
if(uart0_echo) putchar('\n');
uart_on_data_cb(CONSOLE_UART, load->line, load->line_position);
if (load->line_position == 0)
{
/* Get a empty line, then go to get a new line */
printf(load->prmt);
fflush (stdout);
} else {
load->done = 1;
need_dojob = true;
}
continue;
}
/* other control character or not an acsii character */
// if (ch < 0x20 || ch >= 0x80)
// {
// continue;
// }
/* echo */
if(uart0_echo) putchar(ch);
/* it's a large line, discard it */
if ( load->line_position + 1 >= load->len ){
load->line_position = 0;
}
}
load->line[load->line_position] = ch;
load->line_position++;
if(!run_input)
{
if( ((us->need_len!=0) && (load->line_position >= us->need_len)) || \
(load->line_position >= load->len) || \
((us->end_char>=0) && ((unsigned char)ch==(unsigned char)us->end_char)) )
{
uart_on_data_cb(CONSOLE_UART, load->line, load->line_position);
load->line_position = 0;
}
}
ch = 0;
}
if( (load->line_position > 0) && (!run_input) && (us->need_len==0) && (us->end_char<0) )
{
uart_on_data_cb(CONSOLE_UART, load->line, load->line_position);
load->line_position = 0;
}
return need_dojob;
}
/*
** Header to allow luac.cross compile within NodeMCU
** See Copyright Notice in lua.h
*/
#ifndef luac_cross_h
#define luac_cross_h
#define C_HEADER_ASSERT <assert.h>
#define C_HEADER_CTYPE <ctype.h>
#define C_HEADER_ERRNO <errno.h>
#define C_HEADER_FCNTL <fcntl.h>
#define C_HEADER_LOCALE <locale.h>
#define C_HEADER_MATH <math.h>
#define C_HEADER_STDIO <stdio.h>
#define C_HEADER_STDLIB <stdlib.h>
#define C_HEADER_STRING <string.h>
#define C_HEADER_TIME <time.h>
#ifdef LUA_CROSS_COMPILER
#define ICACHE_RODATA_ATTR
#endif
#endif /* luac_cross_h */
foreach(def idf_build_set_property(COMPILE_DEFINITIONS -DLUA_USE_ESP APPEND)
"-DLUA_OPTIMIZE_MEMORY=2"
"-DMIN_OPT_LEVEL=2"
"-DLUA_OPTIMIZE_DEBUG=${CONFIG_LUA_OPTIMIZE_DEBUG}"
)
idf_build_set_property(COMPILE_DEFINITIONS ${def} APPEND)
endforeach()
if(CONFIG_LUA_NUMBER_INTEGRAL)
idf_build_set_property(COMPILE_DEFINITIONS -DLUA_NUMBER_INTEGRAL APPEND)
endif()
idf_component_register(luac_cross)
# Not sure why we can't directly depend on ${SDKCONFIG_HEADER} in our
# externalproject_add(), but them's the brakes...
add_custom_command(
OUTPUT sdkconfig.h
COMMAND cp ${SDKCONFIG_HEADER} sdkconfig.h
DEPENDS ${SDKCONFIG_HEADER}
VERBATIM
)
add_custom_target(sdkconfig_h DEPENDS sdkconfig.h)
externalproject_add(luac_cross_build
PREFIX ${BUILD_DIR}/luac_cross
SOURCE_DIR ${COMPONENT_DIR}
CONFIGURE_COMMAND ""
BUILD_COMMAND make -f ${COMPONENT_DIR}/Makefile BUILD_DIR_BASE=${BUILD_DIR} COMPONENT_PATH=${COMPONENT_DIR} CONFIG_LUA_OPTIMIZE_DEBUG=${CONFIG_LUA_OPTIMIZE_DEBUG} PYTHON=${PYTHON}
INSTALL_COMMAND ""
BUILD_ALWAYS 1
DEPENDS sdkconfig_h
)
...@@ -77,9 +77,9 @@ static int can_setup( lua_State *L ) ...@@ -77,9 +77,9 @@ static int can_setup( lua_State *L )
{ {
if(xCanTaskHandle != NULL) if(xCanTaskHandle != NULL)
luaL_error( L, "Stop CAN before setup" ); luaL_error( L, "Stop CAN before setup" );
luaL_checkanytable (L, 1); luaL_checktable (L, 1);
luaL_checkanyfunction (L, 2); luaL_checkfunction (L, 2);
lua_settop (L, 2); lua_settop (L, 2);
if(can_on_received != LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, can_on_received); if(can_on_received != LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, can_on_received);
can_on_received = luaL_ref(L, LUA_REGISTRYINDEX); can_on_received = luaL_ref(L, LUA_REGISTRYINDEX);
...@@ -148,7 +148,7 @@ static int can_send( lua_State *L ) ...@@ -148,7 +148,7 @@ static int can_send( lua_State *L )
} }
// Module function map // Module function map
LROT_BEGIN(can) LROT_BEGIN(can, NULL, 0)
LROT_FUNCENTRY( setup, can_setup ) LROT_FUNCENTRY( setup, can_setup )
LROT_FUNCENTRY( start, can_start ) LROT_FUNCENTRY( start, can_start )
LROT_FUNCENTRY( stop, can_stop ) LROT_FUNCENTRY( stop, can_stop )
......
...@@ -52,7 +52,7 @@ static int ldac_write( lua_State *L ) ...@@ -52,7 +52,7 @@ static int ldac_write( lua_State *L )
// Module function map // Module function map
LROT_BEGIN(dac) LROT_BEGIN(dac, NULL, 0)
LROT_FUNCENTRY( enable, ldac_enable ) LROT_FUNCENTRY( enable, ldac_enable )
LROT_FUNCENTRY( disable, ldac_disable ) LROT_FUNCENTRY( disable, ldac_disable )
LROT_FUNCENTRY( write, ldac_write ) LROT_FUNCENTRY( write, ldac_write )
......
...@@ -184,7 +184,7 @@ static int leth_on( lua_State *L ) ...@@ -184,7 +184,7 @@ static int leth_on( lua_State *L )
{ {
const char *event_name = luaL_checkstring( L, 1 ); const char *event_name = luaL_checkstring( L, 1 );
if (!lua_isnoneornil( L, 2 )) { if (!lua_isnoneornil( L, 2 )) {
luaL_checkanyfunction( L, 2 ); luaL_checkfunction( L, 2 );
} }
lua_settop( L, 2 ); lua_settop( L, 2 );
...@@ -274,7 +274,7 @@ cleanup_mac_phy: ...@@ -274,7 +274,7 @@ cleanup_mac_phy:
} }
LROT_BEGIN(eth) LROT_BEGIN(eth, NULL, 0)
LROT_FUNCENTRY( init, leth_init ) LROT_FUNCENTRY( init, leth_init )
LROT_FUNCENTRY( on, leth_on ) LROT_FUNCENTRY( on, leth_on )
LROT_FUNCENTRY( get_speed, leth_get_speed ) LROT_FUNCENTRY( get_speed, leth_get_speed )
......
...@@ -134,7 +134,7 @@ static int node_i2s_start( lua_State *L ) ...@@ -134,7 +134,7 @@ static int node_i2s_start( lua_State *L )
int top = lua_gettop( L ); int top = lua_gettop( L );
luaL_checkanytable (L, 2); luaL_checktable (L, 2);
i2s_config_t i2s_config; i2s_config_t i2s_config;
memset( &i2s_config, 0, sizeof( i2s_config ) ); memset( &i2s_config, 0, sizeof( i2s_config ) );
...@@ -309,7 +309,7 @@ static int node_i2s_mute( lua_State *L ) ...@@ -309,7 +309,7 @@ static int node_i2s_mute( lua_State *L )
// Module function map // Module function map
LROT_BEGIN(i2s) LROT_BEGIN(i2s, NULL, 0)
LROT_FUNCENTRY( start, node_i2s_start ) LROT_FUNCENTRY( start, node_i2s_start )
LROT_FUNCENTRY( stop, node_i2s_stop ) LROT_FUNCENTRY( stop, node_i2s_stop )
LROT_FUNCENTRY( read, node_i2s_read ) LROT_FUNCENTRY( read, node_i2s_read )
......
...@@ -539,12 +539,12 @@ static int pulsecnt_channel_config( lua_State *L, uint8_t channel ) { ...@@ -539,12 +539,12 @@ static int pulsecnt_channel_config( lua_State *L, uint8_t channel ) {
// Lua: pc:chan0Config(pulse_gpio_num, ctrl_gpio_num, pos_mode, neg_mode, lctrl_mode, hctrl_mode, counter_l_lim, counter_h_lim) // Lua: pc:chan0Config(pulse_gpio_num, ctrl_gpio_num, pos_mode, neg_mode, lctrl_mode, hctrl_mode, counter_l_lim, counter_h_lim)
// Example: pc:chan0Config(2, 4, pulsecnt.PCNT_COUNT_INC, pulsecnt.PCNT_COUNT_DIS, pulsecnt.PCNT_MODE_REVERSE, pulsecnt.PCNT_MODE_KEEP, -100, 100) // Example: pc:chan0Config(2, 4, pulsecnt.PCNT_COUNT_INC, pulsecnt.PCNT_COUNT_DIS, pulsecnt.PCNT_MODE_REVERSE, pulsecnt.PCNT_MODE_KEEP, -100, 100)
static int pulsecnt_channel0_config( lua_State *L, uint8_t channel ) { static int pulsecnt_channel0_config( lua_State *L ) {
return pulsecnt_channel_config(L, 0); return pulsecnt_channel_config(L, 0);
} }
// Lua: pc:chan1Config(pulse_gpio_num, ctrl_gpio_num, pos_mode, neg_mode, lctrl_mode, hctrl_mode, counter_l_lim, counter_h_lim) // Lua: pc:chan1Config(pulse_gpio_num, ctrl_gpio_num, pos_mode, neg_mode, lctrl_mode, hctrl_mode, counter_l_lim, counter_h_lim)
// Example: pc:chan1Config(2, 4, pulsecnt.PCNT_COUNT_INC, pulsecnt.PCNT_COUNT_DIS, pulsecnt.PCNT_MODE_REVERSE, pulsecnt.PCNT_MODE_KEEP, -100, 100) // Example: pc:chan1Config(2, 4, pulsecnt.PCNT_COUNT_INC, pulsecnt.PCNT_COUNT_DIS, pulsecnt.PCNT_MODE_REVERSE, pulsecnt.PCNT_MODE_KEEP, -100, 100)
static int pulsecnt_channel1_config( lua_State *L, uint8_t channel ) { static int pulsecnt_channel1_config( lua_State *L ) {
return pulsecnt_channel_config(L, 1); return pulsecnt_channel_config(L, 1);
} }
...@@ -565,7 +565,7 @@ static int pulsecnt_create( lua_State *L ) { ...@@ -565,7 +565,7 @@ static int pulsecnt_create( lua_State *L ) {
// user did not provide a callback. that's ok. just don't give them one. // user did not provide a callback. that's ok. just don't give them one.
isCallback = false; isCallback = false;
} else { } else {
luaL_argcheck(L, lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION, stack, "Must be function"); luaL_checkfunction(L, stack);
} }
// ok, we have our unit number which is required. good. now create our object // ok, we have our unit number which is required. good. now create our object
...@@ -678,7 +678,7 @@ static int pulsecnt_unregister(lua_State* L){ ...@@ -678,7 +678,7 @@ static int pulsecnt_unregister(lua_State* L){
return 0; return 0;
} }
LROT_BEGIN(pulsecnt_dyn) LROT_BEGIN(pulsecnt_dyn, NULL, 0)
LROT_FUNCENTRY( getCnt, pulsecnt_getCnt ) LROT_FUNCENTRY( getCnt, pulsecnt_getCnt )
LROT_FUNCENTRY( clear, pulsecnt_clear ) LROT_FUNCENTRY( clear, pulsecnt_clear )
LROT_FUNCENTRY( testCb, pulsecnt_testCb ) LROT_FUNCENTRY( testCb, pulsecnt_testCb )
...@@ -696,7 +696,7 @@ LROT_BEGIN(pulsecnt_dyn) ...@@ -696,7 +696,7 @@ LROT_BEGIN(pulsecnt_dyn)
LROT_TABENTRY ( __index, pulsecnt_dyn ) LROT_TABENTRY ( __index, pulsecnt_dyn )
LROT_END(pulsecnt_dyn, NULL, 0) LROT_END(pulsecnt_dyn, NULL, 0)
LROT_BEGIN(pulsecnt) LROT_BEGIN(pulsecnt, NULL, 0)
LROT_FUNCENTRY( create, pulsecnt_create ) LROT_FUNCENTRY( create, pulsecnt_create )
LROT_NUMENTRY ( PCNT_MODE_KEEP, 0 ) /*pcnt_ctrl_mode_t.PCNT_MODE_KEEP*/ LROT_NUMENTRY ( PCNT_MODE_KEEP, 0 ) /*pcnt_ctrl_mode_t.PCNT_MODE_KEEP*/
LROT_NUMENTRY ( PCNT_MODE_REVERSE, 1 ) /*pcnt_ctrl_mode_t.PCNT_MODE_REVERSE*/ LROT_NUMENTRY ( PCNT_MODE_REVERSE, 1 ) /*pcnt_ctrl_mode_t.PCNT_MODE_REVERSE*/
...@@ -717,7 +717,7 @@ LROT_END(pulsecnt, NULL, 0) ...@@ -717,7 +717,7 @@ LROT_END(pulsecnt, NULL, 0)
int luaopen_pulsecnt(lua_State *L) { int luaopen_pulsecnt(lua_State *L) {
luaL_rometatable(L, "pulsecnt.pctr", (void *)pulsecnt_dyn_map); luaL_rometatable(L, "pulsecnt.pctr", LROT_TABLEREF(pulsecnt_dyn));
pulsecnt_task_id = task_get_id(pulsecnt_task); pulsecnt_task_id = task_get_id(pulsecnt_task);
......
...@@ -187,7 +187,7 @@ static int lsdmmc_read( lua_State * L) ...@@ -187,7 +187,7 @@ static int lsdmmc_read( lua_State * L)
luaL_addlstring( &b, rbuf, num_sec * 512 ); luaL_addlstring( &b, rbuf, num_sec * 512 );
luaL_pushresult( &b ); luaL_pushresult( &b );
luaM_freearray( L, rbuf, rbuf_size, uint8_t ); luaN_freearray( L, rbuf, rbuf_size );
// all ok // all ok
return 1; return 1;
...@@ -195,7 +195,7 @@ static int lsdmmc_read( lua_State * L) ...@@ -195,7 +195,7 @@ static int lsdmmc_read( lua_State * L)
} else } else
err_msg = "card access failed"; err_msg = "card access failed";
luaM_freearray( L, rbuf, rbuf_size, uint8_t ); luaN_freearray( L, rbuf, rbuf_size );
return luaL_error( L, err_msg ); return luaL_error( L, err_msg );
} }
...@@ -327,7 +327,7 @@ static int lsdmmc_umount( lua_State *L ) ...@@ -327,7 +327,7 @@ static int lsdmmc_umount( lua_State *L )
return luaL_error( L, err_msg ); return luaL_error( L, err_msg );
} }
LROT_BEGIN(sdmmc_card) LROT_BEGIN(sdmmc_card, NULL, 0)
LROT_FUNCENTRY( read, lsdmmc_read ) LROT_FUNCENTRY( read, lsdmmc_read )
LROT_FUNCENTRY( write, lsdmmc_write ) LROT_FUNCENTRY( write, lsdmmc_write )
LROT_FUNCENTRY( get_info, lsdmmc_get_info ) LROT_FUNCENTRY( get_info, lsdmmc_get_info )
...@@ -336,7 +336,7 @@ LROT_BEGIN(sdmmc_card) ...@@ -336,7 +336,7 @@ LROT_BEGIN(sdmmc_card)
LROT_TABENTRY( __index, sdmmc_card ) LROT_TABENTRY( __index, sdmmc_card )
LROT_END(sdmmc_card, NULL, 0) LROT_END(sdmmc_card, NULL, 0)
LROT_BEGIN(sdmmc) LROT_BEGIN(sdmmc, NULL, 0)
LROT_FUNCENTRY( init, lsdmmc_init ) LROT_FUNCENTRY( init, lsdmmc_init )
LROT_NUMENTRY( HS1, SDMMC_HOST_SLOT_0 ) LROT_NUMENTRY( HS1, SDMMC_HOST_SLOT_0 )
LROT_NUMENTRY( HS2, SDMMC_HOST_SLOT_1 ) LROT_NUMENTRY( HS2, SDMMC_HOST_SLOT_1 )
...@@ -352,7 +352,7 @@ LROT_END(sdmmc, NULL, 0) ...@@ -352,7 +352,7 @@ LROT_END(sdmmc, NULL, 0)
static int luaopen_sdmmc( lua_State *L ) static int luaopen_sdmmc( lua_State *L )
{ {
luaL_rometatable(L, "sdmmc.card", (void *)sdmmc_card_map); luaL_rometatable(L, "sdmmc.card", LROT_TABLEREF(sdmmc_card));
// initialize cards // initialize cards
for (int i = 0; i < NUM_CARDS; i++ ) { for (int i = 0; i < NUM_CARDS; i++ ) {
......
...@@ -179,7 +179,7 @@ static int touch_create( lua_State *L ) { ...@@ -179,7 +179,7 @@ static int touch_create( lua_State *L ) {
touch_t tp = &tpObj; touch_t tp = &tpObj;
// const int top = lua_gettop(L); // const int top = lua_gettop(L);
luaL_checkanytable (L, 1); luaL_checktable (L, 1);
tp->is_debug = opt_checkbool(L, "isDebug", false); tp->is_debug = opt_checkbool(L, "isDebug", false);
tp->filterMs = opt_checkint(L, "filterMs", 0); tp->filterMs = opt_checkint(L, "filterMs", 0);
...@@ -227,7 +227,7 @@ static int touch_create( lua_State *L ) { ...@@ -227,7 +227,7 @@ static int touch_create( lua_State *L ) {
isCallback = false; isCallback = false;
if (tp->is_debug) ESP_LOGI(TAG, "No callback provided. Not turning on interrupt." ); if (tp->is_debug) ESP_LOGI(TAG, "No callback provided. Not turning on interrupt." );
} else { } else {
luaL_argcheck(L, lua_type(L, -1) == LUA_TFUNCTION || lua_type(L, -1) == LUA_TLIGHTFUNCTION, -1, "Cb must be function"); luaL_checkfunction(L, -1);
//get the lua function reference //get the lua function reference
luaL_unref(L, LUA_REGISTRYINDEX, tp->cb_ref); luaL_unref(L, LUA_REGISTRYINDEX, tp->cb_ref);
...@@ -589,7 +589,7 @@ static int touch_unregister(lua_State* L) { ...@@ -589,7 +589,7 @@ static int touch_unregister(lua_State* L) {
return 0; return 0;
} }
LROT_BEGIN(touch_dyn) LROT_BEGIN(touch_dyn, NULL, 0)
LROT_FUNCENTRY( read, touch_read ) LROT_FUNCENTRY( read, touch_read )
LROT_FUNCENTRY( intrEnable, touch_intrEnable ) LROT_FUNCENTRY( intrEnable, touch_intrEnable )
LROT_FUNCENTRY( intrDisable, touch_intrDisable ) LROT_FUNCENTRY( intrDisable, touch_intrDisable )
...@@ -601,7 +601,7 @@ LROT_BEGIN(touch_dyn) ...@@ -601,7 +601,7 @@ LROT_BEGIN(touch_dyn)
LROT_TABENTRY ( __index, touch_dyn ) LROT_TABENTRY ( __index, touch_dyn )
LROT_END(touch_dyn, NULL, 0) LROT_END(touch_dyn, NULL, 0)
LROT_BEGIN(touch) LROT_BEGIN(touch, NULL, 0)
LROT_FUNCENTRY( create, touch_create ) LROT_FUNCENTRY( create, touch_create )
LROT_NUMENTRY ( TOUCH_HVOLT_KEEP, TOUCH_HVOLT_KEEP ) LROT_NUMENTRY ( TOUCH_HVOLT_KEEP, TOUCH_HVOLT_KEEP )
LROT_NUMENTRY ( TOUCH_HVOLT_2V4, TOUCH_HVOLT_2V4 ) LROT_NUMENTRY ( TOUCH_HVOLT_2V4, TOUCH_HVOLT_2V4 )
...@@ -626,7 +626,7 @@ LROT_END(touch, NULL, 0) ...@@ -626,7 +626,7 @@ LROT_END(touch, NULL, 0)
int luaopen_touch(lua_State *L) { int luaopen_touch(lua_State *L) {
luaL_rometatable(L, "touch.pctr", (void *)touch_dyn_map); luaL_rometatable(L, "touch.pctr", LROT_TABLEREF(touch_dyn));
touch_task_id = task_get_id(touch_task); touch_task_id = task_get_id(touch_task);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment