script

package module
v0.0.0-...-3558dc3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 17, 2021 License: MIT Imports: 31 Imported by: 0

README

script 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)

Differ from Lua

  • Functions should be declared in the topmost scope:
    • do function foo() ... end end is invalid.
    • function foo() function bar() ... end end is invalid.
  • Use lambda to declare anonymous functions:
    • local foo = lambda(x) ... end.
    • Last return can be omitted: lambda (x) x=x+1; x end <=> lambda (x) x=x+1; return x end.
  • Syntax of calling functions strictly requires no spaces between callee and '(':
    • print(1) is the only right way of calling a function.
    • print (1) literally means two things: 1) get value of print and discard it, 2) evaluate (1).
  • To write variadic functions:
    • function foo(a, b...) end.
    • args = {1, 2, 3}; foo(args...).
  • Simple keyword arguments syntax sugar:
    • foo(a, b=2, c=3) will be converted to foo(a, { b=2, c=3 }).
    • There is no REAL keyword argument in script, e.g.: function foo(a) return type(a) end:
      • foo(1) returns "number".
      • foo(a=1) <=> foo({a=1}) returns "table".
  • Returning multiple arguments will be translated into returning a table, e.g.:
    • function f() return 1, 2 end; local a, b = f().
    • function f() return {1, 2} end; local tmp = f(); local a, b = tmp[0], tmp[1].
    • local 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 ... end.
    • for i=n-1,-1,-1 do ... end.
  • Functions loaded from table will have a self-like argument at first, to not-to-have it, use : operator, e.g.:
    • a={foo=lambda(this) print(this.v) end, v=1} a.foo() will print 1.
    • a={foo=lambda(this) print(this) end} a:foo() will print nil.
    • That's to say, you should call most lib functions using :.
  • You can define up to 32000 variables (varies depending on the number of temporal variables generated by interpreter) in a function.
  • Numbers are int64 + float64 internally, interpreter may promote it to float64 when needed and downgrade it to int64 when possible.
  • You can return anywhere inside functions, continue inside for-loops, goto any label within the same function.

Run

program, err := script.LoadString("return 1")
v, err := program.Run() // v == 1

Global Values

script.AddGlobalValue("G", func() int { return 1 })

program, _ := script.LoadString("return G() + 1")
v, err := program.Run() // v == 2

program, _ = script.LoadString("return G() + 2")
v, err = program.Run() // v == 3

program, _ = script.LoadString("return G + 2", &CompileOptions{
	GlobalKeyValues: {
		"G": 10, // override the global 'G'
	},
})
v, err = program.Run() // v == 12

Benchmarks

Refer to here.

Documentation

Index

Constants

View Source
const (
	ValueSize = unsafe.Sizeof(Value{})
)
View Source
const Version int64 = 327

Variables

