Files
moxa/interp/run.go

1318 lines
27 KiB
Go

package interp
import (
"fmt"
"log"
"reflect"
)
// Builtin type defines functions which run at CFG execution
type Builtin func(f *Frame) Builtin
type BuiltinGenerator func(n *Node)
var builtin = [...]BuiltinGenerator{
Nop: nop,
Addr: addr,
Assign: assign,
AssignX: assignX,
Add: add,
And: and,
Call: call,
Case: _case,
CompositeLit: arrayLit,
Dec: nop,
Equal: equal,
GetFunc: getFunc,
Greater: greater,
Inc: inc,
Land: land,
Lor: lor,
Lower: lower,
Mul: mul,
Negate: negate,
Not: not,
NotEqual: notEqual,
Quotient: quotient,
Range: _range,
Recv: recv,
Remain: remain,
Return: _return,
Send: send,
Slice: slice,
Slice0: slice0,
Star: deref,
Sub: sub,
TypeAssert: typeAssert,
}
func (interp *Interpreter) run(n *Node, cf *Frame) {
var f *Frame
if cf == nil {
f = interp.Frame
} else {
f = &Frame{anc: cf, data: make([]reflect.Value, n.flen)}
}
for i, t := range n.types {
// FIXME: nil types are forbidden and should be detected at compile time (CFG)
if t != nil && i < len(f.data) && !f.data[i].IsValid() {
f.data[i] = reflect.New(t).Elem()
}
}
//log.Println(n.index, "run", n.start.index)
runCfg(n.start, f)
}
// Functions set to run during execution of CFG
// runCfg executes a node AST by walking its CFG and running node builtin at each step
func runCfg(n *Node, f *Frame) {
for exec := n.exec; exec != nil; {
exec = exec(f)
}
}
func typeAssert(n *Node) {
value := genValue(n.child[0])
i := n.findex
next := getExec(n.tnext)
if n.child[0].typ.cat == ValueT {
n.exec = func(f *Frame) Builtin {
f.data[i] = value(f).Elem()
return next
}
} else {
n.exec = func(f *Frame) Builtin {
f.data[i] = value(f)
return next
}
}
}
func typeAssert2(n *Node) {
value := genValue(n.child[0]) // input value
value0 := genValue(n.anc.child[0]) // returned result
value1 := genValue(n.anc.child[1]) // returned status
next := getExec(n.tnext)
if n.child[0].typ.cat == ValueT {
n.exec = func(f *Frame) Builtin {
if value(f).IsValid() && !value(f).IsNil() {
value0(f).Set(value(f).Elem())
}
value1(f).SetBool(true)
return next
}
} else {
n.exec = func(f *Frame) Builtin {
value0(f).Set(value(f))
value1(f).SetBool(true)
return next
}
}
}
func convert(n *Node) {
i := n.findex
var value func(*Frame) reflect.Value
if n.child[1].typ.cat == FuncT {
value = genNodeWrapper(n.child[1])
} else {
value = genValue(n.child[1])
}
typ := n.child[0].typ.TypeOf()
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
f.data[i] = value(f).Convert(typ)
return next
}
}
// assignX implements multiple value assignement
func assignX(n *Node) {
l := len(n.child) - 1
b := n.child[l].findex
s := n.child[:l]
next := getExec(n.tnext)
values := make([]func(*Frame) reflect.Value, l)
for i, c := range s {
values[i] = genValue(c)
}
n.exec = func(f *Frame) Builtin {
for i, value := range values {
if f.data[b+i].IsValid() {
value(f).Set(f.data[b+i])
}
}
return next
}
}
// assign implements single value assignement
func assign(n *Node) {
value := genValue(n)
value1 := genValue(n.child[1])
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
value(f).Set(value1(f))
return next
}
}
func assignMap(n *Node) {
value := genValue(n.child[0].child[0]) // map
value0 := genValue(n.child[0].child[1]) // key
value1 := genValue(n.child[1]) // value
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
value(f).SetMapIndex(value0(f), value1(f))
return next
}
}
func and(n *Node) {
i := n.findex
value0 := genValue(n.child[0])
value1 := genValue(n.child[1])
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
f.data[i].SetInt(value0(f).Int() & value1(f).Int())
return next
}
}
func not(n *Node) {
value := genValue(n.child[0])
tnext := getExec(n.tnext)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *Frame) Builtin {
if !value(f).Bool() {
return tnext
}
return fnext
}
} else {
i := n.findex
n.exec = func(f *Frame) Builtin {
f.data[i].SetBool(!value(f).Bool())
return tnext
}
}
}
func addr(n *Node) {
i := n.findex
value := genValue(n.child[0])
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
f.data[i] = value(f).Addr()
return next
}
}
func deref(n *Node) {
value := genValue(n.child[0])
tnext := getExec(n.tnext)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *Frame) Builtin {
if value(f).Elem().Bool() {
return tnext
}
return fnext
}
} else {
i := n.findex
n.exec = func(f *Frame) Builtin {
f.data[i] = value(f).Elem()
return tnext
}
}
}
func _println(n *Node) {
child := n.child[1:]
next := getExec(n.tnext)
values := make([]func(*Frame) reflect.Value, len(child))
for i, c := range child {
values[i] = genValue(c)
}
n.exec = func(f *Frame) Builtin {
for i, value := range values {
if i > 0 {
fmt.Printf(" ")
}
fmt.Printf("%v", value(f))
// Handle multiple results of a function call argmument
for j := 1; j < child[i].fsize; j++ {
fmt.Printf(" %v", f.data[child[i].findex+j])
}
}
fmt.Println("")
return next
}
}
func _panic(n *Node) {
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
log.Panic("in _panic")
return next
}
}
func genNodeWrapper(n *Node) func(*Frame) reflect.Value {
def := n.val.(*Node)
setExec(def.child[3].start)
start := def.child[3].start
var receiver func(*Frame) reflect.Value
if n.recv != nil {
receiver = genValueRecv(n)
}
return func(f *Frame) reflect.Value {
return reflect.MakeFunc(n.typ.TypeOf(), func(in []reflect.Value) []reflect.Value {
// Allocate and init local frame. All values to be settable and addressable.
frame := Frame{anc: f, data: make([]reflect.Value, def.flen)}
for i, t := range def.types {
if t != nil {
frame.data[i] = reflect.New(t).Elem()
}
}
// Copy method receiver as first argument, if defined
i := 0
if receiver != nil {
frame.data[def.framepos[i]].Set(receiver(f))
i++
}
// Copy function input arguments in local frame
for _, arg := range in {
frame.data[def.framepos[i]].Set(arg)
i++
}
// Interpreter code execution
runCfg(start, &frame)
// Return output values in a result vector
var result []reflect.Value
if len(def.child[2].child) > 1 {
if fieldList := def.child[2].child[1]; fieldList != nil {
result = make([]reflect.Value, len(fieldList.child))
for i := range fieldList.child {
result[i] = frame.data[i]
}
}
}
return result
})
}
}
func call(n *Node) {
goroutine := n.anc.kind == GoStmt
method := n.child[0].recv != nil
var values []func(*Frame) reflect.Value
if method {
// Compute method receiver value
values = append(values, genValueRecv(n.child[0]))
}
variadic := variadicPos(n)
value := genValue(n.child[0])
child := n.child[1:]
tnext := getExec(n.tnext)
fnext := getExec(n.fnext)
// compute input argument value functions
for i, c := range child {
if isRegularCall(c) {
for j := range c.child[0].typ.ret {
ind := c.findex + j
values = append(values, func(f *Frame) reflect.Value { return f.data[ind] })
}
} else {
if c.kind == BasicLit {
var argType reflect.Type
if variadic >= 0 && i >= variadic {
argType = n.child[0].typ.arg[variadic].TypeOf()
} else {
argType = n.child[0].typ.arg[i].TypeOf()
}
convertLiteralValue(c, argType)
}
values = append(values, genValue(c))
}
}
// compute frame indexes for return values
ret := make([]int, len(n.child[0].typ.ret))
for i := range n.child[0].typ.ret {
ret[i] = n.findex + i
}
n.exec = func(f *Frame) Builtin {
def := value(f).Interface().(*Node)
anc := f
// Get closure frame context (if any)
if def.frame != nil {
anc = def.frame
}
nf := Frame{anc: anc, data: make([]reflect.Value, def.flen)}
var vararg reflect.Value
// Init local frame values
for i, t := range def.types {
if t != nil {
nf.data[i] = reflect.New(t).Elem()
}
}
// Init variadic argument vector
if variadic >= 0 {
fi := def.framepos[variadic]
nf.data[fi] = reflect.New(reflect.SliceOf(def.types[fi])).Elem()
vararg = nf.data[fi]
}
// Copy input parameters from caller
for i, v := range values {
src := v(f)
if method && i == 0 {
dest := nf.data[def.framepos[i]]
// Accomodate to receiver type
ks, kd := src.Kind(), dest.Kind()
if ks != kd {
if kd == reflect.Ptr {
dest.Set(src.Addr())
} else {
dest.Set(src.Elem())
}
} else {
dest.Set(src)
}
} else if variadic >= 0 && i >= variadic {
vararg.Set(reflect.Append(vararg, src))
} else {
nf.data[def.framepos[i]].Set(src)
}
}
// Execute function body
if goroutine {
go runCfg(def.child[3].start, &nf)
return tnext
} else {
runCfg(def.child[3].start, &nf)
}
// Handle branching according to boolean result
if fnext != nil {
if nf.data[0].Bool() {
return tnext
}
return fnext
}
// Propagate return values to caller frame
//log.Println(n.index, "call rets:", ret, nf.data[:len(ret)])
for i, r := range ret {
f.data[r] = nf.data[i]
}
return tnext
}
}
// Call a function from a bin import, accessible through reflect
func callBin(n *Node) {
tnext := getExec(n.tnext)
fnext := getExec(n.fnext)
child := n.child[1:]
value := genValue(n.child[0])
var values []func(*Frame) reflect.Value
funcType := n.child[0].typ.rtype
variadic := -1
if funcType.IsVariadic() {
variadic = funcType.NumIn() - 1
}
receiverOffset := 0
if n.child[0].recv != nil {
receiverOffset = 1
}
for i, c := range child {
if isRegularCall(c) {
// Handle nested function calls: pass returned values as arguments
for j := range c.child[0].typ.ret {
ind := c.findex + j
values = append(values, func(f *Frame) reflect.Value { return f.data[ind] })
}
} else {
if c.kind == BasicLit {
// Convert literal value (untyped) to function argument type (if not an interface{})
var argType reflect.Type
if variadic >= 0 && i >= variadic {
argType = funcType.In(variadic).Elem()
} else {
argType = funcType.In(i + receiverOffset)
}
convertLiteralValue(c, argType)
if !reflect.ValueOf(c.val).IsValid() { // Handle "nil"
c.val = reflect.Zero(argType)
}
}
// FIXME: nil types are forbidden and should be handled at compile time (CFG)
if c.typ != nil && c.typ.cat == FuncT {
values = append(values, genNodeWrapper(c))
} else {
values = append(values, genValue(c))
}
}
}
l := len(values)
fsize := n.child[0].fsize
if n.anc.kind == GoStmt {
// Execute function in a goroutine, discard results
n.exec = func(f *Frame) Builtin {
in := make([]reflect.Value, l)
for i, v := range values {
in[i] = v(f)
}
go value(f).Call(in)
return tnext
}
} else if fnext != nil {
// Handle branching according to boolean result
n.exec = func(f *Frame) Builtin {
in := make([]reflect.Value, l)
for i, v := range values {
in[i] = v(f)
}
r := value(f).Call(in)
if r[0].Bool() {
return tnext
}
return fnext
}
} else {
n.exec = func(f *Frame) Builtin {
in := make([]reflect.Value, l)
for i, v := range values {
in[i] = v(f)
}
//log.Println(n.index, "callbin", value(f).Type(), in)
r := value(f).Call(in)
//log.Println(n.index, "callBin, res:", v, fsize, n.findex)
for i := 0; i < fsize; i++ {
f.data[n.findex+i] = r[i]
}
return tnext
}
}
}
func getIndexBinMethod(n *Node) {
i := n.findex
m := n.val.(int)
value := genValue(n.child[0])
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
f.data[i] = value(f).Method(m)
return next
}
}
// getIndexArray returns array value from index
func getIndexArray(n *Node) {
tnext := getExec(n.tnext)
value0 := genValue(n.child[0])
value1 := genValue(n.child[1])
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *Frame) Builtin {
if value0(f).Index(int(value1(f).Int())).Bool() {
return tnext
}
return fnext
}
} else {
i := n.findex
n.exec = func(f *Frame) Builtin {
f.data[i] = value0(f).Index(int(value1(f).Int()))
return tnext
}
}
}
// getIndexMap retrieves map value from index
func getIndexMap(n *Node) {
value0 := genValue(n.child[0]) // map
value1 := genValue(n.child[1]) // index
tnext := getExec(n.tnext)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *Frame) Builtin {
if value0(f).MapIndex(value1(f)).Bool() {
return tnext
}
return fnext
}
} else {
i := n.findex
n.exec = func(f *Frame) Builtin {
f.data[i] = value0(f).MapIndex(value1(f))
return tnext
}
}
}
// getIndexMap2 retrieves map value from index and set status
func getIndexMap2(n *Node) {
i := n.findex
value0 := genValue(n.child[0]) // map
value1 := genValue(n.child[1]) // index
value2 := genValue(n.anc.child[1]) // status
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
f.data[i] = value0(f).MapIndex(value1(f))
value2(f).SetBool(f.data[i].IsValid())
return next
}
}
func getFunc(n *Node) {
i := n.findex
next := getExec(n.tnext)
if len(n.types) == 0 {
n.types = frameTypes(n, n.flen)
}
n.exec = func(f *Frame) Builtin {
frame := *f
node := *n
node.val = &node
node.frame = &frame
f.data[i] = reflect.ValueOf(&node)
return next
}
}
func getIndexSeq(n *Node) {
value := genValue(n.child[0])
index := n.val.([]int)
tnext := getExec(n.tnext)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *Frame) Builtin {
if value(f).FieldByIndex(index).Bool() {
return tnext
}
return fnext
}
} else {
i := n.findex
n.exec = func(f *Frame) Builtin {
f.data[i] = value(f).FieldByIndex(index)
return tnext
}
}
}
func getPtrIndexSeq(n *Node) {
index := n.val.([]int)
value := genValue(n.child[0])
tnext := getExec(n.tnext)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *Frame) Builtin {
if value(f).Elem().FieldByIndex(index).Bool() {
return tnext
}
return fnext
}
} else {
i := n.findex
n.exec = func(f *Frame) Builtin {
f.data[i] = value(f).Elem().FieldByIndex(index)
return tnext
}
}
}
func mul(n *Node) {
i := n.findex
value0 := genValue(n.child[0])
value1 := genValue(n.child[1])
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
f.data[i].SetInt(value0(f).Int() * value1(f).Int())
return next
}
}
func quotient(n *Node) {
i := n.findex
value0 := genValue(n.child[0])
value1 := genValue(n.child[1])
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
f.data[i].SetInt(value0(f).Int() / value1(f).Int())
return next
}
}
func remain(n *Node) {
i := n.findex
value0 := genValue(n.child[0])
value1 := genValue(n.child[1])
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
f.data[i].SetInt(value0(f).Int() % value1(f).Int())
return next
}
}
func negate(n *Node) {
i := n.findex
value := genValue(n.child[0])
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
f.data[i].SetInt(-value(f).Int())
return next
}
}
func add(n *Node) {
i := n.findex
value0 := genValue(n.child[0])
value1 := genValue(n.child[1])
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
f.data[i].SetInt(value0(f).Int() + value1(f).Int())
return next
}
}
func sub(n *Node) {
i := n.findex
value0 := genValue(n.child[0])
value1 := genValue(n.child[1])
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
f.data[i].SetInt(value0(f).Int() - value1(f).Int())
return next
}
}
func equal(n *Node) {
i := n.findex
value0 := genValue(n.child[0])
value1 := genValue(n.child[1])
tnext := getExec(n.tnext)
if n.fnext == nil {
n.exec = func(f *Frame) Builtin {
f.data[i].SetBool(value0(f).Interface() == value1(f).Interface())
return tnext
}
} else {
fnext := getExec(n.fnext)
n.exec = func(f *Frame) Builtin {
if value0(f).Interface() == value1(f).Interface() {
return tnext
}
return fnext
}
}
}
func notEqual(n *Node) {
i := n.findex
value0 := genValue(n.child[0])
value1 := genValue(n.child[1])
tnext := getExec(n.tnext)
if n.fnext == nil {
n.exec = func(f *Frame) Builtin {
f.data[i].SetBool(value0(f).Interface() != value1(f).Interface())
return tnext
}
} else {
fnext := getExec(n.fnext)
n.exec = func(f *Frame) Builtin {
if value0(f).Interface() != value1(f).Interface() {
return tnext
}
return fnext
}
}
}
func inc(n *Node) {
value := genValue(n)
value0 := genValue(n.child[0])
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
value(f).SetInt(value0(f).Int() + 1)
return next
}
}
func greater(n *Node) {
i := n.findex
value0 := genValue(n.child[0])
value1 := genValue(n.child[1])
tnext := getExec(n.tnext)
if n.fnext == nil {
n.exec = func(f *Frame) Builtin {
f.data[i].SetBool(value0(f).Int() > value1(f).Int())
return tnext
}
} else {
fnext := getExec(n.fnext)
n.exec = func(f *Frame) Builtin {
if value0(f).Int() > value1(f).Int() {
return tnext
}
return fnext
}
}
}
func land(n *Node) {
value0 := genValue(n.child[0])
value1 := genValue(n.child[1])
tnext := getExec(n.tnext)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *Frame) Builtin {
if value0(f).Bool() && value1(f).Bool() {
return tnext
}
return fnext
}
} else {
i := n.findex
n.exec = func(f *Frame) Builtin {
f.data[i].SetBool(value0(f).Bool() && value1(f).Bool())
return tnext
}
}
}
func lor(n *Node) {
value0 := genValue(n.child[0])
value1 := genValue(n.child[1])
tnext := getExec(n.tnext)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *Frame) Builtin {
if value0(f).Bool() || value1(f).Bool() {
return tnext
}
return fnext
}
} else {
i := n.findex
n.exec = func(f *Frame) Builtin {
f.data[i].SetBool(value0(f).Bool() || value1(f).Bool())
return tnext
}
}
}
func lower(n *Node) {
value0 := genValue(n.child[0])
value1 := genValue(n.child[1])
tnext := getExec(n.tnext)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *Frame) Builtin {
if value0(f).Int() < value1(f).Int() {
return tnext
}
return fnext
}
} else {
i := n.findex
n.exec = func(f *Frame) Builtin {
f.data[i].SetBool(value0(f).Int() < value1(f).Int())
return tnext
}
}
}
func nop(n *Node) {
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
return next
}
}
// TODO: optimize return according to nb of child
func _return(n *Node) {
child := n.child
next := getExec(n.tnext)
values := make([]func(*Frame) reflect.Value, len(child))
for i, c := range child {
values[i] = genValue(c)
}
n.exec = func(f *Frame) Builtin {
for i, value := range values {
f.data[i] = value(f)
}
return next
}
}
func arrayLit(n *Node) {
value := valueGenerator(n, n.findex)
next := getExec(n.tnext)
child := n.child[1:]
a := n.typ.zero()
values := make([]func(*Frame) reflect.Value, len(child))
for i, c := range child {
convertLiteralValue(c, n.typ.val.TypeOf())
values[i] = genValue(c)
}
if n.typ.size > 0 {
// Fixed size array
n.exec = func(f *Frame) Builtin {
for i, v := range values {
a.Index(i).Set(v(f))
}
value(f).Set(a)
return next
}
} else {
// Slice
n.exec = func(f *Frame) Builtin {
for _, v := range values {
a = reflect.Append(a, v(f))
}
value(f).Set(a)
return next
}
}
}
func mapLit(n *Node) {
value := valueGenerator(n, n.findex)
next := getExec(n.tnext)
child := n.child[1:]
typ := n.typ.TypeOf()
keys := make([]func(*Frame) reflect.Value, len(child))
values := make([]func(*Frame) reflect.Value, len(child))
for i, c := range child {
convertLiteralValue(c.child[0], n.typ.key.TypeOf())
convertLiteralValue(c.child[1], n.typ.val.TypeOf())
keys[i] = genValue(c.child[0])
values[i] = genValue(c.child[1])
}
n.exec = func(f *Frame) Builtin {
m := reflect.MakeMap(typ)
for i, k := range keys {
m.SetMapIndex(k(f), values[i](f))
}
value(f).Set(m)
return next
}
}
// compositeLit creates a struct object
func compositeLit(n *Node) {
value := valueGenerator(n, n.findex)
next := getExec(n.tnext)
child := n.child[1:]
a := n.typ.zero()
values := make([]func(*Frame) reflect.Value, len(child))
for i, c := range child {
convertLiteralValue(c, n.typ.field[i].typ.TypeOf())
values[i] = genValue(c)
}
n.exec = func(f *Frame) Builtin {
for i, v := range values {
a.Field(i).Set(v(f))
}
value(f).Set(a)
return next
}
}
// compositeSparse creates a struct Object, filling fields from sparse key-values
func compositeSparse(n *Node) {
value := valueGenerator(n, n.findex)
next := getExec(n.tnext)
child := n.child[1:]
values := make(map[int]func(*Frame) reflect.Value)
a := n.typ.zero()
for _, c := range child {
convertLiteralValue(c.child[1], n.typ.field[c.findex].typ.TypeOf())
values[c.findex] = genValue(c.child[1])
}
n.exec = func(f *Frame) Builtin {
for i, v := range values {
a.Field(i).Set(v(f))
}
value(f).Set(a)
return next
}
}
func empty(n *Node) {}
func _range(n *Node) {
index0 := n.child[0].findex // array index location in frame
index1 := n.child[1].findex // array value location in frame
value := genValue(n.child[2]) // array
fnext := getExec(n.fnext)
tnext := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
a := value(f)
v0 := f.data[index0]
v0.SetInt(v0.Int() + 1)
i := int(v0.Int())
if i >= a.Len() {
return fnext
}
f.data[index1].Set(a.Index(i))
return tnext
}
// Init sequence
next := n.exec
n.child[0].exec = func(f *Frame) Builtin {
f.data[index0].SetInt(-1)
return next
}
}
func rangeMap(n *Node) {
index0 := n.child[0].findex // array index location in frame
index1 := n.child[1].findex // array value location in frame
value := genValue(n.child[2]) // array
fnext := getExec(n.fnext)
tnext := getExec(n.tnext)
// TODO: move i and keys to frame
var i int
var keys []reflect.Value
n.exec = func(f *Frame) Builtin {
a := value(f)
i++
if i >= a.Len() {
return fnext
}
f.data[index0].Set(keys[i])
f.data[index1].Set(a.MapIndex(keys[i]))
return tnext
}
// Init sequence
next := n.exec
n.child[0].exec = func(f *Frame) Builtin {
keys = value(f).MapKeys()
i = -1
return next
}
}
func _case(n *Node) {
//i := n.findex
value0 := genValue(n.anc.anc.child[0])
value1 := genValue(n.child[0])
tnext := getExec(n.tnext)
fnext := getExec(n.fnext)
n.exec = func(f *Frame) Builtin {
if value0(f).Interface() == value1(f).Interface() {
return tnext
}
return fnext
}
}
// TODO: handle variable number of arguments to append
func _append(n *Node) {
i := n.findex
value0 := genValue(n.child[1])
value1 := genValue(n.child[2])
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
f.data[i] = reflect.Append(value0(f), value1(f))
return next
}
}
func _cap(n *Node) {
i := n.findex
value := genValue(n.child[1])
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
f.data[i].SetInt(int64(value(f).Cap()))
return next
}
}
func _len(n *Node) {
i := n.findex
value := genValue(n.child[1])
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
f.data[i].SetInt(int64(value(f).Len()))
return next
}
}
// _make allocates and initializes a slice, a map or a chan.
func _make(n *Node) {
i := n.findex
next := getExec(n.tnext)
typ := n.child[1].typ.TypeOf()
switch typ.Kind() {
case reflect.Array, reflect.Slice:
value := genValue(n.child[2])
switch len(n.child) {
case 3:
n.exec = func(f *Frame) Builtin {
len := int(value(f).Int())
f.data[i] = reflect.MakeSlice(typ, len, len)
return next
}
case 4:
value1 := genValue(n.child[3])
n.exec = func(f *Frame) Builtin {
f.data[i] = reflect.MakeSlice(typ, int(value(f).Int()), int(value1(f).Int()))
return next
}
}
case reflect.Chan:
switch len(n.child) {
case 2:
n.exec = func(f *Frame) Builtin {
f.data[i] = reflect.MakeChan(typ, 0)
return next
}
case 3:
value := genValue(n.child[2])
n.exec = func(f *Frame) Builtin {
f.data[i] = reflect.MakeChan(typ, int(value(f).Int()))
return next
}
}
case reflect.Map:
switch len(n.child) {
case 2:
n.exec = func(f *Frame) Builtin {
f.data[i] = reflect.MakeMap(typ)
return next
}
case 3:
value := genValue(n.child[2])
n.exec = func(f *Frame) Builtin {
f.data[i] = reflect.MakeMapWithSize(typ, int(value(f).Int()))
return next
}
}
}
}
// recv reads from a channel
func recv(n *Node) {
value := genValue(n.child[0])
tnext := getExec(n.tnext)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *Frame) Builtin {
if v, _ := value(f).Recv(); v.Bool() {
return tnext
}
return fnext
}
} else {
i := n.findex
n.exec = func(f *Frame) Builtin {
f.data[i], _ = value(f).Recv()
return tnext
}
}
}
func convertLiteralValue(n *Node, t reflect.Type) {
if n.kind != BasicLit || t == nil || t.Kind() == reflect.Interface {
return
}
n.val = reflect.ValueOf(n.val).Convert(t)
}
// Write to a channel
func send(n *Node) {
next := getExec(n.tnext)
value0 := genValue(n.child[0]) // channel
convertLiteralValue(n.child[1], n.child[0].typ.val.TypeOf())
value1 := genValue(n.child[1]) // value to send
n.exec = func(f *Frame) Builtin {
value0(f).Send(value1(f))
return next
}
}
// slice expression: array[low:high:max]
func slice(n *Node) {
i := n.findex
next := getExec(n.tnext)
value0 := genValue(n.child[0]) // array
value1 := genValue(n.child[1]) // low (if 2 or 3 args) or high (if 1 arg)
switch len(n.child) {
case 2:
n.exec = func(f *Frame) Builtin {
a := value0(f)
f.data[i] = a.Slice(int(value1(f).Int()), a.Len())
return next
}
case 3:
value2 := genValue(n.child[2]) // max
n.exec = func(f *Frame) Builtin {
a := value0(f)
f.data[i] = a.Slice(int(value1(f).Int()), int(value2(f).Int()))
return next
}
case 4:
value2 := genValue(n.child[2])
value3 := genValue(n.child[3])
n.exec = func(f *Frame) Builtin {
a := value0(f)
f.data[i] = a.Slice3(int(value1(f).Int()), int(value2(f).Int()), int(value3(f).Int()))
return next
}
}
}
// slice expression, no low value: array[:high:max]
func slice0(n *Node) {
i := n.findex
next := getExec(n.tnext)
value0 := genValue(n.child[0])
switch len(n.child) {
case 1:
n.exec = func(f *Frame) Builtin {
a := value0(f)
f.data[i] = a.Slice(0, a.Len())
return next
}
case 2:
value1 := genValue(n.child[1])
n.exec = func(f *Frame) Builtin {
a := value0(f)
f.data[i] = a.Slice(0, int(value1(f).Int()))
return next
}
case 3:
value1 := genValue(n.child[1])
value2 := genValue(n.child[2])
n.exec = func(f *Frame) Builtin {
a := value0(f)
f.data[i] = a.Slice3(0, int(value1(f).Int()), int(value2(f).Int()))
return next
}
}
}
func isNil(n *Node) {
value := genValue(n.child[0])
tnext := getExec(n.tnext)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *Frame) Builtin {
if value(f).IsNil() {
return tnext
}
return fnext
}
} else {
i := n.findex
n.exec = func(f *Frame) Builtin {
f.data[i].SetBool(value(f).IsNil())
return tnext
}
}
}
func isNotNil(n *Node) {
value := genValue(n.child[0])
tnext := getExec(n.tnext)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *Frame) Builtin {
if value(f).IsNil() {
return fnext
}
return tnext
}
} else {
i := n.findex
n.exec = func(f *Frame) Builtin {
f.data[i].SetBool(!value(f).IsNil())
return tnext
}
}
}