Skip to content

Commit 4448cbd

Browse files
committed
✨ properly reading array values
1 parent 0e751c5 commit 4448cbd

File tree

7 files changed

+70
-15
lines changed

7 files changed

+70
-15
lines changed

PascalInterpreter/PascalInterpreter/FatalError.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import Foundation
1111
/**
1212
Taken from https://medium.com/@marcosantadev/how-to-test-fatalerror-in-swift-e1be9ff11a29
1313
*/
14-
func fatalError(_ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Never {
14+
/*func fatalError(_ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Never {
1515
FatalErrorUtil.fatalErrorClosure(message(), file, line)
16-
}
16+
}*/
1717

1818
struct FatalErrorUtil {
1919

PascalInterpreter/PascalInterpreter/Interpreter/Interpreter.swift

+17-3
Original file line numberDiff line numberDiff line change
@@ -109,19 +109,33 @@ public class Interpreter {
109109
fatalError("No call stack frame")
110110
}
111111

112-
if let expression = assignment.index, case let .number(.integer(index)) = eval(node: expression) {
112+
switch assignment.left {
113+
case let array as ArrayVariable:
114+
guard case let .number(.integer(index)) = eval(node: array.index) else {
115+
fatalError("Cannot use non-Integer index with array '\(array.name)'")
116+
}
113117
currentFrame.set(variable: assignment.left.name, value: eval(node: assignment.right), index: index)
114-
} else {
118+
default:
115119
currentFrame.set(variable: assignment.left.name, value: eval(node: assignment.right))
116120
}
121+
117122
return .none
118123
}
119124

120125
func eval(variable: Variable) -> Value {
121126
guard let currentFrame = callStack.peek() else {
122127
fatalError("No call stack frame")
123128
}
124-
return currentFrame.get(variable: variable.name)
129+
130+
switch variable {
131+
case let array as ArrayVariable:
132+
guard case let .number(.integer(index)) = eval(node: array.index) else {
133+
fatalError("Cannot use non-Integer index with array '\(array.name)'")
134+
}
135+
return currentFrame.get(variable: array.name, index: index)
136+
default:
137+
return currentFrame.get(variable: variable.name)
138+
}
125139
}
126140

127141
func eval(block: Block) -> Value {

PascalInterpreter/PascalInterpreter/Lexer/Lexer.swift

+19-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ public class Lexer {
1818
private let text: String
1919
private var currentPosition: Int
2020
private var currentCharacter: Character?
21+
private var isStringStart = false
22+
private var wasStringLast = false
2123

2224
// MARK: - Constants
2325

@@ -150,13 +152,11 @@ public class Lexer {
150152
}
151153

152154
private func string() -> Token {
153-
advance()
154155
var lexem = ""
155156
while let character = currentCharacter, character != "'" {
156157
lexem += String(character)
157158
advance()
158159
}
159-
advance()
160160
return .constant(.string(lexem))
161161
}
162162

@@ -171,6 +171,20 @@ public class Lexer {
171171

172172
while let currentCharacter = currentCharacter {
173173

174+
if wasStringLast {
175+
wasStringLast = false
176+
if currentCharacter == "'" {
177+
advance()
178+
}
179+
return .apostrophe
180+
}
181+
182+
if isStringStart {
183+
wasStringLast = true
184+
isStringStart = false
185+
return string()
186+
}
187+
174188
if CharacterSet.whitespacesAndNewlines.contains(currentCharacter.unicodeScalars.first!) {
175189
skipWhitestace()
176190
continue
@@ -183,7 +197,9 @@ public class Lexer {
183197
}
184198

185199
if currentCharacter == "'" {
186-
return string()
200+
advance()
201+
isStringStart = !isStringStart
202+
return .apostrophe
187203
}
188204

189205
// if the character is a digit, convert it to int, create an integer token and move position

PascalInterpreter/PascalInterpreter/Parser/AST.swift

+10-3
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,10 @@ class Compound: AST {
7777
class Assignment: AST {
7878
let left: Variable
7979
let right: AST
80-
let index: AST?
8180

82-
init(left: Variable, right: AST, index: AST? = nil) {
81+
init(left: Variable, right: AST) {
8382
self.left = left
8483
self.right = right
85-
self.index = index
8684
}
8785
}
8886

@@ -94,6 +92,15 @@ class Variable: AST {
9492
}
9593
}
9694

95+
class ArrayVariable: Variable {
96+
let index: AST
97+
98+
init(name: String, index: AST) {
99+
self.index = index
100+
super.init(name: name)
101+
}
102+
}
103+
97104
class NoOp: AST {
98105
}
99106

PascalInterpreter/PascalInterpreter/Parser/Parser.swift

+13-2
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ public class Parser {
476476
eat(.bracket(.right))
477477
eat(.assign)
478478
let right = expr()
479-
return Assignment(left: left, right: right, index: indexExpression)
479+
return Assignment(left: left, right: right)
480480
}
481481
eat(.assign)
482482
let right = expr()
@@ -547,6 +547,12 @@ public class Parser {
547547
switch currentToken {
548548
case let .id(value):
549549
eat(.id(value))
550+
if currentToken == .bracket(.left) {
551+
eat(.bracket(.left))
552+
let index = expr()
553+
eat(.bracket(.right))
554+
return ArrayVariable(name: value, index: index)
555+
}
550556
return Variable(name: value)
551557
default:
552558
fatalError("Syntax error, expected variable, found \(currentToken)")
@@ -585,8 +591,13 @@ public class Parser {
585591
let result = expr()
586592
eat(.parenthesis(.right))
587593
return result
588-
case let .constant(.string(value)):
594+
case .apostrophe:
595+
eat(.apostrophe)
596+
guard case let .constant(.string(value)) = currentToken else {
597+
fatalError("Expected string literal after '")
598+
}
589599
eat(.constant(.string(value)))
600+
eat(.apostrophe)
590601
return value
591602
case let .constant(.boolean(value)):
592603
eat(.constant(.boolean(value)))

PascalInterpreter/PascalInterpreterTests/InterpreterTests.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -260,14 +260,15 @@ class InterpreterTests: XCTestCase {
260260
begin
261261
data[i] := i;
262262
end;
263+
writeln(data[2]);
263264
end.
264265
"""
265266

266267
let interpeter = Interpreter(program)
267268
interpeter.interpret()
268269
let (scalars, arrays) = interpeter.getState()
269270
XCTAssert(scalars == [:])
270-
XCTAssert(arrays.count==1)
271+
XCTAssert(arrays.count == 1)
271272
XCTAssert(arrays["DATA"]! == [Value.number(.integer(1)), Value.number(.integer(2)), Value.number(.integer(3)), Value.number(.integer(4)), Value.number(.integer(5))])
272273
}
273274
}

PascalInterpreter/PascalInterpreterTests/LexerTests.swift

+7-1
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ class LexerTests: XCTestCase {
408408
}
409409

410410
func testDataTypes() {
411-
let lexer = Lexer("a: Integer; b: Real; c: Boolean; c:= true; c:=false; d:= 'Test string'")
411+
let lexer = Lexer("a: Integer; b: Real; c: Boolean; c:= true; c:=false; d:= 'Test string'; 'Another'")
412412
XCTAssert(lexer.getNextToken() == .id("a"))
413413
XCTAssert(lexer.getNextToken() == .colon)
414414
XCTAssert(lexer.getNextToken() == .type(.integer))
@@ -431,7 +431,13 @@ class LexerTests: XCTestCase {
431431
XCTAssert(lexer.getNextToken() == .semi)
432432
XCTAssert(lexer.getNextToken() == .id("d"))
433433
XCTAssert(lexer.getNextToken() == .assign)
434+
XCTAssert(lexer.getNextToken() == .apostrophe)
434435
XCTAssert(lexer.getNextToken() == .constant(.string("Test string")))
436+
XCTAssert(lexer.getNextToken() == .apostrophe)
437+
XCTAssert(lexer.getNextToken() == .semi)
438+
XCTAssert(lexer.getNextToken() == .apostrophe)
439+
XCTAssert(lexer.getNextToken() == .constant(.string("Another")))
440+
XCTAssert(lexer.getNextToken() == .apostrophe)
435441
XCTAssert(lexer.getNextToken() == .eof)
436442
}
437443

0 commit comments

Comments
 (0)