Slang/compilers/__init__.py

41 lines
1.5 KiB
Python

#!/usr/bin/python3
# Slang compilers
from ..ast import SlSyntaxError, SlValidationError
import abc, traceback
class Compiler(abc.ABC):
@abc.abstractclassmethod
def compile_ast(cls, ast):
pass
def lstripcount(s, chars): # TODO: commonize
for ii, i in enumerate(s):
if (i not in chars): break
else: ii = 0
return (ii, s[ii:])
class SlCompilationError(Exception):
__slots__ = ('desc', 'node', 'line', 'scope')
def __init__(self, desc, node, line='', *, scope=None):
self.desc, self.node, self.line, self.scope = desc, node, line, scope
def __str__(self):
l, line = lstripcount(self.line.partition('\n')[0].replace('\t', ' '), ' \t')
offset = (self.node.offset-l) if (self.node.offset != -1) else len(line)
return (f'\033[2m(in {self.scope})\033[0m ' if (self.scope is not None) else '') + f"Compilation error: {self.desc}{self.at}"+(':\n' + \
' \033[1m'+line[:offset]+'\033[91m'+line[offset:]+'\033[0m\n' + \
' '+' '*offset+'\033[95m^'+'~'*(self.node.length-1)+'\033[0m' if (line) else '') + \
(f"\n\n\033[1;95mCaused by:\033[0m\n{self.__cause__ if (isinstance(self.__cause__, (SlSyntaxError, SlValidationError, SlCompilationError))) else ' '+str().join(traceback.format_exception(type(self.__cause__), self.__cause__, self.__cause__.__traceback__))}" if (self.__cause__ is not None) else '')
@property
def at(self):
return f" at line {self.node.lineno}, offset {self.node.offset}"
@property
def lineno(self):
return self.node.lineno
# by Sdore, 2019