View Source
var (
	ReaderProto = Map(Str("__name"), Str("reader"),
		Str("read"), Func2("read", func(rx, n Value) Value {
			f := rx.Table().GetString("_f").Interface().(io.Reader)
			switch n.Type() {
			case typ.Number:
				p := make([]byte, n.MaybeInt(0))
				rn, err := f.Read(p)
				if err == nil || rn > 0 {
					return Bytes(p[:rn])
				}
				if err == io.EOF {
					return Nil
				}
				panic(err)
			default:
				buf, err := ioutil.ReadAll(f)
				panicErr(err)
				return Bytes(buf)
			}
		}, "read() string", "\tread all bytes, return nil if EOF reached", "read(n: int) string", "\tread n bytes"),
		Str("readbuf"), Func2("readbuf", func(rx, n Value) Value {
			rn, err := rx.Table().GetString("_f").Interface().(io.Reader).Read(n.Interface().([]byte))
			return Array(Int(int64(rn)), Val(err))
		}, "$f(buf: bytes) array", "\tread into buf and return { bytes_read, error } in Go style"),
		Str("readlines"), Func2("readlines", func(rx, cb Value) Value {
			f := rx.Table().GetString("_f").Interface().(io.Reader)
			delim := rx.Table().GetString("delim").MaybeStr("\n")
			if cb == Nil {
				buf, err := ioutil.ReadAll(f)
				if err != nil {
					panic(err)
				}
				parts := bytes.Split(buf, []byte(delim))
				var res []Value
				for i, line := range parts {
					if i < len(parts)-1 {
						line = append(line, delim...)
					}
					res = append(res, Bytes(line))
				}
				return Array(res...)
			}
			for rd := bufio.NewReader(f); ; {
				line, err := rd.ReadString(delim[0])
				if len(line) > 0 {
					if v, err := cb.MustFunc("callback").Call(Str(line)); err != nil {
						panic(err)
					} else if v != Nil {
						return v
					}
				}
				if err != nil {
					if err != io.EOF {
						panic(err)
					}
					break
				}
			}
			return Nil
		},
			"readlines() array", "\tread the whole file and return lines as a table array",
			"readlines(f: function)", "\tfor every line read, f(line) will be called", "\tto exit the reading, return anything other than nil in f",
		),
	).Table()

	WriterProto = Map(Str("__name"), Str("writer"),
		Str("write"), Func2("write", func(rx, buf Value) Value {
			f := rx.Table().GetString("_f").Interface().(io.Writer)
			wn, err := f.Write([]byte(buf.MustStr("")))
			panicErr(err)
			return Int(int64(wn))
		}, "$f({w}: value, buf: string) int", "\twrite buf to w"),
		Str("pipe"), Func3("pipe", func(dest, src, n Value) Value {
			var wn int64
			var err error
			if n := n.MaybeInt(0); n > 0 {
				wn, err = io.CopyN(NewWriter(dest), NewReader(src), n)
			} else {
				wn, err = io.Copy(NewWriter(dest), NewReader(src))
			}
			panicErr(err)
			return Int(wn)
		}, "$f({w}: value, r: value) int", "\tcopy bytes from r to w, return number of bytes copied",
			"$f({w}: value, r: value, n: int) int", "\tcopy at most n bytes from r to w"),
	).Table()

	SeekerProto = Map(Str("__name"), Str("seeker"),
		Str("seek"), Func3("seek", func(rx, off, where Value) Value {
			f := rx.Table().GetString("_f").Interface().(io.Seeker)
			wn, err := f.Seek(off.MustInt("offset"), int(where.MustInt("where")))
			panicErr(err)
			return Int(int64(wn))
		}, "")).Table()

	CloserProto = Map(Str("__name"), Str("closer"),
		Str("close"), Func1("close", func(rx Value) Value {
			panicErr(rx.Table().GetString("_f").Interface().(io.Closer).Close())
			return Nil
		}, "")).Table()

	ReadWriterProto = ReaderProto.Copy().Merge(WriterProto, Str("__name"), Str("readwriter"))

	ReadCloserProto = ReaderProto.Copy().Merge(CloserProto, Str("__name"), Str("readcloser"))

	WriteCloserProto = WriterProto.Copy().Merge(CloserProto, Str("__name"), Str("writecloser"))

	ReadWriteCloserProto = ReadWriterProto.Copy().Merge(CloserProto, Str("__name"), Str("readwritecloser"))

	ReadWriteSeekCloserProto = ReadWriteCloserProto.Copy().Merge(SeekerProto, Str("__name"), Str("readwriteseekcloser"))
)
View Source
var (
	Nil     = Value{}
	Zero    = Int(0)
	NullStr = Str("")
	False   = Bool(false)
	True    = Bool(true)
)

Functions

func AddGlobalValue

func AddGlobalValue(k string, v interface{}, doc ...string)

func NewCloser

func NewCloser(v Value) io.Closer

NewCloser creates an io.Closer from value if possible

func NewReader

func NewReader(v Value) io.Reader

NewReader creates an io.Reader from value if possible

func NewWriter

func NewWriter(v Value) io.Writer

NewWriter creates an io.Writer from value if possible

func RemoveGlobalValue

func RemoveGlobalValue(k string)

func Stringify

func Stringify(v interface{}) string

func WebREPLHandler

func WebREPLHandler(opt *CompileOptions, cb func(*Program)) func(w http.ResponseWriter, r *http.Request)

Types

type CompileOptions

type CompileOptions struct {
	GlobalKeyValues map[string]interface{}
}

type Env

type Env struct {
	Global *Program
	A      Value

	// Debug info for native functions to read
	IP         uint32
	CS         *Function
	Stacktrace []stacktrace
	// contains filtered or unexported fields
}

Env is the environment for a function to run within. stack contains arguments used by the execution and is a global shared value, local can only use stack[stackOffset:] A stores the result of the execution

func (*Env) B

func (env *Env) B(index int) Value

B is an alias of Get

func (*Env) Clear

func (env *Env) Clear()

Clear clears the current stack

func (*Env) CopyStack

func (env *Env) CopyStack() []Value

func (*Env) Get

func (env *Env) Get(index int) Value

Get gets a value from the current stack

func (*Env) Prepend

func (env *Env) Prepend(v Value)

func (*Env) Push

func (env *Env) Push(v Value)

Push pushes a value into the current stack

func (*Env) PushVararg

func (env *Env) PushVararg(v []Value)

func (*Env) Set

func (env *Env) Set(index int, value Value)

Set sets a value in the current stack

func (*Env) Size

