Skip to content

Commit 0dbe770

Browse files
committed
Insert error extension nodes instead of raising exceptions
Signed-off-by: Nathan Rebours <nathan.p.rebours@gmail.com>
1 parent 7e24536 commit 0dbe770

38 files changed

Lines changed: 283 additions & 357 deletions

CHANGES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
### Changed
66

7+
- Insert errors in the AST rather than raising exceptions. This allows
8+
merlin to report all ppx_yojson errors at once. (#44, @NathanReb)
9+
710
### Deprecated
811

912
### Fixed

dune-project

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,5 @@
3030
(and
3131
:with-test
3232
(>= 1.6.0)))))
33+
34+
(cram enable)
Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
1+
open Ppxlib
2+
13
let unsupported_payload ~loc =
2-
Location.raise_errorf ~loc "ppx_yojson: unsupported payload"
4+
Location.error_extensionf ~loc "ppx_yojson: unsupported payload"
35

46
let unsupported_record_field ~loc =
5-
Location.raise_errorf ~loc "ppx_yojson: unsupported record field"
7+
Location.error_extensionf ~loc "ppx_yojson: unsupported record field"
68

79
let too_many_fields_in_record_pattern ~loc =
8-
Location.raise_errorf ~loc
10+
Location.error_extensionf ~loc
911
"ppx_yojson: record patterns with more than 4 fields aren't supported. \
1012
Consider using ppx_deriving_yojson to handle more complex json objects."
1113

1214
let bad_expr_antiquotation_payload ~loc =
13-
Location.raise_errorf ~loc
15+
Location.error_extensionf ~loc
1416
"ppx_yojson: bad antiquotation payload, should be a single expression"
1517

1618
let bad_pat_antiquotation_payload ~loc =
17-
Location.raise_errorf ~loc
19+
Location.error_extensionf ~loc
1820
"ppx_yojson: bad antiquotation payload, should be a pattern"

lib/raise.mli renamed to lib/error.mli

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,18 @@
55
accurate information as to what should be fixed.
66
*)
77

8-
val unsupported_payload : loc:Ppxlib.Location.t -> 'a
8+
val unsupported_payload : loc:Ppxlib.Location.t -> Ppxlib.extension
99
(** Use this for unsupported payload expressions. *)
1010

11-
val unsupported_record_field : loc:Ppxlib.Location.t -> 'a
11+
val unsupported_record_field : loc:Ppxlib.Location.t -> Ppxlib.extension
1212
(** Use this for unsupported Longident used as record fields. *)
1313

14-
val too_many_fields_in_record_pattern : loc:Ppxlib.Location.t -> 'a
14+
val too_many_fields_in_record_pattern :
15+
loc:Ppxlib.Location.t -> Ppxlib.extension
1516
(** Use this for record pattern with more than 4 fields. *)
1617

17-
val bad_expr_antiquotation_payload : loc:Ppxlib.Location.t -> 'a
18+
val bad_expr_antiquotation_payload : loc:Ppxlib.Location.t -> Ppxlib.extension
1819
(** Use this for bad payload in expression antiquotation [[%y ...]]. *)
1920

20-
val bad_pat_antiquotation_payload : loc:Ppxlib.Location.t -> 'a
21+
val bad_pat_antiquotation_payload : loc:Ppxlib.Location.t -> Ppxlib.extension
2122
(** Use this for bad payload in pattern antiquotation [[%y? ...]]. *)

lib/expression.ml

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ module type EXPANDER = sig
44
val expand_bool : loc:location -> bool -> expression
55
val expand_float : loc:location -> string -> expression
66
val expand_int : loc:location -> pexp_loc:location -> string -> expression
7-
val expand_intlit : loc:location -> string -> expression
7+
val expand_intlit : loc:location -> pexp_loc:location -> string -> expression
88
val expand_list : loc:location -> expression list -> expression
99
val expand_none : loc:location -> unit -> expression
1010

