diff --git a/doc/luerl.txt b/doc/luerl.txt index f35ad11b..c515a4fd 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_new.txt b/doc/luerl_new.txt deleted file mode 100644 index 0b96f4a0..00000000 --- a/doc/luerl_new.txt +++ /dev/null @@ -1,156 +0,0 @@ -luerl_new(3) Library Functions Manual luerl_new(3) - -Name - luerl_new - New basic interface to the Luerl system - -Interface functions - New Version - The Lua State parameter is the state of a Lua VM instance. It must be - created with the luerl_new: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. - - 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. - - LuaCallReturn = {ok, Result, State} | {lua_error, Error, State} - This is the return value from evaluating a Lua call. - - Functions - luerl_new:init() -> State. - Get a new Lua State = a fresh Lua VM instance. - - luerl_new:gc(State) -> State. - Runs the garbage collector on a state and returns the new state. - - luerl_new:load(String|Binary[, CompileOptions], State) -> {ok, Function, - State} | CompileError; - Parse a Lua chunk as string or binary, and return a compiled chunk - (‘form’). - - luerl_new:loadfile(FileName[, CompileOptions], State) -> {ok, Function, - State} | CompileError. - Parse a Lua file, and return a compiled chunk (‘form’). - - luerl_new: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_new:load_module(KeyPath, ErlangModule, State) -> State. - Load ErlangModule and install its table at KeyPath which is NOT en‐ - coded. - - luerl_new:load_module_dec(EncodedKeyPath, ErlangModule, State) -> State. - Load ErlangModule and install its table at KeyPath which is encoded. - - luerl_new: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_new: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_new:dofile(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 NOT decoded, and the new Lua State. Equivalent to doing - luerl:do(“return dofile(‘FileName’)”). - - luerl_new: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_new:call(FuncRef, ArgRefs, State) -> {ok, Result, State} - luerl_new: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_new:call_function(FuncRef, ArgRefs, State] -> {ok, Result, State} | - {lua_error, Error, State}. - Call a function already defined in the state. Result is NOT decoded. - - luerl_new: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_new:call_method(ObjRef, Method, ArgRefs, State) -> {ok, Result, - State} | {lua_error, Error, State}. - Call a method already defined in the state. - - luerl_new: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_new:get_table_keys(KeyPath, State) -> {ok, Result, State} | {lua_er‐ - ror, Error, State}. - Gets a value inside the Lua state. KeyPath and Result are NOT en‐ - coded/decoded. - - luerl_new:get_table_keys_dec(KeyPath, State) -> {ok, Result, State} | - {lua_error, Error, State}. - Gets a value inside the Lua state. KeyPath and Result are automati‐ - cally encoded/decoded. - - luerl_new:set_table_keys(KeyPath, Value, State) -> State. - Sets a value inside the Lua state. KeyPath and Value are NOT encoded. - - luerl_new:set_table_keys_dec(KeyPath, Value, State) -> State. - Sets a value inside the Lua state. KeyPath and Value are automatically - encoded. - - luerl_new:get_stacktrace(State) -> [{FuncName,{file,File‐ - Name},{line,Line}}]. - Return a stack trace of the current call stack in the state. - - luerl_new:encode(Term, State) -> {LuerlTerm,State}. - Encode the Erlang representation of a term into Luerl form updating the - state when necessary. - - luerl_new:encode_list([Term], State) -> {[LuerlTerm],State}. - Encode a list of Erlang term representations into a list of Luerl forms - updating the state when necessary. - - luerl_new:decode(LuerlTerm, State) -> Term. - Decode a term in the Luerl form into its Erlang representation. - - luerl_new: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_new(3) diff --git a/doc/luerl_old.txt b/doc/luerl_old.txt new file mode 100644 index 00000000..2dcf4229 --- /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 3ecb3d2c..cc0121c3 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_new.3 b/doc/man/luerl_new.3 deleted file mode 100644 index 3f342cdc..00000000 --- a/doc/man/luerl_new.3 +++ /dev/null @@ -1,149 +0,0 @@ -.\" Automatically generated by Pandoc 3.3 -.\" -.TH "luerl_new" "3" "2018\-2023" "" -.SH Name -luerl_new \- New 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_new: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. -.PP -\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_new:init() \-> State. -Get a new Lua State = a fresh Lua VM instance. -.SS luerl_new:gc(State) \-> State. -Runs the garbage collector on a state and returns the new state. -.SS luerl_new: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_new:loadfile(FileName[, CompileOptions], State) \-> {ok, Function, State} | CompileError. -Parse a Lua file, and return a compiled chunk (`form'). -.SS luerl_new: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_new: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_new: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_new: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_new: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_new: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_new: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_new:call(FuncRef, ArgRefs, State) \-> {ok, Result, State} -.SS luerl_new: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_new:call_function(FuncRef, ArgRefs, State] \-> {ok, Result, State} | {lua_error, Error, State}. -Call a function already defined in the state. -\f[CR]Result\f[R] is \f[B]NOT\f[R] decoded. -.SS luerl_new:call_function_dec(KeyPath, Args, State) \-> {ok, Result, State} | {lua_error, Error, State}. -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 -automatically encoded/decoded. -.SS luerl_new:call_method(ObjRef, Method, ArgRefs, State) \-> {ok, Result, State} | {lua_error, Error, State}. -Call a method already defined in the state. -.SS luerl_new:call_method_dec(KeyPath, Method, Args, State) \-> {ok, Result, State} | {lua_error, Error, State}. -Call a method already defined in the state. -\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_new: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_new: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] and \f[CR]Result\f[R] are automatically -encoded/decoded. -.SS luerl_new:set_table_keys(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_new:set_table_keys_dec(KeyPath, Value, State) \-> State. -Sets a value inside the Lua state. -\f[CR]KeyPath\f[R] and \f[CR]Value\f[R] are automatically encoded. -.SS luerl_new:get_stacktrace(State) \-> [{FuncName,{file,FileName},{line,Line}}]. -Return a stack trace of the current call stack in the state. -.SS luerl_new:encode(Term, State) \-> {LuerlTerm,State}. -Encode the Erlang representation of a term into Luerl form updating the -state when necessary. -.SS luerl_new: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_new:decode(LuerlTerm, State) \-> Term. -Decode a term in the Luerl form into its Erlang representation. -.SS luerl_new: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 00000000..a3e4e042 --- /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 c98516f3..c64fc3e2 100644 Binary files a/doc/pdf/luerl.pdf and b/doc/pdf/luerl.pdf differ diff --git a/doc/pdf/luerl_new.pdf b/doc/pdf/luerl_new.pdf deleted file mode 100644 index 18b07de2..00000000 Binary files a/doc/pdf/luerl_new.pdf and /dev/null differ diff --git a/doc/pdf/luerl_old.pdf b/doc/pdf/luerl_old.pdf new file mode 100644 index 00000000..3ec06591 Binary files /dev/null and b/doc/pdf/luerl_old.pdf differ diff --git a/doc/src/luerl.3.md b/doc/src/luerl.3.md index f5319e2d..4575feb4 100644 --- a/doc/src/luerl.3.md +++ b/doc/src/luerl.3.md @@ -1,97 +1,124 @@ % 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:set_table(KeyPath, Value, State) -> State. - Sets a value inside the Lua state. Value is automatically encoded. +#### 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:set_table1(KeyPath, Value, State) -> State. +#### 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: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_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. + +#### 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. + +#### luerl:put_private(Key, Term, State) -> State. +Puts a private value under key that is not exposed to the runtime. - You can use this function to expose an function to the Lua code by using this interface: - `fun(Args, State) -> {Results, State}` +#### luerl:get_private(Key, State) -> Term. +Get a private value for the given key. - Args and Results must be a list of Luerl compatible Erlang values. +#### luerl:delete_private(Key, State) -> Term. +Deletes the private value for the given key. diff --git a/doc/src/luerl_new.3.md b/doc/src/luerl_new.3.md deleted file mode 100644 index f6ed4d1e..00000000 --- a/doc/src/luerl_new.3.md +++ /dev/null @@ -1,109 +0,0 @@ -% luerl_new(3) -% Jean Chassoul, Robert Virding -% 2018-2023 - -# Name -luerl_new - New basic interface to the Luerl system - -# Interface functions - New Version -The **Lua State** parameter is the state of a Lua VM instance. It must be created with the **luerl_new: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. - -**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. - - -**LuaCallReturn = {ok, Result, State} | {lua_error, Error, State}** -This is the return value from evaluating a Lua call. - -## Functions - -#### luerl_new:init() -> State. - Get a new Lua State = a fresh Lua VM instance. - -#### luerl_new:gc(State) -> State. - Runs the garbage collector on a state and returns the new state. - -#### luerl_new:load(String|Binary[, CompileOptions], State) -> {ok, Function, State} | CompileError; - Parse a Lua chunk as string or binary, and return a compiled chunk ('form'). - -#### luerl_new:loadfile(FileName[, CompileOptions], State) -> {ok, Function, State} | CompileError. - Parse a Lua file, and return a compiled chunk ('form'). - -#### luerl_new: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_new:load_module(KeyPath, ErlangModule, State) -> State. - Load `ErlangModule` and install its table at `KeyPath` which is **NOT** encoded. - -#### luerl_new:load_module_dec(EncodedKeyPath, ErlangModule, State) -> State. - Load `ErlangModule` and install its table at `KeyPath` which is encoded. - -#### luerl_new: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_new: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_new: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_new: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_new:call(FuncRef, ArgRefs, State) -> {ok, Result, State} - -#### luerl_new: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_new:call_function(FuncRef, ArgRefs, State] -> {ok, Result, State} | {lua_error, Error, State}. -Call a function already defined in the state. `Result` is **NOT** decoded. - -#### luerl_new: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_new:call_method(ObjRef, Method, ArgRefs, State) -> {ok, Result, State} | {lua_error, Error, State}. -Call a method already defined in the state. - -#### luerl_new: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_new: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_new:get_table_keys_dec(KeyPath, State) -> {ok, Result, State} | {lua_error, Error, State}. - Gets a value inside the Lua state. `KeyPath` and `Result` are automatically encoded/decoded. - -#### luerl_new:set_table_keys(KeyPath, Value, State) -> State. - Sets a value inside the Lua state. `KeyPath` and `Value` are **NOT** encoded. - -#### luerl_new:set_table_keys_dec(KeyPath, Value, State) -> State. - Sets a value inside the Lua state. `KeyPath` and `Value` are automatically encoded. - -#### luerl_new:get_stacktrace(State) -> [{FuncName,{file,FileName},{line,Line}}]. -Return a stack trace of the current call stack in the state. - -#### luerl_new:encode(Term, State) -> {LuerlTerm,State}. -Encode the Erlang representation of a term into Luerl form updating -the state when necessary. - -#### luerl_new:encode_list([Term], State) -> {[LuerlTerm],State}. -Encode a list of Erlang term representations into a list of Luerl -forms updating the state when necessary. - -#### luerl_new:decode(LuerlTerm, State) -> Term. -Decode a term in the Luerl form into its Erlang representation. - -#### luerl_new: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 00000000..345ec366 --- /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/examples/benchmark/benchmarks.erl b/examples/benchmark/benchmarks.erl index 0153a2e1..ce8e38cd 100644 --- a/examples/benchmark/benchmarks.erl +++ b/examples/benchmark/benchmarks.erl @@ -10,50 +10,48 @@ -define(DEFAULT_ITER, 1000). run() -> - Files = filelib:wildcard("suites/*.lua"), - [run(File) || File <- Files], - ok. + Files = filelib:wildcard("suites/*.lua"), + [ run(File) || File <- Files ] , + ok. run(File) -> - Lua0 = luerl:init(), - {ok, Form, Lua1} = luerl:loadfile(File, Lua0), - {_Resp, Lua2} = luerl:do(Form, Lua1), - report_file(File), - [do_benchmark(Benchmark, Lua2) || Benchmark <- benchmarks(Lua2)], - {ok, Lua2}. + Lua0 = luerl:init(), + {ok, _Resp, Lua2} = luerl:dofile(File, Lua0), + report_file(File), + [ do_benchmark(Benchmark, Lua2) || Benchmark <- benchmarks(Lua2) ], + {ok, Lua2}. do_benchmark(Benchmark, Lua) -> - Iter = num_iterations(Lua), - report_benchmark(Benchmark), - {Time, _Resp} = timer:tc(?MODULE, do_iteration, - [Iter, Benchmark, Lua]), - report_time(Time), - ok. - -do_iteration(0, _Benchmark, _Lua) -> ok; + Iter = num_iterations(Lua), + report_benchmark(Benchmark), + {Time, _Resp} = timer:tc(?MODULE, do_iteration, + [Iter, Benchmark, Lua]), + report_time(Time), + ok. + +do_iteration(0, _Benchmark, _Lua) -> + ok; do_iteration(Iter, Benchmark, Lua) -> - luerl:call_method1([<<"bench">>, Benchmark], [], Lua), - do_iteration(Iter - 1, Benchmark, Lua). + luerl:call_method([<<"bench">>], Benchmark, [], Lua), + do_iteration(Iter - 1, Benchmark, Lua). num_iterations(Lua) -> - case luerl:eval("return NUM_ITERATIONS", Lua) of - {ok, [Iter]} when is_number(Iter) -> round(Iter); - _any -> ?DEFAULT_ITER + case luerl:do("return NUM_ITERATIONS", Lua) of + {ok, [Iter], _} when is_number(Iter) -> round(Iter); + _Any -> ?DEFAULT_ITER end. benchmarks(Lua0) -> - {ok, Chunk, Lua1} = luerl:loadfile("util/extract_bench_keys.lua", Lua0), - {ok, [Benchmarks]} = luerl:eval(Chunk, Lua1), - [Key || {_Index, Key} <- Benchmarks]. + io:format("benchmarks\n", []), + {ok, [Benchmarks], _} = luerl:dofile_dec("util/extract_bench_keys.lua", Lua0), + [ Key || {_Index, Key} <- Benchmarks ]. report_file(File) -> - io:format("~n~s ms~n", [string:left(File, 26)]). + io:format("~n~s ms~n", [string:left(File, 26)]). report_benchmark(Benchmark) -> - io:format(" ~s", - [string:left(binary_to_list(Benchmark), 24, $.)]). + io:format(" ~s", + [string:left(binary_to_list(Benchmark), 24, $.)]). report_time(Time) -> - io:format(" ~p~n", [Time / 1000]). - - + io:format(" ~p~n", [Time / 1000]). diff --git a/examples/euler/euler.erl b/examples/euler/euler.erl index 3bdbd43d..7ff66da8 100644 --- a/examples/euler/euler.erl +++ b/examples/euler/euler.erl @@ -22,12 +22,14 @@ run() -> run(File, Solution) -> Lua0 = luerl:init(), {ok, Form, Lua1} = luerl:loadfile(File, Lua0), - case timer:tc(luerl, eval, [Form, Lua1]) of - {T, {ok, [Return]}} when Return == Solution -> + case timer:tc(luerl, call_chunk, [Form, [], Lua1]) of + {T, {ok, [Return], _}} when Return == Solution -> io:format("~s (returned ~p in ~pus)~n", [File, Return, T]); - {T, {ok, [Return]}} -> + {T, {ok, [Return], _}} -> io:format("~s (expected ~p but got ~p in ~pus)~n", [File, Solution, Return, T]); + {_, {lua_error, Error, State}} -> + io:format("luerl error: ~p~n", [{Error,State}]); {_, {error, Error, State}} -> - io:format("luerl error: ~p~n", [{Error,State}]) + io:format("Error: ~p~n", [{Error,State}]) end. diff --git a/examples/hello/Makefile b/examples/hello/Makefile index 2a92e062..9a0459db 100644 --- a/examples/hello/Makefile +++ b/examples/hello/Makefile @@ -1,9 +1,7 @@ EXAMPLES = hello \ hello2 \ hello_table \ - hello_table_new \ hello_userdata \ - hello_userdata_new \ hello_sandbox \ hello_funcalls diff --git a/examples/hello/hello.erl b/examples/hello/hello.erl index 6e719c96..78dedd67 100644 --- a/examples/hello/hello.erl +++ b/examples/hello/hello.erl @@ -17,6 +17,6 @@ run() -> % separately parse, then execute State0 = luerl:init(), {ok, Chunk, State1} = luerl:load("print(\"Hello, Chunk!\")", State0), - {_Ret, _NewState} = luerl:do(Chunk, State1), + {ok,_Ret, _NewState} = luerl:call(Chunk, [], State1), done. diff --git a/examples/hello/hello2.erl b/examples/hello/hello2.erl index 152e494a..42c00f40 100644 --- a/examples/hello/hello2.erl +++ b/examples/hello/hello2.erl @@ -18,69 +18,64 @@ run() -> St0A = luerl:init(), % execute a string - luerl:eval("print(\"(1) Hello, Robert!\")", St0A), - luerl:eval(<<"print(\"(2) Hello, Roberto!\")">>, St0A), - luerl:do("print(\"(3) Hej, Robert!\")", St0A), - luerl:do(<<"print(\"(4) Olà, Roberto!\")">>, St0A), + luerl:do("print(\"(1) Hello, Robert!\")", St0A), + luerl:do(<<"print(\"(2) Hello, Roberto!\")">>, St0A), % execute a string, get a result - {ok,A} = luerl:eval("return 1 + 1", St0A), - {ok,A} = luerl:eval(<<"return 1 + 1">>, St0A), + {ok,A,_} = luerl:do("return 1 + 1", St0A), + {ok,A,_} = luerl:do(<<"return 1 + 1">>, St0A), io:format("(5) 1 + 1 = ~p!~n", [A]), % execute a file - luerl:evalfile("./hello2-1.lua", St0A), luerl:dofile("./hello2-1.lua", St0A), % execute a file, get a result - {ok,B} = luerl:evalfile("./hello2-2.lua", St0A), - {B,_} = luerl:dofile("./hello2-2.lua", St0A), + {ok,B,_} = luerl:dofile("./hello2-2.lua", St0A), io:format("(7) 2137 * 42 = ~p?~n", [B]), - % execute a standard function - luerl:call_function([print], [<<"(8) Hello, standard print function!">>], St0A), - luerl:call_function([print], [<<"(9) Hello, standard print function!">>], St0A), - {Result1,_} = luerl:call_function([table,pack], [<<"a">>,<<"b">>,42], St0A), - {Result1,_} = luerl:call_function([table,pack], [<<"a">>,<<"b">>,42], St0A), + % execute a standard function + luerl:call_function_dec([print], + [<<"(8) Hello, standard print function!">>], St0A), + luerl:call_function_dec([print], + [<<"(9) Hello, standard print function!">>], St0A), + {ok,Result1,_} = luerl:call_function_dec([table,pack], + [<<"a">>,<<"b">>,42], St0A), + {ok,Result1,_} = luerl:call_function_dec([table,pack], + [<<"a">>,<<"b">>,42], St0A), io:format("(10) ~p?~n", [Result1]), % separately parse, then execute (doubles (11) and Chunk1 as assertion) St1A = luerl:init(), {ok,Chunk1,St1B} = luerl:load("print(\"(11) Hello, Chunk 1!\")", St1A), {ok,Chunk1,_} = luerl:load(<<"print(\"(11) Hello, Chunk 1!\")">>, St1A), - luerl:eval(Chunk1, St1B), - luerl:do(Chunk1, St1B), + luerl:call_chunk(Chunk1, [], St1B), % separately parse, then execute (doubles (12) and Chunk2 as assertion) St2A = luerl:init(), {ok,Chunk2,St2B} = luerl:load("function chunk2() print(\"(12) Hello, Chunk 2!\") end", St2A), {ok,Chunk2,_} = luerl:load(<<"function chunk2() print(\"(12) Hello, Chunk 2!\") end">>, St2A), - {ok,Result2} = luerl:eval(Chunk2, St2B), - {Result2,St2C} = luerl:do(Chunk2, St2B), - {Result2,St2D} = luerl:do(<<"function chunk2() print(\"(12) Hello, Chunk 2!\") end">>, St2A), - luerl:call_function([chunk2], [], St2C), - luerl:call_function([chunk2], [], St2D), + {ok,Result2,St2C} = luerl:call_chunk(Chunk2, [], St2B), + {ok,Result2,St2D} = luerl:do(<<"function chunk2() print(\"(12) Hello, Chunk 2!\") end">>, St2A), + luerl:call_function_dec([chunk2], [], St2C), + luerl:call_function_dec([chunk2], [], St2D), % separately parse, then execute a file. The file defines a function no() St3A = luerl:init(), {ok,Chunk3,St3B} = luerl:loadfile("./hello2-3.lua", St3A), - {ok,Result3} = luerl:eval(Chunk3, St3B), - {Result3,St3C} = luerl:do(Chunk3, St3B), - {[],_} = luerl:call_function([no], [], St3C), + {ok,_Result3,St3C} = luerl:call_chunk(Chunk3, St3B), + {ok,[],_} = luerl:call_function_dec([no], [], St3C), % separately parse, then execute, get a result St4A = luerl:init(), {ok,Chunk4,St4B} = luerl:load("return '(17b) Marvelous wheater today, isn°t it!'", St4A), {ok,Chunk4,_} = luerl:load(<<"return '(17b) Marvelous wheater today, isn°t it!'">>, St4A), - {ok,Result4} = luerl:eval(Chunk4, St4B), - {Result4,_} = luerl:do(Chunk4, St4B), + {ok,Result4,_} = luerl:call_chunk(Chunk4, [], St4B), io:format("(17) And I say: ~p~n", [Result4]), % separately parse, then execute a file, get a result St5A = luerl:init(), {ok,Chunk5,St5B} = luerl:loadfile("./hello2-4.lua", St5A), - {ok,Result5} = luerl:eval(Chunk5, St5B), - {Result5,_} = luerl:do(Chunk5, St5B), + {ok,Result5,_} = luerl:call_chunk(Chunk5, St5B), io:format("(18) And he says: ~p~n", [Result5]), @@ -88,77 +83,68 @@ run() -> % create state New = luerl:init(), - {_,_New2} = luerl:do("print '(19) hello generix'", New), + {ok,_,_New2} = luerl:do("print '(19) hello generix'", New), % change state - {_,State0} = luerl:do("a = 1000", New), - {_,State01} = luerl:do("a = 1000", New), + {ok,_,State0} = luerl:do("a = 1000", New), + {ok,_,State01} = luerl:do("a = 1000", New), % execute a string, using passed in State0 - luerl:eval("print('(20) ' .. a)", State0), - luerl:eval(<<"print('(21) ' .. a+1)">>, State0), luerl:do("print('(22) ' .. a+2)", State0), luerl:do(<<"print('(23) ' .. a+3)">>, State0), % execute a string, get a result from passed in State0 - {ok,E} = luerl:eval("return 4 * a", State0), - {ok,E} = luerl:eval(<<"return 4 * a">>, State0), - {E,_} = luerl:do("return 4 * a", State0), - {E,_} = luerl:do(<<"return 4 * a">>, State0), + {ok,E,_} = luerl:do("return 4 * a", State0), + {ok,E,_} = luerl:do(<<"return 4 * a">>, State0), io:format("(24) 4 x a = ~p!~n", [E]), % execute a string, get a result, change State0 - {Z,State02} = luerl:do("a = 123; return a * 3", State01), - {Z,State03} = luerl:do(<<"return (3 * a)">>, State02), + {ok,Z,State02} = luerl:do("a = 123; return a * 3", State01), + {ok,Z,State03} = luerl:do(<<"return (3 * a)">>, State02), io:format("(25) a = ~p~n", [Z]), % execute a file using passed in state - luerl:evalfile("./hello2-5.lua", State03), luerl:dofile("./hello2-5.lua", State03), % execute a file that changes the State0 - {_,State04} = luerl:dofile("./hello2-6.lua", State03), + {ok,_,State04} = luerl:dofile("./hello2-6.lua", State03), luerl:do("print('(27) (b) ' .. a)", State04), % execute a file, get a result - {ok,F} = luerl:evalfile("./hello2-7.lua", State04), - {F,State05} = luerl:dofile("./hello2-7.lua", State04), + {ok,F,State05} = luerl:dofile("./hello2-7.lua", State04), io:format("(28) F: ~ts~n", [F]), % execute a file that changes the State0, and get a value back - {F,State06} = luerl:dofile("./hello2-7.lua", State05), + {ok,F,State06} = luerl:dofile("./hello2-7.lua", State05), io:format("(29) F: ~ts = ", [F]), luerl:do("print('(30) F: ' .. a)", State06), % separately parse, then execute {ok,Chunk11,_} = luerl:load("print(\"(31) Hello, \" .. a .. \"!\")", State06), {ok,Chunk11,State07} = luerl:load(<<"print(\"(31) Hello, \" .. a .. \"!\")">>, State06), - luerl:eval(Chunk11,State07), - luerl:do(Chunk11,State07), + luerl:call_chunk(Chunk11,State07), % separately parse, then execute a file. The file defines a function old() {ok,Chunk12,St7} = luerl:loadfile("./hello2-8.lua", State07), - {ok,Result12} = luerl:eval(Chunk12, St7), - {Result12,State07A} = luerl:do(Chunk12,St7), - luerl:call_function([old],[],State07A), + {ok,_Result12,State07A} = luerl:call_chunk(Chunk12,St7), + luerl:call_function_dec([old],[],State07A), % separately parse, then execute, get a result {ok,Chunk13,St8} = luerl:load("a = '(30a)' .. a .. ' (this is Greek)'; return a", State07), {ok,Chunk13,_} = luerl:load(<<"a = '(30a)' .. a .. ' (this is Greek)'; return a">>, State07), - {ok,Result07} = luerl:eval(Chunk13, St8), - {Result07,State08} = luerl:do(Chunk13, St8), + {ok,Result07,State08} = luerl:call_chunk(Chunk13, St8), io:format("(34) And again I said: ~ts~n", [Result07]), % separately parse, then execute a file, get a result. The file defines confirm(p) {ok,Chunk14,St9} = luerl:loadfile("./hello2-9.lua", State08), - {ok,Result14} = luerl:eval(Chunk14, St9), - {Result14,State14} = luerl:do(Chunk14, St9), + {ok,Result14,State14} = luerl:call_chunk(Chunk14, St9), io:format("(35) And twice: ~ts~n", [Result14]), - {Result14A,_} = luerl:call_function([confirm], [<<"Is it?">>], State14), + {ok,Result14A,_} = luerl:call_function_dec([confirm], + [<<"Is it?">>], State14), io:format("(36) Well: ~ts~n", [Result14A]), % execute a file, get the decoded result of a table - {ok,Result15} = luerl:evalfile("./hello2-10.lua", State14), + {ok,Result15,_} = luerl:dofile("./hello2-10.lua", State14), io:format("(37) Decoded table: ~p~n", [Result15]), io:format("done~n"). diff --git a/examples/hello/hello_funcalls.erl b/examples/hello/hello_funcalls.erl index 34d8690b..061466da 100644 --- a/examples/hello/hello_funcalls.erl +++ b/examples/hello/hello_funcalls.erl @@ -8,21 +8,28 @@ -export([run/0,mfa_function/3]). -regular_function(Args,St) -> +regular_function(Args, St) -> io:format("regular_function(~p)\n", [Args]), {[42], St}. -mfa_function(StaticArgs,DynamicArgs,St) -> +mfa_function(StaticArgs, DynamicArgs, St) -> io:format("mfa_function(~p, ~p)\n", [StaticArgs, DynamicArgs]), {[42], St}. run() -> LuaScript = <<"return hello_funcall(4, 5, 6)">>, Lua = luerl:init(), - Lua1 = luerl:set_table([<<"hello_funcall">>], fun regular_function/2, Lua), - % The argument part of {M,F,A} won't get encoded, so that is why we can get away with passing a tuple here. - Lua2 = luerl:set_table([<<"hello_funcall">>], {hello_funcalls,mfa_function,{1,2}}, Lua), - {Res1, _} = luerl:do(LuaScript, Lua1), + {ok,Lua1} = luerl:set_table_keys_dec([<<"hello_funcall">>], + fun regular_function/2, Lua), + + % The argument part of {M,F,A} won't get encoded, so that is why + % we can get away with passing a tuple here. + {ok,Lua2} = luerl:set_table_keys_dec([<<"hello_funcall">>], + {hello_funcalls,mfa_function,{1,2}}, + Lua), + + {ok,Res1, _} = luerl:do(LuaScript, Lua1), io:format("regular_function got ~p~n", Res1), - {Res2, _} = luerl:do(LuaScript, Lua2), + + {ok,Res2, _} = luerl:do(LuaScript, Lua2), io:format("mfa_function got ~p~n", Res2). diff --git a/examples/hello/hello_sandbox.erl b/examples/hello/hello_sandbox.erl index 8e73e3c0..78a5f7fa 100644 --- a/examples/hello/hello_sandbox.erl +++ b/examples/hello/hello_sandbox.erl @@ -10,17 +10,20 @@ run() -> %% Default sandboxed state. SbSt = luerl_sandbox:init(), + io:format("inited\n"), + %% Sandboxing globals - {error, {lua_error, Reason, _}} = - luerl_sandbox:run("return os.getenv(\"HOME\")", SbSt), + %% {error, {lua_error, Reason, _}} = + {lua_error, Reason, _} = + luerl_sandbox:run("return os.getenv(\"HOME\")", [], SbSt), io:format("os.getenv with sandbox: ~p~n",[Reason]), %% Customizing sandbox %% first with default Luerl state. - {[<<"number">>], _} = luerl_sandbox:run("return type(1)", luerl:init()), + {ok,[<<"number">>], _} = luerl_sandbox:run("return type(1)", luerl:init()), %% then with sandboxed type function - {error, {lua_error, _, _}} = + {lua_error, _, _} = luerl_sandbox:run("return type(1)", luerl_sandbox:init([['_G', type]])), %% Using sandboxed state outside of runner @@ -54,8 +57,8 @@ run() -> %% Unlimited reductions Flags3 = #{max_reductions => none}, - {[], _} = luerl_sandbox:run("a={}; for i=1,10 do a[i] = 5 end", - Flags3, SbSt), + {ok, [], _} = luerl_sandbox:run("a={}; for i=1,10 do a[i] = 5 end", + Flags3, SbSt), io:format("Finished running with unlimited reductions ~n",[]), done. diff --git a/examples/hello/hello_table.erl b/examples/hello/hello_table.erl index acc768ef..0f0d802d 100644 --- a/examples/hello/hello_table.erl +++ b/examples/hello/hello_table.erl @@ -1,23 +1,26 @@ %% File : hello_table.erl %% Purpose : Brief demonstration of Luerl table access. -%% Use $ erlc hello_table.erl && erl -pa ../../ebin -s hello_table run -s init stop -noshell +%% Use $ erlc hello_table_new.erl && erl -pa ../../ebin -s hello_table_new run -s init stop -noshell -module(hello_table). -export([run/0]). run() -> LuaScript = <<"hello_table = { hello=\"world\" }; return hello_table">>, - {[_Table], Lua0} = luerl:do(LuaScript, luerl:init()), + {ok, [_Table], Lua0} = luerl:do(LuaScript, luerl:init()), - {World, Lua1} = luerl:get_table([hello_table, hello], Lua0), - Lua2 = luerl:set_table([hello_table, hello], there, Lua1), - {HelloDict,Lua3} = luerl:get_table([hello_table], Lua2), - {There, Lua4} = luerl:get_table([hello_table, hello], Lua3), + {ok,World,Lua1} = luerl:get_table_keys_dec([hello_table, hello], Lua0), + {ok,Lua2} = luerl:set_table_keys_dec([hello_table, hello], there, Lua1), + {ok,HelloDict,Lua3} = luerl:get_table_keys_dec([hello_table], Lua2), + {ok,There, Lua4} = luerl:get_table_keys_dec([hello_table, hello], Lua3), io:format("(1) hello ~s ~s - ~p~n", [There, World, HelloDict]), - - Lua5 = luerl:set_table1([<<"hello_table">>, <<"goodbye">>], <<"bye">>, Lua4), - {Bye, Lua6} = luerl:get_table1([<<"hello_table">>, <<"goodbye">>], Lua5), - {HelloTab, _Lua7} = luerl:get_table1([<<"hello_table">>], Lua6), + + {ok,Lua5} = + luerl:set_table_keys([<<"hello_table">>, <<"goodbye">>], + <<"bye">>, Lua4), + {ok, Bye, Lua6} = + luerl:get_table_keys([<<"hello_table">>, <<"goodbye">>], Lua5), + {ok, HelloTab, _Lua7} = luerl:get_table_keys([<<"hello_table">>], Lua6), io:format("(2) ~s - ~p~n", [Bye, HelloTab]), done. diff --git a/examples/hello/hello_table_new.erl b/examples/hello/hello_table_new.erl deleted file mode 100644 index 0bae4fa3..00000000 --- a/examples/hello/hello_table_new.erl +++ /dev/null @@ -1,28 +0,0 @@ -%% File : hello_table.erl -%% Purpose : Brief demonstration of Luerl table access. -%% Use $ erlc hello_table_new.erl && erl -pa ../../ebin -s hello_table_new run -s init stop -noshell - --module(hello_table_new). --export([run/0]). - -run() -> - LuaScript = <<"hello_table = { hello=\"world\" }; return hello_table">>, - {ok, [_Table], Lua0} = luerl_new:do(LuaScript, luerl_new:init()), - - {ok,World, Lua1} = - luerl_new:get_table_keys_dec([hello_table, hello], Lua0), - {ok,_,Lua2} = - luerl_new:set_table_keys_dec([hello_table, hello], there, Lua1), - {ok,HelloDict,Lua3} = luerl_new:get_table_keys_dec([hello_table], Lua2), - {ok,There, Lua4} = luerl_new:get_table_keys_dec([hello_table, hello], Lua3), - io:format("(1) hello ~s ~s - ~p~n", [There, World, HelloDict]), - - {ok,_,Lua5} = - luerl_new:set_table_keys([<<"hello_table">>, <<"goodbye">>], - <<"bye">>, Lua4), - {ok, Bye, Lua6} = - luerl_new:get_table_keys([<<"hello_table">>, <<"goodbye">>], Lua5), - {ok, HelloTab, _Lua7} = luerl_new:get_table_keys([<<"hello_table">>], Lua6), - io:format("(2) ~s - ~p~n", [Bye, HelloTab]), - - done. diff --git a/examples/hello/hello_userdata.erl b/examples/hello/hello_userdata.erl index 0461024b..5c1150ef 100644 --- a/examples/hello/hello_userdata.erl +++ b/examples/hello/hello_userdata.erl @@ -1,19 +1,20 @@ %% File : hello_userdata.erl %% Purpose : Brief demonstration of Luerl userdata access. -%% Use $ erlc hello_userdata.erl && erl -pa ../../ebin -s hello_userdata run -s init stop -noshell +%% Use $ erlc hello_userdata_new.erl && erl -pa ../../ebin -s hello_userdata_new run -s init stop -noshell -module(hello_userdata). -export([run/0]). run() -> St0 = luerl:init(), - U42 = {userdata,42}, %The original decoded data + U42 = {userdata,42}, %The original decoded data {Uref,St1} = luerl:encode(U42, St0), - St2 = luerl:set_table1([<<"u1">>], Uref, St1), - St3 = luerl:set_table1([<<"u2">>], Uref, St2), + {ok,St2} = luerl:set_table_keys([<<"u1">>], Uref, St1), + {ok,St3} = luerl:set_table_keys([<<"u2">>], Uref, St2), %% This call wraps the actual data for us. St4 = luerl_heap:set_userdata_data(Uref, 84, St3), - U84 = {userdata,84}, %New decoded data - {U84,St5} = luerl:get_table([<<"u1">>], St4), - {U84,St6} = luerl:get_table([<<"u2">>], St5), + {ok,Uref,St5} = luerl:get_table_keys([<<"u1">>], St4), + {ok,Uref,St6} = luerl:get_table_keys([<<"u2">>], St5), + U84 = {userdata,84}, %New decoded data + U84 = luerl:decode(Uref, St6), St6. diff --git a/examples/hello/hello_userdata_new.erl b/examples/hello/hello_userdata_new.erl deleted file mode 100644 index 0223a8fc..00000000 --- a/examples/hello/hello_userdata_new.erl +++ /dev/null @@ -1,20 +0,0 @@ -%% File : hello_userdata_new.erl -%% Purpose : Brief demonstration of Luerl userdata access. -%% Use $ erlc hello_userdata_new.erl && erl -pa ../../ebin -s hello_userdata_new run -s init stop -noshell - --module(hello_userdata_new). --export([run/0]). - -run() -> - St0 = luerl_new:init(), - U42 = {userdata,42}, %The original decoded data - {Uref,St1} = luerl_new:encode(U42, St0), - {ok,_,St2} = luerl_new:set_table_keys([<<"u1">>], Uref, St1), - {ok,_,St3} = luerl_new:set_table_keys([<<"u2">>], Uref, St2), - %% This call wraps the actual data for us. - St4 = luerl_heap:set_userdata_data(Uref, 84, St3), - {ok,Uref,St5} = luerl_new:get_table_keys([<<"u1">>], St4), - {ok,Uref,St6} = luerl_new:get_table_keys([<<"u2">>], St5), - U84 = {userdata,84}, %New decoded data - U84 = luerl_new:decode(Uref, St6), - St6. diff --git a/examples/minibench/minibench.erl b/examples/minibench/minibench.erl index 9718526d..84e9fc4f 100644 --- a/examples/minibench/minibench.erl +++ b/examples/minibench/minibench.erl @@ -80,8 +80,8 @@ run() -> io:format("Pure parsing~n"), I6 = 100000, {T6,_State61} = timer:tc(fun() -> [luerl:load("return 1 + 1", - luerl:init()) || - _ <- lists:seq(1,I6)] end), + luerl:init()) || + _ <- lists:seq(1,I6)] end), io:format("Adding Up: ~p microseconds for ~p x calling Lua and returning the result of 1 + 1.~n", [T6,I6]), io:format("Per call: ~p microseconds.~n", [T6/I6]), @@ -92,12 +92,11 @@ run() -> io:format("Parse and execute '1 + 1', re-using state~n"), I7 = 100000, State7 = luerl:init(), - {T7,_State71} = timer:tc(fun() -> do_loop_state(I7, "return 1 + 1", State7) end), + {T7,_State71} = timer:tc(fun() -> do_loop_do(I7, "return 1 + 1", State7) end), io:format("Adding Up: ~p microseconds for ~p x calling Lua and returning the result of 1 + 1.~n", [T7,I7]), io:format("Per call: ~p microseconds.~n", [T7/I7]), - done. % helper @@ -107,11 +106,16 @@ do_loop(N, Chunk) when N > 0 -> do_loop(0, _) -> ok. do_loop_state(N, Chunk, State) when N > 0 -> - luerl:do(Chunk, State), + luerl:call_chunk(Chunk, [], State), do_loop_state(N-1, Chunk, State); do_loop_state(0, _, _) -> ok. +do_loop_do(N, String, State) when N > 0 -> + luerl:do(String, State), + do_loop_do(N-1, String, State); +do_loop_do(0, _, _) -> ok. + do_loop_chain(N, Chunk, State0) when N > 0 -> - {_,State1} = luerl:do(Chunk, State0), + {ok,_,State1} = luerl:call_chunk(Chunk, [], State0), do_loop_chain(N-1, Chunk, State1); do_loop_chain(0, _, _) -> ok. diff --git a/examples/minibench/minibench2.erl b/examples/minibench/minibench2.erl index 61815ada..a4818531 100644 --- a/examples/minibench/minibench2.erl +++ b/examples/minibench/minibench2.erl @@ -17,36 +17,43 @@ run() -> io:format("This is a benchmark of frequent fast calls into Luerl.~n"), % I. eval and execute + DoStr1 = "a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b; return c", io:format("----------------------------------------------------------~n"), - io:format("Init state, parse and execute 'a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b'~n"), + io:format("Init state, parse and execute '~s'~n", [DoStr1]), I1 = 10000, - {T1,_State} = timer:tc(fun() -> do_loop(I1, "a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b; return c") end), + {T1,_State} = timer:tc(fun() -> do_loop(I1, DoStr1) end), - io:format("Adding Up: ~p microseconds for ~p x calling Lua and returning the result of a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b.~n", [T1,I1]), + io:format("Adding Up: ~p microseconds for ~p x calling Lua and returning the result of '~s'.~n", + [T1,I1,DoStr1]), io:format("Per call: ~p microseconds.~n", [T1/I1]), % II. eval once, then only execute + DoStr2 = "a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b; return c", io:format("----------------------------------------------------------~n"), - io:format("Init state, and execute pre-parsed 'a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b'~n"), + io:format("Init state, and execute pre-parsed '~s'~n", [DoStr2]), I2 = 10000, - {ok, Chunk2, State2} = luerl:load("a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b; return c", luerl:init()), + {ok, Chunk2, State2} = luerl:load(DoStr2, luerl:init()), {T2,_State21} = timer:tc(fun() -> do_loop_state(I2, Chunk2, State2) end), - io:format("Adding Up: ~p microseconds for ~p x calling Lua and returning the result of a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b.~n", [T2,I2]), + io:format("Adding Up: ~p microseconds for ~p x calling Lua and returning the result of '~s'.~n", + [T2,I2,DoStr2]), io:format("Per call: ~p microseconds.~n", [T2/I2]), % III. eval once, then only execute + DoStr3 = "a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b; return c", io:format("----------------------------------------------------------~n"), - io:format("Execute pre-parse execute 'a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b', re-using same state~n"), + io:format("Execute pre-parse execute '~s', re-using same state~n", + [DoStr3]), I3 = 10000, - {ok, Chunk3, State3} = luerl:load("a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b; return c", luerl:init()), + {ok, Chunk3, State3} = luerl:load(DoStr3, luerl:init()), {T3,_State31} = timer:tc(fun() -> do_loop_state(I3, Chunk3, State3) end), - io:format("Adding Up: ~p microseconds for ~p x calling Lua and returning the result of a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b.~n", [T3,I3]), + io:format("Adding Up: ~p microseconds for ~p x calling Lua and returning the result of '~s'.~n", + [T3,I3,DoStr3]), io:format("Per call: ~p microseconds.~n", [T3/I3]), @@ -62,60 +69,68 @@ run() -> % V. eval once, then only execute, re-use previous state + DoStr5 = "a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b; return c", io:format("----------------------------------------------------------~n"), - io:format("Execute pre-parsed 'a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b', re-using state from last result~n"), + io:format("Execute pre-parsed '~s', re-using state from last result~n", + [DoStr5]), I5 = 10000, - {ok, Chunk5, State5} = luerl:load("a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b; return c", luerl:init()), + {ok, Chunk5, State5} = luerl:load(DoStr5, luerl:init()), {T5,_State51} = timer:tc(fun() -> do_loop_chain(I5, Chunk5, State5) end), - io:format("Adding Up: ~p microseconds for ~p x calling Lua and returning the result of a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b.~n", [T5,I5]), + io:format("Adding Up: ~p microseconds for ~p x calling Lua and returning the result of '~s'.~n", [T5,I5,DoStr5]), io:format("Per call: ~p microseconds.~n", [T5/I5]), % Vb. function call, re-use previous state + DoStr5b = "function OneAndOne() a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b; return c end", io:format("----------------------------------------------------------~n"), - io:format("Execute pre-parsed function with 'a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b', re-using state from last result~n"), + io:format("Execute pre-parsed function '~s', re-using state from last result~n", + [DoStr5b]), I5b = 10000, State5b = luerl:init(), - {[],State5b1} = luerl:do("function OneAndOne() a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b; return c end", State5b), + {ok,[],State5b1} = luerl:do(DoStr5b, State5b), io:format("-"), - {T5b,_State5b1} = timer:tc(fun() -> do_loop_state(I5b, "return OneAndOne()", State5b1) end), + {T5b,_State5b1} = timer:tc(fun() -> do_loop_do(I5b, "return OneAndOne()", State5b1) end), - io:format("Adding Up: ~p microseconds for ~p x calling Lua and returning the result of a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b.~n", [T5b,I5b]), + io:format("Adding Up: ~p microseconds for ~p x calling Lua and returning the result of '~s'.~n", + [T5b,I5b,DoStr5b]), io:format("Per call: ~p microseconds.~n", [T5b/I5b]), % Vc. empty function call, re-use previous state + DoStr5c = "function EmptyFunc() end", io:format("----------------------------------------------------------~n"), io:format("Execute empty function, re-using state from last result~n"), I5c = 10000, State5c = luerl:init(), - {[],State5c1} = luerl:do("function EmptyFunc() end", State5c), + {ok,[],State5c1} = luerl:do(DoStr5c, State5c), io:format("-"), - {T5c,_State5c1} = timer:tc(fun() -> do_loop_state(I5c, "EmptyFunc()", State5c1) end), + {T5c,_State5c1} = timer:tc(fun() -> do_loop_do(I5c, "EmptyFunc()", State5c1) end), - io:format("Adding Up: ~p microseconds for ~p x calling empty function.~n", [T5c,I5c]), + io:format("Adding Up: ~p microseconds for ~p x calling empty function.~n", + [T5c,I5c]), io:format("Per call: ~p microseconds.~n", [T5c/I5c]), % VI. measure but parsing + DoStr6 = "a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b; return c", io:format("----------------------------------------------------------~n"), io:format("Pure parsing~n"), I6 = 10000, - {T6,_State61} = timer:tc(fun() -> [luerl:load("a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b; return c", - luerl:init()) || - _ <- lists:seq(1,I6)] end), + {T6,_State61} = timer:tc(fun() -> [luerl:load(DoStr6, luerl:init()) || + _ <- lists:seq(1,I6)] end), - io:format("Adding Up: ~p microseconds for ~p x calling Lua and returning the result of a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b.~n", [T6,I6]), + io:format("Adding Up: ~p microseconds for ~p x calling Lua and returning the result of '~s'.~n", [T6,I6,DoStr6]), io:format("Per call: ~p microseconds.~n", [T6/I6]), % VII. Parse and execute + DoStr7 = "a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b; return c", io:format("----------------------------------------------------------~n"), io:format("Parse and execute 'a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b', re-using state~n"), I7 = 10000, State7 = luerl:init(), - {T7,_State71} = timer:tc(fun() -> do_loop_state(I7, "a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b; return c", State7) end), + {T7,_State71} = timer:tc(fun() -> do_loop_do(I7, DoStr7, State7) end), - io:format("Adding Up: ~p microseconds for ~p x calling Lua and returning the result of a = 7.33; b = 9000; c = (33 * a / b) ^ 15 * a + b.~n", [T7,I7]), + io:format("Adding Up: ~p microseconds for ~p x calling Lua and returning the result of '~s'.~n", [T7,I7,DoStr7]), io:format("Per call: ~p microseconds.~n", [T7/I7]), @@ -128,11 +143,16 @@ do_loop(N, Chunk) when N > 0 -> do_loop(0, _) -> ok. do_loop_state(N, Chunk, State) when N > 0 -> - luerl:do(Chunk, State), + luerl:call_chunk(Chunk, [], State), do_loop_state(N-1, Chunk, State); do_loop_state(0, _, _) -> ok. +do_loop_do(N, String, State) when N > 0 -> + {ok,_,State1} = luerl:do(String, State), + do_loop_do(N-1, String, State1); +do_loop_do(0, _, _) -> ok. + do_loop_chain(N, Chunk, State0) when N > 0 -> - {_,State1} = luerl:do(Chunk, State0), + {ok,_,State1} = luerl:call_chunk(Chunk, State0), do_loop_chain(N-1, Chunk, State1); do_loop_chain(0, _, _) -> ok. diff --git a/include/luerl.hrl b/include/luerl.hrl index 41cd5f0a..824dcac5 100644 --- a/include/luerl.hrl +++ b/include/luerl.hrl @@ -1,4 +1,4 @@ -%% Copyright (c) 2013-2019 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. @@ -25,16 +25,17 @@ envs, %Environment table usds, %Userdata table fncs, %Function table - g, %Global table - %% - stk=[], %Current stack - cs=[], %Current call stack - %% - meta=[], %Data type metatables - rand, %Random state + g, %Global table + %% + stk=[], %Current stack + cs=[], %Current call stack + %% + meta=[], %Data type metatables + rand, %Random state tag, %Unique tag trace_func=none, %Trace function - trace_data %Trace data + trace_data, %Trace data + private=#{} }). %% Table structure. @@ -46,10 +47,10 @@ %% Metatables for atomic datatypes. -record(meta, {nil=nil, - boolean=nil, - number=nil, - string=nil - }). + boolean=nil, + number=nil, + string=nil + }). %% Frames for the call stack. %% Call return frame @@ -111,10 +112,10 @@ body}). %Code block -define(IS_LUAFUNC(F), is_record(F, lua_func)). --record(erl_func,{code}). %Erlang code (fun) +-record(erl_func,{code}). %Erlang code (fun) -define(IS_ERLFUNC(F), is_record(F, erl_func)). --record(erl_mfa,{m,f,a}). %Erlang code (MFA) +-record(erl_mfa,{m,f,a}). %Erlang code (MFA) -define(IS_ERLMFA(F), is_record(F, erl_mfa)). %% Test if it a function, of either sort. @@ -145,28 +146,31 @@ -define(SET_TABLE(N, T, Ts), maps:put(N, T, Ts)). -define(UPD_TABLE(N, Upd, Ts), maps:update_with(N, Upd, Ts)). -define(DEL_TABLE(N, Ts), maps:remove(N, Ts)). +-define(CHK_TABLE(N, Ts), maps:is_key(N, Ts)). -define(FILTER_TABLES(Pred, Ts), maps:filter(Pred, Ts)). -define(FOLD_TABLES(Fun, Acc, Ts), maps:fold(Fun, Acc, Ts)). -endif. -ifdef(TS_USE_ARRAY). -%% Use arrays to handle tables. +%% Use arrays to handle tables. We leave the default value as undefined. -define(MAKE_TABLE(), array:new()). -define(GET_TABLE(N, Ar), array:get(N, Ar)). -define(SET_TABLE(N, T, Ar), array:set(N, T, Ar)). -define(UPD_TABLE(N, Upd, Ar), - array:set(N, (Upd)(array:get(N, Ar)), Ar)). + array:set(N, (Upd)(array:get(N, Ar)), Ar)). -define(DEL_TABLE(N, Ar), array:reset(N, Ar)). +-define(CHK_TABLE(N, Ar), + ((N >= 0) andalso (array:get(N, Ar) =/= undefined))). -define(FILTER_TABLES(Pred, Ar), - ((fun (___Def) -> - ___Fil = fun (___K, ___V) -> - case Pred(___K, ___V) of - true -> ___V; - false -> ___Def - end - end, - array:sparse_map(___Fil, Ar) - end)(array:default(Ar)))). + ((fun (___Def) -> + ___Fil = fun (___K, ___V) -> + case Pred(___K, ___V) of + true -> ___V; + false -> ___Def + end + end, + array:sparse_map(___Fil, Ar) + end)(array:default(Ar)))). -define(FOLD_TABLES(Fun, Acc, Ar), array:sparse_foldl(Fun, Acc, Ar)). -endif. @@ -177,6 +181,7 @@ -define(SET_TABLE(N, T, Ts), orddict:store(N, T, Ts)). -define(UPD_TABLE(N, Upd, Ts), orddict:update(N, Upd, Ts)). -define(DEL_TABLE(N, Ts), orddict:erase(N, Ts)). +-define(CHK_TABLE(N, Ts), orddict:is_key(N, Ts)). -define(FILTER_TABLES(Pred, Ts), orddict:filter(Pred, Ts)). -define(FOLD_TABLES(Fun, Acc, Ts), orddict:fold(Fun, Acc, Ts)). -endif. @@ -188,8 +193,9 @@ -define(SET_TABLE(N, T, Pd), put(N, T)). -define(UPD_TABLE(N, Upd, Pd), put(N, (Upd)(get(N)))). -define(DEL_TABLE(N, Pd), erase(N)). --define(FILTER_TABLES(Pred, Pd), Pd). %This needs work --define(FOLD_TABLES(Fun, Acc, Pd), Pd). %This needs work +-define(CHK_TABLE(N, Pd), (get(N) =/= undefined)). +-define(FILTER_TABLES(Pred, Pd), Pd). %This needs work +-define(FOLD_TABLES(Fun, Acc, Pd), Pd). %This needs work -endif. -ifdef(TS_USE_ETS). @@ -198,13 +204,13 @@ -define(GET_TABLE(N, E), ets:lookup_element(E, N, 2)). -define(SET_TABLE(N, T, E), begin ets:insert(E, {N,T}), E end). -define(UPD_TABLE(N, Upd, E), - begin ets:update_element(E, N, {2,(Upd)(ets:lookup_element(E, N, 2))}), - E end). + begin ets:update_element(E, N, {2,(Upd)(ets:lookup_element(E, N, 2))}), + E end). -define(DEL_TABLE(N, E), begin ets:delete(E, N), E end). --define(FILTER_TABLES(Pred, E), E). %This needs work +-define(FILTER_TABLES(Pred, E), E). %This needs work -define(FOLD_TABLES(Fun, Acc, E), - ets:foldl(fun ({___K, ___T}, ___Acc) -> Fun(___K, ___T, ___Acc) end, - Acc, E)). + ets:foldl(fun ({___K, ___T}, ___Acc) -> Fun(___K, ___T, ___Acc) end, + Acc, E)). -endif. %% Define CATCH to handle deprecated get_stacktrace/0 diff --git a/src/Elixir.Luerl.New.erl b/src/Elixir.Luerl.New.erl deleted file mode 100644 index 1dc4e22a..00000000 --- a/src/Elixir.Luerl.New.erl +++ /dev/null @@ -1,162 +0,0 @@ -%% Copyright (c) 2013-2021 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. - -%% File : luerl_ex.erl -%% Authors : Cees de Groot -%% Purpose : Elixir-style wrappers for luerl.erl - -%% This module just contains functions that forward to luerl.erl, but place -%% the VM State arguments in the first position rather than the last. This -%% better matches Elixir conventions and allows for using the Elixir pipe -%% operator '|>' to chain Luerl function calls. - --module('Elixir.Luerl.New'). - -%% Basic user API to luerl. --export([init/0,gc/1, - load/2,load/3,loadfile/2,loadfile/3, - 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_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_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]). - -%%Helping with storing VM state --export([externalize/1,internalize/1]). - -init() -> - luerl_new:init(). - -gc(St) -> - luerl_new:gc(St). - -set_trace_func(St, Func) -> - luerl_new:set_trace_func(Func, St). - -clear_trace_func(St) -> - luerl_new:clear_trace_func(St). - -get_trace_data(St) -> - luerl_new:get_trace_data(St). - -set_trace_data(St, Tdata) -> - luerl_new:set_trace_data(Tdata, St). - -load(St, Bin) -> - luerl_new:load(Bin, St). - -load(St, Bin, Opts) -> - luerl_new:load(Bin, Opts, St). - -loadfile(St, Name) -> - luerl_new:loadfile(Name, St). - -loadfile(St, Name, Opts) -> - luerl_new:loadfile(Name, Opts, St). - -load_module(St, Lfp, Mod) -> - luerl_new:load_module(Lfp, Mod, St). - -load_module_dec(St, Dfp, Mod) -> - luerl_new:load_module_dec(Dfp, Mod, St). - -do(St, S) -> - luerl_new:do(S, St). - -do(St, S, Opts) -> - luerl_new:do(S, Opts, St). - -do_dec(St, S) -> - luerl_new:do_dec(S, St). - -do_dec(St, S, Opts) -> - luerl_new:do_dec(S, Opts, St). - -dofile(St, Path) -> - luerl_new:dofile(Path, St). - -dofile(St, Path, Opts) -> - luerl_new:dofile(Path, Opts, St). - -dofile_dec(St, Path) -> - luerl_new:dofile_dec(Path, St). - -dofile_dec(St, Path, Opts) -> - luerl_new:dofile_dec(Path, Opts, St). - -call(St, C, Args) -> - luerl_new:call(C, Args, St). - -call_chunk(St, C) -> - luerl_new:call_chunk(C, St). - -call_chunk(St, C, Args) -> - luerl_new:call_chunk(C, Args, St). - -call_function(St, Fp, Args) -> - luerl_new:call_function(Fp, Args, St). - -call_function_dec(St, Dfunc, Dargs) -> - luerl_new:call_function_dec(Dfunc, Dargs, St). - -call_method(St, Obj, Meth, Args) -> - luerl_new:call_method(Obj, Meth, Args, St). - -call_method_dec(St, Dobj, Dmeth, Dargs) -> - luerl_new:call_method_dec(Dobj, Dmeth, Dargs, St). - -get_table_keys(St, Keys) -> - luerl_new:get_table_keys(Keys, St). - -get_table_keys_dec(St, Dkeys) -> - luerl_new:get_table_keys_dec(Dkeys, St). - -set_table_keys(St, Keys, Val) -> - luerl_new:set_table_keys(Keys, Val, St). - -set_table_keys_dec(St, Dkeys, Dval) -> - luerl_new:set_table_keys_dec(Dkeys, Dval, St). - -get_stacktrace(St) -> - luerl_new:get_stacktrace(St). - -encode(St, V) -> - luerl_new:encode(V, St). - -encode_list(St, Ts) -> - luerl_new:encode_list(Ts, St). - -decode(St, V) -> - luerl_new:decode(V, St). - -decode_list(St, Lts) -> - luerl_new:decode_list(Lts, St). - -externalize(St) -> - luerl_new:externalize(St). - -internalize(St) -> - luerl_new:internalize(St). diff --git a/src/Elixir.Luerl.Old.erl b/src/Elixir.Luerl.Old.erl new file mode 100644 index 00000000..03fffff1 --- /dev/null +++ b/src/Elixir.Luerl.Old.erl @@ -0,0 +1,164 @@ +%% 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. +%% 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. + +%% File : luerl_ex.erl +%% Authors : Cees de Groot +%% Purpose : Elixir-style wrappers for luerl_old.erl + +%% This module just contains functions that forward to luerl_old.erl, +%% but place the VM State arguments in the first position rather than +%% the last. This better matches Elixir conventions and allows for +%% using the Elixir pipe operator '|>' to chain Luerl function calls. + +-module('Elixir.Luerl.Old'). + +-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]). + +eval(St, Chunk) -> + luerl_old:eval(Chunk, St). + +evalfile(St, Path) -> + luerl_old:evalfile(Path, St). + +do(St, S) -> + luerl_old:do(S, St). + +dofile(St, Path) -> + luerl_old:dofile(Path, St). + +load(St, Bin) -> + luerl_old:load(Bin, St). + +load(St, Bin, Opts) -> + luerl_old:load(Bin, Opts, St). + +loadfile(St, Name) -> + luerl_old:loadfile(Name, St). + +loadfile(St, Name, Opts) -> + luerl_old:loadfile(Name, Opts, St). + +path_loadfile(St, Name) -> + luerl_old:path_loadfile(Name, St). + +path_loadfile(St, Dirs, Name) -> + luerl_old:path_loadfile(Dirs, Name, St). + +path_loadfile(St, Dir, Name, Opts) -> + luerl_old:path_loadfile(Dir, Name, Opts, St). + +load_module(St, Fp, Mod) -> + luerl_old:load_module(Fp, Mod, St). + +load_module1(St, Fp, Mod) -> + luerl_old:load_module1(Fp, Mod, St). + +init() -> + luerl_old:init(). + +call(St, C, As) -> + luerl_old:call(C, As, St). + +call_chunk(St, C, As) -> + luerl_old:call_chunk(C, As, St). + +call_function(St, Fp, As) -> + luerl_old:call_function(Fp, As, St). + +call_function1(St, Lfp, Las) -> + luerl_old:call_function1(Lfp, Las, St). + +function_list(St, Ks) -> + luerl_old:function_list(Ks, St). + +call_method(St, Fp, As) -> + luerl_old:call_method(Fp, As, St). + +call_method1(St, Fp, Las) -> + luerl_old:call_method1(Fp, Las, St). + +method_list(St, Ks) -> + luerl_old:method_list(Ks, St). + +get_table(St, Fp) -> + luerl_old:get_table(Fp, St). + +get_table1(St, Fp) -> + luerl_old:get_table1(Fp, St). + +set_table(St, Fp, V) -> + luerl_old:set_table(Fp, V, St). + +set_table1(St, Lfp, Lv) -> + luerl_old:set_table1(Lfp, Lv, St). + +set_table1(St, Tab, Key, Lv) -> + luerl_old:set_table1(Tab, Key, Lv, St). + +stop(St) -> + luerl_old:stop(St). + +gc(St) -> + luerl_old:gc(St). + +set_trace_func(St, Func) -> + luerl_old:set_trace_func(Func, St). + +clear_trace_func(St) -> + luerl_old:clear_trace_func(St). + +get_trace_data(St) -> + luerl_old:get_trace_data(St). + +set_trace_data(St, Tdata) -> + luerl_old:set_trace_data(Tdata, St). + +get_stacktrace(St) -> + luerl_old:get_stacktrace(St). + +encode_list(St, Ts) -> + luerl_old:encode_list(Ts, St). + +encode(St, V) -> + luerl_old:encode(V, St). + +decode_list(St, Lts) -> + luerl_old:decode_list(Lts, St). + +decode(St, V) -> + luerl_old:decode(V, St). + +externalize(St) -> + luerl_old_new:externalize(St). + +internalize(St) -> + luerl_old_new:internalize(St). diff --git a/src/Elixir.Luerl.erl b/src/Elixir.Luerl.erl index 03d01037..c13e56d0 100644 --- a/src/Elixir.Luerl.erl +++ b/src/Elixir.Luerl.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. @@ -23,39 +23,54 @@ -module('Elixir.Luerl'). --export([eval/2,evalfile/2, - do/2,dofile/2, - load/2,load/3, - loadfile/2,loadfile/3, +-include("luerl.hrl"). + +%% 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_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, + 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]). %%Helping with storing VM state -export([externalize/1,internalize/1]). -eval(St, Chunk) -> - luerl:eval(Chunk, St). +%% Storing and retrieving private data +-export([put_private/3,get_private/2,delete_private/2]). -evalfile(St, Path) -> - luerl:evalfile(Path, St). +init() -> + luerl:init(). -do(St, S) -> - luerl:do(S, St). +gc(St) -> + luerl:gc(St). -dofile(St, Path) -> - luerl:dofile(Path, St). +set_trace_func(St, Func) -> + luerl:set_trace_func(Func, St). + +clear_trace_func(St) -> + luerl:clear_trace_func(St). + +get_trace_data(St) -> + luerl:get_trace_data(St). + +set_trace_data(St, Tdata) -> + luerl:set_trace_data(Tdata, St). load(St, Bin) -> luerl:load(Bin, St). @@ -69,98 +84,118 @@ loadfile(St, Name) -> loadfile(St, Name, Opts) -> luerl:loadfile(Name, Opts, St). +path_loadfile(St, Path, Name) -> + luerl:path_loadfile(Path, Name, St). + +path_loadfile(St, Path, Name, Options) -> + luerl:path_loadfile(Path, Name, Options, St). + path_loadfile(St, Name) -> luerl:path_loadfile(Name, St). -path_loadfile(St, Dirs, Name) -> - luerl:path_loadfile(Dirs, Name, St). +load_module(St, Lfp, Mod) -> + luerl:load_module(Lfp, Mod, St). -path_loadfile(St, Dir, Name, Opts) -> - luerl:path_loadfile(Dir, Name, Opts, St). +load_module_dec(St, Dfp, Mod) -> + luerl:load_module_dec(Dfp, Mod, St). -load_module(St, Fp, Mod) -> - luerl:load_module(Fp, Mod, St). +do(St, S) -> + luerl:do(S, St). -load_module1(St, Fp, Mod) -> - luerl:load_module1(Fp, Mod, St). +do(St, S, Opts) -> + luerl:do(S, Opts, St). -init() -> - luerl:init(). +do_dec(St, S) -> + luerl:do_dec(S, St). -call(St, C, As) -> - luerl:call(C, As, St). +do_dec(St, S, Opts) -> + luerl:do_dec(S, Opts, St). -call_chunk(St, C, As) -> - luerl:call_chunk(C, As, St). +dofile(St, Path) -> + luerl:dofile(Path, St). -call_function(St, Fp, As) -> - luerl:call_function(Fp, As, St). +dofile(St, Path, Opts) -> + luerl:dofile(Path, Opts, St). -call_function1(St, Lfp, Las) -> - luerl:call_function1(Lfp, Las, St). +dofile_dec(St, Path) -> + luerl:dofile_dec(Path, St). -function_list(St, Ks) -> - luerl:function_list(Ks, St). +dofile_dec(St, Path, Opts) -> + luerl:dofile_dec(Path, Opts, St). -call_method(St, Fp, As) -> - luerl:call_method(Fp, As, St). +call(St, C, Args) -> + luerl:call(C, Args, St). -call_method1(St, Fp, Las) -> - luerl:call_method1(Fp, Las, St). +call_chunk(St, C) -> + luerl:call_chunk(C, St). -method_list(St, Ks) -> - luerl:method_list(Ks, St). +call_chunk(St, C, Args) -> + luerl:call_chunk(C, Args, St). -get_table(St, Fp) -> - luerl:get_table(Fp, St). +call_function(St, Fp, Args) -> + luerl:call_function(Fp, Args, St). -get_table1(St, Fp) -> - luerl:get_table1(Fp, St). +call_function_enc(St, Dfunc, Dargs) -> + luerl:call_function_enc(Dfunc, Dargs, St). -set_table(St, Fp, V) -> - luerl:set_table(Fp, V, St). +call_function_dec(St, Dfunc, Dargs) -> + luerl:call_function_dec(Dfunc, Dargs, St). -set_table1(St, Lfp, Lv) -> - luerl:set_table1(Lfp, Lv, St). +call_method(St, Obj, Meth, Args) -> + luerl:call_method(Obj, Meth, Args, St). -set_table1(St, Tab, Key, Lv) -> - luerl:set_table1(Tab, Key, Lv, St). +call_method_dec(St, Dobj, Dmeth, Dargs) -> + luerl:call_method_dec(Dobj, Dmeth, Dargs, St). -stop(St) -> - luerl:stop(St). +get_table_keys(St, Keys) -> + luerl:get_table_keys(Keys, St). -gc(St) -> - luerl:gc(St). +get_table_keys_dec(St, Dkeys) -> + luerl:get_table_keys_dec(Dkeys, St). -set_trace_func(St, Func) -> - luerl:set_trace_func(Func, St). +set_table_keys(St, Keys, Val) -> + luerl:set_table_keys(Keys, Val, St). -clear_trace_func(St) -> - luerl:clear_trace_func(St). +set_table_keys_dec(St, Dkeys, Dval) -> + luerl:set_table_keys_dec(Dkeys, Dval, St). -get_trace_data(St) -> - luerl:get_trace_data(St). +get_table_key(St, Tab, Key) -> + luerl:get_table_key(Tab, Key, St). -set_trace_data(St, Tdata) -> - luerl:set_trace_data(Tdata, St). +set_table_key(St, Tab, Key, Val) -> + luerl:set_table_key(Tab, Key, Val, St). get_stacktrace(St) -> luerl:get_stacktrace(St). -encode_list(St, Ts) -> - luerl:encode_list(Ts, St). - encode(St, V) -> luerl:encode(V, St). -decode_list(St, Lts) -> - luerl:decode_list(Lts, St). +encode_list(St, Ts) -> + luerl:encode_list(Ts, St). decode(St, V) -> luerl:decode(V, St). +decode_list(St, Lts) -> + luerl:decode_list(Lts, St). + externalize(St) -> - luerl_new:externalize(St). + luerl:externalize(St). internalize(St) -> - luerl_new:internalize(St). + luerl:internalize(St). + +put_private(St, K, V) -> + luerl:put_private(K, V, St). + +get_private(St, Key) -> + maps:get(Key, St#luerl.private, nil). + +delete_private(St, K) -> + try + luerl:delete_private(K, St) + catch + error:{badkey, _} -> + St + end. diff --git a/src/luerl.erl b/src/luerl.erl index aebcd354..5f92f100 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,97 @@ %% 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. +%% Storing and retrieving private data +-export([put_private/3,get_private/2,delete_private/2]). + +%% 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 +115,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,156 +132,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. - {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). +%% 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}]}]. @@ -344,44 +402,41 @@ 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(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), + %% Encode the table elements in the list. + EncTab = 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, + {Es,{_,St1}} = lists:mapfoldl(EncTab, {1,St0}, L), {T,St2} = luerl_heap:alloc_table(Es, St1), - {T,St2}; %No more to do for now + {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, + 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) -> - Args1 = decode_list(Args, State), - Res = F(Args1), - encode_list(Res, State) - end, + 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); -% 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(_, _) -> error(badarg). %Can't encode anything else +%% % 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. @@ -398,42 +453,53 @@ 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(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(_, _, _) -> error(badarg). %Shouldn't have anything else +decode(#usdref{}=U, St, In) -> + decode_userdata(U, St, In); +decode(#funref{}=Fun, St, In) -> + decode_luafunc(Fun, St, In); +decode(#erl_func{}=Fun, St, In) -> + decode_erlfunc(Fun, St, In); +decode(#erl_mfa{}=Mfa, St, In) -> + decode_erlmfa(Mfa, St, In); +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 + 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) -> +decode_userdata(U, St, _In) -> {#userdata{d=Data},_} = luerl_heap:get_userdata(U, St), {userdata,Data}. +decode_luafunc(Fun, _St, _In) -> + %% io:format("dec ~p\n", [Fun]), + fun(Args, State) -> + luerl_emul:functioncall(Fun, Args, State) + end. + +decode_erlfunc(#erl_func{code=Fun}=_Ef, _St, _In) -> + %% io:format("dec ~p\n", [Ef]), + Fun. %Just the bare fun + +decode_erlmfa(#erl_mfa{m=Mod,f=Func,a=Arg}=_Mfa, _St, _In) -> + %% io:format("mfa ~p\n", [Mfa]), + {Mod,Func,Arg}. + %% 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. @@ -443,3 +509,20 @@ externalize(S) -> internalize(S) -> luerl_lib_math:internalize(S). + +%% put_private(Key, Value, State) -> +%% State. +%% get_private(Key, State) -> +%% Value. +%% delete_private(Key, State) -> +%% Value. +put_private(Key, Value, S) -> + Private = maps:put(Key, Value, S#luerl.private), + S#luerl{private=Private}. + +get_private(Key, S) -> + maps:get(Key, S#luerl.private). + +delete_private(Key, S) -> + Private = maps:remove(Key, S#luerl.private), + S#luerl{private=Private}. diff --git a/src/luerl.hrl b/src/luerl.hrl index 21ce2762..824dcac5 100644 --- a/src/luerl.hrl +++ b/src/luerl.hrl @@ -34,7 +34,8 @@ rand, %Random state tag, %Unique tag trace_func=none, %Trace function - trace_data %Trace data + trace_data, %Trace data + private=#{} }). %% Table structure. diff --git a/src/luerl_emul.erl b/src/luerl_emul.erl index d7e6cd38..6e26f6b2 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. @@ -304,15 +304,15 @@ load_chunk_i(I, Funrs, St) -> {I,Funrs,St}. call(Func, St) -> call(Func, [], St). -call(#funref{}=Funref, Args, St0) -> %Lua function +call(#funref{}=Funref, Args, St0) -> %Lua function {Ret,St1} = functioncall(Funref, Args, St0), %% Should do GC here. {Ret,St1}; -call(#erl_func{}=Func, Args, St0) -> %Erlang function +call(#erl_func{}=Func, Args, St0) -> %Erlang function {Ret,St1} = functioncall(Func, Args, St0), %% Should do GC here. {Ret,St1}; -call(#erl_mfa{}=Func, Args, St0) -> %Erlang function as MFA triplet +call(#erl_mfa{}=Func, Args, St0) -> %Erlang function as MFA triplet {Ret,St1} = functioncall(Func, Args, St0), {Ret,St1}. @@ -791,7 +791,7 @@ call_luafunc(#lua_func{lsz=Lsz,esz=Esz,pars=_Pars,body=Fis}, call_erlfunc(Func, Args, Stk, Cs0, #luerl{stk=Stk0}=St0) -> case Func(Args, St0#luerl{stk=Stk,cs=Cs0}) of %% {Ret,#luerl{}=St1} when is_list(Ret) -> - {Ret,St1} -> + {Ret,St1} when is_list(Ret) -> [#call_frame{is=Is,cont=Cont,lvs=Lvs,env=Env}|Cs1] = Cs0, emul(Is, Cont, Lvs, [Ret|Stk], Env, Cs1, St1#luerl{stk=Stk0,cs=Cs1}); _Other -> @@ -807,7 +807,7 @@ call_erlfunc(Func, Args, Stk, Cs0, #luerl{stk=Stk0}=St0) -> call_erlmfa({M,F,A}, Args, Stk, Cs0, #luerl{stk=Stk0}=St0) -> case apply(M, F, [A, Args, St0#luerl{stk=Stk,cs=Cs0}]) of - {Ret,St1} -> + {Ret,St1} when is_list(Ret) -> [#call_frame{is=Is,cont=Cont,lvs=Lvs,env=Env}|Cs1] = Cs0, emul(Is, Cont, Lvs, [Ret|Stk], Env, Cs1, St1#luerl{stk=Stk0,cs=Cs1}); _Other -> diff --git a/src/luerl_new.erl b/src/luerl_new.erl deleted file mode 100644 index 22185b14..00000000 --- a/src/luerl_new.erl +++ /dev/null @@ -1,466 +0,0 @@ -%% Copyright (c) 2020-2021 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. - -%% File : luerl_new.erl -%% Authors : Robert Virding -%% Purpose : The new basic LUA 5.3 interface. - --module(luerl_new). - --include("luerl.hrl"). - -%% 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_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_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]). - -%% Helping with storing VM state --export([externalize/1,internalize/1]). - -%% init() -> State. - -init() -> - luerl_emul:init(). - -%% 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}. - -%% 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) -> - case luerl_comp:string(Str, Opts) of - {ok,Chunk} -> - {FunRef,St1} = luerl_emul:load_chunk(Chunk, St0), - {ok,FunRef,St1}; - Error -> %Compile error - Error - end. - -%% 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 -> Error - 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,_} -> ";"; %Windows - _ -> ":" %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(LuaTablePath, ModuleName, State) -> State. -%% Load module and add module table to the path. - -load_module([_|_] = Lfp, Mod, St0) -> - {Tab,St1} = Mod:install(St0), - luerl_emul:set_table_keys(Lfp, Tab, St1); -load_module(_, _, _) -> - error(badarg). - -%% load_module_dec(DecodedTablePath, ModuleName, State) -> State. -%% Load module and add module table to the path. - -load_module_dec([_|_] = Dfp, Mod, St0) -> - {Efp,St1} = encode_list(Dfp, St0), - load_module(Efp, Mod, St1); -load_module_dec(_, _, _) -> - error(badarg). - -%% luerl:do(String|Binary|Form, State) -> -%% luerl:do(String|Binary|Form, CompileOptions, State) -> -%% {ok,Result,NewState} | {lua_error,Error,State}. - -do(S, St) -> do(S, [return], St). - -do(S, Opts, St0) -> - case load(S, Opts, St0) of - {ok,Func,St1} -> - call_function(Func, [], St1); - Error -> Error - end. - -do_dec(S, St) -> - do_dec(S, [return], St). - -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, Args, State) -> -%% {ok,LuaReturn,State} | {lua_error,Error,State}. - -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_dec(DecodedFuncRef, Args, State) -> -%% {ok,DecodedReturn,State} | {lua_error,Error,State}. - -call_function_dec(Dtpath, Dargs, St0) -> - {ok,Efunc,St1} = get_table_keys_dec(Dtpath, St0), - {Eargs,St2} = encode_list(Dargs, St1), - case call_function(Efunc, Eargs, St2) of - {ok,Eret,St3} -> - {ok,decode_list(Eret, St3),St3}; - 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,Return,State} | {lua_error,Error,State}. - -get_table_keys(Keys, St0) -> - try - {Ret,St1} = luerl_emul:get_table_keys(Keys, St0), - {ok,Ret,St1} - catch - error:{lua_error,_E,_St} = LuaErr -> - LuaErr - end. - -get_table_keys_dec(Dkeys, St0) -> - {Ekeys,St1} = encode_list(Dkeys, St0), - get_table_keys(Ekeys, St1). - -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_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) -> - %% Encode the table elements in the list. - EncTab = 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, - {Es,{_,St1}} = lists:mapfoldl(EncTab, {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(_, _) -> error(badarg). %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(_, _, _) -> error(badarg). %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. - -externalize(S) -> - luerl_lib_math:externalize(S). - -internalize(S) -> - luerl_lib_math:internalize(S). diff --git a/src/luerl_old.erl b/src/luerl_old.erl index b978067d..f3e90d3c 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/src/luerl_sandbox.erl b/src/luerl_sandbox.erl index 37c8d501..f186551d 100644 --- a/src/luerl_sandbox.erl +++ b/src/luerl_sandbox.erl @@ -67,7 +67,7 @@ init(St) -> init(St, []) -> luerl:gc(St); init(St0, [Path|Tail]) -> - St1 = luerl:set_table(Path, ?SANDBOXED_VALUE, St0), + {ok,St1} = luerl:set_table_keys_dec(Path, ?SANDBOXED_VALUE, St0), init(St1, Tail). %% The default flags for running the sandboxed process. diff --git a/test/Elixir.Luerl_tests.erl b/test/Elixir.Luerl_tests.erl new file mode 100644 index 00000000..dd392a48 --- /dev/null +++ b/test/Elixir.Luerl_tests.erl @@ -0,0 +1,25 @@ +%% 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('Elixir.Luerl_tests'). + +-include_lib("eunit/include/eunit.hrl"). + +private_test() -> + State1 = 'Elixir.Luerl':init(), + State2 = 'Elixir.Luerl':put_private(State1, secret, <<"mysecret">>), + ?assertMatch(<<"mysecret">>, 'Elixir.Luerl':get_private(State2, secret)), + ?assertMatch(nil, 'Elixir.Luerl':get_private(State2, missing)), + State3 = 'Elixir.Luerl':delete_private(State2, secret), + ?assertMatch(nil, 'Elixir.Luerl':get_private(State3, secret)). diff --git a/test/lib_os_SUITE.erl b/test/lib_os_SUITE.erl index 0647fbbe..ef0417db 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 5b37c13c..c6ef699f 100644 --- a/test/luerl_funcall_tests.erl +++ b/test/luerl_funcall_tests.erl @@ -23,86 +23,91 @@ external_fun_test() -> State = luerl:init(), - F = fun([A], S) -> - {[A + 2, [A + 3, A + 4]], S} - end, - State1 = luerl:set_table([<<"testFun">>], F, State), - {_, State2} = luerl: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:call_function([test], [2], State2), - [BoolVal, BoolVal2, BoolVal3] = Res, - ?assertEqual(true, BoolVal), - ?assertEqual(true, BoolVal2), - ?assertEqual(true, BoolVal3). - -external_nostate_fun_test() -> - State = luerl:init(), - F = fun([A]) -> - [A + 2, [A + 3, A + 4]] - end, - State1 = luerl:set_table([<<"testFun">>], F, State), + F = fun(Args, S) -> + %% Must decode the args and encode the return value. + [A] = luerl:decode_list(Args, S), + luerl:encode_list([A + 2, [A + 3, A + 4]], S) + end, + {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), - [BoolVal, BoolVal2, BoolVal3] = Res, + " local a, b = testFun(i)\n" + " return (a == i + 2), (b[1] == i + 3), (b[2] == i + 4)\n" + "end">>, + {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), ?assertEqual(true, BoolVal3). 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). define_fun_in_lua_test() -> State = luerl: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:do(Chunk, State), - {[Fun], _State2} = luerl:call_function([mkadder], [1], State1), - {[Fun2], _State3} = luerl:call_function([mkadder], [2], State1), - ?assertEqual([5], Fun([4])), - ?assertEqual([5.0], Fun([4.0])), - ?assertEqual([6], Fun2([4])). + " return function(i)\n" + " print(\"Call into Luerl!\")\n" + " return i + incby\n" + " end\n" + "end\n">>, + {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)), + ?assertMatch({[5.0],_}, Fun2([4.0], State2)), + ?assertMatch({[6], _}, Fun3([4], State3)). define_fun2_in_lua_test() -> State = luerl: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:do(Chunk, State), - {[Fun], _State2} = luerl:call_function([mklist], [5], State1), - {[Fun2], _State3} = luerl: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])). + " 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">>, + {ok, _, State1} = luerl:do(Chunk, State), + + %% 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} = 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)), + + {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}]], + luerl:decode_list(Res3, State31)). newindex_metamethod_test() -> State = luerl: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:do(Chunk, State), + "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]">>, + {ok, [TVal, MVal], _State1} = luerl:do_dec(Chunk, State), ?assertEqual(456, TVal), ?assertEqual(nil, MVal). diff --git a/test/luerl_new_tests.erl b/test/luerl_new_tests.erl deleted file mode 100644 index 17c647a6..00000000 --- a/test/luerl_new_tests.erl +++ /dev/null @@ -1,26 +0,0 @@ -- module(luerl_new_tests). - --include_lib("eunit/include/eunit.hrl"). - -encode_test() -> - State = luerl_new:init(), - ?assertMatch({nil, _State}, luerl_new:encode(nil, State)), - ?assertMatch({false, _State}, luerl_new:encode(false, State)), - ?assertMatch({true, _State}, luerl_new:encode(true, State)), - ?assertMatch({<<"binary">>, _State}, luerl_new:encode(<<"binary">>, State)), - ?assertMatch({<<"atom">>, _State}, luerl_new:encode(atom, State)), - ?assertMatch({5, _State}, luerl_new:encode(5, State)), - ?assertMatch({{tref, _}, _State}, luerl_new:encode(#{a => 1, b => 2}, State)). - -encode_map_test() -> - ?assertMatch({{tref, _}, _State}, luerl_new:encode(#{a => 1}, luerl_new:init())). - -encode_table_test() -> - {Table, State} = luerl_new:encode(#{a => 1}, luerl_new:init()), - {ok, [], State1} = luerl_new:set_table_keys([<<"foo">>], Table, State), - ?assertMatch({ok, Table, _State2}, luerl_new:get_table_keys([<<"foo">>], State1)), - ?assertMatch({tref, _}, Table), - ?assertMatch({Table, _State}, luerl_new:encode(Table, State1)). - -invalid_table_test() -> - ?assertException(error, badarg, luerl_new:encode({tref, 42}, luerl_new:init())). diff --git a/test/luerl_old_funcall_tests.erl b/test/luerl_old_funcall_tests.erl new file mode 100644 index 00000000..2be2c24c --- /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 00000000..2778187f --- /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_old: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 07cb30c6..1bd41a85 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 624d95c1..dc026eb6 100644 --- a/test/luerl_tests.erl +++ b/test/luerl_tests.erl @@ -1,4 +1,18 @@ -- module(luerl_tests). +%% 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"). @@ -10,15 +24,29 @@ encode_test() -> ?assertMatch({<<"binary">>, _State}, luerl:encode(<<"binary">>, State)), ?assertMatch({<<"atom">>, _State}, luerl:encode(atom, State)), ?assertMatch({5, _State}, luerl:encode(5, State)), - ?assertMatch({{tref, _}, _State}, luerl:encode(#{a => 1, b => 2}, State)). + ?assertMatch({{tref, _}, _State}, luerl:encode(#{a => 1, b => 2}, State)), + ?assertMatch({{tref, _}, _State}, luerl:encode([{a,1},{b,2}], State)). -encode_map_test() -> - ?assertMatch({{tref, _}, _State}, luerl:encode(#{a => 1}, luerl:init())). +encode_error_test() -> + State = luerl:init(), + ?assertException(error, {badarg, _}, luerl:encode({a,1}, State)). encode_table_test() -> {Table, State} = luerl:encode(#{a => 1}, luerl:init()), - ?assertMatch({tref, _}, Table), - ?assertMatch({Table, _State}, luerl:encode(Table, State)). + {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() -> + State = luerl:init(), + ?assertException(error, {badarg, {invalid, value}}, + luerl:encode({invalid, value}, State)). -invalid_table_test() -> - ?assertException(error, badarg, luerl:encode({tref, 42}, luerl:init())). +private_test() -> + State1 = luerl:init(), + State2 = luerl:put_private(secret, <<"mysecret">>, State1), + ?assertMatch(<<"mysecret">>, luerl:get_private(secret, State2)), + ?assertException(error, {badkey, missing}, luerl:get_private(missing, State2)), + State3 = luerl:delete_private(secret, State2), + ?assertException(error, {badkey, secret}, luerl:get_private(secret, State3)). diff --git a/test/luerl_time_SUITE.erl b/test/luerl_time_SUITE.erl index 40c44490..582a83df 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.