Add compilation to JavaScript
This commit is contained in:
parent
f5d999a3dd
commit
cdf33bd6da
78
ir.py
78
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 []:
|
||||
|
|
Loading…
Reference in a new issue