func (env *Env) Size() int

func (*Env) Stack

func (env *Env) Stack() []Value

func (*Env) String

func (env *Env) String() string

type ExecError

type ExecError struct {
	// contains filtered or unexported fields
}

ExecError represents the runtime error

func (*ExecError) Error

func (e *ExecError) Error() string

func (*ExecError) GetRootPanic

func (e *ExecError) GetRootPanic() interface{}

type FuncBody

type FuncBody struct {
	Code       packet
	Name       string
	DocString  string
	StackSize  uint16
	NumParams  uint16
	Variadic   bool
	Native     func(env *Env)
	LoadGlobal *Program
	Locals     []string
}

type Function

type Function struct {
	*FuncBody
	Receiver Value
}

func (*Function) Call

func (c *Function) Call(args ...Value) (v1 Value, err error)

func (*Function) CallVal

func (c *Function) CallVal(args ...interface{}) (v1 interface{}, err error)

func (*Function) Copy

func (f *Function) Copy() *Function

func (*Function) EmergStop

func (c *Function) EmergStop()

EmergStop terminates the execution of Func After calling, Func will become unavailable for any further operations

func (*Function) PrettyCode

func (c *Function) PrettyCode() string

func (*Function) Pure

func (f *Function) Pure() *Function

func (*Function) String

func (c *Function) String() string

func (*Function) Value

func (c *Function) Value() Value

type Program

type Program struct {
	Top          *Function
	Symbols      map[string]*symbol
	MaxStackSize int64
	Stack        *[]Value
	Functions    []*Function
	Stdout       io.Writer
	Stderr       io.Writer
	Stdin        io.Reader
}

func LoadFile

func LoadFile(path string, opt *CompileOptions) (*Program, error)

func LoadString

func LoadString(code string, opt *CompileOptions) (*Program, error)

func (*Program) EmergStop

func (p *Program) EmergStop()

EmergStop terminates the execution of program After calling, program will become unavailable for any further operations

func (*Program) Get

func (p *Program) Get(k string) (v Value, ok bool)

func (*Program) PrettyCode

func (p *Program) PrettyCode() string

func (*Program) Run

func (p *Program) Run() (v1 Value, err error)

func (*Program) Set

func (p *Program) Set(k string, v Value) (ok bool)

type Table

type Table struct {
	// contains filtered or unexported fields
}

func NewTable

func NewTable(size int) *Table

func (*Table) ArrayLen

func (m *Table) ArrayLen() int

func (*Table) ArrayPart

func (m *Table) ArrayPart() []Value

func (*Table) Clear

func (m *Table) Clear()

Clear clears the table, where already allocated memory will be reused.

func (*Table) ClearArray

func (m *Table) ClearArray()

func (*Table) ClearMap

func (m *Table) ClearMap()

func (*Table) Contains

func (m *Table) Contains(k Value) bool

func (*Table) Copy

func (m *Table) Copy() *Table

func (*Table) Foreach

func (m *Table) Foreach(f func(k, v Value) bool)

func (*Table) Get

func (m *Table) Get(k Value) (v Value)

Get retrieves the value for a given key.

func (*Table) GetString

func (m *Table) GetString(k string) (v Value)

func (*Table) Len

func (m *Table) Len() int

func (*Table) MapLen

func (m *Table) MapLen() int

func (*Table) MapPart

func (m *Table) MapPart() map[Value]Value

func (*Table) Merge

func (m *Table) Merge(src *Table, kvs ...Value) *Table

func (*Table) Name

func (m *Table) Name() string

func (*Table) New

func (m *Table) New() *Table

func (*Table) Next

func (m *Table) Next(k Value) (Value, Value)

func (*Table) Parent

func (m *Table) Parent() *Table

func (*Table) RawGet

func (m *Table) RawGet(k Value) (v Value)

func (*Table) RawSet

func (m *Table) RawSet(k, v Value) (prev Value)

func (*Table) Set

func (m *Table) Set(k, v Value) (prev Value)

Set inserts or updates a key/val pair into the Map. If val == Nil, then key will get deleted

func (*Table) SetFirstParent

func (m *Table) SetFirstParent(m2 *Table)

func (*Table) SetParent

func (m *Table) SetParent(m2 *Table)

func (*Table) SetString

func (m *Table) SetString(k string, v Value) (prev Value)

func (*Table) Size

func (m *Table) Size() int

func (*Table) String

func (m *Table) String() string

func (*Table) Value

func (m *Table) Value() Value

type Value

type Value struct {
	// contains filtered or unexported fields
}

Value is the basic data type used by the intepreter, an empty Value naturally represent nil

var (
	StrLib   Value
	MathLib  Value
	TableLib Value
	OSLib    Value
	IOLib    Value
)