@@ -43,13 +43,16 @@ end
4343
module Ezjsonm_expander : EXPANDER = struct
4444
include Common
4545

46-
let expand_intlit ~loc _ = Raise.unsupported_payload ~loc
46+
let expand_intlit ~loc:_ ~pexp_loc:loc _ =
47+
Ast_builder.Default.pexp_extension ~loc (Error.unsupported_payload ~loc)
4748

4849
let expand_int ~loc ~pexp_loc s =
4950
match int_of_string_opt s with
5051
| Some i ->
5152
[%expr `Float [%e Ast_builder.Default.efloat ~loc (string_of_int i)]]
52-
| _ -> Raise.unsupported_payload ~loc:pexp_loc
53+
| _ ->
54+
Ast_builder.Default.pexp_extension ~loc:pexp_loc
55+
(Error.unsupported_payload ~loc:pexp_loc)
5356

5457
let expand_list ~loc exprs =
5558
expand_list ~loc (fun e -> [%expr `A [%e e]]) exprs
@@ -61,19 +64,22 @@ end
6164
module Yojson_expander : EXPANDER = struct
6265
include Common
6366

64-
let expand_intlit ~loc s =
67+
let expand_intlit ~loc ~pexp_loc:_ s =
6568
[%expr `Intlit [%e Ast_builder.Default.estring ~loc s]]
6669

6770
let expand_int ~loc ~pexp_loc s =
6871
match int_of_string_opt s with
6972
| Some i -> [%expr `Int [%e Ast_builder.Default.eint ~loc i]]
7073
| None when Integer_const.is_binary s ->
71-
Raise.unsupported_payload ~loc:pexp_loc
74+
Ast_builder.Default.pexp_extension ~loc:pexp_loc
75+
(Error.unsupported_payload ~loc:pexp_loc)
7276
| None when Integer_const.is_octal s ->
73-
Raise.unsupported_payload ~loc:pexp_loc
77+
Ast_builder.Default.pexp_extension ~loc:pexp_loc
78+
(Error.unsupported_payload ~loc:pexp_loc)
7479
| None when Integer_const.is_hexadecimal s ->
75-
Raise.unsupported_payload ~loc:pexp_loc
76-
| None -> expand_intlit ~loc s
80+
Ast_builder.Default.pexp_extension ~loc:pexp_loc
81+
(Error.unsupported_payload ~loc:pexp_loc)
82+
| None -> expand_intlit ~loc ~pexp_loc s
7783

