Fix/lua no funcs known (#15)

* lua fixes:

- fix lua function calling, didn't work in the last
releases (regression)
- add lua funcs which don't modify the stack (for converters etc)
- added better lua examples
This commit is contained in:
T.v.Dein
2023-11-08 19:03:37 +01:00
committed by GitHub
parent 31a0ddd547
commit a964a99f3d
8 changed files with 91 additions and 38 deletions

View File

@@ -225,10 +225,15 @@ the `register()` function to register your functions to the
calculator. This function takes these parameters: calculator. This function takes these parameters:
- function name - function name
- number of arguments expected (1,2 or -1 allowed), -1 means batch - number of arguments expected (see below)
mode
- help text - help text
Number of expected arguments can be:
- 0: expect 1 argument but do NOT modify the stack
- 1-n: do a singular calculation
- -1: batch mode work with all numbers on the stack
Please [refer to the lua language Please [refer to the lua language
reference](https://www.lua.org/manual/5.4/) for more details about reference](https://www.lua.org/manual/5.4/) for more details about
LUA. LUA.

24
calc.go
View File

@@ -151,16 +151,16 @@ func NewCalc() *Calc {
// pre-calculate mode switching arrays // pre-calculate mode switching arrays
c.Constants = strings.Split(Constants, " ") c.Constants = strings.Split(Constants, " ")
for name := range LuaFuncs {
c.LuaFunctions = append(c.LuaFunctions, name)
}
return &c return &c
} }
// setup the interpreter, called from main() // setup the interpreter, called from main(), import lua functions
func (c *Calc) SetInt(I *Interpreter) { func (c *Calc) SetInt(I *Interpreter) {
c.interpreter = I c.interpreter = I
for name := range LuaFuncs {
c.LuaFunctions = append(c.LuaFunctions, name)
}
} }
func (c *Calc) ToggleDebug() { func (c *Calc) ToggleDebug() {
@@ -448,6 +448,8 @@ func (c *Calc) luafunc(funcname string) {
var err error var err error
switch c.interpreter.FuncNumArgs(funcname) { switch c.interpreter.FuncNumArgs(funcname) {
case 0:
fallthrough
case 1: case 1:
x, err = c.interpreter.CallLuaFunc(funcname, c.stack.Last()) x, err = c.interpreter.CallLuaFunc(funcname, c.stack.Last())
case 2: case 2:
@@ -465,7 +467,15 @@ func (c *Calc) luafunc(funcname string) {
c.stack.Backup() c.stack.Backup()
dopush := true
switch c.interpreter.FuncNumArgs(funcname) { switch c.interpreter.FuncNumArgs(funcname) {
case 0:
a := c.stack.Last()
if len(a) == 1 {
c.History("%s(%f) = %f", funcname, a, x)
}
dopush = false
case 1: case 1:
a := c.stack.Pop() a := c.stack.Pop()
c.History("%s(%f) = %f", funcname, a, x) c.History("%s(%f) = %f", funcname, a, x)
@@ -478,7 +488,9 @@ func (c *Calc) luafunc(funcname string) {
c.History("%s(*) = %f", funcname, x) c.History("%s(*) = %f", funcname, x)
} }
c.stack.Push(x) if dopush {
c.stack.Push(x)
}
c.Result() c.Result()
} }

38
example.lua Normal file
View File

@@ -0,0 +1,38 @@
-- simple function, return the lower number of the two operands
function lower(a,b)
if a < b then
return a
else
return b
end
end
-- calculate parallel resistance. Batch function (registered with -1,
-- see below). Takes a table as parameter.
--
-- Formula: 1/( (1/R1) + (1/R2) + ...)
function parallelresistance(list)
sumres = 0
for i, value in ipairs(list) do
sumres = sumres + 1 / value
end
return 1 / sumres
end
-- converter example
function inch2centimeter(inches)
return inches * 2.54
end
function init()
-- expects 2 args
register("lower", 2, "lower")
-- expects a list of all numbers on the stack, batch mode
register("parallelresistance", -1, "parallel resistance")
-- expects 1 arg, but doesn't pop()
register("inch2centimeter", 0)
end

View File

@@ -25,7 +25,8 @@ import (
) )
type Interpreter struct { type Interpreter struct {
debug bool debug bool
script string
} }
// LUA interpreter, instanciated in main() // LUA interpreter, instanciated in main()
@@ -42,8 +43,12 @@ type LuaFunction struct {
// have access to the interpreter instance // have access to the interpreter instance
var LuaFuncs map[string]LuaFunction var LuaFuncs map[string]LuaFunction
func NewInterpreter(script string, debug bool) *Interpreter {
return &Interpreter{debug: debug, script: script}
}
// initialize the lua environment properly // initialize the lua environment properly
func InitLua(config string, debug bool) *Interpreter { func (i *Interpreter) InitLua() {
// we only load a subset of lua Open modules and don't allow // we only load a subset of lua Open modules and don't allow
// net, system or io stuff // net, system or io stuff
for _, pair := range []struct { for _, pair := range []struct {
@@ -66,7 +71,7 @@ func InitLua(config string, debug bool) *Interpreter {
} }
// load the lua config (which we expect to contain init() and math functions) // load the lua config (which we expect to contain init() and math functions)
if err := L.DoFile(config); err != nil { if err := L.DoFile(i.script); err != nil {
panic(err) panic(err)
} }
@@ -84,8 +89,6 @@ func InitLua(config string, debug bool) *Interpreter {
}); err != nil { }); err != nil {
panic(err) panic(err)
} }
return &Interpreter{debug: debug}
} }
func (i *Interpreter) Debug(msg string) { func (i *Interpreter) Debug(msg string) {
@@ -113,6 +116,8 @@ func (i *Interpreter) CallLuaFunc(funcname string, items []float64) (float64, er
funcname, LuaFuncs[funcname].numargs)) funcname, LuaFuncs[funcname].numargs))
switch LuaFuncs[funcname].numargs { switch LuaFuncs[funcname].numargs {
case 0:
fallthrough
case 1: case 1:
// 1 arg variant // 1 arg variant
if err := L.CallByParam(lua.P{ if err := L.CallByParam(lua.P{

View File

@@ -30,7 +30,7 @@ import (
lua "github.com/yuin/gopher-lua" lua "github.com/yuin/gopher-lua"
) )
const VERSION string = "2.0.5" const VERSION string = "2.0.6"
const Usage string = `This is rpn, a reverse polish notation calculator cli. const Usage string = `This is rpn, a reverse polish notation calculator cli.
@@ -98,8 +98,9 @@ func main() {
// our config file is interpreted as lua code, only functions can // our config file is interpreted as lua code, only functions can
// be defined, init() will be called by InitLua(). // be defined, init() will be called by InitLua().
if _, err := os.Stat(configfile); err == nil { if _, err := os.Stat(configfile); err == nil {
I := InitLua(configfile, enabledebug) luarunner := NewInterpreter(configfile, enabledebug)
calc.SetInt(I) luarunner.InitLua()
calc.SetInt(luarunner)
} }
if len(flag.Args()) > 1 { if len(flag.Args()) > 1 {

10
rpn.go
View File

@@ -210,7 +210,6 @@ COMMENTS
In this case only 123 will be added to the stack. In this case only 123 will be added to the stack.
VARIABLES VARIABLES
You can register the last item of the stack into a variable. Variable You can register the last item of the stack into a variable. Variable
names must be all caps. Use the ">NAME" command to put a value into names must be all caps. Use the ">NAME" command to put a value into
@@ -245,8 +244,13 @@ EXTENDING RPN USING LUA
* function name * function name
* number of arguments expected (1,2 or -1 allowed), -1 means batch * number of arguments expected (see below)
mode.
Number of expected arguments can be:
- 0: expect 1 argument but do NOT modify the stack
- 1-n: do a singular calculation
- -1: batch mode work with all numbers on the stack
* help text * help text

View File

@@ -273,8 +273,13 @@ function name
=item * =item *
number of arguments expected (1,2 or -1 allowed), -1 means batch number of arguments expected (see below)
mode.
Number of expected arguments can be:
- 0: expect 1 argument but do NOT modify the stack
- 1-n: do a singular calculation
- -1: batch mode work with all numbers on the stack
=item * =item *

View File

@@ -1,17 +0,0 @@
function add(a,b)
return a + b
end
function test(a)
return a
end
function parallelresistance(a,b)
return 1.0 / (a * b)
end
function init()
register("add", 2, "addition")
register("test", 1, "test")
register("parallelresistance", 2, "parallel resistance")
end