Skip to content

Commit 3c22b22

Browse files
authored
Merge pull request #21 from igorkulman/while-loop
While loop
2 parents d8ed491 + 18ef840 commit 3c22b22

File tree

13 files changed

+104
-9
lines changed

13 files changed

+104
-9
lines changed

PascalInterpreter/PascalInterpreter/Interpreter/Interpreter.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ public class Interpreter {
4848
return eval(ifElse: ifElse)
4949
case let repeatUntil as RepeatUntil:
5050
return eval(repeatUntil: repeatUntil)
51+
case let whileLoop as While:
52+
return eval(whileLoop: whileLoop)
5153
case let forLoop as For:
5254
return eval(forLoop: forLoop)
5355
default:
@@ -182,6 +184,14 @@ public class Interpreter {
182184
return .none
183185
}
184186

187+
func eval(whileLoop: While) -> Value {
188+
while case .boolean(true) = eval(condition: whileLoop.condition) {
189+
eval(node: whileLoop.statement)
190+
}
191+
192+
return .none
193+
}
194+
185195
func eval(forLoop: For) -> Value {
186196
guard let currentFrame = callStack.peek() else {
187197
fatalError("No call stack frame")

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: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ public class Parser {
279279
| assignment_statement
280280
| repeat_until
281281
| for_loop
282+
| while_loop
282283
| empty
283284
*/
284285
private func statement() -> AST {
@@ -289,6 +290,8 @@ public class Parser {
289290
return ifElseStatement()
290291
case .repeat:
291292
return repeatUntilLoop()
293+
case .while:
294+
return whileLoop()
292295
case .for:
293296
return forLoop()
294297
case .id:
@@ -325,7 +328,20 @@ public class Parser {
325328

326329
/**
327330
Rule:
328-
331+
332+
for_loop : WHILE condition DO statement
333+
*/
334+
private func whileLoop() -> While {
335+
eat(.while)
336+
let condition = self.condition()
337+
eat(.do)
338+
let statement = self.statement()
339+
return While(statement: statement, condition: condition)
340+
}
341+
342+
/**
343+
Rule:
344+
329345
for_loop : FOR variable ASSIGN expression TO expression DO statement
330346
*/
331347
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
}

PascalInterpreter/PascalInterpreterTests/ParserTests.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,4 +469,27 @@ class ParserTests: XCTestCase {
469469
let node = Program(name: "Main", block: block)
470470
XCTAssertEqual(result, node)
471471
}
472+
473+
func testProgramWithWhileLoop() {
474+
let program =
475+
"""
476+
program Main;
477+
var x: integer;
478+
479+
begin
480+
x:=0;
481+
while x < 6 do
482+
x:=x+1;
483+
writeln(x);
484+
end. { Main }
485+
"""
486+
487+
let parser = Parser(program)
488+
let result = parser.parse()
489+
let xDec = VariableDeclaration(variable: Variable(name: "x"), type: VariableType(type: .integer))
490+
let compound = Compound(children: [Assignment(left: Variable(name: "x"), right: Number.integer(0)), While(statement: Assignment(left: Variable(name: "x"), right: BinaryOperation(left: Variable(name: "x"), operation: BinaryOperationType.plus, right: Number.integer(1))), condition: Condition(type: .lessThan, leftSide: Variable(name: "x"), rightSide: Number.integer(6))), FunctionCall(name: "writeln", actualParameters: [Variable(name: "x")]), NoOp()])
491+
let block = Block(declarations: [xDec], compound: compound)
492+
let node = Program(name: "Main", block: block)
493+
XCTAssertEqual(result, node)
494+
}
472495
}

0 commit comments

Comments
 (0)