Skip to content

Commit 71b68c4

Browse files
committed
✨ Lexer support for while loops
1 parent d8ed491 commit 71b68c4

File tree

9 files changed

+49
-9
lines changed

9 files changed

+49
-9
lines changed

PascalInterpreter/PascalInterpreter/Lexer/Lexer.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public class Lexer {
4343
"FOR": .for,
4444
"TO": .to,
4545
"DO": .do,
46+
"WHILE": .while
4647
]
4748

4849
public init(_ text: String) {

PascalInterpreter/PascalInterpreter/Lexer/Token+Extensions.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ extension Token: Equatable {
6969
return true
7070
case (.do, .do):
7171
return true
72+
case (.while, .while):
73+
return true
7274
default:
7375
return false
7476
}
@@ -211,6 +213,8 @@ extension Token: CustomStringConvertible {
211213
return "TO"
212214
case .do:
213215
return "DO"
216+
case .while:
217+
return "WHILE"
214218
}
215219
}
216220
}

PascalInterpreter/PascalInterpreter/Lexer/Token.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,5 @@ public enum Token {
6565
case `for`
6666
case to
6767
case `do`
68+
case `while`
6869
}

PascalInterpreter/PascalInterpreter/Parser/AST+Extensions.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ extension AST {
120120
return "REPEAT"
121121
case is For:
122122
return "FOR"
123+
case is While:
124+
return "WHILE"
123125
default:
124126
fatalError("Missed AST case \(self)")
125127
}
@@ -185,6 +187,8 @@ extension AST {
185187
return []
186188
case let repeatUntil as RepeatUntil:
187189
return [repeatUntil.condition, repeatUntil.statement]
190+
case let whileLoop as While:
191+
return [whileLoop.condition, whileLoop.statement]
188192
case let forLoop as For:
189193
return [forLoop.variable, forLoop.startValue, forLoop.endValue, forLoop.statement]
190194
default:

PascalInterpreter/PascalInterpreter/Parser/AST.swift

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,22 @@ class IfElse: AST {
198198
}
199199
}
200200

201-
class RepeatUntil: AST {
201+
protocol Loop: AST {
202+
var statement: AST { get }
203+
var condition: Condition { get }
204+
}
205+
206+
class RepeatUntil: Loop {
207+
let statement: AST
208+
let condition: Condition
209+
210+
init(statement: AST, condition: Condition) {
211+
self.statement = statement
212+
self.condition = condition
213+
}
214+
}
215+
216+
class While: Loop {
202217
let statement: AST
203218
let condition: Condition
204219

PascalInterpreter/PascalInterpreter/Parser/Parser.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ public class Parser {
325325

326326
/**
327327
Rule:
328-
328+
329329
for_loop : FOR variable ASSIGN expression TO expression DO statement
330330
*/
331331
private func forLoop() -> For {

PascalInterpreter/PascalInterpreter/Semantic analyzer/Visitor.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ protocol Visitor: class {
2727
func visit(call: FunctionCall)
2828
func visit(condition: Condition)
2929
func visit(ifElse: IfElse)
30-
func visit(repeatUntil: RepeatUntil)
30+
func visit(loop: Loop)
3131
func visit(forLoop: For)
3232
}
3333

@@ -68,8 +68,8 @@ extension Visitor {
6868
visit(condition: condition)
6969
case let ifElse as IfElse:
7070
visit(ifElse: ifElse)
71-
case let repeatUntil as RepeatUntil:
72-
visit(repeatUntil: repeatUntil)
71+
case let loop as Loop:
72+
visit(loop: loop)
7373
case let forLoop as For:
7474
visit(forLoop: forLoop)
7575
default:
@@ -163,9 +163,9 @@ extension Visitor {
163163
}
164164
}
165165

166-
func visit(repeatUntil: RepeatUntil) {
167-
visit(node: repeatUntil.statement)
168-
visit(node: repeatUntil.condition)
166+
func visit(loop: Loop) {
167+
visit(node: loop.statement)
168+
visit(node: loop.condition)
169169
}
170170

171171
func visit(forLoop: For) {

PascalInterpreter/PascalInterpreterTests/LexerTests.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,4 +465,19 @@ class LexerTests: XCTestCase {
465465
XCTAssert(lexer.getNextToken() == .parenthesis(.right))
466466
XCTAssert(lexer.getNextToken() == .eof)
467467
}
468+
469+
func testWhileTokens() {
470+
let lexer = Lexer("while x<5 do x:= x+1 ")
471+
XCTAssert(lexer.getNextToken() == .while)
472+
XCTAssert(lexer.getNextToken() == .id("x"))
473+
XCTAssert(lexer.getNextToken() == .lessThan)
474+
XCTAssert(lexer.getNextToken() == .constant(.integer(5)))
475+
XCTAssert(lexer.getNextToken() == .do)
476+
XCTAssert(lexer.getNextToken() == .id("x"))
477+
XCTAssert(lexer.getNextToken() == .assign)
478+
XCTAssert(lexer.getNextToken() == .id("x"))
479+
XCTAssert(lexer.getNextToken() == .operation(.plus))
480+
XCTAssert(lexer.getNextToken() == .constant(.integer(1)))
481+
XCTAssert(lexer.getNextToken() == .eof)
482+
}
468483
}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Simple Swift interpreter for the Pascal language inspired by the [Let’s Build
1414
* function calls
1515
* procedure calls
1616
* recursion
17-
* loops (for, repet until)
17+
* loops (for, repet until, while)
1818
* logical conditions (if)
1919
* standard Pascal functions (writeln, write, readln, read, random)
2020

0 commit comments

Comments
 (0)