package comby-kernel

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file rule.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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
open Core_kernel
open Vangstrom

open Types.Ast


module Make (Metasyntax : Types.Metasyntax.S) (External : Types.External.S) = struct

  module Template = Template.Make (Metasyntax) (External)

  let is_whitespace = function
    | ' ' | '\t' | '\r' | '\n' -> true
    | _ -> false

  let spaces =
    take_while is_whitespace

  let spaces1 =
    satisfy is_whitespace *>
    take_while is_whitespace

  let alphanum =
    satisfy (function
        | 'a' .. 'z'
        | 'A' .. 'Z'
        | '0' .. '9' -> true
        | _ -> false)

  let to_atom s =
    match Template.parse s with
    | [] -> String ""
    | [ Constant c ] -> String c
    | t -> Template t

  (** Interpret escape sequences inside quotes *)
  let char_token_s =
    (char '\\' *> any_char >>|
     function
     | 'r' -> Char.to_string '\r'
     | 'n' -> Char.to_string '\n'
     | 't' -> Char.to_string '\t'
     | '\\' -> Char.to_string '\\'
     | c -> Format.sprintf {|\%c|} c)
    <|> (lift String.of_char any_char)

  (** With escape sequences *)
  let quote s =
    lift2 (fun _ v -> String.concat v)
      (string s)
      (many_till char_token_s (string s))

  let raw s =
    lift2 (fun _ v -> String.of_char_list v)
      (string s)
      (many_till any_char (string s))

  let quoted_parser =
    choice ~failure_msg:"could not parse quoted value"
      [ quote {|"|}; quote {|'|}; raw {|`|} ]

  let map_special s =
    if String.is_prefix s ~prefix:"~" then
      Template (Template.parse (Format.sprintf ":[%s]" s))
    else if String.equal s "_" then
      Template (Template.parse ":[_]")
    else
      to_atom s

  let up_to p =
    many1 (not_followed_by p *> any_char)

  let atom_up_to_spaces () =
    choice
      [ (lift to_atom quoted_parser)
      ; lift (fun v -> to_atom (String.of_char_list v)) (up_to spaces1)
      ]

  let atom_up_to_terminal () =
    choice
      [ (lift to_atom quoted_parser)
      ; (lift
           (fun v -> to_atom (String.of_char_list v))
           (up_to
              (choice
                 [ spaces1 *> return ()
                 ; char ',' *> return ()
                 ; char '}' *> return ()
                 ])))
      ]

  let antecedent_parser () =
    choice ~failure_msg:"could not parse LHS of ->"
      [ (lift to_atom quoted_parser)
      ; (lift (fun v -> map_special (String.of_char_list v)) (up_to (spaces *> string Syntax.arrow)))
      ]

  let value_to_open_brace () =
    choice
      [ (lift to_atom quoted_parser)
      ; (lift (fun v -> to_atom (String.of_char_list v)) (up_to (spaces *> char '{')))
      ]

  let value_to_comma () =
    choice
      [ (lift to_atom quoted_parser)
      ; (lift (fun v -> to_atom (String.of_char_list v)) (up_to (spaces *> char ',')))
      ]

  let rewrite_consequent_parser () =
    choice
      [ (lift to_atom quoted_parser)
      ; (lift (fun v -> to_atom (String.of_char_list v)) (up_to (spaces *> char '}')))
      ]

  let operator_parser =
    choice
      [ string Syntax.equal
      ; string Syntax.not_equal
      ]

  let make_equality_expression left operator right =
    if String.equal operator Syntax.equal then
      Equal (left, right)
    else
      Not_equal (left, right)

  let optional_trailing c = option () (skip (Char.equal c))

  let option_parser =
    lift (fun _ -> Option "nested") (spaces *> (string Syntax.option_nested) <* spaces)

  let true' = lift (fun _ -> True) (spaces *> string Syntax.true' <* spaces)

  let false' = lift (fun _ -> False) (spaces *> string Syntax.false' <* spaces)

  (** <atom> [==, !=] <atom> *)
  let compare_parser =
    lift3
      make_equality_expression
      (spaces *> atom_up_to_spaces ())
      (spaces *> operator_parser)
      (spaces *> atom_up_to_terminal ())
    <* spaces

  let make_rewrite_expression atom match_template rewrite_template =
    Rewrite (atom, (match_template, rewrite_template))

  (** rewrite <atom> { <atom> -> <atom> } *)
  let rewrite_pattern_parser =
    lift3
      make_rewrite_expression
      (string Syntax.start_rewrite_pattern
       *> spaces*> value_to_open_brace () <* spaces <* char '{' <* spaces)
      (antecedent_parser () <* spaces <* string Syntax.arrow <* spaces)
      (rewrite_consequent_parser () <* spaces <* char '}')

  (** <atom> -> atom [, <expr>], [,] *)
  let match_arrow_parser expression_parser =
    both
      (antecedent_parser () <* spaces <* string Syntax.arrow <* spaces)
      (sep_by (char ',') expression_parser <* spaces <* optional_trailing ',' <* spaces)

  (** [|] <match_arrow> *)
  let first_case_parser expression_parser =
    spaces *> option () (Omega_parser_helper.ignore @@ string Syntax.pipe_operator *> spaces) *>
    match_arrow_parser expression_parser

  (** | <match_arrow> *)
  let case_parser expression_parser =
    spaces *> string Syntax.pipe_operator *> spaces *>
    match_arrow_parser expression_parser

  (** [|] <match_arrow> | <match_arrow> *)
  let case_block expression_parser =
    first_case_parser expression_parser >>= fun case ->
    many (case_parser expression_parser) >>= fun cases ->
    return (case :: cases)

  (** match <atom> { <case_parser> } *)
  let match_pattern_parser expression_parser =
    lift3
      (fun _ atom cases -> Match (atom, cases))
      (string Syntax.start_match_pattern *> spaces)
      (value_to_open_brace () <* spaces <* char '{' <* spaces)
      (case_block expression_parser <* char '}' <* spaces)

  let expression_parser =
    fix (fun expression_parser ->
        choice ~failure_msg:"could not parse expression"
          [ match_pattern_parser expression_parser
          ; rewrite_pattern_parser
          ; compare_parser
          ; true'
          ; false'
          ; option_parser
          ])

  (** where <expression> [,] *)
  let parse =
    spaces *> string Syntax.rule_prefix *>
    spaces1 *> sep_by1 (spaces *> char ',' <* spaces) expression_parser
    <* optional_trailing ','
    <* spaces

  let create rule =
    match parse_string ~consume:All (parse <* end_of_input) rule with
    | Ok rule -> Ok rule
    | Error error -> Or_error.error_string error
end

type t = Types.Rule.t
[@@deriving sexp]

let create
    ?(metasyntax = Metasyntax.default_metasyntax)
    ?(external_handler = External.default_external)
    rule =
  let (module Metasyntax) = Metasyntax.create metasyntax in
  let module External = struct let handler = external_handler end in
  let (module Rule : Types.Rule.S) = (module (Make (Metasyntax) (External))) in
  Rule.create rule

type options =
  { nested : bool
  }

let options rule =
  List.fold rule ~init:{ nested = false } ~f:(fun acc -> function
      | Types.Ast.Option name when String.(name = Syntax.option_nested) -> { nested = true }
      | _ -> acc)
OCaml

Innovation. Community. Security.