7884
let expand_list ~loc exprs =
7985
expand_list ~loc (fun e -> [%expr `List [%e e]]) exprs
@@ -86,7 +92,8 @@ module Make (Expander : EXPANDER) = struct
8692
let expand_anti_quotation ~pexp_loc = function
8793
| PStr [ { pstr_desc = Pstr_eval (expr, _); _ } ] -> expr
8894
| PStr _ | PSig _ | PTyp _ | PPat _ ->
89-
Raise.bad_expr_antiquotation_payload ~loc:pexp_loc
95+
Ast_builder.Default.pexp_extension ~loc:pexp_loc
96+
(Error.bad_expr_antiquotation_payload ~loc:pexp_loc)
9097

9198
let rec expand ~loc ~path expr =
9299
match expr with
@@ -99,9 +106,10 @@ module Make (Expander : EXPANDER) = struct
99106
Expander.expand_int ~loc ~pexp_loc s
100107
| {
101108
pexp_desc = Pexp_constant (Pconst_integer (s, Some ('l' | 'L' | 'n')));
109+
pexp_loc;
102110
_;
103111
} ->
104-
Expander.expand_intlit ~loc s
112+
Expander.expand_intlit ~loc ~pexp_loc s
105113
| { pexp_desc = Pexp_constant (Pconst_float (s, None)); _ } ->
106114
Expander.expand_float ~loc s
107115
| [%expr []] -> Expander.expand_list ~loc []
@@ -112,7 +120,9 @@ module Make (Expander : EXPANDER) = struct
112120
| { pexp_desc = Pexp_extension ({ txt = "y" | "aq"; _ }, p); pexp_loc; _ }
113121
->
114122
expand_anti_quotation ~pexp_loc p
115-
| _ -> Raise.unsupported_payload ~loc:expr.pexp_loc
123+
| _ ->
124+
Ast_builder.Default.pexp_extension ~loc:expr.pexp_loc
125+
(Error.unsupported_payload ~loc:expr.pexp_loc)
116126

117127
and expand_list ~loc ~path = function
118128
| [%expr []] -> []
@@ -124,20 +134,27 @@ module Make (Expander : EXPANDER) = struct
124134

125135
and expand_record ~path l =
126136
let expand_one (f, e) =
137+
let as_attr =
138+
List.find_opt
139+
(fun attr -> String.equal attr.attr_name.txt "as")
140+
e.pexp_attributes
141+
in
127142
let field =
128-
match
129-
( List.find_opt
130-
(fun attr -> String.equal attr.attr_name.txt "as")
131-
e.pexp_attributes,
132-
f )
133-
with
143+
match (as_attr, f) with
134144
| Some { attr_payload; attr_loc = loc; _ }, _ ->
135145
Ast_pattern.(parse (single_expr_payload (estring __)))
136-
loc attr_payload (fun e -> e)
137-
| None, { txt = Lident s; _ } -> Utils.rewrite_field_name s
138-
| None, { txt = _; loc } -> Raise.unsupported_record_field ~loc
146+
loc attr_payload (fun e -> Ok e)
147+
| None, { txt = Lident s; _ } -> Ok (Utils.rewrite_field_name s)
148+
| None, { txt = _; loc } ->
149+
let extension =
150+
Ast_builder.Default.pexp_extension ~loc
151+
(Error.unsupported_record_field ~loc)
152+
in
153+
Error extension
139154
in
140-
(field, expand ~loc:e.pexp_loc ~path e)
155+
match field with
156+
| Ok field -> (field, expand ~loc:e.pexp_loc ~path e)
157+
| Error extension -> ("error", extension)
141158
in
142159
List.map expand_one l
143160
end

lib/pattern.ml

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@ let expand_int ~loc ~ppat_loc s =
1010
match int_of_string_opt s with
1111
| Some i -> [%pat? `Int [%p Ast_builder.Default.pint ~loc i]]
1212
| None when Integer_const.is_binary s ->
13-
Raise.unsupported_payload ~loc:ppat_loc
13+
Ast_builder.Default.ppat_extension ~loc:ppat_loc
14+
(Error.unsupported_payload ~loc:ppat_loc)
1415
| None when Integer_const.is_octal s ->
15-
Raise.unsupported_payload ~loc:ppat_loc
16+
Ast_builder.Default.ppat_extension ~loc:ppat_loc
17+
(Error.unsupported_payload ~loc:ppat_loc)
1618
| None when Integer_const.is_hexadecimal s ->
17-
Raise.unsupported_payload ~loc:ppat_loc
19+
Ast_builder.Default.ppat_extension ~loc:ppat_loc
20+
(Error.unsupported_payload ~loc:ppat_loc)
1821
| None -> expand_intlit ~loc s
1922

2023
let expand_float ~loc s = [%pat? `Float [%p Ast_builder.Default.pfloat ~loc s]]
@@ -23,7 +26,8 @@ let expand_var ~loc var = Ast_builder.Default.ppat_var ~loc var
2326
let expand_anti_quotation ~ppat_loc = function
2427
| PPat (ppat, _) -> ppat
2528
| PStr _ | PSig _ | PTyp _ ->
26-
Raise.bad_pat_antiquotation_payload ~loc:ppat_loc
29+
Ast_builder.Default.ppat_extension ~loc:ppat_loc
30+
(Error.bad_pat_antiquotation_payload ~loc:ppat_loc)
2731

2832
let rec expand ~loc ~path pat =
2933
match pat with
@@ -54,7 +58,8 @@ let rec expand ~loc ~path pat =
5458
| [%pat? [%p? _] :: [%p? _]] -> [%pat? `List [%p expand_list ~loc ~path pat]]
5559
| { ppat_desc = Ppat_record (l, Closed); ppat_loc; _ } ->
5660
expand_record ~loc ~ppat_loc ~path l
57-
| { ppat_loc = loc; _ } -> Raise.unsupported_payload ~loc
61+
| { ppat_loc = loc; _ } ->
62+
Ast_builder.Default.ppat_extension ~loc (Error.unsupported_payload ~loc)
5863

5964
and expand_list ~loc ~path = function
6065
| [%pat? []] -> [%pat? []]
@@ -66,27 +71,36 @@ and expand_list ~loc ~path = function
6671

6772
and expand_record ~loc ~ppat_loc ~path l =
6873
let expand_one (f, p) =
74+
let as_attr =
75+
List.find_opt
76+
(fun attr -> String.equal attr.attr_name.txt "as")
77+
p.ppat_attributes
78+
in
6979
let field =
70-
match
71-
( List.find_opt
72-
(fun attr -> String.equal attr.attr_name.txt "as")
73-
p.ppat_attributes,
74-
f )
75-
with
80+
match (as_attr, f) with
7681
| Some { attr_payload; attr_loc = loc; _ }, _ ->
7782
Ast_pattern.(parse (single_expr_payload (estring __)))
78-
loc attr_payload (fun e -> e)
79-
| None, { txt = Lident s; _ } -> Utils.rewrite_field_name s
80-
| None, { txt = _; loc } -> Raise.unsupported_record_field ~loc
83+
loc attr_payload (fun e -> Ok e)
84+
| None, { txt = Lident s; _ } -> Ok (Utils.rewrite_field_name s)
85+
| None, { txt = _; loc } ->
86+
let pat_ext =
87+
Ast_builder.Default.ppat_extension ~loc
88+
(Error.unsupported_record_field ~loc)
89+
in
90+
Error pat_ext
8191
in
82-
[%pat?
83-
[%p Ast_builder.Default.pstring ~loc field], [%p expand ~loc ~path p]]
92+
match field with
93+
| Ok field ->
94+
[%pat?
95+
[%p Ast_builder.Default.pstring ~loc field], [%p expand ~loc ~path p]]
96+
| Error extension -> extension
8497
in
8598
let assoc_pattern pat_list =
8699
[%pat? `Assoc [%p Ast_builder.Default.plist ~loc pat_list]]
87100
in
88101
if List.length l > 4 then
89-
Raise.too_many_fields_in_record_pattern ~loc:ppat_loc
102+
Ast_builder.Default.ppat_extension ~loc:ppat_loc
103+
(Error.too_many_fields_in_record_pattern ~loc:ppat_loc)
90104
else
91105
let pat_list = List.map expand_one l in
92106
let permutations = Utils.permutations pat_list in

test/rewriter/errors/bin/dune

Lines changed: 0 additions & 8 deletions
This file was deleted.

test/rewriter/errors/bin/gen_dune_rules.ml

Lines changed: 0 additions & 25 deletions
This file was deleted.

test/rewriter/errors/bin/pp.ml

Lines changed: 0 additions & 1 deletion
This file was deleted.

test/rewriter/errors/dune

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,3 @@
1-
(include dune.inc)
2-
3-
(rule
4-
(targets dune.inc.gen)
1+
(cram
52
(deps
6-
(source_tree .))
7-
(action
8-
(with-stdout-to
9-
%{targets}
10-
(run ./bin/gen_dune_rules.exe))))
11-
12-
(rule
13-
(alias runtest)
14-
(action
15-
(diff dune.inc dune.inc.gen)))
3+
(package ppx_yojson)))

0 commit comments

Comments
 (0)