scope_analysis: added support for deferred computation
This commit is contained in:
@@ -81,6 +81,30 @@ let resolve_set tbl env sym expr =
|
|||||||
| Global i -> Ok (SetGlobal (i, expr))
|
| Global i -> Ok (SetGlobal (i, expr))
|
||||||
| _ -> Error "resolve_set: symbol resolution returned something invalid."
|
| _ -> Error "resolve_set: symbol resolution returned something invalid."
|
||||||
|
|
||||||
|
(* We need to do some more sophisticated analysis to detect cases where
|
||||||
|
a symbol is accessed before it is defined.
|
||||||
|
If a symbol is accessed in a lambda body, that is fine, since that computation
|
||||||
|
is delayed, but for top-level forms that are directly executed we must be strict.
|
||||||
|
|
||||||
|
The analyze function is strict by default, until it encounters a lambda, at which
|
||||||
|
point it switches to resolving against all symbols.
|
||||||
|
global_tbl is a table that contains ALL defined symbols,
|
||||||
|
tbl is a table that contains symbols defined only until this point.
|
||||||
|
|
||||||
|
NOTE: because we currently convert all let expressions into lambdas, things like
|
||||||
|
this won't immediately be rejected by the compiler:
|
||||||
|
|
||||||
|
(let ((a 5))
|
||||||
|
b)
|
||||||
|
(define b 5)
|
||||||
|
|
||||||
|
I may consider adding special support for let forms, as this is pretty annoying.
|
||||||
|
*)
|
||||||
|
let convert program =
|
||||||
|
let global_tbl = extract_globals program in
|
||||||
|
let id_counter = (ref (-1)) in
|
||||||
|
let id () =
|
||||||
|
id_counter := !id_counter + 1; !id_counter in
|
||||||
let rec analyze tbl current = function
|
let rec analyze tbl current = function
|
||||||
| Core_ast.Literal s -> Ok (Literal s)
|
| Core_ast.Literal s -> Ok (Literal s)
|
||||||
| Var sym -> resolve_symbol tbl current sym
|
| Var sym -> resolve_symbol tbl current sym
|
||||||
@@ -88,7 +112,7 @@ let rec analyze tbl current = function
|
|||||||
let* inner = analyze tbl current expr in
|
let* inner = analyze tbl current expr in
|
||||||
resolve_set tbl current sym inner
|
resolve_set tbl current sym inner
|
||||||
| Lambda (s, body) ->
|
| Lambda (s, body) ->
|
||||||
let* body = (analyze tbl (s :: current) body) in
|
let* body = (analyze global_tbl (s :: current) body) in
|
||||||
Ok (Lambda body)
|
Ok (Lambda body)
|
||||||
| Apply (f, e) ->
|
| Apply (f, e) ->
|
||||||
let* f = analyze tbl current f in
|
let* f = analyze tbl current f in
|
||||||
@@ -102,3 +126,11 @@ let rec analyze tbl current = function
|
|||||||
| Begin el ->
|
| Begin el ->
|
||||||
let* body = traverse (analyze tbl current) el in
|
let* body = traverse (analyze tbl current) el in
|
||||||
Ok (Begin body)
|
Ok (Begin body)
|
||||||
|
in
|
||||||
|
let[@tail_mod_cons] rec aux tbl = function
|
||||||
|
| [] -> []
|
||||||
|
| (Core_ast.Expr e) :: rest -> (analyze tbl [] e) :: (aux tbl rest)
|
||||||
|
| (Define (s, e)) :: rest ->
|
||||||
|
let tbl = SymbolTable.add s (id ()) tbl in
|
||||||
|
(analyze tbl [] e) :: (aux tbl rest)
|
||||||
|
in aux SymbolTable.empty program
|
||||||
|
|||||||
Reference in New Issue
Block a user