Define a new Method action to detect method calls on interface types. In this case the receiver is resolved from a dynamic type rather than a static one. Handle method calls where receiver is a pointer. In typeAssert, always return an interface value with the concrete type, to fix method lookup on interface objects. Add relevant tests.
1580 lines
34 KiB
Go
1580 lines
34 KiB
Go
package interp
|
|
|
|
//go:generate go run ../cmd/genop/genop.go
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
)
|
|
|
|
// Builtin type defines functions which run at CFG execution
|
|
type Builtin func(f *Frame) Builtin
|
|
|
|
// BuiltinGenerator type defines a builtin generator function
|
|
type BuiltinGenerator func(n *Node)
|
|
|
|
var builtin = [...]BuiltinGenerator{
|
|
Nop: nop,
|
|
Addr: addr,
|
|
Assign: assign,
|
|
AssignX: assignX,
|
|
Add: add,
|
|
AddAssign: addAssign,
|
|
And: and,
|
|
AndAssign: andAssign,
|
|
AndNot: andnot,
|
|
AndNotAssign: andnotAssign,
|
|
Call: call,
|
|
Case: _case,
|
|
CompositeLit: arrayLit,
|
|
Dec: dec,
|
|
Defer: _defer,
|
|
Equal: equal,
|
|
GetFunc: getFunc,
|
|
Greater: greater,
|
|
GreaterEqual: greaterEqual,
|
|
Inc: inc,
|
|
Land: land,
|
|
Lor: lor,
|
|
Lower: lower,
|
|
LowerEqual: lowerEqual,
|
|
Mul: mul,
|
|
MulAssign: mulAssign,
|
|
Negate: negate,
|
|
Not: not,
|
|
NotEqual: notEqual,
|
|
Or: or,
|
|
OrAssign: orAssign,
|
|
Quo: quo,
|
|
QuoAssign: quoAssign,
|
|
Range: _range,
|
|
Recv: recv,
|
|
Rem: rem,
|
|
RemAssign: remAssign,
|
|
Return: _return,
|
|
Send: send,
|
|
Shl: shl,
|
|
ShlAssign: shlAssign,
|
|
Shr: shr,
|
|
ShrAssign: shrAssign,
|
|
Slice: slice,
|
|
Slice0: slice0,
|
|
Star: deref,
|
|
Sub: sub,
|
|
SubAssign: subAssign,
|
|
TypeAssert: typeAssert,
|
|
Xor: xor,
|
|
XorAssign: xorAssign,
|
|
}
|
|
|
|
type valueInterface struct {
|
|
node *Node
|
|
value reflect.Value
|
|
}
|
|
|
|
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) {
|
|
defer func() {
|
|
f.recovered = recover()
|
|
for _, val := range f.deferred {
|
|
val[0].Call(val[1:])
|
|
}
|
|
if f.recovered != nil {
|
|
panic(f.recovered)
|
|
}
|
|
}()
|
|
|
|
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)
|
|
|
|
switch {
|
|
case n.child[0].typ.cat == ValueT:
|
|
n.exec = func(f *Frame) Builtin {
|
|
f.data[i] = value(f).Elem()
|
|
return next
|
|
}
|
|
case n.child[1].typ.cat == InterfaceT:
|
|
n.exec = func(f *Frame) Builtin {
|
|
v := value(f).Interface().(valueInterface)
|
|
f.data[i] = reflect.ValueOf(valueInterface{v.node, v.value})
|
|
return next
|
|
}
|
|
default:
|
|
n.exec = func(f *Frame) Builtin {
|
|
v := value(f).Interface().(valueInterface)
|
|
f.data[i] = v.value
|
|
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)
|
|
|
|
switch {
|
|
case 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
|
|
}
|
|
case n.child[1].typ.cat == InterfaceT:
|
|
n.exec = func(f *Frame) Builtin {
|
|
v, ok := value(f).Interface().(valueInterface)
|
|
value0(f).Set(reflect.ValueOf(valueInterface{v.node, v.value}))
|
|
value1(f).SetBool(ok)
|
|
return next
|
|
}
|
|
default:
|
|
n.exec = func(f *Frame) Builtin {
|
|
v, ok := value(f).Interface().(valueInterface)
|
|
value0(f).Set(v.value)
|
|
value1(f).SetBool(ok)
|
|
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 assignment
|
|
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 assignment
|
|
func assign(n *Node) {
|
|
next := getExec(n.tnext)
|
|
|
|
if n.child[0].typ.cat == InterfaceT {
|
|
valueAddr := genValueAddr(n)
|
|
value1 := genValueInterface(n.lastChild())
|
|
n.exec = func(f *Frame) Builtin {
|
|
*(valueAddr(f)) = value1(f)
|
|
return next
|
|
}
|
|
} else {
|
|
value := genValue(n)
|
|
dest, src := n.child[0], n.lastChild()
|
|
var value1 func(*Frame) reflect.Value
|
|
if dest.typ.cat == ValueT && src.typ.cat == FuncT {
|
|
value1 = genNodeWrapper(src)
|
|
} else {
|
|
value1 = genValue(src)
|
|
}
|
|
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
|
|
var value0, value1 func(*Frame) reflect.Value
|
|
|
|
if n.child[0].child[1].typ.cat == InterfaceT { // key
|
|
value0 = genValueInterface(n.child[0].child[1])
|
|
} else {
|
|
value0 = genValue(n.child[0].child[1])
|
|
}
|
|
|
|
if n.child[1].typ.cat == InterfaceT { // value
|
|
value1 = genValueInterface(n.child[1])
|
|
} else {
|
|
value1 = genValue(n.child[1])
|
|
}
|
|
next := getExec(n.tnext)
|
|
|
|
n.exec = func(f *Frame) Builtin {
|
|
value(f).SetMapIndex(value0(f), value1(f))
|
|
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 argument
|
|
for j := 1; j < child[i].fsize; j++ {
|
|
fmt.Printf(" %v", f.data[child[i].findex+j])
|
|
}
|
|
}
|
|
fmt.Println("")
|
|
return next
|
|
}
|
|
}
|
|
|
|
func _recover(n *Node) {
|
|
tnext := getExec(n.tnext)
|
|
i := n.findex
|
|
var err error
|
|
nilErr := reflect.ValueOf(&err).Elem()
|
|
|
|
n.exec = func(f *Frame) Builtin {
|
|
if f.anc.recovered == nil {
|
|
f.data[i] = nilErr
|
|
} else {
|
|
f.data[i] = reflect.ValueOf(f.anc.recovered)
|
|
f.anc.recovered = nil
|
|
}
|
|
return tnext
|
|
}
|
|
}
|
|
|
|
func _panic(n *Node) {
|
|
value := genValue(n.child[1])
|
|
|
|
n.exec = func(f *Frame) Builtin {
|
|
panic(value(f))
|
|
}
|
|
}
|
|
|
|
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 {
|
|
if n.frame != nil { // Use closure context if defined
|
|
f = n.frame
|
|
}
|
|
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, c := range fieldList.child {
|
|
if c.typ.cat == FuncT {
|
|
gv := genNodeWrapper(frame.data[i].Interface().(*Node))
|
|
result[i] = gv(f)
|
|
} else {
|
|
result[i] = frame.data[i]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result
|
|
})
|
|
}
|
|
}
|
|
|
|
func _defer(n *Node) {
|
|
tnext := getExec(n.tnext)
|
|
values := make([]func(*Frame) reflect.Value, len(n.child[0].child))
|
|
var method func(*Frame) reflect.Value
|
|
|
|
for i, c := range n.child[0].child {
|
|
if c.typ.cat == FuncT {
|
|
values[i] = genNodeWrapper(c)
|
|
} else {
|
|
if c.recv != nil {
|
|
// defer a method on a binary obj
|
|
mi := c.val.(int)
|
|
m := genValue(c.child[0])
|
|
method = func(f *Frame) reflect.Value { return m(f).Method(mi) }
|
|
}
|
|
values[i] = genValue(c)
|
|
}
|
|
}
|
|
|
|
if method != nil {
|
|
n.exec = func(f *Frame) Builtin {
|
|
val := make([]reflect.Value, len(values))
|
|
val[0] = method(f)
|
|
for i, v := range values[1:] {
|
|
val[i+1] = v(f)
|
|
}
|
|
f.deferred = append([][]reflect.Value{val}, f.deferred...)
|
|
return tnext
|
|
}
|
|
} else {
|
|
n.exec = func(f *Frame) Builtin {
|
|
val := make([]reflect.Value, len(values))
|
|
for i, v := range values {
|
|
val[i] = v(f)
|
|
}
|
|
f.deferred = append([][]reflect.Value{val}, f.deferred...)
|
|
return tnext
|
|
}
|
|
}
|
|
}
|
|
|
|
func call(n *Node) {
|
|
goroutine := n.anc.kind == GoStmt
|
|
var method bool
|
|
value := genValue(n.child[0])
|
|
var values []func(*Frame) reflect.Value
|
|
if n.child[0].recv != nil {
|
|
// Compute method receiver value
|
|
values = append(values, genValueRecv(n.child[0]))
|
|
method = true
|
|
} else if n.child[0].action == Method {
|
|
// add a place holder for interface method receiver
|
|
values = append(values, nil)
|
|
method = true
|
|
}
|
|
variadic := variadicPos(n)
|
|
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) {
|
|
// Arguments are return values of a nested function call
|
|
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)
|
|
}
|
|
if len(n.child[0].typ.arg) > i && n.child[0].typ.arg[i].cat == InterfaceT {
|
|
values = append(values, genValueInterface(c))
|
|
} else {
|
|
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 {
|
|
switch {
|
|
case method && i == 0:
|
|
// compute receiver
|
|
var src reflect.Value
|
|
if v == nil {
|
|
src = def.recv.val
|
|
if len(def.recv.index) > 0 {
|
|
if src.Kind() == reflect.Ptr {
|
|
src = src.Elem().FieldByIndex(def.recv.index)
|
|
} else {
|
|
src = src.FieldByIndex(def.recv.index)
|
|
}
|
|
}
|
|
} else {
|
|
src = v(f)
|
|
}
|
|
dest := nf.data[def.framepos[i]]
|
|
// Accommodate 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)
|
|
}
|
|
case variadic >= 0 && i >= variadic:
|
|
vararg.Set(reflect.Append(vararg, v(f)))
|
|
case len(def.typ.arg) > i && def.typ.arg[i].cat == InterfaceT:
|
|
nf.data[def.framepos[i]] = v(f)
|
|
default:
|
|
nf.data[def.framepos[i]].Set(v(f))
|
|
}
|
|
}
|
|
|
|
// Execute function body
|
|
if goroutine {
|
|
go runCfg(def.child[3].start, &nf)
|
|
return tnext
|
|
}
|
|
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 {
|
|
switch c.typ.cat {
|
|
case FuncT:
|
|
values = append(values, genNodeWrapper(c))
|
|
case InterfaceT:
|
|
values = append(values, genValueInterfaceValue(c))
|
|
default:
|
|
values = append(values, genValue(c))
|
|
}
|
|
} else {
|
|
values = append(values, genValue(c))
|
|
}
|
|
}
|
|
}
|
|
l := len(values)
|
|
fsize := n.child[0].fsize
|
|
|
|
switch {
|
|
case 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
|
|
}
|
|
case 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
|
|
}
|
|
default:
|
|
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:", r, fsize, n.findex, len(r), len(f.data))
|
|
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 getMethod(n *Node) {
|
|
i := n.findex
|
|
next := getExec(n.tnext)
|
|
|
|
n.exec = func(f *Frame) Builtin {
|
|
frame := *f
|
|
node := *(n.val.(*Node))
|
|
node.val = &node
|
|
node.recv = n.recv
|
|
node.frame = &frame
|
|
f.data[i] = reflect.ValueOf(&node)
|
|
return next
|
|
}
|
|
}
|
|
|
|
func getMethodByName(n *Node) {
|
|
next := getExec(n.tnext)
|
|
value0 := genValue(n.child[0])
|
|
name := n.child[1].ident
|
|
i := n.findex
|
|
|
|
n.exec = func(f *Frame) Builtin {
|
|
val := value0(f).Interface().(valueInterface)
|
|
m, li := val.node.typ.lookupMethod(name)
|
|
frame := *f
|
|
node := *m
|
|
node.val = &node
|
|
node.recv = &Receiver{nil, val.value, li}
|
|
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 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 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 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
|
|
if !n.typ.untyped {
|
|
child = n.child[1:]
|
|
}
|
|
|
|
values := make([]func(*Frame) reflect.Value, len(child))
|
|
index := make([]int, len(child))
|
|
rtype := n.typ.val.TypeOf()
|
|
var max, prev int
|
|
|
|
for i, c := range child {
|
|
if c.kind == KeyValueExpr {
|
|
convertLiteralValue(c.child[1], rtype)
|
|
values[i] = genValue(c.child[1])
|
|
index[i] = c.child[0].val.(int)
|
|
} else {
|
|
convertLiteralValue(c, rtype)
|
|
values[i] = genValue(c)
|
|
index[i] = prev
|
|
}
|
|
prev = index[i] + 1
|
|
if prev > max {
|
|
max = prev
|
|
}
|
|
}
|
|
|
|
var a reflect.Value
|
|
if n.typ.size > 0 {
|
|
a, _ = n.typ.zero()
|
|
} else {
|
|
a = reflect.MakeSlice(n.typ.TypeOf(), max, max)
|
|
}
|
|
|
|
n.exec = func(f *Frame) Builtin {
|
|
for i, v := range values {
|
|
a.Index(index[i]).Set(v(f))
|
|
}
|
|
value(f).Set(a)
|
|
return next
|
|
}
|
|
}
|
|
|
|
func mapLit(n *Node) {
|
|
value := valueGenerator(n, n.findex)
|
|
next := getExec(n.tnext)
|
|
child := n.child
|
|
if !n.typ.untyped {
|
|
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
|
|
}
|
|
}
|
|
|
|
// compositeBin creates and populats a struct object from a binary type
|
|
func compositeBin(n *Node) {
|
|
next := getExec(n.tnext)
|
|
value := valueGenerator(n, n.findex)
|
|
typ := n.typ.rtype
|
|
child := n.child[1:]
|
|
values := make([]func(*Frame) reflect.Value, len(child))
|
|
fieldIndex := make([][]int, len(child))
|
|
for i, c := range child {
|
|
if c.kind == KeyValueExpr {
|
|
if sf, ok := typ.FieldByName(c.child[0].ident); ok {
|
|
fieldIndex[i] = sf.Index
|
|
convertLiteralValue(c.child[1], sf.Type)
|
|
if c.child[1].typ.cat == FuncT {
|
|
values[i] = genNodeWrapper(c.child[1])
|
|
} else {
|
|
values[i] = genValue(c.child[1])
|
|
}
|
|
}
|
|
} else {
|
|
fieldIndex[i] = []int{i}
|
|
convertLiteralValue(c.child[1], typ.Field(i).Type)
|
|
if c.typ.cat == FuncT {
|
|
values[i] = genNodeWrapper(c.child[1])
|
|
} else {
|
|
values[i] = genValue(c)
|
|
}
|
|
}
|
|
}
|
|
|
|
n.exec = func(f *Frame) Builtin {
|
|
s := reflect.New(typ).Elem()
|
|
for i, v := range values {
|
|
s.FieldByIndex(fieldIndex[i]).Set(v(f))
|
|
}
|
|
value(f).Set(s)
|
|
return next
|
|
}
|
|
}
|
|
|
|
// compositeLit creates and populates a struct object
|
|
func compositeLit(n *Node) {
|
|
value := valueGenerator(n, n.findex)
|
|
next := getExec(n.tnext)
|
|
child := n.child
|
|
if !n.typ.untyped {
|
|
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())
|
|
if c.typ.cat == FuncT {
|
|
values[i] = genNodeWrapper(c)
|
|
} else {
|
|
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
|
|
if !n.typ.untyped {
|
|
child = n.child[1:]
|
|
}
|
|
|
|
values := make(map[int]func(*Frame) reflect.Value)
|
|
a, _ := n.typ.zero()
|
|
for _, c := range child {
|
|
field := n.typ.fieldIndex(c.child[0].ident)
|
|
convertLiteralValue(c.child[1], n.typ.field[field].typ.TypeOf())
|
|
values[field] = 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) {
|
|
tnext := getExec(n.tnext)
|
|
|
|
switch {
|
|
case n.anc.anc.kind == TypeSwitch:
|
|
fnext := getExec(n.fnext)
|
|
sn := n.anc.anc // switch node
|
|
types := make([]*Type, len(n.child)-1)
|
|
for i := range types {
|
|
types[i] = n.child[i].typ
|
|
}
|
|
value := genValue(sn.child[1].lastChild().child[0])
|
|
if len(sn.child[1].child) == 2 {
|
|
// assign in switch guard
|
|
vaddr := genValueAddr(sn.child[1].child[0])
|
|
switch len(types) {
|
|
case 0:
|
|
// default clause: assign var to interface value
|
|
n.exec = func(f *Frame) Builtin {
|
|
*(vaddr(f)) = value(f)
|
|
return tnext
|
|
}
|
|
case 1:
|
|
// match against 1 type: assign var to concrete value
|
|
typ := types[0]
|
|
n.exec = func(f *Frame) Builtin {
|
|
if v := value(f); !v.IsValid() {
|
|
// match zero value against nil
|
|
if typ.cat == NilT {
|
|
return tnext
|
|
}
|
|
return fnext
|
|
} else if vi := v.Interface().(valueInterface); vi.node.typ.id() == typ.id() {
|
|
*(vaddr(f)) = vi.value
|
|
return tnext
|
|
}
|
|
return fnext
|
|
}
|
|
default:
|
|
// match against multiple types: assign var to interface value
|
|
n.exec = func(f *Frame) Builtin {
|
|
vtyp := value(f).Interface().(valueInterface).node.typ
|
|
for _, typ := range types {
|
|
if vtyp.id() == typ.id() {
|
|
*(vaddr(f)) = value(f)
|
|
return tnext
|
|
}
|
|
}
|
|
return fnext
|
|
}
|
|
}
|
|
} else {
|
|
// no assign in switch guard
|
|
if len(n.child) <= 1 {
|
|
n.exec = func(f *Frame) Builtin { return tnext }
|
|
} else {
|
|
n.exec = func(f *Frame) Builtin {
|
|
vtyp := value(f).Interface().(valueInterface).node.typ
|
|
for _, typ := range types {
|
|
if vtyp.id() == typ.id() {
|
|
return tnext
|
|
}
|
|
}
|
|
return fnext
|
|
}
|
|
}
|
|
}
|
|
|
|
case len(n.child) <= 1: // default clause
|
|
n.exec = func(f *Frame) Builtin { return tnext }
|
|
|
|
default:
|
|
fnext := getExec(n.fnext)
|
|
l := len(n.anc.anc.child)
|
|
value := genValue(n.anc.anc.child[l-2])
|
|
values := make([]func(*Frame) reflect.Value, len(n.child)-1)
|
|
for i := range values {
|
|
values[i] = genValue(n.child[i])
|
|
}
|
|
n.exec = func(f *Frame) Builtin {
|
|
for _, v := range values {
|
|
if value(f).Interface() == v(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
|
|
}
|
|
}
|
|
|
|
func clauseChanDir(n *Node) (*Node, *Node, *Node, reflect.SelectDir) {
|
|
dir := reflect.SelectDefault
|
|
var node, assigned, ok *Node
|
|
var stop bool
|
|
|
|
n.Walk(func(m *Node) bool {
|
|
switch m.action {
|
|
case Recv:
|
|
dir = reflect.SelectRecv
|
|
node = m.child[0]
|
|
switch m.anc.action {
|
|
case Assign:
|
|
assigned = m.anc.child[0]
|
|
case AssignX:
|
|
ok = m.anc.child[1]
|
|
// TODO
|
|
}
|
|
stop = true
|
|
case Send:
|
|
dir = reflect.SelectSend
|
|
node = m.child[0]
|
|
assigned = m.child[1]
|
|
stop = true
|
|
}
|
|
return !stop
|
|
}, nil)
|
|
return node, assigned, ok, dir
|
|
}
|
|
|
|
func _select(n *Node) {
|
|
nbClause := len(n.child)
|
|
chans := make([]*Node, nbClause)
|
|
assigned := make([]*Node, nbClause)
|
|
ok := make([]*Node, nbClause)
|
|
clause := make([]Builtin, nbClause)
|
|
chanValues := make([]func(*Frame) reflect.Value, nbClause)
|
|
assignedValues := make([]func(*Frame) reflect.Value, nbClause)
|
|
okValues := make([]func(*Frame) reflect.Value, nbClause)
|
|
cases := make([]reflect.SelectCase, nbClause)
|
|
|
|
for i := 0; i < nbClause; i++ {
|
|
if len(n.child[i].child) > 1 {
|
|
clause[i] = getExec(n.child[i].child[1].start)
|
|
chans[i], assigned[i], ok[i], cases[i].Dir = clauseChanDir(n.child[i])
|
|
chanValues[i] = genValue(chans[i])
|
|
if assigned[i] != nil {
|
|
assignedValues[i] = genValue(assigned[i])
|
|
}
|
|
if ok[i] != nil {
|
|
okValues[i] = genValue(ok[i])
|
|
}
|
|
} else {
|
|
clause[i] = getExec(n.child[i].child[0].start)
|
|
cases[i].Dir = reflect.SelectDefault
|
|
}
|
|
}
|
|
|
|
n.exec = func(f *Frame) Builtin {
|
|
for i := range cases {
|
|
switch cases[i].Dir {
|
|
case reflect.SelectRecv:
|
|
cases[i].Chan = chanValues[i](f)
|
|
case reflect.SelectSend:
|
|
cases[i].Chan = chanValues[i](f)
|
|
cases[i].Send = assignedValues[i](f)
|
|
case reflect.SelectDefault:
|
|
// Keep zero values for comm clause
|
|
}
|
|
}
|
|
j, v, s := reflect.Select(cases)
|
|
if cases[j].Dir == reflect.SelectRecv && assignedValues[j] != nil {
|
|
assignedValues[j](f).Set(v)
|
|
if ok[j] != nil {
|
|
okValues[j](f).SetBool(s)
|
|
}
|
|
}
|
|
return clause[j]
|
|
}
|
|
}
|
|
|
|
// 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
|
|
}
|
|
}
|
|
}
|