func Array

func Array(m ...Value) Value

Array creates an array consists of given arguments

func Bool

func Bool(v bool) Value

Bool creates a boolean value

func Byte

func Byte(s byte) Value

Byte creates a one-byte string value

func Bytes

func Bytes(b []byte) Value

Bytes creates a string value from bytes

func Float

func Float(f float64) Value

Float creates a number value

func Func

func Func(name string, f func(env *Env), doc ...string) Value

Func creates a function

func Func1

func Func1(name string, f func(Value) Value, doc ...string) Value

func Func2

func Func2(name string, f func(Value, Value) Value, doc ...string) Value

func Func3

func Func3(name string, f func(Value, Value, Value) Value, doc ...string) Value

func Int

func Int(i int64) Value

Int creates a number value

func Map

func Map(kvs ...Value) Value

Map creates a map from `kvs`, which should be laid out as: key1, value1, key2, value2, ...

func MustRun

func MustRun(p *Program, err error) Value

func Run

func Run(p *Program, err error) (Value, error)

func Rune

func Rune(r rune) Value

Rune creates a one-rune string value encoded in UTF-8

func Str

func Str(s string) Value

Str creates a string value

func TableMerge

func TableMerge(dst Value, src Value, kvs ...Value) Value

TableMerge merges key-value pairs from `src` and `kvs` into `dst`

func TableProto

func TableProto(p *Table, kvs ...Value) Value

TableProto creates a table whose parent will be set to `p`

func Val

func Val(i interface{}) Value

Val creates a `Value` from golang `interface{}` `slice`, `array` and `map` will be left as is (except []Value), to convert them recursively, use ValRec instead

func ValRec

func ValRec(v interface{}) Value

func (Value) Bool

func (v Value) Bool() bool

Bool returns value as a boolean without checking Type()

func (Value) Equal

func (v Value) Equal(r Value) bool

Equal tests whether two values are equal

func (Value) Float

func (v Value) Float() float64

Float returns value as a float without checking Type()

func (Value) Func

func (v Value) Func() *Function

Func returns value as a function without checking Type()

func (Value) HashCode

func (v Value) HashCode() uint64

func (Value) Int

func (v Value) Int() int64

Int returns value as an int without checking Type()

func (Value) Interface

func (v Value) Interface() interface{}

Interface returns value as an interface{}

func (Value) IsFalse

func (v Value) IsFalse() bool

IsFalse tests whether value is falsy: nil, false, empty string or 0

func (Value) IsInt

func (v Value) IsInt() bool

IsInt tests whether value is an integer number

func (Value) IsValue

func (v Value) IsValue(parser.Node)

Reverse-reference in 'parser' package

func (Value) JSONString

func (v Value) JSONString() string

func (Value) MarshalJSON

func (v Value) MarshalJSON() ([]byte, error)

func (Value) MaybeFloat

func (v Value) MaybeFloat(d float64) float64

func (Value) MaybeInt

func (v Value) MaybeInt(d int64) int64

func (Value) MaybeStr

func (v Value) MaybeStr(d string) string

func (Value) MaybeTableGetString

func (v Value) MaybeTableGetString(key string) Value

func (Value) MustBool

func (v Value) MustBool(msg string) bool

func (Value) MustFloat

func (v Value) MustFloat(msg string) float64

func (Value) MustFunc

func (v Value) MustFunc(msg string) *Function

func (Value) MustInt

func (v Value) MustInt(msg string) int64

func (Value) MustNum

func (v Value) MustNum(msg string) Value

func (Value) MustStr

func (v Value) MustStr(msg string) string

func (Value) MustTable

func (v Value) MustTable(msg string) *Table

func (Value) ReflectValue

func (v Value) ReflectValue(t reflect.Type) reflect.Value

ReflectValue returns value as a reflect.Value based on reflect.Type

func (Value) Str

func (v Value) Str() string

Str returns value as a string without checking Type()

func (Value) StrLen

func (v Value) StrLen() int

StrLen returns the length of string without checking Type()

func (Value) String

func (v Value) String() string

func (Value) Table

func (v Value) Table() *Table

Table returns value as a table without checking Type()

func (Value) Type

func (v Value) Type() typ.ValueType

Type returns the type of value

type ValueIO

type ValueIO Value

func (ValueIO) Close

func (m ValueIO) Close() error

func (ValueIO) Read

func (m ValueIO) Read(p []byte) (int, error)

func (ValueIO) Write

func (m ValueIO) Write(p []byte) (int, error)

Directories

Path Synopsis
cmd
Modified upon: yuin/gopher-lua
Modified upon: yuin/gopher-lua
tests

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL