|
|
|
|
@ -277,6 +277,22 @@ func TestInterpretBinaryExprInvalidOperatorType(t *testing.T) {
|
|
|
|
|
i.VisitBinaryExpr(binary)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestInterpretLogicalExpr(t *testing.T) {
|
|
|
|
|
i := New(errors.NewMockErrorLogger())
|
|
|
|
|
left := &ast.LiteralExpr{Value: true}
|
|
|
|
|
right := &ast.LiteralExpr{Value: false}
|
|
|
|
|
logical := &ast.LogicalExpr{
|
|
|
|
|
Left: left,
|
|
|
|
|
Operator: token.Token{Type: token.AND, Lexeme: "and"},
|
|
|
|
|
Right: right,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result := i.VisitLogicalExpr(logical)
|
|
|
|
|
if result != false {
|
|
|
|
|
t.Errorf("expected false, got %v", result)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestInterpretErrorStatement(t *testing.T) {
|
|
|
|
|
i := New(errors.NewMockErrorLogger())
|
|
|
|
|
errorStmt := &ast.ErrorStmt{Value: "error"}
|
|
|
|
|
@ -538,3 +554,68 @@ func TestInterpretIfStatementElseBranch(t *testing.T) {
|
|
|
|
|
t.Errorf("run() = %v; want %v", out, expected)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestInterpretWhileStatement(t *testing.T) {
|
|
|
|
|
old := os.Stdout // keep backup of the real stdout
|
|
|
|
|
r, w, err := os.Pipe()
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
os.Stdout = w
|
|
|
|
|
|
|
|
|
|
outC := make(chan string)
|
|
|
|
|
// copy the output in a separate goroutine so printing can't block indefinitely
|
|
|
|
|
go func() {
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
io.Copy(&buf, r)
|
|
|
|
|
outC <- buf.String()
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
// begin unit test
|
|
|
|
|
i := New(errors.NewMockErrorLogger())
|
|
|
|
|
varStmt := &ast.VarStmt{
|
|
|
|
|
Name: token.Token{Type: token.IDENTIFIER, Lexeme: "i"},
|
|
|
|
|
Initializer: &ast.LiteralExpr{Value: 3.0},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i.VisitVarStmt(varStmt)
|
|
|
|
|
|
|
|
|
|
whileStmt := &ast.WhileStmt{
|
|
|
|
|
Condition: &ast.BinaryExpr{
|
|
|
|
|
Left: &ast.VariableExpr{Name: token.Token{Type: token.IDENTIFIER, Lexeme: "i"}},
|
|
|
|
|
Operator: token.Token{Type: token.GREATER, Lexeme: ">"},
|
|
|
|
|
Right: &ast.LiteralExpr{Value: 0.0},
|
|
|
|
|
},
|
|
|
|
|
Body: &ast.BlockStmt{
|
|
|
|
|
Statements: []ast.Stmt{
|
|
|
|
|
&ast.PrintStmt{
|
|
|
|
|
Expression: &ast.VariableExpr{Name: token.Token{Type: token.IDENTIFIER, Lexeme: "i"}},
|
|
|
|
|
},
|
|
|
|
|
&ast.ExpressionStmt{
|
|
|
|
|
Expression: &ast.AssignExpr{
|
|
|
|
|
Name: token.Token{Type: token.IDENTIFIER, Lexeme: "i"},
|
|
|
|
|
Value: &ast.BinaryExpr{
|
|
|
|
|
Left: &ast.VariableExpr{Name: token.Token{Type: token.IDENTIFIER, Lexeme: "i"}},
|
|
|
|
|
Operator: token.Token{Type: token.MINUS, Lexeme: "-"},
|
|
|
|
|
Right: &ast.LiteralExpr{Value: 1.0},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i.VisitWhileStmt(whileStmt)
|
|
|
|
|
// end unit test
|
|
|
|
|
|
|
|
|
|
// back to normal state
|
|
|
|
|
w.Close()
|
|
|
|
|
os.Stdout = old // restoring the real stdout
|
|
|
|
|
out := <-outC
|
|
|
|
|
|
|
|
|
|
// reading our temp stdout
|
|
|
|
|
expected := "3\n2\n1\n"
|
|
|
|
|
if out != expected {
|
|
|
|
|
t.Errorf("run() = %v; want %v", out, expected)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|