]
% (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 _)).
}
% 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 :- !,
if (var S) (declare_constraint (evar X T S) [X, S])
true. % If S is assigned we consider its a well type term
: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 @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 @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
% 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 tt].
% Attributes for a record field. Can be left unspecified, see defaults
% below.
kind field-attribute type.
type coercion bool -> field-attribute. % default false
type canonical bool -> field-attribute. % default true, if field is named
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 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.say ...] Prints an info 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.
external pred coq.env.typeof i:gref, o:term.
external pred coq.env.indt % reads the inductive type declaration for the environment
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
i:inductive, % reference to the inductive type
o:indt-decl. % HOAS description of the inductive type
% [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)
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.const GR Bo Ty] reads the type Ty and the body Bo of constant GR.
% Opaque constants have Bo = none.
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
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)
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.
% [coq.env.module MP Contents] lists the contents of a module (recurses on
% submodules) *E*
external pred coq.env.module i:modpath, o:list gref.
% [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.current-path Path] lists the current module path
external pred coq.env.current-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: 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)
% [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)
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)
% - @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:
% - @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 ]
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)).
% -- Universes --------------------------------------------------------
% Univ.Universe.t
typeabbrev univ (ctype "univ").
% Universes (for the sort term former)
kind universe type.
type prop universe. % impredicative sort of propositions
type sprop universe. % impredicative sort of propositions with definitional proof irrelevance
type typ univ -> universe. % predicative sort of data (carries a level)
% [coq.univ.print] prints the set of universe constraints
external pred coq.univ.print .
% [coq.univ.leq U1 U2] constrains U1 <= U2
external pred coq.univ.leq i:univ, i:univ.
% [coq.univ.eq U1 U2] constrains U1 = U2
external pred coq.univ.eq i:univ, i:univ.
% [coq.univ.new Names U] fresh universe *E*
external pred coq.univ.new i:list id, o:univ.
% [coq.univ.sup U1 U2] constrains U2 = U1 + 1
external pred coq.univ.sup i:univ, i:univ.
% [coq.univ.max U1 U2 U3] constrains U3 = max U1 U2
external pred coq.univ.max i:univ, i:univ, o:univ.
% Very low level, don't use
% [coq.univ.algebraic-max U1 U2 U3] constrains U3 = Max(U1,U2) *E*
external pred coq.univ.algebraic-max i:univ, i:univ, o:univ.
% [coq.univ.algebraic-sup U1 U2] constrains U2 = Sup(U1) *E*
external pred coq.univ.algebraic-sup i:univ, o:univ.
% -- 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.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.
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 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 universe -> 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 Db] reads all instances
external pred coq.TC.db o:list tc-instance.
% [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)
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 (option 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 (option 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.
% -- 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:universe, 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.
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.
external pred coq.elaborate-ty-skeleton i:term, o:universe, o:term,
o:diagnostic.
% -- Coq's reduction machines ------------------------------------
% [coq.reduction.lazy.whd_all T Tred] Puts T in weak head normal form
external pred coq.reduction.lazy.whd_all i:term, o:term.
% [coq.reduction.lazy.norm T Tred] Puts T in normal form
external pred coq.reduction.lazy.norm i:term, o:term.
% [coq.reduction.cbv.norm T Tred] Puts T in weak head normal form
external pred coq.reduction.cbv.norm i:term, o:term.
% [coq.reduction.vm.norm T Ty Tred] Puts T in normal form. 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. 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.
% -- 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 --------------------------------------------
% [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 named Tac on goal G
% (passing the arguments of G, see coq.ltac.call for a handy wrapper)
external pred coq.ltac.call-ltac1 i:string, 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.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)
% [coq.elpi.accumulate Scope DbName Clause]
% Declare that, once the program is over, the given clause 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)
external pred coq.elpi.accumulate i:scope, i:id, i:clause.
% -- 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).
% 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.13.0/coq-elpi.opam 0000664 0000000 0000000 00000002700 14200463340 0015667 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"
"ocaml" {>= "4.07"}
"elpi" {>= "1.14.0" & < "1.15.0~"}
"coq" {>= "8.15" & < "8.16~" }
]
tags: [ "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.13.0/default.nix 0000664 0000000 0000000 00000000661 14200463340 0015450 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.13.0/elpi-builtin.elpi 0000664 0000000 0000000 00000111113 14200463340 0016547 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 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 constant occurs in the term
i:any, % a constant (global or 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.
% -- 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.
coq-elpi-1.13.0/elpi/ 0000775 0000000 0000000 00000000000 14200463340 0014232 5 ustar 00root root 0000000 0000000 coq-elpi-1.13.0/elpi/README.md 0000664 0000000 0000000 00000001537 14200463340 0015517 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.13.0/elpi/coq-HOAS.elpi 0000664 0000000 0000000 00000044574 14200463340 0016435 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 commands. [Definition], [Axiom], [Record] and [Context]
% take precedence over the [str] argument above (when not "quoted").
%
% Eg. Record m A : T := K { f : t; .. }.
type indt-decl indt-decl -> argument.
% Eg. Definition m A : T := B. (or Axiom when the body is none)
type const-decl id -> option term -> arity -> 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 universe -> term. % Prop, Type@{i}
% constants: inductive types, inductive constructors, definitions
type global gref -> 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
%type proj @gref -> term -> term. % applied primitive projection
% 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 _)).
}
% 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 :- !,
if (var S) (declare_constraint (evar X T S) [X, S])
true. % If S is assigned we consider its a well type term
: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 @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 @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
% 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 tt].
coq-elpi-1.13.0/elpi/coq-elaborator.elpi 0000664 0000000 0000000 00000001133 14200463340 0020015 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"
:before "default-assign-evar"
evar X Ty R :- !, of X Ty 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.
coq-elpi-1.13.0/elpi/coq-elpi-checker.elpi 0000664 0000000 0000000 00000001613 14200463340 0020221 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.13.0/elpi/coq-lib.elpi 0000664 0000000 0000000 00000067317 14200463340 0016451 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 (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 (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.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),
(copy (global (indt GR)) 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.
% 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-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 :- coq.arity->term Arity A, do-ok! Diag [
coq.typecheck-ty A _,
coq.typecheck-indt-decl.heuristic-var-type A,
d\ @pi-parameter ID A i\ forall-ok (KDecl i) (coq.typecheck-indt-decl-c i A) 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 (constructor "fields" (arity (K i)))
]
].
pred coq.typecheck-indt-decl-c i:term, i:term, i:indc-decl, o:diagnostic.
coq.typecheck-indt-decl-c I S (constructor _ID Arity) Diag :- coq.arity->term Arity T, do-ok! Diag [
coq.typecheck-ty T KS,
coq.typecheck-indt-decl-c.unify-arrow-tgt I S T,
lift-ok (coq.arity->sort S IS) "",
lift-ok (if (IS = typ U1, KS = typ U2) (coq.univ.leq U2 U1) true) "constructor universe too large"
].
pred coq.typecheck-indt-decl-c.unify-arrow-tgt i:term, i:term, i:term, o:diagnostic.
coq.typecheck-indt-decl-c.unify-arrow-tgt I A (prod N S T) D :-
@pi-decl N S x\ coq.typecheck-indt-decl-c.unify-arrow-tgt I A (T x) D.
coq.typecheck-indt-decl-c.unify-arrow-tgt I A (let N S B T) D :-
@pi-def N S B x\ coq.typecheck-indt-decl-c.unify-arrow-tgt I A (T x) D.
coq.typecheck-indt-decl-c.unify-arrow-tgt I A Concl D :-
coq.count-prods A N,
coq.mk-n-holes N 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,
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 A1) (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:universe, 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 (if (U = typ U1, UA = typ U2) (coq.univ.leq U2 U1) true) "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:term, i:indc-decl, o:indc-decl, o:diagnostic.
coq.elaborate-indt-decl-skeleton-c I S (constructor ID Arity) (constructor ID Arity1) Diag :- do-ok! Diag [
coq.elaborate-arity-skeleton Arity KS Arity1,
coq.typecheck-indt-decl-c.unify-arity-tgt I S Arity1,
lift-ok (coq.arity->sort S IS) "",
lift-ok (if (IS = typ U1, KS = typ U2) (coq.univ.leq U2 U1) true) "constructor universe too large"
].
pred coq.typecheck-indt-decl-c.unify-arity-tgt i:term, i:term, i:arity, o:diagnostic.
coq.typecheck-indt-decl-c.unify-arity-tgt I A (parameter ID _ T C) D :-
@pi-parameter ID T p\ coq.typecheck-indt-decl-c.unify-arity-tgt I A (C p) D.
coq.typecheck-indt-decl-c.unify-arity-tgt I A (arity C) D :-
coq.typecheck-indt-decl-c.unify-arrow-tgt I A C D.
% Lifts coq.elaborate-skeleton to arity
pred coq.elaborate-arity-skeleton i:arity, o:universe, o:arity, o:diagnostic.
coq.elaborate-arity-skeleton (parameter ID Imp T A) U (parameter ID Imp T1 A1) Diag :- do-ok! Diag [
coq.elaborate-ty-skeleton T _ T1, % parameters don't count
d\ @pi-parameter ID T1 i\ coq.elaborate-arity-skeleton (A i) U (A1 i) d
].
coq.elaborate-arity-skeleton (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:universe.
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 (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.
% 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 [] (global (indt GR)) Args,
coq.env.indt GR _ Lno _ Arity Kn Kt,
take Lno Args LArgs,
coq.mk-app (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\ coq.mk-app (global (indc k)) LArgs) 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"
type get-option string -> A -> prop.
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.13.0/elpi/elpi-command-template.elpi 0000664 0000000 0000000 00000000642 14200463340 0021265 0 ustar 00root root 0000000 0000000 /* Loaded when Elpi Tactic 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.13.0/elpi/elpi-elaborator.elpi 0000664 0000000 0000000 00000035160 14200463340 0020173 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.
type get-option string -> A -> prop.
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 (typ S1)) [] (sort (typ S2)) [] M eq :- !, swap M coq.univ.eq S1 S2.
unif (sort (typ S1)) [] (sort (typ S2)) [] M leq :- !, swap M coq.univ.leq S1 S2.
unif (sort (typ _)) [] (sort prop) [] ff _ :- !, fail.
unif (sort prop) [] (sort (typ _)) [] ff eq :- !, fail.
unif (sort prop) [] (sort (typ _)) [] ff leq :- !.
unif (sort prop) [] (sort prop) [] ff eq :- !.
unif (sort X) [] (sort X) [] ff _ :- !.
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.
% 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
% 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 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 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 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 (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 prop) (sort (typ U)) (sort prop) :-
if (var U) (coq.univ.new [] U) true.
of (sort (typ T) as X) (sort S) X :- % XXX TODO: unif
coq.univ.sup T T+1,
if (var S) (S = typ T+1)
(if (S = prop) false
(S = typ U, coq.univ.leq T+1 U)).
of (sort V) T X :- var V, coq.univ.new [] U, V = typ U, of (sort V) T X.
of (global GR as X) T X :- 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.
% PTS sorts %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
pred pts i:universe, i:universe, o:universe.
pts prop prop prop.
pts (typ U) prop prop :- if (var U) (coq.univ.new [] U) true.
pts (typ T1) (typ T2) (typ M) :- coq.univ.max T1 T2 M.
pts prop (typ T2) (typ T2).
pts (uvar as X) (prop as Y) R :- coq.univ.new [] U, X = typ U, pts X Y R.
pts (prop as X) (uvar as Y) R :- coq.univ.new [] U, Y = typ U, pts X X R.
pts (uvar as X) (typ _ as Y) R :- coq.univ.new [] U, X = typ U, pts X Y R.
pts (typ _ as X) (uvar as Y) R :- coq.univ.new [] U, Y = typ U, pts X Y R.
pts (uvar as X) (uvar as Y) R :- not(var R), R = prop, !,
X = prop, Y = prop.
pts (uvar as X) (uvar as Y) R :- var R, !,
coq.univ.new [] U, X = typ U,
coq.univ.new [] V, Y = typ V,
pts X Y R.
% vim:set ft=lprolog spelllang=:
coq-elpi-1.13.0/elpi/elpi-ltac.elpi 0000664 0000000 0000000 00000011011 14200463340 0016751 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 _ Ev _) GS :-
RawEv = T, coq.ltac.collect-goals Ev GS _.
pred refine.typecheck i:term, i:goal, o:list sealed-goal.
refine.typecheck T (goal _ _ Ty Ev _) GS :-
coq.typecheck T Ty ok,
Ev = T, coq.ltac.collect-goals Ev GS _.
pred refine.no_check i:term, i:goal, o:list sealed-goal.
refine.no_check T (goal _ _ _ Ev _) GS :-
Ev = T, coq.ltac.collect-goals Ev GS _.
% 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 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.13.0/elpi/elpi-reduction.elpi 0000664 0000000 0000000 00000007515 14200463340 0020040 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 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:stack, % args
o:term, % body
o:stack. % args after hd-beta
unfold GR A BO BOC :- 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.13.0/elpi/elpi-tactic-template.elpi 0000664 0000000 0000000 00000001103 14200463340 0021107 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.13.0/etc/ 0000775 0000000 0000000 00000000000 14200463340 0014054 5 ustar 00root root 0000000 0000000 coq-elpi-1.13.0/etc/alectryon_elpi.py 0000775 0000000 0000000 00000027255 14200463340 0017455 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("Permalink",re.IGNORECASE)
ghref_scrape_href_re = re.compile('href=([\'"])(.*?)\\1',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
try:
with request.urlopen(uri) as f:
html = f.read().decode('utf-8')
except:
msg = inliner.reporter.error("{}: could not download: {}".format(role,uri), line=lineno)
return [inliner.problematic(rawtext, rawtext, msg)], [msg]
try:
link = ghref_scrape_re.search(html).group(1)
puri = ghref_scrape_href_re.search(link).group(2)
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" + puri
rawuri = puri.replace('/blob/','/raw/')
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.13.0/etc/coq-elpi.lang 0000664 0000000 0000000 00000027350 14200463340 0016437 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.13.0/etc/logo.png 0000664 0000000 0000000 00000114521 14200463340 0015526 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ÚŠ.+¾