757 lines
19 KiB
Go
757 lines
19 KiB
Go
package interp
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"time"
|
|
)
|
|
|
|
// Builtin type defines functions which run at CFG execution
|
|
type Builtin func(n *Node, f *Frame)
|
|
|
|
var builtin = [...]Builtin{
|
|
Nop: nop,
|
|
Addr: addr,
|
|
ArrayLit: arrayLit,
|
|
Assign: assign,
|
|
AssignX: assignX,
|
|
Assign0: assign0,
|
|
Add: add,
|
|
And: and,
|
|
Call: call,
|
|
CallF: call,
|
|
Case: _case,
|
|
CompositeLit: arrayLit,
|
|
Dec: nop,
|
|
Equal: equal,
|
|
GetFunc: getFunc,
|
|
GetIndex: getIndex,
|
|
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,
|
|
}
|
|
|
|
var goBuiltin = map[string]Builtin{
|
|
"append": _append,
|
|
"len": _len,
|
|
"make": _make,
|
|
"println": _println,
|
|
"sleep": sleep,
|
|
}
|
|
|
|
// Run a Go function
|
|
func Run(def *Node, cf *Frame, recv *Node, rseq []int, args []*Node, rets []int, fork bool, goroutine bool) {
|
|
//log.Println("run", def.index, def.child[1].ident, "allocate", def.flen)
|
|
// Allocate a new Frame to store local variables
|
|
anc := cf.anc
|
|
if fork {
|
|
anc = cf
|
|
} else if def.frame != nil {
|
|
anc = def.frame
|
|
}
|
|
f := Frame{anc: anc, data: make([]interface{}, def.flen)}
|
|
|
|
// Assign receiver value, if defined (for methods)
|
|
if recv != nil {
|
|
if rseq != nil {
|
|
f.data[def.child[0].findex] = valueSeq(recv, rseq, cf) // Promoted method
|
|
} else {
|
|
f.data[def.child[0].findex] = value(recv, cf)
|
|
}
|
|
}
|
|
|
|
// Pass func parameters by value: copy each parameter from caller frame
|
|
// Get list of param indices built by FuncType at CFG
|
|
defargs := def.child[2].child[0]
|
|
paramIndex := defargs.val.([]int)
|
|
i := 0
|
|
for k, arg := range args {
|
|
// Variadic: store remaining args in array
|
|
if i < len(defargs.child) && defargs.child[i].typ.variadic {
|
|
variadic := make([]interface{}, len(args[k:]))
|
|
for l, a := range args[k:] {
|
|
variadic[l] = value(a, cf)
|
|
}
|
|
f.data[paramIndex[i]] = variadic
|
|
break
|
|
} else {
|
|
f.data[paramIndex[i]] = value(arg, cf)
|
|
i++
|
|
// Handle multiple results of a function call argmument
|
|
for j := 1; j < arg.fsize; j++ {
|
|
f.data[paramIndex[i]] = cf.data[arg.findex+j]
|
|
i++
|
|
}
|
|
}
|
|
}
|
|
// Handle empty variadic arg
|
|
if l := len(defargs.child) - 1; len(args) <= l && defargs.child[l].typ.variadic {
|
|
f.data[paramIndex[l]] = []interface{}{}
|
|
}
|
|
|
|
// Execute the function body
|
|
if goroutine {
|
|
go runCfg(def.child[3].start, &f)
|
|
} else {
|
|
runCfg(def.child[3].start, &f)
|
|
// Propagate return values to caller frame
|
|
for i, ret := range rets {
|
|
cf.data[ret] = f.data[i]
|
|
}
|
|
}
|
|
}
|
|
|
|
// Functions set to run during execution of CFG
|
|
|
|
func value(n *Node, f *Frame) interface{} {
|
|
switch n.kind {
|
|
case BasicLit, FuncDecl, SelectorSrc:
|
|
return n.val
|
|
case Rvalue:
|
|
return n.rval
|
|
default:
|
|
if n.sym != nil {
|
|
if n.sym.index < 0 {
|
|
return value(n.sym.node, f)
|
|
}
|
|
for level := n.level; level > 0; level-- {
|
|
f = f.anc
|
|
}
|
|
return f.data[n.sym.index]
|
|
}
|
|
for level := n.level; level > 0; level-- {
|
|
f = f.anc
|
|
}
|
|
if n.findex < 0 {
|
|
return n.val
|
|
}
|
|
return f.data[n.findex]
|
|
}
|
|
}
|
|
|
|
func addrValue(n *Node, f *Frame) *interface{} {
|
|
switch n.kind {
|
|
case BasicLit, FuncDecl, Rvalue:
|
|
return &n.val
|
|
default:
|
|
if n.sym != nil {
|
|
if n.sym.index < 0 {
|
|
return addrValue(n.sym.node, f)
|
|
}
|
|
for level := n.level; level > 0; level-- {
|
|
f = f.anc
|
|
}
|
|
return &f.data[n.sym.index]
|
|
}
|
|
for level := n.level; level > 0; level-- {
|
|
f = f.anc
|
|
}
|
|
if n.findex < 0 {
|
|
return &n.val
|
|
}
|
|
return &f.data[n.findex]
|
|
}
|
|
}
|
|
|
|
// Run by walking the CFG and running node builtin at each step
|
|
func runCfg(n *Node, f *Frame) {
|
|
for n != nil {
|
|
n.run(n, f)
|
|
if n.fnext == nil || value(n, f).(bool) {
|
|
n = n.tnext
|
|
} else {
|
|
n = n.fnext
|
|
}
|
|
}
|
|
}
|
|
|
|
func typeAssert(n *Node, f *Frame) {
|
|
f.data[n.findex] = value(n.child[0], f)
|
|
}
|
|
|
|
func convert(n *Node, f *Frame) {
|
|
f.data[n.findex] = value(n.child[1], f)
|
|
}
|
|
|
|
func convertFuncBin(n *Node, f *Frame) {
|
|
// TODO: use closure generation to improve speed
|
|
f.data[n.findex] = reflect.MakeFunc(n.child[0].typ.rtype.Elem(), n.child[1].wrapNode).Interface()
|
|
}
|
|
|
|
func convertBin(n *Node, f *Frame) {
|
|
// TODO: use closure generation to improve speed
|
|
f.data[n.findex] = reflect.ValueOf(value(n.child[1], f)).Convert(n.child[0].typ.TypeOf()).Interface()
|
|
}
|
|
|
|
// assignX implements multiple value assignement
|
|
func assignX(n *Node, f *Frame) {
|
|
l := len(n.child) - 1
|
|
b := n.child[l].findex
|
|
for i, c := range n.child[:l] {
|
|
*addrValue(c, f) = f.data[b+i]
|
|
}
|
|
}
|
|
|
|
// Indirect assign
|
|
func indirectAssign(n *Node, f *Frame) {
|
|
*(f.data[n.findex].(*interface{})) = value(n.child[1], f)
|
|
}
|
|
|
|
// assign implements single value assignement
|
|
func assign(n *Node, f *Frame) {
|
|
*addrValue(n, f) = value(n.child[1], f)
|
|
}
|
|
|
|
// assign0 implements assignement of zero value
|
|
func assign0(n *Node, f *Frame) {
|
|
l := len(n.child) - 1
|
|
z := n.typ.zero()
|
|
for _, c := range n.child[:l] {
|
|
*addrValue(c, f) = z
|
|
}
|
|
}
|
|
|
|
func assignField(n *Node, f *Frame) {
|
|
(*f.data[n.findex].(*interface{})) = value(n.child[1], f)
|
|
}
|
|
|
|
func assignPtrField(n *Node, f *Frame) {
|
|
(*f.data[n.findex].(*interface{})) = value(n.child[1], f)
|
|
}
|
|
|
|
func assignMap(n *Node, f *Frame) {
|
|
f.data[n.findex].(map[interface{}]interface{})[value(n.child[0].child[1], f)] = value(n.child[1], f)
|
|
}
|
|
|
|
func and(n *Node, f *Frame) {
|
|
f.data[n.findex] = value(n.child[0], f).(int) & value(n.child[1], f).(int)
|
|
}
|
|
|
|
func not(n *Node, f *Frame) {
|
|
f.data[n.findex] = !value(n.child[0], f).(bool)
|
|
}
|
|
|
|
func addr(n *Node, f *Frame) {
|
|
f.data[n.findex] = addrValue(n.child[0], f)
|
|
}
|
|
|
|
func deref(n *Node, f *Frame) {
|
|
f.data[n.findex] = *(value(n.child[0], f).(*interface{}))
|
|
}
|
|
|
|
func _println(n *Node, f *Frame) {
|
|
for i, m := range n.child[1:] {
|
|
if i > 0 {
|
|
fmt.Printf(" ")
|
|
}
|
|
fmt.Printf("%v", value(m, f))
|
|
|
|
// Handle multiple results of a function call argmument
|
|
for j := 1; j < m.fsize; j++ {
|
|
fmt.Printf(" %v", f.data[m.findex+j])
|
|
}
|
|
}
|
|
fmt.Println("")
|
|
}
|
|
|
|
// wrapNode wraps a call to an interpreter node in a function that can be called from runtime
|
|
func (n *Node) wrapNode(in []reflect.Value) []reflect.Value {
|
|
def := n.val.(*Node)
|
|
var result []reflect.Value
|
|
if n.frame == nil {
|
|
n.frame = n.interp.Frame
|
|
}
|
|
frame := Frame{anc: n.frame, data: make([]interface{}, def.flen)}
|
|
|
|
// If fucnction is a method, set its receiver data in the frame
|
|
if len(def.child[0].child) > 0 {
|
|
frame.data[def.child[0].findex] = value(n.recv, n.frame)
|
|
}
|
|
|
|
// Unwrap input arguments from their reflect value and store them in the frame
|
|
paramIndex := def.child[2].child[0].val.([]int)
|
|
i := 0
|
|
for _, arg := range in {
|
|
frame.data[paramIndex[i]] = arg.Interface()
|
|
i++
|
|
}
|
|
|
|
// Interpreter code execution
|
|
runCfg(def.child[3].start, &frame)
|
|
|
|
// Wrap output results in reflect values and return them
|
|
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] = reflect.ValueOf(frame.data[i])
|
|
}
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func call(n *Node, f *Frame) {
|
|
// TODO: method detection should be done at CFG, and handled in a separate callMethod()
|
|
var recv *Node
|
|
var rseq []int
|
|
var forkFrame bool
|
|
|
|
if n.action == CallF {
|
|
forkFrame = true
|
|
}
|
|
|
|
if n.child[0].kind == SelectorExpr && n.child[0].typ.cat != SrcPkgT {
|
|
recv = n.child[0].recv
|
|
rseq = n.child[0].child[1].val.([]int)
|
|
}
|
|
//log.Println(n.index, "call", n.child[0].ident, value(n.child[0], f))
|
|
fn := value(n.child[0], f).(*Node)
|
|
var ret []int
|
|
if len(fn.child[2].child) > 1 {
|
|
if fieldList := fn.child[2].child[1]; fieldList != nil {
|
|
ret = make([]int, len(fieldList.child))
|
|
for i := range fieldList.child {
|
|
ret[i] = n.findex + i
|
|
}
|
|
}
|
|
}
|
|
Run(fn, f, recv, rseq, n.child[1:], ret, forkFrame, false)
|
|
}
|
|
|
|
// Same as call(), but execute function in a goroutine
|
|
func callGoRoutine(n *Node, f *Frame) {
|
|
//println(n.index, "call", n.child[0].ident)
|
|
// TODO: method detection should be done at CFG, and handled in a separate callMethod()
|
|
var recv *Node
|
|
var rseq []int
|
|
var forkFrame bool
|
|
|
|
if n.action == CallF {
|
|
forkFrame = true
|
|
}
|
|
|
|
if n.child[0].kind == SelectorExpr {
|
|
recv = n.child[0].recv
|
|
rseq = n.child[0].child[1].val.([]int)
|
|
}
|
|
fn := value(n.child[0], f).(*Node)
|
|
var ret []int
|
|
if len(fn.child[2].child) > 1 {
|
|
if fieldList := fn.child[2].child[1]; fieldList != nil {
|
|
ret = make([]int, len(fieldList.child))
|
|
for i := range fieldList.child {
|
|
ret[i] = n.findex + i
|
|
}
|
|
}
|
|
}
|
|
Run(fn, f, recv, rseq, n.child[1:], ret, forkFrame, true)
|
|
}
|
|
|
|
// Same as callBin, but for handling f(g()) where g returns multiple values
|
|
func callBinX(n *Node, f *Frame) {
|
|
l := n.child[1].fsize
|
|
b := n.child[1].findex
|
|
in := make([]reflect.Value, l)
|
|
for i := 0; i < l; i++ {
|
|
in[i] = reflect.ValueOf(f.data[b+i])
|
|
}
|
|
fun := value(n.child[0], f).(reflect.Value)
|
|
v := fun.Call(in)
|
|
for i := 0; i < n.fsize; i++ {
|
|
f.data[n.findex+i] = v[i].Interface()
|
|
}
|
|
}
|
|
|
|
// Call a function from a bin import, accessible through reflect
|
|
func callDirectBin(n *Node, f *Frame) {
|
|
in := make([]reflect.Value, len(n.child)-1)
|
|
for i, c := range n.child[1:] {
|
|
if c.kind == Rvalue {
|
|
in[i] = value(c, f).(reflect.Value)
|
|
c.frame = f
|
|
} else {
|
|
in[i] = reflect.ValueOf(value(c, f))
|
|
}
|
|
}
|
|
fun := reflect.ValueOf(value(n.child[0], f))
|
|
v := fun.Call(in)
|
|
for i := 0; i < n.fsize; i++ {
|
|
f.data[n.findex+i] = v[i].Interface()
|
|
}
|
|
}
|
|
|
|
// Call a function from a bin import, accessible through reflect
|
|
func callBin(n *Node, f *Frame) {
|
|
in := make([]reflect.Value, len(n.child)-1)
|
|
for i, c := range n.child[1:] {
|
|
if c.kind == Rvalue {
|
|
in[i] = value(c, f).(reflect.Value)
|
|
c.frame = f
|
|
} else {
|
|
//log.Println(value(c, f), c.sym, c.level)
|
|
in[i] = reflect.ValueOf(value(c, f))
|
|
}
|
|
}
|
|
fun := value(n.child[0], f).(reflect.Value)
|
|
//log.Println(n.index, "in:", in)
|
|
v := fun.Call(in)
|
|
for i := 0; i < n.fsize; i++ {
|
|
f.data[n.findex+i] = v[i].Interface()
|
|
}
|
|
}
|
|
|
|
// Call a method defined by an interface type on an object returned by a bin import, through reflect.
|
|
// In that case, the method func value can be resolved only at execution from the actual value
|
|
// of node, not during CFG.
|
|
func callBinInterfaceMethod(n *Node, f *Frame) {
|
|
}
|
|
|
|
// Call a method on an object returned by a bin import function, through reflect
|
|
func callBinMethod(n *Node, f *Frame) {
|
|
//fun := value(n.child[0], f).(reflect.Value)
|
|
fun := n.child[0].rval
|
|
in := make([]reflect.Value, len(n.child))
|
|
in[0] = reflect.ValueOf(value(n.child[0].child[0], f))
|
|
for i, c := range n.child[1:] {
|
|
if c.kind == Rvalue {
|
|
in[i+1] = value(c, f).(reflect.Value)
|
|
c.frame = f
|
|
} else {
|
|
in[i+1] = reflect.ValueOf(value(c, f))
|
|
}
|
|
}
|
|
//log.Println(n.index, "in callBinMethod", n.ident, in, in[0].MethodByName(n.child[0].child[1].ident).Type())
|
|
if !fun.IsValid() {
|
|
fun = in[0].MethodByName(n.child[0].child[1].ident)
|
|
in = in[1:]
|
|
}
|
|
v := fun.Call(in)
|
|
for i := 0; i < n.fsize; i++ {
|
|
f.data[n.findex+i] = v[i].Interface()
|
|
}
|
|
}
|
|
|
|
// Same as callBinMethod, but for handling f(g()) where g returns multiple values
|
|
func callBinMethodX(n *Node, f *Frame) {
|
|
fun := value(n.child[0], f).(reflect.Value)
|
|
l := n.child[1].fsize
|
|
b := n.child[1].findex
|
|
in := make([]reflect.Value, l+1)
|
|
in[0] = reflect.ValueOf(value(n.child[0].child[0], f))
|
|
for i := 0; i < l; i++ {
|
|
in[i+1] = reflect.ValueOf(f.data[b+i])
|
|
}
|
|
v := fun.Call(in)
|
|
for i := 0; i < n.fsize; i++ {
|
|
f.data[n.findex+i] = v[i].Interface()
|
|
}
|
|
}
|
|
|
|
func getPtrIndexAddr(n *Node, f *Frame) {
|
|
a := (*value(n.child[0], f).(*interface{})).([]interface{})
|
|
f.data[n.findex] = &a[value(n.child[1], f).(int)]
|
|
}
|
|
|
|
func getIndexAddr(n *Node, f *Frame) {
|
|
a := value(n.child[0], f).([]interface{})
|
|
f.data[n.findex] = &a[value(n.child[1], f).(int)]
|
|
}
|
|
|
|
func getPtrIndex(n *Node, f *Frame) {
|
|
// if error, fallback to getIndex, to make receiver methods work both with pointers and objects
|
|
if a, ok := value(n.child[0], f).(*interface{}); ok {
|
|
f.data[n.findex] = (*a).([]interface{})[value(n.child[1], f).(int)]
|
|
} else {
|
|
getIndex(n, f)
|
|
}
|
|
}
|
|
|
|
func getPtrIndexBin(n *Node, f *Frame) {
|
|
a := reflect.ValueOf(value(n.child[0], f)).Elem()
|
|
f.data[n.findex] = a.FieldByIndex(n.val.([]int)).Interface()
|
|
}
|
|
|
|
func getIndexBinMethod(n *Node, f *Frame) {
|
|
a := reflect.ValueOf(value(n.child[0], f))
|
|
f.data[n.findex] = a.MethodByName(n.child[1].ident)
|
|
}
|
|
|
|
func getIndexBin(n *Node, f *Frame) {
|
|
a := reflect.ValueOf(value(n.child[0], f))
|
|
f.data[n.findex] = a.FieldByIndex(n.val.([]int))
|
|
}
|
|
|
|
func getIndex(n *Node, f *Frame) {
|
|
a := value(n.child[0], f).([]interface{})
|
|
f.data[n.findex] = a[value(n.child[1], f).(int)]
|
|
}
|
|
|
|
func getIndexMap(n *Node, f *Frame) {
|
|
m := value(n.child[0], f).(map[interface{}]interface{})
|
|
if f.data[n.findex], f.data[n.findex+1] = m[value(n.child[1], f)]; !f.data[n.findex+1].(bool) {
|
|
// Force a zero value if key is not present in map
|
|
f.data[n.findex] = n.child[0].typ.val.zero()
|
|
}
|
|
}
|
|
|
|
func getFunc(n *Node, f *Frame) {
|
|
node := *n
|
|
node.val = &node
|
|
frame := *f
|
|
node.frame = &frame
|
|
f.data[n.findex] = &node
|
|
n.interp.Frame = &frame // Temporary, store context for futur call from runtime
|
|
}
|
|
|
|
func getMap(n *Node, f *Frame) {
|
|
f.data[n.findex] = value(n.child[0], f).(map[interface{}]interface{})
|
|
}
|
|
|
|
func getPtrIndexSeq(n *Node, f *Frame) {
|
|
a := (*value(n.child[0], f).(*interface{})).([]interface{})
|
|
seq := value(n.child[1], f).([]int)
|
|
l := len(seq) - 1
|
|
for _, i := range seq[:l] {
|
|
a = a[i].([]interface{})
|
|
}
|
|
f.data[n.findex] = a[seq[l]]
|
|
}
|
|
|
|
func getIndexSeq(n *Node, f *Frame) {
|
|
a := value(n.child[0], f).([]interface{})
|
|
seq := value(n.child[1], f).([]int)
|
|
l := len(seq) - 1
|
|
for _, i := range seq[:l] {
|
|
a = a[i].([]interface{})
|
|
}
|
|
f.data[n.findex] = a[seq[l]]
|
|
}
|
|
|
|
func valueSeq(n *Node, seq []int, f *Frame) interface{} {
|
|
a := f.data[n.findex].([]interface{})
|
|
l := len(seq) - 1
|
|
for _, i := range seq[:l] {
|
|
a = a[i].([]interface{})
|
|
}
|
|
return a[seq[l]]
|
|
}
|
|
|
|
func mul(n *Node, f *Frame) {
|
|
f.data[n.findex] = value(n.child[0], f).(int) * value(n.child[1], f).(int)
|
|
}
|
|
|
|
func quotient(n *Node, f *Frame) {
|
|
f.data[n.findex] = value(n.child[0], f).(int) / value(n.child[1], f).(int)
|
|
}
|
|
|
|
func remain(n *Node, f *Frame) {
|
|
f.data[n.findex] = value(n.child[0], f).(int) % value(n.child[1], f).(int)
|
|
}
|
|
|
|
func negate(n *Node, f *Frame) {
|
|
f.data[n.findex] = -value(n.child[0], f).(int)
|
|
}
|
|
|
|
func add(n *Node, f *Frame) {
|
|
f.data[n.findex] = value(n.child[0], f).(int) + value(n.child[1], f).(int)
|
|
}
|
|
|
|
func sub(n *Node, f *Frame) {
|
|
f.data[n.findex] = value(n.child[0], f).(int) - value(n.child[1], f).(int)
|
|
}
|
|
|
|
func equal(n *Node, f *Frame) {
|
|
f.data[n.findex] = value(n.child[0], f) == value(n.child[1], f)
|
|
}
|
|
|
|
func notEqual(n *Node, f *Frame) {
|
|
f.data[n.findex] = value(n.child[0], f) != value(n.child[1], f)
|
|
}
|
|
|
|
func indirectInc(n *Node, f *Frame) {
|
|
*(f.data[n.findex].(*interface{})) = value(n.child[0], f).(int) + 1
|
|
}
|
|
|
|
func inc(n *Node, f *Frame) {
|
|
*addrValue(n, f) = value(n.child[0], f).(int) + 1
|
|
}
|
|
|
|
func greater(n *Node, f *Frame) {
|
|
f.data[n.findex] = value(n.child[0], f).(int) > value(n.child[1], f).(int)
|
|
}
|
|
|
|
func land(n *Node, f *Frame) {
|
|
if v := value(n.child[0], f).(bool); v {
|
|
f.data[n.findex] = value(n.child[1], f).(bool)
|
|
} else {
|
|
f.data[n.findex] = v
|
|
}
|
|
}
|
|
|
|
func lor(n *Node, f *Frame) {
|
|
if v := value(n.child[0], f).(bool); v {
|
|
f.data[n.findex] = v
|
|
} else {
|
|
f.data[n.findex] = value(n.child[1], f).(bool)
|
|
}
|
|
}
|
|
|
|
func lower(n *Node, f *Frame) {
|
|
f.data[n.findex] = value(n.child[0], f).(int) < value(n.child[1], f).(int)
|
|
}
|
|
|
|
func nop(n *Node, f *Frame) {}
|
|
|
|
func _return(n *Node, f *Frame) {
|
|
for i, c := range n.child {
|
|
f.data[i] = value(c, f)
|
|
}
|
|
}
|
|
|
|
// create an array of litteral values
|
|
func arrayLit(n *Node, f *Frame) {
|
|
a := make([]interface{}, len(n.child)-1)
|
|
for i, c := range n.child[1:] {
|
|
a[i] = value(c, f)
|
|
}
|
|
f.data[n.findex] = a
|
|
}
|
|
|
|
// Create a map of litteral values
|
|
func mapLit(n *Node, f *Frame) {
|
|
m := make(map[interface{}]interface{})
|
|
for _, c := range n.child[1:] {
|
|
m[value(c.child[0], f)] = value(c.child[1], f)
|
|
}
|
|
f.data[n.findex] = m
|
|
}
|
|
|
|
// Create a struct object
|
|
func compositeLit(n *Node, f *Frame) {
|
|
l := len(n.typ.field)
|
|
a := n.typ.zero().([]interface{})
|
|
for i := 0; i < l; i++ {
|
|
if i < len(n.child[1:]) {
|
|
c := n.child[i+1]
|
|
a[i] = value(c, f)
|
|
} else {
|
|
a[i] = n.typ.field[i].typ.zero()
|
|
}
|
|
}
|
|
f.data[n.findex] = a
|
|
}
|
|
|
|
// Create a struct Object, filling fields from sparse key-values
|
|
func compositeSparse(n *Node, f *Frame) {
|
|
a := n.typ.zero().([]interface{})
|
|
for _, c := range n.child[1:] {
|
|
// index from key was pre-computed during CFG
|
|
a[c.findex] = value(c.child[1], f)
|
|
}
|
|
f.data[n.findex] = a
|
|
}
|
|
|
|
func _range(n *Node, f *Frame) {
|
|
i, index := 0, n.child[0].findex
|
|
if f.data[index] != nil {
|
|
i = f.data[index].(int) + 1
|
|
}
|
|
a := value(n.child[2], f).([]interface{})
|
|
if i >= len(a) {
|
|
f.data[n.findex] = false
|
|
return
|
|
}
|
|
f.data[index] = i
|
|
f.data[n.child[1].findex] = a[i]
|
|
f.data[n.findex] = true
|
|
}
|
|
|
|
func _case(n *Node, f *Frame) {
|
|
f.data[n.findex] = value(n.anc.anc.child[0], f) == value(n.child[0], f)
|
|
}
|
|
|
|
// TODO: handle variable number of arguments to append
|
|
func _append(n *Node, f *Frame) {
|
|
a := value(n.child[1], f).([]interface{})
|
|
f.data[n.findex] = append(a, value(n.child[2], f))
|
|
}
|
|
|
|
func _len(n *Node, f *Frame) {
|
|
a := value(n.child[1], f).([]interface{})
|
|
f.data[n.findex] = len(a)
|
|
}
|
|
|
|
// Allocates and initializes a slice, a map or a chan.
|
|
func _make(n *Node, f *Frame) {
|
|
typ := value(n.child[1], f).(*Type)
|
|
switch typ.cat {
|
|
case ArrayT:
|
|
f.data[n.findex] = make([]interface{}, value(n.child[2], f).(int))
|
|
case ChanT:
|
|
f.data[n.findex] = make(chan interface{})
|
|
case MapT:
|
|
f.data[n.findex] = make(map[interface{}]interface{})
|
|
}
|
|
}
|
|
|
|
// Read from a channel
|
|
func recv(n *Node, f *Frame) {
|
|
f.data[n.findex] = <-value(n.child[0], f).(chan interface{})
|
|
}
|
|
|
|
// Write to a channel
|
|
func send(n *Node, f *Frame) {
|
|
value(n.child[0], f).(chan interface{}) <- value(n.child[1], f)
|
|
}
|
|
|
|
// slice expression
|
|
func slice(n *Node, f *Frame) {
|
|
a := value(n.child[0], f).([]interface{})
|
|
switch len(n.child) {
|
|
case 2:
|
|
f.data[n.findex] = a[value(n.child[1], f).(int):]
|
|
case 3:
|
|
f.data[n.findex] = a[value(n.child[1], f).(int):value(n.child[2], f).(int)]
|
|
case 4:
|
|
f.data[n.findex] = a[value(n.child[1], f).(int):value(n.child[2], f).(int):value(n.child[3], f).(int)]
|
|
}
|
|
}
|
|
|
|
// slice expression, no low value
|
|
func slice0(n *Node, f *Frame) {
|
|
//log.Println(n.index, n.child[0].ident, value(n.child[0], f))
|
|
a := value(n.child[0], f).([]interface{})
|
|
switch len(n.child) {
|
|
case 1:
|
|
f.data[n.findex] = a[:]
|
|
case 2:
|
|
f.data[n.findex] = a[0:value(n.child[1], f).(int)]
|
|
case 3:
|
|
f.data[n.findex] = a[0:value(n.child[1], f).(int):value(n.child[2], f).(int)]
|
|
}
|
|
}
|
|
|
|
// Temporary, for debugging purppose
|
|
func sleep(n *Node, f *Frame) {
|
|
duration := time.Duration(value(n.child[1], f).(int))
|
|
time.Sleep(duration * time.Millisecond)
|
|
}
|