-
Notifications
You must be signed in to change notification settings - Fork 0
/
vm_writer.go
116 lines (97 loc) · 2.94 KB
/
vm_writer.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 main
import (
"fmt"
"io"
"strconv"
)
type VMSegmentType string
const (
InvalidVMSegmentType VMSegmentType = ""
ConstVMSegment VMSegmentType = "constant"
ArgumentVMSegment VMSegmentType = "argument"
LocalVMSegment VMSegmentType = "local"
StaticVMSegment VMSegmentType = "static"
ThisVMSegment VMSegmentType = "this"
ThatVMSegment VMSegmentType = "that"
PointerVMSegment VMSegmentType = "pointer"
TempVMSegment VMSegmentType = "temp"
)
type VMOperation string
const (
InvalidVMOperation VMOperation = ""
AddVMOperation VMOperation = "add"
SubVMOperation VMOperation = "sub"
NegVMOperation VMOperation = "neg"
EqVMOperation VMOperation = "eq"
GtVMOperation VMOperation = "gt"
LtVMOperation VMOperation = "lt"
AndVMOperation VMOperation = "and"
OrvMOperation VMOperation = "or"
NotVMOperation VMOperation = "not"
MulVMOperation VMOperation = "mul"
DivVMOperation VMOperation = "div"
)
type VMWriter struct {
output io.Writer
}
func NewVMWriter(w io.Writer) VMWriter {
return VMWriter{output: w}
}
func (w *VMWriter) WriteCommand(command string) {
io.WriteString(w.output, command)
io.WriteString(w.output, "\n")
}
func (w *VMWriter) WritePush(segment VMSegmentType, index MachineWord) {
w.WriteCommand(fmt.Sprintf("push %s %d", segment, index))
}
func (w *VMWriter) WritePop(segment VMSegmentType, index MachineWord) {
w.WriteCommand(fmt.Sprintf("pop %s %d", segment, index))
}
func (w *VMWriter) WriteStringConstant(constant string) {
w.WritePush(ConstVMSegment, MachineWord(len(constant)))
w.WriteCall("String.new", 1)
// Store allocated string pointer in temp segment
w.WritePop(TempVMSegment, 0)
for _, c := range constant {
// Push stored pointer to object
w.WritePush(TempVMSegment, 0)
// Push the character
w.WritePush(ConstVMSegment, MachineWord(c))
// Append another character
w.WriteCall("String.appendChar", 2)
// Remove 0 return value
w.WritePop(TempVMSegment, 1)
}
// Leave pointer to string constant on top of stack
w.WritePush(TempVMSegment, 0)
}
func (w *VMWriter) WriteArithmetic(operation VMOperation) {
switch operation {
case DivVMOperation:
w.WriteCall("Math.divide", 2)
case MulVMOperation:
w.WriteCall("Math.multiply", 2)
default:
w.WriteCommand(string(operation))
}
}
func (w *VMWriter) WriteLabel(label string) {
w.WriteCommand("label " + label)
}
func (w *VMWriter) WriteGoto(label string) {
w.WriteCommand("goto " + label)
}
func (w *VMWriter) WriteIf(label string) {
w.WriteCommand("if-goto " + label)
}
func (w *VMWriter) WriteCall(label string, nargs MachineWord) {
w.WriteCommand("call " + label + " " + strconv.FormatUint(uint64(nargs), 10))
}
func (w *VMWriter) WriteFunction(label string, nlocals MachineWord) {
w.WriteCommand("function " + label + " " + strconv.FormatUint(uint64(nlocals), 10))
}
func (w *VMWriter) WriteReturn() {
w.WriteCommand("return")
}
func (w *VMWriter) Close() {
}