-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathrule_schema_v2_adapter.ml
165 lines (135 loc) · 5.14 KB
/
rule_schema_v2_adapter.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
(* ATD adapter for rule_schema_v2.atd
* See https://atd.readthedocs.io/en/latest/atdgen.html#field-adapter-ocaml
*)
module Formula = struct
(** Convert from original json to ATD-compatible json *)
let normalize (orig : Yojson.Safe.t ) : Yojson.Safe.t =
match orig with
| `String str ->
`Assoc ["pattern", `String str]
(* TODO: check at least one of any/all/... is specified *)
| x -> x
(** Convert from ATD-compatible json to original json *)
let restore (_atd : Yojson.Safe.t) : Yojson.Safe.t =
(* not needed for now; we care just about parsing *)
failwith "Rule_schema_v2_adapter.Formula.restore not implemented"
end
module Condition = struct
let normalize (orig : Yojson.Safe.t ) : Yojson.Safe.t =
match orig with
| `Assoc (("comparison", cmp)::rest) ->
`List [`String "C";
`Assoc (("comparison", cmp)::rest)]
| `Assoc (("metavariable", mvar)::rest) ->
(* TODO: check at least one of type/types/... is specified *)
`List [`String "M";
`Assoc (("metavariable", mvar)::rest)]
(* alt: we could do the String vs List in a separate adapter *)
| `Assoc [("focus", `String x)] ->
`List [`String "F";
`Assoc [("focus", `List [`String x])]]
| `Assoc [("focus", `List x)] ->
`List [`String "F";
`Assoc [("focus", `List x)]]
| x -> x
let restore (_atd : Yojson.Safe.t) : Yojson.Safe.t =
failwith "Rule_schema_v2_adapter.Condition.restore not implemented"
end
module BySideEffect = struct
let normalize (orig : Yojson.Safe.t ) : Yojson.Safe.t =
match orig with
| `Bool true -> `String "true"
| `Bool false -> `String "false"
| x -> x
let restore (_atd : Yojson.Safe.t) : Yojson.Safe.t =
failwith "Rule_schema_v2_adapter.BySideEffect.restore not implemented"
end
module ProjectDependsOn = struct
let normalize (orig : Yojson.Safe.t ) : Yojson.Safe.t =
match orig with
| `Assoc [("depends-on-either", arr)] ->
`List [`String "E";
`Assoc [("depends-on-either", arr)]]
| `Assoc (xs) ->
`List [`String "B";
`Assoc xs]
| x -> x
let restore (_atd : Yojson.Safe.t) : Yojson.Safe.t =
failwith "Rule_schema_v2_adapter.ProjectDependsOn.restore not implemented"
end
(* This is the name of the field that contains the variant constructor
in the user-friendly YAML convention we use to represent variants.
See 'normalize_variant'. *)
let kind_field_name = "kind"
(*
A generic representation for variants. The parameters, if any, must be
an ATD record (JSON object, Yojson assoc).
type t = [
| A <json name="a">
| B <json name="b"> of b
]
type b = {
(* all the fields are optional *)
?k: int option;
}
1. OCaml A is represented as JSON "A". The adapter doesn't change it.
2. OCaml B {k = 42} is represented as JSON {"kind": "B", "k": 42}
which the adapter converts to JSON ["kind", {"k", 42}].
Additionally, the alternate notations {"kind": "A"} and "B" can be
supported in addition to "A" and {"kind": "B"}. This requires specifying
the constructors for which the alternate notation is supported.
Constructors that don't expect an argument must be listed as 'enum'.
Constructors that expect an object argument must be listed as 'obj'.
This gives us the following call:
normalize_generic_variant ~enum:["a"] ~obj:["b"] json
Without specifying 'enum' or 'obj', YAML/JSON interpretation will be
stricter by not tolerating the alternate notations {"kind": "A"} or "B".
YAML example:
- a
- kind: b
k: 42
# assuming default properties:
- kind: b
# shorthand for {kind: b}:
- b
# long form for "a":
- kind: a
TODO: make the ATD tools (atdgen, atdpy, ...) support these alternate
formats as well?
This would allow us to make adapters generic i.e. without
having to specify the 'enum' and 'obj' options. In the example above,
atdgen would read "b" as ["b", {}] and would read ["a", {}] or ["a", null]
as "a" without complaining.
*)
let normalize_variant
?(enum = [])
?(obj = [])
(orig : Yojson.Safe.t ) : Yojson.Safe.t =
match orig with
| `Assoc props ->
(match List.partition (fun (k, _v) -> k = kind_field_name) props with
| [_, `String kind], [] when List.mem kind enum -> `String kind
| [_, `String kind], other_fields ->
`List [`String kind; `Assoc other_fields]
| _missing_or_duplicate_kind, _ -> orig
)
| `String kind when List.mem kind obj -> `List [`String kind; `Assoc []]
| _string_or_malformed -> orig
(* Unlike 'normalize_variant', this if fully generic.
(because we're going from a strict format to a looser format) *)
let restore_variant
(atd : Yojson.Safe.t ) : Yojson.Safe.t =
match atd with
| `String _ as str -> str
| `List [`String _ as kind; `Assoc fields] ->
`Assoc ((kind_field_name, kind) :: fields)
| _malformed -> atd
module Analyzer = struct
let normalize orig =
normalize_variant
~enum:["entropy"; "redos"]
~obj:["entropy_v2"]
orig
let restore (atd : Yojson.Safe.t) : Yojson.Safe.t =
restore_variant atd
end