196 lines
4.7 KiB
Python
196 lines
4.7 KiB
Python
import enum
|
|
from operator import add
|
|
from functools import reduce
|
|
from string import ascii_letters
|
|
from typing import Union, Dict, Callable, Tuple, List, TypeVar
|
|
|
|
|
|
Number = Union[int, float]
|
|
NamespaceValue = Union[Number, Callable]
|
|
Namespace = Dict[str, NamespaceValue]
|
|
|
|
UNARY_OPERATORS = {"+", "-"}
|
|
ALLOWED_LITERALS = ascii_letters + "_"
|
|
|
|
T = TypeVar("T")
|
|
|
|
|
|
class Stack(List[T]):
|
|
@property
|
|
def top(self):
|
|
return self[-1]
|
|
|
|
|
|
class LexemeType(enum.IntEnum):
|
|
UNKNOWN = 0
|
|
NUMBER = 1
|
|
HEXNUMBER = 2
|
|
FLOAT = 3
|
|
LITERAL = 4
|
|
OPERATOR = 5
|
|
LPAREN = 6 # (
|
|
RPAREN = 7 # )
|
|
DOT = 8
|
|
COMMA = 9
|
|
EOL = 10
|
|
STRING = 11
|
|
|
|
|
|
class TokenKind(enum.IntEnum):
|
|
NUMBER = 0
|
|
LITERAL = 1
|
|
OPERATOR = 2
|
|
UNARY_OPERATOR = 3
|
|
PAREN = 4
|
|
FUNC = 5
|
|
STRING = 6
|
|
OTHER = 7
|
|
|
|
|
|
class TokenType(enum.IntEnum):
|
|
FLOAT = 0
|
|
INTEGER = 1
|
|
OP_EQ = 2
|
|
OP_EQEQ = 3
|
|
OP_NOTEQ = 4
|
|
OP_ADD = 5
|
|
OP_SUB = 6
|
|
OP_DIV = 7
|
|
OP_MUL = 8
|
|
OP_POW = 9
|
|
OP_LSHIFT = 10
|
|
OP_RSHIFT = 11
|
|
OP_BITWISE_AND = 12
|
|
OP_BITWISE_OR = 13
|
|
OP_BITWISE_XOR = 14
|
|
OP_MOD = 15
|
|
OP_FLOORDIV = 16
|
|
OP_SEMICOLON = 17
|
|
OP_COMMA = 18
|
|
OP_GT = 19
|
|
OP_GE = 20
|
|
OP_LT = 21
|
|
OP_LE = 22
|
|
OP_DOT = 35
|
|
UN_POS = 23
|
|
UN_NEG = 24
|
|
LPAREN = 25
|
|
RPAREN = 26
|
|
VAR = 27
|
|
IDENTIFIER = 28
|
|
FUNCCALL = 29
|
|
FUNCDEF = 30
|
|
FUNCNAME = 31
|
|
FUNC = 32
|
|
STRING = 33
|
|
OTHER = 34
|
|
|
|
|
|
OPERATORS_TABLE = {
|
|
"+": TokenType.OP_ADD,
|
|
"-": TokenType.OP_SUB,
|
|
"/": TokenType.OP_DIV,
|
|
"//": TokenType.OP_FLOORDIV,
|
|
"*": TokenType.OP_MUL,
|
|
"**": TokenType.OP_POW,
|
|
"%": TokenType.OP_MOD,
|
|
"<<": TokenType.OP_LSHIFT,
|
|
">>": TokenType.OP_RSHIFT,
|
|
"&": TokenType.OP_BITWISE_AND,
|
|
"|": TokenType.OP_BITWISE_OR,
|
|
"^": TokenType.OP_BITWISE_XOR,
|
|
|
|
"==": TokenType.OP_EQEQ,
|
|
"!=": TokenType.OP_NOTEQ,
|
|
">": TokenType.OP_GT,
|
|
">=": TokenType.OP_GE,
|
|
"<": TokenType.OP_LT,
|
|
"<=": TokenType.OP_LE,
|
|
|
|
".": TokenType.OP_DOT,
|
|
|
|
";": TokenType.OP_SEMICOLON,
|
|
"=": TokenType.OP_EQ,
|
|
",": TokenType.OP_COMMA
|
|
}
|
|
|
|
OPERATORS_CHARS = set(reduce(add, OPERATORS_TABLE.keys()))
|
|
|
|
|
|
class Priorities(enum.IntEnum):
|
|
NONE = 0
|
|
MINIMAL = 1
|
|
MEDIUM = 2
|
|
HIGH = 3
|
|
MAXIMAL = 4
|
|
|
|
|
|
PRIORITIES_TABLE = {
|
|
TokenType.OP_ADD: Priorities.MINIMAL,
|
|
TokenType.OP_SUB: Priorities.MINIMAL,
|
|
|
|
TokenType.OP_DIV: Priorities.MEDIUM,
|
|
TokenType.OP_FLOORDIV: Priorities.MEDIUM,
|
|
TokenType.OP_MUL: Priorities.MEDIUM,
|
|
TokenType.OP_MOD: Priorities.MEDIUM,
|
|
TokenType.OP_LSHIFT: Priorities.MEDIUM,
|
|
TokenType.OP_RSHIFT: Priorities.MEDIUM,
|
|
TokenType.OP_BITWISE_AND: Priorities.MEDIUM,
|
|
TokenType.OP_BITWISE_OR: Priorities.MEDIUM,
|
|
TokenType.OP_BITWISE_XOR: Priorities.MEDIUM,
|
|
|
|
TokenType.UN_POS: Priorities.HIGH,
|
|
TokenType.UN_NEG: Priorities.HIGH,
|
|
|
|
TokenType.OP_POW: Priorities.MAXIMAL,
|
|
TokenType.FUNCCALL: Priorities.MAXIMAL,
|
|
TokenType.FUNCDEF: Priorities.MAXIMAL,
|
|
TokenType.OP_DOT: Priorities.MAXIMAL,
|
|
|
|
TokenType.OP_EQ: Priorities.NONE,
|
|
TokenType.OP_EQEQ: Priorities.NONE,
|
|
TokenType.OP_NOTEQ: Priorities.NONE,
|
|
TokenType.OP_GT: Priorities.NONE,
|
|
TokenType.OP_GE: Priorities.NONE,
|
|
TokenType.OP_LT: Priorities.NONE,
|
|
TokenType.OP_LE: Priorities.NONE,
|
|
TokenType.OP_COMMA: Priorities.NONE,
|
|
TokenType.OP_SEMICOLON: Priorities.NONE,
|
|
}
|
|
|
|
|
|
class PyCalcError(Exception):
|
|
def __init__(self, message: str, pos: Tuple[int, int]):
|
|
self.message = message
|
|
self.pos = pos
|
|
super().__init__(message)
|
|
|
|
class InvalidSyntaxError(PyCalcError):
|
|
def __init__(self, message: str, pos: Tuple[int, int], offending_token: str):
|
|
self.offending_token = offending_token
|
|
super().__init__(message, pos)
|
|
|
|
class ArgumentsError(PyCalcError):
|
|
def __init__(self, message: str, pos: Tuple[int, int], function_name: str, expected_args: int, received_args: int):
|
|
self.function_name = function_name
|
|
self.expected_args = expected_args
|
|
self.received_args = received_args
|
|
super().__init__(message, pos)
|
|
|
|
class NameNotFoundError(PyCalcError):
|
|
def __init__(self, message: str, pos: Tuple[int, int], variable_name: str):
|
|
self.variable_name = variable_name
|
|
super().__init__(message, pos)
|
|
|
|
class UnknownTokenError(PyCalcError):
|
|
def __init__(self, message: str, pos: Tuple[int, int], token: str):
|
|
self.token = token
|
|
super().__init__(message, pos)
|
|
|
|
class ExternalFunctionError(PyCalcError):
|
|
def __init__(self, message: str, pos: Tuple[int, int], function_name: str):
|
|
self.function_name = function_name
|
|
super().__init__(message, pos)
|
|
|
|
class NoCodeError(Exception):
|
|
pass |