From cb320b921c0574474430fe8d38aa5438a9f6ee98 Mon Sep 17 00:00:00 2001 From: Frederick Yin Date: Tue, 30 Aug 2022 15:39:10 +0800 Subject: hackc: var declaration in/out of subroutine --- projects/hackc/syntax.py | 39 ++++++++++++++++++++++++--------------- 1 file 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" ( = static | field) or "subroutine" ( = var) Format: ; @@ -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) -- cgit v1.2.3