Skip to content

Commit

Permalink
♻️ simpler Interpreter memory storage
Browse files Browse the repository at this point in the history
  • Loading branch information
igorkulman committed Dec 25, 2017
1 parent 47793f8 commit 31eafc0
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 144 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Expand Up @@ -66,3 +66,5 @@ fastlane/Preview.html
fastlane/screenshots
fastlane/test_output
/Examples/SPI
/PascalInterpreter/.DS_Store
.DS_Store
4 changes: 4 additions & 0 deletions PascalInterpreter/PascalInterpreter.xcodeproj/project.pbxproj
Expand Up @@ -30,6 +30,7 @@
F300A0F11FDDB77000E5894D /* InterpreterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F300A0EC1FDDB77000E5894D /* InterpreterTests.swift */; };
F300A0F21FDDB77000E5894D /* SemanticAnalyzerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F300A0ED1FDDB77000E5894D /* SemanticAnalyzerTests.swift */; };
F34109A81FE2683900271A57 /* Visitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34109A71FE2683900271A57 /* Visitor.swift */; };
F385A7DB1FF109E5004BAD6F /* Value+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F385A7DA1FF109E5004BAD6F /* Value+Extensions.swift */; };
F3D90E131FE6A0C600FA79B3 /* Interpreter+Standard.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3D90E121FE6A0C600FA79B3 /* Interpreter+Standard.swift */; };
F3EF28D01FE12EBF001F36AB /* Frame.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3EF28CF1FE12EBF001F36AB /* Frame.swift */; };
F3EF28D21FE12F4D001F36AB /* Stack.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3EF28D11FE12F4D001F36AB /* Stack.swift */; };
Expand Down Expand Up @@ -72,6 +73,7 @@
F300A0EC1FDDB77000E5894D /* InterpreterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InterpreterTests.swift; sourceTree = "<group>"; };
F300A0ED1FDDB77000E5894D /* SemanticAnalyzerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SemanticAnalyzerTests.swift; sourceTree = "<group>"; };
F34109A71FE2683900271A57 /* Visitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Visitor.swift; sourceTree = "<group>"; };
F385A7DA1FF109E5004BAD6F /* Value+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Value+Extensions.swift"; sourceTree = "<group>"; };
F3D90E121FE6A0C600FA79B3 /* Interpreter+Standard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Interpreter+Standard.swift"; sourceTree = "<group>"; };
F3EF28CF1FE12EBF001F36AB /* Frame.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Frame.swift; sourceTree = "<group>"; };
F3EF28D11FE12F4D001F36AB /* Stack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stack.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -147,6 +149,7 @@
F3D90E121FE6A0C600FA79B3 /* Interpreter+Standard.swift */,
F3EF28D11FE12F4D001F36AB /* Stack.swift */,
F300A0C41FDDB6BD00E5894D /* Value.swift */,
F385A7DA1FF109E5004BAD6F /* Value+Extensions.swift */,
);
path = Interpreter;
sourceTree = "<group>";
Expand Down Expand Up @@ -353,6 +356,7 @@
F300A0C71FDDB6BE00E5894D /* Value.swift in Sources */,
F3D90E131FE6A0C600FA79B3 /* Interpreter+Standard.swift in Sources */,
F3EF28D21FE12F4D001F36AB /* Stack.swift in Sources */,
F385A7DB1FF109E5004BAD6F /* Value+Extensions.swift in Sources */,
F300A0E71FDDB74800E5894D /* SymbolTable.swift in Sources */,
F300A0D81FDDB6F400E5894D /* AST+Extensions.swift in Sources */,
F34109A81FE2683900271A57 /* Visitor.swift in Sources */,
Expand Down
90 changes: 18 additions & 72 deletions PascalInterpreter/PascalInterpreter/Interpreter/Frame.swift
Expand Up @@ -9,10 +9,7 @@
import Foundation

