tokin/repl.py
2025-02-16 22:16:06 +02:00

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()