Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file sexp_grammar.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207(** Representation of S-expression grammars *)(** This module defines a representation for s-expression grammars. Using ppx_sexp_conv
and [[@@deriving sexp_grammar]] produces a grammar that is compatible with the derived
[of_sexp] for a given type.
As with other derived definitions, polymorphic types derive a function that takes a
grammar for each type argument and produces a grammar for the monomorphized type.
Monomorphic types derive a grammar directly. To avoid top-level side effects,
[[@@deriving sexp_grammar]] wraps grammars in the [Lazy] constructor as needed.
This type may change over time as our needs for expressive grammars change. We will
attempt to make changes backward-compatible, or at least provide a reasonable upgrade
path. *)[@@@warning"-30"](* allow duplicate field names *)(** Grammar of a sexp. *)typegrammar=|Anyofstring(** accepts any sexp; string is a type name for human readability *)|Bool(** accepts the atoms "true" or "false", modulo capitalization *)|Char(** accepts any single-character atom *)|Integer(** accepts any atom matching ocaml integer syntax, regardless of bit width *)|Float(** accepts any atom matching ocaml float syntax *)|String(** accepts any atom *)|Optionofgrammar(** accepts an option, both [None] vs [Some _] and [()] vs [(_)]. *)|Listoflist_grammar(** accepts a list *)|Variantofvariant(** accepts clauses keyed by a leading or sole atom *)|Unionofgrammarlist(** accepts a sexp if any of the listed grammars accepts it *)|Taggedofgrammarwith_tag(** annotates a grammar with a client-specific key/value pair *)|Tyvarofstring(** Name of a type variable, e.g. [Tyvar "a"] for ['a]. Only meaningful when the body of
the innermost enclosing [defn] defines a corresponding type variable. *)|Tyconofstring*grammarlist*defnlist(** Type constructor applied to arguments, and its definition.
For example, writing [Tycon ("tree", [ Integer ], defns)] represents [int tree], for
whatever [tree] is defined as in [defns]. The following defines [tree] as a binary
tree with the parameter type stored at the leaves.
{[
let defns =
[ { tycon = "tree"
; tyvars = ["a"]
; grammar =
Variant
{ name_kind = Capitalized
; clauses =
[ { name = "Node"
; args = Cons (Recursive ("node", [Tyvar "a"]), Empty)
}
; { name = "Leaf"
; args = Cons (Recursive ("leaf", [Tyvar "a"]), Empty)
}
]
}
}
; { tycon = "node"
; tyvars = ["a"]
; grammar = List (Many (Recursive "tree", [Tyvar "a"]))
}
; { tycon = "leaf"
; tyvars = ["a"]
; grammar = [Tyvar "a"]
}
]
;;
]}
To illustrate the meaning of [Tycon] with respect to [defns], and to demonstrate one
way to access them, it is equivalent to expand the definition of "tree" one level
and move the [defns] to enclosed recursive references:
{[
Tycon ("tree", [ Integer ], defns)
-->
Variant
{ name_kind = Capitalized
; clauses =
[ { name = "Node"
; args = Cons (Tycon ("node", [Tyvar "a"], defns), Empty)
}
; { name = "Leaf"
; args = Cons (Tycon ("leaf", [Tyvar "a"], defns), Empty)
}
]
}
]}
This transformation exposes the structure of a grammar with recursive references,
while preserving the meaning of recursively-defined elements. *)|Recursiveofstring*grammarlist(** Type constructor applied to arguments. Used to denote recursive type references.
Only meaningful when used inside the [defn]s of a [Tycon] grammar, to refer to a
type constructor in the nearest enclosing [defn] list. *)|Lazyofgrammarlazy_t(** Lazily computed grammar. Use [Lazy] to avoid top-level side effects. To define
recursive grammars, use [Recursive] instead. *)(** Grammar of a list of sexps. *)andlist_grammar=|Empty(** accepts an empty list of sexps *)|Consofgrammar*list_grammar(** accepts a non-empty list with head and tail matching the given grammars *)|Manyofgrammar(** accepts zero or more sexps, each matching the given grammar *)|Fieldsofrecord(** accepts sexps representing fields of a record *)(** Case sensitivity options for names of variant constructors. *)andcase_sensitivity=|Case_insensitive(** Comparison is case insensitive. Used for custom parsers. *)|Case_sensitive(** Comparison is case sensitive. Used for polymorphic variants. *)|Case_sensitive_except_first_character(** Comparison is case insensitive for the first character and case sensitive afterward.
Used for regular variants. *)(** Grammar of variants. Accepts any sexp matching one of the clauses. *)andvariant={case_sensitivity:case_sensitivity;clauses:clausewith_tag_listlist}(** Grammar of a single variant clause. Accepts sexps based on the [clause_kind]. *)andclause={name:string;clause_kind:clause_kind}(** Grammar of a single variant clause's contents. [Atom_clause] accepts an atom matching
the clause's name. [List_clause] accepts a list whose head is an atom matching the
clause's name and whose tail matches [args]. The clause's name is matched modulo the
variant's [name_kind]. *)andclause_kind=|Atom_clause|List_clauseof{args:list_grammar}(** Grammar of a record. Accepts any list of sexps specifying each of the fields,
regardless of order. If [allow_extra_fields] is specified, ignores sexps with names
not found in [fields]. *)andrecord={allow_extra_fields:bool;fields:fieldwith_tag_listlist}(** Grammar of a record field. A field must show up exactly once in a record if
[required], or at most once otherwise. Accepts a list headed by [name] as an atom,
followed by sexps matching [args]. *)andfield={name:string;required:bool;args:list_grammar}(** Grammar tagged with client-specific key/value pair. *)and'awith_tag={key:string;value:Sexp.t;grammar:'a}and'awith_tag_list=|Tagof'awith_tag_listwith_tag|No_tagof'a(** Grammar of a recursive type definition. Names the [tycon] being defined, and the
[tyvars] it takes as parameters. Specifies the [grammar] of the [tycon]. The grammar
may refer to any of the [tyvars], and to any of the [tycon]s from the same set of
[Recursive] definitions. *)anddefn={tycon:string;tyvars:stringlist;grammar:grammar}(** Top-level grammar type. Has a phantom type parameter to associate each grammar with
the type its sexps represent. This makes it harder to apply grammars to the wrong
type, while grammars can still be easily coerced to a new type if needed. *)type_t={untyped:grammar}[@@unboxed]letcoerce(typeab)({untyped=_}ast:at):bt=tlettag(typea)({untyped=grammar}:at)~key~value:at={untyped=Tagged{key;value;grammar}};;(** This reserved key is used for all tags generated from doc comments. *)letdoc_comment_tag="sexp_grammar.doc_comment"(** This reserved key can be used to associate a type name with a grammar. *)lettype_name_tag="sexp_grammar.type_name"(** This reserved key indicates that a sexp represents a key/value association. The tag's
value is ignored. *)letassoc_tag="sexp_grammar.assoc"(** This reserved key indicates that a sexp is a key in a key/value association. The tag's
value is ignored. *)letassoc_key_tag="sexp_grammar.assoc.key"(** This reserved key indicates that a sexp is a value in a key/value association. The
tag's value is ignored. *)letassoc_value_tag="sexp_grammar.assoc.value"(** When the key is set to [Atom "false"] for a variant clause, that clause should not be
suggested in auto-completion based on the sexp grammar. *)letcompletion_suggested="sexp_grammar.completion-suggested"