{-# OPTIONS --safe --cubical-compatible --no-sized-types --no-guardedness #-}
module SemanticExplanation.Translate where
open import SemanticExplanation.Base
open import SemanticExplanation.Domain
open import SemanticExplanation.IR
open import SemanticExplanation.Reflection.Reduce
open import SemanticExplanation.Reflection.View
import Agda.Builtin.Reflection as R
infixl 1 _>>=_
_>>=_ : ∀ {a b} {A : Set a} {B : Set b} → R.TC A → (A → R.TC B) → R.TC B
_>>=_ = R.bindTC
data Phase : Set where
reduction classification interpretation : Phase
data FailureTag : Set where
budgetExhausted : FailureTag
unknownHead : FailureTag
unsupportedTerm : FailureTag
unsupportedExpression : FailureTag
unboundVariable : FailureTag
ambiguousBinderClassification : FailureTag
unsupportedBinderVisibility : FailureTag
unsupportedBinderModality : FailureTag
nondependentEntityBinder : FailureTag
proofDependentPremise : FailureTag
dependentInfrastructureBinder : FailureTag
predicateArityMismatch : FailureTag
expressionArityMismatch : FailureTag
data FailureDetail : Set where
noDetail : FailureDetail
nameDetail : R.Name → FailureDetail
termDetail : R.Term → FailureDetail
visibilityDetail : R.Visibility → FailureDetail
modalityDetail : R.Relevance → R.Quantity → FailureDetail
record TranslationFailure : Set where
constructor translation-failure
field
phase : Phase
tag : FailureTag
path : List Nat
detail : FailureDetail
attemptedRules : List String
data Result {a} (A : Set a) : Set a where
success : A → Result A
failure : TranslationFailure → Result A
record ExprArguments (scope : Nat) : Set where
constructor expr-arguments
field
expressions : List (ExprIR scope)
provenance : List ProvenanceEntry
record ExprTranslation (scope : Nat) : Set where
constructor translated-expr
field
expression : ExprIR scope
provenance : List ProvenanceEntry
Env : Nat → Set
Env scope = List (Maybe (Fin scope))
liftMaybeFin : ∀ {n} → Maybe (Fin n) → Maybe (Fin (suc n))
liftMaybeFin nothing = nothing
liftMaybeFin (just index) = just (fsuc index)
extendEntity : ∀ {n} → Env n → Env (suc n)
extendEntity env = just fzero ∷ map liftMaybeFin env
extendNonsemantic : ∀ {n} → Env n → Env n
extendNonsemantic env = nothing ∷ env
mkFailure : Phase → FailureTag → FailureDetail → TranslationFailure
mkFailure phase tag detail = translation-failure phase tag [] detail []
resultMap : ∀ {a b} {A : Set a} {B : Set b} → (A → B) → Result A → Result B
resultMap f (success value) = success (f value)
resultMap f (failure problem) = failure problem
normalModality : R.Relevance → R.Quantity → Bool
normalModality R.relevant R.quantity-ω = true
normalModality _ _ = false
surfaceArity : ExprSurface → Nat
surfaceArity (constantWord _) = zero
surfaceArity (unaryForm _ _) = suc zero
surfaceArity (binaryForm _ _ _) = suc (suc zero)
mutual
translateExpr : ∀ {scope} → Nat → DomainSpec → Env scope → R.Term → Result (ExprTranslation scope)
translateExpr zero spec env term =
failure (mkFailure interpretation budgetExhausted (termDetail term))
translateExpr (suc fuel) spec env (R.var index []) with lookupNat env index
... | nothing = failure (mkFailure interpretation unboundVariable noDetail)
... | just nothing = failure (mkFailure interpretation unboundVariable noDetail)
... | just (just semanticIndex) =
success (translated-expr (bound semanticIndex) [])
translateExpr (suc fuel) spec env (R.def name args) =
translateExpressionHead fuel spec env name args
translateExpr (suc fuel) spec env (R.con name args) =
translateExpressionHead fuel spec env name args
translateExpr (suc fuel) spec env term =
failure (mkFailure interpretation unsupportedExpression (termDetail term))
translateExpressionHead
: ∀ {scope} → Nat → DomainSpec → Env scope → R.Name
→ List (R.Arg R.Term) → Result (ExprTranslation scope)
translateExpressionHead fuel spec env name args
with findExpression name (DomainSpec.expressions spec)
... | nothing =
failure (mkFailure interpretation unsupportedExpression (nameDetail name))
... | just rule
with translateArguments fuel spec env (ExpressionRule.ruleId rule) zero
(ExpressionRule.roles rule) args
... | failure problem = failure problem
... | success translatedArgs
with length (ExprArguments.expressions translatedArgs) ==N
surfaceArity (ExpressionRule.surface rule)
... | false =
failure (mkFailure interpretation expressionArityMismatch (nameDetail name))
... | true =
success
(translated-expr
(application (ExpressionRule.ruleId rule) (ExpressionRule.surface rule)
(ExprArguments.expressions translatedArgs))
(ruleUsed (ExpressionRule.ruleId rule)
∷ ExprArguments.provenance translatedArgs))
translateArguments
: ∀ {scope}
→ Nat
→ DomainSpec
→ Env scope
→ String
→ Nat
→ List ArgRole
→ List (R.Arg R.Term)
→ Result (ExprArguments scope)
translateArguments zero spec env ruleId position roles args =
failure (mkFailure interpretation budgetExhausted noDetail)
translateArguments (suc fuel) spec env ruleId position [] [] =
success (expr-arguments [] [])
translateArguments (suc fuel) spec env ruleId position [] (_ ∷ _) =
failure (mkFailure interpretation predicateArityMismatch noDetail)
translateArguments (suc fuel) spec env ruleId position (_ ∷ _) [] =
failure (mkFailure interpretation predicateArityMismatch noDetail)
translateArguments (suc fuel) spec env ruleId position
(semanticExpression ∷ roles) (R.arg _ term ∷ args)
with translateExpr fuel spec env term
... | failure problem = failure problem
... | success translatedExpression
with translateArguments fuel spec env ruleId (suc position) roles args
... | failure problem = failure problem
... | success rest =
success
(expr-arguments
(ExprTranslation.expression translatedExpression
∷ ExprArguments.expressions rest)
(ExprTranslation.provenance translatedExpression
++L ExprArguments.provenance rest))
translateArguments (suc fuel) spec env ruleId position
(infrastructureArgument ∷ roles) (_ ∷ args)
with translateArguments fuel spec env ruleId (suc position) roles args
... | failure problem = failure problem
... | success rest =
success
(expr-arguments
(ExprArguments.expressions rest)
(argumentOmitted ruleId position ∷ ExprArguments.provenance rest))
headName : R.Term → Maybe R.Name
headName (R.def name _) = just name
headName (R.con name _) = just name
headName _ = nothing
headArgs : R.Term → List (R.Arg R.Term)
headArgs (R.def _ args) = args
headArgs (R.con _ args) = args
headArgs _ = []
data HeadClass : Set where
entityClass : EntityRule → HeadClass
predicateClass : PredicateRule → HeadClass
infrastructureClass : InfrastructureRule → HeadClass
ambiguousClass unknownClass : HeadClass
classifyHead : DomainSpec → R.Name → HeadClass
classifyHead spec name
with findEntity name (DomainSpec.entities spec)
| findPredicate name (DomainSpec.predicates spec)
| findInfrastructure name (DomainSpec.infrastructure spec)
... | just entityRule | just predicateRule | infrastructureRule = ambiguousClass
... | just entityRule | predicateRule | just infrastructureRule = ambiguousClass
... | entityRule | just predicateRule | just infrastructureRule = ambiguousClass
... | just entityRule | nothing | nothing = entityClass entityRule
... | nothing | just predicateRule | nothing = predicateClass predicateRule
... | nothing | nothing | just infrastructureRule = infrastructureClass infrastructureRule
... | nothing | nothing | nothing = unknownClass
translateAtom
: ∀ {scope}
→ Nat
→ DomainSpec
→ Env scope
→ R.Name
→ List (R.Arg R.Term)
→ Result (Translation scope)
translateAtom fuel spec env name args with findPredicate name (DomainSpec.predicates spec)
... | nothing = failure (mkFailure interpretation unknownHead (nameDetail name))
... | just rule
with translateArguments fuel spec env (PredicateRule.ruleId rule) zero
(PredicateRule.roles rule) args
... | failure problem = failure problem
... | success translatedArgs with PredicateRule.surface rule | ExprArguments.expressions translatedArgs
... | equalityPhrase phrase | left ∷ right ∷ [] =
success
(translated
(equal (PredicateRule.ruleId rule) phrase left right)
(ruleUsed (PredicateRule.ruleId rule)
∷ ExprArguments.provenance translatedArgs))
... | equalityPhrase phrase | expressions =
failure (mkFailure interpretation predicateArityMismatch (nameDetail name))
... | surface | expressions =
success
(translated
(atom
(PredicateRule.ruleId rule)
surface expressions)
(ruleUsed (PredicateRule.ruleId rule)
∷ ExprArguments.provenance translatedArgs))
mutual
translateProp
: ∀ {scope}
→ Nat
→ DomainSpec
→ Env scope
→ R.Term
→ R.TC (Result (Translation scope))
translateProp zero spec env term =
R.returnTC (failure (mkFailure interpretation budgetExhausted (termDetail term)))
translateProp (suc fuel) spec env
(R.pi (R.arg (R.arg-info visibility (R.modality relevance quantity)) domain)
(R.abs hint body)) =
translatePi fuel spec env visibility relevance quantity domain hint body
translateProp (suc fuel) spec env term@(R.def name args)
with findPredicate name (DomainSpec.predicates spec)
... | just rule = R.returnTC (translateAtom fuel spec env name args)
... | nothing with memberName name (DomainSpec.transparentAliases spec)
... | false =
R.returnTC (failure (mkFailure interpretation unknownHead (nameDetail name)))
... | true =
reduceWhnfWith (DomainSpec.transparentAliases spec) term >>= λ reduced →
translateProp fuel spec env reduced >>= λ where
(failure problem) → R.returnTC (failure problem)
(success result) →
R.returnTC
(success
(translated
(Translation.proposition result)
(aliasUnfolded name ∷ Translation.provenance result)))
translateProp (suc fuel) spec env (R.con name args) =
R.returnTC (translateAtom fuel spec env name args)
translateProp (suc fuel) spec env term =
R.returnTC (failure (mkFailure interpretation unsupportedTerm (termDetail term)))
translatePi
: ∀ {scope}
→ Nat
→ DomainSpec
→ Env scope
→ R.Visibility
→ R.Relevance
→ R.Quantity
→ R.Term
→ String
→ R.Term
→ R.TC (Result (Translation scope))
translatePi fuel spec env visibility relevance quantity domain hint body
with headName domain
... | nothing =
translatePremise fuel spec env visibility relevance quantity domain hint body
... | just name with classifyHead spec name
... | ambiguousClass =
R.returnTC
(failure
(mkFailure classification ambiguousBinderClassification (nameDetail name)))
... | entityClass entityRule =
translateEntity fuel spec env visibility relevance quantity
domain hint body name entityRule
... | infrastructureClass infrastructureRule =
translateInfrastructure fuel spec env visibility relevance quantity
domain hint body name infrastructureRule
... | predicateClass predicateRule =
translatePremise fuel spec env visibility relevance quantity domain hint body
... | unknownClass =
translatePremise fuel spec env visibility relevance quantity domain hint body
translateEntity
: ∀ {scope}
→ Nat
→ DomainSpec
→ Env scope
→ R.Visibility
→ R.Relevance
→ R.Quantity
→ R.Term
→ String
→ R.Term
→ R.Name
→ EntityRule
→ R.TC (Result (Translation scope))
translateEntity fuel spec env visibility relevance quantity
domain hint body name entityRule
with visibility | normalModality relevance quantity | occursAt fuel zero body
... | R.visible | true | true =
translateEntitySupported fuel spec env visibility relevance quantity
domain hint body entityRule
... | R.hidden | true | true =
translateEntitySupported fuel spec env visibility relevance quantity
domain hint body entityRule
... | R.visible | true | false =
R.returnTC
(failure (mkFailure classification nondependentEntityBinder (nameDetail name)))
... | R.hidden | true | false =
R.returnTC
(failure (mkFailure classification nondependentEntityBinder (nameDetail name)))
... | R.visible | false | dependency =
R.returnTC
(failure
(mkFailure classification unsupportedBinderModality
(modalityDetail relevance quantity)))
... | _ | modality | dependency =
R.returnTC
(failure
(mkFailure classification unsupportedBinderVisibility
(visibilityDetail visibility)))
translateEntitySupported
: ∀ {scope}
→ Nat
→ DomainSpec
→ Env scope
→ R.Visibility
→ R.Relevance
→ R.Quantity
→ R.Term
→ String
→ R.Term
→ EntityRule
→ R.TC (Result (Translation scope))
translateEntitySupported fuel spec env visibility relevance quantity
domain hint body entityRule
with translateArguments fuel spec env (EntityRule.ruleId entityRule) zero
(EntityRule.roles entityRule) (headArgs domain)
... | failure problem = R.returnTC (failure problem)
... | success domainArguments =
R.extendContext hint
(R.arg (R.arg-info visibility (R.modality relevance quantity)) domain)
(translateProp fuel spec (extendEntity env) body) >>= λ where
(failure problem) → R.returnTC (failure problem)
(success bodyTranslation) →
R.returnTC
(success
(translated
(forallP
(binder hint (EntityRule.word entityRule)
(ExprArguments.expressions domainArguments)
(EntityRule.ruleId entityRule) visibility relevance quantity)
(Translation.proposition bodyTranslation))
(ruleUsed (EntityRule.ruleId entityRule)
∷ (ExprArguments.provenance domainArguments
++L Translation.provenance bodyTranslation))))
translateInfrastructure
: ∀ {scope}
→ Nat
→ DomainSpec
→ Env scope
→ R.Visibility
→ R.Relevance
→ R.Quantity
→ R.Term
→ String
→ R.Term
→ R.Name
→ InfrastructureRule
→ R.TC (Result (Translation scope))
translateInfrastructure fuel spec env visibility relevance quantity
domain hint body name infrastructureRule =
R.extendContext hint
(R.arg (R.arg-info visibility (R.modality relevance quantity)) domain)
(translateProp fuel spec (extendNonsemantic env) body) >>= λ where
(failure problem) → R.returnTC (failure problem)
(success bodyTranslation) →
R.returnTC
(success
(translated
(Translation.proposition bodyTranslation)
(binderOmitted (InfrastructureRule.ruleId infrastructureRule)
∷ Translation.provenance bodyTranslation)))
translatePremise
: ∀ {scope}
→ Nat
→ DomainSpec
→ Env scope
→ R.Visibility
→ R.Relevance
→ R.Quantity
→ R.Term
→ String
→ R.Term
→ R.TC (Result (Translation scope))
translatePremise fuel spec env visibility relevance quantity domain hint body
with visibility | normalModality relevance quantity | occursAt fuel zero body
... | R.visible | true | true =
R.returnTC (failure (mkFailure classification proofDependentPremise noDetail))
... | R.visible | true | false =
translateProp fuel spec env domain >>= λ where
(failure problem) → R.returnTC (failure problem)
(success premiseTranslation) →
R.extendContext hint
(R.arg (R.arg-info visibility (R.modality relevance quantity)) domain)
(translateProp fuel spec (extendNonsemantic env) body) >>= λ where
(failure problem) → R.returnTC (failure problem)
(success bodyTranslation) →
R.returnTC
(success
(translated
(imply
(Translation.proposition premiseTranslation)
(Translation.proposition bodyTranslation))
(Translation.provenance premiseTranslation
++L Translation.provenance bodyTranslation)))
... | R.visible | false | dependency =
R.returnTC
(failure
(mkFailure classification unsupportedBinderModality
(modalityDetail relevance quantity)))
... | _ | modality | dependency =
R.returnTC
(failure
(mkFailure classification unsupportedBinderVisibility
(visibilityDetail visibility)))
translateClosed : Nat → DomainSpec → R.Term → R.TC (Result (Translation zero))
translateClosed fuel spec term = translateProp fuel spec [] term