Skip to content

Commit 7287b92

Browse files
committed
Use Result instead of raise for errors
1 parent afd6ad9 commit 7287b92

File tree

7 files changed

+185
-63
lines changed

7 files changed

+185
-63
lines changed

bin/sgen.ml

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,19 @@ let parse input_file =
1313
let run input_file =
1414
let expr = parse input_file in
1515
let preprocessed = Expr.preprocess expr in
16-
let p = Expr.program_of_expr preprocessed in
17-
let _ = Stellogen.Sgen_eval.eval_program p in
18-
()
16+
match Expr.program_of_expr preprocessed with
17+
| Ok p ->
18+
let _ = Stellogen.Sgen_eval.eval_program p in
19+
()
20+
| Error e ->
21+
let open Stellogen.Sgen_eval in
22+
begin
23+
match pp_err (ExprError e) with
24+
| Ok pp ->
25+
Out_channel.output_string Out_channel.stderr pp;
26+
()
27+
| Error _ -> ()
28+
end
1929

2030
let preprocess_only input_file =
2131
let expr = parse input_file in

examples/binary4.sg

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,21 @@
2121
(:= (and A B R) {
2222
#(if A = 0 and B = _ then R = 0)
2323
#(if A = 1 and B = X then R = X) })
24-
(show (process #b1 #(and b1 b2 r) #b2))
24+
(:= rand (process #b1 #(and b1 b2 r) #b2))
25+
(show #rand)
26+
(== #rand #(make_bin r 0 0 0 1))
2527

2628
(:= (or A B R) {
2729
#(if A = 0 and B = X then R = X)
2830
#(if A = 1 and B = Y then R = 1) })
29-
(show (process #b1 #(or b1 b2 r) #b2))
31+
(:= ror (process #b1 #(or b1 b2 r) #b2))
32+
(show #ror)
33+
(== #ror #(make_bin r 0 0 1 1))
3034

3135
'''
3236
(:= (xor A B R) {
3337
#(if A = X and B = X then R = 0) })
34-
(show (process #b1 #(xor b1 b2 r) #b2))
38+
(:= rxor (process #b1 #(xor b1 b2 r) #b2))
39+
(show #rxor)
40+
(== #rxor #(make_bin r 0 0 1 0))
3541
'''

src/expr.ml

Lines changed: 106 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
open Base
22
open Lsc_ast
33
open Sgen_ast
4+
open Expr_err
5+
6+
let ( let* ) x f = Result.bind x ~f
47

58
type ident = string
69

@@ -25,6 +28,8 @@ type expr =
2528
| List of expr list
2629
[@@derive eq]
2730

31+
let pp_err _ = ""
32+
2833
let primitive = String.append "%"
2934

3035
let nil_op = primitive "nil"
@@ -117,101 +122,152 @@ let symbol_of_str (s : string) : idfunc =
117122
| '-' -> (Neg, rest)
118123
| _ -> (Null, s)
119124

120-
let rec ray_of_expr : expr -> ray = function
121-
| Symbol s -> to_func (symbol_of_str s, [])
122-
| Var "_" -> to_var ("_" ^ fresh_placeholder ())
123-
| Var s -> to_var s
124-
| List [] -> failwith "error: ray cannot be empty"
125-
| List (Symbol h :: t) -> to_func (symbol_of_str h, List.map ~f:ray_of_expr t)
126-
| List (_ :: _) as e ->
127-
failwith ("error: ray " ^ to_string e ^ " must start with constant")
128-
129-
let bans_of_expr : expr list -> ban list =
125+
let rec ray_of_expr : expr -> (ray, expr_err) Result.t = function
126+
| Symbol s -> to_func (symbol_of_str s, []) |> Result.return
127+
| Var "_" -> to_var ("_" ^ fresh_placeholder ()) |> Result.return
128+
| Var s -> to_var s |> Result.return
129+
| List [] -> Error EmptyRay
130+
| List (Symbol h :: t) ->
131+
let* args = List.map ~f:ray_of_expr t |> Result.all in
132+
to_func (symbol_of_str h, args) |> Result.return
133+
| List (_ :: _) as e -> Error (NonConstantRayHeader (to_string e))
134+
135+
let bans_of_expr es : (ban list, expr_err) Result.t =
130136
let ban_of_expr = function
131137
| List [ Symbol k; a; b ] when equal_string k ineq_op ->
132-
Ineq (ray_of_expr a, ray_of_expr b)
138+
let* ra = ray_of_expr a in
139+
let* rb = ray_of_expr b in
140+
Ineq (ra, rb) |> Result.return
133141
| List [ Symbol k; a; b ] when equal_string k incomp_op ->
134-
Incomp (ray_of_expr a, ray_of_expr b)
135-
| _ -> failwith "error: invalid ban expression"
142+
let* ra = ray_of_expr a in
143+
let* rb = ray_of_expr b in
144+
Incomp (ra, rb) |> Result.return
145+
| _ as e -> Error (InvalidBan (to_string e))
136146
in
137-
List.map ~f:ban_of_expr
147+
List.map ~f:ban_of_expr es |> Result.all
138148

139-
let rec raylist_of_expr (e : expr) : ray list =
149+
let rec raylist_of_expr (e : expr) : (ray list, expr_err) Result.t =
140150
match e with
141-
| Symbol k when equal_string k nil_op -> []
142-
| Symbol _ | Var _ -> [ ray_of_expr e ]
151+
| Symbol k when equal_string k nil_op -> Ok []
152+
| Symbol _ | Var _ ->
153+
let* r = ray_of_expr e in
154+
Ok [ r ]
143155
| List [ Symbol s; h; t ] when equal_string s cons_op ->
144-
ray_of_expr h :: raylist_of_expr t
145-
| e -> failwith ("error: unhandled star " ^ to_string e)
156+
let* rh = ray_of_expr h in
157+
let* rt = raylist_of_expr t in
158+
Ok (rh :: rt)
159+
| e -> Error (InvalidRaylist (to_string e))
146160

147-
let rec star_of_expr : expr -> Marked.star = function
161+
let rec star_of_expr : expr -> (Marked.star, expr_err) Result.t = function
148162
| List [ Symbol k; s ] when equal_string k focus_op ->
149-
star_of_expr s |> Marked.remove |> Marked.make_state
163+
let* ss = star_of_expr s in
164+
ss |> Marked.remove |> Marked.make_state |> Result.return
150165
| List [ Symbol k; s; List ps ] when equal_string k params_op ->
151-
Action { content = raylist_of_expr s; bans = bans_of_expr ps }
152-
| e -> Action { content = raylist_of_expr e; bans = [] }
153-
154-
let rec constellation_of_expr : expr -> Marked.constellation = function
155-
| Symbol s -> [ Action { content = [ var (s, None) ]; bans = [] } ]
156-
| Var x -> [ Action { content = [ var (x, None) ]; bans = [] } ]
166+
let* content = raylist_of_expr s in
167+
let* bans = bans_of_expr ps in
168+
Marked.Action { content; bans } |> Result.return
169+
| e ->
170+
let* content = raylist_of_expr e in
171+
Marked.Action { content; bans = [] } |> Result.return
172+
173+
let rec constellation_of_expr :
174+
expr -> (Marked.constellation, expr_err) Result.t = function
175+
| Symbol s ->
176+
[ Marked.Action { content = [ var (s, None) ]; bans = [] } ]
177+
|> Result.return
178+
| Var x ->
179+
[ Marked.Action { content = [ var (x, None) ]; bans = [] } ]
180+
|> Result.return
157181
| List [ Symbol s; h; t ] when equal_string s cons_op ->
158-
star_of_expr h :: constellation_of_expr t
159-
| List g -> [ Action { content = [ ray_of_expr (List g) ]; bans = [] } ]
182+
let* sh = star_of_expr h in
183+
let* ct = constellation_of_expr t in
184+
Ok (sh :: ct)
185+
| List g ->
186+
let* rg = ray_of_expr (List g) in
187+
[ Marked.Action { content = [ rg ]; bans = [] } ] |> Result.return
160188

161189
(* ---------------------------------------
162190
Stellogen expr of Expr
163191
--------------------------------------- *)
164192

165-
let rec sgen_expr_of_expr (e : expr) : sgen_expr =
193+
let rec sgen_expr_of_expr (e : expr) : (sgen_expr, expr_err) Result.t =
166194
match e with
167195
| Symbol k when equal_string k nil_op ->
168-
Raw [ Action { content = []; bans = [] } ]
196+
Raw [ Action { content = []; bans = [] } ] |> Result.return
169197
(* ray *)
170198
| Var _ | Symbol _ ->
171-
Raw [ Action { content = [ ray_of_expr e ]; bans = [] } ]
199+
let* re = ray_of_expr e in
200+
Raw [ Action { content = [ re ]; bans = [] } ] |> Result.return
172201
(* star *)
173-
| List (Symbol s :: _) when equal_string s params_op -> Raw [ star_of_expr e ]
174-
| List (Symbol s :: _) when equal_string s cons_op -> Raw [ star_of_expr e ]
202+
| List (Symbol s :: _) when equal_string s params_op ->
203+
let* se = star_of_expr e in
204+
Raw [ se ] |> Result.return
205+
| List (Symbol s :: _) when equal_string s cons_op ->
206+
let* se = star_of_expr e in
207+
Raw [ se ] |> Result.return
175208
(* id *)
176-
| List [ Symbol k; g ] when equal_string k call_op -> Call (ray_of_expr g)
209+
| List [ Symbol k; g ] when equal_string k call_op ->
210+
let* re = ray_of_expr g in
211+
Call re |> Result.return
177212
(* focus @ *)
178213
| List [ Symbol k; g ] when equal_string k focus_op ->
179-
Focus (sgen_expr_of_expr g)
214+
let* sgg = sgen_expr_of_expr g in
215+
Focus sgg |> Result.return
180216
(* group *)
181217
| List (Symbol k :: gs) when equal_string k group_op ->
182-
Group (List.map ~f:sgen_expr_of_expr gs)
218+
let* sggs = List.map ~f:sgen_expr_of_expr gs |> Result.all in
219+
Group sggs |> Result.return
183220
(* process *)
184-
| List (Symbol "process" :: gs) -> Process (List.map ~f:sgen_expr_of_expr gs)
221+
| List (Symbol "process" :: gs) ->
222+
let* sggs = List.map ~f:sgen_expr_of_expr gs |> Result.all in
223+
Process sggs |> Result.return
185224
(* interact *)
186225
| List (Symbol "interact" :: gs) ->
187-
Exec (false, Group (List.map ~f:sgen_expr_of_expr gs))
226+
let* sggs = List.map ~f:sgen_expr_of_expr gs |> Result.all in
227+
Exec (false, Group sggs) |> Result.return
188228
(* fire *)
189229
| List (Symbol "fire" :: gs) ->
190-
Exec (true, Group (List.map ~f:sgen_expr_of_expr gs))
230+
let* sggs = List.map ~f:sgen_expr_of_expr gs |> Result.all in
231+
Exec (true, Group sggs) |> Result.return
191232
(* eval *)
192-
| List [ Symbol "eval"; g ] -> Eval (sgen_expr_of_expr g)
233+
| List [ Symbol "eval"; g ] ->
234+
let* sgg = sgen_expr_of_expr g in
235+
Eval sgg |> Result.return
193236
(* KEEP LAST -- raw constellation *)
194-
| List g -> Raw (constellation_of_expr (List g))
237+
| List e ->
238+
let* ce = constellation_of_expr (List e) in
239+
Raw ce |> Result.return
195240

196241
(* ---------------------------------------
197242
Stellogen program of Expr
198243
--------------------------------------- *)
199244

200-
let decl_of_expr : expr -> declaration = function
245+
let decl_of_expr : expr -> (declaration, expr_err) Result.t = function
201246
(* definition := *)
202247
| List [ Symbol k; x; g ] when equal_string k def_op ->
203-
Def (ray_of_expr x, sgen_expr_of_expr g)
248+
let* rx = ray_of_expr x in
249+
let* sgg = sgen_expr_of_expr g in
250+
Def (rx, sgg) |> Result.return
204251
(* show *)
205-
| List [ Symbol "show"; g ] -> Show (sgen_expr_of_expr g)
252+
| List [ Symbol "show"; g ] ->
253+
let* sgg = sgen_expr_of_expr g in
254+
Show sgg |> Result.return
206255
(* expect *)
207256
| List [ Symbol k; g1; g2 ] when equal_string k expect_op ->
208-
Expect (sgen_expr_of_expr g1, sgen_expr_of_expr g2, const "default")
257+
let* sgg1 = sgen_expr_of_expr g1 in
258+
let* sgg2 = sgen_expr_of_expr g2 in
259+
Expect (sgg1, sgg2, const "default") |> Result.return
209260
| List [ Symbol k; g1; g2; m ] when equal_string k expect_op ->
210-
Expect (sgen_expr_of_expr g1, sgen_expr_of_expr g2, ray_of_expr m)
261+
let* sgg1 = sgen_expr_of_expr g1 in
262+
let* sgg2 = sgen_expr_of_expr g2 in
263+
let* rm = ray_of_expr m in
264+
Expect (sgg1, sgg2, rm) |> Result.return
211265
(* use *)
212-
| List [ Symbol k; r ] when equal_string k "use" -> Use (ray_of_expr r)
213-
| e -> failwith ("error: invalid declaration " ^ to_string e)
266+
| List [ Symbol k; r ] when equal_string k "use" ->
267+
let* rr = ray_of_expr r in
268+
Use rr |> Result.return
269+
| e -> Error (InvalidDeclaration (to_string e))
214270

215-
let program_of_expr = List.map ~f:decl_of_expr
271+
let program_of_expr e = List.map ~f:decl_of_expr e |> Result.all
216272

217273
let preprocess e = e |> List.map ~f:expand_macro |> unfold_decl_def []

src/expr_err.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
type expr_err =
2+
| EmptyRay
3+
| NonConstantRayHeader of string
4+
| InvalidBan of string
5+
| InvalidRaylist of string
6+
| InvalidDeclaration of string

src/sgen_ast.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
open Base
22
open Lsc_ast
3+
open Expr_err
34

45
type ident = StellarRays.term
56

@@ -19,6 +20,7 @@ type sgen_expr =
1920
type err =
2021
| ExpectError of Marked.constellation * Marked.constellation * ident
2122
| UnknownID of string
23+
| ExprError of expr_err
2224

2325
type env = { objs : (ident * sgen_expr) list }
2426

src/sgen_eval.ml

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,32 @@ let pp_err e : (string, err) Result.t =
6464
| UnknownID x ->
6565
sprintf "%s: identifier '%s' not found.\n" (red "UnknownID Error") x
6666
|> Result.return
67+
| ExprError e -> begin
68+
match e with
69+
| EmptyRay ->
70+
sprintf "%s: rays cannot be empty.\n" (red "Expression Parsing Error")
71+
|> Result.return
72+
| NonConstantRayHeader e ->
73+
sprintf "%s: ray '%s' must start with a constant function symbol.\n"
74+
(red "Expression Parsing Error")
75+
e
76+
|> Result.return
77+
| InvalidBan e ->
78+
sprintf "%s: invalid ban expression '%s'.\n"
79+
(red "Expression Parsing Error")
80+
e
81+
|> Result.return
82+
| InvalidRaylist e ->
83+
sprintf "%s: expression '%s' is not a valid star.\n"
84+
(red "Expression Parsing Error")
85+
e
86+
|> Result.return
87+
| InvalidDeclaration e ->
88+
sprintf "%s: expression '%s' is not a valid declaration.\n"
89+
(red "Expression Parsing Error")
90+
e
91+
|> Result.return
92+
end
6793

6894
let rec eval_sgen_expr (env : env) :
6995
sgen_expr -> (Marked.constellation, err) Result.t = function
@@ -105,7 +131,12 @@ let rec eval_sgen_expr (env : env) :
105131
match eval_e with
106132
| [ State { content = [ r ]; bans = _ } ]
107133
| [ Action { content = [ r ]; bans = _ } ] ->
108-
r |> expr_of_ray |> Expr.sgen_expr_of_expr |> eval_sgen_expr env
134+
let er = expr_of_ray r in
135+
begin
136+
match Expr.sgen_expr_of_expr er with
137+
| Ok sg -> eval_sgen_expr env sg
138+
| Error e -> Error (ExprError e)
139+
end
109140
| e ->
110141
failwith
111142
( "eval error: "
@@ -147,7 +178,7 @@ let rec eval_decl env : declaration -> (env, err) Result.t = function
147178
(Marked.normalize_all eval_e2)
148179
then Error (ExpectError (eval_e1, eval_e2, message))
149180
else Ok env
150-
| Use path ->
181+
| Use path -> (
151182
let open Lsc_ast.StellarRays in
152183
let formatted_filename : string =
153184
match path with
@@ -163,9 +194,11 @@ let rec eval_decl env : declaration -> (env, err) Result.t = function
163194
Sedlexing.set_position lexbuf (start_pos formatted_filename);
164195
let expr = Sgen_parsing.parse_with_error formatted_filename lexbuf in
165196
let preprocessed = Expr.preprocess expr in
166-
let p = Expr.program_of_expr preprocessed in
167-
let* env = eval_program p in
168-
Ok env
197+
match Expr.program_of_expr preprocessed with
198+
| Ok p ->
199+
let* env = eval_program p in
200+
Ok env
201+
| Error e -> Error (ExprError e) )
169202

170203
and eval_program (p : program) =
171204
match

test/test.ml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,17 @@ let sgen filename () =
44
let lexbuf = Sedlexing.Utf8.from_channel (Stdlib.open_in filename) in
55
let expr = Stellogen.Sgen_parsing.parse_with_error filename lexbuf in
66
let preprocessed = Stellogen.Expr.preprocess expr in
7-
let p = Stellogen.Expr.program_of_expr preprocessed in
8-
Stellogen.Sgen_eval.eval_program p
7+
match Stellogen.Expr.program_of_expr preprocessed with
8+
| Ok p -> Stellogen.Sgen_eval.eval_program p
9+
| Error e ->
10+
let open Stellogen.Sgen_eval in
11+
begin
12+
match pp_err (ExprError e) with
13+
| Ok pp ->
14+
Out_channel.output_string Out_channel.stderr pp;
15+
Error (ExprError e)
16+
| Error e -> Error e
17+
end
918

1019
let make_ok_test name path f =
1120
let test got () =

0 commit comments

Comments
 (0)