From cdf33bd6daa577fe468fcf2d72c6603625a54ac0 Mon Sep 17 00:00:00 2001 From: Emi Simpson Date: Wed, 15 Mar 2023 13:36:07 -0400 Subject: [PATCH] Add compilation to JavaScript --- ir.py | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 74 insertions(+), 4 deletions(-) diff --git a/ir.py b/ir.py index a5a18b4..c631699 100644 --- a/ir.py +++ b/ir.py @@ -1,6 +1,6 @@ from emis_funky_funktions import * -from typing import Mapping, Sequence, Tuple, TypeAlias +from typing import Collection, Mapping, Sequence, Tuple, TypeAlias import types_ @@ -33,6 +33,9 @@ class NamePattern: def __repr__(self) -> str: return self.name + def codegen(self, match_on: str) -> Tuple[Sequence[str], Collection[Tuple[str, str]]]: + return (tuple(), [(self.name, match_on)]) + @dataclass(frozen=True) class IgnorePattern: """ @@ -59,6 +62,9 @@ class IgnorePattern: def __repr__(self) -> str: return '_' + def codegen(self, match_on: str) -> Tuple[Sequence[str], Collection[Tuple[str, str]]]: + return (tuple(), tuple()) + @dataclass(frozen=True) class IntPattern: value: int @@ -89,6 +95,9 @@ class IntPattern: def __repr__(self) -> str: return repr(self.value) + def codegen(self, match_on: str) -> Tuple[Sequence[str], Collection[Tuple[str, str]]]: + return ((f'{match_on} === {self.value}',), tuple()) + @dataclass(frozen=True) class SPattern: pred: Pattern @@ -120,6 +129,10 @@ class SPattern: def __repr__(self) -> str: return 'S ' + repr(self.pred) + def codegen(self, match_on: str) -> Tuple[Sequence[str], Collection[Tuple[str, str]]]: + pred_conditions, pred_bindings = self.pred.codegen(f'({match_on} - 1)') + return ((f'{match_on} > 0', *pred_conditions), pred_bindings) + @dataclass(frozen=True) class ReplHole: typ_bindings: types_.Context @@ -137,10 +150,20 @@ class ReplHole: def __repr__(self) -> str: return "[]" + def codegen(self) -> str: + return '[]' + + def render(self) -> str: + return '\n'.join( + f'{var_name} = ({var_expr.codegen()});' + for (var_name, var_expr) in self.val_bindings + ) + @dataclass(frozen=True) class Builtin: name: str f: Callable[[Expression], Option[Expression]] + js: str def subst(self, expression: Expression, variable: str) -> Expression: return self @@ -157,6 +180,9 @@ class Builtin: def __repr__(self) -> str: return "'" + repr(self.name)[1:-1] + "'" + def codegen(self) -> str: + return self.js + @cur2 @staticmethod def _PLUS_CONST(i: int, e: Expression) -> Option[Expression]: @@ -169,16 +195,21 @@ class Builtin: def _PLUS(e: Expression) -> Option[Expression]: match e: case Int(v): - return Some(Builtin(f'+{v}', Builtin._PLUS_CONST(v))) + return Some(Builtin(f'+{v}', Builtin._PLUS_CONST(v), f'(x => x + {v})')) return None @staticmethod def PLUS() -> 'Builtin': - return Builtin('+', Builtin._PLUS) + return Builtin('+', Builtin._PLUS, '(x => y => x + y)') @staticmethod def S() -> 'Builtin': - return Builtin('S', Builtin._PLUS_CONST(1)) + return Builtin('S', Builtin._PLUS_CONST(1), '(x => x + 1)') + +BUILTIN_SUBSTITUTIONS: Sequence[Tuple[str, Expression]] = ( + ('+', Builtin.PLUS()), + ('S', Builtin.S()), +) @dataclass(frozen=True) class Function: @@ -204,6 +235,32 @@ class Function: return Some(subst_all(bindings, body)) raise Exception('Unreachable') + def codegen_inner(self) -> str: + return (':'.join( + ( + '&&'.join( + iter(pattern.codegen('$local_temp$')[0]) + ) or '1' + ) + '?' + ( + '((' + ','.join( + binding_name + for (binding_name, binding_value) + in pattern.codegen('$local_temp$')[1] + ) + f') => ({branch.codegen()}))(' + ','.join( + binding_value + for (binding_name, binding_value) + in pattern.codegen('$local_temp$')[1] + ) + ')' + if len(pattern.codegen('$local_temp$')[1]) else + branch.codegen() + ) + for (pattern, branch) in self.forms + ) or '0?undefined') + ':undefined' + + def codegen(self) -> str: + return '($local_temp$) => ' + self.codegen_inner() + def codegen_named(self, name) -> str: + return f'function {name}($local_temp$){{return {self.codegen_inner()}}}' def __repr__(self) -> str: return '{ ' + ', '.join('"' + repr(repr(p))[1:-1] + '" : ' + repr(e) for (p, e) in self.forms) + ' }' @@ -244,6 +301,10 @@ class LetBinding: def __repr__(self) -> str: return f'( {repr(self.lhs)}, {repr(self.rhs)}, {repr(self.body)} )' + def codegen(self) -> str: + rhs_cg = self.rhs.codegen_named(self.lhs) if isinstance(self.rhs, Function) else self.rhs.codegen() + return f'(({self.lhs}) => {self.body.codegen()})({rhs_cg})' + @dataclass class Application: first: Expression @@ -274,6 +335,9 @@ class Application: def __repr__(self) -> str: return f'[ {repr(self.first)}, {repr(self.arg)} ]' + def codegen(self) -> str: + return f'({self.first.codegen()})({self.arg.codegen()})' + @dataclass class Int: value: int @@ -290,6 +354,9 @@ class Int: def __repr__(self) -> str: return str(self.value) + def codegen(self) -> str: + return str(self.value) + @dataclass class Variable: name: str @@ -314,6 +381,9 @@ class Variable: def __repr__(self) -> str: return '"' + repr(self.name)[1:-1] + '"' + def codegen(self) -> str: + return self.name + def subst_all(bindings: Sequence[Tuple[str, Expression]], body: Expression) -> Expression: match bindings: case []: