Skip to content

Commit f5c71d2

Browse files
committed
🚧 adding Boolean support, support for evaluating method parameters
1 parent b282e73 commit f5c71d2

File tree

11 files changed

+78
-78
lines changed

11 files changed

+78
-78
lines changed

PascalInterpreter/PascalInterpreter/Interpreter/Frame.swift

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import Foundation
1111
class Frame {
1212
var integerMemory: [String: Int] = [:]
1313
var realMemory: [String: Double] = [:]
14+
var booleanMemory: [String: Bool] = [:]
1415
let scope: ScopedSymbolTable
1516
let previousFrame: Frame?
1617

@@ -19,7 +20,7 @@ class Frame {
1920
self.previousFrame = previousFrame
2021
}
2122

22-
func set(variable: String, value: Number) {
23+
func set(variable: String, value: Value) {
2324
// variable define in current scole (procedure declataion, etc)
2425
if let symbol = scope.lookup(variable, currentScopeOnly: true),
2526
let variableSymbol = symbol as? VariableSymbol,
@@ -28,17 +29,34 @@ class Frame {
2829
switch type {
2930
case .integer:
3031
switch value {
31-
case .integer(let value):
32-
integerMemory[variable] = value
33-
case .real:
34-
fatalError("Cannot assign Real value to Int variable \(variable)")
32+
case let .number(number):
33+
switch number {
34+
case let .integer(value):
35+
integerMemory[variable] = value
36+
case .real:
37+
fatalError("Cannot assign Real value to Int variable \(variable)")
38+
}
39+
case .boolean:
40+
fatalError("Cannot assign Boolean value to Int variable \(variable)")
3541
}
3642
case .real:
3743
switch value {
38-
case .integer(let value):
39-
realMemory[variable] = Double(value)
40-
case .real(let value):
41-
realMemory[variable] = value
44+
case let .number(number):
45+
switch number {
46+
case let .integer(value):
47+
realMemory[variable] = Double(value)
48+
case let .real(value):
49+
realMemory[variable] = value
50+
}
51+
case .boolean:
52+
fatalError("Cannot assign Boolean value to Real variable \(variable)")
53+
}
54+
case .boolean:
55+
switch value {
56+
case let .boolean(boolean):
57+
booleanMemory[variable] = boolean
58+
default:
59+
fatalError("Cannot assign \(value) value to Boolean variable \(variable)")
4260
}
4361
}
4462
return
@@ -48,17 +66,19 @@ class Frame {
4866
previousFrame!.set(variable: variable, value: value)
4967
}
5068

51-
func get(variable: String) -> Number {
69+
func get(variable: String) -> Value {
5270
// variable define in current scole (procedure declataion, etc)
5371
if let symbol = scope.lookup(variable, currentScopeOnly: true),
5472
let variableSymbol = symbol as? VariableSymbol,
5573
let type = variableSymbol.type as? BuiltInTypeSymbol {
5674

5775
switch type {
5876
case .integer:
59-
return .integer(integerMemory[variable]!)
77+
return .number(.integer(integerMemory[variable]!))
6078
case .real:
61-
return .real(realMemory[variable]!)
79+
return .number(.real(realMemory[variable]!))
80+
case .boolean:
81+
return .boolean(booleanMemory[variable]!)
6282
}
6383
}
6484

PascalInterpreter/PascalInterpreter/Interpreter/Interpreter.swift

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public class Interpreter {
2020
scopes = semanticAnalyzer.analyze(node: tree)
2121
}
2222

23-
@discardableResult private func eval(node: AST) -> Number? {
23+
@discardableResult private func eval(node: AST) -> Value? {
2424
switch node {
2525
case let number as Number:
2626
return eval(number: number)
@@ -45,49 +45,50 @@ public class Interpreter {
4545
}
4646
}
4747

48-
func eval(number: Number) -> Number? {
49-
return number
48+
func eval(number: Number) -> Value? {
49+
return .number(number)
5050
}
5151

52-
func eval(unaryOperation: UnaryOperation) -> Number? {
53-
guard let result = eval(node: unaryOperation.operand) else {
52+
func eval(unaryOperation: UnaryOperation) -> Value? {
53+
guard let value = eval(node: unaryOperation.operand), case let .number(result) = value else {
5454
fatalError("Cannot use unary \(unaryOperation.operation) on non number")
5555
}
5656

5757
switch unaryOperation.operation {
5858
case .plus:
59-
return +result
59+
return .number(+result)
6060
case .minus:
61-
return -result
61+
return .number(-result)
6262
}
6363
}
64-
func eval(binaryOperation: BinaryOperation) -> Number? {
65-
guard let leftResult = eval(node: binaryOperation.left), let rightResult = eval(node: binaryOperation.right) else {
64+
func eval(binaryOperation: BinaryOperation) -> Value? {
65+
guard let leftValue = eval(node: binaryOperation.left), case let .number(leftResult) = leftValue,
66+
let rightValue = eval(node: binaryOperation.right), case let .number(rightResult) = rightValue else {
6667
fatalError("Cannot use binary \(binaryOperation.operation) on non numbers")
6768
}
6869

6970
switch binaryOperation.operation {
7071
case .plus:
71-
return leftResult + rightResult
72+
return .number(leftResult + rightResult)
7273
case .minus:
73-
return leftResult - rightResult
74+
return .number(leftResult - rightResult)
7475
case .mult:
75-
return leftResult * rightResult
76+
return .number(leftResult * rightResult)
7677
case .integerDiv:
77-
return leftResult rightResult
78+
return .number(leftResult rightResult)
7879
case .floatDiv:
79-
return leftResult / rightResult
80+
return .number(leftResult / rightResult)
8081
}
8182
}
8283

83-
func eval(compound: Compound) -> Number? {
84+
func eval(compound: Compound) -> Value? {
8485
for child in compound.children {
8586
eval(node: child)
8687
}
8788
return nil
8889
}
8990

90-
func eval(assignment: Assignment) -> Number? {
91+
func eval(assignment: Assignment) -> Value? {
9192
guard let currentFrame = callStack.peek() else {
9293
fatalError("No call stack frame")
9394
}
@@ -96,29 +97,29 @@ public class Interpreter {
9697
return nil
9798
}
9899

99-
func eval(variable: Variable) -> Number? {
100+
func eval(variable: Variable) -> Value? {
100101
guard let currentFrame = callStack.peek() else {
101102
fatalError("No call stack frame")
102103
}
103104

104105
return currentFrame.get(variable: variable.name)
105106
}
106107

107-
func eval(block: Block) -> Number? {
108+
func eval(block: Block) -> Value? {
108109
for declaration in block.declarations {
109110
eval(node: declaration)
110111
}
111112

112113
return eval(node: block.compound)
113114
}
114115

115-
func eval(program: Program) -> Number? {
116+
func eval(program: Program) -> Value? {
116117
let frame = Frame(scope: scopes["global"]!, previousFrame: nil)
117118
callStack.push(frame)
118119
return eval(node: program.block)
119120
}
120121

121-
func eval(call: ProcedureCall) -> Number? {
122+
func eval(call: ProcedureCall) -> Value? {
122123
let current = callStack.peek()!
123124
let frame = Frame(scope: scopes[call.name]!, previousFrame: current)
124125
callStack.push(frame)
@@ -127,15 +128,18 @@ public class Interpreter {
127128
return nil
128129
}
129130

130-
private func callProcedure(procedure: String, params: [Number], frame: Frame) {
131+
private func callProcedure(procedure: String, params: [AST], frame: Frame) {
131132
guard let symbol = frame.scope.lookup(procedure), let procedureSymbol = symbol as? ProcedureSymbol else {
132133
fatalError("Symbol(procedure) not found '\(procedure)'")
133134
}
134135

135136
if procedureSymbol.params.count > 0 {
136137

137138
for i in 0 ... procedureSymbol.params.count - 1 {
138-
frame.set(variable: procedureSymbol.params[i].name, value: params[i])
139+
guard let evaluated = eval(node: params[i]) else {
140+
fatalError("Cannot assing empty value")
141+
}
142+
frame.set(variable: procedureSymbol.params[i].name, value: evaluated)
139143
}
140144
}
141145

PascalInterpreter/PascalInterpreter/Interpreter/Result.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import Foundation
1010

11-
enum Result {
12-
case none
11+
enum Value {
1312
case number(Number)
13+
case boolean(Bool)
1414
}

PascalInterpreter/PascalInterpreter/Lexer/Lexer.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,12 @@ public class Lexer {
2727
"DIV": .operation(.integerDiv),
2828
"INTEGER": .type(.integer),
2929
"REAL": .type(.real),
30+
"BOOLEAN": .type(.boolean),
3031
"BEGIN": .begin,
3132
"END": .end,
32-
"PROCEDURE": .procedure
33+
"PROCEDURE": .procedure,
34+
"TRUE": .constant(.boolean(true)),
35+
"FALSE": .constant(.boolean(false))
3336
]
3437

3538
public init(_ text: String) {

PascalInterpreter/PascalInterpreter/Lexer/Token+Extensions.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ extension Type: CustomStringConvertible {
8686
return "INTEGER"
8787
case .real:
8888
return "REAL"
89+
case .boolean:
90+
return "BOOLEAN"
8991
}
9092
}
9193
}
@@ -108,6 +110,8 @@ extension Constant: CustomStringConvertible {
108110
return "INTEGER_CONST(\(value))"
109111
case let .real(value):
110112
return "REAL_CONST(\(value))"
113+
case let .boolean(value):
114+
return "BOOLEAN_CONST(\(value))"
111115
}
112116
}
113117
}

PascalInterpreter/PascalInterpreter/Lexer/Token.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@ public enum Parenthesis {
2424
public enum Constant {
2525
case integer(Int)
2626
case real(Double)
27+
case boolean(Bool)
2728
}
2829

2930
public enum Type {
3031
case integer
3132
case real
33+
case boolean
3234
}
3335

3436
public enum Token {

PascalInterpreter/PascalInterpreter/Parser/AST.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public enum Number: AST {
2525
case integer(Int)
2626
case real(Double)
2727
}
28+
2829
public protocol AST {
2930
}
3031

@@ -144,9 +145,9 @@ class Param: AST {
144145

145146
class ProcedureCall: AST {
146147
let name: String
147-
let actualParameters: [Number]
148+
let actualParameters: [AST]
148149

149-
init(name: String, actualParameters: [Number]) {
150+
init(name: String, actualParameters: [AST]) {
150151
self.name = name
151152
self.actualParameters = actualParameters
152153
}

PascalInterpreter/PascalInterpreter/Semantic analyzer/SemanticAnalyzer.swift

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -89,21 +89,9 @@ public class SemanticAnalyzer: Visitor {
8989
}
9090

9191
for i in 0 ... procedure.params.count - 1 {
92-
guard let variableSymbol = procedure.params[i] as? VariableSymbol, let type = variableSymbol.type as? BuiltInTypeSymbol else {
92+
guard let variableSymbol = procedure.params[i] as? VariableSymbol, variableSymbol.type is BuiltInTypeSymbol else {
9393
fatalError("Procedure declared with wrong parameters '\(call.name)'")
9494
}
95-
96-
switch type {
97-
case .integer:
98-
switch call.actualParameters[i] {
99-
case .integer:
100-
break
101-
case .real:
102-
fatalError("Cannot assing Real to Integer parameter in procedure call '\(call.name)'")
103-
}
104-
case .real:
105-
break
106-
}
10795
}
10896
}
10997
}

PascalInterpreter/PascalInterpreter/Semantic analyzer/Symbol.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@ protocol Symbol {
1515
public enum BuiltInTypeSymbol: Symbol {
1616
case integer
1717
case real
18+
case boolean
1819

1920
var name: String {
2021
switch self {
2122
case .integer:
2223
return "INTEGER"
2324
case .real:
2425
return "REAL"
26+
case .boolean:
27+
return "BOOLEAN"
2528
}
2629
}
2730
}

PascalInterpreter/PascalInterpreter/Semantic analyzer/SymbolTable.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public class ScopedSymbolTable {
2222

2323
insert(BuiltInTypeSymbol.integer)
2424
insert(BuiltInTypeSymbol.real)
25+
insert(BuiltInTypeSymbol.boolean)
2526
}
2627

2728
func insert(_ symbol: Symbol) {

0 commit comments

Comments
 (0)