-
Notifications
You must be signed in to change notification settings - Fork 171
/
statement_generation.go
131 lines (103 loc) · 3.61 KB
/
statement_generation.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package bytecode
import (
"fmt"
"github.com/goby-lang/goby/ast"
)
func (g *Generator) compileStatements(stmts []ast.Statement, scope *scope, table *localTable) {
is := &instructionSet{label: &label{Name: Program}}
for _, statement := range stmts {
g.compileStatement(is, statement, scope, table)
}
g.endInstructions(is)
g.instructionSets = append(g.instructionSets, is)
}
func (g *Generator) compileStatement(is *instructionSet, statement ast.Statement, scope *scope, table *localTable) {
scope.line++
switch stmt := statement.(type) {
case *ast.ExpressionStatement:
g.compileExpression(is, stmt.Expression, scope, table)
case *ast.DefStatement:
g.compileDefStmt(is, stmt, scope)
case *ast.ClassStatement:
g.compileClassStmt(is, stmt, scope, table)
case *ast.ModuleStatement:
g.compileModuleStmt(is, stmt, scope)
case *ast.ReturnStatement:
g.compileExpression(is, stmt.ReturnValue, scope, table)
g.endInstructions(is)
case *ast.WhileStatement:
g.compileWhileStmt(is, stmt, scope, table)
case *ast.NextStatement:
g.compileNextStatement(is, scope)
}
}
func (g *Generator) compileWhileStmt(is *instructionSet, stmt *ast.WhileStatement, scope *scope, table *localTable) {
anchor1 := &anchor{}
is.define(Jump, anchor1)
is.define(PutNull)
is.define(Pop)
is.define(Jump, anchor1)
anchor2 := &anchor{is.Count}
scope.anchor = anchor1
g.compileCodeBlock(is, stmt.Body, scope, table)
anchor1.line = is.Count
g.compileExpression(is, stmt.Condition, scope, table)
is.define(BranchIf, anchor2)
is.define(PutNull)
is.define(Pop)
}
func (g *Generator) compileNextStatement(is *instructionSet, scope *scope) {
is.define(Jump, scope.anchor)
}
func (g *Generator) compileClassStmt(is *instructionSet, stmt *ast.ClassStatement, scope *scope, table *localTable) {
is.define(PutSelf)
if stmt.SuperClass != nil {
g.compileExpression(is, stmt.SuperClass, scope, table)
is.define(DefClass, "class:"+stmt.Name.Value, stmt.SuperClassName)
} else {
is.define(DefClass, "class:"+stmt.Name.Value)
}
is.define(Pop)
scope = newScope(scope, stmt)
// compile class's content
newIS := &instructionSet{}
newIS.setLabel(fmt.Sprintf("%s:%s", LabelDefClass, stmt.Name.Value))
g.compileCodeBlock(newIS, stmt.Body, scope, scope.localTable)
newIS.define(Leave)
g.instructionSets = append(g.instructionSets, newIS)
}
func (g *Generator) compileModuleStmt(is *instructionSet, stmt *ast.ModuleStatement, scope *scope) {
is.define(PutSelf)
is.define(DefClass, "module:"+stmt.Name.Value)
is.define(Pop)
scope = newScope(scope, stmt)
newIS := &instructionSet{}
newIS.setLabel(fmt.Sprintf("%s:%s", LabelDefClass, stmt.Name.Value))
g.compileCodeBlock(newIS, stmt.Body, scope, scope.localTable)
newIS.define(Leave)
g.instructionSets = append(g.instructionSets, newIS)
}
func (g *Generator) compileDefStmt(is *instructionSet, stmt *ast.DefStatement, scope *scope) {
is.define(PutSelf)
is.define(PutString, fmt.Sprintf("\"%s\"", stmt.Name.Value))
switch stmt.Receiver.(type) {
case *ast.SelfExpression:
is.define(DefSingletonMethod, len(stmt.Parameters))
case nil:
is.define(DefMethod, len(stmt.Parameters))
}
scope = newScope(scope, stmt)
// compile method definition's content
newIS := &instructionSet{}
newIS.setLabel(fmt.Sprintf("%s:%s", LabelDef, stmt.Name.Value))
for i := 0; i < len(stmt.Parameters); i++ {
scope.localTable.setLCL(stmt.Parameters[i].Value, scope.localTable.depth)
}
if len(stmt.BlockStatement.Statements) == 0 {
newIS.define(PutNull)
} else {
g.compileCodeBlock(newIS, stmt.BlockStatement, scope, scope.localTable)
}
g.endInstructions(newIS)
g.instructionSets = append(g.instructionSets, newIS)
}