summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederick Yin <fkfd@fkfd.me>2022-08-30 15:39:10 +0800
committerFrederick Yin <fkfd@fkfd.me>2022-08-30 15:39:10 +0800
commitcb320b921c0574474430fe8d38aa5438a9f6ee98 (patch)
tree4229990283cf9da61e8488a1dc7adda0301b312e
parent43df98ea8f491b31b580fd909e92d5fea486599d (diff)
hackc: var declaration in/out of subroutine
-rw-r--r--projects/hackc/syntax.py39
1 files changed, 24 insertions, 15 deletions
diff --git a/projects/hackc/syntax.py b/projects/hackc/syntax.py
index a07e69e..281bd17 100644
--- a/projects/hackc/syntax.py
+++ b/projects/hackc/syntax.py
@@ -29,12 +29,10 @@ class Class:
raise JackSyntaxError(
f"Expected `class`, got `{tokens[0]}` instead", tokens[0]
)
- if tokens[1].type != "identifier":
- raise JackSyntaxError(
- f"You cannot name a class `{tokens[1]}`", tokens[1]
- )
name = tokens[1]
+ if name.type != "identifier":
+ raise JackSyntaxError(f"You cannot name a class `{name}`", name)
if tokens[2] != LEFT_BRACE:
raise JackSyntaxError(
@@ -44,7 +42,9 @@ class Class:
tokens_consumed = 3
while True:
- variables, token_cnt = Variable.from_tokens(tokens[tokens_consumed:])
+ variables, token_cnt = Variable.from_tokens(
+ tokens[tokens_consumed:], context="class"
+ )
if variables is None:
break
variables.print_verbose()
@@ -60,9 +60,12 @@ class Variable:
self.names = names
@classmethod
- def from_tokens(cls, tokens: list) -> tuple:
- """Construct variable declaration statement.
- Return a tuple of a Variable instance and number of tokens consumed.
+ def from_tokens(cls, tokens: list, context: str) -> tuple:
+ """Construct variable declaration statement from a list of tokens.
+ Return a tuple of an instance of Variable and number of tokens consumed.
+ When `tokens` does not begin with a variable declaration, return (None, 0).
+
+ context -- "class" (<scope> = static | field) or "subroutine" (<scope> = var)
Format:
<scope> <type> <one or more names, joined with a comma>;
@@ -75,13 +78,19 @@ class Variable:
return (None, 0)
scope = tokens[0]
-
- if tokens[1] not in PRIMITIVE_TYPES and tokens[1].type != "identifier":
+ if scope in ["static", "field"] and context != "class":
raise JackSyntaxError(
- f"Expected datatype, got `{tokens[1]}` instead", tokens[1]
+ f"You cannot declare a {scope} variable in a subroutine", scope
+ )
+ if scope == "var" and context != "subroutine":
+ raise JackSyntaxError(
+ f"You cannot declare a local variable outside of a subroutine",
+ scope,
)
type = tokens[1]
+ if type not in PRIMITIVE_TYPES and type.type != "identifier":
+ raise JackSyntaxError(f"Expected datatype, got `{tokens[1]}` instead", type)
tokens_consumed = 2
names = [] # names of variables
@@ -94,9 +103,7 @@ class Variable:
names.append(token)
expecting_identifier = False
else:
- raise JackSyntaxError(
- f"Expected `,`, got `{token}` instead", token
- )
+ raise JackSyntaxError(f"Expected `,`, got `{token}` instead", token)
elif token == ",":
if not expecting_identifier:
expecting_identifier = True
@@ -112,7 +119,9 @@ class Variable:
break
else:
expected = "variable name" if expecting_identifier else "`,` or `;`"
- raise JackSyntaxError(f"Expected {expected}, got `{token}` instead", token)
+ raise JackSyntaxError(
+ f"Expected {expected}, got `{token}` instead", token
+ )
return (Variable(scope, type, names), tokens_consumed)