diff options
Diffstat (limited to 'projects/hackc/syntax.py')
-rw-r--r-- | projects/hackc/syntax.py | 146 |
1 files changed, 0 insertions, 146 deletions
diff --git a/projects/hackc/syntax.py b/projects/hackc/syntax.py deleted file mode 100644 index 281bd17..0000000 --- a/projects/hackc/syntax.py +++ /dev/null @@ -1,146 +0,0 @@ -from .tokens import Token -from .utils import * - -SCOPES = ["static", "field", "var"] -PRIMITIVE_TYPES = ["int", "char", "boolean"] - - -class Class: - def __init__(self, name: Token, variables: list, subroutines: list): - self.name = name - self.variables = variables - self.subroutines = subroutines - - @classmethod - def from_tokens(cls, tokens: list): - """Construct a class from a list of tokens. - - In standard Jack, one file is exactly one class. - - Format: - class <name> { - <zero or more class variable declarations> - <zero or more subroutines> - } - """ - if len(tokens) < 4: - return None - if tokens[0] != "class": - raise JackSyntaxError( - f"Expected `class`, got `{tokens[0]}` instead", tokens[0] - ) - - name = tokens[1] - if name.type != "identifier": - raise JackSyntaxError(f"You cannot name a class `{name}`", name) - - if tokens[2] != LEFT_BRACE: - raise JackSyntaxError( - f"Expected `{LEFT_BRACE}`, got `{tokens[2]}` instead", tokens[2] - ) - - tokens_consumed = 3 - - while True: - variables, token_cnt = Variable.from_tokens( - tokens[tokens_consumed:], context="class" - ) - if variables is None: - break - variables.print_verbose() - tokens_consumed += token_cnt - - return Class(name, variables, []) - - -class Variable: - def __init__(self, scope: Token, type: Token, names: list[Token]): - self.scope = scope - self.type = type - self.names = names - - @classmethod - 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>; - - <scope> = static | field | var - <type> = int | char | boolean | <class name> - """ - if len(tokens) < 4 or tokens[0] not in SCOPES: - # not variable declaration - return (None, 0) - - scope = tokens[0] - if scope in ["static", "field"] and context != "class": - raise JackSyntaxError( - 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 - expecting_identifier = True - - for token in tokens[2:]: - tokens_consumed += 1 - if token.type == "identifier": - if expecting_identifier: - names.append(token) - expecting_identifier = False - else: - raise JackSyntaxError(f"Expected `,`, got `{token}` instead", token) - elif token == ",": - if not expecting_identifier: - expecting_identifier = True - else: - raise JackSyntaxError( - f"Expected variable name, got `,` instead", token - ) - elif token == ";": - if expecting_identifier: - raise JackSyntaxError( - f"Expected variable name, got `;` instead", token - ) - break - else: - expected = "variable name" if expecting_identifier else "`,` or `;`" - raise JackSyntaxError( - f"Expected {expected}, got `{token}` instead", token - ) - - return (Variable(scope, type, names), tokens_consumed) - - def print_verbose(self): - print(f"Declare {len(self.names)} variable(s):") - for name in self.names: - print(self.scope, self.type, name) - - -class Subroutine: - def __init__(self): - pass - - -class Statement: - def __init__(self): - super().__init__() - - -class IfStatement(Statement): - def __init__(self): - super().__init__() |