lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

It was thus said that the Great Duane Leslie once stated:
> If a fixed upvalue list (i.e. without ...) is provided without _ENV,
> then the function cannot lookup global values and this will actually
> generate a syntax error at parsing rather than at runtime.  This has
> the advantage that 'strict' mode is now enforceable at the parsing
> stage rather than at runtime (current with _ENV modification).

  You can get this with load() (and loadfile()) but passing in an empty
environment for the chunk.

> If a fixed upvalue list is provided with _ENV but without locals from
> its context then those locals will not be accessible and globals will
> be sought instead.  This brings the 'strict' behaviour to closures
> since I can prevent them from accidentally seeing a local variable in
> their scope, and in combination with the normal strict _ENV I can
> report it at runtime, or with disabling _ENV as well cause a syntax
> error at parse time.

  I'm not sure I understand this.  An example?

> My motivation for this was to allow users to provide custom functions
> in a controlled way.  I let them provide a function as a string, and
> then I compile it with the following:
> compiled = load("local "..table.concat(upvals, ", ").."; return
> function (...) <"..table.concat(upvals,", ")..">; "..userfunc..";
> end")()
> Which gives a syntax error if they try to access a
> variable/function/table that is not declared either as a local by them
> or in the upvals list, and means that when I serialise using
> `string.dump(compiled,true)` I know exactly what upvalues to bind
> where when reloading the function.
> Anyway, the patch is attached, and if anyone has an feedback I'd be
> interested to hear it.

  I've some work on serializing Lua (using CBOR [1] encoding).  When the
module was loaded, I cached a copy of all global variables.  That way, if
someone wanted to serialize, say, 'table' (the stock Lua table module), all
I had to do was mark it as a standard Lua value of 'table' [2] and save a
bunch of work.  

  When I encountered a user-defined function [4], I emitted the function and
then each upvalue.  I didn't depend upon the names of local variables (_ENV
is not always guarenteed to be the first upvalue, or even the first table
upvalue).  When I encountered a table, if it matched the cached "_G" value,
then I encoded the string "_G" as a standard Lua value [2].  If an upvalue
was a table that didn't match any existing table, then I encoded a Lua table
and the fields.  This would catch a default _ENV, as well as custom _ENVs,
as well as any other upvalues. [6]

  Looking back on the work (I didn't finish it), I missed out on metatables
and associated user values but in theory it could be added without too much
issue.  Yes, locals were restored (extensive use of the debug module
required for all of this to work).

  -spc (In a way, it was odd ... everything about the encoding was
	architecutally neutral *except* for the actual functions themselves
	... )

[1]	RFC-7049

	But this can't serialize Lua.  I haven't included the code for that

[2]	CBOR allows data items to be tagged for semantics.  I defined a tag
	for "standard Lua value" and used that to tag a string, the name of
	which defines the name of the global value [3].

[3]	Which means that had I non-standard globals, I needed to ensure they
	existed before deserializing the data.  I just assumed they existed.

[4]	In Lua---no way I could deal with user-defined functions in C [5].

[5]	Usually in a module, but there is org.conman.tcc

	which allows you to include C code directly in a Lua codebase and
	compile it into memory for immediate use.

[6]	There are extensions in CBOR that allow for circular references, so
	even something as pathological as:

		x = {}
		y = {}
		x.y = y
		y.x = x
		x.x = x
		y.y = y

	Can still be encoded.