78 lines
2.2 KiB
Go
78 lines
2.2 KiB
Go
// Package interp implements a Go interpreter.
|
|
package interp
|
|
|
|
import (
|
|
"go/ast"
|
|
)
|
|
|
|
// Function to run at CFG execution
|
|
type RunFun func(n *Node, i *Interpreter)
|
|
|
|
// Structure for AST and CFG
|
|
type Node struct {
|
|
Child []*Node // child subtrees
|
|
anc *Node // ancestor
|
|
Start *Node // entry point in subtree (CFG)
|
|
snext *Node // successor (CFG)
|
|
next [2]*Node // conditional successors, for false and for true (CFG)
|
|
index int // node index (dot display)
|
|
findex int // index of value in frame
|
|
run RunFun // function to run at CFG execution
|
|
val *interface{} // pointer on generic value (CFG execution)
|
|
ident string // set if node is a var or func
|
|
isNop bool // node run function us a no-op
|
|
isConst bool // node value is a constant
|
|
anode *ast.Node // original ast node (temporary, will be removed)
|
|
}
|
|
|
|
// A Frame contains values for the current execution level
|
|
type Frame struct {
|
|
up *Frame // up level in call stack
|
|
down *Frame // down in call stack
|
|
val []interface{} // array of values
|
|
}
|
|
|
|
// Interpreter contains global resources and state
|
|
type Interpreter struct {
|
|
sym map[string]*interface{}
|
|
constant map[string]*interface{}
|
|
frame *Frame
|
|
out interface{}
|
|
}
|
|
|
|
// n.isLeaf() returns true if Node n is a leaf in the AST
|
|
func (n *Node) isLeaf() bool {
|
|
return len((*n).Child) == 0
|
|
}
|
|
|
|
// n.Walk(cbin, cbout) traverses AST n in depth first order, call cbin function
|
|
// at node entry and cbout function at node exit.
|
|
func (n *Node) Walk(cbin func(n *Node), cbout func(n *Node)) {
|
|
if cbin != nil {
|
|
cbin(n)
|
|
}
|
|
for _, Child := range n.Child {
|
|
Child.Walk(cbin, cbout)
|
|
}
|
|
if cbout != nil {
|
|
cbout(n)
|
|
}
|
|
}
|
|
|
|
// NewInterpreter()creates and returns a new interpreter object
|
|
func NewInterpreter() *Interpreter {
|
|
return &Interpreter{sym: make(map[string]*interface{})}
|
|
}
|
|
|
|
// i.Eval(s) evaluates Go code represented as a string
|
|
func (i *Interpreter) Eval(src string) interface{} {
|
|
root := Ast(src)
|
|
//root.AstDot()
|
|
entry := root.Child[1].Child[2] // FIXME: entry point should be resolved from 'main' name
|
|
entry.Cfg()
|
|
entry.OptimCfg()
|
|
//entry.CfgDot()
|
|
i.Run(entry.Start)
|
|
return i.out
|
|
}
|