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"]]}] ["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 ### Multi-argument functions
```json ```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", "fibb_helper",
{ {

18
ir.py
View File

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