diff --git a/.gitignore b/.gitignore index a46e2b704..ea62da0ac 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ _log docs/build docs/source +ppx_elpi/tests/pp.exe diff --git a/dune b/dune index c5091d875..62948d5fa 100644 --- a/dune +++ b/dune @@ -3,8 +3,7 @@ (public_name elpi) (libraries elpi) (modules elpi_REPL) - (package elpi) -) + (package elpi)) (env (dev diff --git a/dune-project b/dune-project index 8ed5c34f8..eb76c4bea 100644 --- a/dune-project +++ b/dune-project @@ -1,3 +1,11 @@ (lang dune 2.8) (name elpi) (using menhir 2.0) + +(package + (name elpi)) + +(package + (name ocaml-elpi)) + +(package (name elpi-option-legacy-parser)) diff --git a/elpi.opam b/elpi.opam index abd79cec9..5906d033c 100644 --- a/elpi.opam +++ b/elpi.opam @@ -27,6 +27,8 @@ depends: [ "atdgen" {>= "2.10.0"} "atdts" {>= "2.10.0"} "odoc" {with-doc} + "ocaml-migrate-parsetree" + "stdcompat" ] synopsis: "ELPI - Embeddable λProlog Interpreter" description: """ diff --git a/ocaml-elpi/document_ocaml_ast_for_elpi.ml b/ocaml-elpi/document_ocaml_ast_for_elpi.ml new file mode 100644 index 000000000..3862c07d5 --- /dev/null +++ b/ocaml-elpi/document_ocaml_ast_for_elpi.ml @@ -0,0 +1,23 @@ +(* This simple file documents is Sys.argv.(1) the Elpi description of OCaml's AST *) + +open Elpi.API + +let builtin = let open BuiltIn in + declare ~file_name:(Sys.argv.(1)) + (Ocaml_elpi_ppx.Ocaml_ast_for_elpi.parsetree_declaration) + +let main () = + let elpi = Setup.init ~builtins:[builtin ; Elpi.Builtin.std_builtins] () in + BuiltIn.document_file builtin; + flush_all (); + let program = Parse.program ~elpi ~files:[] in + let program = Compile.program ~elpi ~flags:Compile.default_flags [program] in + let query = + let open Query in + compile program (Ast.Loc.initial "ppx") @@ + Query { predicate = "true"; arguments = N } in + if Compile.static_check ~checker:Elpi.Builtin.(default_checker ()) query then exit 0 + else (Printf.eprintf "document_ocaml_ast: generated elpi code does not type check"; exit 1) +;; + +main () diff --git a/ocaml-elpi/dune b/ocaml-elpi/dune new file mode 100644 index 000000000..5f31fda14 --- /dev/null +++ b/ocaml-elpi/dune @@ -0,0 +1,30 @@ + +(library + (name ocaml_elpi_ppx) + (public_name ocaml-elpi.ppx) + (libraries + ocaml-compiler-libs.shadow + ocaml-compiler-libs.common + compiler-libs.common + ocaml-migrate-parsetree + elpi ppxlib ppx_show.runtime) + (flags (:standard -open Ocaml_shadow -safe-string)) + (preprocess (pps ppx_show elpi.ppx)) + (modules ocaml_ast_for_elpi main_ocaml_elpi_rewriter) + (kind ppx_rewriter) +) + +(rule + (target ocaml_ast.elpi) + (mode promote) + (action (run ./document_ocaml_ast_for_elpi.exe %{target})) ) + +(executable + (name document_ocaml_ast_for_elpi) + (modules document_ocaml_ast_for_elpi) + (optional) + (libraries ocaml-elpi.ppx)) + +(env + (dev + (flags (:standard -warn-error -A)))) diff --git a/ocaml-elpi/main_ocaml_elpi_rewriter.ml b/ocaml-elpi/main_ocaml_elpi_rewriter.ml new file mode 100644 index 000000000..a6e8ff199 --- /dev/null +++ b/ocaml-elpi/main_ocaml_elpi_rewriter.ml @@ -0,0 +1,194 @@ +open Elpi.API +open Ocaml_ast_for_elpi + +let builtin = let open BuiltIn in + declare ~file_name:(Sys.argv.(1)) parsetree_declaration + +let mapper_src = {| +namespace ppx { + +pred map.list i:(A -> B -> prop), i:list A, o:list B. +map.list _ [] []. +map.list F [X|XS] [Y|YS] :- F X Y, map.list F XS YS. + +pred map.option i:(A -> B -> prop), i:option A, o:option B. +map.option _ none none. +map.option F (some X) (some Y) :- F X Y. + +pred map.pair i:(A1 -> B1 -> prop), i:(A2 -> B2 -> prop), i:pair A1 A2, o:pair B1 B2. +map.pair F1 F2 (pr X1 X2) (pr Y1 Y2) :- F1 X1 Y1, F2 X2 Y2. + +pred map.triple i:(A1 -> B1 -> prop), i:(A2 -> B2 -> prop), i:(A3 -> B3 -> prop), i:triple A1 A2 A3, o:triple B1 B2 B3. +map.triple F1 F2 F3 (triple X1 X2 X3) (triple Y1 Y2 Y3) :- F1 X1 Y1, F2 X2 Y2, F3 X3 Y3. + +pred map.quadruple i:(A1 -> B1 -> prop), i:(A2 -> B2 -> prop), i:(A3 -> B3 -> prop), i:(A4 -> B4 -> prop), i:quadruple A1 A2 A3 A4, o:quadruple B1 B2 B3 B4. +map.quadruple F1 F2 F3 F4 (quadruple X1 X2 X3 X4) (quadruple Y1 Y2 Y3 Y4) :- F1 X1 Y1, F2 X2 Y2, F3 X3 Y3, F4 X4 Y4. + +pred map.quintuple i:(A1 -> B1 -> prop), i:(A2 -> B2 -> prop), i:(A3 -> B3 -> prop), i:(A4 -> B4 -> prop), i:(A5 -> B5 -> prop), i:quintuple A1 A2 A3 A4 A5, o:quintuple B1 B2 B3 B4 B5. +map.quintuple F1 F2 F3 F4 F5 (quintuple X1 X2 X3 X4 X5) (quintuple Y1 Y2 Y3 Y4 Y5) :- F1 X1 Y1, F2 X2 Y2, F3 X3 Y3, F4 X4 Y4, F5 X5 Y5. + +} +|} + +let mapper = String.concat "\n" (mapper_src :: parsetree_mapper) + +let program_src = ref "" +let typecheck = ref false +let debug = ref (try ignore(Sys.getenv "DEBUG"); true with Not_found -> false) + +let map_structure s = + if !program_src = "" then begin + Printf.eprintf {| +ocaml-elpi.ppx: no program specified. Supported options: + --cookie 'program=\"some_file.elpi\"' source code of the rewriter (mandatory) + --cookie typecheck=1 typcheck the program + --cookie debug=1 print debug trace (also env DEBUG=1) +|}; + exit 1; + end; + let elpi = Setup.init ~builtins:[builtin;Elpi.Builtin.std_builtins] ~file_resolver:(Parse.std_resolver ~paths:[] ()) () in + BuiltIn.document_file builtin; + if !debug then + ignore @@ Setup.trace ["-trace-on";"tty";"stderr";"-trace-only";"user";"-trace-only-pred";"map";"-trace-at";"run";"1";"99999"]; + let program = Parse.program ~elpi ~files:[!program_src] in + let mapper = + Parse.program_from ~elpi ~loc:(Ast.Loc.initial "mapper") (Lexing.from_string mapper) in + let program = Compile.program ~elpi ~flags:Compile.default_flags [program;mapper] in + let query = + let open Query in + compile program (Ast.Loc.initial "ppx") @@ + CQuery ("map.structure", DC(structure,s,(QC(structure,"Result",NC))),new ctx_for_structure [],RawData.no_constraints) in + if !typecheck then begin + if not @@ Compile.static_check ~checker:Elpi.Builtin.(default_checker ()) query then begin + exit 1 + end + end; + let exe = Compile.optimize query in + match Execute.once exe with + | Execute.Success { output = (s,_); _ } -> s + | _ -> + Printf.eprintf "elpi.ocaml_ppx: rewriter %s failed" !program_src; + exit 1 +;; + +let erase_loc = + let open Ppxlib in + (* let open Ppxlib.Ast_pattern in *) + object + inherit [State.t] Ast_traverse.fold_map + method! location _ (st : State.t) = Ocaml_ast_for_elpi.dummy_location, st + method! location_stack l (st : State.t) = [], st + end +;; + +let expression_quotation ~depth state _loc s = + let e = Ppxlib.Parse.expression (Lexing.from_string s) in + let e, state = erase_loc#expression e state in + let ctx = new ctx_for_expression [] state in + let csts = RawData.no_constraints in + let state, x, gls = (expression).ContextualConversion.embed ~depth ctx csts state e in + assert(gls = []); + state, x + +let () = Quotation.register_named_quotation ~name:"expr" expression_quotation +let () = Quotation.set_default_quotation expression_quotation + +let pattern_quotation ~depth state _loc s = + let e = Ppxlib.Parse.pattern (Lexing.from_string s) in + let e, state = erase_loc#pattern e state in + let ctx = new ctx_for_pattern [] state in + let csts = RawData.no_constraints in + let state, x, gls = (pattern).ContextualConversion.embed ~depth ctx csts state e in + assert(gls = []); + state, x + +let () = Quotation.register_named_quotation ~name:"pat" pattern_quotation + +let type_quotation ~depth state _loc s = + let e = Ppxlib.Parse.core_type (Lexing.from_string s) in + let e, state = erase_loc#core_type e state in + let ctx = new ctx_for_core_type [] state in + let csts = RawData.no_constraints in + let state, x, gls = (core_type).ContextualConversion.embed ~depth ctx csts state e in + assert(gls = []); + state, x + +let () = Quotation.register_named_quotation ~name:"type" type_quotation + +let stri_quotation ~depth state _loc s = + let e = Ppxlib.Parse.toplevel_phrase (Lexing.from_string s) in + match e with + | Ptop_def [e] -> + let e, state = erase_loc#structure_item e state in + let ctx = new ctx_for_structure_item [] state in + let csts = RawData.no_constraints in + let state, x, gls = (structure_item).ContextualConversion.embed ~depth ctx csts state e in + assert(gls = []); + state, x + | Ptop_def _ -> + Ppxlib.Location.raise_errorf "{{:stri ...}} takes only one signature item, use {{:str ...}} for more" + | Ptop_dir { pdir_loc = loc; _ } -> + Ppxlib.Location.raise_errorf ~loc "{{:stri ...}} cannot contain a #directive" + +let () = Quotation.register_named_quotation ~name:"stri" stri_quotation + +let sigi_quotation ~depth state _loc s = + let e = Ppxlib.Parse.interface (Lexing.from_string s) in + match e with + | [e] -> + let e, state = erase_loc#signature_item e state in + let ctx = new ctx_for_signature_item [] state in + let csts = RawData.no_constraints in + let state, x, gls = (signature_item).ContextualConversion.embed ~depth ctx csts state e in + assert(gls = []); + state, x + | _ -> + Ppxlib.Location.raise_errorf "{{:sigi ...}} takes only one signature item, use {{:sig ...}} for more" + +let () = Quotation.register_named_quotation ~name:"sigi" stri_quotation + +let structure_quotation ~depth state _loc s = + let e = Ppxlib.Parse.implementation (Lexing.from_string s) in + let e, state = erase_loc#structure e state in + let ctx = new ctx_for_structure [] state in + let csts = RawData.no_constraints in + let state, x, gls = (structure).ContextualConversion.embed ~depth ctx csts state e in + assert(gls = []); + state, x + +let () = Quotation.register_named_quotation ~name:"str" structure_quotation + +let signature_quotation ~depth state _loc s = + let e = Ppxlib.Parse.interface (Lexing.from_string s) in + let e, state = erase_loc#signature e state in + let ctx = new ctx_for_signature [] state in + let csts = RawData.no_constraints in + let state, x, gls = (signature).ContextualConversion.embed ~depth ctx csts state e in + assert(gls = []); + state, x + +let () = Quotation.register_named_quotation ~name:"sig" signature_quotation + + +open Ppxlib + +let arg_program t = + match Driver.Cookies.get t "program" Ast_pattern.(estring __) with + | Some p -> program_src := p + | _ -> () + +let arg_typecheck t = + match Driver.Cookies.get t "typecheck" Ast_pattern.(__) with + | Some _ -> typecheck := true + | _ -> () + +let arg_debug t = + match Driver.Cookies.get t "debug" Ast_pattern.(__) with + | Some _ -> debug := true + | _ -> () + +let () = + Driver.Cookies.add_handler arg_program; + Driver.register_transformation + ~impl:map_structure + "elpi" diff --git a/ocaml-elpi/ocaml_ast.elpi b/ocaml-elpi/ocaml_ast.elpi new file mode 100644 index 000000000..7e58468e3 --- /dev/null +++ b/ocaml-elpi/ocaml_ast.elpi @@ -0,0 +1,630 @@ + + +% position +kind position type. +type position string -> int -> int -> int -> position. % position + +% location +kind location type. +type location position -> position -> bool -> location. % location + +typeabbrev location-stack (list location). % location_stack + +% loc +kind loc_ type -> type. +type loc A0 -> location -> loc_ A0. % loc + +% longident +kind longident type. +type lident string -> longident. % Lident +type ldot longident -> string -> longident. % Ldot +type lapply longident -> longident -> longident. % Lapply + +typeabbrev longident-loc (loc_ longident). % longident_loc + +% rec_flag +kind rec-flag type. +type nonrecursive rec-flag. % Nonrecursive +type recursive rec-flag. % Recursive + +% direction_flag +kind direction-flag type. +type upto direction-flag. % Upto +type downto direction-flag. % Downto + +% private_flag +kind private-flag type. +type private private-flag. % Private +type public private-flag. % Public + +% mutable_flag +kind mutable-flag type. +type immutable mutable-flag. % Immutable +type mutable mutable-flag. % Mutable + +% virtual_flag +kind virtual-flag type. +type virtual virtual-flag. % Virtual +type concrete virtual-flag. % Concrete + +% override_flag +kind override-flag type. +type override override-flag. % Override +type fresh override-flag. % Fresh + +% closed_flag +kind closed-flag type. +type closed_ closed-flag. % Closed +type open_ closed-flag. % Open + +typeabbrev label string. % label + +% arg_label +kind arg-label type. +type nolabel arg-label. % Nolabel +type labelled string -> arg-label. % Labelled +type optional string -> arg-label. % Optional + +% variance +kind variance type. +type covariant variance. % Covariant +type contravariant variance. % Contravariant +type novariance variance. % NoVariance + +% injectivity +kind injectivity type. +type injective injectivity. % Injective +type noinjectivity injectivity. % NoInjectivity + +% constant +kind constant_ type. +type pconst-integer string -> option char -> constant_. % Pconst_integer +type pconst-char char -> constant_. % Pconst_char +type pconst-string string -> location -> option string -> + constant_. % Pconst_string +type pconst-float string -> option char -> constant_. % Pconst_float + +% attribute +kind attribute type. +type attribute loc_ string -> payload -> location -> + attribute. % attribute + +typeabbrev extension (pair (loc_ string) payload). % extension + +typeabbrev attributes (list attribute). % attributes + +% payload +kind payload type. +type pstr structure -> payload. % PStr +type psig signature -> payload. % PSig +type ptyp core-type -> payload. % PTyp +type ppat pattern -> option expression -> payload. % PPat + +% core_type +kind core-type type. +type core-type core-type-desc -> location -> location-stack -> + attributes -> core-type. % core_type + +% core_type_desc +kind core-type-desc type. +type ptyp-any core-type-desc. % Ptyp_any +type ptyp-var string -> core-type-desc. % Ptyp_var +type ptyp-arrow arg-label -> core-type -> core-type -> + core-type-desc. % Ptyp_arrow +type ptyp-tuple list core-type -> core-type-desc. % Ptyp_tuple +type ptyp-constr longident-loc -> list core-type -> + core-type-desc. % Ptyp_constr +type ptyp-object list object-field -> closed-flag -> + core-type-desc. % Ptyp_object +type ptyp-class longident-loc -> list core-type -> + core-type-desc. % Ptyp_class +type ptyp-alias core-type -> string -> core-type-desc. % Ptyp_alias +type ptyp-variant list row-field -> closed-flag -> option (list label) -> + core-type-desc. % Ptyp_variant +type ptyp-poly list (loc_ string) -> core-type -> + core-type-desc. % Ptyp_poly +type ptyp-package package-type -> core-type-desc. % Ptyp_package +type ptyp-extension extension -> core-type-desc. % Ptyp_extension + +typeabbrev package-type (pair longident-loc (list (pair longident-loc core-type))). % package_type + +% row_field +kind row-field type. +type row-field row-field-desc -> location -> attributes -> + row-field. % row_field + +% row_field_desc +kind row-field-desc type. +type rtag loc_ label -> bool -> list core-type -> row-field-desc. % Rtag +type rinherit core-type -> row-field-desc. % Rinherit + +% object_field +kind object-field type. +type object-field object-field-desc -> location -> attributes -> + object-field. % object_field + +% object_field_desc +kind object-field-desc type. +type otag loc_ label -> core-type -> object-field-desc. % Otag +type oinherit core-type -> object-field-desc. % Oinherit + +% pattern +kind pattern type. +type pattern pattern-desc -> location -> location-stack -> attributes -> + pattern. % pattern + +% pattern_desc +kind pattern-desc type. +type ppat-any pattern-desc. % Ppat_any +type ppat-var loc_ string -> pattern-desc. % Ppat_var +type ppat-alias pattern -> loc_ string -> pattern-desc. % Ppat_alias +type ppat-constant constant_ -> pattern-desc. % Ppat_constant +type ppat-interval constant_ -> constant_ -> pattern-desc. % Ppat_interval +type ppat-tuple list pattern -> pattern-desc. % Ppat_tuple +type ppat-construct longident-loc -> + option (pair (list (loc_ string)) pattern) -> + pattern-desc. % Ppat_construct +type ppat-variant label -> option pattern -> pattern-desc. % Ppat_variant +type ppat-record list (pair longident-loc pattern) -> closed-flag -> + pattern-desc. % Ppat_record +type ppat-array list pattern -> pattern-desc. % Ppat_array +type ppat-or pattern -> pattern -> pattern-desc. % Ppat_or +type ppat-constraint pattern -> core-type -> + pattern-desc. % Ppat_constraint +type ppat-type longident-loc -> pattern-desc. % Ppat_type +type ppat-lazy pattern -> pattern-desc. % Ppat_lazy +type ppat-unpack loc_ (option string) -> pattern-desc. % Ppat_unpack +type ppat-exception pattern -> pattern-desc. % Ppat_exception +type ppat-extension extension -> pattern-desc. % Ppat_extension +type ppat-open longident-loc -> pattern -> pattern-desc. % Ppat_open + +% expression +kind expression type. +type expression expression-desc -> location -> location-stack -> + attributes -> expression. % expression + +% expression_desc +kind expression-desc type. +type pexp-ident longident-loc -> expression-desc. % Pexp_ident +type pexp-constant constant_ -> expression-desc. % Pexp_constant +type pexp-let rec-flag -> list value-binding -> expression -> + expression-desc. % Pexp_let +type pexp-function list case -> expression-desc. % Pexp_function +type pexp-fun arg-label -> option expression -> pattern -> expression -> + expression-desc. % Pexp_fun +type pexp-apply expression -> list (pair arg-label expression) -> + expression-desc. % Pexp_apply +type pexp-match expression -> list case -> expression-desc. % Pexp_match +type pexp-try expression -> list case -> expression-desc. % Pexp_try +type pexp-tuple list expression -> expression-desc. % Pexp_tuple +type pexp-construct longident-loc -> option expression -> + expression-desc. % Pexp_construct +type pexp-variant label -> option expression -> + expression-desc. % Pexp_variant +type pexp-record list (pair longident-loc expression) -> + option expression -> expression-desc. % Pexp_record +type pexp-field expression -> longident-loc -> + expression-desc. % Pexp_field +type pexp-setfield expression -> longident-loc -> expression -> + expression-desc. % Pexp_setfield +type pexp-array list expression -> expression-desc. % Pexp_array +type pexp-ifthenelse expression -> expression -> option expression -> + expression-desc. % Pexp_ifthenelse +type pexp-sequence expression -> expression -> + expression-desc. % Pexp_sequence +type pexp-while expression -> expression -> expression-desc. % Pexp_while +type pexp-for pattern -> expression -> expression -> direction-flag -> + expression -> expression-desc. % Pexp_for +type pexp-constraint expression -> core-type -> + expression-desc. % Pexp_constraint +type pexp-coerce expression -> option core-type -> core-type -> + expression-desc. % Pexp_coerce +type pexp-send expression -> loc_ label -> expression-desc. % Pexp_send +type pexp-new longident-loc -> expression-desc. % Pexp_new +type pexp-setinstvar loc_ label -> expression -> + expression-desc. % Pexp_setinstvar +type pexp-override list (pair (loc_ label) expression) -> + expression-desc. % Pexp_override +type pexp-letmodule loc_ (option string) -> module-expr -> expression -> + expression-desc. % Pexp_letmodule +type pexp-letexception extension-constructor -> expression -> + expression-desc. % Pexp_letexception +type pexp-assert expression -> expression-desc. % Pexp_assert +type pexp-lazy expression -> expression-desc. % Pexp_lazy +type pexp-poly expression -> option core-type -> + expression-desc. % Pexp_poly +type pexp-object class-structure -> expression-desc. % Pexp_object +type pexp-newtype loc_ string -> expression -> + expression-desc. % Pexp_newtype +type pexp-pack module-expr -> expression-desc. % Pexp_pack +type pexp-open open-declaration -> expression -> + expression-desc. % Pexp_open +type pexp-letop letop -> expression-desc. % Pexp_letop +type pexp-extension extension -> expression-desc. % Pexp_extension +type pexp-unreachable expression-desc. % Pexp_unreachable + +% case +kind case type. +type case pattern -> option expression -> expression -> case. % case + +% letop +kind letop type. +type letop binding-op -> list binding-op -> expression -> letop. % letop + +% binding_op +kind binding-op type. +type binding-op loc_ string -> pattern -> expression -> location -> + binding-op. % binding_op + +% value_description +kind value-description type. +type value-description loc_ string -> core-type -> list string -> + attributes -> location -> + value-description. % value_description + +% type_declaration +kind type-declaration type. +type type-declaration loc_ string -> + list (pair core-type (pair variance injectivity)) -> + list (triple core-type core-type location) -> + type-kind -> private-flag -> option core-type -> + attributes -> location -> + type-declaration. % type_declaration + +% type_kind +kind type-kind type. +type ptype-abstract type-kind. % Ptype_abstract +type ptype-variant list constructor-declaration -> + type-kind. % Ptype_variant +type ptype-record list label-declaration -> type-kind. % Ptype_record +type ptype-open type-kind. % Ptype_open + +% label_declaration +kind label-declaration type. +type label-declaration loc_ string -> mutable-flag -> core-type -> + location -> attributes -> + label-declaration. % label_declaration + +% constructor_declaration +kind constructor-declaration type. +type constructor-declaration loc_ string -> list (loc_ string) -> + constructor-arguments -> option core-type -> + location -> attributes -> + constructor-declaration. % constructor_declaration + +% constructor_arguments +kind constructor-arguments type. +type pcstr-tuple list core-type -> constructor-arguments. % Pcstr_tuple +type pcstr-record list label-declaration -> + constructor-arguments. % Pcstr_record + +% type_extension +kind type-extension type. +type type-extension longident-loc -> + list (pair core-type (pair variance injectivity)) -> + list extension-constructor -> private-flag -> + location -> attributes -> + type-extension. % type_extension + +% extension_constructor +kind extension-constructor type. +type extension-constructor loc_ string -> extension-constructor-kind -> + location -> attributes -> + extension-constructor. % extension_constructor + +% type_exception +kind type-exception type. +type type-exception extension-constructor -> location -> attributes -> + type-exception. % type_exception + +% extension_constructor_kind +kind extension-constructor-kind type. +type pext-decl list (loc_ string) -> constructor-arguments -> + option core-type -> extension-constructor-kind. % Pext_decl +type pext-rebind longident-loc -> + extension-constructor-kind. % Pext_rebind + +% class_type +kind class-type type. +type class-type class-type-desc -> location -> attributes -> + class-type. % class_type + +% class_type_desc +kind class-type-desc type. +type pcty-constr longident-loc -> list core-type -> + class-type-desc. % Pcty_constr +type pcty-signature class-signature -> class-type-desc. % Pcty_signature +type pcty-arrow arg-label -> core-type -> class-type -> + class-type-desc. % Pcty_arrow +type pcty-extension extension -> class-type-desc. % Pcty_extension +type pcty-open open-description -> class-type -> + class-type-desc. % Pcty_open + +% class_signature +kind class-signature type. +type class-signature core-type -> list class-type-field -> + class-signature. % class_signature + +% class_type_field +kind class-type-field type. +type class-type-field class-type-field-desc -> location -> attributes -> + class-type-field. % class_type_field + +% class_type_field_desc +kind class-type-field-desc type. +type pctf-inherit class-type -> class-type-field-desc. % Pctf_inherit +type pctf-val quadruple (loc_ label) mutable-flag virtual-flag core-type -> + class-type-field-desc. % Pctf_val +type pctf-method quadruple (loc_ label) private-flag virtual-flag core-type -> + class-type-field-desc. % Pctf_method +type pctf-constraint pair core-type core-type -> + class-type-field-desc. % Pctf_constraint +type pctf-attribute attribute -> class-type-field-desc. % Pctf_attribute +type pctf-extension extension -> class-type-field-desc. % Pctf_extension + +% class_infos +kind class-infos type -> type. +type class-infos virtual-flag -> + list (pair core-type (pair variance injectivity)) -> + loc_ string -> A0 -> location -> attributes -> + class-infos A0. % class_infos + +typeabbrev class-description (class-infos class-type). % class_description + +typeabbrev class-type-declaration (class-infos class-type). % class_type_declaration + +% class_expr +kind class-expr type. +type class-expr class-expr-desc -> location -> attributes -> + class-expr. % class_expr + +% class_expr_desc +kind class-expr-desc type. +type pcl-constr longident-loc -> list core-type -> + class-expr-desc. % Pcl_constr +type pcl-structure class-structure -> class-expr-desc. % Pcl_structure +type pcl-fun arg-label -> option expression -> pattern -> class-expr -> + class-expr-desc. % Pcl_fun +type pcl-apply class-expr -> list (pair arg-label expression) -> + class-expr-desc. % Pcl_apply +type pcl-let rec-flag -> list value-binding -> class-expr -> + class-expr-desc. % Pcl_let +type pcl-constraint class-expr -> class-type -> + class-expr-desc. % Pcl_constraint +type pcl-extension extension -> class-expr-desc. % Pcl_extension +type pcl-open open-description -> class-expr -> + class-expr-desc. % Pcl_open + +% class_structure +kind class-structure type. +type class-structure pattern -> list class-field -> + class-structure. % class_structure + +% class_field +kind class-field type. +type class-field class-field-desc -> location -> attributes -> + class-field. % class_field + +% class_field_desc +kind class-field-desc type. +type pcf-inherit override-flag -> class-expr -> option (loc_ string) -> + class-field-desc. % Pcf_inherit +type pcf-val triple (loc_ label) mutable-flag class-field-kind -> + class-field-desc. % Pcf_val +type pcf-method triple (loc_ label) private-flag class-field-kind -> + class-field-desc. % Pcf_method +type pcf-constraint pair core-type core-type -> + class-field-desc. % Pcf_constraint +type pcf-initializer expression -> class-field-desc. % Pcf_initializer +type pcf-attribute attribute -> class-field-desc. % Pcf_attribute +type pcf-extension extension -> class-field-desc. % Pcf_extension + +% class_field_kind +kind class-field-kind type. +type cfk-virtual core-type -> class-field-kind. % Cfk_virtual +type cfk-concrete override-flag -> expression -> + class-field-kind. % Cfk_concrete + +typeabbrev class-declaration (class-infos class-expr). % class_declaration + +% module_type +kind module-type type. +type module-type module-type-desc -> location -> attributes -> + module-type. % module_type + +% module_type_desc +kind module-type-desc type. +type pmty-ident longident-loc -> module-type-desc. % Pmty_ident +type pmty-signature signature -> module-type-desc. % Pmty_signature +type pmty-functor functor-parameter -> module-type -> + module-type-desc. % Pmty_functor +type pmty-with module-type -> list with-constraint -> + module-type-desc. % Pmty_with +type pmty-typeof module-expr -> module-type-desc. % Pmty_typeof +type pmty-extension extension -> module-type-desc. % Pmty_extension +type pmty-alias longident-loc -> module-type-desc. % Pmty_alias + +% functor_parameter +kind functor-parameter type. +type unit functor-parameter. % Unit +type named loc_ (option string) -> module-type -> + functor-parameter. % Named + +typeabbrev signature (list signature-item). % signature + +% signature_item +kind signature-item type. +type signature-item signature-item-desc -> location -> + signature-item. % signature_item + +% signature_item_desc +kind signature-item-desc type. +type psig-value value-description -> signature-item-desc. % Psig_value +type psig-type rec-flag -> list type-declaration -> + signature-item-desc. % Psig_type +type psig-typesubst list type-declaration -> + signature-item-desc. % Psig_typesubst +type psig-typext type-extension -> signature-item-desc. % Psig_typext +type psig-exception type-exception -> + signature-item-desc. % Psig_exception +type psig-module module-declaration -> signature-item-desc. % Psig_module +type psig-modsubst module-substitution -> + signature-item-desc. % Psig_modsubst +type psig-recmodule list module-declaration -> + signature-item-desc. % Psig_recmodule +type psig-modtype module-type-declaration -> + signature-item-desc. % Psig_modtype +type psig-modtypesubst module-type-declaration -> + signature-item-desc. % Psig_modtypesubst +type psig-open open-description -> signature-item-desc. % Psig_open +type psig-include include-description -> + signature-item-desc. % Psig_include +type psig-class list class-description -> + signature-item-desc. % Psig_class +type psig-class-type list class-type-declaration -> + signature-item-desc. % Psig_class_type +type psig-attribute attribute -> signature-item-desc. % Psig_attribute +type psig-extension extension -> attributes -> + signature-item-desc. % Psig_extension + +% module_declaration +kind module-declaration type. +type module-declaration loc_ (option string) -> module-type -> + attributes -> location -> + module-declaration. % module_declaration + +% module_substitution +kind module-substitution type. +type module-substitution loc_ string -> longident-loc -> attributes -> + location -> + module-substitution. % module_substitution + +% module_type_declaration +kind module-type-declaration type. +type module-type-declaration loc_ string -> option module-type -> + attributes -> location -> + module-type-declaration. % module_type_declaration + +% open_infos +kind open-infos type -> type. +type open-infos A0 -> override-flag -> location -> attributes -> + open-infos A0. % open_infos + +typeabbrev open-description (open-infos longident-loc). % open_description + +typeabbrev open-declaration (open-infos module-expr). % open_declaration + +% include_infos +kind include-infos type -> type. +type include-infos A0 -> location -> attributes -> + include-infos A0. % include_infos + +typeabbrev include-description (include-infos module-type). % include_description + +typeabbrev include-declaration (include-infos module-expr). % include_declaration + +% with_constraint +kind with-constraint type. +type pwith-type longident-loc -> type-declaration -> + with-constraint. % Pwith_type +type pwith-module longident-loc -> longident-loc -> + with-constraint. % Pwith_module +type pwith-modtype loc_ longident -> module-type -> + with-constraint. % Pwith_modtype +type pwith-modtypesubst loc_ longident -> module-type -> + with-constraint. % Pwith_modtypesubst +type pwith-typesubst longident-loc -> type-declaration -> + with-constraint. % Pwith_typesubst +type pwith-modsubst longident-loc -> longident-loc -> + with-constraint. % Pwith_modsubst + +% module_expr +kind module-expr type. +type module-expr module-expr-desc -> location -> attributes -> + module-expr. % module_expr + +% module_expr_desc +kind module-expr-desc type. +type pmod-ident longident-loc -> module-expr-desc. % Pmod_ident +type pmod-structure structure -> module-expr-desc. % Pmod_structure +type pmod-functor functor-parameter -> module-expr -> + module-expr-desc. % Pmod_functor +type pmod-apply module-expr -> module-expr -> + module-expr-desc. % Pmod_apply +type pmod-constraint module-expr -> module-type -> + module-expr-desc. % Pmod_constraint +type pmod-unpack expression -> module-expr-desc. % Pmod_unpack +type pmod-extension extension -> module-expr-desc. % Pmod_extension + +typeabbrev structure (list structure-item). % structure + +% structure_item +kind structure-item type. +type structure-item structure-item-desc -> location -> + structure-item. % structure_item + +% structure_item_desc +kind structure-item-desc type. +type pstr-eval expression -> attributes -> + structure-item-desc. % Pstr_eval +type pstr-value rec-flag -> list value-binding -> + structure-item-desc. % Pstr_value +type pstr-primitive value-description -> + structure-item-desc. % Pstr_primitive +type pstr-type rec-flag -> list type-declaration -> + structure-item-desc. % Pstr_type +type pstr-typext type-extension -> structure-item-desc. % Pstr_typext +type pstr-exception type-exception -> + structure-item-desc. % Pstr_exception +type pstr-module module-binding -> structure-item-desc. % Pstr_module +type pstr-recmodule list module-binding -> + structure-item-desc. % Pstr_recmodule +type pstr-modtype module-type-declaration -> + structure-item-desc. % Pstr_modtype +type pstr-open open-declaration -> structure-item-desc. % Pstr_open +type pstr-class list class-declaration -> + structure-item-desc. % Pstr_class +type pstr-class-type list class-type-declaration -> + structure-item-desc. % Pstr_class_type +type pstr-include include-declaration -> + structure-item-desc. % Pstr_include +type pstr-attribute attribute -> structure-item-desc. % Pstr_attribute +type pstr-extension extension -> attributes -> + structure-item-desc. % Pstr_extension + +% value_binding +kind value-binding type. +type value-binding pattern -> expression -> attributes -> location -> + value-binding. % value_binding + +% module_binding +kind module-binding type. +type module-binding loc_ (option string) -> module-expr -> attributes -> + location -> module-binding. % module_binding + +% toplevel_phrase +kind toplevel-phrase type. +type ptop-def structure -> toplevel-phrase. % Ptop_def +type ptop-dir toplevel-directive -> toplevel-phrase. % Ptop_dir + +% toplevel_directive +kind toplevel-directive type. +type toplevel-directive loc_ string -> option directive-argument -> + location -> + toplevel-directive. % toplevel_directive + +% directive_argument +kind directive-argument type. +type directive-argument directive-argument-desc -> location -> + directive-argument. % directive_argument + +% directive_argument_desc +kind directive-argument-desc type. +type pdir-string string -> directive-argument-desc. % Pdir_string +type pdir-int string -> option char -> directive-argument-desc. % Pdir_int +type pdir-ident longident -> directive-argument-desc. % Pdir_ident +type pdir-bool bool -> directive-argument-desc. % Pdir_bool + + + + diff --git a/ocaml-elpi/ocaml_ast_for_elpi.ml b/ocaml-elpi/ocaml_ast_for_elpi.ml new file mode 100644 index 000000000..7816c5414 --- /dev/null +++ b/ocaml-elpi/ocaml_ast_for_elpi.ml @@ -0,0 +1,1115 @@ +let parsetree_declaration = ref [] +let parsetree_mapper = ref [] +open Ppxlib_ast +open Ocaml_common + +let elpi_loc_of_location loc = + let open Location in + let open Lexing in + { + Elpi.API.Ast.Loc.source_name = loc.loc_end.pos_fname; + source_start = loc.loc_end.pos_cnum; + source_stop = loc.loc_end.pos_cnum; + line = loc.loc_end.pos_lnum; + line_starts_at = loc.loc_end.pos_bol; + } + +let dummy_position = + let open Lexing in + { + pos_fname = "$elpi"; + pos_lnum = 0; + pos_bol = 0; + pos_cnum = 0; + } + +let dummy_location = + let open Location in + { + loc_start = dummy_position; + loc_end = dummy_position; + loc_ghost = false + } + +let maybe_override_embed default = fun ~depth h c st e -> + let open Parsetree in + match e with + | ({ Location.txt = ("e"|"p"|"t"|"m"|"i"); _ }, PStr [{ pstr_desc = Pstr_eval ({ pexp_desc = Parsetree.Pexp_constant (Pconst_string(s,_,_)); pexp_loc = loc; _ },[]) ; _}]) -> + let loc = elpi_loc_of_location loc in + let st, x = Elpi.API.Quotation.lp ~depth st loc s in + st, x, [] + | e -> default ~depth h c st e + +let maybe_override_embed2 default = fun ~depth h c st e a -> + let open Parsetree in + match e with + | ({ Location.txt = ("e"|"p"|"t"|"m"|"i"); _ }, PStr [{ pstr_desc = Pstr_eval ({ pexp_desc = Parsetree.Pexp_constant (Pconst_string(s,_,_)); pexp_loc = loc; _ },[]) ; _}]) -> + let loc = elpi_loc_of_location loc in + let st, x = Elpi.API.Quotation.lp ~depth st loc s in + st, x, [] + | _ -> default ~depth h c st e a + +module Warnings = struct + include Warnings + + let pp_loc fmt vl = Location.print_loc fmt vl +end + +module Longident = struct + include Longident + let pp fmt vl = Format.fprintf fmt "%s" (String.concat "." (Longident.flatten vl)) +end +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) +(* *) +(* Copyright 1996 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(** Definition of the OCaml AST *) + + +(* This file is obtained by: + + - copying a subset of the corresponding ast_xxx.ml file from migrate-parsetree + (sub-modules Asttypes and Parsetree) + - adding the type definitions for position, location, loc and longident + - flattening all the modules + - removing Asttypes.constant (unused and conflicts with Parsetree.constant) + - renaming a few types: + - - Location.t -> location + - - Longident.t -> longident + - adding a type longident_loc = longident loc and replacing all the occurences of the + latter by the former. This is so that we can override iteration an the level of a + longident loc + - replacing all the (*IF_CURRENT = Foo.bar*) by: = Foo.bar + - removing the extra values at the end of the file + - replacing app [type ...] by [and ...] to make everything one recursive block + - adding [@@deriving_inline traverse][@@@end] at the end +*) + +(* Source code locations (ranges of positions), used in parsetree. *) + +type position = Lexing.position = + { pos_fname : string + ; pos_lnum : int + ; pos_bol : int + ; pos_cnum : int + } + +and location = Location.t = { + loc_start: position; + loc_end: position; + loc_ghost: bool; +} [@@elpi.embed fun default ~depth h c st start end_ ghost -> + if ghost = false && start = dummy_position && end_ = dummy_position then + let st, v = Elpi.API.FlexibleData.Elpi.make st in + st, Elpi.API.RawData.mkUnifVar v ~args: [] st, [] + else + default ~depth h c st start end_ ghost ] + [@@elpi.default_constructor_readback fun default ~depth h c st t -> + match Elpi.API.RawData.look ~depth t with + | Elpi.API.RawData.UnifVar _ -> st, dummy_location, [] + | _ -> default ~depth h c st t] + +and location_stack = location list + +(* Note on the use of Lexing.position in this module. + If [pos_fname = ""], then use [!input_name] instead. + If [pos_lnum = -1], then [pos_bol = 0]. Use [pos_cnum] and + re-parse the file to get the line and character numbers. + Else all fields are correct. + +*) +and 'a loc = 'a Location.loc = { + txt : 'a; + loc : location; +} +[@@elpi.type_code "loc_"] + +(* Long identifiers, used in parsetree. *) + +and longident = Longident.t = + Lident of string + | Ldot of longident * string + | Lapply of longident * longident +[@@deriving show, elpi { declaration = parsetree_declaration; mapper = parsetree_mapper }] + +type longident_loc = longident loc + +(** Auxiliary AST types used by parsetree and typedtree. *) + +and rec_flag = Asttypes.rec_flag = Nonrecursive | Recursive + +and direction_flag = Asttypes.direction_flag = Upto | Downto + +(* Order matters, used in polymorphic comparison *) +and private_flag = Asttypes.private_flag = Private | Public + +and mutable_flag = Asttypes.mutable_flag = Immutable | Mutable + +and virtual_flag = Asttypes.virtual_flag = Virtual | Concrete + +and override_flag = Asttypes.override_flag = Override | Fresh + +and closed_flag = Asttypes.closed_flag = Closed [@elpi.code "closed_"] | Open [@elpi.code "open_"] + +and label = string + +and arg_label = Asttypes.arg_label = + Nolabel + | Labelled of string (* label:T -> ... *) + | Optional of string (* ?label:T -> ... *) + +and variance = Asttypes.variance = + | Covariant + | Contravariant + | NoVariance + +and injectivity = Asttypes.injectivity = + | Injective + | NoInjectivity + + +(** Abstract syntax tree produced by parsing *) + +and constant = Parsetree.constant = + Pconst_integer of string * char option + (* 3 3l 3L 3n + + Suffixes [g-z][G-Z] are accepted by the parser. + Suffixes except 'l', 'L' and 'n' are rejected by the typechecker + *) + | Pconst_char of char + (* 'c' *) + | Pconst_string of string * location * string option + (* "constant" + {delim|other constant|delim} + *) + | Pconst_float of string * char option + (* 3.4 2e5 1.4e-4 + + Suffixes [g-z][G-Z] are accepted by the parser. + Suffixes are rejected by the typechecker. + *) +[@@elpi.type_code "constant_"] (* silly bug in Elpi, constant is also a builtin *) +(** {1 Extension points} *) + +and attribute = Parsetree.attribute = + { attr_name : string loc; + attr_payload : payload; + attr_loc : location; + } +(* [@id ARG] + [@@id ARG] + + Metadata containers passed around within the AST. + The compiler ignores unknown attributes. +*) + +and extension = string loc * payload +(* [%id ARG] + [%%id ARG] + + Sub-language placeholder -- rejected by the typechecker. +*) + +and attributes = attribute list + +and payload = Parsetree.payload = + | PStr of structure + | PSig of signature (* : SIG *) + | PTyp of core_type (* : T *) + | PPat of pattern * expression option (* ? P or ? P when E *) + +(** {1 Core language} *) + +(* Type expressions *) + +and core_type = Parsetree.core_type = + { + ptyp_desc: core_type_desc; + ptyp_loc: location; + ptyp_loc_stack: location_stack; + ptyp_attributes: attributes; (* ... [@id1] [@id2] *) + } + +and core_type_desc = Parsetree.core_type_desc = + | Ptyp_any + (* _ *) + | Ptyp_var of string + (* 'a *) + | Ptyp_arrow of arg_label * core_type * core_type + (* T1 -> T2 Simple + ~l:T1 -> T2 Labelled + ?l:T1 -> T2 Optional + *) + | Ptyp_tuple of core_type list + (* T1 * ... * Tn + + Invariant: n >= 2 + *) + | Ptyp_constr of longident_loc * core_type list + (* tconstr + T tconstr + (T1, ..., Tn) tconstr + *) + | Ptyp_object of object_field list * closed_flag + (* < l1:T1; ...; ln:Tn > (flag = Closed) + < l1:T1; ...; ln:Tn; .. > (flag = Open) + *) + | Ptyp_class of longident_loc * core_type list + (* #tconstr + T #tconstr + (T1, ..., Tn) #tconstr + *) + | Ptyp_alias of core_type * string + (* T as 'a *) + | Ptyp_variant of row_field list * closed_flag * label list option + (* [ `A|`B ] (flag = Closed; labels = None) + [> `A|`B ] (flag = Open; labels = None) + [< `A|`B ] (flag = Closed; labels = Some []) + [< `A|`B > `X `Y ](flag = Closed; labels = Some ["X";"Y"]) + *) + | Ptyp_poly of string loc list * core_type + (* 'a1 ... 'an. T + + Can only appear in the following context: + + - As the core_type of a Ppat_constraint node corresponding + to a constraint on a let-binding: let x : 'a1 ... 'an. T + = e ... + + - Under Cfk_virtual for methods (not values). + + - As the core_type of a Pctf_method node. + + - As the core_type of a Pexp_poly node. + + - As the pld_type field of a label_declaration. + + - As a core_type of a Ptyp_object node. + *) + + | Ptyp_package of package_type + (* (module S) *) + | Ptyp_extension of extension [@elpi.embed maybe_override_embed ] + (* [%id] *) + +and package_type = longident_loc * (longident_loc * core_type) list + (* + (module S) + (module S with type t1 = T1 and ... and tn = Tn) +*) + +and row_field = Parsetree.row_field = + { prf_desc : row_field_desc; + prf_loc : location; + prf_attributes : attributes; + } + +and row_field_desc = Parsetree.row_field_desc = + | Rtag of label loc * bool * core_type list + (* [`A] ( true, [] ) + [`A of T] ( false, [T] ) + [`A of T1 & .. & Tn] ( false, [T1;...Tn] ) + [`A of & T1 & .. & Tn] ( true, [T1;...Tn] ) + + - The 2nd field is true if the tag contains a + constant (empty) constructor. + - '&' occurs when several types are used for the same constructor + (see 4.2 in the manual) + + - TODO: switch to a record representation, and keep location + *) + | Rinherit of core_type + (* [ T ] *) + +and object_field = Parsetree.object_field = + { pof_desc : object_field_desc; + pof_loc : location; + pof_attributes : attributes; + } + +and object_field_desc = Parsetree.object_field_desc = + | Otag of label loc * core_type + | Oinherit of core_type + +(* Patterns *) + +and pattern = Parsetree.pattern = + { + ppat_desc: pattern_desc; + ppat_loc: location; + ppat_loc_stack: location_stack; + ppat_attributes: attributes; (* ... [@id1] [@id2] *) + } + +and pattern_desc = Parsetree.pattern_desc = + | Ppat_any + (* _ *) + | Ppat_var of string loc + (* x *) + | Ppat_alias of pattern * string loc + (* P as 'a *) + | Ppat_constant of constant + (* 1, 'a', "true", 1.0, 1l, 1L, 1n *) + | Ppat_interval of constant * constant + (* 'a'..'z' + + Other forms of interval are recognized by the parser + but rejected by the type-checker. *) + | Ppat_tuple of pattern list + (* (P1, ..., Pn) + + Invariant: n >= 2 + *) + | Ppat_construct of longident_loc * (string loc list * pattern) option + (* C None + C P Some P + C (P1, ..., Pn) Some (Ppat_tuple [P1; ...; Pn]) + *) + | Ppat_variant of label * pattern option + (* `A (None) + `A P (Some P) + *) + | Ppat_record of (longident_loc * pattern) list * closed_flag + (* { l1=P1; ...; ln=Pn } (flag = Closed) + { l1=P1; ...; ln=Pn; _} (flag = Open) + + Invariant: n > 0 + *) + | Ppat_array of pattern list + (* [| P1; ...; Pn |] *) + | Ppat_or of pattern * pattern + (* P1 | P2 *) + | Ppat_constraint of pattern * core_type + (* (P : T) *) + | Ppat_type of longident_loc + (* #tconst *) + | Ppat_lazy of pattern + (* lazy P *) + | Ppat_unpack of string option loc + (* (module P) + Note: (module P : S) is represented as + Ppat_constraint(Ppat_unpack, Ptyp_package) + *) + | Ppat_exception of pattern + (* exception P *) + | Ppat_extension of extension [@elpi.embed maybe_override_embed ] + (* [%id] *) + | Ppat_open of longident_loc * pattern + (* M.(P) *) + +(* Value expressions *) + +and expression = Parsetree.expression = + { + pexp_desc: expression_desc; + pexp_loc: location; + pexp_loc_stack: location_stack; + pexp_attributes: attributes; (* ... [@id1] [@id2] *) + } + +and expression_desc = Parsetree.expression_desc = + | Pexp_ident of longident_loc + (* x + M.x + *) + | Pexp_constant of constant + (* 1, 'a', "true", 1.0, 1l, 1L, 1n *) + | Pexp_let of rec_flag * value_binding list * expression + (* let P1 = E1 and ... and Pn = EN in E (flag = Nonrecursive) + let rec P1 = E1 and ... and Pn = EN in E (flag = Recursive) + *) + | Pexp_function of case list + (* function P1 -> E1 | ... | Pn -> En *) + | Pexp_fun of arg_label * expression option * pattern * expression + (* fun P -> E1 (Simple, None) + fun ~l:P -> E1 (Labelled l, None) + fun ?l:P -> E1 (Optional l, None) + fun ?l:(P = E0) -> E1 (Optional l, Some E0) + + Notes: + - If E0 is provided, only Optional is allowed. + - "fun P1 P2 .. Pn -> E1" is represented as nested Pexp_fun. + - "let f P = E" is represented using Pexp_fun. + *) + | Pexp_apply of expression * (arg_label * expression) list + (* E0 ~l1:E1 ... ~ln:En + li can be empty (non labeled argument) or start with '?' + (optional argument). + + Invariant: n > 0 + *) + | Pexp_match of expression * case list + (* match E0 with P1 -> E1 | ... | Pn -> En *) + | Pexp_try of expression * case list + (* try E0 with P1 -> E1 | ... | Pn -> En *) + | Pexp_tuple of expression list + (* (E1, ..., En) + + Invariant: n >= 2 + *) + | Pexp_construct of longident_loc * expression option + (* C None + C E Some E + C (E1, ..., En) Some (Pexp_tuple[E1;...;En]) + *) + | Pexp_variant of label * expression option + (* `A (None) + `A E (Some E) + *) + | Pexp_record of (longident_loc * expression) list * expression option + (* { l1=P1; ...; ln=Pn } (None) + { E0 with l1=P1; ...; ln=Pn } (Some E0) + + Invariant: n > 0 + *) + | Pexp_field of expression * longident_loc + (* E.l *) + | Pexp_setfield of expression * longident_loc * expression + (* E1.l <- E2 *) + | Pexp_array of expression list + (* [| E1; ...; En |] *) + | Pexp_ifthenelse of expression * expression * expression option + (* if E1 then E2 else E3 *) + | Pexp_sequence of expression * expression + (* E1; E2 *) + | Pexp_while of expression * expression + (* while E1 do E2 done *) + | Pexp_for of + pattern * expression * expression * direction_flag * expression + (* for i = E1 to E2 do E3 done (flag = Upto) + for i = E1 downto E2 do E3 done (flag = Downto) + *) + | Pexp_constraint of expression * core_type + (* (E : T) *) + | Pexp_coerce of expression * core_type option * core_type + (* (E :> T) (None, T) + (E : T0 :> T) (Some T0, T) + *) + | Pexp_send of expression * label loc + (* E # m *) + | Pexp_new of longident_loc + (* new M.c *) + | Pexp_setinstvar of label loc * expression + (* x <- 2 *) + | Pexp_override of (label loc * expression) list + (* {< x1 = E1; ...; Xn = En >} *) + | Pexp_letmodule of string option loc * module_expr * expression + (* let module M = ME in E *) + | Pexp_letexception of extension_constructor * expression + (* let exception C in E *) + | Pexp_assert of expression + (* assert E + Note: "assert false" is treated in a special way by the + type-checker. *) + | Pexp_lazy of expression + (* lazy E *) + | Pexp_poly of expression * core_type option + (* Used for method bodies. + + Can only be used as the expression under Cfk_concrete + for methods (not values). *) + | Pexp_object of class_structure + (* object ... end *) + | Pexp_newtype of string loc * expression + (* fun (type t) -> E *) + | Pexp_pack of module_expr + (* (module ME) + + (module ME : S) is represented as + Pexp_constraint(Pexp_pack, Ptyp_package S) *) + | Pexp_open of open_declaration * expression + (* M.(E) + let open M in E + let! open M in E *) + | Pexp_letop of letop + (* let* P = E in E + let* P = E and* P = E in E *) + | Pexp_extension of extension [@elpi.embed maybe_override_embed ] + (* [%id] *) + | Pexp_unreachable + (* . *) + +and case = Parsetree.case = (* (P -> E) or (P when E0 -> E) *) + { + pc_lhs: pattern; + pc_guard: expression option; + pc_rhs: expression; + } + +and letop = Parsetree.letop = + { let_ : binding_op; + ands : binding_op list; + body : expression; + } + +and binding_op = Parsetree.binding_op = + { pbop_op : string loc; + pbop_pat : pattern; + pbop_exp : expression; + pbop_loc : location; + } + +(* Value descriptions *) + +and value_description = Parsetree.value_description = + { + pval_name: string loc; + pval_type: core_type; + pval_prim: string list; + pval_attributes: attributes; (* ... [@@id1] [@@id2] *) + pval_loc: location; + } + + (* + val x: T (prim = []) + external x: T = "s1" ... "sn" (prim = ["s1";..."sn"]) +*) + +(* Type declarations *) + +and type_declaration = Parsetree.type_declaration = + { + ptype_name: string loc; + ptype_params: (core_type * (variance * injectivity)) list; + (* ('a1,...'an) t; None represents _*) + ptype_cstrs: (core_type * core_type * location) list; + (* ... constraint T1=T1' ... constraint Tn=Tn' *) + ptype_kind: type_kind; + ptype_private: private_flag; (* = private ... *) + ptype_manifest: core_type option; (* = T *) + ptype_attributes: attributes; (* ... [@@id1] [@@id2] *) + ptype_loc: location; + } + + (* + type t (abstract, no manifest) + type t = T0 (abstract, manifest=T0) + type t = C of T | ... (variant, no manifest) + type t = T0 = C of T | ... (variant, manifest=T0) + type t = {l: T; ...} (record, no manifest) + type t = T0 = {l : T; ...} (record, manifest=T0) + type t = .. (open, no manifest) +*) + +and type_kind = Parsetree.type_kind = + | Ptype_abstract + | Ptype_variant of constructor_declaration list + | Ptype_record of label_declaration list + (* Invariant: non-empty list *) + | Ptype_open + +and label_declaration = Parsetree.label_declaration = + { + pld_name: string loc; + pld_mutable: mutable_flag; + pld_type: core_type; + pld_loc: location; + pld_attributes: attributes; (* l : T [@id1] [@id2] *) + } + +(* { ...; l: T; ... } (mutable=Immutable) + { ...; mutable l: T; ... } (mutable=Mutable) + + Note: T can be a Ptyp_poly. +*) + +and constructor_declaration = Parsetree.constructor_declaration = + { + pcd_name: string loc; + pcd_vars: string loc list; + pcd_args: constructor_arguments; + pcd_res: core_type option; + pcd_loc: location; + pcd_attributes: attributes; (* C of ... [@id1] [@id2] *) + } + +and constructor_arguments = Parsetree.constructor_arguments = + | Pcstr_tuple of core_type list + | Pcstr_record of label_declaration list + + (* + | C of T1 * ... * Tn (res = None, args = Pcstr_tuple []) + | C: T0 (res = Some T0, args = []) + | C: T1 * ... * Tn -> T0 (res = Some T0, args = Pcstr_tuple) + | C of {...} (res = None, args = Pcstr_record) + | C: {...} -> T0 (res = Some T0, args = Pcstr_record) + | C of {...} as t (res = None, args = Pcstr_record) +*) + +and type_extension = Parsetree.type_extension = + { + ptyext_path: longident_loc; + ptyext_params: (core_type * (variance * injectivity)) list; + ptyext_constructors: extension_constructor list; + ptyext_private: private_flag; + ptyext_loc: location; + ptyext_attributes: attributes; (* ... [@@id1] [@@id2] *) + } + (* + type t += ... +*) + +and extension_constructor = Parsetree.extension_constructor = + { + pext_name: string loc; + pext_kind : extension_constructor_kind; + pext_loc : location; + pext_attributes: attributes; (* C of ... [@id1] [@id2] *) + } + +and type_exception = Parsetree.type_exception = + { ptyexn_constructor: extension_constructor; + ptyexn_loc: location; + ptyexn_attributes: attributes; + } + +and extension_constructor_kind = Parsetree.extension_constructor_kind = + Pext_decl of string loc list * constructor_arguments * core_type option + (* + | C of T1 * ... * Tn ([T1; ...; Tn], None) + | C: T0 ([], Some T0) + | C: T1 * ... * Tn -> T0 ([T1; ...; Tn], Some T0) + *) + | Pext_rebind of longident_loc + (* + | C = D + *) + +(** {1 Class language} *) + +(* Type expressions for the class language *) + +and class_type = Parsetree.class_type = + { + pcty_desc: class_type_desc; + pcty_loc: location; + pcty_attributes: attributes; (* ... [@id1] [@id2] *) + } + +and class_type_desc = Parsetree.class_type_desc = + | Pcty_constr of longident_loc * core_type list + (* c + ['a1, ..., 'an] c *) + | Pcty_signature of class_signature + (* object ... end *) + | Pcty_arrow of arg_label * core_type * class_type + (* T -> CT Simple + ~l:T -> CT Labelled l + ?l:T -> CT Optional l + *) + | Pcty_extension of extension [@elpi.embed maybe_override_embed ] + (* [%id] *) + | Pcty_open of open_description * class_type + (* let open M in CT *) + +and class_signature = Parsetree.class_signature = + { + pcsig_self: core_type; + pcsig_fields: class_type_field list; + } +(* object('selfpat) ... end + object ... end (self = Ptyp_any) +*) + +and class_type_field = Parsetree.class_type_field = + { + pctf_desc: class_type_field_desc; + pctf_loc: location; + pctf_attributes: attributes; (* ... [@@id1] [@@id2] *) + } + +and class_type_field_desc = Parsetree.class_type_field_desc = + | Pctf_inherit of class_type + (* inherit CT *) + | Pctf_val of (label loc * mutable_flag * virtual_flag * core_type) + (* val x: T *) + | Pctf_method of (label loc * private_flag * virtual_flag * core_type) + (* method x: T + + Note: T can be a Ptyp_poly. + *) + | Pctf_constraint of (core_type * core_type) + (* constraint T1 = T2 *) + | Pctf_attribute of attribute + (* [@@@id] *) + | Pctf_extension of extension [@elpi.embed maybe_override_embed ] + (* [%%id] *) + +and 'a class_infos = 'a Parsetree.class_infos = + { + pci_virt: virtual_flag; + pci_params: (core_type * (variance * injectivity)) list; + pci_name: string loc; + pci_expr: 'a; + pci_loc: location; + pci_attributes: attributes; (* ... [@@id1] [@@id2] *) + } +(* class c = ... + class ['a1,...,'an] c = ... + class virtual c = ... + + Also used for "class type" declaration. +*) + +and class_description = class_type class_infos + +and class_type_declaration = class_type class_infos + +(* Value expressions for the class language *) + +and class_expr = Parsetree.class_expr = + { + pcl_desc: class_expr_desc; + pcl_loc: location; + pcl_attributes: attributes; (* ... [@id1] [@id2] *) + } + +and class_expr_desc = Parsetree.class_expr_desc = + | Pcl_constr of longident_loc * core_type list + (* c + ['a1, ..., 'an] c *) + | Pcl_structure of class_structure + (* object ... end *) + | Pcl_fun of arg_label * expression option * pattern * class_expr + (* fun P -> CE (Simple, None) + fun ~l:P -> CE (Labelled l, None) + fun ?l:P -> CE (Optional l, None) + fun ?l:(P = E0) -> CE (Optional l, Some E0) + *) + | Pcl_apply of class_expr * (arg_label * expression) list + (* CE ~l1:E1 ... ~ln:En + li can be empty (non labeled argument) or start with '?' + (optional argument). + + Invariant: n > 0 + *) + | Pcl_let of rec_flag * value_binding list * class_expr + (* let P1 = E1 and ... and Pn = EN in CE (flag = Nonrecursive) + let rec P1 = E1 and ... and Pn = EN in CE (flag = Recursive) + *) + | Pcl_constraint of class_expr * class_type + (* (CE : CT) *) + | Pcl_extension of extension [@elpi.embed maybe_override_embed ] + (* [%id] *) + | Pcl_open of open_description * class_expr + (* let open M in CE *) + + +and class_structure = Parsetree.class_structure = + { + pcstr_self: pattern; + pcstr_fields: class_field list; + } +(* object(selfpat) ... end + object ... end (self = Ppat_any) +*) + +and class_field = Parsetree.class_field = + { + pcf_desc: class_field_desc; + pcf_loc: location; + pcf_attributes: attributes; (* ... [@@id1] [@@id2] *) + } + +and class_field_desc = Parsetree.class_field_desc = + | Pcf_inherit of override_flag * class_expr * string loc option + (* inherit CE + inherit CE as x + inherit! CE + inherit! CE as x + *) + | Pcf_val of (label loc * mutable_flag * class_field_kind) + (* val x = E + val virtual x: T + *) + | Pcf_method of (label loc * private_flag * class_field_kind) + (* method x = E (E can be a Pexp_poly) + method virtual x: T (T can be a Ptyp_poly) + *) + | Pcf_constraint of (core_type * core_type) + (* constraint T1 = T2 *) + | Pcf_initializer of expression + (* initializer E *) + | Pcf_attribute of attribute + (* [@@@id] *) + | Pcf_extension of extension [@elpi.embed maybe_override_embed ] + (* [%%id] *) + +and class_field_kind = Parsetree.class_field_kind = + | Cfk_virtual of core_type + | Cfk_concrete of override_flag * expression + +and class_declaration = class_expr class_infos + +(** {1 Module language} *) + +(* Type expressions for the module language *) + +and module_type = Parsetree.module_type = + { + pmty_desc: module_type_desc; + pmty_loc: location; + pmty_attributes: attributes; (* ... [@id1] [@id2] *) + } + +and module_type_desc = Parsetree.module_type_desc = + | Pmty_ident of longident_loc + (* S *) + | Pmty_signature of signature + (* sig ... end *) + | Pmty_functor of functor_parameter * module_type + (* functor(X : MT1) -> MT2 *) + | Pmty_with of module_type * with_constraint list + (* MT with ... *) + | Pmty_typeof of module_expr + (* module type of ME *) + | Pmty_extension of extension [@elpi.embed maybe_override_embed ] + (* [%id] *) + | Pmty_alias of longident_loc + (* (module M) *) + +and functor_parameter = Parsetree.functor_parameter = + | Unit + | Named of string option loc * module_type + +and signature = signature_item list + +and signature_item = Parsetree.signature_item = + { + psig_desc: signature_item_desc; + psig_loc: location; + } + +and signature_item_desc = Parsetree.signature_item_desc = + | Psig_value of value_description + (* + val x: T + external x: T = "s1" ... "sn" + *) + | Psig_type of rec_flag * type_declaration list + (* type t1 = ... and ... and tn = ... *) + | Psig_typesubst of type_declaration list + (* type t1 := ... and ... and tn := ... *) + | Psig_typext of type_extension + (* type t1 += ... *) + | Psig_exception of type_exception + (* exception C of T *) + | Psig_module of module_declaration + (* module X : MT *) + | Psig_modsubst of module_substitution + (* module X := M *) + | Psig_recmodule of module_declaration list + (* module rec X1 : MT1 and ... and Xn : MTn *) + | Psig_modtype of module_type_declaration + | Psig_modtypesubst of module_type_declaration + (* module type S = MT + module type S *) + | Psig_open of open_description + (* open X *) + | Psig_include of include_description + (* include MT *) + | Psig_class of class_description list + (* class c1 : ... and ... and cn : ... *) + | Psig_class_type of class_type_declaration list + (* class type ct1 = ... and ... and ctn = ... *) + | Psig_attribute of attribute + (* [@@@id] *) + | Psig_extension of extension * attributes [@elpi.embed maybe_override_embed2 ] + (* [%%id] *) + +and module_declaration = Parsetree.module_declaration = + { + pmd_name: string option loc; + pmd_type: module_type; + pmd_attributes: attributes; (* ... [@@id1] [@@id2] *) + pmd_loc: location; + } +(* S : MT *) + +and module_substitution = Parsetree.module_substitution = + { pms_name: string loc; + pms_manifest: longident_loc; + pms_attributes: attributes; + pms_loc: location; + } + +and module_type_declaration = Parsetree.module_type_declaration = + { + pmtd_name: string loc; + pmtd_type: module_type option; + pmtd_attributes: attributes; (* ... [@@id1] [@@id2] *) + pmtd_loc: location; + } +(* S = MT + S (abstract module type declaration, pmtd_type = None) +*) + +and 'a open_infos = 'a Parsetree.open_infos = + { popen_expr: 'a; + popen_override: override_flag; + popen_loc: location; + popen_attributes: attributes; + } + +and open_description = longident_loc open_infos +(* open! X - popen_override = Override (silences the 'used identifier + shadowing' warning) + open X - popen_override = Fresh +*) + +and open_declaration = module_expr open_infos + +and 'a include_infos = 'a Parsetree.include_infos = + { + pincl_mod: 'a; + pincl_loc: location; + pincl_attributes: attributes; + } + +and include_description = module_type include_infos +(* include MT *) + +and include_declaration = module_expr include_infos +(* include ME *) + +and with_constraint = Parsetree.with_constraint = + | Pwith_type of longident_loc * type_declaration + (* with type X.t = ... + + Note: the last component of the longident must match + the name of the type_declaration. *) + | Pwith_module of longident_loc * longident_loc + (* with module X.Y = Z *) + | Pwith_modtype of longident loc * module_type + | Pwith_modtypesubst of longident loc * module_type + | Pwith_typesubst of longident_loc * type_declaration + (* with type X.t := ..., same format as [Pwith_type] *) + | Pwith_modsubst of longident_loc * longident_loc + (* with module X.Y := Z *) + +(* Value expressions for the module language *) + +and module_expr = Parsetree.module_expr = + { + pmod_desc: module_expr_desc; + pmod_loc: location; + pmod_attributes: attributes; (* ... [@id1] [@id2] *) + } + +and module_expr_desc = Parsetree.module_expr_desc = + | Pmod_ident of longident_loc + (* X *) + | Pmod_structure of structure + (* struct ... end *) + | Pmod_functor of functor_parameter * module_expr + (* functor(X : MT1) -> ME *) + | Pmod_apply of module_expr * module_expr + (* ME1(ME2) *) + | Pmod_constraint of module_expr * module_type + (* (ME : MT) *) + | Pmod_unpack of expression + (* (val E) *) + | Pmod_extension of extension [@elpi.embed maybe_override_embed ] + (* [%id] *) + +and structure = structure_item list + +and structure_item = Parsetree.structure_item = + { + pstr_desc: structure_item_desc; + pstr_loc: location; + } + +and structure_item_desc = Parsetree.structure_item_desc = + | Pstr_eval of expression * attributes + (* E *) + | Pstr_value of rec_flag * value_binding list + (* let P1 = E1 and ... and Pn = EN (flag = Nonrecursive) + let rec P1 = E1 and ... and Pn = EN (flag = Recursive) + *) + | Pstr_primitive of value_description + (* val x: T + external x: T = "s1" ... "sn" *) + | Pstr_type of rec_flag * type_declaration list + (* type t1 = ... and ... and tn = ... *) + | Pstr_typext of type_extension + (* type t1 += ... *) + | Pstr_exception of type_exception + (* exception C of T + exception C = M.X *) + | Pstr_module of module_binding + (* module X = ME *) + | Pstr_recmodule of module_binding list + (* module rec X1 = ME1 and ... and Xn = MEn *) + | Pstr_modtype of module_type_declaration + (* module type S = MT *) + | Pstr_open of open_declaration + (* open X *) + | Pstr_class of class_declaration list + (* class c1 = ... and ... and cn = ... *) + | Pstr_class_type of class_type_declaration list + (* class type ct1 = ... and ... and ctn = ... *) + | Pstr_include of include_declaration + (* include ME *) + | Pstr_attribute of attribute + (* [@@@id] *) + | Pstr_extension of extension * attributes + (* [%%id] *) + +and value_binding = Parsetree.value_binding = + { + pvb_pat: pattern; + pvb_expr: expression; + pvb_attributes: attributes; + pvb_loc: location; + } + +and module_binding = Parsetree.module_binding = + { + pmb_name: string option loc; + pmb_expr: module_expr; + pmb_attributes: attributes; + pmb_loc: location; + } +(* X = ME *) + +(** {1 Toplevel} *) + +(* Toplevel phrases *) + +and toplevel_phrase = Parsetree.toplevel_phrase = + | Ptop_def of structure + | Ptop_dir of toplevel_directive + (* #use, #load ... *) + +and toplevel_directive = Parsetree.toplevel_directive = + { pdir_name : string loc; + pdir_arg : directive_argument option; + pdir_loc : location; + } +and directive_argument = Parsetree.directive_argument = + { pdira_desc : directive_argument_desc; + pdira_loc : location; + } + +and directive_argument_desc = Parsetree.directive_argument_desc = + | Pdir_string of string + | Pdir_int of string * char option + | Pdir_ident of longident + | Pdir_bool of bool +[@@deriving show, elpi { declaration = parsetree_declaration; mapper = parsetree_mapper }] + +let parsetree_declaration = !parsetree_declaration +let parsetree_mapper = !parsetree_mapper diff --git a/ocaml-elpi/tests/dune b/ocaml-elpi/tests/dune new file mode 100644 index 000000000..b653e1cc8 --- /dev/null +++ b/ocaml-elpi/tests/dune @@ -0,0 +1,27 @@ +(env + (dev + (flags (:standard -warn-error -A)))) + +(executable + (name pp) + (modules pp) + (libraries ocaml-elpi.ppx ppxlib)) + +(include dune.inc) + +(executable + (name gen_dune) + (libraries re) + (modules gen_dune) +) + +(rule + (targets dune.inc.gen) + (deps (:gen gen_dune.exe) (source_tree .)) + (action (with-stdout-to %{targets} (run %{gen}))) +) + +(rule + (alias runtest) + (action (diff dune.inc dune.inc.gen)) +) \ No newline at end of file diff --git a/ocaml-elpi/tests/dune.inc b/ocaml-elpi/tests/dune.inc new file mode 100644 index 000000000..e8d18fdcf --- /dev/null +++ b/ocaml-elpi/tests/dune.inc @@ -0,0 +1,15 @@ + +(rule + (targets test_swap.actual.ml) + (deps (:pp pp.exe) (:input test_swap.ml) ../ocaml_ast.elpi test_swap.elpi) + (action (run ./%{pp} --impl %{input} --cookie "program=\"test_swap.elpi\"" -o %{targets}))) + +(rule + (alias runtest) + (action (diff test_swap.expected.ml test_swap.actual.ml))) + +(executable + (name test_swap) + (modules test_swap) + (preprocess (pps ocaml-elpi.ppx -- --cookie "program=\"ocaml-elpi/tests/test_swap.elpi\""))) + diff --git a/ocaml-elpi/tests/gen_dune.ml b/ocaml-elpi/tests/gen_dune.ml new file mode 100644 index 000000000..7025fe2a6 --- /dev/null +++ b/ocaml-elpi/tests/gen_dune.ml @@ -0,0 +1,35 @@ + + +let output_stanzas filename = + let base = Filename.remove_extension filename in + Printf.printf {| +(rule + (targets %s.actual.ml) + (deps (:pp pp.exe) (:input %s.ml) ../ocaml_ast.elpi %s.elpi) + (action (run ./%%{pp} --impl %%{input} --cookie "program=\"%s.elpi\"" -o %%{targets}))) + +(rule + (alias runtest) + (action (diff %s.expected.ml %s.actual.ml))) + +(executable + (name %s) + (modules %s) + (preprocess (pps ocaml-elpi.ppx -- --cookie "program=\"ocaml-elpi/tests/%s.elpi\""))) + +|} + base base base base base base base base base + +let is_test filename = + Filename.check_suffix filename ".ml" && + not (Filename.check_suffix (Filename.remove_extension filename) ".pp") && + not (Filename.check_suffix (Filename.remove_extension filename) ".actual") && + not (Filename.check_suffix (Filename.remove_extension filename) ".expected") && + Re.Str.string_match (Re.Str.regexp_string "test_") filename 0 + +let () = + Sys.readdir "." + |> Array.to_list + |> List.sort String.compare + |> List.filter is_test + |> List.iter output_stanzas \ No newline at end of file diff --git a/ocaml-elpi/tests/pp.ml b/ocaml-elpi/tests/pp.ml new file mode 100644 index 000000000..e3cba4049 --- /dev/null +++ b/ocaml-elpi/tests/pp.ml @@ -0,0 +1 @@ +let () = Ppxlib.Driver.standalone () diff --git a/ocaml-elpi/tests/test_swap.elpi b/ocaml-elpi/tests/test_swap.elpi new file mode 100644 index 000000000..c9e7a750c --- /dev/null +++ b/ocaml-elpi/tests/test_swap.elpi @@ -0,0 +1,3 @@ + +map.value-binding (value-binding {{:pat ( [%e "P1"], [%e "P2" ] ) }} E X L) + (value-binding {{:pat ( [%e "P2"], [%e "P1" ] ) }} E X L) :- !. diff --git a/ocaml-elpi/tests/test_swap.expected.ml b/ocaml-elpi/tests/test_swap.expected.ml new file mode 100644 index 000000000..0d195515d --- /dev/null +++ b/ocaml-elpi/tests/test_swap.expected.ml @@ -0,0 +1 @@ +let (y, x) = (3, 4) diff --git a/ocaml-elpi/tests/test_swap.ml b/ocaml-elpi/tests/test_swap.ml new file mode 100644 index 000000000..2bc0d5cb6 --- /dev/null +++ b/ocaml-elpi/tests/test_swap.ml @@ -0,0 +1 @@ +let x, y = 3, 4 \ No newline at end of file diff --git a/ocaml-elpi/vendored/README.md b/ocaml-elpi/vendored/README.md new file mode 100644 index 000000000..c1672dcd4 --- /dev/null +++ b/ocaml-elpi/vendored/README.md @@ -0,0 +1 @@ +We need ppx_show in ast_ocaml_elpi.ml, but version 0.2 is not in opam \ No newline at end of file diff --git a/ocaml-elpi/vendored/ppx_show-0.2.0/.gitignore b/ocaml-elpi/vendored/ppx_show-0.2.0/.gitignore new file mode 100644 index 000000000..1d9165198 --- /dev/null +++ b/ocaml-elpi/vendored/ppx_show-0.2.0/.gitignore @@ -0,0 +1,5 @@ +*~ +/_build +*.install +*.opam +.merlin diff --git a/ocaml-elpi/vendored/ppx_show-0.2.0/ChangeLog b/ocaml-elpi/vendored/ppx_show-0.2.0/ChangeLog new file mode 100644 index 000000000..b3e91d596 --- /dev/null +++ b/ocaml-elpi/vendored/ppx_show-0.2.0/ChangeLog @@ -0,0 +1,7 @@ +# 2019-09-09, version 0.2.0 + +- Reverse the parenthesis and the constructor name for single argument, + to make more outputs parsable by OCaml (e.g. `Constructor (ref (42))`) + (Suggested by Sebastien Mondet). + +- Update to ppxlib 0.9.0 (OCaml 4.08 syntax tree). diff --git a/ocaml-elpi/vendored/ppx_show-0.2.0/LICENSE b/ocaml-elpi/vendored/ppx_show-0.2.0/LICENSE new file mode 100644 index 000000000..6aa4e2d26 --- /dev/null +++ b/ocaml-elpi/vendored/ppx_show-0.2.0/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2019, MARTINEZ Thierry +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ocaml-elpi/vendored/ppx_show-0.2.0/Makefile b/ocaml-elpi/vendored/ppx_show-0.2.0/Makefile new file mode 100644 index 000000000..104b21dd8 --- /dev/null +++ b/ocaml-elpi/vendored/ppx_show-0.2.0/Makefile @@ -0,0 +1,38 @@ +DUNE := dune +DUNE_PREFIX := _build/default + +tests_dir = tests +tests := $(notdir $(wildcard $(tests_dir)/*)) + +# All targets are phony targets since we want to rely on dune for +# dependency management. + +.PHONY : all + +all : + dune build + +ppx_show.opam : dune-project + dune build ppx_show.opam + +.PHONY : clean + +clean : + dune clean + +.PHONY : install + +install : + dune build @install + dune install + +.PHONY : tests +tests : $(tests) + +define foreach_test +.PHONY : $(test) +$(test) : + $(DUNE) build $(tests_dir)/$(test)/$(test).exe + $(DUNE_PREFIX)/$(tests_dir)/$(test)/$(test).exe +endef +$(foreach test,$(tests),$(eval $(foreach_test))) diff --git a/ocaml-elpi/vendored/ppx_show-0.2.0/README.md b/ocaml-elpi/vendored/ppx_show-0.2.0/README.md new file mode 100644 index 000000000..30da8d795 --- /dev/null +++ b/ocaml-elpi/vendored/ppx_show-0.2.0/README.md @@ -0,0 +1,7 @@ +# OCaml PPX deriver for deriving `show` based on `ppxlib`. + +This library reimplements the `show` plugin from [`ppx_deriving`] as a +`ppxlib` deriver. +In particular, this deriver works with OCaml 4.08.0. + +[`ppx_deriving`]: https://github.com/ocaml-ppx/ppx_deriving \ No newline at end of file diff --git a/ocaml-elpi/vendored/ppx_show-0.2.0/dune-project b/ocaml-elpi/vendored/ppx_show-0.2.0/dune-project new file mode 100644 index 000000000..78aee28f0 --- /dev/null +++ b/ocaml-elpi/vendored/ppx_show-0.2.0/dune-project @@ -0,0 +1,20 @@ +(lang dune 1.10) + +(generate_opam_files true) + +(license BSD) +(maintainers "Thierry Martinez ") +(authors "Thierry Martinez ") +(source (uri "git+https://gitlab.inria.fr/tmartine/ppx_show")) +(homepage "https://gitlab.inria.fr/tmartine/ppx_show") +(bug_reports "https://gitlab.inria.fr/tmartine/ppx_show") +(documentation "https://gitlab.inria.fr/tmartine/ppx_show") +(version "0.2.0") + +(package + (name ppx_show) + (synopsis "OCaml PPX deriver for deriving show based on ppxlib") + (depends + (ppxlib (>= 0.9.0)) + (stdcompat (>= 9)))) + diff --git a/ocaml-elpi/vendored/ppx_show-0.2.0/runtime/dune b/ocaml-elpi/vendored/ppx_show-0.2.0/runtime/dune new file mode 100644 index 000000000..d782856fa --- /dev/null +++ b/ocaml-elpi/vendored/ppx_show-0.2.0/runtime/dune @@ -0,0 +1,3 @@ +(library + (name ppx_show_runtime) + (public_name ppx_show.runtime)) \ No newline at end of file diff --git a/ocaml-elpi/vendored/ppx_show-0.2.0/runtime/ppx_show_runtime.ml b/ocaml-elpi/vendored/ppx_show-0.2.0/runtime/ppx_show_runtime.ml new file mode 100644 index 000000000..ff74a6658 --- /dev/null +++ b/ocaml-elpi/vendored/ppx_show-0.2.0/runtime/ppx_show_runtime.ml @@ -0,0 +1,29 @@ +module Format = Format + +module String = String + +module Int32 = Int32 + +module Int64 = Int64 + +module Nativeint = Nativeint + +module Bytes = Bytes + +module Lazy = Lazy + +let pp_list pp_item fmt items = + Format.pp_open_box fmt 1; + Format.pp_print_string fmt "["; + begin match items with + | [] -> () + | hd :: tl -> + pp_item fmt hd; + tl |> List.iter begin fun item -> + Format.pp_print_string fmt ";"; + Format.pp_print_space fmt (); + pp_item fmt item + end + end; + Format.pp_print_string fmt "]"; + Format.pp_close_box fmt () diff --git a/ocaml-elpi/vendored/ppx_show-0.2.0/runtime/ppx_show_runtime.mli b/ocaml-elpi/vendored/ppx_show-0.2.0/runtime/ppx_show_runtime.mli new file mode 100644 index 000000000..5664f8ccd --- /dev/null +++ b/ocaml-elpi/vendored/ppx_show-0.2.0/runtime/ppx_show_runtime.mli @@ -0,0 +1,17 @@ +module Format = Format + +module String = String + +module Int32 = Int32 + +module Int64 = Int64 + +module Nativeint = Nativeint + +module Bytes = Bytes + +module Lazy = Lazy + +val pp_list : + (Format.formatter -> 'a -> unit) -> + Format.formatter -> 'a list -> unit diff --git a/ocaml-elpi/vendored/ppx_show-0.2.0/src/dune b/ocaml-elpi/vendored/ppx_show-0.2.0/src/dune new file mode 100644 index 000000000..006779b07 --- /dev/null +++ b/ocaml-elpi/vendored/ppx_show-0.2.0/src/dune @@ -0,0 +1,7 @@ +(library + (public_name ppx_show) + (kind ppx_rewriter) + (preprocess (pps ppxlib.metaquot)) +; -warning 40: Constructor or label name used out of scope. (OCaml <=4.06.0) + (flags -open Stdcompat -w -40) + (libraries ppxlib stdcompat)) \ No newline at end of file diff --git a/ocaml-elpi/vendored/ppx_show-0.2.0/src/ppx_show.ml b/ocaml-elpi/vendored/ppx_show-0.2.0/src/ppx_show.ml new file mode 100644 index 000000000..d8efaf57c --- /dev/null +++ b/ocaml-elpi/vendored/ppx_show-0.2.0/src/ppx_show.ml @@ -0,0 +1,413 @@ +open Ppxlib + +let attr_nobuiltin : (core_type, unit -> unit) Ppxlib.Attribute.t = + Ppxlib.Attribute.declare "deriving.show.nobuiltin" Core_type + (Ppxlib.Ast_pattern.(pstr nil)) + Fun.id + +let attr_opaque : (core_type, unit -> unit) Ppxlib.Attribute.t = + Ppxlib.Attribute.declare "deriving.show.opaque" Core_type + (Ppxlib.Ast_pattern.(pstr nil)) + Fun.id + +let attr_printer : (core_type, expression) Ppxlib.Attribute.t = + Ppxlib.Attribute.declare "deriving.show.printer" Core_type + (Ppxlib.Ast_pattern.(single_expr_payload __)) + Fun.id + +let attr_polyprinter : (core_type, expression) Ppxlib.Attribute.t = + Ppxlib.Attribute.declare "deriving.show.polyprinter" Core_type + (Ppxlib.Ast_pattern.(single_expr_payload __)) + Fun.id + +let pp_open_box i : expression = + let loc = !Ast_helper.default_loc in + [%expr Ppx_show_runtime.Format.pp_open_box fmt + [%e (Ast_helper.Exp.constant (Ast_helper.Const.int i))]] + +let pp_close_box () : expression = + let loc = !Ast_helper.default_loc in + [%expr Ppx_show_runtime.Format.pp_close_box fmt ()] + +let pp_print_space () : expression = + let loc = !Ast_helper.default_loc in + [%expr Ppx_show_runtime.Format.pp_print_space fmt ()] + +let pp_print_string_expression e : expression = + let loc = !Ast_helper.default_loc in + [%expr Ppx_show_runtime.Format.pp_print_string fmt + [%e e]] + +let pp_print_string s = + pp_print_string_expression + (Ast_helper.Exp.constant (Ast_helper.Const.string s)) + +let pp_list_of_record ~path (fields : (string * expression list) list) + : expression list = + List.flatten [ + [pp_open_box 2; pp_print_string "{ "]; + List.flatten begin + Tools.separate [pp_print_string ";"; pp_print_space ()] + begin fields |> List.map begin fun (name, value) -> + let name = Tools.expand_path ~path name in + pp_open_box 0 :: pp_print_string (name ^ " =") :: pp_print_space () + :: value @ [pp_close_box ()] + end end + end; + [pp_print_space (); pp_print_string "}"; pp_close_box ()]] + +let pp_list_of_tuple (values : expression list list) : expression list = + List.flatten [ + [pp_open_box 1; pp_print_string "("]; + List.flatten begin + Tools.separate [pp_print_string ","; pp_print_space ()] + begin values |> List.map begin fun value -> + pp_open_box 0 :: value @ [pp_close_box ()] + end end + end; + [pp_print_string ")"; pp_close_box ()]] + +let binders_of_printers printers = + printers |> List.mapi begin fun i printer -> + let binder = "x" ^ string_of_int i in + Tools.pat_var_of_string binder, printer (Tools.ident_of_string binder) + end |> List.split + +type constructor_arguments = + | No_argument + | Singleton of (expression -> expression list) + | Tuple of (expression -> expression list) list + +type kind = + | Construct + | Variant + +let pp_cases_of_cases ?(path = []) kind cases = + cases |> List.map begin fun (constr, arguments) -> + let pat, constr = + match kind with + | Construct -> + let loc = !Ast_helper.default_loc in + Ast_helper.Pat.construct { loc; txt = Lident constr }, + Tools.expand_path ~path constr + | Variant -> + Ast_helper.Pat.variant constr, "`" ^ constr in + let arguments, printers = + match arguments with + | No_argument -> None, [pp_print_string constr] + | Singleton printer -> + let binder = "x" in + Some (Tools.pat_var_of_string binder), + begin + pp_open_box 1 :: + pp_print_string (constr ^ " (") :: + printer (Tools.ident_of_string binder) @ + [pp_print_string ")"; pp_close_box ()] + end + | Tuple printers -> + let binders, printers = binders_of_printers printers in + Some (Ast_helper.Pat.tuple binders), + begin + pp_open_box 0 :: + pp_print_string constr :: + pp_print_space () :: + pp_list_of_tuple printers @ + [pp_close_box ()] + end in + Ast_helper.Exp.case (pat arguments) (Tools.seq printers) + end + +let rec pp_list_of_type (ty : core_type) (value : expression) + : expression list = + let loc = ty.ptyp_loc in + match Ppxlib.Attribute.get attr_printer ty with + | Some printer -> + [Ast_helper.Exp.apply printer [Nolabel, [%expr fmt]; Nolabel, value]] + | None -> + if Ppxlib.Attribute.get attr_opaque ty = None then + match ty with + | { ptyp_desc = Ptyp_any; _ } -> + [pp_print_string "_"] + | { ptyp_desc = Ptyp_arrow _; _ } -> + [pp_print_string ""] + | { ptyp_desc = Ptyp_tuple types; _ } -> + let binders, printers = + binders_of_printers (types |> List.map pp_list_of_type) in + [Ast_helper.Exp.let_ Nonrecursive [Ast_helper.Vb.mk (Ast_helper.Pat.tuple binders) value] + (Tools.seq (pp_list_of_tuple printers))] + | { ptyp_desc = Ptyp_variant (fields, _, _); _ } -> + let cases = + fields |> List.map begin fun (field : row_field) -> + match field.prf_desc with + | Rtag (label, true, _) -> + label.txt, No_argument + | Rtag (label, false, ty :: _) -> + label.txt, Singleton (pp_list_of_type ty) + | _ -> + failwith "Not implemented open tag" + end in + [Ast_helper.Exp.match_ value (pp_cases_of_cases Variant cases)] + | { ptyp_desc = Ptyp_var x; _ } -> + [Ast_helper.Exp.apply + (Ast_helper.Exp.ident { loc; txt = Lident (Tools.poly_var x)}) + [Nolabel, [%expr fmt]; Nolabel, value]] + | { ptyp_desc = Ptyp_constr (constr, arguments); _ } -> + begin match + if Ppxlib.Attribute.get attr_nobuiltin ty = None then + pp_list_of_builtin_type ty value + else + [] + with + | [] -> + let printer = + match Ppxlib.Attribute.get attr_polyprinter ty with + | None -> + Ast_helper.Exp.ident (constr |> + Tools.map_loc (Tools.mangle_lid (Prefix "pp"))) + | Some printer -> printer in + [Ast_helper.Exp.apply printer + begin + begin arguments |> List.map begin + fun ty : (arg_label * expression) -> + Nolabel, [%expr fun fmt x -> + [%e Tools.seq (pp_list_of_type ty [%expr x])]] + end end @ + [Nolabel, [%expr fmt]; Nolabel, value] + end] + | list -> list + end + | _ -> + Location.raise_errorf "ppx_show: Not implemented %a" + (Pprintast.core_type) ty + else + [pp_print_string ""] + +and pp_list_of_builtin_type (ty : core_type) (value : expression) + : expression list = + let loc = ty.ptyp_loc in + match ty with + | [%type: unit] -> [pp_print_string "()"] + | [%type: int] -> + [[%expr Ppx_show_runtime.Format.pp_print_int fmt [%e value]]] + | [%type: int32] -> + [pp_print_string_expression + [%expr Ppx_show_runtime.Int32.to_string [%e value]]; + pp_print_string "l"] + | [%type: int64] -> + [pp_print_string_expression + [%expr Ppx_show_runtime.Int64.to_string [%e value]]; + pp_print_string "L"] + | [%type: nativeint] -> + [pp_print_string_expression + [%expr Ppx_show_runtime.Nativeint.to_string [%e value]]; + pp_print_string "n"] + | [%type: float] -> + [[%expr Ppx_show_runtime.Format.pp_print_float fmt [%e value]]] + | [%type: bool] -> + [[%expr Ppx_show_runtime.Format.pp_print_bool fmt [%e value]]] + | [%type: char] -> + [[%expr Ppx_show_runtime.Format.pp_print_char fmt [%e value]]] + | [%type: string] -> + [pp_print_string "\""; + pp_print_string_expression + [%expr Ppx_show_runtime.String.escaped [%e value]]; + pp_print_string "\""] + | [%type: bytes] -> + [pp_print_string "\""; + pp_print_string_expression + [%expr Ppx_show_runtime.String.escaped + (Ppx_show_runtime.Bytes.to_string [%e value])]; + pp_print_string "\""] + | [%type: [%t? ty] ref] -> + pp_open_box 1 :: pp_print_string "ref (" :: + pp_list_of_type ty [%expr ! [%e value]] @ + [pp_print_string ")"; pp_close_box ()] + | [%type: [%t? ty] Lazy.t] -> + [pp_open_box 1; pp_print_string "lazy ("; + [%expr + if Ppx_show_runtime.Lazy.is_val [%e value] then + [%e Tools.seq (pp_list_of_type ty + [%expr Ppx_show_runtime.Lazy.force [%e value]])] + else + Ppx_show_runtime.Format.pp_print_string fmt ""]; + pp_print_string ")"; pp_close_box ()] + | [%type: [%t? sub] option] -> + [Ast_helper.Exp.match_ + (Ast_helper.Exp.constraint_ value [%type: _ option]) begin + pp_cases_of_cases Construct [ + "None", No_argument; + "Some", Singleton (fun x -> pp_list_of_type sub x)] + end] + | [%type: ([%t? ok], [%t? error]) result] -> + [Ast_helper.Exp.match_ + (Ast_helper.Exp.constraint_ value [%type: (_, _) result]) begin + pp_cases_of_cases Construct [ + "Ok", Singleton (fun x -> pp_list_of_type ok x); + "Error", Singleton (fun x -> pp_list_of_type error x)] + end] + | [%type: [%t? ty] list] -> + [[%expr Ppx_show_runtime.pp_list (fun fmt x -> + [%e Tools.seq (pp_list_of_type ty [%expr x])]) fmt [%e value]]] + | _ -> [] + +let pp_list_of_label_declaration_list ?(path = []) + (labels : label_declaration list) + (value : expression) : expression list = + let fields = labels |> List.map begin fun (label : label_declaration) -> + label.pld_name.txt, + pp_list_of_type label.pld_type (Ast_helper.Exp.field value + (label.pld_name |> Tools.map_loc (fun name : Longident.t -> + Lident name))) + end in + pp_list_of_record ~path fields + +let pp_of_variant ~with_path (constrs : constructor_declaration list) + (value : expression) : expression = + let cases = + constrs |> List.map begin fun (constr : constructor_declaration) -> + constr.pcd_name.txt, + match constr.pcd_args with + | Pcstr_tuple [] -> No_argument + | Pcstr_tuple [ty] -> Singleton (pp_list_of_type ty) + | Pcstr_tuple list -> + Tuple (list |> List.map pp_list_of_type) + | Pcstr_record labels -> + Singleton (pp_list_of_label_declaration_list labels) + end in + let path = + match with_path with + | None -> [] + | Some path -> path in + Ast_helper.Exp.match_ value (pp_cases_of_cases ~path Construct cases) + +let pp_of_record ~with_path (labels : label_declaration list) + (value : expression) : expression = + let path = + match with_path with + | None -> [] + | Some path -> path in + Tools.seq (pp_list_of_label_declaration_list ~path labels value) + +let pp = "pp" + +let show = "show" + +let fmt_ty (ty : core_type) : core_type = + let loc = ty.ptyp_loc in + [%type: Ppx_show_runtime.Format.formatter -> [%t ty] -> unit] + +let type_of_type_decl (td : type_declaration) : core_type = + let loc = td.ptype_loc in + Ast_helper.with_default_loc loc begin fun () -> + let ty = Tools.core_type_of_type_decl td in + Tools.poly_arrow_of_type_decl fmt_ty td (fmt_ty ty) + end + +let pp_of_type_decl ~with_path (td : type_declaration) : value_binding = + let with_path = + match with_path with + | None -> None + | Some path -> Some (Tools.path_of_type_decl ~path td) in + let loc = td.ptype_loc in + Ast_helper.with_default_loc loc begin fun () -> + let name = Tools.mangle_type_decl (Prefix pp) td in + let printer : expression = + match td.ptype_kind with + | Ptype_abstract -> + begin match td.ptype_manifest with + | None -> + Location.raise_errorf ~loc + "show cannot be derived for fully abstract types" + | Some ty -> + Tools.seq (pp_list_of_type ty [%expr x]) + end + | Ptype_variant constrs -> + pp_of_variant ~with_path constrs [%expr x] + | Ptype_record labels -> + pp_of_record ~with_path labels [%expr x] + | Ptype_open -> + Location.raise_errorf ~loc "show cannot be derived for open types" in + let printer : expression = + [%expr fun fmt x -> + [%e printer]] in + let printer = Tools.poly_fun_of_type_decl td printer in + let constraint_ = + Ast_helper.Typ.poly (td.ptype_params |> List.map begin + fun (ty, _) : string Location.loc -> + { loc = ty.ptyp_loc; txt = Tools.var_of_type ty } + end) + (type_of_type_decl td) in + Ast_helper.Vb.mk + ~attrs:[Ast_helper.Attr.mk + { loc; txt = "ocaml.warning" } (PStr [%str "-39"])] + (Ast_helper.Pat.constraint_ (Ast_helper.Pat.var name) constraint_) printer + end + +let show_of_type_decl (td : type_declaration) : value_binding = + let loc = td.ptype_loc in + Ast_helper.with_default_loc loc begin fun () -> + let name = Tools.mangle_type_decl (Prefix show) td in + let printer_name = Tools.mangle_type_decl (Prefix pp) td in + let printer : expression = + Tools.poly_apply_of_type_decl td (Tools.ident_of_str printer_name) in + let printer : expression = + [%expr fun x -> + Ppx_show_runtime.Format.asprintf "@[%a@]" [%e printer] x] in + let printer = Tools.poly_fun_of_type_decl td printer in + Ast_helper.Vb.mk (Ast_helper.Pat.var name) printer + end + +let pp_type_of_type_decl (td : type_declaration) : value_description = + let loc = td.ptype_loc in + Ast_helper.with_default_loc loc begin fun () -> + let name = Tools.mangle_type_decl (Prefix pp) td in + Ast_helper.Val.mk name (type_of_type_decl td) + end + +let show_type_of_type_decl (td : type_declaration) : value_description = + let loc = td.ptype_loc in + Ast_helper.with_default_loc loc begin fun () -> + let name = Tools.mangle_type_decl (Prefix show) td in + let ty = Tools.core_type_of_type_decl td in + let ty = + Tools.poly_arrow_of_type_decl fmt_ty td + (Ast_helper.Typ.arrow Nolabel ty [%type: string]) in + Ast_helper.Val.mk name ty + end + +let make_str ~loc ~path (rec_flag, tds) (with_path : expression option) + : structure = + let with_path = + match with_path with + | Some [%expr false] -> None + | _ -> + match String.split_on_char '.' (Filename.basename path) with + | filename :: "ml" :: path + | filename :: _ :: "ml" :: path -> + Some (String.capitalize_ascii filename :: path) + | _ -> prerr_endline path; assert false in + let vbs = tds |> List.map (pp_of_type_decl ~with_path) in + [Ast_helper.Str.value ~loc rec_flag vbs; + Ast_helper.Str.value ~loc Nonrecursive (tds |> List.map show_of_type_decl)] + +let str_type_decl = + Ppxlib.Deriving.Generator.make + Ppxlib.Deriving.Args.(empty +> + arg "with_path" __) + make_str + +let make_sig ~loc ~path:_ (_rec_flag, tds) : signature = + let vds = tds |> List.map pp_type_of_type_decl in + let shows = tds |> List.map show_type_of_type_decl in + (vds |> List.map (fun vd -> Ast_helper.Sig.value ~loc vd)) @ + (shows |> List.map (fun vd -> Ast_helper.Sig.value ~loc vd)) + +let sig_type_decl = Ppxlib.Deriving.Generator.make_noarg make_sig + +let extension ~loc ~path:_ ty : expression = + let binder = "x" in + [%expr fun fmt x -> + [%e Tools.seq (pp_list_of_type ty (Tools.ident_of_string binder))]] + +let deriver = + Ppxlib.Deriving.add "show" ~str_type_decl ~sig_type_decl ~extension diff --git a/ocaml-elpi/vendored/ppx_show-0.2.0/src/tools.ml b/ocaml-elpi/vendored/ppx_show-0.2.0/src/tools.ml new file mode 100644 index 000000000..cef10bc86 --- /dev/null +++ b/ocaml-elpi/vendored/ppx_show-0.2.0/src/tools.ml @@ -0,0 +1,117 @@ +open Ppxlib + +let rec rev_map_append f list accu = + match list with + | [] -> accu + | hd :: tl -> rev_map_append f tl (List.rev_append (f hd) accu) + +let flatten_map f list = + List.rev (rev_map_append f list []) + +let map_loc (f : 'a -> 'b) ({ loc; txt } : 'a loc) : 'b loc = + { loc; txt = f txt } + +type affix = + | Prefix of string + | Suffix of string + | PrefixSuffix of string * string + +let mangle ?(fixpoint = "t") affix name = + if name = fixpoint then + match affix with + | Prefix x | Suffix x -> x + | PrefixSuffix (x, y) -> x ^ "_" ^ y + else + match affix with + | Prefix x -> x ^ "_" ^ name + | Suffix x -> name ^ "_" ^ x + | PrefixSuffix (x, y) -> x ^ "_" ^ name ^ "_" ^ y + +let mangle_type_decl ?fixpoint affix (td : type_declaration) : string loc = + map_loc (mangle ?fixpoint affix) td.ptype_name + +let mangle_lid ?fixpoint affix (lid : Longident.t) : Longident.t = + match lid with + | Lident s -> Lident (mangle ?fixpoint affix s) + | Ldot (p, s) -> Ldot (p, mangle ?fixpoint affix s) + | Lapply _ -> invalid_arg "mangle_lid" + +let seq ?(loc = !Ast_helper.default_loc) list : expression = + match List.rev list with + | [] -> [%expr ()] + | hd :: tl -> + List.fold_left begin fun acc item : expression -> + [%expr [%e item]; [%e acc]] + end hd tl + +let separate separator l = + match l with + | [] | [_] -> l + | hd :: tl -> + let revl = + List.fold_left begin fun acc x -> + x :: separator :: acc + end [] tl in + hd :: List.rev revl + +let poly_var x = + "poly_" ^ x + +let var_of_type (ty : core_type) = + match ty.ptyp_desc with + | Ptyp_var x -> x + | _ -> invalid_arg "var_of_type" + +let poly_fun_of_type_decl (td : type_declaration) (e : expression) + : expression = + let loc = !Ast_helper.default_loc in + List.fold_left begin fun acc (ty, _) : expression -> + let var = var_of_type ty in + [%expr fun [%p Ast_helper.Pat.var { loc; txt = poly_var var }] -> [%e acc]] + end e (List.rev td.ptype_params) + +let poly_arrow_of_type_decl (mkvar : core_type -> core_type) + (td : type_declaration) (ty : core_type) + : core_type = + let loc = !Ast_helper.default_loc in + List.fold_left begin fun acc ((ty : core_type), _) : core_type -> + [%type: [%t mkvar ty] -> [%t acc]] + end ty (List.rev td.ptype_params) + +let core_type_of_type_decl (td : type_declaration) : core_type = + Ast_helper.Typ.constr + (td.ptype_name |> map_loc (fun x : Longident.t -> Lident x)) + (List.map fst td.ptype_params) + +let expand_path ~path ident = + String.concat "." (path @ [ident]) + +let path_of_type_decl ~path (td : type_declaration) = + match td.ptype_manifest with + | Some { ptyp_desc = Ptyp_constr ({ txt = lid; _ }, _); _ } -> + begin match lid with + | Lident _ -> [] + | Ldot (lid, _) -> Ocaml_common.Longident.flatten lid + | Lapply _ -> assert false + end + | _ -> path + +let pat_var_of_string s = + let loc = !Ast_helper.default_loc in + Ast_helper.Pat.var { loc; txt = s } + +let ident_of_string s = + let loc = !Ast_helper.default_loc in + Ast_helper.Exp.ident { loc; txt = Lident s } + +let ident_of_str ({ loc; txt } : string Location.loc) = + Ast_helper.Exp.ident { loc; txt = Lident txt } + +let poly_apply_of_type_decl (td : type_declaration) (e : expression) = + match td.ptype_params with + | [] -> e + | _ -> + Ast_helper.Exp.apply e begin td.ptype_params |> List.map begin + fun (ty, _) : (arg_label * expression) -> + Nolabel, ident_of_string (poly_var (var_of_type ty)) + end end diff --git a/ocaml-elpi/vendored/ppx_show-0.2.0/src/tools.mli b/ocaml-elpi/vendored/ppx_show-0.2.0/src/tools.mli new file mode 100644 index 000000000..9b7782cc6 --- /dev/null +++ b/ocaml-elpi/vendored/ppx_show-0.2.0/src/tools.mli @@ -0,0 +1,46 @@ +open Ppxlib + +val flatten_map : ('a -> 'b list) -> 'a list -> 'b list +(** [flatten_map f list] is equal to [List.flatten (List.map f list)]. *) + +val map_loc : ('a -> 'b) -> 'a Location.loc -> 'b Location.loc + +type affix = + | Prefix of string + | Suffix of string + | PrefixSuffix of string * string + +val mangle : ?fixpoint : string -> affix -> string -> string + +val mangle_lid : ?fixpoint : string -> affix -> Longident.t -> Longident.t + +val mangle_type_decl : + ?fixpoint : string -> affix -> type_declaration -> string Location.loc + +val seq : ?loc : Location.t -> expression list -> expression + +val separate : 'a -> 'a list -> 'a list + +val poly_var : string -> string + +val poly_fun_of_type_decl : type_declaration -> expression -> expression + +val poly_arrow_of_type_decl : + (core_type -> core_type) -> type_declaration -> core_type + -> core_type + +val core_type_of_type_decl : type_declaration -> core_type + +val expand_path : path : string list -> string -> string + +val path_of_type_decl : path : string list -> type_declaration -> string list + +val pat_var_of_string : string -> pattern + +val ident_of_string : string -> expression + +val ident_of_str : string Location.loc -> expression + +val poly_apply_of_type_decl : type_declaration -> expression -> expression + +val var_of_type : core_type -> string diff --git a/ocaml-elpi/vendored/ppx_show-0.2.0/tests/show/dune b/ocaml-elpi/vendored/ppx_show-0.2.0/tests/show/dune new file mode 100644 index 000000000..fb5419938 --- /dev/null +++ b/ocaml-elpi/vendored/ppx_show-0.2.0/tests/show/dune @@ -0,0 +1,5 @@ +(executable + (name show) + (preprocess (pps ppx_show)) + ; (flags -dsource) + (libraries ppx_show_runtime)) \ No newline at end of file diff --git a/ocaml-elpi/vendored/ppx_show-0.2.0/tests/show/show.ml b/ocaml-elpi/vendored/ppx_show-0.2.0/tests/show/show.ml new file mode 100644 index 000000000..143af3d1d --- /dev/null +++ b/ocaml-elpi/vendored/ppx_show-0.2.0/tests/show/show.ml @@ -0,0 +1,111 @@ +type enum = A | B of int | C of bool * int | D of { a : int; b : string } + [@@deriving show] + +let exit_code = ref 0 + +let string_match line s s' = + if s <> s' then + begin + Format.eprintf "Mismatch at line %d: got \"%s\" but \"%s\" expected@." + line (String.escaped s) (String.escaped s'); + exit_code := 1 + end + +let () = + string_match __LINE__ + (Format.asprintf "@[%a@]" [%show: int32] 1l) "1l" + +let () = + string_match __LINE__ + (Format.asprintf "@[%a@]" [%show: int64] 1L) "1L" + +let () = + string_match __LINE__ + (Format.asprintf "@[%a@]" [%show: nativeint] 1n) "1n" + +let () = + string_match __LINE__ + (Format.asprintf "@[%a@]" [%show: float] 1.) "1." + +let () = + string_match __LINE__ + (Format.asprintf "@[%a@]" [%show: int option] (Some 1)) "Some (1)" + +let () = + string_match __LINE__ + (Format.asprintf "@[%a@]" [%show: int ref] (ref 1)) "ref (1)" + +let () = + string_match __LINE__ + (Format.asprintf "@[%a@]" [%show: int Lazy.t] (lazy 1)) "lazy (1)" + +let () = + string_match __LINE__ + (Format.asprintf "@[%a@]" [%show: (int, unit) result] (Error ())) + "Error (())" + +let () = + string_match __LINE__ + (Format.asprintf "@[%a@]" [%show: int list] [1; 2; 3]) "[1; 2; 3]" + +let () = + string_match __LINE__ + (Format.asprintf "@[%a@]" [%show: int * bool * string] (1, false, "a")) + "(1, false, \"a\")" + +let () = + string_match __LINE__ + (Format.asprintf "@[%a@]" [%show: [`A | `B of int]] `A) "`A" + +let () = + string_match __LINE__ + (Format.asprintf "@[%a@]" [%show: [`A | `B of int]] (`B 1)) "`B (1)" + +let () = + string_match __LINE__ + (Format.asprintf "@[%a@]" [%show: [`A | `B of int * int]] (`B (1, 2))) + "`B ((1, 2))" + +let () = + string_match __LINE__ (Format.asprintf "@[%a@]" pp_enum A) "Show.A" + +let () = + string_match __LINE__ (Format.asprintf "@[%a@]" pp_enum (B 1)) "Show.B (1)" + +let () = + string_match __LINE__ + (Format.asprintf "@[%a@]" pp_enum (C (false, 2))) "Show.C (false, 2)" + +let () = + string_match __LINE__ + (Format.asprintf "@[%a@]" pp_enum (D { a = 1; b = "foo" })) + "Show.D ({ a = 1; b = \"foo\" })" + +type 'a poly = A of enum | B of 'a poly * 'a + [@@deriving show { with_path = false }] + +let () = + string_match __LINE__ + (Format.asprintf "@[%a@]" (pp_poly pp_enum) (A A)) "A (Show.A)" + +let () = + string_match __LINE__ + (Format.asprintf "@[%a@]" (pp_poly pp_enum) (B (A A, A))) + "B (A (Show.A), Show.A)" + +let pp_int fmt _ = Format.pp_print_string fmt "a" + +let () = + string_match __LINE__ + (Format.asprintf "@[%a@]" [%show: int [@show.nobuiltin]] 1) "a" + +module Test : sig + type t = A [@@deriving show] +end = struct + type t = A [@@deriving show] +end + +let () = + string_match __LINE__ (Test.show A) "Show.Test.A" + +let () = exit !exit_code diff --git a/ppx_elpi/dune b/ppx_elpi/dune new file mode 100644 index 000000000..98b55a9df --- /dev/null +++ b/ppx_elpi/dune @@ -0,0 +1,15 @@ +(library + (name ppx_elpi) + (public_name elpi.ppx) + (synopsis "[@@elpi]") + (libraries re ppxlib elpi) + (preprocess (pps ppxlib.metaquot)) + (ppx_runtime_libraries elpi) + (modules ppx_elpi) + (kind ppx_rewriter) + (optional) +) + +(env + (dev + (flags (:standard -warn-error -A)))) \ No newline at end of file diff --git a/ppx_elpi/ppx_elpi.ml b/ppx_elpi/ppx_elpi.ml new file mode 100644 index 000000000..2be943275 --- /dev/null +++ b/ppx_elpi/ppx_elpi.ml @@ -0,0 +1,1651 @@ +[@@@warning "-27"] +open Ppxlib +open Ppxlib.Ast_pattern + +(** + + This PPX deriver can synthesize glue code for Elpi. The following kind of data + types are supported: + + - Opaque, eg [type t] (or types with a definition but that one does not + want to expose to elpi). See the [@@elpi.opaque e] attribute. Phantom + parameters are not supported for now. + + - Alias, eg [type 'a t = ('a * int) list ]. + + - Algebraic, eg [type t = K | S]. Such a type can have two roles: + - a datum: a syntax tree, potentially with binders + - the context for a datum: all data with binders must be equipped with + one or more data types describing the info attached to bound variables. + + Example of a HOAS data type + + type lctx = + | Entry of string[@elpi.key] * ty + [@@elpi.index (module String)] + [@@deriving elpi] + + type l = + | Lam of string * ty * (term[@elpi.binder ctx ..]) + | Var of string [@elpi.variable ctx] + [@@deriving elpi] + + Output: + + class type ctx_for_l = object + inherit Conversion.ctx + method lctx : lctx Conversion.ctx_field + end + val l : 'c. (l, #ctx_for_l as 'c) Conversion.t + val in_ctx_for_l : ctx_for_l Conversion.ctx_readback + + Usage: predicates using HOAS arguments must specify a context large enough + for all arguments. + + Pred("term->string", + In(l, "T", + InOut(string, "S", + Read("what else"))), + in_ctx_for_l, + fun (x : l) _ ~depth:_ (c : ctx_for_l) (_ : Data.constraints) (_ : State.t) -> + ... x ... c#lctx ... + + Here in_ctx_for_l is a context rich enough to support the readback of data of + type l and string. + + Deriving directives: + [@@deriving elpi] + Derive a Elpi.API.ContextualConversion.t for the data types in the + mutually recursive block. The name of the conversion in the one of the + type. See the Conventions section of this doc for mode info on the + naming of generated code. + [@@deriving elpi { context = [ty1; ...; tyn]}] + Specify the types describing the context under which the data type lives + and the order in which they should be read back. Default is the list + of types mentioned in [@elpi.binder] and [@elpi.var], in no specified + order. + [@@deriving elpi { declaration = l }] + Also append to list (l : Elpi.API.BuiltIn.declaration list ref) + all MLCData delarations that were derived. + [@@deriving elpi { mapper = l }] + Also append to list (l : Elpi.API.BuiltIn.declaration list ref) + all LPCode declarations of mappers for the data types, eg a + pred map.typename i:typename, o:typename + (with parameters if the type is a container). The mapper is identity + one, it is up to the user to place his code before this one and override + the cases he wants in order to implement a non trivial map. + + The type must come with a pretty printer named following the usual + convention (named pp if the type is named t, pp_ty otherwise). + Using both [@@derving show, elpi] on each data type is the simplest option + (from the ppx_show package, not the ppx_deriving one). + See also [@@elpi.pp]. + + Type attributes: + + [@@elpi.type_readback f] + [f] mandatory: a function of type Elpi.API.ContextualConversion.readback. + Take over the readback of the entire type (useful in a block of mutually + recursive types). + + [@@elpi.type_embed f] + [f] mandatory: a function of type Elpi.API.ContextualConversion.embedding. + Take over the embed of the entire type (useful in a block of mutually + recursive types). + + [@@elpi.pp f] + [f] mandatory: code for pretty printing the data. Its type is the one + ppx_deriving.show would produce. + + [@@elpi.type_code] + See the constructor attribute with name [code]. + + [@@elpi.type_doc] + See the constructor attribute with name [doc]. + + [@@elpi.default_constructor_readback f] + [f] mandatory: a function of type Elpi.API.ContextualConversion.readback + called when the term is not any of the constructors. The default is a + runtime type error. This option can be used to read back flexible terms + (in addition to regular constructors). + + [@@elpi.index (module M)] + [M] mandatory: is an OrderedType and Show, it is used to instantiate the + functor Elpi.Utils.Map.Make. When used in a type, each + constructors must have exactly one argument with attribute [@elpi.key] + and that argument must be of type M.t. + + [@@elpi.opaque e] + [e] mandatory: is a Elpi.API.OpaqueData.declaration, it is necessary for + opaque data types. + + Constructor attributes: + + [@elpi.var ctx to_key] An Elpi bound variable. + [ctx] mandatory: is the name if the context in which the variable + is bound. + [to_key] optional: is a function from the constructor arguments to the + value being the [@elpi.key] for the context [ctx]. + + [@elpi.skip] Not exposed to Elpi. + + [@elpi.embed f] Custom embedding code. + [f] optional: function of type + Elpi.API.ContextualConversion.(embedding -> embedding) + where the input function is the one this ppx would generate. If you + want to override it only in some cases, just call this argument in the + other ones. + + [@elpi.readback f] Custom readback code. + [f] optional: function of type + Elpi.API.ContextualConversion.(readback -> readback) + see [@elpi.emebed]. + + [@elpi.code name code] Custom Elpi declaration. + [name] mandatory: a string that stands for the name of the type + constructor. The default is the name of the OCaml constructor in lowercase + where _ is replaced by - . Eg Foo_BAR becomes foo-bar. + [code] optional: is a string used as the Elpi type declaration for the + constructor. Default is derived from the types of the fields. Example + "type lam (term -> term) -> term. % Lam" + + [@elpi.doc s] Custom documentation. + [s] mandatory: a string. Default doc is the name of the OCaml constructor, + see the example above. + + Constructor field attribute: + + [@elpi.key] Field used as a key in the Map to values of this type. + + [@elpi.binder ty ctx mk_ctx_entry] Field is below one binder. + [ty] optional: name (string) of the elpi abstraction type, + eg the "XXX" in (XXX -> term). Default is the type name. + [ctx] mandatory: name of the context in which the variable is bound + [mk_ctx_entry] mandatory: function taking all other fields and returning + a ctx entry (a value in the type [ctx]). + + Extensions: + + [%elpi : ty] the conversion of type ty + This does not synthesize the conversion code but rather compose the + existing ones. + + Conventions: + + is a value of type Elpi.API.ContextualConversion.t for type ty. + + in_ is a value of type Elpi.API.ContextualConversion.ctx_readback + for type . + + Elpi__Map is a module of signature Elpi.API.Utils.Map.S built using + Elpi.API.Utils.Map.Make(M) where type is annotated with + [@@elpi.index (module M)]. + + TODO: elpi_push_xxx elpi_pop_xxx elpi_xxx_state elpi_xxx_to_key elpi_xxx + + Internal conventions: + + Variables are named elpi__something so that they don't collide with + any variable named elpi_something or something. + + *) + +let arguments = Deriving.Args.(empty + +> arg "declaration" __ + +> arg "mapper" __ + +> arg "context" __ +) + +let att_elpi_tcode = Attribute.(declare "elpi.type_code" Context.type_declaration (single_expr_payload __) (fun x -> x)) +let att_elpi_tdoc = Attribute.(declare "elpi.type_doc" Context.type_declaration (single_expr_payload (estring __)) (fun x -> x)) +let att_elpi_def_k_readback = Attribute.(declare "elpi.default_constructor_readback" Context.type_declaration (single_expr_payload __) (fun x -> x)) +let att_elpi_tpp = Attribute.(declare "elpi.pp" Context.type_declaration (single_expr_payload __) (fun x -> x)) +let att_elpi_treadback = Attribute.(declare "elpi.type_readback" Context.type_declaration (single_expr_payload __) (fun x -> x)) +let att_elpi_tembed = Attribute.(declare "elpi.type_embed" Context.type_declaration (single_expr_payload __) (fun x -> x)) +let att_elpi_tindex = Attribute.(declare "elpi.index" Context.type_declaration (single_expr_payload (pexp_pack __)) (fun x -> x)) +let att_elpi_tcdata = Attribute.(declare "elpi.opaque" Context.type_declaration (single_expr_payload __) (fun x -> x)) + +let att_elpi_var = Attribute.(declare "elpi.var" Context.constructor_declaration (single_expr_payload __) (fun x -> x)) +let att_elpi_skip = Attribute.(declare "elpi.skip" Context.constructor_declaration (pstr nil) ()) +let att_elpi_embed = Attribute.(declare "elpi.embed" Context.constructor_declaration (single_expr_payload __) (fun x -> x)) +let att_elpi_readback = Attribute.(declare "elpi.readback" Context.constructor_declaration (single_expr_payload __) (fun x -> x)) +let att_elpi_code = Attribute.(declare "elpi.code" Context.constructor_declaration (single_expr_payload __) (fun x -> x)) +let att_elpi_doc = Attribute.(declare "elpi.doc" Context.constructor_declaration (single_expr_payload (estring __)) (fun x -> x)) + +let att_elpi_key = Attribute.(declare "elpi.key" Context.core_type (pstr nil) ()) +let att_elpi_binder = Attribute.(declare "elpi.binder" Context.core_type (single_expr_payload __) (fun x -> x)) + + let elpi_name_mangle txt = + String.map (function '_' -> '-' | x -> x) @@ + String.lowercase_ascii txt +let elpi_map_name x = "Elpi_"^x^"_Map" +let elpi_state_name x = "elpi_"^x^"_state" +let elpi_ctx_class_module_name x = "Ctx_for_" ^ x +let elpi_ctx_class_name x = elpi_ctx_class_module_name x ^ ".t" +let elpi_ctx_object_name x = "ctx_for_" ^ x +let elpi_readback_ctx_name x = "context_made_of_" ^ x +let elpi_in_ctx_for_name x = "in_" ^ elpi_ctx_object_name x +let elpi_to_key x = "elpi_" ^ x ^ "_to_key" +let elpi_is_ctx_entry_name x = "elpi_is_" ^ x +let elpi_embed_name x = "elpi_embed_" ^ x +let elpi_readback_name x = "elpi_readback_" ^ x +let elpi_push x = "elpi_push_" ^ x +let elpi_pop x = "elpi_pop_" ^ x +let elpi_kname t k = "elpi_constant_constructor_" ^ t ^ "_" ^ k ^ "c" +let elpi_tname t = "elpi_constant_type_" ^ t ^ "c" +let elpi_kname_str t k = "elpi_constant_constructor_" ^ t ^ "_" ^ k +let elpi_tname_str t = "elpi_constant_type_" ^ t +let elpi_cdata_name x = "elpi_opaque_data_decl_" ^ x +let param_prefix = "elpi__param__" +let fresh = + let x = ref 0 in + fun () -> incr x; Printf.sprintf "elpi__%d" !x +let elpi_Map ~loc x f = Ast_builder.Default.evar ~loc ("Elpi_"^x^"_Map." ^ f) + + +let option_is_some = function Some _ -> true | _ -> false +let option_get = function Some x -> x | _ -> assert false +let option_map f = function Some x -> Some (f x) | _ -> None +let option_default d = function Some x -> x | _ -> d +let option_to_list = function Some x -> [x] | None -> [] +let rec filter_map f = function + | [] -> [] + | x :: xs -> + match f x with + | None -> filter_map f xs + | Some y -> y :: filter_map f xs + +let error ?loc = Location.raise_errorf ?loc +let nYI ~loc ~__LOC__ () = error ~loc "nYI: %s" __LOC__ + +let elpi_loc_of_position (module B : Ast_builder.S) pos = let open B in + let open Location in + let open Lexing in + [%expr { + Elpi.API.Ast.Loc.source_name = [%e estring @@ pos.pos_fname ]; + source_start = [%e eint @@ pos.pos_cnum ]; + source_stop = [%e eint @@ pos.pos_cnum ]; + line = [%e eint @@ pos.pos_lnum ]; + line_starts_at = [%e eint @@ pos.pos_bol ]; + }] + +let pexp_disable_warnings (module B : Ast_builder.S) x = + let open B in + let _ = loc in + [%expr [%e x ][@warning "-26-27-32-39-60"]] + +let rec on_last f = function + | [] -> assert false + | [x] -> [f x] + | y :: ys -> y :: on_last f ys + +type codegen_directive = + | Standard + | Custom of { ml : expression; pos : position } + | Name of { get_key : expression; ctx_name : string } +let is_name = function Name _ -> true | _ -> false + +type arg_type = + | FO of { + key : bool; (* has the [@elpi.key] attribute *) + readback : expression; + embed : expression; + ty_ast : expression; + ty : core_type; + } + | HO of { (* [@elpi.binder ctx build_ctx] *) + ctx : string; + build_ctx : expression; + arrow_src_elpi : string; (* name of ctx in elpi *) + readback : expression; + embed : expression; + ty_ast : expression; (* to generate the elpi type of the constructor *) + ty : core_type; + } +let is_key = function FO { key = k; _ } -> k | _ -> false +let is_HO = function HO _ -> true | _ -> false + +let ctx_index_ty (module B : Ast_builder.S) = let open B in + FO { + readback = [%expr Elpi.API.BuiltInContextualData.nominal.Elpi.API.ContextualConversion.readback ]; + embed = [%expr Elpi.API.BuiltInContextualData.nominal.Elpi.API.ContextualConversion.embed ]; + ty_ast = [%expr Elpi.API.BuiltInContextualData.nominal.Elpi.API.ContextualConversion.ty ]; + ty = [%type: Elpi.API.Data.constant ]; + key = false; + } + +type elpi_constructor = + | Skip of { constructor_name : string; has_args : bool } + | Expose of expose +and expose = { + declaration : structure_item list; (* constants for constructor *) + constant : expression; + constant_name : string; + constructor : expression list -> expression; + pattern : pattern list -> pattern; + arg_types : arg_type list; + embed : codegen_directive; + readback : codegen_directive; + elpi_code : expression option; (* string *) + elpi_doc : string; + ctx_names : string list; +} + +type elpi_type_decl = + | Opaque of expression + | Alias of core_type + | Algebraic of elpi_constructor list * expression option (* default readback *) + +type elpi_type = { + name : string; + elpi_name : string; + elpi_code : string option; + elpi_doc : string; + params : string list; + type_decl : elpi_type_decl; + pp : expression option; + index : module_expr option; + } + +module SSet = struct (* We need to preserve the order *) + module SSet = Elpi.API.Utils.Set.Make(struct + include String + let pp fmt x = Format.pp_print_string fmt x + let show x = x + end) + + type t = string list + let mem = List.mem + let is_empty x = x = [] + let elements l = l + let of_list l = l + let subset l1 l2 = SSet.subset + (List.fold_right SSet.add l1 SSet.empty) + (List.fold_right SSet.add l2 SSet.empty) + let empty = [] + let add x l = if List.mem x l then l else x :: l + let pp fmt l = Elpi.API.RawPp.list Format.pp_print_string " " fmt l + let diff l1 l2 = SSet.diff + (List.fold_right SSet.add l1 SSet.empty) + (List.fold_right SSet.add l2 SSet.empty) |> SSet.elements +end + +type elpi_mutual_type = { + types : elpi_type list; + names : string list; + ctx_names : SSet.t; + context : (string * module_expr * elpi_type) option; +} + +type type_extras = { + ty_constants : structure_item list; + ty_embed : value_binding; + ty_readback : value_binding; + ty_ctx_class_type : structure_item; + ty_conversion : value_binding list; + ty_conversion_name : string; + ty_elpi_declaration : elpi_declaration; + ty_opaque : bool; + ty_in_ctx : structure_item list; (* for contextual ADTs *) + ty_library : expression option; (* should be Elpi AST *) +} +and elpi_declaration = { + decl : structure_item; + decl_name : expression +} + +type context_extras = { + ty_context_helpers : structure_item list; + ty_context_readback : structure_item list; +} + +type mutual_type_extras = { + ty_extras : type_extras list; + ctx_extras : context_extras option; +} + +let is_pred context name = + match context with None -> false | Some (n,_,_) -> n = name + +let ctx_for k = function + | None -> assert false + | Some l -> + try List.assoc k l + with Not_found -> + error "cannot find context type for %s" k + +let rec drop_skip = function + | [] -> [] + | Skip _ :: l -> drop_skip l + | Expose x :: l -> x :: drop_skip l +let rec keep_skip = function + | [] -> [] + | Skip { constructor_name; has_args } :: l -> (constructor_name, has_args) :: keep_skip l + | Expose _ :: l -> keep_skip l + +let rec list_take i = function + | [] -> [] + | _ :: _ when i = 0 -> [] + | x :: xs -> x :: list_take (i-1) xs + +let rec embed_k (module B : Ast_builder.S) c all_kargs all_tmp kargs tmp tys n = let open B in + match kargs, tmp, tys with + | [], [], [] -> + [%expr elpi__state, Elpi.API.RawData.mkAppL [%e c] [%e elist @@ List.map evar @@ List.map fst all_kargs], List.concat [%e elist all_tmp] ] + | (px,ex) :: xs, y :: ys, (FO { embed = t; _ }) :: ts -> [%expr + let elpi__state, [%p pvar px], [%p pvar y] = + [%e t] ~depth: elpi__depth elpi__hyps elpi__constraints elpi__state [%e ex] in + [%e embed_k (module B) c all_kargs all_tmp xs ys ts (n+1)]] + | (px,ex) :: xs, y :: ys, HO{ build_ctx = f; embed = t; ctx = ctx_name; _ } :: ts -> + let xtmp = fresh () in + let elpi_to_key = evar (elpi_to_key ctx_name) in + let elpi_push = evar (elpi_push ctx_name) in + let elpi_pop = evar (elpi_pop ctx_name) in + [%expr + let elpi__ctx_entry = [%e eapply f (List.map snd @@ list_take n all_kargs) ] in + let elpi__ctx_key = [%e elpi_to_key ] ~depth: elpi__depth elpi__ctx_entry in + let elpi__ctx_entry = { Elpi.API.ContextualConversion.entry = elpi__ctx_entry; depth = elpi__depth } in + let elpi__state = [%e elpi_push ] ~depth: (elpi__depth + 1) elpi__state elpi__ctx_key elpi__ctx_entry in + let elpi__state, [%p pvar xtmp], [%p pvar y] = + [%e t] ~depth: (elpi__depth + 1) elpi__hyps elpi__constraints elpi__state [%e ex] in + let [%p pvar px] = Elpi.API.RawData.mkLam [%e evar xtmp] in + let elpi__state = [%e elpi_pop ] ~depth: (elpi__depth + 1) elpi__state elpi__ctx_key in + [%e embed_k (module B) c all_kargs all_tmp xs ys ts (n+1)]] + | _ -> assert false +;; + +let embed_var (module B : Ast_builder.S) ctx_name args p = let open B in + let elpi_Map = elpi_Map ~loc ctx_name in + [%expr + let elpi__ctx2dbl, _ = Elpi.API.State.get [%e evar (elpi_state_name ctx_name)] elpi__state in + let elpi__key = [%e eapply p args] in + if not ([%e elpi_Map "mem" ] elpi__key elpi__ctx2dbl) then + Elpi.API.Utils.error "Unbound variable"; + elpi__state, Elpi.API.RawData.mkBound ([%e elpi_Map "find" ] elpi__key elpi__ctx2dbl), [] + ] + +let error_constructor_not_supported (module B : Ast_builder.S) (constructor,has_args) = let open B in + case ~guard:None ~lhs:(ppat_construct (Located.lident constructor) (if has_args then Some (pvar "_") else None)) + ~rhs:[%expr Elpi.API.Utils.error ("constructor "^[%e estring constructor]^" is not supported") ] + +let abstract_standard_branch_embed (module B : Ast_builder.S) l e = let open B in + let rec aux = function + | [] -> e + | x::xs -> [%expr fun [%p pvar x] -> [%e aux xs]] + in + [%expr fun ~depth: elpi__depth elpi__hyps elpi__constraints elpi__state -> [%e aux l ]] + +let embed_branch (module B : Ast_builder.S) is_pred = function + | Skip { constructor_name; has_args } -> error_constructor_not_supported (module B) (constructor_name,has_args) + | Expose { constant; arg_types; embed; pattern; _ } -> let open B in + let pvl, pattern, types = + let pvl = List.map (fun _ -> fresh()) arg_types in + let kpattern = pattern (List.map pvar pvl) in + if is_pred then + let idx = fresh () in + idx :: pvl, ppat_tuple [pvar idx;kpattern], ctx_index_ty (module B) :: arg_types + else pvl, kpattern, arg_types in + let standard = + let evl = List.map (fun _ -> fresh()) types in + let pvl2 = List.map (fun x -> fresh (), evar x) pvl in + embed_k (module B) constant pvl2 (List.map evar evl) pvl2 evl types 0 in + case ~guard:None ~lhs:pattern + ~rhs:begin match embed with + | Custom { ml; _ } -> + eapply [%expr [%e ml] [%e abstract_standard_branch_embed (module B) pvl standard ] + ~depth: elpi__depth elpi__hyps elpi__constraints elpi__state] (List.map evar pvl) + | Standard -> standard + | Name { get_key; ctx_name } -> + embed_var (module B) ctx_name (List.map evar pvl) get_key + end + +let embed (module B : Ast_builder.S) is_pred kl = let open B in + [%expr fun ~depth: elpi__depth elpi__hyps elpi__constraints elpi__state -> + [%e pexp_function (List.map (embed_branch (module B) is_pred) kl) ]] + +let readback_k (module B : Ast_builder.S) c mk_k t ts = let open B in + let one all_kargs n p1 e1 t x kont = + match t with + | FO { readback = t; _ } -> [%expr + let elpi__state, [%p pvar p1], [%p pvar e1] = + [%e t] ~depth: elpi__depth elpi__hyps elpi__constraints elpi__state [%e x] in + [%e kont] ] + | HO { build_ctx = f; readback = t; ctx = ctx_name; _ } -> + let elpi_to_key = evar (elpi_to_key ctx_name) in + let elpi_push = evar (elpi_push ctx_name) in + let elpi_pop = evar (elpi_pop ctx_name) in + [%expr + let elpi__ctx_entry = [%e eapply f (List.map evar @@ list_take n all_kargs) ] in + let elpi__ctx_key = [%e elpi_to_key ] ~depth: elpi__depth elpi__ctx_entry in + let elpi__ctx_entry = { Elpi.API.ContextualConversion.entry = elpi__ctx_entry; depth = elpi__depth } in + let elpi__state = [%e elpi_push ] ~depth: elpi__depth elpi__state elpi__ctx_key elpi__ctx_entry in + let elpi__state, [%p pvar p1], [%p pvar e1] = + match Elpi.API.RawData.look ~depth: elpi__depth [%e x] with + | Elpi.API.RawData.Lam elpi__bo -> + [%e t] ~depth: (elpi__depth + 1) elpi__hyps elpi__constraints elpi__state elpi__bo + | _ -> assert false in + let elpi__state = [%e elpi_pop ] ~depth: elpi__depth elpi__state elpi__ctx_key in + [%e kont]] in + let rec roll_readback all_kargs n all_tmp kargs tmp tys = + match kargs, tmp, tys with + | [], [], [] -> + [%expr (elpi__state, [%e mk_k (List.map evar all_kargs)], List.concat [%e elist @@ List.map evar all_tmp]) ] + | x :: xs, y :: ys, t :: ts -> + one all_kargs n x y t (evar x) (roll_readback all_kargs (n+1) all_tmp xs ys ts) + | _ -> assert false + in + let rec roll_pat = function + | [] -> [%pat? [] ] + | x :: xs -> [%pat? [%p pvar x] :: [%p roll_pat xs] ] in + let ps = List.map (fun _ -> fresh()) ts in + let es = List.map (fun _ -> fresh()) ts in + let p1, e1 = fresh (), fresh () in + let all_kargs = p1 :: ps in + one all_kargs 0 p1 e1 t [%expr elpi__x] [%expr + match elpi__xs with + | [%p roll_pat ps ] -> + [%e roll_readback all_kargs 1 (e1 :: es) ps es ts] + | _ -> Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ Elpi.API.RawData.Constants.show [%e c]) + ] + +let readback_var (module B : Ast_builder.S) ctx_name constructor = let open B in + let elpi_to_key = evar (elpi_to_key ctx_name) in + let elpi_state_component = evar (elpi_state_name ctx_name) in + [%expr + let _, elpi__dbl2ctx = Elpi.API.State.get [%e elpi_state_component ] elpi__state in + if not (Elpi.API.RawData.Constants.Map.mem elpi__hd elpi__dbl2ctx) then + Elpi.API.Utils.error (Format.asprintf "Unbound variable: %s in %a" + (Elpi.API.RawData.Constants.show elpi__hd) + (Elpi.API.RawData.Constants.Map.pp (Elpi.API.ContextualConversion.pp_ctx_entry [%e evar ("pp_" ^ ctx_name)])) elpi__dbl2ctx); + let { Elpi.API.ContextualConversion.entry = elpi__entry; depth = elpi__depth } = Elpi.API.RawData.Constants.Map.find elpi__hd elpi__dbl2ctx in + elpi__state, [%e constructor [ [%expr [%e elpi_to_key ] ~depth: elpi__depth elpi__entry ] ] ], [] + ] + +let abstract_standard_branch_readback (module B : Ast_builder.S) pos e = let open B in + [%expr fun ~depth: elpi__depth elpi__hyps elpi__constraints elpi__state -> function + | [] -> [%e e ] + | _ -> Elpi.API.Utils.error ~loc: [%e elpi_loc_of_position (module B) pos ] "standard branch readback takes 0 arguments"] + +let abstract_standard_branch_readback2 (module B : Ast_builder.S) pos e = let open B in + [%expr fun ~depth: elpi__depth elpi__hyps elpi__constraints elpi__state -> function + | elpi__x :: elpi__xs -> [%e e ] + | [] -> Elpi.API.Utils.error ~loc: [%e elpi_loc_of_position (module B) pos ] "standard branch readback takes 1 argument or more"] + +let readback_branch (module B : Ast_builder.S) is_pred { constant; constructor; arg_types; readback; _ } = let open B in + let types, mk_k = + if is_pred then ctx_index_ty (module B) :: arg_types, (function x :: xs -> pexp_tuple [x;constructor xs] | [] -> assert false) + else arg_types, constructor in + match types with + | [] -> + let standard = [%expr elpi__state, [%e constructor [] ], []] in + case ~lhs:[%pat? Elpi.API.RawData.Const elpi__hd] + ~guard:(Some [%expr elpi__hd == [%e constant]]) + ~rhs:begin match readback with + | Standard -> standard + | Custom { ml; pos } -> [%expr [%e ml] [%e abstract_standard_branch_readback (module B) pos standard] ~depth: elpi__depth [] ] + | Name _ -> assert false + end + | t :: ts -> + let standard = readback_k (module B) constant mk_k t ts in + match readback with + | Standard -> + case ~lhs:[%pat? Elpi.API.RawData.App (elpi__hd,elpi__x,elpi__xs)] + ~guard:(Some [%expr elpi__hd == [%e constant]]) + ~rhs:standard + | Custom { ml; pos } -> + case ~lhs:[%pat? Elpi.API.RawData.App (elpi__hd,elpi__x,elpi__xs)] + ~guard:(Some [%expr elpi__hd == [%e constant]]) + ~rhs:([%expr [%e ml] [%e abstract_standard_branch_readback2 (module B) pos standard ] ~depth: elpi__depth elpi__hyps elpi__constraints elpi__state (elpi__x :: elpi__xs)]) + | Name { ctx_name; _} -> assert(ts = []); + case ~lhs:[%pat? Elpi.API.RawData.Const elpi__hd] + ~guard:(Some [%expr elpi__hd >= 0]) + ~rhs:(readback_var (module B) ctx_name constructor) + +let abstract_standard_default_readback (module B : Ast_builder.S) e = let open B in + [%expr fun ~depth: elpi__depth elpi__hyps elpi__constraints elpi__state elpi__x -> [%e e]] + +let readback (module B : Ast_builder.S) name is_pred default_readback kl = let open B in + [%expr fun ~depth: elpi__depth elpi__hyps elpi__constraints elpi__state elpi__x -> + [%e pexp_match [%expr Elpi.API.RawData.look ~depth: elpi__depth elpi__x] + (List.map (readback_branch (module B) is_pred) (drop_skip kl) @ + [case ~guard:None ~lhs:[%pat? _ ] + ~rhs:begin + let standard = + [%expr Elpi.API.Utils.type_error (Format.asprintf "Not a constructor of type %s: %a" + [%e estring name] (Elpi.API.RawPp.term elpi__depth) elpi__x) ] in + match default_readback with + | None -> standard + | Some e -> [%expr [%e e] [%e abstract_standard_default_readback (module B) standard ] ~depth: elpi__depth elpi__hyps elpi__constraints elpi__state elpi__x ] + end])]] + +let ctx_entry_key (module B : Ast_builder.S) kl = let open B in + let project { pattern; arg_types; _ } = + let pvl = List.map (function FO { key = true; _ } -> fresh() | _ -> "_") arg_types in + let rec find_key vl tl = + match vl, tl with + | v :: _, FO { key = true; _ } :: _ -> evar v + | _ :: vs, _ :: ts -> find_key vs ts + | _ -> assert false in + + case ~lhs:(pattern (List.map pvar pvl)) ~guard:None ~rhs:(find_key pvl arg_types) in + [%expr fun ~depth:_ -> [%e pexp_function ( + List.map project (drop_skip kl) @ + List.map (error_constructor_not_supported (module B)) (keep_skip kl)) ] ] + +let is_ctx_entry (module B : Ast_builder.S) kl = let open B in + [%expr fun { Elpi.API.Data.hdepth = elpi__depth; hsrc = elpi__x } -> + match Elpi.API.RawData.look ~depth: elpi__depth elpi__x with + | Elpi.API.RawData.Const _ -> None + | Elpi.API.RawData.App(elpi__hd,elpi__idx,_) -> + if [%e + List.fold_left (fun e -> function + | Skip _ -> e + | Expose { constant; _ } -> + [%expr [%e e] || elpi__hd == [%e constant]]) + [%expr false] kl + ] + then match Elpi.API.RawData.look ~depth: elpi__depth elpi__idx with + | Elpi.API.RawData.Const x -> Some x + | _ -> Elpi.API.Utils.type_error "context entry applied to a non nominal" + else None + | _ -> None ] +(* +let ctx_readback (module B : Ast_builder.S) name = let open B in + let elpi_Map = elpi_Map ~loc name in + let elpi_push = evar (elpi_push name) in + let elpi_to_key = evar (elpi_to_key name) in + let elpi_is_ctx_entry = evar (elpi_is_ctx_entry_name name) in + let elpi_state_component = evar (elpi_state_name name) in + [%expr fun ~depth: elpi__depth elpi__hyps elpi__constraints elpi__state -> + let module CMap = Elpi.API.RawData.Constants.Map in + let elpi__filtered_hyps = + List.fold_left (fun elpi__m ({ Elpi.API.RawData.hdepth = elpi__i; hsrc = elpi__hsrc } as elpi__hyp) -> + match [%e elpi_is_ctx_entry ] ~depth:elpi__i elpi__hsrc with + | None -> elpi__m + | Some elpi__idx -> + if CMap.mem elpi__idx elpi__m then + Elpi.API.Utils.type_error "more than one context entry for the same nominal"; + CMap.add elpi__idx elpi__hyp elpi__m + ) CMap.empty (Elpi.API.RawData.of_hyps elpi__hyps) in + let rec elpi__aux elpi__state elpi__gls elpi__i = + if elpi__i = elpi__depth then + elpi__state, List.concat (List.rev elpi__gls) + else if not (CMap.mem elpi__i elpi__filtered_hyps) then + elpi__aux elpi__state elpi__gls (elpi__i+1) + else + let elpi__hyp = CMap.find elpi__i elpi__filtered_hyps in + let elpi__hyp_depth = elpi__hyp.Elpi.API.RawData.hdepth in + let elpi__state, (elpi__nominal, elpi__t), elpi__gls_t = + [%e evar name].Elpi.API.ContextualConversion.readback ~depth: elpi__hyp_depth elpi__hyps elpi__constraints elpi__state elpi__hyp.Elpi.API.RawData.hsrc in + assert(elpi__nominal = elpi__i); + let elpi__s = [%e elpi_to_key ] ~depth: elpi__hyp_depth elpi__t in + let elpi__state = [%e elpi_push ] ~depth:elpi__i elpi__state elpi__s { Elpi.API.ContextualConversion.entry = elpi__t; depth = elpi__hyp_depth } in + elpi__aux elpi__state (elpi__gls_t :: elpi__gls) (elpi__i+1) in + let elpi__state = Elpi.API.State.set [%e elpi_state_component ] elpi__state + ([%e elpi_Map "empty" ], CMap.empty) in + let elpi__state, elpi__gls = elpi__aux elpi__state [] 0 in + let _, elpi__dbl2ctx = Elpi.API.State.get [%e elpi_state_component ] elpi__state in + elpi__state, elpi__dbl2ctx, elpi__constraints, elpi__gls] + +let rec compose_ctx_readback (module B : Ast_builder.S) = function + | [] -> assert false + | [x] -> B.evar (elpi_in_name_alone x) + | x :: xs -> let open B in + [%expr Elpi.API.ContextualConversion.(|+|) + [%e evar (elpi_in_name_alone x) ] + [%e compose_ctx_readback (module B) xs] ] +*) + + + +let ctx_push (module B : Ast_builder.S) name = let open B in + let elpi_Map = elpi_Map ~loc name in + [%expr fun ~depth:elpi__depth elpi__state elpi__name elpi__ctx_item -> + let elpi__ctx2dbl, elpi__dbl2ctx = Elpi.API.State.get [%e evar (elpi_state_name name)] elpi__state in + let elpi__i = elpi__depth in + let elpi__ctx2dbl = [%e elpi_Map "add" ] elpi__name elpi__i elpi__ctx2dbl in + let elpi__dbl2ctx = Elpi.API.RawData.Constants.Map.add elpi__i elpi__ctx_item elpi__dbl2ctx in + let elpi__state = Elpi.API.State.set [%e evar (elpi_state_name name)] elpi__state (elpi__ctx2dbl, elpi__dbl2ctx) in + elpi__state] + +let ctx_pop (module B : Ast_builder.S) name = let open B in + let elpi_Map = elpi_Map ~loc name in + [%expr fun ~depth:elpi__depth elpi__state elpi__name -> + let elpi__ctx2dbl, elpi__dbl2ctx = Elpi.API.State.get [%e evar (elpi_state_name name)] elpi__state in + let elpi__i = elpi__depth in + let elpi__ctx2dbl = [%e elpi_Map "remove" ] elpi__name elpi__ctx2dbl in + let elpi__dbl2ctx = Elpi.API.RawData.Constants.Map.remove elpi__i elpi__dbl2ctx in + let elpi__state = Elpi.API.State.set [%e evar (elpi_state_name name)] elpi__state (elpi__ctx2dbl, elpi__dbl2ctx) in + elpi__state] + +let rec fmap f = function [] -> [] | x :: xs -> match f x with None -> fmap f xs | Some x -> x :: fmap f xs + +let conversion_of (module B : Ast_builder.S) ty = let open B in + let rec aux = function + | [%type: string] -> [%expr Elpi.API.BuiltInContextualData.string] + | [%type: int] -> [%expr Elpi.API.BuiltInContextualData.int] + | [%type: float] -> [%expr Elpi.API.BuiltInContextualData.float] + | [%type: bool] -> [%expr Elpi.Builtin.PPX.bool] + | [%type: char] -> [%expr Elpi.Builtin.PPX.char] + | [%type: [%t? typ] list] -> [%expr Elpi.API.BuiltInContextualData.list [%e aux typ ]] + | [%type: [%t? typ] option] -> [%expr Elpi.Builtin.PPX.option [%e aux typ ]] + | [%type: [%t? typ1] * [%t? typ2]] -> [%expr Elpi.Builtin.PPX.pair [%e aux typ1 ] [%e aux typ2 ]] + | [%type: [%t? typ1] * [%t? typ2] * [%t? typ3]] -> [%expr Elpi.Builtin.PPX.triple [%e aux typ1 ] [%e aux typ2 ] [%e aux typ3 ]] + | [%type: [%t? typ1] * [%t? typ2] * [%t? typ3] * [%t? typ4]] -> [%expr Elpi.Builtin.PPX.quadruple [%e aux typ1 ] [%e aux typ2 ] [%e aux typ3 ] [%e aux typ4 ]] + | [%type: [%t? typ1] * [%t? typ2] * [%t? typ3] * [%t? typ4] * [%t? typ5]] -> [%expr Elpi.Builtin.PPX.quintuple [%e aux typ1 ] [%e aux typ2 ] [%e aux typ3 ] [%e aux typ4 ] [%e aux typ5 ]] + | { ptyp_desc = Ptyp_tuple _; _ } -> error ~loc "seriously? I don't have sixtuples at hand, file a bugreport" + | { ptyp_desc = Ptyp_constr ({ txt = id; _ }, params); _ } -> + let id = pexp_ident @@ Located.mk id in + eapply id (List.map aux params) + | t -> error ~loc "cannot compute conversion for type %a" Pprintast.core_type t + in + aux ty + +let is_parameter id = Re.(Str.string_match (Str.regexp_string param_prefix) id 0) + +let rec find_embed_of (module B : Ast_builder.S) current_mutrec_block ty = let open B in + let rec aux ty = + match ty with + | [%type: [%t? typ] list] -> + [%expr (let embed = [%e aux typ] in + (fun ~depth h c s l -> + let s, l, eg = Elpi.API.Utils.map_acc (embed ~depth h c) s l in + s, Elpi.API.Utils.list_to_lp_list l, eg)) ] + | [%type: [%t? typ] option] -> [%expr Elpi.Builtin.PPX.embed_option [%e aux typ ]] + | [%type: [%t? typ1] * [%t? typ2]] -> [%expr Elpi.Builtin.PPX.embed_pair [%e aux typ1 ] [%e aux typ2 ]] + | [%type: [%t? typ1] * [%t? typ2] * [%t? typ3]] -> [%expr Elpi.Builtin.PPX.embed_triple [%e aux typ1 ] [%e aux typ2 ] [%e aux typ3 ]] + | [%type: [%t? typ1] * [%t? typ2] * [%t? typ3] * [%t? typ4]] -> [%expr Elpi.Builtin.PPX.embed_quadruple [%e aux typ1 ] [%e aux typ2 ] [%e aux typ3 ] [%e aux typ4 ]] + | [%type: [%t? typ1] * [%t? typ2] * [%t? typ3] * [%t? typ4] * [%t? typ5]] -> [%expr Elpi.Builtin.PPX.embed_quintuple [%e aux typ1 ] [%e aux typ2 ] [%e aux typ3 ] [%e aux typ4 ] [%e aux typ5 ]] + | { ptyp_desc = Ptyp_constr ({ txt = Longident.Lident id; _ }, params); _ } + when List.mem id current_mutrec_block || is_parameter id -> + eapply (evar (elpi_embed_name id)) (List.map (find_embed_of (module B) current_mutrec_block) params) + | t -> [%expr [%e conversion_of (module B) t ].Elpi.API.ContextualConversion.embed ] + in + [%expr fun ~depth h c s t -> [%e aux ty ] ~depth h c s t ] + +let rec find_readback_of (module B : Ast_builder.S) current_mutrec_block ty = let open B in + let rec aux ty = + match ty with + | [%type: [%t? typ] list] -> + [%expr (let readback = [%e aux typ] in + (fun ~depth h c s t -> Elpi.API.Utils.map_acc (readback ~depth h c) s (Elpi.API.Utils.lp_list_to_list ~depth t)))] + | [%type: [%t? typ] option] -> [%expr Elpi.Builtin.PPX.readback_option [%e aux typ ]] + | [%type: [%t? typ1] * [%t? typ2]] -> [%expr Elpi.Builtin.PPX.readback_pair [%e aux typ1 ] [%e aux typ2 ]] + | [%type: [%t? typ1] * [%t? typ2] * [%t? typ3]] -> [%expr Elpi.Builtin.PPX.readback_triple [%e aux typ1 ] [%e aux typ2 ] [%e aux typ3 ]] + | [%type: [%t? typ1] * [%t? typ2] * [%t? typ3] * [%t? typ4]] -> [%expr Elpi.Builtin.PPX.readback_quadruple [%e aux typ1 ] [%e aux typ2 ] [%e aux typ3 ] [%e aux typ4 ]] + | [%type: [%t? typ1] * [%t? typ2] * [%t? typ3] * [%t? typ4] * [%t? typ5]] -> [%expr Elpi.Builtin.PPX.readback_quintuple [%e aux typ1 ] [%e aux typ2 ] [%e aux typ3 ] [%e aux typ4 ] [%e aux typ5 ]] + | { ptyp_desc = Ptyp_constr ({ txt = Longident.Lident id; _ }, params); _ } + when List.mem id current_mutrec_block || is_parameter id -> + eapply (evar (elpi_readback_name id)) (List.map (find_readback_of (module B) current_mutrec_block) params) + | t -> [%expr [%e conversion_of (module B) t ].Elpi.API.ContextualConversion.readback ] + in + [%expr fun ~depth h c s t -> [%e aux ty ] ~depth h c s t ] + +let rec find_ty_ast_of (module B : Ast_builder.S) current_mutrec_block ty = let open B in + match ty with + | { ptyp_desc = Ptyp_constr ({ txt = Longident.Lident id; _ }, []); _ } + when List.mem id current_mutrec_block -> + [%expr Elpi.API.ContextualConversion.TyName([%e evar @@ elpi_tname_str id])] + | { ptyp_desc = Ptyp_constr ({ txt = Longident.Lident id; _ }, p::ps); _ } + when List.mem id current_mutrec_block -> + [%expr Elpi.API.ContextualConversion.TyApp([%e evar @@ elpi_tname_str id],[%e find_ty_ast_of (module B) current_mutrec_block p],[%e elist @@ List.map (find_ty_ast_of (module B) current_mutrec_block) ps ])] + | [%type: [%t? typ] list] -> [%expr Elpi.API.ContextualConversion.TyApp("list", [%e find_ty_ast_of (module B) current_mutrec_block typ ], [])] + | [%type: [%t? typ] option] -> [%expr Elpi.API.ContextualConversion.TyApp("option", [%e find_ty_ast_of (module B) current_mutrec_block typ ], [])] + | [%type: [%t? typ1] * [%t? typ2]] -> [%expr Elpi.API.ContextualConversion.TyApp("pair", [%e find_ty_ast_of (module B) current_mutrec_block typ1 ], [ [%e find_ty_ast_of (module B) current_mutrec_block typ2 ] ])] + | [%type: [%t? typ1] * [%t? typ2] * [%t? typ3]] -> [%expr Elpi.API.ContextualConversion.TyApp("triple", [%e find_ty_ast_of (module B) current_mutrec_block typ1 ], [ [%e find_ty_ast_of (module B) current_mutrec_block typ2 ]; [%e find_ty_ast_of (module B) current_mutrec_block typ3 ] ])] + | [%type: [%t? typ1] * [%t? typ2] * [%t? typ3] * [%t? typ4]] -> [%expr Elpi.API.ContextualConversion.TyApp("quadruple", [%e find_ty_ast_of (module B) current_mutrec_block typ1 ], [ [%e find_ty_ast_of (module B) current_mutrec_block typ2 ]; [%e find_ty_ast_of (module B) current_mutrec_block typ3 ]; [%e find_ty_ast_of (module B) current_mutrec_block typ4 ] ])] + | [%type: [%t? typ1] * [%t? typ2] * [%t? typ3] * [%t? typ4] * [%t? typ5]] -> [%expr Elpi.API.ContextualConversion.TyApp("quintuple", [%e find_ty_ast_of (module B) current_mutrec_block typ1 ], [ [%e find_ty_ast_of (module B) current_mutrec_block typ2 ]; [%e find_ty_ast_of (module B) current_mutrec_block typ3 ]; [%e find_ty_ast_of (module B) current_mutrec_block typ4 ]; [%e find_ty_ast_of (module B) current_mutrec_block typ5 ] ])] + | t -> [%expr [%e conversion_of (module B) t ].Elpi.API.ContextualConversion.ty ] + +let find_mapper_of (module B : Ast_builder.S) current_mutrec_block params ty = let open B in + let rec aux ty = + match ty with + | [%type: [%t? typ] list] -> [%expr Printf.sprintf "(ppx.map.list %s)" [%e aux typ] ] + | [%type: [%t? typ] option] -> [%expr Printf.sprintf "(ppx.map.option %s)" [%e aux typ] ] + | [%type: [%t? typ1] * [%t? typ2]] -> [%expr Printf.sprintf "(ppx.map.pair %s %s)" [%e aux typ1] [%e aux typ2] ] + | [%type: [%t? typ1] * [%t? typ2] * [%t? typ3]] -> [%expr Printf.sprintf "(ppx.map.triple %s %s %s)" [%e aux typ1] [%e aux typ2] [%e aux typ3] ] + | [%type: [%t? typ1] * [%t? typ2] * [%t? typ3] * [%t? typ4]] -> [%expr Printf.sprintf "(ppx.map.quadruple %s %s %s %s)" [%e aux typ1] [%e aux typ2] [%e aux typ3] [%e aux typ4] ] + | [%type: [%t? typ1] * [%t? typ2] * [%t? typ3] * [%t? typ4] * [%t? typ5]] -> [%expr Printf.sprintf "(ppx.map.quintuple %s %s %s %s %s)" [%e aux typ1] [%e aux typ2] [%e aux typ3] [%e aux typ4] [%e aux typ5] ] + | { ptyp_desc = Ptyp_constr ({ txt = Longident.Lident id; _ }, []); _ } when List.mem_assoc id params -> + estring @@ List.assoc id params + | { ptyp_desc = Ptyp_constr ({ txt = Longident.Lident id; _ }, []); _ } when List.mem id current_mutrec_block -> + [%expr "map." ^ [%e evar @@ elpi_tname_str id]] + | { ptyp_desc = Ptyp_constr ({ txt = Longident.Lident id; _ }, ps); _ } when List.mem id current_mutrec_block -> + [%expr "(map." ^ [%e evar @@ elpi_tname_str id] ^ " " ^ String.concat " " [%e elist @@ List.map (aux) ps] ^ ")"] + | _ -> [%expr "(=)"] + in + fun (v1,v2) -> [%expr "(" ^ [%e aux ty] ^ " " ^ [%e estring v1 ] ^ " " ^[%e estring v2 ] ^ ")" ] +;; + +let one_lident = function + | { pexp_desc = Pexp_ident { txt = Lident x ; _ }; _ } -> Some x + | _ -> None + +let one_string = function + | { pexp_desc = Pexp_constant (Pconst_string(s,_,None)); _ } -> Some s + | _ -> None + +let one_or_two_strings (module B : Ast_builder.S) = function + | Pexp_constant (Pconst_string (s,_,None)) -> s, None + | Pexp_apply(x,[_,y]) when option_is_some (one_string x) && option_is_some (one_string y) -> + option_get (one_string x), one_string y + | _ -> error "string or ident expected" + +let get_elpi_code (module B : Ast_builder.S) kname kattributes = + match Attribute.get att_elpi_code kattributes with + | None -> elpi_name_mangle kname, None + | Some payload -> one_or_two_strings (module B) payload.pexp_desc + +let get_elpi_tcode (module B : Ast_builder.S) kname kattributes = + match Attribute.get att_elpi_tcode kattributes with + | None -> elpi_name_mangle kname, None + | Some payload -> one_or_two_strings (module B) payload.pexp_desc + +let get_elpi_doc kname kattributes = + option_default kname (Attribute.get att_elpi_doc kattributes) +let get_elpi_tdoc kname kattributes = + option_default kname (Attribute.get att_elpi_tdoc kattributes) +let get_elpi_tdefkreadback tattributes = + Attribute.get att_elpi_def_k_readback tattributes +let get_elpi_pp tattributes = + Attribute.get att_elpi_tpp tattributes +let get_elpi_tindex tattributes = + Attribute.get att_elpi_tindex tattributes +let get_elpi_tcdata ~loc tattributes = + match Attribute.get att_elpi_tcdata tattributes with + | None -> error ~loc "opaque data types must have a [@@elpi.opaque d] attribute" + | Some c -> c +let has_elpi_tcdata tattributes = + option_is_some (Attribute.get att_elpi_tcdata tattributes) + +let parse_lident_list (module B : Ast_builder.S) = let open B in + let rec aux = function + | [%expr [] ] -> [] + | [%expr [%e? { pexp_desc = Pexp_ident { txt = Lident id; _}; _} ] :: [%e? tl ] ] -> id :: aux tl + | _ -> error ~loc "ident expected" + in + aux + +let analyze_tuple_constructor (module B : Ast_builder.S) tyname kname kattributes tl constructor pattern same_mutrec_block = let open B in + let c_str = elpi_kname_str tyname kname in + let c = elpi_kname tyname kname in + let elpi_doc = get_elpi_doc kname kattributes in + let str, elpi_code = get_elpi_code (module B) kname kattributes in + let decl_str = value_binding ~pat:(pvar c_str) ~expr:(estring str) in + let decl = value_binding ~pat:(pvar c) ~expr:[%expr Elpi.API.RawData.Constants.declare_global_symbol [%e evar @@ c_str ] ] in + let tl = + tl |> List.map (fun ty -> + match Attribute.get att_elpi_binder ty with + | Some [%expr [%e? { pexp_desc = Pexp_constant (Pconst_string(arrow_src_elpi,_,None)); _}] [%e? { pexp_desc = Pexp_ident { txt = Lident ctx; _}; _}] [%e? build_ctx] ] -> + HO { + ty; ctx; build_ctx; arrow_src_elpi; + readback = find_readback_of (module B) same_mutrec_block ty; + embed = find_embed_of (module B) same_mutrec_block ty; + ty_ast = find_ty_ast_of (module B) same_mutrec_block ty; + } + | Some [%expr [%e? { pexp_desc = Pexp_ident { txt = Lident ctx; _}; _}] [%e? build_ctx] ] -> + HO { + ty; ctx; build_ctx; arrow_src_elpi = tyname; + readback = find_readback_of (module B) same_mutrec_block ty; + embed = find_embed_of (module B) same_mutrec_block ty; + ty_ast = find_ty_ast_of (module B) same_mutrec_block ty; + } + | Some _ -> error ~loc "use [@elpi.binder \"ty\" ctx mk_ctx_entry]" + | None -> + let key = None <> Attribute.get att_elpi_key ty in + FO { + ty; key; + readback = find_readback_of (module B) same_mutrec_block ty; + embed = find_embed_of (module B) same_mutrec_block ty; + ty_ast = find_ty_ast_of (module B) same_mutrec_block ty; + }) in + let var_ = + match Attribute.get att_elpi_var kattributes with + | Some [%expr [%e? ctx_name ] [%e? get_key ]] when option_is_some (one_lident ctx_name) -> + Some (Name { get_key; ctx_name = option_get (one_lident ctx_name) }) + | Some [%expr [%e? ctx_name] ] when option_is_some (one_lident ctx_name) -> + Some (Name { get_key = [%expr fun x -> x]; ctx_name = option_get (one_lident ctx_name) }) + | Some _ -> error ~loc "use [@elpi.var ctx to_key]" + | None -> None in + let readback = Attribute.get att_elpi_readback kattributes in + let embed = Attribute.get att_elpi_embed kattributes in + let readback, embed = + let opt2custom = function None -> Standard | Some ml -> Custom { ml; pos = B.loc.loc_end } in + match readback, embed, var_ with + | _, _, None -> opt2custom readback, opt2custom embed + | None, None, Some p -> + if List.length tl = 1 then p, p + else error "[@elpi.var] on a constructor with zero or more than one argument and not [@elpi.readback]" + | None, (Some _ as e), Some p -> + if List.length tl = 1 then p, opt2custom e + else error "[@elpi.var] on a constructor with more than one argument and not [@elpi.readback]" + | (Some _ as r), None, Some p -> opt2custom r, p + | Some _, Some _, Some _ -> error "[@elpi.var] on a constructor with [@elpi.readback] and [@elpi.embed]" in + let ctx_names_of_directive = function + | Custom _ -> [] + | Standard -> [] + | Name { ctx_name; _ } -> [ctx_name] in + let ctx_names = + List.concat (ctx_names_of_directive embed :: ctx_names_of_directive readback :: + List.map (function HO { ctx; _ } -> [ctx] | _ -> []) tl) in + Expose { + declaration = [pstr_value Nonrecursive [decl_str]; pstr_value Nonrecursive [decl]] ; + constant = evar c; + constant_name = str; + elpi_code = option_map estring elpi_code; + elpi_doc; + arg_types = tl; + constructor; + pattern; + embed; + readback; + ctx_names; + } +;; + +let analyze_constructor (module B : Ast_builder.S) tyname same_mutrec_block decl = let open B in + match decl with + | { pcd_name = { txt = kname ; _ }; pcd_args; _ } when Attribute.get att_elpi_skip decl = Some () -> + Skip { constructor_name = kname; has_args = not (pcd_args = Pcstr_tuple []) } + | { pcd_name = { txt = kname ; _ }; pcd_args = Pcstr_tuple tl; pcd_res = None; _ } -> + let make_k args = + if args = [] then pexp_construct (Located.lident kname) None + else pexp_construct (Located.lident kname) (Some (pexp_tuple args)) in + let match_k args = + if args = [] then ppat_construct (Located.lident kname) None + else ppat_construct (Located.lident kname) (Some (ppat_tuple args)) in + analyze_tuple_constructor (module B) tyname kname decl tl make_k match_k same_mutrec_block + | { pcd_name = { txt = kname ; _ }; pcd_args = Pcstr_record lbltl; pcd_res = None; _ } -> + let lbls, tl = List.(split (map (fun { pld_name = { txt; _ }; pld_type; _} -> txt, pld_type) lbltl)) in + let make_k args = pexp_construct (Located.lident kname) (Some (pexp_record (List.map2 (fun x y -> B.Located.lident x,y) lbls args) None)) in + let match_k args = ppat_construct (Located.lident kname) (Some (ppat_record (List.map2 (fun x y -> B.Located.lident x,y) lbls args) Closed)) in + analyze_tuple_constructor (module B) tyname kname decl tl make_k match_k same_mutrec_block + | { pcd_loc = loc; _ } -> error ~loc "unsupportd constructor declaration" + +let extract_tyvar (x,_) = + match x.ptyp_desc with + | Ptyp_var s -> s + | _ -> error ~loc:x.ptyp_loc "Type abstracted over something that is not a type variable" + +let analyze_params (module B : Ast_builder.S) params = let open B in + let tyvars = List.map extract_tyvar params in + let mapper = object + inherit Ast_traverse.map as super + method! core_type x = + match x.ptyp_desc with + | Ptyp_var x when List.mem x tyvars -> ptyp_constr (B.Located.mk (Longident.parse @@ param_prefix ^ x)) [] + | _ -> super#core_type x + end in + List.map ((^) param_prefix) tyvars, mapper + +let mk_kind (module B : Ast_builder.S) vl name = let open B in + match List.map (fun x -> [%expr [%e evar x ].Elpi.API.ContextualConversion.ty]) vl with + | [] -> [%expr Elpi.API.ContextualConversion.TyName [%e name ]] + | x :: xs -> [%expr Elpi.API.ContextualConversion.TyApp([%e name], [%e x], [%e elist @@ xs])] + +let consistency_check ~loc tyds = + let context = ref None in + List.iter (fun tyd -> + let name, csts = + match tyd with + | { name; type_decl = Algebraic (l,_); _ } -> name, drop_skip l + | { name; _ } -> name, [] in + let some_have_key = + List.exists (fun { arg_types; _ } -> List.exists is_key arg_types) csts in + let all_have_1_key = + List.for_all (fun { arg_types; _ } -> + 1 = List.(length (filter is_key arg_types))) csts in + match tyd.index with + | None when some_have_key -> + error ~loc "type %s has [@elpi.key] but no index was provided. Use [@@elpi { index = (module M) }]" name + | Some _ when some_have_key && (not all_have_1_key) -> + error ~loc "type %s has constructor that does not have exactly one argumet marked as [@elpi.key]" name + | Some _ when all_have_1_key && tyd.params <> [] -> + error ~loc "type %s has [@elpi.key] but has parameters, not supported" name + | Some _ when !context <> None -> + let other, _, _ = option_get !context in + error ~loc "both %s and %s have [@elpi.key], not supported" name other + | Some m when all_have_1_key -> context := Some (name,m,tyd) + | _ -> ()) tyds; + !context +;; + +let pp_doc (module B : Ast_builder.S) kind elpi_name elpi_code elpi_doc is_pred csts = let open B in [%expr fun fmt () -> + [%e match elpi_code with + | None -> [%expr Elpi.API.PPX.Doc.kind fmt [%e kind] ~doc:[%e estring elpi_doc ] ] + | Some code -> + [%expr + Format.fprintf fmt "%s" ("% " ^ [%e estring elpi_doc ]); + Format.fprintf fmt "@\n@[kind %s@[ %s.@]@]@\n" + [%e elpi_name ] [%e code ] ] + ] ; + [%e esequence @@ + List.(concat @@ (drop_skip csts |> map (fun { constant_name = c; arg_types; embed; readback; elpi_code; elpi_doc; _ } -> + let types, ty = + if is_pred then ctx_index_ty (module B) :: arg_types, [%expr Elpi.API.ContextualConversion.TyName "prop"] + else arg_types, [%expr kind ] in + if is_name embed || is_name readback then [] + else [ + match elpi_code with + | Some code -> + [%expr + Format.fprintf fmt "@[type %s@[ %s. %% %s@]@]@\n" [%e estring c] [%e code] [%e estring elpi_doc ]] + | None -> [%expr + Elpi.API.PPX.Doc.constructor fmt + ~ty:[%e ty ] + ~name:[%e estring c] + ~doc:[%e estring elpi_doc ] + ~args:[%e elist @@ List.map (function + | FO { ty_ast; _ } -> ty_ast + | HO { arrow_src_elpi = s; ty_ast; _ } -> + [%expr Elpi.API.ContextualConversion.TyApp("->", + Elpi.API.ContextualConversion.TyName [%e estring s], + [[%e ty_ast]]) ] + ) types] + ] + ]))) + ]] +;; + + +let typeabbrev_for (module B : Ast_builder.S) f params = let open B in + let vars = List.mapi (fun i _ -> Printf.sprintf "A%d" i) params in + if params = [] then f else [%expr "(" ^ [%e f] ^ " " ^ [%e estring (String.concat " " vars) ] ^")" ] + +let typeabbrev_for_conv (module B : Ast_builder.S) ct = let open B in + [%expr Elpi.API.PPX.Doc.(show_ty_ast ~prec:AppArg) @@ [%e conversion_of (module B) ct].Elpi.API.ContextualConversion.ty ] + +let mk_pp_name (module B : Ast_builder.S) name = function + | None -> if name = "t" then B.evar "pp" else B.evar ("pp_" ^ name) + | Some e -> e + +let pp_for_conversion (module B : Ast_builder.S) name is_pred params pp = let open B in + let pp = mk_pp_name (module B) name pp in + if is_pred then [%expr fun fmt (_,x) -> [%e pp] fmt x] + else eapply pp (List.map (fun x -> [%expr [%e evar x].pp]) params) + +let quantify_ty_over_params (module B : Ast_builder.S) params t = let open B in + ptyp_poly (List.map Located.mk params) t + +let ctx_obj (module B : Ast_builder.S) name _is_pred _all_ctx = let open B in + ptyp_poly [] (ptyp_class (Located.lident (elpi_ctx_class_name name)) []) + +let conversion_type (module B : Ast_builder.S) name params is_pred all_ctx = let open B in + let rec aux = function + | [] -> + let t = ptyp_constr (Located.lident name) (List.map ptyp_var params) in + let t = if is_pred then ptyp_tuple [ [%type: Elpi.API.RawData.constant ] ;t] else t in + [%type: ([%t t ],[%t ctx_obj (module B) name is_pred all_ctx ] as 'c,'csts) Elpi.API.ContextualConversion.t] + | t :: ts -> [%type: ([%t ptyp_var t ],[%t ctx_obj (module B) name is_pred all_ctx ] as 'c,'csts) Elpi.API.ContextualConversion.t -> [%t aux ts]] + in + quantify_ty_over_params (module B) (params @ ["c";"csts"]) (aux params) + + +let readback_type (module B : Ast_builder.S) name params is_pred all_ctx = let open B in + let rec aux = function + | [] -> + let t = ptyp_constr (Located.lident name) (List.map ptyp_var params) in + let t = if is_pred then ptyp_tuple [ [%type: Elpi.API.RawData.constant ] ;t] else t in + [%type: ([%t t ], [%t ctx_obj (module B) name is_pred all_ctx ] as 'c, 'csts) Elpi.API.ContextualConversion.readback] + | t :: ts -> [%type: ([%t ptyp_var t ], [%t ctx_obj (module B) name is_pred all_ctx ] as 'c, 'csts) Elpi.API.ContextualConversion.readback -> [%t aux ts]] + in + quantify_ty_over_params (module B) (params @ ["c";"csts"]) (aux params) + +let embed_type (module B : Ast_builder.S) name params is_pred all_ctx = let open B in + let rec aux = function + | [] -> + let t = ptyp_constr (Located.lident name) (List.map ptyp_var params) in + let t = if is_pred then ptyp_tuple [ [%type: Elpi.API.RawData.constant ] ;t] else t in + [%type: ([%t t ],[%t ctx_obj (module B) name is_pred all_ctx ] as 'c, 'csts) Elpi.API.ContextualConversion.embedding] + | t :: ts -> [%type: ([%t ptyp_var t ],[%t ctx_obj (module B) name is_pred all_ctx ] as 'c, 'csts) Elpi.API.ContextualConversion.embedding -> [%t aux ts]] + in + quantify_ty_over_params (module B) (params @ ["c";"csts"]) (aux params) + + +let lift_conversion (module B : Ast_builder.S) e = let open B in + [%expr + let { Elpi.API.Conversion.embed; readback; ty; pp_doc; pp } = [%e e ] in + let embed = (fun ~depth _ _ s t -> embed ~depth s t) in + let readback = (fun ~depth _ _ s t -> readback ~depth s t) in + { Elpi.API.ContextualConversion.embed; readback; ty; pp_doc; pp } + ] + +let coversion_for_opaque (module B : Ast_builder.S) elpi_name name = let open B in + value_binding ~pat:(ppat_constraint (pvar name) + (quantify_ty_over_params (module B) ["c"] + [%type: ( [%t ptyp_constr (Located.lident name) []] , #Elpi.API.ContextualConversion.ctx as 'c, 'csts) Elpi.API.ContextualConversion.t])) + ~expr:(lift_conversion (module B) (evar @@ elpi_cdata_name name)) + (* + + let name = [%e elpi_name ] in + let { Elpi.API.RawOpaqueData.cin; isc; cout; name=c }, constants_map, doc = [%e evar @@ elpi_cdata_name name ] in + + let ty = Elpi.API.ContextualConversion.TyName name in + let embed ~depth:_ state x = + state, Elpi.API.RawData.mkCData (cin x), [] in + let readback ~depth state t = + match Elpi.API.RawData.look ~depth t with + | Elpi.API.RawData.CData c when isc c -> state, cout c, [] + | Elpi.API.RawData.Const i when i < 0 -> + begin try state, snd @@ Elpi.API.RawData.Constants.Map.find i constants_map, [] + with Not_found -> raise (Elpi.API.Conversion.TypeErr(ty,depth,t)) end + | _ -> raise (Elpi.API.Conversion.TypeErr(ty,depth,t)) in + let pp_doc fmt () = + if doc <> "" then begin + Format.fprintf fmt "%s" ("% " ^ doc); + Format.fprintf fmt "@\n"; + end; + Format.fprintf fmt "@[typeabbrev %s (ctype \"%s\").@]@\n@\n" name c; + Elpi.API.RawData.Constants.Map.iter (fun _ (c,_) -> + Format.fprintf fmt "@[type %s %s.@]@\n" c name) + constants_map + in + { Elpi.API.ContextualConversion.embed; readback; ty; pp_doc; pp = (fun fmt x -> Elpi.API.RawOpaqueData.pp fmt (cin x)) } +*) + + +let abstract_expr_over_params (module B : Ast_builder.S) vl f e = let open B in + let rec aux = function + | [] -> e + | v :: vs -> [%expr fun [%p pvar (f v) ] -> [%e aux vs]] + in + aux vl + +let ctx_class_type_for_tyd (module B : Ast_builder.S) all_ctx { name; _ } = let open B in + pstr_module @@ module_binding ~name:(Located.mk (Some (elpi_ctx_class_module_name name))) ~expr:(pmod_structure [ + pstr_class_type [class_infos ~virt:Concrete ~params:[] + ~name:(Located.mk "t") + ~expr:(pcty_signature @@ class_signature ~self:[%type: _] ~fields:( + (pctf_inherit (pcty_constr (Located.lident "Elpi.API.ContextualConversion.ctx") [])) + :: List.flatten (SSet.elements all_ctx |> List.(map (fun c -> + [ + pctf_inherit (pcty_constr (Located.lident @@ elpi_ctx_class_name c) []); + pctf_method (Located.mk c,Public,Concrete,[%type: [%t ptyp_constr (Located.lident c) [] ] Elpi.API.ContextualConversion.ctx_field]); + ])))))] + ]) + +let conversion_for_tyd (module B : Ast_builder.S) all_ctx { name; params; elpi_name; elpi_code; elpi_doc; type_decl; pp; index } = let open B in + let is_pred = option_is_some index in + match type_decl with + | Opaque _ -> + [coversion_for_opaque (module B) (estring elpi_name) name] + | Alias _ -> + [value_binding ~pat:(ppat_constraint (pvar name) (conversion_type (module B) name params is_pred all_ctx)) ~expr:(abstract_expr_over_params (module B) params (fun x -> x) ([%expr + let kind = [%e mk_kind (module B) params (estring elpi_name) ] in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = [%e pp_doc (module B) [%expr kind] (estring elpi_name) (option_map estring elpi_code) elpi_doc is_pred [] ]; + pp = [%e pp_for_conversion (module B) name is_pred params pp ]; + embed = [%e eapply (evar (elpi_embed_name name)) (List.map (fun x -> [%expr [%e evar x].Elpi.API.ContextualConversion.embed]) params) ]; + readback = [%e eapply (evar (elpi_readback_name name)) (List.map (fun x -> [%expr [%e evar x].Elpi.API.ContextualConversion.readback]) params) ]; + }]))] + | Algebraic(csts,_)-> + [value_binding ~pat:(ppat_constraint (pvar name) (conversion_type (module B) name params is_pred all_ctx)) ~expr:(abstract_expr_over_params (module B) params (fun x -> x) ([%expr + let kind = [%e mk_kind (module B) params (estring elpi_name) ] in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = [%e pp_doc (module B) [%expr kind] (estring elpi_name) (option_map estring elpi_code) elpi_doc is_pred csts ]; + pp = [%e pp_for_conversion (module B) name is_pred params pp ]; + embed = [%e eapply (evar (elpi_embed_name name)) (List.map (fun x -> [%expr [%e evar x].Elpi.API.ContextualConversion.embed]) params) ]; + readback = [%e eapply (evar (elpi_readback_name name)) (List.map (fun x -> [%expr [%e evar x].Elpi.API.ContextualConversion.readback]) params) ]; + }]))] +;; + +let initial_state (module B : Ast_builder.S) name = let open B in + let elpi_Map = elpi_Map ~loc name in [%expr + ( [%e elpi_Map "empty" ] : [%t ptyp_constr (Located.lident (elpi_map_name name ^ ".t")) [ [%type: Elpi.API.RawData.constant] ] ]) + , + (Elpi.API.RawData.Constants.Map.empty : [%t ptyp_constr (Located.lident name) [] ] Elpi.API.ContextualConversion.ctx_entry Elpi.API.RawData.Constants.Map.t) + ] + +let conversion_context_for_tyd (module B : Ast_builder.S) name = let open B in [ + [%stri let [%p pvar @@ elpi_readback_ctx_name name] = { + Elpi.API.ContextualConversion.is_entry_for_nominal = [%e evar @@ elpi_is_ctx_entry_name name ]; + to_key = [%e evar @@ elpi_to_key name ]; + push = [%e evar @@ elpi_push name ]; + pop = [%e evar @@ elpi_pop name ]; + conv = [%e evar name]; + init = (fun state -> Elpi.API.State.set [%e evar @@ elpi_state_name name ] state [%e initial_state (module B) name]); + get = (fun state -> snd @@ Elpi.API.State.get [%e evar @@ elpi_state_name name ] state); + }]] + +let embed_for_tyd (module B : Ast_builder.S) same_mutrec_block all_ctx { name; params; type_decl; index; _ } = let open B in + let is_pred = option_is_some index in + match type_decl with + | Opaque _ -> if params <> [] then error ~loc "opaque data type with parameters not supported"; + value_binding ~pat:(pvar (elpi_embed_name name)) ~expr:[%expr [%e evar name].Elpi.API.ContextualConversion.embed ] + | Alias orig -> + value_binding ~pat:(ppat_constraint (pvar (elpi_embed_name name)) (embed_type (module B) name params is_pred all_ctx)) + ~expr:(abstract_expr_over_params (module B) params elpi_embed_name @@ find_embed_of (module B) same_mutrec_block orig) + | Algebraic(csts,_) -> + value_binding ~pat:(ppat_constraint (pvar (elpi_embed_name name)) (embed_type (module B) name params is_pred all_ctx)) + ~expr:(abstract_expr_over_params (module B) params elpi_embed_name @@ embed (module B) is_pred csts) + +let readback_for_tyd (module B : Ast_builder.S) same_mutrec_block all_ctx { name; params; type_decl; index; _ } = let open B in + let is_pred = option_is_some index in + match type_decl with + | Opaque _ -> if params <> [] then error ~loc "opaque data type with parameters not supported"; + value_binding ~pat:(pvar (elpi_readback_name name)) ~expr:[%expr [%e evar name].Elpi.API.ContextualConversion.readback ] + | Alias orig -> + value_binding ~pat:(ppat_constraint (pvar (elpi_readback_name name)) (readback_type (module B) name params is_pred all_ctx)) + ~expr:(abstract_expr_over_params (module B) params elpi_readback_name @@ find_readback_of (module B) same_mutrec_block orig) + | Algebraic(csts,def_readback) -> + value_binding ~pat:(ppat_constraint (pvar (elpi_readback_name name)) (readback_type (module B) name params is_pred all_ctx)) + ~expr:(abstract_expr_over_params (module B) params elpi_readback_name @@ readback (module B) name is_pred def_readback csts) + +let in_ctx_for_tyd (module B : Ast_builder.S) ctx { name; _ } = let open B in + let ctx = SSet.elements ctx in + [ + pstr_class [class_infos ~virt:Concrete ~params:[] + ~name:(Located.mk @@ elpi_ctx_object_name name) + ~expr:(pcl_fun Nolabel None (ppat_constraint (pvar "h") (ptyp_constr (Located.lident "Elpi.API.Data.hyps") [])) @@ + pcl_fun Nolabel None (ppat_constraint (pvar "s") (ptyp_constr (Located.lident "Elpi.API.Data.state") [])) @@ + pcl_constraint + (pcl_structure @@ class_structure ~self:(pvar "_") + ~fields:( + pcf_inherit Fresh + (pcl_apply (pcl_constr (Located.lident "Elpi.API.ContextualConversion.ctx") []) [Nolabel,evar "h"]) None + :: List.flatten (ctx |> List.map (fun c -> [ + pcf_inherit Override + (pcl_apply (pcl_constr (Located.lident @@ elpi_ctx_object_name c) []) [Nolabel,evar "h";Nolabel,evar "s"]) None ; + pcf_method (Located.mk c,Public,Cfk_concrete (Fresh, + [%expr [%e evar @@ elpi_readback_ctx_name c ].Elpi.API.ContextualConversion.get s]))])))) + (pcty_constr (Located.lident @@ elpi_ctx_class_name name) []))] +; + (* apparently you cannot declare a class type and a class with the same name *) + [%stri let [%p pvar @@ elpi_in_ctx_for_name name ] : + ([%t ptyp_constr (Located.lident @@ elpi_ctx_class_name name) []],'csts) Elpi.API.ContextualConversion.ctx_readback + = fun ~depth h c s -> [%e + let gls = List.mapi (fun i _ -> Printf.sprintf "gls%d" i) ctx in + let rec aux = function + | [] -> [%expr s, [%e pexp_new @@ Located.lident @@ elpi_ctx_object_name name] h s, c, List.concat [%e elist @@ List.map evar gls ]] + | (c,gls) :: cs -> + [%expr + let ctx = [%e pexp_new @@ Located.lident @@ elpi_ctx_object_name c] h s in + let s, [%p pvar gls ] = + Elpi.API.PPX.readback_context ~depth [%e evar @@ elpi_readback_ctx_name c] ctx h c s in + [%e aux cs ] + ] + in + aux (List.combine ctx gls) + ]] +] + +let constants_of_tyd (module B : Ast_builder.S) { type_decl ; elpi_name; name; _ } = let open B in + let c_str = elpi_tname_str name in + let decl_str = + value_binding ~pat:(pvar c_str) ~expr:(estring elpi_name) in + let decl = + let c = elpi_tname name in + value_binding ~pat:(pvar c) ~expr:[%expr Elpi.API.RawData.Constants.declare_global_symbol [%e evar c_str ]] in + pstr_value Nonrecursive [decl_str] :: + pstr_value Nonrecursive [decl] :: + match type_decl with + | Alias _ -> [] + | Opaque opaque_data -> + [pstr_value Nonrecursive [ + value_binding ~pat:(pvar @@ elpi_cdata_name name) + ~expr:[%expr Elpi.API.OpaqueData.declare [%e opaque_data]]]] + | Algebraic (csts,_) -> List.flatten @@ List.map (fun x -> x.declaration) @@ drop_skip csts + +let elpi_declaration_of_tyd (module B : Ast_builder.S) tyd = let open B in + let decl_name = "elpi_"^tyd.name in + let decl = + match tyd.type_decl with + | Alias orig -> + (if tyd.params = [] then (fun x -> x) + else pexp_let Nonrecursive (List.mapi (fun i x -> value_binding ~pat:(pvar x) ~expr:(pexp_ident @@ Located.lident @@ Printf.sprintf "Elpi.API.BuiltInContextualData.polyA%d" i)) tyd.params)) + [%expr + Elpi.API.BuiltIn.LPCode ("typeabbrev " ^ + [%e typeabbrev_for (module B) (estring tyd.elpi_name) tyd.params ] ^ " " ^ + [%e typeabbrev_for_conv (module B) orig ] ^ ". % " ^ [%e estring tyd.elpi_doc ]) ] + | Opaque _ -> + [%expr Elpi.API.BuiltIn.MLDataC [%e + if tyd.params = [] then evar tyd.name + else error ~loc "opaque with params" ]] + | Algebraic _ -> + let vars = List.mapi (fun i _ -> pexp_ident @@ Located.lident @@ Printf.sprintf "Elpi.API.BuiltInContextualData.polyA%d" i) tyd.params in + [%expr Elpi.API.BuiltIn.MLDataC [%e + if tyd.params = [] then evar tyd.name + else eapply (evar tyd.name) vars]] in + { decl = pstr_value Nonrecursive [value_binding ~pat:(pvar decl_name) ~expr:decl]; + decl_name = evar decl_name; } + +let mapper_for_tyd (module B : Ast_builder.S) same_block tyd = let open B in + if option_is_some tyd.index then None else + let tyvars = List.mapi (fun i _ -> Printf.sprintf "X%d" i) tyd.params in + let tyvars1 = List.mapi (fun i _ -> Printf.sprintf "Y%d" i) tyd.params in + let ty_w_params vars = + if vars = [] then tyd.elpi_name + else tyd.elpi_name ^ " " ^ String.concat " " vars in + let fvars = List.mapi (fun i _ -> Printf.sprintf "F%d" i) tyd.params in + let param2fv = List.combine tyd.params fvars in + let ty_fvars = + if tyvars = [] then "" + else String.concat ", " (List.map2 (Printf.sprintf "i:(%s -> %s -> prop)") tyvars tyvars1) ^ ", " in + let pred_decl = + estring @@ Printf.sprintf "pred map.%s %s i:%s, o:%s." tyd.elpi_name ty_fvars (ty_w_params tyvars) (ty_w_params tyvars1) in + let fvars_str = if fvars = [] then "" else (String.concat " " fvars ^ " ") in + match tyd.type_decl with + | Opaque _ -> None + | Alias orig -> + let mapper = + [%expr Printf.sprintf "map.%s %sA B :- %s." + [%e estring @@ tyd.elpi_name] + [%e estring @@ fvars_str] + [%e find_mapper_of (module B) same_block param2fv orig ("A","B") ]] in + Some [%expr String.concat "\n" [%e elist [pred_decl ; mapper]]] + | Algebraic(csts,_) -> + let mapka ty (v1,v2) = + match ty with + | FO { ty; _ } -> find_mapper_of (module B) same_block param2fv ty (v1,v2) + | HO _ -> [%expr Printf.sprintf "(pi x\ fixme x => (=) %s %s)" [%e estring @@ v1] [%e estring @@ v2] ] in + let mapk { constant_name; arg_types; _ } = + if arg_types = [] then + estring @@ Printf.sprintf "map.%s %s%s %s." tyd.elpi_name fvars_str constant_name constant_name + else + let vars = List.mapi (fun i _ -> Printf.sprintf "A%d" i) arg_types in + let vars1 = List.mapi (fun i _ -> Printf.sprintf "B%d" i) arg_types in + let vars_s = String.concat " " vars in + let vars1_s = String.concat " " vars1 in + let body = List.map2 mapka arg_types (List.combine vars vars1) in + [%expr Printf.sprintf "map.%s %s(%s %s) (%s %s) :- %s." + [%e estring @@ tyd.elpi_name] + [%e estring @@ fvars_str] + [%e estring @@ constant_name] + [%e estring @@ vars_s] + [%e estring @@ constant_name] + [%e estring @@ vars1_s] + (String.concat ", " [%e elist @@ body])] in + let mapper = List.map mapk (drop_skip csts) in + Some [%expr String.concat "\n" [%e elist @@ (pred_decl :: mapper @ [estring "\n"])]] +;; + +let extras_of_task (module B : Ast_builder.S) { types; names; context; ctx_names } = let open B in + let is_opaque = function Opaque _ -> true | _ -> false in + let ty_extras = + types |> List.map (fun tyd -> { + ty_constants = constants_of_tyd (module B) tyd; + ty_embed = embed_for_tyd (module B) names ctx_names tyd; + ty_readback = readback_for_tyd (module B) names ctx_names tyd; + ty_ctx_class_type = ctx_class_type_for_tyd (module B) ctx_names tyd; + ty_conversion = conversion_for_tyd (module B) ctx_names tyd; + ty_conversion_name = tyd.name; + ty_elpi_declaration = elpi_declaration_of_tyd (module B) tyd; + ty_opaque = is_opaque tyd.type_decl; + ty_library = mapper_for_tyd (module B) names tyd; + ty_in_ctx = in_ctx_for_tyd (module B) ctx_names tyd; + }) in + let ctx_extras = + match context with + | None -> None + | Some(name,m,tyd) -> + let elpi_name = tyd.elpi_name in + let csts = + match tyd.type_decl with Algebraic(x,_) -> x | _ -> error "context ADT must be explicit" in + Some { + ty_context_helpers = [ + pstr_module (module_binding ~name:(Located.mk (Some (elpi_map_name name))) + ~expr:(pmod_apply (pmod_ident (Located.mk (Longident.parse "Elpi.API.Utils.Map.Make"))) m)); + pstr_value Nonrecursive [value_binding ~pat:(pvar (elpi_state_name name)) ~expr:[%expr + Elpi.API.State.declare ~name:[%e estring elpi_name] ~pp:(fun fmt _ -> Format.fprintf fmt "TODO") + ~init:(fun () -> [%e initial_state (module B) name]) + ~start:(fun x -> x); + ]]; + pstr_value Nonrecursive [value_binding ~pat:(pvar (elpi_to_key name)) ~expr:(ctx_entry_key (module B) csts)]; + pstr_value Nonrecursive [value_binding ~pat:(pvar (elpi_is_ctx_entry_name name)) ~expr:(is_ctx_entry (module B) csts)]; + pstr_value Nonrecursive [value_binding ~pat:(pvar (elpi_push name)) ~expr:(ctx_push (module B) name)]; + pstr_value Nonrecursive [value_binding ~pat:(pvar (elpi_pop name)) ~expr:(ctx_pop (module B) name)]; + ]; + ty_context_readback = conversion_context_for_tyd (module B) tyd.name; + } in + { ty_extras; ctx_extras } +;; + +let analyze_typedecl (module B : Ast_builder.S) same_mutrec_block tdecl = + match tdecl with + | { + ptype_name = { txt = name ; _ }; + ptype_params = params; + ptype_cstrs = _; + ptype_kind = k; + ptype_manifest; + _ + } when (k = Ptype_abstract && ptype_manifest = None) || has_elpi_tcdata tdecl -> + let params, _ = analyze_params (module B) params in + let elpi_name, elpi_code = get_elpi_tcode (module B) name tdecl in + let elpi_doc = get_elpi_tdoc name tdecl in + let pp = get_elpi_pp tdecl in + let index = get_elpi_tindex tdecl in + let cdata = get_elpi_tcdata ~loc:B.loc tdecl in + { name; params; type_decl = Opaque cdata; elpi_name; elpi_code; elpi_doc; pp; index } + + | { + ptype_name = { txt = name ; _ }; + ptype_params = params; + ptype_cstrs = _; + ptype_kind = Ptype_abstract; + ptype_manifest = Some alias; + _ + } -> + let params, typ = analyze_params (module B) params in + let alias = typ#core_type alias in + let elpi_name, elpi_code = get_elpi_tcode (module B) name tdecl in + let elpi_doc = get_elpi_tdoc name tdecl in + let pp = get_elpi_pp tdecl in + let index = get_elpi_tindex tdecl in + { name; params; type_decl = Alias alias; elpi_name; elpi_code; elpi_doc; pp; index } + + | { + ptype_name = { txt = name ; _ }; + ptype_params = params; + ptype_cstrs = _; + ptype_kind = Ptype_variant csts; + _ + } -> + let params, typ = analyze_params (module B) params in + let csts = List.map typ#constructor_declaration csts in + let csts = List.map (analyze_constructor (module B) name same_mutrec_block) csts in + let elpi_name, elpi_code = get_elpi_tcode (module B) name tdecl in + let elpi_doc = get_elpi_tdoc name tdecl in + let default_readback = get_elpi_tdefkreadback tdecl in + let pp = get_elpi_pp tdecl in + let index = get_elpi_tindex tdecl in + { name; params; type_decl = Algebraic(csts,default_readback); elpi_name; elpi_code; elpi_doc; pp; index } + + | { + ptype_name = { txt = name ; _ }; + ptype_params = params; + ptype_cstrs = _; + ptype_kind = Ptype_record lbltl; + ptype_attributes; + _ + } -> + let params, typ = analyze_params (module B) params in + let lbltl = List.map typ#label_declaration lbltl in + let lbls, tl = List.(split (map (fun { pld_name = { txt; _ }; pld_type; _} -> txt, pld_type) lbltl)) in + let make_k args = B.pexp_record (List.map2 (fun x y -> B.Located.lident x, y) lbls args) None in + let match_k args = B.ppat_record (List.map2 (fun x y -> B.Located.lident x, y) lbls args) Closed in + let kdecl = { + pcd_name = B.Located.mk name; + pcd_args = Pcstr_tuple []; pcd_vars=[]; + pcd_res = None; + pcd_loc = B.loc; + pcd_attributes = ptype_attributes; + } in + let csts = [analyze_tuple_constructor (module B) name name kdecl tl make_k match_k same_mutrec_block] in + let elpi_name, elpi_code = get_elpi_tcode (module B) name tdecl in + let elpi_doc = get_elpi_tdoc name tdecl in + let default_readback = get_elpi_tdefkreadback tdecl in + let pp = get_elpi_pp tdecl in + let index = get_elpi_tindex tdecl in + { name; params; type_decl = Algebraic(csts,default_readback); elpi_name; elpi_code; elpi_doc; pp; index } + + | _ -> error ~loc:B.loc "unsupportd type declaration" +;; + +let typedecl_extras (module B : Ast_builder.S) all_context tyds = + let tyd_names = List.map (fun x -> x.ptype_name.txt) tyds in + let tyds = List.map (analyze_typedecl (module B) tyd_names) tyds in + let ctx_names = + List.fold_left (fun acc x -> match x.type_decl with + | Opaque _ | Alias _ -> acc + | Algebraic (cl,_) -> + List.fold_left (fun acc -> function + | Skip _ -> acc + | Expose { ctx_names; _ } -> List.fold_right SSet.add ctx_names acc) + acc cl) + SSet.empty tyds in + let ctx_names = + match all_context with + | None -> ctx_names + | Some all -> + let all = parse_lident_list (module B) all in + let all = SSet.of_list all in + if not (SSet.subset ctx_names all) then + error ~loc:B.loc "[deriving elpi { context }] directive contains %a but the type mentions more: %a" SSet.pp all SSet.pp (SSet.diff ctx_names all); + all in + + let context = consistency_check ~loc:B.loc tyds in + + let mut = { types = tyds; ctx_names; names = tyd_names; context } in + + extras_of_task (module B) mut +;; + +(* + let one_ty t = + match t.ptyp_desc with + | Ptyp_constr({ txt; _ },args) -> + if args <> [] then nYI ~loc ~__LOC__ () + else + if List.length (Longident.flatten_exn txt) > 1 then nYI ~loc ~__LOC__ () + else String.concat "." (Longident.flatten_exn txt) + | _ -> error ~loc "[@elpi.context] payload is invalid: %a" Ocaml_common.Pprintast.core_type (Selected_ast.To_ocaml.copy_core_type t) in + let one_arrow t = + match t.ptyp_desc with + | Ptyp_arrow(_,s,t) -> one_ty s , one_ty t + | _ -> error ~loc "[elpi.context] payload is invalid: %a" Ocaml_common.Pprintast.core_type (Selected_ast.To_ocaml.copy_core_type t) in + let kind = + match index, context with + | None, None -> ADT + | Some m, None -> CTX(m,[]) + | Some m, Some ty -> CTX(m,[one_ty ty]) + | None, Some ty -> + match ty.ptyp_desc with + | Ptyp_tuple l -> HOAS (List.map one_arrow l) + | Ptyp_arrow _ -> HOAS [one_arrow ty] + | _ -> HOAS [tyd.name, one_ty ty] + in + + let task = tyd, kind in + + consistency_check ~loc:B.loc task; + + extras_of_task (module B) task tyd_names +;; +*) + +let tydecls ~loc append_decl append_mapper all_context _r tdls = + let module B = Ast_builder.Make(struct let loc = loc end) in + let open B in + let { ty_extras; ctx_extras } = typedecl_extras (module B) all_context tdls in + let opaque_extra, non_opaque_extra = List.partition (fun x -> x.ty_opaque) ty_extras in + + pstr_attribute { attr_name = Located.mk "warning"; attr_payload = PStr [pstr_eval (estring "-26-27-32-39-60") []]; attr_loc = loc } :: + + List.(concat (map (fun x -> x.ty_constants) ty_extras)) @ + option_default [] (option_map (fun x -> x.ty_context_helpers) ctx_extras) @ + List.(map (fun x -> x.ty_ctx_class_type) ty_extras) @ + + begin if opaque_extra <> [] then + [pstr_value Nonrecursive List.(concat_map (fun x -> x.ty_conversion) opaque_extra)] @ + [pstr_value Nonrecursive List.(map (fun x -> x.ty_embed) opaque_extra)] @ + [pstr_value Nonrecursive List.(map (fun x -> x.ty_readback) opaque_extra)] + else [] end @ + + begin if non_opaque_extra <> [] then + [pstr_value Recursive ( + List.map (fun x -> x.ty_embed) non_opaque_extra @ + List.map (fun x -> x.ty_readback) non_opaque_extra @ + List.concat_map (fun x -> x.ty_conversion) non_opaque_extra + )] + else [] end @ + + option_default [] (option_map (fun x -> x.ty_context_readback) ctx_extras) @ + List.(map (fun x -> x.ty_elpi_declaration.decl) ty_extras) @ + List.(concat (map (fun x -> x.ty_in_ctx) ty_extras)) @ + + begin match append_decl with + | None -> [] + | Some l -> [pstr_value Nonrecursive [value_binding ~pat:(punit) + ~expr:[%expr [%e l] := ![%e l] @ + [%e elist @@ List.(map (fun x -> x.ty_elpi_declaration.decl_name) ty_extras) ]]]] + end @ + + begin match append_mapper with + | None -> [] + | Some l -> [pstr_value Nonrecursive [value_binding ~pat:(punit) + ~expr:[%expr [%e l] := ![%e l] @ [String.concat "\n" + [%e elist @@ List.map (fun x -> + match x.ty_library with + | None -> [%expr ""] + | Some e -> e) ty_extras] + ]]]] + end +;; + +let conversion_of_expansion ~loc ~path:_ ty = + conversion_of (module Ast_builder.Make(struct let loc = loc end)) ty + +let conversion_extension = + Extension.declare + "elpi" + Extension.Context.expression + Ast_pattern.(ptyp __) + conversion_of_expansion + +let expand_str ~loc ~path:_ (r,tydecl) (declaration : expression option) (mapper : expression option) (context : expression option) = tydecls ~loc declaration mapper context r tydecl +let expand_sig ~loc ~path:_ (_r,_tydecl) (_index : module_expr option) = nYI ~loc ~__LOC__ () + +let attributes = Attribute.([ + T att_elpi_tcode; + T att_elpi_tdoc; + T att_elpi_var ; + T att_elpi_skip ; + T att_elpi_embed; + T att_elpi_readback; + T att_elpi_code; + T att_elpi_doc; + T att_elpi_key; + T att_elpi_binder +]) + + +let str_type_decl_generator = + Deriving.Generator.make + ~attributes + arguments + expand_str + +let arguments = Deriving.Args.(empty + +> arg "index" (pexp_pack __) +) + +let sig_type_decl_generator = + Deriving.Generator.make + ~attributes + arguments + expand_sig + +let my_deriver = + Deriving.add + ~str_type_decl:str_type_decl_generator + ~sig_type_decl:sig_type_decl_generator + "elpi" + +let () = + Driver.register_transformation + ~extensions:[ conversion_extension; ] + "elpi.conversion" diff --git a/ppx_elpi/tests/README.md b/ppx_elpi/tests/README.md new file mode 100644 index 000000000..e51ce1eae --- /dev/null +++ b/ppx_elpi/tests/README.md @@ -0,0 +1,17 @@ +## Usage + +To add a new test + +```shell +touch test_XXX.ml +touch test_XXX.expected.ml +touch test_XXX.expected.elpi +dune runtest --auto-promote # promotes the dune file +``` + +As a template for `test_XXX.ml` you should use `test_simple_adt.ml`` + +To run tests and acknowledge a change +```shell +dune runtest --auto-promote # promotes the output +``` diff --git a/ppx_elpi/tests/dune b/ppx_elpi/tests/dune new file mode 100644 index 000000000..05663311d --- /dev/null +++ b/ppx_elpi/tests/dune @@ -0,0 +1,28 @@ +(env + (dev + (flags (:standard -warn-error -A)))) + +(executable + (name pp) + (modules pp) + (promote) + (libraries elpi.ppx ppxlib)) + +(include dune.inc) + +(executable + (name gen_dune) + (libraries re) + (modules gen_dune) +) + +(rule + (targets dune.inc.gen) + (deps (:gen gen_dune.exe) (source_tree .)) + (action (with-stdout-to %{targets} (run %{gen}))) +) + +(rule + (alias runtest) + (action (diff dune.inc dune.inc.gen)) +) \ No newline at end of file diff --git a/ppx_elpi/tests/dune.inc b/ppx_elpi/tests/dune.inc new file mode 100644 index 000000000..4980df001 --- /dev/null +++ b/ppx_elpi/tests/dune.inc @@ -0,0 +1,299 @@ + +(rule + (targets test_alias_type.actual.ml) + (deps (:pp pp.exe) (:input test_alias_type.ml)) + (action (run ./%{pp} -deriving-keep-w32 both --impl %{input} -o %{targets}))) + +(rule + (alias runtest) + (action (diff test_alias_type.expected.ml test_alias_type.actual.ml))) + +(rule + (alias runtest) + (action (diff test_alias_type.expected.elpi test_alias_type.actual.elpi))) + +(rule + (target test_alias_type.actual.elpi) + (action (run ./test_alias_type.exe %{target}))) + +(executable + (name test_alias_type) + (modules test_alias_type) + (preprocess (pps elpi.ppx))) + + +(rule + (targets test_container.actual.ml) + (deps (:pp pp.exe) (:input test_container.ml)) + (action (run ./%{pp} -deriving-keep-w32 both --impl %{input} -o %{targets}))) + +(rule + (alias runtest) + (action (diff test_container.expected.ml test_container.actual.ml))) + +(rule + (alias runtest) + (action (diff test_container.expected.elpi test_container.actual.elpi))) + +(rule + (target test_container.actual.elpi) + (action (run ./test_container.exe %{target}))) + +(executable + (name test_container) + (modules test_container) + (preprocess (pps elpi.ppx))) + + +(rule + (targets test_double_contextual.actual.ml) + (deps (:pp pp.exe) (:input test_double_contextual.ml)) + (action (run ./%{pp} -deriving-keep-w32 both --impl %{input} -o %{targets}))) + +(rule + (alias runtest) + (action (diff test_double_contextual.expected.ml test_double_contextual.actual.ml))) + +(rule + (alias runtest) + (action (diff test_double_contextual.expected.elpi test_double_contextual.actual.elpi))) + +(rule + (target test_double_contextual.actual.elpi) + (action (run ./test_double_contextual.exe %{target}))) + +(executable + (name test_double_contextual) + (modules test_double_contextual) + (preprocess (pps elpi.ppx))) + + +(rule + (targets test_mutual_adt.actual.ml) + (deps (:pp pp.exe) (:input test_mutual_adt.ml)) + (action (run ./%{pp} -deriving-keep-w32 both --impl %{input} -o %{targets}))) + +(rule + (alias runtest) + (action (diff test_mutual_adt.expected.ml test_mutual_adt.actual.ml))) + +(rule + (alias runtest) + (action (diff test_mutual_adt.expected.elpi test_mutual_adt.actual.elpi))) + +(rule + (target test_mutual_adt.actual.elpi) + (action (run ./test_mutual_adt.exe %{target}))) + +(executable + (name test_mutual_adt) + (modules test_mutual_adt) + (preprocess (pps elpi.ppx))) + + +(rule + (targets test_opaque_type.actual.ml) + (deps (:pp pp.exe) (:input test_opaque_type.ml)) + (action (run ./%{pp} -deriving-keep-w32 both --impl %{input} -o %{targets}))) + +(rule + (alias runtest) + (action (diff test_opaque_type.expected.ml test_opaque_type.actual.ml))) + +(rule + (alias runtest) + (action (diff test_opaque_type.expected.elpi test_opaque_type.actual.elpi))) + +(rule + (target test_opaque_type.actual.elpi) + (action (run ./test_opaque_type.exe %{target}))) + +(executable + (name test_opaque_type) + (modules test_opaque_type) + (preprocess (pps elpi.ppx))) + + +(rule + (targets test_opaque_type_alias.actual.ml) + (deps (:pp pp.exe) (:input test_opaque_type_alias.ml)) + (action (run ./%{pp} -deriving-keep-w32 both --impl %{input} -o %{targets}))) + +(rule + (alias runtest) + (action (diff test_opaque_type_alias.expected.ml test_opaque_type_alias.actual.ml))) + +(rule + (alias runtest) + (action (diff test_opaque_type_alias.expected.elpi test_opaque_type_alias.actual.elpi))) + +(rule + (target test_opaque_type_alias.actual.elpi) + (action (run ./test_opaque_type_alias.exe %{target}))) + +(executable + (name test_opaque_type_alias) + (modules test_opaque_type_alias) + (preprocess (pps elpi.ppx))) + + +(rule + (targets test_poly_adt.actual.ml) + (deps (:pp pp.exe) (:input test_poly_adt.ml)) + (action (run ./%{pp} -deriving-keep-w32 both --impl %{input} -o %{targets}))) + +(rule + (alias runtest) + (action (diff test_poly_adt.expected.ml test_poly_adt.actual.ml))) + +(rule + (alias runtest) + (action (diff test_poly_adt.expected.elpi test_poly_adt.actual.elpi))) + +(rule + (target test_poly_adt.actual.elpi) + (action (run ./test_poly_adt.exe %{target}))) + +(executable + (name test_poly_adt) + (modules test_poly_adt) + (preprocess (pps elpi.ppx))) + + +(rule + (targets test_poly_alias.actual.ml) + (deps (:pp pp.exe) (:input test_poly_alias.ml)) + (action (run ./%{pp} -deriving-keep-w32 both --impl %{input} -o %{targets}))) + +(rule + (alias runtest) + (action (diff test_poly_alias.expected.ml test_poly_alias.actual.ml))) + +(rule + (alias runtest) + (action (diff test_poly_alias.expected.elpi test_poly_alias.actual.elpi))) + +(rule + (target test_poly_alias.actual.elpi) + (action (run ./test_poly_alias.exe %{target}))) + +(executable + (name test_poly_alias) + (modules test_poly_alias) + (preprocess (pps elpi.ppx))) + + +(rule + (targets test_simple_adt.actual.ml) + (deps (:pp pp.exe) (:input test_simple_adt.ml)) + (action (run ./%{pp} -deriving-keep-w32 both --impl %{input} -o %{targets}))) + +(rule + (alias runtest) + (action (diff test_simple_adt.expected.ml test_simple_adt.actual.ml))) + +(rule + (alias runtest) + (action (diff test_simple_adt.expected.elpi test_simple_adt.actual.elpi))) + +(rule + (target test_simple_adt.actual.elpi) + (action (run ./test_simple_adt.exe %{target}))) + +(executable + (name test_simple_adt) + (modules test_simple_adt) + (preprocess (pps elpi.ppx))) + + +(rule + (targets test_simple_adt_record.actual.ml) + (deps (:pp pp.exe) (:input test_simple_adt_record.ml)) + (action (run ./%{pp} -deriving-keep-w32 both --impl %{input} -o %{targets}))) + +(rule + (alias runtest) + (action (diff test_simple_adt_record.expected.ml test_simple_adt_record.actual.ml))) + +(rule + (alias runtest) + (action (diff test_simple_adt_record.expected.elpi test_simple_adt_record.actual.elpi))) + +(rule + (target test_simple_adt_record.actual.elpi) + (action (run ./test_simple_adt_record.exe %{target}))) + +(executable + (name test_simple_adt_record) + (modules test_simple_adt_record) + (preprocess (pps elpi.ppx))) + + +(rule + (targets test_simple_contextual.actual.ml) + (deps (:pp pp.exe) (:input test_simple_contextual.ml)) + (action (run ./%{pp} -deriving-keep-w32 both --impl %{input} -o %{targets}))) + +(rule + (alias runtest) + (action (diff test_simple_contextual.expected.ml test_simple_contextual.actual.ml))) + +(rule + (alias runtest) + (action (diff test_simple_contextual.expected.elpi test_simple_contextual.actual.elpi))) + +(rule + (target test_simple_contextual.actual.elpi) + (action (run ./test_simple_contextual.exe %{target}))) + +(executable + (name test_simple_contextual) + (modules test_simple_contextual) + (preprocess (pps elpi.ppx))) + + +(rule + (targets test_simple_record.actual.ml) + (deps (:pp pp.exe) (:input test_simple_record.ml)) + (action (run ./%{pp} -deriving-keep-w32 both --impl %{input} -o %{targets}))) + +(rule + (alias runtest) + (action (diff test_simple_record.expected.ml test_simple_record.actual.ml))) + +(rule + (alias runtest) + (action (diff test_simple_record.expected.elpi test_simple_record.actual.elpi))) + +(rule + (target test_simple_record.actual.elpi) + (action (run ./test_simple_record.exe %{target}))) + +(executable + (name test_simple_record) + (modules test_simple_record) + (preprocess (pps elpi.ppx))) + + +(rule + (targets test_two_layers_context.actual.ml) + (deps (:pp pp.exe) (:input test_two_layers_context.ml)) + (action (run ./%{pp} -deriving-keep-w32 both --impl %{input} -o %{targets}))) + +(rule + (alias runtest) + (action (diff test_two_layers_context.expected.ml test_two_layers_context.actual.ml))) + +(rule + (alias runtest) + (action (diff test_two_layers_context.expected.elpi test_two_layers_context.actual.elpi))) + +(rule + (target test_two_layers_context.actual.elpi) + (action (run ./test_two_layers_context.exe %{target}))) + +(executable + (name test_two_layers_context) + (modules test_two_layers_context) + (preprocess (pps elpi.ppx))) + diff --git a/ppx_elpi/tests/gen_dune.ml b/ppx_elpi/tests/gen_dune.ml new file mode 100644 index 000000000..e7c620901 --- /dev/null +++ b/ppx_elpi/tests/gen_dune.ml @@ -0,0 +1,43 @@ + + +let output_stanzas filename = + let base = Filename.remove_extension filename in + Printf.printf {| +(rule + (targets %s.actual.ml) + (deps (:pp pp.exe) (:input %s.ml)) + (action (run ./%%{pp} -deriving-keep-w32 both --impl %%{input} -o %%{targets}))) + +(rule + (alias runtest) + (action (diff %s.expected.ml %s.actual.ml))) + +(rule + (alias runtest) + (action (diff %s.expected.elpi %s.actual.elpi))) + +(rule + (target %s.actual.elpi) + (action (run ./%s.exe %%{target}))) + +(executable + (name %s) + (modules %s) + (preprocess (pps elpi.ppx))) + +|} + base base base base base base base base base base + +let is_test filename = + Filename.check_suffix filename ".ml" && + not (Filename.check_suffix (Filename.remove_extension filename) ".pp") && + not (Filename.check_suffix (Filename.remove_extension filename) ".actual") && + not (Filename.check_suffix (Filename.remove_extension filename) ".expected") && + Re.Str.string_match (Re.Str.regexp_string "test_") filename 0 + +let () = + Sys.readdir "." + |> Array.to_list + |> List.sort String.compare + |> List.filter is_test + |> List.iter output_stanzas \ No newline at end of file diff --git a/ppx_elpi/tests/pp.ml b/ppx_elpi/tests/pp.ml new file mode 100644 index 000000000..e3cba4049 --- /dev/null +++ b/ppx_elpi/tests/pp.ml @@ -0,0 +1 @@ +let () = Ppxlib.Driver.standalone () diff --git a/ppx_elpi/tests/test_alias_type.expected.elpi b/ppx_elpi/tests/test_alias_type.expected.elpi new file mode 100644 index 000000000..9a92e117a --- /dev/null +++ b/ppx_elpi/tests/test_alias_type.expected.elpi @@ -0,0 +1,7 @@ + + +typeabbrev simple int. % simple + + + + diff --git a/ppx_elpi/tests/test_alias_type.expected.ml b/ppx_elpi/tests/test_alias_type.expected.ml new file mode 100644 index 000000000..b7760c2ba --- /dev/null +++ b/ppx_elpi/tests/test_alias_type.expected.ml @@ -0,0 +1,80 @@ +let elpi_stuff = ref [] +let pp_simple _ _ = () +type simple = int[@@deriving elpi { declaration = elpi_stuff }] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_simple = "simple" + let elpi_constant_type_simplec = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_type_simple + module Ctx_for_simple = + struct + class type t = object inherit Elpi.API.ContextualConversion.ctx end + end + let rec elpi_embed_simple : + 'c 'csts . + (simple, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding + = + fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.embed + ~depth h c s t + and elpi_readback_simple : + 'c 'csts . + (simple, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback + = + fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.readback + ~depth h c s t + and simple : + 'c 'csts . + (simple, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.t + = + let kind = Elpi.API.ContextualConversion.TyName "simple" in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> Elpi.API.PPX.Doc.kind fmt kind ~doc:"simple"; ()); + pp = pp_simple; + embed = elpi_embed_simple; + readback = elpi_readback_simple + } + let elpi_simple = + Elpi.API.BuiltIn.LPCode + ("typeabbrev " ^ + ("simple" ^ + (" " ^ + (((let open Elpi.API.PPX.Doc in show_ty_ast ~prec:AppArg) @@ + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.ty) + ^ (". % " ^ "simple"))))) + class ctx_for_simple (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_simple.t = + object (_) inherit ((Elpi.API.ContextualConversion.ctx) h) end + let (in_ctx_for_simple : + (Ctx_for_simple.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> (s, ((new ctx_for_simple) h s), c, (List.concat [])) + let () = elpi_stuff := ((!elpi_stuff) @ [elpi_simple]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +open Elpi.API +let builtin = + let open BuiltIn in declare ~file_name:(Sys.argv.(1)) (!elpi_stuff) +let main () = + let _elpi = Setup.init ~builtins:[builtin] () in + BuiltIn.document_file builtin; exit 0 +;;main () diff --git a/ppx_elpi/tests/test_alias_type.ml b/ppx_elpi/tests/test_alias_type.ml new file mode 100644 index 000000000..d23e13396 --- /dev/null +++ b/ppx_elpi/tests/test_alias_type.ml @@ -0,0 +1,18 @@ +let elpi_stuff = ref [] + +let pp_simple _ _ = () +type simple = int +[@@deriving elpi { declaration = elpi_stuff }] + +open Elpi.API + +let builtin = let open BuiltIn in + declare ~file_name:(Sys.argv.(1)) !elpi_stuff + +let main () = + let _elpi = Setup.init ~builtins:[builtin] () in + BuiltIn.document_file builtin; + exit 0 +;; + +main () diff --git a/ppx_elpi/tests/test_container.expected.elpi b/ppx_elpi/tests/test_container.expected.elpi new file mode 100644 index 000000000..24da75ab0 --- /dev/null +++ b/ppx_elpi/tests/test_container.expected.elpi @@ -0,0 +1,16 @@ + + +% loc +kind loc type -> type. +type loc int -> A0 -> loc A0. % loc + +% term +kind term type. +type a int -> term. % A +type b string -> bool -> term. % B + +typeabbrev x (pair (loc term) int). % x + + + + diff --git a/ppx_elpi/tests/test_container.expected.ml b/ppx_elpi/tests/test_container.expected.ml new file mode 100644 index 000000000..2ace2a050 --- /dev/null +++ b/ppx_elpi/tests/test_container.expected.ml @@ -0,0 +1,394 @@ +let declaration = ref [] +let pp_loc _ _ _ = () +type 'a loc = { + loc: int ; + data: 'a }[@@deriving elpi { declaration }] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_loc = "loc" + let elpi_constant_type_locc = + Elpi.API.RawData.Constants.declare_global_symbol elpi_constant_type_loc + let elpi_constant_constructor_loc_loc = "loc" + let elpi_constant_constructor_loc_locc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_loc_loc + module Ctx_for_loc = + struct + class type t = object inherit Elpi.API.ContextualConversion.ctx end + end + let rec elpi_embed_loc : + 'elpi__param__a 'c 'csts . + ('elpi__param__a, #Ctx_for_loc.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding -> + ('elpi__param__a loc, #Ctx_for_loc.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding + = + fun elpi_embed_elpi__param__a -> + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | { loc = elpi__5; data = elpi__6 } -> + let (elpi__state, elpi__9, elpi__7) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__5 in + let (elpi__state, elpi__10, elpi__8) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + elpi_embed_elpi__param__a ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__6 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_loc_locc + [elpi__9; elpi__10]), + (List.concat [elpi__7; elpi__8])) + and elpi_readback_loc : + 'elpi__param__a 'c 'csts . + ('elpi__param__a, #Ctx_for_loc.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback -> + ('elpi__param__a loc, #Ctx_for_loc.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback + = + fun elpi_readback_elpi__param__a -> + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_loc_locc -> + let (elpi__state, elpi__4, elpi__3) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | elpi__1::[] -> + let (elpi__state, elpi__1, elpi__2) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + elpi_readback_elpi__param__a ~depth h + c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state + elpi__1 in + (elpi__state, { loc = elpi__4; data = elpi__1 }, + (List.concat [elpi__3; elpi__2])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_loc_locc))) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "loc" (Elpi.API.RawPp.term elpi__depth) elpi__x) + and loc : + 'elpi__param__a 'c 'csts . + ('elpi__param__a, #Ctx_for_loc.t as 'c, 'csts) + Elpi.API.ContextualConversion.t -> + ('elpi__param__a loc, #Ctx_for_loc.t as 'c, 'csts) + Elpi.API.ContextualConversion.t + = + fun elpi__param__a -> + let kind = + Elpi.API.ContextualConversion.TyApp + ("loc", (elpi__param__a.Elpi.API.ContextualConversion.ty), []) in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"loc"; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"loc" + ~doc:"loc" + ~args:[Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.ty; + elpi__param__a.Elpi.API.ContextualConversion.ty]); + pp = (pp_loc elpi__param__a.pp); + embed = + (elpi_embed_loc + elpi__param__a.Elpi.API.ContextualConversion.embed); + readback = + (elpi_readback_loc + elpi__param__a.Elpi.API.ContextualConversion.readback) + } + let elpi_loc = + Elpi.API.BuiltIn.MLDataC (loc Elpi.API.BuiltInContextualData.polyA0) + class ctx_for_loc (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_loc.t = + object (_) inherit ((Elpi.API.ContextualConversion.ctx) h) end + let (in_ctx_for_loc : + (Ctx_for_loc.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> fun s -> (s, ((new ctx_for_loc) h s), c, (List.concat [])) + let () = declaration := ((!declaration) @ [elpi_loc]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +let pp_term _ _ = () +type term = + | A of int + | B of string * bool [@@deriving elpi { declaration }] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_term = "term" + let elpi_constant_type_termc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_type_term + let elpi_constant_constructor_term_A = "a" + let elpi_constant_constructor_term_Ac = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_term_A + let elpi_constant_constructor_term_B = "b" + let elpi_constant_constructor_term_Bc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_term_B + module Ctx_for_term = + struct + class type t = object inherit Elpi.API.ContextualConversion.ctx end + end + let rec elpi_embed_term : + 'c 'csts . + (term, #Ctx_for_term.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | A elpi__17 -> + let (elpi__state, elpi__19, elpi__18) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__17 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_term_Ac [elpi__19]), + (List.concat [elpi__18])) + | B (elpi__20, elpi__21) -> + let (elpi__state, elpi__24, elpi__22) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__20 in + let (elpi__state, elpi__25, elpi__23) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__21 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_term_Bc [elpi__24; elpi__25]), + (List.concat [elpi__22; elpi__23])) + and elpi_readback_term : + 'c 'csts . + (term, #Ctx_for_term.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_term_Ac -> + let (elpi__state, elpi__12, elpi__11) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | [] -> + (elpi__state, (A elpi__12), + (List.concat [elpi__11])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_term_Ac))) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_term_Bc -> + let (elpi__state, elpi__16, elpi__15) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | elpi__13::[] -> + let (elpi__state, elpi__13, elpi__14) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state + elpi__13 in + (elpi__state, (B (elpi__16, elpi__13)), + (List.concat [elpi__15; elpi__14])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_term_Bc))) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "term" (Elpi.API.RawPp.term elpi__depth) elpi__x) + and term : + 'c 'csts . + (term, #Ctx_for_term.t as 'c, 'csts) Elpi.API.ContextualConversion.t + = + let kind = Elpi.API.ContextualConversion.TyName "term" in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"term"; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"a" ~doc:"A" + ~args:[Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.ty]; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"b" ~doc:"B" + ~args:[Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.ty; + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.ty]); + pp = pp_term; + embed = elpi_embed_term; + readback = elpi_readback_term + } + let elpi_term = Elpi.API.BuiltIn.MLDataC term + class ctx_for_term (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_term.t = + object (_) inherit ((Elpi.API.ContextualConversion.ctx) h) end + let (in_ctx_for_term : + (Ctx_for_term.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> (s, ((new ctx_for_term) h s), c, (List.concat [])) + let () = declaration := ((!declaration) @ [elpi_term]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +let pp_x _ _ = () +type x = (term loc * int)[@@deriving elpi { declaration }] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_x = "x" + let elpi_constant_type_xc = + Elpi.API.RawData.Constants.declare_global_symbol elpi_constant_type_x + module Ctx_for_x = + struct + class type t = object inherit Elpi.API.ContextualConversion.ctx end + end + let rec elpi_embed_x : + 'c 'csts . + (x, #Ctx_for_x.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding + = + fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + (Elpi.Builtin.PPX.embed_pair + (loc term).Elpi.API.ContextualConversion.embed + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.embed) + ~depth h c s t + and elpi_readback_x : + 'c 'csts . + (x, #Ctx_for_x.t as 'c, 'csts) Elpi.API.ContextualConversion.readback + = + fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + (Elpi.Builtin.PPX.readback_pair + (loc term).Elpi.API.ContextualConversion.readback + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.readback) + ~depth h c s t + and x : + 'c 'csts . + (x, #Ctx_for_x.t as 'c, 'csts) Elpi.API.ContextualConversion.t + = + let kind = Elpi.API.ContextualConversion.TyName "x" in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> fun () -> Elpi.API.PPX.Doc.kind fmt kind ~doc:"x"; ()); + pp = pp_x; + embed = elpi_embed_x; + readback = elpi_readback_x + } + let elpi_x = + Elpi.API.BuiltIn.LPCode + ("typeabbrev " ^ + ("x" ^ + (" " ^ + (((let open Elpi.API.PPX.Doc in show_ty_ast ~prec:AppArg) @@ + (Elpi.Builtin.PPX.pair (loc term) + Elpi.API.BuiltInContextualData.int).Elpi.API.ContextualConversion.ty) + ^ (". % " ^ "x"))))) + class ctx_for_x (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_x.t = + object (_) inherit ((Elpi.API.ContextualConversion.ctx) h) end + let (in_ctx_for_x : + (Ctx_for_x.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> fun s -> (s, ((new ctx_for_x) h s), c, (List.concat [])) + let () = declaration := ((!declaration) @ [elpi_x]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +let xx : 'c 'csts . (x, 'c, 'csts) Elpi.API.ContextualConversion.t = x +open Elpi.API +let builtin = + let open BuiltIn in declare ~file_name:(Sys.argv.(1)) (!declaration) +let main () = + let _elpi = Setup.init ~builtins:[builtin] () in + BuiltIn.document_file builtin; exit 0 +;;main () diff --git a/ppx_elpi/tests/test_container.ml b/ppx_elpi/tests/test_container.ml new file mode 100644 index 000000000..fc2b3a367 --- /dev/null +++ b/ppx_elpi/tests/test_container.ml @@ -0,0 +1,34 @@ +let declaration = ref [] + +let pp_loc _ _ _ = () + +type 'a loc = { + loc : int; + data : 'a; +} +[@@deriving elpi { declaration }] + +let pp_term _ _ = () +type term = + | A of int + | B of string * bool +[@@deriving elpi { declaration }] + +let pp_x _ _ = () +type x = term loc * int +[@@deriving elpi { declaration }] + +let xx : 'c 'csts. (x,'c,'csts) Elpi.API.ContextualConversion.t = x + +open Elpi.API + +let builtin = let open BuiltIn in + declare ~file_name:(Sys.argv.(1)) !declaration + +let main () = + let _elpi= Setup.init ~builtins:[builtin] () in + BuiltIn.document_file builtin; + exit 0 +;; + +main () \ No newline at end of file diff --git a/ppx_elpi/tests/test_double_contextual.expected.elpi b/ppx_elpi/tests/test_double_contextual.expected.elpi new file mode 100644 index 000000000..f7a8480f3 --- /dev/null +++ b/ppx_elpi/tests/test_double_contextual.expected.elpi @@ -0,0 +1,23 @@ + + +% tyctx +kind tyctx type. +type tentry nominal -> string -> bool -> prop. % TEntry + +% ty +kind ty type. +type tapp string -> ty -> ty. % TApp +type tall bool -> string -> (ty -> ty) -> ty. % TAll + +% tctx +kind tctx type. +type entry nominal -> string -> ty -> prop. % Entry + +% term +kind term type. +type app term -> term -> term. % App +type lam ty -> string -> (term -> term) -> term. % Lam + + + + diff --git a/ppx_elpi/tests/test_double_contextual.expected.ml b/ppx_elpi/tests/test_double_contextual.expected.ml new file mode 100644 index 000000000..0ef910d35 --- /dev/null +++ b/ppx_elpi/tests/test_double_contextual.expected.ml @@ -0,0 +1,1090 @@ +let declaration = ref [] +module String = + struct + include String + let pp fmt s = Format.fprintf fmt "%s" s + let show = Format.asprintf "%a" pp + end +let pp_tyctx _ _ = () +type tyctx = + | TEntry of ((string)[@elpi.key ]) * bool [@@elpi.index (module String)] +[@@deriving elpi { declaration }] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_tyctx = "tyctx" + let elpi_constant_type_tyctxc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_type_tyctx + let elpi_constant_constructor_tyctx_TEntry = "tentry" + let elpi_constant_constructor_tyctx_TEntryc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_tyctx_TEntry + module Elpi_tyctx_Map = (Elpi.API.Utils.Map.Make)(String) + let elpi_tyctx_state = + Elpi.API.State.declare ~name:"tyctx" + ~pp:(fun fmt -> fun _ -> Format.fprintf fmt "TODO") + ~init:(fun () -> + ((Elpi_tyctx_Map.empty : Elpi.API.RawData.constant + Elpi_tyctx_Map.t), + (Elpi.API.RawData.Constants.Map.empty : tyctx + Elpi.API.ContextualConversion.ctx_entry + Elpi.API.RawData.Constants.Map.t))) + ~start:(fun x -> x) + let elpi_tyctx_to_key ~depth:_ = + function | TEntry (elpi__16, _) -> elpi__16 + let elpi_is_tyctx { Elpi.API.Data.hdepth = elpi__depth; hsrc = elpi__x } + = + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.Const _ -> None + | Elpi.API.RawData.App (elpi__hd, elpi__idx, _) -> + if false || (elpi__hd == elpi_constant_constructor_tyctx_TEntryc) + then + (match Elpi.API.RawData.look ~depth:elpi__depth elpi__idx with + | Elpi.API.RawData.Const x -> Some x + | _ -> + Elpi.API.Utils.type_error + "context entry applied to a non nominal") + else None + | _ -> None + let elpi_push_tyctx ~depth:elpi__depth elpi__state elpi__name + elpi__ctx_item = + let (elpi__ctx2dbl, elpi__dbl2ctx) = + Elpi.API.State.get elpi_tyctx_state elpi__state in + let elpi__i = elpi__depth in + let elpi__ctx2dbl = Elpi_tyctx_Map.add elpi__name elpi__i elpi__ctx2dbl in + let elpi__dbl2ctx = + Elpi.API.RawData.Constants.Map.add elpi__i elpi__ctx_item + elpi__dbl2ctx in + let elpi__state = + Elpi.API.State.set elpi_tyctx_state elpi__state + (elpi__ctx2dbl, elpi__dbl2ctx) in + elpi__state + let elpi_pop_tyctx ~depth:elpi__depth elpi__state elpi__name = + let (elpi__ctx2dbl, elpi__dbl2ctx) = + Elpi.API.State.get elpi_tyctx_state elpi__state in + let elpi__i = elpi__depth in + let elpi__ctx2dbl = Elpi_tyctx_Map.remove elpi__name elpi__ctx2dbl in + let elpi__dbl2ctx = + Elpi.API.RawData.Constants.Map.remove elpi__i elpi__dbl2ctx in + let elpi__state = + Elpi.API.State.set elpi_tyctx_state elpi__state + (elpi__ctx2dbl, elpi__dbl2ctx) in + elpi__state + module Ctx_for_tyctx = + struct + class type t = object inherit Elpi.API.ContextualConversion.ctx end + end + let rec elpi_embed_tyctx : + 'c 'csts . + ((Elpi.API.RawData.constant * tyctx), #Ctx_for_tyctx.t as 'c, + 'csts) Elpi.API.ContextualConversion.embedding + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | (elpi__9, TEntry (elpi__7, elpi__8)) -> + let (elpi__state, elpi__13, elpi__10) = + Elpi.API.BuiltInContextualData.nominal.Elpi.API.ContextualConversion.embed + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__9 in + let (elpi__state, elpi__14, elpi__11) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__7 in + let (elpi__state, elpi__15, elpi__12) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__8 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_tyctx_TEntryc + [elpi__13; elpi__14; elpi__15]), + (List.concat [elpi__10; elpi__11; elpi__12])) + and elpi_readback_tyctx : + 'c 'csts . + ((Elpi.API.RawData.constant * tyctx), #Ctx_for_tyctx.t as 'c, + 'csts) Elpi.API.ContextualConversion.readback + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_tyctx_TEntryc -> + let (elpi__state, elpi__6, elpi__5) = + Elpi.API.BuiltInContextualData.nominal.Elpi.API.ContextualConversion.readback + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__x in + (match elpi__xs with + | elpi__1::elpi__2::[] -> + let (elpi__state, elpi__1, elpi__3) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__1 in + let (elpi__state, elpi__2, elpi__4) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__2 in + (elpi__state, + (elpi__6, (TEntry (elpi__1, elpi__2))), + (List.concat [elpi__5; elpi__3; elpi__4])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_tyctx_TEntryc))) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "tyctx" (Elpi.API.RawPp.term elpi__depth) elpi__x) + and tyctx : + 'c 'csts . + ((Elpi.API.RawData.constant * tyctx), #Ctx_for_tyctx.t as 'c, + 'csts) Elpi.API.ContextualConversion.t + = + let kind = Elpi.API.ContextualConversion.TyName "tyctx" in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"tyctx"; + Elpi.API.PPX.Doc.constructor fmt + ~ty:(Elpi.API.ContextualConversion.TyName "prop") + ~name:"tentry" ~doc:"TEntry" + ~args:[Elpi.API.BuiltInContextualData.nominal.Elpi.API.ContextualConversion.ty; + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.ty; + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.ty]); + pp = (fun fmt -> fun (_, x) -> pp_tyctx fmt x); + embed = elpi_embed_tyctx; + readback = elpi_readback_tyctx + } + let context_made_of_tyctx = + { + Elpi.API.ContextualConversion.is_entry_for_nominal = elpi_is_tyctx; + to_key = elpi_tyctx_to_key; + push = elpi_push_tyctx; + pop = elpi_pop_tyctx; + conv = tyctx; + init = + (fun state -> + Elpi.API.State.set elpi_tyctx_state state + ((Elpi_tyctx_Map.empty : Elpi.API.RawData.constant + Elpi_tyctx_Map.t), + (Elpi.API.RawData.Constants.Map.empty : tyctx + Elpi.API.ContextualConversion.ctx_entry + Elpi.API.RawData.Constants.Map.t))); + get = + (fun state -> snd @@ (Elpi.API.State.get elpi_tyctx_state state)) + } + let elpi_tyctx = Elpi.API.BuiltIn.MLDataC tyctx + class ctx_for_tyctx (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_tyctx.t = + object (_) inherit ((Elpi.API.ContextualConversion.ctx) h) end + let (in_ctx_for_tyctx : + (Ctx_for_tyctx.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> (s, ((new ctx_for_tyctx) h s), c, (List.concat [])) + let () = declaration := ((!declaration) @ [elpi_tyctx]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +let pp_ty _ _ = () +type ty = + | TVar of string [@elpi.var tyctx] + | TApp of string * ty + | TAll of bool * string * + ((ty)[@elpi.binder tyctx (fun b -> fun s -> TEntry (s, b))]) [@@deriving + elpi + { + declaration + }] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_ty = "ty" + let elpi_constant_type_tyc = + Elpi.API.RawData.Constants.declare_global_symbol elpi_constant_type_ty + let elpi_constant_constructor_ty_TVar = "tvar" + let elpi_constant_constructor_ty_TVarc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_ty_TVar + let elpi_constant_constructor_ty_TApp = "tapp" + let elpi_constant_constructor_ty_TAppc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_ty_TApp + let elpi_constant_constructor_ty_TAll = "tall" + let elpi_constant_constructor_ty_TAllc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_ty_TAll + module Ctx_for_ty = + struct + class type t = + object + inherit Elpi.API.ContextualConversion.ctx + inherit Ctx_for_tyctx.t + method tyctx : tyctx Elpi.API.ContextualConversion.ctx_field + end + end + let rec elpi_embed_ty : + 'c 'csts . + (ty, #Ctx_for_ty.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | TVar elpi__29 -> + let (elpi__ctx2dbl, _) = + Elpi.API.State.get elpi_tyctx_state elpi__state in + let elpi__key = (fun x -> x) elpi__29 in + (if not (Elpi_tyctx_Map.mem elpi__key elpi__ctx2dbl) + then Elpi.API.Utils.error "Unbound variable"; + (elpi__state, + (Elpi.API.RawData.mkBound + (Elpi_tyctx_Map.find elpi__key elpi__ctx2dbl)), [])) + | TApp (elpi__32, elpi__33) -> + let (elpi__state, elpi__36, elpi__34) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__32 in + let (elpi__state, elpi__37, elpi__35) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> fun t -> elpi_embed_ty ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__33 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_ty_TAppc + [elpi__36; elpi__37]), + (List.concat [elpi__34; elpi__35])) + | TAll (elpi__38, elpi__39, elpi__40) -> + let (elpi__state, elpi__44, elpi__41) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__38 in + let (elpi__state, elpi__45, elpi__42) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__39 in + let elpi__ctx_entry = + (fun b -> fun s -> TEntry (s, b)) elpi__38 elpi__39 in + let elpi__ctx_key = + elpi_tyctx_to_key ~depth:elpi__depth elpi__ctx_entry in + let elpi__ctx_entry = + { + Elpi.API.ContextualConversion.entry = elpi__ctx_entry; + depth = elpi__depth + } in + let elpi__state = + elpi_push_tyctx ~depth:(elpi__depth + 1) elpi__state + elpi__ctx_key elpi__ctx_entry in + let (elpi__state, elpi__47, elpi__43) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> fun t -> elpi_embed_ty ~depth h c s t) + ~depth:(elpi__depth + 1) elpi__hyps elpi__constraints + elpi__state elpi__40 in + let elpi__46 = Elpi.API.RawData.mkLam elpi__47 in + let elpi__state = + elpi_pop_tyctx ~depth:(elpi__depth + 1) elpi__state + elpi__ctx_key in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_ty_TAllc + [elpi__44; elpi__45; elpi__46]), + (List.concat [elpi__41; elpi__42; elpi__43])) + and elpi_readback_ty : + 'c 'csts . + (ty, #Ctx_for_ty.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.Const elpi__hd when elpi__hd >= 0 -> + let (_, elpi__dbl2ctx) = + Elpi.API.State.get elpi_tyctx_state elpi__state in + (if + not + (Elpi.API.RawData.Constants.Map.mem elpi__hd + elpi__dbl2ctx) + then + Elpi.API.Utils.error + (Format.asprintf "Unbound variable: %s in %a" + (Elpi.API.RawData.Constants.show elpi__hd) + (Elpi.API.RawData.Constants.Map.pp + (Elpi.API.ContextualConversion.pp_ctx_entry + pp_tyctx)) elpi__dbl2ctx); + (let { + Elpi.API.ContextualConversion.entry = elpi__entry; + depth = elpi__depth } + = + Elpi.API.RawData.Constants.Map.find elpi__hd + elpi__dbl2ctx in + (elpi__state, + (TVar + (elpi_tyctx_to_key ~depth:elpi__depth elpi__entry)), + []))) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_ty_TAppc -> + let (elpi__state, elpi__22, elpi__21) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | elpi__19::[] -> + let (elpi__state, elpi__19, elpi__20) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> elpi_readback_ty ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__19 in + (elpi__state, (TApp (elpi__22, elpi__19)), + (List.concat [elpi__21; elpi__20])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_ty_TAppc))) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_ty_TAllc -> + let (elpi__state, elpi__28, elpi__27) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | elpi__23::elpi__24::[] -> + let (elpi__state, elpi__23, elpi__25) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state + elpi__23 in + let elpi__ctx_entry = + (fun b -> fun s -> TEntry (s, b)) elpi__28 + elpi__23 in + let elpi__ctx_key = + elpi_tyctx_to_key ~depth:elpi__depth + elpi__ctx_entry in + let elpi__ctx_entry = + { + Elpi.API.ContextualConversion.entry = + elpi__ctx_entry; + depth = elpi__depth + } in + let elpi__state = + elpi_push_tyctx ~depth:elpi__depth elpi__state + elpi__ctx_key elpi__ctx_entry in + let (elpi__state, elpi__24, elpi__26) = + match Elpi.API.RawData.look ~depth:elpi__depth + elpi__24 + with + | Elpi.API.RawData.Lam elpi__bo -> + ((fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + elpi_readback_ty ~depth h c s t)) + ~depth:(elpi__depth + 1) elpi__hyps + elpi__constraints elpi__state elpi__bo + | _ -> assert false in + let elpi__state = + elpi_pop_tyctx ~depth:elpi__depth elpi__state + elpi__ctx_key in + (elpi__state, (TAll (elpi__28, elpi__23, elpi__24)), + (List.concat [elpi__27; elpi__25; elpi__26])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_ty_TAllc))) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "ty" (Elpi.API.RawPp.term elpi__depth) elpi__x) + and ty : + 'c 'csts . + (ty, #Ctx_for_ty.t as 'c, 'csts) Elpi.API.ContextualConversion.t + = + let kind = Elpi.API.ContextualConversion.TyName "ty" in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"ty"; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"tapp" + ~doc:"TApp" + ~args:[Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.ty; + Elpi.API.ContextualConversion.TyName + elpi_constant_type_ty]; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"tall" + ~doc:"TAll" + ~args:[Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.ty; + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.ty; + Elpi.API.ContextualConversion.TyApp + ("->", (Elpi.API.ContextualConversion.TyName "ty"), + [Elpi.API.ContextualConversion.TyName + elpi_constant_type_ty])]); + pp = pp_ty; + embed = elpi_embed_ty; + readback = elpi_readback_ty + } + let elpi_ty = Elpi.API.BuiltIn.MLDataC ty + class ctx_for_ty (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_ty.t = + object (_) + inherit ((Elpi.API.ContextualConversion.ctx) h) + inherit ! ((ctx_for_tyctx) h s) + method tyctx = + context_made_of_tyctx.Elpi.API.ContextualConversion.get s + end + let (in_ctx_for_ty : + (Ctx_for_ty.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> + let ctx = (new ctx_for_tyctx) h s in + let (s, gls0) = + Elpi.API.PPX.readback_context ~depth context_made_of_tyctx + ctx h c s in + (s, ((new ctx_for_ty) h s), c, (List.concat [gls0])) + let () = declaration := ((!declaration) @ [elpi_ty]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +let pp_tctx _ _ = () +type tctx = + | Entry of ((string)[@elpi.key ]) * ty [@@elpi.index (module String)] +[@@deriving elpi { declaration; context = [tyctx] }] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_tctx = "tctx" + let elpi_constant_type_tctxc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_type_tctx + let elpi_constant_constructor_tctx_Entry = "entry" + let elpi_constant_constructor_tctx_Entryc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_tctx_Entry + module Elpi_tctx_Map = (Elpi.API.Utils.Map.Make)(String) + let elpi_tctx_state = + Elpi.API.State.declare ~name:"tctx" + ~pp:(fun fmt -> fun _ -> Format.fprintf fmt "TODO") + ~init:(fun () -> + ((Elpi_tctx_Map.empty : Elpi.API.RawData.constant + Elpi_tctx_Map.t), + (Elpi.API.RawData.Constants.Map.empty : tctx + Elpi.API.ContextualConversion.ctx_entry + Elpi.API.RawData.Constants.Map.t))) + ~start:(fun x -> x) + let elpi_tctx_to_key ~depth:_ = + function | Entry (elpi__63, _) -> elpi__63 + let elpi_is_tctx { Elpi.API.Data.hdepth = elpi__depth; hsrc = elpi__x } = + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.Const _ -> None + | Elpi.API.RawData.App (elpi__hd, elpi__idx, _) -> + if false || (elpi__hd == elpi_constant_constructor_tctx_Entryc) + then + (match Elpi.API.RawData.look ~depth:elpi__depth elpi__idx with + | Elpi.API.RawData.Const x -> Some x + | _ -> + Elpi.API.Utils.type_error + "context entry applied to a non nominal") + else None + | _ -> None + let elpi_push_tctx ~depth:elpi__depth elpi__state elpi__name + elpi__ctx_item = + let (elpi__ctx2dbl, elpi__dbl2ctx) = + Elpi.API.State.get elpi_tctx_state elpi__state in + let elpi__i = elpi__depth in + let elpi__ctx2dbl = Elpi_tctx_Map.add elpi__name elpi__i elpi__ctx2dbl in + let elpi__dbl2ctx = + Elpi.API.RawData.Constants.Map.add elpi__i elpi__ctx_item + elpi__dbl2ctx in + let elpi__state = + Elpi.API.State.set elpi_tctx_state elpi__state + (elpi__ctx2dbl, elpi__dbl2ctx) in + elpi__state + let elpi_pop_tctx ~depth:elpi__depth elpi__state elpi__name = + let (elpi__ctx2dbl, elpi__dbl2ctx) = + Elpi.API.State.get elpi_tctx_state elpi__state in + let elpi__i = elpi__depth in + let elpi__ctx2dbl = Elpi_tctx_Map.remove elpi__name elpi__ctx2dbl in + let elpi__dbl2ctx = + Elpi.API.RawData.Constants.Map.remove elpi__i elpi__dbl2ctx in + let elpi__state = + Elpi.API.State.set elpi_tctx_state elpi__state + (elpi__ctx2dbl, elpi__dbl2ctx) in + elpi__state + module Ctx_for_tctx = + struct + class type t = + object + inherit Elpi.API.ContextualConversion.ctx + inherit Ctx_for_tyctx.t + method tyctx : tyctx Elpi.API.ContextualConversion.ctx_field + end + end + let rec elpi_embed_tctx : + 'c 'csts . + ((Elpi.API.RawData.constant * tctx), #Ctx_for_tctx.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | (elpi__56, Entry (elpi__54, elpi__55)) -> + let (elpi__state, elpi__60, elpi__57) = + Elpi.API.BuiltInContextualData.nominal.Elpi.API.ContextualConversion.embed + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__56 in + let (elpi__state, elpi__61, elpi__58) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__54 in + let (elpi__state, elpi__62, elpi__59) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + ty.Elpi.API.ContextualConversion.embed ~depth + h c s t) ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__55 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_tctx_Entryc + [elpi__60; elpi__61; elpi__62]), + (List.concat [elpi__57; elpi__58; elpi__59])) + and elpi_readback_tctx : + 'c 'csts . + ((Elpi.API.RawData.constant * tctx), #Ctx_for_tctx.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_tctx_Entryc -> + let (elpi__state, elpi__53, elpi__52) = + Elpi.API.BuiltInContextualData.nominal.Elpi.API.ContextualConversion.readback + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__x in + (match elpi__xs with + | elpi__48::elpi__49::[] -> + let (elpi__state, elpi__48, elpi__50) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state + elpi__48 in + let (elpi__state, elpi__49, elpi__51) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + ty.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state + elpi__49 in + (elpi__state, + (elpi__53, (Entry (elpi__48, elpi__49))), + (List.concat [elpi__52; elpi__50; elpi__51])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_tctx_Entryc))) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "tctx" (Elpi.API.RawPp.term elpi__depth) elpi__x) + and tctx : + 'c 'csts . + ((Elpi.API.RawData.constant * tctx), #Ctx_for_tctx.t as 'c, 'csts) + Elpi.API.ContextualConversion.t + = + let kind = Elpi.API.ContextualConversion.TyName "tctx" in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"tctx"; + Elpi.API.PPX.Doc.constructor fmt + ~ty:(Elpi.API.ContextualConversion.TyName "prop") + ~name:"entry" ~doc:"Entry" + ~args:[Elpi.API.BuiltInContextualData.nominal.Elpi.API.ContextualConversion.ty; + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.ty; + ty.Elpi.API.ContextualConversion.ty]); + pp = (fun fmt -> fun (_, x) -> pp_tctx fmt x); + embed = elpi_embed_tctx; + readback = elpi_readback_tctx + } + let context_made_of_tctx = + { + Elpi.API.ContextualConversion.is_entry_for_nominal = elpi_is_tctx; + to_key = elpi_tctx_to_key; + push = elpi_push_tctx; + pop = elpi_pop_tctx; + conv = tctx; + init = + (fun state -> + Elpi.API.State.set elpi_tctx_state state + ((Elpi_tctx_Map.empty : Elpi.API.RawData.constant + Elpi_tctx_Map.t), + (Elpi.API.RawData.Constants.Map.empty : tctx + Elpi.API.ContextualConversion.ctx_entry + Elpi.API.RawData.Constants.Map.t))); + get = + (fun state -> snd @@ (Elpi.API.State.get elpi_tctx_state state)) + } + let elpi_tctx = Elpi.API.BuiltIn.MLDataC tctx + class ctx_for_tctx (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_tctx.t = + object (_) + inherit ((Elpi.API.ContextualConversion.ctx) h) + inherit ! ((ctx_for_tyctx) h s) + method tyctx = + context_made_of_tyctx.Elpi.API.ContextualConversion.get s + end + let (in_ctx_for_tctx : + (Ctx_for_tctx.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> + let ctx = (new ctx_for_tyctx) h s in + let (s, gls0) = + Elpi.API.PPX.readback_context ~depth context_made_of_tyctx + ctx h c s in + (s, ((new ctx_for_tctx) h s), c, (List.concat [gls0])) + let () = declaration := ((!declaration) @ [elpi_tctx]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +let pp_term _ _ = () +type term = + | Var of string [@elpi.var tctx] + | App of term * term + | Lam of ty * string * + ((term)[@elpi.binder tctx (fun b -> fun s -> Entry (s, b))]) [@@deriving + elpi + { + declaration + }] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_term = "term" + let elpi_constant_type_termc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_type_term + let elpi_constant_constructor_term_Var = "var" + let elpi_constant_constructor_term_Varc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_term_Var + let elpi_constant_constructor_term_App = "app" + let elpi_constant_constructor_term_Appc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_term_App + let elpi_constant_constructor_term_Lam = "lam" + let elpi_constant_constructor_term_Lamc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_term_Lam + module Ctx_for_term = + struct + class type t = + object + inherit Elpi.API.ContextualConversion.ctx + inherit Ctx_for_tctx.t + method tctx : tctx Elpi.API.ContextualConversion.ctx_field + end + end + let rec elpi_embed_term : + 'c 'csts . + (term, #Ctx_for_term.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | Var elpi__76 -> + let (elpi__ctx2dbl, _) = + Elpi.API.State.get elpi_tctx_state elpi__state in + let elpi__key = (fun x -> x) elpi__76 in + (if not (Elpi_tctx_Map.mem elpi__key elpi__ctx2dbl) + then Elpi.API.Utils.error "Unbound variable"; + (elpi__state, + (Elpi.API.RawData.mkBound + (Elpi_tctx_Map.find elpi__key elpi__ctx2dbl)), [])) + | App (elpi__79, elpi__80) -> + let (elpi__state, elpi__83, elpi__81) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> fun t -> elpi_embed_term ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__79 in + let (elpi__state, elpi__84, elpi__82) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> fun t -> elpi_embed_term ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__80 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_term_Appc + [elpi__83; elpi__84]), + (List.concat [elpi__81; elpi__82])) + | Lam (elpi__85, elpi__86, elpi__87) -> + let (elpi__state, elpi__91, elpi__88) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + ty.Elpi.API.ContextualConversion.embed ~depth + h c s t) ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__85 in + let (elpi__state, elpi__92, elpi__89) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__86 in + let elpi__ctx_entry = + (fun b -> fun s -> Entry (s, b)) elpi__85 elpi__86 in + let elpi__ctx_key = + elpi_tctx_to_key ~depth:elpi__depth elpi__ctx_entry in + let elpi__ctx_entry = + { + Elpi.API.ContextualConversion.entry = elpi__ctx_entry; + depth = elpi__depth + } in + let elpi__state = + elpi_push_tctx ~depth:(elpi__depth + 1) elpi__state + elpi__ctx_key elpi__ctx_entry in + let (elpi__state, elpi__94, elpi__90) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> fun t -> elpi_embed_term ~depth h c s t) + ~depth:(elpi__depth + 1) elpi__hyps elpi__constraints + elpi__state elpi__87 in + let elpi__93 = Elpi.API.RawData.mkLam elpi__94 in + let elpi__state = + elpi_pop_tctx ~depth:(elpi__depth + 1) elpi__state + elpi__ctx_key in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_term_Lamc + [elpi__91; elpi__92; elpi__93]), + (List.concat [elpi__88; elpi__89; elpi__90])) + and elpi_readback_term : + 'c 'csts . + (term, #Ctx_for_term.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.Const elpi__hd when elpi__hd >= 0 -> + let (_, elpi__dbl2ctx) = + Elpi.API.State.get elpi_tctx_state elpi__state in + (if + not + (Elpi.API.RawData.Constants.Map.mem elpi__hd + elpi__dbl2ctx) + then + Elpi.API.Utils.error + (Format.asprintf "Unbound variable: %s in %a" + (Elpi.API.RawData.Constants.show elpi__hd) + (Elpi.API.RawData.Constants.Map.pp + (Elpi.API.ContextualConversion.pp_ctx_entry + pp_tctx)) elpi__dbl2ctx); + (let { + Elpi.API.ContextualConversion.entry = elpi__entry; + depth = elpi__depth } + = + Elpi.API.RawData.Constants.Map.find elpi__hd + elpi__dbl2ctx in + (elpi__state, + (Var + (elpi_tctx_to_key ~depth:elpi__depth elpi__entry)), + []))) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_term_Appc -> + let (elpi__state, elpi__69, elpi__68) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> elpi_readback_term ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__x in + (match elpi__xs with + | elpi__66::[] -> + let (elpi__state, elpi__66, elpi__67) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + elpi_readback_term ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__66 in + (elpi__state, (App (elpi__69, elpi__66)), + (List.concat [elpi__68; elpi__67])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_term_Appc))) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_term_Lamc -> + let (elpi__state, elpi__75, elpi__74) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + ty.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | elpi__70::elpi__71::[] -> + let (elpi__state, elpi__70, elpi__72) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state + elpi__70 in + let elpi__ctx_entry = + (fun b -> fun s -> Entry (s, b)) elpi__75 elpi__70 in + let elpi__ctx_key = + elpi_tctx_to_key ~depth:elpi__depth + elpi__ctx_entry in + let elpi__ctx_entry = + { + Elpi.API.ContextualConversion.entry = + elpi__ctx_entry; + depth = elpi__depth + } in + let elpi__state = + elpi_push_tctx ~depth:elpi__depth elpi__state + elpi__ctx_key elpi__ctx_entry in + let (elpi__state, elpi__71, elpi__73) = + match Elpi.API.RawData.look ~depth:elpi__depth + elpi__71 + with + | Elpi.API.RawData.Lam elpi__bo -> + ((fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + elpi_readback_term ~depth h c s t)) + ~depth:(elpi__depth + 1) elpi__hyps + elpi__constraints elpi__state elpi__bo + | _ -> assert false in + let elpi__state = + elpi_pop_tctx ~depth:elpi__depth elpi__state + elpi__ctx_key in + (elpi__state, (Lam (elpi__75, elpi__70, elpi__71)), + (List.concat [elpi__74; elpi__72; elpi__73])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_term_Lamc))) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "term" (Elpi.API.RawPp.term elpi__depth) elpi__x) + and term : + 'c 'csts . + (term, #Ctx_for_term.t as 'c, 'csts) Elpi.API.ContextualConversion.t + = + let kind = Elpi.API.ContextualConversion.TyName "term" in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"term"; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"app" + ~doc:"App" + ~args:[Elpi.API.ContextualConversion.TyName + elpi_constant_type_term; + Elpi.API.ContextualConversion.TyName + elpi_constant_type_term]; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"lam" + ~doc:"Lam" + ~args:[ty.Elpi.API.ContextualConversion.ty; + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.ty; + Elpi.API.ContextualConversion.TyApp + ("->", + (Elpi.API.ContextualConversion.TyName "term"), + [Elpi.API.ContextualConversion.TyName + elpi_constant_type_term])]); + pp = pp_term; + embed = elpi_embed_term; + readback = elpi_readback_term + } + let elpi_term = Elpi.API.BuiltIn.MLDataC term + class ctx_for_term (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_term.t = + object (_) + inherit ((Elpi.API.ContextualConversion.ctx) h) + inherit ! ((ctx_for_tctx) h s) + method tctx = + context_made_of_tctx.Elpi.API.ContextualConversion.get s + end + let (in_ctx_for_term : + (Ctx_for_term.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> + let ctx = (new ctx_for_tctx) h s in + let (s, gls0) = + Elpi.API.PPX.readback_context ~depth context_made_of_tctx ctx + h c s in + (s, ((new ctx_for_term) h s), c, (List.concat [gls0])) + let () = declaration := ((!declaration) @ [elpi_term]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +let _ = fun (f : #ctx_for_tctx -> unit) -> fun (x : ctx_for_term) -> f x +open Elpi.API +open BuiltInPredicate +open Notation +let term_to_string = + CPred + ("term->string", in_ctx_for_term, + (CIn + (term, "T", + (COut (BuiltInContextualData.string, "S", (CRead "what else"))))), + (fun (t : term) -> + fun (_ety : string oarg) -> + fun ~depth:_ -> + fun c -> + fun (_cst : Data.constraints) -> + fun (_state : State.t) -> + !: + (Format.asprintf "@[%a@ ; %a@ |-@ %a@]@\n%!" + (RawData.Constants.Map.pp + (ContextualConversion.pp_ctx_entry pp_tctx)) + c#tyctx + (RawData.Constants.Map.pp + (ContextualConversion.pp_ctx_entry pp_tctx)) + c#tctx term.pp t))) +let builtin1 = + let open BuiltIn in + declare ~file_name:"test_ppx.elpi" + ((!declaration) @ + ([MLCode (term_to_string, DocAbove); + LPDoc "----------------- elpi ----------------"] @ + (let open Elpi.Builtin in core_builtins @ elpi_builtins))) +let builtin2 = + let open BuiltIn in declare ~file_name:(Sys.argv.(1)) (!declaration) +let main () = + let _elpi = Setup.init ~builtins:[builtin1; builtin2] () in + BuiltIn.document_file builtin2; exit 0 +;;main () diff --git a/ppx_elpi/tests/test_double_contextual.ml b/ppx_elpi/tests/test_double_contextual.ml new file mode 100644 index 000000000..2a454244a --- /dev/null +++ b/ppx_elpi/tests/test_double_contextual.ml @@ -0,0 +1,75 @@ +let declaration = ref [] + +module String = struct + include String + let pp fmt s = Format.fprintf fmt "%s" s + let show = Format.asprintf "%a" pp +end + +let pp_tyctx _ _ = () +type tyctx = TEntry of (string[@elpi.key]) * bool +[@@elpi.index (module String)] +[@@deriving elpi { declaration }] + + +let pp_ty _ _ = () +type ty = + | TVar of string [@elpi.var tyctx] + | TApp of string * ty + | TAll of bool * string * (ty[@elpi.binder tyctx (fun b s -> TEntry(s,b))]) +[@@deriving elpi { declaration; }] + + + +let pp_tctx _ _ = () +type tctx = Entry of (string[@elpi.key]) * ty +[@@elpi.index (module String)] +[@@deriving elpi { declaration ; context = [tyctx]} ] + + +let pp_term _ _ = () +type term = + | Var of string [@elpi.var tctx] + | App of term * term + | Lam of ty * string * (term[@elpi.binder tctx (fun b s -> Entry(s,b))]) +[@@deriving elpi { declaration }] + +let _ = + fun (f : #ctx_for_tctx -> unit) -> + fun (x : ctx_for_term) -> + f x + + +open Elpi.API +open BuiltInPredicate +open Notation + +let term_to_string = CPred("term->string",in_ctx_for_term, + CIn(term,"T", + COut(BuiltInContextualData.string,"S", + CRead("what else"))), + fun (t : term) (_ety : string oarg) + ~depth:_ c (_cst : Data.constraints) (_state : State.t) -> + + !: (Format.asprintf "@[%a@ ; %a@ |-@ %a@]@\n%!" + (RawData.Constants.Map.pp (ContextualConversion.pp_ctx_entry pp_tctx)) c#tyctx + (RawData.Constants.Map.pp (ContextualConversion.pp_ctx_entry pp_tctx)) c#tctx + term.pp t) + +) + +let builtin1 = let open BuiltIn in + declare ~file_name:"test_ppx.elpi" (!declaration @ [ + MLCode(term_to_string,DocAbove); + LPDoc "----------------- elpi ----------------" + ] @ Elpi.Builtin.(core_builtins @ elpi_builtins)) + +let builtin2 = let open BuiltIn in + declare ~file_name:(Sys.argv.(1)) !declaration + +let main () = + let _elpi = Setup.init ~builtins:[builtin1;builtin2] () in + BuiltIn.document_file builtin2; + exit 0 +;; +main () diff --git a/ppx_elpi/tests/test_mutual_adt.expected.elpi b/ppx_elpi/tests/test_mutual_adt.expected.elpi new file mode 100644 index 000000000..2ab1d84fb --- /dev/null +++ b/ppx_elpi/tests/test_mutual_adt.expected.elpi @@ -0,0 +1,15 @@ + + +% simple +kind simple type. +type a simple. % A +type b int -> mut -> simple. % B + +% mut +kind mut type. +type c mut. % C +type d simple -> mut. % D + + + + diff --git a/ppx_elpi/tests/test_mutual_adt.expected.ml b/ppx_elpi/tests/test_mutual_adt.expected.ml new file mode 100644 index 000000000..4a6af059d --- /dev/null +++ b/ppx_elpi/tests/test_mutual_adt.expected.ml @@ -0,0 +1,259 @@ +let elpi_stuff = ref [] +let pp_simple _ _ = () +let pp_mut _ _ = () +type simple = + | A + | B of int * mut +and mut = + | C + | D of simple [@@deriving elpi { declaration = elpi_stuff }] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_simple = "simple" + let elpi_constant_type_simplec = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_type_simple + let elpi_constant_constructor_simple_A = "a" + let elpi_constant_constructor_simple_Ac = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_simple_A + let elpi_constant_constructor_simple_B = "b" + let elpi_constant_constructor_simple_Bc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_simple_B + let elpi_constant_type_mut = "mut" + let elpi_constant_type_mutc = + Elpi.API.RawData.Constants.declare_global_symbol elpi_constant_type_mut + let elpi_constant_constructor_mut_C = "c" + let elpi_constant_constructor_mut_Cc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_mut_C + let elpi_constant_constructor_mut_D = "d" + let elpi_constant_constructor_mut_Dc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_mut_D + module Ctx_for_simple = + struct + class type t = object inherit Elpi.API.ContextualConversion.ctx end + end + module Ctx_for_mut = + struct + class type t = object inherit Elpi.API.ContextualConversion.ctx end + end + let rec elpi_embed_simple : + 'c 'csts . + (simple, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | A -> + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_simple_Ac []), + (List.concat [])) + | B (elpi__5, elpi__6) -> + let (elpi__state, elpi__9, elpi__7) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__5 in + let (elpi__state, elpi__10, elpi__8) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> fun t -> elpi_embed_mut ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__6 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_simple_Bc + [elpi__9; elpi__10]), + (List.concat [elpi__7; elpi__8])) + and elpi_embed_mut : + 'c 'csts . + (mut, #Ctx_for_mut.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | C -> + (elpi__state, + (Elpi.API.RawData.mkAppL elpi_constant_constructor_mut_Cc + []), (List.concat [])) + | D elpi__13 -> + let (elpi__state, elpi__15, elpi__14) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> fun t -> elpi_embed_simple ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__13 in + (elpi__state, + (Elpi.API.RawData.mkAppL elpi_constant_constructor_mut_Dc + [elpi__15]), (List.concat [elpi__14])) + and elpi_readback_simple : + 'c 'csts . + (simple, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.Const elpi__hd when + elpi__hd == elpi_constant_constructor_simple_Ac -> + (elpi__state, A, []) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_simple_Bc -> + let (elpi__state, elpi__4, elpi__3) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | elpi__1::[] -> + let (elpi__state, elpi__1, elpi__2) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> elpi_readback_mut ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__1 in + (elpi__state, (B (elpi__4, elpi__1)), + (List.concat [elpi__3; elpi__2])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_simple_Bc))) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "simple" (Elpi.API.RawPp.term elpi__depth) elpi__x) + and elpi_readback_mut : + 'c 'csts . + (mut, #Ctx_for_mut.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.Const elpi__hd when + elpi__hd == elpi_constant_constructor_mut_Cc -> + (elpi__state, C, []) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_mut_Dc -> + let (elpi__state, elpi__12, elpi__11) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> elpi_readback_simple ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__x in + (match elpi__xs with + | [] -> + (elpi__state, (D elpi__12), + (List.concat [elpi__11])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_mut_Dc))) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "mut" (Elpi.API.RawPp.term elpi__depth) elpi__x) + and simple : + 'c 'csts . + (simple, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.t + = + let kind = Elpi.API.ContextualConversion.TyName "simple" in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"simple"; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"a" ~doc:"A" + ~args:[]; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"b" ~doc:"B" + ~args:[Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.ty; + Elpi.API.ContextualConversion.TyName + elpi_constant_type_mut]); + pp = pp_simple; + embed = elpi_embed_simple; + readback = elpi_readback_simple + } + and mut : + 'c 'csts . + (mut, #Ctx_for_mut.t as 'c, 'csts) Elpi.API.ContextualConversion.t + = + let kind = Elpi.API.ContextualConversion.TyName "mut" in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"mut"; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"c" ~doc:"C" + ~args:[]; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"d" ~doc:"D" + ~args:[Elpi.API.ContextualConversion.TyName + elpi_constant_type_simple]); + pp = pp_mut; + embed = elpi_embed_mut; + readback = elpi_readback_mut + } + let elpi_simple = Elpi.API.BuiltIn.MLDataC simple + let elpi_mut = Elpi.API.BuiltIn.MLDataC mut + class ctx_for_simple (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_simple.t = + object (_) inherit ((Elpi.API.ContextualConversion.ctx) h) end + let (in_ctx_for_simple : + (Ctx_for_simple.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> (s, ((new ctx_for_simple) h s), c, (List.concat [])) + class ctx_for_mut (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_mut.t = + object (_) inherit ((Elpi.API.ContextualConversion.ctx) h) end + let (in_ctx_for_mut : + (Ctx_for_mut.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> fun s -> (s, ((new ctx_for_mut) h s), c, (List.concat [])) + let () = elpi_stuff := ((!elpi_stuff) @ [elpi_simple; elpi_mut]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +open Elpi.API +let builtin = + let open BuiltIn in declare ~file_name:(Sys.argv.(1)) (!elpi_stuff) +let main () = + let _elpi = Setup.init ~builtins:[builtin] () in + BuiltIn.document_file builtin; exit 0 +;;main () diff --git a/ppx_elpi/tests/test_mutual_adt.ml b/ppx_elpi/tests/test_mutual_adt.ml new file mode 100644 index 000000000..f4ff079d7 --- /dev/null +++ b/ppx_elpi/tests/test_mutual_adt.ml @@ -0,0 +1,20 @@ +let elpi_stuff = ref [] + +let pp_simple _ _ = () +let pp_mut _ _ = () +type simple = A | B of int * mut +and mut = C | D of simple +[@@deriving elpi { declaration = elpi_stuff }] + +open Elpi.API + +let builtin = let open BuiltIn in + declare ~file_name:(Sys.argv.(1)) !elpi_stuff + +let main () = + let _elpi = Setup.init ~builtins:[builtin] () in + BuiltIn.document_file builtin; + exit 0 +;; + +main () \ No newline at end of file diff --git a/ppx_elpi/tests/test_mutual_contextual.expected.elpi b/ppx_elpi/tests/test_mutual_contextual.expected.elpi new file mode 100644 index 000000000..e69de29bb diff --git a/ppx_elpi/tests/test_mutual_contextual.expected.ml b/ppx_elpi/tests/test_mutual_contextual.expected.ml new file mode 100644 index 000000000..1b50076a8 --- /dev/null +++ b/ppx_elpi/tests/test_mutual_contextual.expected.ml @@ -0,0 +1,684 @@ +let declaration = ref [] +module String = + struct + include String + let pp fmt s = Format.fprintf fmt "%s" s + let show = Format.asprintf "%a" pp + end +type term = + | Var of string [@elpi.var ctx] + | App of term * term + | Tapp of term * ty + | Lam of ty * string * + ((term)[@elpi.binder ctx (fun b -> fun s -> Entry (s, b))]) +and ty = + | TVar of string [@elpi.var ctx] + | TIdx of ty * term + | TAbs of string * bool * + ((ty)[@elpi.binder ctx (fun s -> fun b -> TEntry (s, b))]) +and ctx = + | Entry of ((string)[@elpi.index ]) * ty + | TEentry of ((string)[@elpi.index ]) * bool [@@elpi.index (module String)] +[@@deriving elpi { declaration }] +include + struct + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_term = "term" + let elpi_constant_type_termc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_type_term + let elpi_constant_constructor_term_Var = "var" + let elpi_constant_constructor_term_Varc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_term_Var + let elpi_constant_constructor_term_App = "app" + let elpi_constant_constructor_term_Appc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_term_App + let elpi_constant_constructor_term_Tapp = "tapp" + let elpi_constant_constructor_term_Tappc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_term_Tapp + let elpi_constant_constructor_term_Lam = "lam" + let elpi_constant_constructor_term_Lamc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_term_Lam + let elpi_constant_type_ty = "ty" + let elpi_constant_type_tyc = + Elpi.API.RawData.Constants.declare_global_symbol elpi_constant_type_ty + let elpi_constant_constructor_ty_TVar = "tvar" + let elpi_constant_constructor_ty_TVarc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_ty_TVar + let elpi_constant_constructor_ty_TIdx = "tidx" + let elpi_constant_constructor_ty_TIdxc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_ty_TIdx + let elpi_constant_constructor_ty_TAbs = "tabs" + let elpi_constant_constructor_ty_TAbsc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_ty_TAbs + let elpi_constant_type_ctx = "ctx" + let elpi_constant_type_ctxc = + Elpi.API.RawData.Constants.declare_global_symbol elpi_constant_type_ctx + let elpi_constant_constructor_ctx_Entry = "entry" + let elpi_constant_constructor_ctx_Entryc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_ctx_Entry + let elpi_constant_constructor_ctx_TEentry = "teentry" + let elpi_constant_constructor_ctx_TEentryc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_ctx_TEentry + module Ctx_for_term = + struct + class type t = + object + inherit Elpi.API.Conversion.ctx + inherit Ctx_for_ctx.t + method ctx : ctx Elpi.API.Conversion.ctx_field + end + end + module Ctx_for_ty = + struct + class type t = + object + inherit Elpi.API.Conversion.ctx + inherit Ctx_for_ctx.t + method ctx : ctx Elpi.API.Conversion.ctx_field + end + end + module Ctx_for_ctx = + struct + class type t = + object + inherit Elpi.API.Conversion.ctx + inherit Ctx_for_ctx.t + method ctx : ctx Elpi.API.Conversion.ctx_field + end + end + let rec elpi_embed_term : + 'c . (term, #Ctx_for_term.t as 'c) Elpi.API.Conversion.embedding = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | Var elpi__17 -> + let (elpi__ctx2dbl, _) = + Elpi.API.State.get elpi_ctx_state elpi__state in + let elpi__key = (fun x -> x) elpi__17 in + (if not (Elpi_ctx_Map.mem elpi__key elpi__ctx2dbl) + then Elpi.API.Utils.error "Unbound variable"; + (elpi__state, + (Elpi.API.RawData.mkBound + (Elpi_ctx_Map.find elpi__key elpi__ctx2dbl)), [])) + | App (elpi__20, elpi__21) -> + let (elpi__state, elpi__24, elpi__22) = + elpi_embed_term ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__20 in + let (elpi__state, elpi__25, elpi__23) = + elpi_embed_term ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__21 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_term_Appc + [elpi__24; elpi__25]), + (List.concat [elpi__22; elpi__23])) + | Tapp (elpi__26, elpi__27) -> + let (elpi__state, elpi__30, elpi__28) = + elpi_embed_term ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__26 in + let (elpi__state, elpi__31, elpi__29) = + elpi_embed_ty ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__27 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_term_Tappc + [elpi__30; elpi__31]), + (List.concat [elpi__28; elpi__29])) + | Lam (elpi__32, elpi__33, elpi__34) -> + let (elpi__state, elpi__38, elpi__35) = + elpi_embed_ty ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__32 in + let (elpi__state, elpi__39, elpi__36) = + Elpi.API.PPX.embed_string ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__33 in + let elpi__ctx_entry = + (fun b -> fun s -> Entry (s, b)) elpi__32 elpi__33 in + let elpi__ctx_key = + elpi_ctx_to_key ~depth:elpi__depth elpi__ctx_entry in + let elpi__ctx_entry = + { + Elpi.API.Conversion.entry = elpi__ctx_entry; + depth = elpi__depth + } in + let elpi__state = + elpi_push_ctx ~depth:(elpi__depth + 1) elpi__state + elpi__ctx_key elpi__ctx_entry in + let (elpi__state, elpi__41, elpi__37) = + elpi_embed_term ~depth:(elpi__depth + 1) elpi__hyps + elpi__constraints elpi__state elpi__34 in + let elpi__40 = Elpi.API.RawData.mkLam elpi__41 in + let elpi__state = + elpi_pop_ctx ~depth:(elpi__depth + 1) elpi__state + elpi__ctx_key in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_term_Lamc + [elpi__38; elpi__39; elpi__40]), + (List.concat [elpi__35; elpi__36; elpi__37])) + and elpi_embed_ty : + 'c . (ty, #Ctx_for_ty.t as 'c) Elpi.API.Conversion.embedding = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | TVar elpi__54 -> + let (elpi__ctx2dbl, _) = + Elpi.API.State.get elpi_ctx_state elpi__state in + let elpi__key = (fun x -> x) elpi__54 in + (if not (Elpi_ctx_Map.mem elpi__key elpi__ctx2dbl) + then Elpi.API.Utils.error "Unbound variable"; + (elpi__state, + (Elpi.API.RawData.mkBound + (Elpi_ctx_Map.find elpi__key elpi__ctx2dbl)), [])) + | TIdx (elpi__57, elpi__58) -> + let (elpi__state, elpi__61, elpi__59) = + elpi_embed_ty ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__57 in + let (elpi__state, elpi__62, elpi__60) = + elpi_embed_term ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__58 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_ty_TIdxc + [elpi__61; elpi__62]), + (List.concat [elpi__59; elpi__60])) + | TAbs (elpi__63, elpi__64, elpi__65) -> + let (elpi__state, elpi__69, elpi__66) = + Elpi.API.PPX.embed_string ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__63 in + let (elpi__state, elpi__70, elpi__67) = + Elpi.Builtin.PPX.embed_bool ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__64 in + let elpi__ctx_entry = + (fun s -> fun b -> TEntry (s, b)) elpi__63 elpi__64 in + let elpi__ctx_key = + elpi_ctx_to_key ~depth:elpi__depth elpi__ctx_entry in + let elpi__ctx_entry = + { + Elpi.API.Conversion.entry = elpi__ctx_entry; + depth = elpi__depth + } in + let elpi__state = + elpi_push_ctx ~depth:(elpi__depth + 1) elpi__state + elpi__ctx_key elpi__ctx_entry in + let (elpi__state, elpi__72, elpi__68) = + elpi_embed_ty ~depth:(elpi__depth + 1) elpi__hyps + elpi__constraints elpi__state elpi__65 in + let elpi__71 = Elpi.API.RawData.mkLam elpi__72 in + let elpi__state = + elpi_pop_ctx ~depth:(elpi__depth + 1) elpi__state + elpi__ctx_key in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_ty_TAbsc + [elpi__69; elpi__70; elpi__71]), + (List.concat [elpi__66; elpi__67; elpi__68])) + and elpi_embed_ctx : + 'c . + ((Elpi.API.RawData.constant * ctx), #Ctx_for_ctx.t as 'c) + Elpi.API.Conversion.embedding + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | (elpi__87, Entry (elpi__85, elpi__86)) -> + let (elpi__state, elpi__91, elpi__88) = + Elpi.API.BuiltInData.nominal.Elpi.API.Conversion.embed + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__87 in + let (elpi__state, elpi__92, elpi__89) = + Elpi.API.PPX.embed_string ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__85 in + let (elpi__state, elpi__93, elpi__90) = + elpi_embed_ty ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__86 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_ctx_Entryc + [elpi__91; elpi__92; elpi__93]), + (List.concat [elpi__88; elpi__89; elpi__90])) + | (elpi__96, TEentry (elpi__94, elpi__95)) -> + let (elpi__state, elpi__100, elpi__97) = + Elpi.API.BuiltInData.nominal.Elpi.API.Conversion.embed + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__96 in + let (elpi__state, elpi__101, elpi__98) = + Elpi.API.PPX.embed_string ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__94 in + let (elpi__state, elpi__102, elpi__99) = + Elpi.Builtin.PPX.embed_bool ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__95 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_ctx_TEentryc + [elpi__100; elpi__101; elpi__102]), + (List.concat [elpi__97; elpi__98; elpi__99])) + let rec elpi_readback_term : + 'c . (term, #Ctx_for_term.t as 'c) Elpi.API.Conversion.readback = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.Const elpi__hd when elpi__hd >= 0 -> + let (_, elpi__dbl2ctx) = + Elpi.API.State.get elpi_ctx_state elpi__state in + (if + not + (Elpi.API.RawData.Constants.Map.mem elpi__hd + elpi__dbl2ctx) + then + Elpi.API.Utils.error + (Format.asprintf "Unbound variable: %s in %a" + (Elpi.API.RawData.Constants.show elpi__hd) + (Elpi.API.RawData.Constants.Map.pp + (Elpi.API.Conversion.pp_ctx_entry pp_ctx)) + elpi__dbl2ctx); + (let { Elpi.API.Conversion.entry = elpi__entry; + depth = elpi__depth } + = + Elpi.API.RawData.Constants.Map.find elpi__hd + elpi__dbl2ctx in + (elpi__state, + (Var (elpi_ctx_to_key ~depth:elpi__depth elpi__entry)), + []))) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_term_Appc -> + let (elpi__state, elpi__6, elpi__5) = + elpi_readback_term ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | elpi__3::[] -> + let (elpi__state, elpi__3, elpi__4) = + elpi_readback_term ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__3 in + (elpi__state, (App (elpi__6, elpi__3)), + (List.concat [elpi__5; elpi__4])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_term_Appc))) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_term_Tappc -> + let (elpi__state, elpi__10, elpi__9) = + elpi_readback_term ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | elpi__7::[] -> + let (elpi__state, elpi__7, elpi__8) = + elpi_readback_ty ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__7 in + (elpi__state, (Tapp (elpi__10, elpi__7)), + (List.concat [elpi__9; elpi__8])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_term_Tappc))) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_term_Lamc -> + let (elpi__state, elpi__16, elpi__15) = + elpi_readback_ty ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | elpi__11::elpi__12::[] -> + let (elpi__state, elpi__11, elpi__13) = + Elpi.API.PPX.readback_string ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state + elpi__11 in + let elpi__ctx_entry = + (fun b -> fun s -> Entry (s, b)) elpi__16 elpi__11 in + let elpi__ctx_key = + elpi_ctx_to_key ~depth:elpi__depth elpi__ctx_entry in + let elpi__ctx_entry = + { + Elpi.API.Conversion.entry = elpi__ctx_entry; + depth = elpi__depth + } in + let elpi__state = + elpi_push_ctx ~depth:elpi__depth elpi__state + elpi__ctx_key elpi__ctx_entry in + let (elpi__state, elpi__12, elpi__14) = + match Elpi.API.RawData.look ~depth:elpi__depth + elpi__12 + with + | Elpi.API.RawData.Lam elpi__bo -> + elpi_readback_term ~depth:(elpi__depth + 1) + elpi__hyps elpi__constraints elpi__state + elpi__bo + | _ -> assert false in + let elpi__state = + elpi_pop_ctx ~depth:elpi__depth elpi__state + elpi__ctx_key in + (elpi__state, (Lam (elpi__16, elpi__11, elpi__12)), + (List.concat [elpi__15; elpi__13; elpi__14])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_term_Lamc))) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "term" (Elpi.API.RawPp.term elpi__depth) elpi__x) + and elpi_readback_ty : + 'c . (ty, #Ctx_for_ty.t as 'c) Elpi.API.Conversion.readback = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.Const elpi__hd when elpi__hd >= 0 -> + let (_, elpi__dbl2ctx) = + Elpi.API.State.get elpi_ctx_state elpi__state in + (if + not + (Elpi.API.RawData.Constants.Map.mem elpi__hd + elpi__dbl2ctx) + then + Elpi.API.Utils.error + (Format.asprintf "Unbound variable: %s in %a" + (Elpi.API.RawData.Constants.show elpi__hd) + (Elpi.API.RawData.Constants.Map.pp + (Elpi.API.Conversion.pp_ctx_entry pp_ctx)) + elpi__dbl2ctx); + (let { Elpi.API.Conversion.entry = elpi__entry; + depth = elpi__depth } + = + Elpi.API.RawData.Constants.Map.find elpi__hd + elpi__dbl2ctx in + (elpi__state, + (TVar + (elpi_ctx_to_key ~depth:elpi__depth elpi__entry)), + []))) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_ty_TIdxc -> + let (elpi__state, elpi__47, elpi__46) = + elpi_readback_ty ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | elpi__44::[] -> + let (elpi__state, elpi__44, elpi__45) = + elpi_readback_term ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__44 in + (elpi__state, (TIdx (elpi__47, elpi__44)), + (List.concat [elpi__46; elpi__45])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_ty_TIdxc))) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_ty_TAbsc -> + let (elpi__state, elpi__53, elpi__52) = + Elpi.API.PPX.readback_string ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | elpi__48::elpi__49::[] -> + let (elpi__state, elpi__48, elpi__50) = + Elpi.Builtin.PPX.readback_bool ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state + elpi__48 in + let elpi__ctx_entry = + (fun s -> fun b -> TEntry (s, b)) elpi__53 + elpi__48 in + let elpi__ctx_key = + elpi_ctx_to_key ~depth:elpi__depth elpi__ctx_entry in + let elpi__ctx_entry = + { + Elpi.API.Conversion.entry = elpi__ctx_entry; + depth = elpi__depth + } in + let elpi__state = + elpi_push_ctx ~depth:elpi__depth elpi__state + elpi__ctx_key elpi__ctx_entry in + let (elpi__state, elpi__49, elpi__51) = + match Elpi.API.RawData.look ~depth:elpi__depth + elpi__49 + with + | Elpi.API.RawData.Lam elpi__bo -> + elpi_readback_ty ~depth:(elpi__depth + 1) + elpi__hyps elpi__constraints elpi__state + elpi__bo + | _ -> assert false in + let elpi__state = + elpi_pop_ctx ~depth:elpi__depth elpi__state + elpi__ctx_key in + (elpi__state, (TAbs (elpi__53, elpi__48, elpi__49)), + (List.concat [elpi__52; elpi__50; elpi__51])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_ty_TAbsc))) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "ty" (Elpi.API.RawPp.term elpi__depth) elpi__x) + and elpi_readback_ctx : + 'c . + ((Elpi.API.RawData.constant * ctx), #Ctx_for_ctx.t as 'c) + Elpi.API.Conversion.readback + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_ctx_Entryc -> + let (elpi__state, elpi__78, elpi__77) = + Elpi.API.BuiltInData.nominal.Elpi.API.Conversion.readback + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__x in + (match elpi__xs with + | elpi__73::elpi__74::[] -> + let (elpi__state, elpi__73, elpi__75) = + Elpi.API.PPX.readback_string ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state + elpi__73 in + let (elpi__state, elpi__74, elpi__76) = + elpi_readback_ty ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__74 in + (elpi__state, + (elpi__78, (Entry (elpi__73, elpi__74))), + (List.concat [elpi__77; elpi__75; elpi__76])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_ctx_Entryc))) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_ctx_TEentryc -> + let (elpi__state, elpi__84, elpi__83) = + Elpi.API.BuiltInData.nominal.Elpi.API.Conversion.readback + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__x in + (match elpi__xs with + | elpi__79::elpi__80::[] -> + let (elpi__state, elpi__79, elpi__81) = + Elpi.API.PPX.readback_string ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state + elpi__79 in + let (elpi__state, elpi__80, elpi__82) = + Elpi.Builtin.PPX.readback_bool ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state + elpi__80 in + (elpi__state, + (elpi__84, (TEentry (elpi__79, elpi__80))), + (List.concat [elpi__83; elpi__81; elpi__82])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_ctx_TEentryc))) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "ctx" (Elpi.API.RawPp.term elpi__depth) elpi__x) + let term : 'c . (term, #Ctx_for_term.t as 'c) Elpi.API.Conversion.t = + let kind = Elpi.API.Conversion.TyName "term" in + { + Elpi.API.Conversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"term"; + (Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"app" + ~doc:"App" + ~args:[Elpi.API.Conversion.TyName elpi_constant_type_term; + Elpi.API.Conversion.TyName elpi_constant_type_term]; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"tapp" + ~doc:"Tapp" + ~args:[Elpi.API.Conversion.TyName elpi_constant_type_term; + Elpi.API.Conversion.TyName elpi_constant_type_ty]); + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"lam" + ~doc:"Lam" + ~args:[Elpi.API.Conversion.TyName elpi_constant_type_ty; + Elpi.API.BuiltInData.string.Elpi.API.Conversion.ty; + Elpi.API.Conversion.TyApp + ("->", (Elpi.API.Conversion.TyName "term"), + [Elpi.API.Conversion.TyName + elpi_constant_type_term])]); + pp = pp_term; + embed = elpi_embed_term; + readback = elpi_readback_term + } + let ty : 'c . (ty, #Ctx_for_ty.t as 'c) Elpi.API.Conversion.t = + let kind = Elpi.API.Conversion.TyName "ty" in + { + Elpi.API.Conversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"ty"; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"tidx" + ~doc:"TIdx" + ~args:[Elpi.API.Conversion.TyName elpi_constant_type_ty; + Elpi.API.Conversion.TyName elpi_constant_type_term]; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"tabs" + ~doc:"TAbs" + ~args:[Elpi.API.BuiltInData.string.Elpi.API.Conversion.ty; + Elpi.Builtin.bool.Elpi.API.Conversion.ty; + Elpi.API.Conversion.TyApp + ("->", (Elpi.API.Conversion.TyName "ty"), + [Elpi.API.Conversion.TyName elpi_constant_type_ty])]); + pp = pp_ty; + embed = elpi_embed_ty; + readback = elpi_readback_ty + } + let ctx : + 'c . + ((Elpi.API.RawData.constant * ctx), #Ctx_for_ctx.t as 'c) + Elpi.API.Conversion.t + = + let kind = Elpi.API.Conversion.TyName "ctx" in + { + Elpi.API.Conversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"ctx"; + Elpi.API.PPX.Doc.constructor fmt + ~ty:(Elpi.API.Conversion.TyName "prop") ~name:"entry" + ~doc:"Entry" + ~args:[Elpi.API.BuiltInData.nominal.Elpi.API.Conversion.ty; + Elpi.API.BuiltInData.string.Elpi.API.Conversion.ty; + Elpi.API.Conversion.TyName elpi_constant_type_ty]; + Elpi.API.PPX.Doc.constructor fmt + ~ty:(Elpi.API.Conversion.TyName "prop") ~name:"teentry" + ~doc:"TEentry" + ~args:[Elpi.API.BuiltInData.nominal.Elpi.API.Conversion.ty; + Elpi.API.BuiltInData.string.Elpi.API.Conversion.ty; + Elpi.Builtin.bool.Elpi.API.Conversion.ty]); + pp = (fun fmt -> fun (_, x) -> pp_ctx fmt x); + embed = elpi_embed_ctx; + readback = elpi_readback_ctx + } + let elpi_term = Elpi.API.BuiltIn.MLData term + let elpi_ty = Elpi.API.BuiltIn.MLData ty + let elpi_ctx = Elpi.API.BuiltIn.MLData ctx + class ctx_for_term (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_term.t = + object (_) + inherit ((Elpi.API.Conversion.ctx) h) + inherit ! ((ctx_for_ctx) h s) + method ctx = context_made_of_ctx.Elpi.API.Conversion.get s + end + let (in_ctx_for_term : Ctx_for_term.t Elpi.API.Conversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> + let ctx = (new ctx_for_ctx) h s in + let (s, gls0) = + Elpi.API.PPX.readback_context ~depth context_made_of_ctx ctx + h c s in + (s, ((new ctx_for_term) h s), (List.concat [gls0])) + class ctx_for_ty (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_ty.t = + object (_) + inherit ((Elpi.API.Conversion.ctx) h) + inherit ! ((ctx_for_ctx) h s) + method ctx = context_made_of_ctx.Elpi.API.Conversion.get s + end + let (in_ctx_for_ty : Ctx_for_ty.t Elpi.API.Conversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> + let ctx = (new ctx_for_ctx) h s in + let (s, gls0) = + Elpi.API.PPX.readback_context ~depth context_made_of_ctx ctx + h c s in + (s, ((new ctx_for_ty) h s), (List.concat [gls0])) + class ctx_for_ctx (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_ctx.t = + object (_) + inherit ((Elpi.API.Conversion.ctx) h) + inherit ! ((ctx_for_ctx) h s) + method ctx = context_made_of_ctx.Elpi.API.Conversion.get s + end + let (in_ctx_for_ctx : Ctx_for_ctx.t Elpi.API.Conversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> + let ctx = (new ctx_for_ctx) h s in + let (s, gls0) = + Elpi.API.PPX.readback_context ~depth context_made_of_ctx ctx + h c s in + (s, ((new ctx_for_ctx) h s), (List.concat [gls0])) + let () = declaration := ((!declaration) @ [elpi_term; elpi_ty; elpi_ctx]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +open Elpi.API +let in_ctx + : ((tctx ContextualConversion.ctx_entry RawData.Constants.Map.t * ctx + ContextualConversion.ctx_entry RawData.Constants.Map.t), + Data.constraints) ContextualConversion.ctx_readback + = in_ctx +let builtin = + let open BuiltIn in declare ~file_name:(Sys.argv.(1)) (!declaration) +let main () = + let (_elpi, _) = Setup.init ~builtins:[builtin] ~basedir:"." [] in + BuiltIn.document_file builtin; exit 0 +;;main () diff --git a/ppx_elpi/tests/test_mutual_contextual.ml.disabled b/ppx_elpi/tests/test_mutual_contextual.ml.disabled new file mode 100644 index 000000000..4b0d2a673 --- /dev/null +++ b/ppx_elpi/tests/test_mutual_contextual.ml.disabled @@ -0,0 +1,40 @@ +let declaration = ref [] + +module String = struct + include String + let pp fmt s = Format.fprintf fmt "%s" s + let show = Format.asprintf "%a" pp +end + +type term = + | Var of string [@elpi.var tctx] + | App of term * term + | Tapp of term * ty + | Lam of ty * string * (term[@elpi.binder tctx (fun b s -> Entry(s,b))]) +and ty = + | TVar of string [@elpi.var tctx] + | TIdx of ty * term + | TAbs of string * bool * (ty[@elpi.binder tctx (fun s b -> TEntry(s,b))]) +and tctx = + | Entry of (string[@elpi.index]) * ty + | TEentry of (string[@elpi.index]) * bool + [@@elpi.index (module String)] +[@@deriving elpi { declaration }] + +ONLY ONE + +open Elpi.API +open BuiltInPredicate +open Notation +let in_ctx_for_term : 'csts. (ctx_for_term, 'csts) ContextualConversion.ctx_readback = in_ctx_for_term + +let builtin = let open BuiltIn in + declare ~file_name:(Sys.argv.(1)) !declaration + +let main () = + let _elpi = Setup.init ~builtins:[builtin] () in + BuiltIn.document_file builtin; + exit 0 +;; + +main () diff --git a/ppx_elpi/tests/test_opaque_type.expected.elpi b/ppx_elpi/tests/test_opaque_type.expected.elpi new file mode 100644 index 000000000..8bff7f9d1 --- /dev/null +++ b/ppx_elpi/tests/test_opaque_type.expected.elpi @@ -0,0 +1,8 @@ + + +typeabbrev simple (ctype "simple"). + + + + + diff --git a/ppx_elpi/tests/test_opaque_type.expected.ml b/ppx_elpi/tests/test_opaque_type.expected.ml new file mode 100644 index 000000000..8316c773f --- /dev/null +++ b/ppx_elpi/tests/test_opaque_type.expected.ml @@ -0,0 +1,70 @@ +let elpi_stuff = ref [] +let pp_simple _ _ = () +type simple[@@elpi.opaque + { + Elpi.API.OpaqueData.name = "simple"; + doc = ""; + pp = (fun fmt -> fun _ -> Format.fprintf fmt ""); + compare = Stdlib.compare; + hash = Hashtbl.hash; + hconsed = false; + constants = [] + }][@@deriving elpi { declaration = elpi_stuff }] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_simple = "simple" + let elpi_constant_type_simplec = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_type_simple + let elpi_opaque_data_decl_simple = + Elpi.API.OpaqueData.declare + { + Elpi.API.OpaqueData.name = "simple"; + doc = ""; + pp = (fun fmt -> fun _ -> Format.fprintf fmt ""); + compare = Stdlib.compare; + hash = Hashtbl.hash; + hconsed = false; + constants = [] + } + module Ctx_for_simple = + struct + class type t = object inherit Elpi.API.ContextualConversion.ctx end + end + let simple : + 'c . + (simple, #Elpi.API.ContextualConversion.ctx as 'c, 'csts) + Elpi.API.ContextualConversion.t + = + let { Elpi.API.Conversion.embed = embed; readback; ty; pp_doc; pp } = + elpi_opaque_data_decl_simple in + let embed ~depth _ _ s t = embed ~depth s t in + let readback ~depth _ _ s t = readback ~depth s t in + { Elpi.API.ContextualConversion.embed = embed; readback; ty; pp_doc; pp + } + let elpi_embed_simple = simple.Elpi.API.ContextualConversion.embed + let elpi_readback_simple = simple.Elpi.API.ContextualConversion.readback + let elpi_simple = Elpi.API.BuiltIn.MLDataC simple + class ctx_for_simple (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_simple.t = + object (_) inherit ((Elpi.API.ContextualConversion.ctx) h) end + let (in_ctx_for_simple : + (Ctx_for_simple.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> (s, ((new ctx_for_simple) h s), c, (List.concat [])) + let () = elpi_stuff := ((!elpi_stuff) @ [elpi_simple]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +open Elpi.API +let test : + 'h . (simple, #ContextualConversion.ctx as 'h, 'c) ContextualConversion.t = + simple +let builtin = + let open BuiltIn in declare ~file_name:(Sys.argv.(1)) (!elpi_stuff) +let main () = + let _elpi = Setup.init ~builtins:[builtin] () in + BuiltIn.document_file builtin; exit 0 +;;main () diff --git a/ppx_elpi/tests/test_opaque_type.ml b/ppx_elpi/tests/test_opaque_type.ml new file mode 100644 index 000000000..a4027a52d --- /dev/null +++ b/ppx_elpi/tests/test_opaque_type.ml @@ -0,0 +1,20 @@ +let elpi_stuff = ref [] + +let pp_simple _ _ = () +type simple [@@elpi.opaque {Elpi.API.OpaqueData.name = "simple"; doc = ""; pp = (fun fmt _ -> Format.fprintf fmt ""); compare = Stdlib.compare; hash = Hashtbl.hash; hconsed = false; constants = []; } ] +[@@deriving elpi { declaration = elpi_stuff }] + +open Elpi.API + +let test : 'h. (simple, #ContextualConversion.ctx as 'h,'c) ContextualConversion.t = simple + +let builtin = let open BuiltIn in + declare ~file_name:(Sys.argv.(1)) !elpi_stuff + +let main () = + let _elpi = Setup.init ~builtins:[builtin] () in + BuiltIn.document_file builtin; + exit 0 +;; + +main () diff --git a/ppx_elpi/tests/test_opaque_type_alias.expected.elpi b/ppx_elpi/tests/test_opaque_type_alias.expected.elpi new file mode 100644 index 000000000..8bff7f9d1 --- /dev/null +++ b/ppx_elpi/tests/test_opaque_type_alias.expected.elpi @@ -0,0 +1,8 @@ + + +typeabbrev simple (ctype "simple"). + + + + + diff --git a/ppx_elpi/tests/test_opaque_type_alias.expected.ml b/ppx_elpi/tests/test_opaque_type_alias.expected.ml new file mode 100644 index 000000000..c1ff0f1bf --- /dev/null +++ b/ppx_elpi/tests/test_opaque_type_alias.expected.ml @@ -0,0 +1,71 @@ +let elpi_stuff = ref [] +let pp_simple _ _ = () +type simple = bool[@@elpi.opaque + { + Elpi.API.OpaqueData.name = "simple"; + doc = ""; + pp = + (fun fmt -> fun _ -> Format.fprintf fmt ""); + compare = Stdlib.compare; + hash = Hashtbl.hash; + hconsed = false; + constants = [] + }][@@deriving elpi { declaration = elpi_stuff }] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_simple = "simple" + let elpi_constant_type_simplec = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_type_simple + let elpi_opaque_data_decl_simple = + Elpi.API.OpaqueData.declare + { + Elpi.API.OpaqueData.name = "simple"; + doc = ""; + pp = (fun fmt -> fun _ -> Format.fprintf fmt ""); + compare = Stdlib.compare; + hash = Hashtbl.hash; + hconsed = false; + constants = [] + } + module Ctx_for_simple = + struct + class type t = object inherit Elpi.API.ContextualConversion.ctx end + end + let simple : + 'c . + (simple, #Elpi.API.ContextualConversion.ctx as 'c, 'csts) + Elpi.API.ContextualConversion.t + = + let { Elpi.API.Conversion.embed = embed; readback; ty; pp_doc; pp } = + elpi_opaque_data_decl_simple in + let embed ~depth _ _ s t = embed ~depth s t in + let readback ~depth _ _ s t = readback ~depth s t in + { Elpi.API.ContextualConversion.embed = embed; readback; ty; pp_doc; pp + } + let elpi_embed_simple = simple.Elpi.API.ContextualConversion.embed + let elpi_readback_simple = simple.Elpi.API.ContextualConversion.readback + let elpi_simple = Elpi.API.BuiltIn.MLDataC simple + class ctx_for_simple (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_simple.t = + object (_) inherit ((Elpi.API.ContextualConversion.ctx) h) end + let (in_ctx_for_simple : + (Ctx_for_simple.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> (s, ((new ctx_for_simple) h s), c, (List.concat [])) + let () = elpi_stuff := ((!elpi_stuff) @ [elpi_simple]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +open Elpi.API +let test : + 'h . (simple, #ContextualConversion.ctx as 'h, 'c) ContextualConversion.t = + simple +let builtin = + let open BuiltIn in declare ~file_name:(Sys.argv.(1)) (!elpi_stuff) +let main () = + let _elpi = Setup.init ~builtins:[builtin] () in + BuiltIn.document_file builtin; exit 0 +;;main () diff --git a/ppx_elpi/tests/test_opaque_type_alias.ml b/ppx_elpi/tests/test_opaque_type_alias.ml new file mode 100644 index 000000000..36fc7bfd7 --- /dev/null +++ b/ppx_elpi/tests/test_opaque_type_alias.ml @@ -0,0 +1,20 @@ +let elpi_stuff = ref [] + +let pp_simple _ _ = () +type simple = bool [@@elpi.opaque {Elpi.API.OpaqueData.name = "simple"; doc = ""; pp = (fun fmt _ -> Format.fprintf fmt ""); compare = Stdlib.compare; hash = Hashtbl.hash; hconsed = false; constants = []; } ] +[@@deriving elpi { declaration = elpi_stuff }] + +open Elpi.API + +let test : 'h. (simple, #ContextualConversion.ctx as 'h,'c) ContextualConversion.t = simple + +let builtin = let open BuiltIn in + declare ~file_name:(Sys.argv.(1)) !elpi_stuff + +let main () = + let _elpi = Setup.init ~builtins:[builtin] () in + BuiltIn.document_file builtin; + exit 0 +;; + +main () diff --git a/ppx_elpi/tests/test_poly_adt.expected.elpi b/ppx_elpi/tests/test_poly_adt.expected.elpi new file mode 100644 index 000000000..bf07da145 --- /dev/null +++ b/ppx_elpi/tests/test_poly_adt.expected.elpi @@ -0,0 +1,11 @@ + + +% simple +kind simple type -> type. +type a simple A0. % A +type b int -> simple A0. % B +type c list A0 -> int -> simple A0. % C + + + + diff --git a/ppx_elpi/tests/test_poly_adt.expected.ml b/ppx_elpi/tests/test_poly_adt.expected.ml new file mode 100644 index 000000000..545c6f749 --- /dev/null +++ b/ppx_elpi/tests/test_poly_adt.expected.ml @@ -0,0 +1,250 @@ +let elpi_stuff = ref [] +let pp_simple _ _ _ = () +type 'a simple = + | A + | B of int + | C of 'a list * int [@@deriving elpi { declaration = elpi_stuff }] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_simple = "simple" + let elpi_constant_type_simplec = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_type_simple + let elpi_constant_constructor_simple_A = "a" + let elpi_constant_constructor_simple_Ac = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_simple_A + let elpi_constant_constructor_simple_B = "b" + let elpi_constant_constructor_simple_Bc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_simple_B + let elpi_constant_constructor_simple_C = "c" + let elpi_constant_constructor_simple_Cc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_simple_C + module Ctx_for_simple = + struct + class type t = object inherit Elpi.API.ContextualConversion.ctx end + end + let rec elpi_embed_simple : + 'elpi__param__a 'c 'csts . + ('elpi__param__a, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding -> + ('elpi__param__a simple, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding + = + fun elpi_embed_elpi__param__a -> + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | A -> + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_simple_Ac []), + (List.concat [])) + | B elpi__7 -> + let (elpi__state, elpi__9, elpi__8) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__7 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_simple_Bc [elpi__9]), + (List.concat [elpi__8])) + | C (elpi__10, elpi__11) -> + let (elpi__state, elpi__14, elpi__12) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + (let embed = elpi_embed_elpi__param__a in + fun ~depth -> + fun h -> + fun c -> + fun s -> + fun l -> + let (s, l, eg) = + Elpi.API.Utils.map_acc + (embed ~depth h c) s l in + (s, + (Elpi.API.Utils.list_to_lp_list + l), eg)) ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__10 in + let (elpi__state, elpi__15, elpi__13) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__11 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_simple_Cc + [elpi__14; elpi__15]), + (List.concat [elpi__12; elpi__13])) + and elpi_readback_simple : + 'elpi__param__a 'c 'csts . + ('elpi__param__a, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback -> + ('elpi__param__a simple, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback + = + fun elpi_readback_elpi__param__a -> + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.Const elpi__hd when + elpi__hd == elpi_constant_constructor_simple_Ac -> + (elpi__state, A, []) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_simple_Bc -> + let (elpi__state, elpi__2, elpi__1) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | [] -> + (elpi__state, (B elpi__2), + (List.concat [elpi__1])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_simple_Bc))) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_simple_Cc -> + let (elpi__state, elpi__6, elpi__5) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + (let readback = + elpi_readback_elpi__param__a in + fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.Utils.map_acc + (readback ~depth h c) s + (Elpi.API.Utils.lp_list_to_list + ~depth t)) ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__x in + (match elpi__xs with + | elpi__3::[] -> + let (elpi__state, elpi__3, elpi__4) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state + elpi__3 in + (elpi__state, (C (elpi__6, elpi__3)), + (List.concat [elpi__5; elpi__4])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_simple_Cc))) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "simple" (Elpi.API.RawPp.term elpi__depth) elpi__x) + and simple : + 'elpi__param__a 'c 'csts . + ('elpi__param__a, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.t -> + ('elpi__param__a simple, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.t + = + fun elpi__param__a -> + let kind = + Elpi.API.ContextualConversion.TyApp + ("simple", (elpi__param__a.Elpi.API.ContextualConversion.ty), []) in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"simple"; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"a" ~doc:"A" + ~args:[]; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"b" ~doc:"B" + ~args:[Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.ty]; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"c" ~doc:"C" + ~args:[Elpi.API.ContextualConversion.TyApp + ("list", + (elpi__param__a.Elpi.API.ContextualConversion.ty), + []); + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.ty]); + pp = (pp_simple elpi__param__a.pp); + embed = + (elpi_embed_simple + elpi__param__a.Elpi.API.ContextualConversion.embed); + readback = + (elpi_readback_simple + elpi__param__a.Elpi.API.ContextualConversion.readback) + } + let elpi_simple = + Elpi.API.BuiltIn.MLDataC (simple Elpi.API.BuiltInContextualData.polyA0) + class ctx_for_simple (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_simple.t = + object (_) inherit ((Elpi.API.ContextualConversion.ctx) h) end + let (in_ctx_for_simple : + (Ctx_for_simple.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> (s, ((new ctx_for_simple) h s), c, (List.concat [])) + let () = elpi_stuff := ((!elpi_stuff) @ [elpi_simple]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +let t1 : + 'a 'c 'csts . + ('a, #Elpi.API.ContextualConversion.ctx as 'c, 'csts) + Elpi.API.ContextualConversion.t -> + ('a simple, #Elpi.API.ContextualConversion.ctx as 'c, 'csts) + Elpi.API.ContextualConversion.t + = simple +class type o = + object inherit Elpi.API.ContextualConversion.ctx method foobar : bool end +let t2 + : (int simple, o, Elpi.API.Data.constraints) + Elpi.API.ContextualConversion.t + = simple Elpi.API.BuiltInContextualData.int +let t3 + : (float simple, o, Elpi.API.Data.constraints) + Elpi.API.ContextualConversion.t + = simple Elpi.API.BuiltInContextualData.float +open Elpi.API +let builtin = + let open BuiltIn in declare ~file_name:(Sys.argv.(1)) (!elpi_stuff) +let main () = + let _elpi = Setup.init ~builtins:[builtin] () in + BuiltIn.document_file builtin; exit 0 +;;main () diff --git a/ppx_elpi/tests/test_poly_adt.ml b/ppx_elpi/tests/test_poly_adt.ml new file mode 100644 index 000000000..20ee5d106 --- /dev/null +++ b/ppx_elpi/tests/test_poly_adt.ml @@ -0,0 +1,25 @@ +let elpi_stuff = ref [] + +let pp_simple _ _ _ = () +type 'a simple = A | B of int | C of 'a list * int +[@@deriving elpi { declaration = elpi_stuff } ] + +let t1 : 'a 'c 'csts. ('a, #Elpi.API.ContextualConversion.ctx as 'c, 'csts) Elpi.API.ContextualConversion.t -> ('a simple, #Elpi.API.ContextualConversion.ctx as 'c, 'csts) Elpi.API.ContextualConversion.t = simple + +class type o = object inherit Elpi.API.ContextualConversion.ctx method foobar : bool end + +let t2 : (int simple, o, Elpi.API.Data.constraints) Elpi.API.ContextualConversion.t = simple Elpi.API.BuiltInContextualData.int +let t3 : (float simple, o, Elpi.API.Data.constraints) Elpi.API.ContextualConversion.t = simple Elpi.API.BuiltInContextualData.float + +open Elpi.API + +let builtin = let open BuiltIn in + declare ~file_name:(Sys.argv.(1)) !elpi_stuff + +let main () = + let _elpi = Setup.init ~builtins:[builtin] () in + BuiltIn.document_file builtin; + exit 0 +;; + +main () diff --git a/ppx_elpi/tests/test_poly_alias.expected.elpi b/ppx_elpi/tests/test_poly_alias.expected.elpi new file mode 100644 index 000000000..06136db4a --- /dev/null +++ b/ppx_elpi/tests/test_poly_alias.expected.elpi @@ -0,0 +1,7 @@ + + +typeabbrev (simple A0) (pair A0 int). % simple + + + + diff --git a/ppx_elpi/tests/test_poly_alias.expected.ml b/ppx_elpi/tests/test_poly_alias.expected.ml new file mode 100644 index 000000000..2a3e491fa --- /dev/null +++ b/ppx_elpi/tests/test_poly_alias.expected.ml @@ -0,0 +1,105 @@ +let elpi_stuff = ref [] +let pp_simple _ _ _ = () +type 'a simple = ('a * int)[@@deriving elpi { declaration = elpi_stuff }] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_simple = "simple" + let elpi_constant_type_simplec = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_type_simple + module Ctx_for_simple = + struct + class type t = object inherit Elpi.API.ContextualConversion.ctx end + end + let rec elpi_embed_simple : + 'elpi__param__a 'c 'csts . + ('elpi__param__a, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding -> + ('elpi__param__a simple, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding + = + fun elpi_embed_elpi__param__a -> + fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + (Elpi.Builtin.PPX.embed_pair elpi_embed_elpi__param__a + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.embed) + ~depth h c s t + and elpi_readback_simple : + 'elpi__param__a 'c 'csts . + ('elpi__param__a, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback -> + ('elpi__param__a simple, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback + = + fun elpi_readback_elpi__param__a -> + fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + (Elpi.Builtin.PPX.readback_pair + elpi_readback_elpi__param__a + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.readback) + ~depth h c s t + and simple : + 'elpi__param__a 'c 'csts . + ('elpi__param__a, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.t -> + ('elpi__param__a simple, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.t + = + fun elpi__param__a -> + let kind = + Elpi.API.ContextualConversion.TyApp + ("simple", (elpi__param__a.Elpi.API.ContextualConversion.ty), []) in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> Elpi.API.PPX.Doc.kind fmt kind ~doc:"simple"; ()); + pp = (pp_simple elpi__param__a.pp); + embed = + (elpi_embed_simple + elpi__param__a.Elpi.API.ContextualConversion.embed); + readback = + (elpi_readback_simple + elpi__param__a.Elpi.API.ContextualConversion.readback) + } + let elpi_simple = + let elpi__param__a = Elpi.API.BuiltInContextualData.polyA0 in + Elpi.API.BuiltIn.LPCode + ("typeabbrev " ^ + (("(" ^ ("simple" ^ (" " ^ ("A0" ^ ")")))) ^ + (" " ^ + (((let open Elpi.API.PPX.Doc in show_ty_ast ~prec:AppArg) @@ + (Elpi.Builtin.PPX.pair elpi__param__a + Elpi.API.BuiltInContextualData.int).Elpi.API.ContextualConversion.ty) + ^ (". % " ^ "simple"))))) + class ctx_for_simple (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_simple.t = + object (_) inherit ((Elpi.API.ContextualConversion.ctx) h) end + let (in_ctx_for_simple : + (Ctx_for_simple.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> (s, ((new ctx_for_simple) h s), c, (List.concat [])) + let () = elpi_stuff := ((!elpi_stuff) @ [elpi_simple]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +open Elpi.API +let x : + 'a 'c 'csts . + ('a, 'c, 'csts) ContextualConversion.t -> + ('a simple, 'c, 'csts) ContextualConversion.t + = simple +let builtin = + let open BuiltIn in declare ~file_name:(Sys.argv.(1)) (!elpi_stuff) +let main () = + let _elpi = Setup.init ~builtins:[builtin] () in + BuiltIn.document_file builtin; exit 0 +;;main () diff --git a/ppx_elpi/tests/test_poly_alias.ml b/ppx_elpi/tests/test_poly_alias.ml new file mode 100644 index 000000000..420234b25 --- /dev/null +++ b/ppx_elpi/tests/test_poly_alias.ml @@ -0,0 +1,20 @@ +let elpi_stuff = ref [] + +let pp_simple _ _ _ = () +type 'a simple = 'a * int +[@@deriving elpi { declaration = elpi_stuff }] + +open Elpi.API + +let x : 'a 'c 'csts. ('a, 'c,'csts) ContextualConversion.t -> ('a simple, 'c, 'csts) ContextualConversion.t = simple + +let builtin = let open BuiltIn in + declare ~file_name:(Sys.argv.(1)) !elpi_stuff + +let main () = + let _elpi = Setup.init ~builtins:[builtin] () in + BuiltIn.document_file builtin; + exit 0 +;; + +main () diff --git a/ppx_elpi/tests/test_ppx.mli b/ppx_elpi/tests/test_ppx.mli new file mode 100644 index 000000000..e69de29bb diff --git a/ppx_elpi/tests/test_simple_adt.expected.elpi b/ppx_elpi/tests/test_simple_adt.expected.elpi new file mode 100644 index 000000000..e188187fb --- /dev/null +++ b/ppx_elpi/tests/test_simple_adt.expected.elpi @@ -0,0 +1,10 @@ + + +% simple +kind simple type. +type a simple. % A +type b int -> simple. % B + + + + diff --git a/ppx_elpi/tests/test_simple_adt.expected.ml b/ppx_elpi/tests/test_simple_adt.expected.ml new file mode 100644 index 000000000..57822164c --- /dev/null +++ b/ppx_elpi/tests/test_simple_adt.expected.ml @@ -0,0 +1,130 @@ +let elpi_stuff = ref [] +let pp_simple _ _ = () +type simple = + | A + | B of int [@@deriving elpi { declaration = elpi_stuff }] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_simple = "simple" + let elpi_constant_type_simplec = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_type_simple + let elpi_constant_constructor_simple_A = "a" + let elpi_constant_constructor_simple_Ac = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_simple_A + let elpi_constant_constructor_simple_B = "b" + let elpi_constant_constructor_simple_Bc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_simple_B + module Ctx_for_simple = + struct + class type t = object inherit Elpi.API.ContextualConversion.ctx end + end + let rec elpi_embed_simple : + 'c 'csts . + (simple, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | A -> + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_simple_Ac []), + (List.concat [])) + | B elpi__3 -> + let (elpi__state, elpi__5, elpi__4) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__3 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_simple_Bc [elpi__5]), + (List.concat [elpi__4])) + and elpi_readback_simple : + 'c 'csts . + (simple, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.Const elpi__hd when + elpi__hd == elpi_constant_constructor_simple_Ac -> + (elpi__state, A, []) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_simple_Bc -> + let (elpi__state, elpi__2, elpi__1) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | [] -> + (elpi__state, (B elpi__2), (List.concat [elpi__1])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_simple_Bc))) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "simple" (Elpi.API.RawPp.term elpi__depth) elpi__x) + and simple : + 'c 'csts . + (simple, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.t + = + let kind = Elpi.API.ContextualConversion.TyName "simple" in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"simple"; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"a" ~doc:"A" + ~args:[]; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"b" ~doc:"B" + ~args:[Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.ty]); + pp = pp_simple; + embed = elpi_embed_simple; + readback = elpi_readback_simple + } + let elpi_simple = Elpi.API.BuiltIn.MLDataC simple + class ctx_for_simple (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_simple.t = + object (_) inherit ((Elpi.API.ContextualConversion.ctx) h) end + let (in_ctx_for_simple : + (Ctx_for_simple.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> (s, ((new ctx_for_simple) h s), c, (List.concat [])) + let () = elpi_stuff := ((!elpi_stuff) @ [elpi_simple]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +open Elpi.API +let builtin = + let open BuiltIn in declare ~file_name:(Sys.argv.(1)) (!elpi_stuff) +let main () = + let _elpi = Setup.init ~builtins:[builtin] () in + BuiltIn.document_file builtin; exit 0 +;;main () diff --git a/ppx_elpi/tests/test_simple_adt.ml b/ppx_elpi/tests/test_simple_adt.ml new file mode 100644 index 000000000..ad113784c --- /dev/null +++ b/ppx_elpi/tests/test_simple_adt.ml @@ -0,0 +1,18 @@ +let elpi_stuff = ref [] + +let pp_simple _ _ = () +type simple = A | B of int +[@@deriving elpi { declaration = elpi_stuff }] + +open Elpi.API + +let builtin = let open BuiltIn in + declare ~file_name:(Sys.argv.(1)) !elpi_stuff + +let main () = + let _elpi= Setup.init ~builtins:[builtin] () in + BuiltIn.document_file builtin; + exit 0 +;; + +main () \ No newline at end of file diff --git a/ppx_elpi/tests/test_simple_adt_record.expected.elpi b/ppx_elpi/tests/test_simple_adt_record.expected.elpi new file mode 100644 index 000000000..bd46ad6ad --- /dev/null +++ b/ppx_elpi/tests/test_simple_adt_record.expected.elpi @@ -0,0 +1,10 @@ + + +% simple +kind simple type. +type k1 int -> bool -> simple. % K1 +type k2 bool -> simple. % K2 + + + + diff --git a/ppx_elpi/tests/test_simple_adt_record.expected.ml b/ppx_elpi/tests/test_simple_adt_record.expected.ml new file mode 100644 index 000000000..31b07c1d0 --- /dev/null +++ b/ppx_elpi/tests/test_simple_adt_record.expected.ml @@ -0,0 +1,180 @@ +let elpi_stuff = ref [] +let pp_simple _ _ = () +type simple = + | K1 of { + f: int ; + g: bool } + | K2 of { + f2: bool } [@@deriving elpi { declaration = elpi_stuff }] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_simple = "simple" + let elpi_constant_type_simplec = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_type_simple + let elpi_constant_constructor_simple_K1 = "k1" + let elpi_constant_constructor_simple_K1c = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_simple_K1 + let elpi_constant_constructor_simple_K2 = "k2" + let elpi_constant_constructor_simple_K2c = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_simple_K2 + module Ctx_for_simple = + struct + class type t = object inherit Elpi.API.ContextualConversion.ctx end + end + let rec elpi_embed_simple : + 'c 'csts . + (simple, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | K1 { f = elpi__7; g = elpi__8 } -> + let (elpi__state, elpi__11, elpi__9) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__7 in + let (elpi__state, elpi__12, elpi__10) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__8 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_simple_K1c + [elpi__11; elpi__12]), + (List.concat [elpi__9; elpi__10])) + | K2 { f2 = elpi__13 } -> + let (elpi__state, elpi__15, elpi__14) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__13 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_simple_K2c [elpi__15]), + (List.concat [elpi__14])) + and elpi_readback_simple : + 'c 'csts . + (simple, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_simple_K1c -> + let (elpi__state, elpi__4, elpi__3) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | elpi__1::[] -> + let (elpi__state, elpi__1, elpi__2) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__1 in + (elpi__state, (K1 { f = elpi__4; g = elpi__1 }), + (List.concat [elpi__3; elpi__2])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_simple_K1c))) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_simple_K2c -> + let (elpi__state, elpi__6, elpi__5) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | [] -> + (elpi__state, (K2 { f2 = elpi__6 }), + (List.concat [elpi__5])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_simple_K2c))) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "simple" (Elpi.API.RawPp.term elpi__depth) elpi__x) + and simple : + 'c 'csts . + (simple, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.t + = + let kind = Elpi.API.ContextualConversion.TyName "simple" in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"simple"; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"k1" ~doc:"K1" + ~args:[Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.ty; + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.ty]; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"k2" ~doc:"K2" + ~args:[Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.ty]); + pp = pp_simple; + embed = elpi_embed_simple; + readback = elpi_readback_simple + } + let elpi_simple = Elpi.API.BuiltIn.MLDataC simple + class ctx_for_simple (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_simple.t = + object (_) inherit ((Elpi.API.ContextualConversion.ctx) h) end + let (in_ctx_for_simple : + (Ctx_for_simple.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> (s, ((new ctx_for_simple) h s), c, (List.concat [])) + let () = elpi_stuff := ((!elpi_stuff) @ [elpi_simple]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +open Elpi.API +let builtin = + let open BuiltIn in declare ~file_name:(Sys.argv.(1)) (!elpi_stuff) +let main () = + let _elpi = Setup.init ~builtins:[builtin] () in + BuiltIn.document_file builtin; exit 0 +;;main () diff --git a/ppx_elpi/tests/test_simple_adt_record.ml b/ppx_elpi/tests/test_simple_adt_record.ml new file mode 100644 index 000000000..3e5da8212 --- /dev/null +++ b/ppx_elpi/tests/test_simple_adt_record.ml @@ -0,0 +1,18 @@ +let elpi_stuff = ref [] + +let pp_simple _ _ = () +type simple = K1 of { f : int; g : bool } | K2 of { f2 : bool } +[@@deriving elpi { declaration = elpi_stuff }] + +open Elpi.API + +let builtin = let open BuiltIn in + declare ~file_name:(Sys.argv.(1)) !elpi_stuff + +let main () = + let _elpi = Setup.init ~builtins:[builtin] () in + BuiltIn.document_file builtin; + exit 0 +;; + +main () diff --git a/ppx_elpi/tests/test_simple_contextual.expected.elpi b/ppx_elpi/tests/test_simple_contextual.expected.elpi new file mode 100644 index 000000000..0822d5efd --- /dev/null +++ b/ppx_elpi/tests/test_simple_contextual.expected.elpi @@ -0,0 +1,14 @@ + + +% tctx +kind tctx type. +type entry nominal -> string -> bool -> prop. % Entry + +% term +kind term type. +type app term -> term -> term. % App +type lam bool -> string -> (term -> term) -> term. % Lam + + + + diff --git a/ppx_elpi/tests/test_simple_contextual.expected.ml b/ppx_elpi/tests/test_simple_contextual.expected.ml new file mode 100644 index 000000000..ee1655e84 --- /dev/null +++ b/ppx_elpi/tests/test_simple_contextual.expected.ml @@ -0,0 +1,567 @@ +let declaration = ref [] +module String = + struct + include String + let pp fmt s = Format.fprintf fmt "%s" s + let show = Format.asprintf "%a" pp + end +let pp_tctx _ _ = () +type tctx = + | Entry of ((string)[@elpi.key ]) * bool [@@elpi.index (module String)] +[@@deriving elpi { declaration }] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_tctx = "tctx" + let elpi_constant_type_tctxc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_type_tctx + let elpi_constant_constructor_tctx_Entry = "entry" + let elpi_constant_constructor_tctx_Entryc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_tctx_Entry + module Elpi_tctx_Map = (Elpi.API.Utils.Map.Make)(String) + let elpi_tctx_state = + Elpi.API.State.declare ~name:"tctx" + ~pp:(fun fmt -> fun _ -> Format.fprintf fmt "TODO") + ~init:(fun () -> + ((Elpi_tctx_Map.empty : Elpi.API.RawData.constant + Elpi_tctx_Map.t), + (Elpi.API.RawData.Constants.Map.empty : tctx + Elpi.API.ContextualConversion.ctx_entry + Elpi.API.RawData.Constants.Map.t))) + ~start:(fun x -> x) + let elpi_tctx_to_key ~depth:_ = + function | Entry (elpi__16, _) -> elpi__16 + let elpi_is_tctx { Elpi.API.Data.hdepth = elpi__depth; hsrc = elpi__x } = + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.Const _ -> None + | Elpi.API.RawData.App (elpi__hd, elpi__idx, _) -> + if false || (elpi__hd == elpi_constant_constructor_tctx_Entryc) + then + (match Elpi.API.RawData.look ~depth:elpi__depth elpi__idx with + | Elpi.API.RawData.Const x -> Some x + | _ -> + Elpi.API.Utils.type_error + "context entry applied to a non nominal") + else None + | _ -> None + let elpi_push_tctx ~depth:elpi__depth elpi__state elpi__name + elpi__ctx_item = + let (elpi__ctx2dbl, elpi__dbl2ctx) = + Elpi.API.State.get elpi_tctx_state elpi__state in + let elpi__i = elpi__depth in + let elpi__ctx2dbl = Elpi_tctx_Map.add elpi__name elpi__i elpi__ctx2dbl in + let elpi__dbl2ctx = + Elpi.API.RawData.Constants.Map.add elpi__i elpi__ctx_item + elpi__dbl2ctx in + let elpi__state = + Elpi.API.State.set elpi_tctx_state elpi__state + (elpi__ctx2dbl, elpi__dbl2ctx) in + elpi__state + let elpi_pop_tctx ~depth:elpi__depth elpi__state elpi__name = + let (elpi__ctx2dbl, elpi__dbl2ctx) = + Elpi.API.State.get elpi_tctx_state elpi__state in + let elpi__i = elpi__depth in + let elpi__ctx2dbl = Elpi_tctx_Map.remove elpi__name elpi__ctx2dbl in + let elpi__dbl2ctx = + Elpi.API.RawData.Constants.Map.remove elpi__i elpi__dbl2ctx in + let elpi__state = + Elpi.API.State.set elpi_tctx_state elpi__state + (elpi__ctx2dbl, elpi__dbl2ctx) in + elpi__state + module Ctx_for_tctx = + struct + class type t = object inherit Elpi.API.ContextualConversion.ctx end + end + let rec elpi_embed_tctx : + 'c 'csts . + ((Elpi.API.RawData.constant * tctx), #Ctx_for_tctx.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | (elpi__9, Entry (elpi__7, elpi__8)) -> + let (elpi__state, elpi__13, elpi__10) = + Elpi.API.BuiltInContextualData.nominal.Elpi.API.ContextualConversion.embed + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__9 in + let (elpi__state, elpi__14, elpi__11) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__7 in + let (elpi__state, elpi__15, elpi__12) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__8 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_tctx_Entryc + [elpi__13; elpi__14; elpi__15]), + (List.concat [elpi__10; elpi__11; elpi__12])) + and elpi_readback_tctx : + 'c 'csts . + ((Elpi.API.RawData.constant * tctx), #Ctx_for_tctx.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_tctx_Entryc -> + let (elpi__state, elpi__6, elpi__5) = + Elpi.API.BuiltInContextualData.nominal.Elpi.API.ContextualConversion.readback + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__x in + (match elpi__xs with + | elpi__1::elpi__2::[] -> + let (elpi__state, elpi__1, elpi__3) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__1 in + let (elpi__state, elpi__2, elpi__4) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__2 in + (elpi__state, (elpi__6, (Entry (elpi__1, elpi__2))), + (List.concat [elpi__5; elpi__3; elpi__4])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_tctx_Entryc))) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "tctx" (Elpi.API.RawPp.term elpi__depth) elpi__x) + and tctx : + 'c 'csts . + ((Elpi.API.RawData.constant * tctx), #Ctx_for_tctx.t as 'c, 'csts) + Elpi.API.ContextualConversion.t + = + let kind = Elpi.API.ContextualConversion.TyName "tctx" in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"tctx"; + Elpi.API.PPX.Doc.constructor fmt + ~ty:(Elpi.API.ContextualConversion.TyName "prop") + ~name:"entry" ~doc:"Entry" + ~args:[Elpi.API.BuiltInContextualData.nominal.Elpi.API.ContextualConversion.ty; + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.ty; + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.ty]); + pp = (fun fmt -> fun (_, x) -> pp_tctx fmt x); + embed = elpi_embed_tctx; + readback = elpi_readback_tctx + } + let context_made_of_tctx = + { + Elpi.API.ContextualConversion.is_entry_for_nominal = elpi_is_tctx; + to_key = elpi_tctx_to_key; + push = elpi_push_tctx; + pop = elpi_pop_tctx; + conv = tctx; + init = + (fun state -> + Elpi.API.State.set elpi_tctx_state state + ((Elpi_tctx_Map.empty : Elpi.API.RawData.constant + Elpi_tctx_Map.t), + (Elpi.API.RawData.Constants.Map.empty : tctx + Elpi.API.ContextualConversion.ctx_entry + Elpi.API.RawData.Constants.Map.t))); + get = + (fun state -> snd @@ (Elpi.API.State.get elpi_tctx_state state)) + } + let elpi_tctx = Elpi.API.BuiltIn.MLDataC tctx + class ctx_for_tctx (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_tctx.t = + object (_) inherit ((Elpi.API.ContextualConversion.ctx) h) end + let (in_ctx_for_tctx : + (Ctx_for_tctx.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> (s, ((new ctx_for_tctx) h s), c, (List.concat [])) + let () = declaration := ((!declaration) @ [elpi_tctx]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +let tctx : + 'c 'csts . ((int * tctx), 'c, 'csts) Elpi.API.ContextualConversion.t = tctx +let context_made_of_tctx : + 'c 'csts . + (tctx, string, #ctx_for_tctx as 'c, 'csts) + Elpi.API.ContextualConversion.context + = context_made_of_tctx +let in_ctx_for_tctx + : (ctx_for_tctx, 'csts) Elpi.API.ContextualConversion.ctx_readback = + in_ctx_for_tctx +let pp_term _ _ = () +type term = + | Var of string [@elpi.var tctx] + | App of term * term + | Lam of bool * string * + ((term)[@elpi.binder "term" tctx (fun b -> fun s -> Entry (s, b))]) +[@@deriving elpi { declaration }] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_term = "term" + let elpi_constant_type_termc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_type_term + let elpi_constant_constructor_term_Var = "var" + let elpi_constant_constructor_term_Varc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_term_Var + let elpi_constant_constructor_term_App = "app" + let elpi_constant_constructor_term_Appc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_term_App + let elpi_constant_constructor_term_Lam = "lam" + let elpi_constant_constructor_term_Lamc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_term_Lam + module Ctx_for_term = + struct + class type t = + object + inherit Elpi.API.ContextualConversion.ctx + inherit Ctx_for_tctx.t + method tctx : tctx Elpi.API.ContextualConversion.ctx_field + end + end + let rec elpi_embed_term : + 'c 'csts . + (term, #Ctx_for_term.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | Var elpi__29 -> + let (elpi__ctx2dbl, _) = + Elpi.API.State.get elpi_tctx_state elpi__state in + let elpi__key = (fun x -> x) elpi__29 in + (if not (Elpi_tctx_Map.mem elpi__key elpi__ctx2dbl) + then Elpi.API.Utils.error "Unbound variable"; + (elpi__state, + (Elpi.API.RawData.mkBound + (Elpi_tctx_Map.find elpi__key elpi__ctx2dbl)), [])) + | App (elpi__32, elpi__33) -> + let (elpi__state, elpi__36, elpi__34) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> fun t -> elpi_embed_term ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__32 in + let (elpi__state, elpi__37, elpi__35) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> fun t -> elpi_embed_term ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__33 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_term_Appc + [elpi__36; elpi__37]), + (List.concat [elpi__34; elpi__35])) + | Lam (elpi__38, elpi__39, elpi__40) -> + let (elpi__state, elpi__44, elpi__41) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__38 in + let (elpi__state, elpi__45, elpi__42) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__39 in + let elpi__ctx_entry = + (fun b -> fun s -> Entry (s, b)) elpi__38 elpi__39 in + let elpi__ctx_key = + elpi_tctx_to_key ~depth:elpi__depth elpi__ctx_entry in + let elpi__ctx_entry = + { + Elpi.API.ContextualConversion.entry = elpi__ctx_entry; + depth = elpi__depth + } in + let elpi__state = + elpi_push_tctx ~depth:(elpi__depth + 1) elpi__state + elpi__ctx_key elpi__ctx_entry in + let (elpi__state, elpi__47, elpi__43) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> fun t -> elpi_embed_term ~depth h c s t) + ~depth:(elpi__depth + 1) elpi__hyps elpi__constraints + elpi__state elpi__40 in + let elpi__46 = Elpi.API.RawData.mkLam elpi__47 in + let elpi__state = + elpi_pop_tctx ~depth:(elpi__depth + 1) elpi__state + elpi__ctx_key in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_term_Lamc + [elpi__44; elpi__45; elpi__46]), + (List.concat [elpi__41; elpi__42; elpi__43])) + and elpi_readback_term : + 'c 'csts . + (term, #Ctx_for_term.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.Const elpi__hd when elpi__hd >= 0 -> + let (_, elpi__dbl2ctx) = + Elpi.API.State.get elpi_tctx_state elpi__state in + (if + not + (Elpi.API.RawData.Constants.Map.mem elpi__hd + elpi__dbl2ctx) + then + Elpi.API.Utils.error + (Format.asprintf "Unbound variable: %s in %a" + (Elpi.API.RawData.Constants.show elpi__hd) + (Elpi.API.RawData.Constants.Map.pp + (Elpi.API.ContextualConversion.pp_ctx_entry + pp_tctx)) elpi__dbl2ctx); + (let { + Elpi.API.ContextualConversion.entry = elpi__entry; + depth = elpi__depth } + = + Elpi.API.RawData.Constants.Map.find elpi__hd + elpi__dbl2ctx in + (elpi__state, + (Var + (elpi_tctx_to_key ~depth:elpi__depth elpi__entry)), + []))) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_term_Appc -> + let (elpi__state, elpi__22, elpi__21) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> elpi_readback_term ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__x in + (match elpi__xs with + | elpi__19::[] -> + let (elpi__state, elpi__19, elpi__20) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + elpi_readback_term ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__19 in + (elpi__state, (App (elpi__22, elpi__19)), + (List.concat [elpi__21; elpi__20])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_term_Appc))) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_term_Lamc -> + let (elpi__state, elpi__28, elpi__27) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | elpi__23::elpi__24::[] -> + let (elpi__state, elpi__23, elpi__25) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state + elpi__23 in + let elpi__ctx_entry = + (fun b -> fun s -> Entry (s, b)) elpi__28 elpi__23 in + let elpi__ctx_key = + elpi_tctx_to_key ~depth:elpi__depth + elpi__ctx_entry in + let elpi__ctx_entry = + { + Elpi.API.ContextualConversion.entry = + elpi__ctx_entry; + depth = elpi__depth + } in + let elpi__state = + elpi_push_tctx ~depth:elpi__depth elpi__state + elpi__ctx_key elpi__ctx_entry in + let (elpi__state, elpi__24, elpi__26) = + match Elpi.API.RawData.look ~depth:elpi__depth + elpi__24 + with + | Elpi.API.RawData.Lam elpi__bo -> + ((fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + elpi_readback_term ~depth h c s t)) + ~depth:(elpi__depth + 1) elpi__hyps + elpi__constraints elpi__state elpi__bo + | _ -> assert false in + let elpi__state = + elpi_pop_tctx ~depth:elpi__depth elpi__state + elpi__ctx_key in + (elpi__state, (Lam (elpi__28, elpi__23, elpi__24)), + (List.concat [elpi__27; elpi__25; elpi__26])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_term_Lamc))) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "term" (Elpi.API.RawPp.term elpi__depth) elpi__x) + and term : + 'c 'csts . + (term, #Ctx_for_term.t as 'c, 'csts) Elpi.API.ContextualConversion.t + = + let kind = Elpi.API.ContextualConversion.TyName "term" in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"term"; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"app" + ~doc:"App" + ~args:[Elpi.API.ContextualConversion.TyName + elpi_constant_type_term; + Elpi.API.ContextualConversion.TyName + elpi_constant_type_term]; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"lam" + ~doc:"Lam" + ~args:[Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.ty; + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.ty; + Elpi.API.ContextualConversion.TyApp + ("->", + (Elpi.API.ContextualConversion.TyName "term"), + [Elpi.API.ContextualConversion.TyName + elpi_constant_type_term])]); + pp = pp_term; + embed = elpi_embed_term; + readback = elpi_readback_term + } + let elpi_term = Elpi.API.BuiltIn.MLDataC term + class ctx_for_term (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_term.t = + object (_) + inherit ((Elpi.API.ContextualConversion.ctx) h) + inherit ! ((ctx_for_tctx) h s) + method tctx = + context_made_of_tctx.Elpi.API.ContextualConversion.get s + end + let (in_ctx_for_term : + (Ctx_for_term.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> + let ctx = (new ctx_for_tctx) h s in + let (s, gls0) = + Elpi.API.PPX.readback_context ~depth context_made_of_tctx ctx + h c s in + (s, ((new ctx_for_term) h s), c, (List.concat [gls0])) + let () = declaration := ((!declaration) @ [elpi_term]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +let term : + 'c 'csts . + (term, #ctx_for_term as 'c, 'csts) Elpi.API.ContextualConversion.t + = term +let in_ctx_for_term + : (ctx_for_term, 'csts) Elpi.API.ContextualConversion.ctx_readback = + in_ctx_for_term +open Elpi.API +open BuiltInPredicate +open Notation +let term_to_string = + CPred + ("term->string", in_ctx_for_term, + (CIn + (term, "T", + (COut (BuiltInContextualData.string, "S", (CRead "what else"))))), + (fun (t : term) -> + fun (_ety : string oarg) -> + fun ~depth:_ -> + fun c -> + fun (_cst : Data.constraints) -> + fun (_state : State.t) -> + !: + (Format.asprintf "@[%a@ |-@ %a@]@\n%!" + (RawData.Constants.Map.pp + (ContextualConversion.pp_ctx_entry pp_tctx)) + c#tctx term.pp t))) +let builtin1 = + let open BuiltIn in + declare ~file_name:"test_ppx.elpi" + ((!declaration) @ + ([MLCode (term_to_string, DocAbove); + LPDoc "----------------- elpi ----------------"] @ + (let open Elpi.Builtin in core_builtins @ elpi_builtins))) +let builtin2 = + let open BuiltIn in declare ~file_name:(Sys.argv.(1)) (!declaration) +let main () = + let _elpi = Setup.init ~builtins:[builtin1; builtin2] () in + BuiltIn.document_file builtin2; exit 0 +;;main () diff --git a/ppx_elpi/tests/test_simple_contextual.ml b/ppx_elpi/tests/test_simple_contextual.ml new file mode 100644 index 000000000..a7a72cc45 --- /dev/null +++ b/ppx_elpi/tests/test_simple_contextual.ml @@ -0,0 +1,59 @@ +let declaration = ref [] + +module String = struct + include String + let pp fmt s = Format.fprintf fmt "%s" s + let show = Format.asprintf "%a" pp +end + +let pp_tctx _ _ = () +type tctx = Entry of (string[@elpi.key]) * bool + [@@elpi.index (module String)] +[@@deriving elpi { declaration }] + +let tctx : 'c 'csts. (int * tctx, 'c,'csts) Elpi.API.ContextualConversion.t = tctx +let context_made_of_tctx : 'c 'csts. (tctx, string, #ctx_for_tctx as 'c,'csts) Elpi.API.ContextualConversion.context = context_made_of_tctx +let in_ctx_for_tctx : (ctx_for_tctx,'csts) Elpi.API.ContextualConversion.ctx_readback = in_ctx_for_tctx + +let pp_term _ _ = () +type term = + | Var of string [@elpi.var tctx] + | App of term * term + | Lam of bool * string * (term[@elpi.binder "term" tctx (fun b s -> Entry(s,b))]) +[@@deriving elpi { declaration }] + +let term : 'c 'csts. (term, #ctx_for_term as 'c, 'csts) Elpi.API.ContextualConversion.t = term +let in_ctx_for_term : (ctx_for_term, 'csts) Elpi.API.ContextualConversion.ctx_readback = in_ctx_for_term + +open Elpi.API +open BuiltInPredicate +open Notation + +let term_to_string = CPred("term->string",in_ctx_for_term, + CIn(term,"T", + COut(BuiltInContextualData.string,"S", + CRead("what else"))), + fun (t : term) (_ety : string oarg) + ~depth:_ c (_cst : Data.constraints) (_state : State.t) -> + + !: (Format.asprintf "@[%a@ |-@ %a@]@\n%!" + (RawData.Constants.Map.pp (ContextualConversion.pp_ctx_entry pp_tctx)) c#tctx + term.pp t) + +) + +let builtin1 = let open BuiltIn in + declare ~file_name:"test_ppx.elpi" (!declaration @ [ + MLCode(term_to_string,DocAbove); + LPDoc "----------------- elpi ----------------" + ] @ Elpi.Builtin.(core_builtins @ elpi_builtins)) + +let builtin2 = let open BuiltIn in + declare ~file_name:(Sys.argv.(1)) !declaration + +let main () = + let _elpi = Setup.init ~builtins:[builtin1;builtin2] () in + BuiltIn.document_file builtin2; + exit 0 +;; +main () diff --git a/ppx_elpi/tests/test_simple_record.expected.elpi b/ppx_elpi/tests/test_simple_record.expected.elpi new file mode 100644 index 000000000..1f2783c04 --- /dev/null +++ b/ppx_elpi/tests/test_simple_record.expected.elpi @@ -0,0 +1,9 @@ + + +% simple +kind simple type. +type simple int -> bool -> simple. % simple + + + + diff --git a/ppx_elpi/tests/test_simple_record.expected.ml b/ppx_elpi/tests/test_simple_record.expected.ml new file mode 100644 index 000000000..391f38c9a --- /dev/null +++ b/ppx_elpi/tests/test_simple_record.expected.ml @@ -0,0 +1,138 @@ +let elpi_stuff = ref [] +let pp_simple _ _ = () +type simple = { + f: int ; + g: bool }[@@deriving elpi { declaration = elpi_stuff }] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_simple = "simple" + let elpi_constant_type_simplec = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_type_simple + let elpi_constant_constructor_simple_simple = "simple" + let elpi_constant_constructor_simple_simplec = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_simple_simple + module Ctx_for_simple = + struct + class type t = object inherit Elpi.API.ContextualConversion.ctx end + end + let rec elpi_embed_simple : + 'c 'csts . + (simple, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | { f = elpi__5; g = elpi__6 } -> + let (elpi__state, elpi__9, elpi__7) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__5 in + let (elpi__state, elpi__10, elpi__8) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__6 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_simple_simplec + [elpi__9; elpi__10]), + (List.concat [elpi__7; elpi__8])) + and elpi_readback_simple : + 'c 'csts . + (simple, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_simple_simplec -> + let (elpi__state, elpi__4, elpi__3) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | elpi__1::[] -> + let (elpi__state, elpi__1, elpi__2) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__1 in + (elpi__state, { f = elpi__4; g = elpi__1 }, + (List.concat [elpi__3; elpi__2])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_simple_simplec))) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "simple" (Elpi.API.RawPp.term elpi__depth) elpi__x) + and simple : + 'c 'csts . + (simple, #Ctx_for_simple.t as 'c, 'csts) + Elpi.API.ContextualConversion.t + = + let kind = Elpi.API.ContextualConversion.TyName "simple" in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"simple"; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"simple" + ~doc:"simple" + ~args:[Elpi.API.BuiltInContextualData.int.Elpi.API.ContextualConversion.ty; + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.ty]); + pp = pp_simple; + embed = elpi_embed_simple; + readback = elpi_readback_simple + } + let elpi_simple = Elpi.API.BuiltIn.MLDataC simple + class ctx_for_simple (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_simple.t = + object (_) inherit ((Elpi.API.ContextualConversion.ctx) h) end + let (in_ctx_for_simple : + (Ctx_for_simple.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> (s, ((new ctx_for_simple) h s), c, (List.concat [])) + let () = elpi_stuff := ((!elpi_stuff) @ [elpi_simple]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +open Elpi.API +let builtin = + let open BuiltIn in declare ~file_name:(Sys.argv.(1)) (!elpi_stuff) +let main () = + let _elpi = Setup.init ~builtins:[builtin] () in + BuiltIn.document_file builtin; exit 0 +;;main () diff --git a/ppx_elpi/tests/test_simple_record.ml b/ppx_elpi/tests/test_simple_record.ml new file mode 100644 index 000000000..4ef6b8fc4 --- /dev/null +++ b/ppx_elpi/tests/test_simple_record.ml @@ -0,0 +1,18 @@ +let elpi_stuff = ref [] + +let pp_simple _ _ = () +type simple = { f : int; g : bool } +[@@deriving elpi { declaration = elpi_stuff }] + +open Elpi.API + +let builtin = let open BuiltIn in + declare ~file_name:(Sys.argv.(1)) !elpi_stuff + +let main () = + let _elpi = Setup.init ~builtins:[builtin] () in + BuiltIn.document_file builtin; + exit 0 +;; + +main () \ No newline at end of file diff --git a/ppx_elpi/tests/test_two_layers_context.expected.elpi b/ppx_elpi/tests/test_two_layers_context.expected.elpi new file mode 100644 index 000000000..e69de29bb diff --git a/ppx_elpi/tests/test_two_layers_context.expected.ml b/ppx_elpi/tests/test_two_layers_context.expected.ml new file mode 100644 index 000000000..0c9989609 --- /dev/null +++ b/ppx_elpi/tests/test_two_layers_context.expected.ml @@ -0,0 +1,1427 @@ +let declaration = ref [] +module String = + struct + include String + let pp fmt s = Format.fprintf fmt "%s" s + let show x = x + end +let pp_tctx _ _ = () +type tctx = + | TDecl of ((string)[@elpi.key ]) * bool [@@elpi.index (module String)] +[@@deriving elpi { declaration }] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_tctx = "tctx" + let elpi_constant_type_tctxc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_type_tctx + let elpi_constant_constructor_tctx_TDecl = "tdecl" + let elpi_constant_constructor_tctx_TDeclc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_tctx_TDecl + module Elpi_tctx_Map = (Elpi.API.Utils.Map.Make)(String) + let elpi_tctx_state = + Elpi.API.State.declare ~name:"tctx" + ~pp:(fun fmt -> fun _ -> Format.fprintf fmt "TODO") + ~init:(fun () -> + ((Elpi_tctx_Map.empty : Elpi.API.RawData.constant + Elpi_tctx_Map.t), + (Elpi.API.RawData.Constants.Map.empty : tctx + Elpi.API.ContextualConversion.ctx_entry + Elpi.API.RawData.Constants.Map.t))) + ~start:(fun x -> x) + let elpi_tctx_to_key ~depth:_ = + function | TDecl (elpi__16, _) -> elpi__16 + let elpi_is_tctx { Elpi.API.Data.hdepth = elpi__depth; hsrc = elpi__x } = + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.Const _ -> None + | Elpi.API.RawData.App (elpi__hd, elpi__idx, _) -> + if false || (elpi__hd == elpi_constant_constructor_tctx_TDeclc) + then + (match Elpi.API.RawData.look ~depth:elpi__depth elpi__idx with + | Elpi.API.RawData.Const x -> Some x + | _ -> + Elpi.API.Utils.type_error + "context entry applied to a non nominal") + else None + | _ -> None + let elpi_push_tctx ~depth:elpi__depth elpi__state elpi__name + elpi__ctx_item = + let (elpi__ctx2dbl, elpi__dbl2ctx) = + Elpi.API.State.get elpi_tctx_state elpi__state in + let elpi__i = elpi__depth in + let elpi__ctx2dbl = Elpi_tctx_Map.add elpi__name elpi__i elpi__ctx2dbl in + let elpi__dbl2ctx = + Elpi.API.RawData.Constants.Map.add elpi__i elpi__ctx_item + elpi__dbl2ctx in + let elpi__state = + Elpi.API.State.set elpi_tctx_state elpi__state + (elpi__ctx2dbl, elpi__dbl2ctx) in + elpi__state + let elpi_pop_tctx ~depth:elpi__depth elpi__state elpi__name = + let (elpi__ctx2dbl, elpi__dbl2ctx) = + Elpi.API.State.get elpi_tctx_state elpi__state in + let elpi__i = elpi__depth in + let elpi__ctx2dbl = Elpi_tctx_Map.remove elpi__name elpi__ctx2dbl in + let elpi__dbl2ctx = + Elpi.API.RawData.Constants.Map.remove elpi__i elpi__dbl2ctx in + let elpi__state = + Elpi.API.State.set elpi_tctx_state elpi__state + (elpi__ctx2dbl, elpi__dbl2ctx) in + elpi__state + module Ctx_for_tctx = + struct + class type t = object inherit Elpi.API.ContextualConversion.ctx end + end + let rec elpi_embed_tctx : + 'c 'csts . + ((Elpi.API.RawData.constant * tctx), #Ctx_for_tctx.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | (elpi__9, TDecl (elpi__7, elpi__8)) -> + let (elpi__state, elpi__13, elpi__10) = + Elpi.API.BuiltInContextualData.nominal.Elpi.API.ContextualConversion.embed + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__9 in + let (elpi__state, elpi__14, elpi__11) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__7 in + let (elpi__state, elpi__15, elpi__12) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__8 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_tctx_TDeclc + [elpi__13; elpi__14; elpi__15]), + (List.concat [elpi__10; elpi__11; elpi__12])) + and elpi_readback_tctx : + 'c 'csts . + ((Elpi.API.RawData.constant * tctx), #Ctx_for_tctx.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_tctx_TDeclc -> + let (elpi__state, elpi__6, elpi__5) = + Elpi.API.BuiltInContextualData.nominal.Elpi.API.ContextualConversion.readback + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__x in + (match elpi__xs with + | elpi__1::elpi__2::[] -> + let (elpi__state, elpi__1, elpi__3) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__1 in + let (elpi__state, elpi__2, elpi__4) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__2 in + (elpi__state, (elpi__6, (TDecl (elpi__1, elpi__2))), + (List.concat [elpi__5; elpi__3; elpi__4])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_tctx_TDeclc))) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "tctx" (Elpi.API.RawPp.term elpi__depth) elpi__x) + and tctx : + 'c 'csts . + ((Elpi.API.RawData.constant * tctx), #Ctx_for_tctx.t as 'c, 'csts) + Elpi.API.ContextualConversion.t + = + let kind = Elpi.API.ContextualConversion.TyName "tctx" in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"tctx"; + Elpi.API.PPX.Doc.constructor fmt + ~ty:(Elpi.API.ContextualConversion.TyName "prop") + ~name:"tdecl" ~doc:"TDecl" + ~args:[Elpi.API.BuiltInContextualData.nominal.Elpi.API.ContextualConversion.ty; + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.ty; + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.ty]); + pp = (fun fmt -> fun (_, x) -> pp_tctx fmt x); + embed = elpi_embed_tctx; + readback = elpi_readback_tctx + } + let context_made_of_tctx = + { + Elpi.API.ContextualConversion.is_entry_for_nominal = elpi_is_tctx; + to_key = elpi_tctx_to_key; + push = elpi_push_tctx; + pop = elpi_pop_tctx; + conv = tctx; + init = + (fun state -> + Elpi.API.State.set elpi_tctx_state state + ((Elpi_tctx_Map.empty : Elpi.API.RawData.constant + Elpi_tctx_Map.t), + (Elpi.API.RawData.Constants.Map.empty : tctx + Elpi.API.ContextualConversion.ctx_entry + Elpi.API.RawData.Constants.Map.t))); + get = + (fun state -> snd @@ (Elpi.API.State.get elpi_tctx_state state)) + } + let elpi_tctx = Elpi.API.BuiltIn.MLDataC tctx + class ctx_for_tctx (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_tctx.t = + object (_) inherit ((Elpi.API.ContextualConversion.ctx) h) end + let (in_ctx_for_tctx : + (Ctx_for_tctx.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> (s, ((new ctx_for_tctx) h s), c, (List.concat [])) + let () = declaration := ((!declaration) @ [elpi_tctx]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +let pp_tye _ _ = () +type tye = + | TVar of string [@elpi.var tctx] + | TConst of string + | TArrow of tye * tye [@@deriving elpi { declaration }] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_tye = "tye" + let elpi_constant_type_tyec = + Elpi.API.RawData.Constants.declare_global_symbol elpi_constant_type_tye + let elpi_constant_constructor_tye_TVar = "tvar" + let elpi_constant_constructor_tye_TVarc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_tye_TVar + let elpi_constant_constructor_tye_TConst = "tconst" + let elpi_constant_constructor_tye_TConstc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_tye_TConst + let elpi_constant_constructor_tye_TArrow = "tarrow" + let elpi_constant_constructor_tye_TArrowc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_tye_TArrow + module Ctx_for_tye = + struct + class type t = + object + inherit Elpi.API.ContextualConversion.ctx + inherit Ctx_for_tctx.t + method tctx : tctx Elpi.API.ContextualConversion.ctx_field + end + end + let rec elpi_embed_tye : + 'c 'csts . + (tye, #Ctx_for_tye.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | TVar elpi__25 -> + let (elpi__ctx2dbl, _) = + Elpi.API.State.get elpi_tctx_state elpi__state in + let elpi__key = (fun x -> x) elpi__25 in + (if not (Elpi_tctx_Map.mem elpi__key elpi__ctx2dbl) + then Elpi.API.Utils.error "Unbound variable"; + (elpi__state, + (Elpi.API.RawData.mkBound + (Elpi_tctx_Map.find elpi__key elpi__ctx2dbl)), [])) + | TConst elpi__28 -> + let (elpi__state, elpi__30, elpi__29) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__28 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_tye_TConstc [elpi__30]), + (List.concat [elpi__29])) + | TArrow (elpi__31, elpi__32) -> + let (elpi__state, elpi__35, elpi__33) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> fun t -> elpi_embed_tye ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__31 in + let (elpi__state, elpi__36, elpi__34) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> fun t -> elpi_embed_tye ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__32 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_tye_TArrowc + [elpi__35; elpi__36]), + (List.concat [elpi__33; elpi__34])) + and elpi_readback_tye : + 'c 'csts . + (tye, #Ctx_for_tye.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.Const elpi__hd when elpi__hd >= 0 -> + let (_, elpi__dbl2ctx) = + Elpi.API.State.get elpi_tctx_state elpi__state in + (if + not + (Elpi.API.RawData.Constants.Map.mem elpi__hd + elpi__dbl2ctx) + then + Elpi.API.Utils.error + (Format.asprintf "Unbound variable: %s in %a" + (Elpi.API.RawData.Constants.show elpi__hd) + (Elpi.API.RawData.Constants.Map.pp + (Elpi.API.ContextualConversion.pp_ctx_entry + pp_tctx)) elpi__dbl2ctx); + (let { + Elpi.API.ContextualConversion.entry = elpi__entry; + depth = elpi__depth } + = + Elpi.API.RawData.Constants.Map.find elpi__hd + elpi__dbl2ctx in + (elpi__state, + (TVar + (elpi_tctx_to_key ~depth:elpi__depth elpi__entry)), + []))) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_tye_TConstc -> + let (elpi__state, elpi__20, elpi__19) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | [] -> + (elpi__state, (TConst elpi__20), + (List.concat [elpi__19])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_tye_TConstc))) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_tye_TArrowc -> + let (elpi__state, elpi__24, elpi__23) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> elpi_readback_tye ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__x in + (match elpi__xs with + | elpi__21::[] -> + let (elpi__state, elpi__21, elpi__22) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> elpi_readback_tye ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__21 in + (elpi__state, (TArrow (elpi__24, elpi__21)), + (List.concat [elpi__23; elpi__22])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_tye_TArrowc))) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "tye" (Elpi.API.RawPp.term elpi__depth) elpi__x) + and tye : + 'c 'csts . + (tye, #Ctx_for_tye.t as 'c, 'csts) Elpi.API.ContextualConversion.t + = + let kind = Elpi.API.ContextualConversion.TyName "tye" in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"tye"; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"tconst" + ~doc:"TConst" + ~args:[Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.ty]; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"tarrow" + ~doc:"TArrow" + ~args:[Elpi.API.ContextualConversion.TyName + elpi_constant_type_tye; + Elpi.API.ContextualConversion.TyName + elpi_constant_type_tye]); + pp = pp_tye; + embed = elpi_embed_tye; + readback = elpi_readback_tye + } + let elpi_tye = Elpi.API.BuiltIn.MLDataC tye + class ctx_for_tye (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_tye.t = + object (_) + inherit ((Elpi.API.ContextualConversion.ctx) h) + inherit ! ((ctx_for_tctx) h s) + method tctx = + context_made_of_tctx.Elpi.API.ContextualConversion.get s + end + let (in_ctx_for_tye : + (Ctx_for_tye.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> + let ctx = (new ctx_for_tctx) h s in + let (s, gls0) = + Elpi.API.PPX.readback_context ~depth context_made_of_tctx ctx + h c s in + (s, ((new ctx_for_tye) h s), c, (List.concat [gls0])) + let () = declaration := ((!declaration) @ [elpi_tye]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +let tye : + 'a 'csts . (tye, #ctx_for_tye as 'a, 'csts) Elpi.API.ContextualConversion.t + = tye +let pp_ty _ _ = () +type ty = + | Mono of tye + | Forall of string * bool * + ((ty)[@elpi.binder "tye" tctx (fun s -> fun b -> TDecl (s, b))]) [@@deriving + elpi] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_ty = "ty" + let elpi_constant_type_tyc = + Elpi.API.RawData.Constants.declare_global_symbol elpi_constant_type_ty + let elpi_constant_constructor_ty_Mono = "mono" + let elpi_constant_constructor_ty_Monoc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_ty_Mono + let elpi_constant_constructor_ty_Forall = "forall" + let elpi_constant_constructor_ty_Forallc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_ty_Forall + module Ctx_for_ty = + struct + class type t = + object + inherit Elpi.API.ContextualConversion.ctx + inherit Ctx_for_tctx.t + method tctx : tctx Elpi.API.ContextualConversion.ctx_field + end + end + let rec elpi_embed_ty : + 'c 'csts . + (ty, #Ctx_for_ty.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | Mono elpi__45 -> + let (elpi__state, elpi__47, elpi__46) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + tye.Elpi.API.ContextualConversion.embed ~depth + h c s t) ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__45 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_ty_Monoc [elpi__47]), + (List.concat [elpi__46])) + | Forall (elpi__48, elpi__49, elpi__50) -> + let (elpi__state, elpi__54, elpi__51) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__48 in + let (elpi__state, elpi__55, elpi__52) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__49 in + let elpi__ctx_entry = + (fun s -> fun b -> TDecl (s, b)) elpi__48 elpi__49 in + let elpi__ctx_key = + elpi_tctx_to_key ~depth:elpi__depth elpi__ctx_entry in + let elpi__ctx_entry = + { + Elpi.API.ContextualConversion.entry = elpi__ctx_entry; + depth = elpi__depth + } in + let elpi__state = + elpi_push_tctx ~depth:(elpi__depth + 1) elpi__state + elpi__ctx_key elpi__ctx_entry in + let (elpi__state, elpi__57, elpi__53) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> fun t -> elpi_embed_ty ~depth h c s t) + ~depth:(elpi__depth + 1) elpi__hyps elpi__constraints + elpi__state elpi__50 in + let elpi__56 = Elpi.API.RawData.mkLam elpi__57 in + let elpi__state = + elpi_pop_tctx ~depth:(elpi__depth + 1) elpi__state + elpi__ctx_key in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_ty_Forallc + [elpi__54; elpi__55; elpi__56]), + (List.concat [elpi__51; elpi__52; elpi__53])) + and elpi_readback_ty : + 'c 'csts . + (ty, #Ctx_for_ty.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_ty_Monoc -> + let (elpi__state, elpi__38, elpi__37) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + tye.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | [] -> + (elpi__state, (Mono elpi__38), + (List.concat [elpi__37])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_ty_Monoc))) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_ty_Forallc -> + let (elpi__state, elpi__44, elpi__43) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | elpi__39::elpi__40::[] -> + let (elpi__state, elpi__39, elpi__41) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state + elpi__39 in + let elpi__ctx_entry = + (fun s -> fun b -> TDecl (s, b)) elpi__44 elpi__39 in + let elpi__ctx_key = + elpi_tctx_to_key ~depth:elpi__depth + elpi__ctx_entry in + let elpi__ctx_entry = + { + Elpi.API.ContextualConversion.entry = + elpi__ctx_entry; + depth = elpi__depth + } in + let elpi__state = + elpi_push_tctx ~depth:elpi__depth elpi__state + elpi__ctx_key elpi__ctx_entry in + let (elpi__state, elpi__40, elpi__42) = + match Elpi.API.RawData.look ~depth:elpi__depth + elpi__40 + with + | Elpi.API.RawData.Lam elpi__bo -> + ((fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + elpi_readback_ty ~depth h c s t)) + ~depth:(elpi__depth + 1) elpi__hyps + elpi__constraints elpi__state elpi__bo + | _ -> assert false in + let elpi__state = + elpi_pop_tctx ~depth:elpi__depth elpi__state + elpi__ctx_key in + (elpi__state, + (Forall (elpi__44, elpi__39, elpi__40)), + (List.concat [elpi__43; elpi__41; elpi__42])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_ty_Forallc))) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "ty" (Elpi.API.RawPp.term elpi__depth) elpi__x) + and ty : + 'c 'csts . + (ty, #Ctx_for_ty.t as 'c, 'csts) Elpi.API.ContextualConversion.t + = + let kind = Elpi.API.ContextualConversion.TyName "ty" in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"ty"; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"mono" + ~doc:"Mono" ~args:[tye.Elpi.API.ContextualConversion.ty]; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"forall" + ~doc:"Forall" + ~args:[Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.ty; + Elpi.Builtin.PPX.bool.Elpi.API.ContextualConversion.ty; + Elpi.API.ContextualConversion.TyApp + ("->", (Elpi.API.ContextualConversion.TyName "tye"), + [Elpi.API.ContextualConversion.TyName + elpi_constant_type_ty])]); + pp = pp_ty; + embed = elpi_embed_ty; + readback = elpi_readback_ty + } + let elpi_ty = Elpi.API.BuiltIn.MLDataC ty + class ctx_for_ty (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_ty.t = + object (_) + inherit ((Elpi.API.ContextualConversion.ctx) h) + inherit ! ((ctx_for_tctx) h s) + method tctx = + context_made_of_tctx.Elpi.API.ContextualConversion.get s + end + let (in_ctx_for_ty : + (Ctx_for_ty.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> + let ctx = (new ctx_for_tctx) h s in + let (s, gls0) = + Elpi.API.PPX.readback_context ~depth context_made_of_tctx ctx + h c s in + (s, ((new ctx_for_ty) h s), c, (List.concat [gls0])) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +let ty : + 'a 'csts . (ty, #ctx_for_ty as 'a, 'csts) Elpi.API.ContextualConversion.t = + ty +let pp_ctx _ _ = () +type ctx = + | Decl of ((string)[@elpi.key ]) * ty [@@elpi.index (module String)] +[@@deriving elpi { declaration; context = [tctx] }] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_ctx = "ctx" + let elpi_constant_type_ctxc = + Elpi.API.RawData.Constants.declare_global_symbol elpi_constant_type_ctx + let elpi_constant_constructor_ctx_Decl = "decl" + let elpi_constant_constructor_ctx_Declc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_ctx_Decl + module Elpi_ctx_Map = (Elpi.API.Utils.Map.Make)(String) + let elpi_ctx_state = + Elpi.API.State.declare ~name:"ctx" + ~pp:(fun fmt -> fun _ -> Format.fprintf fmt "TODO") + ~init:(fun () -> + ((Elpi_ctx_Map.empty : Elpi.API.RawData.constant + Elpi_ctx_Map.t), + (Elpi.API.RawData.Constants.Map.empty : ctx + Elpi.API.ContextualConversion.ctx_entry + Elpi.API.RawData.Constants.Map.t))) + ~start:(fun x -> x) + let elpi_ctx_to_key ~depth:_ = function | Decl (elpi__73, _) -> elpi__73 + let elpi_is_ctx { Elpi.API.Data.hdepth = elpi__depth; hsrc = elpi__x } = + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.Const _ -> None + | Elpi.API.RawData.App (elpi__hd, elpi__idx, _) -> + if false || (elpi__hd == elpi_constant_constructor_ctx_Declc) + then + (match Elpi.API.RawData.look ~depth:elpi__depth elpi__idx with + | Elpi.API.RawData.Const x -> Some x + | _ -> + Elpi.API.Utils.type_error + "context entry applied to a non nominal") + else None + | _ -> None + let elpi_push_ctx ~depth:elpi__depth elpi__state elpi__name + elpi__ctx_item = + let (elpi__ctx2dbl, elpi__dbl2ctx) = + Elpi.API.State.get elpi_ctx_state elpi__state in + let elpi__i = elpi__depth in + let elpi__ctx2dbl = Elpi_ctx_Map.add elpi__name elpi__i elpi__ctx2dbl in + let elpi__dbl2ctx = + Elpi.API.RawData.Constants.Map.add elpi__i elpi__ctx_item + elpi__dbl2ctx in + let elpi__state = + Elpi.API.State.set elpi_ctx_state elpi__state + (elpi__ctx2dbl, elpi__dbl2ctx) in + elpi__state + let elpi_pop_ctx ~depth:elpi__depth elpi__state elpi__name = + let (elpi__ctx2dbl, elpi__dbl2ctx) = + Elpi.API.State.get elpi_ctx_state elpi__state in + let elpi__i = elpi__depth in + let elpi__ctx2dbl = Elpi_ctx_Map.remove elpi__name elpi__ctx2dbl in + let elpi__dbl2ctx = + Elpi.API.RawData.Constants.Map.remove elpi__i elpi__dbl2ctx in + let elpi__state = + Elpi.API.State.set elpi_ctx_state elpi__state + (elpi__ctx2dbl, elpi__dbl2ctx) in + elpi__state + module Ctx_for_ctx = + struct + class type t = + object + inherit Elpi.API.ContextualConversion.ctx + inherit Ctx_for_tctx.t + method tctx : tctx Elpi.API.ContextualConversion.ctx_field + end + end + let rec elpi_embed_ctx : + 'c 'csts . + ((Elpi.API.RawData.constant * ctx), #Ctx_for_ctx.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | (elpi__66, Decl (elpi__64, elpi__65)) -> + let (elpi__state, elpi__70, elpi__67) = + Elpi.API.BuiltInContextualData.nominal.Elpi.API.ContextualConversion.embed + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__66 in + let (elpi__state, elpi__71, elpi__68) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__64 in + let (elpi__state, elpi__72, elpi__69) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + ty.Elpi.API.ContextualConversion.embed ~depth + h c s t) ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__65 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_ctx_Declc + [elpi__70; elpi__71; elpi__72]), + (List.concat [elpi__67; elpi__68; elpi__69])) + and elpi_readback_ctx : + 'c 'csts . + ((Elpi.API.RawData.constant * ctx), #Ctx_for_ctx.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_ctx_Declc -> + let (elpi__state, elpi__63, elpi__62) = + Elpi.API.BuiltInContextualData.nominal.Elpi.API.ContextualConversion.readback + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__x in + (match elpi__xs with + | elpi__58::elpi__59::[] -> + let (elpi__state, elpi__58, elpi__60) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state + elpi__58 in + let (elpi__state, elpi__59, elpi__61) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + ty.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state + elpi__59 in + (elpi__state, + (elpi__63, (Decl (elpi__58, elpi__59))), + (List.concat [elpi__62; elpi__60; elpi__61])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_ctx_Declc))) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "ctx" (Elpi.API.RawPp.term elpi__depth) elpi__x) + and ctx : + 'c 'csts . + ((Elpi.API.RawData.constant * ctx), #Ctx_for_ctx.t as 'c, 'csts) + Elpi.API.ContextualConversion.t + = + let kind = Elpi.API.ContextualConversion.TyName "ctx" in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"ctx"; + Elpi.API.PPX.Doc.constructor fmt + ~ty:(Elpi.API.ContextualConversion.TyName "prop") + ~name:"decl" ~doc:"Decl" + ~args:[Elpi.API.BuiltInContextualData.nominal.Elpi.API.ContextualConversion.ty; + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.ty; + ty.Elpi.API.ContextualConversion.ty]); + pp = (fun fmt -> fun (_, x) -> pp_ctx fmt x); + embed = elpi_embed_ctx; + readback = elpi_readback_ctx + } + let context_made_of_ctx = + { + Elpi.API.ContextualConversion.is_entry_for_nominal = elpi_is_ctx; + to_key = elpi_ctx_to_key; + push = elpi_push_ctx; + pop = elpi_pop_ctx; + conv = ctx; + init = + (fun state -> + Elpi.API.State.set elpi_ctx_state state + ((Elpi_ctx_Map.empty : Elpi.API.RawData.constant + Elpi_ctx_Map.t), + (Elpi.API.RawData.Constants.Map.empty : ctx + Elpi.API.ContextualConversion.ctx_entry + Elpi.API.RawData.Constants.Map.t))); + get = (fun state -> snd @@ (Elpi.API.State.get elpi_ctx_state state)) + } + let elpi_ctx = Elpi.API.BuiltIn.MLDataC ctx + class ctx_for_ctx (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_ctx.t = + object (_) + inherit ((Elpi.API.ContextualConversion.ctx) h) + inherit ! ((ctx_for_tctx) h s) + method tctx = + context_made_of_tctx.Elpi.API.ContextualConversion.get s + end + let (in_ctx_for_ctx : + (Ctx_for_ctx.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> + let ctx = (new ctx_for_tctx) h s in + let (s, gls0) = + Elpi.API.PPX.readback_context ~depth context_made_of_tctx ctx + h c s in + (s, ((new ctx_for_ctx) h s), c, (List.concat [gls0])) + let () = declaration := ((!declaration) @ [elpi_ctx]) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +type term = + | Var of string [@elpi.var ctx] + | App of term list [@elpi.code "appl"][@elpi.doc "bla bla"] + | Lam of string * ty * + ((term)[@elpi.binder ctx (fun s -> fun ty -> Decl (s, ty))]) + | Literal of int [@elpi.skip ] + | Cast of term * ty + [@elpi.embed + fun default -> + fun ~depth -> + fun hyps -> + fun constraints -> + fun state -> + fun a1 -> fun a2 -> default ~depth hyps constraints state a1 a2] + [@elpi.readback + fun default -> + fun ~depth -> + fun hyps -> + fun constraints -> + fun state -> fun l -> default ~depth hyps constraints state l] + [@elpi.code "type-cast" "term -> ty -> term"][@@deriving + elpi + { context = [tctx; ctx] }] +[@@elpi.pp + let rec aux fmt = + function + | Var s -> Format.fprintf fmt "%s" s + | App tl -> Format.fprintf fmt "App %a" (Elpi.API.RawPp.list aux " ") tl + | Lam (s, ty, t) -> Format.fprintf fmt "Lam %s (%a)" s aux t + | Literal i -> Format.fprintf fmt "%d" i + | Cast (t, _) -> aux fmt t in + aux] +include + struct + [@@@ocaml.warning "-60"] + [@@@warning "-26-27-32-39-60"] + let elpi_constant_type_term = "term" + let elpi_constant_type_termc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_type_term + let elpi_constant_constructor_term_Var = "var" + let elpi_constant_constructor_term_Varc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_term_Var + let elpi_constant_constructor_term_App = "appl" + let elpi_constant_constructor_term_Appc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_term_App + let elpi_constant_constructor_term_Lam = "lam" + let elpi_constant_constructor_term_Lamc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_term_Lam + let elpi_constant_constructor_term_Cast = "type-cast" + let elpi_constant_constructor_term_Castc = + Elpi.API.RawData.Constants.declare_global_symbol + elpi_constant_constructor_term_Cast + module Ctx_for_term = + struct + class type t = + object + inherit Elpi.API.ContextualConversion.ctx + inherit Ctx_for_tctx.t + method tctx : tctx Elpi.API.ContextualConversion.ctx_field + inherit Ctx_for_ctx.t + method ctx : ctx Elpi.API.ContextualConversion.ctx_field + end + end + let rec elpi_embed_term : + 'c 'csts . + (term, #Ctx_for_term.t as 'c, 'csts) + Elpi.API.ContextualConversion.embedding + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | Var elpi__88 -> + let (elpi__ctx2dbl, _) = + Elpi.API.State.get elpi_ctx_state elpi__state in + let elpi__key = (fun x -> x) elpi__88 in + (if not (Elpi_ctx_Map.mem elpi__key elpi__ctx2dbl) + then Elpi.API.Utils.error "Unbound variable"; + (elpi__state, + (Elpi.API.RawData.mkBound + (Elpi_ctx_Map.find elpi__key elpi__ctx2dbl)), [])) + | App elpi__91 -> + let (elpi__state, elpi__93, elpi__92) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + (let embed = elpi_embed_term in + fun ~depth -> + fun h -> + fun c -> + fun s -> + fun l -> + let (s, l, eg) = + Elpi.API.Utils.map_acc + (embed ~depth h c) s l in + (s, + (Elpi.API.Utils.list_to_lp_list l), + eg)) ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__91 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_term_Appc [elpi__93]), + (List.concat [elpi__92])) + | Lam (elpi__94, elpi__95, elpi__96) -> + let (elpi__state, elpi__100, elpi__97) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.embed + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__94 in + let (elpi__state, elpi__101, elpi__98) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + ty.Elpi.API.ContextualConversion.embed ~depth + h c s t) ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__95 in + let elpi__ctx_entry = + (fun s -> fun ty -> Decl (s, ty)) elpi__94 elpi__95 in + let elpi__ctx_key = + elpi_ctx_to_key ~depth:elpi__depth elpi__ctx_entry in + let elpi__ctx_entry = + { + Elpi.API.ContextualConversion.entry = elpi__ctx_entry; + depth = elpi__depth + } in + let elpi__state = + elpi_push_ctx ~depth:(elpi__depth + 1) elpi__state + elpi__ctx_key elpi__ctx_entry in + let (elpi__state, elpi__103, elpi__99) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> fun t -> elpi_embed_term ~depth h c s t) + ~depth:(elpi__depth + 1) elpi__hyps elpi__constraints + elpi__state elpi__96 in + let elpi__102 = Elpi.API.RawData.mkLam elpi__103 in + let elpi__state = + elpi_pop_ctx ~depth:(elpi__depth + 1) elpi__state + elpi__ctx_key in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_term_Lamc + [elpi__100; elpi__101; elpi__102]), + (List.concat [elpi__97; elpi__98; elpi__99])) + | Literal _ -> + Elpi.API.Utils.error + ("constructor " ^ ("Literal" ^ " is not supported")) + | Cast (elpi__104, elpi__105) -> + ((fun default -> + fun ~depth -> + fun hyps -> + fun constraints -> + fun state -> + fun a1 -> + fun a2 -> + default ~depth hyps constraints state a1 a2)) + (fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__104 -> + fun elpi__105 -> + let (elpi__state, elpi__108, elpi__106) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + elpi_embed_term ~depth h c s t) + ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__104 in + let (elpi__state, elpi__109, elpi__107) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + ty.Elpi.API.ContextualConversion.embed + ~depth h c s t) + ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state elpi__105 in + (elpi__state, + (Elpi.API.RawData.mkAppL + elpi_constant_constructor_term_Castc + [elpi__108; elpi__109]), + (List.concat [elpi__106; elpi__107]))) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__104 elpi__105 + and elpi_readback_term : + 'c 'csts . + (term, #Ctx_for_term.t as 'c, 'csts) + Elpi.API.ContextualConversion.readback + = + fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + fun elpi__x -> + match Elpi.API.RawData.look ~depth:elpi__depth elpi__x with + | Elpi.API.RawData.Const elpi__hd when elpi__hd >= 0 -> + let (_, elpi__dbl2ctx) = + Elpi.API.State.get elpi_ctx_state elpi__state in + (if + not + (Elpi.API.RawData.Constants.Map.mem elpi__hd + elpi__dbl2ctx) + then + Elpi.API.Utils.error + (Format.asprintf "Unbound variable: %s in %a" + (Elpi.API.RawData.Constants.show elpi__hd) + (Elpi.API.RawData.Constants.Map.pp + (Elpi.API.ContextualConversion.pp_ctx_entry + pp_ctx)) elpi__dbl2ctx); + (let { + Elpi.API.ContextualConversion.entry = elpi__entry; + depth = elpi__depth } + = + Elpi.API.RawData.Constants.Map.find elpi__hd + elpi__dbl2ctx in + (elpi__state, + (Var (elpi_ctx_to_key ~depth:elpi__depth elpi__entry)), + []))) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_term_Appc -> + let (elpi__state, elpi__77, elpi__76) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + (let readback = elpi_readback_term in + fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.Utils.map_acc + (readback ~depth h c) s + (Elpi.API.Utils.lp_list_to_list + ~depth t)) ~depth h c s t) + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state elpi__x in + (match elpi__xs with + | [] -> + (elpi__state, (App elpi__77), + (List.concat [elpi__76])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_term_Appc))) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_term_Lamc -> + let (elpi__state, elpi__83, elpi__82) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state elpi__x in + (match elpi__xs with + | elpi__78::elpi__79::[] -> + let (elpi__state, elpi__78, elpi__80) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + ty.Elpi.API.ContextualConversion.readback + ~depth h c s t) ~depth:elpi__depth + elpi__hyps elpi__constraints elpi__state + elpi__78 in + let elpi__ctx_entry = + (fun s -> fun ty -> Decl (s, ty)) elpi__83 + elpi__78 in + let elpi__ctx_key = + elpi_ctx_to_key ~depth:elpi__depth elpi__ctx_entry in + let elpi__ctx_entry = + { + Elpi.API.ContextualConversion.entry = + elpi__ctx_entry; + depth = elpi__depth + } in + let elpi__state = + elpi_push_ctx ~depth:elpi__depth elpi__state + elpi__ctx_key elpi__ctx_entry in + let (elpi__state, elpi__79, elpi__81) = + match Elpi.API.RawData.look ~depth:elpi__depth + elpi__79 + with + | Elpi.API.RawData.Lam elpi__bo -> + ((fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + elpi_readback_term ~depth h c s t)) + ~depth:(elpi__depth + 1) elpi__hyps + elpi__constraints elpi__state elpi__bo + | _ -> assert false in + let elpi__state = + elpi_pop_ctx ~depth:elpi__depth elpi__state + elpi__ctx_key in + (elpi__state, (Lam (elpi__83, elpi__78, elpi__79)), + (List.concat [elpi__82; elpi__80; elpi__81])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_term_Lamc))) + | Elpi.API.RawData.App (elpi__hd, elpi__x, elpi__xs) when + elpi__hd == elpi_constant_constructor_term_Castc -> + ((fun default -> + fun ~depth -> + fun hyps -> + fun constraints -> + fun state -> + fun l -> + default ~depth hyps constraints state l)) + (fun ~depth:elpi__depth -> + fun elpi__hyps -> + fun elpi__constraints -> + fun elpi__state -> + function + | elpi__x::elpi__xs -> + let (elpi__state, elpi__87, elpi__86) = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + elpi_readback_term ~depth h c + s t) ~depth:elpi__depth + elpi__hyps elpi__constraints + elpi__state elpi__x in + (match elpi__xs with + | elpi__84::[] -> + let (elpi__state, elpi__84, elpi__85) + = + (fun ~depth -> + fun h -> + fun c -> + fun s -> + fun t -> + ty.Elpi.API.ContextualConversion.readback + ~depth h c s t) + ~depth:elpi__depth elpi__hyps + elpi__constraints elpi__state + elpi__84 in + (elpi__state, + (Cast (elpi__87, elpi__84)), + (List.concat [elpi__86; elpi__85])) + | _ -> + Elpi.API.Utils.type_error + ("Not enough arguments to constructor: " + ^ + (Elpi.API.RawData.Constants.show + elpi_constant_constructor_term_Castc))) + | [] -> + Elpi.API.Utils.error + ~loc:{ + Elpi.API.Ast.Loc.source_name = + "test_two_layers_context.ml"; + source_start = 1860; + source_stop = 1860; + line = 55; + line_starts_at = 1849 + } + "standard branch readback takes 1 argument or more") + ~depth:elpi__depth elpi__hyps elpi__constraints + elpi__state (elpi__x :: elpi__xs) + | _ -> + Elpi.API.Utils.type_error + (Format.asprintf "Not a constructor of type %s: %a" + "term" (Elpi.API.RawPp.term elpi__depth) elpi__x) + and term : + 'c 'csts . + (term, #Ctx_for_term.t as 'c, 'csts) Elpi.API.ContextualConversion.t + = + let kind = Elpi.API.ContextualConversion.TyName "term" in + { + Elpi.API.ContextualConversion.ty = kind; + pp_doc = + (fun fmt -> + fun () -> + Elpi.API.PPX.Doc.kind fmt kind ~doc:"term"; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"appl" + ~doc:"bla bla" + ~args:[Elpi.API.ContextualConversion.TyApp + ("list", + (Elpi.API.ContextualConversion.TyName + elpi_constant_type_term), [])]; + Elpi.API.PPX.Doc.constructor fmt ~ty:kind ~name:"lam" + ~doc:"Lam" + ~args:[Elpi.API.BuiltInContextualData.string.Elpi.API.ContextualConversion.ty; + ty.Elpi.API.ContextualConversion.ty; + Elpi.API.ContextualConversion.TyApp + ("->", + (Elpi.API.ContextualConversion.TyName "term"), + [Elpi.API.ContextualConversion.TyName + elpi_constant_type_term])]; + Format.fprintf fmt "@[type %s@[ %s. %% %s@]@]@\n" + "type-cast" "term -> ty -> term" "Cast"); + pp = + (let rec aux fmt = + function + | Var s -> Format.fprintf fmt "%s" s + | App tl -> + Format.fprintf fmt "App %a" (Elpi.API.RawPp.list aux " ") tl + | Lam (s, ty, t) -> Format.fprintf fmt "Lam %s (%a)" s aux t + | Literal i -> Format.fprintf fmt "%d" i + | Cast (t, _) -> aux fmt t in + aux); + embed = elpi_embed_term; + readback = elpi_readback_term + } + let elpi_term = Elpi.API.BuiltIn.MLDataC term + class ctx_for_term (h : Elpi.API.Data.hyps) (s : Elpi.API.Data.state) + : Ctx_for_term.t = + object (_) + inherit ((Elpi.API.ContextualConversion.ctx) h) + inherit ! ((ctx_for_tctx) h s) + method tctx = + context_made_of_tctx.Elpi.API.ContextualConversion.get s + inherit ! ((ctx_for_ctx) h s) + method ctx = context_made_of_ctx.Elpi.API.ContextualConversion.get s + end + let (in_ctx_for_term : + (Ctx_for_term.t, 'csts) Elpi.API.ContextualConversion.ctx_readback) = + fun ~depth -> + fun h -> + fun c -> + fun s -> + let ctx = (new ctx_for_tctx) h s in + let (s, gls0) = + Elpi.API.PPX.readback_context ~depth context_made_of_tctx ctx + h c s in + let ctx = (new ctx_for_ctx) h s in + let (s, gls1) = + Elpi.API.PPX.readback_context ~depth context_made_of_ctx ctx + h c s in + (s, ((new ctx_for_term) h s), c, (List.concat [gls0; gls1])) + end[@@ocaml.doc "@inline"][@@merlin.hide ] +let term : + 'a 'csts . + (term, #ctx_for_term as 'a, 'csts) Elpi.API.ContextualConversion.t + = term +open Elpi.API +open BuiltInPredicate +open Notation +let term_to_string = + CPred + ("term->string", in_ctx_for_term, + (CIn + (term, "T", + (COut (BuiltInContextualData.string, "S", (CRead "what else"))))), + (fun (t : term) -> + fun (_ety : string oarg) -> + fun ~depth:_ -> + fun c -> + fun (_cst : Data.constraints) -> + fun (_state : State.t) -> + !: + (Format.asprintf "@[%a@ %a@ |-@ %a@]@\n%!" + (RawData.Constants.Map.pp + (ContextualConversion.pp_ctx_entry pp_tctx)) + c#tctx + (RawData.Constants.Map.pp + (ContextualConversion.pp_ctx_entry pp_ctx)) + c#ctx term.pp t))) +let builtin = + let open BuiltIn in + declare ~file_name:"test_ppx.elpi" + ((!declaration) @ + ([MLCode (term_to_string, DocAbove); + LPDoc "----------------- elpi ----------------"] @ + (let open Elpi.Builtin in core_builtins @ elpi_builtins))) +let program = + {| +main :- + pi x w y q t\ + tdecl t "alpha" tt => + decl y "arg" (forall "ss" tt s\ mono (tarrow (tconst "nat") s)) => + decl x "f" (mono (tarrow (tconst "nat") t)) => + print {term->string (appl [x, y, lam "zzzz" (mono t) z\ z])}. + +|} +let main () = + let elpi = Setup.init ~builtins:[builtin] () in + let out = open_out (Sys.argv.(1)) in + let fmt = Format.formatter_of_out_channel out in + Setup.set_err_formatter fmt; + Setup.set_std_formatter fmt; + (let program = + Parse.program_from ~elpi ~loc:(Ast.Loc.initial "test") + (Lexing.from_string program) in + let goal = Parse.goal ~elpi ~loc:(Ast.Loc.initial "test") ~text:"main." in + let program = Compile.program ~elpi ~flags:Compile.default_flags [program] in + let goal = Compile.query program goal in + let exe = Compile.optimize goal in + match Execute.once exe with + | Execute.Success _ -> + (Format.pp_print_flush fmt (); close_out out; exit 0) + | _ -> exit 1) +;;main () diff --git a/ppx_elpi/tests/test_two_layers_context.ml b/ppx_elpi/tests/test_two_layers_context.ml new file mode 100644 index 000000000..ce8af52a4 --- /dev/null +++ b/ppx_elpi/tests/test_two_layers_context.ml @@ -0,0 +1,109 @@ +let declaration = ref [] + +module String = struct + include String + let pp fmt s = Format.fprintf fmt "%s" s + let show x = x +end + +let pp_tctx _ _ = () +type tctx = TDecl of (string[@elpi.key]) * bool + [@@elpi.index (module String)] +[@@deriving elpi { declaration } ] + +let pp_tye _ _ = () +type tye = + | TVar of string [@elpi.var tctx] + | TConst of string + | TArrow of tye * tye +[@@deriving elpi { declaration } ] + +let tye : 'a 'csts. (tye, #ctx_for_tye as 'a,'csts) Elpi.API.ContextualConversion.t = tye + +let pp_ty _ _ = () +type ty = + | Mono of tye + | Forall of string * bool * (ty[@elpi.binder "tye" tctx (fun s b -> TDecl(s,b))]) +[@@deriving elpi ] + +let ty : 'a 'csts. (ty, #ctx_for_ty as 'a,'csts) Elpi.API.ContextualConversion.t = ty + +let pp_ctx _ _ = () +type ctx = Decl of (string[@elpi.key]) * ty + [@@elpi.index (module String)] +[@@deriving elpi { declaration ; context = [tctx] } ] + +type term = + | Var of string [@elpi.var ctx] + | App of term list [@elpi.code "appl"] [@elpi.doc "bla bla"] + | Lam of string * ty * (term[@elpi.binder ctx (fun s ty -> Decl(s,ty))]) + | Literal of int [@elpi.skip] + | Cast of term * ty + (* Example: override the embed and readback code for this constructor *) + [@elpi.embed fun default ~depth hyps constraints state a1 a2 -> + default ~depth hyps constraints state a1 a2 ] + [@elpi.readback fun default ~depth hyps constraints state l -> + default ~depth hyps constraints state l ] + [@elpi.code "type-cast" "term -> ty -> term"] +[@@deriving elpi { context = [ tctx ; ctx ] } ] +[@@elpi.pp let rec aux fmt = function + | Var s -> Format.fprintf fmt "%s" s + | App tl -> Format.fprintf fmt "App %a" (Elpi.API.RawPp.list aux " ") tl + | Lam(s,ty,t) -> Format.fprintf fmt "Lam %s (%a)" s aux t + | Literal i -> Format.fprintf fmt "%d" i + | Cast(t,_) -> aux fmt t + in aux ] + +let term : 'a 'csts. (term, #ctx_for_term as 'a,'csts) Elpi.API.ContextualConversion.t = term + +open Elpi.API +open BuiltInPredicate +open Notation + +let term_to_string = CPred("term->string",in_ctx_for_term, + CIn(term,"T", + COut(BuiltInContextualData.string,"S", + CRead("what else"))), + fun (t : term) (_ety : string oarg) + ~depth:_ c (_cst : Data.constraints) (_state : State.t) -> + + !: (Format.asprintf "@[%a@ %a@ |-@ %a@]@\n%!" + (RawData.Constants.Map.pp (ContextualConversion.pp_ctx_entry pp_tctx)) c#tctx + (RawData.Constants.Map.pp (ContextualConversion.pp_ctx_entry pp_ctx)) c#ctx + term.pp t) + +) + +let builtin = let open BuiltIn in + declare ~file_name:"test_ppx.elpi" (!declaration @ [ + MLCode(term_to_string,DocAbove); + LPDoc "----------------- elpi ----------------" + ] @ Elpi.Builtin.(core_builtins @ elpi_builtins)) + +let program = {| +main :- + pi x w y q t\ + tdecl t "alpha" tt => + decl y "arg" (forall "ss" tt s\ mono (tarrow (tconst "nat") s)) => + decl x "f" (mono (tarrow (tconst "nat") t)) => + print {term->string (appl [x, y, lam "zzzz" (mono t) z\ z])}. + +|} + +let main () = + let elpi = Setup.init ~builtins:[builtin] () in + let out = open_out Sys.argv.(1) in + let fmt = Format.formatter_of_out_channel out in + Setup.set_err_formatter fmt; + Setup.set_std_formatter fmt; + let program = Parse.program_from ~elpi ~loc:(Ast.Loc.initial "test") (Lexing.from_string program) in + let goal = Parse.goal ~elpi ~loc:(Ast.Loc.initial "test") ~text:"main." in + let program = Compile.program ~elpi ~flags:Compile.default_flags [program] in + let goal = Compile.query program goal in + let exe = Compile.optimize goal in + match Execute.once exe with + | Execute.Success _ -> Format.pp_print_flush fmt (); close_out out; exit 0 + | _ -> exit 1 + ;; + +main () diff --git a/src/API.ml b/src/API.ml index 5b0f8dfb7..fb6ea47a7 100644 --- a/src/API.ml +++ b/src/API.ml @@ -153,6 +153,13 @@ module Data = struct hsrc : term } type hyps = hyp list + type constant = int + module Constants = struct + + module Map = ED.Constants.Map + + end + end module Compile = struct @@ -255,7 +262,6 @@ end module Conversion = struct type ty_ast = ED.Conversion.ty_ast = TyName of string | TyApp of string * ty_ast * ty_ast list - type extra_goal = ED.Conversion.extra_goal = .. type extra_goal += | Unify = ED.Conversion.Unify @@ -278,7 +284,13 @@ exception TypeErr = ED.Conversion.TypeErr end -module ContextualConversion = ED.ContextualConversion +module ContextualConversion = struct + include ED.ContextualConversion + let (^^) t = { t with + embed = (fun ~depth h c s x -> t.embed ~depth (new ctx h#raw) c s x); + readback = (fun ~depth h c s x -> t.readback ~depth (new ctx h#raw) c s x); + } +end module RawOpaqueData = struct @@ -341,7 +353,7 @@ module RawOpaqueData = struct ED.Constants.Map.add c v cm, VM.add v c vm) constants (ED.Constants.Map.empty,VM.empty) in let values_map x = VM.find x values_map in - conversion_of_cdata ~name ?doc ~constants_map ~values_map ~constants ~pp cd + constants_map, conversion_of_cdata ~name ?doc ~constants_map ~values_map ~constants ~pp cd let declare { name; doc; pp; compare; hash; hconsed; constants; } = let cdata = Util.CData.declare { @@ -353,6 +365,16 @@ module RawOpaqueData = struct } in conversion_of_cdata ~name ~doc ~constants ~compare ~pp cdata + module PPX = struct + let declare d = + let map, (cd, _) = declare d in + cd, map, d.doc + end + + let declare d = snd @@ declare d + let conversion_of_cdata ~name ?doc ?constants ~compare ~pp cd = + snd @@ conversion_of_cdata ~name ?doc ?constants ~compare ~pp cd + let morph1 { cin; cout } f x = cin (f (cout x)) let morph2 { cin; cout } f x y = cin (f (cout x) (cout y)) let map { cout } { cin } f x = cin (f (cout x)) @@ -413,6 +435,7 @@ module OpaqueData = struct end + module BuiltInData = struct let int = snd @@ RawOpaqueData.conversion_of_cdata ~name:"int" ~compare:(fun x y -> x - y) ~pp:(fun fmt x -> Util.CData.pp fmt (ED.C.int.Util.CData.cin x)) ED.C.int @@ -509,6 +532,113 @@ module BuiltInData = struct end +module BuiltInContextualData = struct + + let int : 'c 'csts. (int,'c,'csts) ContextualConversion.t = + let open ContextualConversion in + let it = BuiltInData.int in { + ty = it.Conversion.ty; pp = it.Conversion.pp; pp_doc = it.Conversion.pp_doc; + embed = (fun ~depth _ _ s x -> it.Conversion.embed ~depth s x); + readback = (fun ~depth _ _ s x -> it.Conversion.readback ~depth s x); + } + let float : 'c 'csts. (float,'c,'csts) ContextualConversion.t = + let open ContextualConversion in + let it = BuiltInData.float in { + ty = it.Conversion.ty; pp = it.Conversion.pp; pp_doc = it.Conversion.pp_doc; + embed = (fun ~depth _ _ s x -> it.Conversion.embed ~depth s x); + readback = (fun ~depth _ _ s x -> it.Conversion.readback ~depth s x); + } + let string : 'c 'csts. (string,'c,'csts) ContextualConversion.t = + let open ContextualConversion in + let it = BuiltInData.string in { + ty = it.Conversion.ty; pp = it.Conversion.pp; pp_doc = it.Conversion.pp_doc; + embed = (fun ~depth _ _ s x -> it.Conversion.embed ~depth s x); + readback = (fun ~depth _ _ s x -> it.Conversion.readback ~depth s x); + } + let loc : 'c 'csts. (Util.Loc.t,'c,'csts) ContextualConversion.t = + let open ContextualConversion in + let it = BuiltInData.loc in { + ty = it.Conversion.ty; pp = it.Conversion.pp; pp_doc = it.Conversion.pp_doc; + embed = (fun ~depth _ _ s x -> it.Conversion.embed ~depth s x); + readback = (fun ~depth _ _ s x -> it.Conversion.readback ~depth s x); + } + + + let polyA0 = + let embed ~depth:_ _ _ state x = state, x, [] in + let readback ~depth _ _ state t = state, t, [] in + { ContextualConversion.embed; readback; ty = Conversion.TyName "A0"; + pp = (fun fmt _ -> Format.fprintf fmt ""); + pp_doc = (fun fmt () -> ()) } + let polyA1 = + let embed ~depth:_ _ _ state x = state, x, [] in + let readback ~depth _ _ state t = state, t, [] in + { ContextualConversion.embed; readback; ty = Conversion.TyName "A1"; + pp = (fun fmt _ -> Format.fprintf fmt ""); + pp_doc = (fun fmt () -> ()) } + let polyA2 = + let embed ~depth:_ _ _ state x = state, x, [] in + let readback ~depth _ _ state t = state, t, [] in + { ContextualConversion.embed; readback; ty = Conversion.TyName "A2"; + pp = (fun fmt _ -> Format.fprintf fmt ""); + pp_doc = (fun fmt () -> ()) } + let polyA3 = + let embed ~depth:_ _ _ state x = state, x, [] in + let readback ~depth _ _ state t = state, t, [] in + { ContextualConversion.embed; readback; ty = Conversion.TyName "A3"; + pp = (fun fmt _ -> Format.fprintf fmt ""); + pp_doc = (fun fmt () -> ()) } + + let any = + let embed ~depth:_ _ _ state x = state, x, [] in + let readback ~depth _ _ state t = state, t, [] in + { ContextualConversion.embed; readback; ty = Conversion.TyName "any"; + pp = (fun fmt _ -> Format.fprintf fmt ""); + pp_doc = (fun fmt () -> ()) } + + let map_acc f s l = + let rec aux acc extra s = function + | [] -> s, List.rev acc, List.(concat (rev extra)) + | x :: xs -> + let s, x, gls = f s x in + aux (x :: acc) (gls :: extra) s xs + in + aux [] [] s l + + let list d = + let embed ~depth h c s l = + let module R = (val !r) in let open R in + let s, l, eg = map_acc (d.ContextualConversion.embed ~depth h c) s l in + s, list_to_lp_list l, eg in + let readback ~depth h c s t = + let module R = (val !r) in let open R in + map_acc (d.ContextualConversion.readback ~depth h c) s + (lp_list_to_list ~depth t) + in + let pp fmt l = + Format.fprintf fmt "[%a]" (Util.pplist d.pp ~boxed:true "; ") l in + { ContextualConversion.embed; readback; + ty = TyApp ("list",d.ty,[]); + pp; + pp_doc = (fun fmt () -> ()) } + + let nominal = + let embed ~depth:_ _ _ state x = + let module R = (val !r) in + if x < 0 then Util.type_error "not a bound variable"; + state, R.mkConst x, [] in + let readback ~depth _ _ state t = + let module R = (val !r) in + match R.deref_head ~depth t with + | ED.Const i when i >= 0 -> state, i, [] + | _ -> Util.type_error "not a bound variable" in + { ContextualConversion.embed; readback; ty = TyName "nominal"; + pp = (fun fmt d -> Format.fprintf fmt "%d" d); + pp_doc = (fun fmt () -> ()) } + +end + + module Elpi = struct type t = Arg of string | Ref of ED.uvar_body @@ -657,24 +787,15 @@ module RawData = struct let ctypec = ED.Global_symbols.ctypec let spillc = ED.Global_symbols.spillc - module Map = ED.Constants.Map + module Map = Data.Constants.Map module Set = ED.Constants.Set end let of_term x = x - let of_hyp x = x - let of_hyps x = x - - type hyp = Data.hyp = { - hdepth : int; - hsrc : term - } - type hyps = hyp list - type suspended_goal = ED.suspended_goal = { - context : hyps; + context : Data.hyps; goal : int * term } @@ -1004,17 +1125,30 @@ end module Query = struct type name = string - type 'f arguments = 'f ED.Query.arguments = + type 'a arguments = 'a ED.Query.arguments = | N : unit arguments | D : 'a Conversion.t * 'a * 'x arguments -> 'x arguments | Q : 'a Conversion.t * name * 'x arguments -> ('a * 'x) arguments - type 'x t = Query of { predicate : name; arguments : 'x arguments } + type ('a,'b,'c) carguments = ('a,'b,'c) ED.Query.carguments = + | NC : (unit,'c,'csts) carguments + | DC : ('a,'c,'csts) ContextualConversion.t * 'a * ('x,'c,'csts) carguments -> ('x,'c,'csts) carguments + | QC : ('a,'c,'csts) ContextualConversion.t * name * ('x,'c,'csts) carguments -> ('a * 'x,'c,'csts) carguments + + type 'x t = + | Query of { predicate : name; arguments : 'x arguments } + | CQuery : name * ('x,#ContextualConversion.ctx as 'c,'csts) carguments * (ED.State.t -> 'c) * 'csts -> 'x t + + let compile p loc = function + | Query { predicate; arguments } -> + let p, predicate = Compiler.lookup_query_predicate p predicate in + let q = ED.Query.Query{ predicate; arguments } in + Compiler.query_of_data p loc q + | CQuery(predicate, arguments, ctx, csts) -> + let p, predicate = Compiler.lookup_query_predicate p predicate in + let q = ED.Query.CQuery(predicate, arguments, ctx, csts) in + Compiler.query_of_data p loc q - let compile p loc (Query { predicate; arguments }) = - let p, predicate = Compiler.lookup_query_predicate p predicate in - let q = ED.Query.Query{ predicate; arguments } in - Compiler.query_of_data p loc q end module State = struct @@ -1259,7 +1393,6 @@ module Calc = struct let calc = let open BuiltIn in - let open ContextualConversion in let open BuiltInPredicate.Notation in [ LPDoc " -- Evaluation --"; @@ -1270,8 +1403,8 @@ module Calc = struct MLCode(Pred("calc", In(BuiltInData.poly "A", "Expr", Out(BuiltInData.poly "A", "Out", - Read(unit_ctx, "unifies Out with the value of Expr. It can be used in tandem with spilling, eg [f {calc (N + 1)}]"))), - (fun t _ ~depth _ _ state -> !: (eval ~depth state t))), + Read("unifies Out with the value of Expr. It can be used in tandem with spilling, eg [f {calc (N + 1)}]"))), + (fun t _ ~depth state -> !: (eval ~depth state t))), DocAbove); ] @@ -1381,3 +1514,51 @@ module RawPp = struct let show_term = ED.show_term end end + +module PPX = struct + module Doc = struct + let comment = ED.BuiltInPredicate.pp_comment + let kind fmt ty ~doc = ED.BuiltInPredicate.ADT.document_kind fmt ty doc + let constructor fmt ~name ~doc ~ty ~args = + ED.BuiltInPredicate.ADT.document_constructor + fmt name doc (List.map (fun x -> (false,ED.Conversion.show_ty_ast ~prec:Arrow x,"")) (args @ [ty])) + let adt ~doc ~ty ~args = + ED.BuiltInPredicate.ADT.document_adt doc ty + (List.map (fun (n,s,a) -> n,s,List.map (fun x -> (false,ED.Conversion.show_ty_ast ~prec:Arrow x,"")) (a@[ty])) args) + type prec_level = ED.Conversion.prec_level = Arrow | AppArg + let show_ty_ast = ED.Conversion.show_ty_ast + + end + + type context_description = + | C : ('a,'k,'c,'csts) ContextualConversion.context -> context_description + + let readback_context { ContextualConversion.conv; to_key; push; is_entry_for_nominal; init} ctx ~depth hyps constraints state = + let module CMap = RawData.Constants.Map in + let filtered_hyps = + List.fold_left (fun m hyp -> + match is_entry_for_nominal hyp with + | None -> m + | Some idx -> + if CMap.mem idx m then + Utils.type_error "more than one context entry for the same nominal"; + CMap.add idx hyp m) CMap.empty + hyps in + let rec aux state gls i = + if i = depth then state, List.concat (List.rev gls) + else + if not (CMap.mem i filtered_hyps) then aux state gls (i + 1) + else + let hyp = CMap.find i filtered_hyps in + let hyp_depth = hyp.Data.hdepth in + let state, (nominal, t), gls_t = + conv.ContextualConversion.readback + ~depth:hyp_depth ctx constraints state hyp.Data.hsrc in + assert (nominal = i); + let s = to_key ~depth:hyp_depth t in + let state = + push ~depth:i state s { ContextualConversion.entry = t; depth = hyp_depth } in + aux state (gls_t :: gls) (i + 1) in + let state = init state in + aux state [] 0 +end diff --git a/src/API.mli b/src/API.mli index 830cfc71e..1e17aa443 100644 --- a/src/API.mli +++ b/src/API.mli @@ -165,9 +165,23 @@ module Data : sig } (* Hypothetical context *) - type hyp + type hyp = { + hdepth : int; + hsrc : term + } type hyps = hyp list + type constant = int + module Constants : sig + + module Map : sig + include Map.S with type key = constant + val show : (Format.formatter -> 'a -> unit) -> 'a t -> string + val pp : (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a t -> unit + end + + end + end module Compile : sig @@ -287,6 +301,7 @@ module Conversion : sig type ty_ast = TyName of string | TyApp of string * ty_ast * ty_ast list + type extra_goal = .. type extra_goal += | Unify of Data.term * Data.term @@ -319,14 +334,20 @@ module ContextualConversion : sig type ty_ast = Conversion.ty_ast = TyName of string | TyApp of string * ty_ast * ty_ast list + class ctx : Data.hyps -> + object + method raw : Data.hyps + end type ('a,'hyps,'constraints) embedding = depth:int -> 'hyps -> 'constraints -> Data.state -> 'a -> Data.state * Data.term * Conversion.extra_goals + constraint 'hyps = #ctx type ('a,'hyps,'constraints) readback = depth:int -> 'hyps -> 'constraints -> Data.state -> Data.term -> Data.state * 'a * Conversion.extra_goals + constraint 'hyps = #ctx type ('a,'h,'c) t = { ty : ty_ast; @@ -335,21 +356,40 @@ module ContextualConversion : sig embed : ('a,'h,'c) embedding; (* 'a -> term *) readback : ('a,'h,'c) readback; (* term -> 'a *) } + constraint 'h = #ctx + val (^^) : ('a, ctx, 'c) t -> ('a, 'x, 'c) t + + type 'a ctx_entry = { entry : 'a; depth : int } + val pp_ctx_entry : (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a ctx_entry -> unit + val show_ctx_entry : (Format.formatter -> 'a -> unit) -> 'a ctx_entry -> string + + type 'a ctx_field = 'a ctx_entry Data.Constants.Map.t + + (* A context that can be read on top of context 'c, made of items 'a indexed by 'k *) + type ('a,'k,'c,'csts) context = { + is_entry_for_nominal : Data.hyp -> Data.constant option; + to_key : depth:int -> 'a -> 'k; + push : depth:int -> Data.state -> 'k -> 'a ctx_entry -> Data.state; + pop : depth:int -> Data.state -> 'k -> Data.state; + conv : (Data.constant * 'a, #ctx as 'c, 'csts) t; + init : Data.state -> Data.state; + get : Data.state -> 'a ctx_field + } type ('hyps,'constraints) ctx_readback = depth:int -> Data.hyps -> Data.constraints -> Data.state -> Data.state * 'hyps * 'constraints * Conversion.extra_goals + constraint 'hyps = #ctx - val unit_ctx : (unit,unit) ctx_readback - val raw_ctx : (Data.hyps,Data.constraints) ctx_readback + val unit_ctx : (ctx,unit) ctx_readback + val raw_ctx : (ctx,Data.constraints) ctx_readback - (* cast *) - val (!<) : ('a,unit,unit) t -> 'a Conversion.t + type dummy + val in_raw_ctx : (ctx,Data.constraints) ctx_readback + val in_raw : (dummy, dummy, #ctx as 'a,'csts) context - (* morphisms *) - val (!>) : 'a Conversion.t -> ('a,'hyps,'constraints) t - val (!>>) : ('a Conversion.t -> 'b Conversion.t) -> ('a,'hyps,'constraints) t -> ('b,'hyps,'constraints) t - val (!>>>) : ('a Conversion.t -> 'b Conversion.t -> 'c Conversion.t) -> ('a,'hyps,'constraints) t -> ('b,'hyps,'constraints) t -> ('c,'hyps,'constraints) t + (* cast *) + val (!<) : ('a,ctx,unit) t -> 'a Conversion.t end @@ -376,6 +416,28 @@ module BuiltInData : sig end +module BuiltInContextualData : sig + + (** See {!module:Elpi.Builtin} for a few more *) + val int : (int,'c,'csts) ContextualConversion.t + val float : (float,'c,'csts) ContextualConversion.t + val string : (string,'c,'csts) ContextualConversion.t + val list : ('a,'c,'csts) ContextualConversion.t -> ('a list,'c,'csts) ContextualConversion.t + val loc : (Ast.Loc.t,'c,'csts) ContextualConversion.t + + (* poly "A" is what one would use for, say, [type eq A -> A -> prop] *) + val polyA0 : (Data.term,'c,'csts) ContextualConversion.t + val polyA1 : (Data.term,'c,'csts) ContextualConversion.t + val polyA2 : (Data.term,'c,'csts) ContextualConversion.t + val polyA3 : (Data.term,'c,'csts) ContextualConversion.t + + (* any is like poly "X" for X fresh *) + val any : (Data.term,'c,'csts) ContextualConversion.t + + val nominal : (Data.constant,'c,'csts) ContextualConversion.t + +end + (** Declare data from the host application that is opaque (no syntax), like int but not like list or pair *) module OpaqueData : sig @@ -560,33 +622,37 @@ module BuiltInPredicate : sig type 'a oarg = Keep | Discard type 'a ioarg = private Data of 'a | NoData - type once - type ('function_type, 'inernal_outtype_in, 'internal_hyps, 'internal_constraints) ffi = - (* Arguemnts that are translated independently of the program context *) - | In : 't Conversion.t * doc * ('i, 'o,'h,'c) ffi -> ('t -> 'i,'o,'h,'c) ffi - | Out : 't Conversion.t * doc * ('i, 'o * 't option,'h,'c) ffi -> ('t oarg -> 'i,'o,'h,'c) ffi - | InOut : 't ioarg Conversion.t * doc * ('i, 'o * 't option,'h,'c) ffi -> ('t ioarg -> 'i,'o,'h,'c) ffi - - (* Arguemnts that are translated looking at the program context *) - | CIn : ('t,'h,'c) ContextualConversion.t * doc * ('i, 'o,'h,'c) ffi -> ('t -> 'i,'o,'h,'c) ffi - | COut : ('t,'h,'c) ContextualConversion.t * doc * ('i, 'o * 't option,'h,'c) ffi -> ('t oarg -> 'i,'o,'h,'c) ffi - | CInOut : ('t ioarg,'h,'c) ContextualConversion.t * doc * ('i, 'o * 't option,'h,'c) ffi -> ('t ioarg -> 'i,'o,'h,'c) ffi - - (* The easy case: all arguments are context independent *) - | Easy : doc -> (depth:int -> 'o, 'o, unit, unit) ffi - - (* The advanced case: arguments are context dependent, here we provide the - context readback function *) - | Read : ('h,'c) ContextualConversion.ctx_readback * doc -> (depth:int -> 'h -> 'c -> Data.state -> 'o, 'o,'h,'c) ffi - | Full : ('h,'c) ContextualConversion.ctx_readback * doc -> (depth:int -> 'h -> 'c -> Data.state -> Data.state * 'o * Conversion.extra_goals, 'o,'h,'c) ffi - | FullHO : ('h,'c) ContextualConversion.ctx_readback * doc -> (once:once -> depth:int -> 'h -> 'c -> Data.state -> Data.state * 'o * Conversion.extra_goals, 'o,'h,'c) ffi - | VariadicIn : ('h,'c) ContextualConversion.ctx_readback * ('t,'h,'c) ContextualConversion.t * doc -> ('t list -> depth:int -> 'h -> 'c -> Data.state -> Data.state * 'o, 'o,'h,'c) ffi - | VariadicOut : ('h,'c) ContextualConversion.ctx_readback * ('t,'h,'c) ContextualConversion.t * doc -> ('t oarg list -> depth:int -> 'h -> 'c -> Data.state -> Data.state * ('o * 't option list option), 'o,'h,'c) ffi - | VariadicInOut : ('h,'c) ContextualConversion.ctx_readback * ('t ioarg,'h,'c) ContextualConversion.t * doc -> ('t ioarg list -> depth:int -> 'h -> 'c -> Data.state -> Data.state * ('o * 't option list option), 'o,'h,'c) ffi - - type t = Pred : name * ('a,unit,'h,'c) ffi * 'a -> t + (* Arguemnts that are translated independently of the program context *) + type ('function_type, 'inernal_outtype_in) ffi = + | In : 't Conversion.t * doc * ('i, 'o) ffi -> ('t -> 'i,'o) ffi + | Out : 't Conversion.t * doc * ('i, 'o * 't option) ffi -> ('t oarg -> 'i,'o) ffi + | InOut : 't ioarg Conversion.t * doc * ('i, 'o * 't option) ffi -> ('t ioarg -> 'i,'o) ffi + | Easy : doc -> (depth:int -> 'o, 'o) ffi + | Read : doc -> (depth:int -> Data.state -> 'o,'o) ffi + | Full : doc -> (depth:int -> Data.state -> Data.state * 'o * Conversion.extra_goals, 'o) ffi + | FullHO : doc -> (once:once -> depth:int -> Data.state -> Data.state * 'o * Conversion.extra_goals, 'o) ffi + | VariadicIn : 't Conversion.t * doc -> ('t list -> depth:int -> Data.state -> Data.state * 'o, 'o) ffi + | VariadicOut : 't Conversion.t * doc -> ('t oarg list -> depth:int -> Data.state -> Data.state * ('o * 't option list option), 'o) ffi + | VariadicInOut : ('t ioarg) Conversion.t * doc -> ('t ioarg list -> depth:int -> Data.state -> Data.state * ('o * 't option list option), 'o) ffi + + (* Arguemnts that are translated looking at the program context *) + type ('function_type, 'inernal_outtype_in, 'internal_hyps, 'internal_constraints) cffi = + | CIn : ('t,'h,'c) ContextualConversion.t * doc * ('i, 'o,'h,'c) cffi -> ('t -> 'i,'o,'h,'c) cffi + | COut : ('t,'h,'c) ContextualConversion.t * doc * ('i, 'o * 't option,'h,'c) cffi -> ('t oarg -> 'i,'o,'h,'c) cffi + | CInOut : ('t ioarg,'h,'c) ContextualConversion.t * doc * ('i, 'o * 't option,'h,'c) cffi -> ('t ioarg -> 'i,'o,'h,'c) cffi + | CEasy : doc -> (depth:int -> 'h -> 'c -> 'o, 'o,'h,'c) cffi + | CRead : doc -> (depth:int -> 'h -> 'c -> Data.state -> 'o, 'o,'h,'c) cffi + | CFull : doc -> (depth:int -> 'h -> 'c -> Data.state -> Data.state * 'o * Conversion.extra_goals, 'o,'h,'c) cffi + | CFullHO : doc -> (once:once -> depth:int -> 'h -> 'c -> Data.state -> Data.state * 'o * Conversion.extra_goals, 'o,'h,'c) cffi + | CVariadicIn : ('t,'h,'c) ContextualConversion.t * doc -> ('t list -> depth:int -> 'h -> 'c -> Data.state -> Data.state * 'o, 'o,'h,'c) cffi + | CVariadicOut : ('t,'h,'c) ContextualConversion.t * doc -> ('t oarg list -> depth:int -> 'h -> 'c -> Data.state -> Data.state * ('o * 't option list option), 'o,'h,'c) cffi + | CVariadicInOut : ('t ioarg,'h,'c) ContextualConversion.t * doc -> ('t ioarg list -> depth:int -> 'h -> 'c -> Data.state -> Data.state * ('o * 't option list option), 'o,'h,'c) cffi + + type t = + | Pred : name * ('a,unit) ffi * 'a -> t + | CPred : name * ('h,'c) ContextualConversion.ctx_readback * ('a,unit,'h,'c) cffi * 'a -> t (** Tools for InOut arguments. * @@ -769,8 +835,14 @@ module Query : sig | N : unit arguments | D : 'a Conversion.t * 'a * 'x arguments -> 'x arguments | Q : 'a Conversion.t * name * 'x arguments -> ('a * 'x) arguments + type (_,_,_) carguments = + | NC : (unit,'c,'csts) carguments + | DC : ('a,'c,'csts) ContextualConversion.t * 'a * ('x,'c,'csts) carguments -> ('x,'c,'csts) carguments + | QC : ('a,'c,'csts) ContextualConversion.t * name * ('x,'c,'csts) carguments -> ('a * 'x,'c,'csts) carguments - type 'x t = Query of { predicate : name; arguments : 'x arguments } + type 'x t = + | Query of { predicate : name; arguments : 'x arguments } + | CQuery : name * ('x,#ContextualConversion.ctx as 'c,'csts) carguments * (Data.state -> 'c) * 'csts -> 'x t val compile : Compile.program -> Ast.Loc.t -> 'a t -> 'a Compile.query @@ -956,6 +1028,10 @@ module RawOpaqueData : sig val declare : 'a declaration -> 'a cdata * 'a Conversion.t + module PPX : sig + val declare : 'a declaration -> 'a cdata * 'a Data.Constants.Map.t * doc + end + val pp : Format.formatter -> t -> unit val show : t -> string val equal : t -> t -> bool @@ -1026,7 +1102,7 @@ end * substitutes assigned unification variables by their value. *) module RawData : sig - type constant = int (** De Bruijn levels (not indexes): + type constant = Data.constant (** De Bruijn levels (not indexes): the distance of the binder from the root. Starts at 0 and grows for bound variables; global constants have negative values. *) @@ -1071,16 +1147,9 @@ module RawData : sig val mkConst : constant -> term (* no check, works for globals and bound *) val cmp_builtin : builtin -> builtin -> int - type hyp = { - hdepth : int; - hsrc : term - } - type hyps = hyp list - val of_hyp : Data.hyp -> hyp - val of_hyps : Data.hyp list -> hyps type suspended_goal = { - context : hyps; + context : Data.hyps; goal : int * term } val constraints : Data.constraints -> suspended_goal list @@ -1109,7 +1178,7 @@ module RawData : sig (* Marker for spilling function calls, as in [{ rev L }] *) val spillc : constant - module Map : Map.S with type key = constant + module Map = Data.Constants.Map module Set : Set.S with type elt = constant end @@ -1303,4 +1372,37 @@ module RawPp : sig end +module PPX : sig + + module Doc : sig + val kind : Format.formatter -> Conversion.ty_ast -> doc:string -> unit + val comment : Format.formatter -> string -> unit + val constructor : Format.formatter -> + name:string -> doc:string -> + ty:Conversion.ty_ast -> + args:Conversion.ty_ast list -> unit + val adt : + doc:string -> + ty:Conversion.ty_ast -> + args:(string * string * Conversion.ty_ast list) list -> + Format.formatter -> unit -> unit + + type prec_level = Arrow | AppArg + val show_ty_ast: ?prec:prec_level -> Conversion.ty_ast -> string + + end + + type context_description = + | C : ('a,'k,'c,'csts) ContextualConversion.context -> context_description + + val readback_context : + ('a,'k,'c,'csts) ContextualConversion.context -> + 'c -> + depth:int -> + Data.hyps -> + 'csts -> + Data.state -> Data.state * Conversion.extra_goals + +end + (**/**) diff --git a/src/builtin.ml b/src/builtin.ml index 98d891935..d4bc539c7 100644 --- a/src/builtin.ml +++ b/src/builtin.ml @@ -105,6 +105,111 @@ let bool = AlgebraicData.declare { ] }|> ContextualConversion.(!<) +let char : char Conversion.t = { + ty = TyName "char"; + pp_doc = (fun fmt () -> Format.fprintf fmt "Char values: single character strings"); + pp = (fun fmt b -> Format.fprintf fmt "%c" b); + embed = (fun ~depth (st: State.t) (c: char) -> BuiltInData.string.embed ~depth st (String.make 1 c)); + readback = (fun ~depth st term -> + let st,name,goals = BuiltInData.string.readback ~depth st term in + st,name.[0],goals + ); +} + + + +module PPX = struct + + let bool : (bool,'c,'csts) ContextualConversion.t = { + ty = TyName "bool"; + pp_doc = (fun fmt () -> Format.fprintf fmt "Char values: single character strings"); + pp = (fun fmt b -> Format.fprintf fmt "%b" b); + embed = (fun ~depth _ _ (st: State.t) c -> bool.embed ~depth st c); + readback = (fun ~depth _ _ st term -> bool.readback ~depth st term); + } + let char : (char,'c,'csts) ContextualConversion.t = { + ty = TyName "char"; + pp_doc = (fun fmt () -> Format.fprintf fmt "Char values: single character strings"); + pp = (fun fmt b -> Format.fprintf fmt "%c" b); + embed = (fun ~depth _ _ (st: State.t) (c: char) -> BuiltInData.string.embed ~depth st (String.make 1 c)); + readback = (fun ~depth _ _ st term -> + let st,name,goals = BuiltInData.string.readback ~depth st term in + st,name.[0],goals + ); + } + + let pair a b = let open AlgebraicData in declare { + ty = TyApp ("pair",a.ContextualConversion.ty,[b.ContextualConversion.ty]); + doc = "Pair: the constructor is pr, since ',' is for conjunction"; + pp = (fun fmt o -> Format.fprintf fmt "%a" (Util.pp_pair a.ContextualConversion.pp b.ContextualConversion.pp) o); + constructors = [ + K("pr","",CA(a,CA(b,N)), + B (fun a b -> (a,b)), + M (fun ~ok ~ko:_ -> function (a,b) -> ok a b)); + ] + } + + let triple a b c = let open AlgebraicData in declare { + ty = TyApp ("triple",a.ContextualConversion.ty,[b.ContextualConversion.ty;c.ContextualConversion.ty]); + doc = "Triple: the constructor is trpl, since ',' is for conjunction"; + pp = (fun fmt o -> Format.fprintf fmt "%a" (Util.pp_triple a.ContextualConversion.pp b.ContextualConversion.pp c.ContextualConversion.pp) o); + constructors = [ + K("trpl","",CA(a,CA(b,CA(c,N))), + B (fun a b c -> (a,b, c)), + M (fun ~ok ~ko:_ -> function (a,b,c) -> ok a b c)); + ] + } + + let quadruple a b c d = let open AlgebraicData in declare { + ty = TyApp ("quadruple",a.ContextualConversion.ty,[b.ContextualConversion.ty;c.ContextualConversion.ty;d.ContextualConversion.ty]); + doc = "Quadruple: the constructor is quadrpl, since ',' is for conjunction"; + pp = (fun fmt o -> Format.fprintf fmt "%a" (Util.pp_quadruple a.ContextualConversion.pp b.ContextualConversion.pp c.ContextualConversion.pp d.ContextualConversion.pp) o); + constructors = [ + K("quadrpl","",CA(a,CA(b,CA(c,CA(d,N)))), + B (fun a b c d -> (a,b,c,d)), + M (fun ~ok ~ko:_ -> function (a,b,c,d) -> ok a b c d)); + ] + } + + let option a = let open AlgebraicData in declare { + ty = TyApp("option",a.ContextualConversion.ty,[]); + doc = "The option type (aka Maybe)"; + pp = (fun fmt o -> Format.fprintf fmt "%a" (Util.pp_option a.ContextualConversion.pp) o); + constructors = [ + K("none","",N, + B None, + M (fun ~ok ~ko -> function None -> ok | _ -> ko ())); + K("some","",CA(a,N), + B (fun x -> Some x), + M (fun ~ok ~ko -> function Some x -> ok x | _ -> ko ())); + ] + } + + let hack embed = { + ContextualConversion.embed; + readback = (fun ~depth _ _ st x -> assert false); + ty = Conversion.TyName "hack"; + pp = (fun fmt x -> assert false); + pp_doc = (fun fmt x -> assert false); + } + let embed_option a = (option (hack a)).ContextualConversion.embed + let embed_pair a b = (pair (hack a) (hack b)).ContextualConversion.embed + let embed_triple a b c = (triple (hack a) (hack b) (hack c)).ContextualConversion.embed + let embed_quadruple a b c d = (quadruple (hack a) (hack b) (hack c) (hack d)).ContextualConversion.embed + + let hack readback = { + ContextualConversion.readback; + embed = (fun ~depth _ _ st x -> assert false); + ty = ContextualConversion.TyName "hack"; + pp = (fun fmt x -> assert false); + pp_doc = (fun fmt x -> assert false); + } + let readback_option a = (option (hack a)).ContextualConversion.readback + let readback_pair a b = (pair (hack a) (hack b)).ContextualConversion.readback + let readback_triple a b c = (triple (hack a) (hack b) (hack c)).ContextualConversion.readback + let readback_quadruple a b c d = (quadruple (hack a) (hack b) (hack c) (hack d)).ContextualConversion.readback +end + let pair a b = let open AlgebraicData in declare { ty = TyApp ("pair",a.Conversion.ty,[b.Conversion.ty]); doc = "Pair: the constructor is pr, since ',' is for conjunction"; @@ -116,6 +221,28 @@ let pair a b = let open AlgebraicData in declare { ] } |> ContextualConversion.(!<) +let triple a b c = let open AlgebraicData in declare { + ty = TyApp ("triple",a.Conversion.ty,[b.Conversion.ty;c.Conversion.ty]); + doc = "Triple: the constructor is trpl, since ',' is for conjunction"; + pp = (fun fmt o -> Format.fprintf fmt "%a" (Util.pp_triple a.Conversion.pp b.Conversion.pp c.Conversion.pp) o); + constructors = [ + K("trpl","",A(a,A(b,A(c,N))), + B (fun a b c -> (a,b, c)), + M (fun ~ok ~ko:_ -> function (a,b,c) -> ok a b c)); + ] +} |> ContextualConversion.(!<) + +let quadruple a b c d = let open AlgebraicData in declare { + ty = TyApp ("quadruple",a.Conversion.ty,[b.Conversion.ty;c.Conversion.ty;d.Conversion.ty]); + doc = "Quadruple: the constructor is quadrpl, since ',' is for conjunction"; + pp = (fun fmt o -> Format.fprintf fmt "%a" (Util.pp_quadruple a.Conversion.pp b.Conversion.pp c.Conversion.pp d.Conversion.pp) o); + constructors = [ + K("quadrpl","",A(a,A(b,A(c,A(d,N)))), + B (fun a b c d -> (a,b,c,d)), + M (fun ~ok ~ko:_ -> function (a,b,c,d) -> ok a b c d)); + ] +} |> ContextualConversion.(!<) + let option a = let open AlgebraicData in declare { ty = TyApp("option",a.Conversion.ty,[]); doc = "The option type (aka Maybe)"; @@ -253,11 +380,26 @@ let unspecC data = let open API.ContextualConversion in let open API.RawData in let state, x, gls = data.readback ~depth hyps constraints state (kool t) in state, Given x, gls) } -let unspec d = API.ContextualConversion.(!<(unspecC (!> d))) +let unspec data = let open API.Conversion in let open API.RawData in { + ty = data.ty; + pp_doc = data.pp_doc; + pp = (fun fmt -> function + | Unspec -> Format.fprintf fmt "Unspec" + | Given x -> Format.fprintf fmt "Given %a" data.pp x); + embed = (fun ~depth state -> function + | Given x -> data.embed ~depth state x + | Unspec -> state, mkDiscard, []); + readback = (fun ~depth state x -> + match look ~depth x with + | UnifVar _ -> state, Unspec, [] + | t -> + let state, x, gls = data.readback ~depth state (kool t) in + state, Given x, gls) +} (** Core built-in ********************************************************* *) -let core_builtins = let open BuiltIn in let open ContextualConversion in [ +let core_builtins = let open BuiltIn in [ LPDoc " == Core builtins ====================================="; @@ -304,8 +446,8 @@ let core_builtins = let open BuiltIn in let open ContextualConversion in [ "external type declare_constraint any -> any -> variadic any prop."); LPCode "external pred print_constraints. % prints all constraints"; - MLCode(Pred("halt", VariadicIn(unit_ctx, !> BuiltInData.any, "halts the program and print the terms"), - (fun args ~depth _ _ -> + MLCode(Pred("halt", VariadicIn(BuiltInData.any, "halts the program and print the terms"), + (fun args ~depth -> if args = [] then error "halt" else let b = Buffer.create 80 in @@ -326,8 +468,8 @@ let core_builtins = let open BuiltIn in let open ContextualConversion in [ MLCode(Pred(pname, In(BuiltInData.poly "A","X", In(BuiltInData.poly "A","Y", - Read(unit_ctx,("checks if X " ^ psym ^ " Y. Works for string, int and float")))), - (fun t1 t2 ~depth _ _ state -> + Read(("checks if X " ^ psym ^ " Y. Works for string, int and float")))), + (fun t1 t2 ~depth state -> let open RawOpaqueData in let t1 = look ~depth (Calc.eval ~depth state t1) in let t2 = look ~depth (Calc.eval ~depth state t2) in @@ -647,8 +789,8 @@ let lp_builtins = let open BuiltIn in let open BuiltInData in [ MLCode(Pred("string_to_term", In(string, "S", Out(any, "T", - Full(ContextualConversion.unit_ctx, "parses a term T from S"))), - (fun text _ ~depth () () state -> + Full("parses a term T from S"))), + (fun text _ ~depth state -> try let state, t = Quotation.term_at ~depth state text in state, !:t, [] @@ -659,8 +801,8 @@ let lp_builtins = let open BuiltIn in let open BuiltInData in [ MLCode(Pred("readterm", In(in_stream, "InStream", Out(any, "T", - Full(ContextualConversion.unit_ctx, "reads T from InStream, ends with \\n"))), - (fun (i,source_name) _ ~depth () () state -> + Full( "reads T from InStream, ends with \\n"))), + (fun (i,source_name) _ ~depth state -> try let text = input_line i in let state, t = Quotation.term_at ~depth state text in @@ -681,21 +823,21 @@ let lp_builtins = let open BuiltIn in let open BuiltInData in [ (** ELPI specific built-in ************************************************ *) -let elpi_builtins = let open BuiltIn in let open BuiltInData in let open ContextualConversion in [ +let elpi_builtins = let open BuiltIn in let open BuiltInData in [ LPDoc "== Elpi builtins ====================================="; MLCode(Pred("dprint", - VariadicIn(unit_ctx, !> any, "prints raw terms (debugging)"), - (fun args ~depth _ _ state -> + VariadicIn(any, "prints raw terms (debugging)"), + (fun args ~depth state -> Format.fprintf Format.std_formatter "@[%a@]@\n%!" (RawPp.list (RawPp.Debug.term depth) " ") args ; state, ())), DocAbove); MLCode(Pred("print", - VariadicIn(unit_ctx, !> any,"prints terms"), - (fun args ~depth _ _ state -> + VariadicIn(any,"prints terms"), + (fun args ~depth state -> Format.fprintf Format.std_formatter "@[%a@]@\n%!" (RawPp.list (RawPp.term depth) " ") args ; state, ())), @@ -710,9 +852,9 @@ counter C N :- trace.counter C N.|}; In(string, "QueryText", Out(list (poly "A"), "QuotedProgram", Out(poly "A", "QuotedQuery", - Full (unit_ctx, "quotes the program from FileName and the QueryText. "^ + Full ("quotes the program from FileName and the QueryText. "^ "See elpi-quoted_syntax.elpi for the syntax tree"))))), - (fun f s _ _ ~depth _ _ state -> + (fun f s _ _ ~depth state -> let elpi = Setup.init ~builtins:[BuiltIn.declare ~file_name:"(dummy)" []] @@ -824,7 +966,7 @@ let safeno = ref 0 let fresh_int = ref 0 (* factor the code of name and constant *) -let name_or_constant name condition = (); fun x out ~depth _ _ state -> +let name_or_constant name condition = (); fun x out ~depth state -> let len = List.length out in if len != 0 && len != 2 then type_error (name^" only supports 1 or 3 arguments"); @@ -872,7 +1014,7 @@ and same_term_list ~depth xs ys = | x::xs, y::ys -> same_term ~depth x y && same_term_list ~depth xs ys | _ -> false -let elpi_nonlogical_builtins = let open BuiltIn in let open BuiltInData in let open ContextualConversion in [ +let elpi_nonlogical_builtins = let open BuiltIn in let open BuiltInData in [ LPDoc "== Elpi nonlogical builtins ====================================="; @@ -880,8 +1022,8 @@ let elpi_nonlogical_builtins = let open BuiltIn in let open BuiltInData in let o MLCode(Pred("var", InOut(ioarg_any, "V", - VariadicInOut(unit_ctx, !> (ioarg_any),"checks if the term V is a variable. When used with tree arguments it relates an applied variable with its head and argument list.")), - (fun x out ~depth _ _ state -> + VariadicInOut(ioarg_any,"checks if the term V is a variable. When used with tree arguments it relates an applied variable with its head and argument list.")), + (fun x out ~depth state -> let len = List.length out in if len != 0 && len != 2 then type_error ("var only supports 1 or 3 arguments"); @@ -911,8 +1053,8 @@ let elpi_nonlogical_builtins = let open BuiltIn in let open BuiltInData in let o MLCode(Pred("prune", Out(any, "V", In(list any, "L", - Full (unit_ctx, "V is pruned to L (V is unified with a variable that only sees the list of names L)"))), - (fun _ l ~depth _ _ state -> + Full ("V is pruned to L (V is unified with a variable that only sees the list of names L)"))), + (fun _ l ~depth state -> if not (List.for_all (fun t -> match look ~depth t with | Const n -> n >= 0 | _ -> false) l) then @@ -968,13 +1110,13 @@ X == Y :- same_term X Y. MLCode(Pred("name", InOut(ioarg_any, "T", - VariadicInOut(unit_ctx, !> (ioarg any),"checks if T is a eigenvariable. When used with tree arguments it relates an applied name with its head and argument list.")), + VariadicInOut(ioarg any,"checks if T is a eigenvariable. When used with tree arguments it relates an applied name with its head and argument list.")), (name_or_constant "name" (fun x -> x >= 0))), DocAbove); MLCode(Pred("constant", InOut(ioarg_any, "T", - VariadicInOut(unit_ctx, !> (ioarg any),"checks if T is a (global) constant. When used with tree arguments it relates an applied constant with its head and argument list.")), + VariadicInOut(ioarg any,"checks if T is a (global) constant. When used with tree arguments it relates an applied constant with its head and argument list.")), (name_or_constant "constant" (fun x -> x < 0))), DocAbove); @@ -1003,8 +1145,8 @@ X == Y :- same_term X Y. MLCode(Pred("closed_term", Out(any, "T", - Full (unit_ctx, "unify T with a variable that has no eigenvariables in scope")), - (fun _ ~depth _ _ state -> + Full ("unify T with a variable that has no eigenvariables in scope")), + (fun _ ~depth state -> let state, k = FlexibleData.Elpi.make state in state, !:(mkUnifVar k ~args:[] state), [])), DocAbove); @@ -1211,8 +1353,8 @@ set, In(set,"M", In(HOAdaptors.pred1 alpha,"F", Out(set,"M1", - FullHO(ContextualConversion.unit_ctx, "Filter M w.r.t. the predicate F")))), - (fun m f _ ~once ~depth _ _ state -> + FullHO("Filter M w.r.t. the predicate F")))), + (fun m f _ ~once ~depth state -> let state, m, gls = HOAdaptors.filter1 ~once ~depth ~filter:Set.filter f m state in @@ -1224,8 +1366,8 @@ set, In(set,"M", In(HOAdaptors.pred2 alpha alpha,"F", Out(set,"M1", - FullHO(ContextualConversion.unit_ctx, "Map M w.r.t. the predicate F")))), - (fun m f _ ~once ~depth _ _ state -> + FullHO("Map M w.r.t. the predicate F")))), + (fun m f _ ~once ~depth state -> let state, m, gls = HOAdaptors.map1 ~once ~depth ~map:Set.map f m state in @@ -1315,8 +1457,8 @@ let open BuiltIn in let open BuiltInData in In(map "A","M", In(HOAdaptors.pred2 alpha closed_A,"F", Out(map "A","M1", - FullHO(ContextualConversion.unit_ctx, "Filter M w.r.t. the predicate F")))), - (fun m f _ ~once ~depth _ _ state -> + FullHO("Filter M w.r.t. the predicate F")))), + (fun m f _ ~once ~depth state -> let state, m, gls = HOAdaptors.filter2 ~once ~depth ~filter:Map.filter f m state in @@ -1328,8 +1470,8 @@ let open BuiltIn in let open BuiltInData in In(map "A","M", In(HOAdaptors.pred3 alpha closed_A closed_B,"F", Out(map "B","M1", - FullHO(ContextualConversion.unit_ctx, "Map M w.r.t. the predicate F")))), - (fun m f _ ~once ~depth _ _ state -> + FullHO( "Map M w.r.t. the predicate F")))), + (fun m f _ ~once ~depth state -> let state, m, gls = HOAdaptors.map2 ~once ~depth ~map:Map.mapi f m state in diff --git a/src/builtin.mli b/src/builtin.mli index 8482c507a..7440b08cf 100644 --- a/src/builtin.mli +++ b/src/builtin.mli @@ -56,8 +56,28 @@ val std_builtins : API.Setup.builtins (* Type descriptors for built-in predicates *) val pair : 'a API.Conversion.t -> 'b API.Conversion.t -> ('a * 'b) API.Conversion.t +val triple : 'a API.Conversion.t -> 'b API.Conversion.t -> 'c API.Conversion.t -> ('a * 'b * 'c) API.Conversion.t +val quadruple : 'a API.Conversion.t -> 'b API.Conversion.t -> 'c API.Conversion.t -> 'd API.Conversion.t -> ('a * 'b * 'c * 'd) API.Conversion.t val option : 'a API.Conversion.t -> 'a option API.Conversion.t val bool : bool API.Conversion.t +val char : char API.Conversion.t + +module PPX : sig + val embed_option : ('a, 'ctx, 'csts) API.ContextualConversion.embedding -> ('a option, 'ctx, 'csts) API.ContextualConversion.embedding + val embed_pair : ('a, 'ctx, 'csts) API.ContextualConversion.embedding -> ('b, 'ctx, 'csts) API.ContextualConversion.embedding -> ('a * 'b, 'ctx, 'csts) API.ContextualConversion.embedding + val embed_triple : ('a, 'ctx, 'csts) API.ContextualConversion.embedding -> ('b, 'ctx, 'csts) API.ContextualConversion.embedding -> ('c, 'ctx, 'csts) API.ContextualConversion.embedding -> ('a * 'b * 'c, 'ctx, 'csts) API.ContextualConversion.embedding + val embed_quadruple : ('a, 'ctx, 'csts) API.ContextualConversion.embedding -> ('b, 'ctx, 'csts) API.ContextualConversion.embedding -> ('c, 'ctx, 'csts) API.ContextualConversion.embedding -> ('d, 'ctx, 'csts) API.ContextualConversion.embedding -> ('a * 'b * 'c * 'd, 'ctx, 'csts) API.ContextualConversion.embedding + val readback_option : ('a, 'ctx, 'csts) API.ContextualConversion.readback -> ('a option, 'ctx, 'csts) API.ContextualConversion.readback + val readback_pair : ('a, 'ctx, 'csts) API.ContextualConversion.readback -> ('b, 'ctx, 'csts) API.ContextualConversion.readback -> ('a * 'b, 'ctx, 'csts) API.ContextualConversion.readback + val readback_triple : ('a, 'ctx, 'csts) API.ContextualConversion.readback -> ('b, 'ctx, 'csts) API.ContextualConversion.readback -> ('c, 'ctx, 'csts) API.ContextualConversion.readback -> ('a * 'b * 'c, 'ctx, 'csts) API.ContextualConversion.readback + val readback_quadruple : ('a, 'ctx, 'csts) API.ContextualConversion.readback -> ('b, 'ctx, 'csts) API.ContextualConversion.readback -> ('c, 'ctx, 'csts) API.ContextualConversion.readback -> ('d, 'ctx, 'csts) API.ContextualConversion.readback -> ('a * 'b * 'c * 'd, 'ctx, 'csts) API.ContextualConversion.readback + val option : ('a, 'ctx, 'csts) API.ContextualConversion.t -> ('a option, 'ctx, 'csts) API.ContextualConversion.t + val pair : ('a, 'ctx, 'csts) API.ContextualConversion.t -> ('b, 'ctx, 'csts) API.ContextualConversion.t -> ('a * 'b, 'ctx, 'csts) API.ContextualConversion.t + val triple : ('a, 'ctx, 'csts) API.ContextualConversion.t -> ('b, 'ctx, 'csts) API.ContextualConversion.t -> ('c, 'ctx, 'csts) API.ContextualConversion.t -> ('a * 'b * 'c, 'ctx, 'csts) API.ContextualConversion.t + val quadruple : ('a, 'ctx, 'csts) API.ContextualConversion.t -> ('b, 'ctx, 'csts) API.ContextualConversion.t -> ('c, 'ctx, 'csts) API.ContextualConversion.t -> ('d, 'ctx, 'csts) API.ContextualConversion.t -> ('a * 'b * 'c * 'd, 'ctx, 'csts) API.ContextualConversion.t + val bool : (bool, 'ctx, 'csts) API.ContextualConversion.t + val char : (char, 'ctx, 'csts) API.ContextualConversion.t +end (* A standard way to make a predicate always succeed but still give errors *) type diagnostic = private OK | ERROR of string API.BuiltInPredicate.ioarg diff --git a/src/compiler.ml b/src/compiler.ml index 545e6ce4c..74e2fb0d7 100644 --- a/src/compiler.ml +++ b/src/compiler.ml @@ -317,7 +317,7 @@ let builtins : t D.State.component = D.State.declare let all state = (D.State.get builtins state).constants -let register state (D.BuiltInPredicate.Pred(s,_,_) as b) = +let register state s b = if s = "" then anomaly "Built-in predicate name must be non empty"; if not (D.State.get D.while_compiling state) then anomaly "Built-in can only be declared at compile time"; @@ -331,6 +331,10 @@ let register state (D.BuiltInPredicate.Pred(s,_,_) as b) = code = b :: code; }) ;; +let register state = function +| D.BuiltInPredicate.Pred(s,_,_) as b -> register state s b +| D.BuiltInPredicate.CPred(s,_,_,_) as b -> register state s b + let is_declared_str state x = let declared = (D.State.get builtins state).names in @@ -539,7 +543,7 @@ type 'a query = { chr : (constant list * prechr_rule list) list; initial_depth : int; query : preterm; - query_arguments : 'a Query.arguments [@opaque]; + query_adt : 'a Query.t [@opaque]; (* We pre-compile the query to ease the API *) initial_goal : term; assignments : term StrMap.t; compiler_state : State.t; @@ -2291,7 +2295,7 @@ let query_of_ast (compiler_state, assembled_program) t state_update = chr = assembled_program.Assembled.chr; initial_depth; query; - query_arguments = Query.N; + query_adt = Query.(Query {predicate=0;arguments=N}); initial_goal; assignments; compiler_state = state |> (uvbodies_of_assignments assignments) |> state_update; @@ -2322,18 +2326,18 @@ let query_of_term (compiler_state, assembled_program) f = chr = assembled_program.Assembled.chr; initial_depth; query; - query_arguments = Query.N; + query_adt = Query.(Query {predicate=0;arguments=N}); initial_goal; assignments; compiler_state = state |> (uvbodies_of_assignments assignments); } -let query_of_data (state, p) loc (Query.Query { arguments } as descr) = +let query_of_data (state, p) loc descr = let query = query_of_term (state, p) (fun ~depth state -> let state, term, gls = R.embed_query ~mk_Arg ~depth state descr in state, (loc, term), gls) in - { query with query_arguments = arguments } + { query with query_adt = descr } let lookup_query_predicate (state, p) pred = let state, pred = Symbols.allocate_global_symbol_str state pred in @@ -2430,7 +2434,7 @@ let run initial_goal; assignments; compiler_state = state; - query_arguments; + query_adt; } = check_all_builtin_are_typed state types; @@ -2473,7 +2477,8 @@ let run let builtins = Hashtbl.create 17 in let pred_list = (State.get Builtins.builtins state).code in List.iter - (fun (D.BuiltInPredicate.Pred(s,_,_) as p) -> + (function + | (D.BuiltInPredicate.Pred(s,_,_) | D.BuiltInPredicate.CPred(s,_,_,_) as p) -> let c, _ = Symbols.get_global_symbol_str state s in Hashtbl.add builtins c p) pred_list; @@ -2485,7 +2490,7 @@ let run initial_goal; initial_runtime_state = State.end_compilation state; assignments; - query_arguments; + query_adt; symbol_table; builtins; } diff --git a/src/data.ml b/src/data.ml index cec54b7c7..d1b31e7d0 100644 --- a/src/data.ml +++ b/src/data.ml @@ -740,6 +740,7 @@ let rec show_ty_ast ?prec = function let src = show_ty_ast ~prec:Arrow src in let tgt = show_ty_ast tgt in with_par prec Arrow (src ^" -> "^ tgt) + | TyApp (s,x,xs) -> let t = String.concat " " (s :: List.map (show_ty_ast ~prec:AppArg) (x::xs)) in with_par prec AppArg t @@ -760,13 +761,23 @@ module ContextualConversion = struct type ty_ast = Conversion.ty_ast = TyName of string | TyApp of string * ty_ast * ty_ast list [@@deriving show] + type hyp = clause_src + + class ctx (h : hyps) = + object + method raw = h + end + type ('a,'hyps,'constraints) embedding = depth:int -> 'hyps -> 'constraints -> State.t -> 'a -> State.t * term * Conversion.extra_goals + constraint 'hyps = #ctx type ('a,'hyps,'constraints) readback = depth:int -> 'hyps -> 'constraints -> State.t -> term -> State.t * 'a * Conversion.extra_goals + constraint 'hyps = #ctx + type ('a,'hyps,'constraints) t = { ty : ty_ast; @@ -775,19 +786,61 @@ module ContextualConversion = struct embed : ('a,'hyps,'constraints) embedding [@opaque]; (* 'a -> term *) readback : ('a,'hyps,'constraints) readback [@opaque]; (* term -> 'a *) } + constraint 'hyps = #ctx [@@deriving show] + type 'a ctx_entry = { entry : 'a; depth : int } + [@@deriving show] + + type 'a ctx_field = 'a ctx_entry Constants.Map.t + + type ('a,'k,'h,'csts) context = { + is_entry_for_nominal : hyp -> constant option; + to_key : depth:int -> 'a -> 'k; + push : depth:int -> State.t -> 'k -> 'a ctx_entry -> State.t; + pop : depth:int -> State.t -> 'k -> State.t; + conv : (constant * 'a, #ctx as 'h,'csts) t; + init : State.t -> State.t; + get : State.t -> 'a ctx_field + } + type ('hyps,'constraints) ctx_readback = depth:int -> hyps -> constraints -> State.t -> State.t * 'hyps * 'constraints * Conversion.extra_goals + constraint 'hyps = #ctx + + type dummy = unit + + let dummy = { + ty = TyName "dummy"; + pp = (fun _ _ -> assert false); + pp_doc = (fun _ _ -> assert false); + embed = (fun ~depth _ _ _ _ -> assert false); + readback = (fun ~depth _ _ _ _ -> assert false); + } + + let in_raw = { + is_entry_for_nominal = (fun _ -> None); + to_key = (fun ~depth _ -> ()); + push = (fun ~depth st _ _ -> st); + pop = (fun ~depth st _ -> st); + conv = dummy; + init = (fun st -> st); + get = (fun st -> Constants.Map.empty); + } + + let build_raw_ctx h s = new ctx h + + let in_raw_ctx : (ctx,'a) ctx_readback = + fun ~depth:_ h c s -> s, build_raw_ctx h s, c,[] - let unit_ctx : (unit,unit) ctx_readback = fun ~depth:_ _ _ s -> s, (), (), [] - let raw_ctx : (hyps,constraints) ctx_readback = fun ~depth:_ h c s -> s, h, c, [] + let unit_ctx : (ctx,unit) ctx_readback = fun ~depth:_ h c s -> s, build_raw_ctx h s, (), [] + let raw_ctx : (ctx,constraints) ctx_readback = fun ~depth:_ h c s -> s, build_raw_ctx h s, c, [] let (!<) { ty; pp_doc; pp; embed; readback; } = { Conversion.ty; pp; pp_doc; - embed = (fun ~depth s t -> embed ~depth () () s t); - readback = (fun ~depth s t -> readback ~depth () () s t); + embed = (fun ~depth s t -> embed ~depth (build_raw_ctx [] s) () s t); + readback = (fun ~depth s t -> readback ~depth (build_raw_ctx [] s) () s t); } let (!>) { Conversion.ty; pp_doc; pp; embed; readback; } = { @@ -934,24 +987,33 @@ type doc = string type 'a oarg = Keep | Discard type 'a ioarg = Data of 'a | NoData -type ('function_type, 'inernal_outtype_in, 'internal_hyps, 'internal_constraints) ffi = - | In : 't Conversion.t * doc * ('i, 'o,'h,'c) ffi -> ('t -> 'i,'o,'h,'c) ffi - | Out : 't Conversion.t * doc * ('i, 'o * 't option,'h,'c) ffi -> ('t oarg -> 'i,'o,'h,'c) ffi - | InOut : 't ioarg Conversion.t * doc * ('i, 'o * 't option,'h,'c) ffi -> ('t ioarg -> 'i,'o,'h,'c) ffi - - | CIn : ('t,'h,'c) ContextualConversion.t * doc * ('i, 'o,'h,'c) ffi -> ('t -> 'i,'o,'h,'c) ffi - | COut : ('t,'h,'c) ContextualConversion.t * doc * ('i, 'o * 't option,'h,'c) ffi -> ('t oarg -> 'i,'o,'h,'c) ffi - | CInOut : ('t ioarg,'h,'c) ContextualConversion.t * doc * ('i, 'o * 't option,'h,'c) ffi -> ('t ioarg -> 'i,'o,'h,'c) ffi - - | Easy : doc -> (depth:int -> 'o, 'o,unit,unit) ffi - | Read : ('h,'c) ContextualConversion.ctx_readback * doc -> (depth:int -> 'h -> 'c -> State.t -> 'o, 'o,'h,'c) ffi - | Full : ('h,'c) ContextualConversion.ctx_readback * doc -> (depth:int -> 'h -> 'c -> State.t -> State.t * 'o * Conversion.extra_goals, 'o,'h,'c) ffi - | FullHO : ('h,'c) ContextualConversion.ctx_readback * doc -> (once:(depth:int -> term -> State.t -> State.t) -> depth:int -> 'h -> 'c -> State.t -> State.t * 'o * Conversion.extra_goals, 'o,'h,'c) ffi - | VariadicIn : ('h,'c) ContextualConversion.ctx_readback * ('t,'h,'c) ContextualConversion.t * doc -> ('t list -> depth:int -> 'h -> 'c -> State.t -> State.t * 'o, 'o,'h,'c) ffi - | VariadicOut : ('h,'c) ContextualConversion.ctx_readback * ('t,'h,'c) ContextualConversion.t * doc -> ('t oarg list -> depth:int -> 'h -> 'c -> State.t -> State.t * ('o * 't option list option), 'o,'h,'c) ffi - | VariadicInOut : ('h,'c) ContextualConversion.ctx_readback * ('t ioarg,'h,'c) ContextualConversion.t * doc -> ('t ioarg list -> depth:int -> 'h -> 'c -> State.t -> State.t * ('o * 't option list option), 'o,'h,'c) ffi - -type t = Pred : name * ('a,unit,'h,'c) ffi * 'a -> t +type ('function_type, 'inernal_outtype_in) ffi = + | In : 't Conversion.t * doc * ('i, 'o) ffi -> ('t -> 'i,'o) ffi + | Out : 't Conversion.t * doc * ('i, 'o * 't option) ffi -> ('t oarg -> 'i,'o) ffi + | InOut : 't ioarg Conversion.t * doc * ('i, 'o * 't option) ffi -> ('t ioarg -> 'i,'o) ffi + | Easy : doc -> (depth:int -> 'o, 'o) ffi + | Read : doc -> (depth:int -> State.t -> 'o,'o) ffi + | Full : doc -> (depth:int -> State.t -> State.t * 'o * Conversion.extra_goals, 'o) ffi + | FullHO : doc -> (once:(depth:int -> term -> State.t -> State.t) -> depth:int -> State.t -> State.t * 'o * Conversion.extra_goals, 'o) ffi + | VariadicIn : 't Conversion.t * doc -> ('t list -> depth:int -> State.t -> State.t * 'o, 'o) ffi + | VariadicOut : 't Conversion.t * doc -> ('t oarg list -> depth:int -> State.t -> State.t * ('o * 't option list option), 'o) ffi + | VariadicInOut : 't ioarg Conversion.t * doc -> ('t ioarg list -> depth:int -> State.t -> State.t * ('o * 't option list option), 'o) ffi + +type ('function_type, 'inernal_outtype_in, 'internal_hyps, 'internal_constraints) cffi = + | CIn : ('t,'h,'c) ContextualConversion.t * doc * ('i, 'o,'h,'c) cffi -> ('t -> 'i,'o,'h,'c) cffi + | COut : ('t,'h,'c) ContextualConversion.t * doc * ('i, 'o * 't option,'h,'c) cffi -> ('t oarg -> 'i,'o,'h,'c) cffi + | CInOut : ('t ioarg,'h,'c) ContextualConversion.t * doc * ('i, 'o * 't option,'h,'c) cffi -> ('t ioarg -> 'i,'o,'h,'c) cffi + | CEasy : doc -> (depth:int -> 'h -> 'c -> 'o, 'o,'h,'c) cffi + | CRead : doc -> (depth:int -> 'h -> 'c -> State.t -> 'o, 'o,'h,'c) cffi + | CFull : doc -> (depth:int -> 'h -> 'c -> State.t -> State.t * 'o * Conversion.extra_goals, 'o,'h,'c) cffi + | CFullHO : doc -> (once:(depth:int -> term -> State.t -> State.t) -> depth:int -> 'h -> 'c -> State.t -> State.t * 'o * Conversion.extra_goals, 'o,'h,'c) cffi + | CVariadicIn : ('t,'h,'c) ContextualConversion.t * doc -> ('t list -> depth:int -> 'h -> 'c -> State.t -> State.t * 'o, 'o,'h,'c) cffi + | CVariadicOut : ('t,'h,'c) ContextualConversion.t * doc -> ('t oarg list -> depth:int -> 'h -> 'c -> State.t -> State.t * ('o * 't option list option), 'o,'h,'c) cffi + | CVariadicInOut : ('t ioarg,'h,'c) ContextualConversion.t * doc -> ('t ioarg list -> depth:int -> 'h -> 'c -> State.t -> State.t * ('o * 't option list option), 'o,'h,'c) cffi + +type t = + | Pred : name * ('a,unit) ffi * 'a -> t + | CPred : name * ('h,'c) ContextualConversion.ctx_readback * ('a,unit,'h,'c) cffi * 'a -> t type doc_spec = DocAbove | DocNext @@ -1122,8 +1184,8 @@ and embed : type a h c. matcher ~ok ~ko:(aux rest) t state in aux bindings state -let rec compile_arguments : type b bs m ms t h c. - (bs,b,ms,m,t,h,c) constructor_arguments -> (t,h,c) ContextualConversion.t -> (bs,ms,t,h,c) compiled_constructor_arguments = +let rec compile_arguments : type b bs m ms t c. + (bs,b,ms,m,t,'h,c) constructor_arguments -> (t,#ContextualConversion.ctx as 'h,c) ContextualConversion.t -> (bs,ms,t,'h,c) compiled_constructor_arguments = fun arg self -> match arg with | N -> XN @@ -1178,7 +1240,7 @@ let compile_matcher : type bs b m ms t h c. (bs,b,ms,m,t,h,c) constructor_argume let rec tyargs_of_args : type a b c d e. string -> (a,b,c,d,e) compiled_constructor_arguments -> (bool * string * string) list = fun self -> function | XN -> [false,self,""] - | XA ({ ty },rest) -> (false,Conversion.show_ty_ast ty,"") :: tyargs_of_args self rest + | XA ({ ty },rest) -> (false,Conversion.show_ty_ast ~prec:Arrow ty,"") :: tyargs_of_args self rest let compile_constructors ty self self_name l = let names = @@ -1196,7 +1258,10 @@ let document_constructor fmt name doc argsdoc = Fmt.fprintf fmt "@[type %s@[%a.%s@]@]@\n" name pp_ty_args argsdoc (if doc = "" then "" else " % " ^ doc) -let document_kind fmt = function +let document_kind fmt ty doc = + if doc <> "" then + begin pp_comment fmt ("% " ^ doc); Fmt.fprintf fmt "@\n" end; + match ty with | Conversion.TyApp(s,_,l) -> let n = List.length l + 2 in let l = Array.init n (fun _ -> "type") in @@ -1204,15 +1269,17 @@ let document_kind fmt = function s (String.concat " -> " (Array.to_list l)) | Conversion.TyName s -> Fmt.fprintf fmt "@[kind %s type.@]@\n" s -let document_adt doc ty ks cks fmt () = - if doc <> "" then - begin pp_comment fmt ("% " ^ doc); Fmt.fprintf fmt "@\n" end; - document_kind fmt ty; +let document_compiled_adt doc ty ks cks fmt () = + document_kind fmt ty doc; List.iter (fun (K(name,doc,_,_,_)) -> if name <> "uvar" then let argsdoc = StrMap.find name cks in document_constructor fmt name doc argsdoc) ks +let document_adt doc ty ks fmt () = + document_kind fmt ty doc; + List.iter (fun (name,doc,spec) -> document_constructor fmt name doc spec) ks + let adt ~mkinterval ~look ~mkConst ~alloc ~mkUnifVar { ty; constructors; doc; pp } = let readback_ref = ref (fun ~depth _ _ _ _ -> assert false) in let embed_ref = ref (fun ~depth _ _ _ _ -> assert false) in @@ -1221,7 +1288,7 @@ let adt ~mkinterval ~look ~mkConst ~alloc ~mkUnifVar { ty; constructors; doc; pp ContextualConversion.ty; pp; pp_doc = (fun fmt () -> - document_adt doc ty constructors !sconstructors_ref fmt ()); + document_compiled_adt doc ty constructors !sconstructors_ref fmt ()); readback = (fun ~depth hyps constraints state term -> !readback_ref ~depth hyps constraints state term); embed = (fun ~depth hyps constraints state term -> @@ -1299,21 +1366,36 @@ let pp_variadictype fmt name doc_pred ty args = let document_pred fmt docspec name ffi = let rec doc - : type i o h c. (bool * string * string) list -> (i,o,h,c) ffi -> unit + : type i o. (bool * string * string) list -> (i,o) ffi -> unit = fun args -> function | In( { Conversion.ty }, s, ffi) -> doc ((true,Conversion.show_ty_ast ty,s) :: args) ffi | Out( { Conversion.ty }, s, ffi) -> doc ((false,Conversion.show_ty_ast ty,s) :: args) ffi | InOut( { Conversion.ty }, s, ffi) -> doc ((false,Conversion.show_ty_ast ty,s) :: args) ffi + | Easy s -> pp_pred fmt docspec name s args + | Read s -> pp_pred fmt docspec name s args + | Full s -> pp_pred fmt docspec name s args + | FullHO s -> pp_pred fmt docspec name s args + | VariadicIn({ Conversion.ty }, s) -> pp_variadictype fmt name s (Conversion.show_ty_ast ty) args + | VariadicOut({ Conversion.ty }, s) -> pp_variadictype fmt name s (Conversion.show_ty_ast ty) args + | VariadicInOut({ Conversion.ty }, s) -> pp_variadictype fmt name s (Conversion.show_ty_ast ty) args + + in + doc [] ffi +;; +let document_cpred fmt docspec name ffi = + let rec doc + : type i o h c. (bool * string * string) list -> (i,o,h,c) cffi -> unit + = fun args -> function | CIn( { ContextualConversion.ty }, s, ffi) -> doc ((true,Conversion.show_ty_ast ty,s) :: args) ffi | COut( { ContextualConversion.ty }, s, ffi) -> doc ((false,Conversion.show_ty_ast ty,s) :: args) ffi | CInOut( { ContextualConversion.ty }, s, ffi) -> doc ((false,Conversion.show_ty_ast ty,s) :: args) ffi - | Read (_,s) -> pp_pred fmt docspec name s args - | Easy s -> pp_pred fmt docspec name s args - | Full (_,s) -> pp_pred fmt docspec name s args - | FullHO (_,s) -> pp_pred fmt docspec name s args - | VariadicIn( _,{ ContextualConversion.ty }, s) -> pp_variadictype fmt name s (Conversion.show_ty_ast ty) args - | VariadicOut( _,{ ContextualConversion.ty }, s) -> pp_variadictype fmt name s (Conversion.show_ty_ast ty) args - | VariadicInOut( _,{ ContextualConversion.ty }, s) -> pp_variadictype fmt name s (Conversion.show_ty_ast ty) args + | CEasy s -> pp_pred fmt docspec name s args + | CRead s -> pp_pred fmt docspec name s args + | CFull s -> pp_pred fmt docspec name s args + | CFullHO s -> pp_pred fmt docspec name s args + | CVariadicIn({ ContextualConversion.ty }, s) -> pp_variadictype fmt name s (Conversion.show_ty_ast ty) args + | CVariadicOut({ ContextualConversion.ty }, s) -> pp_variadictype fmt name s (Conversion.show_ty_ast ty) args + | CVariadicInOut({ ContextualConversion.ty }, s) -> pp_variadictype fmt name s (Conversion.show_ty_ast ty) args in doc [] ffi ;; @@ -1325,11 +1407,17 @@ let document fmt l calc_list = Fmt.fprintf fmt "@\n@\n"; List.iter (function | MLCode(Pred(name,ffi,_), docspec) -> - document_pred fmt docspec name ffi; - if name = "calc" then begin - Format.fprintf fmt "%s@\n@\n" "% --- Operators ---"; - List.iter (fun (_,x) -> Format.fprintf fmt "%s@\n@\n" x.CalcHooks.ty_decl ) calc_list - end; + document_pred fmt docspec name ffi; + if name = "calc" then begin + Format.fprintf fmt "%s@\n@\n" "% --- Operators ---"; + List.iter (fun (_,x) -> Format.fprintf fmt "%s@\n@\n" x.CalcHooks.ty_decl ) calc_list + end; + | MLCode(CPred(name,_,ffi,_), docspec) -> + document_cpred fmt docspec name ffi; + if name = "calc" then begin + Format.fprintf fmt "%s@\n@\n" "% --- Operators ---"; + List.iter (fun (_,x) -> Format.fprintf fmt "%s@\n@\n" x.CalcHooks.ty_decl ) calc_list + end; | MLData { pp_doc } -> Fmt.fprintf fmt "%a@\n" pp_doc () | MLDataC { pp_doc } -> Fmt.fprintf fmt "%a@\n" pp_doc () | LPCode s -> Fmt.fprintf fmt "%s" s; Fmt.fprintf fmt "@\n@\n" @@ -1349,9 +1437,14 @@ module Query = struct | N : unit arguments | D : 'a Conversion.t * 'a * 'x arguments -> 'x arguments | Q : 'a Conversion.t * name * 'x arguments -> ('a * 'x) arguments + type (_,_,_) carguments = + | NC : (unit,'c,'csts) carguments + | DC : ('a,'c,'csts) ContextualConversion.t * 'a * ('x,'c,'csts) carguments -> ('x,'c,'csts) carguments + | QC : ('a,'c,'csts) ContextualConversion.t * name * ('x,'c,'csts) carguments -> ('a * 'x,'c,'csts) carguments type 'x t = | Query of { predicate : constant; arguments : 'x arguments } + | CQuery : constant * ('x,#ContextualConversion.ctx as 'c,'csts) carguments * (State.t -> 'c) * 'csts -> 'x t end @@ -1380,7 +1473,7 @@ type 'a executable = { (* solution *) assignments : term Util.StrMap.t; (* type of the query, reified *) - query_arguments: 'a Query.arguments; + query_adt: 'a Query.t; } type pp_ctx = { diff --git a/src/runtime.ml b/src/runtime.ml index 2226ee0d4..33608a6f5 100644 --- a/src/runtime.ml +++ b/src/runtime.ml @@ -2139,35 +2139,115 @@ let map_acc f s l = in aux [] [] s l -let call (Data.BuiltInPredicate.Pred(bname,ffi,compute)) ~once ~depth hyps constraints state data = - let rec aux : type i o h c. - (i,o,h,c) Data.BuiltInPredicate.ffi -> h -> c -> compute:i -> reduce:(State.t -> o -> State.t * Conversion.extra_goals) -> +let call_pred bname ffi compute ~once ~depth _hyps _constraints state data = + let rec aux : type i o. + (i,o) Data.BuiltInPredicate.ffi -> compute:i -> reduce:(State.t -> o -> State.t * Conversion.extra_goals) -> term list -> int -> State.t -> Conversion.extra_goals list -> State.t * Conversion.extra_goals = - fun ffi ctx constraints ~compute ~reduce data n state extra -> + fun ffi ~compute ~reduce data n state extra -> match ffi, data with + | Data.BuiltInPredicate.Read _, [] -> + let result = wrap_type_err bname 0 (compute ~depth) state in + let state, l = reduce state result in + state, List.(concat (rev extra) @ rev l) + | Data.BuiltInPredicate.Full _, [] -> + let state, result, gls = wrap_type_err bname 0 (compute ~depth) state in + let state, l = reduce state result in + state, List.(concat (rev extra)) @ gls @ List.rev l + | Data.BuiltInPredicate.FullHO _, [] -> + let state, result, gls = wrap_type_err bname 0 (compute ~once ~depth) state in + let state, l = reduce state result in + state, List.(concat (rev extra)) @ gls @ List.rev l | Data.BuiltInPredicate.Easy _, [] -> let result = wrap_type_err bname 0 (fun () -> compute ~depth) () in let state, l = reduce state result in state, List.(concat (rev extra) @ rev l) - | Data.BuiltInPredicate.Read _, [] -> - let result = wrap_type_err bname 0 (compute ~depth ctx constraints) state in - let state, l = reduce state result in - state, List.(concat (rev extra) @ rev l) - | Data.BuiltInPredicate.Full _, [] -> + | Data.BuiltInPredicate.In({ Conversion.readback }, _, ffi), t :: rest -> + let state, i, gls = in_of_term ~depth readback n bname state t in + aux ffi ~compute:(compute i) ~reduce rest (n + 1) state (gls :: extra) + | Data.BuiltInPredicate.Out({ Conversion.embed; readback }, _, ffi), t :: rest -> + let i = out_of_term ~depth readback n bname state t in + let reduce state (rest, out) = + let state, l = reduce state rest in + let state, ass = mk_out_assign ~depth embed bname state i t out in + state, ass @ l in + aux ffi ~compute:(compute i) ~reduce rest (n + 1) state extra + | Data.BuiltInPredicate.InOut({ Conversion.embed; readback }, _, ffi), t :: rest -> + let state, i, gls = inout_of_term ~depth readback n bname state t in + let reduce state (rest, out) = + let state, l = reduce state rest in + let state, ass = mk_inout_assign ~depth embed bname state i t out in + state, ass @ l in + aux ffi ~compute:(compute i) ~reduce rest (n + 1) state (gls :: extra) + | Data.BuiltInPredicate.VariadicIn({ Conversion.readback }, _), data -> + let state, i, gls = + map_acc (in_of_term ~depth readback n bname) state data in + let state, rest = wrap_type_err bname 0 (compute i ~depth) state in + let state, l = reduce state rest in + state, List.(gls @ concat (rev extra) @ rev l) + | Data.BuiltInPredicate.VariadicOut({ Conversion.embed; readback }, _), data -> + let i = List.map (out_of_term ~depth readback n bname state) data in + let state, (rest, out) = wrap_type_err bname 0 (compute i ~depth) state in + let state, l = reduce state rest in + begin match out with + | Some out -> + let state, ass = + map_acc3 (mk_out_assign ~depth embed bname) state i data out in + state, List.(concat (rev extra) @ rev (concat ass) @ l) + | None -> state, List.(concat (rev extra) @ rev l) + end + | Data.BuiltInPredicate.VariadicInOut({ Conversion.embed; readback }, _), data -> + let state, i, gls = + map_acc (inout_of_term ~depth readback n bname) state data in + let state, (rest, out) = wrap_type_err bname 0 (compute i ~depth) state in + let state, l = reduce state rest in + begin match out with + | Some out -> + let state, ass = + map_acc3 (mk_inout_assign ~depth embed bname) state i data out in + state, List.(gls @ concat (rev extra) @ rev (concat ass) @ l) + | None -> state, List.(gls @ concat (rev extra) @ rev l) + end + + | _, t :: _ -> arity_err ~depth bname n (Some t) + | _, [] -> arity_err ~depth bname n None + + in + let reduce state _ = state, [] in + let state, gls = aux ffi ~compute ~reduce data 1 state [] in + state, gls +;; + + + +let call_cpred bname ffi in_ctx compute ~once ~depth hyps constraints state data = + let rec aux : type i o h c. + (i,o,h,c) Data.BuiltInPredicate.cffi -> h -> c -> compute:i -> reduce:(State.t -> o -> State.t * Conversion.extra_goals) -> + term list -> int -> State.t -> Conversion.extra_goals list -> State.t * Conversion.extra_goals = + fun ffi ctx constraints ~compute ~reduce data n state extra -> + match ffi, data with + | Data.BuiltInPredicate.CEasy _, [] -> + let result = wrap_type_err bname 0 (fun () -> compute ~depth ctx constraints) () in + let state, l = reduce state result in + state, List.(concat (rev extra) @ rev l) + | Data.BuiltInPredicate.CRead _, [] -> + let result = wrap_type_err bname 0 (compute ~depth ctx constraints) state in + let state, l = reduce state result in + state, List.(concat (rev extra) @ rev l) + | Data.BuiltInPredicate.CFull _, [] -> let state, result, gls = wrap_type_err bname 0 (compute ~depth ctx constraints) state in let state, l = reduce state result in state, List.(concat (rev extra)) @ gls @ List.rev l - | Data.BuiltInPredicate.FullHO _, [] -> + | Data.BuiltInPredicate.CFullHO _, [] -> let state, result, gls = wrap_type_err bname 0 (compute ~once ~depth ctx constraints) state in let state, l = reduce state result in state, List.(concat (rev extra)) @ gls @ List.rev l - | Data.BuiltInPredicate.VariadicIn(_,{ ContextualConversion.readback }, _), data -> + | Data.BuiltInPredicate.CVariadicIn({ ContextualConversion.readback }, _), data -> let state, i, gls = map_acc (in_of_termC ~depth readback n bname ctx constraints) state data in let state, rest = wrap_type_err bname 0 (compute i ~depth ctx constraints) state in let state, l = reduce state rest in state, List.(gls @ concat (rev extra) @ rev l) - | Data.BuiltInPredicate.VariadicOut(_,{ ContextualConversion.embed; readback }, _), data -> + | Data.BuiltInPredicate.CVariadicOut({ ContextualConversion.embed; readback }, _), data -> let i = List.map (out_of_term ~depth readback n bname state) data in let state, (rest, out) = wrap_type_err bname 0 (compute i ~depth ctx constraints) state in let state, l = reduce state rest in @@ -2178,7 +2258,7 @@ let call (Data.BuiltInPredicate.Pred(bname,ffi,compute)) ~once ~depth hyps const state, List.(concat (rev extra) @ rev (concat ass) @ l) | None -> state, List.(concat (rev extra) @ rev l) end - | Data.BuiltInPredicate.VariadicInOut(_,{ ContextualConversion.embed; readback }, _), data -> + | Data.BuiltInPredicate.CVariadicInOut({ ContextualConversion.embed; readback }, _), data -> let state, i, gls = map_acc (inout_of_termC ~depth readback n bname ctx constraints) state data in let state, (rest, out) = wrap_type_err bname 0 (compute i ~depth ctx constraints) state in @@ -2207,49 +2287,21 @@ let call (Data.BuiltInPredicate.Pred(bname,ffi,compute)) ~once ~depth hyps const let state, ass = mk_inout_assignC ~depth embed bname ctx constraints state i t out in state, ass @ l in aux ffi ctx constraints ~compute:(compute i) ~reduce rest (n + 1) state (gls :: extra) - | Data.BuiltInPredicate.In({ Conversion.readback }, _, ffi), t :: rest -> - let state, i, gls = in_of_term ~depth readback n bname state t in - aux ffi ctx constraints ~compute:(compute i) ~reduce rest (n + 1) state (gls :: extra) - | Data.BuiltInPredicate.Out({ Conversion.embed; readback }, _, ffi), t :: rest -> - let i = out_of_term ~depth readback n bname state t in - let reduce state (rest, out) = - let state, l = reduce state rest in - let state, ass = mk_out_assign ~depth embed bname state i t out in - state, ass @ l in - aux ffi ctx constraints ~compute:(compute i) ~reduce rest (n + 1) state extra - | Data.BuiltInPredicate.InOut({ Conversion.embed; readback }, _, ffi), t :: rest -> - let state, i, gls = inout_of_term ~depth readback n bname state t in - let reduce state (rest, out) = - let state, l = reduce state rest in - let state, ass = mk_inout_assign ~depth embed bname state i t out in - state, ass @ l in - aux ffi ctx constraints ~compute:(compute i) ~reduce rest (n + 1) state (gls :: extra) | _, t :: _ -> arity_err ~depth bname n (Some t) | _, [] -> arity_err ~depth bname n None - in - let rec aux_ctx : type i o h c. (i,o,h,c) Data.BuiltInPredicate.ffi -> (h,c) ContextualConversion.ctx_readback = function - | Data.BuiltInPredicate.FullHO(f,_) -> f - | Data.BuiltInPredicate.Full(f,_) -> f - | Data.BuiltInPredicate.Read(f,_) -> f - | Data.BuiltInPredicate.VariadicIn(f,_,_) -> f - | Data.BuiltInPredicate.VariadicOut(f,_,_) -> f - | Data.BuiltInPredicate.VariadicInOut(f,_,_) -> f - | Data.BuiltInPredicate.Easy _ -> ContextualConversion.unit_ctx - | Data.BuiltInPredicate.In(_,_,rest) -> aux_ctx rest - | Data.BuiltInPredicate.Out(_,_,rest) -> aux_ctx rest - | Data.BuiltInPredicate.InOut(_,_,rest) -> aux_ctx rest - | Data.BuiltInPredicate.CIn(_,_,rest) -> aux_ctx rest - | Data.BuiltInPredicate.COut(_,_,rest) -> aux_ctx rest - | Data.BuiltInPredicate.CInOut(_,_,rest) -> aux_ctx rest in let reduce state _ = state, [] in - let state, ctx, csts, gls_ctx = aux_ctx ffi ~depth hyps constraints state in + let state, ctx, csts, gls_ctx = in_ctx ~depth hyps constraints state in let state, gls = aux ffi ctx csts ~compute ~reduce data 1 state [] in state, gls_ctx @ gls ;; +let call = function + | (Data.BuiltInPredicate.Pred(bname,ffi,compute)) -> call_pred bname ffi compute + | (Data.BuiltInPredicate.CPred(bname,in_ctx,ffi,compute)) -> call_cpred bname ffi in_ctx compute + end let rec embed_query_aux : type a. mk_Arg:(State.t -> name:string -> args:term list -> State.t * term) -> depth:int -> predicate:constant -> Conversion.extra_goals -> term list -> State.t -> a Query.arguments -> State.t * term * Conversion.extra_goals @@ -2266,8 +2318,25 @@ let rec embed_query_aux : type a. mk_Arg:(State.t -> name:string -> args:term li state, C.mkAppL predicate args, gls ;; -let embed_query ~mk_Arg ~depth state (Query.Query { predicate; arguments }) = - embed_query_aux ~mk_Arg ~depth ~predicate [] [] state arguments +let rec embed_cquery_aux : type a csts. mk_Arg:(State.t -> name:string -> args:term list -> State.t * term) -> depth:int -> predicate:constant -> ctx:(#ContextualConversion.ctx as 'c) -> csts:csts -> Conversion.extra_goals -> term list -> State.t -> (a,'c,csts) Query.carguments -> State.t * term * Conversion.extra_goals + = fun ~mk_Arg ~depth ~predicate ~ctx ~csts gls args state descr -> + match descr with + | Data.Query.DC(d,x,rest) -> + let state, x, glsx = d.ContextualConversion.embed ~depth ctx csts state x in + embed_cquery_aux ~mk_Arg ~depth ~predicate ~ctx ~csts (gls @ glsx) (x :: args) state rest + | Data.Query.QC(d,name,rest) -> + let state, x = mk_Arg state ~name ~args:[] in + embed_cquery_aux ~mk_Arg ~depth ~predicate ~ctx ~csts gls (x :: args) state rest + | Data.Query.NC -> + let args = List.rev args in + state, C.mkAppL predicate args, gls +;; + +let embed_query ~mk_Arg ~depth state = function + | Query.Query { predicate; arguments } -> + embed_query_aux ~mk_Arg ~depth ~predicate [] [] state arguments + | Query.CQuery (predicate, arguments, ctx, csts) -> + embed_cquery_aux ~mk_Arg ~depth ~predicate ~ctx:(ctx state) ~csts [] [] state arguments let rec query_solution_aux : type a. a Query.arguments -> term StrMap.t -> State.t -> a = fun args assignments state -> @@ -2279,8 +2348,21 @@ let rec query_solution_aux : type a. a Query.arguments -> term StrMap.t -> State let state, x, _gls = d.Conversion.readback ~depth:0 state x in x, query_solution_aux args assignments state -let output arguments assignments state = - query_solution_aux arguments assignments state +let rec cquery_solution_aux : type a csts. (a,#ContextualConversion.ctx as 'c,csts) Query.carguments -> term StrMap.t -> State.t -> 'c -> csts -> a += fun args assignments state ctx csts -> + match args with + | Data.Query.NC -> () + | Data.Query.DC(_,_,args) -> cquery_solution_aux args assignments state ctx csts + | Data.Query.QC(d,name,args) -> + let x = StrMap.find name assignments in + let state, x, _gls = d.ContextualConversion.readback ~depth:0 ctx csts state x in + x, cquery_solution_aux args assignments state ctx csts + + +let output query assignments state = + match query with + | Query.Query { arguments; _ } -> query_solution_aux arguments assignments state + | Query.CQuery (_,arguments,c,csts) -> cquery_solution_aux arguments assignments state (c state) csts (****************************************************************************** Indexing @@ -3429,7 +3511,7 @@ let try_fire_rule (gid[@trace]) rule (constraints as orig_constraints) = assignments = StrMap.empty; initial_depth = max_depth; initial_runtime_state = !CS.initial_state; - query_arguments = Query.N; + query_adt = Query.(Query { predicate = 0; arguments = N } ); symbol_table = !C.table; builtins = !FFI.builtins; } in @@ -3831,7 +3913,7 @@ let make_runtime : ?max_steps: int -> ?delay_outside_fragment: bool -> 'x execut assignments = StrMap.empty; initial_depth = depth; initial_runtime_state = !CS.initial_state; - query_arguments = Query.N; + query_adt = Query.(Query { predicate = 0; arguments = N }); symbol_table = !C.table; builtins = !FFI.builtins; } in @@ -4036,7 +4118,7 @@ let mk_outcome search get_cs assignments depth = let execute_once ?max_steps ?delay_outside_fragment exec = let { search; get } = make_runtime ?max_steps ?delay_outside_fragment exec in try - let result = fst (mk_outcome search (fun () -> get CS.Ugly.delayed, (exec.initial_depth,get CS.state), get CS.state |> State.end_execution, exec.query_arguments, { Data.uv_names = ref (get Pp.uv_names); table = get C.table }) exec.assignments exec.initial_depth) in + let result = fst (mk_outcome search (fun () -> get CS.Ugly.delayed, (exec.initial_depth,get CS.state), get CS.state |> State.end_execution, exec.query_adt, { Data.uv_names = ref (get Pp.uv_names); table = get C.table }) exec.assignments exec.initial_depth) in [%end_trace "execute_once" ~rid]; result with e -> @@ -4050,7 +4132,7 @@ let execute_loop ?delay_outside_fragment exec ~more ~pp = let k = ref noalts in let do_with_infos f = let time0 = Unix.gettimeofday() in - let o, alts = mk_outcome f (fun () -> get CS.Ugly.delayed, (exec.initial_depth,get CS.state), get CS.state |> State.end_execution, exec.query_arguments, { Data.uv_names = ref (get Pp.uv_names); table = get C.table }) exec.assignments exec.initial_depth in + let o, alts = mk_outcome f (fun () -> get CS.Ugly.delayed, (exec.initial_depth,get CS.state), get CS.state |> State.end_execution, exec.query_adt, { Data.uv_names = ref (get Pp.uv_names); table = get C.table }) exec.assignments exec.initial_depth in let time1 = Unix.gettimeofday() in k := alts; pp (time1 -. time0) o in diff --git a/src/trace_atd.ts b/src/trace_atd.ts index 8d248245d..7bf7fa827 100644 --- a/src/trace_atd.ts +++ b/src/trace_atd.ts @@ -1,22 +1,18 @@ -/* - Generated by atdts from type definitions in 'trace.atd'. +// Generated by atdts from type definitions in 'trace.atd'. +// +// Type-safe translations from/to JSON +// +// For each type 'Foo', there is a pair of functions: +// - 'writeFoo': convert a 'Foo' value into a JSON-compatible value. +// - 'readFoo': convert a JSON-compatible value into a TypeScript value +// of type 'Foo'. - Type-safe translations from/to JSON - - For each type 'Foo', there is a pair of functions: - - 'writeFoo': convert a 'Foo' value into a JSON-compatible value. - - 'readFoo': convert a JSON-compatible value into a TypeScript value - of type 'Foo'. -*/ - -/* tslint:disable */ -/* eslint-disable */ export type Item = { kind: Kind[]; - goal_id: number /*int*/; - runtime_id: number /*int*/; - step: number /*int*/; + goal_id: Int; + runtime_id: Int; + step: Int; name: string; payload: string[]; } @@ -93,9 +89,9 @@ export type Location = export type FileLocation = { filename: string; - line: number /*int*/; - column: number /*int*/; - character: number /*int*/; + line: Int; + column: Int; + character: Int; } export type Event = @@ -128,11 +124,11 @@ export type Frame = { runtime_id: RuntimeId; } -export type GoalId = number /*int*/ +export type GoalId = Int -export type StepId = number /*int*/ +export type StepId = Int -export type RuntimeId = number /*int*/ +export type RuntimeId = Int export type GoalText = string @@ -790,6 +786,8 @@ export function readChrText(x: any, context: any = x): ChrText { // Runtime library ///////////////////////////////////////////////////////////////////// +export type Int = number + export type Option = null | { value: T } function _atd_missing_json_field(type_name: string, json_field_name: string) { @@ -822,7 +820,7 @@ function _atd_bad_ts(expected_type: string, ts_value: any, context: any) { ` Occurs in '${JSON.stringify(context)}'.`) } -function _atd_check_json_tuple(len: number /*int*/, x: any, context: any) { +function _atd_check_json_tuple(len: Int, x: any, context: any) { if (! Array.isArray(x) || x.length !== len) _atd_bad_json('tuple of length ' + len, x, context); } @@ -845,7 +843,7 @@ function _atd_read_bool(x: any, context: any): boolean { } } -function _atd_read_int(x: any, context: any): number /*int*/ { +function _atd_read_int(x: any, context: any): Int { if (Number.isInteger(x)) return x else { @@ -1026,7 +1024,7 @@ function _atd_write_bool(x: any, context: any): boolean { } } -function _atd_write_int(x: any, context: any): number /*int*/ { +function _atd_write_int(x: any, context: any): Int { if (Number.isInteger(x)) return x else { @@ -1135,7 +1133,7 @@ function _atd_write_required_field(type_name: string, } function _atd_write_optional_field(write_elt: (x: T, context: any) => any, - x: T | undefined, + x: T, context: any): any { if (x === undefined || x === null) return x diff --git a/src/utils/util.ml b/src/utils/util.ml index f40e4074e..b062d7f2d 100644 --- a/src/utils/util.ml +++ b/src/utils/util.ml @@ -340,11 +340,77 @@ module Pair = struct let show poly_a poly_b x = Format.asprintf "@[%a@]" (pp poly_a poly_b) x end + +module Triple = struct + + let pp poly_a poly_b poly_c fmt x = + let (x0, x1, x2) = x in + Format.pp_open_box fmt 1; + Format.pp_print_string fmt "("; + Format.pp_open_box fmt 0; + poly_a fmt x0; + Format.pp_close_box fmt (); + Format.pp_print_string fmt ","; + Format.pp_print_space fmt (); + Format.pp_open_box fmt 0; + poly_b fmt x1; + Format.pp_close_box fmt (); + Format.pp_print_string fmt ","; + Format.pp_print_space fmt (); + Format.pp_open_box fmt 0; + poly_c fmt x2; + Format.pp_close_box fmt (); + Format.pp_print_string fmt ")"; + Format.pp_close_box fmt () + + let show poly_a poly_b poly_c x = + Format.asprintf "@[%a@]" (pp poly_a poly_b poly_c) x +end + +module Quadruple = struct + + let pp poly_a poly_b poly_c poly_d fmt x = + let (x0, x1, x2, x3) = x in + Format.pp_open_box fmt 1; + Format.pp_print_string fmt "("; + Format.pp_open_box fmt 0; + poly_a fmt x0; + Format.pp_close_box fmt (); + Format.pp_print_string fmt ","; + Format.pp_print_space fmt (); + Format.pp_open_box fmt 0; + poly_b fmt x1; + Format.pp_close_box fmt (); + Format.pp_print_string fmt ","; + Format.pp_print_space fmt (); + Format.pp_open_box fmt 0; + poly_c fmt x2; + Format.pp_close_box fmt (); + Format.pp_print_string fmt ","; + Format.pp_print_space fmt (); + Format.pp_open_box fmt 0; + poly_d fmt x3; + Format.pp_close_box fmt (); + Format.pp_print_string fmt ")"; + Format.pp_close_box fmt () + + let show poly_a poly_b poly_c poly_d x = + Format.asprintf "@[%a@]" (pp poly_a poly_b poly_c poly_d) x +end + + + + let pp_option f fmt = function None -> () | Some x -> f fmt x let pp_int = Int.pp let pp_string = String.pp let pp_pair = Pair.pp let show_pair = Pair.show +let pp_triple = Triple.pp +let show_triple = Triple.show +let pp_quadruple = Quadruple.pp +let show_quadruple = Quadruple.show + let remove_from_list x = let rec aux acc = diff --git a/src/utils/util.mli b/src/utils/util.mli index bf5c5ec5f..4a6a77677 100644 --- a/src/utils/util.mli +++ b/src/utils/util.mli @@ -174,6 +174,32 @@ val show_pair : (Format.formatter -> 'b -> unit) -> ('a * 'b) -> string +val pp_triple : + (Format.formatter -> 'a -> unit) -> + (Format.formatter -> 'b -> unit) -> + (Format.formatter -> 'c -> unit) -> + Format.formatter -> 'a * 'b * 'c -> unit +val show_triple : + (Format.formatter -> 'a -> unit) -> + (Format.formatter -> 'b -> unit) -> + (Format.formatter -> 'c -> unit) -> + ('a * 'b * 'c) -> string + +val pp_quadruple : + (Format.formatter -> 'a -> unit) -> + (Format.formatter -> 'b -> unit) -> + (Format.formatter -> 'c -> unit) -> + (Format.formatter -> 'd -> unit) -> + Format.formatter -> 'a * 'b * 'c * 'd -> unit +val show_quadruple : + (Format.formatter -> 'a -> unit) -> + (Format.formatter -> 'b -> unit) -> + (Format.formatter -> 'c -> unit) -> + (Format.formatter -> 'd -> unit) -> + ('a * 'b * 'c * 'd) -> string + + + (* for open types *) type 'a spaghetti_printer val mk_spaghetti_printer : unit -> 'a spaghetti_printer @@ -275,4 +301,4 @@ end (* file access *) val std_resolver : ?cwd:string -> paths:string list -> unit -> - (?cwd:string -> unit:string -> unit -> string) \ No newline at end of file + (?cwd:string -> unit:string -> unit -> string)