NJ is a simple script engine written in golang with Lua-like syntax.
(If you are looking for a Lua 5.2 compatible engine, refer to tag v0.2)
- There is no
table, instead there arearrayandobjectrespectively:a=[1, 2, 3].a={a=1, b=2}.- Empty array and empty object are
truewhen used as booleans.
- There are
typedarray anduntypedarray:- Untyped arrays are generic arrays created by
[...], it is the builtin array type. - Typed arrays are special arrays created by Go, say
[]byte:a = bytes(16)creates a 16-byte long[]byte.a.append(1)appends 1 to it.a.append(true)will panic.a.untype().append(true)willuntypethe array into a (new) generic array.
- Untyped arrays are generic arrays created by
- Functions are callable objects:
function foo() end; assert(type(foo), "object")function foo() end; assert(foo is callable)
- Closures are created by capturing all symbols seen in the current scope and binding them to the returned function:
function foo(a, b) return function(c) return self.a + self.b + c end endassert(foo(1, 2)(3), 6)
- Syntax of calling functions strictly requires no spaces between the callee and '(':
print(1)is the only right way of calling a function.print (1)literally means two things: 1) get value ofprintand discard it, 2) evaluate(1).- Also note that all required arguments must be provided to call a function properly:
function foo(a, b) end; foo(1)is invalid.
- Spacing rule also applies to unary operator
-:a = 1-a <=> a = 1 - ameans assign the result of1-atoa.a = 1 -ameans assign1toaand negatea.a = 1 -a+1means assign1toaand eval-a+1.a = -ameans negateaand assign the result toa.a = - ais invalid.
- There are two ways to write
if:if cond then true else false endas a statement.local a = if(cond, true, false)as an expression.if(cond) then ... endis invalid, spaces afterifstatement is mandatory.if (cond, true, false)is invalid, spaces afterifexpression is not allowed.
- To write variadic functions:
function foo(a, b...) end; args = [1, 2, 3]; foo(args...).- Parameters after
...are optional:function foo(a ... b, c) end; foo(1); foo(1, 2); foo(1, 2, 3)
- Returning multiple arguments will be translated into returning an array, e.g.:
function foo() return 1, 2 end <=> function foo() return [1, 2] endlocal a, b, c = d <=> local a, b, c = d[0], d[1], d[2]
- Everything starts at ZERO. For-loops start inclusively and end exclusively, e.g.:
a=[1, 2]; assert(a[0] == 1).for i=0,n do ... endranges[0, n-1].for i=n-1,-1,-1 do ... endranges[n-1, 0].
- For method function, it can access
thiswhich points to the receiver:a={}; function a.foo(x) this.x = x end; a.foo(1); assert(a.x, 1)
- For any function, use
selfto get itself in the body:function foo(x) self.x = x end; foo(1); assert(foo.x, 1)
- You can define up to 32000 variables (varies depending on the number of temporal variables generated by interpreter) in a function.
- Numbers are
int64 + float64internally, interpreter may promote it tofloat64when needed and downgrade it toint64when possible. - You can
returnanywhere inside functions,continueinside for-loops,gotoany label within the same function.
program, err := nj.LoadString("return 1")
v, err := program.Run() // v == 1bas.AddGlobal("G", bas.ValueOf(func() int { return 1 }))
program, _ := nj.LoadString("return G() + 1")
v, err := program.Run() // v == 2
program, _ = nj.LoadString("return G() + 2")
v, err = program.Run() // v == 3
program, _ = nj.LoadString("return G + 2", &CompileOptions{
Globals: bas.NewObject(0).SetProp("G", 10).ToMap(), // override the global 'G'
})
v, err = program.Run() // v == 12Refer to here.