-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathphases.ml
139 lines (131 loc) · 5.02 KB
/
phases.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
open Printf
open Exprs
open Errors
open Pretty
open Assembly
type 'a name_envt = (string * 'a) list
type 'a tag_envt = (tag * 'a) list
(* There are lots of ways to work with pipelines of functions that "can fail
at any point". They all have various drawbacks, though. See
http://keleshev.com/composable-error-handling-in-ocaml for a decent writeup
of some of the techniques. Since we haven't introduced all of the OCaml
concepts mentioned there, this file uses a variation on the ideas shown in
that blog post. *)
(* Describes individual phases of compilation.
Feel free to add additional constructors here, and
add a "helper" function just afterward. *)
type phase =
| Source of string
| Parsed of sourcespan program
| WellFormed of sourcespan program
| Renamed of tag program
| Desugared of sourcespan program
| AddedNatives of sourcespan program
| Tagged of tag program
| ANFed of tag aprogram
| Located of tag aprogram * arg name_envt name_envt
| Result of string
;;
(* These functions simply apply a phase constructor, because OCaml
doesn't allow you to pass data-constructors as first-class values *)
let source s = Source s
let parsed p = Parsed p
let well_formed p = WellFormed p
let renamed p = Renamed p
let desugared p = Desugared p
let tagged p = Tagged p
let anfed p = ANFed p
let add_natives p = AddedNatives p
let locate_bindings(p, e) = Located(p, e)
let result s = Result s
;;
(* When a stage of the compiler fails, return all the errors that occured,
along with whatever phases of the compiler successfully completed *)
type failure = exn list * phase list
(* An individual function might fail sometimes, and either return a value
or a bunch of errors *)
type 'a fallible = ('a, exn list) result
(* An overall pipeline returns either a final result (of type 'a) and
a list of prior phases, or it returns a failure as above *)
type 'a pipeline = ('a * phase list, failure) result
(* Adds another phase to the growing pipeline, using a function that might fail.
If the function returns an Error full of exns, then the pipeline dies right there.
If the function *throws* an exception, the pipeline dies right there.
If the function succeeds, then the pipeline grows (using log to add the result
onto the pipeline).
NOTE: Executing add_err_phase will never throw any exceptions.
*)
let add_err_phase
(log : 'b -> phase)
(next : 'a -> 'b fallible)
(cur_pipeline : 'a pipeline)
: 'b pipeline =
match cur_pipeline with
| Error (errs, trace) -> Error (errs, trace)
| Ok (cur_val, trace) ->
try
match (next cur_val) with
| Error errs -> Error(errs, trace)
| Ok new_val -> Ok(new_val, (log new_val) :: trace)
with
| Failure s -> Error([Failure("Compile error: " ^ s)], trace)
| err -> Error([Failure("Unexpected compile error: " ^ Printexc.to_string err)], trace)
;;
(* Adds another phase to the growing pipeline, using a function that should never fail.
If the function *throws* an exception, the pipeline dies right there.
Otherwise, the pipeline grows (using log to add the result onto the pipeline).
NOTE: Executing add_phase will never throw any exceptions.
*)
let add_phase
(log : 'b -> phase)
(next : 'a -> 'b)
(cur_pipeline : 'a pipeline)
: 'b pipeline =
match cur_pipeline with
| Error(errs, trace)-> Error(errs, trace)
| Ok(cur_val, trace) ->
try
let new_val = next cur_val in
Ok(new_val, (log new_val) :: trace)
with
| Failure s -> Error([Failure("Compile error: " ^ s)], trace)
| err -> Error([Failure("Unexpected compile error: " ^ Printexc.to_string err)], trace)
;;
let no_op_phase (cur_pipeline : 'a pipeline) = cur_pipeline
;;
(* Stringifies a list of phases, for debug printing purposes *)
let print_trace (trace : phase list) : string list =
let phase_name p = match p with
| Source _ -> "Source"
| Parsed _ -> "Parsed"
| WellFormed _ -> "Well-formed"
| Renamed _ -> "Renamed"
| Desugared _ -> "Desugared"
| AddedNatives _ -> "Natives Added"
| Tagged _ -> "Tagged"
| ANFed _ -> "ANF'ed"
| Located _ -> "Located"
| Result _ -> "Result" in
let string_of_phase p = match p with
| Source s -> s
| Parsed p
| WellFormed p -> string_of_program p
| Renamed p -> string_of_program p
| Desugared p -> string_of_program p
| AddedNatives p -> string_of_program p
| Tagged p -> string_of_program_with 1000 (fun tag -> sprintf "@%d" tag) p
| ANFed p -> string_of_aprogram_with 1000 (fun tag -> sprintf "@%d" tag) p
| Located(p, e) ->
string_of_aprogram_with 1000 (fun tag -> sprintf "@%d" tag) p
^ "\nEnvs:\n"
^ ExtString.String.join "\n"
(List.map
(fun (name, env) ->
name
^ ":\n\t"
^ (ExtString.String.join
"\n\t"
(List.map (fun (name, arg) -> name ^ "=>" ^ (arg_to_asm arg)) env))) e)
| Result s -> s in
List.mapi (fun n p -> sprintf "Phase %d (%s):\n%s" n (phase_name p) (string_of_phase p)) (List.rev trace)
;;