diff --git a/ppx/ppx_attribute_value.ml b/ppx/attribute_value.ml similarity index 82% rename from ppx/ppx_attribute_value.ml rename to ppx/attribute_value.ml index 317c9d67b..6a55136c6 100644 --- a/ppx/ppx_attribute_value.ml +++ b/ppx/attribute_value.ml @@ -20,14 +20,13 @@ [@@@ocaml.warning "-3"] open Ast_helper -module Pc = Ppx_common type 'a gparser = ?separated_by:string -> ?default:string -> Location.t -> string -> 'a -> Parsetree.expression option type parser = string gparser -type vparser = string Pc.value gparser +type vparser = string Common.value gparser (* Handle expr *) @@ -72,7 +71,7 @@ let list delimiter separated_by element_parser ?separated_by:_ ?default:_ loc name s = exp_list delimiter separated_by element_parser loc name s - |> Ppx_common.list loc + |> Common.list loc |> fun e -> Some e let spaces = list (Re_str.regexp " +") "space" @@ -91,8 +90,8 @@ let wrap (parser : parser) implementation = expr @@ fun ?separated_by:_ ?default:_ loc name s -> match parser loc name s with - | None -> Ppx_common.error loc "wrap applied to presence; nothing to wrap" - | Some e -> Some (Ppx_common.wrap implementation loc e) + | None -> Common.error loc "wrap applied to presence; nothing to wrap" + | Some e -> Some (Common.wrap implementation loc e) let nowrap (parser : parser) _ = expr @@ @@ -116,7 +115,7 @@ let must_be_a | None -> singular_description in - Ppx_common.error loc "Value of %s must be %s" name description + Common.error loc "Value of %s must be %s" name description @@ -134,12 +133,12 @@ let group_matched index s = with Not_found -> false let int_exp loc s = - try Some (Ppx_common.int loc (int_of_string s)) + try Some (Common.int loc (int_of_string s)) with Failure _ -> None let float_exp loc s = try - Some (Ppx_common.float loc @@ float_of_string s) + Some (Common.float loc @@ float_of_string s) with Failure _ -> None @@ -154,22 +153,22 @@ let char ?separated_by:_ ?default:_ loc name s = let open Markup.Encoding in let report _ error = - Ppx_common.error loc "%s in attribute %s" + Common.error loc "%s in attribute %s" (Markup.Error.to_string error |> String.capitalize) name in let decoded = string s |> decode ~report utf_8 in let c = match next decoded with - | None -> Ppx_common.error loc "No character in attribute %s" name + | None -> Common.error loc "No character in attribute %s" name | Some i when i <= 255 -> Char.chr i | Some _ -> - Ppx_common.error loc "Character out of range in attribute %s" name + Common.error loc "Character out of range in attribute %s" name in begin match next decoded with | None -> () - | Some _ -> Ppx_common.error loc "Multiple characters in attribute %s" name + | Some _ -> Common.error loc "Multiple characters in attribute %s" name end; Some (with_default_loc loc @@ fun () -> Ast_convenience.char c) @@ -179,7 +178,7 @@ let onoff ?separated_by:_ ?default:_ loc name s = | "" | "on" -> true | "off" -> false | _ -> - Ppx_common.error loc {|Value of %s must be "on", "" or "off"|} name + Common.error loc {|Value of %s must be "on", "" or "off"|} name in Some (bool_exp loc b) @@ -188,7 +187,7 @@ let bool ?separated_by:_ ?default:_ loc name s = | "" | "true" -> true | "false" -> false | _ -> - Ppx_common.error loc {|Value of %s must be "true", "" or "false"|} name + Common.error loc {|Value of %s must be "true", "" or "false"|} name in Some (bool_exp loc b) @@ -196,7 +195,7 @@ let unit ?separated_by:_ ?default:_ loc name s = if s = "" || s = name then Some (Ast_convenience.(with_default_loc loc unit)) else - Ppx_common.error loc + Common.error loc {|Value of %s must be %s or "".|} name name @@ -218,8 +217,8 @@ let points ?separated_by:_ ?default:_ loc name s = let expressions = spaces_or_commas_ float loc name s in let rec pair acc = function - | [] -> List.rev acc |> Ppx_common.list loc - | [_] -> Ppx_common.error loc "Unpaired coordinate in %s" name + | [] -> List.rev acc |> Common.list loc + | [_] -> Common.error loc "Unpaired coordinate in %s" name | ex::ey::rest -> pair (([%expr [%e ex], [%e ey]] [@metaloc loc])::acc) rest in @@ -230,7 +229,7 @@ let number_pair ?separated_by:_ ?default:_ loc name s = begin match spaces_or_commas_ float loc name s with | [orderx] -> [%expr [%e orderx], None] | [orderx; ordery] -> [%expr [%e orderx], Some [%e ordery]] - | _ -> Ppx_common.error loc "%s requires one or two numbers" name + | _ -> Common.error loc "%s requires one or two numbers" name end [@metaloc loc] in @@ -241,7 +240,7 @@ let fourfloats ?separated_by:_ ?default:_ loc name s = | [min_x; min_y; width; height] -> Some [%expr ([%e min_x], [%e min_y], [%e width], [%e height])] [@metaloc loc] - | _ -> Ppx_common.error loc "Value of %s must be four numbers" name + | _ -> Common.error loc "Value of %s must be four numbers" name (* These are always in a list; hence the error message. *) let icon_size = @@ -249,7 +248,7 @@ let icon_size = fun ?separated_by:_ ?default:_ loc name s -> if not @@ does_match regexp s then - Ppx_common.error loc "Value of %s must be a %s, or %s" + Common.error loc "Value of %s must be a %s, or %s" name "space-separated list of icon sizes, such as 16x16" "any"; let width, height = @@ -257,13 +256,13 @@ let icon_size = int_of_string (Re_str.matched_group 1 s), int_of_string (Re_str.matched_group 2 s) with Invalid_argument _ -> - Ppx_common.error loc "Icon dimension out of range in %s" name + Common.error loc "Icon dimension out of range in %s" name in Some [%expr - [%e Ppx_common.int loc width], - [%e Ppx_common.int loc height]] [@metaloc loc] + [%e Common.int loc width], + [%e Common.int loc height]] [@metaloc loc] @@ -284,7 +283,7 @@ let svg_quantity = let n = match float_exp loc (Re_str.matched_group 1 s) with | Some n -> n - | None -> Ppx_common.error loc "Number out of range in %s" name + | None -> Common.error loc "Number out of range in %s" name in let unit_string = Re_str.matched_group 4 s in @@ -307,7 +306,7 @@ let svg_length = | "pt" -> [%expr `Pt] | "px" -> [%expr `Px] | "%" -> [%expr `Percent] - | s -> Ppx_common.error loc "Invalid length unit %s in %s" s name + | s -> Common.error loc "Invalid length unit %s in %s" s name end [@metaloc loc] in @@ -322,7 +321,7 @@ let angle_ = | "deg" -> [%expr `Deg] | "rad" -> [%expr `Rad] | "grad" -> [%expr `Grad] - | s -> Ppx_common.error loc "Invalid angle unit %s in %s" s name + | s -> Common.error loc "Invalid angle unit %s in %s" s name end [@metaloc loc] in @@ -333,7 +332,7 @@ let angle ?separated_by ?default loc name s = let offset = let bad_form name loc = - Ppx_common.error loc "Value of %s must be a number or percentage" name in + Common.error loc "Value of %s must be a number or percentage" name in let regexp = Re_str.regexp "\\([-+0-9eE.]+\\)\\(%\\)?" in @@ -356,7 +355,7 @@ let transform = fun ?separated_by:_ ?default:_ loc name s -> if not @@ does_match regexp s then - Ppx_common.error loc "Value of %s must be an SVG transform" name; + Common.error loc "Value of %s must be an SVG transform" name; let kind = Re_str.matched_group 1 s in let values = Re_str.matched_group 2 s in @@ -368,7 +367,7 @@ let transform = | [a; b; c; d; e; f] -> [%expr `Matrix ([%e a], [%e b], [%e c], [%e d], [%e e], [%e f])] | _ -> - Ppx_common.error loc "%s: matrix requires six numbers" name + Common.error loc "%s: matrix requires six numbers" name end | "translate" -> @@ -376,14 +375,14 @@ let transform = | [tx; ty] -> [%expr `Translate ([%e tx], Some [%e ty])] | [tx] -> [%expr `Translate ([%e tx], None)] | _ -> - Ppx_common.error loc "%s: translate requires one or two numbers" name + Common.error loc "%s: translate requires one or two numbers" name end | "scale" -> begin match spaces_or_commas_ float loc "scale" values with | [sx; sy] -> [%expr `Scale ([%e sx], Some [%e sy])] | [sx] -> [%expr `Scale ([%e sx], None)] - | _ -> Ppx_common.error loc "%s: scale requires one or two numbers" name + | _ -> Common.error loc "%s: scale requires one or two numbers" name end | "rotate" -> @@ -395,10 +394,10 @@ let transform = [%expr `Rotate ([%e angle_ loc "rotate" a], Some ([%e cx], [%e cy]))] | _ -> - Ppx_common.error loc "%s: rotate center requires two numbers" name + Common.error loc "%s: rotate center requires two numbers" name end | _ -> - Ppx_common.error loc + Common.error loc "%s: rotate requires an angle and an optional center" name end @@ -406,7 +405,7 @@ let transform = | "skewY" -> [%expr `SkewY [%e angle_ loc "skewY" values]] - | s -> Ppx_common.error loc "%s: %s is not a valid transform type" name s + | s -> Common.error loc "%s: %s is not a valid transform type" name s end [@metaloc loc] in @@ -433,7 +432,7 @@ let variant ?separated_by:_ ?default:_ loc _ s = let total_variant (unary, nullary) ?separated_by:_ ?default:_ loc _name s = let variand = variand s in if List.mem variand nullary then Some (Exp.variant ~loc variand None) - else Some (Exp.variant ~loc unary (Some (Ppx_common.string loc s))) + else Some (Exp.variant ~loc unary (Some (Common.string loc s))) @@ -456,20 +455,20 @@ let paint_without_icc loc _name s = in match icc_color_start with - | None -> [%expr `Color ([%e Ppx_common.string loc s], None)] + | None -> [%expr `Color ([%e Common.string loc s], None)] | Some i -> let icc_color = Re_str.matched_group 1 s in let color = String.sub s 0 i in [%expr `Color - ([%e Ppx_common.string loc color], - Some [%e Ppx_common.string loc icc_color])] + ([%e Common.string loc color], + Some [%e Common.string loc icc_color])] end [@metaloc loc] let paint ?separated_by:_ ?default:_ loc name s = if not @@ Re_str.string_match (Re_str.regexp "url(\\([^)]+\\))") s 0 then Some (paint_without_icc loc name s) else - let iri = Re_str.matched_group 1 s |> Ppx_common.string loc in + let iri = Re_str.matched_group 1 s |> Common.string loc in let remainder_start = Re_str.group_end 0 in let remainder_length = String.length s - remainder_start in let remainder = @@ -491,13 +490,13 @@ let srcset_element = let e = begin match Re_str.bounded_split space s 2 with | [url] -> - [%expr `Url [%e Ppx_common.string loc url]] + [%expr `Url [%e Common.string loc url]] | [url; descriptor] -> let bad_descriptor () = - Ppx_common.error loc "Bad width or density descriptor in %s" name in + Common.error loc "Bad width or density descriptor in %s" name in - let url = Ppx_common.string loc url in + let url = Common.string loc url in let suffix_index = String.length descriptor - 1 in let is_width = @@ -513,7 +512,7 @@ let srcset_element = match int_exp loc (String.sub descriptor 0 suffix_index) with | Some n -> n | None -> - Ppx_common.error loc "Bad number for width in %s" name + Common.error loc "Bad number for width in %s" name in [%expr `Url_width ([%e url], [%e n])] @@ -523,12 +522,12 @@ let srcset_element = match float_exp loc (String.sub descriptor 0 suffix_index) with | Some n -> n | None -> - Ppx_common.error loc "Bad number for pixel density in %s" name + Common.error loc "Bad number for pixel density in %s" name in [%expr `Url_pixel ([%e url], [%e n])] - | _ -> Ppx_common.error loc "Missing URL in %s" name + | _ -> Common.error loc "Missing URL in %s" name end [@metaloc loc] in @@ -537,7 +536,7 @@ let srcset_element = let number_or_datetime ?separated_by:_ ?default:_ loc _ s = match int_exp loc s with | Some n -> Some [%expr `Number [%e n]] - | None -> Some [%expr `Datetime [%e Pc.string loc s]] + | None -> Some [%expr `Datetime [%e Common.string loc s]] [@metaloc loc] @@ -552,6 +551,6 @@ let in2 = in_ let xmlns ?separated_by:_ ?default:_ loc name s = if s <> Markup.Ns.html then - Ppx_common.error loc "%s: namespace must be %s" name Markup.Ns.html; + Common.error loc "%s: namespace must be %s" name Markup.Ns.html; Some [%expr `W3_org_1999_xhtml] [@metaloc loc] diff --git a/ppx/ppx_attribute_value.mli b/ppx/attribute_value.mli similarity index 98% rename from ppx/ppx_attribute_value.mli rename to ppx/attribute_value.mli index 8fefaf540..f1053096c 100644 --- a/ppx/ppx_attribute_value.mli +++ b/ppx/attribute_value.mli @@ -24,7 +24,7 @@ type 'a gparser = ?separated_by:string -> ?default:string -> Location.t -> string -> 'a -> Parsetree.expression option type parser = string gparser -type vparser = string Ppx_common.value gparser +type vparser = string Common.value gparser (** Attribute value parsers are assigned to each attribute depending on the type of the attribute's argument, though some attributes have special parsers based on their name, or on a [[@@reflect]] annotation. A parser is a @@ -76,11 +76,11 @@ val spaces_or_commas : parser -> parser (** {3 Top combinators} Exported parsers should always use one of those combinators last. *) -val wrap : parser -> Ppx_common.lang -> vparser +val wrap : parser -> Common.lang -> vparser (** [wrap parser module_ _ _ s] applies [parser _ _ s] to get a parse tree for [e], then evaluates to the parse tree for [module_.Xml.W.return e]. *) -val nowrap : parser -> Ppx_common.lang -> vparser +val nowrap : parser -> Common.lang -> vparser (** [nowrap parser _ _ _ s] evaluates to [parser _ _ s]. The purpose of this combinator is to provide a signature similar to [wrap] in situations where wrapping is not wanted. *) diff --git a/ppx/ppx_attributes.ml b/ppx/attributes.ml similarity index 85% rename from ppx/ppx_attributes.ml rename to ppx/attributes.ml index 6af37d806..ecc6e1f0e 100644 --- a/ppx/ppx_attributes.ml +++ b/ppx/attributes.ml @@ -19,7 +19,7 @@ let parse loc (ns, element_name) attributes = let language, (module Reflected) = - Ppx_namespace.reflect loc ns in + Namespace.reflect loc ns in (* For prefix ["prefix"] and attribute names ["prefix-foo"], evaluates to [Some "foo"], otherwise evaluates to [None]. @@ -52,23 +52,23 @@ let parse loc (ns, element_name) attributes = let test_renamed (_, a, es) = a = local_name && List.mem element_name es in let unknown () = - Ppx_common.error loc "Unknown attribute in %s element: %s" - (Ppx_common.lang language) local_name + Common.error loc "Unknown attribute in %s element: %s" + (Common.lang language) local_name in (* Check whether this attribute is individually labeled. Parse its argument and accumulate the attribute if so. *) - match Ppx_common.find test_labeled Reflected.labeled_attributes with + match Common.find test_labeled Reflected.labeled_attributes with | Some (_, label, parser) -> let e = match parser language loc local_name value with | None -> - Ppx_common.error loc + Common.error loc "Internal error: labeled attribute %s without an argument" label | Some e -> e in - (Ppx_common.Label.labelled label, e)::labeled, regular + (Common.Label.labelled label, e)::labeled, regular | None -> (* The attribute is not individually labeled, so it is passed in ~a. @@ -87,17 +87,17 @@ let parse loc (ns, element_name) attributes = let parser = try List.assoc tyxml_name Reflected.attribute_parsers with Not_found -> - Ppx_common.error loc "Internal error: no parser for %s" tyxml_name + Common.error loc "Internal error: no parser for %s" tyxml_name in - let identifier = Ppx_common.make ~loc language tyxml_name in - let tag = Ppx_common.string loc tag in + let identifier = Common.make ~loc language tyxml_name in + let tag = Common.string loc tag in let e = match parser language loc local_name value with | Some e' -> [%expr [%e identifier] [%e tag] [%e e']] [@metaloc loc] | None -> - Ppx_common.error loc "Internal error: no expression for %s" + Common.error loc "Internal error: no expression for %s" tyxml_name in @@ -114,7 +114,7 @@ let parse loc (ns, element_name) attributes = | _, Some tag -> parse_prefixed_attribute tag "a_aria" | None, None -> let tyxml_name = - match Ppx_common.find test_renamed Reflected.renamed_attributes with + match Common.find test_renamed Reflected.renamed_attributes with | Some (name, _, _) -> name | None -> tyxml_name in @@ -124,7 +124,7 @@ let parse loc (ns, element_name) attributes = with Not_found -> unknown () in - let identifier = Ppx_common.make ~loc language tyxml_name in + let identifier = Common.make ~loc language tyxml_name in let e = match parser language loc local_name value with @@ -143,7 +143,7 @@ let parse loc (ns, element_name) attributes = if regular = [] then List.rev labeled else let regular = - Ppx_common.Label.labelled "a", - Ppx_common.list loc (List.rev regular) + Common.Label.labelled "a", + Common.list loc (List.rev regular) in List.rev (regular::labeled) diff --git a/ppx/ppx_attributes.mli b/ppx/attributes.mli similarity index 91% rename from ppx/ppx_attributes.mli rename to ppx/attributes.mli index 5c1f03854..1c99b0fdf 100644 --- a/ppx/ppx_attributes.mli +++ b/ppx/attributes.mli @@ -19,11 +19,9 @@ (** Attribute parsing. *) - - val parse : - Location.t -> Markup.name -> (Markup.name * string Ppx_common.value) list -> - (Ppx_common.Label.t * Parsetree.expression) list + Location.t -> Markup.name -> (Markup.name * string Common.value) list -> + (Common.Label.t * Parsetree.expression) list (** [parse loc element_name attributes] evaluates to a list of labeled parse trees, each representing an attribute argument to the element function for [element_name]. For example, if called on the HTML element diff --git a/ppx/ppx_common.ml b/ppx/common.ml similarity index 100% rename from ppx/ppx_common.ml rename to ppx/common.ml diff --git a/ppx/ppx_common.mli b/ppx/common.mli similarity index 100% rename from ppx/ppx_common.mli rename to ppx/common.mli diff --git a/ppx/ppx_element.ml b/ppx/element.ml similarity index 76% rename from ppx/ppx_element.ml rename to ppx/element.ml index ba169d86a..8bfc8917e 100644 --- a/ppx/ppx_element.ml +++ b/ppx/element.ml @@ -21,14 +21,14 @@ let parse ~loc ~parent_lang ~name:((ns, name) as element_name) ~attributes children = - let attributes = Ppx_attributes.parse loc element_name attributes in - let lang, (module Reflected) = Ppx_namespace.reflect loc ns in + let attributes = Attributes.parse loc element_name attributes in + let lang, (module Reflected) = Namespace.reflect loc ns in let lang = match parent_lang, lang with - | Ppx_common.Html, Svg -> Ppx_common.Html + | Common.Html, Svg -> Common.Html | Html, Html | Svg, Svg -> lang | Svg, Html -> - Ppx_common.error loc + Common.error loc "Nesting of Html element inside svg element is not supported" in @@ -36,12 +36,12 @@ let parse try List.assoc name Reflected.renamed_elements with Not_found -> Tyxml_name.ident name in - let element_function = Ppx_common.make ~loc lang name in + let element_function = Common.make ~loc lang name in let assembler = try List.assoc name Reflected.element_assemblers with Not_found -> - Ppx_common.error loc "Unknown %s element %s" (Ppx_common.lang lang) name + Common.error loc "Unknown %s element %s" (Common.lang lang) name in let children = assembler ~lang ~loc ~name children in @@ -49,8 +49,8 @@ let parse Ast_helper.Exp.apply ~loc element_function (attributes @ children) let comment ~loc ~lang s = - let tot = Ppx_common.make ~loc lang "tot" in - let comment = Ppx_common.make ~loc lang "Xml.comment" in - let s = Ppx_common.string loc s in + let tot = Common.make ~loc lang "tot" in + let comment = Common.make ~loc lang "Xml.comment" in + let s = Common.string loc s in (* Using metaquot here avoids fiddling with labels. *) [%expr [%e tot] ([%e comment] [%e s])][@metaloc loc] diff --git a/ppx/ppx_element.mli b/ppx/element.mli similarity index 88% rename from ppx/ppx_element.mli rename to ppx/element.mli index 7e9d69fed..ec6b7c527 100644 --- a/ppx/ppx_element.mli +++ b/ppx/element.mli @@ -21,10 +21,10 @@ val parse : loc:Location.t -> - parent_lang:Ppx_common.lang -> + parent_lang:Common.lang -> name:Markup.name -> - attributes:(Markup.name * string Ppx_common.value) list -> - Parsetree.expression Ppx_common.value list -> + attributes:(Markup.name * string Common.value) list -> + Parsetree.expression Common.value list -> Parsetree.expression (** [parse ~loc ~parent_lang ~name ~attributes children] evaluates to a parse tree for applying the TyXML function corresponding @@ -34,7 +34,7 @@ val parse : val comment : loc:Location.t -> - lang:Ppx_common.lang -> + lang:Common.lang -> string -> Parsetree.expression (** [comment ~loc ~ns s] evaluates to a parse tree that represents an XML comment. *) diff --git a/ppx/ppx_element_content.ml b/ppx/element_content.ml similarity index 74% rename from ppx/ppx_element_content.ml rename to ppx/element_content.ml index 66da446a3..b23d3ef39 100644 --- a/ppx/ppx_element_content.ml +++ b/ppx/element_content.ml @@ -19,14 +19,13 @@ open Asttypes open Parsetree -module Pc = Ppx_common type assembler = - lang:Ppx_common.lang -> + lang:Common.lang -> loc:Location.t -> name:string -> - Parsetree.expression Ppx_common.value list -> - (Pc.Label.t * Parsetree.expression) list + Parsetree.expression Common.value list -> + (Common.Label.t * Parsetree.expression) list @@ -44,7 +43,7 @@ let to_pcdata = function (** Test if the expression is a pcdata containing only whitespaces. *) let is_whitespace = function - | Pc.Val e -> begin + | Common.Val e -> begin match to_pcdata e with | Some s when String.trim s = "" -> true | _ -> false @@ -67,7 +66,7 @@ let filter_surrounding_whitespace children = (* Given a parse tree and a string [name], checks whether the parse tree is an application of a function with name [name]. *) let is_element_with_name name = function - | Pc.Val {pexp_desc = Pexp_apply ({pexp_desc = Pexp_ident {txt}}, _)} + | Common.Val {pexp_desc = Pexp_apply ({pexp_desc = Pexp_ident {txt}}, _)} when txt = name -> true | _ -> false @@ -78,7 +77,7 @@ let partition name children = (* Given the name [n] of a function in [Html_sigs.T], evaluates to ["Html." ^ n]. *) let html local_name = - Longident.Ldot (Lident Pc.(implementation Html), local_name) + Longident.Ldot (Lident Common.(implementation Html), local_name) @@ -86,18 +85,18 @@ let html local_name = let nullary ~lang:_ ~loc ~name children = if children <> [] then - Pc.error loc "%s should have no content" name; - [Pc.Label.nolabel, [%expr ()] [@metaloc loc]] + Common.error loc "%s should have no content" name; + [Common.Label.nolabel, [%expr ()] [@metaloc loc]] let unary ~lang ~loc ~name children = match children with | [child] -> - let child = Pc.wrap_value lang loc child in - [Pc.Label.nolabel, child] - | _ -> Pc.error loc "%s should have exactly one child" name + let child = Common.wrap_value lang loc child in + [Common.Label.nolabel, child] + | _ -> Common.error loc "%s should have exactly one child" name let star ~lang ~loc ~name:_ children = - [Pc.Label.nolabel, Pc.list_wrap_value lang loc children] + [Common.Label.nolabel, Common.list_wrap_value lang loc children] @@ -121,9 +120,9 @@ let head ~lang ~loc ~name children = match title with | [title] -> - (Pc.Label.nolabel, Pc.wrap_value lang loc title) :: star ~lang ~loc ~name others + (Common.Label.nolabel, Common.wrap_value lang loc title) :: star ~lang ~loc ~name others | _ -> - Pc.error loc + Common.error loc "%s element must have exactly one title child element" name let figure ~lang ~loc ~name children = @@ -131,16 +130,16 @@ let figure ~lang ~loc ~name children = | [] -> star ~lang ~loc ~name children | first::others -> if is_element_with_name (html "figcaption") first then - (Pc.Label.labelled "figcaption", - [%expr `Top [%e Pc.wrap_value lang loc first]]):: + (Common.Label.labelled "figcaption", + [%expr `Top [%e Common.wrap_value lang loc first]]):: (star ~lang ~loc ~name others) else let children_reversed = List.rev children in let last = List.hd children_reversed in if is_element_with_name (html "figcaption") last then let others = List.rev (List.tl children_reversed) in - (Pc.Label.labelled "figcaption", - [%expr `Bottom [%e Pc.wrap_value lang loc last]]):: + (Common.Label.labelled "figcaption", + [%expr `Bottom [%e Common.wrap_value lang loc last]]):: (star ~lang ~loc ~name others) else star ~lang ~loc ~name children @@ -150,7 +149,7 @@ let object_ ~lang ~loc ~name children = let params, others = partition (html "param") children in if params <> [] then - (Pc.Label.labelled "params", Pc.list_wrap_value lang loc params) :: + (Common.Label.labelled "params", Common.list_wrap_value lang loc params) :: star ~lang ~loc ~name others else star ~lang ~loc ~name others @@ -159,7 +158,7 @@ let audio_video ~lang ~loc ~name children = let sources, others = partition (html "source") children in if sources <> [] then - (Pc.Label.labelled "srcs", Pc.list_wrap_value lang loc sources) :: + (Common.Label.labelled "srcs", Common.list_wrap_value lang loc sources) :: star ~lang ~loc ~name others else star ~lang ~loc ~name others @@ -172,13 +171,13 @@ let table ~lang ~loc ~name children = let one label = function | [] -> [] - | [child] -> [Pc.Label.labelled label, Pc.wrap_value lang loc child] - | _ -> Pc.error loc "%s cannot have more than one %s" name label + | [child] -> [Common.Label.labelled label, Common.wrap_value lang loc child] + | _ -> Common.error loc "%s cannot have more than one %s" name label in let columns = if columns = [] then [] - else [Pc.Label.labelled "columns", Pc.list_wrap_value lang loc columns] + else [Common.Label.labelled "columns", Common.list_wrap_value lang loc columns] in (one "caption" caption) @ @@ -193,9 +192,9 @@ let fieldset ~lang ~loc ~name children = match legend with | [] -> star ~lang ~loc ~name others | [legend] -> - (Pc.Label.labelled "legend", Pc.wrap_value lang loc legend):: + (Common.Label.labelled "legend", Common.wrap_value lang loc legend):: (star ~lang ~loc ~name others) - | _ -> Pc.error loc "%s cannot have more than one legend" name + | _ -> Common.error loc "%s cannot have more than one legend" name let datalist ~lang ~loc ~name children = let options, others = partition (html "option") children in @@ -203,12 +202,12 @@ let datalist ~lang ~loc ~name children = let children = begin match others with | [] -> - Pc.Label.labelled "children", - [%expr `Options [%e Pc.list_wrap_value lang loc options]] + Common.Label.labelled "children", + [%expr `Options [%e Common.list_wrap_value lang loc options]] | _ -> - Pc.Label.labelled "children", - [%expr `Phras [%e Pc.list_wrap_value lang loc children]] + Common.Label.labelled "children", + [%expr `Phras [%e Common.list_wrap_value lang loc children]] end [@metaloc loc] in @@ -219,14 +218,14 @@ let details ~lang ~loc ~name children = match summary with | [summary] -> - (Pc.Label.nolabel, Pc.wrap_value lang loc summary):: + (Common.Label.nolabel, Common.wrap_value lang loc summary):: (star ~lang ~loc ~name others) - | _ -> Pc.error loc "%s must have exactly one summary child" name + | _ -> Common.error loc "%s must have exactly one summary child" name let menu ~lang ~loc ~name children = let children = - Pc.Label.labelled "child", - [%expr `Flows [%e Pc.list_wrap_value lang loc children]] + Common.Label.labelled "child", + [%expr `Flows [%e Common.list_wrap_value lang loc children]] [@metaloc loc] in children::(nullary ~lang ~loc ~name []) @@ -238,8 +237,8 @@ let html ~lang ~loc ~name children = match head, body, others with | [head], [body], [] -> - [Pc.Label.nolabel, Pc.wrap_value lang loc head; - Pc.Label.nolabel, Pc.wrap_value lang loc body] + [Common.Label.nolabel, Common.wrap_value lang loc head; + Common.Label.nolabel, Common.wrap_value lang loc body] | _ -> - Pc.error loc + Common.error loc "%s element must have exactly head and body child elements" name diff --git a/ppx/ppx_element_content.mli b/ppx/element_content.mli similarity index 92% rename from ppx/ppx_element_content.mli rename to ppx/element_content.mli index a9fa5dd10..a66b407bc 100644 --- a/ppx/ppx_element_content.mli +++ b/ppx/element_content.mli @@ -21,11 +21,11 @@ only tell how to pass already-parsed children to element functions. *) type assembler = - lang:Ppx_common.lang -> + lang:Common.lang -> loc:Location.t -> name:string -> - Parsetree.expression Ppx_common.value list -> - (Ppx_common.Label.t * Parsetree.expression) list + Parsetree.expression Common.value list -> + (Common.Label.t * Parsetree.expression) list (** Assemblers satisfy: [assembler ~lang ~loc ~name children] evaluates to a list of optionally-labeled parse trees for passing [children] to the the element function for element [name]. For example, for a table element @@ -86,5 +86,5 @@ val select : assembler (** Remove pcdata containing only whitespace that are at the beginning or the end of the list. *) val filter_surrounding_whitespace : - Parsetree.expression Ppx_common.value list -> - Parsetree.expression Ppx_common.value list + Parsetree.expression Common.value list -> + Parsetree.expression Common.value list diff --git a/ppx/jbuild b/ppx/jbuild index 497d820a0..4916fd313 100644 --- a/ppx/jbuild +++ b/ppx/jbuild @@ -1,49 +1,32 @@ (jbuild_version 1) -(executable - ((name ppx_reflect) - (libraries (ppx_tools_versioned - tyxml.tools)) - (preprocess (pps (ppx_tools_versioned.metaquot_405))) - (modules (ppx_reflect)) - (flags (:standard - -safe-string - -open Migrate_parsetree - -open Ast_405 - -open Ppx_tools_405 - -w "-9" - )) -)) - (rule ((targets (html_sigs_reflected.ml)) - (deps (ppx_reflect.exe ../lib/html_sigs.mli)) + (deps (reflect/reflect.exe ../lib/html_sigs.mli)) (action (run ${^} ${@})))) (rule ((targets (svg_sigs_reflected.ml)) - (deps (ppx_reflect.exe ../lib/svg_sigs.mli)) + (deps (reflect/reflect.exe ../lib/svg_sigs.mli)) (action (run ${^} ${@})))) (rule ((targets (html_types_reflected.ml)) - (deps (ppx_reflect.exe ../lib/html_types.mli)) + (deps (reflect/reflect.exe ../lib/html_types.mli)) (action (run ${^} ${@})))) (rule ((targets (svg_types_reflected.ml)) - (deps (ppx_reflect.exe ../lib/svg_types.mli)) + (deps (reflect/reflect.exe ../lib/svg_types.mli)) (action (run ${^} ${@})))) (library ((name tyxml_ppx) - (public_name tyxml-ppx) + (public_name tyxml-ppx.internal) (libraries (re.str ppx_tools_versioned markup tyxml.tools )) (preprocess (pps (ppx_tools_versioned.metaquot_405))) - (modules_without_implementation (ppx_sigs_reflected)) - (modules (:standard \ ppx_reflect)) - (kind ppx_rewriter) + (modules_without_implementation (sigs_reflected)) (flags (:standard -safe-string -open Migrate_parsetree diff --git a/ppx/ppx_namespace.ml b/ppx/namespace.ml similarity index 82% rename from ppx/ppx_namespace.ml rename to ppx/namespace.ml index b6b99751f..ecd0a0e17 100644 --- a/ppx/ppx_namespace.ml +++ b/ppx/namespace.ml @@ -17,14 +17,14 @@ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02111-1307, USA. *) -let get : Ppx_common.lang -> (module Ppx_sigs_reflected.S) = function +let get : Common.lang -> (module Sigs_reflected.S) = function | Html -> (module Html_sigs_reflected) | Svg -> (module Svg_sigs_reflected) let to_lang loc ns = - if ns = Markup.Ns.html then Ppx_common.Html - else if ns = Markup.Ns.svg then Ppx_common.Svg - else Ppx_common.error loc "Unknown namespace %s" ns + if ns = Markup.Ns.html then Common.Html + else if ns = Markup.Ns.svg then Common.Svg + else Common.error loc "Unknown namespace %s" ns let reflect loc ns = let l = to_lang loc ns in (l, get l) diff --git a/ppx/ppx_namespace.mli b/ppx/namespace.mli similarity index 82% rename from ppx/ppx_namespace.mli rename to ppx/namespace.mli index e70211785..ad5e520b1 100644 --- a/ppx/ppx_namespace.mli +++ b/ppx/namespace.mli @@ -19,17 +19,15 @@ (** Namespace-specific values. *) - - val reflect : - Location.t -> string -> Ppx_common.lang * (module Ppx_sigs_reflected.S) + Location.t -> string -> Common.lang * (module Sigs_reflected.S) (** When given either [Markup.Ns.html] or [Markup.Ns.svg] as argument, evaluates to the title of the corresponding markup language, the name of the run-time module containing its TyXML implementation, and a preprocessing-time module containing reflection information. *) -val get : Ppx_common.lang -> (module Ppx_sigs_reflected.S) -(** Similar to {!reflect} but takes a {!Ppx_common.lang} directly. *) +val get : Common.lang -> (module Sigs_reflected.S) +(** Similar to {!reflect} but takes a {!Common.lang} directly. *) -val to_lang : Location.t -> string -> Ppx_common.lang +val to_lang : Location.t -> string -> Common.lang (** Takes a namespace and returns the appropriate language. *) diff --git a/ppx/ppx_tyxml_empty.ml b/ppx/ppx_tyxml_empty.ml deleted file mode 100644 index 3fe087d25..000000000 --- a/ppx/ppx_tyxml_empty.ml +++ /dev/null @@ -1 +0,0 @@ -(* Dummy ML file to workaround https://github.com/ocsigen/lwt/issues/91 *) diff --git a/ppx/ppx_tyxml_mustache.ml b/ppx/ppx_tyxml_mustache.ml new file mode 100644 index 000000000..fb52d349d --- /dev/null +++ b/ppx/ppx_tyxml_mustache.ml @@ -0,0 +1,224 @@ + +open Ast_helper +module AC = Ast_convenience + +let mustache_from_file file = + let chan = open_in file in + let lex = Lexing.from_channel chan in + Location.init lex file ; + let t = Mustache.With_locations.parse_lx lex in + close_in chan ; + t + +let mustache_from_string ~lexloc string = + let lex = Lexing.from_string string in + lex.Lexing.lex_start_p <- lexloc ; + lex.Lexing.lex_curr_p <- lexloc ; + Mustache.With_locations.parse_lx lex + +let antiquot_pcdata ~loc ~lang var = + let pcdata = Ppx_common.make ~loc lang "pcdata" in + AC.list [ + Exp.apply ~loc pcdata + [Ppx_common.Label.nolabel, AC.evar var] + ] + +module Var = struct + + module Env = Map.Make(String) + + type kind = + | Var + | Expr + | Section of kind Env.t + + let pp fmt = function + | Var -> Format.pp_print_string fmt "variable" + | Expr -> Format.pp_print_string fmt "unescaped variable" + | Section _ -> Format.pp_print_string fmt "section" + + let rec equal k k' = match k, k' with + | Var, Var | Expr, Expr -> true + | Section env, Section env' -> + Env.equal equal env env' + | _, _ -> false + + let error s k k' = + Location.error @@ Format.asprintf + "Variable %s is used both as a %a and a %a. This is not allowed." + s pp k' pp k + + let add env s k = + if Env.mem s env then + let k' = Env.find s env in + if equal k k then env + else raise @@ Location.Error (error s k k') + else + Env.add s k env + + let union = + let f s parentkind kind = match parentkind, kind with + | Some k, Some k' -> raise @@ Location.Error (error s k k') + | Some k, None | None, Some k -> Some k + | None, None -> None + in Env.merge f + + let section env s secenv = + let k = Section secenv in + add env s k + +end + +module Template = struct + + type t = desc Location.loc list + and desc = + | Markup of string + | Pcdata of string + | Expr of string + | Section of section + and section = { + inverted : bool; + name: string; + contents: t; + } + + let mkloc {Mustache.With_locations. loc_start ; loc_end } txt = + let loc = {Location. loc_ghost = true ; loc_start ; loc_end} in + [{Location. loc ; txt}] + + let rec of_mustache resolve = + Mustache.With_locations.fold + ~string:(fun ~loc x -> mkloc loc @@ Markup x) + ~section: + (fun ~loc ~inverted name contents -> + mkloc loc @@ Section { inverted ; name ; contents}) + ~escaped:(fun ~loc x -> mkloc loc @@ Pcdata x) + ~unescaped:(fun ~loc x -> mkloc loc @@ Expr x) + ~partial: + (fun ~loc:_ s -> + of_mustache resolve @@ mustache_from_file @@ resolve s) + ~comment:(fun ~loc:_ _ -> []) + ~concat:(fun ~loc:_ l -> List.concat l) + + let bindings ~env ~sec_env ~id = + let f s b b' = match b, b' with + | Some k, Some k' -> + if Var.equal k k' then None + else raise @@ Location.Error (Var.error s k k') + | None, Some k' -> Some k' + | _, None -> None + in + let env = Var.Env.merge f env sec_env in + let make_binding k _ l = + Vb.mk (AC.pvar k) (Exp.send id k) :: l + in + Exp.let_ Asttypes.Nonrecursive @@ Var.Env.fold make_binding env [] + + let rec desc_to_expr ~lang env {Location. txt; loc} = + Ast_helper.default_loc := loc ; + match (txt : desc) with + | Markup s -> env, AC.str s + | Pcdata s -> + Var.add env s Var, antiquot_pcdata ~loc ~lang s + | Expr s -> + Var.add env s Expr, AC.evar s + | Section { inverted ; name ; contents } -> + let sec_env, e = + to_expr ~simplify:false ~loc ~lang Var.Env.empty contents + in + let env = Var.section env name sec_env in + let id = AC.evar name in + let pid = AC.pvar name in + if inverted then + env, [%expr if [%e id] = [] then [] else [%e e]] + else + let e = bindings ~env ~sec_env ~id e in + env, [%expr List.concat (List.map (fun [%p pid] -> [%e e]) [%e id])] + + and to_expr ~simplify ~loc ~lang env l = + let f (env, acc) t = + let env, expr = desc_to_expr ~lang env t in + env, expr::acc + in + let env, l = List.fold_left f (env, []) l in + env, Ppx_tyxml.markup_to_expr ~simplify lang loc @@ List.rev l + + let make_function env e = + let f s _k e = + Exp.fun_ (AC.Label.labelled s) None (AC.pvar s) e + in + Var.Env.fold f env e + +end + +let list_as_app = function + | [] -> AC.unit () + | h :: t -> Exp.apply h (List.map (fun x -> AC.Label.nolabel, x) t) + +let expr_of_mustache ~loc ~lang t = + let env, e = + Template.to_expr ~simplify:true ~loc ~lang Var.Env.empty @@ + Template.of_mustache (fun _s -> assert false) @@ + t + in + Template.make_function env e + +let expr_of_string ~loc ~lang ~lexloc s = + expr_of_mustache ~loc ~lang @@ + mustache_from_string ~lexloc s + + +(** Mappers *) + +open Parsetree + +let error loc = + Ppx_common.error loc "Invalid payload for [%%template]." + +let extract_str loc str = + match AC.get_str_with_quotation_delimiter str with + | None -> error loc + | Some (s,quot) -> (Ppx_tyxml.Loc.string_start quot loc, s) + +let expr mapper e = + let sloc = e.pexp_loc in + match e.pexp_desc with + | Pexp_extension ({ txt = ("template" | "tyxml.template")}, payload) -> + begin match payload with + | PStr [[%stri let [%p? var] = [%e? str] in [%e? e]]] -> + let loc = str.pexp_loc in + let lexloc, s = extract_str loc str in + Exp.let_ ~loc:sloc Asttypes.Nonrecursive + [Vb.mk ~loc:sloc var @@ + expr_of_string ~loc ~lang:Html ~lexloc s] + e + + | PStr [{pstr_desc = Pstr_eval (str, _)}] -> + let loc = str.pexp_loc in + let lexloc, s = extract_str loc str in + expr_of_string ~loc ~lang:Html ~lexloc s + + | _ -> error sloc + end + | _ -> Ast_mapper.default_mapper.expr mapper e + +let structure_item mapper stri = + let sloc = stri.pstr_loc in + match stri.pstr_desc with + | Pstr_extension (({ txt = ("template" | "tyxml.template")}, payload), _) -> + begin match payload with + | PStr [([%stri let [%p? var] = [%e? str]] as decl)] -> + let loc = str.pexp_loc in + let lexloc, s = extract_str loc str in + Str.value ~loc:decl.pstr_loc Asttypes.Nonrecursive + [Vb.mk ~loc:decl.pstr_loc var @@ + expr_of_string ~loc ~lang:Html ~lexloc s] + | _ -> error sloc + end + | _ -> Ast_mapper.default_mapper.structure_item mapper stri + +let mapper _ = + { Ast_mapper. default_mapper with expr ; structure_item } + +let () = Ast_mapper.register "tyxml.template" mapper diff --git a/ppx/ppx_tyxml_standalone.ml b/ppx/ppx_tyxml_standalone.ml deleted file mode 100644 index 3d15db43a..000000000 --- a/ppx/ppx_tyxml_standalone.ml +++ /dev/null @@ -1,3 +0,0 @@ -open Migrate_parsetree -module M = Ppx_tyxml_register (* dirty way to force link *) -let () = Driver.run_main () diff --git a/ppx/reflect/jbuild b/ppx/reflect/jbuild new file mode 100644 index 000000000..ec5de3646 --- /dev/null +++ b/ppx/reflect/jbuild @@ -0,0 +1,14 @@ +(jbuild_version 1) + +(executable + ((name reflect) + (libraries (ppx_tools_versioned tyxml.tools)) + (preprocess (pps (ppx_tools_versioned.metaquot_405))) + (flags (:standard + -safe-string + -open Migrate_parsetree + -open Ast_405 + -open Ppx_tools_405 + -w "-9" + )) +)) diff --git a/ppx/ppx_reflect.ml b/ppx/reflect/reflect.ml similarity index 98% rename from ppx/ppx_reflect.ml rename to ppx/reflect/reflect.ml index 05ae454d0..2fdf609e0 100644 --- a/ppx/ppx_reflect.ml +++ b/ppx/reflect/reflect.ml @@ -21,7 +21,7 @@ and value declarations are read for type information, which is stored in corresponding [_reflected] files - for example, [html_sigs.mli] results in [html_sigs_reflected.ml]. See comments by functions below and in - [ppx_sigs_reflected.mli] for details. *) + [sigs_reflected.mli] for details. *) open Ast_mapper open Asttypes @@ -92,7 +92,7 @@ module FunTyp = struct (* Given the name of a TyXML attribute function and a list of its argument - types, selects the attribute value parser (in module [Ppx_attribute_value]) + types, selects the attribute value parser (in module [Attribute_value]) that should be used for that attribute. *) let rec to_attribute_parser lang name = function | [] -> [%expr nowrap presence] @@ -261,7 +261,7 @@ let ocaml_attributes_to_renamed_attribute name attributes = (* Given a val declaration, determines whether it is for an element. If so, evaluates to the element's child assembler (from module - [Ppx_element_content]), list of attributes passed as labeled arguments, and + [Element_content]), list of attributes passed as labeled arguments, and markup name, if different from its TyXML name (for example, [object_] is [object] in markup). @@ -429,7 +429,7 @@ end let emit_module () = default_loc := Location.(in_file !input_name) ; begin if !attribute_parsers <> [] then [%str - open Ppx_attribute_value + open Attribute_value let attribute_parsers = [%e Combi.(list @@ tuple2 str expr) !attribute_parsers ] @@ -438,7 +438,7 @@ let emit_module () = let labeled_attributes = [%e Combi.(list @@ tuple3 str str expr) !labeled_attributes ] - open Ppx_element_content + open Element_content let element_assemblers = [%e Combi.(list @@ tuple2 str id) !element_assemblers ] diff --git a/ppx/register/jbuild b/ppx/register/jbuild new file mode 100644 index 000000000..926a9daa7 --- /dev/null +++ b/ppx/register/jbuild @@ -0,0 +1,8 @@ +(jbuild_version 1) + +(library + ((name tyxml_ppx_register) + (public_name tyxml-ppx) + (libraries (tyxml-ppx.internal)) + (kind ppx_rewriter) +)) diff --git a/ppx/ppx_tyxml_register.ml b/ppx/register/tyxml_ppx_register.ml similarity index 80% rename from ppx/ppx_tyxml_register.ml rename to ppx/register/tyxml_ppx_register.ml index 845e3a6dc..d27eb3c37 100644 --- a/ppx/ppx_tyxml_register.ml +++ b/ppx/register/tyxml_ppx_register.ml @@ -3,4 +3,4 @@ open Migrate_parsetree let () = Driver.register ~name:"tyxml" Versions.ocaml_405 - Ppx_tyxml.mapper + Tyxml_ppx.mapper diff --git a/ppx/ppx_sigs_reflected.mli b/ppx/sigs_reflected.mli similarity index 87% rename from ppx/ppx_sigs_reflected.mli rename to ppx/sigs_reflected.mli index 16b26310c..660e211a3 100644 --- a/ppx/ppx_sigs_reflected.mli +++ b/ppx/sigs_reflected.mli @@ -20,22 +20,20 @@ (** Signature of [Html_sigs_reflected] and [Svg_sigs_reflected] (but not [Html_types_reflected]). *) - - module type S = sig val attribute_parsers : - (string * (Ppx_common.lang -> Ppx_attribute_value.vparser)) list + (string * (Common.lang -> Attribute_value.vparser)) list (** Pairs [tyxml_attribute_name, wrapped_attribute_value_parser]. *) val renamed_attributes : (string * string * string list) list (** Triples [tyxml_attribute_name, markup_name, in_element_types]. *) val labeled_attributes : - (string * string * (Ppx_common.lang -> Ppx_attribute_value.vparser)) list + (string * string * (Common.lang -> Attribute_value.vparser)) list (** Triples [tyxml_element_name, label, wrapped_attribute_value_parser]. *) - val element_assemblers : (string * Ppx_element_content.assembler) list + val element_assemblers : (string * Element_content.assembler) list (** Pairs [tyxml_element_name, child_argument_assembler]. *) val renamed_elements : (string * string) list diff --git a/ppx/ppx_tyxml.ml b/ppx/tyxml_ppx.ml similarity index 90% rename from ppx/ppx_tyxml.ml rename to ppx/tyxml_ppx.ml index 99701dc32..f21ab5e70 100644 --- a/ppx/ppx_tyxml.ml +++ b/ppx/tyxml_ppx.ml @@ -20,7 +20,7 @@ open Asttypes open Parsetree -type lang = Ppx_common.lang = Html | Svg +type lang = Common.lang = Html | Svg module Loc = struct @@ -170,7 +170,7 @@ module Antiquot = struct let get loc s = if H.mem tbl s then H.find tbl s else - Ppx_common.error loc + Common.error loc "Internal error: This expression placeholder is not registered" let contains loc s = match Re.exec_opt re_id s with @@ -186,7 +186,7 @@ module Antiquot = struct match contains loc s with | `No -> () | `Yes e | `Whole e -> - Ppx_common.error e.pexp_loc + Common.error e.pexp_loc "OCaml expressions are not accepted as %s names" kind end @@ -194,9 +194,9 @@ end (** Building block to rebuild the output with expressions intertwined. *) let make_pcdata ~loc ~lang s = - let pcdata = Ppx_common.make ~loc lang "pcdata" in + let pcdata = Common.make ~loc lang "pcdata" in Ast_helper.Exp.apply ~loc pcdata - [Ppx_common.Label.nolabel, Ppx_common.string loc s] + [Common.Label.nolabel, Common.string loc s] (** Walk the text list to replace placeholders by OCaml expressions when appropriate. Use {!make_pcdata} on the rest. *) @@ -205,7 +205,7 @@ let make_text ~loc ~lang ss = let push_pcdata buf l = let s = Buffer.contents buf in Buffer.clear buf ; - if s = "" then l else Ppx_common.value (make_pcdata ~loc ~lang s) :: l + if s = "" then l else Common.value (make_pcdata ~loc ~lang s) :: l in let rec aux ~loc res = function | [] -> push_pcdata buf res @@ -214,17 +214,17 @@ let make_text ~loc ~lang ss = aux ~loc res t | `Delim g :: t -> let e = Antiquot.get loc @@ Re.get g 0 in - aux ~loc (Ppx_common.antiquot e :: push_pcdata buf res) t + aux ~loc (Common.antiquot e :: push_pcdata buf res) t in aux ~loc [] @@ Re.split_full Antiquot.re_id @@ String.concat "" ss let replace_attribute ~loc (attr,value) = Antiquot.assert_no_antiquot ~loc "attribute" attr ; match Antiquot.contains loc value with - | `No -> (attr, Ppx_common.value value) - | `Whole e -> (attr, Ppx_common.antiquot e) + | `No -> (attr, Common.value value) + | `Whole e -> (attr, Common.antiquot e) | `Yes _ -> - Ppx_common.error loc + Common.error loc "Mixing literals and OCaml expressions is not supported in attribute values" @@ -273,13 +273,13 @@ let ast_to_stream expressions = source, Loc.make_location_map strings let context_of_lang = function - | Ppx_common.Svg -> Some (`Fragment "svg") + | Common.Svg -> Some (`Fragment "svg") | Html -> None (** Given the payload of a [%html ...] or [%svg ...] expression, converts it to a TyXML expression representing the markup contained therein. *) -let markup_to_expr lang loc expr = +let markup_to_expr ?(simplify=true) lang loc expr = let context = context_of_lang lang in let input_stream, adjust_location = ast_to_stream expr in @@ -293,7 +293,7 @@ let markup_to_expr lang loc expr = let message = Markup.Error.to_string error |> String.capitalize_ascii in - Ppx_common.error loc "%s" message) + Common.error loc "%s" message) input_stream in let signals = Markup.signals parser in @@ -309,21 +309,21 @@ let markup_to_expr lang loc expr = assemble lang (node @ children) | Some (`Start_element (name, attributes)) -> - let newlang = Ppx_namespace.to_lang loc @@ fst name in + let newlang = Namespace.to_lang loc @@ fst name in let loc = get_loc () in let sub_children = assemble newlang [] in Antiquot.assert_no_antiquot ~loc "element" name ; let attributes = List.map (replace_attribute ~loc) attributes in let node = - Ppx_element.parse + Element.parse ~parent_lang:lang ~loc ~name ~attributes sub_children in - assemble lang (Ppx_common.Val node :: children) + assemble lang (Common.Val node :: children) | Some (`Comment s) -> let loc = get_loc () in - let node = Ppx_common.value @@ Ppx_element.comment ~loc ~lang s in + let node = Common.value @@ Element.comment ~loc ~lang s in assemble lang (node :: children) | Some (`Xml _ | `Doctype _ | `PI _) -> @@ -331,21 +331,21 @@ let markup_to_expr lang loc expr = in let l = - Ppx_element_content.filter_surrounding_whitespace @@ + Element_content.filter_surrounding_whitespace @@ assemble lang [] in match l with - | [ Val x | Antiquot x ] -> x - | l -> Ppx_common.list_wrap_value lang loc l + | [ Val x | Antiquot x ] when simplify -> x + | l -> Common.list_wrap_value lang loc l let markup_to_expr_with_implementation lang modname loc expr = match modname with | Some modname -> - let current_modname = Ppx_common.implementation lang in - Ppx_common.set_implementation lang modname ; + let current_modname = Common.implementation lang in + Common.set_implementation lang modname ; let res = markup_to_expr lang loc expr in - Ppx_common.set_implementation lang current_modname ; + Common.set_implementation lang current_modname ; res | _ -> markup_to_expr lang loc expr @@ -364,7 +364,7 @@ let get_modname ~loc len l = let loc = Loc.shrink loc ~xbegin:(len - String.length s) ~xend:0 in if l = [] then None else if not (List.for_all is_capitalized l) then - Ppx_common.error loc "This identifier is not a module name" + Common.error loc "This identifier is not a module name" else Some s let re_dot = Re.(compile @@ char '.') @@ -374,10 +374,10 @@ let dispatch_ext {txt ; loc} = match l with | "html" :: l | "tyxml" :: "html" :: l -> - Some (Ppx_common.Html, get_modname ~loc len l) + Some (Common.Html, get_modname ~loc len l) | "svg" :: l | "tyxml" :: "svg" :: l -> - Some (Ppx_common.Svg, get_modname ~loc len l) + Some (Common.Svg, get_modname ~loc len l) | _ -> None let application_to_list expr = @@ -390,7 +390,7 @@ open Ast_mapper open Ast_helper let error { txt ; loc } = - Ppx_common.error loc "Invalid payload for [%%%s]" txt + Common.error loc "Invalid payload for [%%%s]" txt let markup_cases ~lang ~modname cases = let f ({pc_rhs} as case) = diff --git a/ppx/ppx_tyxml.mli b/ppx/tyxml_ppx.mli similarity index 88% rename from ppx/ppx_tyxml.mli rename to ppx/tyxml_ppx.mli index fcc26e5e9..bbac87895 100644 --- a/ppx/ppx_tyxml.mli +++ b/ppx/tyxml_ppx.mli @@ -29,10 +29,18 @@ open Migrate_parsetree.Ast_405 type lang = Html | Svg val markup_to_expr : + ?simplify:bool -> lang -> Location.t -> Parsetree.expression list -> Parsetree.expression (** Given the payload of a [%html ...] or [%svg ...] expression, converts it to a TyXML expression representing the markup contained therein. *) -val mapper : _ -> _ -> Ast_mapper.mapper +val mapper : string list -> Ast_mapper.mapper + + +(** Utils *) + +module Loc : sig + val string_start : string option -> Location.t -> Lexing.position +end diff --git a/test/mustache.ml b/test/mustache.ml new file mode 100644 index 000000000..89a22120f --- /dev/null +++ b/test/mustache.ml @@ -0,0 +1,12 @@ +open Tyxml + +let%template f ={| +Hello {{name}} +You have just won {{value}} dollars! +{{#repo}} + {{foo}} {{name}} +{{/repo}} +{{^repo}} + No repos :( +{{/repo}} +|}