from dataclasses import dataclass from enum import Enum, auto from typing import Any # tokens and types # NOTE: this can probably be simplified class TokenType(Enum): PRINT = auto() OPEN_PAREN = auto() CLOSE_PAREN = auto() EOF = auto() # literals INT = auto() FLOAT = auto() STRING = auto() TRUE = auto() FALSE = auto() # arithmetic PLUS = auto() DASH = auto() STAR = auto() SLASH = auto() # strings DOUBLE_QUOTE = auto() # comparison GREATER = auto() GREATER_EQUAL = auto() LESS = auto() LESS_EQUAL = auto() EQUAL = auto() NOT = auto() AND = auto() OR = auto() # flow IF = auto() FOR_COUNT = auto() PIPE = auto() # keywords DEF = auto() LAMBDA = auto() # symbols SYMBOL = auto() # types INT_TYPE = auto() FLOAT_TYPE = auto() STRING_TYPE = auto() ANY_TYPE = auto() LIST_TYPE = auto() class TypeEnum(Enum): ANY = auto() STRING = auto() INT = auto() FLOAT = auto() NUMBER = auto() LIST = auto() LITERAL = auto() BOOL = auto() def __str__(self): return f":{self.name.lower()}" TYPE_HIERARCHY = { TypeEnum.ANY: None, TypeEnum.LITERAL: TypeEnum.ANY, TypeEnum.LIST: TypeEnum.ANY, TypeEnum.STRING: TypeEnum.LITERAL, TypeEnum.BOOL: TypeEnum.LITERAL, TypeEnum.NUMBER: TypeEnum.LITERAL, TypeEnum.INT: TypeEnum.NUMBER, TypeEnum.FLOAT: TypeEnum.NUMBER } def is_subtype_of(candidate, expected): if candidate == expected: return True parent = TYPE_HIERARCHY[candidate] while parent is not None: if parent == expected: return True parent = TYPE_HIERARCHY[parent] return False @dataclass class Token: type_: TokenType text: str value: Any line: int def __str__(self): return f"{self.type_.name} {self.text} {self.line}" class Literal: def __init__(self, value, type_=None): self.value = value if type_ is None: self.type_ = TypeEnum.ANY else: self.type_ = type_ def __str__(self): return f"{self.value}:literal" class Int(Literal): def __init__(self, value): super().__init__(value, TypeEnum.INT) def __str__(self): return f"{self.value}" class Float(Literal): def __init__(self, value): super().__init__(value, TypeEnum.FLOAT) def __str__(self): return f"{self.value}" class Bool(Literal): def __init__(self, value): super().__init__(value, TypeEnum.BOOL) def __str__(self): return f"#{str(self.value).lower()}" class String(Literal): def __init__(self, value): super().__init__(value, TypeEnum.STRING) def __str__(self): return f'"{repr(self.value)[1:-1]}"' class Type: def __init__(self, name): self.name = name def __str__(self): return self.name class Symbol: def __init__(self, name, line): self.name = name self.line = line def __str__(self): return f"'{self.name}" class List: def __init__(self, args, data=False): self.args = args self.data = data self.type_ = TypeEnum.LIST def __str__(self): return "(" + " ".join(f"{arg}" for arg in self.args) + ")" class TypedList(List): def __init__(self, args, data=True, type_=Type("string")): super().__init__(args, data) self.type_ = type_ def __str__(self): return super().__str__() + f"{self.type_}" class Strings(TypedList): def __init__(self, args, data=True): super().__init__(args, data, Type(":string"))