Compare commits

...

6 Commits

4 changed files with 24 additions and 16 deletions

View File

@ -135,14 +135,6 @@ aka a let binding without an "in" clause
["addTwo", {"x": ["S", ["S", "x"]]}]
```
### Execute REPL within context
(this is still a bit buggy, and may create an invalid REPL)
```json
[{"x": []}, 12]
```
### Multi-argument functions
```json

View File

@ -1,5 +1,12 @@
[
"fibb",
"slow_fibb",
{
"0": 0,
"1": 1,
"n": ["+", ["slow_fibb", ["+", "n", -2]], ["slow_fibb", ["+", "n", -1]]]
},
"fast_fibb",
[
"fibb_helper",
{

18
ir.py
View File

@ -11,6 +11,12 @@ import types_
Expression: TypeAlias = 'MonoFunc | Application | Int | Variable | Builtin | LetBinding | ReplHole | Switch'
Value: TypeAlias = 'MonoFunc | Int | Builtin | ReplHole'
dollar_count: int = 0
def mk_dollar() -> str:
global dollar_count
dollar_count += 1
return f'${dollar_count-1}'
@dataclass(frozen=True)
class ReplHole:
typ_bindings: types_.Context
@ -34,7 +40,7 @@ class ReplHole:
def render(self) -> str:
return '\n'.join(
f'const {var_name} = ({var_expr.codegen()});'
for (var_name, var_expr) in self.val_bindings
for (var_name, var_expr) in self.val_bindings[::-1]
if var_name not in types_.BUILTINS_CONTEXT
)
@ -120,18 +126,20 @@ class MonoFunc:
case [(var, [])]: # Binds a single variable to the entire input
return Ok(MonoFunc(var, body))
local_variable = mk_dollar()
# If those special cases fail, we eliminate the pattern matching to produce a
# single body:
match_trees = tuple( # Construct a match tree for each possible branch
pattern.match_tree(
EMPTY_STRUCT_PATH,
LeafNode.from_value(bindings_to_lets(pattern.bindings(), Variable('$'), body))
LeafNode.from_value(bindings_to_lets(pattern.bindings(), Variable(local_variable), body))
)
for (pattern, body) in forms
)
unified_match_tree = merge_all_trees(match_trees) # Unify all the trees
compiled_tree = compile_tree(unified_match_tree, Variable('$')) # Turn each tree into IR
return compiled_tree <= p(MonoFunc, '$')
compiled_tree = compile_tree(unified_match_tree, Variable(local_variable)) # Turn each tree into IR
return compiled_tree <= p(MonoFunc, local_variable)
def try_apply(self, v: Expression) -> Option[Expression]:
return Some(self.body.subst(v, self.arg))
@ -222,7 +230,7 @@ class Application:
return unwrap_opt(self.first.try_apply(self.arg)).codegen()
else:
match self.first:
case Application(Builtin(Builtin.BB_PLUS), addend1):
case Application(Builtin(Builtin.BB_PLUS()), addend1):
return f'({addend1.codegen()} + {self.arg.codegen()})'
case Builtin(Builtin.BB_PLUS_CONST(n)):
return f'({self.arg.codegen()}{n:+})'

5
opt.py
View File

@ -10,8 +10,9 @@ Optimization: TypeAlias = Callable[[Expression], Option[Expression]]
def eliminate_single_let(expr: Expression) -> Option[Expression]:
match expr:
case LetBinding(lhs, rhs, body):
if count_uses(lhs, body) <= 1:
# RHS is used at most once i nthe body
rhs_is_simple = isinstance(rhs, Int | Variable | Builtin)
if count_uses(lhs, body) <= 1 or rhs_is_simple:
# RHS is used at most once i nthe body or replication wouldnt be costly
if count_uses(lhs, rhs) > 0:
# RHS is recursive
if not isinstance(body, Variable):