Skip to content

Commit

Permalink
fix: break statement out of for loop give an error #19
Browse files Browse the repository at this point in the history
  • Loading branch information
gravataLonga committed Jun 27, 2022
1 parent 1ec9487 commit a5f84fe
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 1 deletion.
2 changes: 2 additions & 0 deletions evaluator/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ func evalProgram(stmts []ast.Statement, env *object.Environment) object.Object {
switch result := result.(type) {
case *object.ReturnValue:
return result.Value
case *object.Break:
return object.NewErrorFormat("'break' not in the 'loop' context")
case *object.Error:
return result
}
Expand Down
10 changes: 10 additions & 0 deletions evaluator/evaluator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"testing"
)

// testBooleanObject helper for testing if object.Object is equal expected.
func testBooleanObject(t *testing.T, obj object.Object, expected bool) bool {
result, ok := obj.(*object.Boolean)
if !ok {
Expand All @@ -21,6 +22,7 @@ func testBooleanObject(t *testing.T, obj object.Object, expected bool) bool {
return true
}

// testIntegerObject helper for testing if object.Object is equal expected.
func testIntegerObject(t *testing.T, obj object.Object, expected int64) bool {
result, ok := obj.(*object.Integer)
if !ok {
Expand All @@ -35,6 +37,7 @@ func testIntegerObject(t *testing.T, obj object.Object, expected int64) bool {
return true
}

// testStringObject helper for testing if object.Object is equal expected.
func testStringObject(t *testing.T, obj object.Object, expected string) bool {
result, ok := obj.(*object.String)
if !ok {
Expand All @@ -49,6 +52,7 @@ func testStringObject(t *testing.T, obj object.Object, expected string) bool {
return true
}

// testFloatObject helper for testing if object.Object is equal expected.
func testFloatObject(t *testing.T, obj object.Object, expected float64) bool {
result, ok := obj.(*object.Float)
if !ok {
Expand All @@ -63,6 +67,7 @@ func testFloatObject(t *testing.T, obj object.Object, expected float64) bool {
return true
}

// testNullObject helper for testing if object.Object is equal expected NULL.
func testNullObject(t *testing.T, obj object.Object) bool {
if obj != object.NULL {
t.Errorf("object is not NULL. got=%T (%+v)", obj, obj)
Expand All @@ -71,6 +76,8 @@ func testNullObject(t *testing.T, obj object.Object) bool {
return true
}

// testObjectLiteral helper for testing if object is equal expected interface{}
// we will decide which object test based on value passed in interface{}
func testObjectLiteral(
t *testing.T,
objectResult object.Object,
Expand Down Expand Up @@ -145,6 +152,7 @@ func testObjectLiteral(
return false
}

// checkParserErrors check if there are parser errors
func checkParserErrors(t *testing.T, p *parser.Parser) {
errors := p.Errors()
if len(errors) == 0 {
Expand All @@ -157,6 +165,8 @@ func checkParserErrors(t *testing.T, p *parser.Parser) {
t.FailNow()
}

// testEval execute input code and check if there are parser error
// and return result object.Object
func testEval(input string, t *testing.T) object.Object {
l := lexer.New(input)
p := parser.New(l)
Expand Down
22 changes: 22 additions & 0 deletions evaluator/for_statement_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,25 @@ func TestForStatement(t *testing.T) {
}
}
}

func TestBreakOutsideForLoop(t *testing.T) {
input := `break`
expected := "'break' not in the 'loop' context"

evaluated := testEval(input, t)

if evaluated == nil {
t.Fatalf("evaluated is empty")
}

err, ok := evaluated.(*object.Error)

if !ok {
t.Fatalf("expected error. Got: %s", evaluated.Inspect())
}

if err.Message != expected {
t.Fatalf("expected error message to be %s, got: %s", expected, err.Message)
}

}
2 changes: 1 addition & 1 deletion object/break.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ type Break struct {
Value Object
}

func (b *Break) Type() ObjectType { return RETURN_VALUE_OBJ }
func (b *Break) Type() ObjectType { return BREAK_VALUE_OBJ }
func (b *Break) Inspect() string { return b.Value.Inspect() }

0 comments on commit a5f84fe

Please sign in to comment.