class Frame {
var integerMemory: [String: Int] = [:]
var realMemory: [String: Double] = [:]
var booleanMemory: [String: Bool] = [:]
var stringMemory: [String: String] = [:]
var memory: [String: Value] = [:]
let scope: ScopedSymbolTable
let previousFrame: Frame?
var returnValue: Value = .none
Expand All @@ -23,21 +20,7 @@ class Frame {
}

func remove(variable: String) {
if let symbol = scope.lookup(variable, currentScopeOnly: true),
let variableSymbol = symbol as? VariableSymbol,
let type = variableSymbol.type as? BuiltInTypeSymbol {

switch type {
case .integer:
integerMemory.removeValue(forKey: variable)
case .real:
realMemory.removeValue(forKey: variable)
case .boolean:
booleanMemory.removeValue(forKey: variable)
case .string:
stringMemory.removeValue(forKey: variable)
}
}
memory.removeValue(forKey: variable)
}

func set(variable: String, value: Value) {
Expand All @@ -52,46 +35,21 @@ class Frame {
let variableSymbol = symbol as? VariableSymbol,
let type = variableSymbol.type as? BuiltInTypeSymbol {

switch type {
case .integer:
switch value {
case let .number(number):
switch number {
case let .integer(value):
integerMemory[variable] = value
case .real:
fatalError("Cannot assign Real value to Int variable \(variable)")
}
default:
fatalError("Cannot assign \(value) to Int variable \(variable)")
}
case .real:
switch value {
case let .number(number):
switch number {
case let .integer(value):
realMemory[variable] = Double(value)
case let .real(value):
realMemory[variable] = value
}
default:
fatalError("Cannot assign \(value) to Real variable \(variable)")
}
case .boolean:
switch value {
case let .boolean(boolean):
booleanMemory[variable] = boolean
default:
fatalError("Cannot assign \(value) value to Boolean variable \(variable)")
}
case .string:
switch value {
case let .string(string):
stringMemory[variable] = string
default:
fatalError("Cannot assign \(value) value to String variable \(variable)")
}
switch (value, type) {
case (.number(.integer), .integer ):
memory[variable] = value
case (.number(.integer(let value)), .real ):
memory[variable] = .number(.real(Double(value)))
case (.number(.real), .real ):
memory[variable] = value
case (.boolean, .boolean ):
memory[variable] = value
case (.string, .string ):
memory[variable] = value
default:
fatalError("Cannot assing \(value) to \(type)")
}

return
}

Expand All @@ -101,20 +59,8 @@ class Frame {

func get(variable: String) -> Value {
// variable define in current scole (procedure declataion, etc)
if let symbol = scope.lookup(variable, currentScopeOnly: true),
let variableSymbol = symbol as? VariableSymbol,
let type = variableSymbol.type as? BuiltInTypeSymbol {

switch type {
case .integer:
return .number(.integer(integerMemory[variable]!))
case .real:
return .number(.real(realMemory[variable]!))
case .boolean:
return .boolean(booleanMemory[variable]!)
case .string:
return .string(stringMemory[variable]!)
}
if scope.lookup(variable, currentScopeOnly: true) != nil {
return memory[variable]!
}

// previous scope, eg global
Expand Down
Expand Up @@ -236,15 +236,12 @@ public class Interpreter {
eval(node: tree)
}

func getState() -> ([String: Int], [String: Double], [String: Bool], [String: String]) {
return (callStack.peek()!.integerMemory, callStack.peek()!.realMemory, callStack.peek()!.booleanMemory, callStack.peek()!.stringMemory)
func getState() -> ([String: Value]) {
return (callStack.peek()!.memory)
}

public func printState() {
print("Final interpreter memory state (\(callStack.peek()!.scope.name)):")
print("Int: \(callStack.peek()!.integerMemory)")
print("Real: \(callStack.peek()!.realMemory)")
print("Boolean: \(callStack.peek()!.booleanMemory)")
print("String: \(callStack.peek()!.stringMemory)")
print(callStack.peek()!.memory)
}
}
@@ -0,0 +1,44 @@
//
// Value+Extensions.swift
// PascalInterpreter
//
// Created by Igor Kulman on 25/12/2017.
// Copyright © 2017 Igor Kulman. All rights reserved.
//

import Foundation

extension Value: Equatable {
static func == (lhs: Value, rhs: Value) -> Bool {
switch (lhs, rhs) {
case let (.number(left), .number(right)):
return left == right
case let (.boolean(left), .boolean(right)):
return left == right
case let (.string(left), .string(right)):
return left == right
default:
return false
}
}
}

extension Value: CustomStringConvertible {
public var description: String {
switch self {
case .none:
return "NIL"
case .boolean(let value):
return "BOOLEAN(\(value))"
case .string(let value):
return "STRING(\(value))"
case .number(let number):
switch number {
case .integer(let value):
return "INTEGER(\(value)"
case .real(let value):
return "REAL(\(value)"
}
}
}
}
15 changes: 0 additions & 15 deletions PascalInterpreter/PascalInterpreter/Interpreter/Value.swift
Expand Up @@ -14,18 +14,3 @@ enum Value {
case boolean(Bool)
case string(String)
}

extension Value: Equatable {
static func == (lhs: Value, rhs: Value) -> Bool {
switch (lhs, rhs) {
case let (.number(left), .number(right)):
return left == right
case let (.boolean(left), .boolean(right)):
return left == right
case let (.string(left), .string(right)):
return left == right
default:
return false
}
}
}
2 changes: 1 addition & 1 deletion PascalInterpreter/PascalInterpreter/Lexer/Lexer.swift
Expand Up @@ -43,7 +43,7 @@ public class Lexer {
"FOR": .for,
"TO": .to,
"DO": .do,
"WHILE": .while,
"WHILE": .while
]

public init(_ text: String) {
Expand Down
70 changes: 20 additions & 50 deletions PascalInterpreter/PascalInterpreterTests/InterpreterTests.swift
Expand Up @@ -25,11 +25,8 @@ class InterpreterTests: XCTestCase {

let interpeter = Interpreter(program)
interpeter.interpret()
let (integerState, realState, boolState, stringState) = interpeter.getState()
XCTAssert(integerState == ["a": 2])
XCTAssert(realState == [:])
XCTAssert(boolState == [:])
XCTAssert(stringState == [:])
let state = interpeter.getState()
XCTAssert(state == ["a": Value.number(.integer(2))])
}

func testMoreComplexProgram() {
Expand All @@ -51,11 +48,8 @@ class InterpreterTests: XCTestCase {

let interpeter = Interpreter(program)
interpeter.interpret()
let (integerState, realState, boolState, stringState) = interpeter.getState()
XCTAssert(integerState == ["b": 25, "number": 2, "a": 2, "x": 11, "c": 27])
XCTAssert(realState == [:])
XCTAssert(boolState == [:])
XCTAssert(stringState == [:])
let state = interpeter.getState()
XCTAssert(state == ["b": Value.number(.integer(25)), "number": Value.number(.integer(2)), "a": Value.number(.integer(2)), "x": Value.number(.integer(11)), "c": Value.number(.integer(27))])
}

func testProgramWithDeclarations() {
Expand All @@ -75,11 +69,8 @@ class InterpreterTests: XCTestCase {

let interpeter = Interpreter(program)
interpeter.interpret()
let (integerState, realState, boolState, stringState) = interpeter.getState()
XCTAssert(integerState == ["b": 25, "a": 2])
XCTAssert(realState == ["y": 5.9971428571428573])
XCTAssert(boolState == [:])
XCTAssert(stringState == [:])
let state = interpeter.getState()
XCTAssert(state == ["b": Value.number(.integer(25)), "a": Value.number(.integer(2)), "y": Value.number(.real( 5.9971428571428573))])
}

func testProgramWithProcedureCallAndNoParameters() {
Expand All @@ -103,11 +94,8 @@ class InterpreterTests: XCTestCase {

let interpeter = Interpreter(program)
interpeter.interpret()
let (integerState, realState, boolState, stringState) = interpeter.getState()
XCTAssert(integerState == [:])
XCTAssert(realState == ["x": 7, "y": 5])
XCTAssert(boolState == [:])
XCTAssert(stringState == [:])
let state = interpeter.getState()
XCTAssert(state == ["x": Value.number(.real(7)), "y": Value.number(.real( 5))])
}

func testProgramWithProcedureCallAndParameters() {
Expand All @@ -129,11 +117,8 @@ class InterpreterTests: XCTestCase {

let interpeter = Interpreter(program)
interpeter.interpret()
let (integerState, realState, boolState, stringState) = interpeter.getState()
XCTAssert(integerState == [:])
XCTAssert(realState == ["x": 5, "y": 3])
XCTAssert(boolState == [:])
XCTAssert(stringState == [:])
let state = interpeter.getState()
XCTAssert(state == ["x": Value.number(.real(5)), "y": Value.number(.real(3))])
}

func testProgramWithRecursiveFunction() {
Expand All @@ -157,11 +142,8 @@ class InterpreterTests: XCTestCase {

let interpeter = Interpreter(program)
interpeter.interpret()
let (integerState, realState, boolState, stringState) = interpeter.getState()
XCTAssert(realState == [:])
XCTAssert(integerState == ["result": 720])
XCTAssert(boolState == [:])
XCTAssert(stringState == [:])
let state = interpeter.getState()
XCTAssert(state == ["result": Value.number(.integer(720))])
}

func testProgramWithRecursiveAndBuiltInFunctions() {
Expand All @@ -186,11 +168,8 @@ class InterpreterTests: XCTestCase {

let interpeter = Interpreter(program)
interpeter.interpret()
let (integerState, realState, boolState, stringState) = interpeter.getState()
XCTAssert(realState == [:])
XCTAssert(integerState == ["result": 720])
XCTAssert(boolState == [:])
XCTAssert(stringState == [:])
let state = interpeter.getState()
XCTAssert(state == ["result": Value.number(.integer(720))])
}

func testProgramWithRecursiveFunctionsAndParameterTheSameName() {
Expand All @@ -215,11 +194,8 @@ class InterpreterTests: XCTestCase {

let interpeter = Interpreter(program)
interpeter.interpret()
let (integerState, realState, boolState, stringState) = interpeter.getState()
XCTAssert(realState == [:])
XCTAssert(integerState == ["result": 720, "number": 6])
XCTAssert(boolState == [:])
XCTAssert(stringState == [:])
let state = interpeter.getState()
XCTAssert(state == ["result": Value.number(.integer(720)), "number": Value.number(.integer(6))])
}

func testProgramWithRepeatUntil() {
Expand All @@ -239,11 +215,8 @@ class InterpreterTests: XCTestCase {

let interpeter = Interpreter(program)
interpeter.interpret()
let (integerState, realState, boolState, stringState) = interpeter.getState()
XCTAssert(realState == [:])
XCTAssert(integerState == ["x": 6])
XCTAssert(boolState == [:])
XCTAssert(stringState == [:])
let state = interpeter.getState()
XCTAssert(state == ["x": Value.number(.integer(6))])
}

func testProgramWithForLoop() {
Expand All @@ -262,10 +235,7 @@ class InterpreterTests: XCTestCase {

let interpeter = Interpreter(program)
interpeter.interpret()
let (integerState, realState, boolState, stringState) = interpeter.getState()
XCTAssert(realState == [:])
XCTAssert(integerState == ["x": 6])
XCTAssert(boolState == [:])
XCTAssert(stringState == [:])
let state = interpeter.getState()
XCTAssert(state == ["x": Value.number(.integer(6))])
}
}

0 comments on commit 31eafc0

Please sign in to comment.