90 lines
2.6 KiB
Python
90 lines
2.6 KiB
Python
import langbuiltins
|
|
from lexer import kinds
|
|
from parser import parse, ParseError, BinOp, UnaryOp, Atom
|
|
from ir import toIr, evaluate, Application
|
|
from typechecker import typecheck, TypecheckError
|
|
from formatter import printValue
|
|
|
|
def prettyprintParsetree(tree, nesting=0):
|
|
indent = ' ' * nesting
|
|
if isinstance(tree, BinOp):
|
|
print(f'{indent}binop: {tree.operator}')
|
|
prettyprintParsetree(tree.left, nesting + 1)
|
|
prettyprintParsetree(tree.right, nesting + 1)
|
|
elif isinstance(tree, UnaryOp):
|
|
print(f'{indent}unaryop: {tree.operator}')
|
|
prettyprintParsetree(tree.inner, nesting + 1)
|
|
elif isinstance(tree, Atom):
|
|
print(f'{indent}atom: {tree}')
|
|
else:
|
|
print(f'{indent}{tree}')
|
|
|
|
kindNames = {
|
|
kinds.eof: 'the end of the expression',
|
|
kinds.number: 'a number',
|
|
kinds.plus: "'+'",
|
|
kinds.minus: "'-'",
|
|
kinds.multiply: "'*'",
|
|
kinds.divide: "'/'",
|
|
kinds.openparen: "'('",
|
|
kinds.closeparen: "')'",
|
|
}
|
|
|
|
def kindNameList(kinds):
|
|
if len(kinds) == 1:
|
|
return kindNames[kinds[0]]
|
|
elif len(kinds) == 2:
|
|
return f'{kindNames[kinds[0]]} or {kindNames[kinds[1]]}'
|
|
else:
|
|
last = kindNames[kinds[-1]]
|
|
rest = ', '.join(kindNames[kind] for kind in kinds[:-1])
|
|
return f'{rest}, or {last}'
|
|
|
|
def prettyprintParseError(source, e):
|
|
beforeToken = source[:e.token.index]
|
|
afterToken = source[e.token.index + len(e.token.text):]
|
|
if e.token.kind == kinds.eof:
|
|
print(f'Error: Unexpected end of expression. Expected {kindNameList(e.expected)}.')
|
|
print(f'{source}\x1b[4m \x1b[0m')
|
|
elif e.token.kind == kinds.unknown:
|
|
print('Error: Not recognized.')
|
|
print(f'{beforeToken}\x1b[4m{e.token.text}\x1b[0m{afterToken}')
|
|
else:
|
|
print(f'Error: Expected {kindNameList(e.expected)}, but got {kindNames[e.token.kind]}.')
|
|
print(f'{beforeToken}\x1b[4m{e.token.text}\x1b[0m{afterToken}')
|
|
|
|
def prettyprintIr(ir):
|
|
for index, node in enumerate(ir):
|
|
if isinstance(node.value, Application):
|
|
inputs = ', '.join(f'${i}' for i in node.value.inputs)
|
|
value = f'{node.value.op}({inputs})'
|
|
else:
|
|
value = node.value
|
|
print(f'${index}: {node.type} = {value}')
|
|
|
|
def prettyprintTypecheckError(e):
|
|
print(f'Error: Incompatible types {e.a} and {e.b}')
|
|
|
|
def repl():
|
|
try:
|
|
while True:
|
|
string = input('> ')
|
|
try:
|
|
parsed = parse(string)
|
|
except ParseError as e:
|
|
prettyprintParseError(string, e)
|
|
continue
|
|
ir, resultNode = toIr(parsed)
|
|
try:
|
|
typecheck(langbuiltins.types, ir)
|
|
except TypecheckError as e:
|
|
prettyprintTypecheckError(e)
|
|
continue
|
|
evaluate(langbuiltins.impls, ir)
|
|
result = ir[resultNode]
|
|
printValue(result.value.value, result.type)
|
|
except EOFError:
|
|
print()
|
|
|
|
if __name__ == '__main__':
|
|
repl()
|