summaryrefslogtreecommitdiff
path: root/projects/hackc/expressions.py
diff options
context:
space:
mode:
authorFrederick Yin <fkfd@fkfd.me>2022-09-03 11:22:20 +0800
committerFrederick Yin <fkfd@fkfd.me>2022-09-03 11:22:20 +0800
commitb1794edb3d76db7c1a86fc14a60bc95b833bc7c7 (patch)
tree582288c1618a74405d3c183410d7525b8d6aa31f /projects/hackc/expressions.py
parentbed429a1d17b43678a70bc286aac12a0bd6e387d (diff)
hackc: more statements; UnexpectedToken
Diffstat (limited to 'projects/hackc/expressions.py')
-rw-r--r--projects/hackc/expressions.py96
1 files changed, 79 insertions, 17 deletions
diff --git a/projects/hackc/expressions.py b/projects/hackc/expressions.py
index f4623da..2e08cef 100644
--- a/projects/hackc/expressions.py
+++ b/projects/hackc/expressions.py
@@ -24,9 +24,7 @@ class Term:
"""Format: '(' <expression> ')'"""
expr, dt = Expression.from_tokens(tokens[1:])
if tokens[dt + 1] != RIGHT_PAREN:
- raise JackSyntaxError(
- f"Expected `{RIGHT_PAREN}`, got `{tokens[dt]}` instead", tokens[dt]
- )
+ raise UnaryTerm(RIGHT_PAREN, tokens[dt])
return (expr, dt + 2)
if tokens[0].type == "identifier":
if tokens[1] in [LEFT_PAREN, "."]:
@@ -69,9 +67,7 @@ class SubscriptTerm:
raise JackSyntaxError(f"Expected subscript", tokens[2])
t += dt
if tokens[t] != RIGHT_BRACKET:
- raise JackSyntaxError(
- f"Expected `{RIGHT_BRACKET}`, got `{tokens[t]}` instead", tokens[t]
- )
+ raise UnexpectedToken(RIGHT_BRACKET, tokens[t])
return (SubscriptTerm(var, sub), t + 1)
def __str__(self):
@@ -95,16 +91,6 @@ class UnaryTerm:
return f"({self.op}{self.term})"
-class SubroutineCall:
- def __init__(self, name: Token, exprs: list):
- self.name = name
- self.exprs = exprs
-
- @classmethod
- def from_tokens(cls, tokens: list) -> tuple:
- pass
-
-
class Expression:
def __init__(self, lhs: Term, op=None, rhs=None):
self.lhs = lhs
@@ -119,6 +105,8 @@ class Expression:
<term> (<op> <term>)?
"""
lhs, dt = Term.from_tokens(tokens)
+ if lhs is None:
+ return (None, 0)
t = dt
op = tokens[t]
@@ -128,7 +116,7 @@ class Expression:
t += 1
rhs, dt = Term.from_tokens(tokens[t:])
if rhs is None:
- raise JSE(f"Expected other term, got `{rhs}` instead", rhs)
+ raise UnexpectedToken("other term", rhs)
t += dt
return (Expression(lhs, op, rhs), t)
@@ -138,3 +126,77 @@ class Expression:
return f"({self.lhs} {self.op} {self.rhs})"
else:
return str(self.lhs)
+
+
+class ExpressionList:
+ def __init__(self, exprs: list[Expression]):
+ self.exprs = exprs
+
+ @classmethod
+ def from_tokens(cls, tokens: list) -> tuple:
+ """Construct list of expressions.
+
+ Format:
+ (<expression> (',' <expression>)*)?
+ """
+ t = 0
+ exprs = []
+ while True:
+ expr, dt = Expression.from_tokens(tokens[t:])
+ if expr is None:
+ if t == 0:
+ # only allow lack of expression right after paren
+ break
+ else:
+ # expect expression after comma
+ raise JackSyntaxError(f"Expected expression", tokens[t])
+ t += dt
+ exprs.append(expr)
+ if tokens[t] != ",":
+ break
+ t += 1
+
+ return (ExpressionList(exprs), t)
+
+ def __str__(self):
+ return ", ".join([str(expr) for expr in self.exprs])
+
+
+class SubroutineCall:
+ def __init__(self, jack_class: Token, name: Token, exprs: ExpressionList):
+ self.jack_class = jack_class
+ self.name = name
+ self.exprs = exprs
+
+ @classmethod
+ def from_tokens(cls, tokens: list) -> tuple:
+ """Construct invocation of subroutine.
+
+ Format:
+ (<class> '.')? <subroutine> '(' <expression list> ')'
+ """
+ t = 0
+ jack_class = None
+ if tokens[1] == ".":
+ jack_class = tokens[0]
+ t = 2
+
+ name = tokens[t]
+ if name.type != "identifier":
+ raise UnexpectedToken("subroutine name", name)
+ t += 1
+
+ if tokens[t] != LEFT_PAREN:
+ raise UnexpectedToken(LEFT_PAREN, tokens[t])
+ t += 1
+
+ exprs, dt = ExpressionList.from_tokens(tokens[t:])
+ t += dt
+ if tokens[t] != RIGHT_PAREN:
+ raise UnexpectedToken(RIGHT_PAREN, tokens[t])
+ return (SubroutineCall(jack_class, name, exprs), t + 1)
+
+ def __str__(self):
+ if self.jack_class is None:
+ return f"{self.name}({self.exprs})"
+ return f"{self.jack_class}.{self.name}({self.exprs})"