config/lang: make formal Stack object

This commit is contained in:
Mitchell Hashimoto 2015-01-13 09:46:13 -08:00
parent 6d9db3139c
commit d1a0ea9d9b
1 changed files with 32 additions and 15 deletions

View File

@ -44,7 +44,7 @@ func (e *Engine) Execute(root ast.Node) (interface{}, ast.Type, error) {
type executeVisitor struct {
Scope *Scope
stack []*ast.LiteralNode
stack EngineStack
err error
lock sync.Mutex
}
@ -58,15 +58,15 @@ func (v *executeVisitor) Visit(root ast.Node) (interface{}, ast.Type, error) {
// Get our result and clear out everything else
var result *ast.LiteralNode
if len(v.stack) > 0 {
result = v.stack[len(v.stack)-1]
if v.stack.Len() > 0 {
result = v.stack.Pop()
} else {
result = new(ast.LiteralNode)
}
resultErr := v.err
// Clear everything else so we aren't just dangling
v.stack = nil
v.stack.Reset()
v.err = nil
return result.Value, result.Type, resultErr
@ -102,7 +102,7 @@ func (v *executeVisitor) visitCall(n *ast.Call) {
// The arguments are on the stack in reverse order, so pop them off.
args := make([]interface{}, len(n.Args))
for i, _ := range n.Args {
node := v.stackPop()
node := v.stack.Pop()
args[len(n.Args)-1-i] = node.Value
}
@ -114,7 +114,7 @@ func (v *executeVisitor) visitCall(n *ast.Call) {
}
// Push the result
v.stackPush(&ast.LiteralNode{
v.stack.Push(&ast.LiteralNode{
Value: result,
Type: function.ReturnType,
})
@ -125,7 +125,7 @@ func (v *executeVisitor) visitConcat(n *ast.Concat) {
// order. So pop them off, reverse their order, and concatenate.
nodes := make([]*ast.LiteralNode, 0, len(n.Exprs))
for range n.Exprs {
nodes = append(nodes, v.stackPop())
nodes = append(nodes, v.stack.Pop())
}
var buf bytes.Buffer
@ -133,14 +133,14 @@ func (v *executeVisitor) visitConcat(n *ast.Concat) {
buf.WriteString(nodes[i].Value.(string))
}
v.stackPush(&ast.LiteralNode{
v.stack.Push(&ast.LiteralNode{
Value: buf.String(),
Type: ast.TypeString,
})
}
func (v *executeVisitor) visitLiteral(n *ast.LiteralNode) {
v.stack = append(v.stack, n)
v.stack.Push(n)
}
func (v *executeVisitor) visitVariableAccess(n *ast.VariableAccess) {
@ -151,22 +151,39 @@ func (v *executeVisitor) visitVariableAccess(n *ast.VariableAccess) {
return
}
v.stack = append(v.stack, &ast.LiteralNode{
v.stack.Push(&ast.LiteralNode{
Value: variable.Value,
Type: variable.Type,
})
}
func (v *executeVisitor) stackPush(n *ast.LiteralNode) {
v.stack = append(v.stack, n)
// EngineStack is a stack of ast.LiteralNodes that the Engine keeps track
// of during execution. This is currently backed by a dumb slice, but can be
// replaced with a better data structure at some point in the future if this
// turns out to require optimization.
type EngineStack struct {
stack []*ast.LiteralNode
}
func (v *executeVisitor) stackPop() *ast.LiteralNode {
var x *ast.LiteralNode
x, v.stack = v.stack[len(v.stack)-1], v.stack[:len(v.stack)-1]
func (s *EngineStack) Len() int {
return len(s.stack)
}
func (s *EngineStack) Push(n *ast.LiteralNode) {
s.stack = append(s.stack, n)
}
func (s *EngineStack) Pop() *ast.LiteralNode {
x := s.stack[len(s.stack)-1]
s.stack[len(s.stack)-1] = nil
s.stack = s.stack[:len(s.stack)-1]
return x
}
func (s *EngineStack) Reset() {
s.stack = nil
}
// Scope represents a lookup scope for execution.
type Scope struct {
// VarMap and FuncMap are the mappings of identifiers to functions