Skip to content

Commit f08bb63

Browse files
committed
Add Break and Continue
1 parent 7fa4e11 commit f08bb63

File tree

4 files changed

+79
-19
lines changed

4 files changed

+79
-19
lines changed

ast/ast.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,3 +375,21 @@ type Null struct {
375375
func (n *Null) expressionNode() {}
376376
func (n *Null) TokenLiteral() string { return n.Token.Literal }
377377
func (n *Null) String() string { return n.Token.Literal }
378+
379+
type Break struct {
380+
Statement
381+
Token token.Token // the 'break' token
382+
}
383+
384+
func (b *Break) expressionNode() {}
385+
func (b *Break) TokenLiteral() string { return b.Token.Literal }
386+
func (b *Break) String() string { return b.Token.Literal }
387+
388+
type Continue struct {
389+
Statement
390+
Token token.Token // the 'continue' token
391+
}
392+
393+
func (c *Continue) expressionNode() {}
394+
func (c *Continue) TokenLiteral() string { return c.Token.Literal }
395+
func (c *Continue) String() string { return c.Token.Literal }

evaluator/evaluator.go

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ import (
1010
)
1111

1212
var (
13-
NULL = &object.Null{}
14-
TRUE = &object.Boolean{Value: true}
15-
FALSE = &object.Boolean{Value: false}
13+
NULL = &object.Null{}
14+
TRUE = &object.Boolean{Value: true}
15+
FALSE = &object.Boolean{Value: false}
16+
BREAK = &object.Break{}
17+
CONTINUE = &object.Continue{}
1618
)
1719

1820
func Eval(node ast.Node, env *object.Environment) object.Object {
@@ -109,6 +111,10 @@ func Eval(node ast.Node, env *object.Environment) object.Object {
109111
return evalDictLiteral(node, env)
110112
case *ast.WhileExpression:
111113
return evalWhileExpression(node, env)
114+
case *ast.Break:
115+
return evalBreak(node)
116+
case *ast.Continue:
117+
return evalContinue(node)
112118
case *ast.Null:
113119
return NULL
114120
case *ast.AssignmentExpression:
@@ -381,7 +387,7 @@ func evalBlockStatement(block *ast.BlockStatement, env *object.Environment) obje
381387

382388
if result != nil {
383389
rt := result.Type()
384-
if rt == object.RETURN_VALUE_OBJ || rt == object.ERROR_OBJ {
390+
if rt == object.RETURN_VALUE_OBJ || rt == object.ERROR_OBJ || rt == object.CONTINUE_OBJ || rt == object.BREAK_OBJ {
385391
return result
386392
}
387393
}
@@ -550,23 +556,27 @@ func evalDictIndexExpression(dict, index object.Object, line int) object.Object
550556
}
551557

552558
func evalWhileExpression(we *ast.WhileExpression, env *object.Environment) object.Object {
553-
var result object.Object
554-
555-
for {
556-
condition := Eval(we.Condition, env)
557-
if isError(condition) {
558-
return condition
559+
condition := Eval(we.Condition, env)
560+
if isError(condition) {
561+
return condition
562+
}
563+
if isTruthy(condition) {
564+
evaluated := Eval(we.Consequence, env)
565+
if isError(evaluated) {
566+
return evaluated
559567
}
560-
561-
if isTruthy(condition) {
562-
result = Eval(we.Consequence, env)
563-
} else {
564-
break
568+
if evaluated.Type() == object.BREAK_OBJ {
569+
return evaluated
565570
}
571+
evalWhileExpression(we, env)
566572
}
573+
return NULL
574+
}
567575

568-
if result != nil {
569-
return result
570-
}
571-
return nil
576+
func evalBreak(node *ast.Break) object.Object {
577+
return BREAK
578+
}
579+
580+
func evalContinue(node *ast.Continue) object.Object {
581+
return CONTINUE
572582
}

object/object.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ const (
2222
BUILTIN_OBJ = "YA_NDANI"
2323
ARRAY_OBJ = "ARRAY"
2424
DICT_OBJ = "KAMUSI"
25+
CONTINUE_OBJ = "ENDELEA"
26+
BREAK_OBJ = "SUSA"
2527
)
2628

2729
type Object interface {
@@ -189,3 +191,13 @@ func (d *Dict) Inspect() string {
189191
type Hashable interface {
190192
HashKey() HashKey
191193
}
194+
195+
type Continue struct{}
196+
197+
func (c *Continue) Type() ObjectType { return CONTINUE_OBJ }
198+
func (c *Continue) Inspect() string { return "continue" }
199+
200+
type Break struct{}
201+
202+
func (b *Break) Type() ObjectType { return BREAK_OBJ }
203+
func (b *Break) Inspect() string { return "break" }

parser/parser.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ func (p *Parser) parseStatement() ast.Statement {
134134
return p.parseLetStatment()
135135
case token.RETURN:
136136
return p.parseReturnStatement()
137+
case token.BREAK:
138+
return p.parseBreak()
139+
case token.CONTINUE:
140+
return p.parseContinue()
137141
default:
138142
return p.parseExpressionStatement()
139143
}
@@ -560,3 +564,19 @@ func (p *Parser) parseWhileExpression() ast.Expression {
560564

561565
return expression
562566
}
567+
568+
func (p *Parser) parseBreak() *ast.Break {
569+
stmt := &ast.Break{Token: p.curToken}
570+
for p.curTokenIs(token.SEMICOLON) {
571+
p.nextToken()
572+
}
573+
return stmt
574+
}
575+
576+
func (p *Parser) parseContinue() *ast.Continue {
577+
stmt := &ast.Continue{Token: p.curToken}
578+
for p.curTokenIs(token.SEMICOLON) {
579+
p.nextToken()
580+
}
581+
return stmt
582+
}

0 commit comments

Comments
 (0)