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

73 lines
1.6 KiB
Python

import dataclasses
import fractions
from parser import BinOp, UnaryOp, Atom
from lexer import kinds, Token
from typesystem import Type, UnknownType, Rational, Integer
@dataclasses.dataclass
class Literal:
value: int | fractions.Fraction
@dataclasses.dataclass
class Application:
op: str
inputs: [int]
@dataclasses.dataclass
class Node:
value: Application | Literal
type: Type
def toIr(tree):
nodes = []
def newNode(value, type = None):
if type is None:
type = UnknownType()
nodes.append(Node(
value=value,
type=type
))
return len(nodes) - 1
def numberLiteral(string):
if '.' in string:
return newNode(Literal(fractions.Fraction(string)), Rational())
else:
value = int(string)
return newNode(Literal(value), Integer(value, value))
def inner(tree):
if isinstance(tree, BinOp):
left = inner(tree.left)
right = inner(tree.right)
return newNode(Application(
op=tree.operator.text,
inputs=[left, right]
))
elif isinstance(tree, UnaryOp):
return newNode(Application(
op=tree.operator.text,
inputs=[inner(tree.inner)]
))
else:
assert isinstance(tree, Atom)
assert isinstance(tree.value, Token)
assert tree.value.kind == kinds.number
return numberLiteral(tree.value.text)
result = inner(tree)
return nodes, result
def evaluate(context, nodes):
for node in nodes:
if isinstance(node.value, Literal):
continue
assert isinstance(node.value, Application)
assert all(isinstance(nodes[i].value, Literal) for i in node.value.inputs)
args = [nodes[i].value.value for i in node.value.inputs]
result = context[node.value.op](*args)
node.value = Literal(result)
# TODO: unit tests