diff --git a/polymer/eduke32/source/lunatic/bittest.lua b/polymer/eduke32/source/lunatic/bittest.lua new file mode 100644 index 000000000..7efe1e7f6 --- /dev/null +++ b/polymer/eduke32/source/lunatic/bittest.lua @@ -0,0 +1,53 @@ + +local string = require "string" + +local getticks + +local bit = require("bit") +local print = print + +if (string.dump) then + -- stand-alone + local os = require "os" + function getticks() + return os.clock()*1000 + end +else + -- embedded + getticks = gv.gethitickms + + module(...) +end + +-- from http://bitop.luajit.org/api.html + +local band, bxor = bit.band, bit.bxor +local rshift, rol = bit.rshift, bit.rol + +local m = 1000000 + +function sieve() + local count = 0 + local p = {} + + for i=0,(m+31)/32 do p[i] = -1 end + + local t = getticks() + + for i=2,m do + if band(rshift(p[rshift(i, 5)], i), 1) ~= 0 then + count = count + 1 + for j=i+i,m,i do + local jx = rshift(j, 5) + p[jx] = band(p[jx], rol(-2, j)) + end + end + end + + print(string.format("Found %d primes up to %d (%.02f ms)", count, m, + getticks()-t)) +end + +if (string.dump) then + sieve() +end diff --git a/polymer/eduke32/source/lunatic/defs.ilua b/polymer/eduke32/source/lunatic/defs.ilua index fda38bb07..b83bc097e 100644 --- a/polymer/eduke32/source/lunatic/defs.ilua +++ b/polymer/eduke32/source/lunatic/defs.ilua @@ -471,6 +471,13 @@ playerdata_t g_player[MAXPLAYERS]; ]] -- functions +decl[[ +int32_t kopen4loadfrommod(const char *filename, char searchfirst); +int32_t kfilelength(int32_t handle); +void kclose(int32_t handle); +int32_t kread(int32_t handle, void *buffer, int32_t leng); +]] + ffi.cdef[[ int32_t ksqrt(uint32_t num); ]] @@ -510,6 +517,8 @@ local allowed_modules = { coroutine=coroutine, bit=bit, table=table, math=math, string=string, } +local package_loaded = {} + for modname, themodule in pairs(allowed_modules) do local mt = { __index = themodule, @@ -522,22 +531,95 @@ for modname, themodule in pairs(allowed_modules) do allowed_modules[modname] = setmetatable({}, mt) end +local function check_valid_modname(modname) + if (type(modname) ~= "string") then + error("module name must be a string", 5) + end + + -- TODO: restrict valid names? +end + +local function errorf(level, fmt, ...) + local errmsg = string.format(fmt, ...) + error(errmsg, level+1) + + -- XXX: error(nil) propagates to C! +end + +local ERRLEV = 5 + -- The "require" function accessible to Lunatic code. -- Base modules in allowed_modules are wrapped so that they cannot be --- modified, (TODO:) user modules are searched in the EDuke32 search +-- modified, user modules are searched in the EDuke32 search -- path. Also, our require never messes with the global environment, -- it only returns the module. local function our_require(modname) - local themodule = allowed_modules[modname] + check_valid_modname(modname) - if (themodule==nil) then - error("NOT IMPLEMENTED") - -- need to search user modules here + -- see whether it's a base module name first + if (allowed_modules[modname] ~= nil) then + return allowed_modules[modname] end - return themodule + --- search user modules + + if (package_loaded[modname] ~= nil) then + -- already loaded + return package_loaded[modname] + end + + local function readintostr(fn) + -- XXX: this is pretty much the same as the code in El_RunOnce() + + local fd = ffiC.kopen4loadfrommod(fn, 0) -- TODO: g_loadFromGroupOnly + if (fd < 0) then + errorf(ERRLEV, "Couldn't open file \"%s\"", fn) + end + + local sz = ffiC.kfilelength(fd) + if (sz == 0) then + ffiC.kclose(fd) + errorf(ERRLEV, "Didn't load module \"%s\": zero-length file", fn) + end + + if (sz < 0) then + ffi.kclose(fd) + error("INTERNAL ERROR: kfilelength() returned negative length", 5) + end + + local str = ffi.new("char [?]", sz) -- XXX: what does it do on out of mem? + local readlen = ffiC.kread(fd, str, sz) + + ffiC.kclose(fd); fd=-1 + + if (readlen ~= sz) then + errorf(ERRLEV, "INTERNAL ERROR: couldn't read \"%s\" wholly", fn) + end + + return ffi.string(str, sz) + end + + -- TODO: better pattern-matching (permit "", .lua, .elua ?) + local str = readintostr(modname .. ".lua") + + local modfunc, errmsg = loadstring(str) + if (modfunc == nil) then + errorf(ERRLEV-1, "Couldn't load \"%s\": %s", fn, errmsg) + end + + local modtab = modfunc(modname) + + if (modtab ~= nil) then + if (type(modtab) ~= "table") then + errorf(ERRLEV-1, "Didn't load module \"%s\": expected table as return value", modname) + end + package_loaded[modname] = modtab + end + + return package_loaded[modname] end + -- _G tweaks -- pull in only 'safe' stuff local G_ = {} -- our soon-to-be global environment @@ -546,7 +628,18 @@ local G_ = {} -- our soon-to-be global environment -- this table, since user code could later do pairs=nil. local oG = _G +-- replacement for "module" +local function our_module(modname) + check_valid_modname(modname) + + local M = {} + package_loaded[modname] = M + -- change the environment of the function which called us: + oG.setfenv(2, M) +end + G_.require = our_require +G_.module = our_module ---G_.coroutine = coroutine G_.assert = assert G_.tostring = tostring diff --git a/polymer/eduke32/source/lunatic/dynsymlist b/polymer/eduke32/source/lunatic/dynsymlist index bf39748b5..9c4b84c3c 100644 --- a/polymer/eduke32/source/lunatic/dynsymlist +++ b/polymer/eduke32/source/lunatic/dynsymlist @@ -26,6 +26,11 @@ nextspritestat; headsectbunch; nextsectbunch; +kopen4loadfrommod; +kfilelength; +kclose; +kread; + ksqrt; hitscan; diff --git a/polymer/eduke32/source/lunatic/lunatic.c b/polymer/eduke32/source/lunatic/lunatic.c index bd4f66c85..427395b5e 100644 --- a/polymer/eduke32/source/lunatic/lunatic.c +++ b/polymer/eduke32/source/lunatic/lunatic.c @@ -108,7 +108,7 @@ int32_t El_RunOnce(El_State *estate, const char *fn) lua_State *const L = estate->L; - fid = kopen4load(fn, 0); + fid = kopen4load(fn, 0); // TODO: g_loadFromGroupOnly, kopen4loadfrommod ? if (fid < 0) return 1; diff --git a/polymer/eduke32/source/lunatic/test.elua b/polymer/eduke32/source/lunatic/test.elua index 69a4707e6..dd16efe9e 100644 --- a/polymer/eduke32/source/lunatic/test.elua +++ b/polymer/eduke32/source/lunatic/test.elua @@ -237,4 +237,7 @@ gameactor(1680, -- LIZTROOP printf("EVENT_INIT = %d", gv.EVENT_INIT) -- tests default defines +local bittest = require "bittest" +bittest.sieve() + print('---=== END TEST SCRIPT ===---')