Files
moxa/interp/run.go
Marc Vertes 6657e9a18b feat: add support for named output variables (#113)
* feat: add support for named output variables

Function output parameters are located at the start of the function
frame, uninitialized, as they could be only set through return
statements.

Supporting named output variables requires to:

- identify and allocate symbols corresponding to output names:
  done at ident parsing, with the funcRet() helper,

- compute the location of output name in the frame:
  done with retRank() helper,

- initialize the frame entry with the zero value of symbol type,
  as the symbol can be accessed and written at multiple times,
  and return not setting the variable (opposite to unnamed).
  Done with frameType() helper, which now takes into account
  output parameters.

* refactor: simplify memory management

Perform function frame analysis at pre-order, instead of post-order, to
initialize memory frame, and track value types. Remove all operation
involving unitialized types. Frame memory layout is now build
incrementally, instead of having to perform dedicated tree walks on AST.
2019-03-12 19:58:02 +01:00

1572 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, len(n.types))}
}
for i, t := range n.types {
f.data[i] = reflect.New(t).Elem()
}
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].Set(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].Set(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
}
}
// assignX2 implements multiple value assignment for expression where type is defined
func assignX2(n *Node) {
l := len(n.child) - 2
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)
value := genValue(n)
dest, src := n.child[0], n.lastChild()
var value1 func(*Frame) reflect.Value
switch {
case n.child[0].typ.cat == InterfaceT:
value1 = genValueInterface(src)
case dest.typ.cat == ValueT && src.typ.cat == FuncT:
value1 = genNodeWrapper(src)
default:
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))
}
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
numRet := len(def.typ.ret)
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, len(def.types))}
d := frame.data
for i, t := range def.types {
d[i] = reflect.New(t).Elem()
}
// Copy method receiver as first argument, if defined
if receiver != nil {
d[numRet].Set(receiver(f))
d = d[numRet+1:]
} else {
d = d[numRet:]
}
// Copy function input arguments in local frame
for i, arg := range in {
d[i].Set(arg)
}
// Interpreter code execution
runCfg(start, &frame)
result := frame.data[:numRet]
for i, r := range result {
if v, ok := r.Interface().(*Node); ok {
result[i] = genNodeWrapper(v)(f)
}
}
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
}
numRet := len(n.child[0].typ.ret)
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, len(def.types))}
var vararg reflect.Value
// Init local frame values
for i, t := range def.types {
nf.data[i] = reflect.New(t).Elem()
}
// Init variadic argument vector
if variadic >= 0 {
vararg = nf.data[numRet+variadic]
}
// Copy input parameters from caller
dest := nf.data[numRet:]
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)
}
// Accommodate to receiver type
d := dest[0]
if ks, kd := src.Kind(), d.Kind(); ks != kd {
if kd == reflect.Ptr {
d.Set(src.Addr())
} else {
d.Set(src.Elem())
}
} else {
d.Set(src)
}
case variadic >= 0 && i >= variadic:
vararg.Set(reflect.Append(vararg, v(f)))
default:
dest[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
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)
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)
}
res := value(f).Call(in)
if res[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)
}
copy(f.data[n.findex:], value(f).Call(in))
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)
n.exec = func(f *Frame) Builtin {
frame := *f
node := *n
node.val = &node
node.frame = &frame
f.data[i].Set(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
}
srcValue := genValue(sn.child[1].lastChild().child[0])
if len(sn.child[1].child) == 2 {
// assign in switch guard
destValue := genValue(n.lastChild().child[0])
switch len(types) {
case 0:
// default clause: assign var to interface value
n.exec = func(f *Frame) Builtin {
destValue(f).Set(srcValue(f))
return tnext
}
case 1:
// match against 1 type: assign var to concrete value
typ := types[0]
n.exec = func(f *Frame) Builtin {
v := srcValue(f)
if !v.IsValid() {
// match zero value against nil
if typ.cat == NilT {
return tnext
}
return fnext
}
vi := v.Interface().(valueInterface)
if vi.node == nil {
if typ.cat == NilT {
return tnext
}
return fnext
}
if vi.node.typ.id() == typ.id() {
destValue(f).Set(vi.value)
return tnext
}
return fnext
}
default:
// match against multiple types: assign var to interface value
n.exec = func(f *Frame) Builtin {
val := srcValue(f)
vid := val.Interface().(valueInterface).node.typ.id()
for _, typ := range types {
if vid == typ.id() {
destValue(f).Set(val)
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 := srcValue(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
}
}
}