Add let statements

This commit is contained in:
Emi Simpson 2023-03-08 11:03:36 -05:00
parent c27852daba
commit a49b7b5baf
Signed by: Emi
GPG key ID: A12F2C2FFDC3D847
2 changed files with 98 additions and 35 deletions

View file

@ -3,7 +3,7 @@ from typing import *
from silly_thing import * from silly_thing import *
from pattern import lex_and_parse_pattern from pattern import lex_and_parse_pattern
from ir import Function, Application, Int, Variable from ir import Function, Application, Int, Variable, LetBinding, Unit
import json import json
@ -19,6 +19,11 @@ def json_to_ir(j: JsonType) -> Expression:
elif isinstance(j, str): elif isinstance(j, str):
return Variable(j) return Variable(j)
elif isinstance(j, Sequence): elif isinstance(j, Sequence):
return Application([json_to_ir(e) for e in j]) match j:
case [first, *rest]:
return Application(json_to_ir(first), [json_to_ir(a) for a in rest])
case []:
return Unit()
raise Exception('Unreachable')
else: else:
return Int(j) return Int(j)

116
ir.py
View file

@ -3,7 +3,7 @@ from emis_funky_funktions import *
from typing import Mapping, Sequence, Tuple, TypeAlias from typing import Mapping, Sequence, Tuple, TypeAlias
Expression: TypeAlias = 'Function | Application | Int | Variable | Builtin' Expression: TypeAlias = 'Function | Application | Int | Variable | Builtin | LetBinding | Unit'
Pattern: TypeAlias = 'NamePattern | IntPattern | SPattern | IgnorePattern' Pattern: TypeAlias = 'NamePattern | IntPattern | SPattern | IgnorePattern'
@dataclass(frozen=True) @dataclass(frozen=True)
@ -118,6 +118,20 @@ class SPattern:
def __repr__(self) -> str: def __repr__(self) -> str:
return 'S ' + repr(self.pred) return 'S ' + repr(self.pred)
@dataclass(frozen=True)
class Unit:
def subst(self, expression: Expression, variable: str) -> Expression:
return self
def is_value(self) -> bool:
return True
def step(self) -> Option[Expression]:
return None
def __repr__(self) -> str:
return "[]"
@dataclass(frozen=True) @dataclass(frozen=True)
class Builtin: class Builtin:
name: str name: str
@ -189,48 +203,92 @@ class Function:
return '{ ' + ', '.join('"' + repr(repr(p))[1:-1] + '" : ' + repr(e) for (p, e) in self.forms) + ' }' return '{ ' + ', '.join('"' + repr(repr(p))[1:-1] + '" : ' + repr(e) for (p, e) in self.forms) + ' }'
@dataclass @dataclass
class Application: class LetBinding:
expressions: Sequence[Expression] lhs: str
rhs: Expression
body: Expression
def subst(self, expression: Expression, variable: str) -> Expression: def subst(self, expression: Expression, variable: str) -> Expression:
return Application([ if self.lhs == variable:
e.subst(expression, variable) return self
for e in self.expressions else:
]) return LetBinding(
self.lhs,
self.rhs.subst(expression, variable),
self.body.subst(expression, variable)
)
def is_value(self) -> bool: def is_value(self) -> bool:
return not len(self.expressions) return False
def step(self) -> Option[Expression]: def step(self) -> Option[Expression]:
match self.expressions: if self.rhs.is_value():
return Some(self.body.subst(
self.rhs.subst(
LetBinding(self.lhs, self.rhs, Variable(self.lhs)),
self.lhs
),
self.lhs
))
else:
return map_opt(lambda rhs_step:
LetBinding(self.lhs, rhs_step, self.body),
self.rhs.step()
)
def __repr__(self) -> str:
if isinstance(self.body, LetBinding) or isinstance(self.body, Application):
return f'L[ {repr(self.lhs)}, {repr(self.rhs)},{repr(self.body)[1:-1]}]'
else:
return f'L[ {repr(self.lhs)}, {repr(self.rhs)}, {repr(self.body)}]'
@dataclass
class Application:
first: Expression
args: Sequence[Expression]
def subst(self, expression: Expression, variable: str) -> Expression:
return Application(
self.first.subst(expression, variable),
[r.subst(expression, variable) for r in self.args]
)
def is_value(self) -> bool:
return False
def step(self) -> Option[Expression]:
match self.args:
case []: case []:
return None return Some(self.first)
case [e]: case [a, *rest]:
return Some(e) match self.first.step():
case [f, a, *rest]: case Some(first_stepped):
if f.is_value(): return Some(Application(first_stepped, self.args))
if a.is_value(): case None:
if isinstance(f, Function) or isinstance(f, Builtin): match a.step():
case Some(a_stepped):
return Some(Application(self.first, [a_stepped, *rest]))
case None:
if isinstance(self.first, Function) or isinstance(self.first, Builtin):
return map_opt( return map_opt(
lambda maybe_f_sub: Application([maybe_f_sub, *rest]), lambda f_sub: Application(f_sub, rest),
f.try_apply(a) self.first.try_apply(a)
) )
elif isinstance(self.first, Variable):
lhs = self.first.name
rhs = a
body = rest
match body:
case []:
return Some(Unit())
case [body_first, *body_rest]:
return Some(LetBinding(lhs, rhs, Application(body_first, body_rest)))
else: else:
return None return None
else:
return map_opt(
lambda next_a: Application([f, next_a, *rest]),
a.step()
)
else:
return map_opt(
lambda next_f: Application([next_f, a, *rest]),
f.step()
)
raise Exception('Unreachable') raise Exception('Unreachable')
def __repr__(self) -> str: def __repr__(self) -> str:
return '[ ' + ', '.join(repr(e) for e in self.expressions) + ' ]' return f'[ {repr(self.first)}, ' + ', '.join(repr(e) for e in self.args) + ' ]'
@dataclass @dataclass
class Int: class Int: