-
Notifications
You must be signed in to change notification settings - Fork 0
/
eval.go
116 lines (100 loc) · 1.83 KB
/
eval.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package scrl
import (
"fmt"
"io"
"os"
"time"
)
func (self *Vm) Eval(stack *Stack, pc Pc) (Pc, error) {
NEXT:
switch op := self.ops[pc].(type) {
case *AndOp:
v := stack.PeekBack()
if v.IsTrue() {
stack.PopBack()
pc++
} else {
pc = op.falsePc
}
goto NEXT
case *BenchOpT:
reps := stack.PopBack().d.(int)
startTime := time.Now()
pc++
startPc := pc
for i := 0; i < reps; i++ {
var err error
if pc, err = self.Eval(stack, startPc); err != nil {
return pc, err
}
stack.Clear()
}
stack.PushBack(NewVal(&AbcLib.TimeType, time.Now().Sub(startTime)))
goto NEXT
case *CallOp:
var err error
pc, err = op.target.Call(self, stack, op.pos, pc+1)
if err != nil {
return pc, err
}
goto NEXT
case *DequeOp:
d := NewValDeque(stack.Cut(op.itemCount))
stack.PushBack(NewVal(&AbcLib.DequeType, d))
pc++
goto NEXT
case *FunArgOp:
stack.PushBack(self.calls.PeekBack().args[op.index])
pc++
goto NEXT
case *GotoOp:
pc = op.pc
goto NEXT
case *IfOp:
v := stack.PopBack()
if v.IsTrue() {
pc++
} else {
pc = op.elsePc
}
goto NEXT
case *OrOp:
v := stack.PeekBack()
if v.IsTrue() {
pc = op.truePc
} else {
stack.PopBack()
pc++
}
goto NEXT
case *PairOpT:
r := stack.PopBack()
l := stack.PopBack()
stack.PushBack(NewVal(&AbcLib.PairType, NewPair(l, r)))
pc++
goto NEXT
case *PushOp:
stack.PushBack(op.val)
pc++
goto NEXT
case *RetOpT:
pc = self.calls.PopBack().retPc
goto NEXT
case *SetOp:
s := NewValSet(stack.Cut(op.itemCount))
stack.PushBack(NewVal(&AbcLib.SetType, s))
pc++
goto NEXT
case *StopOpT:
//Exit
case *TraceOpT:
pc++
fmt.Fprintf(os.Stdout, "%v ", pc)
self.ops[pc].Dump(os.Stdout)
io.WriteString(os.Stdout, "\n")
goto NEXT
default:
return pc, fmt.Errorf("Invalid op: %v %v", pc, op)
}
return pc, nil
}