]
% (RawEvar x1 x2) ( x1 x2) (Ev x1 x2)
%
% where, by default, declare-evar creates a syntactic constraint as
%
% {x1 x2} :
% decl x1 `x` , def x2 `y` x1 ?-
% evar (RawEvar x1 x2) ( x1 x2) (Ev x1 x2) /* suspended on RawEvar, Ev */
%
% When the program is over, a remaining syntactic constraint like the one above
% is read back and transformed into the corresponding evar_info.
pred decl i:term, o:name, o:term. % Var Name Ty
pred def i:term, o:name, o:term, o:term. % Var Name Ty Bo
pred declare-evar i:list prop, i:term, i:term, i:term. % Ctx RawEvar Ty Evar
:name "default-declare-evar"
declare-evar Ctx RawEv Ty Ev :-
declare_constraint (declare-evar Ctx RawEv Ty Ev) [RawEv].
% When a goal (evar _ _ _) is turned into a constraint the context is filtered
% to only contain decl, def, pp. For now no handling rules for this set of
% constraints other than one to remove a constraint
pred rm-evar i:term, i:term.
rm-evar (uvar as X) (uvar as Y):- !, declare_constraint (rm-evar X Y) [X,Y].
rm-evar _ _.
constraint declare-evar evar def decl cache rm-evar {
% Override the actual context
rule \ (declare-evar Ctx RawEv Ty Ev) <=> (Ctx => evar RawEv Ty Ev).
rule \ (rm-evar (uvar X _) (uvar Y _)) (evar (uvar X _) _ (uvar Y _)).
rule \ (rm-evar (uvar X _) (uvar Y _)).
}
% The (evar R Ty E) predicate suspends when R and E are flexible,
% and is solved otherwise.
% The client may want to provide an alternative implementation of
% the clause "default-assign-evar", for example to typechecks that the
% term assigned to E has type Ty, or that the term assigned to R
% elaborates to a term of type Ty that gets assigned to E.
% In tactic mode, elpi/coq-elaborator.elpi wires things up that way.
pred evar i:term, i:term, o:term. % Evar Ty RefinedSolution
evar (uvar as X) T S :- var S _ VL, !,
prune T VL, prune X VL, declare_constraint (evar X T S) [X, S].
:name "default-assign-evar"
evar _ _ _. % volatile, only unresolved evars are considered as evars
% To ease the creation of a context with decl and def
% Eg. @pi-decl `x` x1\ @pi-def `y` y\ ...
macro @pi-decl N T F :- pi x\ decl x N T => F x.
macro @pi-def N T B F :- pi x\ def x N T B => cache x B_ => F x.
macro @pi-parameter ID T F :-
sigma N\ (coq.id->name ID N, pi x\ decl x N T => F x).
macro @pi-inductive ID A F :-
sigma N\ (coq.id->name ID N, coq.arity->term A T, pi x\ decl x N T => F x).
% Sometimes it can be useful to pass to Coq a term with unification variables
% representing "untyped holes" like an implicit argument _. In particular
% a unification variable may exit the so called pattern fragment (applied
% to distinct variables) and hence cannot be reliably mapped to Coq as an evar,
% but can still be considered as an implicit argument.
% By loading in the context get-option "HOAS:holes" tt one forces that
% behavior. Here a convenience macro to be put on the LHS of =>
macro @holes! :- get-option "HOAS:holes" tt.
% Similarly, some APIs take a term skeleton in input. In that case unification
% variables are totally disregarded (not even mapped to Coq evars). They are
% interpreted as the {{ lib:elpi.hole }} constant, which represents an implicit
% argument. As a consenque these APIs don't modify the input term at all, but
% rather return a copy. Note that if {{ lib:elpi.hole }} is used directly, then
% it has to be applied to all variables in scope, since Coq erases variables
% that are not used. For example using {{ forall x : nat, lib:elpi.hole }} as
% a term skeleton is equivalent to {{ nat -> lib:elpi.hole }}, while
% {{ forall x : nat, lib:elpi.hole x lib:elpi.hole more args }} puts x in
% the scope of the hole (and passes to is more args).
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Coq's goals and tactic invocation
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% A Coq goal is essentially a sequent, like the evar_info above, but since it
% has to be manipulated as first class Elpi data, it is represented in a slightly
% different way. For example
%
% x : t
% y := v : x
% ----------
% g x y
%
% is represented by the following term of type sealed-goal
%
% nabla x1\
% nabla x2\
% seal
% (goal
% [def x2 `y` x1 , decl x1 `x` ]
% (RawEvar x1 x2) ( x1 x2) (Evar x1 x2)
% (Arguments x1 x2))
kind goal type.
kind sealed-goal type.
type nabla (term -> sealed-goal) -> sealed-goal.
type seal goal -> sealed-goal.
typeabbrev goal-ctx (list prop).
type goal goal-ctx -> term -> term -> term -> list argument -> goal.
% A sealed-goal closes with nabla the bound names of a
%
% (goal Ctx RawSolution Ty Solution Arguments)
%
% where Ctx is a list of decl or def and Solution is a unification variable
% to be assigned to a term of type Ty in order to make progress.
% RawSolution is used as a trigger: when a term is assigned to it, it is
% elaborated against Ty and the resulting term is assigned to Solution.
%
% Arguments contains data attached to the goal, which lives in its context
% and can be used by tactics to solve the goals.
% A tactic (an elpi predicate which makes progress on a Coq goal) is
% a predicate of type
% sealed-goal -> list sealed-goal -> prop
%
% while the main entry point for a tactic written in Elpi is solve
% which has type
% goal -> list sealed-goal -> prop
%
% The utility (coq.ltac.open T G GL) postulates all the variables bounds
% by nabla and loads the goal context before calling T on the unsealed
% goal. The invocation of a tactic with arguments
% 3 x "y" (h x)
% on the previous goal results in the following Elpi query:
%
% (pi x1\ decl x1 `x` =>
% pi x2\ def x2 `y` x1 =>
% declare-evar
% [def x2 `y` x1 , decl x1 `x` ]
% (RawEvar x1 x2) ( x1 x2) (Evar x1 x2)),
% (coq.ltac.open solve
% (nabla x1\ nabla x2\ seal
% (goal
% [def x2 `y` x1 , decl x1 `x` ]
% (RawEvar x1 x2) ( x1 x2) (Evar x1 x2)
% [int 3, str `x`, str`y`, trm (app[const `h`,x1])]))
% NewGoals)
%
% If the goal sequent contains other evars, then a tactic invocation is
% an Elpi query made of the conjunction of all the declare-evar queries
% corresponding to these evars and the query corresponding to the goal
% sequent. NewGoals can be assigned to a list of goals that should be
% declared as open. Omitted goals are shelved. If NewGoals is not
% assigned, then all unresolved evars become new goals, but the order
% of such goals is not specified.
% The file elpi-ltac.elpi provides a few combinators (other than coq.ltac.open)
% in the tradition of LCF tacticals. The main difference is that the arguments
% of custom written tactics must not be passed as predicate arguments but rather
% put in the goal they receive. Indeed these arguments can contain terms, and
% their bound variables cannot escape the seal. coq.ltac.set-goal-arguments
% can be used to put an argument from the current goal context into another
% goal. The coq.ltac.call utility can call Ltac1 code (written in Coq) and
% pass arguments via this mechanism.
% Last, since Elpi is alerady a logic programming language with primitive
% support for unification variables, most of the work of a tactic can be
% performed without using tacticals (which work on sealed goals) but rather
% in the context of the original goal. The last step is typically to call
% the refine utility with a term synthesized by the tactic or invoke some
% Ltac1 code on that term (e.g. to call vm_compute, see also the example
% on the reflexive tactic).
% ----- Multi goals tactics. ----
% Coq provides goal selectors, such as all:, to pass to a tactic more than one
% goal. In order to write such a tactic, Coq-Elpi provides another entry point
% called msolve. To be precise, if there are two goals under focus, say and
% , then all: elpi tac runs the following query
%
% msolve [,] NewGoals ; % note the disjunction
% coq.ltac.all (coq.ltac.open solve) [,] NewGoals
%
% So, if msolve has no clause, Coq-Elpi will use solve on all the goals
% independently. If msolve has a cluse, then it can manipulate the entire list
% of sealed goals. Note that the argument is in both and but
% it is interpreted in both contexts independently. If both goals have a proof
% variable named "x" then passing (@eq_refl _ x) as equips both goals with
% a (raw) proof that "x = x", no matter what their type is.
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Declarations for Coq's API (environment read/write access, etc).
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% tt = Yes, ff = No, unspecified = No (unspecified means "_" or a variable).
typeabbrev opaque? bool. macro @opaque! :- tt. macro @transparent! :- ff.
%%%%%%% Attributes to be passed to APIs as in @local! => coq.something %%%%%%%%
macro @global! :- get-option "coq:locality" "global".
macro @local! :- get-option "coq:locality" "local".
macro @primitive! :- get-option "coq:primitive" tt. % primitive records
macro @reversible! :- get-option "coq:reversible" tt. % coercions
macro @no-tc! :- get-option "coq:no_tc" tt. % skip typeclass inference
macro @uinstance! I :- get-option "coq:uinstance" I. % universe instance
% declaration of universe polymorphic constants
% The first list is the one of the unvierse variables being bound
% The first boolean is tt if this list can be extended by Coq (or it has to
% mention all universes actually used)
% The second list if the one with the constaints amond where universes
% The second boolean is tt if this list can be extended by Coq or it has to
% mention all universe constraints actually required to type check the
% declaration)
macro @udecl! Vs LV Cs LC :- get-option "coq:udecl" (upoly-decl Vs LV Cs LC).
macro @udecl-cumul! Vs LV Cs LC :- get-option "coq:udecl-cumul" (upoly-decl-cumul Vs LV Cs LC).
macro @univpoly! :- @udecl! [] tt [] tt.
macro @univpoly-cumul! :- @udecl-cumul! [] tt [] tt.
macro @ppwidth! N :- get-option "coq:ppwidth" N. % printing width
macro @ppall! :- get-option "coq:pp" "all". % printing all
macro @ppmost! :- get-option "coq:pp" "most". % printing most of contents
macro @pplevel! N :- get-option "coq:pplevel" N. % printing precedence (for parentheses)
macro @keepunivs! :- get-option "coq:keepunivs" tt. % skeletons elaboration
macro @dropunivs! :- get-option "coq:keepunivs" ff. % add-indt/add-const
macro @using! S :- get-option "coq:using" S. % like the #[using=S] attribute
macro @inline-at! N :- get-option "coq:inline" (coq.inline.at N). % like Inline(N)
macro @inline! N :- get-option "coq:inline" coq.inline.default. % like
macro @redflags! F :- get-option "coq:redflags" F. % for whd & co
% both arguments are strings eg "8.12.0" "use foo instead"
macro @deprecated! Since Msg :-
get-option "coq:deprecated" (pr Since Msg).
macro @ltacfail! N :- get-option "ltac:fail" N.
% Declaration of inductive types %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
kind indt-decl type.
kind indc-decl type.
kind record-decl type.
% An arity is written, in Coq syntax, as:
% (x : T1) .. (xn : Tn) : S1 -> ... -> Sn -> U
% This syntax is used, for example, in the type of an inductive type or
% in the type of constructors. We call the abstractions on the left of ":"
% "parameters" while we call the type following the ":" (proper) arity.
% Note: in some contexts, like the type of an inductive type constructor,
% Coq makes no distinction between these two writings
% (xn : Tn) : forall y1 : S1, ... and (xn : Tn) (y1 : S1) : ...
% while Elpi is a bit more restrictive, since it understands user directives
% such as the implicit status of an arguments (eg, using {} instead of () around
% the binder), only on parameters.
% Moreover parameters carry the name given by the user as an "id", while binders
% in terms only carry it as a "name", an irrelevant pretty pringintg hint (see
% also the HOAS of terms). A user command can hence only use the names of
% parameters, and not the names of "forall" quantified variables in the arity.
%
% See also the arity->term predicate in coq-lib.elpi
type parameter id -> implicit_kind -> term -> (term -> arity) -> arity.
type arity term -> arity.
type parameter id -> implicit_kind -> term -> (term -> indt-decl) -> indt-decl.
type inductive id -> bool -> arity -> (term -> list indc-decl) -> indt-decl. % tt means inductive, ff coinductive
type record id -> term -> id -> record-decl -> indt-decl.
type constructor id -> arity -> indc-decl.
type field field-attributes -> id -> term -> (term -> record-decl) -> record-decl.
type end-record record-decl.
% Example.
% Remark that A is a regular parameter; y is a non-uniform parameter and t
% also features an index of type bool.
%
% Inductive t (A : Type) | (y : nat) : bool -> Type :=
% | K1 (x : A) {n : nat} : S n = y -> t A n true -> t A y true
% | K2 : t A y false
%
% is written
%
% (parameter "A" explicit {{ Type }} a\
% inductive "t" tt (parameter "y" explicit {{ nat }} _\
% arity {{ bool -> Type }})
% t\
% [ constructor "K1"
% (parameter "y" explicit {{ nat }} y\
% (parameter "x" explicit a x\
% (parameter "n" maximal {{ nat }} n\
% arity {{ S lp:n = lp:y -> lp:t lp:n true -> lp:t lp:y true }})))
% , constructor "K2"
% (parameter "y" explicit {{ nat }} y\
% arity {{ lp:t lp:y false }}) ])
%
% Remark that the uniform parameters are not passed to occurrences of t, since
% they never change, while non-uniform parameters are both abstracted
% in each constructor type and passed as arguments to t.
%
% The coq.typecheck-indt-decl API can be used to fill in implicit arguments
% an infer universe constraints in the declaration above (e.g. the hidden
% argument of "=" in the arity of K1).
%
% Note: when and inductive type declaration is passed as an argument to an
% Elpi command non uniform parameters must be separated from the uniform ones
% with a | (a syntax introduced in Coq 8.12 and accepted by coq-elpi since
% version 1.4, in Coq this separator is optional, but not in Elpi).
% Context declaration (used as an argument to Elpi commands)
kind context-decl type.
% Eg. (x : T) or (x := B), body is optional, type may be a variable
type context-item id -> implicit_kind -> term -> option term -> (term -> context-decl) -> context-decl.
type context-end context-decl.
typeabbrev field-attributes (list field-attribute).
% retrocompatibility macro for Coq v8.10
macro @coercion! :- [coercion reversible].
% Attributes for a record field. Can be left unspecified, see defaults
% below.
kind field-attribute type.
type coercion coercion-status -> field-attribute. % default off
type canonical bool -> field-attribute. % default true, if field is named
% Status of a record field w.r.t. coercions
kind coercion-status type.
type regular coercion-status.
type reversible coercion-status.
type off coercion-status.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% builtins %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This section contains the API to access Coq
% The marker *E* means *experimental*, i.e. use at your own risk, it may change
% substantially or even disappear in future versions.
% -- Misc ---------------------------------------------------------
% [coq.info ...] Prints an info message
external type coq.info variadic any prop.
% [coq.notice ...] Prints a notice message
external type coq.notice variadic any prop.
% [coq.say ...] Prints a notice message
external type coq.say variadic any prop.
% [coq.warn ...] Prints a generic warning message
external type coq.warn variadic any prop.
% [coq.warning Category Name ...]
% Prints a warning message with a Name and Category which can be used
% to silence this warning or turn it into an error. See coqc -w command
% line option
external type coq.warning string -> string -> variadic any prop.
% [coq.error ...] Prints and *aborts* the program. It is a fatal error for
% Elpi and Ltac
external type coq.error variadic any prop.
% [coq.version VersionString Major Minor Patch] Fetches the version of Coq,
% as a string and as 3 numbers
external pred coq.version o:string, o:int, o:int, o:int.
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% API for objects belonging to the logic
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% -- Environment: names -----------------------------------------------
% To make the API more precise we use different data types for the names
% of global objects.
% Note: [ctype \"bla\"] is an opaque data type and by convention it is
% written [@bla].
% Global constant name
typeabbrev constant (ctype "constant").
% Inductive type name
typeabbrev inductive (ctype "inductive").
% Inductive constructor name
typeabbrev constructor (ctype "constructor").
% Global objects: inductive types, inductive constructors, definitions
kind gref type.
type const constant -> gref. % Nat.add, List.append, ...
type indt inductive -> gref. % nat, list, ...
type indc constructor -> gref. % O, S, nil, cons, ...
% [id] is a name that matters, we piggy back on Elpi's strings.
% Note: [name] is a name that does not matter.
typeabbrev id string.
% Name of a module /*E*/
typeabbrev modpath (ctype "modpath").
% Name of a module type /*E*/
typeabbrev modtypath (ctype "modtypath").
% -- Environment: read ------------------------------------------------
% Note: The type [term] is defined in coq-HOAS.elpi
% Result of coq.locate-all
kind located type.
type loc-gref gref -> located.
type loc-modpath modpath -> located.
type loc-modtypath modtypath -> located.
type loc-abbreviation abbreviation -> located.
% [coq.locate-all Name Located] finds all possible meanings of a string.
% Does not fail.
external pred coq.locate-all i:id, o:list located.
% [coq.locate Name GlobalReference] locates a global definition, inductive
% type or constructor via its name.
% It unfolds syntactic notations, e.g. "Notation old_name := new_name."
% It undestands qualified names, e.g. "Nat.t".
% It understands Coqlib Registered names using the "lib:" prefix,
% eg "lib:core.bool.true".
% It's a fatal error if Name cannot be located.
external pred coq.locate i:id, o:gref.
% [coq.env.typeof GR Ty] reads the type Ty of a global reference.
% Supported attributes:
% - @uinstance! I (default: fresh instance I)
external pred coq.env.typeof i:gref, o:term.
% [coq.env.global GR T] turns a global reference GR into a term, or
% viceversa.
% T = (global GR) or, if GR points to a universe polymorphic term,
% T = (pglobal GR I).
% Supported attributes:
% - @uinstance! I (default: fresh instance I)
external pred coq.env.global o:gref, o:term.
external pred coq.env.indt % reads the inductive type declaration for the environment.
% Supported attributes:
% - @uinstance! I (default: fresh instance I)
i:inductive, % reference to the inductive type
o:bool, % tt if the type is inductive (ff for co-inductive)
o:int, % number of parameters
o:int, % number of parameters that are uniform (<= parameters)
o:term, % type of the inductive type constructor including parameters
o:list constructor, % list of constructor names
o:list term. % list of the types of the constructors (type of KNames) including parameters
external pred coq.env.indt-decl % reads the inductive type declaration for the environment.
% Supported attributes:
% - @uinstance! I (default: fresh instance I)
i:inductive, % reference to the inductive type
o:indt-decl. % HOAS description of the inductive type
% [coq.env.indc->indt K I N] finds the inductive I to which constructor K
% belongs and its position N among the other constructors
external pred coq.env.indc->indt i:constructor, o:inductive, o:int.
% [coq.env.indc GR ParamNo UnifParamNo Kno Ty] reads the type Ty of an
% inductive constructor GR, as well as
% the number of parameters ParamNo and uniform parameters
% UnifParamNo and the number of the constructor Kno (0 based).
% Supported attributes:
% - @uinstance! I (default: fresh instance I)
external pred coq.env.indc i:constructor, o:int, o:int, o:int, o:term.
% [coq.env.informative? Ind] Checks if Ind is informative, that is, if
% it can be eliminated to build a Type. Inductive types in Type
% are
% informative, as well a singleton types in Prop (which are
% regarded as not non-informative).
external pred coq.env.informative? i:inductive.
% [coq.env.record? Ind PrimProjs] checks if Ind is a record (PrimProjs = tt
% if Ind has primitive projections)
external pred coq.env.record? i:inductive, o:bool.
% [coq.env.recursive? Ind] checks if Ind is recursive
external pred coq.env.recursive? i:inductive.
% [coq.env.opaque? GR] checks if GR is an opaque constant
external pred coq.env.opaque? i:constant.
% [coq.env.univpoly? GR PolyArity] checks if GR is universe polymorphic and
% if so returns the number of universe variables
external pred coq.env.univpoly? i:gref, o:int.
% [coq.env.const GR Bo Ty] reads the type Ty and the body Bo of constant
% GR.
% Opaque constants have Bo = none.
% Supported attributes:
% - @uinstance! I (default: fresh instance I)
external pred coq.env.const i:constant, o:option term, o:term.
% [coq.env.const-body GR Bo] reads the body of a constant, even if it is
% opaque.
% If such body is none, then the constant is a true axiom.
% Supported attributes:
% - @uinstance! I (default: fresh instance I)
external pred coq.env.const-body i:constant, o:option term.
% [coq.env.primitive? GR] tests if GR is a primitive constant (like uin63
% addition) or a primitive type (like uint63)
external pred coq.env.primitive? i:constant.
% [coq.locate-module ModName ModPath] locates a module. It's a fatal error
% if ModName cannot be located. *E*
external pred coq.locate-module i:id, o:modpath.
% [coq.locate-module-type ModName ModPath] locates a module. It's a fatal
% error if ModName cannot be located. *E*
external pred coq.locate-module-type i:id, o:modtypath.
% Contents of a module
kind module-item type.
type submodule modpath -> list module-item -> module-item.
type module-type modtypath -> module-item.
type gref gref -> module-item.
type module-functor modpath -> list modtypath -> module-item.
type module-type-functor modtypath -> list modtypath -> module-item.
% [coq.env.module MP Contents] lists the contents of a module (recurses on
% submodules) *E*
external pred coq.env.module i:modpath, o:list module-item.
% [coq.env.module-type MTP Entries] lists the items made visible by module
% type (does not recurse on submodules) *E*
external pred coq.env.module-type i:modtypath, o:list id.
% [coq.env.section GlobalObjects] lists the global objects that are marked
% as to be abstracted at the end of the enclosing sections
external pred coq.env.section o:list constant.
% [coq.env.dependencies GR MP Deps] Computes the direct dependencies of GR.
% If MP is given, Deps only contains grefs from that module
external pred coq.env.dependencies i:gref, i:modpath, o:coq.gref.set.
% [coq.env.transitive-dependencies GR MP Deps] Computes the transitive
% dependencies of GR. If MP is given, Deps only contains grefs from that
% module
external pred coq.env.transitive-dependencies i:gref, i:modpath,
o:coq.gref.set.
% [coq.env.term-dependencies T S] Computes all the grefs S occurring in the
% term T
external pred coq.env.term-dependencies i:term, o:coq.gref.set.
% [coq.env.current-path Path] lists the current module path
external pred coq.env.current-path o:list string.
% [coq.env.current-section-path Path] lists the current section path
external pred coq.env.current-section-path o:list string.
% Deprecated, use coq.env.opaque?
pred coq.env.const-opaque? i:constant.
coq.env.const-opaque? C :-
coq.warning "elpi.deprecated" "elpi.const-opaque" "use coq.env.opaque? in place of coq.env.const-opaque?",
coq.env.opaque? C.
% Deprecated, use coq.env.primitive?
pred coq.env.const-primitive? i:constant.
coq.env.const-primitive? C :-
coq.warning "elpi.deprecated" "elpi.const-primitive" "use coq.env.primitive? in place of coq.env.const-primitive?",
coq.env.primitive? C.
% -- Environment: write -----------------------------------------------
% Note: (monomorphic) universe constraints are taken from ELPI's
% constraints store. Use coq.univ-* in order to add constraints (or any
% higher level facility as coq.typecheck). Load in the context attributes
% such as @univpoly!, @univpoly-cumul!, @udecl! or @udecl-cumul! in order to
% declare universe polymorphic constants or inductives.
% [coq.env.add-const Name Bo Ty Opaque C] Declare a new constant: C gets a
% constant derived from Name
% and the current module; Ty can be left unspecified and in that case
% the
% inferred one is taken (as in writing Definition x := t); Bo can be
% left
% unspecified and in that case an axiom is added (or a section variable,
% if a section is open and @local! is used). Omitting the body and the type
% is
% an error. Note: using this API for declaring an axiom or a section
% variable is
% deprecated, use coq.env.add-axiom or coq.env.add-section-variable
% instead.
% Supported attributes:
% - @local! (default: false)
% - @using! (default: section variables actually used)
% - @univpoly! (default unset)
% - @udecl! (default unset)
% - @dropunivs! (default: false, drops all universe constraints from the
% store after the definition)
%
external pred coq.env.add-const i:id, i:term, i:term, i:opaque?,
o:constant.
% [coq.env.add-axiom Name Ty C] Declare a new axiom: C gets a constant
% derived from Name
% and the current module.
% Supported attributes:
% - @local! (default: false)
% - @univpoly! (default unset)
% - @using! (default: section variables actually used)
% - @inline! (default: no inlining)
% - @inline-at! N (default: no inlining)
external pred coq.env.add-axiom i:id, i:term, o:constant.
% [coq.env.add-section-variable Name Ty C] Declare a new section variable: C
% gets a constant derived from Name
% and the current module
external pred coq.env.add-section-variable i:id, i:term, o:constant.
% [coq.env.add-indt Decl I] Declares an inductive type.
% Supported attributes:
% - @dropunivs! (default: false, drops all universe constraints from the
% store after the definition)
% - @primitive! (default: false, makes records primitive)
external pred coq.env.add-indt i:indt-decl, o:inductive.
% Interactive module construction
% Coq Module inline directive
kind coq.inline type.
type coq.inline.no coq.inline. % Coq's [no inline] (aka !)
type coq.inline.default coq.inline. % The default, can be omitted
type coq.inline.at int -> coq.inline. % Coq's [inline at ]
% [coq.env.fresh-global-id ID FID] Generates an id FID which is fresh in
% the current module and looks similar to ID, i.e. it is ID concatenated
% with a number, starting from 1.
% [coq.env.fresh-global-id X X] can be used to check if X is taken
external pred coq.env.fresh-global-id i:id, o:id.
external pred coq.env.begin-module-functor % Starts a functor *E*
i:id, % The name of the functor
i:option modtypath, % Its module type
i:list (pair id modtypath). % Parameters of the functor
pred coq.env.begin-module i:id, i:option modtypath.
coq.env.begin-module Name MP :-
coq.env.begin-module-functor Name MP [].
% [coq.env.end-module ModPath] end the current module that becomes known as
% ModPath *E*
external pred coq.env.end-module o:modpath.
external pred coq.env.begin-module-type-functor % Starts a module type functor *E*
i:id, % The name of the functor
i:list (pair id modtypath). % The parameters of the functor
pred coq.env.begin-module-type i:id.
coq.env.begin-module-type Name :-
coq.env.begin-module-type-functor Name [].
% [coq.env.end-module-type ModTyPath] end the current module type that
% becomes known as ModPath *E*
external pred coq.env.end-module-type o:modtypath.
external pred coq.env.apply-module-functor % Applies a functor *E*
i:id, % The name of the new module
i:option modtypath, % Its module type
i:modpath, % The functor being applied
i:list modpath, % Its arguments
i:coq.inline, % Arguments inlining
o:modpath. % The modpath of the new module
external pred coq.env.apply-module-type-functor % Applies a type functor *E*
i:id, % The name of the new module type
i:modtypath, % The functor
i:list modpath, % Its arguments
i:coq.inline, % Arguments inlining
o:modtypath. % The modtypath of the new module type
% [coq.env.include-module ModPath Inline] is like the vernacular Include,
% Inline can be omitted *E*
external pred coq.env.include-module i:modpath, i:coq.inline.
% [coq.env.include-module-type ModTyPath Inline] is like the vernacular
% Include Type, Inline can be omitted *E*
external pred coq.env.include-module-type i:modtypath, i:coq.inline.
% [coq.env.import-module ModPath] is like the vernacular Import *E*
external pred coq.env.import-module i:modpath.
% [coq.env.export-module ModPath] is like the vernacular Export *E*
external pred coq.env.export-module i:modpath.
% Support for sections is limited, in particular sections and
% Coq quotations may interact in surprising ways. For example
% Section Test.
% Variable x : nat.
% Elpi Query lp:{{ coq.say {{ x }} }}.
% works since x is a global Coq term while
% Elpi Query lp:{{
% coq.env.begin-section "Test",
% coq.env.add-const "x" _ {{ nat }} _ @local! GRX,
% coq.say {{ x }}
% }}.
% may work in a surprising way or may not work at all since
% x is resolved before the section is started hence it cannot
% denote the same x as before.
% [coq.env.begin-section Name] starts a section named Name *E*
external pred coq.env.begin-section i:id.
% [coq.env.end-section] end the current section *E*
external pred coq.env.end-section .
% [coq.env.projections StructureName Projections] given a record
% StructureName lists all projections
external pred coq.env.projections i:inductive, o:list (option constant).
% [coq.env.primitive-projections StructureName Projections] given a record
% StructureName lists all primitive projections
external pred coq.env.primitive-projections i:inductive,
o:list (option (pair projection int)).
% -- Sorts (and their universe level, if applicable) ----------------
% Warning: universe polymorphism has to be considered experimental *E* as
% a feature, not just as a set of APIs. Unfortunately some of the
% current complexity is exposed to the programmer, bare with us.
%
% The big bang is that in Coq one has terms, types and sorts (which are
% the types of types). Some sorts (as of today only Type) some with
% a universe level, on paper Type_i for some i. At the sort level
% Coq features some form of subtyping: a function expecting a function
% to Type, e.g. nat -> Type, can receive a function to Prop, since
% Prop <= Type. So far, so good. But what are these levels i
% exactly?
%
% Universe levels are said to be "algebraic", they are made of
% variables (see the next section) and the two operators +1 and max.
% This is a sort of internal optimization that leaks to the
% user/programmer. Indeed these universe levels cannot be (directly) used
% in all APIs morally expecting a universe level "i", in particular
% the current constraint engine cannot handle constraint with an
% algebraic level on the right, e.g. i <= j+1. Since some APIs only
% accept universe variables, we provide the coq.univ.variable API
% which is able to craft a universe variable which is roughly
% equivalent to an algebraic universe, e.g. k such that j+1 = k.
%
% Coq-Elpi systematically purges algebraic universes from terms (and
% types and sorts) when one reads them from the environment. This
% makes the embedding of terms less precise than what it could be.
% The different data types stay, since Coq will eventually become
% able to handle algebraic universes consistently, making this purging
% phase unnecessary.
% universe level (algebraic: max, +1, univ.variable)
typeabbrev univ (ctype "univ").
% Sorts (kinds of types)
kind sort type.
type prop sort. % impredicative sort of propositions
type sprop sort. % impredicative sort of propositions with definitional proof irrelevance
type typ univ ->
sort. % predicative sort of data (carries a universe level)
% [coq.sort.leq S1 S2] constrains S1 <= S2
external pred coq.sort.leq o:sort, o:sort.
% [coq.sort.eq S1 S2] constrains S1 = S2
external pred coq.sort.eq o:sort, o:sort.
% [coq.sort.sup S1 S2] constrains S2 = S1 + 1
external pred coq.sort.sup o:sort, o:sort.
% [coq.sort.pts-triple S1 S2 S3] constrains S3 = sort of product with domain
% in S1 and codomain in S2
external pred coq.sort.pts-triple o:sort, o:sort, o:sort.
% [coq.univ.print] prints the set of universe constraints
external pred coq.univ.print .
% [coq.univ.new U] A fresh universe.
external pred coq.univ.new o:univ.
% [coq.univ Name U] Finds a named unvierse. Can fail.
external pred coq.univ o:id, o:univ.
% [coq.univ.global? U] succeeds if U is a global universe
external pred coq.univ.global? i:univ.
% [coq.univ.constraints CL] gives the list of constraints, see also
% coq.univ.variable.constraints
external pred coq.univ.constraints o:list univ-constraint.
% -- Universe variables ------
% universe level variable
typeabbrev univ.variable (ctype "univ.variable").
% [coq.univ.variable U L] relates a univ.variable L to a univ U
external pred coq.univ.variable o:univ, o:univ.variable.
% [coq.univ.variable.constraints L CL] gives the list of constraints on L.
% Can be used to craft a strict upoly-decl
external pred coq.univ.variable.constraints i:univ.variable,
o:list univ-constraint.
% [coq.univ.variable.of-term T S] collects all univ.variables occurring in T
external pred coq.univ.variable.of-term i:term, o:coq.univ.variable.set.
% -- Universe instance (for universe polymorphic global terms) ------
% As of today a universe polymorphic constant can only be instantiated
% with universe level variables. That is f@{Prop} is not valid, nor
% is f@{u+1}. One can only write f@{u} for any u.
%
% A univ-instance is morally a list of universe level variables,
% but its list syntax is hidden in the terms. If you really need to
% craft or inspect one of these, the following APIs can help you.
%
% Most of the time the user is expected to use coq.env.global which
% crafts a fresh, appropriate, universe instance and possibly unify that
% term (of the instance it contains) with another one.
% Universes level instance for a universe-polymoprhic constant
typeabbrev univ-instance (ctype "univ-instance").
% [coq.univ-instance UI UL] relates a univ-instance UI and a list of
% universe level variables UL
external pred coq.univ-instance o:univ-instance, o:list univ.variable.
% [coq.univ-instance.unify-eq GR UI1 UI2 Diagnostic] unifies the two
% universe instances for the same gref
external pred coq.univ-instance.unify-eq i:gref, i:univ-instance,
i:univ-instance, o:diagnostic.
% [coq.univ-instance.unify-leq GR UI1 UI2 Diagnostic] unifies the two
% universe instances for the same gref. Note: if the GR is not *cumulative*
% (see Cumulative or #[universes(cumulative)]) then this API imposes an
% equality constraint.
external pred coq.univ-instance.unify-leq i:gref, i:univ-instance,
i:univ-instance, o:diagnostic.
% -- Declaration of universe polymorphic global terms -----------
% These are the data types used to declare how constants
% and inductive types should be declared (see also the @udecl!
% and
% @udecl-cumul! macros). Note that only inductive types can be
% declared as cumulative.
% Constraint between two universes level variables
kind univ-constraint type.
type lt univ.variable -> univ.variable -> univ-constraint.
type le univ.variable -> univ.variable -> univ-constraint.
type eq univ.variable -> univ.variable -> univ-constraint.
% Variance of a universe level variable
kind univ-variance type.
type auto univ.variable -> univ-variance.
type covariant univ.variable -> univ-variance.
type invariant univ.variable -> univ-variance.
type irrelevant univ.variable -> univ-variance.
% Constraints for a non-cumulative declaration. Boolean tt means loose
% (e.g. the '+' in f@{u v + | u < v +})
kind upoly-decl type.
type upoly-decl list univ.variable -> bool -> list univ-constraint ->
bool -> upoly-decl.
% Constraints for a cumulative declaration. Boolean tt means loose (e.g.
% the '+' in f@{u v + | u < v +})
kind upoly-decl-cumul type.
type upoly-decl-cumul list univ-variance -> bool ->
list univ-constraint -> bool -> upoly-decl-cumul.
% -- Primitive --------------------------------------------------------
typeabbrev uint63 (ctype "uint63").
typeabbrev float64 (ctype "float64").
typeabbrev projection (ctype "projection").
% Primitive values
kind primitive-value type.
type uint63 uint63 -> primitive-value. % unsigned integers over 63 bits
type float64 float64 ->
primitive-value. % double precision foalting points
type proj projection -> int -> primitive-value. % primitive projection
% [coq.uint63->int U I] Transforms a primitive unsigned integer U into an
% elpi integer I. Fails if it does not fit.
external pred coq.uint63->int i:uint63, o:int.
% [coq.int->uint63 I U] Transforms an elpi integer I into a primitive
% unsigned integer U. Fails if I is negative.
external pred coq.int->uint63 i:int, o:uint63.
% [coq.float64->float F64 F] Transforms a primitive float on 64 bits to an
% elpi one. Currently, it should not fail.
external pred coq.float64->float i:float64, o:float.
% [coq.float->float64 F F64] Transforms an elpi float F to a primitive float
% on 64 bits. Currently, it should not fail.
external pred coq.float->float64 i:float, o:float64.
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% API for extra logical objects
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% -- Databases (TC, CS, Coercions) ------------------------------------
% Pattern for canonical values
kind cs-pattern type.
type cs-gref gref -> cs-pattern.
type cs-prod cs-pattern.
type cs-default cs-pattern.
type cs-sort sort -> cs-pattern.
% Canonical Structure instances: (cs-instance Proj ValPat Inst)
kind cs-instance type.
type cs-instance gref -> cs-pattern -> gref -> cs-instance.
% [coq.CS.declare-instance GR] Declares GR as a canonical structure
% instance.
% Supported attributes:
% - @local! (default: false)
external pred coq.CS.declare-instance i:gref.
% [coq.CS.db Db] reads all instances
external pred coq.CS.db o:list cs-instance.
% [coq.CS.db-for Proj Value Db] reads all instances for a given Projection
% or canonical Value, or both
external pred coq.CS.db-for i:gref, i:cs-pattern, o:list cs-instance.
% [coq.TC.declare-class GR] Declare GR as a type class
external pred coq.TC.declare-class i:gref.
% Type class instance with priority
kind tc-instance type.
type tc-instance gref -> int -> tc-instance.
% [coq.TC.declare-instance GR Priority] Declare GR as a Global type class
% instance with Priority.
% Supported attributes:
% - @global! (default: true)
external pred coq.TC.declare-instance i:gref, i:int.
% [coq.TC.db Instances] reads all type class instances
external pred coq.TC.db o:list tc-instance.
% [coq.TC.db-tc TypeClasses] reads all type classes
external pred coq.TC.db-tc o:list gref.
% [coq.TC.db-for GR Db] reads all instances of the given class GR
external pred coq.TC.db-for i:gref, o:list tc-instance.
% [coq.TC.class? GR] checks if GR is a class
external pred coq.TC.class? i:gref.
% Node of the coercion graph
kind class type.
type funclass class.
type sortclass class.
type grefclass gref -> class.
% Edge of the coercion graph
kind coercion type.
type coercion gref -> int -> gref -> class ->
coercion. % ref, nparams, src, tgt
% [coq.coercion.declare C] Declares C = (coercion GR NParams From To) as a
% coercion From >-> To.
% NParams can always be omitted, since it is inferred.
% If From or To is unspecified, then the endpoints are inferred.
% Supported attributes:
% - @global! (default: false)
% - @nonuniform! (default: false)
% - @reversible! (default: false)
external pred coq.coercion.declare i:coercion.
% [coq.coercion.db L] reads all declared coercions
external pred coq.coercion.db o:list coercion.
% [coq.coercion.db-for From To L] L is a path From -> To
external pred coq.coercion.db-for i:class, i:class,
o:list (pair gref int).
% Deprecated, use coq.env.projections
pred coq.CS.canonical-projections i:inductive, o:list (option constant).
coq.CS.canonical-projections I L :-
coq.warning "elpi.deprecated" "elpi.canonical-projections" "use coq.env.projections in place of coq.CS.canonical-projections",
coq.env.projections I L.
% -- Coq's Hint DB -------------------------------------
% Locality of hints is a delicate matter since the Coq default
% is, in some cases, to make an hint active even if the module it belongs
% to is not imported (just merely required, which can happen
% transitively).
% Coq is aiming at changing the default to #[export], that makes an
% hint active only when its enclosing module is imported.
% See:
% https://coq.discourse.group/t/change-of-default-locality-for-hint-commands-in-coq-8-13/1140
%
% This old behavior is available via the @global! flag, but is discouraged.
%
% Hint Mode
kind hint-mode type.
type mode-ground hint-mode. % No Evar
type mode-input hint-mode. % No Head Evar
type mode-output hint-mode. % Anything
% [coq.hints.add-mode GR DB Mode] Adds a mode declaration to DB about
% GR.
% Supported attributes:
% - @local! (default is export)
% - @global! (discouraged, may become deprecated)
external pred coq.hints.add-mode i:gref, i:string, i:list hint-mode.
% [coq.hints.modes GR DB Modes] Gets all the mode declarations in DB about
% GR
external pred coq.hints.modes i:gref, i:string, o:list (list hint-mode).
% [coq.hints.set-opaque C DB Opaque] Like Hint Opaque C : DB (or Hint
% Transparent, if the boolean is ff).
% Supported attributes:
% - @local! (default is export)
% - @global! (discouraged, may become deprecated)
external pred coq.hints.set-opaque i:constant, i:string, i:bool.
% [coq.hints.opaque C DB Opaque] Reads if constant C is opaque (tt) or
% transparent (ff) in DB
external pred coq.hints.opaque i:constant, i:string, o:bool.
% [coq.hints.add-resolve GR DB Priority Pattern] Like Hint Resolve GR |
% Priority Pattern : DB.
% Supported attributes:
% - @local! (default is export)
% - @global! (discouraged, may become deprecated)
external pred coq.hints.add-resolve i:gref, i:string, i:int, i:term.
% -- Coq's notational mechanisms -------------------------------------
% Implicit status of an argument
kind implicit_kind type.
type implicit implicit_kind. % regular implicit argument, eg Arguments foo [x]
type maximal implicit_kind. % maximally inserted implicit argument, eg Arguments foo {x}
type explicit implicit_kind. % explicit argument, eg Arguments foo x
% [coq.arguments.implicit GR Imps] reads the implicit arguments declarations
% associated to a global reference. See also the [] and {} flags for the
% Arguments command.
external pred coq.arguments.implicit i:gref, o:list (list implicit_kind).
% [coq.arguments.set-implicit GR Imps] sets the implicit arguments
% declarations associated to a global reference.
% Unspecified means explicit.
% See also the [] and {} flags for the Arguments command.
% Supported attributes:
% - @global! (default: false)
external pred coq.arguments.set-implicit i:gref,
i:list (list implicit_kind).
% [coq.arguments.set-default-implicit GR] sets the default implicit
% arguments declarations associated to a global reference.
% See also the "default implicits" flag to the Arguments command.
% Supported attributes:
% - @global! (default: false)
external pred coq.arguments.set-default-implicit i:gref.
% [coq.arguments.name GR Names] reads the Names of the arguments of a global
% reference. See also the (f (A := v)) syntax.
external pred coq.arguments.name i:gref, o:list (option id).
% [coq.arguments.set-name GR Names] sets the Names of the arguments of a
% global reference.
% See also the :rename flag to the Arguments command.
% Supported attributes:
% - @global! (default: false)
external pred coq.arguments.set-name i:gref, i:list (option id).
% [coq.arguments.scope GR Scopes] reads the notation scope of the arguments
% of a global reference. See also the %scope modifier for the Arguments
% command
external pred coq.arguments.scope i:gref, o:list (list id).
% [coq.arguments.set-scope GR Scopes] sets the notation scope of the
% arguments of a global reference.
% Scope can be a scope name or its delimiter.
% See also the %scope modifier for the Arguments command.
% Supported attributes:
% - @global! (default: false)
external pred coq.arguments.set-scope i:gref, i:list (list id).
% Strategy for simplification tactics
kind simplification_strategy type.
type never simplification_strategy. % Arguments foo : simpl never
type when list int -> option int ->
simplification_strategy. % Arguments foo .. / .. ! ..
type when-nomatch list int -> option int ->
simplification_strategy. % Arguments foo .. / .. ! .. : simpl nomatch
% [coq.arguments.simplification GR Strategy] reads the behavior of the
% simplification tactics. Positions are 0 based. See also the ! and /
% modifiers for the Arguments command
external pred coq.arguments.simplification i:gref,
o:option simplification_strategy.
% [coq.arguments.set-simplification GR Strategy] sets the behavior of the
% simplification tactics.
% Positions are 0 based.
% See also the ! and / modifiers for the Arguments command.
% Supported attributes:
% - @global! (default: false)
external pred coq.arguments.set-simplification i:gref,
i:simplification_strategy.
% [coq.locate-abbreviation Name Abbreviation] locates an abbreviation. It's
% a fatal error if Name cannot be located.
external pred coq.locate-abbreviation i:id, o:abbreviation.
% Name of an abbreviation
typeabbrev abbreviation (ctype "abbreviation").
% [coq.notation.add-abbreviation Name Nargs Body OnlyParsing Abbreviation]
% Declares an abbreviation Name with Nargs arguments.
% The term must begin with at least Nargs "fun" nodes whose domain is
% ignored, eg (fun _ _ x\ fun _ _ y\ app[global "add",x,y]).
% Supported attributes:
% - @deprecated! (default: not deprecated)
% - @global! (default: false)
external pred coq.notation.add-abbreviation i:id, i:int, i:term, i:bool,
o:abbreviation.
% [coq.notation.abbreviation Abbreviation Args Body] Unfolds an abbreviation
external pred coq.notation.abbreviation i:abbreviation, i:list term,
o:term.
% [coq.notation.abbreviation-body Abbreviation Nargs Body] Retrieves the
% body of an abbreviation
external pred coq.notation.abbreviation-body i:abbreviation, o:int,
o:term.
% [coq.notation.add-abbreviation-for-tactic Name TacticName FixedArgs]
% Declares a parsing rule similar to
% Notation Name X1..Xn := ltac:(elpi TacticName FixedArgs (X1)..(Xn))
% so that Name can be used in the middle of a term to invoke an
% elpi tactic. While FixedArgs can contain str, int, and trm all
% other arguments will necessarily be terms, and their number is
% not fixed (the user can pass as many as he likes).
% The tactic receives as the elpi.loc attribute the precise location
% at which the term is written (unlike if a regular abbreviation was
% declared by hand).
% A call to coq.notation.add-abbreviation-for-tactic TacName TacName []
% is equivalent to Elpi Export TacName.
external pred coq.notation.add-abbreviation-for-tactic i:string,
i:string,
i:list argument.
% Generic attribute value
kind attribute-value type.
type leaf-str string -> attribute-value.
type leaf-loc loc -> attribute-value.
type node list attribute -> attribute-value.
% Generic attribute
kind attribute type.
type attribute string -> attribute-value -> attribute.
% see coq-lib.elpi for coq.parse-attributes generating the options below
type get-option string -> A -> prop.
% -- Coq's pretyper ---------------------------------------------------
% [coq.sigma.print] Prints Coq's Evarmap and the mapping to/from Elpi's
% unification variables
external pred coq.sigma.print .
% [coq.typecheck T Ty Diagnostic] typchecks a term T returning its type Ty.
% If Ty is provided, then
% the inferred type is unified (see unify-leq) with it.
% Universe constraints are put in the constraint store.
external pred coq.typecheck i:term, o:term, o:diagnostic.
% [coq.typecheck-ty Ty U Diagnostic] typchecks a type Ty returning its
% universe U. If U is provided, then
% the inferred universe is unified (see unify-leq) with it.
% Universe constraints are put in the constraint store.
external pred coq.typecheck-ty i:term, o:sort, o:diagnostic.
% [coq.unify-eq A B Diagnostic] unifies the two terms
external pred coq.unify-eq i:term, i:term, o:diagnostic.
% [coq.unify-leq A B Diagnostic] unifies the two terms (with cumulativity,
% if they are types)
external pred coq.unify-leq i:term, i:term, o:diagnostic.
% [coq.elaborate-skeleton T ETy E Diagnostic] elabotares T against the
% expected type ETy.
% T is allowed to contain holes (unification variables) but these are
% not assigned even if the elaborated term has a term in place of the
% hole. Similarly universe levels present in T are disregarded.
% Supported attributes:
% - @keepunivs! (default false, do not disregard universe levels)
% - @no-tc! (default false, do not infer typeclasses)
external pred coq.elaborate-skeleton i:term, o:term, o:term, o:diagnostic.
% [coq.elaborate-ty-skeleton T U E Diagnostic] elabotares T expecting it to
% be a type of sort U.
% T is allowed to contain holes (unification variables) but these are
% not assigned even if the elaborated term has a term in place of the
% hole. Similarly universe levels present in T are disregarded.
% Supported attributes:
% - @keepunivs! (default false, do not disregard universe levels)
% - @no-tc! (default false, do not infer typeclasses)
external pred coq.elaborate-ty-skeleton i:term, o:sort, o:term,
o:diagnostic.
% -- Coq's reduction flags ------------------------------------
% Flags for lazy, cbv, ... reductions
kind coq.redflag type.
type coq.redflags.beta coq.redflag.
type coq.redflags.delta coq.redflag. % if set then coq.redflags.const disables unfolding
type coq.redflags.match coq.redflag.
type coq.redflags.fix coq.redflag.
type coq.redflags.cofix coq.redflag.
type coq.redflags.zeta coq.redflag.
type coq.redflags.const constant ->
coq.redflag. % enable/disable unfolding
% Set of flags for lazy, cbv, ... reductions
typeabbrev coq.redflags (ctype "coq.redflags").
type coq.redflags.all coq.redflags.
type coq.redflags.allnolet coq.redflags.
type coq.redflags.beta coq.redflags.
type coq.redflags.betadeltazeta coq.redflags.
type coq.redflags.betaiota coq.redflags.
type coq.redflags.betaiotazeta coq.redflags.
type coq.redflags.betazeta coq.redflags.
type coq.redflags.delta coq.redflags.
type coq.redflags.zeta coq.redflags.
type coq.redflags.nored coq.redflags.
% [coq.redflags.add Flags Options NewFlags] Updates reduction Flags by
% adding Options
external pred coq.redflags.add i:coq.redflags, i:list coq.redflag,
o:coq.redflags.
% [coq.redflags.sub Flags Options NewFlags] Updates reduction Flags by
% removing Options
external pred coq.redflags.sub i:coq.redflags, i:list coq.redflag,
o:coq.redflags.
% -- Coq's reduction machines ------------------------------------
% [coq.reduction.lazy.whd T Tred] Puts T in weak head normal form.
% Supported attributes:
% - @redflags! (default coq.redflags.all)
external pred coq.reduction.lazy.whd i:term, o:term.
% [coq.reduction.lazy.norm T Tred] Puts T in normal form.
% Supported attributes:
% - @redflags! (default coq.redflags.all)
external pred coq.reduction.lazy.norm i:term, o:term.
% [coq.reduction.lazy.bi-norm T Tred] Puts T in normal form only reducing
% beta and iota redexes
external pred coq.reduction.lazy.bi-norm i:term, o:term.
% [coq.reduction.cbv.norm T Tred] Puts T in normal form using the call by
% value strategy.
% Supported attributes:
% - @redflags! (default coq.redflags.all)
external pred coq.reduction.cbv.norm i:term, o:term.
% [coq.reduction.vm.norm T Ty Tred] Puts T in normal form using
% [vm_compute]'s machinery. Its type Ty can be omitted (but is recomputed)
external pred coq.reduction.vm.norm i:term, i:term, o:term.
% [coq.reduction.native.norm T Ty Tred] Puts T in normal form using
% [native_compute]'s machinery. Its type Ty can be omitted (but is
% recomputed). Falls back to vm.norm if native compilation is not available.
external pred coq.reduction.native.norm i:term, i:term, o:term.
% [coq.reduction.native.available?] Is native compilation available on this
% system/configuration?
external pred coq.reduction.native.available? .
% Deprecated, use coq.reduction.cbv.norm
pred coq.reduction.cbv.whd_all i:term, o:term.
coq.reduction.cbv.whd_all T R :-
coq.warning "elpi.deprecated" "elpi.cbv-whd-all" "use coq.reduction.cbv.norm in place of coq.reduction.cbv.whd_all",
coq.reduction.cbv.norm T R.
% Deprecated, use coq.reduction.vm.norm
pred coq.reduction.vm.whd_all i:term, i:term, o:term.
coq.reduction.vm.whd_all T TY R :-
coq.warning "elpi.deprecated" "elpi.vm-whd-all" "use coq.reduction.vm.norm in place of coq.reduction.vm.whd_all",
coq.reduction.vm.norm T TY R.
pred coq.reduction.lazy.whd_all i:term, o:term.
coq.reduction.lazy.whd_all X Y :-
@redflags! coq.redflags.all => coq.reduction.lazy.whd X Y.
% [coq.reduction.eta-contract T Tred] Removes all eta expansions from T
external pred coq.reduction.eta-contract i:term, o:term.
% -- Coq's conversion strategy tweaks --------------------------
% Strategy for conversion test
% expand < ... < level -1 < level 0 < level 1 < ... < opaque
kind conversion_strategy type.
type opaque conversion_strategy.
type expand conversion_strategy.
type level int -> conversion_strategy. % default is 0, aka transparent
% [coq.strategy.set CL Level] Sets the unfolding priority for all the
% constants in the list CL. See the command Strategy.
external pred coq.strategy.set i:list constant, i:conversion_strategy.
% [coq.strategy.get C Level] Gets the unfolding priority for C
external pred coq.strategy.get i:constant, o:conversion_strategy.
% -- Coq's tactics --------------------------------------------
% LTac1 tactic expression
typeabbrev ltac1-tactic (ctype "ltac1-tactic").
% [coq.ltac.fail Level ...] Interrupts the Elpi program and calls Ltac's
% fail Level Msg, where Msg is the printing of the remaining arguments.
% Level can be left unspecified and defaults to 0
external type coq.ltac.fail int -> variadic any prop.
% [coq.ltac.collect-goals T Goals ShelvedGoals]
% Turns the holes in T into Goals.
% Goals are closed with nablas.
% ShelvedGoals are goals which can be solved by side effect (they occur
% in the type of the other goals).
% The order of Goals is given by the traversal order of EConstr.fold
% (a
% fold_left over the terms, letin body comes before the type).
%
external pred coq.ltac.collect-goals i:term, o:list sealed-goal,
o:list sealed-goal.
% [coq.ltac.call-ltac1 Tac G GL] Calls Ltac1 tactic Tac on goal G (passing
% the arguments of G, see coq.ltac.call for a handy wrapper).
% Tac can either be a string (the tactic name), or a value
% of type ltac1-tactic, see the tac argument constructor
% and the ltac_tactic:(...) syntax to pass arguments to
% an elpi tactic.
external pred coq.ltac.call-ltac1 i:any, i:goal, o:list sealed-goal.
% [coq.ltac.id-free? ID G]
% Fails if ID is already used in G. Note that ids which are taken are
% renamed
% on the fly (since in the HOAS of terms, names are just pretty printing
% hints), but for the ergonomy of a tactic it may help to know if an
% hypothesis name is already taken.
%
external pred coq.ltac.id-free? i:id, i:goal.
% -- Coq's options system --------------------------------------------
% Coq option value
kind coq.option type.
type coq.option.int option int -> coq.option. % none means unset
type coq.option.string option string -> coq.option. % none means unset
type coq.option.bool bool -> coq.option.
% [coq.option.get Option Value] reads Option. Reading a non existing option
% is a fatal error.
external pred coq.option.get i:list string, o:coq.option.
% [coq.option.set Option Value] writes Option. Writing a non existing option
% is a fatal error.
external pred coq.option.set i:list string, i:coq.option.
% [coq.option.available? Option Deprecated] checks if Option exists and
% tells if is deprecated (tt) or not (ff)
external pred coq.option.available? i:list string, o:bool.
% [coq.option.add Option Value Deprecated]
% adds a new option to Coq setting its current value (and type).
% Deprecated can be left unspecified and defaults to ff.
% This call cannot be undone in a Coq interactive session, use it once
% and for all in a .v file which your clients will load. Eg.
%
% Elpi Query lp:{{ coq.option.add ... }}.
%
%
external pred coq.option.add i:list string, i:coq.option, i:bool.
% -- Datatypes conversions --------------------------------------------
% Name.Name.t: Name hints (in binders), can be input writing a name
% between backticks, e.g. `x` or `_` for anonymous. Important: these are
% just printing hints with no meaning, hence in elpi two name are always
% related: `x` = `y`
typeabbrev name (ctype "name").
% [coq.name-suffix Name Suffix NameSuffix] suffixes a Name with a string or
% an int or another name
external pred coq.name-suffix i:name, i:any, o:name.
% [coq.string->name Hint Name] creates a name hint
external pred coq.string->name i:string, o:name.
pred coq.id->name i:id, o:name.
coq.id->name S N :- coq.string->name S N.
% [coq.name->id Name Id] tuns a pretty printing hint into a string. This API
% is for internal use, no guarantee on its behavior.
external pred coq.name->id i:name, o:id.
% [coq.gref->id GR Id] extracts the label (last component of a full kernel
% name)
external pred coq.gref->id i:gref, o:id.
% [coq.gref->string GR FullPath] extract the full kernel name
external pred coq.gref->string i:gref, o:string.
% [coq.gref->path GR FullPath] extract the full path (kernel name without
% final id), each component is a separate list item
external pred coq.gref->path i:gref, o:list string.
% [coq.modpath->path MP FullPath] extract the full kernel name, each
% component is a separate list item
external pred coq.modpath->path i:modpath, o:list string.
% [coq.modtypath->path MTP FullPath] extract the full kernel name, each
% component is a separate list item
external pred coq.modtypath->path i:modtypath, o:list string.
% [coq.modpath->library MP LibraryPath] extract the enclosing module which
% can be Required
external pred coq.modpath->library i:modpath, o:modpath.
% [coq.modtypath->library MTP LibraryPath] extract the enclosing module
% which can be Required
external pred coq.modtypath->library i:modtypath, o:modpath.
% [coq.term->string T S] prints a term T to a string S using Coq's pretty
% printer
% Supported attributes:
% - @ppwidth! N (default 80, max line length)
% - @ppall! (default: false, prints all details)
% - @ppmost! (default: false, prints most details)
% - @pplevel! (default: _, prints parentheses to reach that level, 200 =
% off)
% - @holes! (default: false, prints evars as _)
external pred coq.term->string i:term, o:string.
% [coq.term->pp T B] prints a term T to a pp.t B using Coq's pretty
% printer"
% Supported attributes:
% - @ppall! (default: false, prints all details)
% - @ppmost! (default: false, prints most details)
% - @pplevel! (default: _, prints parentheses to reach that level, 200 =
% off)
% - @holes! (default: false, prints evars as _)
external pred coq.term->pp i:term, o:coq.pp.
% -- Access to Elpi's data --------------------------------------------
% clauses
%
% A clause like
% :name "foo" :before "bar" foo X Y :- bar X Z, baz Z Y
% is represented as
% clause "foo" (before "bar") (pi x y z\ foo x y :- bar x z, baz z y)
% that is exactly what one would load in the context using =>.
%
% The name and the grafting specification can be left unspecified.
kind clause type.
type clause id -> grafting -> prop -> clause.
% Specify if the clause has to be grafted before or after a named clause
kind grafting type.
type before id -> grafting.
type after id -> grafting.
% Specify to which module the clause should be attached to
kind scope type.
type execution-site scope. % The module inside which the Elpi program is run
type current scope. % The module being defined (see begin/end-module)
type library scope. % The outermost module (carrying the file name)
% see coq.elpi.accumulate-clauses
pred coq.elpi.accumulate i:scope, i:id, i:clause.
coq.elpi.accumulate S N C :- coq.elpi.accumulate-clauses S N [C].
% [coq.elpi.accumulate-clauses Scope DbName Clauses]
% Declare that, once the program is over, the given clauses has to be
% added to the given db (see Elpi Db).
% Clauses usually belong to Coq modules: the Scope argument lets one
% select which module:
% - execution site (default) is the module in which the pogram is
% invoked
% - current is the module currently being constructed (see
% begin/end-module)
% - library is the current file (the module that is named after the file)
% The clauses are visible as soon as the enclosing module is Imported.
% A clause that mentions a section variable is automatically discarded
% at the end of the section.
% Clauses cannot be accumulated inside functors.
% Supported attributes:
% - @local! (default: false, discard at the end of section or module)
% - @global! (default: false, always active, only if Scope is
% execution-site, discouraged)
external pred coq.elpi.accumulate-clauses i:scope, i:id, i:list clause.
% Specify if a predicate argument is in input or output mode
kind argument_mode type.
type in argument_mode.
type out argument_mode.
% [coq.elpi.add-predicate Db Indexing PredName Spec] Declares a new
% predicate PredName in the data base Db. Indexing can be left unspecified.
% Spec gathers a mode and a type for each argument. CAVEAT: types and
% indexing are strings instead of proper data types; beware parsing errors
% are fatal
external pred coq.elpi.add-predicate i:string, i:string, i:string,
i:list (pair argument_mode string).
% [coq.elpi.predicate PredName Args Pred] Pred is the application of
% PredName to Args
external pred coq.elpi.predicate i:string, i:list any, o:prop.
% -- Utils ------------------------------------------------------------
kind coq.gref.set type.
% [coq.gref.set.empty A] The empty set
external pred coq.gref.set.empty o:coq.gref.set.
% [coq.gref.set.mem Elem A] Checks if Elem is in a
external pred coq.gref.set.mem i:gref, i:coq.gref.set.
% [coq.gref.set.add Elem A B] B is A union {Elem}
external pred coq.gref.set.add i:gref, i:coq.gref.set, o:coq.gref.set.
% [coq.gref.set.remove Elem A B] B is A \ {Elem}
external pred coq.gref.set.remove i:gref, i:coq.gref.set, o:coq.gref.set.
% [coq.gref.set.union A B X] X is A union B
external pred coq.gref.set.union i:coq.gref.set, i:coq.gref.set,
o:coq.gref.set.
% [coq.gref.set.inter A B X] X is A intersection B
external pred coq.gref.set.inter i:coq.gref.set, i:coq.gref.set,
o:coq.gref.set.
% [coq.gref.set.diff A B X] X is A \ B
external pred coq.gref.set.diff i:coq.gref.set, i:coq.gref.set,
o:coq.gref.set.
% [coq.gref.set.equal A B] tests A and B for equality
external pred coq.gref.set.equal i:coq.gref.set, i:coq.gref.set.
% [coq.gref.set.subset A B] tests if A is a subset of B
external pred coq.gref.set.subset i:coq.gref.set, i:coq.gref.set.
% [coq.gref.set.elements M L] L is M transformed into list
external pred coq.gref.set.elements i:coq.gref.set, o:list gref.
% [coq.gref.set.cardinal M N] N is the number of elements of M
external pred coq.gref.set.cardinal i:coq.gref.set, o:int.
% CAVEAT: the type parameter of coq.gref.map must be a closed term
kind coq.gref.map type -> type.
% [coq.gref.map.empty M] The empty map
external pred coq.gref.map.empty o:coq.gref.map A.
% [coq.gref.map.mem S M] Checks if S is bound in M
external pred coq.gref.map.mem i:gref, i:coq.gref.map A.
% [coq.gref.map.add S V M M1] M1 is M where V is bound to S
external pred coq.gref.map.add i:gref, i:A, i:coq.gref.map A,
o:coq.gref.map A.
% [coq.gref.map.remove S M M1] M1 is M where S is unbound
external pred coq.gref.map.remove i:gref, i:coq.gref.map A,
o:coq.gref.map A.
% [coq.gref.map.find S M V] V is the binding of S in M
external pred coq.gref.map.find i:gref, i:coq.gref.map A, o:A.
% [coq.gref.map.bindings M L] L is M transformed into an associative list
external pred coq.gref.map.bindings i:coq.gref.map A,
o:list (pair gref A).
kind coq.univ.set type.
% [coq.univ.set.empty A] The empty set
external pred coq.univ.set.empty o:coq.univ.set.
% [coq.univ.set.mem Elem A] Checks if Elem is in a
external pred coq.univ.set.mem i:univ, i:coq.univ.set.
% [coq.univ.set.add Elem A B] B is A union {Elem}
external pred coq.univ.set.add i:univ, i:coq.univ.set, o:coq.univ.set.
% [coq.univ.set.remove Elem A B] B is A \ {Elem}
external pred coq.univ.set.remove i:univ, i:coq.univ.set, o:coq.univ.set.
% [coq.univ.set.union A B X] X is A union B
external pred coq.univ.set.union i:coq.univ.set, i:coq.univ.set,
o:coq.univ.set.
% [coq.univ.set.inter A B X] X is A intersection B
external pred coq.univ.set.inter i:coq.univ.set, i:coq.univ.set,
o:coq.univ.set.
% [coq.univ.set.diff A B X] X is A \ B
external pred coq.univ.set.diff i:coq.univ.set, i:coq.univ.set,
o:coq.univ.set.
% [coq.univ.set.equal A B] tests A and B for equality
external pred coq.univ.set.equal i:coq.univ.set, i:coq.univ.set.
% [coq.univ.set.subset A B] tests if A is a subset of B
external pred coq.univ.set.subset i:coq.univ.set, i:coq.univ.set.
% [coq.univ.set.elements M L] L is M transformed into list
external pred coq.univ.set.elements i:coq.univ.set, o:list univ.
% [coq.univ.set.cardinal M N] N is the number of elements of M
external pred coq.univ.set.cardinal i:coq.univ.set, o:int.
% CAVEAT: the type parameter of coq.univ.map must be a closed term
kind coq.univ.map type -> type.
% [coq.univ.map.empty M] The empty map
external pred coq.univ.map.empty o:coq.univ.map A.
% [coq.univ.map.mem S M] Checks if S is bound in M
external pred coq.univ.map.mem i:univ, i:coq.univ.map A.
% [coq.univ.map.add S V M M1] M1 is M where V is bound to S
external pred coq.univ.map.add i:univ, i:A, i:coq.univ.map A,
o:coq.univ.map A.
% [coq.univ.map.remove S M M1] M1 is M where S is unbound
external pred coq.univ.map.remove i:univ, i:coq.univ.map A,
o:coq.univ.map A.
% [coq.univ.map.find S M V] V is the binding of S in M
external pred coq.univ.map.find i:univ, i:coq.univ.map A, o:A.
% [coq.univ.map.bindings M L] L is M transformed into an associative list
external pred coq.univ.map.bindings i:coq.univ.map A,
o:list (pair univ A).
kind coq.univ.variable.set type.
% [coq.univ.variable.set.empty A] The empty set
external pred coq.univ.variable.set.empty o:coq.univ.variable.set.
% [coq.univ.variable.set.mem Elem A] Checks if Elem is in a
external pred coq.univ.variable.set.mem i:univ.variable,
i:coq.univ.variable.set.
% [coq.univ.variable.set.add Elem A B] B is A union {Elem}
external pred coq.univ.variable.set.add i:univ.variable,
i:coq.univ.variable.set,
o:coq.univ.variable.set.
% [coq.univ.variable.set.remove Elem A B] B is A \ {Elem}
external pred coq.univ.variable.set.remove i:univ.variable,
i:coq.univ.variable.set,
o:coq.univ.variable.set.
% [coq.univ.variable.set.union A B X] X is A union B
external pred coq.univ.variable.set.union i:coq.univ.variable.set,
i:coq.univ.variable.set,
o:coq.univ.variable.set.
% [coq.univ.variable.set.inter A B X] X is A intersection B
external pred coq.univ.variable.set.inter i:coq.univ.variable.set,
i:coq.univ.variable.set,
o:coq.univ.variable.set.
% [coq.univ.variable.set.diff A B X] X is A \ B
external pred coq.univ.variable.set.diff i:coq.univ.variable.set,
i:coq.univ.variable.set,
o:coq.univ.variable.set.
% [coq.univ.variable.set.equal A B] tests A and B for equality
external pred coq.univ.variable.set.equal i:coq.univ.variable.set,
i:coq.univ.variable.set.
% [coq.univ.variable.set.subset A B] tests if A is a subset of B
external pred coq.univ.variable.set.subset i:coq.univ.variable.set,
i:coq.univ.variable.set.
% [coq.univ.variable.set.elements M L] L is M transformed into list
external pred coq.univ.variable.set.elements i:coq.univ.variable.set,
o:list univ.variable.
% [coq.univ.variable.set.cardinal M N] N is the number of elements of M
external pred coq.univ.variable.set.cardinal i:coq.univ.variable.set,
o:int.
% CAVEAT: the type parameter of coq.univ.variable.map must be a closed
% term
kind coq.univ.variable.map type -> type.
% [coq.univ.variable.map.empty M] The empty map
external pred coq.univ.variable.map.empty o:coq.univ.variable.map A.
% [coq.univ.variable.map.mem S M] Checks if S is bound in M
external pred coq.univ.variable.map.mem i:univ.variable,
i:coq.univ.variable.map A.
% [coq.univ.variable.map.add S V M M1] M1 is M where V is bound to S
external pred coq.univ.variable.map.add i:univ.variable, i:A,
i:coq.univ.variable.map A,
o:coq.univ.variable.map A.
% [coq.univ.variable.map.remove S M M1] M1 is M where S is unbound
external pred coq.univ.variable.map.remove i:univ.variable,
i:coq.univ.variable.map A,
o:coq.univ.variable.map A.
% [coq.univ.variable.map.find S M V] V is the binding of S in M
external pred coq.univ.variable.map.find i:univ.variable,
i:coq.univ.variable.map A, o:A.
% [coq.univ.variable.map.bindings M L] L is M transformed into an
% associative list
external pred coq.univ.variable.map.bindings i:coq.univ.variable.map A,
o:list (pair univ.variable A).
% Coq box types for pretty printing:
% - Vertical block: each break leads to a new line
% - Horizontal block: no line breaking
% - Horizontal-vertical block: same as Vertical block, except if this block
% is small enough to fit on a single line in which case it is the same
% as a Horizontal block
% - Horizontal or Vertical block: breaks lead to new line only when
% necessary to print the content of the block (the contents flow
% inside the box)
kind coq.pp.box type.
type coq.pp.v int -> coq.pp.box.
type coq.pp.h coq.pp.box.
type coq.pp.hv int -> coq.pp.box.
type coq.pp.hov int -> coq.pp.box.
% Coq box model for pretty printing. Items:
% - empty
% - spc: a spacem, also a breaking hint
% - str: a non breakable string
% - brk L I: a breaking hint of a given length L contributing I spaces to
% indentation when taken
% - glue: puts things together
% - box B: a box with automatic line breaking according to B
% - comment: embedded \\n are turned into nl (see below)
% - tag: ignored
% - nl: break the line (should not be used)
kind coq.pp type.
type coq.pp.empty coq.pp.
type coq.pp.spc coq.pp.
type coq.pp.str string -> coq.pp.
type coq.pp.brk int -> int -> coq.pp.
type coq.pp.glue list coq.pp -> coq.pp.
type coq.pp.box coq.pp.box -> list coq.pp -> coq.pp.
type coq.pp.comment list string -> coq.pp.
type coq.pp.tag string -> coq.pp -> coq.pp.
type coq.pp.nl coq.pp.
% [coq.pp->string B S] Prints a pp.t box expression B to a string S
% Supported attributes:
% - @ppwidth! N (default 80, max line length)
external pred coq.pp->string i:coq.pp, o:string.
coq-elpi-1.19.3/coq-elpi.opam 0000664 0000000 0000000 00000003125 14511776522 0015720 0 ustar 00root root 0000000 0000000 opam-version: "2.0"
name: "coq-elpi"
version: "dev"
maintainer: "Enrico Tassi "
authors: [ "Enrico Tassi" ]
license: "LGPL-2.1-or-later"
homepage: "https://github.com/LPCIC/coq-elpi"
bug-reports: "https://github.com/LPCIC/coq-elpi/issues"
dev-repo: "git+https://github.com/LPCIC/coq-elpi"
build: [ [ make "build" "COQBIN=%{bin}%/" "ELPIDIR=%{prefix}%/lib/elpi" "OCAMLWARN=" ]
[ make "test" "COQBIN=%{bin}%/" "ELPIDIR=%{prefix}%/lib/elpi" ] {with-test}
]
install: [ make "install" "COQBIN=%{bin}%/" "ELPIDIR=%{prefix}%/lib/elpi" ]
depends: [
"stdlib-shims"
"elpi" {>= "1.16.5" & < "1.18.0~"}
"coq" {>= "8.18" & < "8.19~" }
"dot-merlin-reader" {with-dev}
"ocaml-lsp-server" {with-dev}
]
tags: [
"category:Miscellaneous/Coq Extensions"
"keyword:λProlog"
"keyword:higher order abstract syntax"
"logpath:elpi"
]
synopsis: "Elpi extension language for Coq"
description: """
Coq-elpi provides a Coq plugin that embeds ELPI.
It also provides a way to embed Coq's terms into λProlog using
the Higher-Order Abstract Syntax approach
and a way to read terms back. In addition to that it exports to ELPI a
set of Coq's primitives, e.g. printing a message, accessing the
environment of theorems and data types, defining a new constant and so on.
For convenience it also provides a quotation and anti-quotation for Coq's
syntax in λProlog. E.g. `{{nat}}` is expanded to the type name of natural
numbers, or `{{A -> B}}` to the representation of a product by unfolding
the `->` notation. Finally it provides a way to define new vernacular commands
and
new tactics."""
coq-elpi-1.19.3/default.nix 0000664 0000000 0000000 00000000661 14511776522 0015477 0 ustar 00root root 0000000 0000000 { config ? {}, withEmacs ? false, print-env ? false, do-nothing ? false,
update-nixpkgs ? false, ci-matrix ? false,
override ? {}, ocaml-override ? {}, global-override ? {},
bundle ? null, job ? null, inNixShell ? null, src ? ./.,
}@args:
let auto = fetchGit {
url = "https://github.com/coq-community/coq-nix-toolbox.git";
ref = "master";
rev = import .nix/coq-nix-toolbox.nix;
};
in
import auto ({inherit src;} // args)
coq-elpi-1.19.3/dune-project 0000664 0000000 0000000 00000000000 14511776522 0015640 0 ustar 00root root 0000000 0000000 coq-elpi-1.19.3/elpi-builtin.elpi 0000664 0000000 0000000 00000114152 14511776522 0016604 0 ustar 00root root 0000000 0000000 % Generated file, do not edit
% == Core builtins =====================================
% -- Logic --
pred true.
true.
pred fail.
pred false.
external pred (=) o:A, o:A. % unification
typeabbrev int (ctype "int").
typeabbrev string (ctype "string").
typeabbrev float (ctype "float").
pred (;) o:prop, o:prop.
(A ; _) :- A.
(_ ; B) :- B.
type (:-) prop -> prop -> prop.
type (:-) prop -> list prop -> prop.
type (,) variadic prop prop.
type uvar A.
type (as) A -> A -> A.
type (=>) prop -> prop -> prop.
type (=>) list prop -> prop -> prop.
% -- Control --
external pred !. % The cut operator
pred not i:prop.
not X :- X, !, fail.
not _.
% [declare_constraint C Key1 Key2...] declares C blocked
% on Key1 Key2 ... (variables, or lists thereof).
external type declare_constraint any -> any -> variadic any prop.
external pred print_constraints. % prints all constraints
% [halt ...] halts the program and print the terms
external type halt variadic any prop.
pred stop.
stop :- halt.
% -- Evaluation --
% [calc Expr Out] unifies Out with the value of Expr. It can be used in
% tandem with spilling, eg [f {calc (N + 1)}]
external pred calc i:A, o:A.
pred (is) o:A, i:A.
X is Y :- calc Y X.
type (-) A -> A -> A.
type (i-) int -> int -> int.
type (r-) float -> float -> float.
type (+) int -> int -> int.
type (+) float -> float -> float.
type (i+) int -> int -> int.
type (r+) float -> float -> float.
type (*) int -> int -> int.
type (*) float -> float -> float.
type (/) float -> float -> float.
type (mod) int -> int -> int.
type (div) int -> int -> int.
type (^) string -> string -> string.
type (~) int -> int.
type (~) float -> float.
type (i~) int -> int.
type (r~) float -> float.
type abs int -> int.
type abs float -> float.
type iabs int -> int.
type rabs float -> float.
type max int -> int -> int.
type max float -> float -> float.
type min int -> int -> int.
type min float -> float -> float.
type sqrt float -> float.
type sin float -> float.
type cos float -> float.
type arctan float -> float.
type ln float -> float.
type int_to_real int -> float.
type floor float -> int.
type ceil float -> int.
type truncate float -> int.
type size string -> int.
type chr int -> string.
type rhc string -> int.
type string_to_int string -> int.
type int_to_string int -> string.
type substring string -> int -> int -> string.
type real_to_string float -> string.
% -- Arithmetic tests --
% [lt_ X Y] checks if X < Y. Works for string, int and float
external pred lt_ i:A, i:A.
% [gt_ X Y] checks if X > Y. Works for string, int and float
external pred gt_ i:A, i:A.
% [le_ X Y] checks if X =< Y. Works for string, int and float
external pred le_ i:A, i:A.
% [ge_ X Y] checks if X >= Y. Works for string, int and float
external pred ge_ i:A, i:A.
type (<), (>), (=<), (>=) A -> A -> prop.
X > Y :- gt_ X Y.
X < Y :- lt_ X Y.
X =< Y :- le_ X Y.
X >= Y :- ge_ X Y.
type (i<), (i>), (i=<), (i>=) int -> int -> prop.
X i< Y :- lt_ X Y.
X i> Y :- gt_ X Y.
X i=< Y :- le_ X Y.
X i>= Y :- ge_ X Y.
type (r<), (r>), (r=<), (r>=) float -> float -> prop.
X r< Y :- lt_ X Y.
X r> Y :- gt_ X Y.
X r=< Y :- le_ X Y.
X r>= Y :- ge_ X Y.
type (s<), (s>), (s=<), (s>=) string -> string -> prop.
X s< Y :- lt_ X Y.
X s> Y :- gt_ X Y.
X s=< Y :- le_ X Y.
X s>= Y :- ge_ X Y.
% -- Standard data types (supported in the FFI) --
kind list type -> type.
type (::) X -> list X -> list X.
type ([]) list X.
% Boolean values: tt and ff since true and false are predicates
kind bool type.
type tt bool.
type ff bool.
% Pair: the constructor is pr, since ',' is for conjunction
kind pair type -> type -> type.
type pr A -> B -> pair A B.
pred fst i:pair A B, o:A.
fst (pr A _) A.
pred snd i:pair A B, o:B.
snd (pr _ B) B.
% The option type (aka Maybe)
kind option type -> type.
type none option A.
type some A -> option A.
% Result of a comparison
kind cmp type.
type eq cmp.
type lt cmp.
type gt cmp.
% Used in builtin variants that return Coq's error rather than failing
kind diagnostic type.
type ok diagnostic. % Success
type error string -> diagnostic. % Failure
% == Elpi builtins =====================================
% [dprint ...] prints raw terms (debugging)
external type dprint variadic any prop.
% [print ...] prints terms
external type print variadic any prop.
% Deprecated, use trace.counter
pred counter i:string, o:int.
counter C N :- trace.counter C N.
% [quote_syntax FileName QueryText QuotedProgram QuotedQuery] quotes the
% program from FileName and the QueryText. See elpi-quoted_syntax.elpi for
% the syntax tree
external pred quote_syntax i:string, i:string, o:list A, o:A.
typeabbrev loc (ctype "Loc.t").
% [loc.fields Loc File StartChar StopChar Line LineStartsAtChar] Decomposes
% a loc into its fields
external pred loc.fields i:loc, o:string, o:int, o:int, o:int, o:int.
% == Regular Expressions =====================================
% [rex.match Rex Subject] checks if Subject matches Rex. Matching is based
% on OCaml's Str library
external pred rex.match i:string, i:string.
% [rex.replace Rex Replacement Subject Out] Out is obtained by replacing all
% occurrences of Rex with Replacement in Subject. See also OCaml's
% Str.global_replace
external pred rex.replace i:string, i:string, i:string, o:string.
% [rex.split Rex Subject Out] Out is obtained by splitting Subject at all
% occurrences of Rex. See also OCaml's Str.split
external pred rex.split i:string, i:string, o:list string.
% Deprecated, use rex.match
pred rex_match i:string, i:string.
rex_match Rx S :- rex.match Rx S.
% Deprecated, use rex.replace
pred rex_replace i:string, i:string, i:string, o:string.
rex_replace Rx R S O :- rex.replace Rx R S O.
% Deprecated, use rex.split
pred rex_split i:string, i:string, o:list string.
rex_split Rx S L :- rex.split Rx S L.
% == Elpi nonlogical builtins =====================================
% Opaque ML data types
kind ctyp type.
type ctype string -> ctyp.
% [var V ...] checks if the term V is a variable. When used with tree
% arguments it relates an applied variable with its head and argument list.
external type var any -> variadic any prop.
% [prune V L] V is pruned to L (V is unified with a variable that only sees
% the list of names L)
external pred prune o:any, i:list any.
% [distinct_names L] checks if L is a list of distinct names. If L is the
% scope of a unification variable (its arguments, as per var predicate) then
% distinct_names L checks that such variable is in the Miller pattern
% fragment (L_\lambda)
external pred distinct_names i:list any.
% [same_var V1 V2] checks if the two terms V1 and V2 are the same variable,
% ignoring the arguments of the variables
external pred same_var i:A, i:A.
% [same_term T1 T2] checks if the two terms T1 and T2 are syntactically
% equal (no unification). It behaves differently than same_var since it
% recursively compares the arguments of the variables
external pred same_term i:A, i:A.
% Infix notation for same_term
pred (==) i:A, i:A.
X == Y :- same_term X Y.
% [cmp_term A B Cmp] Compares A and B. Only works if A and B are ground.
external pred cmp_term i:any, i:any, o:cmp.
% [name T ...] checks if T is a eigenvariable. When used with tree arguments
% it relates an applied name with its head and argument list.
external type name any -> variadic any prop.
% [constant T ...] checks if T is a (global) constant. When used with tree
% arguments it relates an applied constant with its head and argument list.
external type constant any -> variadic any prop.
external pred names % generates the list of eigenvariable
o:list any. % list of eigenvariables in order of age (young first)
external pred occurs % checks if the atom occurs in the term
i:any, % an atom, that is a global constant or a bound name (aka eigenvariable)
i:any. % a term
% [closed_term T] unify T with a variable that has no eigenvariables in
% scope
external pred closed_term o:any.
% [ground_term T] Checks if T contains unification variables
external pred ground_term i:any.
% [is_cdata T Ctype] checks if T is primitive of type Ctype, eg (ctype
% "int")
external pred is_cdata i:any, o:ctyp.
pred primitive? i:A, i:string.
primitive? X S :- is_cdata X (ctype S).
% [new_int N] unifies N with a different int every time it is called. Values
% of N are guaranteed to be incresing.
external pred new_int o:int.
% [findall_solution P L] finds all the solved instances of P and puts them
% in L
% in the order in which they are found. Instances can contain
% eigenvariables
% and unification variables.
external pred findall_solutions i:prop, o:list prop.
% Holds data across bracktracking; can only contain closed terms
typeabbrev safe (ctype "safe").
% [new_safe Safe] creates a safe: a store that persists across backtracking
external pred new_safe o:safe.
% [stash_in_safe Safe Data] stores Data in the Safe
external pred stash_in_safe i:safe, i:A.
% [open_safe Safe Data] retrieves the Data stored in Safe
external pred open_safe i:safe, o:list A.
% [if C T E] picks the first success of C then runs T (never E).
% if C has no success it runs E.
pred if i:prop, i:prop, i:prop.
if B T _ :- B, !, T.
if _ _ E :- E.
% [if2 C1 B1 C2 B2 E] like if but with 2 then branches (and one else branch).
pred if2 i:prop, i:prop, i:prop, i:prop, i:prop.
if2 G1 P1 _ _ _ :- G1, !, P1.
if2 _ _ G2 P2 _ :- G2, !, P2.
if2 _ _ _ _ E :- !, E.
% [random.init Seed] Initialize OCaml's PRNG with the given Seed
external pred random.init i:int.
% [random.self_init] Initialize OCaml's PRNG with some seed
external pred random.self_init .
% [random.int Bound N] unifies N with a random int between 0 and Bound
% (excluded)
external pred random.int i:int, o:int.
#line 0 "builtin_stdlib.elpi"
% == stdlib =======================================================
% Conventions:
% - all predicates declare a mode with some input arguments, unless...
% - predicates whose name ends with R are relations (work in any direction,
% that is all arguments are in output mode)
% - predicates whose name ends with ! do contain a cut and generate only the
% first result
% - all errors given by this library end up calling fatal-error[-w-data],
% override it in order to handle them differently
% - all debug prints by this library end up calling debug-print, override it
% in order to handle them differently
namespace std {
pred fatal-error i:string.
:name "default-fatal-error"
fatal-error Msg :- halt Msg.
pred fatal-error-w-data i:string, i:A.
:name "default-fatal-error-w-data"
fatal-error-w-data Msg Data :- halt Msg ":" Data.
pred debug-print i:string, i:A.
:name "default-debug-print"
debug-print Msg Data :- print Msg Data.
% -- Errors, Debugging, Hacks --
pred ignore-failure! i:prop.
ignore-failure! P :- P, !.
ignore-failure! _.
% [assert! C M] takes the first success of C or fails with message M
pred assert! i:prop, i:string.
assert! Cond Msg :- (Cond ; fatal-error-w-data Msg Cond), !.
% [assert-ok! C M] like assert! but the last argument of the predicate must
% be a diagnostic that is printed after M in case it is not ok
pred assert-ok! i:(diagnostic -> prop), i:string.
assert-ok! Cond Msg :- Cond Diagnostic, !, (Diagnostic = ok ; Diagnostic = error S, fatal-error-w-data Msg S), !.
assert-ok! _ Msg :- fatal-error-w-data Msg "no diagnostic returned".
% [spy P] traces the call to P, printing all success and the final failure
pred spy i:prop.
spy P :- trace.counter "run" NR, if (not(NR = 0)) (debug-print "run=" NR) true,
debug-print "----<<---- enter: " P,
P,
debug-print "---->>---- exit: " P.
spy P :- debug-print "---->>---- fail: " P, fail.
% [spy! P] traces the first call to P without leaving a choice point
pred spy! i:prop.
spy! P :- trace.counter "run" NR, if (not(NR = 0)) (debug-print "run=" NR) true,
debug-print "----<<---- enter: " P,
P,
debug-print "---->>---- exit: " P, !.
spy! P :- debug-print "---->>---- fail: " P, fail.
% to silence the type checker
pred unsafe-cast o:A, o:B.
unsafe-cast X X.
% -- List processing --
pred length i:list A, o:int.
length [_|L] N :- length L N1, N is N1 + 1.
length [] 0.
pred rev i:list A, o:list A.
rev L RL :- rev.aux L [] RL.
rev.aux [X|XS] ACC R :- rev.aux XS [X|ACC] R.
rev.aux [] L L.
pred last i:list A, o:A.
last [] _ :- fatal-error "last on empty list".
last [X] X :- !.
last [_|XS] R :- last XS R.
pred append i:list A, i:list A, o:list A.
append [X|XS] L [X|L1] :- append XS L L1 .
append [] L L .
pred appendR o:list A, o:list A, o:list A.
appendR [X|XS] L [X|L1] :- appendR XS L L1 .
appendR [] L L .
pred take i:int, i:list A, o:list A.
take 0 _ [] :- !.
take N [X|XS] [X|L] :- !, N1 is N - 1, take N1 XS L.
take _ _ _ :- fatal-error "take run out of list items".
pred take-last i:int, i:list A, o:list A.
take-last N L R :-
length L M,
D is M - N,
drop D L R.
pred drop i:int, i:list A, o:list A.
drop 0 L L :- !.
drop N [_|XS] L :- !, N1 is N - 1, drop N1 XS L.
drop _ _ _ :- fatal-error "drop run out of list items".
pred drop-last i:int, i:list A, o:list A.
drop-last N L R :-
length L M, I is M - N, take I L R.
pred split-at i:int, i:list A, o:list A, o:list A.
split-at 0 L [] L :- !.
split-at N [X|XS] [X|LN] LM :- !, N1 is N - 1, split-at N1 XS LN LM.
split-at _ _ _ _ :- fatal-error "split-at run out of list items".
pred fold i:list B, i:A, i:(B -> A -> A -> prop), o:A.
fold [] A _ A.
fold [X|XS] A F R :- F X A A1, fold XS A1 F R.
pred fold2 i:list C, i:list B, i:A, i:(C -> B -> A -> A -> prop), o:A.
fold2 [] [_|_] _ _ _ :- fatal-error "fold2 on lists of different length".
fold2 [_|_] [] _ _ _ :- fatal-error "fold2 on lists of different length".
fold2 [] [] A _ A.
fold2 [X|XS] [Y|YS] A F R :- F X Y A A1, fold2 XS YS A1 F R.
pred map i:list A, i:(A -> B -> prop), o:list B.
map [] _ [].
map [X|XS] F [Y|YS] :- F X Y, map XS F YS.
pred map-i i:list A, i:(int -> A -> B -> prop), o:list B.
map-i L F R :- map-i.aux L 0 F R.
map-i.aux [] _ _ [].
map-i.aux [X|XS] N F [Y|YS] :- F N X Y, M is N + 1, map-i.aux XS M F YS.
pred map-filter i:list A, i:(A -> B -> prop), o:list B.
map-filter [] _ [].
map-filter [X|XS] F [Y|YS] :- F X Y, !, map-filter XS F YS.
map-filter [_|XS] F YS :- map-filter XS F YS.
:index(1 1)
pred map2 i:list A, i:list B, i:(A -> B -> C -> prop), o:list C.
map2 [] [_|_] _ _ :- fatal-error "map2 on lists of different length".
map2 [_|_] [] _ _ :- fatal-error "map2 on lists of different length".
map2 [] [] _ [].
map2 [X|XS] [Y|YS] F [Z|ZS] :- F X Y Z, map2 XS YS F ZS.
pred map2-filter i:list A, i:list B, i:(A -> B -> C -> prop), o:list C.
map2-filter [] [_|_] _ _ :- fatal-error "map2-filter on lists of different length".
map2-filter [_|_] [] _ _ :- fatal-error "map2-filter on lists of different length".
map2-filter [] [] _ [].
map2-filter [X|XS] [Y|YS] F [Z|ZS] :- F X Y Z, !, map2-filter XS YS F ZS.
map2-filter [_|XS] [_|YS] F ZS :- map2-filter XS YS F ZS.
pred map-ok i:list A, i:(A -> B -> diagnostic -> prop), o:list A, o:diagnostic.
map-ok [X|L] P [Y|YS] S :- P X Y S0, if (S0 = ok) (map-ok L P YS S) (S = S0).
map-ok [] _ [] ok.
pred fold-map i:list A, i:B, i:(A -> B -> C -> B -> prop), o:list C, o:B.
fold-map [] A _ [] A.
fold-map [X|XS] A F [Y|YS] A2 :- F X A Y A1, fold-map XS A1 F YS A2.
pred omap i:option A, i:(A -> B -> prop), o:option B.
omap none _ none.
omap (some X) F (some Y) :- F X Y.
% [nth N L X] picks in X the N-th element of L (L must be of length > N)
pred nth i:int, i:list A, o:A.
nth 0 [X|_ ] R :- !, X = R.
nth N [_|XS] R :- N > 0, !, N1 is N - 1, nth N1 XS R.
nth N _ _ :- N < 0, !, fatal-error "nth got a negative index".
nth _ _ _ :- fatal-error "nth run out of list items".
% [lookup L K V] sees L as a map from K to V
pred lookup i:list (pair A B), i:A, o:B.
lookup [pr X Y|_] X Y.
lookup [_|LS] X Y :- lookup LS X Y.
% [lookup! L K V] sees L as a map from K to V, stops at the first binding
pred lookup! i:list (pair A B), i:A, o:B.
lookup! [pr X Y|_] X Y :- !.
lookup! [_|LS] X Y :- lookup! LS X Y.
% [mem! L X] succeeds once if X occurs inside L
pred mem! i:list A, o:A.
mem! [X|_] X :- !.
mem! [_|L] X :- mem! L X.
% [mem L X] succeeds every time if X occurs inside L
pred mem i:list A, o:A.
mem [X|_] X.
mem [_|L] X :- mem L X.
pred exists i:list A, i:(A -> prop).
exists [X|_] P :- P X.
exists [_|L] P :- exists L P.
pred exists2 i:list A, i:list B, i:(A -> B -> prop).
exists2 [] [_|_] _ :- fatal-error "exists2 on lists of different length".
exists2 [_|_] [] _ :- fatal-error "exists2 on lists of different length".
exists2 [X|_] [Y|_] P :- P X Y.
exists2 [_|L] [_|M] P :- exists2 L M P.
pred forall i:list A, i:(A -> prop).
forall [] _.
forall [X|L] P :- P X, forall L P.
pred forall-ok i:list A, i:(A -> diagnostic -> prop), o:diagnostic.
forall-ok [X|L] P S :- P X S0, if (S0 = ok) (forall-ok L P S) (S = S0).
forall-ok [] _ ok.
pred forall2 i:list A, i:list B, i:(A -> B -> prop).
forall2 [] [_|_] _ :- fatal-error "forall2 on lists of different length".
forall2 [_|_] [] _ :- fatal-error "forall2 on lists of different length".
forall2 [X|XS] [Y|YS] P :- P X Y, forall2 XS YS P.
forall2 [] [] _.
pred filter i:list A, i:(A -> prop), o:list A.
filter [] _ [].
filter [X|L] P R :- if (P X) (R = X :: L1) (R = L1), filter L P L1.
pred zip i:list A, i:list B, o:list (pair A B).
zip [_|_] [] _ :- fatal-error "zip on lists of different length".
zip [] [_|_] _ :- fatal-error "zip on lists of different length".
zip [X|LX] [Y|LY] [pr X Y|LR] :- zip LX LY LR.
zip [] [] [].
pred unzip i:list (pair A B), o:list A, o:list B.
unzip [] [] [].
unzip [pr X Y|L] [X|LX] [Y|LY] :- unzip L LX LY.
pred flatten i:list (list A), o:list A.
flatten [X|LS] R :- flatten LS LS', append X LS' R.
flatten [] [].
pred null i:list A.
null [].
pred iota i:int, o:list int.
iota N L :- iota.aux 0 N L.
iota.aux X X [] :- !.
iota.aux N X [N|R] :- M is N + 1, iota.aux M X R.
% [intersperse X L R] R is [L0, X, ..., X, LN]
:index(_ 1)
pred intersperse i:A, i:list A, o:list A.
intersperse _ [] [].
intersperse _ [X] [X] :- !.
intersperse Sep [X|XS] [X,Sep|YS] :- intersperse Sep XS YS.
% -- Misc --
pred flip i:(A -> B -> prop), i:B, i:A.
flip P X Y :- P Y X.
pred time i:prop, o:float.
time P T :- gettimeofday Before, P, gettimeofday After, T is After - Before.
pred do! i:list prop.
do! [].
do! [P|PS] :- P, !, do! PS.
:index(_ 1)
pred do-ok! o:diagnostic, i:list (diagnostic -> prop).
do-ok! ok [].
do-ok! S [P|PS] :- P S0, !, if (S0 = ok) (do-ok! S PS) (S = S0).
pred lift-ok i:prop, i:string, o:diagnostic.
lift-ok P Msg R :- (P, R = ok; R = error Msg).
pred spy-do! i:list prop.
spy-do! L :- map L (x\y\y = spy x) L1, do! L1.
pred while-ok-do! i:diagnostic, i:list (diagnostic -> prop), o:diagnostic.
while-ok-do! (error _ as E) _ E.
while-ok-do! ok [] ok.
while-ok-do! ok [P|PS] R :- P C, !, while-ok-do! C PS R.
pred any->string i:A, o:string.
any->string X Y :- term_to_string X Y.
pred max i:A, i:A, o:A.
max N M N :- N >= M, !.
max _ M M.
% [findall P L] L is the list [P1,P2,P3..] where each Pi is a solution to P.
pred findall i:prop, o:list prop.
findall P L :- findall_solutions P L.
}
% [std.string.concat Separator Items Result] concatenates Items
% interspersing Separator
external pred std.string.concat i:string, i:list string, o:string.
% CAVEAT: the type parameter of std.string.map must be a closed term
kind std.string.map type -> type.
% [std.string.map.empty M] The empty map
external pred std.string.map.empty o:std.string.map A.
% [std.string.map.mem S M] Checks if S is bound in M
external pred std.string.map.mem i:string, i:std.string.map A.
% [std.string.map.add S V M M1] M1 is M where V is bound to S
external pred std.string.map.add i:string, i:A, i:std.string.map A,
o:std.string.map A.
% [std.string.map.remove S M M1] M1 is M where S is unbound
external pred std.string.map.remove i:string, i:std.string.map A,
o:std.string.map A.
% [std.string.map.find S M V] V is the binding of S in M
external pred std.string.map.find i:string, i:std.string.map A, o:A.
% [std.string.map.bindings M L] L is M transformed into an associative list
external pred std.string.map.bindings i:std.string.map A,
o:list (pair string A).
% CAVEAT: the type parameter of std.int.map must be a closed term
kind std.int.map type -> type.
% [std.int.map.empty M] The empty map
external pred std.int.map.empty o:std.int.map A.
% [std.int.map.mem S M] Checks if S is bound in M
external pred std.int.map.mem i:int, i:std.int.map A.
% [std.int.map.add S V M M1] M1 is M where V is bound to S
external pred std.int.map.add i:int, i:A, i:std.int.map A,
o:std.int.map A.
% [std.int.map.remove S M M1] M1 is M where S is unbound
external pred std.int.map.remove i:int, i:std.int.map A, o:std.int.map A.
% [std.int.map.find S M V] V is the binding of S in M
external pred std.int.map.find i:int, i:std.int.map A, o:A.
% [std.int.map.bindings M L] L is M transformed into an associative list
external pred std.int.map.bindings i:std.int.map A, o:list (pair int A).
% CAVEAT: the type parameter of std.loc.map must be a closed term
kind std.loc.map type -> type.
% [std.loc.map.empty M] The empty map
external pred std.loc.map.empty o:std.loc.map A.
% [std.loc.map.mem S M] Checks if S is bound in M
external pred std.loc.map.mem i:loc, i:std.loc.map A.
% [std.loc.map.add S V M M1] M1 is M where V is bound to S
external pred std.loc.map.add i:loc, i:A, i:std.loc.map A,
o:std.loc.map A.
% [std.loc.map.remove S M M1] M1 is M where S is unbound
external pred std.loc.map.remove i:loc, i:std.loc.map A, o:std.loc.map A.
% [std.loc.map.find S M V] V is the binding of S in M
external pred std.loc.map.find i:loc, i:std.loc.map A, o:A.
% [std.loc.map.bindings M L] L is M transformed into an associative list
external pred std.loc.map.bindings i:std.loc.map A, o:list (pair loc A).
kind std.string.set type.
% [std.string.set.empty A] The empty set
external pred std.string.set.empty o:std.string.set.
% [std.string.set.mem Elem A] Checks if Elem is in a
external pred std.string.set.mem i:string, i:std.string.set.
% [std.string.set.add Elem A B] B is A union {Elem}
external pred std.string.set.add i:string, i:std.string.set,
o:std.string.set.
% [std.string.set.remove Elem A B] B is A \ {Elem}
external pred std.string.set.remove i:string, i:std.string.set,
o:std.string.set.
% [std.string.set.union A B X] X is A union B
external pred std.string.set.union i:std.string.set, i:std.string.set,
o:std.string.set.
% [std.string.set.inter A B X] X is A intersection B
external pred std.string.set.inter i:std.string.set, i:std.string.set,
o:std.string.set.
% [std.string.set.diff A B X] X is A \ B
external pred std.string.set.diff i:std.string.set, i:std.string.set,
o:std.string.set.
% [std.string.set.equal A B] tests A and B for equality
external pred std.string.set.equal i:std.string.set, i:std.string.set.
% [std.string.set.subset A B] tests if A is a subset of B
external pred std.string.set.subset i:std.string.set, i:std.string.set.
% [std.string.set.elements M L] L is M transformed into list
external pred std.string.set.elements i:std.string.set, o:list string.
% [std.string.set.cardinal M N] N is the number of elements of M
external pred std.string.set.cardinal i:std.string.set, o:int.
kind std.int.set type.
% [std.int.set.empty A] The empty set
external pred std.int.set.empty o:std.int.set.
% [std.int.set.mem Elem A] Checks if Elem is in a
external pred std.int.set.mem i:int, i:std.int.set.
% [std.int.set.add Elem A B] B is A union {Elem}
external pred std.int.set.add i:int, i:std.int.set, o:std.int.set.
% [std.int.set.remove Elem A B] B is A \ {Elem}
external pred std.int.set.remove i:int, i:std.int.set, o:std.int.set.
% [std.int.set.union A B X] X is A union B
external pred std.int.set.union i:std.int.set, i:std.int.set,
o:std.int.set.
% [std.int.set.inter A B X] X is A intersection B
external pred std.int.set.inter i:std.int.set, i:std.int.set,
o:std.int.set.
% [std.int.set.diff A B X] X is A \ B
external pred std.int.set.diff i:std.int.set, i:std.int.set,
o:std.int.set.
% [std.int.set.equal A B] tests A and B for equality
external pred std.int.set.equal i:std.int.set, i:std.int.set.
% [std.int.set.subset A B] tests if A is a subset of B
external pred std.int.set.subset i:std.int.set, i:std.int.set.
% [std.int.set.elements M L] L is M transformed into list
external pred std.int.set.elements i:std.int.set, o:list int.
% [std.int.set.cardinal M N] N is the number of elements of M
external pred std.int.set.cardinal i:std.int.set, o:int.
kind std.loc.set type.
% [std.loc.set.empty A] The empty set
external pred std.loc.set.empty o:std.loc.set.
% [std.loc.set.mem Elem A] Checks if Elem is in a
external pred std.loc.set.mem i:loc, i:std.loc.set.
% [std.loc.set.add Elem A B] B is A union {Elem}
external pred std.loc.set.add i:loc, i:std.loc.set, o:std.loc.set.
% [std.loc.set.remove Elem A B] B is A \ {Elem}
external pred std.loc.set.remove i:loc, i:std.loc.set, o:std.loc.set.
% [std.loc.set.union A B X] X is A union B
external pred std.loc.set.union i:std.loc.set, i:std.loc.set,
o:std.loc.set.
% [std.loc.set.inter A B X] X is A intersection B
external pred std.loc.set.inter i:std.loc.set, i:std.loc.set,
o:std.loc.set.
% [std.loc.set.diff A B X] X is A \ B
external pred std.loc.set.diff i:std.loc.set, i:std.loc.set,
o:std.loc.set.
% [std.loc.set.equal A B] tests A and B for equality
external pred std.loc.set.equal i:std.loc.set, i:std.loc.set.
% [std.loc.set.subset A B] tests if A is a subset of B
external pred std.loc.set.subset i:std.loc.set, i:std.loc.set.
% [std.loc.set.elements M L] L is M transformed into list
external pred std.loc.set.elements i:std.loc.set, o:list loc.
% [std.loc.set.cardinal M N] N is the number of elements of M
external pred std.loc.set.cardinal i:std.loc.set, o:int.
#line 0 "builtin_map.elpi"
kind std.map type -> type -> type.
type std.map std.map.private.map K V -> (K -> K -> cmp -> prop) -> std.map K V.
namespace std.map {
% [make Eq Ltn M] builds an empty map M where keys are compared using Eq and Ltn
pred make i:(K -> K -> cmp -> prop), o:std.map K V.
make Cmp (std.map private.empty Cmp).
% [find K M V] looks in M for the value V associated to K
pred find i:K, i:std.map K V, o:V.
find K (std.map M Cmp) V :- private.find M Cmp K V.
% [add K V M M1] M1 is M where K is bound to V
pred add i:K, i:V, i:std.map K V, o:std.map K V.
add K V (std.map M Cmp) (std.map M1 Cmp) :- private.add M Cmp K V M1.
% [remove K M M1] M1 is M where K is unbound
pred remove i:K, i:std.map K V, o:std.map K V.
remove K (std.map M Cmp) (std.map M1 Cmp) :- private.remove M Cmp K M1.
% [bindings M L] L is the key-value pairs in increasing order
pred bindings i:std.map K V, o:list (pair K V).
bindings (std.map M _) L :- private.bindings M [] L.
namespace private {
% Taken from OCaml's map.ml
kind map type -> type -> type.
type empty map K V.
type node map K V -> K -> V -> map K V -> int -> map K V.
pred height i:map K V, o:int.
height empty 0.
height (node _ _ _ _ H) H.
pred create i:map K V, i:K, i:V, i:map K V, o:map K V.
create L K V R (node L K V R H) :- H is {std.max {height L} {height R}} + 1.
pred bal i:map K V, i:K, i:V, i:map K V, o:map K V.
bal L K V R T :-
height L HL,
height R HR,
HL2 is HL + 2,
HR2 is HR + 2,
bal.aux HL HR HL2 HR2 L K V R T.
bal.aux HL _ _ HR2 (node LL LV LD LR _) X D R T :-
HL > HR2, {height LL} >= {height LR}, !,
create LL LV LD {create LR X D R} T.
bal.aux HL _ _ HR2 (node LL LV LD (node LRL LRV LRD LRR _) _) X D R T :-
HL > HR2, !,
create {create LL LV LD LRL} LRV LRD {create LRR X D R} T.
bal.aux _ HR HL2 _ L X D (node RL RV RD RR _) T :-
HR > HL2, {height RR} >= {height RL}, !,
create {create L X D RL} RV RD RR T.
bal.aux _ HR HL2 _ L X D (node (node RLL RLV RLD RLR _) RV RD RR _) T :-
HR > HL2, !,
create {create L X D RLL} RLV RLD {create RLR RV RD RR} T.
bal.aux _ _ _ _ L K V R T :- create L K V R T.
pred add i:map K V, i:(K -> K -> cmp -> prop), i:K, i:V, o:map K V.
add empty _ K V T :- create empty K V empty T.
add (node _ X _ _ _ as M) Cmp X1 XD M1 :- Cmp X1 X E, add.aux E M Cmp X1 XD M1.
add.aux eq (node L _ _ R H) _ X XD T :- T = node L X XD R H.
add.aux lt (node L V D R _) Cmp X XD T :- bal {add L Cmp X XD} V D R T.
add.aux gt (node L V D R _) Cmp X XD T :- bal L V D {add R Cmp X XD} T.
pred find i:map K V, i:(K -> K -> cmp -> prop), i:K, o:V.
find (node L K1 V1 R _) Cmp K V :- Cmp K K1 E, find.aux E Cmp L R V1 K V.
find.aux eq _ _ _ V _ V.
find.aux lt Cmp L _ _ K V :- find L Cmp K V.
find.aux gt Cmp _ R _ K V :- find R Cmp K V.
pred remove-min-binding i:map K V, o:map K V.
remove-min-binding (node empty _ _ R _) R :- !.
remove-min-binding (node L V D R _) X :- bal {remove-min-binding L} V D R X.
pred min-binding i:map K V, o:K, o:V.
min-binding (node empty V D _ _) V D :- !.
min-binding (node L _ _ _ _) V D :- min-binding L V D.
pred merge i:map K V, i:map K V, o:map K V.
merge empty X X :- !.
merge X empty X :- !.
merge M1 M2 R :-
min-binding M2 X D,
bal M1 X D {remove-min-binding M2} R.
pred remove i:map K V, i:(K -> K -> cmp -> prop), i:K, o:map K V.
remove empty _ _ empty :- !.
remove (node L V D R _) Cmp X M :- Cmp X V E, remove.aux E Cmp L R V D X M.
remove.aux eq _ L R _ _ _ M :- merge L R M.
remove.aux lt Cmp L R V D X M :- bal {remove L Cmp X} V D R M.
remove.aux gt Cmp L R V D X M :- bal L V D {remove R Cmp X} M.
pred bindings i:map K V, i:list (pair K V), o:list (pair K V).
bindings empty X X.
bindings (node L V D R _) X X1 :-
bindings L [pr V D|{bindings R X}] X1.
} % std.map.private
} % std.map
#line 0 "builtin_set.elpi"
kind std.set type -> type.
type std.set std.set.private.set E -> (E -> E -> cmp -> prop) -> std.set E.
namespace std.set {
% [make Eq Ltn M] builds an empty set M where keys are compared using Eq and Ltn
pred make i:(E -> E -> cmp -> prop), o:std.set E.
make Cmp (std.set private.empty Cmp).
% [mem E M] looks if E is in M
pred mem i:E, i:std.set E.
mem E (std.set M Cmp):- private.mem M Cmp E.
% [add E M M1] M1 is M + {E}
pred add i:E, i:std.set E, o:std.set E.
add E (std.set M Cmp) (std.set M1 Cmp) :- private.add M Cmp E M1.
% [remove E M M1] M1 is M - {E}
pred remove i:E, i:std.set E, o:std.set E.
remove E (std.set M Cmp) (std.set M1 Cmp) :- private.remove M Cmp E M1.
% [cardinal S N] N is the number of elements of S
pred cardinal i:std.set E, o:int.
cardinal (std.set M _) N :- private.cardinal M N.
pred elements i:std.set E, o:list E.
elements (std.set M _) L :- private.elements M [] L.
namespace private {
% Taken from OCaml's set.ml
kind set type -> type.
type empty set E.
type node set E -> E -> set E -> int -> set E.
pred height i:set E, o:int.
height empty 0.
height (node _ _ _ H) H.
pred create i:set E, i:E, i:set E, o:set E.
create L E R (node L E R H) :- H is {std.max {height L} {height R}} + 1.
pred bal i:set E, i:E, i:set E, o:set E.
bal L E R T :-
height L HL,
height R HR,
HL2 is HL + 2,
HR2 is HR + 2,
bal.aux HL HR HL2 HR2 L E R T.
bal.aux HL _ _ HR2 (node LL LV LR _) X R T :-
HL > HR2, {height LL} >= {height LR}, !,
create LL LV {create LR X R} T.
bal.aux HL _ _ HR2 (node LL LV (node LRL LRV LRR _) _) X R T :-
HL > HR2, !,
create {create LL LV LRL} LRV {create LRR X R} T.
bal.aux _ HR HL2 _ L X (node RL RV RR _) T :-
HR > HL2, {height RR} >= {height RL}, !,
create {create L X RL} RV RR T.
bal.aux _ HR HL2 _ L X (node (node RLL RLV RLR _) RV RR _) T :-
HR > HL2, !,
create {create L X RLL} RLV {create RLR RV RR} T.
bal.aux _ _ _ _ L E R T :- create L E R T.
pred add i:set E, i:(E -> E -> cmp -> prop), i:E, o:set E.
add empty _ E T :- create empty E empty T.
add (node L X R H) Cmp X1 S :- Cmp X1 X E, add.aux E Cmp L R X X1 H S.
add.aux eq _ L R X _ H (node L X R H).
add.aux lt Cmp L R E X _ T :- bal {add L Cmp X} E R T.
add.aux gt Cmp L R E X _ T :- bal L E {add R Cmp X} T.
pred mem i:set E, i:(E -> E -> cmp -> prop), i:E.
mem (node L K R _) Cmp E :- Cmp E K O, mem.aux O Cmp L R E.
mem.aux eq _ _ _ _.
mem.aux lt Cmp L _ E :- mem L Cmp E.
mem.aux gt Cmp _ R E :- mem R Cmp E.
pred remove-min-binding i:set E, o:set E.
remove-min-binding (node empty _ R _) R :- !.
remove-min-binding (node L E R _) X :- bal {remove-min-binding L} E R X.
pred min-binding i:set E, o:E.
min-binding (node empty E _ _) E :- !.
min-binding (node L _ _ _) E :- min-binding L E.
pred merge i:set E, i:set E, o:set E.
merge empty X X :- !.
merge X empty X :- !.
merge M1 M2 R :-
min-binding M2 X,
bal M1 X {remove-min-binding M2} R.
pred remove i:set E, i:(E -> E -> cmp -> prop), i:E, o:set E.
remove empty _ _ empty.
remove (node L E R _) Cmp X M :- Cmp X E O, remove.aux O Cmp L R E X M.
remove.aux eq _ L R _ _ M :- merge L R M.
remove.aux lt Cmp L R E X M :- bal {remove L Cmp X} E R M.
remove.aux gt Cmp L R E X M :- bal L E {remove R Cmp X} M.
pred cardinal i:set E, o:int.
cardinal empty 0.
cardinal (node L _ R _) N :- N is {cardinal L} + 1 + {cardinal R}.
pred elements i:set E, i:list E, o:list E.
elements empty X X.
elements (node L E R _) Acc X :-
elements L [E|{elements R Acc}] X.
} % std.set.private
} % std.set
% == I/O builtins =====================================
% -- I/O --
typeabbrev in_stream (ctype "in_stream").
type std_in in_stream.
typeabbrev out_stream (ctype "out_stream").
type std_out out_stream.
type std_err out_stream.
% [open_in FileName InStream] opens FileName for input
external pred open_in i:string, o:in_stream.
% [open_out FileName OutStream] opens FileName for output
external pred open_out i:string, o:out_stream.
% [open_append FileName OutStream] opens FileName for output in append mode
external pred open_append i:string, o:out_stream.
% [close_in InStream] closes input stream InStream
external pred close_in i:in_stream.
% [close_out OutStream] closes output stream OutStream
external pred close_out i:out_stream.
% [output OutStream Data] writes Data to OutStream
external pred output i:out_stream, i:string.
% [flush OutStream] flush all output not yet finalized to OutStream
external pred flush i:out_stream.
% [input InStream Bytes Data] reads Bytes from InStream
external pred input i:in_stream, i:int, o:string.
% [input_line InStream Line] reads a full line from InStream
external pred input_line i:in_stream, o:string.
% [eof InStream] checks if no more data can be read from InStream
external pred eof i:in_stream.
% -- System --
% [gettimeofday T] sets T to the number of seconds elapsed since 1/1/1970
external pred gettimeofday o:float.
% [getenv VarName Value] Like Sys.getenv
external pred getenv i:string, o:option string.
% [system Command RetVal] executes Command and sets RetVal to the exit code
external pred system i:string, o:int.
% -- Unix --
% gathers the standard file descriptors or a process
kind unix.process type.
type unix.process out_stream -> in_stream -> in_stream -> unix.process.
% [unix.process.open Executable Arguments Environment P Diagnostic] OCaml's
% Unix.open_process_args_full.
% Note that the first argument is the executable name (as in argv[0]).
% If Executable is omitted it defaults to the first element of
% Arguments.
% Environment can be left unspecified, defaults to the current process
% environment.
% This API only works reliably since OCaml 4.12.
external pred unix.process.open i:string, i:list string, i:list string,
o:unix.process, o:diagnostic.
% [unix.process.close P Diagnostic] OCaml's Unix.close_process_full
external pred unix.process.close i:unix.process, o:diagnostic.
% -- Debugging --
% [term_to_string T S] prints T to S
external pred term_to_string i:any, o:string.
% == Elpi runtime builtins =====================================
% [trace.counter Name Value] reads the Value of a trace point Name
external pred trace.counter i:string, o:int.
% [gc.get MinorHeapSize MajorHeapIncrement SpaceOverhead Verbose MaxOverhead
% StackLimit AllocationPolicy WindowSize] Reads the current settings of the
% garbage collector. See also OCaml's Gc.control type documentation.
external pred gc.get o:int, o:int, o:int, o:int, o:int, o:int, o:int,
o:int.
% [gc.set MinorHeapSize MajorHeapIncrement SpaceOverhead Verbose MaxOverhead
% StackLimit AllocationPolicy WindowSize] Writes the current settings of the
% garbage collector. Any parameter left unspecificed (eg _) is not changed.
% See also OCaml's Gc.control type documentation.
external pred gc.set i:int, i:int, i:int, i:int, i:int, i:int, i:int,
i:int.
% [gc.minor] See OCaml's Gc.minor documentation.
external pred gc.minor .
% [gc.major] See OCaml's Gc.major documentation.
external pred gc.major .
% [gc.full] See OCaml's Gc.full_major documentation.
external pred gc.full .
% [gc.compact] See OCaml's Gc.compact documentation.
external pred gc.compact .
% [gc.stat MinorWords PromotedWords MajorWords MinorCollections
% MajorCollections HeapWords HeapChunks LiveWords LiveBlocks FreeWords
% FreeBlocks LargestFree Fragments Compactions TopHeapWords StackSize] See
% OCaml's Gc.stat documentation.
external pred gc.stat o:float, o:float, o:float, o:int, o:int, o:int,
o:int, o:int, o:int, o:int, o:int, o:int, o:int,
o:int, o:int, o:int.
% [gc.quick-stat MinorWords PromotedWords MajorWords MinorCollections
% MajorCollections HeapWords HeapChunks Compactions TopHeapWords StackSize]
% See OCaml's Gc.quick_stat documentation.
external pred gc.quick-stat o:float, o:float, o:float, o:int, o:int,
o:int, o:int, o:int, o:int, o:int.
% == Lambda Prolog builtins =====================================
% -- Extra I/O --
% [open_string DataIn InStream] opens DataIn as an input stream
external pred open_string i:string, o:in_stream.
% [lookahead InStream NextChar] peeks one byte from InStream
external pred lookahead i:in_stream, o:string.
% -- Hacks --
% [string_to_term S T] parses a term T from S
external pred string_to_term i:string, o:any.
% [readterm InStream T] reads T from InStream, ends with \n
external pred readterm i:in_stream, o:any.
pred printterm i:out_stream, i:A.
printterm S T :- term_to_string T T1, output S T1.
pred read o:A.
read S :- flush std_out, input_line std_in X, string_to_term X S.
coq-elpi-1.19.3/elpi/ 0000775 0000000 0000000 00000000000 14511776522 0014261 5 ustar 00root root 0000000 0000000 coq-elpi-1.19.3/elpi/README.md 0000664 0000000 0000000 00000001537 14511776522 0015546 0 ustar 00root root 0000000 0000000 ### coq-HOAS
Documents how Coq terms are represented in Elpi.
### coq-lib
Standard library of Coq specific utilities (in the coq. namespace).
### elpi-command-template
Selects which files are accumulated in an `Elpi Command`.
### elpi-tactic-template
Selects which files are accumulated in an `Elpi Tactic`.
### coq-elpi-checker
Extends the standard type checker for Elpi programs so that it reports
errors using Coq's I/O primitives.
### elpi-ltac
Implementation of Ltac's like combinators in Elpi.
### elpi-reduction
Implementation of reduction in Elpi. Main entry points are `whd` and `hd-beta`.
### coq-elaborator
Uses the Coq type inference and unification algorithms in order to implement
`of`, `unify-*` and `evar`.
### elpi-elaborator
An elaborator completely written in Elpi (work in progress). It implements
`of`, `unify-*` and `evar`.
coq-elpi-1.19.3/elpi/coq-HOAS.elpi 0000664 0000000 0000000 00000047532 14511776522 0016461 0 ustar 00root root 0000000 0000000 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% coq-HOAS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This section contains the low level data types linking Coq and elpi.
% In particular:
% - the data type for terms and the evar_map entries (a sequent)
% - the entry points for commands and tactics (main and solve)
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Entry points
%
% Command and tactic invocation
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Entry point for commands. Eg. "#[att=true] Elpi mycommand foo 3 (f x)." becomes
% main [str "foo", int 3, trm (app[f,x])]
% in a context where
% attributes [attribute "att" (leaf "true")]
% holds. The encoding of terms is described below.
% See also the coq.parse-attributes utility.
pred main i:list argument.
pred usage.
pred attributes o:list attribute.
% Entry point for tactics. Eg. "elpi mytactic foo 3 (f x)." becomes
% solve
% Where [str "foo", int 3, trm (app[f,x])] is part of .
% The encoding of goals is described below.
% msolve is for tactics that operate on multiple goals (called via all: ).
pred solve i:goal, o:list sealed-goal.
pred msolve i:list sealed-goal, o:list sealed-goal.
% The data type of arguments (for commands or tactics)
kind argument type.
type int int -> argument. % Eg. 1 -2.
type str string -> argument. % Eg. x "y" z.w. or any Coq keyword/symbol
type trm term -> argument. % Eg. (t).
% Extra arguments for tactics
type tac ltac1-tactic -> argument.
% Extra arguments for commands. [Definition], [Axiom], [Record] and [Context]
% take precedence over the [str] argument above (when not "quoted").
%
% Eg. Record or Inductive
type indt-decl indt-decl -> argument.
% Eg. #[universes(polymorphic,...)] Record or Inductive
type upoly-indt-decl indt-decl -> upoly-decl -> argument.
type upoly-indt-decl indt-decl -> upoly-decl-cumul -> argument.
% Eg. Definition or Axiom (when the body is none)
type const-decl id -> option term -> arity -> argument.
% Eg. #[universes(polymorphic,...)] Definition or Axiom
type upoly-const-decl id -> option term -> arity -> upoly-decl -> argument.
% Eg. Context A (b : A).
type ctx-decl context-decl -> argument.
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Coq's terms
%
% Types of term formers
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% -- terms --------------------------------------------------------------------
kind term type.
type sort sort -> term. % Prop, Type@{i}
% constants: inductive types, inductive constructors, definitions
type global gref -> term.
type pglobal gref -> univ-instance -> term.
% binders: to form functions, arities and local definitions
type fun name -> term -> (term -> term) -> term. % fun x : t =>
type prod name -> term -> (term -> term) -> term. % forall x : t,
type let name -> term -> term -> (term -> term) -> term. % let x : T := v in
% other term formers: function application, pattern matching and recursion
type app list term -> term. % app [hd|args]
type match term -> term -> list term -> term. % match t p [branch])
type fix name -> int -> term -> (term -> term) -> term. % fix name rno ty bo
type primitive primitive-value -> term.
% NYI
%type cofix name -> term -> (term -> term) -> term. % cofix name ty bo
% Notes about (match Scrutinee TypingFunction Branches) when
% Inductive i A : A -> nat -> Type := K : forall a : A, i A a 0
% and
% Scrutinee be a term of type (i bool true 7)
%
% - TypingFunction has a very rigid shape that depends on i. Namely
% as many lambdas as indexes plus one lambda for the inductive itself
% where the value of the parameters are taken from the type of the scrutinee:
% fun `a` (indt "bool") a\
% fun `n` (indt "nat) n\
% fun `i` (app[indt "i", indt "bool", a n) i\ ..
% Such spine of fun cannot be omitted; else elpi cannot read the term back.
% See also coq.bind-ind-arity-no-let in coq-lib.elpi, that builds such spine for you,
% or the higher level api coq.build-match (same file) that also takes
% care of breanches.
% - Branches is a list of terms, the order is the canonical one (the order
% of the constructors as they were declared). If the constructor has arguments
% (excluding the parameters) then the corresponding term shall be a Coq
% function. In this case
% fun `x` (indt "bool") x\ ..
% -- helpers ------------------------------------------------------------------
macro @cast T TY :- (let `cast` TY T x\x).
% -- misc ---------------------------------------------------------------------
% When one writes Constraint Handling Rules unification variables are "frozen",
% i.e. represented by a fresh constant (the evar key) and a list of terms
% (typically the variables in scope).
kind evarkey type.
type uvar evarkey -> list term -> term.
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Coq's evar_map
%
% Context and evar declaration
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% An evar_info (displayed as a Coq goal) is essentially a sequent:
%
% x : t
% y := v : x
% ----------
% p x y
%
% is coded as an Elpi query
%
% pi x1\ decl x1 `x` =>
% pi x2\ def x2 `y` x1 =>
% declare-evar
% [def x2 `y` x1 , decl x1 `x` ]
% (RawEvar x1 x2) ( x1 x2) (Ev x1 x2)
%
% where, by default, declare-evar creates a syntactic constraint as
%
% {x1 x2} :
% decl x1 `x` , def x2 `y` x1 ?-
% evar (RawEvar x1 x2) ( x1 x2) (Ev x1 x2) /* suspended on RawEvar, Ev */
%
% When the program is over, a remaining syntactic constraint like the one above
% is read back and transformed into the corresponding evar_info.
pred decl i:term, o:name, o:term. % Var Name Ty
pred def i:term, o:name, o:term, o:term. % Var Name Ty Bo
pred declare-evar i:list prop, i:term, i:term, i:term. % Ctx RawEvar Ty Evar
:name "default-declare-evar"
declare-evar Ctx RawEv Ty Ev :-
declare_constraint (declare-evar Ctx RawEv Ty Ev) [RawEv].
% When a goal (evar _ _ _) is turned into a constraint the context is filtered
% to only contain decl, def, pp. For now no handling rules for this set of
% constraints other than one to remove a constraint
pred rm-evar i:term, i:term.
rm-evar (uvar as X) (uvar as Y):- !, declare_constraint (rm-evar X Y) [X,Y].
rm-evar _ _.
constraint declare-evar evar def decl cache rm-evar {
% Override the actual context
rule \ (declare-evar Ctx RawEv Ty Ev) <=> (Ctx => evar RawEv Ty Ev).
rule \ (rm-evar (uvar X _) (uvar Y _)) (evar (uvar X _) _ (uvar Y _)).
rule \ (rm-evar (uvar X _) (uvar Y _)).
}
% The (evar R Ty E) predicate suspends when R and E are flexible,
% and is solved otherwise.
% The client may want to provide an alternative implementation of
% the clause "default-assign-evar", for example to typechecks that the
% term assigned to E has type Ty, or that the term assigned to R
% elaborates to a term of type Ty that gets assigned to E.
% In tactic mode, elpi/coq-elaborator.elpi wires things up that way.
pred evar i:term, i:term, o:term. % Evar Ty RefinedSolution
evar (uvar as X) T S :- var S _ VL, !,
prune T VL, prune X VL, declare_constraint (evar X T S) [X, S].
:name "default-assign-evar"
evar _ _ _. % volatile, only unresolved evars are considered as evars
% To ease the creation of a context with decl and def
% Eg. @pi-decl `x` x1\ @pi-def `y` y\ ...
macro @pi-decl N T F :- pi x\ decl x N T => F x.
macro @pi-def N T B F :- pi x\ def x N T B => cache x B_ => F x.
macro @pi-parameter ID T F :-
sigma N\ (coq.id->name ID N, pi x\ decl x N T => F x).
macro @pi-inductive ID A F :-
sigma N\ (coq.id->name ID N, coq.arity->term A T, pi x\ decl x N T => F x).
% Sometimes it can be useful to pass to Coq a term with unification variables
% representing "untyped holes" like an implicit argument _. In particular
% a unification variable may exit the so called pattern fragment (applied
% to distinct variables) and hence cannot be reliably mapped to Coq as an evar,
% but can still be considered as an implicit argument.
% By loading in the context get-option "HOAS:holes" tt one forces that
% behavior. Here a convenience macro to be put on the LHS of =>
macro @holes! :- get-option "HOAS:holes" tt.
% Similarly, some APIs take a term skeleton in input. In that case unification
% variables are totally disregarded (not even mapped to Coq evars). They are
% interpreted as the {{ lib:elpi.hole }} constant, which represents an implicit
% argument. As a consenque these APIs don't modify the input term at all, but
% rather return a copy. Note that if {{ lib:elpi.hole }} is used directly, then
% it has to be applied to all variables in scope, since Coq erases variables
% that are not used. For example using {{ forall x : nat, lib:elpi.hole }} as
% a term skeleton is equivalent to {{ nat -> lib:elpi.hole }}, while
% {{ forall x : nat, lib:elpi.hole x lib:elpi.hole more args }} puts x in
% the scope of the hole (and passes to is more args).
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Coq's goals and tactic invocation
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% A Coq goal is essentially a sequent, like the evar_info above, but since it
% has to be manipulated as first class Elpi data, it is represented in a slightly
% different way. For example
%
% x : t
% y := v : x
% ----------
% g x y
%
% is represented by the following term of type sealed-goal
%
% nabla x1\
% nabla x2\
% seal
% (goal
% [def x2 `y` x1 , decl x1 `x` ]
% (RawEvar x1 x2) ( x1 x2) (Evar x1 x2)
% (Arguments x1 x2))
kind goal type.
kind sealed-goal type.
type nabla (term -> sealed-goal) -> sealed-goal.
type seal goal -> sealed-goal.
typeabbrev goal-ctx (list prop).
type goal goal-ctx -> term -> term -> term -> list argument -> goal.
% A sealed-goal closes with nabla the bound names of a
%
% (goal Ctx RawSolution Ty Solution Arguments)
%
% where Ctx is a list of decl or def and Solution is a unification variable
% to be assigned to a term of type Ty in order to make progress.
% RawSolution is used as a trigger: when a term is assigned to it, it is
% elaborated against Ty and the resulting term is assigned to Solution.
%
% Arguments contains data attached to the goal, which lives in its context
% and can be used by tactics to solve the goals.
% A tactic (an elpi predicate which makes progress on a Coq goal) is
% a predicate of type
% sealed-goal -> list sealed-goal -> prop
%
% while the main entry point for a tactic written in Elpi is solve
% which has type
% goal -> list sealed-goal -> prop
%
% The utility (coq.ltac.open T G GL) postulates all the variables bounds
% by nabla and loads the goal context before calling T on the unsealed
% goal. The invocation of a tactic with arguments
% 3 x "y" (h x)
% on the previous goal results in the following Elpi query:
%
% (pi x1\ decl x1 `x` =>
% pi x2\ def x2 `y` x1 =>
% declare-evar
% [def x2 `y` x1 , decl x1 `x` ]
% (RawEvar x1 x2) ( x1 x2) (Evar x1 x2)),
% (coq.ltac.open solve
% (nabla x1\ nabla x2\ seal
% (goal
% [def x2 `y` x1 , decl x1 `x` ]
% (RawEvar x1 x2) ( x1 x2) (Evar x1 x2)
% [int 3, str `x`, str`y`, trm (app[const `h`,x1])]))
% NewGoals)
%
% If the goal sequent contains other evars, then a tactic invocation is
% an Elpi query made of the conjunction of all the declare-evar queries
% corresponding to these evars and the query corresponding to the goal
% sequent. NewGoals can be assigned to a list of goals that should be
% declared as open. Omitted goals are shelved. If NewGoals is not
% assigned, then all unresolved evars become new goals, but the order
% of such goals is not specified.
% The file elpi-ltac.elpi provides a few combinators (other than coq.ltac.open)
% in the tradition of LCF tacticals. The main difference is that the arguments
% of custom written tactics must not be passed as predicate arguments but rather
% put in the goal they receive. Indeed these arguments can contain terms, and
% their bound variables cannot escape the seal. coq.ltac.set-goal-arguments
% can be used to put an argument from the current goal context into another
% goal. The coq.ltac.call utility can call Ltac1 code (written in Coq) and
% pass arguments via this mechanism.
% Last, since Elpi is alerady a logic programming language with primitive
% support for unification variables, most of the work of a tactic can be
% performed without using tacticals (which work on sealed goals) but rather
% in the context of the original goal. The last step is typically to call
% the refine utility with a term synthesized by the tactic or invoke some
% Ltac1 code on that term (e.g. to call vm_compute, see also the example
% on the reflexive tactic).
% ----- Multi goals tactics. ----
% Coq provides goal selectors, such as all:, to pass to a tactic more than one
% goal. In order to write such a tactic, Coq-Elpi provides another entry point
% called msolve. To be precise, if there are two goals under focus, say and
% , then all: elpi tac runs the following query
%
% msolve [,] NewGoals ; % note the disjunction
% coq.ltac.all (coq.ltac.open solve) [,] NewGoals
%
% So, if msolve has no clause, Coq-Elpi will use solve on all the goals
% independently. If msolve has a cluse, then it can manipulate the entire list
% of sealed goals. Note that the argument is in both and but
% it is interpreted in both contexts independently. If both goals have a proof
% variable named "x" then passing (@eq_refl _ x) as equips both goals with
% a (raw) proof that "x = x", no matter what their type is.
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Declarations for Coq's API (environment read/write access, etc).
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% tt = Yes, ff = No, unspecified = No (unspecified means "_" or a variable).
typeabbrev opaque? bool. macro @opaque! :- tt. macro @transparent! :- ff.
%%%%%%% Attributes to be passed to APIs as in @local! => coq.something %%%%%%%%
macro @global! :- get-option "coq:locality" "global".
macro @local! :- get-option "coq:locality" "local".
macro @primitive! :- get-option "coq:primitive" tt. % primitive records
macro @reversible! :- get-option "coq:reversible" tt. % coercions
macro @no-tc! :- get-option "coq:no_tc" tt. % skip typeclass inference
macro @uinstance! I :- get-option "coq:uinstance" I. % universe instance
% declaration of universe polymorphic constants
% The first list is the one of the unvierse variables being bound
% The first boolean is tt if this list can be extended by Coq (or it has to
% mention all universes actually used)
% The second list if the one with the constaints amond where universes
% The second boolean is tt if this list can be extended by Coq or it has to
% mention all universe constraints actually required to type check the
% declaration)
macro @udecl! Vs LV Cs LC :- get-option "coq:udecl" (upoly-decl Vs LV Cs LC).
macro @udecl-cumul! Vs LV Cs LC :- get-option "coq:udecl-cumul" (upoly-decl-cumul Vs LV Cs LC).
macro @univpoly! :- @udecl! [] tt [] tt.
macro @univpoly-cumul! :- @udecl-cumul! [] tt [] tt.
macro @ppwidth! N :- get-option "coq:ppwidth" N. % printing width
macro @ppall! :- get-option "coq:pp" "all". % printing all
macro @ppmost! :- get-option "coq:pp" "most". % printing most of contents
macro @pplevel! N :- get-option "coq:pplevel" N. % printing precedence (for parentheses)
macro @keepunivs! :- get-option "coq:keepunivs" tt. % skeletons elaboration
macro @dropunivs! :- get-option "coq:keepunivs" ff. % add-indt/add-const
macro @using! S :- get-option "coq:using" S. % like the #[using=S] attribute
macro @inline-at! N :- get-option "coq:inline" (coq.inline.at N). % like Inline(N)
macro @inline! N :- get-option "coq:inline" coq.inline.default. % like
macro @redflags! F :- get-option "coq:redflags" F. % for whd & co
% both arguments are strings eg "8.12.0" "use foo instead"
macro @deprecated! Since Msg :-
get-option "coq:deprecated" (pr Since Msg).
macro @ltacfail! N :- get-option "ltac:fail" N.
% Declaration of inductive types %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
kind indt-decl type.
kind indc-decl type.
kind record-decl type.
% An arity is written, in Coq syntax, as:
% (x : T1) .. (xn : Tn) : S1 -> ... -> Sn -> U
% This syntax is used, for example, in the type of an inductive type or
% in the type of constructors. We call the abstractions on the left of ":"
% "parameters" while we call the type following the ":" (proper) arity.
% Note: in some contexts, like the type of an inductive type constructor,
% Coq makes no distinction between these two writings
% (xn : Tn) : forall y1 : S1, ... and (xn : Tn) (y1 : S1) : ...
% while Elpi is a bit more restrictive, since it understands user directives
% such as the implicit status of an arguments (eg, using {} instead of () around
% the binder), only on parameters.
% Moreover parameters carry the name given by the user as an "id", while binders
% in terms only carry it as a "name", an irrelevant pretty pringintg hint (see
% also the HOAS of terms). A user command can hence only use the names of
% parameters, and not the names of "forall" quantified variables in the arity.
%
% See also the arity->term predicate in coq-lib.elpi
type parameter id -> implicit_kind -> term -> (term -> arity) -> arity.
type arity term -> arity.
type parameter id -> implicit_kind -> term -> (term -> indt-decl) -> indt-decl.
type inductive id -> bool -> arity -> (term -> list indc-decl) -> indt-decl. % tt means inductive, ff coinductive
type record id -> term -> id -> record-decl -> indt-decl.
type constructor id -> arity -> indc-decl.
type field field-attributes -> id -> term -> (term -> record-decl) -> record-decl.
type end-record record-decl.
% Example.
% Remark that A is a regular parameter; y is a non-uniform parameter and t
% also features an index of type bool.
%
% Inductive t (A : Type) | (y : nat) : bool -> Type :=
% | K1 (x : A) {n : nat} : S n = y -> t A n true -> t A y true
% | K2 : t A y false
%
% is written
%
% (parameter "A" explicit {{ Type }} a\
% inductive "t" tt (parameter "y" explicit {{ nat }} _\
% arity {{ bool -> Type }})
% t\
% [ constructor "K1"
% (parameter "y" explicit {{ nat }} y\
% (parameter "x" explicit a x\
% (parameter "n" maximal {{ nat }} n\
% arity {{ S lp:n = lp:y -> lp:t lp:n true -> lp:t lp:y true }})))
% , constructor "K2"
% (parameter "y" explicit {{ nat }} y\
% arity {{ lp:t lp:y false }}) ])
%
% Remark that the uniform parameters are not passed to occurrences of t, since
% they never change, while non-uniform parameters are both abstracted
% in each constructor type and passed as arguments to t.
%
% The coq.typecheck-indt-decl API can be used to fill in implicit arguments
% an infer universe constraints in the declaration above (e.g. the hidden
% argument of "=" in the arity of K1).
%
% Note: when and inductive type declaration is passed as an argument to an
% Elpi command non uniform parameters must be separated from the uniform ones
% with a | (a syntax introduced in Coq 8.12 and accepted by coq-elpi since
% version 1.4, in Coq this separator is optional, but not in Elpi).
% Context declaration (used as an argument to Elpi commands)
kind context-decl type.
% Eg. (x : T) or (x := B), body is optional, type may be a variable
type context-item id -> implicit_kind -> term -> option term -> (term -> context-decl) -> context-decl.
type context-end context-decl.
typeabbrev field-attributes (list field-attribute).
% retrocompatibility macro for Coq v8.10
macro @coercion! :- [coercion reversible].
coq-elpi-1.19.3/elpi/coq-elaborator.elpi 0000664 0000000 0000000 00000004017 14511776522 0020050 0 ustar 00root root 0000000 0000000 /* Type inference and unification */
/* license: GNU Lesser General Public License Version 2.1 or later */
/* ------------------------------------------------------------------------- */
% This file does the plumbing to use Coq's elaborator
:name "coq-assign-evar-raw"
:before "default-assign-evar"
evar X Ty R :- var R, !, of X Ty R.
:name "coq-assign-evar-refined-hack-8-17-Prop"
:before "default-assign-evar"
evar X Ty R :- not(var R), same_term Ty {{ Prop }}, coq.version _ 8 17 _, !,
hack-8-17.propagate-Prop-constraint-inward R, coq.typecheck R Ty ok, X = R.
:name "coq-assign-evar-refined"
:before "default-assign-evar"
evar X Ty R :- not(var R), !, coq.typecheck R Ty ok, X = R.
pred unify-eq i:term, i:term.
unify-eq A B :- coq.unify-eq A B ok.
pred unify-leq i:term, i:term.
unify-leq A B :- coq.unify-leq A B ok.
pred of i:term, o:term, o:term.
of T Ty TR :- !, coq.elaborate-skeleton T Ty TR ok.
namespace hack-8-17 {
% This is a very partial fix for Coq 8.17 which "commits" holes to be in Type
% too early. We propagate the Prop constraint by hand in some obvious cases.
% Example (we add the inner ":Prop"):
% Check (A -> _ -> _ : Prop) : Prop.
% Starting with Coq 8.18 this is not necessary anymore
pred propagate-Prop-constraint-inward i:term.
propagate-Prop-constraint-inward {{ forall x : lp:Ty, lp:(F x) }} :- !,
@pi-decl `x` Ty x\
propagate-Prop-constraint-inward (F x).
propagate-Prop-constraint-inward {{ lp:A /\ lp:B }} :- !,
propagate-Prop-constraint-inward A,
propagate-Prop-constraint-inward B.
propagate-Prop-constraint-inward {{ lp:A \/ lp:B }} :- !,
propagate-Prop-constraint-inward A,
propagate-Prop-constraint-inward B.
propagate-Prop-constraint-inward {{ ~ lp:A }} :- !,
propagate-Prop-constraint-inward A.
propagate-Prop-constraint-inward (uvar as X) :- !,
coq.typecheck X {{ Prop }} ok.
propagate-Prop-constraint-inward (app[uvar|_] as X) :- !,
coq.typecheck X {{ Prop }} ok.
propagate-Prop-constraint-inward _. % no-op in all other cases
}
coq-elpi-1.19.3/elpi/coq-elpi-checker.elpi 0000664 0000000 0000000 00000001613 14511776522 0020250 0 ustar 00root root 0000000 0000000 /* coq-elpi: Coq terms as the object language of elpi */
/* license: GNU Lesser General Public License Version 2.1 or later */
/* ------------------------------------------------------------------------- */
% redirect to Coq type checking messages
:before "default-typechecking-error"
error [] _ :- !.
:before "default-typechecking-error"
error [pr L M] tt :- !, coq.error L M.
:before "default-typechecking-error"
error Msgs tt :- !, coq.error "At least one of the following errors holds:" {error-concat Msgs}.
pred error-concat i:list string, o:string.
error-concat [] "\n".
error-concat [pr L X] R :- error-concat XS Rest, term_to_string L LS, R is LS ^ " " ^ X.
error-concat [pr L X|XS] R :- error-concat XS Rest, term_to_string L LS, R is LS ^ " " ^ X ^ "\n" ^ Rest.
:before "default-typechecking-warning"
warning L M :- !, coq.warning "elpi" "elpi.typecheck" L M.
coq-elpi-1.19.3/elpi/coq-lib.elpi 0000664 0000000 0000000 00000077160 14511776522 0016475 0 ustar 00root root 0000000 0000000 /* coq-elpi: Coq terms as the object language of elpi */
/* license: GNU Lesser General Public License Version 2.1 or later */
/* ------------------------------------------------------------------------- */
shorten std.{fatal-error, fatal-error-w-data, debug-print, unsafe-cast}.
shorten std.{rev, map, append, appendR, map2, forall-ok, take, do-ok!, lift-ok}.
shorten std.{ omap, take-last, intersperse, map-ok, string.concat }.
:before "default-fatal-error"
fatal-error M :- !, stop M.
:before "default-fatal-error-w-data"
fatal-error-w-data Msg Data :- !,
term_to_string Data DataS,
M is Msg ^ ": " ^ DataS, stop M.
:before "default-debug-print"
debug-print M Data :- !, coq.say M Data.
% HACK: elpi's stop has no argument
type stop string -> prop.
stop S :- get-option "ltac:fail" N, !, coq.ltac.fail N S.
stop S :- coq.error S. % halt S
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Helpers
%
% Pure LP code that works with the data types and API above.
% Named clauses are natural extension points, eg one can extend
% subst-prod to perform reduction in order to expose a "prod" node.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Term surgery %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
pred coq.subst-prod i:list term, i:term, o:term.
coq.subst-prod [] P P :- !.
coq.subst-prod [X|XS] (prod _ _ F) P :- !, coq.subst-prod XS (F X) P.
coq.subst-prod XS (let _ _ X F) P :- !, coq.subst-prod XS (F X) P.
:name "subst-prod:fail"
coq.subst-prod [_|_] T _ :- !,
fatal-error-w-data "subst-prod: not a product" T.
pred coq.subst-fun i:list term, i:term, o:term.
coq.subst-fun [] T T :- !.
coq.subst-fun [X|XS] (fun _ _ F) T :- !, coq.subst-fun XS (F X) T.
coq.subst-fun XS (let _ _ X F) T :- !, coq.subst-fun XS (F X) T.
:name "subst-fun:fail"
coq.subst-fun [_|_] T _ :- !,
fatal-error-w-data "subst-fun: not a lambda" T.
pred coq.prod-R-fun o:term, o:term.
coq.prod-R-fun (prod N T F) (fun N T R) :- !, pi x\ coq.prod-R-fun (F x) (R x).
coq.prod-R-fun (let N T B F) (let N T B R) :- !, pi x\ coq.prod-R-fun (F x) (R x).
coq.prod-R-fun X X.
pred coq.prod->fun i:term, o:term.
coq.prod->fun (prod N T F) (fun N T R) :- !, pi x\ coq.prod->fun (F x) (R x).
coq.prod->fun (let N T B F) (let N T B R) :- !, pi x\ coq.prod->fun (F x) (R x).
coq.prod->fun X X.
pred coq.count-prods i:term, o:int.
coq.count-prods (prod _ _ B) N :- !, (pi x\ coq.count-prods (B x) M), N is M + 1.
coq.count-prods (let _ _ _ B) N :- !, (pi x\ coq.count-prods (B x) N).
:name "count-prod:end"
coq.count-prods _ 0 :- !.
pred coq.mk-n-holes i:int, o:list A.
coq.mk-n-holes 0 [] :- !.
coq.mk-n-holes N [HOLE_|R] :- !, M is N - 1, coq.mk-n-holes M R.
pred coq.safe-dest-app i:term, o:term, o:list term.
coq.safe-dest-app (app [X|XS]) HD AllArgs :- !,
coq.safe-dest-app X HD ARGS, append ARGS XS AllArgs.
coq.safe-dest-app X X [].
pred coq.mk-app i:term, i:list term, o:term.
coq.mk-app HD [] HD :- !.
coq.mk-app (app L) Args (app LArgs) :- !, append L Args LArgs.
coq.mk-app (fun _ _ F) [A|Args] R :- !, coq.mk-app (F A) Args R.
coq.mk-app (let _ _ A F) Args R :- !, coq.mk-app (F A) Args R.
coq.mk-app HD Args (app [HD|Args]).
pred coq.mk-app-uvar i:term, i:list term, o:term.
coq.mk-app-uvar HD [] HD :- !.
coq.mk-app-uvar (uvar as K) [A|Args] R :- !, unsafe-cast K K', coq.mk-app-uvar (K' A) Args R.
% coq.mk-eta n Ty T: performs up to n (when >= 0) eta expasion of T
% according to its type Ty. If n < 0 it makes as many step as
% products in Ty. There be dragons if T has not type Ty.
pred coq.mk-eta i:int, i:term, i:term, o:term.
coq.mk-eta 0 _ B B :- !.
coq.mk-eta N (prod Name Ty P) (fun _ _ F) (fun Name Ty F1) :- !, N1 is N - 1,
pi x \ coq.mk-eta N1 (P x) (F x) (F1 x).
coq.mk-eta N (prod Name Ty P) B (fun Name Ty B1) :- !, N1 is N - 1,
pi x \ coq.mk-eta N1 (P x) {coq.mk-app B [x]} (B1 x).
:name "mk-eta:end"
coq.mk-eta _ _ B B :- !.
pred coq.saturate i:term, i:term, o:term.
coq.saturate Ty T O :- whd Ty [] (prod N Src Tgt) [], !,
coq.mk-app T [Hole_] R,
@pi-decl N Src x\ coq.saturate (Tgt x) R O.
coq.saturate _ X X.
% [copy A B] can be used to perform a replacement, eg
% (copy (const "foo") (const "bar") :- !) => copy A B
% traverses A replacing foo with bar.
pred copy i:term, o:term.
:name "copy:start"
copy X Y :- name X, !, X = Y, !. % avoid loading "copy x x" at binders
copy (global _ as C) C :- !.
copy (pglobal _ _ as C) C :- !.
copy (sort _ as C) C :- !.
copy (fun N T F) (fun N T1 F1) :- !,
copy T T1, pi x\ copy (F x) (F1 x).
copy (let N T B F) (let N T1 B1 F1) :- !,
copy T T1, copy B B1, pi x\ copy (F x) (F1 x).
copy (prod N T F) (prod N T1 F1) :- !,
copy T T1, (pi x\ copy (F x) (F1 x)).
copy (app L) (app L1) :- !, map L copy L1.
copy (fix N Rno Ty F) (fix N Rno Ty1 F1) :- !,
copy Ty Ty1, pi x\ copy (F x) (F1 x).
copy (match T Rty B) (match T1 Rty1 B1) :- !,
copy T T1, copy Rty Rty1, map B copy B1.
copy (primitive _ as C) C :- !.
copy (uvar M L as X) W :- var X, !, map L copy L1, coq.mk-app-uvar M L1 W.
% when used in CHR rules
copy (uvar X L) (uvar X L1) :- map L copy L1.
pred copy-ctx-item i:prop, o:prop.
copy-ctx-item (decl X N T) (decl X1 N T1) :- copy X X1, copy T T1.
copy-ctx-item (def X N T B) (def X1 N T1 B1) :-
copy X X1, copy T T1, copy B B1.
pred copy-arity i:arity, o:arity.
copy-arity (parameter ID IMP T R) (parameter ID IMP T1 R1) :-
copy T T1, pi x\ copy-arity (R x) (R1 x).
copy-arity (arity T) (arity T1) :- copy T T1.
pred copy-indt-decl i:indt-decl, o:indt-decl.
copy-indt-decl (parameter ID I Ty D) (parameter ID I Ty1 D1) :-
copy Ty Ty1,
@pi-parameter ID Ty1 x\ copy-indt-decl (D x) (D1 x).
copy-indt-decl (inductive ID CO A D) (inductive ID CO A1 D1) :-
copy-arity A A1,
@pi-inductive ID A1 i\ std.map (D i) copy-constructor (D1 i).
copy-indt-decl (record ID T IDK F) (record ID T1 IDK F1) :-
copy T T1,
copy-fields F F1.
pred copy-fields i:record-decl, o:record-decl.
copy-fields end-record end-record.
copy-fields (field Att ID T F) (field Att ID T1 F1) :-
copy T T1,
@pi-parameter ID T1 x\ copy-fields (F x) (F1 x).
pred copy-constructor i:indc-decl, o:indc-decl.
copy-constructor (constructor ID A) (constructor ID A1) :- copy-arity A A1.
pred fold-map i:term, i:A, o:term, o:A.
:name "fold-map:start"
fold-map X A Y A :- name X, !, X = Y, !. % avoid loading "fold-map x A x A" at binders
fold-map (global _ as C) A C A :- !.
fold-map (pglobal _ _ as C) A C A :- !.
fold-map (sort _ as C) A C A :- !.
fold-map (fun N T F) A (fun N T1 F1) A2 :- !,
fold-map T A T1 A1, pi x\ fold-map (F x) A1 (F1 x) A2.
fold-map (let N T B F) A (let N T1 B1 F1) A3 :- !,
fold-map T A T1 A1, fold-map B A1 B1 A2, pi x\ fold-map (F x) A2 (F1 x) A3.
fold-map (prod N T F) A (prod N T1 F1) A2 :- !,
fold-map T A T1 A1, (pi x\ fold-map (F x) A1 (F1 x) A2).
fold-map (app L) A (app L1) A1 :- !, std.fold-map L A fold-map L1 A1.
fold-map (fix N Rno Ty F) A (fix N Rno Ty1 F1) A2 :- !,
fold-map Ty A Ty1 A1, pi x\ fold-map (F x) A1 (F1 x) A2.
fold-map (match T Rty B) A (match T1 Rty1 B1) A3 :- !,
fold-map T A T1 A1, fold-map Rty A1 Rty1 A2, std.fold-map B A2 fold-map B1 A3.
fold-map (primitive _ as C) A C A :- !.
fold-map (uvar M L as X) A W A1 :- var X, !, std.fold-map L A fold-map L1 A1, coq.mk-app-uvar M L1 W.
% when used in CHR rules
fold-map (uvar X L) A (uvar X L1) A1 :- std.fold-map L A fold-map L1 A1.
pred fold-map-ctx-item i:prop, i:A, o:prop,o:A.
fold-map-ctx-item (decl X N T) A (decl X1 N T1) A2 :- fold-map X A X1 A1, fold-map T A1 T1 A2.
fold-map-ctx-item (def X N T B) A (def X1 N T1 B1) A3 :-
fold-map X A X1 A1, fold-map T A1 T1 A2, fold-map B A2 B1 A3.
pred fold-map-arity i:arity, i:A, o:arity, o:A.
fold-map-arity (parameter ID IMP T R) A (parameter ID IMP T1 R1) A2 :-
fold-map T A T1 A1, pi x\ fold-map-arity (R x) A1 (R1 x) A2.
fold-map-arity (arity T) A (arity T1) A1 :- fold-map T A T1 A1.
% Bridges the gap between the data types used to read/write inductives.
% The arguments are the same of coq.env.indt plus an an extra one being
% the output (of type indt-decl).
pred coq.upoly-decl->attribute i:any, o:prop.
coq.upoly-decl->attribute (upoly-decl A B C D) (@udecl! A B C D).
coq.upoly-decl->attribute (upoly-decl-cumul A B C D) (@udecl-cumul! A B C D).
pred coq.upoly-decl.complete-constraints i:upoly-decl, o:upoly-decl.
coq.upoly-decl.complete-constraints (upoly-decl VS LV CS LC) (upoly-decl VS LV CS1 LC) :- std.do! [
std.map VS coq.univ.variable.constraints ExtraL,
std.flatten ExtraL Extra,
std.filter Extra (c\not(std.mem CS c)) New,
std.append CS New CS1,
].
pred coq.upoly-decl-cumul.complete-constraints i:upoly-decl-cumul, o:upoly-decl-cumul.
coq.upoly-decl-cumul.complete-constraints (upoly-decl-cumul VS LV CS LC) (upoly-decl-cumul VS LV CS1 LC) :- std.do! [
std.map VS coq.upoly-decl-cumul.complete-constraints.aux ExtraL,
std.flatten ExtraL Extra,
std.filter Extra (c\not(std.mem CS c)) New,
std.append CS New CS1,
].
coq.upoly-decl-cumul.complete-constraints.aux (auto V) CS :- coq.univ.variable.constraints V CS.
coq.upoly-decl-cumul.complete-constraints.aux (covariant V) CS :- coq.univ.variable.constraints V CS.
coq.upoly-decl-cumul.complete-constraints.aux (invariant V) CS :- coq.univ.variable.constraints V CS.
coq.upoly-decl-cumul.complete-constraints.aux (irrelevant V) CS :- coq.univ.variable.constraints V CS.
pred coq.build-indt-decl
i:(pair inductive id), i:bool, i:int, i:int, i:term, i:list (pair constructor id), i:list term, o:indt-decl.
coq.build-indt-decl GR IsInd Pno UPno Arity Kns Ktys Decl :-
coq.build-indt-decl-aux GR IsInd Pno UPno Arity Kns Ktys [] Decl.
pred coq.build-indt-decl-aux
i:pair inductive id, i:bool, i:int, i:int, i:term, i:list (pair constructor id), i:list term, i:list term, o:indt-decl.
coq.build-indt-decl-aux (pr GR I) IsInd NUPno 0 Ty Kns KtysNu Params (inductive I IsInd Arity Ks) :- !,
coq.term->arity Ty NUPno Arity,
std.map KtysNu (k\coq.term->arity k NUPno) Ktys,
rev Params ParamsR,
(pi i\ Sub i = [ % we factor uniform parameters
(pi x l\ copy (app[global (indt GR)|l]) (app[i|x]):- !, appendR ParamsR x l),
(pi x l ui\ copy (app[pglobal (indt GR) ui|l]) (app[i|x]):- !, appendR ParamsR x l),
(copy (global (indt GR)) i :- !),
(pi ui\ copy (pglobal (indt GR) ui) i :- !)
]),
pi i\
map2 Kns Ktys (gr_name\ ty\ res\
sigma tmp name\
Sub i => copy-arity ty tmp,
gr_name = pr _ name,
res = constructor name tmp)
(Ks i).
coq.build-indt-decl-aux GR IsInd Pno UPno (prod N S T) Kns Ktys Params (parameter NS explicit S Res) :- Pno > 0, UPno > 0, !,
coq.name->id N NS,
Pno1 is Pno - 1,
UPno1 is UPno - 1,
pi p\
map Ktys (coq.subst-prod [p]) (Ktys1 p),
coq.build-indt-decl-aux GR IsInd Pno1 UPno1 (T p) Kns (Ktys1 p) [p|Params] (Res p).
:name "coq.build-indt-decl-aux:fail"
coq.build-indt-decl-aux _ _ _ _ _ _ _ _ _ :- !,
fatal-error "coq.build-indt-decl-aux: invalid declaration".
pred coq.rename-arity
i:(id -> id -> prop),
i:arity,
o:arity.
coq.rename-arity RP (parameter ID I TY In) (parameter ID1 I TY Out) :-
RP ID ID1,
@pi-parameter ID TY p\
coq.rename-arity RP (In p) (Out p).
coq.rename-arity _ (arity T) (arity T).
% [coq.rename-indt-decl RenameParam RenameIndType RenameIndConstr D D1]
% can be used to rename all [id] part of an inductive type declaration
pred coq.rename-indt-decl
i:(id -> id -> prop),
i:(id -> id -> prop),
i:(id -> id -> prop),
i:indt-decl, o:indt-decl.
coq.rename-indt-decl RP RI RK (parameter ID I TY In) (parameter ID1 I TY Out) :-
RP ID ID1,
@pi-parameter ID TY p\
coq.rename-indt-decl RP RI RK (In p) (Out p).
coq.rename-indt-decl RP RI RK (inductive ID Ind A In) (inductive ID1 Ind A1 Out) :-
RI ID ID1,
coq.rename-arity RP A A1,
coq.id->name ID Name,
coq.arity->term A TY,
@pi-decl Name TY i\
std.map (In i) (coq.rename-indt-decl.aux RP RI RK) (Out i).
coq.rename-indt-decl _ RI RK (record ID A KID F) (record ID1 A KID1 F) :-
RI ID ID1,
RK KID KID1.
coq.rename-indt-decl.aux RP _ RK (constructor ID A) (constructor ID1 A1) :-
RK ID ID1,
coq.rename-arity RP A A1.
pred coq.ensure-fresh-global-id i:string, o:string.
coq.ensure-fresh-global-id Exp S :-
Name is Exp,
coq.env.fresh-global-id Name S,
if (Name = S) true
(coq.warning "elpi" "elpi.renamed" "Global name" Name "is taken, using" S "instead").
% Lifts coq.typecheck to inductive declarations
pred coq.typecheck-indt-decl.heuristic-var-type i:term, o:diagnostic.
coq.typecheck-indt-decl.heuristic-var-type (uvar _ _ as X) D :- !,
coq.univ.new U, coq.unify-eq X (sort (typ U)) D.
coq.typecheck-indt-decl.heuristic-var-type _ ok.
pred coq.typecheck-indt-arity i:arity, o:term, o:int, o:diagnostic.
coq.typecheck-indt-arity (parameter ID _ T D) (prod N T F) NU1 Diag :- do-ok! Diag [
coq.typecheck-ty T _,
(d\ @pi-parameter ID T x\ coq.typecheck-indt-arity (D x) (F x) NU d),
lift-ok (NU1 is NU + 1) "",
lift-ok (coq.id->name ID N) "",
].
coq.typecheck-indt-arity (arity T) T 0 Diag :- do-ok! Diag [
coq.typecheck-ty T _,
coq.typecheck-indt-decl.heuristic-var-type T,
].
pred coq.typecheck-indt-decl i:indt-decl, o:diagnostic.
coq.typecheck-indt-decl (parameter ID _ T Decl) Diag :- do-ok! Diag [
coq.typecheck-ty T _,
(d\ @pi-parameter ID T x\ coq.typecheck-indt-decl (Decl x) d),
].
coq.typecheck-indt-decl (inductive ID _ Arity KDecl) Diag :- do-ok! Diag [
coq.typecheck-indt-arity Arity A NUPNO,
d\ @pi-parameter ID A i\ forall-ok (KDecl i) (coq.typecheck-indt-decl-c i A NUPNO) d
].
coq.typecheck-indt-decl (record ID A _IDK FDecl) Diag :- do-ok! Diag [
coq.typecheck-ty A _,
d\ @pi-parameter ID A i\ do-ok! d [
lift-ok (coq.typecheck-indt-decl-field i FDecl (K i)) "",
coq.typecheck-indt-decl-c i A 0 (constructor "fields" (arity (K i)))
]
].
pred coq.typecheck-indc-arity i:arity, i:int, o:term, o:sort, o:diagnostic.
coq.typecheck-indc-arity A 0 T S Diag :- !,
coq.arity->term A T,
coq.typecheck-ty T S Diag.
coq.typecheck-indc-arity (parameter ID _ T D) NUPNO (prod N T F) S Diag :- do-ok! Diag [
coq.typecheck-ty T _,
lift-ok (NUPNO1 is NUPNO - 1) "",
(d\ @pi-parameter ID T x\ coq.typecheck-indc-arity (D x) NUPNO1 (F x) S d),
lift-ok (coq.id->name ID N) "",
].
pred coq.typecheck-indt-decl-c i:term, i:term, i:int, i:indc-decl, o:diagnostic.
coq.typecheck-indt-decl-c I S NUPNO (constructor _ID Arity) Diag :- do-ok! Diag [
coq.typecheck-indc-arity Arity NUPNO T KS,
coq.typecheck-indt-decl-c.unify-arrow-tgt I 0 S T,
lift-ok (coq.arity->sort S IS) "",
lift-ok (coq.sort.leq KS IS) "constructor universe too large"
].
pred coq.typecheck-indt-decl-c.unify-arrow-tgt i:term, i:int, i:term, i:term, o:diagnostic.
coq.typecheck-indt-decl-c.unify-arrow-tgt I P A (prod N S T) D :-
@pi-decl N S x\ coq.typecheck-indt-decl-c.unify-arrow-tgt I P A (T x) D.
coq.typecheck-indt-decl-c.unify-arrow-tgt I P A (let N S B T) D :-
@pi-def N S B x\ coq.typecheck-indt-decl-c.unify-arrow-tgt I P A (T x) D.
coq.typecheck-indt-decl-c.unify-arrow-tgt I P A Concl D :-
coq.count-prods A N,
coq.mk-n-holes {calc (N + P)} Args,
coq.mk-app I Args IArgs,
coq.unify-eq Concl IArgs D.
pred coq.typecheck-indt-decl-field i:term, i:record-decl, o:term.
coq.typecheck-indt-decl-field I end-record I.
coq.typecheck-indt-decl-field I (field _ ID T F) (prod N T F1) :-
coq.id->name ID N,
@pi-decl N T a\ coq.typecheck-indt-decl-field I (F a) (F1 a).
% Lifts coq.elaborate-skeleton to inductive declarations
pred coq.elaborate-indt-decl-skeleton i:indt-decl, o:indt-decl, o:diagnostic.
coq.elaborate-indt-decl-skeleton (parameter ID Imp T Decl) (parameter ID Imp T1 Decl1) Diag :- do-ok! Diag [
coq.elaborate-ty-skeleton T _ T1,
(d\ @pi-parameter ID T1 x\ coq.elaborate-indt-decl-skeleton (Decl x) (Decl1 x) d),
].
coq.elaborate-indt-decl-skeleton (inductive ID I Arity KDecl) (inductive ID I Arity1 KDecl1) Diag :- do-ok! Diag [
coq.elaborate-arity-skeleton Arity _ Arity1,
lift-ok (coq.arity->nparams Arity1 NUPNO) "",
d\ coq.arity->term Arity1 A1, do-ok! d [
coq.typecheck-indt-decl.heuristic-var-type A1,
d\ @pi-parameter ID A1 i\ map-ok (KDecl i) (coq.elaborate-indt-decl-skeleton-c i Arity1 NUPNO) (KDecl1 i) d
]
].
coq.elaborate-indt-decl-skeleton (record ID A IDK FDecl) (record ID A1 IDK FDecl1) Diag :- do-ok! Diag [
coq.elaborate-ty-skeleton A _ A1,
lift-ok (A1 = sort U) "record type is not a sort",
d\ @pi-parameter ID A1 i\ coq.elaborate-indt-decl-skeleton-fields U FDecl FDecl1 d
].
pred coq.elaborate-indt-decl-skeleton-fields i:sort, i:record-decl, o:record-decl, o:diagnostic.
coq.elaborate-indt-decl-skeleton-fields _ end-record end-record ok.
coq.elaborate-indt-decl-skeleton-fields U (field Att ID A Fields) (field Att ID A1 Fields1) Diag :- do-ok! Diag [
coq.elaborate-ty-skeleton A UA A1,
lift-ok (coq.sort.leq UA U) "constructor universe too large",
d\ @pi-parameter ID A1 p\
coq.elaborate-indt-decl-skeleton-fields U (Fields p) (Fields1 p) d
].
pred coq.elaborate-indt-decl-skeleton-c i:term, i:arity, i:int, i:indc-decl, o:indc-decl, o:diagnostic.
coq.elaborate-indt-decl-skeleton-c I SA NUPNO (constructor ID Arity) (constructor ID Arity1) Diag :- do-ok! Diag [
coq.elaborate-arity-skeleton-nuparams Arity NUPNO KS Arity1,
coq.typecheck-indt-decl-c.unify-arity I 0 SA Arity1,
lift-ok (coq.arity->sort {coq.arity->term SA} IS) "",
lift-ok (coq.sort.leq KS IS) "constructor universe too large"
].
pred coq.typecheck-indt-decl-c.unify-arity i:term, i:int, i:arity, i:arity, o:diagnostic.
coq.typecheck-indt-decl-c.unify-arity I PNO (parameter _ _ T1 A) (parameter ID _ T C) D :- do-ok! D [
coq.unify-eq T1 T,
lift-ok (PNO1 is PNO + 1) "",
d\ @pi-parameter ID T p\ coq.typecheck-indt-decl-c.unify-arity I PNO1 (A p) (C p) d
].
coq.typecheck-indt-decl-c.unify-arity I PNO (arity A) (parameter ID _ T C) D :-
@pi-parameter ID T p\ coq.typecheck-indt-decl-c.unify-arity I PNO (arity A) (C p) D.
coq.typecheck-indt-decl-c.unify-arity I PNO (arity A) (arity C) D :-
coq.typecheck-indt-decl-c.unify-arrow-tgt I PNO A C D.
% Lifts coq.elaborate-skeleton to arity
pred coq.elaborate-arity-skeleton i:arity, o:sort, o:arity, o:diagnostic.
coq.elaborate-arity-skeleton (parameter ID Imp T A) U3 (parameter ID Imp T1 A1) Diag :- do-ok! Diag [
coq.elaborate-ty-skeleton T U1 T1,
(d\ @pi-parameter ID T1 i\ coq.elaborate-arity-skeleton (A i) U2 (A1 i) d),
lift-ok (coq.sort.pts-triple U1 U2 U3) "coq.elaborate-arity-skeleton: should not happen",
].
coq.elaborate-arity-skeleton (arity A) U (arity A1) Diag :-
coq.elaborate-ty-skeleton A U A1 Diag.
pred coq.elaborate-arity-skeleton-nuparams i:arity, i:int, o:sort, o:arity, o:diagnostic.
coq.elaborate-arity-skeleton-nuparams (parameter ID Imp T A) 0 U3 (parameter ID Imp T1 A1) Diag :- !, do-ok! Diag [
coq.elaborate-ty-skeleton T U1 T1,
(d\ @pi-parameter ID T1 i\ coq.elaborate-arity-skeleton-nuparams (A i) 0 U2 (A1 i) d),
lift-ok (coq.sort.pts-triple U1 U2 U3) "coq.elaborate-arity-skeleton-nuparams: should not happen",
].
coq.elaborate-arity-skeleton-nuparams (parameter ID Imp T A) N U (parameter ID Imp T1 A1) Diag :- do-ok! Diag [
coq.elaborate-ty-skeleton T _ T1,
lift-ok (M is N - 1) "",
(d\ @pi-parameter ID T1 i\ coq.elaborate-arity-skeleton-nuparams (A i) M U (A1 i) d),
].
coq.elaborate-arity-skeleton-nuparams (arity A) _ U (arity A1) Diag :-
coq.elaborate-ty-skeleton A U A1 Diag.
% Converts an arity to a term
pred coq.arity->term i:arity, o:term.
coq.arity->term (parameter ID _ Ty Rest) (prod Name Ty R) :-
coq.id->name ID Name,
@pi-decl Name Ty x\ coq.arity->term (Rest x) (R x).
coq.arity->term (arity A) A.
pred coq.term->arity i:term, i:int, o:arity.
coq.term->arity T 0 (arity T).
coq.term->arity (prod Name S T) N (parameter ID explicit S R) :-
M is N - 1,
coq.name->id Name ID,
@pi-decl Name S x\ coq.term->arity (T x) M (R x).
% extracts the sort at the end of an arity
pred coq.arity->sort i:term, o:sort.
coq.arity->sort (prod N S X) Y :- !, @pi-decl N S x\ coq.arity->sort (X x) Y.
coq.arity->sort (sort X) X :- !.
:name "arity->sort:fail"
coq.arity->sort T _ :- fatal-error-w-data "arity->sort: not a sort or prod" T.
% Counts how many parameters are there
pred coq.arity->nparams i:arity, o:int.
coq.arity->nparams (parameter _ _ _ In) O :-
pi x\ coq.arity->nparams (In x) O1, O is O1 + 1.
coq.arity->nparams (arity _) 0.
% Prints an arity
pred coq.arity->pp o:arity, o:coq.pp.
coq.arity->pp (parameter ID Imp T Arity) (coq.pp.glue Res) :-
Res = [coq.pp.box (coq.pp.hv 2)
[coq.pp.str A, coq.pp.str ID,
coq.pp.str " :", coq.pp.spc,TPP,coq.pp.str B],
coq.pp.spc, Rest],
if2 (Imp = explicit) (A = "(", B = ")")
(Imp = maximal) (A = "{", B = "}")
(A = "[", B = "]"),
coq.term->pp T TPP,
@pi-parameter ID T x\ coq.arity->pp (Arity x) Rest.
coq.arity->pp (arity T) (coq.pp.glue [coq.pp.str" : ",TPP]) :- coq.term->pp T TPP.
% Get impargs setting from an arity
pred coq.arity->implicits i:arity, o:list implicit_kind.
coq.arity->implicits (parameter Id I Ty F) [I|Is] :-
@pi-parameter Id Ty x\ coq.arity->implicits (F x) Is.
coq.arity->implicits (arity _) [].
% Get impargs setting from an indt-decl
pred coq.indt-decl->implicits i:indt-decl, o:list implicit_kind, o:list (list implicit_kind).
coq.indt-decl->implicits (parameter Id I Ty F) [I|Is] R :-
@pi-parameter Id Ty x\ coq.indt-decl->implicits (F x) Is R1,
std.map R1 (l\r\r = [I|l]) R.
coq.indt-decl->implicits (record _ _ _ _) [] [[]].
coq.indt-decl->implicits (inductive Id _ A Ks) Is R :-
coq.arity->implicits A Is,
@pi-inductive Id A x\
std.map (Ks x) (c\i\sigma a\c = constructor _ a,coq.arity->implicits a i) R.
% Check if some implicits are set
pred coq.any-implicit? i:list implicit_kind.
coq.any-implicit? L :- std.exists L (x\not(x = explicit)).
% extract gref from terms that happen to have one
pred coq.term->gref i:term, o:gref.
coq.term->gref (global GR) GR :- !.
coq.term->gref (pglobal GR _) GR :- !.
coq.term->gref (app [Hd|_]) GR :- !, coq.term->gref Hd GR.
coq.term->gref (let _ _ T x\x) GR :- !, coq.term->gref T GR.
:name "term->gref:fail"
coq.term->gref Term _ :-
fatal-error-w-data "term->gref: input has no global reference" Term.
pred coq.fresh-type o:term.
coq.fresh-type (sort (typ U)) :- coq.univ.new U.
pred coq.sort? i:term.
coq.sort? (sort _).
coq.sort? T :- whd1 T T1, coq.sort? T1.
% Map the term under a spine of fun nodes
pred coq.map-under-fun i:term,
% InputTermUnderLams LamBoundVars TheirTypes Result
i:(term -> list term -> list term -> term -> prop),
o:term.
coq.map-under-fun T F R :- map-under-fun.aux T [] [] F R.
map-under-fun.aux (fun N T B) AccT AccTy F (fun N T R) :- !,
@pi-decl N T x\ map-under-fun.aux (B x) [x|AccT] [T|AccTy] F (R x).
map-under-fun.aux (let N T X B) AccT AccTy F (let N T X R) :- !,
@pi-def N T X x\ map-under-fun.aux (B x) AccT AccTy F (R x).
map-under-fun.aux End AccT AccTy F R :- F End {rev AccT} {rev AccTy} R.
pred coq.iter-under-fun i:term,
% InputTermUnderLams LamBoundVars TheirTypes
i:(term -> list term -> list term -> prop).
coq.iter-under-fun T F :- iter-under-fun.aux T [] [] F.
iter-under-fun.aux (fun N T B) AccT AccTy F :- !,
@pi-decl N T x\ iter-under-fun.aux (B x) [x|AccT] [T|AccTy] F.
iter-under-fun.aux (let _ _ X B) AccT AccTy F :- !,
iter-under-fun.aux (B X) AccT AccTy F.
iter-under-fun.aux End AccT AccTy F :- F End {rev AccT} {rev AccTy}.
% Build a match given the term and function to build the return type and the
% branches
pred coq.build-match
i:term, % T, the term being matched
i:term, % the type of T, expected to be an inductive, eventually applied
% MkRty: IndSort LamBoundVars TheirTypes Result
i:(term -> list term -> list term -> term -> prop),
% MkBranch: Constructor ConstructorTyUnderLams LamBoundVars TheirTypes Result
i:(term -> term -> list term -> list term -> term -> prop),
o:term. % match T (.. MkRty) [ .. MkBranch K1, .. MkBranch K2, ..]
coq.build-match T Tty RtyF BranchF (match T Rty Bs) :-
whd Tty [] HD Args,
if2 (HD = global (indt GR)) true
(HD = pglobal (indt GR) I) true
fail,
@uinstance! I => coq.env.indt GR _ Lno _ Arity Kn Kt,
take Lno Args LArgs,
@uinstance! I => coq.mk-app {coq.env.global (indt GR)} LArgs IndtLArgs,
% Rty
coq.subst-prod LArgs Arity ArityArgs,
coq.bind-ind-arity-no-let IndtLArgs ArityArgs RtyF Rty,
% Bs
map Kt (coq.subst-prod LArgs) KtArgs,
map KtArgs hd-beta-zeta-reduce KtArgsNorm,
map KtArgsNorm coq.prod->fun KtArgsLam,
map Kn (k\r\ sigma K\ coq.env.global (indc k) K, coq.mk-app K LArgs r) KnArgs,
map2 KnArgs KtArgsLam (k\t\coq.map-under-fun t (BranchF k)) Bs.
% XXX the list of arguments are often needed in reverse order
pred coq.bind-ind-arity % calls K under (fun Arity (x : Ity Arity) =>..)
i:term, % the inductive type
i:term, % the arity
i:(term -> list term -> list term -> term -> prop), % Sort Vars Tys Out
o:term. %
bind-ind-arity.aux (prod N T B) (fun N T F) AccT AccTy IT K :- !,
@pi-decl N T x\ bind-ind-arity.aux (B x) (F x) [x|AccT] [T|AccTy] IT K.
bind-ind-arity.aux (let N T X B) (let N T X F) AccT AccTy IT K :- !,
@pi-def N T X x\ bind-ind-arity.aux (B x) (F x) AccT AccTy IT K.
bind-ind-arity.aux (sort _ as Sort) (fun `i` ITy F) AccT AccTy IT K :-
rev AccT Vars,
coq.mk-app IT Vars ITy,
@pi-decl `i` ITy x\ K Sort {append Vars [x]} {rev [ITy|AccTy]} (F x).
coq.bind-ind-arity IT Arity F R :- bind-ind-arity.aux Arity R [] [] IT F.
% As above but let-ins are reduced
pred coq.bind-ind-arity-no-let i:term, i:term, i:(term -> list term -> list term -> term -> prop), o:term.
coq.bind-ind-arity-no-let IT Arity F R :-
(pi N T X B F AccT AccTy IT K\
bind-ind-arity.aux (let N T X B) F AccT AccTy IT K :- !,
bind-ind-arity.aux (B X) F AccT AccTy IT K) =>
bind-ind-arity.aux Arity R [] [] IT F.
pred coq.bind-ind-parameters i:inductive, i:(term -> list term -> list term -> term -> prop), o:term.
coq.bind-ind-parameters I K O :-
coq.env.indt I _ _ N A _ _,
coq.bind-ind-parameters.aux N A [] [] K O.
coq.bind-ind-parameters.aux 0 Ty Vars Tys K O :- !, K Ty {std.rev Vars} {std.rev Tys} O.
coq.bind-ind-parameters.aux I (prod N T F) Vs Ts K (fun N T G) :- I > 0, !, J is I - 1,
@pi-decl N T x\
coq.bind-ind-parameters.aux J (F x) [x|Vs] [T|Ts] K (G x).
coq.bind-ind-parameters.aux I (let N T B F) Vs Ts K (fun N T G) :- I > 0, !, J is I - 1,
@pi-def N T B x\
coq.bind-ind-parameters.aux J (F x) [x|Vs] [T|Ts] K (G x).
coq.bind-ind-parameters.aux I T Vs Ts K O :- I > 0, whd1 T T', !,
coq.bind-ind-parameters.aux I T' Vs Ts K O.
% coq.with-TC Class Instance->Clause Code: runs Code under a context augmented with
% all instances for Class transformed by Instance->Clause.
pred coq.with-TC i:term, i:(tc-instance -> prop -> prop), i:prop.
coq.with-TC Class Instance->Clause Code :-
coq.TC.db-for {coq.term->gref Class} Instances,
map Instances Instance->Clause Hyps, !,
Hyps => Code.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
pred coq.parse-attributes i:list attribute, i:list attribute-signature, o:list prop.
% Coq attribute parser, eg [#[attribute=value] Command]
%
% Usage:
% main _ :-
% attributes A, % fetch
% coq.parse-attributes A Spec Opts, % parse/validate
% Opts => (mycode, get-option "foo" V, mycode). % use
%
% where [Opts] is a list of clauses [get-option StringName Value], where value
% can have any type and [Spec] is a list of [attribute-sigmature].
% Example of an attribute signature:
% [
% att "this" bool,
% att "that.thing" int,
% att "algebraic" (oneof ["foo" `-> foo-thing, "bar" `-> barbar]),
% ]
%
% Env variable COQ_ELPI_ATTRIBUTES can be used to pass attributes to all
% commands. These attributes names are prefixed by 'elpi.' and are of type
% string.
%
% Eg.
% COQ_ELPI_ATTRIBUTES=test=yes,str="some-string" coqc foo.v
% results in commands in foo.v to receive
% [ attribute "elpi.test" (leaf "yes") ,
% attribute "elpi.str" (leaf "some-string") | ...]
% which are automatically accepted and give rise to
% get-option "elpi.test" "yes"
% get-option "elpi.str" "some-string"
kind attribute-signature type.
type att string -> attribute-type -> attribute-signature.
type att-ignore-unknown attribute-signature.
type supported-attribute attribute-signature -> prop.
supported-attribute (att "elpi.loc" loc).
supported-attribute (att Name string) :- rex_match "^elpi\\." Name.
kind attribute-type type.
type int attribute-type.
type string attribute-type.
type bool attribute-type.
type oneof list attribute-mapping -> attribute-type.
type attmap attribute-type.
type loc attribute-type.
kind attribute-mapping type.
type (`->) string -> any -> attribute-mapping.
pred coq.valid-str-attribute i:string, i:string, o:option any, o:diagnostic.
coq.valid-str-attribute Name Value V Diag :-
if (supported-attribute (att Name Type))
(coq.typecheck-attribute Name Type Value LPV Diag, V = some LPV)
(if (supported-attribute att-ignore-unknown) (V = none, Diag = ok)
(Diag = error {calc ( "Attribute " ^ Name ^ " is not supported")})).
pred coq.valid-loc-attribute i:string, i:loc, o:diagnostic.
coq.valid-loc-attribute Name Loc Diag :-
if (supported-attribute (att Name loc))
(if (primitive? Loc "Loc.t") (Diag = ok) (Diag = error {calc ( "Attribute " ^ Name ^ " takes a loc, got " ^ {std.any->string Loc} ) } ))
(if (supported-attribute att-ignore-unknown) (Diag = ok)
(Diag = error {calc ( "Attribute " ^ Name ^ " is not supported")})).
:index (_ 1 1)
pred coq.typecheck-attribute i:string, o:attribute-type, i:string, o:any, o:diagnostic.
coq.typecheck-attribute _ int Value V ok :- V is string_to_int Value, !.
coq.typecheck-attribute N int Value _ (error Msg) :-
Msg is "Attribute " ^ N ^ " takes an integer, got: " ^ Value.
coq.typecheck-attribute _ string V V ok.
coq.typecheck-attribute _ bool "true" tt ok.
coq.typecheck-attribute _ bool "tt" tt ok.
coq.typecheck-attribute _ bool "True" tt ok.
coq.typecheck-attribute _ bool "on" tt ok.
coq.typecheck-attribute _ bool "yes" tt ok.
coq.typecheck-attribute _ bool "" tt ok.
coq.typecheck-attribute _ bool "false" ff ok.
coq.typecheck-attribute _ bool "False" ff ok.
coq.typecheck-attribute _ bool "off" ff ok.
coq.typecheck-attribute _ bool "ff" ff ok.
coq.typecheck-attribute _ bool "no" ff ok.
coq.typecheck-attribute N bool Value _ (error Msg) :-
Msg is "Attribute " ^ N ^ " takes an boolean, got: " ^ Value.
pred coq.is-one-of i:string, o:any, i:attribute-mapping.
coq.is-one-of K V (K `-> V).
coq.typecheck-attribute _ (oneof L) K V ok :- std.exists L (coq.is-one-of K V), !.
coq.typecheck-attribute N (oneof L) K _ (error Msg) :-
std.map L (x\r\ sigma tmp\ x = r `-> tmp) S,
std.fold S "" (s\ a\ calc (a ^ " " ^ s)) OneOf,
Msg is "Attribute " ^ N ^ " takes one of " ^ OneOf ^ ", got: " ^ K.
coq.parse-attributes L S O :-
std.map S (x\r\ r = supported-attribute x) CS,
CS => parse-attributes.aux L "" O, !.
parse-attributes.aux [] _ [].
parse-attributes.aux [attribute S (node L)|AS] Prefix R :- if (Prefix = "") (PS = S) (PS is Prefix ^ "." ^ S), supported-attribute (att PS attmap), !,
parse-attributes.aux AS Prefix R1,
(pi x\ supported-attribute (att x string) :- !) => parse-attributes.aux L "" Map,
std.append R1 [get-option PS Map] R.
parse-attributes.aux [attribute S (node L)|AS] Prefix R :- !,
parse-attributes.aux AS Prefix R1,
if (Prefix = "") (PS = S) (PS is Prefix ^ "." ^ S),
parse-attributes.aux L PS R2,
std.append R1 R2 R.
parse-attributes.aux [attribute S (leaf-str V)|AS] Prefix CLS :- !,
if (Prefix = "") (PS = S) (PS is Prefix ^ "." ^ S),
coq.valid-str-attribute PS V V1 Diag,
if (Diag = error Msg) (coq.error Msg) true,
if (V1 = some Val) (CLS = [get-option PS Val|R]) (CLS = R), % ignored
parse-attributes.aux AS Prefix R.
parse-attributes.aux [attribute S (leaf-loc V)|AS] Prefix CLS :- !,
if (Prefix = "") (PS = S) (PS is Prefix ^ "." ^ S),
coq.valid-loc-attribute PS V Diag,
if (Diag = error Msg) (coq.error Msg) true,
CLS = [get-option PS V|R],
parse-attributes.aux AS Prefix R.
coq-elpi-1.19.3/elpi/elpi-command-template.elpi 0000664 0000000 0000000 00000000642 14511776522 0021314 0 ustar 00root root 0000000 0000000 /* Loaded when Elpi Command is used */
/* license: GNU Lesser General Public License Version 2.1 or later */
/* ------------------------------------------------------------------------- */
accumulate elpi/coq-lib. % basic term manipulation routines
accumulate elpi/elpi-reduction. % whd, hd-beta, ...
accumulate elpi/elpi-ltac. % refine, or, thenl, ...
coq-elpi-1.19.3/elpi/elpi-ltac.elpi 0000664 0000000 0000000 00000011420 14511776522 0017004 0 ustar 00root root 0000000 0000000 /* elpi-ltac: building blocks for tactics */
/* license: GNU Lesser General Public License Version 2.1 or later */
/* ------------------------------------------------------------------------- */
typeabbrev tactic (sealed-goal -> (list sealed-goal -> prop)).
typeabbrev open-tactic (goal -> (list sealed-goal -> prop)).
% The one tactic ------------------------------------------------------------
pred refine i:term, i:goal, o:list sealed-goal.
refine T G GS :- refine.elaborate T G GS.
pred refine.elaborate i:term, i:goal, o:list sealed-goal.
refine.elaborate T (goal _ RawEv Ty Ev _) GS :-
rm-evar RawEv Ev,
@keepunivs! => coq.elaborate-skeleton T Ty TR ok,
coq.ltac.collect-goals TR GS _,
RawEv = T,
Ev = TR.
pred refine.typecheck i:term, i:goal, o:list sealed-goal.
refine.typecheck T (goal _ RawEv Ty Ev _) GS :-
rm-evar RawEv Ev,
coq.typecheck T Ty ok,
coq.ltac.collect-goals T GS _,
RawEv = T,
Ev = T.
pred refine.no_check i:term, i:goal, o:list sealed-goal.
refine.no_check T (goal _ RawEv _ Ev _) GS :-
rm-evar RawEv Ev,
coq.ltac.collect-goals T GS _,
RawEv = T,
Ev = T.
% calling other tactics, with arguments ---------------------------------------
pred coq.ltac i:string, i:sealed-goal, o:list sealed-goal.
coq.ltac Tac G GS :- coq.ltac.open (coq.ltac.call-ltac1 Tac) G GS.
namespace coq.ltac {
pred call i:string, i:list argument, i:goal, o:list sealed-goal.
call Tac Args G GS :-
set-goal-arguments Args G (seal G) (seal G1),
coq.ltac.call-ltac1 Tac G1 GS.
pred set-goal-arguments i:list argument, i:goal, i:sealed-goal, o:sealed-goal.
set-goal-arguments A G (nabla SG) (nabla R) :- pi x\ set-goal-arguments A G (SG x) (R x).
set-goal-arguments A (goal Ctx1 _ _ _ _) (seal (goal Ctx2 REv2 Ty2 Ev2 _)) (seal (goal Ctx2 REv2 Ty2 Ev2 I)) :- same_term Ctx1 Ctx2, !,
A = I.
set-goal-arguments A (goal Ctx1 _ _ _ _) (seal (goal Ctx2 REv2 Ty2 Ev2 _)) (seal (goal Ctx2 REv2 Ty2 Ev2 I)) :-
std.map A (private.move-goal-argument Ctx1 Ctx2) I.
% Tacticals ----------------------------------------------------------------
pred try i:tactic, i:sealed-goal, o:list sealed-goal.
try T G GS :- T G GS.
try _ G [G].
:index(_ 1)
pred all i:tactic, i:list sealed-goal, o:list sealed-goal.
all T [G|Gs] O :- T G O1, all T Gs O2, std.append O1 O2 O.
all _ [] [].
pred thenl i:list tactic, i:sealed-goal, o:list sealed-goal.
thenl [] G [G].
thenl [T|Ts] G GS :- T G NG, all (thenl Ts) NG GS.
pred repeat i:tactic, i:sealed-goal, o:list sealed-goal.
repeat T G GS :- T G GS1, all (repeat T) GS1 GS.
repeat _ G [G].
pred repeat! i:tactic, i:sealed-goal, o:list sealed-goal.
repeat! T G GS :- T G GS1, !, all (repeat T) GS1 GS.
repeat! _ G [G].
pred or i:list tactic, i:sealed-goal, o:list sealed-goal.
or TL G GS :- std.exists TL (t\ t G GS).
:index(_ 1)
pred open i:open-tactic, i:sealed-goal, o:list sealed-goal.
open T (nabla G) O :- (pi x\ open T (G x) (NG x)), private.distribute-nabla NG O.
open _ (seal (goal _ _ _ Solution _)) [] :- not (var Solution), !. % solved by side effect
open T (seal (goal Ctx _ _ _ _ as G)) O :-
std.filter Ctx private.not-already-assumed Ctx1,
Ctx1 => T G O,
if (var O)
(G = goal _ _ _ P _, coq.ltac.collect-goals P O1 O2, std.append O1 O2 O)
true.
% helper code ---------------------------------------------------------------
namespace private {
:index(_ _ 1)
pred move-goal-argument i:list prop, i:list prop, i:argument, o:argument.
move-goal-argument _ _ (int _ as A) A.
move-goal-argument _ _ (str _ as A) A.
move-goal-argument _ _ (tac _) _ :-
coq.error "NIY: move tactic goal argument to another context".
move-goal-argument C D (trm T) (trm T1) :-
std.rev C Cr, std.rev D Dr,
std.assert! (move-term Cr Dr T T1) "cannot move goal argument to the right context", !.
:index(2)
pred move-term i:list prop, i:list prop, i:term, o:term.
move-term [] _ T T1 :- copy T T1.
move-term [decl X _ TX|C1] [decl Y _ TY|C2] T T1 :- std.do! [ copy TX TX1, same_term TX1 TY ], !,
copy X Y => move-term C1 C2 T T1.
move-term [def X _ TX BX|C1] [def Y _ TY BY|C2] T T1 :- std.do! [ copy TX TX1, same_term TX1 TY, copy BX BX1, same_term BX1 BY ], !,
copy X Y => move-term C1 C2 T T1.
move-term [decl X _ _|C1] C2 T T1 :- not(occurs X T), !, move-term C1 C2 T T1.
move-term [def X _ _ _|C1] C2 T T1 :- not(occurs X T), !, move-term C1 C2 T T1.
move-term C1 [_|C2] T T1 :- move-term C1 C2 T T1.
pred distribute-nabla i:(term -> list sealed-goal), o:list sealed-goal.
distribute-nabla (_\ []) [].
distribute-nabla (x\ [X x| XS x]) [nabla X|R] :- (pi x\ occurs x (X x)), !,
distribute-nabla XS R.
distribute-nabla (x\ [X| XS x]) [X|R] :- distribute-nabla XS R.
pred not-already-assumed i:prop.
not-already-assumed (decl X _ _Ty) :- not(decl X _ _ ; def X _ _ _).
not-already-assumed (def X _ _Ty _Bo) :- not(decl X _ _ ; def X _ _ _).
}} coq-elpi-1.19.3/elpi/elpi-reduction.elpi 0000664 0000000 0000000 00000010216 14511776522 0020057 0 ustar 00root root 0000000 0000000 /* Reduction (whd, hd-beta, ...) */
/* license: GNU Lesser General Public License Version 2.1 or later */
/* ------------------------------------------------------------------------- */
% Entry points
typeabbrev stack (list term).
pred hd-beta i:term, i:stack, o:term, o:stack.
pred hd-beta-zeta i:term, i:stack, o:term, o:stack.
pred hd-beta-zeta-reduce i:term, o:term.
pred whd i:term, i:stack, o:term, o:stack.
pred whd-indc i:term, o:constructor, o:stack.
pred unwind i:term, i:stack, o:term.
pred whd1 i:term, o:term.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
shorten std.{append, nth, drop}.
% indirection, to be used if we add to the stack "match" frames
unwind T A R :- if (var T) (coq.mk-app-uvar T A R) (coq.mk-app T A R).
pred nth-stack i:int, i:stack, o:stack, o:term, o:stack.
nth-stack 0 [X|XS] [] X XS :- !.
nth-stack N [X|XS] [X|Before] At After :-
M is N - 1, nth-stack M XS Before At After.
% whd beta-iota-delta-zeta, main code
whd (app [Hd|Args]) C X XC :- !, whd Hd {append Args C} X XC.
whd (fun _ _ _ as X) [] X [] :- !.
whd (fun N T F) [B|C] X XC :- !,
(pi x\ def x N T B => cache x BN_ => whd (F x) C (F1 x) (C1 x)), X = F1 B, XC = C1 B.
whd (let N T B F) C X XC :- !,
(pi x\ def x N T B => cache x BN_ => whd (F x) C (F1 x) (C1 x)), X = F1 B, XC = C1 B.
whd (global (const GR)) C X XC :- unfold GR none C D DC, !, whd D DC X XC.
whd (pglobal (const GR) I) C X XC :- unfold GR (some I) C D DC, !, whd D DC X XC.
whd (primitive (proj _ N)) [A|C] X XC :- whd-indc A _ KA, !,
whd {proj-red KA N C} X XC.
whd (global (const GR) as HD) C X XC :- coq.env.primitive? GR, !,
unwind HD C Orig,
coq.reduction.lazy.whd_all Orig R,
if (same_term Orig R) (X = HD, XC = C) (whd R [] X XC).
whd (match A _ L) C X XC :- whd-indc A GR KA, !,
whd {match-red GR KA L C} X XC.
whd (fix _ N _ F as Fix) C X XC :- nth-stack N C LA A RA, whd-indc A GR KA, !,
whd {fix-red F Fix LA GR KA RA} X XC.
whd N C X XC :- name N, def N _ _ V, !, cache-whd N VN V, whd VN C X XC.
whd X C X C.
% assert A reduces to a constructor
whd-indc A GR KA :- whd A [] VA C, !, VA = global (indc GR), KA = C.
% [whd1 T R] asserts progress was made in reducing T to R.
whd1 T R :-
whd T [] HD ARGS,
unwind HD ARGS R,
not(same_term T R).
% iota step
pred match-red i:constructor, i:list term, i:list term, i:stack, o:term, o:stack.
match-red GR KArgs BL C X XC :-
coq.env.indc GR Lno _ Ki _,
drop Lno KArgs Args,
nth Ki BL Bi,
hd-beta {coq.mk-app Bi Args} C X XC.
pred proj-red i:list term, i:int, i:stack, o:term, o:stack.
proj-red Args FieldNo C V C :-
nth FieldNo Args V.
% iota step
pred fix-red
i:(term -> term), i:term,
i:list term, i:constructor, i:list term, i:list term, o:term, o:stack.
fix-red F Fix LA GR KA RA X XC :-
append LA [{coq.mk-app (global (indc GR)) KA}|RA] ArgsWRedRecNo,
hd-beta {coq.mk-app (F Fix) ArgsWRedRecNo} [] X XC.
pred unfold % delta (global constants) + hd-beta
i:constant, % name
i:option univ-instance, % universe instance if the constant is universe polymorphic
i:stack, % args
o:term, % body
o:stack. % args after hd-beta
unfold GR none A BO BOC :- coq.env.const GR (some B) _, hd-beta B A BO BOC.
unfold GR (some I) A BO BOC :- @uinstance! I => coq.env.const GR (some B) _, hd-beta B A BO BOC.
% ensures its first argument is the whd of the second
pred cache i:term, o:term.
pred cache-whd i:term, i:term, i:term.
cache-whd N K V :- cache N VN, var VN, !, whd V [] X XC, unwind X XC VN, K = VN.
cache-whd N K _ :- cache N K, !.
cache-whd N _ _ :- coq.error "anomaly: def with no cache:" {coq.term->string N}.
hd-beta (app [Hd|Args]) S X C :- !, hd-beta Hd {append Args S} X C.
hd-beta (fun _ _ F) [A|AS] X C :- !, hd-beta (F A) AS X C.
:name "hd-beta:end"
hd-beta X C X C.
hd-beta-zeta (app [Hd|Args]) S X C :- !, hd-beta-zeta Hd {append Args S} X C.
hd-beta-zeta (fun _ _ F) [A|AS] X C :- !, hd-beta-zeta (F A) AS X C.
hd-beta-zeta (let _ _ B F) AS X C :- !, hd-beta-zeta (F B) AS X C.
:name "hd-beta-zeta:end"
hd-beta-zeta X C X C.
hd-beta-zeta-reduce T R :- hd-beta-zeta T [] H S, unwind H S R.
coq-elpi-1.19.3/elpi/elpi-tactic-template.elpi 0000664 0000000 0000000 00000001103 14511776522 0021136 0 ustar 00root root 0000000 0000000 /* Loaded when Elpi Command is used */
/* license: GNU Lesser General Public License Version 2.1 or later */
/* ------------------------------------------------------------------------- */
accumulate elpi/coq-lib. % basic term manipulation routines
accumulate elpi/elpi-reduction. % whd, hd-beta, ...
% Since the elaborator written in Elpi is not ready, we fallback to the Coq one
% accumulate engine/elaborator. % of, unify
accumulate elpi/coq-elaborator.
accumulate elpi/elpi-ltac. % refine, or, thenl, ...
coq-elpi-1.19.3/elpi/elpi_elaborator.elpi 0000664 0000000 0000000 00000035040 14511776522 0020301 0 ustar 00root root 0000000 0000000 /* Type inference and unification */
/* license: GNU Lesser General Public License Version 2.1 or later */
/* ------------------------------------------------------------------------- */
shorten std.{rev, append, ignore-failure!, mem, map2, split-at, map, assert!}.
% Entry points
pred unify-eq i:term, i:term.
pred unify-list-eq i:list term, i:list term.
pred unify-leq i:term, i:term.
pred of i:term, o:term, o:term. % of Term Type(i/o) RefinedTerm
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% Reduction %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
:before "hd-beta:end"
hd-beta (uvar as K) [A|AS] X C :- !, % auto-intro
assert! (of A TA _) "already typed",
unify-eq K (fun `hd_beta_auto` TA F),
hd-beta (F A) AS X C.
:before "hd-beta-zeta:end"
hd-beta-zeta (uvar as K) [A|AS] X C :- !, % auto-intro
assert! (of A TA _) "already typed",
unify-eq K (fun `hd_beta_zeta_auto` TA F),
hd-beta-zeta (F A) AS X C.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% Unification %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% invariant: hd-beta terms
% we start with ff, tt to handle symmetric cases
% NOTE: rec-calls with unify (ensured hd-beta + ff) , symmetric rules are typically !
% NOTE: asymmetric rules are not ! otherwise the flip rule is killed
% NOTE: whd are !
% names: unif X C T D M
kind cumul type.
type eq cumul.
type leq cumul.
macro @tail-cut-if Option Hd Hyps :- (
(Hd :- get-option Option tt, Hyps, !),
(Hd :- not(get-option Option tt), Hyps )
).
pred unif i:term, i:stack, i:term, i:stack, i:bool, i:cumul.
:if "DBG:unif"
unif X CX Y CY D M :-
coq.say {counter "run"} "unif" X CX "==" Y CY "(flipped?" D "cumul:" M ")", fail.
pred swap i:bool, i:(A -> B -> prop), i:A, i:B.
swap tt F A B :- F B A.
swap ff F A B :- F A B.
% flexible cases
@tail-cut-if "unif:greedy" (unif (uvar V L) [] T D _ _) (!, (bind-list L {unwind T D} V)).
@tail-cut-if "unif:greedy" (unif X C (uvar V L) [] _ _) (!, bind-list L {unwind X C} V).
unif (sort prop) [] (sort (uvar as Y)) [] _ _ :- !, Y = prop.
unif X [] (sort (uvar as Y)) [] M U :- !,
coq.univ.new Lvl,
Y = typ Lvl,
unif X [] (sort Y) [] M U.
unif (sort (uvar as X)) [] Y [] M U :- !,
coq.univ.new Lvl,
X = typ Lvl,
unif (sort X) [] Y [] M U.
unif (sort S1) [] (sort S2) [] M eq :- !, swap M coq.sort.eq S1 S2.
unif (sort S1) [] (sort S2) [] M leq :- !, swap M coq.sort.leq S1 S2.
unif (primitive X) [] (primitive X) [] ff _ :- !.
unif (global (indt GR1)) C (global (indt GR2)) D _ _ :- !, GR1 = GR2, unify-ctxs C D.
unif (global (indc GR1)) C (global (indc GR2)) D _ _ :- !, GR1 = GR2, unify-ctxs C D.
unif (pglobal (indt GR1) I1) C (pglobal (indt GR2) I2) D _ eq :- !,
GR1 = GR2,
coq.univ-instance.unify-eq (indt GR1) I1 I2 ok,
unify-ctxs C D.
unif (pglobal (indt GR1) I1) C (pglobal (indt GR2) I2) D _ leq :- !,
GR1 = GR2,
coq.univ-instance.unify-leq (indt GR1) I1 I2 ok,
unify-ctxs C D.
% fast path for stuck term on the right
unif X C (global (indt _) as T) D ff U :- !, unif T D {whd X C} tt U. % TODO:1
unif X C (global (indc _) as T) D ff U :- !, unif T D {whd X C} tt U. % TODO:1
unif X C (pglobal (indt _) _ as T) D ff U :- !, unif T D {whd X C} tt U. % TODO:1
unif X C (pglobal (indc _) _ as T) D ff U :- !, unif T D {whd X C} tt U. % TODO:1
% congruence rules TODO: is the of assumption really needed?
unif (fun N T1 F1) [] (fun M T2 F2) [] _ _ :- !, ignore-failure! (N = M),
unify T1 T2 eq,
pi x\ (decl x N T1) => unify (F1 x) (F2 x) eq.
unif (prod N T1 F1) [] (prod M T2 F2) [] _ U :- !, ignore-failure! (N = M),
unify T1 T2 eq,
pi x\ (decl x N T1) => unify (F1 x) (F2 x) U.
unif (fix N Rno Ty1 F1) B1 (fix M Rno Ty2 F2) B2 _ _ :- !, ignore-failure! (N = M),
unify Ty1 Ty2 eq,
(pi f\ (decl f N Ty1) => unify (F1 f) (F2 f) eq),
unify-ctxs B1 B2.
unif (match A1 R1 L1) B1 (match A2 R2 L2) B2 _ _ :- !,
unify A1 A2 eq, unify R1 R2 eq, unify-list L1 L2, unify-ctxs B1 B2.
% congruence heuristic (same maybe-non-normal head)
unif (let N T1 B1 F1) C1 (let M T2 B2 F2) C2 _ _ :- ignore-failure! (N = M),
unify T1 T2 eq, unify B1 B2 eq,
(@pi-def N T1 B1 x\ unify (F1 x) (F2 x) eq),
unify-ctxs C1 C2, !.
unif (global (const GR)) C (global (const GR)) D _ _ :- unify-ctxs C D, !.
unif (pglobal (const GR) I1) C (pglobal (const GR) I2) D _ eq :-
coq.univ-instance.unify-eq (const GR) I1 I2 ok,
unify-ctxs C D, !.
unif (pglobal (const GR) I1) C (pglobal (const GR) I2) D _ leq :-
coq.univ-instance.unify-leq (const GR) I1 I2 ok,
unify-ctxs C D, !.
unif X C T D _ _ :- name X, name T, X = T, unify-ctxs C D.
% 1 step reduction TODO:1
unif (global (const GR)) C T D M U :- unfold GR none C X1 C1, !, unif X1 C1 T D M U.
unif (pglobal (const GR) I) C T D M U :- unfold GR (some I) C X1 C1, !, unif X1 C1 T D M U.
unif (let N TB B F) C1 T C2 M U :- !,
@pi-def N TB B x\ unif {hd-beta (F x) C1} T C2 M U.
unif (match A _ L) C T D M U :- whd-indc A GR KA, !,
unif {match-red GR KA L C} T D M U.
unif (fix _ N _ F as X) C T D M U :- nth-stack N C LA A RA, whd-indc A GR KA, !,
unif {fix-red F X LA GR KA RA} T D M U.
unif X C T D M U :- name X, def X _ _ V, !, unif {hd-beta V C} T D M U.
% TODO we could use _VN if nonflex
% TODO:1 turn into (if reducible then reduce1 else fully-reduce2 tt)
% symmetry
unif X C T D ff U :- !, unif T D X C tt U.
% error
% unif X C1 Y C2 _tt :- !,
% print "Error: " {coq.term->string {unwind X C1}} "vs" {coq.term->string {unwind Y C2}}. %, halt.
% Contexts happens to be lists, so we just reuse the code
pred unify-list i:list term, i:list term.
unify-list L1 L2 :- unify-ctxs L1 L2.
% the entry points of rec calls: unify unify-ctxs
pred unify-ctxs i:list term, i:list term.
unify-ctxs [] [].
unify-ctxs [X|XS] [Y|YS] :- unify X Y eq, !, unify-ctxs XS YS.
pred unify i:term, i:term, i:cumul.
unify A B C :- unif {hd-beta A []} {hd-beta B []} ff C.
%%%%%% entry points for clients %%%%%%%
unify-eq X Y :- unify X Y eq.
unify-leq X Y :- unify X Y leq.
unify-list-eq L1 L2 :- unify-list L1 L2.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Flexible case %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Binding a list of terms (delift in Matita, invert subst in Coq)
% We use a keyd discipline, i.e. we only bind terms with a rigid head
pred key i:term.
key (global _) :- !.
key (pglobal _ _) :- !.
key C :- name C, !.
key (primitive _) :- !.
pred bind-list i:list term, i:term, o:A.
bind-list [] T T' :- bind T T1, T1 = T'.
bind-list [app [C| AS] |VS] T R :- key C, !,
pi x\
(pi L X\ bind (app[C|L]) X :- get-option "unif:greedy" tt, unify-list-eq L AS, X = x, !) =>
(pi L X\ bind (app[C|L]) X :- not (get-option "unif:greedy" tt),unify-list-eq L AS, X = x) =>
bind-list VS T (R x).
bind-list [C|VS] T R :- key C, def C _ _ V, key V, !,
pi x\ @tail-cut-if "unif:greedy" (bind C x) true =>
@tail-cut-if "unif:greedy" (bind V x) true =>
bind-list VS T (R x).
bind-list [C|VS] T R :- key C, !,
pi x\ @tail-cut-if "unif:greedy" (bind C x) true => bind-list VS T (R x).
bind-list [ _ |VS] T R :- !, pi x\ bind-list VS T (R x).
% CAVEAT: (app FLEX), (match _ _ FLEX) are not terms!
pred bind i:term, o:term.
bind X Y :- name X, X = Y, !.
bind X Y :- name X, def X _ _ T, !, bind T Y.
bind (global _ as C) C :- !.
bind (pglobal _ _ as C) C :- !.
bind (sort _ as C) C :- !.
bind (fix N Rno Ty F) (fix N Rno Ty1 F1) :- !,
bind Ty Ty1, pi x\ decl x N Ty => bind (F x) (F1 x).
bind (match T Rty B) X :- !,
bind T T1, bind Rty Rty1, map B bind B1, X = (match T1 Rty1 B1).
bind (app L) X :- !, map L bind L1, X = app L1.
bind (fun N T F) (fun N T1 F1) :- !,
bind T T1, pi x\ decl x N T => bind (F x) (F1 x).
bind (let N T B F) (let N T1 B1 F1) :- !,
bind T T1, bind B B1, @pi-def N T B x\ bind (F x) (F1 x).
bind (prod N T F) X :- !,
bind T T1, (@pi-decl N T x\ bind (F x) (F1 x)), X = (prod N T1 F1).
bind (uvar M L) W :- map L bind L1, coq.mk-app-uvar M L1 W.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Type checking %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% eat-prod head head-ty args-done todo-args refined-app refined-ty %%%%%%%%
pred bidir-app i:term, i:term, i:list term, o:term.
:name "of:bidirectional-app"
bidir-app _ _ _ _.
pred saturate-dummy i:term, o:term.
saturate-dummy (prod _ _ F) R :- pi x\ saturate-dummy (F x) R.
saturate-dummy X X.
pred ensure-prod.aux i:list A, i:term, o:term, o:bool.
ensure-prod.aux [] X X _.
ensure-prod.aux [_|Args] (prod N S T) (prod N S T1) NU :- !,
pi x\ ensure-prod.aux Args (T x) (T1 x) NU.
ensure-prod.aux [_|Args] uvar (prod Name_ Src_ R) tt :- !,
pi x\ ensure-prod.aux Args (R x) (R x) tt.
ensure-prod.aux Args X R NU :-
whd1 X Y, ensure-prod.aux Args Y R NU.
% TODO: do not fail if whd1 fails and the term is not flexible since it
% may just need to be passed a concrete argument
pred ensure-prod i:list A, i:term.
ensure-prod Args Ty :-
ensure-prod.aux Args Ty R NeedsUnif,
if (var NeedsUnif) true (of R _ R1, unify-eq Ty R1).
pred eat-prod i:list term, i:term, i:term, o:list term, o:term, o:term.
:if "DBG:of" eat-prod [] Hd Prod Adone Res ResTy :-
coq.say "eat-prod" Hd {rev Adone} "==" Res ";" Prod "=<=" ResTy, fail.
eat-prod [] Hd Prod Adone Res ResTy :- !,
rev Adone Args,
unify-eq Res {coq.mk-app Hd Args},
unify-leq Prod ResTy.
% XXX why not unif?
eat-prod [A|AS] Hd (prod _ Src Tgt as Prod) Adone Res ResTy :-
bidir-app Hd Prod Adone ResTy,
of A Src ResA,
eat-prod AS Hd (Tgt ResA) [ResA|Adone] Res ResTy.
% TODO: add a whd1 eg in case of a n-ary function
:if "DBG:of"
of X Tx Rx :- coq.say {counter "run"} "of" X Tx Rx, fail.
of X Tx R :- name X, (decl X _ T ; def X _ T _), unify-leq T Tx, R = X.
of (fun N S F) LamTy (fun M S2 F2) :-
of (prod N S _) (sort _U) (prod M S2 T),
unify-leq (prod M S2 T) LamTy,
pi x\ decl x M S2 => of (F x) (T x) (F2 x).
of (app [X]) Ty R :- !, of X Ty R.
of (app [Hd|Args]) TyApp App :-
of Hd Prod Hd1,
ensure-prod Args Prod,
eat-prod Args Hd1 Prod [] App TyApp.
of (prod N S F) ProdTy (prod N ResS ResF) :-
closed_term U1, closed_term U2, closed_term U,
of S (sort U1) ResS,
(pi x\ decl x N ResS => of (F x) (sort U2) (ResF x)),
pts U1 U2 U,
unify-leq (sort U) ProdTy.
of (match T Rty Bs) ResRtyInst (match ResT ResRty ResBs) :-
of T TyT ResT,
% T : TyT = (indt GR) LArgs RArgs, and (indt GR) : Ty
coq.safe-dest-app TyT (global (indt GR)) Args,
coq.env.indt GR _IsInd Lno _Luno Ty Kn Ks, % TODO LUno
split-at Lno Args LArgs RArgs, % TODO: not a failure, just type err
% fix LArgs on ind ty and constructors ty
coq.subst-prod LArgs Ty TyLArgs,
map Ks (coq.subst-prod LArgs) KsLArgs,
% Rty skeleton (uknown ending) = fun rargs, fun e : indt largs rargs, ?
mk-rty [] {coq.mk-app (global (indt GR)) LArgs} TyLArgs ResRtyRaw,
of ResRtyRaw _ ResRty, unify-eq Rty ResRty,
% Rty must type each branch
map2 KsLArgs Kn (mk-bty Rty Lno) BsTy,
map2 Bs BsTy of ResBs,
% Outside type
unify-leq {coq.mk-app ResRty {append RArgs [ResT]}} ResRtyInst.
of (let N Ty Bo F) TyFx (let N ResTy ResBo ResF) :-
of Ty (sort _) ResTy, of Bo ResTy ResBo,
pi x\ def x N ResTy ResBo => cache x T_ => of (F x) TyFx (ResF x).
of (fix N Rno Ty BoF) ResTy (fix N Rno RTy ResBoF) :-
of Ty (sort _) RTy,
unify-leq RTy ResTy,
pi f\ decl f N RTy => of (BoF f) ResTy (ResBoF f).
of (sort S) (sort S1) (sort S) :- coq.sort.sup S S1.
of (global GR as X) T X :- coq.env.typeof GR T1, unify-leq T1 T.
of (pglobal GR I as X) T X :-
@uinstance! I => coq.env.typeof GR T1, unify-leq T1 T.
of (primitive (uint63 _) as X) T X :- unify-leq {{ lib:elpi.uint63 }} T.
of (primitive (float64 _) as X) T X :- unify-leq {{ lib:elpi.float64 }} T.
of (uvar as X) T Y :- !, evar X T Y.
:if "OVERRIDE_COQ_ELABORATOR"
:name "refiner-assign-evar"
:before "default-assign-evar"
evar X Ty S :- !, of X Ty S.
pred coerce o:term, o:term, o:term, o:term.
pred coerced i:term, i:term, i:term, o:term.
pred coerceible i:term, o:term, i:term, o:term.
of X T R :- get-option "of:coerce" tt, not (var T), of X XT Y, coerced XT T Y R.
:if "DBG:of"
of X Tx Rx :- coq.say {counter "run"} "of [FAIL]" X Tx Rx, fail.
pred utc % Uniqueness of typing
i:list term, % names (canonical)
i:term, % type living in names
i:list term, % values (explicit subst on names)
i:term, % type living in values
o:prop. % goal checking compatibility of the two types
utc [] T1 [] T2 (unify-eq T1V T2) :- !, copy T1 T1V.
utc [N|NS] T1 [V|VS] T2 C :- !, copy N V => utc NS T1 VS T2 C.
utc [] T1 VS T2 C :- !, utc [] {coq.subst-prod VS T1} [] T2 C. % FIXME: reduction
utc [_|NS] (prod _ _ F) [] T2 C :- !, % FIXME: reduction
assert! (pi x\ F x = F1) "restriction bug", utc NS F1 [] T2 C.
% This could be done in ML
pred canonical? i:list term.
canonical? [].
canonical? [N|NS] :- name N, not(mem NS N), canonical? NS.
constraint declare-evar evar decl def cache rm-evar {
rule (E1 : G1 ?- evar _ T1 (uvar K L1)) % canonical
\ (E2 : G2 ?- evar _ T2 (uvar K L2)) % actual
| (canonical? L1, utc L1 T1 L2 T2 Condition,
coq.say "CHR: Uniqueness of typing of" K "+" L1 "<->" L2,
coq.say E1 "|>" G1 "|-" K L1 ":" T1,
coq.say E2 "|>" G2 "|-" K L2 ":" T2,
coq.say E2 "|>" G2 "|-" Condition "\n"
)
<=> (E2 : G2 ?- Condition).
}
% typing match %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
type mk-rty list term -> term -> term -> term -> prop.
mk-rty ARGS HD (prod N S T) (fun N S F) :- !,
pi x\ mk-rty [x|ARGS] HD (T x) (F x).
mk-rty ARGS HD _ (fun _ IndApp _FRESH) :-
coq.mk-app HD {rev ARGS} IndApp.
type mk-bty term -> int -> term -> constructor -> term -> prop.
mk-bty Rty Lno (prod N S T) Ki (prod N S B) :- !,
pi x\ mk-bty Rty Lno (T x) Ki (B x).
mk-bty Rty Lno T Ki AppRtyNorm :-
coq.safe-dest-app T (global (indt _)) Args,
split-at Lno Args LArgs RArgs,
coq.mk-app Rty {append RArgs [{coq.mk-app (global (indc Ki)) {append LArgs RArgs}}]} AppRty,
hd-beta-zeta-reduce AppRty AppRtyNorm.
mk-bty Rty Lno T Ki AppRtyNorm :-
coq.safe-dest-app T (pglobal (indt _) I) Args,
split-at Lno Args LArgs RArgs,
coq.mk-app Rty {append RArgs [{coq.mk-app (pglobal (indc Ki) I) {append LArgs RArgs}}]} AppRty,
hd-beta-zeta-reduce AppRty AppRtyNorm.
% PTS sorts %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
pred pts i:sort, i:sort, o:sort.
pts X Y U :- coq.sort.pts-triple X Y U.
coq-elpi-1.19.3/etc/ 0000775 0000000 0000000 00000000000 14511776522 0014103 5 ustar 00root root 0000000 0000000 coq-elpi-1.19.3/etc/alectryon_elpi.py 0000775 0000000 0000000 00000027421 14511776522 0017477 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
import sys
from os.path import join, dirname
# This is a custom driver: it exposes the same interface as
# Alectryon's usual CLI, but:
# - it sets the internal parameter pp_margin of SerAPI to a different value
# - it installs a new ghref RST role
# - it install a new pygments lexer for Elpi
# - it patches Coq's pygments lexer to handle quotations to Elpi
root = join(dirname(__file__), "..")
sys.path.insert(0, root)
# SERAPI ######################################################################
from alectryon.cli import main
from alectryon.serapi import SerAPI
SerAPI.DEFAULT_PP_ARGS['pp_margin'] = 55
# PYGMENTS ELPI ###############################################################
from pygments.lexer import RegexLexer, default, words, bygroups, include, inherit
from pygments.regexopt import regex_opt, regex_opt_inner
from pygments.token import \
Text, Comment, Operator, Keyword, Name, String, Number
class ElpiLexer(RegexLexer):
"""
For the `Elpi `_ programming language.
.. versionadded:: 1.0
"""
name = 'Elpi'
aliases = ['elpi']
filenames = ['*.elpi']
mimetypes = ['text/x-elpi']
lcase_re = r"[a-z]"
ucase_re = r"[A-Z]"
digit_re = r"[0-9]"
schar2_re = r"(\+|\*|/|\^|<|>|`|'|\?|@|#|~|=|&|!)"
schar_re = r"({}|-|\$|_)".format(schar2_re)
idchar_re = r"({}|{}|{}|{})".format(lcase_re,ucase_re,digit_re,schar_re)
idcharstarns_re = r"({}+|(?=\.[a-z])\.{}+)".format(idchar_re,idchar_re)
symbchar_re = r"({}|{}|{}|{}|:)".format(lcase_re, ucase_re, digit_re, schar_re)
constant_re = r"({}{}*|{}{}*|{}{}*|_{}+)".format(ucase_re, idchar_re, lcase_re, idcharstarns_re,schar2_re, symbchar_re,idchar_re)
symbol_re=r"(,|<=>|->|:-|;|\?-|->|&|=>|as|<|=<|=|==|>=|>|i<|i=<|i>=|i>|is|r<|r=<|r>=|r>|s<|s=<|s>=|s>|@|::|`->|`:|`:=|\^|-|\+|i-|i\+|r-|r\+|/|\*|div|i\*|mod|r\*|~|i~|r~)"
escape_re=r"\(({}|{})\)".format(constant_re,symbol_re)
const_sym_re = r"({}|{}|{})".format(constant_re,symbol_re,escape_re)
tokens = {
'root': [ include('elpi') ],
'elpi': [
include('_elpi-comment'),
(r"(:before|:after|:if|:name)(\s*)(\")",bygroups(Keyword.ElpiMode,Text,String.Double),'elpi-string'),
(r"(:index)(\s*\()",bygroups(Keyword.ElpiMode,Text),'elpi-indexing-expr'),
(r"\b(external pred|pred)(\s+)({})".format(const_sym_re),bygroups(Keyword.ElpiKeyword,Text,Name.ElpiFunction),'elpi-pred-item'),
(r"\b(external type|type)(\s+)(({}(,\s*)?)+)".format(const_sym_re),bygroups(Keyword.ElpiKeyword,Text,Name.ElpiFunction),'elpi-type'),
(r"\b(kind)(\s+)(({}|,)+)".format(const_sym_re),bygroups(Keyword.ElpiKeyword,Text,Name.ElpiFunction),'elpi-type'),
(r"\b(typeabbrev)(\s+)({})".format(const_sym_re),bygroups(Keyword.ElpiKeyword,Text,Name.ElpiFunction),'elpi-type'),
(r"\b(accumulate)(\s+)(\")",bygroups(Keyword.ElpiKeyword,Text,String.Double),'elpi-string'),
(r"\b(accumulate|shorten|namespace|local)(\s+)({})".format(constant_re),bygroups(Keyword.ElpiKeyword,Text,Text)),
(r"\b(pi|sigma)(\s+)([a-zA-Z][A-Za-z0-9_ ]*)(\\)",bygroups(Keyword.ElpiKeyword,Text,Name.ElpiVariable,Text)),
(r"\brule\b",Keyword.ElpiKeyword),
(r"\b(constraint)(\s+)(({}(\s+)?)+)".format(const_sym_re),bygroups(Keyword.ElpiKeyword,Text,Name.ElpiFunction)),
(r"(?=[A-Z_]){}".format(constant_re),Name.ElpiVariable),
(r"(?=[a-z_]){}\\".format(constant_re),Name.ElpiVariable),
(r"_",Name.ElpiVariable),
(r"({}|!|=>|;)".format(symbol_re),Keyword.ElpiKeyword),
(constant_re,Text),
(r"\[|\]|\||=>",Keyword.ElpiKeyword),
(r'"', String.Double, 'elpi-string'),
(r'`', String.Double, 'elpi-btick'),
(r'\'', String.Double, 'elpi-tick'),
(r'\{[^\{]', Text, 'elpi-spill'),
(r"\(",Text,'elpi-in-parens'),
(r'\d[\d_]*', Number.ElpiInteger),
(r'-?\d[\d_]*(.[\d_]*)?([eE][+\-]?\d[\d_]*)', Number.ElpiFloat),
(r"[+\*-/\^]", Operator),
],
'_elpi-comment': [
(r'%[^\n]*\n',Comment),
(r'/\*',Comment,'elpi-multiline-comment'),
(r"\s+",Text),
],
'elpi-multiline-comment': [
(r'\*/',Comment,'#pop'),
(r'.',Comment)
],
'elpi-indexing-expr':[
(r'[0-9 _]+',Number.ElpiInteger),
(r'\)',Text,'#pop'),
],
'elpi-type': [
(r"(ctype\s+)(\")",bygroups(Keyword.Type,String.Double),'elpi-string'),
(r'->',Keyword.Type),
(constant_re,Keyword.Type),
(r"\(|\)",Keyword.Type),
(r"\.",Text,'#pop'),
include('_elpi-comment'),
],
'elpi-pred-item': [
(r"[io]:",Keyword.ElpiMode,'elpi-ctype'),
(r"\.",Text,'#pop'),
include('_elpi-comment'),
],
'elpi-ctype': [
(r"(ctype\s+)(\")",bygroups(Keyword.Type,String.Double),'elpi-string'),
(constant_re,Keyword.Type),
(r"\(|\)",Keyword.Type),
(r",",Text,'#pop'),
(r"\.",Text,'#pop:2'),
include('_elpi-comment'),
],
'elpi-btick': [
(r'[^` ]+', String.Double),
(r'`', String.Double, '#pop'),
],
'elpi-tick': [
(r'[^\' ]+', String.Double),
(r'\'', String.Double, '#pop'),
],
'elpi-string': [
(r'[^\"]+', String.Double),
(r'"', String.Double, '#pop'),
],
'elpi-spill': [
(r'\{[^\{]', Text, '#push'),
(r'\}[^\}]', Text, '#pop'),
include('elpi'),
],
'elpi-in-parens': [
(r"\(", Operator, '#push'),
(r"\)", Operator, '#pop'),
include('elpi'),
],
}
from pygments.lexers._mapping import LEXERS
LEXERS['ElpiLexer'] = ('alectryon_elpi','Elpi',('elpi',),('*.elpi',),('text/x-elpi',))
# PYGMENTS COQ-ELPI ###########################################################
from alectryon.pygments_lexer import CoqLexer
class CoqElpiLexer(CoqLexer, ElpiLexer):
tokens = {
'root': [
# No clue what inherit would do here, so we copy Coq's ones
include('_basic'),
include('_vernac'),
include('_keywords'),
include('_other'),
],
'_quotations': [
(r"lp:\{\{",String.Interpol, 'elpi'),
(r"(lp:)([A-Za-z_0-9']+)",bygroups(String.Interpol, Name.ElpiVariable)),
(r"(lp:)(\()([A-Z][A-Za-z_0-9']*)([a-z0-9 ]+)(\))",bygroups(String.Interpol,String.Interpol,Name.ElpiVariable,Text,String.Interpol)),
],
'antiquotation': [
(r"\}\}",String.Interpol,'#pop'),
include('root')
],
'elpi': [
(r"\}\}",String.Interpol,'#pop'),
(r"\b(global|sort|app|fun|let|prod|match|fix)\b", Keyword.ElpiKeyword),
(r"\{\{(:[a-z]+)?",String.Interpol,'antiquotation'), # back to Coq
inherit
],
'_other': [
include('_quotations'),
inherit
],
}
import alectryon.pygments_lexer
alectryon.pygments_lexer.CoqLexer = CoqElpiLexer
# DOCUTILS ####################################################################
import docutils
from docutils.parsers.rst import directives, roles # type: ignore
from docutils import nodes
def set_line(node, lineno, sm):
node.source, node.line = sm.get_source_and_line(lineno)
import re
import time
import pickle
import atexit
ghref_cache = {}
def dump_ghref_cache():
when = int(time.time() / 1000)
file = '/tmp/ghref_cache_{}'.format(str(when))
pickle.dump(ghref_cache,open(file,'wb'))
atexit.register(dump_ghref_cache)
try:
when = int(time.time() / 1000)
file = '/tmp/ghref_cache_{}'.format(str(when))
ghref_cache = pickle.load(open(file,'rb'))
#print('loaded cache', when, file)
except:
#print('failed to loaded cache', file)
ghref_cache = {}
ghref_scrape_re = re.compile("\"sha\"[: ]*\"([a-zA-Z0-9]+)\"",re.IGNORECASE)
def ghref_role(role, rawtext, text, lineno, inliner, options={}, content=[]):
src = options.get('src',None)
if src is None:
msg = inliner.reporter.error("{}: no src option".format(role), line=lineno)
return [inliner.problematic(rawtext, rawtext, msg)], [msg]
components = str.split(src,sep=" ")
if len(components) != 4:
msg = inliner.reporter.error("{}: src should be 4 space separated strings".format(role), line=lineno)
return [inliner.problematic(rawtext, rawtext, msg)], [msg]
org, repo, branch, path = components
uri = "https://github.com/{}/{}/blob/{}/{}".format(org,repo,branch,path)
roles.set_classes(options)
options.setdefault("classes", []).append("ghref")
if uri in ghref_cache:
code, rawuri, uri = ghref_cache[uri]
else:
from urllib import request
apiuri = "https://api.github.com/repos/{}/{}/commits/{}/branches-where-head".format(org,repo,branch)
try:
with request.urlopen(apiuri) as f:
json = f.read().decode('utf-8')
except:
msg = inliner.reporter.error("{}: could not download: {}".format(role,apiuri), line=lineno)
return [inliner.problematic(rawtext, rawtext, msg)], [msg]
try:
# A json parser would be nicer
sha = ghref_scrape_re.search(json).group(1)
except:
msg = inliner.reporter.error("{}: could not scrape for permalink: {}".format(role,uri), line=lineno)
return [inliner.problematic(rawtext, rawtext, msg)], [msg]
puri = "https://github.com/{}/{}/blob/{}/{}".format(org,repo,sha,path)
rawuri = "https://raw.githubusercontent.com/{}/{}/{}/{}".format(org,repo,sha,path)
try:
with request.urlopen(rawuri) as f:
code = f.read().decode('utf-8')
except:
msg = inliner.reporter.error("{}: could not download: {}".format(role,rawuri), line=lineno)
return [inliner.problematic(rawtext, rawtext, msg)], [msg]
ghref_cache[uri]=(code,rawuri,puri)
uri=puri
mangler = options.get('replace',None)
mangler_with = options.get('replace_with','')
if mangler is None:
name = text
else:
name = re.sub(mangler,mangler_with,text)
pattern = options.get('pattern','')
from string import Template
pattern = Template(pattern).safe_substitute(name = re.escape(name))
pattern = re.compile(pattern)
for num, line in enumerate(code.splitlines(), 1):
if pattern.search(line):
uri = uri + '#L' + str(num)
break
else:
msg = inliner.reporter.error("{}: {} not found in {} using pattern {}".format(role,text,rawuri,pattern), line=lineno)
return [inliner.problematic(rawtext, rawtext, msg)], [msg]
node = nodes.reference(rawtext, text, refuri=uri, **options)
set_line(node, lineno, inliner.reporter)
return [node], []
ghref_role.name = "ghref"
ghref_role.options = {
# the GH source, 4 fields separated by space: org repo branch path. Eg
# :src: cpitclaudel alectryon master alectryon/docutils.py
"src": directives.unchanged,
# the regex to find the location in the raw file at path. I must use $name
# this is replaced by the text in :ghref:`text`. Eg
# :pattern: ^def $name
"pattern": directives.unchanged,
# optionally mangle the name before substituting it in the regexp using
# re.sub. Eg
# :replace: this
# :replace_with: that
"replace": directives.unchanged,
"replace_with": directives.unchanged
}
roles.register_canonical_role("ghref", ghref_role)
###############################################################################
__all__ = [ "ElpiLexer", "CoqElpiLexer"]
if __name__ == "__main__":
main()
coq-elpi-1.19.3/etc/coq-elpi.lang 0000664 0000000 0000000 00000027350 14511776522 0016466 0 ustar 00root root 0000000 0000000
*.v
\(\*
\*\)
\s
[_\p{L}]
[_\p{L}'\pN]
\%{first_ident_char}\%{ident_char}*
(\%{ident}*\.)*\%{ident}
[-+*{}]
\.(\s|\z)
(Definition)|(Let)|(Example)|(SubClass)|(Fixpoint)|(CoFixpoint)|(Scheme)|(Function)|(Hypothesis)|(Axiom)|(Variable)|(Parameter)|(Conjecture)|(Inductive)|(CoInductive)|(Record)|(Structure)|(Ltac)|(Instance)|(Context)|(Class)|(Module(\%{space}+Type)?)|(Existing\%{space}+Instance)|(Canonical\%{space}+Structure)|(Canonical)|(Coercion)
(Hypotheses)|(Axioms)|(Variables)|(Parameters)|(Implicit\%{space}+Type(s)?)
(((Local)|(Global))\%{space}+)?
(Theorem)|(Lemma)|(Fact)|(Remark)|(Corollary)|(Proposition)|(Property)
(Qed)|(Defined)|(Admitted)|(Abort)
((?'gal'\%{locality}(Program\%{space}+)?(\%{single_decl}|\%{begin_proof}))\%{space}+(?'id'\%{ident}))|((?'gal4list'\%{mult_decl})(?'id_list'(\%{space}+\%{ident})*))
[A-Z_][A-Za-z-+_0-9?]*
[a-z][A-Za-z-+_>0-9?\.]*
(:-|\\|,|=>|\]|\[)
""
"
"
do
last
first
apply
auto
case
case
congr
elim
exists
have
gen have
generally have
move
pose
rewrite
set
split
suffices
suff
transitivity
without loss
wlog
by
exact
reflexivity
\(\*\*(\s|\z)
\*\)
\%{decl_head}
\%{dot_sep}
forall
fun
match
fix
cofix
with
for
end
as
let
in
if
then
else
return
using
Prop
Set
Type
\.\.
Proof
\%{end_proof}\%{dot_sep}
\%{dot_sep}
\%{undotted_sep}
(Elpi\%{space}+Accumulate\%{space}+lp:{{|Elpi\%{space}+Db\%{space}+\%{qualit}\%{space}+lp:{{|Elpi\%{space}+Query\%{space}+lp:{{|Elpi\%{space}+Query\%{space}+\%{qualit}\%{space}+lp:{{|Elpi\%{space}+Command\%{space}+\%{qualit}\%{space}+lp:{{|Elpi\%{space}+Tactic\%{space}+\%{qualit}\%{space}+lp:{{|Elpi\%{space}+Program\%{space}+\%{qualit}\%{space}+lp:{{)
}}\%{dot_sep}
fun
prod
sort
let
match
fix
indc
indt
const
prop
app
global
type
kind
pi
sigma
rule
constraint
namespace
\%{lp-var}
\%{lp-name}
""
""
\%{lp-symb}
Add
Check
Eval
Load
Undo
Restart
Goal
Print
Save
Comments
Solve\%{space}+Obligation
((Uns)|(S))et(\%{space}+\%{ident})+
(\%{locality}|((Reserved)|(Tactic))\%{space}+)?Notation
\%{locality}Infix
(Print)|(Reset)\%{space}+Extraction\%{space}+(Inline)|(Blacklist)
(Elpi\%{space}+Trace)|(Elpi\%{space}+Accumulate\%{space}+File)|(Elpi\%{space}+Accumulate\%{space}+Db)|(Elpi\%{space}+Accumulate)|(Elpi\%{space}+Query)|(Elpi\%{space}+Bound\%{space}+Steps)|(Elpi\%{space}+Program)|(Elpi\%{space}+\%{qualit})
\%{locality}Hint\%{space}+
Resolve
Immediate
Constructors
unfold
Opaque
Transparent
Extern
\%{space}+Scope
\%{locality}Open
\%{locality}Close
Bind
Delimit
\%{space}+(?'qua'\%{qualit})
Chapter
Combined\%{space}+Scheme
End
Section
Arguments
Implicit\%{space}+Arguments
(Import)|(Include)
Require(\%{space}+((Import)|(Export)))?
(Recursive\%{space}+)?Extraction(\%{space}+(Language\%{space}+(Ocaml)|(Haskell)|(Scheme)|(Toplevel))|(Library)|((No)?Inline)|(Blacklist))?
Extract\%{space}+(Inlined\%{space}+)?(Constant)|(Inductive)
(?'qua_list'(\%{space}+\%{qualit})+)
Typeclasses (Transparent)|(Opaque)
coq-elpi-1.19.3/etc/logo.png 0000664 0000000 0000000 00000114521 14511776522 0015555 0 ustar 00root root 0000000 0000000 ‰PNG
IHDR 0 Ø l›¿¨ bKGD ÿ ÿ ÿ ½§“ pHYs šœ tIMEä /,54 IDATxÚìw|eöÿßÏÌÜÜôBI¡HèBè`Á,®¬Š
êêêªk[×ÕݵüÔu]¿º®ÔUlTAª„Ðk-@0 éå–™9¿?n¸!¸”y¿^7¯Ü¹SŸ™û¹ç9Ï9çQ""8888œhN8888æàààà˜ƒƒƒƒ#`Ž€98888æàààà˜ƒƒƒƒ#`Ž€98888æàààà˜ƒƒƒ#`Ž€98884<†Ó§Ë²°mÛ¶±,ŸÏ‡išÁ嚦¡i.—‹t].Ó4
¥”ÓˆŽ€94,"BUUÙÙÙìÞ½›ììlrrr8pà ùùùRZZJee%ÕÕÕx<ü~?ǫނÛí&44”°°0ÂÃÉŒŒ¾¢¢¢ˆŠŠ"::š˜˜bcciÔ¨Mš4!!!ÄÄDbcc qÄï@9õÀêBii)«V"==µkײyóföîÝ‹Ïçü$&&’@ãÆ‰‹‹#**ŠÈÈHÂÂÂ
Åívc†a ”BD°,¿ßÏçÃãñPUU|UTTPYYIyy9”——_^¯¿ßišµÎ522’ÄÄDZ·nMÛ¶miÛ¶-)))¤¤¤Ð¦M¢¢¢Ð4Ç{â˜ÃY‹mÛlÚ´‰3f0gÎÖ¬Yƒ×ë%44”ÔÔTºuëFçÎéСíÚµ£E‹ÄÅÅ¡ëú/f»²²2
9xð yyyäææ²oß>öìÙÞ={(((Àãñ…611‘ÔÔTÚ·oOûöíIMM%%%…-ZéXnŽ€9œ©ÝÂmÛ¶1eʦM›FVV.—‹>}ú0dÈ.¾øbÒÒÒˆ‰‰9£®«¬¬ŒÜÜ\vìØÁŽ;ÈÊÊ"++‹;vPPP€ßïÀívO›6mh×®©©©tìØ‘®]»ÒºukBBBœ‡Ä0‡Óòòr¦NʤI“ÈÈÈ $$„K/½”k¯½–aÆÖZ™ÅÅÅdgg³sçNvïÞ]ë•——‡×ë ..Ž®]»Ò§OŸà+99ù³8sø 999¼üòËLž<™’’zõêÅøñã=zôY+Z'bVTT°{÷n6mÚÄúõëY³f
6l ¸¸¥ ôîÝ›pÁгgO¢¢¢œË0‡SÉÁƒyæ™g˜4i"˜1c¸ûî»éÝ»·ãÿ9>Ÿ;v°jÕ*V®\Izz:Û¶mÃçóN=¸ä’KÊ+¯¼B›6mxíµ×:t¨Ó0¿"BVV_~ù%Ó¦McõêÕ†ÁàÁƒ¹é¦›9r$áááNC9æðSvíÚŵ×^˦M›¸÷Þ{yúé§/Ëÿ˜;v0eÊ>øàvîÜIll,cƌᦛnâüóÏw|Ž€9 |÷Ýw\}õÕèºÎ‡~ÈàÁƒë¼íÚÍétïÔÛ 8Å–ÙòåËyï½÷øôÓO)))¡mÛ¶Œ7ŽqãÆ‘ššê4Rpò)ÎB/^ÌW\Abb"ééé'$^EE‡X'ïS„êKNN–e97ãh–ƒR\pÁLœ8‘ýû÷óÑGѱcGž{î9:tèÀ Aƒøàƒ‚ŽvN°iÓ&.ºè"’““™?>M›6=¡íç/ÿŠïÍŒ»èÑ:^£Fk-ûì³Ï¸öÚkIJJ"--^½zqá…rþùçéܤcpðàA¦L™Âäɓٺu+ Ü~ûíÜ~ûíÎ(æQLY‡³„¢¢"i×®´iÓF8P¯}¼·ì)Y´rvÖªª”Iï–ÒÒÒZËyäŽx…‡‡Ë°aÃäí·ß–¼¼<ç†Ë²dñâÅ2jÔ( ·Û-£G–9sæˆ×ëu¨§œÎYă>Hnn.Ë–-«×0}yy9¾¨|÷Ñ=e@Ö_½u)î„…ÕŽ+›;w."Âe—]vÌ0Œˆˆ®¼òJÞxã
vïÞÍÿû_FMÿþý®—ÀþðþùÏ:7»†˜˜n¾ùf–/_ÎܹsiÔ¨ãÆ£o߾̙3縕o.¤ÃiÓO>).—«ÞŽ{‘ÕVÈ;éÔyýw—<)–éì2dˆ òé§Ÿ6ØõmܸQ iß¾½s³‚iš2mÚ4éܹ³(¥ä²Ë.“Õ«W;˜ÃéϧŸ~Ê%—\rRùuY…ÄTv¨ÓºÕÕU˜MÒ«ËùG,_¾œÐÐP.½ôÒ»¾Ù³gœP<Û¹†®ëŒ5ŠuëÖñæ›o²uëVú÷ïÏwÜmÛgï`‡sëÏüîã–-[¸úê«ë½Û¶ñ4ÚC×Öuë>®Ù¼° 1ѵ+³¦§§SYYIÏž=iÔ¨Qƒ]ã¬Y³ ¸êª«œ~BBB¸ýöÛÙ¶m<òÛ¶m;" ¸ª²’}YÛÙ¾fÙ[7ã«)Úx&â„Qœá,X° áŠ+®¨¿õµ+¿QANþtM£U‹6ÆÑìʵ$¹º±|áÂ…
j}±råJÂÃùä’K´íòòòHHH8+⣣ùÿïÿßWVT°uÚiõÝÄgo¡•ùC¦…/ªk/Ÿ@—ÛîÇív;æð˱lÙ2Z¶lI›6mê½-¹+0´re3ÙE‹°+«ÐÊâpW%Ð4´:Ð.¹=†aPí©ÆÛ4›>I~›;w.~¿Ÿ!C†Ô{€âçøæ›o¸âŠ+9r$ãÇçÒK/mÐýŸNl\4Ÿv¯>@Ÿ¢ƒJƒÐ°MBÊ‹è9íÿÈ]ó
îgþKÓ¤fŽ€9ü2¬[·ŽÞ½{ŸÔ>Ê"²è9†î{_Ö®½™äúv’ïÛInñw,óV¡J$TbÑ´¦4îÒ¤Ö>òóóY·nÑÑÑôëׯÁ»Ã‡oÐv›5k–eñÙgŸñÙgŸÍ„ xä‘GHLLØ`%{ü~?sçÎE)Űaôí6lØ ÀM7ÝÄÀ©¨¨àå—_¦}ûö¼ôÒKgE"zQam_þC@¼b[AR7o¾*Ø¿žÌvYùë;ø¾I¸ÂÁEtÞnvN|þŒ¹FGÀÎ`*++ñz½4nܸþ_ä+på·8¦Ï 66Ž€aÒ·ëÅG|þå—_0bĈíÑ[·-{íóùX¿~=†aðâ‹/²dɶlÙÂØ±c©¬¬ä`È!r_{šð²CÑŠk]sñUØE;Øøà«tüÇ;ô'9}¯XdMÚŠ.+¾