from dataclasses import dataclass from enum import Enum, auto from typing import Any from .typeclass import TypeEnum from .exceptions import NebPanic #from . import Function # tokens and types # NOTE: this can probably be simplified class TokenType(Enum): OPEN_PAREN = auto() CLOSE_PAREN = auto() OPEN_BRACKET = auto() CLOSE_BRACKET = auto() OPEN_BRACE = auto() CLOSE_BRACE = auto() EOF = auto() # literals INT = auto() FLOAT = auto() STRING = auto() TRUE = auto() FALSE = auto() # keywords IF = auto() FOR_COUNT = auto() DEF = auto() LAMBDA = auto() FUNC = auto() # symbols SYMBOL = auto() # types INT_TYPE = auto() FLOAT_TYPE = auto() NUMBER_TYPE = auto() STRING_TYPE = auto() ANY_TYPE = auto() LIST_TYPE = auto() LITERAL_TYPE = auto() BOOL_TYPE = auto() USER_TYPE = auto() MANY = auto() COLON = auto() APOSTROPHE = auto() @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 self.type_ = ALL_TYPES[":literal"] else: self.type_ = ALL_TYPES[type_] def __str__(self): return f"{self.value}:literal" class Int(Literal): def __init__(self, value): super().__init__(value, ":int") def __str__(self): return f"{self.value}" class Float(Literal): def __init__(self, value): super().__init__(value, ":float") def __str__(self): return f"{self.value}" class Bool(Literal): def __init__(self, value): super().__init__(value, ":bool") def __str__(self): return f"#{str(self.value).lower()}" class String(Literal): def __init__(self, value): super().__init__(value, ":string") def __str__(self): return f'"{repr(self.value)[1:-1]}"' class Handle: def __init__(self, file): self.file = file self.type_ = TypeEnum.HANDLE def __str__(self): return f"{self.file.name} :handle" class Type: def __init__(self, name, inner=None): self.name = name self.inner = inner def __str__(self): if self.name == ":[]": if self.inner is None: return f":[:any]" else: return f":[{self.inner}]" elif self.name == ":{}": if self.inner is None: return ":{:any}" else: return ":{" + f"{self.inner}" + "}" else: return self.name _native_types = ":any :literal :string :bool :number :int :float :[] :nil :{} :handle :type" ALL_TYPES = {x: Type(x) for x in _native_types.split(" ")} class Symbol: def __init__(self, name, line, quoted=False): self.name = name self.line = line self.quoted = quoted self.type_ = ALL_TYPES[":any"] # TODO no it's not def __str__(self): if self.quoted: return f"'{self.name}" else: return f"{self.name}" class NebDef: def __init__(self, symbol, type_=ALL_TYPES[":any"]): self.name = symbol.name self.symbol = symbol self.line = symbol.line self.type_ = type_ def __str__(self): return f"{self.name} (def)" class NebFuncDef: def __init__(self, symbol, return_type, args, many, body): self.name = symbol.name self.symbol = symbol self.line = symbol.line self.return_type = return_type self.args = args self.many = many self.body = body class Expr: def __init__(self, args): self.args = args self.type_ = ALL_TYPES[":{}"] # TODO no it's not def __str__(self): return "(" + " ".join(f"{arg}" for arg in self.args) + ")" class List: def __init__(self, args): self.args = args self.type_ = ALL_TYPES[":[]"] def __str__(self): return "(" + " ".join(f"{arg}" for arg in self.args) + ")" class Nil(List): def __init__(self): self.args = [] self.type_ = ALL_TYPES[":nil"] # function things class Arg: def __init__(self, name, type_, *, optional=False): self.name = name if f"{type_}" == ":list": self.type_ = ALL_TYPES[":[]"] else: self.type_ = ALL_TYPES[f"{type_}"] self.optional = optional def __str__(self): return f"{self.name} {self.type_}" def string_args(args, many): out = [f"{arg}" for arg in args] if many is not None: many_dup = Arg("&", many.type_) out.append(f"{many_dup}") return " ".join(out).strip() class Environment: def __init__(self, parent=None): self.parent = parent self.environment = {} def register(self, key, value): self.environment[key] = value def reregister(self, key, value): if not self.contains(key): raise NebPanic(f"undefined symbol: '{key}") if key in self.environment: self.register(key, value) else: self.parent.reregister(key, value) def contains(self, key): if key in self.environment: return True elif self.parent is not None: return self.parent.contains(key) else: return False def get(self, key): try: return self.environment[key] except: pass try: return self.parent.get(key) except: raise NebPanic(f"undefined symbol: '{key}") def get_all(self): if self.parent is None: return self.environment else: return dict(self.parent.get_all(), **self.environment) def __str__(self): out = "" for k, v in self.environment.items(): out += f"{k}: {v}, " return out