better implementation of multiple assign
This commit is contained in:
@@ -24,19 +24,9 @@ func Ast(src string) *Node {
|
||||
// is used to keep track of curent ancestor for each depth level
|
||||
ast.Inspect(f, func(node ast.Node) bool {
|
||||
anc = st.top()
|
||||
switch n := node.(type) {
|
||||
switch node.(type) {
|
||||
case nil:
|
||||
anc = st.pop()
|
||||
case *ast.AssignStmt:
|
||||
index++
|
||||
var i interface{}
|
||||
nod := &Node{anc: anc, index: index, anode: &node, val: &i, lhs: len(n.Lhs)}
|
||||
if anc == nil {
|
||||
root = nod
|
||||
} else {
|
||||
anc.Child = append(anc.Child, nod)
|
||||
}
|
||||
st.push(nod)
|
||||
default:
|
||||
index++
|
||||
var i interface{}
|
||||
|
||||
@@ -6,8 +6,6 @@ import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// TODO: remove coupling with go/ast and go/token. This should be handled only in Ast()
|
||||
|
||||
// n.Cfg() generates a control flow graph (CFG) from AST (wiring successors in AST)
|
||||
func (e *Node) Cfg(i *Interpreter) int {
|
||||
symIndex := make(map[string]int)
|
||||
@@ -25,7 +23,7 @@ func (e *Node) Cfg(i *Interpreter) int {
|
||||
}
|
||||
}
|
||||
}, func(n *Node) {
|
||||
switch x := (*n.anode).(type) {
|
||||
switch a := (*n.anode).(type) {
|
||||
case *ast.FuncDecl:
|
||||
n.findex = maxIndex + 1
|
||||
n.isConst = true
|
||||
@@ -41,13 +39,17 @@ func (e *Node) Cfg(i *Interpreter) int {
|
||||
n.run = _return
|
||||
case *ast.IncDecStmt:
|
||||
wireChild(n)
|
||||
switch x.Tok {
|
||||
switch a.Tok {
|
||||
case token.INC:
|
||||
n.run = inc
|
||||
}
|
||||
n.findex = n.Child[0].findex
|
||||
case *ast.AssignStmt:
|
||||
n.run = assign
|
||||
if len(a.Lhs) > 1 && len(a.Rhs) == 1 {
|
||||
n.run = assignX
|
||||
} else {
|
||||
n.run = assign
|
||||
}
|
||||
wireChild(n)
|
||||
n.findex = n.Child[0].findex
|
||||
case *ast.ExprStmt:
|
||||
@@ -64,7 +66,7 @@ func (e *Node) Cfg(i *Interpreter) int {
|
||||
n.findex = n.Child[len(n.Child)-1].findex
|
||||
case *ast.BinaryExpr:
|
||||
wireChild(n)
|
||||
switch x.Op {
|
||||
switch a.Op {
|
||||
case token.ADD:
|
||||
n.run = add
|
||||
case token.AND:
|
||||
@@ -123,17 +125,17 @@ func (e *Node) Cfg(i *Interpreter) int {
|
||||
case *ast.BasicLit:
|
||||
n.isConst = true
|
||||
// FIXME: values must be converted to int or float if possible
|
||||
if v, err := strconv.ParseInt(x.Value, 0, 0); err == nil {
|
||||
if v, err := strconv.ParseInt(a.Value, 0, 0); err == nil {
|
||||
n.val = v
|
||||
} else {
|
||||
n.val = x.Value
|
||||
n.val = a.Value
|
||||
}
|
||||
case *ast.Ident:
|
||||
// Lookup identifier in frame symbol table. If not found
|
||||
// should check if ident can be defined (assign, param passing...)
|
||||
// or should lookup in upper scope of variables
|
||||
// For now, simply allocate a new entry in local sym table
|
||||
n.ident = x.Name
|
||||
n.ident = a.Name
|
||||
if n.findex = symIndex[n.ident]; n.findex == 0 {
|
||||
maxIndex++
|
||||
symIndex[n.ident] = maxIndex
|
||||
|
||||
@@ -19,7 +19,6 @@ type Node struct {
|
||||
findex int // index of value in frame or frame size (func def)
|
||||
run RunFun // function to run at CFG execution
|
||||
val interface{} // pointer on generic value (CFG execution)
|
||||
lhs int // number of left hand side nodes, set if node is an assign statement
|
||||
ident string // set if node is a var or func
|
||||
isNop bool // node run function us a no-op
|
||||
isConst bool // true if node value is constant
|
||||
|
||||
@@ -42,22 +42,20 @@ func value(n *Node, f *Frame) interface{} {
|
||||
|
||||
}
|
||||
|
||||
// AssignX(n, f) implements assignement for a single call which returns multiple values
|
||||
func assignX(n *Node, f *Frame) {
|
||||
l := len(n.Child) - 1
|
||||
b := n.Child[l].findex
|
||||
for i, c := range n.Child[:l] {
|
||||
(*f)[c.findex] = (*f)[b+i]
|
||||
}
|
||||
}
|
||||
|
||||
// Assign implements assignement with the same number of left and right values
|
||||
func assign(n *Node, f *Frame) {
|
||||
// FIXME: should have different assign flavors set by CFG instead
|
||||
if n.lhs > 1 {
|
||||
if len(n.Child)-n.lhs > 1 {
|
||||
// multiple single assign
|
||||
for i := 0; i < n.lhs; i++ {
|
||||
(*f)[n.Child[i].findex] = value(n.Child[len(n.Child)-n.lhs+i], f)
|
||||
}
|
||||
} else {
|
||||
// Multiple vars set from a single call
|
||||
for i := 0; i < n.lhs; i++ {
|
||||
(*f)[n.Child[i].findex] = (*f)[n.Child[len(n.Child)-1].findex+i]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
(*f)[n.findex] = value(n.Child[1], f)
|
||||
l := len(n.Child) / 2
|
||||
for i, c := range n.Child[:l] {
|
||||
(*f)[c.findex] = value(n.Child[l+i], f)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user