diff options
author | Frederick Yin <fkfd@fkfd.me> | 2022-08-30 15:39:10 +0800 |
---|---|---|
committer | Frederick Yin <fkfd@fkfd.me> | 2022-08-30 15:39:10 +0800 |
commit | cb320b921c0574474430fe8d38aa5438a9f6ee98 (patch) | |
tree | 4229990283cf9da61e8488a1dc7adda0301b312e | |
parent | 43df98ea8f491b31b580fd909e92d5fea486599d (diff) |
hackc: var declaration in/out of subroutine
-rw-r--r-- | projects/hackc/syntax.py | 39 |
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) |