Skip to content

Commit

Permalink
Add SymbolTable and related tests
Browse files Browse the repository at this point in the history
- SymbolTable holds the addressed of different symbols, used for A-Instructions and L-Instructions
  • Loading branch information
volf52 committed Dec 21, 2020
1 parent 200153b commit 46b3b43
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 2 deletions.
72 changes: 71 additions & 1 deletion pyasm/coder.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Dict
from typing import Dict, Optional

TranslationTable = Dict[str, str]

Expand Down Expand Up @@ -110,3 +110,73 @@ def translate_comp(mnemonic: str) -> str:
@staticmethod
def translate_jmp(mnemonic: str) -> str:
return Coder.__get_mnemonic(mnemonic, Coder.__JMP, "jmp")


class SymbolTable:
__RESERVED = {
"r0": 0,
"r1": 1,
"r2": 2,
"r3": 3,
"r4": 4,
"r5": 5,
"r6": 6,
"r7": 7,
"r8": 8,
"r9": 9,
"r10": 10,
"r11": 11,
"r12": 12,
"r13": 13,
"r14": 14,
"r15": 15,
"sp": 0,
"lcl": 1,
"arg": 2,
"this": 3,
"that": 4,
"screen": 16384,
"kbd": 24576,
}

__slots__ = "__lookup_table"

def __init__(self):
self.__lookup_table = {}

def __setitem__(self, key: str, value: int) -> None:
if key.lower() in SymbolTable.__RESERVED:
raise ValueError(f"Cannot set a reserved symbol. {key}")

self.__lookup_table[key] = value

def __getitem__(self, key: str):
reserved = SymbolTable.__RESERVED.get(key.lower())
if reserved is not None:
return reserved

return self.__lookup_table[key]

def get(self, key: str, default=None) -> Optional[int]:
reserved = SymbolTable.__RESERVED.get(key.lower())
if reserved is not None:
return reserved

return self.__lookup_table.get(key, default)

def __len__(self) -> int:
return len(self.__lookup_table)

def clear(self) -> None:
self.__lookup_table.clear()

def delete(self, symbol: str) -> bool:
if symbol.lower() in SymbolTable.__RESERVED:
return False

val = self.__lookup_table.get(symbol)
if val is None:
return False

self.__lookup_table.__delitem__(symbol)
return True
74 changes: 73 additions & 1 deletion tests/test_coder.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from pyasm.coder import Coder, InvalidMnemonicError
from pyasm.coder import Coder, InvalidMnemonicError, SymbolTable


def test_coder_cannot_be_instantiated():
Expand Down Expand Up @@ -94,3 +94,75 @@ def test_invalid_comp_(mnemonic: str):

assert mnemonic in str(err.value)
assert "comp" in str(err.value)


@pytest.fixture(scope="module")
def symbol_table() -> SymbolTable:
return SymbolTable()


@pytest.mark.parametrize(
"symbol", ["r0", "R0", "THIS", "SCREEN", "scReEn", "kbd", "R7"]
)
def test_adding_reserved_symbols_to_symbol_table(
symbol_table: SymbolTable, symbol: str
):
with pytest.raises(ValueError):
symbol_table[symbol] = 3

assert len(symbol_table) == 0


def test_getting_reserved_symbols(symbol_table: SymbolTable):
for i in range(1, 15 + 1):
assert symbol_table.get(f"r{i}") == i
assert symbol_table.get(f"R{i}") == i

assert symbol_table.get("sp") == 0
assert symbol_table.get("SP") == 0
assert symbol_table.get("lcl") == 1
assert symbol_table.get("LCL") == 1
assert symbol_table.get("arg") == 2
assert symbol_table.get("ARG") == 2
assert symbol_table.get("this") == 3
assert symbol_table.get("THIS") == 3
assert symbol_table.get("that") == 4
assert symbol_table.get("THAT") == 4


@pytest.mark.integ_test
def test_setting_and_getting_symbol_table_entries_():
symbol_table = SymbolTable()

assert len(symbol_table) == 0

# Get from empty table
with pytest.raises(KeyError):
_ = symbol_table["abc"]

assert symbol_table.get("abc") is None
assert symbol_table.get("abc", default=14) == 14

assert len(symbol_table) == 0

symbol_table["loop"] = 16
assert symbol_table["loop"] == 16
assert symbol_table.get("loop") == 16

assert not symbol_table.delete("r0")
assert not symbol_table.delete("KBD")
assert not symbol_table.delete("abc")
assert symbol_table.delete("loop")
assert symbol_table.get("loop") is None
with pytest.raises(KeyError):
_ = symbol_table["loop"]

symbol_table["end"] = 256
assert symbol_table["end"] == 256
symbol_table["end"] = 147
assert symbol_table["end"] == 147
symbol_table["something_else"] = 123
assert len(symbol_table) == 2

symbol_table.clear()
assert len(symbol_table) == 0

0 comments on commit 46b3b43

Please sign in to comment.