[erlang-questions] Luerl - Lua in Erlang: Interface Definition
Henning Diedrich
hd2010@REDACTED
Sat Feb 25 07:46:38 CET 2012
This may come close:
https://github.com/Eonblast/luerl/tree/henning
For the criticism I still have, see inline comments please.
On 2/24/12 12:19 AM, Robert Virding wrote:
> Hi Henning,
>
> Ok we will go towards making them more Lua-C like. But we are running
> in an Erlang environment so they will handle errors in an Erlangy way:
>
> - The 'eval' functions will catch errors and return {ok,Result} |
> {error,Reason}.
What this gives away is the chance of less cluttered code, to use eval
'in-line' with no pattern matching result extraction, if so wanted.
> - The 'do' and 'call' functions will not catch errors and return
> {Result,NewState}. Errors caught in the Lua code, with 'pcall' which
> does not exist yet, will of course not generate an error at the Erlang
> interface.
Isn't the chance to look at the soon to be discarded stack something
that needs the support of giving over a suitable callback. And thus
offer pcall from Erlang?
> - We will initialise/cleanup the state with 'start'/'stop' in an
> Erlangy way.
> - We will 'encode'/'decode' Lua data.
> - And we will both 'load' and 'compile' Lua and load/compile(String)
> -> {ok,Form} | {error,Reason}.
I did all those changes, and see /examples/hello/hello2.erl. The
interface comes across as bloated like this. I think.
Best,
Henning
> The erlang format of errors from the luerl runtime will be something
> {luerl_error,Error} where will be something like {badarg,sub,Args}. I
> will try to give them similar names as in Lua. Erlang errors are very
> seldom string values, in some cases there are format_error/1 functions
> which return string values. This will also make it easy to see which
> are Lua errors and which are from the Erlang code.
>
> Robert
>
> ------------------------------------------------------------------------
>
> Hi Robert,
>
> Thanks for the feedback. Yes, it's a matter of viewpoint, from
> Erlang or Lua.
>
> If you feel the audience for Luerl would be people who did work
> with Lua before, many of them would know the C interface and thus,
> it could be helpful for them to stick to these names.
>
> Since I work with Lua, embedded Lua and Erlang, I would treasure
> consistency between the C and Erlang underside of Lua.
>
> Lua is so much for embedding that the C interface functions are
> actually listed in the manual earlier than the language functions
> (or at least once it was so).
>
> I'll agree that 'load' is not intuitively right. But it would
> increase consistency.
>
> 'dofile' is a staple of Lua proper, also exists in the C interface
> and again would probably be what somebody coming from Lua would
> look for, so would be --- nice to have in my view. 'evalfile'
> exists for symmetry.
>
> As I wrote, my interface proposal is bloated, but the differences
> between 'do' and 'call' would be that 'call' only takes
> pre-compiled chunks and crashes with anything else. While "do" is
> more careless and can be fed anything: Lua code in Strings,
> Binaries, or pre-compiled chunks.
>
> "eval" - for easiest use, in place, returns pure Result
> "do" - same as eval but returns Result and State*
> "call" - takes only precompiled chunks, returns Result and State
>
> * (in Erlang, you can't just /not/ fetch the second return value,
> as is possible in Lua)
>
> My two cents on: "encode" and "decode" I find them better but
> still not perfect. It's really again the perspective from Erlang.
> "wrap"/ "unwrap"? "stage"/"unstage"? (Looks like no difference to
> "encode" at first sight -- but I do think there is one.)
>
> As for error handling: I came to think that a try-catch wrap in
> eval as standard service would be nice. So using eval you'd be
> sure it will always return, of with an error message. While that
> may in fact be too much Lua thinking, and too alien to Erlang,
> it's what comes to mind for how I would like "eval" to be a
> carefree, fast thing to use. (Erlang has a "let it crash"
> philosophy where errors are usually handled but a process
> automatically restarted.)
>
> The whole point of "pcall" is to be a protected version of "call".
> Using "pcall" in Lua/C interface one can be sure that errors don't
> crash the program and can be handled. Specifically by a handler
> function which has access to the state before the stack is discarded.
>
> I think it may make sense to treat errors that originate in Lua
> (or even in the Luerl VM itself, while in development) differently
> from errors that originate in the Erlang source.
>
> Best,
> Henning
>
> --
> *Henning Diedrich*
> CEO
>
>
>
> Eonblast Corporation
> hdiedrich@REDACTED
> +1.404.418.5002 w
> www.eonblast.com
>
>
> This email contains confidential and/or privileged information. If
> you are not the intended recipient (or have received this email in
> error) please notify the sender immediately and destroy this
> email. Any unauthorized copying, disclosure or distribution of the
> material in this email is prohibited.
>
>
> On 2/22/12 3:04 AM, Robert Virding wrote:
>
> Hi,
>
> Most of the difference is just in terminology and from which
> side you view it, from erlang or Lua. For example, for me
> loading means actually getting it into the sytem not just
> compiling it into a runnable form. And I view these functions
> from the erlang side. I will also admit that I am a bit hazy
> as to how the C-side functions work, it seems easier within
> the language.
>
> 'eval' and 'do' work well for me, though I do wonder if we
> need 'evalfile' and 'dofile'. I prefer 'compile' instead of
> 'load' as this is what is does. 'call' is fine. What is the
> difference between 'call' and 'do'? For creating and
> destroying state I would prefer either 'new' / 'delete' or
> 'start' / 'stop' depending on whether you want to view the
> state as just data or as some form of concurrent activity, a
> separate process in Erlang.
>
> I would use 'encode' / 'decode' for converting between an
> Erlang representation and an internal luerl representation. So:
>
> luerl:encode(Erlang, State) -> {Luerl,State}.
> luerl:decode(Luerl, State) -> Erlang.
>
> Encoding will modify the state as tables only exist within
> that state. If it not done this way then there is no need of
> these functions as the representation is the same and this
> conversion will be done in the other interface functions. So
> for example a Lua strings are Erlang binaries and tables will
> are a list of tuple pairs,
>
> Lua {['a']=97,['b']=98,10,20,30} <==> Erlang
> [{1.0,10.0},{2.0,20.0},{3.0,30.0},{<<"a">>,97.0},{<<"b">>,98.0}]
>
> Putting Lua tables into the state is also the only way to
> handle the difference in the meaning of equality between Lua
> and Erlang.
>
> For errors I have been thinking in the Erlang way. The only
> function to actually return an error value would be 'compile'
> (or 'load') which would become
>
> luerl:compile(String) -> {ok,Chunk} | {error,Reason}.
>
> All errors during the Lua execution, unless they are caught
> internally, would result in Erlang exceptions which would
> handled in the normal Erlang way, either by catching it or
> having the Erlang process die.
>
> The result returned from Lua and the arguments to a call would
> be a list of Erlang values. If no values are returned the list
> is empty otherwise it would contain same number of elements as
> in the 'return' statement.
>
> Those are my thoughts for the moment. Now I will go back and
> try and code the idiosyncrasies of string.sub.
>
> Robert
>
> ------------------------------------------------------------------------
>
> Hi Robert,
>
> To allow for String|Chunk, the chunks returned from ps/1
> would have to be wrapped to be distinguishable from the
> Strings. I think 'functiondef' could be the right choice.
>
> For the names, I'd propose to maybe stay closer to the Lua
> language function names and its C interface [1].
>
> But at any rate, to maybe decide for one of "do" and
> "eval" to 1) return bare results 2) return {Result,
> State}. Rather than making this dependent on whether State
> was handed in or not as a parameter?
>
> Since Lua uses dofile() both in the Lua language and the C
> interface, (and since of course neither case returns
> state), the "do" functions look earmarked for returning
> the simple, bare bones Result. However ... somehow "eval"
> is a better fit for a function that is expected to return
> something.
>
> Lua's C interface uses "load" for parsing-only: load,
> loadfile, lua_load [2], lua_loadfile, lua_loadstring,
> lua_loadbuffer.
>
> This could be an alternative to wrapping the chunks: for
> load, in Lua /"the string mode controls whether the chunk
> can be text or binary (that is, a precompiled chunk). It
> may be the string "b" (only binary chunks), "t" (only text
> chunks), or "bt" (both binary and text). The default is
> "bt". /[5]
>
> The type that the loads return is 'function': /"If there
> are no syntactic errors, returns the compiled chunk as a
> function; otherwise, returns nil plus the error message."
> --- /therefore, the right chunk wrapper could be {
> functiondef, ... }, instead of compiled chunks being lists
> as outermost type.
>
> Execution of pre-parsed/compiled chunks is "call": pcall,
> xpcall, lua_call, lua_pcall [3], and lua_pcallk.
>
> State is created and destroyed by lua_newstate and lua_close.
>
> There is no "eval" in Lua.
>
> So here's my proposal:
>
> luerl:eval(String|Chunk[, State]) -> Result.
> luerl:evalfile(PathString[, State]) -> Result.
>
> luerl:do(String|Chunk[, State]) -> {Result, NewState}.
> luerl:dofile(PathString[, State]) -> {Result, NewState}.
>
> luerl:newstate() -> State.
> luerl:close(State) -> ok.
>
> luerl:load(String) -> {ok, Chunk}.
> luerl:loadfile(PathString) -> {ok, Chunk}.
> luerl:call(Chunk[, State][, ErlParamList()]) -> {Result,
> NewState}.
>
> luerl:tolua(list()) -> LuerlTermsList().
> luerl:toerlang(LuerlTermsList()) -> list().
>
> This would be somewhat in keeping with Lua's naming.
>
> I am unclear about error state returns. Simply in the
> Result I guess?
>
> Relative to your proposal that is:
> luerl:eval(String|Chunk) -> Result. =>
> luerl:eval(String|Chunk[, State]) -> Result.
> luerl:dofile(String) -> Result. =>
> luerl:dofile(PathString[, State]) -> {Result,State}.
> luerl:new() -> State. (currently luerl:init() -> State.)
> =>luerl:newstate() -> State.
> luerl:eval(String|Chunk, State) -> {Result,NewState}. =>
> luerl:eval(String|Chunk, State) -> {Result,NewState}.
> luerl:dofile(String, State) -> {Result,NewState}. => same
> luerl:compile(String) -> {ok,Chunk}. => luerl:load(String)
> -> {ok,Chunk}.
>
> Beyond that, I had thought with 'interface' you would be
> addressing the direct interchange of values between Erlang
> and Lua. I'd be all for making the collection of tables in
> the Lua state accessible and writable, directly, somehow
> navigating into it using a key structure. And if possible,
> vice versa: giving Lua direct access to Erlang state.
>
> Best,
> Henning
>
>
> [1] http://www.lua.org/manual/5.2/manual.html#4.8
>
> [2] /One note I like, in the description of the C function
> lua_load : "The source argument gives a name to the chunk,
> which is used for error messages and in debug information
> (see §4.9)."
> /http://www.lua.org/manual/5.2/manual.html#lua_load -
> http://www.lua.org/manual/5.2/manual.html#2.3
>
> [3] /When you use xpcall or lua_pcall, you may give a
> message handler to be called in case of errors. This
> function is called with the original error message and
> returns a new error message. It is called before the error
> unwinds the stack, so that it can gather more information
> about the error, for instance by inspecting the stack and
> creating a stack traceback. This message handler is still
> protected by the protected call; so, an error inside the
> message handler will call the message handler again. If
> this loop goes on, Lua breaks it and returns an
> appropriate message./ -
> http://www.lua.org/manual/5.2/manual.html#2.3
>
> [4] In Lua (not the C interface), dofile does not run in
> protected mode. http://www.lua.org/manual/5.2/manual.html#6.1
>
> [5] http://www.lua.org/manual/5.2/manual.html#6.1
>
>
>
> On 2/20/12 10:59 PM, Robert Virding wrote:
>
> [snip] I had planned something along the lines of:
>
> luerl:eval(String|Chunk) -> Result.
> luerl:dofile(String) -> Result.
>
> Basic simple interface which initialises a state and
> evaluates the chunk String in it returning a list of
> return values (if any). For example luer:eval("local
> t={'a','b'} return t[1],t[2]") will return
> [<<"a">>,<<"b">>]. luerl:dofile/1 is not really necessary.
>
> luerl:new() -> State.
> luerl:eval(String|Chunk, State) -> {Result,NewState}.
> luerl:dofile(String, State) -> {Result,NewState}.
> luerl:compile(String) -> {ok,Chunk}.
>
> A more complex interface. luerl:new/0 creates an
> initial state. luerl:eval/2 will evaluate a chunk in a
> state and return the values and the updated state.
> This state can be reused to evaluate new chunks. Again
> luerl:dofile/2 is not really necessary.
> luerl:compile(String) compiles the string into an
> internal form ready to run in eval/1/2.
>
> Result is always a list of return values which may be
> empty if the chunk does not do a return with values.
> For data types:
>
> Lua strings are binaries
> Lua numbers are floats
> Lua tables are orddicts (property lists) of key-value
> tuples
> Lua true, false, nil are just the atoms true, false, nil
>
> Anyway something along those lines. It might be nice
> to have a function call wrapper which would allow you
> a more erlang like way of calling a luerl function.
>
> Robert
>
> ------------------------------------------------------------------------
>
> Regarding interface function names:
>
> I wonder what logic Luerl's names of do and eval
> follow:
>
> dofile/1, like eval/1, returns a pragmatic Ret
>
> while do/2 returns {String, State}
>
> Since you are exporting ps/1, there should maybe
> be a dochunk/2?
>
> And /1, too?
>
> Or should it maybe be evalchunk/1, dochunk/2 (the
> /2s with State as second parameter)?
>
> Here are some relevant functions from Lua's C
> interface.
>
> *luaL_dofile*
>
> [-0, +?, m]
> int luaL_dofile (lua_State *L, const char
> *filename);
> Loads and runs the given file. It is defined
> as the following macro:
>
> (luaL_loadfile(L, filename) ||
> lua_pcall(L, 0, LUA_MULTRET, 0))
> It returns false if there are no errors or
> true in case of errors.
>
> *luaL_dostring*
>
> [-0, +?, –]
> int luaL_dostring (lua_State *L, const char *str);
> Loads and runs the given string. It is defined
> as the following macro:
>
> (luaL_loadstring(L, str) || lua_pcall(L,
> 0, LUA_MULTRET, 0))
> It returns false if there are no errors or
> true in case of errors.
>
> *luaL_loadstring*
>
> [-0, +1, –]
> int luaL_loadstring (lua_State *L, const char *s);
> Loads a string as a Lua chunk. This function
> uses lua_load to load the chunk in the
> zero-terminated string s.
>
> This function returns the same results as
> lua_load.
>
> Also as lua_load, this function only loads the
> chunk; it does not run it.
>
> *luaL_newstate*
>
> [-0, +0, –]
> lua_State *luaL_newstate (void);
> Creates a new Lua state. It calls lua_newstate
> with an allocator based on the standard C
> realloc function and then sets a panic
> function (see §4.6) that prints an error
> message to the standard error output in case
> of fatal errors.
>
> Returns the new state, or NULL if there is a
> memory allocation error.
>
>
> Source: http://www.lua.org/manual/5.2/manual.html
>
>
>
>
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions
>
>
>
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20120225/b7f1bad5/attachment.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: image/png
Size: 4856 bytes
Desc: not available
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20120225/b7f1bad5/attachment.png>
More information about the erlang-questions
mailing list