better implementation of multiple assign

This commit is contained in:
Marc Vertes
2018-02-13 12:43:37 +01:00
parent 592d1bc0ac
commit bd06be616d
4 changed files with 25 additions and 36 deletions

View File

@@ -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{}

View File

@@ -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

View File

@@ -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

View File

@@ -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)
}
}