From 0f3f273807bc500f1b827d88460c05c640b0145a Mon Sep 17 00:00:00 2001 From: Robert Virding Date: Tue, 12 Nov 2024 20:55:57 +0100 Subject: [PATCH] First complete test version of new luerl So luerl_new has now become the luerl. For backwards compatibility save the old luerl unchanged as luerl_old. The documentation and test suites have updated as well. A major change in luerl is the encoding/decoding of functions which are assumed to use encoded arguments and return values. --- doc/luerl.txt | 202 +++++++------ doc/luerl_old.txt | 137 +++++++++ doc/man/luerl.3 | 222 +++++++-------- doc/man/luerl_old.3 | 146 ++++++++++ doc/pdf/luerl.pdf | Bin 49599 -> 52771 bytes doc/pdf/luerl_old.pdf | Bin 0 -> 49816 bytes doc/src/luerl.3.md | 128 +++++---- doc/src/luerl_old.3.md | 97 +++++++ src/luerl.erl | 473 +++++++++++++++++-------------- src/luerl_emul.erl | 2 +- src/luerl_old.erl | 436 +++++++++++++++++++++++++++- test/lib_os_SUITE.erl | 4 +- test/luerl_funcall_tests.erl | 38 ++- test/luerl_old_funcall_tests.erl | 108 +++++++ test/luerl_old_tests.erl | 44 +++ test/luerl_return_SUITE.erl | 6 +- test/luerl_tests.erl | 22 +- test/luerl_time_SUITE.erl | 12 +- 18 files changed, 1566 insertions(+), 511 deletions(-) create mode 100644 doc/luerl_old.txt create mode 100644 doc/man/luerl_old.3 create mode 100644 doc/pdf/luerl_old.pdf create mode 100644 doc/src/luerl_old.3.md create mode 100644 test/luerl_old_funcall_tests.erl create mode 100644 test/luerl_old_tests.erl diff --git a/doc/luerl.txt b/doc/luerl.txt index f35ad11..c515a4f 100644 --- a/doc/luerl.txt +++ b/doc/luerl.txt @@ -1,137 +1,167 @@ -luerl(3) luerl(3) +luerl(3) Library Functions Manual luerl(3) +Name + luerl - The basic interface to the Luerl system - -Interface functions +Interface functions - New Version The Lua State parameter is the state of a Lua VM instance. It must be created with the luerl:init() call and be carried from one call to the next. - As it is possible in Lua to create self‐referencing data structures, + As it is possible in Lua to create self-referencing data structures, indeed the standard libraries have many instances of this, then using the functions which decode their return values will generate an error when they would cause an infinite loop during the decoding. An simple example is the top level table which contains a key _G which references - the top‐level table. + the top-level table. - Note that Lua Chunks (see definition below) can travel between differ‐ - ent States. They are precompiled bits of code, independent of State. - That you can ‘carry around’ this is no unique to Luerl but a low‐level - implementation detail of the standard Lua language (https://lua.org), - for more on chunks read (https://www.lua.org/manual/5.3/manu‐ - al.html#3.3.2) the official Lua 5.3 reference manual - (https://www.lua.org/manual/5.3/manual.html). + Note that Lua Chunks (see definition below) can travel between differ‐ + ent States. They are precompiled bits of code, independent of State. + That you can ‘carry around’ this is no unique to Luerl but a low-level + implementation detail of the standard Lua language ⟨https://lua.org⟩, + for more on chunks read ⟨https://www.lua.org/manual/5.3/man‐ + ual.html#3.3.2⟩ the official Lua 5.3 reference manual + ⟨https://www.lua.org/manual/5.3/manual.html⟩. Spec Definitions Binary means an Erlang binary string. Chunks means a portion of precompiled bytecode. State means a Lua State, this is a Lua VM instance. Path means a file system path and file name. - KeyPath means an Erlang list of atoms representing nested names, + KeyPath means an Erlang list of atoms representing nested names, e.g. [table,pack] for table.pack. - Keys means Lua table keys, the keys of a key‐value structure. - - Functions - eval and do functions differ only in what they return. The do func‐ - tions return results and a new Lua State, the eval functions return a - tuple starting on ‘ok’ or ‘error’, then the result, or cause of error. - - do ‐‐> {Result, State} - - eval ‐‐> {ok, Result} | {error, Reason} + Keys means Lua table keys, the keys of a key-value structure. - luerl:eval(String|Binary|Form, State) ‐> {ok, Result} | {error, Reason, - StackTrace}. - Evaluate a Lua expression passed in as a string or binary, and return - its result. + CompileOptions means a list of compiler options. Currently supported + options are ‘return’, which returns the errors and warnings, and ‘re‐ + port’ which will log the errors and warnings. - luerl:evalfile(Path, State) ‐> {ok, Result} | {error, Reason, StackTrace}. - Load and execute a file, and return the result. + LuaCallReturn = {ok, Result, State} | {lua_error, Error, State} + This is the return value from evaluating a Lua call. - luerl:do(String|Binary|Form, State) ‐> {Result, NewState}. - Evaluate a Lua expression and return its result, and the new Lua State. + Functions + luerl:init() -> State + Get a new Lua State = a fresh Lua VM instance. - luerl:dofile(Path, State) ‐> {Result, NewState}. - Load and execute the Lua code in the file and return its result, and - the new Lua State. Equivalent to doing luerl:do(“return dofile(‘File‐ - Name’)”). + luerl:gc(State) -> State + Runs the garbage collector on a state and returns the new state. - luerl:load(String|Binary[, CompileOptions], State) ‐> {ok,Function,New‐ - State} | {error, Reason}. - Parse a Lua chunk as string or binary, and return a compiled chunk + luerl:load(String|Binary[, CompileOptions], State) -> {ok, Function, State} + | CompileError + Parse a Lua chunk as string or binary, and return a compiled chunk (‘form’). - luerl:loadfile(FileName[, CompileOptions], State) ‐> {ok,Function,NewState} - | {error, Reason}. + luerl:loadfile(FileName[, CompileOptions], State) -> {ok, Function, State} + | CompileError Parse a Lua file, and return a compiled chunk (‘form’). - luerl:path_loadfile([Path, ], FileName[, CompileOptions], State) ‐> - {ok,Function,FullName,State} | {error, Reason}. - Search Path until the file FileName is found. Parse the file and re‐ + luerl:path_loadfile([Path, ], FileName[, CompileOptions], State) -> + {ok,Function,FullName,State} | {error, Reason} + Search Path until the file FileName is found. Parse the file and re‐ turn a compiled chunk (‘form’). If Path is not given then the path de‐ fined in the environment variable LUA_LOAD_PATH is used. - luerl:load_module(KeyPath, ErlangModule, State) ‐> State. - Load ErlangModule and install its table at KeyPath which is encoded. - - luerl:load_module1(KeyPath, ErlangModule, State) ‐> State. - Load ErlangModule and install its table at KeyPath which is NOT encoded + luerl:load_module(KeyPath, ErlangModule, State) -> State + Load ErlangModule and install its table at KeyPath which is NOT en‐ + coded. - luerl:init() ‐> State. - Get a new Lua State = a fresh Lua VM instance. + luerl:load_module_dec(EncodedKeyPath, ErlangModule, State) -> State + Load ErlangModule and install its table at KeyPath which is encoded. - luerl:call(Form, Args, State) ‐> {Result,State} - luerl:call_chunk(Form, Args, State) ‐> {Result,State} - Call a compiled chunk or function. Use the call_chunk, call has been + luerl:do(String|Binary|Form, State) -> {ok, Result, NewState} | {lua_error, + Error, State} | CompileError + Evaluate a Lua expression and return its result which is NOT decoded, + and the new Lua State. + + luerl:do_dec(String|Binary|Form, State) -> {ok, Result, NewState} | + {lua_error, Error, State} | CompileError + Evaluate a Lua expression and return its result which is automatically + decoded, and the new Lua State. + + luerl:dofile(Path, State) -> {ok, Result, NewState} | {lua_error, Error, + State} | CompileError + Load and execute the Lua code in the file and return its result which + is NOT decoded, and the new Lua State. Equivalent to doing + luerl:do(“return dofile(‘FileName’)”). + + luerl:dofile_dec(Path[, State]) -> {ok, Result, NewState} | {lua_error, Er‐ + ror, State} | CompileError + Load and execute the Lua code in the file and return its result which + is automatically decoded, and the new Lua State. + + luerl:call(FuncRef, ArgRefs, State) -> {ok, Result, State} + luerl:call_chunk(FuncRef, ArgRefs, State) -> {ok, Result, State} | {lua_er‐ + ror, Error, State} + Call a compiled chunk or function. Use the call_chunk, call has been kept for backwards compatibility. - luerl:call_function(KeyPath, Args, State) ‐> {Result,NewState} - Call a function already defined in the state. KeyPath is a list of - names to the function. KeyPath, Args and Result are automatically en‐ + luerl:call_function(FuncRef | FuncPath, ArgRefs, State] -> {ok, Result, + State} | {lua_error, Error, State} + Call a function already defined in the state. Result is NOT decoded. + + luerl:call_function_dec(KeyPath, Args, State) -> {ok, Result, State} | + {lua_error, Error, State} + Call a function already defined in the state. KeyPath is a list of + keys to the function. KeyPath, Args and Result are automatically en‐ coded/decoded. - luerl:call_function1(KeyPath, Args, State) ‐> {Result,NewState} - Call a function already defined in the state. KeyPath is a list of - keys to the function. KeyPath, Args and Result are NOT encoded/decod‐ - ed. + luerl:call_method(ObjRef, Method, ArgRefs, State) -> {ok, Result, State} | + {lua_error, Error, State} + Call a method already defined in the state. - luerl:call_method(MethPath, Args, State) ‐> {Result,NewState}. - Call a method already defined in the state. MethPath is a list of - names to the method. MethPath, Args and Result are automatically en‐ + luerl:call_method_dec(KeyPath, Method, Args, State) -> {ok, Result, State} + | {lua_error, Error, State} + Call a method already defined in the state. KeyPath is a list of keys + to the method. KeyPath, Method, Args and Result are automatically en‐ coded/decoded. - luerl:call_method1(MethPath, Args, State) ‐> {Result,NewState} - Call a method already defined in the state. MethPath is a list of keys - to the method. Keys, Args and Result are NOT encoded/decoded. + luerl:get_table_keys(KeyPath, State) -> {ok, Result, State} | {lua_error, + Error, State} + Gets a value inside the Lua state. KeyPath and Result are NOT en‐ + coded/decoded. - luerl:stop(State) ‐> GCedState. - Garbage collects the state and (todo:) does away with it. + luerl:get_table_keys_dec(KeyPath, State) -> {ok, Result, State} | {lua_er‐ + ror, Error, State} + Gets a value inside the Lua state. KeyPath is automatically encoded + and Result is decoded. - luerl:gc(State) ‐> State. - Runs the garbage collector on a state and returns the new state. + luerl:set_table_keys(KeyPath, Value, State) -> {ok,State} | {lua_error, Er‐ + ror, State} + Sets a value inside the Lua state. KeyPath and Value are NOT encoded. - luerl:set_table(KeyPath, Value, State) ‐> State. - Sets a value inside the Lua state. Value is automatically encoded. + luerl:set_table_keys_dec(KeyPath, Value, State) -> {ok, Result, State} | + {lua_error, Error, State} + Sets a value inside the Lua state. KeyPath and Value are automatically + encoded and Result is decoded. - luerl:set_table1(KeyPath, Value, State) ‐> State. - Sets a value inside the Lua state. KeyPath and Value are NOT encoded. + luerl:get_table_key(Table, Key, State) -> {ok, Result, State} | {lua_error, + Error, State} + Gets the value of a key in a table. Table and Key are NOT encoded and + Result is NOT decoded. - luerl:get_table(KeyPath, State) ‐> {Result,State}. - Gets a value inside the Lua state. KeyPath and Result are automatical‐ - ly encoded. + luerl:set_table_key(Table, Key, Value, State) -> {ok, State} | {lua_error, + Error, State} + Sets the value of a key in a table. Table, Key and Value are NOT en‐ + coded. - luerl:get_table1(KeyPath, State) ‐> {Result,State}. - Gets a value inside the Lua state. KeyPath and Result are NOT encod‐ - ed/decoded. + luerl:get_stacktrace(State) -> [{FuncName,{file,FileName},{line,Line}}] + Return a stack trace of the current call stack in the state. - You can use this function to expose an function to the Lua code by us‐ - ing this interface: fun(Args, State) ‐> {Results, State} + luerl:encode(Term, State) -> {LuerlTerm,State} + Encode the Erlang representation of a term into Luerl form updating the + state when necessary. - Args and Results must be a list of Luerl compatible Erlang values. + luerl:encode_list([Term], State) -> {[LuerlTerm],State} + Encode a list of Erlang term representations into a list of Luerl forms + updating the state when necessary. -AUTHORS - Jean Chassoul, Robert Virding. + luerl:decode(LuerlTerm, State) -> Term + Decode a term in the Luerl form into its Erlang representation. + luerl:decode_list([LuerlTerm], State) -> [Term] + Decode a list of Luerl terms into a list of Erlang representations. +AUTHORS + Jean Chassoul, Robert Virding. - 2018‐2023 luerl(3) + 2018-2024 luerl(3) diff --git a/doc/luerl_old.txt b/doc/luerl_old.txt new file mode 100644 index 0000000..2dcf422 --- /dev/null +++ b/doc/luerl_old.txt @@ -0,0 +1,137 @@ +luerl_old(3) Library Functions Manual luerl_old(3) + +Name + luerl - The old original interface to the Luerl system + +Interface functions + The Lua State parameter is the state of a Lua VM instance. It must be + created with the luerl:init() call and be carried from one call to the + next. + + As it is possible in Lua to create self-referencing data structures, + indeed the standard libraries have many instances of this, then using + the functions which decode their return values will generate an error + when they would cause an infinite loop during the decoding. An simple + example is the top level table which contains a key _G which references + the top-level table. + + Note that Lua Chunks (see definition below) can travel between differ‐ + ent States. They are precompiled bits of code, independent of State. + That you can ‘carry around’ this is no unique to Luerl but a low-level + implementation detail of the standard Lua language ⟨https://lua.org⟩, + for more on chunks read ⟨https://www.lua.org/manual/5.3/man‐ + ual.html#3.3.2⟩ the official Lua 5.3 reference manual + ⟨https://www.lua.org/manual/5.3/manual.html⟩. + + Spec Definitions + Binary means an Erlang binary string. + Chunks means a portion of precompiled bytecode. + State means a Lua State, this is a Lua VM instance. + Path means a file system path and file name. + KeyPath means an Erlang list of atoms representing nested names, + e.g. [table,pack] for table.pack. + Keys means Lua table keys, the keys of a key-value structure. + + Functions + eval and do functions differ only in what they return. The do func‐ + tions return results and a new Lua State, the eval functions return a + tuple starting on ‘ok’ or ‘error’, then the result, or cause of error. + + do --> {Result, State} + + eval --> {ok, Result} | {error, Reason} + + luerl:eval(String|Binary|Form, State) -> {ok, Result} | {error, Reason, + StackTrace}. + Evaluate a Lua expression passed in as a string or binary, and return + its result. + + luerl:evalfile(Path, State) -> {ok, Result} | {error, Reason, StackTrace}. + + Load and execute a file, and return the result. + + luerl:do(String|Binary|Form, State) -> {Result, NewState}. + Evaluate a Lua expression and return its result, and the new Lua State. + + luerl:dofile(Path, State) -> {Result, NewState}. + Load and execute the Lua code in the file and return its result, and + the new Lua State. Equivalent to doing luerl:do(“return dofile(‘File‐ + Name’)”). + + luerl:load(String|Binary[, CompileOptions], State) -> {ok,Function,New‐ + State} | {error, Reason}. + Parse a Lua chunk as string or binary, and return a compiled chunk + (‘form’). + + luerl:loadfile(FileName[, CompileOptions], State) -> {ok,Function,NewState} + | {error, Reason}. + Parse a Lua file, and return a compiled chunk (‘form’). + + luerl:path_loadfile([Path, ], FileName[, CompileOptions], State) -> + {ok,Function,FullName,State} | {error, Reason}. + Search Path until the file FileName is found. Parse the file and re‐ + turn a compiled chunk (‘form’). If Path is not given then the path de‐ + fined in the environment variable LUA_LOAD_PATH is used. + + luerl:load_module(KeyPath, ErlangModule, State) -> State. + Load ErlangModule and install its table at KeyPath which is encoded. + + luerl:load_module1(KeyPath, ErlangModule, State) -> State. + Load ErlangModule and install its table at KeyPath which is NOT encoded + + luerl:init() -> State. + Get a new Lua State = a fresh Lua VM instance. + + luerl:call(Form, Args, State) -> {Result,State} + luerl:call_chunk(Form, Args, State) -> {Result,State} + Call a compiled chunk or function. Use the call_chunk, call has been + kept for backwards compatibility. + + luerl:call_function(KeyPath, Args, State) -> {Result,NewState} + Call a function already defined in the state. KeyPath is a list of + names to the function. KeyPath, Args and Result are automatically en‐ + coded/decoded. + + luerl:call_function1(KeyPath, Args, State) -> {Result,NewState} + Call a function already defined in the state. KeyPath is a list of + keys to the function. KeyPath, Args and Result are NOT encoded/de‐ + coded. + + luerl:call_method(MethPath, Args, State) -> {Result,NewState}. + Call a method already defined in the state. MethPath is a list of + names to the method. MethPath, Args and Result are automatically en‐ + coded/decoded. + + luerl:call_method1(MethPath, Args, State) -> {Result,NewState} + Call a method already defined in the state. MethPath is a list of keys + to the method. Keys, Args and Result are NOT encoded/decoded. + + luerl:stop(State) -> GCedState. + Garbage collects the state and (todo:) does away with it. + + luerl:gc(State) -> State. + Runs the garbage collector on a state and returns the new state. + + luerl:set_table(KeyPath, Value, State) -> State. + Sets a value inside the Lua state. Value is automatically encoded. + + luerl:set_table1(KeyPath, Value, State) -> State. + Sets a value inside the Lua state. KeyPath and Value are NOT encoded. + + luerl:get_table(KeyPath, State) -> {Result,State}. + Gets a value inside the Lua state. KeyPath and Result are automati‐ + cally encoded. + + luerl:get_table1(KeyPath, State) -> {Result,State}. + Gets a value inside the Lua state. KeyPath and Result are NOT en‐ + coded/decoded. + + You can use this function to expose an function to the Lua code by us‐ + ing this interface: fun(Args, State) -> {Results, State} + + Args and Results must be a list of Luerl compatible Erlang values. + +AUTHORS + Jean Chassoul, Robert Virding. + + 2018-2024 luerl_old(3) diff --git a/doc/man/luerl.3 b/doc/man/luerl.3 index 3ecb3d2..cc0121c 100644 --- a/doc/man/luerl.3 +++ b/doc/man/luerl.3 @@ -1,44 +1,38 @@ -.\" Automatically generated by Pandoc 3.1.6.1 +.\" Automatically generated by Pandoc 3.5 .\" -.\" Define V font for inline verbatim, using C font in formats -.\" that render this, and otherwise B font. -.ie "\f[CB]x\f[]"x" \{\ -. ftr V B -. ftr VI BI -. ftr VB B -. ftr VBI BI -.\} -.el \{\ -. ftr V CR -. ftr VI CI -. ftr VB CB -. ftr VBI CBI -.\} -.TH "luerl" "3" "2018-2023" "" "" -.hy -.SH Interface functions -.PP +.TH "luerl" "3" "2018\-2024" "" +.SH Name +luerl \- The basic interface to the Luerl system +.SH Interface functions \- New Version The \f[B]Lua State\f[R] parameter is the state of a Lua VM instance. It must be created with the \f[B]luerl:init()\f[R] call and be carried from one call to the next. .PP -As it is possible in Lua to create self-referencing data structures, +As it is possible in Lua to create self\-referencing data structures, indeed the standard libraries have many instances of this, then using the functions which decode their return values will generate an error when they would cause an infinite loop during the decoding. An simple example is the top level table which contains a key -\f[B]\f[VB]_G\f[B]\f[R] which references the top-level table. +\f[B]\f[CB]_G\f[B]\f[R] which references the top\-level table. .PP Note that Lua \f[B]Chunks\f[R] (see definition below) can travel between different States. They are precompiled bits of code, independent of State. -That you can `carry around' this is no unique to Luerl but a low-level -implementation detail of the standard Lua language (https://lua.org), -for more on chunks -read (https://www.lua.org/manual/5.3/manual.html#3.3.2) the official Lua -5.3 reference manual (https://www.lua.org/manual/5.3/manual.html). +That you can `carry around' this is no unique to Luerl but a low\-level +implementation detail of the standard Lua \c +.UR https://lua.org +language +.UE \c +, for more on chunks \c +.UR https://www.lua.org/manual/5.3/manual.html#3.3.2 +read +.UE \c +\ the official Lua 5.3 \c +.UR https://www.lua.org/manual/5.3/manual.html +reference manual +.UE \c +\&. .SS Spec Definitions -.PP \f[B]Binary\f[R] means an Erlang binary string. .PD 0 .P @@ -60,117 +54,105 @@ nested names, e.g.\ [table,pack] for table.pack. .PD 0 .P .PD -\f[B]Keys\f[R] means Lua table keys, the keys of a key-value structure. -.SS Functions -.PP -\f[B]eval\f[R] and \f[B]do\f[R] functions differ only in what they -return. -The \f[B]do\f[R] functions return results and a new Lua State, the -\f[B]eval\f[R] functions return a tuple starting on `ok' or `error', -then the result, or cause of error. -.IP -.nf -\f[C] -do --> {Result, State} - -eval --> {ok, Result} | {error, Reason} -\f[R] -.fi -.SS luerl:eval(String|Binary|Form, State) -> {ok, Result} | {error, Reason, StackTrace}. -.PP -Evaluate a Lua expression passed in as a string or binary, and return -its result. -.SS luerl:evalfile(Path, State) -> {ok, Result} | {error, Reason, StackTrace}. -.PP -Load and execute a file, and return the result. -.SS luerl:do(String|Binary|Form, State) -> {Result, NewState}. +\f[B]Keys\f[R] means Lua table keys, the keys of a key\-value structure. .PP -Evaluate a Lua expression and return its result, and the new Lua State. -.SS luerl:dofile(Path, State) -> {Result, NewState}. -.PP -Load and execute the Lua code in the file and return its result, and the -new Lua State. -Equivalent to doing luerl:do(\[lq]return dofile(`FileName')\[rq]). -.SS luerl:load(String|Binary[, CompileOptions], State) -> {ok,Function,NewState} | {error, Reason}. +\f[B]CompileOptions\f[R] means a list of compiler options. +Currently supported options are `return', which returns the errors and +warnings, and `report' which will log the errors and warnings. .PP +\f[B]LuaCallReturn = {ok, Result, State} | {lua_error, Error, +State}\f[R] +.PD 0 +.P +.PD +This is the return value from evaluating a Lua call. +.SS Functions +.SS luerl:init() \-> State +Get a new Lua State = a fresh Lua VM instance. +.SS luerl:gc(State) \-> State +Runs the garbage collector on a state and returns the new state. +.SS luerl:load(String|Binary[, CompileOptions], State) \-> {ok, Function, State} | CompileError Parse a Lua chunk as string or binary, and return a compiled chunk (`form'). -.SS luerl:loadfile(FileName[, CompileOptions], State) -> {ok,Function,NewState} | {error, Reason}. -.PP +.SS luerl:loadfile(FileName[, CompileOptions], State) \-> {ok, Function, State} | CompileError Parse a Lua file, and return a compiled chunk (`form'). -.SS luerl:path_loadfile([Path, ], FileName[, CompileOptions], State) -> {ok,Function,FullName,State} | {error, Reason}. -.PP +.SS luerl:path_loadfile([Path, ], FileName[, CompileOptions], State) \-> {ok,Function,FullName,State} | {error, Reason} Search Path until the file FileName is found. Parse the file and return a compiled chunk (`form'). If Path is not given then the path defined in the environment variable LUA_LOAD_PATH is used. -.SS luerl:load_module(KeyPath, ErlangModule, State) -> State. -.PP -Load \f[V]ErlangModule\f[R] and install its table at \f[V]KeyPath\f[R] +.SS luerl:load_module(KeyPath, ErlangModule, State) \-> State +Load \f[CR]ErlangModule\f[R] and install its table at \f[CR]KeyPath\f[R] +which is \f[B]NOT\f[R] encoded. +.SS luerl:load_module_dec(EncodedKeyPath, ErlangModule, State) \-> State +Load \f[CR]ErlangModule\f[R] and install its table at \f[CR]KeyPath\f[R] which is encoded. -.SS luerl:load_module1(KeyPath, ErlangModule, State) -> State. -.PP -Load \f[V]ErlangModule\f[R] and install its table at \f[V]KeyPath\f[R] -which is \f[B]NOT\f[R] encoded -.SS luerl:init() -> State. -.PP -Get a new Lua State = a fresh Lua VM instance. -.SS luerl:call(Form, Args, State) -> {Result,State} -.SS luerl:call_chunk(Form, Args, State) -> {Result,State} -.PP +.SS luerl:do(String|Binary|Form, State) \-> {ok, Result, NewState} | {lua_error, Error, State} | CompileError +Evaluate a Lua expression and return its result which is \f[B]NOT\f[R] +decoded, and the new Lua State. +.SS luerl:do_dec(String|Binary|Form, State) \-> {ok, Result, NewState} | {lua_error, Error, State} | CompileError +Evaluate a Lua expression and return its result which is automatically +decoded, and the new Lua State. +.SS luerl:dofile(Path, State) \-> {ok, Result, NewState} | {lua_error, Error, State} | CompileError +Load and execute the Lua code in the file and return its result which is +\f[B]NOT\f[R] decoded, and the new Lua State. +Equivalent to doing luerl:do(\[lq]return dofile(`FileName')\[rq]). +.SS luerl:dofile_dec(Path[, State]) \-> {ok, Result, NewState} | {lua_error, Error, State} | CompileError +Load and execute the Lua code in the file and return its result which is +automatically decoded, and the new Lua State. +.SS luerl:call(FuncRef, ArgRefs, State) \-> {ok, Result, State} +.SS luerl:call_chunk(FuncRef, ArgRefs, State) \-> {ok, Result, State} | {lua_error, Error, State} Call a compiled chunk or function. Use the call_chunk, call has been kept for backwards compatibility. -.SS luerl:call_function(KeyPath, Args, State) -> {Result,NewState} -.PP +.SS luerl:call_function(FuncRef | FuncPath, ArgRefs, State] \-> {ok, Result, State} | {lua_error, Error, State} Call a function already defined in the state. -\f[V]KeyPath\f[R] is a list of names to the function. -\f[V]KeyPath\f[R], \f[V]Args\f[R] and \f[V]Result\f[R] are automatically -encoded/decoded. -.SS luerl:call_function1(KeyPath, Args, State) -> {Result,NewState} -.PP +\f[CR]Result\f[R] is \f[B]NOT\f[R] decoded. +.SS luerl:call_function_dec(KeyPath, Args, State) \-> {ok, Result, State} | {lua_error, Error, State} Call a function already defined in the state. -\f[V]KeyPath\f[R] is a list of keys to the function. -\f[V]KeyPath\f[R], \f[V]Args\f[R] and \f[V]Result\f[R] are \f[B]NOT\f[R] -encoded/decoded. -.SS luerl:call_method(MethPath, Args, State) -> {Result,NewState}. -.PP -Call a method already defined in the state. -\f[V]MethPath\f[R] is a list of names to the method. -\f[V]MethPath\f[R], \f[V]Args\f[R] and \f[V]Result\f[R] are +\f[CR]KeyPath\f[R] is a list of keys to the function. +\f[CR]KeyPath\f[R], \f[CR]Args\f[R] and \f[CR]Result\f[R] are automatically encoded/decoded. -.SS luerl:call_method1(MethPath, Args, State) -> {Result,NewState} -.PP +.SS luerl:call_method(ObjRef, Method, ArgRefs, State) \-> {ok, Result, State} | {lua_error, Error, State} +Call a method already defined in the state. +.SS luerl:call_method_dec(KeyPath, Method, Args, State) \-> {ok, Result, State} | {lua_error, Error, State} Call a method already defined in the state. -\f[V]MethPath\f[R] is a list of keys to the method. -\f[V]Keys\f[R], \f[V]Args\f[R] and \f[V]Result\f[R] are \f[B]NOT\f[R] +\f[CR]KeyPath\f[R] is a list of keys to the method. +\f[CR]KeyPath\f[R], \f[CR]Method\f[R], \f[CR]Args\f[R] and +\f[CR]Result\f[R] are automatically encoded/decoded. +.SS luerl:get_table_keys(KeyPath, State) \-> {ok, Result, State} | {lua_error, Error, State} +Gets a value inside the Lua state. +\f[CR]KeyPath\f[R] and \f[CR]Result\f[R] are \f[B]NOT\f[R] encoded/decoded. -.SS luerl:stop(State) -> GCedState. -.PP -Garbage collects the state and (todo:) does away with it. -.SS luerl:gc(State) -> State. -.PP -Runs the garbage collector on a state and returns the new state. -.SS luerl:set_table(KeyPath, Value, State) -> State. -.PP +.SS luerl:get_table_keys_dec(KeyPath, State) \-> {ok, Result, State} | {lua_error, Error, State} +Gets a value inside the Lua state. +\f[CR]KeyPath\f[R] is automatically encoded and \f[CR]Result\f[R] is +decoded. +.SS luerl:set_table_keys(KeyPath, Value, State) \-> {ok,State} | {lua_error, Error, State} Sets a value inside the Lua state. -Value is automatically encoded. -.SS luerl:set_table1(KeyPath, Value, State) -> State. -.PP +\f[CR]KeyPath\f[R] and \f[CR]Value\f[R] are \f[B]NOT\f[R] encoded. +.SS luerl:set_table_keys_dec(KeyPath, Value, State) \-> {ok, Result, State} | {lua_error, Error, State} Sets a value inside the Lua state. -\f[V]KeyPath\f[R] and \f[V]Value\f[R] are \f[B]NOT\f[R] encoded. -.SS luerl:get_table(KeyPath, State) -> {Result,State}. -.PP -Gets a value inside the Lua state. -\f[V]KeyPath\f[R] and \f[V]Result\f[R] are automatically encoded. -.SS luerl:get_table1(KeyPath, State) -> {Result,State}. -.PP -Gets a value inside the Lua state. -\f[V]KeyPath\f[R] and \f[V]Result\f[R] are \f[B]NOT\f[R] -encoded/decoded. -.PP -You can use this function to expose an function to the Lua code by using -this interface: \f[V]fun(Args, State) -> {Results, State}\f[R] -.PP -Args and Results must be a list of Luerl compatible Erlang values. +\f[CR]KeyPath\f[R] and \f[CR]Value\f[R] are automatically encoded and +\f[CR]Result\f[R] is decoded. +.SS luerl:get_table_key(Table, Key, State) \-> {ok, Result, State} | {lua_error, Error, State} +Gets the value of a key in a table. +\f[CR]Table\f[R] and \f[CR]Key\f[R] are \f[B]NOT\f[R] encoded and +\f[CR]Result\f[R] is \f[B]NOT\f[R] decoded. +.SS luerl:set_table_key(Table, Key, Value, State) \-> {ok, State} | {lua_error, Error, State} +Sets the value of a key in a table. +\f[CR]Table\f[R], \f[CR]Key\f[R] and \f[CR]Value\f[R] are \f[B]NOT\f[R] +encoded. +.SS luerl:get_stacktrace(State) \-> [{FuncName,{file,FileName},{line,Line}}] +Return a stack trace of the current call stack in the state. +.SS luerl:encode(Term, State) \-> {LuerlTerm,State} +Encode the Erlang representation of a term into Luerl form updating the +state when necessary. +.SS luerl:encode_list([Term], State) \-> {[LuerlTerm],State} +Encode a list of Erlang term representations into a list of Luerl forms +updating the state when necessary. +.SS luerl:decode(LuerlTerm, State) \-> Term +Decode a term in the Luerl form into its Erlang representation. +.SS luerl:decode_list([LuerlTerm], State) \-> [Term] +Decode a list of Luerl terms into a list of Erlang representations. .SH AUTHORS Jean Chassoul, Robert Virding. diff --git a/doc/man/luerl_old.3 b/doc/man/luerl_old.3 new file mode 100644 index 0000000..a3e4e04 --- /dev/null +++ b/doc/man/luerl_old.3 @@ -0,0 +1,146 @@ +.\" Automatically generated by Pandoc 3.5 +.\" +.TH "luerl_old" "3" "2018\-2024" "" +.SH Name +luerl \- The old original interface to the Luerl system +.SH Interface functions +The \f[B]Lua State\f[R] parameter is the state of a Lua VM instance. +It must be created with the \f[B]luerl:init()\f[R] call and be carried +from one call to the next. +.PP +As it is possible in Lua to create self\-referencing data structures, +indeed the standard libraries have many instances of this, then using +the functions which decode their return values will generate an error +when they would cause an infinite loop during the decoding. +An simple example is the top level table which contains a key +\f[B]\f[CB]_G\f[B]\f[R] which references the top\-level table. +.PP +Note that Lua \f[B]Chunks\f[R] (see definition below) can travel between +different States. +They are precompiled bits of code, independent of State. +That you can `carry around' this is no unique to Luerl but a low\-level +implementation detail of the standard Lua \c +.UR https://lua.org +language +.UE \c +, for more on chunks \c +.UR https://www.lua.org/manual/5.3/manual.html#3.3.2 +read +.UE \c +\ the official Lua 5.3 \c +.UR https://www.lua.org/manual/5.3/manual.html +reference manual +.UE \c +\&. +.SS Spec Definitions +\f[B]Binary\f[R] means an Erlang binary string. +.PD 0 +.P +.PD +\f[B]Chunks\f[R] means a portion of precompiled bytecode. +.PD 0 +.P +.PD +\f[B]State\f[R] means a Lua State, this \f[I]is\f[R] a Lua VM instance. +.PD 0 +.P +.PD +\f[B]Path\f[R] means a file system path and file name. +.PD 0 +.P +.PD +\f[B]KeyPath\f[R] means an Erlang list of \f[B]atoms\f[R] representing +nested names, e.g.\ [table,pack] for table.pack. +.PD 0 +.P +.PD +\f[B]Keys\f[R] means Lua table keys, the keys of a key\-value structure. +.SS Functions +\f[B]eval\f[R] and \f[B]do\f[R] functions differ only in what they +return. +The \f[B]do\f[R] functions return results and a new Lua State, the +\f[B]eval\f[R] functions return a tuple starting on `ok' or `error', +then the result, or cause of error. +.IP +.EX +do \-\-> {Result, State} + +eval \-\-> {ok, Result} | {error, Reason} +.EE +.SS luerl:eval(String|Binary|Form, State) \-> {ok, Result} | {error, Reason, StackTrace}. +Evaluate a Lua expression passed in as a string or binary, and return +its result. +.SS luerl:evalfile(Path, State) \-> {ok, Result} | {error, Reason, StackTrace}. +Load and execute a file, and return the result. +.SS luerl:do(String|Binary|Form, State) \-> {Result, NewState}. +Evaluate a Lua expression and return its result, and the new Lua State. +.SS luerl:dofile(Path, State) \-> {Result, NewState}. +Load and execute the Lua code in the file and return its result, and the +new Lua State. +Equivalent to doing luerl:do(\[lq]return dofile(`FileName')\[rq]). +.SS luerl:load(String|Binary[, CompileOptions], State) \-> {ok,Function,NewState} | {error, Reason}. +Parse a Lua chunk as string or binary, and return a compiled chunk +(`form'). +.SS luerl:loadfile(FileName[, CompileOptions], State) \-> {ok,Function,NewState} | {error, Reason}. +Parse a Lua file, and return a compiled chunk (`form'). +.SS luerl:path_loadfile([Path, ], FileName[, CompileOptions], State) \-> {ok,Function,FullName,State} | {error, Reason}. +Search Path until the file FileName is found. +Parse the file and return a compiled chunk (`form'). +If Path is not given then the path defined in the environment variable +LUA_LOAD_PATH is used. +.SS luerl:load_module(KeyPath, ErlangModule, State) \-> State. +Load \f[CR]ErlangModule\f[R] and install its table at \f[CR]KeyPath\f[R] +which is encoded. +.SS luerl:load_module1(KeyPath, ErlangModule, State) \-> State. +Load \f[CR]ErlangModule\f[R] and install its table at \f[CR]KeyPath\f[R] +which is \f[B]NOT\f[R] encoded +.SS luerl:init() \-> State. +Get a new Lua State = a fresh Lua VM instance. +.SS luerl:call(Form, Args, State) \-> {Result,State} +.SS luerl:call_chunk(Form, Args, State) \-> {Result,State} +Call a compiled chunk or function. +Use the call_chunk, call has been kept for backwards compatibility. +.SS luerl:call_function(KeyPath, Args, State) \-> {Result,NewState} +Call a function already defined in the state. +\f[CR]KeyPath\f[R] is a list of names to the function. +\f[CR]KeyPath\f[R], \f[CR]Args\f[R] and \f[CR]Result\f[R] are +automatically encoded/decoded. +.SS luerl:call_function1(KeyPath, Args, State) \-> {Result,NewState} +Call a function already defined in the state. +\f[CR]KeyPath\f[R] is a list of keys to the function. +\f[CR]KeyPath\f[R], \f[CR]Args\f[R] and \f[CR]Result\f[R] are +\f[B]NOT\f[R] encoded/decoded. +.SS luerl:call_method(MethPath, Args, State) \-> {Result,NewState}. +Call a method already defined in the state. +\f[CR]MethPath\f[R] is a list of names to the method. +\f[CR]MethPath\f[R], \f[CR]Args\f[R] and \f[CR]Result\f[R] are +automatically encoded/decoded. +.SS luerl:call_method1(MethPath, Args, State) \-> {Result,NewState} +Call a method already defined in the state. +\f[CR]MethPath\f[R] is a list of keys to the method. +\f[CR]Keys\f[R], \f[CR]Args\f[R] and \f[CR]Result\f[R] are \f[B]NOT\f[R] +encoded/decoded. +.SS luerl:stop(State) \-> GCedState. +Garbage collects the state and (todo:) does away with it. +.SS luerl:gc(State) \-> State. +Runs the garbage collector on a state and returns the new state. +.SS luerl:set_table(KeyPath, Value, State) \-> State. +Sets a value inside the Lua state. +Value is automatically encoded. +.SS luerl:set_table1(KeyPath, Value, State) \-> State. +Sets a value inside the Lua state. +\f[CR]KeyPath\f[R] and \f[CR]Value\f[R] are \f[B]NOT\f[R] encoded. +.SS luerl:get_table(KeyPath, State) \-> {Result,State}. +Gets a value inside the Lua state. +\f[CR]KeyPath\f[R] and \f[CR]Result\f[R] are automatically encoded. +.SS luerl:get_table1(KeyPath, State) \-> {Result,State}. +Gets a value inside the Lua state. +\f[CR]KeyPath\f[R] and \f[CR]Result\f[R] are \f[B]NOT\f[R] +encoded/decoded. +.PP +You can use this function to expose an function to the Lua code by using +this interface: \f[CR]fun(Args, State) \-> {Results, State}\f[R] +.PP +Args and Results must be a list of Luerl compatible Erlang values. +.SH AUTHORS +Jean Chassoul, Robert Virding. diff --git a/doc/pdf/luerl.pdf b/doc/pdf/luerl.pdf index c98516f3e1f3cd61b6aba0e8363dc8435cef7b49..c64fc3e2ba581ec0a988fee00d16f45b44a1b993 100644 GIT binary patch literal 52771 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 diff --git a/doc/pdf/luerl_old.pdf b/doc/pdf/luerl_old.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3ec06591263c11d4b29104413a9e453c0c13cd25 GIT binary patch literal 49816 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 R`?0a{*_&Uk*SC-N%P&WEZHNE> literal 0 HcmV?d00001 diff --git a/doc/src/luerl.3.md b/doc/src/luerl.3.md index f5319e2..d07ca8f 100644 --- a/doc/src/luerl.3.md +++ b/doc/src/luerl.3.md @@ -1,97 +1,115 @@ % luerl(3) % Jean Chassoul, Robert Virding -% 2018-2023 +% 2018-2024 # Name -luerl - Basic interface to the Luerl system +luerl - The basic interface to the Luerl system -# Interface functions -The **Lua State** parameter is the state of a Lua VM instance. It must be created with the **luerl:init()** call and be carried from one call to the next. +# Interface functions - New Version +The **Lua State** parameter is the state of a Lua VM instance. It must be created with the **luerl:init()** call and be carried from one call to the next. As it is possible in Lua to create self-referencing data structures, indeed the standard libraries have many instances of this, then using the functions which decode their return values will generate an error when they would cause an infinite loop during the decoding. An simple example is the top level table which contains a key **`_G`** which references the top-level table. Note that Lua **Chunks** (see definition below) can travel between different States. They are precompiled bits of code, independent of State. That you can 'carry around' this is no unique to Luerl but a low-level implementation detail of the standard Lua [language](https://lua.org), for more on chunks [read](https://www.lua.org/manual/5.3/manual.html#3.3.2) the official Lua 5.3 [reference manual](https://www.lua.org/manual/5.3/manual.html). ## Spec Definitions -**Binary** means an Erlang binary string. -**Chunks** means a portion of precompiled bytecode. -**State** means a Lua State, this *is* a Lua VM instance. -**Path** means a file system path and file name. -**KeyPath** means an Erlang list of **atoms** representing nested names, e.g. [table,pack] for table.pack. -**Keys** means Lua table keys, the keys of a key-value structure. -## Functions -**eval** and **do** functions differ only in what they return. The **do** functions return results and a new Lua State, the **eval** functions return a tuple starting on 'ok' or 'error', then the result, or cause of error. +**Binary** means an Erlang binary string. +**Chunks** means a portion of precompiled bytecode. +**State** means a Lua State, this *is* a Lua VM instance. +**Path** means a file system path and file name. +**KeyPath** means an Erlang list of **atoms** representing nested names, e.g. [table,pack] for table.pack. +**Keys** means Lua table keys, the keys of a key-value structure. - do --> {Result, State} +**CompileOptions** means a list of compiler options. Currently supported options are 'return', which returns the errors and warnings, and 'report' which will log the errors and warnings. - eval --> {ok, Result} | {error, Reason} -#### luerl:eval(String|Binary|Form, State) -> {ok, Result} | {error, Reason, StackTrace}. - Evaluate a Lua expression passed in as a string or binary, and return its result. +**LuaCallReturn = {ok, Result, State} | {lua_error, Error, State}** +This is the return value from evaluating a Lua call. -#### luerl:evalfile(Path, State) -> {ok, Result} | {error, Reason, StackTrace}. - Load and execute a file, and return the result. +## Functions -#### luerl:do(String|Binary|Form, State) -> {Result, NewState}. - Evaluate a Lua expression and return its result, and the new Lua State. +#### luerl:init() -> State + Get a new Lua State = a fresh Lua VM instance. -#### luerl:dofile(Path, State) -> {Result, NewState}. - Load and execute the Lua code in the file and return its result, and the new Lua State. Equivalent to doing luerl:do("return dofile('FileName')"). +#### luerl:gc(State) -> State + Runs the garbage collector on a state and returns the new state. -#### luerl:load(String|Binary[, CompileOptions], State) -> {ok,Function,NewState} | {error, Reason}. +#### luerl:load(String|Binary[, CompileOptions], State) -> {ok, Function, State} | CompileError Parse a Lua chunk as string or binary, and return a compiled chunk ('form'). -#### luerl:loadfile(FileName[, CompileOptions], State) -> {ok,Function,NewState} | {error, Reason}. +#### luerl:loadfile(FileName[, CompileOptions], State) -> {ok, Function, State} | CompileError Parse a Lua file, and return a compiled chunk ('form'). -#### luerl:path_loadfile([Path, ], FileName[, CompileOptions], State) -> {ok,Function,FullName,State} | {error, Reason}. +#### luerl:path_loadfile([Path, ], FileName[, CompileOptions], State) -> {ok,Function,FullName,State} | {error, Reason} Search Path until the file FileName is found. Parse the file and return a compiled chunk ('form'). If Path is not given then the path defined in the environment variable LUA_LOAD_PATH is used. -#### luerl:load_module(KeyPath, ErlangModule, State) -> State. +#### luerl:load_module(KeyPath, ErlangModule, State) -> State + Load `ErlangModule` and install its table at `KeyPath` which is **NOT** encoded. + +#### luerl:load_module_dec(EncodedKeyPath, ErlangModule, State) -> State Load `ErlangModule` and install its table at `KeyPath` which is encoded. -#### luerl:load_module1(KeyPath, ErlangModule, State) -> State. - Load `ErlangModule` and install its table at `KeyPath` which is **NOT** encoded +#### luerl:do(String|Binary|Form, State) -> {ok, Result, NewState} | {lua_error, Error, State} | CompileError + Evaluate a Lua expression and return its result which is **NOT** decoded, and the new Lua State. -#### luerl:init() -> State. - Get a new Lua State = a fresh Lua VM instance. +#### luerl:do_dec(String|Binary|Form, State) -> {ok, Result, NewState} | {lua_error, Error, State} | CompileError + Evaluate a Lua expression and return its result which is automatically decoded, and the new Lua State. -#### luerl:call(Form, Args, State) -> {Result,State} -#### luerl:call_chunk(Form, Args, State) -> {Result,State} -Call a compiled chunk or function. Use the call_chunk, call has been kept for backwards compatibility. +#### luerl:dofile(Path, State) -> {ok, Result, NewState} | {lua_error, Error, State} | CompileError + Load and execute the Lua code in the file and return its result which is **NOT** decoded, and the new Lua State. Equivalent to doing luerl:do("return dofile('FileName')"). -#### luerl:call_function(KeyPath, Args, State) -> {Result,NewState} -Call a function already defined in the state. `KeyPath` is a list of names to the function. `KeyPath`, `Args` and `Result` are automatically encoded/decoded. +#### luerl:dofile_dec(Path[, State]) -> {ok, Result, NewState} | {lua_error, Error, State} | CompileError + Load and execute the Lua code in the file and return its result which is automatically decoded, and the new Lua State. -#### luerl:call_function1(KeyPath, Args, State) -> {Result,NewState} -Call a function already defined in the state. `KeyPath` is a list of keys to the function. `KeyPath`, `Args` and `Result` are **NOT** encoded/decoded. +#### luerl:call(FuncRef, ArgRefs, State) -> {ok, Result, State} -#### luerl:call_method(MethPath, Args, State) -> {Result,NewState}. -Call a method already defined in the state. `MethPath` is a list of names to the method. `MethPath`, `Args` and `Result` are automatically encoded/decoded. +#### luerl:call_chunk(FuncRef, ArgRefs, State) -> {ok, Result, State} | {lua_error, Error, State} +Call a compiled chunk or function. Use the call_chunk, call has been kept for backwards compatibility. -#### luerl:call_method1(MethPath, Args, State) -> {Result,NewState} -Call a method already defined in the state. `MethPath` is a list of keys to the method. `Keys`, `Args` and `Result` are **NOT** encoded/decoded. +#### luerl:call_function(FuncRef | FuncPath, ArgRefs, State] -> {ok, Result, State} | {lua_error, Error, State} +Call a function already defined in the state. `Result` is **NOT** decoded. -#### luerl:stop(State) -> GCedState. - Garbage collects the state and (todo:) does away with it. +#### luerl:call_function_dec(KeyPath, Args, State) -> {ok, Result, State} | {lua_error, Error, State} +Call a function already defined in the state. `KeyPath` is a list of keys to the function. `KeyPath`, `Args` and `Result` are automatically encoded/decoded. -#### luerl:gc(State) -> State. - Runs the garbage collector on a state and returns the new state. +#### luerl:call_method(ObjRef, Method, ArgRefs, State) -> {ok, Result, State} | {lua_error, Error, State} +Call a method already defined in the state. + +#### luerl:call_method_dec(KeyPath, Method, Args, State) -> {ok, Result, State} | {lua_error, Error, State} +Call a method already defined in the state. `KeyPath` is a list of keys to the method. `KeyPath`, `Method`, `Args` and `Result` are automatically encoded/decoded. + +#### luerl:get_table_keys(KeyPath, State) -> {ok, Result, State} | {lua_error, Error, State} + Gets a value inside the Lua state. `KeyPath` and `Result` are **NOT** encoded/decoded. -#### luerl:set_table(KeyPath, Value, State) -> State. - Sets a value inside the Lua state. Value is automatically encoded. +#### luerl:get_table_keys_dec(KeyPath, State) -> {ok, Result, State} | {lua_error, Error, State} + Gets a value inside the Lua state. `KeyPath` is automatically encoded and `Result` is decoded. -#### luerl:set_table1(KeyPath, Value, State) -> State. +#### luerl:set_table_keys(KeyPath, Value, State) -> {ok,State} | {lua_error, Error, State} Sets a value inside the Lua state. `KeyPath` and `Value` are **NOT** encoded. -#### luerl:get_table(KeyPath, State) -> {Result,State}. - Gets a value inside the Lua state. `KeyPath` and `Result` are automatically encoded. +#### luerl:set_table_keys_dec(KeyPath, Value, State) -> {ok, Result, State} | {lua_error, Error, State} + Sets a value inside the Lua state. `KeyPath` and `Value` are automatically encoded and `Result` is decoded. -#### luerl:get_table1(KeyPath, State) -> {Result,State}. - Gets a value inside the Lua state. `KeyPath` and `Result` are **NOT** encoded/decoded. +#### luerl:get_table_key(Table, Key, State) -> {ok, Result, State} | {lua_error, Error, State} + Gets the value of a key in a table. `Table` and `Key` are **NOT** encoded and `Result` is **NOT** decoded. + +#### luerl:set_table_key(Table, Key, Value, State) -> {ok, State} | {lua_error, Error, State} + Sets the value of a key in a table. `Table`, `Key` and `Value` are **NOT** encoded. + +#### luerl:get_stacktrace(State) -> [{FuncName,{file,FileName},{line,Line}}] +Return a stack trace of the current call stack in the state. + +#### luerl:encode(Term, State) -> {LuerlTerm,State} +Encode the Erlang representation of a term into Luerl form updating +the state when necessary. + +#### luerl:encode_list([Term], State) -> {[LuerlTerm],State} +Encode a list of Erlang term representations into a list of Luerl +forms updating the state when necessary. - You can use this function to expose an function to the Lua code by using this interface: - `fun(Args, State) -> {Results, State}` +#### luerl:decode(LuerlTerm, State) -> Term +Decode a term in the Luerl form into its Erlang representation. - Args and Results must be a list of Luerl compatible Erlang values. +#### luerl:decode_list([LuerlTerm], State) -> [Term] +Decode a list of Luerl terms into a list of Erlang representations. diff --git a/doc/src/luerl_old.3.md b/doc/src/luerl_old.3.md new file mode 100644 index 0000000..345ec36 --- /dev/null +++ b/doc/src/luerl_old.3.md @@ -0,0 +1,97 @@ +% luerl_old(3) +% Jean Chassoul, Robert Virding +% 2018-2024 + +# Name +luerl - The old original interface to the Luerl system + +# Interface functions +The **Lua State** parameter is the state of a Lua VM instance. It must be created with the **luerl:init()** call and be carried from one call to the next. + +As it is possible in Lua to create self-referencing data structures, indeed the standard libraries have many instances of this, then using the functions which decode their return values will generate an error when they would cause an infinite loop during the decoding. An simple example is the top level table which contains a key **`_G`** which references the top-level table. + +Note that Lua **Chunks** (see definition below) can travel between different States. They are precompiled bits of code, independent of State. That you can 'carry around' this is no unique to Luerl but a low-level implementation detail of the standard Lua [language](https://lua.org), for more on chunks [read](https://www.lua.org/manual/5.3/manual.html#3.3.2) the official Lua 5.3 [reference manual](https://www.lua.org/manual/5.3/manual.html). + +## Spec Definitions +**Binary** means an Erlang binary string. +**Chunks** means a portion of precompiled bytecode. +**State** means a Lua State, this *is* a Lua VM instance. +**Path** means a file system path and file name. +**KeyPath** means an Erlang list of **atoms** representing nested names, e.g. [table,pack] for table.pack. +**Keys** means Lua table keys, the keys of a key-value structure. + +## Functions +**eval** and **do** functions differ only in what they return. The **do** functions return results and a new Lua State, the **eval** functions return a tuple starting on 'ok' or 'error', then the result, or cause of error. + + do --> {Result, State} + + eval --> {ok, Result} | {error, Reason} + +#### luerl:eval(String|Binary|Form, State) -> {ok, Result} | {error, Reason, StackTrace}. + Evaluate a Lua expression passed in as a string or binary, and return its result. + +#### luerl:evalfile(Path, State) -> {ok, Result} | {error, Reason, StackTrace}. + Load and execute a file, and return the result. + +#### luerl:do(String|Binary|Form, State) -> {Result, NewState}. + Evaluate a Lua expression and return its result, and the new Lua State. + +#### luerl:dofile(Path, State) -> {Result, NewState}. + Load and execute the Lua code in the file and return its result, and the new Lua State. Equivalent to doing luerl:do("return dofile('FileName')"). + +#### luerl:load(String|Binary[, CompileOptions], State) -> {ok,Function,NewState} | {error, Reason}. + Parse a Lua chunk as string or binary, and return a compiled chunk ('form'). + +#### luerl:loadfile(FileName[, CompileOptions], State) -> {ok,Function,NewState} | {error, Reason}. + Parse a Lua file, and return a compiled chunk ('form'). + +#### luerl:path_loadfile([Path, ], FileName[, CompileOptions], State) -> {ok,Function,FullName,State} | {error, Reason}. + Search Path until the file FileName is found. Parse the file and return a compiled chunk ('form'). If Path is not given then the path defined in the environment variable LUA_LOAD_PATH is used. + +#### luerl:load_module(KeyPath, ErlangModule, State) -> State. + Load `ErlangModule` and install its table at `KeyPath` which is encoded. + +#### luerl:load_module1(KeyPath, ErlangModule, State) -> State. + Load `ErlangModule` and install its table at `KeyPath` which is **NOT** encoded + +#### luerl:init() -> State. + Get a new Lua State = a fresh Lua VM instance. + +#### luerl:call(Form, Args, State) -> {Result,State} +#### luerl:call_chunk(Form, Args, State) -> {Result,State} +Call a compiled chunk or function. Use the call_chunk, call has been kept for backwards compatibility. + +#### luerl:call_function(KeyPath, Args, State) -> {Result,NewState} +Call a function already defined in the state. `KeyPath` is a list of names to the function. `KeyPath`, `Args` and `Result` are automatically encoded/decoded. + +#### luerl:call_function1(KeyPath, Args, State) -> {Result,NewState} +Call a function already defined in the state. `KeyPath` is a list of keys to the function. `KeyPath`, `Args` and `Result` are **NOT** encoded/decoded. + +#### luerl:call_method(MethPath, Args, State) -> {Result,NewState}. +Call a method already defined in the state. `MethPath` is a list of names to the method. `MethPath`, `Args` and `Result` are automatically encoded/decoded. + +#### luerl:call_method1(MethPath, Args, State) -> {Result,NewState} +Call a method already defined in the state. `MethPath` is a list of keys to the method. `Keys`, `Args` and `Result` are **NOT** encoded/decoded. + +#### luerl:stop(State) -> GCedState. + Garbage collects the state and (todo:) does away with it. + +#### luerl:gc(State) -> State. + Runs the garbage collector on a state and returns the new state. + +#### luerl:set_table(KeyPath, Value, State) -> State. + Sets a value inside the Lua state. Value is automatically encoded. + +#### luerl:set_table1(KeyPath, Value, State) -> State. + Sets a value inside the Lua state. `KeyPath` and `Value` are **NOT** encoded. + +#### luerl:get_table(KeyPath, State) -> {Result,State}. + Gets a value inside the Lua state. `KeyPath` and `Result` are automatically encoded. + +#### luerl:get_table1(KeyPath, State) -> {Result,State}. + Gets a value inside the Lua state. `KeyPath` and `Result` are **NOT** encoded/decoded. + + You can use this function to expose an function to the Lua code by using this interface: + `fun(Args, State) -> {Results, State}` + + Args and Results must be a list of Luerl compatible Erlang values. diff --git a/src/luerl.erl b/src/luerl.erl index cd270ae..a90dfc1 100644 --- a/src/luerl.erl +++ b/src/luerl.erl @@ -1,4 +1,4 @@ -%% Copyright (c) 2013-2020 Robert Virding +%% Copyright (c) 2020-2024 Robert Virding %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -12,94 +12,94 @@ %% See the License for the specific language governing permissions and %% limitations under the License. -%% File : luerl.erl -%% Authors : Robert Virding, Henning Diedrich -%% Purpose : The original basic LUA 5.2 interface. +%% File : luerl_new.erl +%% Authors : Robert Virding +%% Purpose : The new basic LUA 5.3 interface. -module(luerl). -include("luerl.hrl"). --export([eval/2,evalfile/2, - do/2,dofile/2, - load/2,load/3, - loadfile/2,loadfile/3, - path_loadfile/2,path_loadfile/3,path_loadfile/4, - load_module/3,load_module1/3, - call/3,call_chunk/3, - call_function/3,call_function1/3,function_list/2, - call_method/3,call_method1/3,method_list/2, - get_table/2,get_table1/2,set_table/3,set_table1/3,set_table1/4, - init/0,stop/1,gc/1, - set_trace_func/2,clear_trace_func/1, - set_trace_data/2,get_trace_data/1, - get_stacktrace/1, - externalize/1,internalize/1 - ]). +%% Basic user API to luerl. +-export([init/0,gc/1, + load/2,load/3,loadfile/2,loadfile/3, + path_loadfile/2,path_loadfile/3,path_loadfile/4, + load_module/3,load_module_dec/3, + do/2,do_dec/2,do/3,do_dec/3, + dofile/2,dofile/3,dofile_dec/2,dofile_dec/3, + call/3,call_chunk/2,call_chunk/3, + call_function/3,call_function_enc/3,call_function_dec/3, + call_method/4,call_method_dec/4, + get_table_keys/2,get_table_keys_dec/2, + set_table_keys/3,set_table_keys_dec/3, + get_table_key/3,set_table_key/4, + get_stacktrace/1 + ]). + +%% Tracing. +-export([set_trace_func/2,clear_trace_func/1, + set_trace_data/2,get_trace_data/1]). %% Encoding and decoding. -export([encode/2,encode_list/2,decode/2,decode_list/2]). -%% luerl:eval(String|Binary|Form, State) -> Result. +%% Helping with storing VM state +-export([externalize/1,internalize/1]). -eval(Chunk, St0) -> - try do(Chunk, St0) of - {Ret,St1} -> {ok, decode_list(Ret, St1)} - catch - ?CATCH(_C, E, S) - {error, E, S} %{error, {E, R}} ? <- todo: decide - end. +%% init() -> State. -%% luerl:evalfile(Path, State) -> {ok, Result} | {error,Reason}. +init() -> + luerl_emul:init(). -evalfile(Path, St0) -> - try dofile(Path, St0) of - {Ret,St1} -> {ok, decode_list(Ret, St1)} - catch - ?CATCH(_C, E, S) - {error, E, S} %{error, {E, R}} ? <- todo: decide - end. +%% gc(State) -> State. +gc(St) -> + luerl_heap:gc(St). + +%% set_trace_func(TraceFunction, State) -> State. +%% clear_trace_func(State) -> State. +%% get_trace_data(State) -> TraceData. +%% set_trace_data(TraceData, State) -> State. +%% Set the trace function and access the trace data. -%% luerl:do(String|Binary|Form, State) -> {Result, NewState} +set_trace_func(Tfunc, St) -> + St#luerl{trace_func=Tfunc}. -do(S, St0) when is_binary(S); is_list(S) -> - {ok,Func,St1} = load(S, St0), - luerl_emul:call(Func, St1); -do(Func, St) -> - luerl_emul:call(Func, St). +clear_trace_func(St) -> + St#luerl{trace_func=none}. -%% luerl:dofile(Path, State) -> {Result, NewState}. +get_trace_data(St) -> + St#luerl.trace_data. -dofile(Path, St0) -> - {ok,Func,St1} = loadfile(Path, St0), - luerl_emul:call(Func, St1). +set_trace_data(Tdata, St) -> + St#luerl{trace_data=Tdata}. -%% load(String|Binary, State) -> {ok,Function,NewState}. -%% load(String|Binary, Options, State) -> {ok,Function,NewState}. +%% load(String|Binary, State) -> {ok,FuncRef,NewState}. +%% load(String|Binary, Options, State) -> {ok,FuncRef,NewState}. load(Bin, St) -> load(Bin, [return], St). load(Bin, Opts, St) when is_binary(Bin) -> - load(binary_to_list(Bin), Opts, St); -load(Str, Opts, St0) when is_list(Str) -> + load(binary_to_list(Bin), Opts, St); +load(Str, Opts, St0) -> case luerl_comp:string(Str, Opts) of - {ok,Chunk} -> - {Func,St1} = luerl_emul:load_chunk(Chunk, St0), - {ok,Func,St1}; - {error,_,_}=E -> E + {ok,Chunk} -> + {FunRef,St1} = luerl_emul:load_chunk(Chunk, St0), + {ok,FunRef,St1}; + Error -> %Compile error + Error end. -%% loadfile(FileName, State) -> {ok,Function,NewState}. -%% loadfile(FileName, Options, State) -> {ok,Function,NewState}. +%% loadfile(FileName, State) -> {ok,FuncRef,NewState}. +%% loadfile(FileName, Options, State) -> {ok,FuncRef,NewState}. loadfile(Name, St) -> loadfile(Name, [return], St). loadfile(Name, Opts, St0) -> case luerl_comp:file(Name, Opts) of - {ok,Chunk} -> - {Func,St1} = luerl_emul:load_chunk(Chunk, St0), - {ok,Func,St1}; - {error,_,_}=E -> E + {ok,Chunk} -> + {Func,St1} = luerl_emul:load_chunk(Chunk, St0), + {ok,Func,St1}; + Error -> Error end. %% path_loadfile(FileName, State) -> {ok,Function,FullName,State}. @@ -112,15 +112,15 @@ loadfile(Name, Opts, St0) -> path_loadfile(Name, St) -> Path = case os:getenv("LUA_LOAD_PATH") of - false -> []; %You get what you asked for - Env -> - %% Get path separator depending on os type. - Sep = case os:type() of - {win32,_} -> ";"; - _ -> ":" %Unix - end, - string:tokens(Env, Sep) %Split into path list - end, + false -> []; %You get what you asked for + Env -> + %% Get path separator depending on os type. + Sep = case os:type() of + {win32,_} -> ";"; %Windows + _ -> ":" %Unix + end, + string:tokens(Env, Sep) %Split into path list + end, path_loadfile(Path, Name, [return], St). path_loadfile(Dirs, Name, St) -> @@ -129,161 +129,211 @@ path_loadfile(Dirs, Name, St) -> path_loadfile([Dir|Dirs], Name, Opts, St0) -> Full = filename:join(Dir, Name), case loadfile(Full, Opts, St0) of - {ok,Func,St1} -> - {ok,Func,Full,St1}; - {error,[{_,_,enoent}],_} -> %Couldn't find the file - path_loadfile(Dirs, Name, St0); - Error -> Error + {ok,Func,St1} -> + {ok,Func,Full,St1}; + {error,[{_,_,enoent}],_} -> %Couldn't find the file + path_loadfile(Dirs, Name, St0); + Error -> Error end; path_loadfile([], _, _, _) -> {error,[{none,file,enoent}],[]}. -%% load_module(TablePath, ModuleName, State) -> State. -%% load_module1(LuaTablePath, ModuleName, State) -> State. +%% load_module(LuaTablePath, ModuleName, State) -> State. %% Load module and add module table to the path. -load_module(Fp, Mod, St0) when is_list(Fp) -> - {Lfp,St1} = encode_list(Fp, St0), - load_module1(Lfp, Mod, St1); -load_module(_, _,_) -> error(badarg). - -load_module1(Lfp, Mod, St0) -> +load_module([_|_] = Lfp, Mod, St0) -> {Tab,St1} = Mod:install(St0), - luerl_emul:set_table_keys(Lfp, Tab, St1). + luerl_emul:set_table_keys(Lfp, Tab, St1); +load_module(_, _, _) -> + error(badarg). -%% init() -> State. -init() -> luerl_emul:init(). - -%% call(Chunk, Args, State) -> {Result,State} - -call(C, As, St) -> call_chunk(C, As, St). - -call_chunk(C, As, St0) -> - {Las,St1} = encode_list(As, St0), - {Lrs,St2} = luerl_emul:call(C, Las, St1), - Rs = decode_list(Lrs, St2), - {Rs,St2}. - -%% call_function(TablePath, Args, State) -> {Result,State}. -%% call_function1(LuaTablePath | Func, LuaArgs, State) -> {LuaResult,State}. - -call_function(Fp, As, St0) -> - %% Encode the input arguments. - %% file:write_file("/Users/rv/lt", io_lib:format("cfp ~p\n", [Fp]), [append]), - {Lfp,St1} = encode_list(Fp, St0), - {Las,St2} = encode_list(As, St1), - %% Find the function definition and call function. - %% file:write_file("/Users/rv/lt", io_lib:format("cfa ~p\n", [{Lfp,Las}]), [append]), - {Lrs,St3} = call_function1(Lfp, Las, St2), - %% file:write_file("/Users/rv/lt", io_lib:format("cfl ~p\n", [Lrs]), [append]), - Rs = decode_list(Lrs, St3), - %% file:write_file("/Users/rv/lt", io_lib:format("cfr ~p\n", [Rs]), [append]), - {Rs,St3}. - -call_function1(Lfp, Las, St0) when is_list(Lfp) -> - {F,St1} = luerl_emul:get_table_keys(Lfp, St0), - %% file:write_file("/Users/rv/lt", io_lib:format("cf1 ~p\n", [F]), [append]), - luerl_emul:functioncall(F, Las, St1); -call_function1(F, Las, St) -> - luerl_emul:functioncall(F, Las, St). - -%% function_list(Keys, State) -> {V,State}. -%% Go down a list of keys and return final value. - -function_list(Ks, St) -> luerl_emul:get_table_keys(Ks, St). - -%% call_method(FuncPath, Args, State) -> {Result,State}. -%% call_method1(FuncPath | FuncPath, Args, State) -> {Result,State}. - -call_method(Fp, As, St0) -> - %% Encode the input arguments. - {Lfp,St1} = encode_list(Fp, St0), - {Las,St2} = encode_list(As, St1), - %% Find the object and method definition and call method. - {O,M,St3} = method_list(Lfp, St2), - {Lrs,St4} = luerl_emul:functioncall(M, [O|Las], St3), - Rs = decode_list(Lrs, St4), - {Rs,St4}. - -call_method1(Fp, Las, St0) -> - %% Find the object and method definition and call method. - {O,M,St1} = method_list(Fp, St0), - luerl_emul:functioncall(M, [O|Las], St1). - -method_list([G|Ks], St0) -> - {First,St1} = luerl_emul:get_global_key(G, St0), - method_list(First, Ks, St1). - -method_list(Tab, [K], St0) -> - {Func,St1} = luerl_emul:get_table_key(Tab, K, St0), - {Tab,Func,St1}; -method_list(Tab, [K|Ks], St0) -> - {Next,St1} = luerl_emul:get_table_key(Tab, K, St0), - method_list(Next, Ks, St1); -method_list(_, _, _) -> error(badarg). - -%% get_table(TablePath, State) -> {Result, State}. -%% Go down a list of keys and return decoded final value. - -get_table(Fp, St0) when is_list(Fp) -> - {Lfp,St1} = encode_list(Fp, St0), - {V,St2} = luerl_emul:get_table_keys(Lfp, St1), - Vd = decode(V, St2), - {Vd,St2}; -get_table(_,_) -> error(badarg). - -%% get_table1(LuaTablePath, State) -> {LuaResult, State}. - -get_table1(Fp, St) when is_list(Fp) -> - luerl_emul:get_table_keys(Fp, St); -get_table1(_,_) -> error(badarg). - -%% set_table(TablePath, Value, State) -> State. -%% Go down a list of keys and set final key to Value. - -set_table(Fp, V, St0) when is_list(Fp) -> - {Lfp,St1} = encode_list(Fp, St0), - {Lv, St2} = encode(V, St1), - set_table1(Lfp, Lv, St2); -set_table(_,_,_) -> error(badarg). - -%% set_table1(LuaTablePath, Value, State) -> State. -%% Must explicitly read table key to get - -set_table1(Lfp, Lv, St) -> - luerl_emul:set_table_keys(Lfp, Lv, St). - -%% set_table1(Table, Key, Value, State) -> State. -%% Must explicitly read table key to get - -set_table1(Tab, Key, Lv, St) -> - luerl_emul:set_table_key(Tab, Key, Lv, St). - -%% stop(State) -> GCedState. -stop(St) -> - luerl_heap:gc(St). +%% load_module_dec(DecodedTablePath, ModuleName, State) -> State. +%% Load module and add module table to the path. -%% gc(State) -> State. -gc(St) -> - luerl_heap:gc(St). +load_module_dec([_|_] = Dfp, Mod, St0) -> + {Efp,St1} = encode_list(Dfp, St0), + load_module(Efp, Mod, St1); +load_module_dec(_, _, _) -> + error(badarg). -%% set_trace_func(TraceFunction, State) -> State. -%% clear_trace_func(State) -> State. -%% get_trace_data(State) -> TraceData. -%% set_trace_data(TraceData, State) -> State. -%% Set the trace function and access the trace data. +%% luerl:do(String|Binary|Form, State) -> +%% luerl:do(String|Binary|Form, CompileOptions, State) -> +%% {ok,Result,NewState} | {lua_error,Error,State}. -set_trace_func(Tfunc, St) -> - St#luerl{trace_func=Tfunc}. +do(S, St) -> do(S, [return], St). -clear_trace_func(St) -> - St#luerl{trace_func=none}. +do(S, Opts, St0) -> + case load(S, Opts, St0) of + {ok,Func,St1} -> + call_function(Func, [], St1); + Error -> Error + end. -get_trace_data(St) -> - St#luerl.trace_data. +do_dec(S, St) -> + do_dec(S, [return], St). -set_trace_data(Tdata, St) -> - St#luerl{trace_data=Tdata}. +do_dec(S, Opts, St0) -> + case do(S, Opts, St0) of + {ok,Eret,St1} -> + {ok,decode_list(Eret, St1),St1}; + Error -> Error + end. + +%% luerl:dofile(FileName, State) -> +%% luerl:dofile(FileName, CompileOptions, State) -> +%% {ok,Result,NewState} | {lua_error,Error,State}. + +dofile(File, St) -> dofile(File, [], St). + +dofile(File, Opts, St0) -> + case loadfile(File, Opts, St0) of + {ok,Func,St1} -> + call_function(Func, [], St1); + Error -> Error + end. + +dofile_dec(File, St) -> + dofile_dec(File, [], St). + +dofile_dec(File, Opts, St0) -> + case dofile(File, Opts, St0) of + {ok,Eret,St1} -> + {ok,decode_list(Eret, St1),St1}; + Error -> Error + end. + +%% call(FuncRef, Args, State) -> +%% call_chunk(FuncRef, State) -> +%% call_chunk(FuncRef, Args, State) -> +%% {ok,Return,State} | {lua_error,Error,State}. + +call(C, As, St) -> + call_function(C, As, St). + +call_chunk(C, St) -> + call_chunk(C, [], St). + +call_chunk(C, As, St) -> + call_function(C, As, St). + +%% call_function(LuaFuncRef | LuaTablePath, Args, State) -> +%% {ok,LuaReturn,State} | {lua_error,Error,State}. + +call_function(Epath, Args, St0) when is_list(Epath) -> + {ok,Efunc,St1} = get_table_keys(Epath, St0), + call_function(Efunc, Args, St1); +call_function(Func, Args, St0) -> + try + {Ret,St1} = luerl_emul:functioncall(Func, Args, St0), + {ok,Ret,St1} + catch + error:{lua_error,_E,_St} = LuaErr -> + LuaErr + end. + +%% call_function_enc(DecodedFuncRef, Args, State) -> +%% {ok,LuaReturn,State} | {lua_error,Error,State}. + +call_function_enc(Dtpath, Dargs, St0) -> + {Epath,St1} = encode_list(Dtpath, St0), + {Eargs,St2} = encode_list(Dargs, St1), + call_function(Epath, Eargs, St2). + +%% call_function_dec(DecodedFuncRef, Args, State) -> +%% {ok,DecodedReturn,State} | {lua_error,Error,State}. + +call_function_dec(Dtpath, Dargs, St0) -> + case call_function_enc(Dtpath, Dargs, St0) of + {ok,Eret,St1} -> + {ok,decode_list(Eret, St1),St1}; + LuaError -> LuaError + end. + +%% call_method(LuaObject, Method, Args, State) -> +%% {ok,Return,State} | {lua_error,Error,State}. + +call_method(Obj, Meth, Args, St0) -> + try + {Ret,St1} = luerl_emul:methodcall(Obj, Meth, Args, St0), + {ok,Ret,St1} + catch + error:{lua_error,_E,_St} = LuaErr -> + LuaErr + end. + +%% call_method_dec(DecodedObject, Method, Args, State) -> +%% {ok,DecodedReturn,State} | {lua_error,Error,State}. + +call_method_dec(Dobj, Dmeth, Dargs, St0) -> + {ok,Eobj,St1} = get_table_keys_dec(Dobj, St0), + {Emeth,St2} = encode(Dmeth, St1), + {Eargs,St3} = encode_list(Dargs, St2), + case call_method(Eobj, Emeth, Eargs, St3) of + {ok,Eret,St4} -> + {ok,decode_list(Eret, St4),St4}; + LuaError -> LuaError + end. + +%% get_table_keys(Keys, State) -> +%% get_table_keys_dec(DecodedKeys, State) -> +%% {ok,Return,State} | {lua_error,Error,State}. +%% set_table_keys(Keys, Val, State) -> +%% set_table_keys_dec(DecodedKeys, DecodedVal, State) -> +%% {ok,State} | {lua_error,Error,State}. + +get_table_keys(Keys, St0) -> + try + {Eret,St1} = luerl_emul:get_table_keys(Keys, St0), + {ok,Eret,St1} + catch + error:{lua_error,_E,_St} = LuaErr -> + LuaErr + end. + +get_table_keys_dec(Dkeys, St0) -> + {Ekeys,St1} = encode_list(Dkeys, St0), + case get_table_keys(Ekeys, St1) of + {ok,Eret,St2} -> + {ok,decode(Eret, St2),St2}; + LuaError -> LuaError + end. + +set_table_keys(Keys, Val, St0) -> + try + St1 = luerl_emul:set_table_keys(Keys, Val, St0), + {ok,St1} + catch + error:{lua_error,_E,_St} = LuaErr -> + LuaErr + end. + +set_table_keys_dec(Dkeys, Dval, St0) -> + {Ekeys,St1} = encode_list(Dkeys, St0), + {Eval,St2} = encode(Dval, St1), + set_table_keys(Ekeys, Eval, St2). + +%% get_table_key(Tab, Key, State) -> +%% {ok,Value,State} | {lua_error,Error,State}. +%% set_table_key(Tab, Key, Value, State) -> +%% {ok,State} | {lua_error,Error,State}. + +get_table_key(Tab, Key, St0) -> + try + {Eret,St1} = luerl_emul:get_table_key(Tab, Key, St0), + {ok,Eret,St1} + catch + error:{lua_error,_E,_St} = LuaErr -> + LuaErr + end. + +set_table_key(Tab, Key, Val, St0) -> + try + St1 = luerl_emul:set_table_key(Tab, Key, Val, St0), + {ok,St1} + catch + error:{lua_error,_E,_St} = LuaErr -> + LuaErr + end. %% get_stacktrace(State) -> [{FuncName,[{file,FileName},{line,Line}]}]. @@ -366,11 +416,14 @@ encode(L, St0) when is_list(L) -> {T,St2}; %No more to do for now encode(F, St) when is_function(F, 2) -> F1 = fun(Args, State) -> F(Args, State) end, + %% io:format("enc ~p\n", [#erl_func{code=F1}]), {#erl_func{code=F1}, St}; encode(F, St) when is_function(F, 1) -> F1 = fun(Args, State) -> Res = F(Args), {Res,State} end, + %% io:format("enc ~p\n", [#erl_func{code=F1}]), {#erl_func{code=F1}, St}; encode({M,F,A}, St) when is_atom(M) and is_atom(F) -> + %% io:format("enc ~p\n", [#erl_mfa{m=M,f=F,a=A}]), {#erl_mfa{m=M,f=F,a=A}, St}; encode({userdata,Data}, St) -> luerl_heap:alloc_userdata(Data, St); diff --git a/src/luerl_emul.erl b/src/luerl_emul.erl index 6407a17..6e26f6b 100644 --- a/src/luerl_emul.erl +++ b/src/luerl_emul.erl @@ -1,4 +1,4 @@ -%% Copyright (c) 2013-2023 Robert Virding +%% Copyright (c) 2013-2024 Robert Virding %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. diff --git a/src/luerl_old.erl b/src/luerl_old.erl index b978067..f3e90d3 100644 --- a/src/luerl_old.erl +++ b/src/luerl_old.erl @@ -1,4 +1,4 @@ -%% Copyright (c) 2013-2021 Robert Virding +%% Copyright (c) 2013-2024 Robert Virding %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -14,18 +14,432 @@ %% File : luerl_old.erl %% Authors : Robert Virding, Henning Diedrich -%% Purpose : The old basic LUA 5.2 interface. - -%% This module is just an interface to the older luerl.erl which might -%% make it easier to migrate the module names if we decide to do so in -%% the future. +%% Purpose : The original basic LUA 5.2 interface. -module(luerl_old). --export(['$handle_undefined_function'/2]). +-include("luerl.hrl"). + +-export([eval/2,evalfile/2, + do/2,dofile/2, + load/2,load/3, + loadfile/2,loadfile/3, + path_loadfile/2,path_loadfile/3,path_loadfile/4, + load_module/3,load_module1/3, + call/3,call_chunk/3, + call_function/3,call_function1/3,function_list/2, + call_method/3,call_method1/3,method_list/2, + get_table/2,get_table1/2,set_table/3,set_table1/3,set_table1/4, + init/0,stop/1,gc/1, + set_trace_func/2,clear_trace_func/1, + set_trace_data/2,get_trace_data/1, + get_stacktrace/1, + externalize/1,internalize/1 + ]). + +%% Encoding and decoding. +-export([encode/2,encode_list/2,decode/2,decode_list/2]). + +%% luerl_old:eval(String|Binary|Form, State) -> Result. + +eval(Chunk, St0) -> + try do(Chunk, St0) of + {Ret,St1} -> {ok, decode_list(Ret, St1)} + catch + ?CATCH(_C, E, S) + {error, E, S} %{error, {E, R}} ? <- todo: decide + end. + +%% luerl_old:evalfile(Path, State) -> {ok, Result} | {error,Reason}. + +evalfile(Path, St0) -> + try dofile(Path, St0) of + {Ret,St1} -> {ok, decode_list(Ret, St1)} + catch + ?CATCH(_C, E, S) + {error, E, S} %{error, {E, R}} ? <- todo: decide + end. + +%% luerl_old:do(String|Binary|Form, State) -> {Result, NewState} + +do(S, St0) when is_binary(S); is_list(S) -> + {ok,Func,St1} = load(S, St0), + luerl_emul:call(Func, St1); +do(Func, St) -> + luerl_emul:call(Func, St). + +%% luerl_old:dofile(Path, State) -> {Result, NewState}. + +dofile(Path, St0) -> + {ok,Func,St1} = loadfile(Path, St0), + luerl_emul:call(Func, St1). + +%% load(String|Binary, State) -> {ok,Function,NewState}. +%% load(String|Binary, Options, State) -> {ok,Function,NewState}. + +load(Bin, St) -> load(Bin, [return], St). + +load(Bin, Opts, St) when is_binary(Bin) -> + load(binary_to_list(Bin), Opts, St); +load(Str, Opts, St0) when is_list(Str) -> + case luerl_comp:string(Str, Opts) of + {ok,Chunk} -> + {Func,St1} = luerl_emul:load_chunk(Chunk, St0), + {ok,Func,St1}; + {error,_,_}=E -> E + end. + +%% loadfile(FileName, State) -> {ok,Function,NewState}. +%% loadfile(FileName, Options, State) -> {ok,Function,NewState}. + +loadfile(Name, St) -> loadfile(Name, [return], St). + +loadfile(Name, Opts, St0) -> + case luerl_comp:file(Name, Opts) of + {ok,Chunk} -> + {Func,St1} = luerl_emul:load_chunk(Chunk, St0), + {ok,Func,St1}; + {error,_,_}=E -> E + end. + +%% path_loadfile(FileName, State) -> {ok,Function,FullName,State}. +%% path_loadfile(Path, FileName, State) -> {ok,Function,FullName,State}. +%% path_loadfile(Path, FileName, Options, State) -> +%% {ok,Function,FullName,State}. +%% When no path is given we use the value of LUA_LOAD_PATH. +%% We manually step down the path to get the correct handling of +%% filenames by the compiler. + +path_loadfile(Name, St) -> + Path = case os:getenv("LUA_LOAD_PATH") of + false -> []; %You get what you asked for + Env -> + %% Get path separator depending on os type. + Sep = case os:type() of + {win32,_} -> ";"; + _ -> ":" %Unix + end, + string:tokens(Env, Sep) %Split into path list + end, + path_loadfile(Path, Name, [return], St). + +path_loadfile(Dirs, Name, St) -> + path_loadfile(Dirs, Name, [return], St). + +path_loadfile([Dir|Dirs], Name, Opts, St0) -> + Full = filename:join(Dir, Name), + case loadfile(Full, Opts, St0) of + {ok,Func,St1} -> + {ok,Func,Full,St1}; + {error,[{_,_,enoent}],_} -> %Couldn't find the file + path_loadfile(Dirs, Name, St0); + Error -> Error + end; +path_loadfile([], _, _, _) -> + {error,[{none,file,enoent}],[]}. + +%% load_module(TablePath, ModuleName, State) -> State. +%% load_module1(LuaTablePath, ModuleName, State) -> State. +%% Load module and add module table to the path. + +load_module(Fp, Mod, St0) when is_list(Fp) -> + {Lfp,St1} = encode_list(Fp, St0), + load_module1(Lfp, Mod, St1); +load_module(_, _,_) -> error(badarg). + +load_module1(Lfp, Mod, St0) -> + {Tab,St1} = Mod:install(St0), + luerl_emul:set_table_keys(Lfp, Tab, St1). + +%% init() -> State. +init() -> luerl_emul:init(). + +%% call(Chunk, Args, State) -> {Result,State} + +call(C, As, St) -> call_chunk(C, As, St). + +call_chunk(C, As, St0) -> + {Las,St1} = encode_list(As, St0), + {Lrs,St2} = luerl_emul:call(C, Las, St1), + Rs = decode_list(Lrs, St2), + {Rs,St2}. + +%% call_function(TablePath, Args, State) -> {Result,State}. +%% call_function1(LuaTablePath | Func, LuaArgs, State) -> {LuaResult,State}. + +call_function(Fp, As, St0) -> + %% Encode the input arguments. + {Lfp,St1} = encode_list(Fp, St0), + {Las,St2} = encode_list(As, St1), + %% Find the function definition and call function. + {Lrs,St3} = call_function1(Lfp, Las, St2), + Rs = decode_list(Lrs, St3), + {Rs,St3}. + +call_function1(Lfp, Las, St0) when is_list(Lfp) -> + {F,St1} = luerl_emul:get_table_keys(Lfp, St0), + luerl_emul:functioncall(F, Las, St1); +call_function1(F, Las, St) -> + luerl_emul:functioncall(F, Las, St). + +%% function_list(Keys, State) -> {V,State}. +%% Go down a list of keys and return final value. + +function_list(Ks, St) -> luerl_emul:get_table_keys(Ks, St). + +%% call_method(FuncPath, Args, State) -> {Result,State}. +%% call_method1(FuncPath | FuncPath, Args, State) -> {Result,State}. + +call_method(Fp, As, St0) -> + %% Encode the input arguments. + {Lfp,St1} = encode_list(Fp, St0), + {Las,St2} = encode_list(As, St1), + %% Find the object and method definition and call method. + {O,M,St3} = method_list(Lfp, St2), + {Lrs,St4} = luerl_emul:functioncall(M, [O|Las], St3), + Rs = decode_list(Lrs, St4), + {Rs,St4}. + +call_method1(Fp, Las, St0) -> + %% Find the object and method definition and call method. + {O,M,St1} = method_list(Fp, St0), + luerl_emul:functioncall(M, [O|Las], St1). + +method_list([G|Ks], St0) -> + {First,St1} = luerl_emul:get_global_key(G, St0), + method_list(First, Ks, St1). + +method_list(Tab, [K], St0) -> + {Func,St1} = luerl_emul:get_table_key(Tab, K, St0), + {Tab,Func,St1}; +method_list(Tab, [K|Ks], St0) -> + {Next,St1} = luerl_emul:get_table_key(Tab, K, St0), + method_list(Next, Ks, St1); +method_list(_, _, _) -> error(badarg). + +%% get_table(TablePath, State) -> {Result, State}. +%% Go down a list of keys and return decoded final value. + +get_table(Fp, St0) when is_list(Fp) -> + {Lfp,St1} = encode_list(Fp, St0), + {V,St2} = luerl_emul:get_table_keys(Lfp, St1), + Vd = decode(V, St2), + {Vd,St2}; +get_table(_,_) -> error(badarg). + +%% get_table1(LuaTablePath, State) -> {LuaResult, State}. + +get_table1(Fp, St) when is_list(Fp) -> + luerl_emul:get_table_keys(Fp, St); +get_table1(_,_) -> error(badarg). + +%% set_table(TablePath, Value, State) -> State. +%% Go down a list of keys and set final key to Value. + +set_table(Fp, V, St0) when is_list(Fp) -> + {Lfp,St1} = encode_list(Fp, St0), + {Lv, St2} = encode(V, St1), + set_table1(Lfp, Lv, St2); +set_table(_,_,_) -> error(badarg). + +%% set_table1(LuaTablePath, Value, State) -> State. +%% Must explicitly read table key to get + +set_table1(Lfp, Lv, St) -> + luerl_emul:set_table_keys(Lfp, Lv, St). + +%% set_table1(Table, Key, Value, State) -> State. +%% Must explicitly read table key to get + +set_table1(Tab, Key, Lv, St) -> + luerl_emul:set_table_key(Tab, Key, Lv, St). + +%% stop(State) -> GCedState. +stop(St) -> + luerl_heap:gc(St). + +%% gc(State) -> State. +gc(St) -> + luerl_heap:gc(St). + +%% set_trace_func(TraceFunction, State) -> State. +%% clear_trace_func(State) -> State. +%% get_trace_data(State) -> TraceData. +%% set_trace_data(TraceData, State) -> State. +%% Set the trace function and access the trace data. + +set_trace_func(Tfunc, St) -> + St#luerl{trace_func=Tfunc}. + +clear_trace_func(St) -> + St#luerl{trace_func=none}. + +get_trace_data(St) -> + St#luerl.trace_data. + +set_trace_data(Tdata, St) -> + St#luerl{trace_data=Tdata}. + +%% get_stacktrace(State) -> [{FuncName,[{file,FileName},{line,Line}]}]. + +get_stacktrace(#luerl{cs=Stack}=St) -> + Fun = fun (Frame, Acc) -> do_stackframe(Frame, Acc, St) end, + {_,Trace} = lists:foldl(Fun, {1,[]}, Stack), + lists:reverse(Trace). + +do_stackframe(#call_frame{func=Funref,args=Args}, {Line,Trace}, St) -> + case Funref of + #funref{} -> + {Func,_} = luerl_heap:get_funcdef(Funref, St), + Anno = Func#lua_func.anno, + Name = case luerl_anno:get(name, Anno) of + undefined -> <<"-no-name-">>; + N -> N + end, + File = luerl_anno:get(file, Anno), + {Line,[{Name,Args,[{file,File},{line,Line}]} | Trace]}; + #erl_func{code=Fun} -> + {module,Module} = erlang:fun_info(Fun, module), + {name,Name} = erlang:fun_info(Fun, name), + FileName = get_filename(Module), + {Line,[{{Module,Name},Args,[{file,FileName}]} | Trace]}; + #erl_mfa{m=M,f=F,a=A} -> + FileName = get_filename(M), + %% {Line,[{{M,F},{A,Args},[{file,FileName}]} | Trace]}; + %% {Line,[{{M,F},[A | Args],[{file,FileName}]} | Trace]}; + {Line,[{{M,F,A},Args,[{file,FileName}]} | Trace]}; + Other -> + {Line,[{Other,Args,[{file,<<"-no-file-">>},{line,Line}]} | Trace]} + end; +do_stackframe(#current_line{line=Line}, {_,Trace}, _St) -> + {Line,Trace}; +do_stackframe(#loop_frame{}, Acc, _St) -> %Ignore these + Acc. + +get_filename(Mod) -> + Comp = erlang:get_module_info(Mod, compile), + case lists:keyfind(source, 1, Comp) of + {source,FileName} -> + BaseName = filename:basename(FileName), + list_to_binary(BaseName); + false -> %The compiler doesn't know + <<"-no-file-">> + end. + +%% Define IS_MAP/1 macro for is_map/1 bif. +-ifdef(HAS_MAPS). +-define(IS_MAP(T), is_map(T)). +-else. +-define(IS_MAP(T), false). +-endif. + +%% encode_list([Term], State) -> {[LuerlTerm],State}. +%% encode(Term, State) -> {LuerlTerm,State}. + +encode_list(Ts, St) -> + lists:mapfoldl(fun encode/2, St, Ts). + +encode(nil, St) -> {nil,St}; +encode(false, St) -> {false,St}; +encode(true, St) -> {true,St}; +encode(B, St) when is_binary(B) -> {B,St}; +encode(A, St) when is_atom(A) -> {atom_to_binary(A, utf8),St}; +encode(N, St) when is_number(N) -> {N,St}; %Integers and floats +encode(F, St) when ?IS_MAP(F) -> encode(maps:to_list(F), St); +encode(L, St0) when is_list(L) -> + {Es,{_,St1}} = lists:mapfoldl(fun ({K0,V0}, {I,S0}) -> + {K1,S1} = encode(K0, S0), + {V1,S2} = encode(V0, S1), + {{K1,V1},{I,S2}}; + (V0, {I,S0}) -> + {V1,S1} = encode(V0, S0), + {{I,V1},{I+1,S1}} + end, {1,St0}, L), + {T,St2} = luerl_heap:alloc_table(Es, St1), + {T,St2}; %No more to do for now +encode(F, St) when is_function(F, 2) -> + F1 = fun(Args, State) -> + Args1 = decode_list(Args, State), + {Res, State1} = F(Args1, State), + encode_list(Res, State1) + end, + {#erl_func{code=F1}, St}; +encode(F, St) when is_function(F, 1) -> + F1 = fun(Args, State) -> + Args1 = decode_list(Args, State), + Res = F(Args1), + encode_list(Res, State) + end, + {#erl_func{code=F1}, St}; +encode({M,F,A}, St) when is_atom(M) and is_atom(F) -> + {#erl_mfa{m=M,f=F,a=A}, St}; +encode({userdata,Data}, St) -> + luerl_heap:alloc_userdata(Data, St); +% Table refs should not be re-encoded +encode(#tref{}=T, St) -> + case luerl_heap:chk_table(T, St) of + ok -> {T, St}; + error -> error(badarg) + end; +encode(Term, _) -> error({badarg,Term}). %Can't encode anything else + +%% decode_list([LuerlTerm], State) -> [Term]. +%% decode(LuerlTerm, State) -> Term. +%% In decode we track of which tables we have seen to detect +%% recursive references and generate an error when that occurs. + +decode_list(Lts, St) -> + lists:map(fun (Lt) -> decode(Lt, St) end, Lts). + +decode(LT, St) -> + decode(LT, St, []). + +decode(nil, _, _) -> nil; +decode(false, _, _) -> false; +decode(true, _, _) -> true; +decode(B, _, _) when is_binary(B) -> B; +decode(N, _, _) when is_number(N) -> N; %Integers and floats +decode(#tref{}=T, St, In) -> + decode_table(T, St, In); +decode(#usdref{}=U, St, _) -> + decode_userdata(U, St); +decode(#funref{}=Fun, State, _) -> + F = fun(Args) -> + {Args1, State1} = encode_list(Args, State), + {Ret, State2} = luerl_emul:functioncall(Fun, Args1, State1), + decode_list(Ret, State2) + end, + F; %Just a bare fun +decode(#erl_func{code=Fun}, _, _) -> Fun; +decode(#erl_mfa{m=M,f=F,a=A}, _, _) -> {M,F,A}; +decode(Lua, _, _) -> error({badarg,Lua}). %Shouldn't have anything else + +decode_table(#tref{i=N}=T, St, In0) -> + case lists:member(N, In0) of + true -> error({recursive_table,T}); %Been here before + false -> + In1 = [N|In0], %We are in this as well + case luerl_heap:get_table(T, St) of + #table{a=Arr,d=Dict} -> + Fun = fun (K, V, Acc) -> + [{decode(K, St, In1),decode(V, St, In1)}|Acc] + end, + Ts = ttdict:fold(Fun, [], Dict), + array:sparse_foldr(Fun, Ts, Arr); + _Undefined -> error(badarg) + end + end. + +decode_userdata(U, St) -> + {#userdata{d=Data},_} = luerl_heap:get_userdata(U, St), + {userdata,Data}. + +%% Externalize and Internalize ensure that the VM state passed in +%% can be stored externally or can be recreated from external storage. +%% Currently very simple: only random state needs special treatment. -%% '$handle_undefined_function'(Func, Args) -%% We just pass the buck and call the old luerl module. +externalize(S) -> + luerl_lib_math:externalize(S). -'$handle_undefined_function'(Func, Args) -> - apply(luerl, Func, Args). +internalize(S) -> + luerl_lib_math:internalize(S). diff --git a/test/lib_os_SUITE.erl b/test/lib_os_SUITE.erl index 0647fbb..ef0417d 100644 --- a/test/lib_os_SUITE.erl +++ b/test/lib_os_SUITE.erl @@ -83,7 +83,7 @@ os_date_table(_) -> os_date_integrated(_) -> State = luerl:init(), Chunk = <<"return os.date('noformat'), os.date(), os.date('%c', 1683371767)">>, - {[NoFormat, _, FromTimeStamp], _State1} = luerl:do(Chunk, State), + {ok, [NoFormat, _, FromTimeStamp], _State1} = luerl:do(Chunk, State), ?assertEqual(<<"noformat">>, NoFormat), %% Date is "Sat May 6 13:16:07 2023", %% Just check year to avoid test flakiness @@ -92,6 +92,6 @@ os_date_integrated(_) -> os_date_integrated_table(_) -> State = luerl:init(), Chunk = <<"return os.date('*t').year">>, - {[Result], _State1} = luerl:do(Chunk, State), + {ok, [Result], _State1} = luerl:do(Chunk, State), {{Year, _, _}, _} = calendar:local_time(), ?assertEqual(Year, Result). diff --git a/test/luerl_funcall_tests.erl b/test/luerl_funcall_tests.erl index 0f237fd..c6ef699 100644 --- a/test/luerl_funcall_tests.erl +++ b/test/luerl_funcall_tests.erl @@ -28,13 +28,13 @@ external_fun_test() -> [A] = luerl:decode_list(Args, S), luerl:encode_list([A + 2, [A + 3, A + 4]], S) end, - State1 = luerl:set_table([<<"testFun">>], F, State), + {ok, State1} = luerl:set_table_keys_dec([<<"testFun">>], F, State), Chunk = <<"function test(i)\n" " local a, b = testFun(i)\n" " return (a == i + 2), (b[1] == i + 3), (b[2] == i + 4)\n" "end">>, - {_, State2} = luerl:do(Chunk, State1), - {Res, _State3} = luerl:call_function([test], [2], State2), + {ok, _, State2} = luerl:do(Chunk, State1), + {ok, Res, _State3} = luerl:call_function_dec([test], [2], State2), [BoolVal, BoolVal2, BoolVal3] = Res = [true,true,true], ?assertEqual(true, BoolVal), ?assertEqual(true, BoolVal2), @@ -42,8 +42,9 @@ external_fun_test() -> return_lib_function_test() -> State = luerl:init(), - {_, State1} = luerl:do(<<"function test()\n return string.find end\n">>, State), - {[{M,F,A}], _State2} = luerl:call_function([test], [1], State1), + {ok, _, State1} = + luerl:do(<<"function test()\n return string.find end\n">>, State), + {ok, [{M,F,A}], _State2} = luerl:call_function_dec([test], [1], State1), {Res, _State3} = apply(M, F, [A, [<<"barfooblafasel">>, <<"foo">>], State1]), ?assertEqual([4, 6], Res). @@ -55,9 +56,9 @@ define_fun_in_lua_test() -> " return i + incby\n" " end\n" "end\n">>, - {_, State1} = luerl:do(Chunk, State), - {[Fun2], State2} = luerl:call_function([mkadder], [1], State1), - {[Fun3], State3} = luerl:call_function([mkadder], [2], State1), + {ok, _, State1} = luerl:do(Chunk, State), + {ok, [Fun2], State2} = luerl:call_function_dec([mkadder], [1], State1), + {ok, [Fun3], State3} = luerl:call_function_dec([mkadder], [2], State1), %% Should really decode the return value, but it is only a number. ?assertMatch({[5], _}, Fun2([4], State2)), @@ -75,18 +76,25 @@ define_fun2_in_lua_test() -> " return list\n" " end\n" "end\n">>, - {_, State1} = luerl:do(Chunk, State), - {[Fun2], State2} = luerl:call_function1([<<"mklist">>], [5], State1), + {ok, _, State1} = luerl:do(Chunk, State), - %% Must decode the return values as they are tables. - {Res21,State21} = luerl:call_function1(Fun2, [4], State2), + %% Build a luerl function and safely call it. + {Emklist, St2} = luerl:encode_list([mklist], State1), + {ok, [Efunc5], St3} = luerl:call_function(Emklist, [5], St2), + {ok, Res20, St4} = luerl:call_function(Efunc5, [4], St3), + ?assertMatch([[{1,4}, {2,4}, {3,4}, {4,4}, {5,4}]], + luerl:decode_list(Res20, St4)), + + %% Build an Erlang fun and just unsafely call it. + {ok, [Fun2], State2} = luerl:call_function_dec([mklist], [5], State1), + {Res21,State21} = Fun2([4], State2), ?assertMatch([[{1,4}, {2,4}, {3,4}, {4,4}, {5,4}]], luerl:decode_list(Res21, State21)), - {Res22,State22} = luerl:call_function1(Fun2, [4.0], State2), + {Res22,State22} = Fun2([4.0], State2), ?assertMatch([[{1,4.0}, {2,4.0}, {3,4.0}, {4,4.0}, {5,4.0}]], luerl:decode_list(Res22, State22)), - {[Fun3], State3} = luerl:call_function([<<"mklist">>], [10], State1), + {ok, [Fun3], State3} = luerl:call_function_dec([mklist], [10], State1), {Res3, State31} = Fun3([4], State3), ?assertMatch([[{1,4}, {2,4}, {3,4}, {4,4}, {5,4}, {6,4}, {7,4}, {8,4}, {9,4}, {10,4}]], @@ -100,6 +108,6 @@ newindex_metamethod_test() -> "end})\n\n" "m[123] = 456\n" "return t[123], m[123]">>, - {[TVal, MVal], _State1} = luerl:do(Chunk, State), + {ok, [TVal, MVal], _State1} = luerl:do_dec(Chunk, State), ?assertEqual(456, TVal), ?assertEqual(nil, MVal). diff --git a/test/luerl_old_funcall_tests.erl b/test/luerl_old_funcall_tests.erl new file mode 100644 index 0000000..2be2c24 --- /dev/null +++ b/test/luerl_old_funcall_tests.erl @@ -0,0 +1,108 @@ +%%% @author Hans-Christian Esperer +%%% @copyright (C) 2015, Hans-Christian Esperer +%%% Licensed under the Apache License, Version 2.0 (the "License"); +%%% you may not use this file except in compliance with the License. +%%% You may obtain a copy of the License at +%%% +%%% http://www.apache.org/licenses/LICENSE-2.0 +%%% +%%% Unless required by applicable law or agreed to in writing, +%%% software distributed under the License is distributed on an "AS +%%% IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +%%% express or implied. See the License for the specific language +%%% governing permissions and limitations under the License. +%%% +%%% @doc +%% +%%% @end +%%% Created : 11 Jan 2015 by Hans-Christian Esperer + +-module(luerl_old_funcall_tests). + +-include_lib("eunit/include/eunit.hrl"). + +external_fun_test() -> + State = luerl_old:init(), + F = fun([A], S) -> + {[A + 2, [A + 3, A + 4]], S} + end, + State1 = luerl_old:set_table([<<"testFun">>], F, State), + {_, State2} = luerl_old:do(<<"function test(i)\n local a, b = testFun(i)\n return (a == i + 2), (b[1] == i + 3), (b[2] == i + 4) end">>, State1), + {Res, _State3} = luerl_old:call_function([test], [2], State2), + [BoolVal, BoolVal2, BoolVal3] = Res, + ?assertEqual(true, BoolVal), + ?assertEqual(true, BoolVal2), + ?assertEqual(true, BoolVal3). + +external_nostate_fun_test() -> + State = luerl_old:init(), + F = fun([A]) -> + [A + 2, [A + 3, A + 4]] + end, + State1 = luerl_old:set_table([<<"testFun">>], F, State), + Chunk = <<"function test(i)\n" + " local a, b = testFun(i)\n" + " return (a == i + 2), (b[1] == i + 3), (b[2] == i + 4)\n" + "end">>, + {_, State2} = luerl_old:do(Chunk, State1), + {Res, _State3} = luerl_old:call_function([test], [2], State2), + [BoolVal, BoolVal2, BoolVal3] = Res, + ?assertEqual(true, BoolVal), + ?assertEqual(true, BoolVal2), + ?assertEqual(true, BoolVal3). + +return_lib_function_test() -> + State = luerl_old:init(), + {_, State1} = luerl_old:do(<<"function test()\n return string.find end\n">>, State), + {[{M,F,A}], _State2} = luerl_old:call_function([test], [1], State1), + {Res, _State3} = apply(M, F, [A, [<<"barfooblafasel">>, <<"foo">>], State1]), + ?assertEqual([4, 6], Res). + +define_fun_in_lua_test() -> + State = luerl_old:init(), + Chunk = <<"function mkadder(incby)\n" + " return function(i)\n" + " print(\"Call into Luerl!\")\n" + " return i + incby\n" + " end\n" + "end\n">>, + {_, State1} = luerl_old:do(Chunk, State), + {[Fun], _State2} = luerl_old:call_function([mkadder], [1], State1), + {[Fun2], _State3} = luerl_old:call_function([mkadder], [2], State1), + ?assertEqual([5], Fun([4])), + ?assertEqual([5.0], Fun([4.0])), + ?assertEqual([6], Fun2([4])). + +define_fun2_in_lua_test() -> + State = luerl_old:init(), + Chunk = <<"function mklist(numentries)\n" + " return function(entryval)\n" + " local list = {}\n" + " for i = 1,numentries do\n" + " list[i] = entryval\n" + " end\n" + " return list\n" + " end\n" + "end\n">>, + {_, State1} = luerl_old:do(Chunk, State), + {[Fun], _State2} = luerl_old:call_function([mklist], [5], State1), + {[Fun2], _State3} = luerl_old:call_function([mklist], [10], State1), + ?assertEqual([[{1,4}, {2,4}, {3,4}, {4,4}, {5,4}]], + Fun([4])), + ?assertEqual([[{1,4.0}, {2,4.0}, {3,4.0}, {4,4.0}, {5,4.0}]], + Fun([4.0])), + ?assertEqual([[{1,4}, {2,4}, {3,4}, {4,4}, {5,4}, + {6,4}, {7,4}, {8,4}, {9,4}, {10,4}]], + Fun2([4])). + +newindex_metamethod_test() -> + State = luerl_old:init(), + Chunk = <<"local t = {}\n" + "local m = setmetatable({}, {__newindex = function (tab, key, value)\n" + "t[key] = value\n" + "end})\n\n" + "m[123] = 456\n" + "return t[123], m[123]">>, + {[TVal, MVal], _State1} = luerl_old:do(Chunk, State), + ?assertEqual(456, TVal), + ?assertEqual(nil, MVal). diff --git a/test/luerl_old_tests.erl b/test/luerl_old_tests.erl new file mode 100644 index 0000000..a918538 --- /dev/null +++ b/test/luerl_old_tests.erl @@ -0,0 +1,44 @@ +%% Copyright (C) 2024 Robert Virding +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. + +-module(luerl_old_tests). + +-include_lib("eunit/include/eunit.hrl"). + +encode_test() -> + State = luerl_old:init(), + ?assertMatch({nil, _State}, luerl_old:encode(nil, State)), + ?assertMatch({false, _State}, luerl_old:encode(false, State)), + ?assertMatch({true, _State}, luerl_old:encode(true, State)), + ?assertMatch({<<"binary">>, _State}, luerl_old:encode(<<"binary">>, State)), + ?assertMatch({<<"atom">>, _State}, luerl_old:encode(atom, State)), + ?assertMatch({5, _State}, luerl_old:encode(5, State)), + ?assertMatch({{tref, _}, _State}, luerl_old:encode(#{a => 1, b => 2}, State)), + ?assertMatch({{tref, _}, _State}, luerl_old:encode([{a,1},{b,2}], State)). + +encode_error_test() -> + State = luerl_old:init(), + ?assertException(error, {badarg, _}, luerl_old:encode({a,1}, State)). + +encode_table_test() -> + {Table, State} = luerl_old:encode(#{a => 1}, luerl_new:init()), + State1 = luerl_old:set_table1([<<"foo">>], Table, State), + ?assertMatch({Table, _State2}, + luerl_old:get_table1([<<"foo">>], State1)), + ?assertMatch({tref, _}, Table). + +invalid_value_test() -> + State = luerl_old:init(), + ?assertException(error, {badarg, {invalid, value}}, + luerl_old:encode({invalid, value}, State)). diff --git a/test/luerl_return_SUITE.erl b/test/luerl_return_SUITE.erl index 07cb30c..1bd41a8 100644 --- a/test/luerl_return_SUITE.erl +++ b/test/luerl_return_SUITE.erl @@ -53,8 +53,8 @@ check_unicode(Config) -> check_unicode_call_fun(<<9810/utf8>>, 3, check_aquarius, St). check_unicode_call_fun(Input, Length, LuaFun, St) -> - {[Input, Input, true, Length, Length], _} = - luerl:call_function([LuaFun], [Input], St). + {ok, [Input, Input, true, Length, Length], _} = + luerl:call_function_dec([LuaFun], [Input], St). table_tests(Config) -> run_and_check(Config, "table_indexed_table.lua", [111, 222, 333]). @@ -66,6 +66,6 @@ run_tests(Config, Tests) -> run_and_check(Config, Script, Expected) -> DataDir = ?config(data_dir, Config), ScriptFile = DataDir ++ Script, - {Result, St} = luerl:dofile(ScriptFile, luerl:init()), + {ok, Result, St} = luerl:dofile(ScriptFile, luerl:init()), Expected = Result, St. diff --git a/test/luerl_tests.erl b/test/luerl_tests.erl index f26d075..26de63e 100644 --- a/test/luerl_tests.erl +++ b/test/luerl_tests.erl @@ -1,3 +1,17 @@ +%% Copyright (C) 2024 Robert Virding +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. + -module(luerl_tests). -include_lib("eunit/include/eunit.hrl"). @@ -18,10 +32,10 @@ encode_error_test() -> ?assertException(error, {badarg, _}, luerl:encode({a,1}, State)). encode_table_test() -> - {Table, State} = luerl:encode(#{a => 1}, luerl_new:init()), - State1 = luerl:set_table1([<<"foo">>], Table, State), - ?assertMatch({Table, _State2}, - luerl:get_table1([<<"foo">>], State1)), + {Table, State} = luerl:encode(#{a => 1}, luerl:init()), + {ok, State1} = luerl:set_table_keys([<<"foo">>], Table, State), + ?assertMatch({ok, Table, _State2}, + luerl:get_table_keys([<<"foo">>], State1)), ?assertMatch({tref, _}, Table). invalid_value_test() -> diff --git a/test/luerl_time_SUITE.erl b/test/luerl_time_SUITE.erl index 40c4449..582a83d 100644 --- a/test/luerl_time_SUITE.erl +++ b/test/luerl_time_SUITE.erl @@ -34,8 +34,12 @@ os_date(_Config) -> ?assertNotMatch({badrpc, _}, LusakaLocalTime), ?assertNotMatch({badrpc, _}, LondonLocalTime), ?assert(LusakaLocalTime =/= LondonLocalTime), - ?assertEqual({ok,[<<"Sat May 6 13:16:07 2023">>]}, rpc:call(LusakaNode, luerl, eval, ["return os.date('%c', 1683371767)", luerl:init()])), - ?assertEqual({ok,[<<"Sat May 6 12:16:07 2023">>]}, rpc:call(LondonNode, luerl, eval, ["return os.date('%c', 1683371767)", luerl:init()])), + ?assertMatch({ok,[<<"Sat May 6 13:16:07 2023">>], _St1}, + rpc:call(LusakaNode, luerl, do_dec, + ["return os.date('%c', 1683371767)", luerl:init()])), + ?assertMatch({ok,[<<"Sat May 6 12:16:07 2023">>], _St2}, + rpc:call(LondonNode, luerl, do_dec, + ["return os.date('%c', 1683371767)", luerl:init()])), ok. windows_tests() -> @@ -50,5 +54,5 @@ set_path(Node) -> ok; Err = {error, _} -> throw({badpath, Path, Err}) - end || Path <- code:get_path(), filelib:is_dir(Path)], - ok. \ No newline at end of file + end || Path <- code:get_path(), filelib:is_dir(Path)], + ok.