scope analysis: created another type to statically eliminate one (im)possible error case
ci/woodpecker/push/debian Pipeline was successful
ci/woodpecker/push/publish Pipeline was successful
ci/woodpecker/push/nix Pipeline was successful
ci/woodpecker/push/fedora Pipeline was successful
ci/woodpecker/cron/publish Pipeline failed
ci/woodpecker/cron/debian Pipeline was successful
ci/woodpecker/cron/nix Pipeline was successful
ci/woodpecker/cron/fedora Pipeline was successful
ci/woodpecker/push/debian Pipeline was successful
ci/woodpecker/push/publish Pipeline was successful
ci/woodpecker/push/nix Pipeline was successful
ci/woodpecker/push/fedora Pipeline was successful
ci/woodpecker/cron/publish Pipeline failed
ci/woodpecker/cron/debian Pipeline was successful
ci/woodpecker/cron/nix Pipeline was successful
ci/woodpecker/cron/fedora Pipeline was successful
This commit is contained in:
@@ -8,28 +8,35 @@ let traverse = Util.traverse
|
|||||||
(* literals are not modified. *)
|
(* literals are not modified. *)
|
||||||
type literal = Core_ast.literal
|
type literal = Core_ast.literal
|
||||||
|
|
||||||
|
(* I made this a separate type, because this behaviour is common to both symbol
|
||||||
|
accesses, and to set! operations on symbols.
|
||||||
|
They can both either refer to a local, or refer to a global, and making a
|
||||||
|
separate type for this lets us statically eliminate a couple potential
|
||||||
|
runtime errors
|
||||||
|
*)
|
||||||
|
type variable =
|
||||||
|
| Local of int
|
||||||
|
| Global of int
|
||||||
|
|
||||||
(* Note:
|
(* Note:
|
||||||
all symbol accesses are replaced with either a local or global access.
|
all symbol accesses are either referring to a local binding or a global one,
|
||||||
Local accesses a symbol in the local scope.
|
and this is distinguished through the variable type above.
|
||||||
Global accesses a symbol in the global scope.
|
|
||||||
|
|
||||||
Lambda expressions are stripped of the symbol name of their single parameter.
|
Lambda expressions are stripped of the symbol name of their single parameter.
|
||||||
This name is not needed at runtime, as all symbol accesses will be resolved
|
This name is not needed at runtime, as all symbol accesses will be resolved
|
||||||
into an index into either the local scope linked list or the global symbol table.
|
into an index into either the local scope linked list or the global symbol table.
|
||||||
|
|
||||||
Set is also split into its global and local versions, just like Var.
|
Set is also split into its global and local versions, using the above variable type.
|
||||||
|
|
||||||
The rest aren't modified at all.
|
The rest aren't modified at all.
|
||||||
*)
|
*)
|
||||||
type expression =
|
type expression =
|
||||||
| Literal of literal
|
| Literal of literal
|
||||||
| Local of int
|
| Var of variable
|
||||||
| Global of int
|
|
||||||
| Apply of expression * expression
|
| Apply of expression * expression
|
||||||
| Lambda of expression
|
| Lambda of expression
|
||||||
| If of expression * expression * expression
|
| If of expression * expression * expression
|
||||||
| SetLocal of int * expression
|
| Set of variable * expression
|
||||||
| SetGlobal of int * expression
|
|
||||||
| Begin of expression list
|
| Begin of expression list
|
||||||
|
|
||||||
|
|
||||||
@@ -64,23 +71,23 @@ let resolve_global tbl sym =
|
|||||||
| Some x -> Ok (Global x)
|
| Some x -> Ok (Global x)
|
||||||
| None -> Error ("symbol " ^ sym ^ " is not defined!")
|
| None -> Error ("symbol " ^ sym ^ " is not defined!")
|
||||||
|
|
||||||
let resolve_lexical tbl env sym =
|
(* First we try to resolve it to a local symbol, then look it up in the
|
||||||
|
global table if we can't find it in the local environment
|
||||||
|
*)
|
||||||
|
let resolve_symbol tbl env sym =
|
||||||
let rec aux counter = function
|
let rec aux counter = function
|
||||||
| [] -> resolve_global tbl sym
|
| [] -> resolve_global tbl sym
|
||||||
| x :: _ when String.equal x sym -> Ok (Local counter)
|
| x :: _ when String.equal x sym -> Ok (Local counter)
|
||||||
| _ :: rest -> aux (counter + 1) rest
|
| _ :: rest -> aux (counter + 1) rest
|
||||||
in aux 0 env
|
in aux 0 env
|
||||||
|
|
||||||
let resolve_symbol tbl env sym =
|
let resolve_var tbl env sym =
|
||||||
resolve_lexical tbl env sym
|
let* sym = resolve_symbol tbl env sym in
|
||||||
|
Ok (Var sym)
|
||||||
|
|
||||||
let resolve_set tbl env sym expr =
|
let resolve_set tbl env sym expr =
|
||||||
let* sym = resolve_symbol tbl env sym in
|
let* sym = resolve_symbol tbl env sym in
|
||||||
match sym with
|
Ok (Set (sym, expr))
|
||||||
| Local i -> Ok (SetLocal (i, expr))
|
|
||||||
| Global i -> Ok (SetGlobal (i, expr))
|
|
||||||
| _ -> Error "resolve_set: symbol resolution returned something invalid."
|
|
||||||
|
|
||||||
(* We need to do some more sophisticated analysis to detect cases where
|
(* We need to do some more sophisticated analysis to detect cases where
|
||||||
a symbol is accessed before it is defined.
|
a symbol is accessed before it is defined.
|
||||||
If a symbol is accessed in a lambda body, that is fine, since that computation
|
If a symbol is accessed in a lambda body, that is fine, since that computation
|
||||||
@@ -102,12 +109,9 @@ let resolve_set tbl env sym expr =
|
|||||||
*)
|
*)
|
||||||
let convert program =
|
let convert program =
|
||||||
let global_tbl = extract_globals program in
|
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_var tbl current sym
|
||||||
| Set (sym, expr) ->
|
| Set (sym, expr) ->
|
||||||
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
|
||||||
@@ -131,7 +135,7 @@ let convert program =
|
|||||||
| [] -> []
|
| [] -> []
|
||||||
| (Core_ast.Expr e) :: rest -> (analyze tbl [] e) :: (aux tbl rest)
|
| (Core_ast.Expr e) :: rest -> (analyze tbl [] e) :: (aux tbl rest)
|
||||||
| (Define (s, e)) :: rest ->
|
| (Define (s, e)) :: rest ->
|
||||||
let tbl = SymbolTable.add s (id ()) tbl in
|
let tbl = SymbolTable.add s (SymbolTable.find s global_tbl) tbl in
|
||||||
(analyze tbl [] (Set (s, e))) :: (aux tbl rest)
|
(analyze tbl [] (Set (s, e))) :: (aux tbl rest)
|
||||||
in
|
in
|
||||||
let* program = traverse (fun x -> x) (aux SymbolTable.empty program) in
|
let* program = traverse (fun x -> x) (aux SymbolTable.empty program) in
|
||||||
|
|||||||
@@ -26,11 +26,11 @@ let rec interpret_literal = function
|
|||||||
let rec interpret_one expr env globals =
|
let rec interpret_one expr env globals =
|
||||||
match expr with
|
match expr with
|
||||||
| Compiler.Scope_analysis.Literal l -> interpret_literal l
|
| Compiler.Scope_analysis.Literal l -> interpret_literal l
|
||||||
| Local i ->
|
| Var (Local i) ->
|
||||||
(match (List.nth_opt env i) with
|
(match (List.nth_opt env i) with
|
||||||
| None -> Error "Error while accessing local variable!"
|
| None -> Error "Error while accessing local variable!"
|
||||||
| Some x -> Ok !x)
|
| Some x -> Ok !x)
|
||||||
| Global i ->
|
| Var (Global i) ->
|
||||||
Ok (Array.get globals i)
|
Ok (Array.get globals i)
|
||||||
| Apply (f, e) ->
|
| Apply (f, e) ->
|
||||||
let* f = interpret_one f env globals in
|
let* f = interpret_one f env globals in
|
||||||
@@ -47,13 +47,13 @@ let rec interpret_one expr env globals =
|
|||||||
(match test with
|
(match test with
|
||||||
| Nil -> interpret_one else_e env globals
|
| Nil -> interpret_one else_e env globals
|
||||||
| _ -> interpret_one then_e env globals)
|
| _ -> interpret_one then_e env globals)
|
||||||
| SetLocal (i, e) ->
|
| Set ((Local i), e) ->
|
||||||
(match (List.nth_opt env i) with
|
(match (List.nth_opt env i) with
|
||||||
| None -> Error "Error while setting local variable!"
|
| None -> Error "Error while setting local variable!"
|
||||||
| Some r ->
|
| Some r ->
|
||||||
let* e = interpret_one e env globals in
|
let* e = interpret_one e env globals in
|
||||||
r := e; Ok e)
|
r := e; Ok e)
|
||||||
| SetGlobal (i, e) ->
|
| Set ((Global i), e) ->
|
||||||
let* e = interpret_one e env globals in
|
let* e = interpret_one e env globals in
|
||||||
Array.set globals i e; Ok e
|
Array.set globals i e; Ok e
|
||||||
| Begin [] -> Ok Nil
|
| Begin [] -> Ok Nil
|
||||||
|
|||||||
Reference in New Issue
Block a user