Continue brain-dumping psudocode and notes. I think I've got most everything critical now

This commit is contained in:
Nathan Braswell
2022-03-21 23:50:59 -04:00
parent b3122f62d1
commit 5c1473d32c
2 changed files with 214 additions and 120 deletions

View File

@@ -135,13 +135,53 @@ fun partial_eval_helper(x, only_head, env, env_stack, memostuff, force):
x is MarkedComb -> if !env.is_real && !x.se.is_real // both aren't real, re-evaluation of closure creation site
|| env.is_real && !x.se.is_real // new env real, but se isn't - the creation of the closure!
then let inner_env = make_tmp_inner_env(x.params, x.de?, env, x.env_id)
in MarkedComb(se=env, body=partial_eval_helper(body, false, inner_env, add inner_env to env_stack, memostuff, false))
in MarkedComb(se=env, body=partial_eval_helper(body, false, inner_env, <add inner_env to env_stack>, memostuff, false))
x is MarkedPrimComb -> x
x is MarkedSymbol -> if x.is_val then x
else env_lookup_helper(x, env)
x is MarkedArray -> if x.is_val then x
else ...TODO...
else let
comb = partial_eval_helper(x.values[0], only_head=true, env, env_stack, memostuff, false)
params = x.values[1:]
if later_head?(comb) return MarkedArray(values=[comb]+params)
if comb.needed_for_progress == true:
comb = partial_eval_helper(comb, only_head=false, ...)
// If not -1, we always partial eval, if >0 we also unval/partial eval to do one full round of eval
wrap_level = comb.wrap_level
while wrap_level >= 0:
if wrap_level >= 1:
params = map(unval, map(\x. partial_eval_helper(x, ...), params))
params = map(\x. partial_eval_helper(x, ...), params)
wrap_level -= 1
if <any of the above error, or couldn't be unvaled yet>:
return MarkedArray(values=[comb.with_wrap_level(wrap_level)] + <params at whatever level they were sucessfully evaluated to>)
if comb is MarkedPrimComb:
result = comb.impl(params)
if result == 'LATER:
return MarkedArray(values=[comb.with_wrap_level(wrap_level)] + params)
else:
return result
if comb.is_varadic:
params = params[:comb.params.len-1] + [ params[comb.params.len-1:] ]
inner_env = MarkedEnv(id=comb.env_id, possible_de_symbol=comb.de?, possible_de=env, symbols=comb.params, values=params, upper=comb.se)
rec_stop_hash = combine_hash(inner_env.hash, comb.body.hash)
if rec_stop_hash in memostuff:
return MarkedArray(values=[comb] + params, transient_needed_env_id=true, rec_stopping_hash=rec_stop_hash)
memostuff.add(rec_stop_hash)
result = partial_eval_helper(body, false, inner_env, <add inner_env to env_stack>, memostuff, false)
memostuff.remove(rec_stop_hash)
if !combiner_return_ok(result, comb.env_id):
transiently_needed = if comb.de? != nil then env.id else nil
return MarkedArray(values=[comb] + params, transient_needed_env_id=transiently_needed, rec_stopping_hash=rec_stop_hash)
return drop_redundent_veval(result, env, env_stack, memostuff)
And then we define a root_env with PrimComb versions of all of the standard functions.
The ones that are most interesting and interact the most with partial evaluation are
@@ -153,16 +193,61 @@ fun needs_params_prim(...):
...
fun give_up_params_prim(...):
...
fun veval_inner(...):
...
fun veval_inner(only_head, de, env_stack, memostuff, params):
body = params[0]
implicent_env = len(params) != 2
eval_env = if implicit_env { de } else { partial_eval_helper(params[1], only_head, de, env_stack, memostuff, false) }
evaled_body = partial_eval_helper(body, only_head, eval_env, env_stack, memostuff, false)
if implicit_env or combiner_return_ok(evaled_body, eval_env.idx):
return drop_redundent_veval(evaled_body, de, env_stack, memostuff)
else:
return drop_redundent_veval(MarkedArray(values=[MarkedPrimComb('veval, wrap_level=-1, val_head_ok=true, handler=veval_inner), evaled_body, eval_env], de, env_stack, memostuff)
root_env = {
eval: ...
vapply: ...
lapply: ...
vau: ....
wrap: ...
unwrap: ...
eval: MarkedPrimComb('eval, wrap_level=1, val_head_ok=true, handler=lambda(only_head, de, env_stack, memostuff, params):
let
body = params[0]
implicit_env = len(params) != 2
return veval_inner(only_head, de, env_stack, memostuff, if implicit_env { [try_unval(body)] } else { [try_unval(body), params[1]] })
)
vapply: MarkedPrimComb('vapply, wrap_level=1, val_head_ok=true, handler=lambda(only_head, de, env_stack, memostuff, [func params env]):
return veval_inner(only_head, de, env_stack, memostuff, [MarkedArray(values=[func]+params), env)
)
lapply: MarkedPrimComb('lapply, wrap_level=1, val_head_ok=true, handler=lambda(only_head, de, env_stack, memostuff, [func params env]):
return veval_inner(only_head, de, env_stack, memostuff, [MarkedArray(values=[func.offset_wrap_level(-1)]+params), env)
)
vau: MarkedPrimComb('vau, wrap_level=0, val_head_ok=true, handler=lambda(only_head, de, env_stack, memostuff, params):
let
de? = if len(params) == 3 { params[0].symbol_value } else { nil }
params = map(lambda(x): s.symbol_value, if de? { params[1] } else { params[0] })
varadic = '& in params
params.remove('&)
implicit_env = len(params) != 2
body = try_unval(if de? { params[2] } else { params[1] })
env_id = <new_id>
if !only_head:
inner_env = make_tmp_inner_env(params, de?, upper=de, id=env_id)
body = partial_eval_helper(body, false, inner_env, <add inner_env to env_stack>, memostuff, false)
return MarkedComb(wrap_level=0, id=new_id, de?=de?, static_env=de, variadic=varadic, params=params, body=body)
)
wrap: ...<returns new MarkedPrimComb/MarkedComb with incremented wrap_level>...
unwrap: ...<returns new MarkedPrimComb/MarkedComb with decremented wrap_level>...
cond: ...
...Oddly tricky - is wrap_level 0, but...
... 1. unvals & partially evaluates starting from the first condition
... 2. if this condition is true, return the unvald & partially evaluated corresponding arm
... 3. if this condition is false, drop the arm and return to 1
... 4. In this case, we have an unknown between true & false
... 5. check to see if combine_hash(x.hash, env.hash) is in memostuff (prevent infinite recursion blocked on a cond guard!)
... 6. if the hash was in memostuff, return MarkedArray(later_hash=the_hash,
... values=[MarkedPrimComb('vcond,wraplevel=-1,...)] + map(unval, <remaining preds/arms>))
... 7. else new_preds_arms = map(partial_eval..., map(unval, <remaining preds/arms>))
... <TODO: 8. remove arms/preds now guarenteed to be false, remove all arms/preds after first true>
... 9. return MarkedArray(values=[MarkedPrimComb('vcond,wraplevel=-1,...)] + new_preds)
...
...The vcond is like cond but doesn't do any unvaling (as it's already been done) (and wrap_level is set to -1 so the function call machinery doesn't touch the params either)
...
symbol?: needs_params_prim(symbol?)
int?: needs_params_prim(int?)
string?: needs_params_prim(string?)
@@ -203,6 +288,10 @@ root_env = {
}
fun compile(...):
...
... tagged words, etc
... eval
... vau / vau helper closure
...
Note that when it's compiling a call, it compiles an if/else chain on the wrap level of the combiner being called.
in the 0 branch, it emits the parameters as constant data
@@ -210,3 +299,8 @@ fun compile(...):
- note that this must be robust to partial-eval errors, as this branch might not ever happen at runtime and be nonsense code!
- if the partial evaluation errors, it emits a value that will cause an error at runtime into the compiled code
in the > 1 branch, it errors
...
...
Must be careful about infiniate recursion, including tricky cases that infinitly ping back and forth between
partial eval and compile even though both have individual internal recursion checks
...