Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Interpreter/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/shubhdevelop/YAPL/YaplErrors"
"github.com/shubhdevelop/YAPL/ast"
"github.com/shubhdevelop/YAPL/environment"
"github.com/shubhdevelop/YAPL/state"
)

type Interpreter struct {
Expand Down Expand Up @@ -262,6 +263,10 @@ func (i *Interpreter) VisitLogicalExpr(expr ast.Logical) interface{} {
func (i *Interpreter) VisitWhileStmtStmt(stmt ast.WhileStmt) interface{} {
for i.isTruthy(i.evaluate(stmt.Condition)) {
i.execute(stmt.Body)
if state.AbruptCompletion {
state.AbruptCompletion = false
break
}
}
return nil
}
Expand All @@ -276,5 +281,13 @@ func (i *Interpreter) executeBlock(statements []ast.Stmt, environment *environme
i.Environment = environment
for _, stmt := range statements {
i.execute(stmt)
if state.AbruptCompletion {
break
}
}
}

func (i *Interpreter) VisitBreakStmtStmt(stmt ast.BreakStmt) interface{} {
state.AbruptCompletion = true
return nil
}
37 changes: 35 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ YAPL (Yet Another Programming Language) is a dynamically-typed, interpreted prog
### Reserved Keywords

```
and, class, else, false, for, fun, if, nil, or, print, return, super, this, true, var, while
and, break, class, else, false, for, fun, if, nil, or, print, return, super, this, true, var, while
```

**Note**: `class`, `fun`, `return`, `super`, and `this` are reserved for future implementation.
Expand Down Expand Up @@ -123,6 +123,21 @@ while (i < 5) {
for (var j = 0; j < 3; j = j + 1) {
print "Iteration: " + j;
}

// Break statement
var a = 1;
while (a < 100) {
while (a < 40) {
if (a == 39) {
break; // Breaks out of inner loop only
}
print a;
a = a + 1;
}
print "now outside";
print a;
a = a + 1;
}
```

#### Block Scoping
Expand Down Expand Up @@ -193,7 +208,7 @@ This implementation represents a mature interpreter with comprehensive language
### ✅ Implemented Features

- **Complete Expression System**: All arithmetic, comparison, logical, and unary operations
- **Control Flow**: `if`/`else` statements, `while` loops, and `for` loops (desugared to while)
- **Control Flow**: `if`/`else` statements, `while` loops, `for` loops (desugared to while), and `break` statements
- **Variable Management**: Declaration, assignment, and proper scoping with block environments
- **Data Types**: Numbers (float64), strings, booleans, and nil
- **Error Handling**: Comprehensive lexical, parse, and runtime error reporting
Expand Down Expand Up @@ -243,6 +258,7 @@ This implementation represents a mature interpreter with comprehensive language
- **If Statement**: `if (condition) statement else statement`
- **While Loop**: `while (condition) statement`
- **For Loop**: `for (initializer; condition; increment) statement`
- **Break Statement**: `break;` (exits the innermost loop)
- **Block Statement**: `{ statement1; statement2; ... }`

#### **Variables**
Expand All @@ -251,6 +267,23 @@ This implementation represents a mature interpreter with comprehensive language
- **Scope**: Block-scoped variables with proper environment nesting
- **Lookup**: Variables are looked up in the current scope and enclosing scopes

#### **Break Statement**
- **Syntax**: `break;`
- **Purpose**: Exits the innermost loop (while or for) immediately
- **Scope**: Only affects the current loop level, outer loops continue normally
- **Usage**: Must be used inside a loop body
- **Example**:
```yapl
var i = 0;
while (i < 10) {
if (i == 5) {
break; // Exits the while loop when i equals 5
}
print i;
i = i + 1;
}
```

#### **Comments**
- **Single-line comments**: `// This is a comment`

Expand Down
1 change: 1 addition & 0 deletions Scanner/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ var KeywordMap = map[string]token.TokenType{
"true": token.TRUE,
"var": token.VAR,
"while": token.WHILE,
"break": token.BREAK,
}

func (s *Scanner) isAtEnd() bool {
Expand Down
3 changes: 2 additions & 1 deletion Token/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const (
TRUE
VAR
WHILE
BREAK

// End of file
EOF
Expand All @@ -66,7 +67,7 @@ func (t TokenType) String() string {
"LESS", "LESS_EQUAL",
"IDENTIFIER", "STRING", "NUMBER",
"AND", "CLASS", "ELSE", "FALSE", "FUN", "FOR", "IF", "NIL", "OR",
"PRINT", "RETURN", "SUPER", "THIS", "TRUE", "VAR", "WHILE",
"PRINT", "RETURN", "SUPER", "THIS", "TRUE", "VAR", "WHILE", "BREAK",
"EOF",
}[t]
}
Expand Down
8 changes: 8 additions & 0 deletions ast/stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type StmtVisitor interface {
VisitPrintStmtStmt(stmt PrintStmt) interface{}
VisitVarStmtStmt(stmt VarStmt) interface{}
VisitWhileStmtStmt(stmt WhileStmt) interface{}
VisitBreakStmtStmt(stmt BreakStmt) interface{}
}

type Stmt interface {
Expand Down Expand Up @@ -69,3 +70,10 @@ func (n WhileStmt) Accept(visitor StmtVisitor) interface{} {
return visitor.VisitWhileStmtStmt(n)
}

type BreakStmt struct {
}

func (n BreakStmt) Accept(visitor StmtVisitor) interface{} {
return visitor.VisitBreakStmtStmt(n)
}

19 changes: 18 additions & 1 deletion parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/shubhdevelop/YAPL/Token"
"github.com/shubhdevelop/YAPL/YaplErrors"
"github.com/shubhdevelop/YAPL/ast"
"github.com/shubhdevelop/YAPL/state"
)

type Parser struct {
Expand Down Expand Up @@ -272,7 +273,9 @@ func (p *Parser) statement() ast.Stmt {
if p.match(token.PRINT) {
return p.printStatement()
}

if p.match(token.BREAK) {
return p.breakStatement()
}
if p.match(token.WHILE) {
return p.whileStatement()
}
Expand Down Expand Up @@ -307,7 +310,9 @@ func (p *Parser) forStatement() ast.Stmt {
}
p.consume(token.RIGHT_PAREN, "Expect ')' after for clauses.")

state.CanInsertBreakStatement = true
body := p.statement()
state.CanInsertBreakStatement = false

if increment != nil {
body = ast.BlockStmt{
Expand Down Expand Up @@ -361,14 +366,26 @@ func (p *Parser) whileStatement() ast.Stmt {
p.consume(token.LEFT_PAREN, "Expect '(' after 'while'.")
condition := p.expression()
p.consume(token.RIGHT_PAREN, "Expect ')' after condition.")

state.CanInsertBreakStatement = true
body := p.statement()
state.CanInsertBreakStatement = false
return ast.WhileStmt{
Condition: condition,
Body: body,
}

}

func (p *Parser) breakStatement() ast.Stmt {
if !state.CanInsertBreakStatement {
p.error(p.peek(), "breakStatement can only exist inside valid iterator")

}
p.consume(token.SEMICOLON, "Expect ';' after value.")
return ast.BreakStmt{}
}

func (p *Parser) block() []ast.Stmt {
statements := []ast.Stmt{}
for !p.check(token.RIGHT_BRACE) && !p.isAtEnd() {
Expand Down
1 change: 1 addition & 0 deletions printer/generateAst.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,5 +125,6 @@ func main() {
"PrintStmt : Expr expression",
"VarStmt : token.Token name, Expr initializer",
"WhileStmt: Expr condition, Stmt body",
"BreakStmt: ",
}, []string{"github.com/shubhdevelop/YAPL/Token"})
}
2 changes: 2 additions & 0 deletions state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ package state

var HadError bool = false
var HadRuntimeError = false
var CanInsertBreakStatement = false
var AbruptCompletion = false
Loading