From e7dd03d5d1822b35bc9e2f34f6367b03d29283f0 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Thu, 20 Jan 2022 09:54:28 -0800 Subject: [PATCH] chore: remove `tmp` dir --- tmp/Basic.lean | 469 ------ tmp/PreludeNew.lean | 1657 -------------------- tmp/eqns/depelim.lean | 81 - tmp/eqns/elim1.lean | 140 -- tmp/eqns/matchArrayLit.lean | 193 --- tmp/eqns/matchVal.lean | 46 - tmp/new-frontend/elaborator.lean | 1004 ------------ tmp/new-frontend/expander.lean | 544 ------- tmp/new-frontend/frontend.lean | 91 -- tmp/new-frontend/parser/basic.lean | 226 --- tmp/new-frontend/parser/combinators.lean | 247 --- tmp/new-frontend/parser/command.lean | 165 -- tmp/new-frontend/parser/declaration.lean | 167 -- tmp/new-frontend/parser/identifier.lean | 70 - tmp/new-frontend/parser/level.lean | 76 - tmp/new-frontend/parser/module.lean | 133 -- tmp/new-frontend/parser/notation.lean | 189 --- tmp/new-frontend/parser/parsec.lean | 674 -------- tmp/new-frontend/parser/pratt.lean | 56 - tmp/new-frontend/parser/rec.lean | 56 - tmp/new-frontend/parser/stringliteral.lean | 54 - tmp/new-frontend/parser/syntax.lean | 222 --- tmp/new-frontend/parser/term.lean | 455 ------ tmp/new-frontend/parser/token.lean | 379 ----- tmp/new-frontend/parser/trie.lean | 109 -- 25 files changed, 7503 deletions(-) delete mode 100644 tmp/Basic.lean delete mode 100644 tmp/PreludeNew.lean delete mode 100644 tmp/eqns/depelim.lean delete mode 100644 tmp/eqns/elim1.lean delete mode 100644 tmp/eqns/matchArrayLit.lean delete mode 100644 tmp/eqns/matchVal.lean delete mode 100644 tmp/new-frontend/elaborator.lean delete mode 100644 tmp/new-frontend/expander.lean delete mode 100644 tmp/new-frontend/frontend.lean delete mode 100644 tmp/new-frontend/parser/basic.lean delete mode 100644 tmp/new-frontend/parser/combinators.lean delete mode 100644 tmp/new-frontend/parser/command.lean delete mode 100644 tmp/new-frontend/parser/declaration.lean delete mode 100644 tmp/new-frontend/parser/identifier.lean delete mode 100644 tmp/new-frontend/parser/level.lean delete mode 100644 tmp/new-frontend/parser/module.lean delete mode 100644 tmp/new-frontend/parser/notation.lean delete mode 100644 tmp/new-frontend/parser/parsec.lean delete mode 100644 tmp/new-frontend/parser/pratt.lean delete mode 100644 tmp/new-frontend/parser/rec.lean delete mode 100644 tmp/new-frontend/parser/stringliteral.lean delete mode 100644 tmp/new-frontend/parser/syntax.lean delete mode 100644 tmp/new-frontend/parser/term.lean delete mode 100644 tmp/new-frontend/parser/token.lean delete mode 100644 tmp/new-frontend/parser/trie.lean diff --git a/tmp/Basic.lean b/tmp/Basic.lean deleted file mode 100644 index bf4521d756..0000000000 --- a/tmp/Basic.lean +++ /dev/null @@ -1,469 +0,0 @@ -/- -Copyright (c) 2019 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Leonardo de Moura, Sebastian Ullrich --/ -prelude -import Init.Control.Reader -import Init.Lean.Meta -import Init.Lean.Parser.Module - -namespace Lean -namespace Elab - -/- -structure ElabContext := -(fileName : String) -(fileMap : FileMap) - -structure ElabScope := -(cmd : String) -(header : Name) -(options : Options := {}) -(ns : Name := Name.anonymous) -- current namespace -(openDecls : List OpenDecl := []) -(univs : List Name := []) -(lctx : LocalContext := {}) -(nextInstIdx : Nat := 1) -(inPattern : Bool := false) - -namespace ElabScope - -instance : Inhabited ElabScope := ⟨{ cmd := "", header := arbitrary _ }⟩ - -end ElabScope - -structure ElabState := -(env : Environment) -(messages : MessageLog := {}) -(cmdPos : String.Pos := 0) -(ngen : NameGenerator := {}) -(mctx : MetavarContext := {}) -(scopes : List ElabScope := [{ cmd := "root", header := Name.anonymous }]) - -inductive ElabException -| io : IO.Error → ElabException -| msg : Message → ElabException -| kernel : KernelException → ElabException -| other : String → ElabException -/- ElabException.silent is used when we log an error in `messages`, and then - want to interrupt the elaborator execution. We use it to make sure the - top-level handler does not record it again in `messages`. See `logErrorAndThrow` -/ -| silent : ElabException - -namespace ElabException - -instance : Inhabited ElabException := ⟨other "error"⟩ - -end ElabException - -abbrev Elab := ReaderT ElabContext (EStateM ElabException ElabState) - -instance str2ElabException : HasCoe String ElabException := ⟨ElabException.other⟩ - -abbrev TermElab := SyntaxNode Expr → Option Expr → Elab (Syntax Expr) -abbrev CommandElab := SyntaxNode → Elab Unit - -abbrev TermElabTable : Type := SMap SyntaxNodeKind TermElab -abbrev CommandElabTable : Type := SMap SyntaxNodeKind CommandElab -def mkBuiltinTermElabTable : IO (IO.Ref TermElabTable) := IO.mkRef {} -def mkBuiltinCommandElabTable : IO (IO.Ref CommandElabTable) := IO.mkRef {} -@[init mkBuiltinTermElabTable] -constant builtinTermElabTable : IO.Ref TermElabTable := arbitrary _ -@[init mkBuiltinCommandElabTable] -constant builtinCommandElabTable : IO.Ref CommandElabTable := arbitrary _ - -def addBuiltinTermElab (k : SyntaxNodeKind) (declName : Name) (elab : TermElab) : IO Unit := -do m ← builtinTermElabTable.get; - when (m.contains k) $ - throw (IO.userError ("invalid builtin term elaborator, elaborator for '" ++ toString k ++ "' has already been defined")); - builtinTermElabTable.modify $ fun m => m.insert k elab - -def addBuiltinCommandElab (k : SyntaxNodeKind) (declName : Name) (elab : CommandElab) : IO Unit := -do m ← builtinCommandElabTable.get; - when (m.contains k) $ - throw (IO.userError ("invalid builtin command elaborator, elaborator for '" ++ toString k ++ "' has already been defined")); - builtinCommandElabTable.modify $ fun m => m.insert k elab - -def checkSyntaxNodeKind (k : Name) : IO Name := -do b ← Parser.isValidSyntaxNodeKind k; - if b then pure k - else throw (IO.userError "failed") - -def checkSyntaxNodeKindAtNamespaces (k : Name) : List Name → IO Name -| [] => throw (IO.userError "failed") -| n::ns => checkSyntaxNodeKind (n ++ k) <|> checkSyntaxNodeKindAtNamespaces ns - -def syntaxNodeKindOfAttrParam (env : Environment) (parserNamespace : Name) (arg : Syntax) : IO SyntaxNodeKind := -match attrParamSyntaxToIdentifier arg with -| some k => - checkSyntaxNodeKind k - <|> - checkSyntaxNodeKindAtNamespaces k env.getNamespaces - <|> - checkSyntaxNodeKind (parserNamespace ++ k) - <|> - throw (IO.userError ("invalid syntax node kind '" ++ toString k ++ "'")) -| none => throw (IO.userError ("syntax node kind is missing")) - -def declareBuiltinElab (env : Environment) (addFn : Name) (kind : SyntaxNodeKind) (declName : Name) : IO Environment := -let name := `_regBuiltinTermElab ++ declName; -let type := mkApp (mkConst `IO) (mkConst `Unit); -let val := mkAppN (mkConst addFn) #[toExpr kind, toExpr declName, mkConst declName]; -let decl := Declaration.defnDecl { name := name, lparams := [], type := type, value := val, hints := ReducibilityHints.opaque, isUnsafe := false }; -match env.addAndCompile {} decl with --- TODO: pretty print error -| Except.error _ => throw (IO.userError ("failed to emit registration code for builtin term elaborator '" ++ toString declName ++ "'")) -| Except.ok env => IO.ofExcept (setInitAttr env name) - -def declareBuiltinTermElab (env : Environment) (kind : SyntaxNodeKind) (declName : Name) : IO Environment := -declareBuiltinElab env `Lean.addBuiltinTermElab kind declName - -def declareBuiltinCommandElab (env : Environment) (kind : SyntaxNodeKind) (declName : Name) : IO Environment := -declareBuiltinElab env `Lean.addBuiltinCommandElab kind declName - -@[init] def registerBuiltinTermElabAttr : IO Unit := -registerAttribute { - name := `builtinTermElab, - descr := "Builtin term elaborator", - add := fun env declName arg persistent => do { - unless persistent $ throw (IO.userError ("invalid attribute 'builtinTermElab', must be persistent")); - kind ← syntaxNodeKindOfAttrParam env `Lean.Parser.Term arg; - match env.find declName with - | none => throw "unknown declaration" - | some decl => - match decl.type with - | Expr.const `Lean.TermElab _ _ => declareBuiltinTermElab env kind declName - | _ => throw (IO.userError ("unexpected term elaborator type at '" ++ toString declName ++ "' `TermElab` expected")) - }, - applicationTime := AttributeApplicationTime.afterCompilation -} - -@[init] def registerBuiltinCommandElabAttr : IO Unit := -registerAttribute { - name := `builtinCommandElab, - descr := "Builtin command elaborator", - add := fun env declName arg persistent => do { - unless persistent $ throw (IO.userError ("invalid attribute 'builtinCommandElab', must be persistent")); - kind ← syntaxNodeKindOfAttrParam env `Lean.Parser.Command arg; - match env.find declName with - | none => throw "unknown declaration" - | some decl => - match decl.type with - | Expr.const `Lean.CommandElab _ _ => declareBuiltinCommandElab env kind declName - | _ => throw (IO.userError ("unexpected command elaborator type at '" ++ toString declName ++ "' `CommandElab` expected")) - }, - applicationTime := AttributeApplicationTime.afterCompilation -} - -structure ElabAttributeEntry := -(kind : SyntaxNodeKind) -(declName : Name) - -structure ElabAttribute (σ : Type) := -(attr : AttributeImpl) -(ext : PersistentEnvExtension ElabAttributeEntry σ) -(kind : String) - -namespace ElabAttribute - -instance {σ} [Inhabited σ] : Inhabited (ElabAttribute σ) := ⟨{ attr := arbitrary _, ext := arbitrary _, kind := "" }⟩ - -end ElabAttribute - -/- -This is just the basic skeleton for the `[termElab]` attribute and environment extension. -The state is initialized using `builtinTermElabTable`. - -The current implementation just uses the bultin elaborators. --/ -def mkElabAttribute {σ} [Inhabited σ] (attrName : Name) (kind : String) (builtinTable : IO.Ref σ) : IO (ElabAttribute σ) := -do ext : PersistentEnvExtension ElabAttributeEntry σ ← registerPersistentEnvExtension { - name := attrName, - addImportedFn := fun es => do - table ← builtinTable.get; - -- TODO: populate table with `es` - pure table, - addEntryFn := fun (s : σ) _ => s, -- TODO - exportEntriesFn := fun _ => #[], -- TODO - statsFn := fun _ => fmt (kind ++ " elaborator attribute") -- TODO - }; - let attrImpl : AttributeImpl := { - name := attrName, - descr := kind ++ " elaborator", - add := fun env decl args persistent => pure env -- TODO - }; - pure { ext := ext, attr := attrImpl, kind := kind } - -abbrev TermElabAttribute := ElabAttribute TermElabTable -def mkTermElabAttribute : IO TermElabAttribute := -mkElabAttribute `elabTerm "term" builtinTermElabTable -@[init mkTermElabAttribute] -constant termElabAttribute : TermElabAttribute := arbitrary _ - -abbrev CommandElabAttribute := ElabAttribute CommandElabTable -def mkCommandElabAttribute : IO CommandElabAttribute := -mkElabAttribute `commandTerm "command" builtinCommandElabTable -@[init mkCommandElabAttribute] -constant commandElabAttribute : CommandElabAttribute := arbitrary _ - -namespace Elab -def logMessage (msg : Message) : Elab Unit := -modify $ fun s => { messages := s.messages.add msg, .. s } - -def getPosition (pos : Option String.Pos := none) : Elab Position := -do ctx ← read; - s ← get; - pure $ ctx.fileMap.toPosition (pos.getD s.cmdPos) - -def mkMessage (msg : String) (pos : Option String.Pos := none) : Elab Message := -do ctx ← read; - s ← get; - let pos := ctx.fileMap.toPosition (pos.getD s.cmdPos); - pure { fileName := ctx.fileName, pos := pos, data := msg } - -def logErrorAt (pos : String.Pos) (errorMsg : String) : Elab Unit := -mkMessage errorMsg pos >>= logMessage - -def logErrorUsingCmdPos (errorMsg : String) : Elab Unit := -do s ← get; - logErrorAt s.cmdPos errorMsg - -def getPos {α} (stx : Syntax α) : Elab String.Pos := -match stx.getPos with -| some p => pure p -| none => do s ← get; pure s.cmdPos - -def logError {α} (stx : Syntax α) (errorMsg : String) : Elab Unit := -do pos ← getPos stx; - logErrorAt pos errorMsg - -def logElabException (e : ElabException) : Elab Unit := -let log (msg : Message) : Elab Unit := - modify $ fun s => { messages := s.messages.add msg, .. s }; -match e with -| ElabException.silent => pure () -- do nothing since message was already logged -| ElabException.msg m => log m -| ElabException.io e => mkMessage (toString e) >>= log -| ElabException.other e => mkMessage e >>= log -| ElabException.kernel e => - match e with - | KernelException.other msg => mkMessage msg >>= log - | _ => mkMessage "kernel exception" >>= log -- TODO(pretty print them) - -def logErrorAndThrow {α β : Type} (stx : Syntax β) (errorMsg : String) : Elab α := -do logError stx errorMsg; - throw ElabException.silent - -def logUnknownDecl {α} (stx : Syntax α) (declName : Name) : Elab Unit := -logError stx ("unknown declaration '" ++ toString declName ++ "'") - -def getEnv : Elab Environment := -do s ← get; pure s.env - -def setEnv (env : Environment) : Elab Unit := -modify $ fun s => { env := env, .. s } - -def elabCommand (stx : Syntax) : Elab Unit := -stx.ifNode - (fun n => do - s ← get; - let tables := commandElabAttribute.ext.getState s.env; - let k := n.getKind; - match tables.find k with - | some elab => elab n - | none => logError stx ("command '" ++ toString k ++ "' has not been implemented")) - (fun _ => logErrorUsingCmdPos ("unexpected command")) --/ - -structure ElabContext := -(fileName : String) -(fileMap : FileMap) - -inductive ElabException -| io : IO.Error → ElabException -| msg : Message → ElabException -| kernel : KernelException → ElabException - -structure ElabState := -(dummy : Unit := ()) - -structure FrontendState := -(elabState : ElabState) -(parserState : Parser.ModuleParserState) - -abbrev Frontend := ReaderT Parser.ParserContextCore (EStateM ElabException FrontendState) - -/- -def getElabContext : Frontend ElabContext := -do c ← read; - pure { fileName := c.fileName, fileMap := c.fileMap } - -@[specialize] def runElab {α} (x : Elab α) : Frontend α := -do c ← getElabContext; - monadLift $ EStateM.adaptState - (fun (s : FrontendState) => (s.elabState, s.parserState)) - (fun es ps => { elabState := es, parserState := ps }) - (x c) - -def elabCommandAtFrontend (stx : Syntax) : Frontend Unit := -runElab (elabCommand stx) - -def updateCmdPos : Frontend Unit := -modify $ fun s => { elabState := { cmdPos := s.parserState.pos, .. s.elabState }, .. s } - -def processCommand : Frontend Bool := -do updateCmdPos; - s ← get; - let es := s.elabState; - let ps := s.parserState; - c ← read; - match Parser.parseCommand es.env c ps es.messages with - | (cmd, ps, messages) => do - set { elabState := { messages := messages, .. es }, parserState := ps }; - if Parser.isEOI cmd || Parser.isExitCommand cmd then do - pure true -- Done - else do - catch (elabCommandAtFrontend cmd) $ fun e => runElab (logElabException e); - pure false - -partial def processCommandsAux : Unit → Frontend Unit -| () => do - done ← processCommand; - if done then pure () - else processCommandsAux () - -def processCommands : Frontend Unit := -processCommandsAux () - -def testFrontend (input : String) (fileName : Option String := none) : IO (Environment × MessageLog) := -do env ← mkEmptyEnvironment; - let fileName := fileName.getD ""; - let ctx := Parser.mkParserContextCore env input fileName; - match Parser.parseHeader env ctx with - | (header, parserState, messages) => do - (env, messages) ← processHeader header messages ctx; - let elabState := { ElabState . env := env, messages := messages }; - match (processCommands ctx).run { elabState := elabState, parserState := parserState } with - | EStateM.Result.ok _ s => pure (s.elabState.env, s.elabState.messages) - | EStateM.Result.error _ s => pure (s.elabState.env, s.elabState.messages) - -instance {α} : Inhabited (Elab α) := -⟨fun _ => arbitrary _⟩ - -def mkFreshName : Elab Name := -modifyGet $ fun s => (s.ngen.curr, { ngen := s.ngen.next, .. s }) - -def getScope : Elab ElabScope := -do s ← get; pure s.scopes.head! - -def getOpenDecls : Elab (List OpenDecl) := -ElabScope.openDecls <$> getScope - -def getUniverses : Elab (List Name) := -ElabScope.univs <$> getScope - -def getNamespace : Elab Name := -do s ← get; - match s.scopes with - | [] => pure Name.anonymous - | (sc::_) => pure sc.ns - -@[specialize] def modifyScope (f : ElabScope → ElabScope) : Elab Unit := -modify $ fun s => - { scopes := match s.scopes with - | h::t => f h :: t - | [] => [], -- unreachable - .. s } - -@[specialize] def modifyGetScope {α} [Inhabited α] (f : ElabScope → α × ElabScope) : Elab α := -modifyGet $ fun s => - match s with - | { scopes := h::t, .. } => - let (a, h) := f h; - (a, { scopes := h :: t, .. s }) - | _ => (arbitrary _, s) - -def localContext : Elab LocalContext := -do scope ← getScope; pure scope.lctx - -def mkLocalDecl (userName : Name) (type : Expr) (bi : BinderInfo := BinderInfo.default) : Elab Expr := -do idx ← mkFreshName; - modifyScope $ fun scope => { lctx := scope.lctx.mkLocalDecl idx userName type bi, .. scope }; - pure (mkFVar idx) - -def mkLambda (xs : Array Expr) (b : Expr) : Elab Expr := -do lctx ← localContext; pure $ lctx.mkLambda xs b - -def mkForall (xs : Array Expr) (b : Expr) : Elab Expr := -do lctx ← localContext; pure $ lctx.mkForall xs b - -def anonymousInstNamePrefix := `_inst - -def mkAnonymousInstName : Elab Name := -do scope ← getScope; - let n := anonymousInstNamePrefix.appendIndexAfter scope.nextInstIdx; - modifyScope $ fun scope => { nextInstIdx := scope.nextInstIdx + 1, .. scope }; - pure n - -def resolveNamespaceUsingScopes (env : Environment) (n : Name) : List ElabScope → Option Name -| [] => none -| { ns := ns, .. } :: scopes => if isNamespace env (ns ++ n) then some (ns ++ n) else resolveNamespaceUsingScopes scopes - -def resolveNamespaceUsingOpenDecls (env : Environment) (n : Name) : List OpenDecl → Option Name -| [] => none -| OpenDecl.simple ns [] :: ds => if isNamespace env (ns ++ n) then some (ns ++ n) else resolveNamespaceUsingOpenDecls ds -| _ :: ds => resolveNamespaceUsingOpenDecls ds - -/- -Given a name `n` try to find namespace it refers to. The resolution procedure works as follows -1- If `n` is the extact name of an existing namespace, then return `n` -2- If `n` is in the scope of `namespace` commands declaring namespace headers `h_1`, ..., `h_n`, - then return `h_1 ++ ... ++ h_i ++ n` if it is the name of an existing namespace. We search "backwards". -3- Finally, for each command `open N`, return `N ++ n` if it is the name of an existing namespace. - We search "backwards" again. That is, we try the most recent `open` command first. - We only consider simple `open` commands. --/ -def resolveNamespace (n : Name) : Elab Name := -do s ← get; - if isNamespace s.env n then pure n - else match resolveNamespaceUsingScopes s.env n s.scopes with - | some n => pure n - | none => do - openDecls ← getOpenDecls; - match resolveNamespaceUsingOpenDecls s.env n openDecls with - | some n => pure n - | none => throw (ElabException.other ("unknown namespace '" ++ toString n ++ "'")) - -@[inline] def withNewScope {α} (x : Elab α) : Elab α := -do modify $ fun s => { scopes := s.scopes.head! :: s.scopes, .. s }; - a ← x; - modify $ fun s => { scopes := s.scopes.tail!, .. s}; - pure a - -@[inline] def withInPattern {α} (x : Elab α) : Elab α := -withNewScope $ do - modifyScope $ fun scope => { inPattern := true, .. scope }; - x - -def inPattern : Elab Bool := -do scope ← getScope; pure $ scope.inPattern - -/- Remark: in an ideal world where performance doesn't matter, we would define `Elab` as - ``` - ExceptT ElabException (StateT ElabException IO) - ``` - and we would not need unsafe features for implementing `runIO`. - We say `Elab` is "morally" built on top of `IO`. -/ -unsafe def runIOUnsafe {α : Type} (x : IO α) : Elab α := -match unsafeIO x with -| Except.ok a => pure a -| Except.error e => throw (ElabException.io e) - -@[implementedBy runIOUnsafe] -constant runIO {α : Type} (x : IO α) : Elab α := arbitrary _ - -end Elab --/ -end Elab -end Lean diff --git a/tmp/PreludeNew.lean b/tmp/PreludeNew.lean deleted file mode 100644 index dff4ff4975..0000000000 --- a/tmp/PreludeNew.lean +++ /dev/null @@ -1,1657 +0,0 @@ -/- -Copyright (c) 2014 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Leonardo de Moura - -notation, basic datatypes and type classes --/ -prelude - -universes u v w - -@[inline] def id {α : Sort u} (a : α) : α := a - -abbrev Function.comp {α : Sort u} {β : Sort v} {δ : Sort w} (f : β → δ) (g : α → β) : α → δ := - fun x => f (g x) - -abbrev Function.const {α : Sort u} (β : Sort v) (a : α) : β → α := - fun x => a - -set_option bootstrap.inductiveCheckResultingUniverse false in -inductive PUnit : Sort u - | unit : PUnit - -/-- An abbreviation for `PUnit.{0}`, its most common instantiation. - This Type should be preferred over `PUnit` where possible to avoid - unnecessary universe parameters. -/ -abbrev Unit : Type := PUnit - -@[matchPattern] abbrev Unit.unit : Unit := PUnit.unit - -/-- Auxiliary unsafe constant used by the Compiler when erasing proofs from code. -/ -unsafe axiom lcProof {α : Prop} : α - -/-- Auxiliary unsafe constant used by the Compiler to mark unreachable code. -/ -unsafe axiom lcUnreachable {α : Sort u} : α - -inductive True : Prop - | intro : True - -inductive False : Prop - -inductive Empty : Type - -def Not (a : Prop) : Prop := a → False - -@[macroInline] def False.elim {C : Sort u} (h : False) : C := - False.rec (fun _ => C) h - -@[macroInline] def absurd {a : Prop} {b : Sort v} (h₁ : a) (h₂ : Not a) : b := - False.elim (h₂ h₁) - -inductive Eq {α : Sort u} (a : α) : α → Prop - | refl {} : Eq a a - -abbrev Eq.ndrec.{u1, u2} {α : Sort u2} {a : α} {motive : α → Sort u1} (m : motive a) {b : α} (h : Eq a b) : motive b := - Eq.rec (motive := fun α _ => motive α) m h - -@[matchPattern] def rfl {α : Sort u} {a : α} : Eq a a := Eq.refl a - -theorem Eq.subst {α : Sort u} {motive : α → Prop} {a b : α} (h₁ : Eq a b) (h₂ : motive a) : motive b := - Eq.ndrec h₂ h₁ - -theorem Eq.symm {α : Sort u} {a b : α} (h : a = b) : b = a := - h ▸ rfl - -@[macroInline] def cast {α β : Sort u} (h : α = β) (a : α) : β := - Eq.rec (motive := fun α _ => α) a h - -theorem congrArg {α : Sort u} {β : Sort v} {a₁ a₂ : α} (f : α → β) (h : Eq a₁ a₂) : Eq (f a₁) (f a₂) := - h ▸ rfl - -/- -Initialize the Quotient Module, which effectively adds the following definitions: - -constant Quot {α : Sort u} (r : α → α → Prop) : Sort u - -constant Quot.mk {α : Sort u} (r : α → α → Prop) (a : α) : Quot r - -constant Quot.lift {α : Sort u} {r : α → α → Prop} {β : Sort v} (f : α → β) : - (∀ a b : α, r a b → Eq (f a) (f b)) → Quot r → β - -constant Quot.ind {α : Sort u} {r : α → α → Prop} {β : Quot r → Prop} : - (∀ a : α, β (Quot.mk r a)) → ∀ q : Quot r, β q --/ -init_quot - -inductive HEq {α : Sort u} (a : α) : {β : Sort u} → β → Prop - | refl {} : HEq a a - -@[matchPattern] def HEq.rfl {α : Sort u} {a : α} : a ≅ a := - HEq.refl a - -theorem eqOfHEq {α : Sort u} {a a' : α} (h : HEq a a') : Eq a a' := - have (α β : Sort u) → (a : α) → (b : β) → HEq a b → (h : Eq α β) → Eq (cast h a) b from - fun α β a b h₁ => - HEq.rec (motive := fun {β} (b : β) (h : HEq a b) => (h₂ : Eq α β) → Eq (cast h₂ a) b) - (fun (h₂ : Eq α α) => rfl) - h₁ - this α α a a' h rfl - -structure Prod (α : Type u) (β : Type v) := - (fst : α) (snd : β) - -attribute [unbox] Prod - -/-- Similar to `Prod`, but `α` and `β` can be propositions. - We use this Type internally to automatically generate the brecOn recursor. -/ -structure PProd (α : Sort u) (β : Sort v) := - (fst : α) (snd : β) - -/-- Similar to `Prod`, but `α` and `β` are in the same universe. -/ -structure MProd (α β : Type u) := - (fst : α) (snd : β) - -structure And (a b : Prop) : Prop := - intro :: (left : a) (right : b) - -inductive Or (a b : Prop) : Prop - | inl (h : a) : Or a b - | inr (h : b) : Or a b - -inductive Bool : Type - | false : Bool - | true : Bool - -export Bool (false true) - -/- Remark: Subtype must take a Sort instead of Type because of the axiom strongIndefiniteDescription. -/ -structure Subtype {α : Sort u} (p : α → Prop) := - (val : α) (property : p val) - -/-- Gadget for optional parameter support. -/ -@[reducible] def optParam (α : Sort u) (default : α) : Sort u := α - -/-- Gadget for marking output parameters in type classes. -/ -@[reducible] def outParam (α : Sort u) : Sort u := α - -/-- Auxiliary Declaration used to implement the notation (a : α) -/ -@[reducible] def typedExpr (α : Sort u) (a : α) : α := a - -/-- Auxiliary Declaration used to implement the named patterns `x@p` -/ -@[reducible] def namedPattern {α : Sort u} (x a : α) : α := a - -/- Auxiliary axiom used to implement `sorry`. -/ -axiom sorryAx (α : Sort u) (synthetic := true) : α - -theorem eqFalseOfNeTrue : {b : Bool} → Not (Eq b true) → b = false - | true, h => False.elim (h rfl) - | false, h => rfl - -theorem eqTrueOfNeFalse : {b : Bool} → Not (Eq b false) → b = true - | true, h => rfl - | false, h => False.elim (h rfl) - -theorem neFalseOfEqTrue : {b : Bool} → Eq b true → Not (Eq b false) - | true, _ => fun h => Bool.noConfusion h - | false, h => Bool.noConfusion h - -theorem neTrueOfEqFalse : {b : Bool} → Eq b false → Not (Eq b true) - | true, h => Bool.noConfusion h - | false, _ => fun h => Bool.noConfusion h - -class Inhabited (α : Sort u) := - mk {} :: (default : α) - -constant arbitrary (α : Sort u) [s : Inhabited α] : α := - @Inhabited.default α s - -instance (α : Sort u) {β : Sort v} [Inhabited β] : Inhabited (α → β) := { - default := fun _ => arbitrary β -} - -instance (α : Sort u) {β : α → Sort v} [(a : α) → Inhabited (β a)] : Inhabited ((a : α) → β a) := { - default := fun a => arbitrary (β a) -} - -/-- Universe lifting operation from Sort to Type -/ -structure PLift (α : Sort u) : Type u := - up :: (down : α) - -/- Bijection between α and PLift α -/ -theorem PLift.upDown {α : Sort u} : ∀ (b : PLift α), up (down b) = b - | up a => rfl - -theorem PLift.downUp {α : Sort u} (a : α) : down (up a) = a := - rfl - -/- Pointed types -/ -structure PointedType := - (type : Type u) - (val : type) - -instance : Inhabited PointedType.{u} := { - default := { type := PUnit.{u+1}, val := ⟨⟩ } -} - -/-- Universe lifting operation -/ -structure ULift.{r, s} (α : Type s) : Type (max s r) := - up :: (down : α) - -/- Bijection between α and ULift.{v} α -/ -theorem ULift.upDown {α : Type u} : ∀ (b : ULift.{v} α), up (down b) = b - | up a => rfl - -theorem ULift.downUp {α : Type u} (a : α) : down (up.{v} a) = a := - rfl - -class inductive Decidable (p : Prop) - | isFalse (h : Not p) : Decidable p - | isTrue (h : p) : Decidable p - -@[inlineIfReduce, nospecialize] def Decidable.decide (p : Prop) [h : Decidable p] : Bool := - Decidable.casesOn (motive := fun _ => Bool) h (fun _ => false) (fun _ => true) - -export Decidable (isTrue isFalse decide) - -abbrev DecidablePred {α : Sort u} (r : α → Prop) := - (a : α) → Decidable (r a) - -abbrev DecidableRel {α : Sort u} (r : α → α → Prop) := - (a b : α) → Decidable (r a b) - -abbrev DecidableEq (α : Sort u) := - (a b : α) → Decidable (Eq a b) - -def decEq {α : Sort u} [s : DecidableEq α] (a b : α) : Decidable (Eq a b) := - s a b - -theorem decideEqTrue : {p : Prop} → [s : Decidable p] → p → Eq (decide p) true - | _, isTrue _, _ => rfl - | _, isFalse h₁, h₂ => absurd h₂ h₁ - -theorem decideEqFalse : {p : Prop} → [s : Decidable p] → Not p → Eq (decide p) false - | _, isTrue h₁, h₂ => absurd h₁ h₂ - | _, isFalse h, _ => rfl - -theorem ofDecideEqTrue {p : Prop} [s : Decidable p] : Eq (decide p) true → p := fun h => - match s with - | isTrue h₁ => h₁ - | isFalse h₁ => absurd h (neTrueOfEqFalse (decideEqFalse h₁)) - -theorem ofDecideEqFalse {p : Prop} [s : Decidable p] : Eq (decide p) false → Not p := fun h => - match s with - | isTrue h₁ => absurd h (neFalseOfEqTrue (decideEqTrue h₁)) - | isFalse h₁ => h₁ - -@[inline] instance : DecidableEq Bool := - fun a b => match a, b with - | false, false => isTrue rfl - | false, true => isFalse (fun h => Bool.noConfusion h) - | true, false => isFalse (fun h => Bool.noConfusion h) - | true, true => isTrue rfl - -class BEq (α : Type u) := (beq : α → α → Bool) - -open BEq (beq) - -instance {α : Type u} [DecidableEq α] : BEq α := - ⟨fun a b => decide (Eq a b)⟩ - --- We use "dependent" if-then-else to be able to communicate the if-then-else condition --- to the branches -@[macroInline] def dite {α : Sort u} (c : Prop) [h : Decidable c] (t : c → α) (e : Not c → α) : α := - Decidable.casesOn (motive := fun _ => α) h e t - -/- if-then-else -/ - -@[macroInline] def ite {α : Sort u} (c : Prop) [h : Decidable c] (t e : α) : α := - Decidable.casesOn (motive := fun _ => α) h (fun _ => e) (fun _ => t) - -@[macroInline] instance {p q} [Decidable p] [Decidable q] : Decidable (And p q) := - if hp : p then - if hq : q then - isTrue ⟨hp, hq⟩ - else - isFalse (fun h => hq (And.right h)) - else - isFalse (fun h => hp (And.left h)) - -@[macroInline] instance {p q} [Decidable p] [Decidable q] : Decidable (Or p q) := - if hp : p then - isTrue (Or.inl hp) - else if hq : q then - isTrue (Or.inr hq) - else - isFalse fun h => match h with - | Or.inl h => hp h - | Or.inr h => hq h - -instance {p} [Decidable p] : Decidable (Not p) := - if hp : p then isFalse (absurd hp) else isTrue hp - -/- Boolean operators -/ - -@[macroInline] def cond {a : Type u} : Bool → a → a → a - | true, x, y => x - | false, x, y => y - -@[macroInline] def or : Bool → Bool → Bool - | true, _ => true - | false, b => b - -@[macroInline] def and : Bool → Bool → Bool - | false, _ => false - | true, b => b - -@[macroInline] def not : Bool → Bool - | true => false - | false => true - -inductive Nat - | zero : Nat - | succ (n : Nat) : Nat - -/- For numeric literals notation -/ -class OfNat (α : Type u) := - (ofNat : Nat → α) - -export OfNat (ofNat) - -instance : OfNat Nat := ⟨id⟩ - -instance : Inhabited Nat := { - default := 0 -} - -class HasLessEq (α : Type u) := (LessEq : α → α → Prop) -class HasLess (α : Type u) := (Less : α → α → Prop) - -export HasLess (Less) -export HasLessEq (LessEq) - -class Add (α : Type u) := (add : α → α → α) -class Mul (α : Type u) := (mul : α → α → α) -class Neg (α : Type u) := (neg : α → α) -class Sub (α : Type u) := (sub : α → α → α) -class Div (α : Type u) := (div : α → α → α) -class Mod (α : Type u) := (mod : α → α → α) -class ModN (α : Type u) := (modn : α → Nat → α) -class Pow (α : Type u) (β : Type v) := (pow : α → β → α) -class Append (α : Type u) := (append : α → α → α) -class OrElse (α : Type u) := (orElse : α → α → α) -class AndThen (α : Type u) := (andThen : α → α → α) - -open Add (add) -open Mul (mul) -open Pow (pow) -open Append (append) - -@[reducible] def GreaterEq {α : Type u} [HasLessEq α] (a b : α) : Prop := LessEq b a -@[reducible] def Greater {α : Type u} [HasLess α] (a b : α) : Prop := Less b a - -set_option bootstrap.gen_matcher_code false in -@[extern "lean_nat_add"] -protected def Nat.add : (@& Nat) → (@& Nat) → Nat - | a, Nat.zero => a - | a, Nat.succ b => Nat.succ (Nat.add a b) - -instance : Add Nat := { - add := Nat.add -} - -set_option bootstrap.gen_matcher_code false in -@[extern "lean_nat_mul"] -protected def Nat.mul : (@& Nat) → (@& Nat) → Nat - | a, 0 => 0 - | a, Nat.succ b => Nat.add (Nat.mul a b) a - -instance : Mul Nat := { - mul := Nat.mul -} - -set_option bootstrap.gen_matcher_code false in -@[extern "lean_nat_pow"] -protected def Nat.pow (m : @& Nat) : (@& Nat) → Nat - | 0 => 1 - | succ n => Nat.mul (Nat.pow m n) m - -instance : Pow Nat Nat := { - pow := Nat.pow -} - -set_option bootstrap.gen_matcher_code false in -@[extern "lean_nat_dec_eq"] -def Nat.beq : Nat → Nat → Bool - | zero, zero => true - | zero, succ m => false - | succ n, zero => false - | succ n, succ m => beq n m - -theorem Nat.eqOfBeqEqTt : {n m : Nat} → Eq (beq n m) true → Eq n m - | zero, zero, h => rfl - | zero, succ m, h => Bool.noConfusion h - | succ n, zero, h => Bool.noConfusion h - | succ n, succ m, h => - have Eq (beq n m) true from h - have Eq n m from eqOfBeqEqTt this - this ▸ rfl - -theorem Nat.neOfBeqEqFf : {n m : Nat} → Eq (beq n m) false → Not (Eq n m) - | zero, zero, h₁, h₂ => Bool.noConfusion h₁ - | zero, succ m, h₁, h₂ => Nat.noConfusion h₂ - | succ n, zero, h₁, h₂ => Nat.noConfusion h₂ - | succ n, succ m, h₁, h₂ => - have beq n m = false from h₁ - Nat.noConfusion h₂ (fun h₂ => absurd h₂ (neOfBeqEqFf this)) - -@[extern "lean_nat_dec_eq"] -protected def Nat.decEq (n m : @& Nat) : Decidable (n = m) := - if h : beq n m = true then isTrue (eqOfBeqEqTt h) - else isFalse (neOfBeqEqFf (eqFalseOfNeTrue h)) - -@[inline] instance : DecidableEq Nat := Nat.decEq - -set_option bootstrap.gen_matcher_code false in -@[extern "lean_nat_dec_le"] -def Nat.ble : Nat → Nat → Bool - | zero, zero => true - | zero, succ m => true - | succ n, zero => false - | succ n, succ m => ble n m - -protected def Nat.le (n m : Nat) : Prop := - ble n m = true - -instance : HasLessEq Nat := ⟨Nat.le⟩ - -protected def Nat.lt (n m : Nat) : Prop := - Nat.le (succ n) m - -instance : HasLess Nat := ⟨Nat.lt⟩ - -theorem Nat.notSuccLeZero : ∀ (n : Nat), LessEq (succ n) 0 → False - | 0, h => nomatch h - | succ n, h => nomatch h - -theorem Nat.notLtZero (n : Nat) : Not (Less n 0) := - notSuccLeZero n - -@[extern "lean_nat_dec_le"] -instance Nat.decLe (n m : @& Nat) : Decidable (LessEq n m) := - decEq (Nat.ble n m) true - -@[extern "lean_nat_dec_lt"] -instance Nat.decLt (n m : @& Nat) : Decidable (Less n m) := - decLe (succ n) m - -theorem Nat.zeroLe : (n : Nat) → LessEq 0 n - | zero => rfl - | succ n => rfl - -theorem Nat.succLeSucc {n m : Nat} (h : LessEq n m) : LessEq (succ n) (succ m) := - h - -theorem Nat.zeroLtSucc (n : Nat) : Less 0 (succ n) := - succLeSucc (zeroLe n) - -theorem Nat.leStep : {n m : Nat} → LessEq n m → LessEq n (succ m) - | zero, zero, h => rfl - | zero, succ n, h => rfl - | succ n, zero, h => Bool.noConfusion h - | succ n, succ m, h => - have LessEq n m from h - have LessEq n (succ m) from leStep this - succLeSucc this - -protected theorem Nat.leTrans : {n m k : Nat} → LessEq n m → LessEq m k → LessEq n k - | zero, m, k, h₁, h₂ => zeroLe _ - | succ n, zero, k, h₁, h₂ => Bool.noConfusion h₁ - | succ n, succ m, zero, h₁, h₂ => Bool.noConfusion h₂ - | succ n, succ m, succ k, h₁, h₂ => - have h₁' : LessEq n m from h₁ - have h₂' : LessEq m k from h₂ - Nat.leTrans h₁' h₂' - -protected theorem Nat.ltTrans {n m k : Nat} (h₁ : Less n m) : Less m k → Less n k := - Nat.leTrans (leStep h₁) - -theorem Nat.leSucc : (n : Nat) → LessEq n (succ n) - | zero => rfl - | succ n => leSucc n - -theorem Nat.leSuccOfLe {n m : Nat} (h : LessEq n m) : LessEq n (succ m) := - Nat.leTrans h (leSucc m) - -protected theorem Nat.eqOrLtOfLe : {n m: Nat} → LessEq n m → Or (Eq n m) (Less n m) - | zero, zero, h => Or.inl rfl - | zero, succ n, h => Or.inr (zeroLe n) - | succ n, zero, h => Bool.noConfusion h - | succ n, succ m, h => - have LessEq n m from h - match Nat.eqOrLtOfLe this with - | Or.inl h => Or.inl (h ▸ rfl) - | Or.inr h => Or.inr (succLeSucc h) - -protected def Nat.leRefl : (n : Nat) → LessEq n n - | zero => rfl - | succ n => Nat.leRefl n - -protected theorem Nat.ltOrGe (n m : Nat) : Or (Less n m) (GreaterEq n m) := - match m with - | zero => Or.inr (zeroLe n) - | succ m => - match Nat.ltOrGe n m with - | Or.inl h => Or.inl (leSuccOfLe h) - | Or.inr h => - match Nat.eqOrLtOfLe h with - | Or.inl h1 => Or.inl (h1 ▸ Nat.leRefl _) - | Or.inr h1 => Or.inr h1 - -protected theorem Nat.leAntisymm : {n m : Nat} → LessEq n m → LessEq m n → Eq n m - | zero, zero, h₁, h₂ => rfl - | succ n, zero, h₁, h₂ => Bool.noConfusion h₁ - | zero, succ m, h₁, h₂ => Bool.noConfusion h₂ - | succ n, succ m, h₁, h₂ => - have h₁' : LessEq n m from h₁ - have h₂' : LessEq m n from h₂ - (Nat.leAntisymm h₁' h₂') ▸ rfl - -protected theorem Nat.ltOfLeOfNe {n m : Nat} (h₁ : LessEq n m) (h₂ : Not (Eq n m)) : Less n m := - match Nat.ltOrGe n m with - | Or.inl h₃ => h₃ - | Or.inr h₃ => absurd (Nat.leAntisymm h₁ h₃) h₂ - -set_option bootstrap.gen_matcher_code false in -@[extern c inline "lean_nat_sub(#1, lean_box(1))"] -def Nat.pred : Nat → Nat - | 0 => 0 - | succ a => a - -theorem Nat.predLePred : {n m : Nat} → LessEq n m → LessEq (pred n) (pred m) - | zero, zero, h => rfl - | zero, succ n, h => zeroLe n - | succ n, zero, h => Bool.noConfusion h - | succ n, succ m, h => h - -theorem Nat.leOfSuccLeSucc {n m : Nat} : LessEq (succ n) (succ m) → LessEq n m := - predLePred - -theorem Nat.leOfLtSucc {m n : Nat} : Less m (succ n) → LessEq m n := - leOfSuccLeSucc - -@[extern "lean_system_platform_nbits"] constant System.Platform.getNumBits : Unit → { n : Nat // Or (Eq n 32) (Eq n 64) } := - fun _ => ⟨64, Or.inr rfl⟩ -- inhabitant - -def System.Platform.numBits : Nat := - (getNumBits ()).val - -theorem System.Platform.numBitsEq : Or (Eq numBits 32) (Eq numBits 64) := - (getNumBits ()).property - -structure Fin (n : Nat) := - (val : Nat) - (isLt : Less val n) - -theorem Fin.eqOfVeq {n} : ∀ {i j : Fin n}, Eq i.val j.val → Eq i j - | ⟨v, h⟩, ⟨_, _⟩, rfl => rfl - -theorem Fin.veqOfEq {n} {i j : Fin n} (h : Eq i j) : i.val = j.val := - h ▸ rfl - -theorem Fin.neOfVne {n} {i j : Fin n} (h : Not (Eq i.val j.val)) : Not (Eq i j) := - fun h' => absurd (veqOfEq h') h - -instance (n : Nat) : DecidableEq (Fin n) := - fun i j => - match decEq i.val j.val with - | isTrue h => isTrue (Fin.eqOfVeq h) - | isFalse h => isFalse (Fin.neOfVne h) - -def uint8Sz : Nat := 256 -structure UInt8 := - (val : Fin uint8Sz) - -set_option bootstrap.gen_matcher_code false in -@[extern c inline "#1 == #2"] -def UInt8.decEq (a b : UInt8) : Decidable (Eq a b) := - match a, b with - | ⟨n⟩, ⟨m⟩ => if h : Eq n m then isTrue (h ▸ rfl) else isFalse (fun h' => UInt8.noConfusion h' (fun h' => absurd h' h)) - -instance : DecidableEq UInt8 := UInt8.decEq - -instance : Inhabited UInt8 := { - default := { val := { val := 0, isLt := decide! } } -} - -def uint16Sz : Nat := 65536 -structure UInt16 := - (val : Fin uint16Sz) - -set_option bootstrap.gen_matcher_code false in -@[extern c inline "#1 == #2"] -def UInt16.decEq (a b : UInt16) : Decidable (Eq a b) := - match a, b with - | ⟨n⟩, ⟨m⟩ => if h : Eq n m then isTrue (h ▸ rfl) else isFalse (fun h' => UInt16.noConfusion h' (fun h' => absurd h' h)) - -instance : DecidableEq UInt16 := UInt16.decEq - -instance : Inhabited UInt16 := { - default := { val := { val := 0, isLt := decide! } } -} - -def uint32Sz : Nat := 4294967296 -structure UInt32 := - (val : Fin uint32Sz) - -set_option bootstrap.gen_matcher_code false in -@[extern c inline "#1 == #2"] -def UInt32.decEq (a b : UInt32) : Decidable (Eq a b) := - match a, b with - | ⟨n⟩, ⟨m⟩ => if h : Eq n m then isTrue (h ▸ rfl) else isFalse (fun h' => UInt32.noConfusion h' (fun h' => absurd h' h)) - -instance : DecidableEq UInt32 := UInt32.decEq - -instance : Inhabited UInt32 := { - default := { val := { val := 0, isLt := decide! } } -} - -def uint64Sz : Nat := 18446744073709551616 -structure UInt64 := - (val : Fin uint64Sz) - -set_option bootstrap.gen_matcher_code false in -@[extern c inline "#1 == #2"] -def UInt64.decEq (a b : UInt64) : Decidable (Eq a b) := - match a, b with - | ⟨n⟩, ⟨m⟩ => if h : Eq n m then isTrue (h ▸ rfl) else isFalse (fun h' => UInt64.noConfusion h' (fun h' => absurd h' h)) - -instance : DecidableEq UInt64 := UInt64.decEq - -instance : Inhabited UInt64 := { - default := { val := { val := 0, isLt := decide! } } -} - -def usizeSz : Nat := pow 2 System.Platform.numBits - -theorem usizeSzEq : Or (Eq usizeSz 4294967296) (Eq usizeSz 18446744073709551616) := - show Or (Eq (pow 2 System.Platform.numBits) 4294967296) (Eq (pow 2 System.Platform.numBits) 18446744073709551616) from - match System.Platform.numBits, System.Platform.numBitsEq with - | _, Or.inl rfl => Or.inl (decide! : (Eq (pow 2 32) (4294967296:Nat))) - | _, Or.inr rfl => Or.inr (decide! : (Eq (pow 2 64) (18446744073709551616:Nat))) - -structure USize := - (val : Fin usizeSz) - -set_option bootstrap.gen_matcher_code false in -@[extern c inline "#1 == #2"] -def USize.decEq (a b : USize) : Decidable (Eq a b) := - match a, b with - | ⟨n⟩, ⟨m⟩ => if h : Eq n m then isTrue (h ▸ rfl) else isFalse (fun h' => USize.noConfusion h' (fun h' => absurd h' h)) - -instance : DecidableEq USize := USize.decEq - -instance : Inhabited USize := { - default := { val := { val := 0, isLt := match usizeSz, usizeSzEq with | _, Or.inl rfl => decide! | _, Or.inr rfl => decide! } } -} - -@[extern "lean_usize_of_nat"] -def USize.ofNat32 (n : @& Nat) (h : Less n 4294967296) : USize := { - val := { - val := n, - isLt := match usizeSz, usizeSzEq with - | _, Or.inl rfl => h - | _, Or.inr rfl => Nat.ltTrans h (decide! : Less 4294967296 18446744073709551616) - } -} - -@[extern "lean_usize_of_nat"] -def USize.ofNatCore (n : @& Nat) (h : Less n usizeSz) : USize := { - val := { val := n, isLt := h } -} - -abbrev Nat.isValidChar (n : Nat) : Prop := - Or (Less n 0xd800) (And (Less 0xdfff n) (Less n 0x110000)) - -abbrev UInt32.isValidChar (n : UInt32) : Prop := - n.val.val.isValidChar - -/-- The `Char` Type represents an unicode scalar value. - See http://www.unicode.org/glossary/#unicode_scalar_value). -/ -structure Char := - (val : UInt32) - (valid : val.isValidChar) - -private theorem validCharIsUInt32 {n : Nat} (h : n.isValidChar) : Less n uint32Sz := - match h with - | Or.inl h => Nat.ltTrans h (decide! : Less 55296 uint32Sz) - | Or.inr ⟨_, h⟩ => Nat.ltTrans h (decide! : Less 1114112 uint32Sz) - -abbrev Char.ofNat (n : Nat) : Char := - if h : n.isValidChar then - { val := ⟨{ val := n, isLt := validCharIsUInt32 h }⟩, valid := h } - else - { val := ⟨{ val := 0, isLt := decide! }⟩, valid := Or.inl decide! } - -theorem Char.eqOfVeq : ∀ {c d : Char}, Eq c.val d.val → Eq c d - | ⟨v, h⟩, ⟨_, _⟩, rfl => rfl - -theorem Char.veqOfEq : ∀ {c d : Char}, Eq c d → Eq c.val d.val - | _, _, rfl => rfl - -theorem Char.neOfVne {c d : Char} (h : Not (Eq c.val d.val)) : Not (Eq c d) := - fun h' => absurd (veqOfEq h') h - -theorem Char.vneOfNe {c d : Char} (h : Not (Eq c d)) : Not (Eq c.val d.val) := - fun h' => absurd (eqOfVeq h') h - -instance : DecidableEq Char := - fun c d => - match decEq c.val d.val with - | isTrue h => isTrue (Char.eqOfVeq h) - | isFalse h => isFalse (Char.neOfVne h) - -inductive Option (α : Type u) - | none : Option α - | some (val : α) : Option α - -attribute [unbox] Option - -export Option (none some) - -instance {α} : Inhabited (Option α) := { - default := none -} - -inductive List (α : Type u) - | nil : List α - | cons (head : α) (tail : List α) : List α - -instance {α} : Inhabited (List α) := { - default := List.nil -} - -protected def List.hasDecEq {α: Type u} [DecidableEq α] : (a b : List α) → Decidable (Eq a b) - | nil, nil => isTrue rfl - | cons a as, nil => isFalse (fun h => List.noConfusion h) - | nil, cons b bs => isFalse (fun h => List.noConfusion h) - | cons a as, cons b bs => - match decEq a b with - | isTrue hab => - match List.hasDecEq as bs with - | isTrue habs => isTrue (hab ▸ habs ▸ rfl) - | isFalse nabs => isFalse (fun h => List.noConfusion h (fun _ habs => absurd habs nabs)) - | isFalse nab => isFalse (fun h => List.noConfusion h (fun hab _ => absurd hab nab)) - -instance {α : Type u} [DecidableEq α] : DecidableEq (List α) := List.hasDecEq - -@[specialize] -def List.foldl {α β} (f : α → β → α) : (init : α) → List β → α - | a, nil => a - | a, cons b l => foldl f (f a b) l - -structure String := - (data : List Char) - -attribute [extern "lean_string_mk"] String.mk -attribute [extern "lean_string_data"] String.data - -@[extern "lean_string_dec_eq"] -def String.decEq (s₁ s₂ : @& String) : Decidable (s₁ = s₂) := - match s₁, s₂ with - | ⟨s₁⟩, ⟨s₂⟩ => - if h : s₁ = s₂ then isTrue (congrArg _ h) - else isFalse (fun h' => String.noConfusion h' (fun h' => absurd h' h)) - -instance : DecidableEq String := String.decEq - -/-- A byte position in a `String`. Internally, `String`s are UTF-8 encoded. -Codepoint positions (counting the Unicode codepoints rather than bytes) -are represented by plain `Nat`s instead. -Indexing a `String` by a byte position is constant-time, while codepoint -positions need to be translated internally to byte positions in linear-time. -/ -abbrev String.Pos := Nat - -structure Substring := - (str : String) - (startPos : String.Pos) - (stopPos : String.Pos) - -@[extern c inline "#3"] -unsafe def unsafeCast {α : Type u} {β : Type v} (a : α) : β := - cast lcProof (PUnit.{v}) - -@[neverExtract, extern "lean_panic_fn"] -constant panic {α : Type u} [Inhabited α] (msg : String) : α - -/- -The Compiler has special support for arrays. -They are implemented using dynamic arrays: https://en.wikipedia.org/wiki/Dynamic_array --/ -structure Array (α : Type u) := - (sz : Nat) - (data : Fin sz → α) - -attribute [extern "lean_array_mk"] Array.mk -attribute [extern "lean_array_data"] Array.data -attribute [extern "lean_array_sz"] Array.sz - -/- The parameter `c` is the initial capacity -/ -@[extern "lean_mk_empty_array_with_capacity"] -def Array.mkEmpty {α : Type u} (c : @& Nat) : Array α := { - sz := 0, - data := fun ⟨x, h⟩ => absurd h (Nat.notLtZero x) -} - -def Array.empty {α : Type u} : Array α := - mkEmpty 0 - -@[reducible, extern "lean_array_get_size"] -def Array.size {α : Type u} (a : @& Array α) : Nat := - a.sz - -@[extern "lean_array_fget"] -def Array.get {α : Type u} (a : @& Array α) (i : @& Fin a.size) : α := - a.data i - -/- "Comfortable" version of `fget`. It performs a bound check at runtime. -/ -@[extern "lean_array_get"] -def Array.get! {α : Type u} [Inhabited α] (a : @& Array α) (i : @& Nat) : α := - if h : Less i a.size then a.get ⟨i, h⟩ else arbitrary α - -@[extern "lean_array_push"] -def push {α : Type u} (a : Array α) (v : α) : Array α := { - sz := Nat.succ a.sz, - data := fun ⟨j, h₁⟩ => - if h₂ : j = a.sz then - v - else - a.data ⟨j, Nat.ltOfLeOfNe (Nat.leOfLtSucc h₁) h₂⟩ -} - -class Bind (m : Type u → Type v) := - (bind : {α β : Type u} → m α → (α → m β) → m β) - -export Bind (bind) - -class Pure (f : Type u → Type v) := - (pure {α : Type u} : α → f α) - -export Pure (pure) - -class Functor (f : Type u → Type v) : Type (max (u+1) v) := - (map : {α β : Type u} → (α → β) → f α → f β) - (mapConst : {α β : Type u} → α → f β → f α := Function.comp map (Function.const _)) - -class Seq (f : Type u → Type v) : Type (max (u+1) v) := - (seq : {α β : Type u} → f (α → β) → f α → f β) - -class SeqLeft (f : Type u → Type v) : Type (max (u+1) v) := - (seqLeft : {α : Type u} → f α → f PUnit → f α) - -class SeqRight (f : Type u → Type v) : Type (max (u+1) v) := - (seqRight : {β : Type u} → f PUnit → f β → f β) - -class Applicative (f : Type u → Type v) extends Functor f, Pure f, Seq f, SeqLeft f, SeqRight f := - (map := fun x y => Seq.seq (pure x) y) - (seqLeft := fun a b => Seq.seq (Functor.map (Function.const _) a) b) - (seqRight := fun a b => Seq.seq (Functor.map (Function.const _ id) a) b) - -class Monad (m : Type u → Type v) extends Applicative m, Bind m : Type (max (u+1) v) := - (map := fun f x => bind x (Function.comp pure f)) - (seq := fun f x => bind f (fun y => Functor.map y x)) - (seqLeft := fun x y => bind x (fun a => bind y (fun _ => pure a))) - (seqRight := fun x y => bind x (fun _ => y)) - -instance {α : Type u} {m : Type u → Type v} [Monad m] : Inhabited (α → m α) := ⟨pure⟩ - -instance {α : Type u} {m : Type u → Type v} [Monad m] [Inhabited α] : Inhabited (m α) := ⟨pure $ arbitrary _⟩ - -/-- A Function for lifting a computation from an inner Monad to an outer Monad. - Like [MonadTrans](https://hackage.haskell.org/package/transformers-0.5.5.0/docs/Control-Monad-Trans-Class.html), - but `n` does not have to be a monad transformer. - Alternatively, an implementation of [MonadLayer](https://hackage.haskell.org/package/layers-0.1/docs/Control-Monad-Layer.html#t:MonadLayer) without `layerInvmap` (so far). -/ -class MonadLift (m : Type u → Type v) (n : Type u → Type w) := - (monadLift : {α : Type u} → m α → n α) - -/-- The reflexive-transitive closure of `MonadLift`. - `monadLift` is used to transitively lift monadic computations such as `StateT.get` or `StateT.put s`. - Corresponds to [MonadLift](https://hackage.haskell.org/package/layers-0.1/docs/Control-Monad-Layer.html#t:MonadLift). -/ -class MonadLiftT (m : Type u → Type v) (n : Type u → Type w) := - (monadLift : {α : Type u} → m α → n α) - -export MonadLiftT (monadLift) - -abbrev liftM := @monadLift - -instance (m n o) [MonadLiftT m n] [MonadLift n o] : MonadLiftT m o := { - monadLift := fun x => MonadLift.monadLift (m := n) (monadLift x) -} - -instance (m) : MonadLiftT m m := { - monadLift := fun x => x -} - -/-- A functor in the category of monads. Can be used to lift monad-transforming functions. - Based on pipes' [MFunctor](https://hackage.haskell.org/package/pipes-2.4.0/docs/Control-MFunctor.html), - but not restricted to monad transformers. - Alternatively, an implementation of [MonadTransFunctor](http://duairc.netsoc.ie/layers-docs/Control-Monad-Layer.html#t:MonadTransFunctor). -/ -class MonadFunctor (m : Type u → Type v) (n : Type u → Type w) := - (monadMap {α : Type u} : (∀ {β}, m β → m β) → n α → n α) - -/-- The reflexive-transitive closure of `MonadFunctor`. - `monadMap` is used to transitively lift Monad morphisms -/ -class MonadFunctorT (m : Type u → Type v) (n : Type u → Type w) := - (monadMap {α : Type u} : (∀ {β}, m β → m β) → n α → n α) - -export MonadFunctorT (monadMap) - -instance (m n o) [MonadFunctorT m n] [MonadFunctor n o] : MonadFunctorT m o := { - monadMap := fun f => MonadFunctor.monadMap (m := n) (monadMap (m := m) f) -} - -instance monadFunctorRefl (m) : MonadFunctorT m m := { - monadMap := fun f => f -} - -inductive Except (ε : Type u) (α : Type v) - | error : ε → Except ε α - | ok : α → Except ε α - -attribute [unbox] Except - -instance {ε : Type u} {α : Type v} [Inhabited ε] : Inhabited (Except ε α) := - ⟨Except.error (arbitrary ε)⟩ - -/-- An implementation of [MonadError](https://hackage.haskell.org/package/mtl-2.2.2/docs/Control-Monad-Except.html#t:MonadError) -/ -class MonadExceptOf (ε : Type u) (m : Type v → Type w) := - (throw {α : Type v} : ε → m α) - (tryCatch {α : Type v} : m α → (ε → m α) → m α) - -abbrev throwThe (ε : Type u) {m : Type v → Type w} [MonadExceptOf ε m] {α : Type v} (e : ε) : m α := - MonadExceptOf.throw e - -abbrev tryCatchThe (ε : Type u) {m : Type v → Type w} [MonadExceptOf ε m] {α : Type v} (x : m α) (handle : ε → m α) : m α := - MonadExceptOf.tryCatch x handle - -/-- Similar to `MonadExceptOf`, but `ε` is an outParam for convenience -/ -class MonadExcept (ε : outParam (Type u)) (m : Type v → Type w) := - (throw {α : Type v} : ε → m α) - (tryCatch {α : Type v} : m α → (ε → m α) → m α) - -export MonadExcept (throw tryCatch) - -instance (ε : outParam (Type u)) (m : Type v → Type w) [MonadExceptOf ε m] : MonadExcept ε m := { - throw := throwThe ε, - tryCatch := tryCatchThe ε -} - -namespace MonadExcept -variables {ε : Type u} {m : Type v → Type w} - -@[inline] protected def orelse [MonadExcept ε m] {α : Type v} (t₁ t₂ : m α) : m α := - tryCatch t₁ fun _ => t₂ - -instance [MonadExcept ε m] {α : Type v} : OrElse (m α) := ⟨MonadExcept.orelse⟩ - -end MonadExcept - -/-- An implementation of [ReaderT](https://hackage.haskell.org/package/transformers-0.5.5.0/docs/Control-Monad-Trans-Reader.html#t:ReaderT) -/ -def ReaderT (ρ : Type u) (m : Type u → Type v) (α : Type u) : Type (max u v) := - ρ → m α - -instance (ρ : Type u) (m : Type u → Type v) (α : Type u) [Inhabited (m α)] : Inhabited (ReaderT ρ m α) := - ⟨fun _ => arbitrary _⟩ - -@[inline] def ReaderT.run {ρ : Type u} {m : Type u → Type v} {α : Type u} (x : ReaderT ρ m α) (r : ρ) : m α := - x r - -@[reducible] def Reader (ρ : Type u) := ReaderT ρ id - -namespace ReaderT - -section -variables {ρ : Type u} {m : Type u → Type v} {α : Type u} - -@[inline] protected def lift (a : m α) : ReaderT ρ m α := - fun r => a - -instance : MonadLift m (ReaderT ρ m) := ⟨ReaderT.lift⟩ - -instance (ε) [MonadExceptOf ε m] : MonadExceptOf ε (ReaderT ρ m) := { - throw := Function.comp ReaderT.lift (throwThe ε), - tryCatch := fun x c r => tryCatchThe ε (x r) (fun e => (c e) r) -} - -end - -section -variables {ρ : Type u} {m : Type u → Type v} [Monad m] {α β : Type u} - -@[inline] protected def read : ReaderT ρ m ρ := - pure - -@[inline] protected def pure (a : α) : ReaderT ρ m α := - fun r => pure a - -@[inline] protected def bind (x : ReaderT ρ m α) (f : α → ReaderT ρ m β) : ReaderT ρ m β := - fun r => bind (x r) fun a => f a r - -@[inline] protected def map (f : α → β) (x : ReaderT ρ m α) : ReaderT ρ m β := - fun r => Functor.map f (x r) - -instance : Monad (ReaderT ρ m) := { - pure := ReaderT.pure, - bind := ReaderT.bind, - map := ReaderT.map -} - -instance (ρ m) [Monad m] : MonadFunctor m (ReaderT ρ m) := ⟨fun f x r => f (x r)⟩ - -@[inline] protected def adapt {ρ' : Type u} [Monad m] {α : Type u} (f : ρ' → ρ) : ReaderT ρ m α → ReaderT ρ' m α := - fun x r => x (f r) - -end -end ReaderT - -/-- An implementation of [MonadReader](https://hackage.haskell.org/package/mtl-2.2.2/docs/Control-Monad-Reader-Class.html#t:MonadReader). - It does not contain `local` because this Function cannot be lifted using `monadLift`. - Instead, the `MonadReaderAdapter` class provides the more general `adaptReader` Function. - - Note: This class can be seen as a simplification of the more "principled" definition - ``` - class MonadReader (ρ : outParam (Type u)) (n : Type u → Type u) := - (lift {α : Type u} : (∀ {m : Type u → Type u} [Monad m], ReaderT ρ m α) → n α) - ``` - -/ -class MonadReaderOf (ρ : Type u) (m : Type u → Type v) := - (read : m ρ) - -@[inline] def readThe (ρ : Type u) {m : Type u → Type v} [MonadReaderOf ρ m] : m ρ := - MonadReaderOf.read - -/-- Similar to `MonadReaderOf`, but `ρ` is an outParam for convenience -/ -class MonadReader (ρ : outParam (Type u)) (m : Type u → Type v) := - (read : m ρ) - -export MonadReader (read) - -instance (ρ : Type u) (m : Type u → Type v) [MonadReaderOf ρ m] : MonadReader ρ m := - ⟨readThe ρ⟩ - -instance {ρ : Type u} {m : Type u → Type v} {n : Type u → Type w} [MonadReaderOf ρ m] [MonadLift m n] : MonadReaderOf ρ n := - ⟨monadLift (MonadReader.read : m ρ)⟩ - -instance {ρ : Type u} {m : Type u → Type v} [Monad m] : MonadReaderOf ρ (ReaderT ρ m) := - ⟨ReaderT.read⟩ - -class MonadWithReaderOf (ρ : Type u) (m : Type u → Type v) := - (withReader {α : Type u} : (ρ → ρ) → m α → m α) - -@[inline] def withTheReader (ρ : Type u) {m : Type u → Type v} [MonadWithReaderOf ρ m] {α : Type u} (f : ρ → ρ) (x : m α) : m α := - MonadWithReaderOf.withReader f x - -class MonadWithReader (ρ : outParam (Type u)) (m : Type u → Type v) := - (withReader {α : Type u} : (ρ → ρ) → m α → m α) - -export MonadWithReader (withReader) - -instance (ρ : Type u) (m : Type u → Type v) [MonadWithReaderOf ρ m] : MonadWithReader ρ m := ⟨withTheReader ρ⟩ - -instance {ρ : Type u} {m : Type u → Type v} {n : Type u → Type v} [MonadWithReaderOf ρ m] [MonadFunctor m n] : MonadWithReaderOf ρ n := - ⟨fun f => monadMap (m := m) (withTheReader ρ f)⟩ - -instance {ρ : Type u} {m : Type u → Type v} [Monad m] : MonadWithReaderOf ρ (ReaderT ρ m) := - ⟨fun f x ctx => x (f ctx)⟩ - -/-- An implementation of [MonadState](https://hackage.haskell.org/package/mtl-2.2.2/docs/Control-Monad-State-Class.html). - In contrast to the Haskell implementation, we use overlapping instances to derive instances - automatically from `monadLift`. -/ -class MonadStateOf (σ : Type u) (m : Type u → Type v) := - /- Obtain the top-most State of a Monad stack. -/ - (get : m σ) - /- Set the top-most State of a Monad stack. -/ - (set : σ → m PUnit) - /- Map the top-most State of a Monad stack. - - Note: `modifyGet f` may be preferable to `do s <- get; let (a, s) := f s; put s; pure a` - because the latter does not use the State linearly (without sufficient inlining). -/ - (modifyGet {α : Type u} : (σ → α × σ) → m α) - -export MonadStateOf (set) - -abbrev getThe (σ : Type u) {m : Type u → Type v} [MonadStateOf σ m] : m σ := - MonadStateOf.get - -@[inline] abbrev modifyThe (σ : Type u) {m : Type u → Type v} [MonadStateOf σ m] (f : σ → σ) : m PUnit := - MonadStateOf.modifyGet fun s => (PUnit.unit, f s) - -@[inline] abbrev modifyGetThe {α : Type u} (σ : Type u) {m : Type u → Type v} [MonadStateOf σ m] (f : σ → α × σ) : m α := - MonadStateOf.modifyGet f - -/-- Similar to `MonadStateOf`, but `σ` is an outParam for convenience -/ -class MonadState (σ : outParam (Type u)) (m : Type u → Type v) := - (get : m σ) - (set : σ → m PUnit) - (modifyGet {α : Type u} : (σ → α × σ) → m α) - -export MonadState (get modifyGet) - -instance (σ : Type u) (m : Type u → Type v) [MonadStateOf σ m] : MonadState σ m := { - set := MonadStateOf.set, - get := getThe σ, - modifyGet := fun f => MonadStateOf.modifyGet f -} - -@[inline] def modify {σ : Type u} {m : Type u → Type v} [MonadState σ m] (f : σ → σ) : m PUnit := - modifyGet fun s => (PUnit.unit, f s) - -@[inline] def getModify {σ : Type u} {m : Type u → Type v} [MonadState σ m] [Monad m] (f : σ → σ) : m σ := - modifyGet fun s => (s, f s) - --- NOTE: The Ordering of the following two instances determines that the top-most `StateT` Monad layer --- will be picked first -instance {σ : Type u} {m : Type u → Type v} {n : Type u → Type w} [MonadStateOf σ m] [MonadLift m n] : MonadStateOf σ n := { - get := liftM (m := m) MonadStateOf.get, - set := fun s => liftM (m := m) (MonadStateOf.set s), - modifyGet := fun f => monadLift (m := m) (MonadState.modifyGet f) -} - -namespace EStateM - -inductive Result (ε σ α : Type u) - | ok : α → σ → Result ε σ α - | error : ε → σ → Result ε σ α - -variables {ε σ α : Type u} - -instance [Inhabited ε] [Inhabited σ] : Inhabited (Result ε σ α) := ⟨Result.error (arbitrary _) (arbitrary _)⟩ - -end EStateM - -open EStateM (Result) in -def EStateM (ε σ α : Type u) := σ → Result ε σ α - -namespace EStateM - -variables {ε σ α β : Type u} - -instance [Inhabited ε] : Inhabited (EStateM ε σ α) := ⟨fun s => - Result.error (arbitrary ε) s⟩ - -@[inline] protected def pure (a : α) : EStateM ε σ α := fun s => - Result.ok a s - -@[inline] protected def set (s : σ) : EStateM ε σ PUnit := fun _ => - Result.ok ⟨⟩ s - -@[inline] protected def get : EStateM ε σ σ := fun s => - Result.ok s s - -@[inline] protected def modifyGet (f : σ → α × σ) : EStateM ε σ α := fun s => - match f s with - | (a, s) => Result.ok a s - -@[inline] protected def throw (e : ε) : EStateM ε σ α := fun s => - Result.error e s - -/-- Auxiliary instance for saving/restoring the "backtrackable" part of the state. -/ -class Backtrackable (δ : outParam (Type u)) (σ : Type u) := - (save : σ → δ) - (restore : σ → δ → σ) - -@[inline] protected def tryCatch {δ} [Backtrackable δ σ] {α} (x : EStateM ε σ α) (handle : ε → EStateM ε σ α) : EStateM ε σ α := fun s => - let d := Backtrackable.save s - match x s with - | Result.error e s => handle e (Backtrackable.restore s d) - | ok => ok - -@[inline] protected def orElse {δ} [Backtrackable δ σ] (x₁ x₂ : EStateM ε σ α) : EStateM ε σ α := fun s => - let d := Backtrackable.save s; - match x₁ s with - | Result.error _ s => x₂ (Backtrackable.restore s d) - | ok => ok - -@[inline] def adaptExcept {ε' : Type u} (f : ε → ε') (x : EStateM ε σ α) : EStateM ε' σ α := fun s => - match x s with - | Result.error e s => Result.error (f e) s - | Result.ok a s => Result.ok a s - -@[inline] protected def bind (x : EStateM ε σ α) (f : α → EStateM ε σ β) : EStateM ε σ β := fun s => - match x s with - | Result.ok a s => f a s - | Result.error e s => Result.error e s - -@[inline] protected def map (f : α → β) (x : EStateM ε σ α) : EStateM ε σ β := fun s => - match x s with - | Result.ok a s => Result.ok (f a) s - | Result.error e s => Result.error e s - -@[inline] protected def seqRight (x : EStateM ε σ PUnit) (y : EStateM ε σ β) : EStateM ε σ β := fun s => - match x s with - | Result.ok _ s => y s - | Result.error e s => Result.error e s - -instance : Monad (EStateM ε σ) := { - bind := EStateM.bind, - pure := EStateM.pure, - map := EStateM.map, - seqRight := EStateM.seqRight -} - -instance {δ} [Backtrackable δ σ] : OrElse (EStateM ε σ α) := { - orElse := EStateM.orElse -} - -instance : MonadStateOf σ (EStateM ε σ) := { - set := EStateM.set, - get := EStateM.get, - modifyGet := EStateM.modifyGet -} - -instance {δ} [Backtrackable δ σ] : MonadExceptOf ε (EStateM ε σ) := { - throw := EStateM.throw, - tryCatch := EStateM.tryCatch -} - -@[inline] def run (x : EStateM ε σ α) (s : σ) : Result ε σ α := - x s - -@[inline] def run' (x : EStateM ε σ α) (s : σ) : Option α := - match run x s with - | Result.ok v _ => some v - | Result.error _ _ => none - -@[inline] def dummySave : σ → PUnit := fun _ => ⟨⟩ - -@[inline] def dummyRestore : σ → PUnit → σ := fun s _ => s - -/- Dummy default instance -/ -instance nonBacktrackable : Backtrackable PUnit σ := { - save := dummySave, - restore := dummyRestore -} - -end EStateM - -class Hashable (α : Type u) := - (hash : α → USize) - -export Hashable (hash) - -@[extern "lean_usize_mix_hash"] -constant mixHash (u₁ u₂ : USize) : USize - -@[extern "lean_string_hash"] -protected constant String.hash (s : @& String) : USize - -instance : Hashable String := ⟨String.hash⟩ - -namespace Lean - -/- Hierarchical names -/ -inductive Name - | anonymous : Name - | str : Name → String → USize → Name - | num : Name → Nat → USize → Name - -instance : Inhabited Name := ⟨Name.anonymous⟩ - -protected def Name.hash : Name → USize - | Name.anonymous => USize.ofNat32 1723 decide! - | Name.str p s h => h - | Name.num p v h => h - -instance : Hashable Name := ⟨Name.hash⟩ - -@[export lean_name_mk_string] -def mkNameStr (p : Name) (s : String) : Name := - Name.str p s (mixHash (hash p) (hash s)) - -@[export lean_name_mk_numeral] -def mkNameNum (p : Name) (v : Nat) : Name := - Name.num p v (mixHash (hash p) (if h : Less v usizeSz then USize.ofNatCore v h else USize.ofNat32 17 decide!)) - -def mkNameSimple (s : String) : Name := - mkNameStr Name.anonymous s - -namespace Name -@[extern "lean_name_eq"] -protected def beq : (@& Name) → (@& Name) → Bool - | anonymous, anonymous => true - | str p₁ s₁ _, str p₂ s₂ _ => BEq.beq s₁ s₂ && Name.beq p₁ p₂ - | num p₁ n₁ _, num p₂ n₂ _ => BEq.beq n₁ n₂ && Name.beq p₁ p₂ - | _, _ => false - -instance : BEq Name := ⟨Name.beq⟩ - -protected def append : Name → Name → Name - | n, anonymous => n - | n, str p s _ => mkNameStr (Name.append n p) s - | n, num p d _ => mkNameNum (Name.append n p) d - -instance : Append Name := ⟨Name.append⟩ - -end Name - -/- Syntax -/ - -/-- - Source information of syntax atoms. All information is generally set for unquoted syntax and unset for syntax in - syntax quotations, but syntax transformations might want to invalidate only one side to make the pretty printer - reformat it. In the special case of the delaborator, we also use purely synthetic position information without - whitespace information. -/ -structure SourceInfo := - /- Will be inferred after parsing by `Syntax.updateLeading`. During parsing, - it is not at all clear what the preceding token was, especially with backtracking. -/ - (leading : Option Substring := none) - (pos : Option String.Pos := none) - (trailing : Option Substring := none) - -instance : Inhabited SourceInfo := ⟨{}⟩ - -abbrev SyntaxNodeKind := Name - -/- Syntax AST -/ - -inductive Syntax - | missing : Syntax - | node (kind : SyntaxNodeKind) (args : Array Syntax) : Syntax - | atom (info : SourceInfo) (val : String) : Syntax - | ident (info : SourceInfo) (rawVal : Substring) (val : Name) (preresolved : List (Prod Name (List String))) : Syntax - -instance : Inhabited Syntax := ⟨Syntax.missing⟩ - -/- Builtin kinds -/ -def choiceKind : SyntaxNodeKind := `choice -def nullKind : SyntaxNodeKind := `null -def identKind : SyntaxNodeKind := `ident -def strLitKind : SyntaxNodeKind := `strLit -def charLitKind : SyntaxNodeKind := `charLit -def numLitKind : SyntaxNodeKind := `numLit -def nameLitKind : SyntaxNodeKind := `nameLit -def fieldIdxKind : SyntaxNodeKind := `fieldIdx -def interpolatedStrLitKind : SyntaxNodeKind := `interpolatedStrLitKind -def interpolatedStrKind : SyntaxNodeKind := `interpolatedStrKind - -namespace Syntax - -def getKind (stx : Syntax) : SyntaxNodeKind := - match stx with - | Syntax.node k args => k - -- We use these "pseudo kinds" for antiquotation kinds. - -- For example, an antiquotation `$id:ident` (using Lean.Parser.Term.ident) - -- is compiled to ``if stx.isOfKind `ident ...`` - | Syntax.missing => `missing - | Syntax.atom _ v => mkNameSimple v - | Syntax.ident _ _ _ _ => identKind - -def setKind (stx : Syntax) (k : SyntaxNodeKind) : Syntax := - match stx with - | Syntax.node _ args => Syntax.node k args - | _ => stx - -def isOfKind (stx : Syntax) (k : SyntaxNodeKind) : Bool := - beq stx.getKind k - -def getArg (stx : Syntax) (i : Nat) : Syntax := - match stx with - | Syntax.node _ args => args.get! i - | _ => Syntax.missing -- panic! "Syntax.getArg: not a node" - --- Add `stx[i]` as sugar for `stx.getArg i` -@[inline] def getOp (self : Syntax) (idx : Nat) : Syntax := - self.getArg idx - -def getArgs (stx : Syntax) : Array Syntax := - match stx with - | Syntax.node _ args => args - | _ => Array.empty - -end Syntax - -inductive ParserDescr - | andthen : ParserDescr → ParserDescr → ParserDescr - | orelse : ParserDescr → ParserDescr → ParserDescr - | optional : ParserDescr → ParserDescr - | lookahead : ParserDescr → ParserDescr - | «try» : ParserDescr → ParserDescr - | many : ParserDescr → ParserDescr - | many1 : ParserDescr → ParserDescr - | sepBy : ParserDescr → ParserDescr → Bool → ParserDescr - | sepBy1 : ParserDescr → ParserDescr → Bool → ParserDescr - | node : Name → Nat → ParserDescr → ParserDescr - | trailingNode : Name → Nat → ParserDescr → ParserDescr - | symbol : String → ParserDescr - | nonReservedSymbol : String → Bool → ParserDescr - | noWs : ParserDescr - | numLit : ParserDescr - | strLit : ParserDescr - | charLit : ParserDescr - | nameLit : ParserDescr - | interpolatedStr : ParserDescr → ParserDescr -- interpolated string - | ident : ParserDescr - | cat : Name → Nat → ParserDescr - | parser : Name → ParserDescr - | notFollowedBy : ParserDescr → ParserDescr - | withPosition : ParserDescr → ParserDescr - | checkCol : Bool → ParserDescr - -instance : Inhabited ParserDescr := ⟨ParserDescr.symbol ""⟩ -abbrev TrailingParserDescr := ParserDescr - -/- -Runtime support for making quotation terms auto-hygienic, by mangling identifiers -introduced by them with a "macro scope" supplied by the context. Details to appear in a -paper soon. --/ - -abbrev MacroScope := Nat -/-- Macro scope used internally. It is not available for our frontend. -/ -def reservedMacroScope := 0 -/-- First macro scope available for our frontend -/ -def firstFrontendMacroScope := add reservedMacroScope 1 - -/-- A monad that supports syntax quotations. Syntax quotations (in term - position) are monadic values that when executed retrieve the current "macro - scope" from the monad and apply it to every identifier they introduce - (independent of whether this identifier turns out to be a reference to an - existing declaration, or an actually fresh binding during further - elaboration). -/ -class MonadQuotation (m : Type → Type) := - -- Get the fresh scope of the current macro invocation - (getCurrMacroScope : m MacroScope) - (getMainModule : m Name) - /- Execute action in a new macro invocation context. This transformer should be - used at all places that morally qualify as the beginning of a "macro call", - e.g. `elabCommand` and `elabTerm` in the case of the elaborator. However, it - can also be used internally inside a "macro" if identifiers introduced by - e.g. different recursive calls should be independent and not collide. While - returning an intermediate syntax tree that will recursively be expanded by - the elaborator can be used for the same effect, doing direct recursion inside - the macro guarded by this transformer is often easier because one is not - restricted to passing a single syntax tree. Modelling this helper as a - transformer and not just a monadic action ensures that the current macro - scope before the recursive call is restored after it, as expected. -/ - (withFreshMacroScope {α : Type} : m α → m α) - -export MonadQuotation (getCurrMacroScope getMainModule withFreshMacroScope) - -instance {m n : Type → Type} [MonadQuotation m] [MonadLift m n] [MonadFunctorT m n] : MonadQuotation n := { - getCurrMacroScope := liftM (m := m) getCurrMacroScope, - getMainModule := liftM (m := m) getMainModule, - withFreshMacroScope := monadMap (m := m) withFreshMacroScope -} - -/- -We represent a name with macro scopes as -``` -._@.(.)*.._hyg. -``` -Example: suppose the module name is `Init.Data.List.Basic`, and name is `foo.bla`, and macroscopes [2, 5] -``` -foo.bla._@.Init.Data.List.Basic._hyg.2.5 -``` - -We may have to combine scopes from different files/modules. -The main modules being processed is always the right most one. -This situation may happen when we execute a macro generated in -an imported file in the current file. -``` -foo.bla._@.Init.Data.List.Basic.2.1.Init.Lean.Expr_hyg.4 -``` - -The delimiter `_hyg` is used just to improve the `hasMacroScopes` performance. --/ - -def Name.hasMacroScopes : Name → Bool - | str _ s _ => beq s "_hyg" - | num p _ _ => hasMacroScopes p - | _ => false - -private def eraseMacroScopesAux : Name → Name - | Name.str p s _ => if s = "_@" then p else eraseMacroScopesAux p - | Name.num p _ _ => eraseMacroScopesAux p - | Name.anonymous => Name.anonymous - -@[export lean_erase_macro_scopes] -def Name.eraseMacroScopes (n : Name) : Name := - match n.hasMacroScopes with - | true => eraseMacroScopesAux n - | false => n - -private def simpMacroScopesAux : Name → Name - | Name.num p i _ => mkNameNum (simpMacroScopesAux p) i - | n => eraseMacroScopesAux n - -/- Helper function we use to create binder names that do not need to be unique. -/ -@[export lean_simp_macro_scopes] -def Name.simpMacroScopes (n : Name) : Name := - match n.hasMacroScopes with - | true => simpMacroScopesAux n - | false => n - -structure MacroScopesView := - (name : Name) - (imported : Name) - (mainModule : Name) - (scopes : List MacroScope) - -instance : Inhabited MacroScopesView := ⟨⟨arbitrary _, arbitrary _, arbitrary _, arbitrary _⟩⟩ - -def MacroScopesView.review (view : MacroScopesView) : Name := - match view.scopes with - | List.nil => view.name - | List.cons _ _ => - let base := (mkNameStr (append (append (mkNameStr view.name "_@") view.imported) view.mainModule) "_hyg") - view.scopes.foldl mkNameNum base - -private def assembleParts : List Name → Name → Name - | List.nil, acc => acc - | List.cons (Name.str _ s _) ps, acc => assembleParts ps (mkNameStr acc s) - | List.cons (Name.num _ n _) ps, acc => assembleParts ps (mkNameNum acc n) - | _, acc => panic "unreachable @ assembleParts" - -private def extractImported (scps : List MacroScope) (mainModule : Name) : Name → List Name → MacroScopesView - | n@(Name.str p str _), parts => - if str = "_@" then - { name := p, mainModule := mainModule, imported := assembleParts parts Name.anonymous, scopes := scps } - else - extractImported scps mainModule p (List.cons n parts) - | n@(Name.num p str _), parts => extractImported scps mainModule p (List.cons n parts) - | _, _ => panic "unreachable @ extractImported" - -private def extractMainModule (scps : List MacroScope) : Name → List Name → MacroScopesView - | n@(Name.str p str _), parts => - if str = "_@" then - { name := p, mainModule := assembleParts parts Name.anonymous, imported := Name.anonymous, scopes := scps } - else - extractMainModule scps p (List.cons n parts) - | n@(Name.num p num _), acc => extractImported scps (assembleParts acc Name.anonymous) n List.nil - | _, _ => panic "unreachable @ extractMainModule" - -private def extractMacroScopesAux : Name → List MacroScope → MacroScopesView - | Name.num p scp _, acc => extractMacroScopesAux p (List.cons scp acc) - | Name.str p str _, acc => extractMainModule acc p List.nil -- str must be "_hyg" - | _, _ => panic "unreachable @ extractMacroScopesAux" - -/-- - Revert all `addMacroScope` calls. `v = extractMacroScopes n → n = v.review`. - This operation is useful for analyzing/transforming the original identifiers, then adding back - the scopes (via `MacroScopesView.review`). -/ -def extractMacroScopes (n : Name) : MacroScopesView := - match n.hasMacroScopes with - | true => extractMacroScopesAux n List.nil - | false => { name := n, scopes := List.nil, imported := Name.anonymous, mainModule := Name.anonymous } - -def addMacroScope (mainModule : Name) (n : Name) (scp : MacroScope) : Name := - match n.hasMacroScopes with - | true => - let view := extractMacroScopes n - match beq view.mainModule mainModule with - | true => mkNameNum n scp - | false => - { view with - imported := view.scopes.foldl mkNameNum (append view.imported view.mainModule), - mainModule := mainModule, - scopes := List.cons scp List.nil - }.review - | false => - mkNameNum (mkNameStr (append (mkNameStr n "_@") mainModule) "_hyg") scp - -@[inline] def MonadQuotation.addMacroScope {m : Type → Type} [MonadQuotation m] [Monad m] (n : Name) : m Name := - bind getMainModule fun mainModule => - bind getCurrMacroScope fun scp => - pure (Lean.addMacroScope mainModule n scp) - -def defaultMaxRecDepth := 512 - -def maxRecDepthErrorMessage : String := - "maximum recursion depth has been reached (use `set_option maxRecDepth ` to increase limit)" - -namespace Macro - -/- References -/ -constant MacroEnvPointed : PointedType.{0} - -def MacroEnv : Type := MacroEnvPointed.type -instance : Inhabited MacroEnv := ⟨MacroEnvPointed.val⟩ - -structure Context := - (macroEnv : MacroEnv) - (mainModule : Name) - (currMacroScope : MacroScope) - (currRecDepth : Nat := 0) - (maxRecDepth : Nat := defaultMaxRecDepth) - -inductive Exception - | error : Syntax → String → Exception - | unsupportedSyntax : Exception - -end Macro - -abbrev MacroM := ReaderT Macro.Context (EStateM Macro.Exception MacroScope) - -abbrev Macro := Syntax → MacroM Syntax - -namespace Macro - -def addMacroScope (n : Name) : MacroM Name := - bind read fun ctx => - pure (Lean.addMacroScope ctx.mainModule n ctx.currMacroScope) - -def throwUnsupported {α} : MacroM α := - throw Exception.unsupportedSyntax - -def throwError {α} (ref : Syntax) (msg : String) : MacroM α := - throw (Exception.error ref msg) - -@[inline] protected def withFreshMacroScope {α} (x : MacroM α) : MacroM α := - bind (modifyGet (fun s => (s, add s 1))) fun fresh => - withReader (fun ctx => { ctx with currMacroScope := fresh }) x - -@[inline] def withIncRecDepth {α} (ref : Syntax) (x : MacroM α) : MacroM α := - bind read fun ctx => - if ctx.currRecDepth = ctx.maxRecDepth then - throw (Exception.error ref maxRecDepthErrorMessage) - else - withReader (fun ctx => { ctx with currRecDepth := add ctx.currRecDepth 1 }) x - -instance : MonadQuotation MacroM := { - getCurrMacroScope := fun ctx => pure ctx.currMacroScope, - getMainModule := fun ctx => pure ctx.mainModule, - withFreshMacroScope := Macro.withFreshMacroScope -} - -unsafe def mkMacroEnvImp (expandMacro? : Syntax → MacroM (Option Syntax)) : MacroEnv := - unsafeCast expandMacro? - -@[implementedBy mkMacroEnvImp] -constant mkMacroEnv (expandMacro? : Syntax → MacroM (Option Syntax)) : MacroEnv - -def expandMacroNotAvailable? (stx : Syntax) : MacroM (Option Syntax) := - throwError stx "expandMacro has not been set" - -def mkMacroEnvSimple : MacroEnv := - mkMacroEnv expandMacroNotAvailable? - -unsafe def expandMacro?Imp (stx : Syntax) : MacroM (Option Syntax) := - bind read fun ctx => - let f : Syntax → MacroM (Option Syntax) := unsafeCast (ctx.macroEnv) - f stx - -/-- `expandMacro? stx` return `some stxNew` if `stx` is a macro, and `stxNew` is its expansion. -/ -@[implementedBy expandMacro?Imp] constant expandMacro? : Syntax → MacroM (Option Syntax) - -end Macro - -export Macro (expandMacro?) - -end Lean - -syntax "foo" term : term - -macro_rules - | `(foo $x) => x - -#check foo 10 diff --git a/tmp/eqns/depelim.lean b/tmp/eqns/depelim.lean deleted file mode 100644 index 518aed35bf..0000000000 --- a/tmp/eqns/depelim.lean +++ /dev/null @@ -1,81 +0,0 @@ -import Init.Lean - -open Lean - -inductive Pattern -| Inaccessible (e : Expr) -| Var (fvarId : FVarId) -| Ctor (fields : List Pattern) -| Val (e : Expr) -| ArrayLit (xs : List Pattern) - -structure AltLHS := -(fvarIds : List FVarId) -- free variables used in the patterns -(patterns : List Pattern) -- We use `List Pattern` since we have nary match-expressions. - -abbrev AltToMinorsMap := PersistentHashMap Nat (List Nat) - -structure ElimResult := -(numMinors : Nat) -- It is the number of alternatives (Reason: support for overlapping equations) -(numEqs : Nat) -- It is the number of minors (Reason: users may want equations that hold definitionally) -(elim : Expr) -- The eliminator. It is not just `Expr.const elimName` because the type of the major premises may contain free variables. -(altMap : AltToMinorsMap) -- each alternative may be "expanded" into multiple minor premise - - -/- -Given a list of major premises `xs` and alternative left-hand-sides, generate an elimination -principle with name `elimName` and equation lemmas for it. --/ --- def mkElim (elimName : Name) (xs : List FVarId) (lhss : List AltLHS) : MetaM ElimResult := --- sorry - -universes u v - -inductive Vec (α : Type u) : Nat → Type u -| nil {} : Vec 0 -| cons : α → forall {n : Nat}, Vec n → Vec (n+1) - -def Vec.elim {α : Type u} (C : forall (n : Nat), Vec α n → Vec α n → Sort v) {n : Nat} (v w : Vec α n) - (h₁ : Unit → C 0 Vec.nil Vec.nil) - (h₂ : forall (hdv : α) (n : Nat) (tlv : Vec α n) (hdw : α) (tlw : Vec α n), C (n+1) (Vec.cons hdv tlv) (Vec.cons hdw tlw)) - : C n v w := -match n, v, w with -| .(0), Vec.nil, Vec.nil => h₁ () -| .(n+1), @Vec.cons .(α) hdv n tlv, @Vec.cons .(α) hdw .(n) tlw => h₂ hdv n tlv hdw tlw - -def Vec.elimHEq {α : Type u} (C : forall (n : Nat) (v w : Vec α n), Sort v) {n : Nat} (v w : Vec α n) - (h₁ : v ≅ @Vec.nil α → w ≅ @Vec.nil α → C 0 Vec.nil Vec.nil) - (h₂ : forall (hdv : α) (n : Nat) (tlv : Vec α n) (hdw : α) (tlw : Vec α n), v ≅ Vec.cons hdv tlv → w ≅ Vec.cons hdw tlw → C (n+1) (Vec.cons hdv tlv) (Vec.cons hdw tlw)) - : C n v w := -Vec.elim (fun n' v' w' => v ≅ v' → w ≅ w' → C n' v' w') v w - (fun _ => h₁) - h₂ - (HEq.refl _) - (HEq.refl _) - -def Vec.elimEq {α : Type u} (C : forall (n : Nat) (v w : Vec α n), Sort v) {n : Nat} (v w : Vec α n) - (h₁ : forall (h : n = 0), (Eq.rec v h : Vec α 0) = Vec.nil → (Eq.rec w h : Vec α 0) = Vec.nil → C 0 Vec.nil Vec.nil) - (h₂ : forall (hdv : α) (n' : Nat) (tlv : Vec α n') - (hdw : α) (tlw : Vec α n') - (h : n = n' + 1), - (Eq.rec v h : Vec α (n'+1)) = Vec.cons hdv tlv → - (Eq.rec w h : Vec α (n'+1)) = Vec.cons hdw tlw → - C (n'+1) (Vec.cons hdv tlv) (Vec.cons hdw tlw)) - : C n v w := -Vec.elim (fun n' v' w' => forall (h : n = n'), (Eq.rec v h : Vec α n') = v' → (Eq.rec w h : Vec α n') = w' → C n' v' w') v w - (fun _ => h₁) - h₂ - rfl - rfl - rfl - -def List.elim {α : Type u} (C : List α → Sort v) (as : List α) - (h₁ : Unit → C []) - (h₂ : forall a, C [a]) - (h₃ : forall (a₁ : α) (as₁ : List α) (a₂ : α) (as₂ : List α), as₁ = a₂ :: as₂ → C (a₁::a₂::as₂)) - : C as := -List.casesOn as - (h₁ ()) - (fun a r => @List.casesOn _ (fun as => r = as → C (a::as)) r - (fun _ => h₂ a) - (fun b bs h => h₃ a r b bs h) rfl) diff --git a/tmp/eqns/elim1.lean b/tmp/eqns/elim1.lean deleted file mode 100644 index 996c23f5de..0000000000 --- a/tmp/eqns/elim1.lean +++ /dev/null @@ -1,140 +0,0 @@ -universes u v - -inductive Foo (α : Type u) -| leaf (a : α) : Foo -| node (left : Foo) (right : Foo) : Foo -| cons (head : α) (tail : Foo) : Foo - -def Foo.elim {α : Type u} (C : Foo α → Foo α → Sort v) (x y : Foo α) - (h₁ : forall (a₁ a₂ : α), C (Foo.leaf a₁) (Foo.leaf a₂)) - (h₂ : forall (l₁ r₁ l₂ r₂ : Foo α), C (Foo.node l₁ r₁) (Foo.node l₂ r₂)) - (h₃ : forall (h₁ t₁ h₂ t₂), C (Foo.cons h₁ t₁) (Foo.cons h₂ t₂)) - (h₄ : forall (x y), C x y) - : C x y := -Foo.casesOn x - (fun a₁ => Foo.casesOn y - (fun a₂ => h₁ a₁ a₂) - (fun l₂ r₂ => h₄ (Foo.leaf a₁) (Foo.node l₂ r₂)) - (fun h₂ t₂ => h₄ (Foo.leaf a₁) (Foo.cons h₂ t₂))) - (fun l₁ r₁ => Foo.casesOn y - (fun a₂ => h₄ (Foo.node l₁ r₁) (Foo.leaf a₂)) - (fun l₂ r₂ => h₂ l₁ r₁ l₂ r₂) - (fun h₂ t₂ => h₄ (Foo.node l₁ r₁) (Foo.cons h₂ t₂))) - (fun h₁ t₁ => Foo.casesOn y - (fun a₂ => h₄ (Foo.cons h₁ t₁) (Foo.leaf a₂)) - (fun l₂ r₂ => h₄ (Foo.cons h₁ t₁) (Foo.node l₂ r₂)) - (fun h₂ t₂ => h₃ h₁ t₁ h₂ t₂)) - -def f : List Nat → List Nat → List Nat -| x::xs, _ => [] -| _, [] => [] -| xs, ys => xs ++ ys - -def List.elim (C : List Nat → List Nat → Sort v) (xs ys : List Nat) - (h₁ : forall x xs ys, C (x::xs) ys) - (h₂ : forall xs, C xs []) - (h₃ : forall xs ys, C xs ys) - : C xs ys := -List.casesOn xs - (List.casesOn ys - (h₂ []) - (fun y ys => h₃ [] (y::ys))) - (fun x xs => h₁ x xs ys) - -theorem List.elim.eq1 (C : List Nat → List Nat → Sort v) - (h₁ : forall x xs ys, C (x::xs) ys) - (h₂ : forall xs, C xs []) - (h₃ : forall xs ys, C xs ys) - (x : Nat) (xs ys : List Nat) - : List.elim C (x::xs) ys h₁ h₂ h₃ = h₁ x xs ys := -rfl - -theorem List.elim.eq2 (C : List Nat → List Nat → Sort v) - (h₁ : forall x xs ys, C (x::xs) ys) - (h₂ : forall xs, C xs []) - (h₃ : forall xs ys, C xs ys) - (xs : List Nat) - : (forall x' xs', xs = x'::xs' → False) → List.elim C xs [] h₁ h₂ h₃ = h₂ xs := -List.casesOn xs - (fun _ => rfl) - (fun x xs h => False.elim (h x xs rfl)) - -theorem List.elim.eq3 (C : List Nat → List Nat → Sort v) - (h₁ : forall x xs ys, C (x::xs) ys) - (h₂ : forall xs, C xs []) - (h₃ : forall xs ys, C xs ys) - (xs : List Nat) (ys : List Nat) - : (forall x' xs', xs = x'::xs' → False) → (ys = [] → False) → List.elim C xs ys h₁ h₂ h₃ = h₃ xs ys := -List.casesOn xs - (List.casesOn ys - (fun _ h => False.elim (h rfl)) - (fun y ys _ _ => rfl)) - (fun x xs h _ => False.elim (h x xs rfl)) - -theorem List.elim.eq3.a (C : List Nat → List Nat → Sort v) - (h₁ : forall x xs ys, C (x::xs) ys) - (h₂ : forall xs, C xs []) - (h₃ : forall xs ys, C xs ys) - (y : Nat) (ys : List Nat) - : List.elim C [] (y::ys) h₁ h₂ h₃ = h₃ [] (y::ys) := -rfl - -def List.elim2 (C : List Nat → List Nat → Sort v) (xs ys : List Nat) - (h₁ : forall x xs ys, C (x::xs) ys) - (h₂ : forall xs, (forall (x' : Nat) (xs' : List Nat), xs = x' :: xs' → False) → C xs []) - (h₃ : forall xs ys, (forall (x' : Nat) (xs' : List Nat), xs = x' :: xs' → False) → (ys = [] → False) → C xs ys) - : C xs ys := -List.casesOn xs - (List.casesOn ys - (h₂ [] (fun _ _ h => List.noConfusion h)) - (fun y ys => h₃ [] (y::ys) (fun _ _ h => List.noConfusion h) (fun h => List.noConfusion h))) - (fun x xs => h₁ x xs ys) - -def List.elim3 (C : List Nat → List Nat → List Nat → Sort v) (xs ys zs : List Nat) - (h₁ : forall zs, C [] [] zs) - (h₂ : forall xs ys, C xs ys []) - (h₃ : forall xs ys zs, C xs ys zs) - : C xs ys zs := -List.casesOn xs - (List.casesOn ys - (h₁ zs) - (fun y ys => List.casesOn zs - (h₃ [] (y::ys) []) - (fun z zs => h₃ [] (y::ys) (z::zs)))) - (fun x xs => - (List.casesOn zs - (h₂ (x::xs) ys) - (fun z zs => h₃ (x::xs) ys (z::zs)))) - -theorem List.elim3.eq (C : List Nat → List Nat → List Nat → Sort v) - (h₁ : forall zs, C [] [] zs) - (h₂ : forall xs ys, C xs ys []) - (h₃ : forall xs ys zs, C xs ys zs) - (xs ys zs : List Nat) - : (xs = [] → ys = [] → False) → (zs = [] → False) → List.elim3 C xs ys zs h₁ h₂ h₃ = h₃ xs ys zs := -List.casesOn xs - (List.casesOn ys - (fun h _ => False.elim (h rfl rfl)) - (fun y ys => List.casesOn zs - (fun _ h => False.elim (h rfl)) - (fun z zs _ _ => rfl))) - (fun x xs => - List.casesOn zs - (fun _ h => False.elim (h rfl)) - (fun z zs _ _ => rfl)) - -theorem List.elim3.eq.a (C : List Nat → List Nat → List Nat → Sort v) - (h₁ : forall zs, C [] [] zs) - (h₂ : forall xs ys, C xs ys []) - (h₃ : forall xs ys zs, C xs ys zs) - (y : Nat) (ys : List Nat) (z : Nat) (zs : List Nat) - : List.elim3 C [] (y::ys) (z::zs) h₁ h₂ h₃ = h₃ [] (y::ys) (z::zs) := -rfl - -theorem List.elim3.eq.b (C : List Nat → List Nat → List Nat → Sort v) - (h₁ : forall zs, C [] [] zs) - (h₂ : forall xs ys, C xs ys []) - (h₃ : forall xs ys zs, C xs ys zs) - (x : Nat) (xs : List Nat) (y : Nat) (ys : List Nat) (z : Nat) (zs : List Nat) - : List.elim3 C (x::xs) (y::ys) (z::zs) h₁ h₂ h₃ = h₃ (x::xs) (y::ys) (z::zs) := -rfl diff --git a/tmp/eqns/matchArrayLit.lean b/tmp/eqns/matchArrayLit.lean deleted file mode 100644 index 349ccbf588..0000000000 --- a/tmp/eqns/matchArrayLit.lean +++ /dev/null @@ -1,193 +0,0 @@ -universes u v - -namespace Experiment1 -inductive ArrayLitMatch (α : Type u) -| sz0 {} : ArrayLitMatch -| sz1 (a₁ : α) : ArrayLitMatch -| sz2 (a₁ a₂ : α) : ArrayLitMatch -| sz3 (a₁ a₂ a₃ : α) : ArrayLitMatch -| other {} : ArrayLitMatch - -def matchArrayLit {α : Type u} (a : Array α) : ArrayLitMatch α := -if a.size = 0 then - ArrayLitMatch.sz0 -else if h : a.size = 1 then - ArrayLitMatch.sz1 (a.getLit 0 h (ofDecideEqTrue rfl)) -else if h : a.size = 2 then - ArrayLitMatch.sz2 (a.getLit 0 h (ofDecideEqTrue rfl)) (a.getLit 1 h (ofDecideEqTrue rfl)) -else if h : a.size = 3 then - ArrayLitMatch.sz3 (a.getLit 0 h (ofDecideEqTrue rfl)) (a.getLit 1 h (ofDecideEqTrue rfl)) (a.getLit 2 h (ofDecideEqTrue rfl)) -else - ArrayLitMatch.other - -def matchArrayLit.eq0 {α : Type u} : matchArrayLit (#[] : Array α) = ArrayLitMatch.sz0 := -rfl - -def matchArrayLit.eq1 {α : Type u} (a₁ : α) : matchArrayLit #[a₁] = ArrayLitMatch.sz1 a₁ := -rfl - -def matchArrayLit.eq2 {α : Type u} (a₁ a₂ : α) : matchArrayLit #[a₁, a₂] = ArrayLitMatch.sz2 a₁ a₂ := -rfl - -def matchArrayLit.eq3 {α : Type u} (a₁ a₂ a₃ : α) : matchArrayLit #[a₁, a₂, a₃] = ArrayLitMatch.sz3 a₁ a₂ a₃ := -rfl - -def matchArrayLit.eq4 {α : Type u} (a₁ a₂ a₃ a₄ : α) : matchArrayLit #[a₁, a₂, a₃, a₄] = ArrayLitMatch.other := -rfl -end Experiment1 - -def toListLitAux {α : Type u} (a : Array α) (n : Nat) (hsz : a.size = n) : ∀ (i : Nat), i ≤ a.size → List α → List α -| 0, hi, acc => acc -| (i+1), hi, acc => toListLitAux i (Nat.leOfSuccLe hi) (a.getLit i hsz (Nat.ltOfLtOfEq (Nat.ltOfLtOfLe (Nat.ltSuccSelf i) hi) hsz) :: acc) - -def toArrayLit {α : Type u} (a : Array α) (n : Nat) (hsz : a.size = n) : Array α := -List.toArray $ toListLitAux a n hsz n (hsz ▸ Nat.leRefl _) [] - -theorem toArrayLitEq {α : Type u} (a : Array α) (n : Nat) (hsz : a.size = n) : a = toArrayLit a n hsz := --- TODO: this is painful to prove without proper automation -sorry -/- -First, we need to prove -∀ i j acc, i ≤ a.size → (toListLitAux a n hsz (i+1) hi acc).index j = if j < i then a.getLit j hsz _ else acc.index (j - i) -by induction - -Base case is trivial -(j : Nat) (acc : List α) (hi : 0 ≤ a.size) - |- (toListLitAux a n hsz 0 hi acc).index j = if j < 0 then a.getLit j hsz _ else acc.index (j - 0) -... |- acc.index j = acc.index j - -Induction - -(j : Nat) (acc : List α) (hi : i+1 ≤ a.size) - |- (toListLitAux a n hsz (i+1) hi acc).index j = if j < i + 1 then a.getLit j hsz _ else acc.index (j - (i + 1)) - ... |- (toListLitAux a n hsz i hi' (a.getLit i hsz _ :: acc)).index j = if j < i + 1 then a.getLit j hsz _ else acc.index (j - (i + 1)) * by def - ... |- if j < i then a.getLit j hsz _ else (a.getLit i hsz _ :: acc).index (j-i) * by induction hypothesis - = - if j < i + 1 then a.getLit j hsz _ else acc.index (j - (i + 1)) -If j < i, then both are a.getLit j hsz _ -If j = i, then lhs reduces else-branch to (a.getLit i hsz _) and rhs is then-brachn (a.getLit i hsz _) -If j >= i + 1, we use - - j - i >= 1 > 0 - - (a::as).index k = as.index (k-1) If k > 0 - - j - (i + 1) = (j - i) - 1 - Then lhs = (a.getLit i hsz _ :: acc).index (j-i) = acc.index (j-i-1) = acc.index (j-(i+1)) = rhs - -With this proof, we have - -∀ j, j < n → (toListLitAux a n hsz n _ []).index j = a.getLit j hsz _ - -We also need - -- (toListLitAux a n hsz n _ []).length = n -- j < n -> (List.toArray as).getLit j _ _ = as.index j - -Then using Array.extLit, we have that a = List.toArray $ toListLitAux a n hsz n _ [] --/ - -theorem Array.eqLitOfSize0 {α : Type u} (a : Array α) (hsz : a.size = 0) : a = #[] := -toArrayLitEq a 0 hsz -/- -Array.ext a #[] h (fun i h₁ h₂ => absurd h₂ (Nat.notLtZero _)) --/ - -theorem Array.eqLitOfSize1 {α : Type u} (a : Array α) (hsz : a.size = 1) : a = #[a.getLit 0 hsz (ofDecideEqTrue rfl)] := -toArrayLitEq a 1 hsz -/- -Array.extLit a #[a.getLit 0 hsz (ofDecideEqTrue rfl)] hsz rfl $ fun i => - match i with - | 0 => fun hi => rfl - | (n+1) => fun hi => - have n < 0 from hi; - absurd this (Nat.notLtZero _) --/ - -theorem Array.eqLitOfSize2 {α : Type u} (a : Array α) (hsz : a.size = 2) : a = #[a.getLit 0 hsz (ofDecideEqTrue rfl), a.getLit 1 hsz (ofDecideEqTrue rfl)] := -toArrayLitEq a 2 hsz -/- -Array.extLit a #[a.getLit 0 hsz (ofDecideEqTrue rfl), a.getLit 1 hsz (ofDecideEqTrue rfl)] hsz rfl $ fun i => - match i with - | 0 => fun hi => rfl - | 1 => fun hi => rfl - | (n+2) => fun hi => - have n < 0 from hi; - absurd this (Nat.notLtZero _) --/ - -theorem Array.eqLitOfSize3 {α : Type u} (a : Array α) (hsz : a.size = 3) : - a = #[a.getLit 0 hsz (ofDecideEqTrue rfl), a.getLit 1 hsz (ofDecideEqTrue rfl), a.getLit 2 hsz (ofDecideEqTrue rfl)] := -toArrayLitEq a 3 hsz -/- -Array.extLit a #[a.getLit 0 hsz (ofDecideEqTrue rfl), a.getLit 1 hsz (ofDecideEqTrue rfl), a.getLit 2 hsz (ofDecideEqTrue rfl)] hsz rfl $ fun i => - match i with - | 0 => fun hi => rfl - | 1 => fun hi => rfl - | 2 => fun hi => rfl - | (n+3) => fun hi => - have n < 0 from hi; - absurd this (Nat.notLtZero _) --/ - -/- -Matcher for the following patterns -``` -| #[] => _ -| #[a₁] => _ -| #[a₁, a₂, a₃] => _ -| a => _ -``` -/ -def matchArrayLit {α : Type u} (C : Array α → Sort v) (a : Array α) - (h₁ : Unit → C #[]) - (h₂ : ∀ a₁, C #[a₁]) - (h₃ : ∀ a₁ a₂ a₃, C #[a₁, a₂, a₃]) - (h₄ : ∀ a, C a) - : C a := -if h : a.size = 0 then - @Eq.rec _ _ (fun x _ => C x) (h₁ ()) _ (toArrayLitEq a 0 h).symm -else if h : a.size = 1 then - @Eq.rec _ _ (fun x _ => C x) (h₂ (a.getLit 0 h (ofDecideEqTrue rfl))) _ (toArrayLitEq a 1 h).symm -else if h : a.size = 3 then - @Eq.rec _ _ (fun x _ => C x) (h₃ (a.getLit 0 h (ofDecideEqTrue rfl)) (a.getLit 1 h (ofDecideEqTrue rfl)) (a.getLit 2 h (ofDecideEqTrue rfl))) _ (toArrayLitEq a 3 h).symm -else - h₄ a - -/- Equational lemmas that should be generated automatically. -/ -theorem matchArrayLit.eq1 {α : Type u} (C : Array α → Sort v) - (h₁ : Unit → C #[]) - (h₂ : ∀ a₁, C #[a₁]) - (h₃ : ∀ a₁ a₂ a₃, C #[a₁, a₂, a₃]) - (h₄ : ∀ a, C a) - : matchArrayLit C #[] h₁ h₂ h₃ h₄ = h₁ () := -rfl - -theorem matchArrayLit.eq2 {α : Type u} (C : Array α → Sort v) - (h₁ : Unit → C #[]) - (h₂ : ∀ a₁, C #[a₁]) - (h₃ : ∀ a₁ a₂ a₃, C #[a₁, a₂, a₃]) - (h₄ : ∀ a, C a) - (a₁ : α) - : matchArrayLit C #[a₁] h₁ h₂ h₃ h₄ = h₂ a₁ := -rfl - -theorem matchArrayLit.eq3 {α : Type u} (C : Array α → Sort v) - (h₁ : Unit → C #[]) - (h₂ : ∀ a₁, C #[a₁]) - (h₃ : ∀ a₁ a₂ a₃, C #[a₁, a₂, a₃]) - (h₄ : ∀ a, C a) - (a₁ a₂ a₃ : α) - : matchArrayLit C #[a₁, a₂, a₃] h₁ h₂ h₃ h₄ = h₃ a₁ a₂ a₃ := -rfl - -theorem matchArrayLit.eq4 {α : Type u} (C : Array α → Sort v) - (h₁ : Unit → C #[]) - (h₂ : ∀ a₁, C #[a₁]) - (h₃ : ∀ a₁ a₂ a₃, C #[a₁, a₂, a₃]) - (h₄ : ∀ a, C a) - (a : Array α) - (n₁ : a.size ≠ 0) (n₂ : a.size ≠ 1) (n₃ : a.size ≠ 3) - : matchArrayLit C a h₁ h₂ h₃ h₄ = h₄ a := -match a, n₁, n₂, n₃ with -| ⟨0, _⟩, n₁, _, _ => absurd rfl n₁ -| ⟨1, _⟩, _, n₂, _ => absurd rfl n₂ -| ⟨2, _⟩, _, _, _ => rfl -| ⟨3, _⟩, _, _, n₃ => absurd rfl n₃ -| ⟨n+4, _⟩, _, _, _ => rfl diff --git a/tmp/eqns/matchVal.lean b/tmp/eqns/matchVal.lean deleted file mode 100644 index e4fdada066..0000000000 --- a/tmp/eqns/matchVal.lean +++ /dev/null @@ -1,46 +0,0 @@ -universes v -/- -matcher for the following patterns -``` -| "hello" => _ -| "world" => _ -| a => _ -``` -/ -def matchString (C : String → Sort v) (s : String) - (h₁ : Unit → C "hello") - (h₂ : Unit → C "world") - (h₃ : ∀ s, C s) - : C s := -dite (s = "hello") - (fun h => @Eq.ndrec _ _ (fun x => C x) (h₁ ()) _ h.symm) - (fun _ => dite (s = "world") - (fun h => @Eq.ndrec _ _ (fun x => C x) (h₂ ()) _ h.symm) - (fun _ => h₃ s)) - -theorem matchString.Eq1 (C : String → Sort v) - (h₁ : Unit → C "hello") - (h₂ : Unit → C "world") - (h₃ : ∀ s, C s) - : matchString C "hello" h₁ h₂ h₃ = h₁ () := -difPos rfl - -axiom neg1 : "world" ≠ "hello" - -theorem matchString.Eq2 (C : String → Sort v) - (h₁ : Unit → C "hello") - (h₂ : Unit → C "world") - (h₃ : ∀ s, C s) - : matchString C "world" h₁ h₂ h₃ = h₂ () := -have aux₁ : matchString C "world" h₁ h₂ h₃ = if h : "world" = "world" then @Eq.rec _ _ (fun x _ => C x) (h₂ ()) _ h.symm else h₃ "world" from difNeg neg1; -have aux₂ : (if h : "world" = "world" then @Eq.rec _ _ (fun x _ => C x) (h₂ ()) _ h.symm else h₃ "world" : C "world") = h₂ () from difPos rfl; -Eq.trans aux₁ aux₂ - -theorem matchString.Eq3 (C : String → Sort v) - (h₁ : Unit → C "hello") - (h₂ : Unit → C "world") - (h₃ : ∀ s, C s) - (s : String) (n₁ : s ≠ "hello") (n₂ : s ≠ "world") - : matchString C s h₁ h₂ h₃ = h₃ s := -have aux₁ : matchString C s h₁ h₂ h₃ = if h : s = "world" then @Eq.rec _ _ (fun x _ => C x) (h₂ ()) _ h.symm else h₃ s from difNeg n₁; -have aux₂ : (if h : s = "world" then @Eq.rec _ _ (fun x _ => C x) (h₂ ()) _ h.symm else h₃ s : C s) = h₃ s from difNeg n₂; -Eq.trans aux₁ aux₂ diff --git a/tmp/new-frontend/elaborator.lean b/tmp/new-frontend/elaborator.lean deleted file mode 100644 index 223a7ea4b0..0000000000 --- a/tmp/new-frontend/elaborator.lean +++ /dev/null @@ -1,1004 +0,0 @@ -/- -Copyright (c) 2018 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Author: Sebastian Ullrich - -Elaborator for the Lean language: takes commands and produces side effects --/ -prelude -import init.lean.parser.module -import init.lean.expander -import init.lean.expr -import init.lean.options -import init.lean.environment - -namespace Lean --- deprecated Constructor -@[extern "lean_expr_local"] -constant Expr.local (n : Name) (pp : Name) (ty : Expr) (bi : BinderInfo) : Expr := default Expr - -namespace Elaborator --- TODO(Sebastian): move --- TODO(Sebastian): should be its own Monad? -structure NameGenerator := -(«prefix» : Name) -(nextIdx : UInt32) - -structure SectionVar := -(uniqName : Name) -(BinderInfo : BinderInfo) -(type : Expr) - -/-- Simplified State of the Lean 3 Parser. Maps are replaced with lists for easier interop. -/ -structure OldElaboratorState := -(env : Environment) -(ngen : NameGenerator) -(univs : List (Name × Level)) -(vars : List (Name × SectionVar)) -(includeVars : List Name) -(Options : Options) -(nextInstIdx : Nat) -(ns : Name) - -@[extern "lean_elaborator_elaborate_command"] -constant elaborateCommand (filename : @& String) (e : Expr) (s : @& OldElaboratorState) : Option OldElaboratorState × MessageLog := (none, ⟨[]⟩) - -open Parser -open Parser.Combinators -open Parser.Term -open Parser.command -open Parser.command.NotationSpec -open Expander - --- TODO(Sebastian): move -/-- An RBMap that remembers the insertion order. -/ -structure OrderedRBMap (α β : Type) (lt : α → α → Bool) := -(entries : List (α × β)) -(map : RBMap α (Nat × β) lt) -(size : Nat) - -namespace OrderedRBMap -variables {α β : Type} {lt : α → α → Bool} (m : OrderedRBMap α β lt) - -def empty : OrderedRBMap α β lt := {entries := [], map := mkRBMap _ _ _, size := 0} - -def insert (k : α) (v : β) : OrderedRBMap α β lt := -{entries := (k, v)::m.entries, map := m.map.insert k (m.size, v), size := m.size + 1} - -def find (a : α) : Option (Nat × β) := -m.map.find a - -def ofList (l : List (α × β)) : OrderedRBMap α β lt := -l.foldl (λ m p, OrderedRBMap.insert m (Prod.fst p) (Prod.snd p)) OrderedRBMap.empty -end OrderedRBMap - -structure ElaboratorConfig extends FrontendConfig := -(initialParserCfg : ModuleParserConfig) - -instance elaboratorConfigCoeFrontendConfig : HasCoe ElaboratorConfig FrontendConfig := -⟨ElaboratorConfig.toFrontendConfig⟩ - -/-- Elaborator State that will be reverted at the end of a section or namespace. -/ -structure Scope := --- "section" or "namespace" (or "MODULE"), currently -(cmd : String) --- Scope header, should match identifier after `end`. Can be `Name.anonymous` for sections. -(header : Name) -(notations : List NotationMacro := []) -/- The set of local universe variables. - We remember their insertion order so that we can keep the order when copying them to declarations. -/ -(univs : OrderedRBMap Name Level Name.quickLt := OrderedRBMap.empty) -/- The set of local variables. -/ -(vars : OrderedRBMap Name SectionVar Name.quickLt := OrderedRBMap.empty) -/- The subset of `vars` that is tagged as always included. -/ -(includeVars : RBTree Name Name.quickLt := mkRBTree _ _) -/- The stack of nested active `namespace` commands. -/ -(nsStack : List Name := []) -/- The set of active `open` declarations. -/ -(openDecls : List openSpec.View := []) -(Options : Options := {}) - -/-- An `export` command together with the namespace it was declared in. Opening the namespace activates - the export. -/ -structure ScopedExportDecl := -(inNs : Name) -(spec : openSpec.View) - -structure ElaboratorState := --- TODO(Sebastian): retrieve from environment -(reservedNotations : List reserveNotation.View := []) -(notations : List NotationMacro := []) -(notationCounter := 0) -/- The current set of `export` declarations (active or inactive). -/ -(exportDecls : List ScopedExportDecl := []) - --- Stack of current scopes. The bottom-most Scope is the Module Scope. -(scopes : List Scope) -(messages : MessageLog := MessageLog.empty) -(parserCfg : ModuleParserConfig) -(expanderCfg : Expander.ExpanderConfig) -(env : Environment) -(ngen : NameGenerator) -(nextInstIdx : Nat := 0) - -@[derive Monad MonadRec MonadReader MonadState MonadExcept] -def ElaboratorM := RecT Syntax Unit $ ReaderT ElaboratorConfig $ StateT ElaboratorState $ ExceptT Message Id -abbrev Elaborator := Syntax → ElaboratorM Unit - -instance elaboratorInh (α : Type) : Inhabited (ElaboratorM α) := -⟨λ _ _ _, Except.error (default _)⟩ - -/-- Recursively elaborate any command. -/ -def command.elaborate : Elaborator := recurse - -def currentScope : ElaboratorM Scope := do - st ← get, - match st.scopes with - | [] := error none "currentScope: unreachable" - | sc::_ := pure sc - -def modifyCurrentScope (f : Scope → Scope) : ElaboratorM Unit := do - st ← get, - match st.scopes with - | [] := error none "modifyCurrentScope: unreachable" - | sc::scs := set {st with scopes := f sc::scs} - -def mangleIdent (id : SyntaxIdent) : Name := -id.scopes.foldl Name.mkNumeral id.val - -partial def levelGetAppArgs : Syntax → ElaboratorM (Syntax × List Syntax) -| stx := do - match stx.kind with - | some Level.leading := pure (stx, []) - | some Level.trailing := match view Level.trailing stx with - | Level.trailing.View.app lta := do - (fn, args) ← levelGetAppArgs lta.fn, - pure (fn, lta.Arg :: args) - | Level.trailing.View.addLit _ := pure (stx, []) - | _ := error stx $ "levelGetAppArgs: unexpected input: " ++ toString stx - -def levelAdd : Level → Nat → Level -| l 0 := l -| l (n+1) := (levelAdd l n).succ - -partial def toLevel : Syntax → ElaboratorM Level -| stx := do - (fn, args) ← levelGetAppArgs stx, - sc ← currentScope, - match fn.kind with - | some Level.leading := match view Level.leading fn, args with - | Level.leading.View.hole _, [] := pure $ Level.mvar Name.anonymous - | Level.leading.View.lit lit, [] := pure $ Level.ofNat lit.toNat - | Level.leading.View.var id, [] := let id := mangleIdent id in match sc.univs.find id with - | some _ := pure $ Level.Param id - | none := error stx $ "unknown universe variable '" ++ toString id ++ "'" - | Level.leading.View.max _, (Arg::args) := List.foldr Level.max <$> toLevel Arg <*> args.mmap toLevel - | Level.leading.View.imax _, (Arg::args) := List.foldr Level.imax <$> toLevel Arg <*> args.mmap toLevel - | _, _ := error stx "ill-formed universe Level" - | some Level.trailing := match view Level.trailing fn, args with - | Level.trailing.View.addLit lta, [] := do - l ← toLevel lta.lhs, - pure $ levelAdd l lta.rhs.toNat - | _, _ := error stx "ill-formed universe Level" - | _ := error stx $ "toLevel: unexpected input: " ++ toString stx - -def Expr.mkAnnotation (ann : Name) (e : Expr) := -Expr.mdata (MData.empty.setName `annotation ann) e - -def dummy : Expr := Expr.const `Prop [] - -def mkEqns (type : Expr) (eqns : List (Name × List Expr × Expr)): Expr := - let eqns := eqns.map $ λ ⟨fn, lhs, rhs⟩, do { - let fn := Expr.local fn fn type BinderInfo.auxDecl, - let lhs := Expr.mkApp (Expr.mkAnnotation `@ fn) lhs, - Expr.app lhs rhs - } in - Expr.mkAnnotation `preEquations $ Expr.mkCapp `_ eqns - -partial def toPexpr : Syntax → ElaboratorM Expr -| stx@(Syntax.rawNode {kind := k, args := args}) := do - e ← match k with - | @identUnivs := do - let v := view identUnivs stx, - e ← match v with - | {id := id, univs := some univs} := Expr.const (mangleIdent id) <$> univs.levels.mmap toLevel - | {id := id, univs := none} := pure $ Expr.const (mangleIdent id) [], - let m := MData.empty.setName `annotation `preresolved, - let m := v.id.preresolved.enum.foldl (λ (m : MData) ⟨i, n⟩, m.setName (Name.anonymous.mkNumeral i) n) m, - pure $ Expr.mdata m e - | @app := let v := view app stx in - Expr.app <$> toPexpr v.fn <*> toPexpr v.Arg - | @lambda := do - let lam := view lambda stx, - binders.View.simple bnder ← pure lam.binders - | error stx "ill-formed lambda", - (bi, id, type) ← pure bnder.toBinderInfo, - Expr.lam (mangleIdent id) bi <$> toPexpr type <*> toPexpr lam.body - | @pi := do - let v := view pi stx, - binders.View.simple bnder ← pure v.binders - | error stx "ill-formed pi", - (bi, id, type) ← pure bnder.toBinderInfo, - Expr.pi (mangleIdent id) bi <$> toPexpr type <*> toPexpr v.range - | @sort := match view sort stx with - | sort.View.Sort _ := pure $ Expr.sort Level.zero - | sort.View.Type _ := pure $ Expr.sort $ Level.succ Level.zero - | @sortApp := do - let v := view sortApp stx, - match view sort v.fn with - | sort.View.Sort _ := Expr.sort <$> toLevel v.Arg - | sort.View.Type _ := (Expr.sort ∘ Level.succ) <$> toLevel v.Arg - | @anonymousConstructor := do - let v := view anonymousConstructor stx, - p ← toPexpr $ mkApp (review hole {}) (v.args.map SepBy.Elem.View.item), - pure $ Expr.mkAnnotation `anonymousConstructor p - | @hole := pure $ Expr.mvar Name.anonymous dummy - | @«have» := do - let v := view «have» stx, - let id := (mangleIdent <$> optIdent.View.id <$> v.id).getOrElse `this, - let proof := match v.proof with - | haveProof.View.Term hpt := hpt.Term - | haveProof.View.from hpf := hpf.from.proof, - lam ← Expr.lam id BinderInfo.default <$> toPexpr v.prop <*> toPexpr v.body, - Expr.app (Expr.mkAnnotation `have lam) <$> toPexpr proof - | @«show» := do - let v := view «show» stx, - prop ← toPexpr v.prop, - proof ← toPexpr v.from.proof, - pure $ Expr.mkAnnotation `show $ Expr.app (Expr.lam `this BinderInfo.default prop $ Expr.bvar 0) proof - | @«let» := do - let v := view «let» stx, - letLhs.View.id {id := id, binders := [], type := some ty} ← pure v.lhs - | error stx "ill-formed let", - Expr.elet (mangleIdent id) <$> toPexpr ty.type <*> toPexpr v.value <*> toPexpr v.body - | @projection := do - let v := view projection stx, - let val := match v.proj with - | projectionSpec.View.id id := DataValue.ofName id.val - | projectionSpec.View.num n := DataValue.ofNat n.toNat, - Expr.mdata (MData.empty.insert `fieldNotation val) <$> toPexpr v.Term - | @explicit := do - let v := view explicit stx, - let ann := match v.mod with - | explicitModifier.View.explicit _ := `@ - | explicitModifier.View.partialExplicit _ := `@@, - Expr.mkAnnotation ann <$> toPexpr (review identUnivs v.id) - | @inaccessible := do - let v := view inaccessible stx, - Expr.mkAnnotation `innaccessible <$> toPexpr v.Term -- sic - | @borrowed := do - let v := view borrowed stx, - Expr.mkAnnotation `borrowed <$> toPexpr v.Term - | @number := do - let v := view number stx, - pure $ Expr.lit $ Literal.natVal v.toNat - | @stringLit := do - let v := view stringLit stx, - pure $ Expr.lit $ Literal.strVal (v.value.getOrElse "NOTAString") - | @choice := do - last::rev ← List.reverse <$> args.mmap (λ a, toPexpr a) - | error stx "ill-formed choice", - pure $ Expr.mdata (MData.empty.setNat `choice args.length) $ - rev.reverse.foldr Expr.app last - | @structInst := do - let v := view structInst stx, - -- order should be: fields*, sources*, catchall? - let (fields, other) := v.items.span (λ it, ↑match SepBy.Elem.View.item it with - | structInstItem.View.field _ := true - | _ := false), - let (sources, catchall) := other.span (λ it, ↑match SepBy.Elem.View.item it with - | structInstItem.View.source {source := some _} := true - | _ := false), - catchall ← match catchall with - | [] := pure false - | [{item := structInstItem.View.source _}] := pure true - | {item := it}::_ := error (review structInstItem it) $ "unexpected item in structure instance notation", - - fields ← fields.mmap (λ f, match SepBy.Elem.View.item f with - | structInstItem.View.field f := - Expr.mdata (MData.empty.setName `field $ mangleIdent f.id) <$> toPexpr f.val - | _ := error stx "toPexpr: unreachable"), - sources ← sources.mmap (λ src, match SepBy.Elem.View.item src with - | structInstItem.View.source {source := some src} := toPexpr src - | _ := error stx "toPexpr: unreachable"), - sources ← match v.with with - | none := pure sources - | some src := do { src ← toPexpr src.source, pure $ sources ++ [src]}, - - let m := MData.empty.setNat "structure instance" fields.length, - let m := m.setBool `catchall catchall, - let m := m.setName `struct $ - (mangleIdent <$> structInstType.View.id <$> v.type).getOrElse Name.anonymous, - let dummy := Expr.sort Level.zero, - pure $ Expr.mdata m $ (fields ++ sources).foldr Expr.app dummy - | @«match» := do - let v := view «match» stx, - eqns ← (v.equations.map SepBy.Elem.View.item).mmap $ λ (eqn : matchEquation.View), do { - lhs ← eqn.lhs.mmap $ λ l, toPexpr l.item, - rhs ← toPexpr eqn.rhs, - pure (`_matchFn, lhs, rhs) - }, - type ← toPexpr $ getOptType v.type, - let eqns := mkEqns type eqns, - Expr.mdata mdata e ← pure eqns - | error stx "toPexpr: unreachable", - let eqns := Expr.mdata (mdata.setBool `match true) e, - Expr.mkApp eqns <$> v.scrutinees.mmap (λ scr, toPexpr scr.item) - | _ := error stx $ "toPexpr: unexpected Node: " ++ toString k.name, - match k with - | @app := pure e -- no Position - | _ := do - cfg ← read, - match stx.getPos with - | some pos := - let pos := cfg.fileMap.toPosition pos in - pure $ Expr.mdata ((MData.empty.setNat `column pos.column).setNat `row pos.line) e - | none := pure e -| stx := error stx $ "toPexpr: unexpected: " ++ toString stx - -/-- Returns the active namespace, that is, the concatenation of all active `namespace` commands. -/ -def getNamespace : ElaboratorM Name := do - sc ← currentScope, - pure $ match sc.nsStack with - | ns::_ := ns - | _ := Name.anonymous - -def oldElabCommand (stx : Syntax) (cmd : Expr) : ElaboratorM Unit := -do cfg ← read, - let pos := cfg.fileMap.toPosition $ stx.getPos.getOrElse (default _), - let cmd := match cmd with - | Expr.mdata m e := Expr.mdata ((m.setNat `column pos.column).setNat `row pos.line) e - | e := e, - st ← get, - sc ← currentScope, - ns ← getNamespace, - let (st', msgs) := elaborateCommand cfg.filename cmd { - ns := ns, - univs := sc.univs.entries.reverse, - vars := sc.vars.entries.reverse, - includeVars := sc.includeVars.toList, - Options := sc.Options, - ..st}, - match st' with - | some st' := do modifyCurrentScope $ λ sc, {sc with - univs := OrderedRBMap.ofList st'.univs, - vars := OrderedRBMap.ofList st'.vars, - includeVars := RBTree.ofList st'.includeVars, - Options := st'.Options, - }, - modify $ λ st, {..st', ..st} - | none := pure (), -- error - modify $ λ st, {st with messages := st.messages ++ msgs} - -def namesToPexpr (ns : List Name) : Expr := -Expr.mkCapp `_ $ ns.map (λ n, Expr.const n []) - -def attrsToPexpr (attrs : List (SepBy.Elem.View attrInstance.View (Option SyntaxAtom))) : ElaboratorM Expr := -Expr.mkCapp `_ <$> attrs.mmap (λ attr, - Expr.mkCapp attr.item.Name.val <$> attr.item.args.mmap toPexpr) - -def declModifiersToPexpr (mods : declModifiers.View) : ElaboratorM Expr := do - let mdata : MData := {}, - let mdata := match mods.docComment with - | some {doc := some doc, ..} := mdata.setString `docString doc.val - | _ := mdata, - let mdata := match mods.visibility with - | some (visibility.View.private _) := mdata.setBool `private true - | some (visibility.View.protected _) := mdata.setBool `protected true - | _ := mdata, - let mdata := mdata.setBool `noncomputable mods.noncomputable.isSome, - let mdata := mdata.setBool `unsafe mods.unsafe.isSome, - Expr.mdata mdata <$> attrsToPexpr (match mods.attrs with - | some attrs := attrs.attrs - | none := []) - -def identUnivParamsToPexpr (id : identUnivParams.View) : Expr := -Expr.const (mangleIdent id.id) $ match id.univParams with - | some params := params.params.map (Level.Param ∘ mangleIdent) - | none := [] - -/-- Execute `elab` and reset local Scope (universes, ...) after it has finished. -/ -def locally (elab : ElaboratorM Unit) : - ElaboratorM Unit := do - sc ← currentScope, - elab, - modifyCurrentScope $ λ _, sc - -def simpleBindersToPexpr (bindrs : List simpleBinder.View) : ElaboratorM Expr := -Expr.mkCapp `_ <$> bindrs.mmap (λ b, do - let (bi, id, type) := b.toBinderInfo, - let id := mangleIdent id, - type ← toPexpr type, - pure $ Expr.local id id type bi) - -def elabDefLike (stx : Syntax) (mods : declModifiers.View) (dl : defLike.View) (kind : Nat) : ElaboratorM Unit := -match dl with -| {sig := {params := bracketedBinders.View.simple bbs}, ..} := do - let mdata := MData.empty.setName `command `defs, - mods ← declModifiersToPexpr mods, - let kind := Expr.lit $ Literal.natVal kind, - match dl.oldUnivParams with - | some uparams := - modifyCurrentScope $ λ sc, {sc with univs := - (uparams.ids.map mangleIdent).foldl (λ m id, OrderedRBMap.insert m id (Level.Param id)) sc.univs} - | none := pure (), - -- do we actually need this?? - let uparams := namesToPexpr $ match dl.oldUnivParams with - | some uparams := uparams.ids.map mangleIdent - | none := [], - let id := mangleIdent dl.Name.id, - let type := getOptType dl.sig.type, - type ← toPexpr type, - let fns := Expr.mkCapp `_ [Expr.local id id type BinderInfo.auxDecl], - val ← match dl.val with - | declVal.View.simple val := toPexpr val.body - | declVal.View.emptyMatch _ := pure $ mkEqns type [] - | declVal.View.match eqns := do { - eqns ← eqns.mmap (λ (eqn : equation.View), do - lhs ← eqn.lhs.mmap toPexpr, - rhs ← toPexpr eqn.rhs, - pure (id, lhs, rhs) - ), - pure $ mkEqns type eqns - }, - params ← simpleBindersToPexpr bbs, - oldElabCommand stx $ Expr.mdata mdata $ Expr.mkCapp `_ [mods, kind, uparams, fns, params, val] -| _ := error stx "elabDefLike: unexpected input" - -def inferModToPexpr (mod : Option inferModifier.View) : Expr := -Expr.lit $ Literal.natVal $ match mod with -| none := 0 -| some $ inferModifier.View.relaxed _ := 1 -| some $ inferModifier.View.strict _ := 2 - -def declaration.elaborate : Elaborator := -λ stx, locally $ do - let decl := view «declaration» stx, - match decl.inner with - | declaration.inner.View.«axiom» c@{sig := {params := bracketedBinders.View.simple [], type := type}, ..} := do - let mdata := MData.empty.setName `command `«axiom», -- CommentTo(Kha): It was `constant` here - mods ← declModifiersToPexpr decl.modifiers, - let id := identUnivParamsToPexpr c.Name, - type ← toPexpr type.type, - oldElabCommand stx $ Expr.mdata mdata $ Expr.mkCapp `_ [mods, id, type] - | declaration.inner.View.defLike dl := do - -- The numeric literals below should reflect the enum values - -- enum class declCmdKind { Theorem, Definition, OpaqueConst, Example, Instance, Var, Abbreviation }; - let kind := match dl.kind with - | defLike.kind.View.theorem _ := 0 - | defLike.kind.View.def _ := 1 - | defLike.kind.View.«constant» _ := 2 - | defLike.kind.View.abbreviation _ := 6 - | defLike.kind.View.«abbrev» _ := 6, - elabDefLike stx decl.modifiers dl kind - - -- these are almost macros for `def`, Except the Elaborator handles them specially at a few places - -- based on the kind - | declaration.inner.View.example ex := - elabDefLike stx decl.modifiers { - kind := defLike.kind.View.def, - Name := {id := Name.anonymous}, - sig := {..ex.sig}, - ..ex} 3 - | declaration.inner.View.instance i := - elabDefLike stx decl.modifiers { - kind := defLike.kind.View.def, - Name := i.Name.getOrElse {id := Name.anonymous}, - sig := {..i.sig}, - ..i} 4 - - | declaration.inner.View.inductive ind@{«class» := none, sig := {params := bracketedBinders.View.simple bbs}, ..} := do - let mdata := MData.empty.setName `command `inductives, - mods ← declModifiersToPexpr decl.modifiers, - attrs ← attrsToPexpr (match decl.modifiers.attrs with - | some attrs := attrs.attrs - | none := []), - let mutAttrs := Expr.mkCapp `_ [attrs], - match ind.oldUnivParams with - | some uparams := - modifyCurrentScope $ λ sc, {sc with univs := - (uparams.ids.map mangleIdent).foldl (λ m id, OrderedRBMap.insert m id (Level.Param id)) sc.univs} - | none := pure (), - let uparams := namesToPexpr $ match ind.oldUnivParams with - | some uparams := uparams.ids.map mangleIdent - | none := [], - let id := mangleIdent ind.Name.id, - let type := getOptType ind.sig.type, - type ← toPexpr type, - let indL := Expr.local id id type BinderInfo.default, - let inds := Expr.mkCapp `_ [indL], - params ← simpleBindersToPexpr bbs, - introRules ← ind.introRules.mmap (λ (r : introRule.View), do - ({params := bracketedBinders.View.simple [], type := some ty}) ← pure r.sig - | error stx "declaration.elaborate: unexpected input", - type ← toPexpr ty.type, - let Name := mangleIdent r.Name, - pure $ Expr.local Name Name type BinderInfo.default), - let introRules := Expr.mkCapp `_ introRules, - let introRules := Expr.mkCapp `_ [introRules], - let inferKinds := ind.introRules.map $ λ (r : introRule.View), inferModToPexpr r.inferMod, - let inferKinds := Expr.mkCapp `_ inferKinds, - let inferKinds := Expr.mkCapp `_ [inferKinds], - oldElabCommand stx $ Expr.mdata mdata $ - Expr.mkCapp `_ [mods, mutAttrs, uparams, inds, params, introRules, inferKinds] - - | declaration.inner.View.structure s@{keyword := structureKw.View.structure _, sig := {params := bracketedBinders.View.simple bbs}, ..} := do - let mdata := MData.empty.setName `command `structure, - mods ← declModifiersToPexpr decl.modifiers, - match s.oldUnivParams with - | some uparams := - modifyCurrentScope $ λ sc, {sc with univs := - (uparams.ids.map mangleIdent).foldl (λ m id, OrderedRBMap.insert m id (Level.Param id)) sc.univs} - | none := pure (), - let uparams := namesToPexpr $ match s.oldUnivParams with - | some uparams := uparams.ids.map mangleIdent - | none := [], - let Name := mangleIdent s.Name.id, - let Name := Expr.local Name Name dummy BinderInfo.default, - let type := getOptType s.sig.type, - type ← toPexpr type, - params ← simpleBindersToPexpr bbs, - let parents := match s.extends with - | some ex := ex.parents - | none := [], - parents ← parents.mmap (toPexpr ∘ SepBy.Elem.View.item), - let parents := Expr.mkCapp `_ parents, - let mk := match s.ctor with - | some ctor := mangleIdent ctor.Name - | none := `mk, - let mk := Expr.local mk mk dummy BinderInfo.default, - let infer := inferModToPexpr (s.ctor >>= structureCtor.View.inferMod), - fieldBlocks ← s.fieldBlocks.mmap (λ bl, do - (bi, content) ← match bl with - | structureFieldBlock.View.explicit {content := structExplicitBinderContent.View.notation _} := - error stx "declaration.elaborate: unexpected input" - | structureFieldBlock.View.explicit {content := structExplicitBinderContent.View.other c} := - pure (BinderInfo.default, c) - | structureFieldBlock.View.implicit {content := c} := pure (BinderInfo.implicit, c) - | structureFieldBlock.View.strictImplicit {content := c} := pure (BinderInfo.strictImplicit, c) - | structureFieldBlock.View.instImplicit {content := c} := pure (BinderInfo.instImplicit, c), - let bi := Expr.local `_ `_ dummy bi, - let ids := namesToPexpr $ content.ids.map mangleIdent, - let kind := inferModToPexpr content.inferMod, - let type := getOptType content.sig.type, - type ← toPexpr type, - pure $ Expr.mkCapp `_ [bi, ids, kind, type]), - let fieldBlocks := Expr.mkCapp `_ fieldBlocks, - oldElabCommand stx $ Expr.mdata mdata $ - Expr.mkCapp `_ [mods, uparams, Name, params, parents, type, mk, infer, fieldBlocks] - | _ := - error stx "declaration.elaborate: unexpected input" - -def variables.elaborate : Elaborator := -λ stx, do - let mdata := MData.empty.setName `command `variables, - let v := view «variables» stx, - vars ← match v.binders with - | bracketedBinders.View.simple bbs := bbs.mfilter $ λ b, do - let (bi, id, type) := b.toBinderInfo, - if type.isOfKind bindingAnnotationUpdate then do - sc ← currentScope, - let id := mangleIdent id, - match sc.vars.find id with - | some (_, v) := - modifyCurrentScope $ λ sc, {sc with vars := - sc.vars.insert id {v with BinderInfo := bi}} - | none := error (Syntax.ident id) "", - pure false - else pure true - | _ := error stx "variables.elaborate: unexpected input", - vars ← simpleBindersToPexpr vars, - oldElabCommand stx $ Expr.mdata mdata vars - -def include.elaborate : Elaborator := -λ stx, do - let v := view «include» stx, - -- TODO(Sebastian): error checking - modifyCurrentScope $ λ sc, {sc with includeVars := - v.ids.foldl (λ vars v, vars.insert $ mangleIdent v) sc.includeVars} - --- TODO: RBMap.remove -/- -def omit.elaborate : Elaborator := -λ stx, do - let v := View «omit» stx, - modify $ λ st, {st with localState := {sc with includeVars := - v.ids.foldl (λ vars v, vars.remove $ mangleIdent v) sc.includeVars}} --/ - -def Module.header.elaborate : Elaborator := -λ stx, do - let header := view Module.header stx, - match header with - | {«prelude» := some _, imports := []} := pure () - | _ := error stx "not implemented: imports" - -def precToNat : Option precedence.View → Nat -| (some prec) := prec.Term.toNat -| none := 0 - --- TODO(Sebastian): Command parsers like `structure` will need access to these -def CommandParserConfig.registerNotationTokens (spec : NotationSpec.View) (cfg : CommandParserConfig) : - Except String CommandParserConfig := -do spec.rules.mfoldl (λ (cfg : CommandParserConfig) r, match r.symbol with - | notationSymbol.View.quoted {symbol := some a, prec := prec, ..} := - pure {cfg with tokens := cfg.tokens.insert a.val.trim {«prefix» := a.val.trim, lbp := precToNat prec}} - | _ := throw "registerNotationTokens: unreachable") cfg - -def CommandParserConfig.registerNotationParser (k : SyntaxNodeKind) (nota : notation.View) - (cfg : CommandParserConfig) : Except String CommandParserConfig := -do -- build and register Parser - ps ← nota.spec.rules.mmap (λ r : rule.View, do - psym ← match r.symbol with - | notationSymbol.View.quoted {symbol := some a ..} := - pure (symbol a.val : termParser) - | _ := throw "registerNotationParser: unreachable", - ptrans ← match r.transition with - | some (transition.View.binder b) := - pure $ some $ Term.binderIdent.Parser - | some (transition.View.binders b) := - pure $ some $ Term.binders.Parser - | some (transition.View.Arg {action := none, ..}) := - pure $ some Term.Parser - | some (transition.View.Arg {action := some {kind := actionKind.View.prec prec}, ..}) := - pure $ some $ Term.Parser prec.toNat - | some (transition.View.Arg {action := some {kind := actionKind.View.scoped sc}, ..}) := - pure $ some $ Term.Parser $ precToNat sc.prec - | none := pure $ none - | _ := throw "registerNotationParser: unimplemented", - pure $ psym::ptrans.toMonad - ), - firstRule::_ ← pure nota.spec.rules | throw "registerNotationParser: unreachable", - firstTk ← match firstRule.symbol with - | notationSymbol.View.quoted {symbol := some a ..} := - pure a.val.trim - | _ := throw "registerNotationParser: unreachable", - let ps := ps.bind id, - cfg ← match nota.local, nota.spec.prefixArg with - | none, none := pure {cfg with leadingTermParsers := - cfg.leadingTermParsers.insert firstTk $ Parser.Combinators.node k ps} - | some _, none := pure {cfg with localLeadingTermParsers := - cfg.localLeadingTermParsers.insert firstTk $ Parser.Combinators.node k ps} - | none, some _ := pure {cfg with trailingTermParsers := - cfg.trailingTermParsers.insert firstTk $ Parser.Combinators.node k (getLeading::ps.map coe)} - | some _, some _ := pure {cfg with localTrailingTermParsers := - cfg.localTrailingTermParsers.insert firstTk $ Parser.Combinators.node k (getLeading::ps.map coe)}, - pure cfg - -/-- Recreate `ElaboratorState.parserCfg` from the Elaborator State and the initial config, - effectively treating it as a cache. -/ -def updateParserConfig : ElaboratorM Unit := -do st ← get, - sc ← currentScope, - cfg ← read, - let ccfg := cfg.initialParserCfg.toCommandParserConfig, - ccfg ← st.reservedNotations.mfoldl (λ ccfg rnota, - match CommandParserConfig.registerNotationTokens rnota.spec ccfg with - | Except.ok ccfg := pure ccfg - | Except.error e := error (review reserveNotation rnota) e) ccfg, - ccfg ← (st.notations ++ sc.notations).mfoldl (λ ccfg nota, - match CommandParserConfig.registerNotationTokens nota.nota.spec ccfg >>= - CommandParserConfig.registerNotationParser nota.kind nota.nota with - | Except.ok ccfg := pure ccfg - | Except.error e := error (review «notation» nota.nota) e) ccfg, - set {st with parserCfg := {cfg.initialParserCfg with toCommandParserConfig := ccfg}} - -def postprocessNotationSpec (spec : NotationSpec.View) : NotationSpec.View := --- default leading tokens to `max` --- NOTE: should happen after copying precedences from reserved notation -match spec with -| {prefixArg := none, rules := r@{symbol := notationSymbol.View.quoted sym@{prec := none, ..}, ..}::rs} := - {spec with rules := {r with symbol := notationSymbol.View.quoted {sym with prec := some - {Term := precedenceTerm.View.lit $ precedenceLit.View.num $ number.View.ofNat maxPrec} - }}::rs} -| _ := spec - -def reserveNotation.elaborate : Elaborator := -λ stx, do - let v := view reserveNotation stx, - let v := {v with spec := postprocessNotationSpec v.spec}, - -- TODO: sanity checks? - modify $ λ st, {st with reservedNotations := v::st.reservedNotations}, - updateParserConfig - -def matchPrecedence : Option precedence.View → Option precedence.View → Bool -| none (some rp) := true -| (some sp) (some rp) := sp.Term.toNat = rp.Term.toNat -| _ _ := false - -/-- Check if a notation is compatible with a reserved notation, and if so, copy missing - precedences in the notation from the reserved notation. -/ -def matchSpec (spec reserved : NotationSpec.View) : Option NotationSpec.View := -do guard $ spec.prefixArg.isSome = reserved.prefixArg.isSome, - rules ← (spec.rules.zip reserved.rules).mmap $ λ ⟨sr, rr⟩, do { - notationSymbol.View.quoted sq@{symbol := some sa, ..} ← pure sr.symbol - | failure, - notationSymbol.View.quoted rq@{symbol := some ra, ..} ← pure rr.symbol - | failure, - guard $ sa.val.trim = ra.val.trim, - guard $ matchPrecedence sq.prec rq.prec, - st ← match sr.transition, rr.transition with - | some (transition.View.binder sb), some (transition.View.binder rb) := - guard (matchPrecedence sb.prec rb.prec) *> pure rr.transition - | some (transition.View.binders sb), some (transition.View.binders rb) := - guard (matchPrecedence sb.prec rb.prec) *> pure rr.transition - | some (transition.View.Arg sarg), some (transition.View.Arg rarg) := do - sact ← match action.View.kind <$> sarg.action, action.View.kind <$> rarg.action with - | some (actionKind.View.prec sp), some (actionKind.View.prec rp) := - guard (sp.toNat = rp.toNat) *> pure sarg.action - | none, some (actionKind.View.prec rp) := - pure rarg.action - | _, _ := failure, - pure $ some $ transition.View.Arg {sarg with action := sact} - | none, none := pure none - | _, _ := failure, - pure $ {rule.View . - symbol := notationSymbol.View.quoted rq, - transition := st} - }, - pure $ {spec with rules := rules} - -def notation.elaborateAux : notation.View → ElaboratorM notation.View := -λ nota, do - st ← get, - -- check reserved notations - matched ← pure $ st.reservedNotations.filterMap $ - λ rnota, matchSpec nota.spec rnota.spec, - nota ← match matched with - | [matched] := pure {nota with spec := matched} - | [] := pure nota - | _ := error (review «notation» nota) "invalid notation, matches multiple reserved notations", - -- TODO: sanity checks - pure {nota with spec := postprocessNotationSpec nota.spec} - --- TODO(Sebastian): better kind names, Module prefix? -def mkNotationKind : ElaboratorM SyntaxNodeKind := -do st ← get, - set {st with notationCounter := st.notationCounter + 1}, - pure {name := (`_notation).mkNumeral st.notationCounter} - -/-- Register a notation in the Expander. Unlike with notation parsers, there is no harm in - keeping local notation macros registered after closing a section. -/ -def registerNotationMacro (nota : notation.View) : ElaboratorM NotationMacro := -do k ← mkNotationKind, - let m : NotationMacro := ⟨k, nota⟩, - let transf := mkNotationTransformer m, - modify $ λ st, {st with expanderCfg := {st.expanderCfg with transformers := st.expanderCfg.transformers.insert k.name transf}}, - pure m - -def notation.elaborate : Elaborator := -λ stx, do - let nota := view «notation» stx, - -- HACK: ignore List Literal notation using :fold - let usesFold := nota.spec.rules.any $ λ r, match r.transition with - | some (transition.View.Arg {action := some {kind := actionKind.View.fold _, ..}, ..}) := true - | _ := false, - if usesFold then do { - cfg ← read, - modify $ λ st, {st with messages := st.messages.add {filename := cfg.filename, pos := ⟨1,0⟩, - severity := MessageSeverity.warning, text := "ignoring notation using 'fold' action"}} - } else do { - nota ← notation.elaborateAux nota, - m ← registerNotationMacro nota, - match nota.local with - | some _ := modifyCurrentScope $ λ sc, {sc with notations := m::sc.notations} - | none := modify $ λ st, {st with notations := m::st.notations}, - updateParserConfig - } - -def universe.elaborate : Elaborator := -λ stx, do - let univ := view «universe» stx, - let id := mangleIdent univ.id, - sc ← currentScope, - match sc.univs.find id with - | none := modifyCurrentScope $ λ sc, {sc with univs := sc.univs.insert id (Level.Param id)} - | some _ := error stx $ "a universe named '" ++ toString id ++ "' has already been declared in this Scope" - -def attribute.elaborate : Elaborator := -λ stx, do - let attr := view «attribute» stx, - let mdata := MData.empty.setName `command `attribute, - let mdata := mdata.setBool `local $ attr.local.isSome, - attrs ← attrsToPexpr attr.attrs, - ids ← attr.ids.mmap (λ id, match id.preresolved with - | [] := error (Syntax.ident id) $ "unknown identifier '" ++ toString id.val ++ "'" - | [c] := pure $ Expr.const c [] - | _ := error (Syntax.ident id) "invalid 'attribute' command, identifier is ambiguous"), - let ids := Expr.mkCapp `_ ids, - oldElabCommand stx $ Expr.mdata mdata $ Expr.app attrs ids - -def check.elaborate : Elaborator := -λ stx, do - let v := view check stx, - let mdata := MData.empty.setName `command `#check, - e ← toPexpr v.Term, - oldElabCommand stx $ Expr.mdata mdata e - -def open.elaborate : Elaborator := -λ stx, do - let v := view «open» stx, - -- TODO: do eager sanity checks (namespace does not exist, etc.) - modifyCurrentScope $ λ sc, {sc with openDecls := sc.openDecls ++ v.spec} - -def export.elaborate : Elaborator := -λ stx, do - let v := view «export» stx, - ns ← getNamespace, - -- TODO: do eager sanity checks (namespace does not exist, etc.) - modify $ λ st, {st with exportDecls := st.exportDecls ++ v.spec.map (λ spec, ⟨ns, spec⟩)} - -def initQuot.elaborate : Elaborator := -λ stx, oldElabCommand stx $ Expr.mdata (MData.empty.setName `command `initQuot) dummy - -def setOption.elaborate : Elaborator := -λ stx, do - let v := view «setOption» stx, - let opt := v.opt.val, - sc ← currentScope, - let opts := sc.Options, - -- TODO(Sebastian): check registered Options - let opts := match v.val with - | optionValue.View.Bool b := opts.setBool opt (match b with boolOptionValue.View.True _ := true | _ := false) - | optionValue.View.String lit := match lit.value with - | some s := opts.setString opt s - | none := opts -- Parser already failed - | optionValue.View.num lit := opts.setNat opt lit.toNat, - modifyCurrentScope $ λ sc, {sc with Options := opts} - -/-- List of commands: recursively elaborate each command. -/ -def noKind.elaborate : Elaborator := λ stx, do - some n ← pure stx.asNode - | error stx "noKind.elaborate: unreachable", - n.args.mfor command.elaborate - -def end.elaborate : Elaborator := -λ cmd, do - let v := view «end» cmd, - st ← get, - -- NOTE: bottom-most (Module) Scope cannot be closed - sc::sc'::scps ← pure st.scopes - | error cmd "invalid 'end', there is no open Scope to end", - let endName := mangleIdent $ v.Name.getOrElse Name.anonymous, - when (endName ≠ sc.header) $ - error cmd $ "invalid end of " ++ sc.cmd ++ ", expected Name '" ++ - toString sc.header ++ "'", - set {st with scopes := sc'::scps}, - -- local notations may have vanished - updateParserConfig - -def section.elaborate : Elaborator := -λ cmd, do - let sec := view «section» cmd, - let header := mangleIdent $ sec.Name.getOrElse Name.anonymous, - sc ← currentScope, - modify $ λ st, {st with scopes := {sc with cmd := "section", header := header}::st.scopes} - -def namespace.elaborate : Elaborator := -λ cmd, do - let v := view «namespace» cmd, - let header := mangleIdent v.Name, - sc ← currentScope, - ns ← getNamespace, - let sc' := {sc with cmd := "namespace", header := header, nsStack := (ns ++ header)::sc.nsStack}, - modify $ λ st, {st with scopes := sc'::st.scopes} - -def eoi.elaborate : Elaborator := -λ cmd, do - st ← get, - when (st.scopes.length > 1) $ - error cmd "invalid end of input, expected 'end'" - --- TODO(Sebastian): replace with attribute -def elaborators : RBMap Name Elaborator Name.quickLt := RBMap.fromList [ - (Module.header.name, Module.header.elaborate), - (notation.name, notation.elaborate), - (reserveNotation.name, reserveNotation.elaborate), - (universe.name, universe.elaborate), - (noKind.name, noKind.elaborate), - (end.name, end.elaborate), - (section.name, section.elaborate), - (namespace.name, namespace.elaborate), - (variables.name, variables.elaborate), - (include.name, include.elaborate), - --(omit.name, omit.elaborate), - (declaration.name, declaration.elaborate), - (attribute.name, attribute.elaborate), - (open.name, open.elaborate), - (export.name, export.elaborate), - (check.name, check.elaborate), - (initQuot.name, initQuot.elaborate), - (setOption.name, setOption.elaborate), - (Module.eoi.name, eoi.elaborate) -] _ - --- TODO: optimize -def isOpenNamespace (sc : Scope) : Name → Bool -| Name.anonymous := true -| ns := - -- check surrounding namespaces - ns ∈ sc.nsStack ∨ - -- check opened namespaces - sc.openDecls.any (λ od, od.id.val = ns) ∨ - -- TODO: check active exports - false - --- TODO: `hiding`, `as`, `renaming` -def matchOpenSpec (n : Name) (spec : openSpec.View) : Option Name := -let matchesOnly := match spec.only with -| none := true -| some only := n = only.id.val ∨ only.ids.any (λ id, n = id.val) in -if matchesOnly then some (spec.id.val ++ n) else none - -def resolveContext : Name → ElaboratorM (List Name) -| n := do - st ← get, - sc ← currentScope, pure $ - - -- TODO(Sebastian): check the interaction betwen preresolution and section variables - match sc.vars.find n with - | some (_, v) := [v.uniqName] - | _ := - - -- global resolution - - -- check surrounding namespaces first - -- TODO: check for `protected` - match sc.nsStack.filter (λ ns, st.env.contains (ns ++ n)) with - | ns::_ := [ns ++ n] -- prefer innermost namespace - | _ := - - -- check environment directly - (let unrooted := n.replacePrefix `_root_ Name.anonymous in - match st.env.contains unrooted with - | true := [unrooted] - | _ := []) - ++ - -- check opened namespaces - (let ns' := sc.openDecls.filterMap (matchOpenSpec n) in - ns'.filter (λ n', st.env.contains n')) - ++ - -- check active exports - -- TODO: optimize - -- TODO: Lean 3 activates an export in `foo` even on `open foo (specificThing)`, but does that make sense? - (let eds' := st.exportDecls.filter (λ ed, isOpenNamespace sc ed.inNs) in - let ns' := eds'.filterMap (λ ed, matchOpenSpec n ed.spec) in - ns'.filter (λ n', st.env.contains n')) - - -- TODO: projection notation - -partial def preresolve : Syntax → ElaboratorM Syntax -| (Syntax.ident id) := do - let n := mangleIdent id, - ns ← resolveContext n, - pure $ Syntax.ident {id with preresolved := ns ++ id.preresolved} -| (Syntax.rawNode n) := do - args ← n.args.mmap preresolve, - pure $ Syntax.rawNode {n with args := args} -| stx := pure stx - -def mkState (cfg : ElaboratorConfig) (env : Environment) (opts : Options) : ElaboratorState := { - parserCfg := cfg.initialParserCfg, - expanderCfg := {transformers := Expander.builtinTransformers, ..cfg}, - env := env, - ngen := ⟨`_ngen.fixme, 0⟩, - scopes := [{cmd := "MODULE", header := `MODULE, Options := opts}]} - -def processCommand (cfg : ElaboratorConfig) (st : ElaboratorState) (cmd : Syntax) : ElaboratorState := -let st := {st with messages := MessageLog.empty} in -let r := @ExceptT.run _ Id _ $ flip StateT.run st $ flip ReaderT.run cfg $ RecT.run - (command.elaborate cmd) - (λ _, error cmd "Elaborator.run: recursion depth exceeded") - (λ cmd, do - some n ← pure cmd.asNode | - error cmd $ "not a command: " ++ toString cmd, - some elab ← pure $ elaborators.find n.kind.name | - error cmd $ "unknown command: " ++ toString n.kind.name, - cmd' ← preresolve cmd, - elab cmd') in -match r with -| Except.ok ((), st) := st -| Except.error e := {st with messages := st.messages.add e} - -end Elaborator -end Lean diff --git a/tmp/new-frontend/expander.lean b/tmp/new-frontend/expander.lean deleted file mode 100644 index 9faab85927..0000000000 --- a/tmp/new-frontend/expander.lean +++ /dev/null @@ -1,544 +0,0 @@ -/- -Copyright (c) 2018 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Author: Sebastian Ullrich - -Macro Expander for the Lean language, using a variant of the [sets of scopes](http://www.cs.utah.edu/plt/Scope-sets/) hygiene algorithm. - -TODO(Sebastian): document/link to documentation of algorithm - --/ -prelude -import init.lean.parser.module -import init.lean.expr - -namespace Lean -namespace Expander -open Parser -open Parser.Combinators -open Parser.Term -open Parser.command - -structure TransformerConfig extends FrontendConfig --- TODO(Sebastian): the recursion point for `localExpand` probably needs to be stored here - -instance transformerConfigCoeFrontendConfig : HasCoe TransformerConfig FrontendConfig := -⟨TransformerConfig.toFrontendConfig⟩ - --- TODO(Sebastian): recursive expansion -@[derive Monad MonadReader MonadExcept] -def TransformM := ReaderT FrontendConfig $ ExceptT Message Id -abbrev transformer := Syntax → TransformM (Option Syntax) - -/-- We allow macros to refuse expansion. This means that nodes can decide whether to act as macros - or not depending on their contents, allowing them to unfold to some normal form without changing - the general Node kind and shape (and thus View Type). -/ -def noExpansion : TransformM (Option Syntax) := -pure none - -def error {m : Type → Type} {ρ : Type} [Monad m] [MonadReader ρ m] [HasLiftT ρ FrontendConfig] - [MonadExcept Message m] {α : Type} - (context : Option Syntax) (text : String) : m α := -do cfg ← read, - throw { - filename := FrontendConfig.filename ↑cfg, - pos := (FrontendConfig.fileMap ↑cfg).toPosition $ (context >>= Syntax.getPos).getOrElse (default _), - text := text - } - -/-- Coercion useful for introducing macro-local variables. Use `globId` to refer to global bindings instead. -/ -instance coeNameIdent : HasCoe Name SyntaxIdent := -⟨λ n, {val := n, rawVal := Substring.ofString n.toString}⟩ - -/-- Create an identifier preresolved against a global binding. Because we cannot use Syntax quotations yet, - which the Expander would have preresolved against the global context at macro declaration time, - we have to do the preresolution manually instead. -/ -def globId (n : Name) : Syntax := -review identUnivs { - id :={val := n, rawVal := Substring.ofString n.toString, preresolved := [n]}, -} - -instance coeIdentIdentUnivs : HasCoe SyntaxIdent identUnivs.View := -⟨λ id, {id := id}⟩ - -instance coeIdentBinderId : HasCoe SyntaxIdent binderIdent.View := -⟨binderIdent.View.id⟩ - -instance coeIdentsBindersExt {α : Type} [HasCoeT α binderIdent.View] : HasCoe (List α) Term.bindersExt.View := -⟨λ ids, {leadingIds := ids.map coe}⟩ - -instance coeBracketedBinderMixedBinder : HasCoe bracketedBinder.View mixedBinder.View := -⟨mixedBinder.View.bracketed⟩ - -instance coeMixedBindersBindersExt {α : Type} [HasCoeT α mixedBinder.View] : HasCoe (List α) Term.bindersExt.View := -⟨λ mbs, {leadingIds := [], remainder := some $ bindersRemainder.View.mixed $ mbs.map coe}⟩ - -instance coeBindersExtBinders : HasCoe Term.bindersExt.View Term.binders.View := -⟨Term.binders.View.extended⟩ - -instance coeSimpleBinderBinders : HasCoe Term.simpleBinder.View Term.binders.View := -⟨Term.binders.View.simple⟩ - -instance coeBinderBracketedBinder : HasCoe Term.binder.View Term.bracketedBinder.View := -⟨λ b, match b with - | binder.View.bracketed bb := bb - | binder.View.unbracketed bc := Term.bracketedBinder.View.explicit - {content := explicitBinderContent.View.other bc}⟩ - -section «notation» -open Parser.command.NotationSpec - -/-- A notation together with a unique Node kind. -/ -structure NotationMacro := -(kind : SyntaxNodeKind) -(nota : notation.View) - -/-- Helper State of the loop in `mkNotationTransformer`. -/ -structure NotationTransformerState := -(stx : Syntax) --- children of `stx` that have not been consumed yet -(stxArgs : List Syntax := []) --- substitutions for notation variables (reversed) -(substs : List (SyntaxIdent × Syntax) := []) --- filled by `binders` transitions, consumed by `scoped` actions -(scoped : Option $ Term.binders.View := none) - -private def popStxArg : StateT NotationTransformerState TransformM Syntax := -do st ← get, - match st.stxArgs with - | Arg::args := set {st with stxArgs := args} *> pure Arg - | _ := error st.stx "mkNotationTransformer: unreachable" - -def mkNotationTransformer (nota : NotationMacro) : transformer := -λ stx, do - some {args := stxArgs, ..} ← pure stx.asNode - | error stx "mkNotationTransformer: unreachable", - flip StateT.run' {NotationTransformerState . stx := stx, stxArgs := stxArgs} $ do - let spec := nota.nota.spec, - -- Walk through the notation specification, consuming `stx` args and building up substitutions - -- for the notation RHS. - -- Also see `CommandParserConfig.registerNotationParser` for the expected structure of `stx`. - match spec.prefixArg with - | none := pure () - | some Arg := do { stxArg ← popStxArg, modify $ λ st, {st with substs := (Arg, stxArg)::st.substs} }, - nota.nota.spec.rules.mfor (λ r : rule.View, do - match r.symbol with - | notationSymbol.View.quoted {symbol := some a ..} := popStxArg - | _ := error stx "mkNotationTransformer: unreachable", - match r.transition with - | some (transition.View.binder b) := - do { stxArg ← popStxArg, modify $ λ st, {st with scoped := some $ binders.View.extended {leadingIds := [view binderIdent.Parser stxArg]}} } - | some (transition.View.binders b) := - do { stxArg ← popStxArg, modify $ λ st, {st with scoped := some $ view Term.binders.Parser stxArg} } - | some (transition.View.Arg {action := none, id := id}) := - do { stxArg ← popStxArg, modify $ λ st, {st with substs := (id, stxArg)::st.substs} } - | some (transition.View.Arg {action := some {kind := actionKind.View.prec _}, id := id}) := - do { stxArg ← popStxArg, modify $ λ st, {st with substs := (id, stxArg)::st.substs} } - | some (transition.View.Arg {action := some {kind := actionKind.View.scoped sc}, id := id}) := do - stxArg ← popStxArg, - {scoped := some bnders, ..} ← get - | error stx "mkNotationTransformer: unreachable", - -- TODO(Sebastian): not correct with multiple binders - let scLam := review lambda {binders := [sc.id], body := sc.Term}, - let lam := review lambda {binders := bnders, body := stxArg}, - let Arg := review app {fn := scLam, Arg := lam}, - modify $ λ st, {st with substs := (id, Arg)::st.substs} - | none := pure () - | _ := error stx "mkNotationTransformer: unimplemented"), - st ← get, - -- apply substitutions - -- HACK: this substitution completely disregards binders on the notation's RHS. - -- We have discussed switching to a more explicit antiquotation Syntax like %%_ - -- that cannot be abstracted over. - let substs := st.substs.map (λ ⟨id, t⟩, (id.val, t)), - let t := nota.nota.Term.replace $ λ stx, match tryView identUnivs stx with - | some {id := id, univs := none} := pure $ substs.lookup id.val - | _ := pure none, - pure $ some $ t - -def mixfixToNotationSpec (k : mixfix.kind.View) (sym : notationSymbol.View) : TransformM NotationSpec.View := -let prec := match sym with -| notationSymbol.View.quoted q := q.prec -/-| _ := none -/ in --- `notation` allows more Syntax after `:` than mixfix commands, so we have to do a small conversion -let precToAction := λ prec, {action.View . kind := actionKind.View.prec prec} in -match k with -| mixfix.kind.View.prefix _ := - -- `prefix sym:prec` ~> `notation sym:prec b:prec` - pure { - rules := [{ - symbol := sym, - transition := transition.View.Arg {id := `b, - action := precToAction <$> precedence.View.Term <$> prec}}]} -| mixfix.kind.View.postfix _ := - -- `postfix tk:prec` ~> `notation a tk:prec` - pure { - prefixArg := `a, - rules := [{symbol := sym}]} -| mixfix.kind.View.infixr _ := do - -- `infixr tk:prec` ~> `notation a tk:prec b:(prec-1)` - act ← match prec with - | some prec := if prec.Term.toNat = 0 - then error (review «precedence» prec) "invalid `infixr` declaration, given precedence must greater than zero" - else pure $ some $ precToAction $ precedenceTerm.View.lit $ precedenceLit.View.num $ number.View.ofNat $ prec.Term.toNat - 1 - | none := pure none, - pure { - prefixArg := `a, - rules := [{ - symbol := sym, - transition := transition.View.Arg {id := `b, - action := act}}]} -| _ := - -- `infix/infixl tk:prec` ~> `notation a tk:prec b:prec` - pure { - prefixArg := `a, - rules := [{ - symbol := sym, - transition := transition.View.Arg {id := `b, - action := precToAction <$> precedence.View.Term <$> prec}}]} - -def mixfix.transform : transformer := -λ stx, do - let v := view mixfix stx, - let notaSym := match v.symbol with - | mixfixSymbol.View.quoted q := notationSymbol.View.quoted q - | mixfixSymbol.View.unquoted u := notationSymbol.View.quoted {symbol := u}, - spec ← mixfixToNotationSpec v.kind notaSym, - let Term := match v.kind with - | mixfix.kind.View.prefix _ := - -- `prefix tk:prec? := e` ~> `notation tk:prec? b:prec? := e b` - review app {fn := v.Term, Arg := review identUnivs `b} - | mixfix.kind.View.postfix _ := - -- `postfix tk:prec? := e` ~> `notation tk:prec? b:prec? := e b` - review app {fn := v.Term, Arg := review identUnivs `a} - | _ := - review app {fn := review app {fn := v.Term, Arg := review identUnivs `a}, Arg := review identUnivs `b}, - pure $ review «notation» {«local» := v.local, spec := spec, Term := Term} - -def reserveMixfix.transform : transformer := -λ stx, do - let v := view reserveMixfix stx, - spec ← mixfixToNotationSpec v.kind v.symbol, - pure $ review reserveNotation {spec := spec} - -end «notation» - -def mkSimpleBinder (id : SyntaxIdent) (bi : BinderInfo) (type : Syntax) : simpleBinder.View := -let bc : binderContent.View := {ids := [id], type := some {type := type}} in -match bi with -| BinderInfo.default := simpleBinder.View.explicit {id := id, type := type} -| BinderInfo.implicit := simpleBinder.View.implicit {id := id, type := type} -| BinderInfo.strictImplicit := simpleBinder.View.strictImplicit {id := id, type := type} -| BinderInfo.instImplicit := simpleBinder.View.instImplicit {id := id, type := type} -| BinderInfo.auxDecl := /- should not happen -/ - simpleBinder.View.explicit {id := id, type := type} - -def binderIdentToIdent : binderIdent.View → SyntaxIdent -| (binderIdent.View.id id) := id -| (binderIdent.View.hole _) := "a" - -def getOptType : Option typeSpec.View → Syntax -| none := review hole {} -| (some v) := v.type - -def expandBracketedBinder : bracketedBinder.View → TransformM (List simpleBinder.View) --- local notation: should have been handled by caller, erase -| (bracketedBinder.View.explicit {content := explicitBinderContent.View.notation _}) := pure [] -| mbb := do - (bi, bc) ← match mbb with - | bracketedBinder.View.explicit {content := bc} := pure (match bc with - | explicitBinderContent.View.other bc := (BinderInfo.default, bc) - | _ := (BinderInfo.default, {ids := []}) /- unreachable, see above -/) - | bracketedBinder.View.implicit {content := bc} := pure (BinderInfo.implicit, bc) - | bracketedBinder.View.strictImplicit {content := bc} := pure (BinderInfo.strictImplicit, bc) - | bracketedBinder.View.instImplicit {content := bc} := - pure $ Prod.mk BinderInfo.instImplicit $ match bc with - | instImplicitBinderContent.View.anonymous bca := - {ids := ["_inst_"], type := some {type := bca.type}} - | instImplicitBinderContent.View.named bcn := - {ids := [bcn.id], type := some {type := bcn.type}} - | bracketedBinder.View.anonymousConstructor ctor := - error (review anonymousConstructor ctor) "unexpected anonymous Constructor", - let type := getOptType bc.type, - type ← match bc.default with - | none := pure type - | some (binderDefault.View.val bdv) := pure $ mkApp (globId `optParam) [type, bdv.Term] - | some bdv@(binderDefault.View.tac bdt) := match bc.type with - | none := pure $ mkApp (globId `autoParam) [bdt.Term] - | some _ := error (review binderDefault bdv) "unexpected auto Param after Type annotation", - pure $ bc.ids.map (λ bid, mkSimpleBinder (binderIdentToIdent bid) bi type) - -/-- Unfold `binders.View.extended` into `binders.View.simple`. -/ -def expandBinders (mkBinding : binders.View → Syntax → Syntax) (bnders : binders.View) - (body : Syntax) : TransformM (Option Syntax) := do - binders.View.extended extBinders ← pure bnders - | noExpansion, - -- build Result `r` bottom-up - let r := body, - r ← match extBinders.remainder with - | bindersRemainder.View.mixed brms := brms.mfoldr (λ brm r, match brm with - -- anonymous Constructor binding ~> binding + match - | mixedBinder.View.bracketed (bracketedBinder.View.anonymousConstructor ctor) := - pure $ mkBinding (mkSimpleBinder "x" BinderInfo.default (review hole {})) $ review «match» { - scrutinees := [review identUnivs ↑"x"], - equations := [{item := {lhs := [review anonymousConstructor ctor], rhs := r}}] - } - -- local notation: should have been handled by caller, erase - | mixedBinder.View.bracketed mbb := do - bnders ← expandBracketedBinder mbb, - pure $ bnders.foldr (λ bnder, mkBinding bnder) r - | mixedBinder.View.id bid := pure $ - mkBinding (mkSimpleBinder (binderIdentToIdent bid) BinderInfo.default (review hole {})) r - ) r - | _ := pure r, - let leadingTy := match extBinders.remainder with - | bindersRemainder.View.type brt := brt.type - | _ := review hole {}, - let r := extBinders.leadingIds.foldr (λ bid r, - mkBinding (mkSimpleBinder (binderIdentToIdent bid) BinderInfo.default leadingTy) r) r, - pure r - -def bracketedBinders.transform : transformer := -λ stx, do - let v := view bracketedBinders stx, - match v with - | bracketedBinders.View.simple _ := noExpansion - | bracketedBinders.View.extended bnders := do - bnders ← bnders.mmap expandBracketedBinder, - pure $ review bracketedBinders $ bracketedBinders.View.simple $ List.join bnders - -def lambda.transform : transformer := -λ stx, do - let v := view lambda stx, - expandBinders (λ binders body, review lambda {binders := binders, body := body}) v.binders v.body - -def pi.transform : transformer := -λ stx, do - let v := view pi stx, - expandBinders (λ binders body, review pi {op := v.op, binders := binders, range := body}) v.binders v.range - -def depArrow.transform : transformer := -λ stx, do - let v := view depArrow stx, - pure $ review pi { - op := Syntax.atom {val := "Π"}, - binders := binders.View.extended [v.binder], - range := v.range} - -def arrow.transform : transformer := -λ stx, do - let v := view arrow stx, - pure $ review pi { - op := Syntax.atom {val := "Π"}, - binders := binders.View.simple $ simpleBinder.View.explicit {id := `a, type := v.dom}, - range := v.range} - -def paren.transform : transformer := -λ stx, do - let v := view paren stx, - match v.content with - | none := pure $ globId `Unit.unit - | some {Term := t, special := none} := pure t - | some {Term := t, special := parenSpecial.View.tuple tup} := - pure $ (t::tup.tail.map SepBy.Elem.View.item).foldr1Opt (λ t tup, mkApp (globId `Prod.mk) [t, tup]) - | some {Term := t, special := parenSpecial.View.typed pst} := - pure $ mkApp (globId `typedExpr) [pst.type, t] - -def assume.transform : transformer := -λ stx, do - let v := view «assume» stx, - let binders : binders.View := match v.binders with - | assumeBinders.View.anonymous aba := binders.View.simple $ - -- TODO(Sebastian): unhygienic! - simpleBinder.View.explicit {id := "this", type := aba.type} - | assumeBinders.View.binders abb := abb, - pure $ review lambda {binders := binders, body := v.body} - -def if.transform : transformer := -λ stx, do - let v := view «if» stx, - pure $ match v.id with - | some id := mkApp (globId `dite) [v.prop, - review lambda {binders := binders.View.simple $ simpleBinder.View.explicit {id := id.id, type := v.prop}, body := v.thenBranch}, - review lambda {binders := binders.View.simple $ simpleBinder.View.explicit {id := id.id, type := mkApp (globId `Not) [v.prop]}, body := v.elseBranch}] - | none := mkApp (globId `ite) [v.prop, v.thenBranch, v.elseBranch] - -def let.transform : transformer := -λ stx, do - let v := view «let» stx, - match v.lhs with - | letLhs.View.id {id := _, binders := [], type := some _} := noExpansion - | letLhs.View.id lli@{id := _, binders := [], type := none} := - pure $ review «let» {v with lhs := letLhs.View.id {lli with type := some {type := review hole {}}}} - | letLhs.View.id lli@{id := _, binders := _, type := ty} := - let bindrs := binders.View.extended lli.binders in - pure $ review «let» {v with - lhs := letLhs.View.id { - id := lli.id, - binders := [], - type := some {type := review pi {op := Syntax.atom {val := "Π"}, binders := bindrs, range := getOptType ty}}}, - value := review lambda {binders := bindrs, body := v.value}} - | letLhs.View.pattern llp := - pure $ review «match» { - scrutinees := [v.value], - equations := [{item := {lhs := [llp], rhs := v.body}}]} - --- move parameters into Type -def axiom.transform : transformer := -λ stx, do - let v := view «axiom» stx, - match v with - | {sig := {params := bracketedBinders.View.extended bindrs, type := type}, ..} := do - let bindrs := binders.View.extended bindrs, - pure $ review «axiom» {v with sig := { - params := bracketedBinders.View.simple [], - type := {type := review pi {op := Syntax.atom {val := "Π"}, binders := bindrs, range := type.type}}}} - | _ := noExpansion - -def declaration.transform : transformer := -λ stx, do - let v := view «declaration» stx, - match v.inner with - | declaration.inner.View.inductive ind@{«class» := some _, ..} := - let attrs := v.modifiers.attrs.getOrElse {attrs := []} in - pure $ review «declaration» {v with - modifiers := {v.modifiers with attrs := some {attrs with attrs := - {item := {Name := "class", args := []}} :: attrs.attrs}}, - inner := declaration.inner.View.inductive {ind with «class» := none} - } - | declaration.inner.View.structure s@{keyword := structureKw.View.class _, ..} := - let attrs := v.modifiers.attrs.getOrElse {attrs := []} in - pure $ review «declaration» {v with - modifiers := {v.modifiers with attrs := some {attrs with attrs := - {item := {Name := "class", args := []}} :: attrs.attrs}}, - inner := declaration.inner.View.structure {s with keyword := structureKw.View.structure} - } - | _ := noExpansion - -def introRule.transform : transformer := -λ stx, do - let v := view «introRule» stx, - match v.sig with - | {params := bracketedBinders.View.extended bindrs, type := some type} := do - let bindrs := binders.View.extended bindrs, - pure $ review «introRule» {v with sig := { - params := bracketedBinders.View.simple [], - type := some {type := review pi {op := Syntax.atom {val := "Π"}, binders := bindrs, - range := type.type}}}} - | _ := noExpansion - -/- We expand `variable` into `variables` instead of the other way around since, in theory, - elaborating multiple variables at the same time makes it possible to omit more information. -/ -def variable.transform : transformer := -λ stx, do - let v := view «variable» stx, - pure $ review «variables» {binders := bracketedBinders.View.extended [v.binder]} - -@[derive HasView] -def bindingAnnotationUpdate.Parser : termParser := -node! bindingAnnotationUpdate ["dummy"] -- FIXME: bad node! expansion - -def variables.transform : transformer := -λ stx, do - let v := view «variables» stx, - match v.binders with - | bracketedBinders.View.simple _ := noExpansion - | bracketedBinders.View.extended bnders := do - bnders ← bnders.mmap $ λ b, match b with - -- binding annotation update - | bracketedBinder.View.explicit eb@{content := - explicitBinderContent.View.other bc@{ids := ids, type := none, default := none}} := - expandBracketedBinder $ bracketedBinder.View.explicit {eb with content := - explicitBinderContent.View.other {bc with type := some {type := review bindingAnnotationUpdate {}}}} - | _ := expandBracketedBinder b, - pure $ review «variables» {binders := bracketedBinders.View.simple $ List.join bnders} - -def Level.leading.transform : transformer := -λ stx, do - let v := view Level.leading stx, - match v with - | Level.leading.View.paren p := pure p.inner - | _ := noExpansion - -def Subtype.transform : transformer := -λ stx, do - let v := view Term.Subtype stx, - pure $ mkApp (globId `Subtype) [review lambda { - binders := mkSimpleBinder v.id BinderInfo.default $ getOptType v.type, - body := v.prop - }] - -def universes.transform : transformer := -λ stx, do - let v := view «universes» stx, - pure $ Syntax.list $ v.ids.map (λ id, review «universe» {id := id}) - -def sorry.transform : transformer := -λ stx, pure $ mkApp (globId `sorryAx) [review hole {}, globId `Bool.false] - --- TODO(Sebastian): replace with attribute -def builtinTransformers : RBMap Name transformer Name.quickLt := RBMap.fromList [ - (mixfix.name, mixfix.transform), - (reserveMixfix.name, reserveMixfix.transform), - (bracketedBinders.name, bracketedBinders.transform), - (lambda.name, lambda.transform), - (pi.name, pi.transform), - (depArrow.name, depArrow.transform), - (arrow.name, arrow.transform), - (paren.name, paren.transform), - (assume.name, assume.transform), - (if.name, if.transform), - (let.name, let.transform), - (axiom.name, axiom.transform), - (declaration.name, declaration.transform), - (introRule.name, introRule.transform), - (variable.name, variable.transform), - (variables.name, variables.transform), - (Level.leading.name, Level.leading.transform), - (Term.Subtype.name, Subtype.transform), - (universes.name, universes.transform), - (sorry.name, sorry.transform) -] _ - -structure ExpanderState := -(nextScope : MacroScope) - -structure ExpanderConfig extends TransformerConfig := -(transformers : RBMap Name transformer Name.quickLt) - -instance ExpanderConfig.HasLift : HasLift ExpanderConfig TransformerConfig := -⟨ExpanderConfig.toTransformerConfig⟩ - -@[reducible] def ExpanderM := StateT ExpanderState $ ReaderT ExpanderConfig $ ExceptT Message Id - -section -local attribute [reducible] MacroScope -def ExpanderState.new : ExpanderState := ⟨0⟩ -def mkScope : ExpanderM MacroScope := -do st ← get, - set {st with nextScope := st.nextScope + 1}, - pure st.nextScope -end - -private def expandCore : Nat → Syntax → ExpanderM Syntax -| 0 stx := error stx "macro expansion limit exceeded" -| (fuel + 1) stx := -do some n ← pure stx.asNode | pure stx, - cfg ← read, - some t ← pure $ cfg.transformers.find n.kind.name - -- not a macro: recurse - | Syntax.mkNode n.kind <$> n.args.mmap (expandCore fuel), - sc ← mkScope, - let n' := Syntax.mkNode n.kind $ n.args.map (Syntax.flipScopes [sc]), - some stx' ← StateT.lift $ λ cfg, t n' ↑cfg - -- no unfolding: recurse - | Syntax.mkNode n.kind <$> n.args.mmap (expandCore fuel), - -- flip again, expand iteratively - expandCore fuel $ stx'.flipScopes [sc] - -def expand (stx : Syntax) : ReaderT ExpanderConfig (Except Message) Syntax := --- TODO(Sebastian): persist macro scopes across commands/files -Prod.fst <$> expandCore 1000 stx ExpanderState.new - -end Expander -end Lean diff --git a/tmp/new-frontend/frontend.lean b/tmp/new-frontend/frontend.lean deleted file mode 100644 index 5147e49261..0000000000 --- a/tmp/new-frontend/frontend.lean +++ /dev/null @@ -1,91 +0,0 @@ -/- -Copyright (c) 2018 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Author: Sebastian Ullrich --/ - -import init.lean.parser.module init.lean.expander init.lean.elaborator init.lean.util init.io - -namespace Lean -open Lean.Parser -open Lean.Expander -open Lean.Elaborator - -def mkConfig (filename := "") (input := "") : Except String ModuleParserConfig := -do t ← Parser.mkTokenTrie $ - Parser.tokens Module.header.Parser ++ - Parser.tokens command.builtinCommandParsers ++ - Parser.tokens Term.builtinLeadingParsers ++ - Parser.tokens Term.builtinTrailingParsers, - pure $ { - filename := filename, input := input, tokens := t, - fileMap := FileMap.fromString input, - commandParsers := command.builtinCommandParsers, - leadingTermParsers := Term.builtinLeadingParsers, - trailingTermParsers := Term.builtinTrailingParsers, - } - -def runFrontend (filename input : String) (printMsg : Message → IO Unit) (collectOutputs : Bool) : - StateT Environment IO (List Syntax) := λ env, do - parserCfg ← ioOfExcept $ mkConfig filename input, - -- TODO(Sebastian): `parseHeader` should be called directly by Lean.cpp - match parseHeader parserCfg with - | (_, Except.error msg) := printMsg msg *> pure ([], env) - | (_, Except.ok (pSnap, msgs)) := do - msgs.toList.mfor printMsg, - let expanderCfg : ExpanderConfig := {transformers := builtinTransformers, ..parserCfg}, - let elabCfg : ElaboratorConfig := {filename := filename, input := input, initialParserCfg := parserCfg, ..parserCfg}, - let opts := Options.empty.setBool `trace.as_messages true, - let elabSt := Elaborator.mkState elabCfg env opts, - let addOutput (out : Syntax) outs := if collectOutputs then out::outs else [], - IO.Prim.iterate (pSnap, elabSt, parserCfg, expanderCfg, ([] : List Syntax)) $ λ ⟨pSnap, elabSt, parserCfg, expanderCfg, outs⟩, do { - let pos := parserCfg.fileMap.toPosition pSnap.it.offset, - r ← monadLift $ profileitPure "parsing" pos $ λ _, parseCommand parserCfg pSnap, - match r with - | (cmd, Except.error msg) := do { - -- fatal error (should never happen?) - printMsg msg, - msgs.toList.mfor printMsg, - pure $ Sum.inr ((addOutput cmd outs).reverse, elabSt.env) - } - | (cmd, Except.ok (pSnap, msgs)) := do { - msgs.toList.mfor printMsg, - r ← monadLift $ profileitPure "expanding" pos $ λ _, (expand cmd).run expanderCfg, - match r with - | Except.ok cmd' := do { - --IO.println cmd', - elabSt ← monadLift $ profileitPure "elaborating" pos $ λ _, Elaborator.processCommand elabCfg elabSt cmd', - elabSt.messages.toList.mfor printMsg, - if cmd'.isOfKind Module.eoi then - /-printMsg {filename := filename, severity := MessageSeverity.information, - pos := ⟨1, 0⟩, - text := "Parser cache hit rate: " ++ toString out.cache.hit ++ "/" ++ - toString (out.cache.hit + out.cache.miss)},-/ - pure $ Sum.inr ((addOutput cmd outs).reverse, elabSt.env) - else - pure (Sum.inl (pSnap, elabSt, elabSt.parserCfg, elabSt.expanderCfg, addOutput cmd outs)) - } - | Except.error e := printMsg e *> pure (Sum.inl (pSnap, elabSt, parserCfg, expanderCfg, addOutput cmd outs)) - } - } - -@[export lean_process_file] -def processFile (f s : String) (json : Bool) : StateT Environment IO Unit := do - let printMsg : Message → IO Unit := λ msg, - if json then - IO.println $ "{\"file_name\": \"\", \"pos_line\": " ++ toString msg.pos.line ++ - ", \"pos_col\": " ++ toString msg.pos.column ++ - ", \"severity\": " ++ repr (match msg.severity with - | MessageSeverity.information := "information" - | MessageSeverity.warning := "warning" - | MessageSeverity.error := "error") ++ - ", \"caption\": " ++ repr msg.caption ++ - ", \"text\": " ++ repr msg.text ++ "}" - else IO.println msg.toString, - -- print and erase uncaught exceptions - catch - (runFrontend f s printMsg false *> pure ()) - (λ e, do - monadLift (printMsg {filename := f, severity := MessageSeverity.error, pos := ⟨1, 0⟩, text := e}), - throw e) -end Lean diff --git a/tmp/new-frontend/parser/basic.lean b/tmp/new-frontend/parser/basic.lean deleted file mode 100644 index f6c7f0d7cb..0000000000 --- a/tmp/new-frontend/parser/basic.lean +++ /dev/null @@ -1,226 +0,0 @@ -/- -Copyright (c) 2018 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Author: Sebastian Ullrich - -Parser for the Lean language --/ -prelude -import init.lean.parser.parsec init.lean.parser.syntax init.lean.parser.rec -import init.lean.parser.trie -import init.lean.parser.identifier init.data.rbmap init.lean.message - -namespace Lean -namespace Parser - -/- Maximum standard precedence. This is the precedence of Function application. - In the standard Lean language, only the token `.` has a left-binding power greater - than `maxPrec` (so that field accesses like `g (h x).f` are parsed as `g ((h x).f)`, - not `(g (h x)).f`). -/ -def maxPrec : Nat := 1024 - -structure TokenConfig := -(«prefix» : String) -/- Left-binding power used by the Term Parser. The Term Parser operates in the context - of a right-binding power between 0 (used by parentheses and on the top-Level) and - (usually) `maxPrec` (used by Function application). After parsing an initial Term, - it continues parsing and expanding that Term only when the left-binding power of - the next token is greater than the current right-binding power. For example, it - never continues parsing an argument after the initial parse, unless a token with - lbp > maxPrec is encountered. Conversely, the Term Parser will always continue - parsing inside parentheses until it finds a token with lbp 0 (such as `)`). -/ -(lbp : Nat := 0) --- reading a token should not need any State -/- An optional Parser that is activated after matching `prefix`. - It should return a Syntax tree with a "hole" for the - `SourceInfo` surrounding the token, which will be supplied - by the `token` Parser. - - Remark: `suffixParser` has many applications for example for parsing - hexdecimal numbers, `prefix` is `0x` and `suffixParser` is the Parser `digit*`. - We also use it to parse String literals: here `prefix` is just `"`. --/ -(suffixParser : Option (Parsec' (SourceInfo → Syntax)) := none) - --- Backtrackable State -structure ParserState := -(messages : MessageLog) - -structure TokenCacheEntry := -(startIt stopIt : String.OldIterator) -(tk : Syntax) - --- Non-backtrackable State -structure ParserCache := -(tokenCache : Option TokenCacheEntry := none) --- for profiling -(hit miss : Nat := 0) - -structure FrontendConfig := -(filename : String) -(input : String) -(fileMap : FileMap) - -/- Remark: if we have a Node in the Trie with `some TokenConfig`, the String induced by the path is equal to the `TokenConfig.prefix`. -/ -structure ParserConfig extends FrontendConfig := -(tokens : Trie TokenConfig) - -instance parserConfigCoe : HasCoe ParserConfig FrontendConfig := -⟨ParserConfig.toFrontendConfig⟩ - -@[derive Monad Alternative MonadParsec MonadExcept] -def parserCoreT (m : Type → Type) [Monad m] := -ParsecT Syntax $ StateT ParserCache $ m - -@[derive Monad Alternative MonadReader MonadParsec MonadExcept] -def ParserT (ρ : Type) (m : Type → Type) [Monad m] := ReaderT ρ $ parserCoreT m -@[derive Monad Alternative MonadReader MonadParsec MonadExcept] -def BasicParserM := ParserT ParserConfig Id -abbrev basicParser := BasicParserM Syntax -abbrev monadBasicParser := HasMonadLiftT BasicParserM - -section -local attribute [reducible] BasicParserM ParserT parserCoreT -@[inline] def getCache : BasicParserM ParserCache := -monadLift (get : StateT ParserCache Id _) - -@[inline] def putCache : ParserCache → BasicParserM PUnit := -λ c, monadLift (set c : StateT ParserCache Id _) -end - - -- an arbitrary `Parser` Type; parsers are usually some Monad stack based on `BasicParserM` returning `Syntax` -variable {ρ : Type} - -class HasTokens (r : ρ) := mk {} :: -(tokens : List TokenConfig) - -@[noinline, nospecialize] def tokens (r : ρ) [HasTokens r] := -HasTokens.tokens r - -instance HasTokens.Inhabited (r : ρ) : Inhabited (HasTokens r) := -⟨⟨[]⟩⟩ - -instance List.nil.tokens : Parser.HasTokens ([] : List ρ) := -default _ - -instance List.cons.tokens (r : ρ) (rs : List ρ) [Parser.HasTokens r] [Parser.HasTokens rs] : - Parser.HasTokens (r::rs) := -⟨tokens r ++ tokens rs⟩ - -class HasView (α : outParam Type) (r : ρ) := -(view : Syntax → α) -(review : α → Syntax) - -export HasView (view review) - -def tryView {α : Type} (k : SyntaxNodeKind) [HasView α k] (stx : Syntax) : Option α := -if stx.isOfKind k then some (HasView.view k stx) else none - -instance HasView.default (r : ρ) : Inhabited (Parser.HasView Syntax r) := -⟨{ view := id, review := id }⟩ - -class HasViewDefault (r : ρ) (α : outParam Type) [HasView α r] (default : α) := mk {} - -def messageOfParsecMessage {μ : Type} (cfg : FrontendConfig) (msg : Parsec.Message μ) : Message := -{filename := cfg.filename, pos := cfg.fileMap.toPosition msg.it.offset, text := msg.text} - -/-- Run Parser stack, returning a partial Syntax tree in case of a fatal error -/ -protected def run {m : Type → Type} {α ρ : Type} [Monad m] [HasCoeT ρ FrontendConfig] (cfg : ρ) (s : String) (r : StateT ParserState (ParserT ρ m) α) : -m (Sum α Syntax × MessageLog) := -do (r, _) ← (((r.run {messages:=MessageLog.empty}).run cfg).parse s).run {}, -pure $ match r with -| Except.ok (a, st) := (Sum.inl a, st.messages) -| Except.error msg := (Sum.inr msg.custom.get, MessageLog.empty.add (messageOfParsecMessage cfg msg)) - -open MonadParsec -open Parser.HasView -variables {α : Type} {m : Type → Type} -local notation `Parser` := m Syntax - -def logMessage {μ : Type} [Monad m] [MonadReader ρ m] [HasLiftT ρ FrontendConfig] [MonadState ParserState m] - (msg : Parsec.Message μ) : m Unit := -do cfg ← read, - modify (λ st, {st with messages := st.messages.add (messageOfParsecMessage ↑cfg msg)}) - -def mkTokenTrie (tokens : List TokenConfig) : Except String (Trie TokenConfig) := -do -- the only hardcoded tokens, because they are never directly mentioned by a `Parser` - let builtinTokens : List TokenConfig := [{«prefix» := "/-"}, {«prefix» := "--"}], - t ← (builtinTokens ++ tokens).mfoldl (λ (t : Trie TokenConfig) tk, - match t.find tk.prefix with - | some tk' := match tk.lbp, tk'.lbp with - | l, 0 := pure $ t.insert tk.prefix tk - | 0, _ := pure t - | l, l' := if l = l' then pure t else throw $ - "invalid token '" ++ tk.prefix ++ "', has been defined with precedences " ++ - toString l ++ " and " ++ toString l' - | none := pure $ t.insert tk.prefix tk) - Trie.empty, - pure t - - -/- Monad stacks used in multiple files -/ - -/- NOTE: We move `RecT` under `ParserT`'s `ReaderT` so that `termParser`, which does not - have access to `commandParser`'s ρ (=`CommandParserConfig`) can still recurse into it - (for command quotations). This means that the `CommandParserConfig` will be reset - on a recursive call to `command.Parser`, i.e. it forgets about locally registered parsers, - but that's not an issue for our intended uses of it. -/ -@[derive Monad Alternative MonadReader MonadParsec MonadExcept MonadRec] -def CommandParserM (ρ : Type) := ReaderT ρ $ RecT Unit Syntax $ parserCoreT Id - -section -local attribute [reducible] ParserT CommandParserM -instance CommandParserM.MonadReaderAdapter (ρ ρ' : Type) : - MonadReaderAdapter ρ ρ' (CommandParserM ρ) (CommandParserM ρ') := -inferInstance -instance CommandParserM.basicParser (ρ : Type) [HasLiftT ρ ParserConfig] : monadBasicParser (CommandParserM ρ) := -⟨λ _ x cfg rec, x.run ↑cfg⟩ -end - -/- The `Nat` at `RecT` is the lbp` -/ -@[derive Monad Alternative MonadReader MonadParsec MonadExcept MonadRec monadBasicParser] -def TermParserM := RecT Nat Syntax $ CommandParserM ParserConfig -abbrev termParser := TermParserM Syntax - -/-- A Term Parser for a suffix or infix notation that accepts a preceding Term. -/ -@[derive Monad Alternative MonadReader MonadParsec MonadExcept MonadRec monadBasicParser] -def TrailingTermParserM := ReaderT Syntax TermParserM -abbrev trailingTermParser := TrailingTermParserM Syntax - -instance trailingTermParserCoe : HasCoe termParser trailingTermParser := -⟨λ x _, x⟩ - -/-- A multimap indexed by tokens. Used for indexing parsers by their leading token. -/ -def TokenMap (α : Type) := RBMap Name (List α) Name.quickLt - -def TokenMap.insert {α : Type} (map : TokenMap α) (k : Name) (v : α) : TokenMap α := -match map.find k with -| none := map.insert k [v] -| some vs := map.insert k (v::vs) - -def TokenMap.ofList {α : Type} : List (Name × α) → TokenMap α -| [] := mkRBMap _ _ _ -| (⟨k,v⟩::xs) := (TokenMap.ofList xs).insert k v - -instance tokenMapNil.tokens : Parser.HasTokens $ @TokenMap.ofList ρ [] := -default _ - -instance tokenMapCons.tokens (k : Name) (r : ρ) (rs : List (Name × ρ)) [Parser.HasTokens r] [Parser.HasTokens $ TokenMap.ofList rs] : - Parser.HasTokens $ TokenMap.ofList ((k,r)::rs) := -⟨tokens r ++ tokens (TokenMap.ofList rs)⟩ - --- This needs to be a separate structure since `termParser`s cannot contain themselves in their config -structure CommandParserConfig extends ParserConfig := -(leadingTermParsers : TokenMap termParser) -(trailingTermParsers : TokenMap trailingTermParser) --- local Term parsers (such as from `local notation`) hide previous parsers instead of overloading them -(localLeadingTermParsers : TokenMap termParser := mkRBMap _ _ _) -(localTrailingTermParsers : TokenMap trailingTermParser := mkRBMap _ _ _) - -instance commandParserConfigCoeParserConfig : HasCoe CommandParserConfig ParserConfig := -⟨CommandParserConfig.toParserConfig⟩ - -abbrev commandParser := CommandParserM CommandParserConfig Syntax - -end «Parser» -end Lean diff --git a/tmp/new-frontend/parser/combinators.lean b/tmp/new-frontend/parser/combinators.lean deleted file mode 100644 index 1a9a801f1d..0000000000 --- a/tmp/new-frontend/parser/combinators.lean +++ /dev/null @@ -1,247 +0,0 @@ -/- -Copyright (c) 2018 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Author: Sebastian Ullrich - -Syntax-tree creating Parser Combinators --/ -prelude -import init.lean.parser.basic -import init.data.list.instances - -namespace Lean -namespace Parser - -namespace Combinators -open HasTokens HasView MonadParsec - -variables {α : Type} {m : Type → Type} -local notation `Parser` := m Syntax -variables [Monad m] [MonadExcept (Parsec.Message Syntax) m] [MonadParsec Syntax m] [Alternative m] - -def node (k : SyntaxNodeKind) (rs : List Parser) : Parser := -do args ← rs.mfoldl (λ (args : List Syntax) r, do - -- on error, append partial Syntax tree to previous successful parses and rethrow - a ← catch r $ λ msg, match args with - -- do not wrap an error in the first argument to uphold the invariant documented at `SyntaxNode` - | [] := throw msg - | _ := - let args := msg.custom.get :: args in - throw {msg with custom := Syntax.mkNode k args.reverse}, - pure (a::args) - ) [], - pure $ Syntax.mkNode k args.reverse - -@[reducible] def seq : List Parser → Parser := node noKind - -instance node.tokens (k) (rs : List Parser) [Parser.HasTokens rs] : Parser.HasTokens (node k rs) := -⟨tokens rs⟩ - -instance node.view (k) (rs : List Parser) [i : HasView α k] : Parser.HasView α (node k rs) := -{ view := i.view, review := i.review } - --- Each Parser Combinator comes equipped with `HasView` and `HasTokens` instances - -private def many1Aux (p : Parser) : List Syntax → Nat → Parser -| as 0 := error "unreachable" -| as (n+1) := do - a ← catch p (λ msg, throw {msg with custom := - -- append `Syntax.missing` to make clear that List is incomplete - Syntax.list (Syntax.missing::msg.custom.get::as).reverse}), - many1Aux (a::as) n <|> pure (Syntax.list (a::as).reverse) - -def many1 (r : Parser) : Parser := -do rem ← remaining, many1Aux r [] (rem+1) - -instance many1.tokens (r : Parser) [Parser.HasTokens r] : Parser.HasTokens (many1 r) := -⟨tokens r⟩ - -instance many1.view (r : Parser) [Parser.HasView α r] : Parser.HasView (List α) (many1 r) := -{ view := λ stx, match stx.asNode with - | some n := n.args.map (HasView.view r) - | _ := [HasView.view r Syntax.missing], - review := λ as, Syntax.list $ as.map (review r) } - -def many (r : Parser) : Parser := -many1 r <|> pure (Syntax.list []) - -instance many.tokens (r : Parser) [Parser.HasTokens r] : Parser.HasTokens (many r) := -⟨tokens r⟩ - -instance many.view (r : Parser) [HasView α r] : Parser.HasView (List α) (many r) := -/- Remark: `many1.view` can handle empty list. -/ -{..many1.view r} - -private def sepByAux (p : m Syntax) (sep : Parser) (allowTrailingSep : Bool) : Bool → List Syntax → Nat → Parser -| pOpt as 0 := error "unreachable" -| pOpt as (n+1) := do - let p := if pOpt then some <$> p <|> pure none else some <$> p, - some a ← catch p (λ msg, throw {msg with custom := - -- append `Syntax.missing` to make clear that List is incomplete - Syntax.list (Syntax.missing::msg.custom.get::as).reverse}) - | pure (Syntax.list as.reverse), - -- I don't want to think about what the output on a failed separator parse should look like - let sep := try sep, - some s ← some <$> sep <|> pure none - | pure (Syntax.list (a::as).reverse), - sepByAux allowTrailingSep (s::a::as) n - -def sepBy (p sep : Parser) (allowTrailingSep := true) : Parser := -do rem ← remaining, sepByAux p sep allowTrailingSep true [] (rem+1) - -def sepBy1 (p sep : Parser) (allowTrailingSep := true) : Parser := -do rem ← remaining, sepByAux p sep allowTrailingSep false [] (rem+1) - -instance sepBy.tokens (p sep : Parser) (a) [Parser.HasTokens p] [Parser.HasTokens sep] : - Parser.HasTokens (sepBy p sep a) := -⟨tokens p ++ tokens sep⟩ - -structure SepBy.Elem.View (α β : Type) := -(item : α) -(separator : Option β := none) - -instance SepBy.Elem.View.itemCoe {α β : Type} : HasCoeT α (SepBy.Elem.View α β) := -⟨λ a, ⟨a, none⟩⟩ - -private def sepBy.viewAux {α β} (p sep : Parser) [Parser.HasView α p] [Parser.HasView β sep] : - List Syntax → List (SepBy.Elem.View α β) -| [] := [] -| [stx] := [⟨HasView.view p stx, none⟩] -| (stx1::stx2::stxs) := ⟨HasView.view p stx1, some $ HasView.view sep stx2⟩::sepBy.viewAux stxs - -instance sepBy.view {α β} (p sep : Parser) (a) [Parser.HasView α p] [Parser.HasView β sep] : - Parser.HasView (List (SepBy.Elem.View α β)) (sepBy p sep a) := -{ view := λ stx, match stx.asNode with - | some n := sepBy.viewAux p sep n.args - | _ := [⟨view p Syntax.missing, none⟩], - review := λ as, Syntax.list $ as.bind (λ a, match a with - | ⟨v, some vsep⟩ := [review p v, review sep vsep] - | ⟨v, none⟩ := [review p v]) } - -instance sepBy1.tokens (p sep : Parser) (a) [Parser.HasTokens p] [Parser.HasTokens sep] : - Parser.HasTokens (sepBy1 p sep a) := -⟨tokens (sepBy p sep a)⟩ - -instance sepBy1.View {α β} (p sep : Parser) (a) [Parser.HasView α p] [Parser.HasView β sep] : - Parser.HasView (List (SepBy.Elem.View α β)) (sepBy1 p sep a) := -{..sepBy.view p sep a} - -/-- Optionally parse `r`. `require` can be used to conditionally override the - behavior without changing the structure of the syntax tree. -/ -def optional (r : Parser) (require := false) : Parser := -if require then r else -do r ← optional $ - -- on error, wrap in "some" - catch r (λ msg, throw {msg with custom := Syntax.list [msg.custom.get]}), - pure $ match r with - | some r := Syntax.list [r] - | none := Syntax.list [] - -instance optional.tokens (r : Parser) [Parser.HasTokens r] (req) : Parser.HasTokens (optional r req) := -⟨tokens r⟩ -instance optional.view (r : Parser) [Parser.HasView α r] (req) : Parser.HasView (Option α) (optional r req) := -{ view := λ stx, match stx.asNode with - | some {args := [], ..} := none - | some {args := [stx], ..} := some $ HasView.view r stx - | _ := some $ view r Syntax.missing, - review := λ a, match a with - | some a := Syntax.list [review r a] - | none := Syntax.list [] } -instance optional.viewDefault (r : Parser) [Parser.HasView α r] (req) : Parser.HasViewDefault (optional r req) (Option α) none := ⟨⟩ - -/-- Parse a List `[p1, ..., pn]` of parsers as `p1 <|> ... <|> pn`. - Note that there is NO explicit encoding of which Parser was chosen; - parsers should instead produce distinct Node names for disambiguation. -/ -def anyOf (rs : List Parser) : Parser := -match rs with -| [] := error "anyOf" -| (r::rs) := rs.foldl (<|>) r - -instance anyOf.tokens (rs : List Parser) [Parser.HasTokens rs] : Parser.HasTokens (anyOf rs) := -⟨tokens rs⟩ -instance anyOf.view (rs : List Parser) : Parser.HasView Syntax (anyOf rs) := default _ - -/-- Parse a List `[p1, ..., pn]` of parsers with `MonadParsec.longestMatch`. - If the Result is ambiguous, wrap it in a `choice` Node. - Note that there is NO explicit encoding of which Parser was chosen; - parsers should instead produce distinct Node names for disambiguation. -/ -def longestMatch (rs : List Parser) : Parser := -do stxs ← MonadParsec.longestMatch rs, - match stxs with - | [stx] := pure stx - | _ := pure $ Syntax.mkNode choice stxs - -instance longestMatch.tokens (rs : List Parser) [Parser.HasTokens rs] : Parser.HasTokens (longestMatch rs) := -⟨tokens rs⟩ -instance longestMatch.view (rs : List Parser) : Parser.HasView Syntax (longestMatch rs) := default _ - -def choiceAux : List Parser → Nat → Parser -| [] _ := error "choice: Empty List" -| (r::rs) i := - do { stx ← r, - pure $ Syntax.mkNode ⟨Name.mkNumeral Name.anonymous i⟩ [stx] } - <|> choiceAux rs (i+1) - -/-- Parse a List `[p1, ..., pn]` of parsers as `p1 <|> ... <|> pn`. - The Result will be wrapped in a Node with the index of the successful - Parser as the Name. - - Remark: Does not have a `HasView` instance because we only use it in `nodeChoice!` macros - that define their own views. -/ -def choice (rs : List Parser) : Parser := -choiceAux rs 0 - -instance choice.tokens (rs : List Parser) [Parser.HasTokens rs] : Parser.HasTokens (choice rs) := -⟨tokens rs⟩ - -/-- Like `choice`, but using `longestMatch`. Does not create choice nodes, prefers the first successful Parser. -/ -def longestChoice (rs : List Parser) : Parser := -do stx::stxs ← MonadParsec.longestMatch $ rs.enum.map $ λ ⟨i, r⟩, do { - stx ← r, - pure $ Syntax.mkNode ⟨Name.mkNumeral Name.anonymous i⟩ [stx] - } | error "unreachable", - pure stx - -instance longestChoice.tokens (rs : List Parser) [Parser.HasTokens rs] : Parser.HasTokens (longestChoice rs) := - -⟨tokens rs⟩ -instance try.tokens (r : Parser) [Parser.HasTokens r] : Parser.HasTokens (try r) := -⟨tokens r⟩ -instance try.view (r : Parser) [i : Parser.HasView α r] : Parser.HasView α (try r) := -{..i} - -instance label.tokens (r : Parser) (l) [Parser.HasTokens r] : Parser.HasTokens (label r l) := -⟨tokens r⟩ -instance label.view (r : Parser) (l) [i : Parser.HasView α r] : Parser.HasView α (label r l) := -{..i} - -instance recurse.tokens (α δ m a) [MonadRec α δ m] : Parser.HasTokens (recurse a : m δ) := -default _ -- recursive use should not contribute any new tokens -instance recurse.view (α δ m a) [MonadRec α δ m] : Parser.HasView Syntax (recurse a : m δ) := default _ - -instance monadLift.tokens {m' : Type → Type} [HasMonadLiftT m m'] (r : m Syntax) [Parser.HasTokens r] : - Parser.HasTokens (monadLift r : m' Syntax) := -⟨tokens r⟩ -instance monadLift.view {m' : Type → Type} [HasMonadLiftT m m'] (r : m Syntax) [i : Parser.HasView α r] : - Parser.HasView α (monadLift r : m' Syntax) := -{..i} - -instance seqLeft.tokens {α : Type} (x : m α) (p : m Syntax) [Parser.HasTokens p] : Parser.HasTokens (p <* x) := -⟨tokens p⟩ -instance seqLeft.view {α β : Type} (x : m α) (p : m Syntax) [i : Parser.HasView β p] : Parser.HasView β (p <* x) := -{..i} - -instance seqRight.tokens {α : Type} (x : m α) (p : m Syntax) [Parser.HasTokens p] : Parser.HasTokens (x *> p) := -⟨tokens p⟩ -instance seqRight.view {α β : Type} (x : m α) (p : m Syntax) [i : Parser.HasView β p] : Parser.HasView β (x *> p) := -{..i} - -instance coe.tokens {β} (r : Parser) [Parser.HasTokens r] [HasCoeT Parser β]: Parser.HasTokens (coe r : β) := -⟨tokens r⟩ -instance coe.view {β} (r : Parser) [i : Parser.HasView α r] [HasCoeT Parser β] : Parser.HasView α (coe r : β) := -{..i} -instance coe.viewDefault {β} (d : α) (r : Parser) [HasView α r] [Parser.HasViewDefault r α d] [HasCoeT Parser β] : Parser.HasViewDefault (coe r : β) α d := ⟨⟩ - -end Combinators -end Parser -end Lean diff --git a/tmp/new-frontend/parser/command.lean b/tmp/new-frontend/parser/command.lean deleted file mode 100644 index d43aa19346..0000000000 --- a/tmp/new-frontend/parser/command.lean +++ /dev/null @@ -1,165 +0,0 @@ -/- -Copyright (c) 2018 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Author: Sebastian Ullrich - -Command parsers --/ -prelude -import init.lean.parser.declaration - -namespace Lean -namespace Parser - -open Combinators MonadParsec -open Parser.HasTokens Parser.HasView - -local postfix `?`:10000 := optional -local postfix *:10000 := Combinators.many -local postfix +:10000 := Combinators.many1 - -set_option class.instance_max_depth 300 - -@[derive Parser.HasView Parser.HasTokens] -def command.Parser : commandParser := -recurse () "command" - -namespace «command» - -@[derive Parser.HasView Parser.HasTokens] -def openSpec.Parser : commandParser := -node! openSpec [ - id: ident.Parser, - as: node! openSpec.as ["as", id: ident.Parser]?, - only: node! openSpec.only [try ["(", id: ident.Parser], ids: ident.Parser*, ")"]?, - «renaming»: node! openSpec.renaming [try ["(", "renaming"], items: node! openSpec.renaming.item [«from»: ident.Parser, "->", to: ident.Parser]+, ")"]?, - «hiding»: node! openSpec.hiding ["(", "hiding", ids: ident.Parser+, ")"]? -]+ - -@[derive Parser.HasTokens] -def open.Parser : commandParser := -node! «open» ["open", spec: openSpec.Parser] - -@[derive Parser.HasTokens] -def export.Parser : commandParser := -node! «export» ["export", spec: openSpec.Parser] - -@[derive Parser.HasTokens] -def section.Parser : commandParser := -node! «section» ["section", Name: ident.Parser?] - -@[derive Parser.HasTokens] -def namespace.Parser : commandParser := -node! «namespace» ["namespace", Name: ident.Parser] - -@[derive Parser.HasTokens] -def variable.Parser : commandParser := -node! «variable» ["variable", binder: Term.binder.Parser] - -@[derive Parser.HasTokens] -def variables.Parser : commandParser := --- TODO: should require at least one binder -node! «variables» ["variables", binders: Term.bracketedBinders.Parser] - -@[derive Parser.HasTokens] -def include.Parser : commandParser := -node! «include» ["include ", ids: ident.Parser+] - -@[derive Parser.HasTokens] -def omit.Parser : commandParser := -node! «omit» ["omit ", ids: ident.Parser+] - -@[derive Parser.HasTokens] -def end.Parser : commandParser := -node! «end» ["end", Name: ident.Parser?] - -@[derive Parser.HasTokens] -def universe.Parser : commandParser := -anyOf [ - node! «universes» ["universes", ids: ident.Parser+], - node! «universe» ["universe", id: ident.Parser] -] - -@[derive Parser.HasTokens Parser.HasView] -def check.Parser : commandParser := -node! check ["#check", Term: Term.Parser] - -@[derive Parser.HasTokens Parser.HasView] -def attribute.Parser : commandParser := -node! «attribute» [ - try [«local»: (symbol "local ")?, "attribute "], - "[", - attrs: sepBy1 attrInstance.Parser (symbol ", "), - "] ", - ids: ident.Parser* -] - -@[derive Parser.HasTokens Parser.HasView] -def initQuot.Parser : commandParser := -node! «initQuot» ["initQuot"] - -@[derive Parser.HasTokens Parser.HasView] -def setOption.Parser : commandParser := -node! «setOption» ["setOption", opt: ident.Parser, val: nodeChoice! optionValue { - Bool: nodeChoice! boolOptionValue { - True: symbolOrIdent "true", - False: symbolOrIdent "false", - }, - String: stringLit.Parser, - -- TODO(Sebastian): fractional numbers - num: number.Parser, -}] - -@[derive HasTokens] -def builtinCommandParsers : TokenMap commandParser := TokenMap.ofList [ - ("/--", declaration.Parser), - ("@[", declaration.Parser), - ("private", declaration.Parser), - ("protected", declaration.Parser), - ("noncomputable", declaration.Parser), - ("unsafe", declaration.Parser), - ("def", declaration.Parser), - ("abbreviation", declaration.Parser), - ("abbrev", declaration.Parser), - ("theorem", declaration.Parser), - ("instance", declaration.Parser), - ("axiom", declaration.Parser), - ("constant", declaration.Parser), - ("class", declaration.Parser), - ("inductive", declaration.Parser), - ("structure", declaration.Parser), - - ("variable", variable.Parser), - ("variables", variables.Parser), - ("namespace", namespace.Parser), - ("end", end.Parser), - ("open", open.Parser), - ("section", section.Parser), - ("universe", universe.Parser), - ("universes", universe.Parser), - ("local", notation.Parser), - ("notation", notation.Parser), - ("reserve", reserveNotation.Parser), - ("local", mixfix.Parser), - ("prefix", mixfix.Parser), - ("infix", mixfix.Parser), - ("infixl", mixfix.Parser), - ("infixr", mixfix.Parser), - ("postfix", mixfix.Parser), - ("reserve", reserveMixfix.Parser), - ("#check", check.Parser), - ("local", attribute.Parser), - ("attribute", attribute.Parser), - ("export", export.Parser), - ("include", include.Parser), - ("omit", omit.Parser), - ("initQuot", initQuot.Parser), - ("setOption", setOption.Parser)] -end «command» - -def commandParser.run (commands : TokenMap commandParser) (p : commandParser) - : ParserT CommandParserConfig Id Syntax := -λ cfg, (p.run cfg).runParsec $ λ _, (indexed commands >>= anyOf : commandParser).run cfg - -end Parser -end Lean diff --git a/tmp/new-frontend/parser/declaration.lean b/tmp/new-frontend/parser/declaration.lean deleted file mode 100644 index 6cf4322341..0000000000 --- a/tmp/new-frontend/parser/declaration.lean +++ /dev/null @@ -1,167 +0,0 @@ -/- -Copyright (c) 2018 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Author: Sebastian Ullrich - -Parsers for commands that declare things --/ - -prelude -import init.lean.parser.term - -namespace Lean -namespace Parser - -open Combinators MonadParsec -open Parser.HasTokens Parser.HasView - -instance termParserCommandParserCoe : HasCoe termParser commandParser := -⟨λ p, adaptReader coe $ p.run⟩ - -namespace «command» - -local postfix `?`:10000 := optional -local postfix *:10000 := Combinators.many -local postfix +:10000 := Combinators.many1 - -@[derive HasTokens HasView] -def docComment.Parser : commandParser := -node! docComment ["/--", doc: raw $ many' (notFollowedBy (str "-/") *> any), "-/"] - -@[derive HasTokens HasView] -def attrInstance.Parser : commandParser := --- use `rawIdent` because of attribute names such as `instance` -node! attrInstance [Name: rawIdent.Parser, args: (Term.Parser maxPrec)*] - -@[derive HasTokens HasView] -def declAttributes.Parser : commandParser := --- TODO(Sebastian): custom attribute parsers -node! declAttributes ["@[", attrs: sepBy1 attrInstance.Parser (symbol ","), "]"] - -set_option class.instance_max_depth 300 - -@[derive HasTokens HasView] -def declModifiers.Parser : commandParser := -node! declModifiers [ - docComment: docComment.Parser?, - attrs: declAttributes.Parser?, - visibility: nodeChoice! visibility {"private", "protected"}?, - «noncomputable»: (symbol "noncomputable")?, - «unsafe»: (symbol "unsafe")?, -] - -@[derive HasTokens HasView] -def declSig.Parser : commandParser := -node! declSig [ - params: Term.bracketedBinders.Parser, - type: Term.typeSpec.Parser, -] - -@[derive HasTokens HasView] -def optDeclSig.Parser : commandParser := -node! optDeclSig [ - params: Term.bracketedBinders.Parser, - type: Term.optType.Parser, -] - -@[derive HasTokens HasView] -def equation.Parser : commandParser := -node! equation ["|", lhs: (Term.Parser maxPrec)+, ":=", rhs: Term.Parser] - -@[derive HasTokens HasView] -def declVal.Parser : commandParser := -nodeChoice! declVal { - simple: node! simpleDeclVal [":=", body: Term.Parser], - emptyMatch: symbol ".", - «match»: equation.Parser+ -} - -@[derive HasTokens HasView] -def inferModifier.Parser : commandParser := -nodeChoice! inferModifier { - relaxed: try $ node! relaxedInferModifier ["{", "}"], - strict: try $ node! strictInferModifier ["(", ")"], -} - -@[derive HasTokens HasView] -def introRule.Parser : commandParser := -node! introRule [ - "|", - Name: ident.Parser, - inferMod: inferModifier.Parser?, - sig: optDeclSig.Parser, -] - -@[derive HasTokens HasView] -def structBinderContent.Parser : commandParser := -node! structBinderContent [ - ids: ident.Parser+, - inferMod: inferModifier.Parser?, - sig: optDeclSig.Parser, - default: Term.binderDefault.Parser?, -] - -@[derive HasTokens HasView] -def structureFieldBlock.Parser : commandParser := -nodeChoice! structureFieldBlock { - explicit: node! structExplicitBinder ["(", content: nodeChoice! structExplicitBinderContent { - «notation»: command.notationLike.Parser, - other: structBinderContent.Parser - }, right: symbol ")"], - implicit: node! structImplicitBinder ["{", content: structBinderContent.Parser, "}"], - strictImplicit: node! strictImplicitBinder ["⦃", content: structBinderContent.Parser, "⦄"], - instImplicit: node! instImplicitBinder ["[", content: structBinderContent.Parser, "]"], -} - -@[derive HasTokens HasView] -def oldUnivParams.Parser : commandParser := -node! oldUnivParams ["{", ids: ident.Parser+, "}"] - -@[derive Parser.HasTokens Parser.HasView] -def identUnivParams.Parser : commandParser := -node! identUnivParams [ - id: ident.Parser, - univParams: node! univParams [".{", params: ident.Parser+, "}"]? -] - -@[derive HasTokens HasView] -def structure.Parser : commandParser := -node! «structure» [ - keyword: nodeChoice! structureKw {"structure", "class"}, - oldUnivParams: oldUnivParams.Parser?, - Name: identUnivParams.Parser, - sig: optDeclSig.Parser, - «extends»: node! «extends» ["extends", parents: sepBy1 Term.Parser (symbol ",")]?, - ":=", - ctor: node! structureCtor [Name: ident.Parser, inferMod: inferModifier.Parser?, "::"]?, - fieldBlocks: structureFieldBlock.Parser*, -] - -@[derive HasTokens HasView] -def declaration.Parser : commandParser := -node! declaration [ - modifiers: declModifiers.Parser, - inner: nodeChoice! declaration.inner { - «defLike»: node! «defLike» [ - kind: nodeChoice! defLike.kind {"def", "abbreviation", "abbrev", "theorem", "constant"}, - oldUnivParams: oldUnivParams.Parser?, - Name: identUnivParams.Parser, sig: optDeclSig.Parser, val: declVal.Parser], - «instance»: node! «instance» ["instance", Name: identUnivParams.Parser?, sig: declSig.Parser, val: declVal.Parser], - «example»: node! «example» ["example", sig: declSig.Parser, val: declVal.Parser], - «axiom»: node! «axiom» [ - kw: nodeChoice! constantKeyword {"axiom"}, - Name: identUnivParams.Parser, - sig: declSig.Parser], - «inductive»: node! «inductive» [try [«class»: (symbol "class")?, "inductive"], - oldUnivParams: oldUnivParams.Parser?, - Name: identUnivParams.Parser, - sig: optDeclSig.Parser, - localNotation: notationLike.Parser?, - introRules: introRule.Parser*], - «structure»: structure.Parser, - } -] - -end «command» -end Parser -end Lean diff --git a/tmp/new-frontend/parser/identifier.lean b/tmp/new-frontend/parser/identifier.lean deleted file mode 100644 index a6c23cd3d0..0000000000 --- a/tmp/new-frontend/parser/identifier.lean +++ /dev/null @@ -1,70 +0,0 @@ -/- -Copyright (c) 2018 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Leonardo de Moura --/ -prelude -import init.data.char.basic init.lean.parser.parsec - -namespace Lean - -def isGreek (c : Char) : Bool := -0x391 ≤ c.val && c.val ≤ 0x3dd - -def isLetterLike (c : Char) : Bool := -(0x3b1 ≤ c.val && c.val ≤ 0x3c9 && c.val ≠ 0x3bb) || -- Lower greek, but lambda -(0x391 ≤ c.val && c.val ≤ 0x3A9 && c.val ≠ 0x3A0 && c.val ≠ 0x3A3) || -- Upper greek, but Pi and Sigma -(0x3ca ≤ c.val && c.val ≤ 0x3fb) || -- Coptic letters -(0x1f00 ≤ c.val && c.val ≤ 0x1ffe) || -- Polytonic Greek Extended Character Set -(0x2100 ≤ c.val && c.val ≤ 0x214f) || -- Letter like block -(0x1d49c ≤ c.val && c.val ≤ 0x1d59f) -- Latin letters, Script, Double-struck, Fractur - -def isSubScriptAlnum (c : Char) : Bool := -(0x207f ≤ c.val && c.val ≤ 0x2089) || -- n superscript and numberic subscripts -(0x2090 ≤ c.val && c.val ≤ 0x209c) || -(0x1d62 ≤ c.val && c.val ≤ 0x1d6a) - -def isIdFirst (c : Char) : Bool := -c.isAlpha || c = '_' || isLetterLike c - -def isIdRest (c : Char) : Bool := -c.isAlphanum || c = '_' || c = '\'' || isLetterLike c || isSubScriptAlnum c - -def idBeginEscape := '«' -def idEndEscape := '»' -def isIdBeginEscape (c : Char) : Bool := -c = idBeginEscape -def isIdEndEscape (c : Char) : Bool := -c = idEndEscape - -namespace Parser -variables {m : Type → Type} {μ : Type} [Monad m] [MonadParsec μ m] [Alternative m] -open MonadParsec - -def idPartDefault : m String := -do c ← satisfy isIdFirst, - takeWhileCont isIdRest (toString c) - -def idPartEscaped : m String := -ch idBeginEscape *> takeUntil1 isIdEndEscape <* ch idEndEscape - -def idPart : m String := -cond isIdBeginEscape - idPartEscaped - idPartDefault - -def identifier : m Name := -(try $ do s ← idPart, - foldl Name.mkString (mkSimpleName s) (ch '.' *> idPart)) "identifier" - -def cIdentifier : m String := -(try $ do c ← satisfy (λ c, c.isAlpha || c = '_'), - takeWhileCont (λ c, c.isAlphanum || c = '_') (toString c)) "C identifier" - -def cppIdentifier : m String := -(try $ do n ← cIdentifier, - ns ← many ((++) <$> str "::" <*> cIdentifier), - pure $ String.join (n::ns)) "C++ identifier" - -end Parser -end Lean diff --git a/tmp/new-frontend/parser/level.lean b/tmp/new-frontend/parser/level.lean deleted file mode 100644 index 94b54ea1ef..0000000000 --- a/tmp/new-frontend/parser/level.lean +++ /dev/null @@ -1,76 +0,0 @@ -/- -Copyright (c) 2018 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Author: Sebastian Ullrich - -Level-Level parsers --/ -prelude -import init.lean.parser.pratt - -namespace Lean -namespace Parser -open Combinators Parser.HasView MonadParsec - -@[derive Monad Alternative MonadReader MonadParsec MonadExcept MonadRec monadBasicParser] -def LevelParserM := RecT Nat Syntax BasicParserM -abbrev levelParser := LevelParserM Syntax - -/-- A Level Parser for a suffix or infix notation that accepts a preceding Term Level. -/ -@[derive Monad Alternative MonadReader MonadParsec MonadExcept MonadRec monadBasicParser] -def TrailingLevelParserM := ReaderT Syntax LevelParserM -abbrev trailingLevelParser := TrailingLevelParserM Syntax - -instance trailingLevelParserCoe : HasCoe levelParser trailingLevelParser := -⟨λ x _, x⟩ - -@[derive Parser.HasTokens Parser.HasView] -def Level.Parser (rbp := 0) : levelParser := -recurse rbp "universe Level" - -namespace Level -/-- Access leading Term -/ -def getLeading : trailingLevelParser := read -instance : HasTokens getLeading := default _ -instance : HasView Syntax getLeading := default _ - -@[derive Parser.HasTokens Parser.HasView] -def paren.Parser : levelParser := -node! «paren» ["(":maxPrec, inner: Level.Parser 0, ")"] - -@[derive Parser.HasTokens Parser.HasView] -def leading.Parser : levelParser := -nodeChoice! leading { - max: symbolOrIdent "max", - imax: symbolOrIdent "imax", - hole: symbol "_" maxPrec, - paren: paren.Parser, - lit: number.Parser, - var: ident.Parser -} - -@[derive Parser.HasTokens Parser.HasView] -def app.Parser : trailingLevelParser := -node! app [fn: getLeading, Arg: Level.Parser maxPrec] - -@[derive Parser.HasTokens Parser.HasView] -def addLit.Parser : trailingLevelParser := -node! addLit [lhs: getLeading, "+", rhs: number.Parser] - -@[derive Parser.HasTokens Parser.HasView] -def trailing.Parser : trailingLevelParser := -nodeChoice! trailing { - app: app.Parser, - addLit: addLit.Parser -} -end Level - -@[derive Parser.HasTokens Parser.HasView] -def levelParser.run (p : levelParser) : basicParser := -prattParser Level.leading.Parser Level.trailing.Parser p - -instance levelParserCoe : HasCoe levelParser basicParser := -⟨levelParser.run⟩ - -end Parser -end Lean diff --git a/tmp/new-frontend/parser/module.lean b/tmp/new-frontend/parser/module.lean deleted file mode 100644 index 2ced51fdb3..0000000000 --- a/tmp/new-frontend/parser/module.lean +++ /dev/null @@ -1,133 +0,0 @@ -/- -Copyright (c) 2018 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Author: Sebastian Ullrich - -Module-Level parsers --/ -prelude -import init.lean.parser.command - -namespace Lean -namespace Parser - -open Combinators MonadParsec -open Parser.HasTokens Parser.HasView - -local postfix `?`:10000 := optional -local postfix *:10000 := Combinators.many -local postfix +:10000 := Combinators.many1 - -structure ModuleParserConfig extends CommandParserConfig := -(commandParsers : TokenMap commandParser) - -instance moduleParserConfigCoe : HasCoe ModuleParserConfig CommandParserConfig := -⟨ModuleParserConfig.toCommandParserConfig⟩ - -section -@[derive Monad Alternative MonadReader MonadState MonadParsec MonadExcept] -def ModuleParserM := StateT ParserState $ ParserT ModuleParserConfig Id -abbrev moduleParser := ModuleParserM Syntax -end - -instance ModuleParserM.liftParserT (ρ : Type) [HasLiftT ModuleParserConfig ρ] : - HasMonadLift (ParserT ρ Id) ModuleParserM := -{ monadLift := λ α x st cfg, (λ a, (a, st)) <$> x.run ↑cfg } - -section -local attribute [reducible] BasicParserM -instance ModuleParserM.BasicParserM (ρ : Type) [HasLiftT ModuleParserConfig ρ] : - HasMonadLift BasicParserM ModuleParserM := - inferInstance -end - -namespace Module -@[derive Parser.HasView Parser.HasTokens] -def prelude.Parser : basicParser := -node! «prelude» ["prelude"] - -@[derive Parser.HasView Parser.HasTokens] -def importPath.Parser : basicParser := --- use `raw` to ignore registered tokens like ".." -node! importPath [ - dirups: (rawStr ".")*, - Module: ident.Parser] - -@[derive Parser.HasView Parser.HasTokens] -def import.Parser : basicParser := -node! «import» ["import", imports: importPath.Parser+] - -@[derive Parser.HasView Parser.HasTokens] -def header.Parser : basicParser := -node! «header» [«prelude»: prelude.Parser?, imports: import.Parser*] - -@[pattern] def eoi : SyntaxNodeKind := ⟨`Lean.Parser.Module.eoi⟩ - -def eoi.Parser : moduleParser := do - MonadParsec.eoi, - it ← leftOver, - -- add `eoi` Node for left-over input - let stop := it.toEnd, - pure $ Syntax.mkNode eoi [Syntax.atom ⟨some ⟨⟨stop, stop⟩, stop.offset, ⟨stop, stop⟩⟩, ""⟩] - -/-- Read command, recovering from errors inside commands (attach partial Syntax tree) - as well as unknown commands (skip input). -/ -private def commandWrecAux : Bool → Nat → ModuleParserM (Bool × Syntax) -| recovering 0 := error "unreachable" -| recovering (Nat.succ n) := do - -- terminate at EOF - Nat.succ _ ← remaining | (Prod.mk false) <$> eoi.Parser, - (recovering, c) ← catch (do { - cfg ← read, - c ← monadLift $ command.Parser.run cfg.commandParsers, - pure (false, some c) - } <|> do { - -- unknown command: try to skip token, or else single character - when (¬ recovering) $ do { - it ← leftOver, - logMessage {expected := DList.singleton "command", it := it, custom := some ()} - }, - try (monadLift token *> pure ()) <|> (any *> pure ()), - pure (true, none) - }) $ λ msg, do { - -- error inside command: log error, return partial Syntax tree - logMessage msg, - pure (true, some msg.custom.get) - }, - /- NOTE: We need to make very sure that these recursive calls are happening in tail positions. - Otherwise, resuming the coroutine is linear in the number of previous commands. -/ - match c with - | some c := pure (recovering, c) - | none := commandWrecAux recovering n - -def parseCommandWithRecovery (recovering : Bool) := -do { rem ← remaining, commandWrecAux recovering rem.succ } -end Module -open Module - -structure ModuleParserSnapshot := --- it there was a parse error in the previous command, we shouldn't complain if parsing immediately after it --- fails as well -(recovering : Bool) -(it : String.OldIterator) - --- return (partial) Syntax tree and single fatal or multiple non-fatal messages -def resumeModuleParser {α : Type} (cfg : ModuleParserConfig) (snap : ModuleParserSnapshot) (mkRes : α → Syntax × ModuleParserSnapshot) - (p : ModuleParserM α) : Syntax × Except Message (ModuleParserSnapshot × MessageLog) := -let (r, _) := ((((Prod.mk <$> p <*> leftOver).run {messages:=MessageLog.empty}).run cfg).runFrom snap.it).run {} in -match r with -| Except.ok ((a, it), st) := let (stx, snap) := mkRes a in (stx, Except.ok ({snap with it := it}, st.messages)) -| Except.error msg := (msg.custom.get, Except.error $ messageOfParsecMessage cfg msg) - -def parseHeader (cfg : ModuleParserConfig) := -let snap := {ModuleParserSnapshot . recovering := false, it := cfg.input.mkOldIterator} in -resumeModuleParser cfg snap (λ stx, (stx, snap)) $ do - -- `token` assumes that there is no leading whitespace - monadLift whitespace, - monadLift header.Parser - -def parseCommand (cfg) (snap) := resumeModuleParser cfg snap (λ p, (Prod.snd p, {snap with recovering := Prod.fst p})) - (parseCommandWithRecovery snap.recovering) - -end Parser -end Lean diff --git a/tmp/new-frontend/parser/notation.lean b/tmp/new-frontend/parser/notation.lean deleted file mode 100644 index bce3240f6d..0000000000 --- a/tmp/new-frontend/parser/notation.lean +++ /dev/null @@ -1,189 +0,0 @@ -/- -Copyright (c) 2018 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Author: Sebastian Ullrich - -Notation parsers --/ -prelude -import init.lean.parser.token - -namespace Lean -namespace Parser - -open Combinators MonadParsec -open Parser.HasTokens Parser.HasView - -local postfix `?`:10000 := optional -local postfix *:10000 := Combinators.many -local postfix +:10000 := Combinators.many1 - -@[derive Parser.HasTokens Parser.HasView] -def Term.Parser (rbp := 0) : termParser := -recurse rbp "Term" - -set_option class.instance_max_depth 100 - -namespace «command» -namespace NotationSpec -@[derive Parser.HasTokens Parser.HasView] -def precedenceLit.Parser : termParser := -nodeChoice! precedenceLit { - num: number.Parser, - max: symbolOrIdent "max", - -- TODO(Sebastian): `precOf`? -} - -def precedenceLit.View.toNat : precedenceLit.View → Nat -| (precedenceLit.View.num n) := n.toNat -| (precedenceLit.View.max _) := maxPrec - -@[derive Parser.HasTokens Parser.HasView] -def precedenceTerm.Parser : termParser := -nodeChoice! precedenceTerm { - lit: precedenceLit.Parser, - offset: node! precedenceOffset ["(", lit: precedenceLit.Parser, - op: nodeChoice! precedenceOffsetOp {" + ", " - "}, - offset: number.Parser, - ")", - ] -} - -def precedenceTerm.View.toNat : precedenceTerm.View → Nat -| (precedenceTerm.View.lit l) := l.toNat -| (precedenceTerm.View.offset o) := match o.op with - | (precedenceOffsetOp.View.«+» _) := o.lit.toNat.add o.offset.toNat - | (precedenceOffsetOp.View.«-» _) := o.lit.toNat - o.offset.toNat - -@[derive Parser.HasTokens Parser.HasView] -def precedence.Parser : termParser := -node! «precedence» [":", Term: precedenceTerm.Parser] - -@[derive Parser.HasTokens Parser.HasView] -def quotedSymbol.Parser : termParser := -raw $ takeUntil (= '`') - -@[derive Parser.HasTokens Parser.HasView] -def symbolQuote.Parser : termParser := -node! symbolQuote [ - leftQuote: rawStr "`", - symbol: quotedSymbol.Parser, - rightQuote: rawStr "`" true, -- consume trailing ws - prec: precedence.Parser?] - -def unquotedSymbol.Parser : termParser := -try $ do { - it ← leftOver, - stx@(Syntax.atom _) ← monadLift token | error "" (DList.singleton "symbol") it, - pure stx -} "symbol" - -instance unquotedSymbol.tokens : Parser.HasTokens unquotedSymbol.Parser := ⟨[]⟩ -instance unquotedSymbol.View : Parser.HasView (Option SyntaxAtom) unquotedSymbol.Parser := -{ view := λ stx, match stx with - | Syntax.atom atom := some atom - | _ := none, - review := λ a, (Syntax.atom <$> a).getOrElse Syntax.missing } - ---TODO(Sebastian): cannot be called `symbol` because of hygiene problems -@[derive Parser.HasTokens Parser.HasView] -def notationSymbol.Parser : termParser := -nodeChoice! notationSymbol { - quoted: symbolQuote.Parser, - --TODO(Sebastian): decide if we want this in notations - --unquoted: unquotedSymbol.Parser -} - -@[derive Parser.HasTokens Parser.HasView] -def mixfixSymbol.Parser : termParser := -nodeChoice! mixfixSymbol { - quoted: symbolQuote.Parser, - unquoted: unquotedSymbol.Parser -} - -@[derive Parser.HasTokens Parser.HasView] -def foldAction.Parser : termParser := -node! foldAction [ - "(", - op: anyOf [symbolOrIdent "foldl", symbolOrIdent "foldr"], - sep: notationSymbol.Parser, - folder: node! foldActionFolder [ - "(", - arg1: ident.Parser, - arg2: ident.Parser, - ",", - rhs: Term.Parser, - ")" - ], - init: Term.Parser, - endTk: notationSymbol.Parser, - ")" -] - -@[derive Parser.HasTokens Parser.HasView] -def action.Parser : termParser := -node! action [":", kind: nodeChoice! actionKind { - prec: try precedenceTerm.Parser, - prev: symbolOrIdent "prev", - scoped: node! scopedAction [ - try ["(", scoped: symbolOrIdent "scoped"], - prec: precedence.Parser?, - id: ident.Parser, - ", ", - Term: Term.Parser, - ")", - ], - fold: foldAction.Parser -}] - -@[derive Parser.HasTokens Parser.HasView] -def transition.Parser : termParser := -nodeChoice! transition { - binder: node! binder [binder: symbolOrIdent "binder", prec: precedence.Parser?], - binders: node! binders [binders: symbolOrIdent "binders", prec: precedence.Parser?], - Arg: node! argument [id: ident.Parser, action: action.Parser?] -} - -@[derive Parser.HasTokens Parser.HasView] -def rule.Parser : termParser := -node! rule [symbol: notationSymbol.Parser, transition: transition.Parser?] - -end NotationSpec - -@[derive Parser.HasTokens Parser.HasView] -def NotationSpec.Parser : termParser := -node! NotationSpec [prefixArg: ident.Parser?, rules: NotationSpec.rule.Parser*] - -@[derive Parser.HasTokens Parser.HasView] -def notation.Parser : termParser := -node! «notation» [ - try [«local»: (symbol "local ")?, "notation"], - spec: NotationSpec.Parser, ":=", Term: Term.Parser] - -@[derive Parser.HasTokens Parser.HasView] -def reserveNotation.Parser : termParser := -node! «reserveNotation» [try ["reserve", "notation"], spec: NotationSpec.Parser] - -@[derive Parser.HasTokens Parser.HasView] -def mixfix.kind.Parser : termParser := -nodeChoice! mixfix.kind {"prefix", "infix", "infixl", "infixr", "postfix"} - -@[derive Parser.HasTokens Parser.HasView] -def mixfix.Parser : termParser := -node! «mixfix» [ - try [«local»: (symbol "local ")?, kind: mixfix.kind.Parser], - symbol: NotationSpec.mixfixSymbol.Parser, ":=", Term: Term.Parser] - -@[derive Parser.HasTokens Parser.HasView] -def notationLike.Parser : termParser := -nodeChoice! notationLike {«notation»: notation.Parser, mixfix: mixfix.Parser} - -@[derive Parser.HasTokens Parser.HasView] -def reserveMixfix.Parser : termParser := -node! «reserveMixfix» [ - try ["reserve", kind: mixfix.kind.Parser], - symbol: NotationSpec.notationSymbol.Parser] - -end «command» -end Parser -end Lean diff --git a/tmp/new-frontend/parser/parsec.lean b/tmp/new-frontend/parser/parsec.lean deleted file mode 100644 index 0256f5ea62..0000000000 --- a/tmp/new-frontend/parser/parsec.lean +++ /dev/null @@ -1,674 +0,0 @@ -/- -Copyright (c) 2018 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Leonardo de Moura, Sebastian Ullrich - -Implementation for the Parsec Parser Combinators described in the -paper: -https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/Parsec-paper-letter.pdf --/ -prelude -import init.data.tostring init.data.string.basic init.data.list.basic init.control.except -import init.data.repr init.lean.name init.data.dlist init.control.monadfail init.control.combinators -import init.lean.format - -/- Old String iterator -/ -namespace String -structure OldIterator := -(s : String) (offset : Nat) (i : Nat) - -def mkOldIterator (s : String) : OldIterator := -⟨s, 0, 0⟩ - -namespace OldIterator -def remaining : OldIterator → Nat -| ⟨s, o, _⟩ := s.length - o - -def toString : OldIterator → String -| ⟨s, _, _⟩ := s - -def remainingBytes : OldIterator → Nat -| ⟨s, _, i⟩ := s.bsize - i - -def curr : OldIterator → Char -| ⟨s, _, i⟩ := get s i - -def next : OldIterator → OldIterator -| ⟨s, o, i⟩ := ⟨s, o+1, s.next i⟩ - -def prev : OldIterator → OldIterator -| ⟨s, o, i⟩ := ⟨s, o-1, s.prev i⟩ - -def hasNext : OldIterator → Bool -| ⟨s, _, i⟩ := i < utf8ByteSize s - -def hasPrev : OldIterator → Bool -| ⟨s, _, i⟩ := i > 0 - -def setCurr : OldIterator → Char → OldIterator -| ⟨s, o, i⟩ c := ⟨s.set i c, o, i⟩ - -def toEnd : OldIterator → OldIterator -| ⟨s, o, _⟩ := ⟨s, s.length, s.bsize⟩ - -def extract : OldIterator → OldIterator → String -| ⟨s₁, _, b⟩ ⟨s₂, _, e⟩ := - if s₁ ≠ s₂ || b > e then "" - else s₁.extract b e - -def forward : OldIterator → Nat → OldIterator -| it 0 := it -| it (n+1) := forward it.next n - -def remainingToString : OldIterator → String -| ⟨s, _, i⟩ := s.extract i s.bsize - -/- (isPrefixOfRemaining it₁ it₂) is `true` Iff `it₁.remainingToString` is a prefix - of `it₂.remainingToString`. -/ -def isPrefixOfRemaining : OldIterator → OldIterator → Bool -| ⟨s₁, _, i₁⟩ ⟨s₂, _, i₂⟩ := s₁.extract i₁ s₁.bsize = s₂.extract i₂ (i₂ + (s₁.bsize - i₁)) - -def nextn : OldIterator → Nat → OldIterator -| it 0 := it -| it (i+1) := nextn it.next i - -def prevn : OldIterator → Nat → OldIterator -| it 0 := it -| it (i+1) := prevn it.prev i -end OldIterator - -private def oldLineColumnAux : Nat → String.OldIterator → Nat × Nat → Nat × Nat -| 0 it r := r -| (k+1) it r@(line, col) := - if it.hasNext = false then r - else match it.curr with - | '\n' := oldLineColumnAux k it.next (line+1, 0) - | other := oldLineColumnAux k it.next (line, col+1) - -def oldLineColumn (s : String) (offset : Nat) : Nat × Nat := -oldLineColumnAux offset s.mkOldIterator (1, 0) - -end String - - -namespace Lean -namespace Parser -open String (OldIterator) - -namespace Parsec -@[reducible] def Position : Type := Nat - -structure Message (μ : Type := Unit) := -(it : OldIterator) -(unexpected : String := "") -- unexpected input -(expected : DList String := ∅) -- expected productions -(custom : Option μ) - -def expected.toString : List String → String -| [] := "" -| [e] := e -| [e1, e2] := e1 ++ " or " ++ e2 -| (e::es) := e ++ ", " ++ expected.toString es - -def Message.text {μ : Type} (msg : Message μ) : String := -let unexpected := (if msg.unexpected = "" then [] else ["unexpected " ++ msg.unexpected]) in -let exList := msg.expected.toList in -let expected := if exList = [] then [] else ["expected " ++ expected.toString exList] in -"\n".intercalate $ unexpected ++ expected - - -protected def Message.toString {μ : Type} (msg : Message μ) : String := -let (line, col) := msg.it.toString.oldLineColumn msg.it.offset in --- always print ":"; we assume at least one of `unexpected` and `expected` to be non-Empty -"error at line " ++ toString line ++ ", column " ++ toString col ++ ":\n" ++ msg.text - -instance {μ : Type} : HasToString (Message μ) := -⟨Message.toString⟩ - --- use for e.g. upcasting Parsec errors with `MonadExcept.liftExcept` -instance {μ : Type} : HasLift (Message μ) String := -⟨toString⟩ - -/- -Remark: we store expected "error" messages in `okEps` results. -They contain the error that would have occurred if a -successful "epsilon" Alternative was not taken. --/ -inductive Result (μ α : Type) -| ok {} (a : α) (it : OldIterator) (expected : Option $ DList String) : Result -| error {} (msg : Message μ) (consumed : Bool) : Result - -@[inline] def Result.mkEps {μ α : Type} (a : α) (it : OldIterator) : Result μ α := -Result.ok a it (some ∅) -end Parsec - -open Parsec - -def ParsecT (μ : Type) (m : Type → Type) (α : Type) := -OldIterator → m (Result μ α) - -abbrev Parsec (μ : Type) := ParsecT μ Id -/-- `Parsec` without custom error Message Type -/ -abbrev Parsec' := Parsec Unit - -namespace ParsecT -open Parsec.Result -variables {m : Type → Type} [Monad m] {μ α β : Type} - -def run (p : ParsecT μ m α) (s : String) (fname := "") : m (Except (Message μ) α) := -do r ← p s.mkOldIterator, - pure $ match r with - | ok a _ _ := Except.ok a - | error msg _ := Except.error msg - -def runFrom (p : ParsecT μ m α) (it : OldIterator) (fname := "") : m (Except (Message μ) α) := -do r ← p it, - pure $ match r with - | ok a _ _ := Except.ok a - | error msg _ := Except.error msg - -@[inline] protected def pure (a : α) : ParsecT μ m α := -λ it, pure (mkEps a it) - -def eps : ParsecT μ m Unit := -ParsecT.pure () - -protected def failure : ParsecT μ m α := -λ it, pure (error { unexpected := "failure", it := it, custom := none } false) - -def merge (msg₁ msg₂ : Message μ) : Message μ := -{ expected := msg₁.expected ++ msg₂.expected, ..msg₁ } - -@[inlineIfReduce] def bindMkRes (ex₁ : Option (DList String)) (r : Result μ β) : Result μ β := -match ex₁, r with -| none, ok b it _ := ok b it none -| none, error msg _ := error msg true -| some ex₁, ok b it (some ex₂) := ok b it (some $ ex₁ ++ ex₂) -| some ex₁, error msg₂ false := error { expected := ex₁ ++ msg₂.expected, .. msg₂ } false -| some ex₁, other := other - -/-- - The `bind p q` Combinator behaves as follows: - 1- If `p` fails, then it fails. - 2- If `p` succeeds and consumes input, then execute `q` - 3- If `q` succeeds but does not consume input, then execute `q` - and merge error messages if both do not consume any input. --/ -@[inline] protected def bind (p : ParsecT μ m α) (q : α → ParsecT μ m β) : ParsecT μ m β := -λ it, do - r ← p it, - match r with - | ok a it ex₁ := bindMkRes ex₁ <$> q a it - | error msg c := pure (error msg c) - -/-- More efficient `bind` that does not correctly merge `expected` and `consumed` information. -/ -@[inline] def bind' (p : ParsecT μ m α) (q : α → ParsecT μ m β) : ParsecT μ m β := -λ it, do - r ← p it, - match r with - | ok a it ex₁ := q a it - | error msg c := pure (error msg c) - -instance : Monad (ParsecT μ m) := -{ bind := λ _ _, ParsecT.bind, pure := λ _, ParsecT.pure } - -/-- `Monad` instance using `bind'`. -/ -def Monad' : Monad (ParsecT μ m) := -{ bind := λ _ _, ParsecT.bind', pure := λ _, ParsecT.pure } - -instance : MonadFail Parsec' := -{ fail := λ _ s it, error { unexpected := s, it := it, custom := () } false } - -instance : MonadExcept (Message μ) (ParsecT μ m) := -{ throw := λ _ msg it, pure (error msg false), - catch := λ _ p c it, do - r ← p it, - match r with - | error msg cns := do { - r ← c msg msg.it, - pure $ match r with - | error msg' cns' := error msg' (cns || cns') - | other := other } - | other := pure other } - -instance : HasMonadLift m (ParsecT μ m) := -{ monadLift := λ α x it, do a ← x, pure (mkEps a it) } - -def expect (msg : Message μ) (exp : String) : Message μ := -{expected := DList.singleton exp, ..msg} - -@[inlineIfReduce] def labelsMkRes (r : Result μ α) (lbls : DList String) : Result μ α := -match r with - | ok a it (some _) := ok a it (some lbls) - | error msg false := error {expected := lbls, ..msg} false - | other := other - -@[inline] def labels (p : ParsecT μ m α) (lbls : DList String) : ParsecT μ m α := -λ it, do - r ← p it, - pure $ labelsMkRes r lbls - -@[inlineIfReduce] def tryMkRes (r : Result μ α) : Result μ α := -match r with -| error msg _ := error msg false -| other := other - -/-- -`try p` behaves like `p`, but it pretends `p` hasn't -consumed any input when `p` fails. - -It is useful for implementing infinite lookahead. -The Parser `try p <|> q` will try `q` even when -`p` has consumed input. - -It is also useful for specifying both the lexer and Parser -together. -``` - (do try (ch 'l' >> ch 'e' >> ch 't'), whitespace, ...) - <|> - ... -``` -Without the `try` Combinator we will not be able to backtrack on the `let` keyword. --/ -@[inline] def try (p : ParsecT μ m α) : ParsecT μ m α := -λ it, do - r ← p it, - pure $ tryMkRes r - -@[inlineIfReduce] def orelseMkRes (msg₁ : Message μ) (r : Result μ α) : Result μ α := -match r with -| ok a it' (some ex₂) := ok a it' (some $ msg₁.expected ++ ex₂) -| error msg₂ false := error (merge msg₁ msg₂) false -| other := other - -/-- - The `orelse p q` Combinator behaves as follows: - 1- If `p` succeeds *or* consumes input, return - its Result. Otherwise, execute `q` and return its - Result. - Recall that the `try p` Combinator can be used to - pretend that `p` did not consume any input, and - simulate infinite lookahead. - 2- If both `p` and `q` did not consume any input, then - combine their error messages (even if one of - them succeeded). --/ -@[inline] protected def orelse (p q : ParsecT μ m α) : ParsecT μ m α := -λ it, do - r ← p it, - match r with - | error msg₁ false := do { r ← q it, pure $ orelseMkRes msg₁ r } - | other := pure other - -instance : Alternative (ParsecT μ m) := -{ orelse := λ _, ParsecT.orelse, - failure := λ _, ParsecT.failure, - ..ParsecT.Monad } - -/-- Run `p`, but do not consume any input when `p` succeeds. -/ -@[specialize] def lookahead (p : ParsecT μ m α) : ParsecT μ m α := -λ it, do - r ← p it, - pure $ match r with - | ok a s' _ := mkEps a it - | other := other -end ParsecT - -/- Type class for abstracting from concrete Monad stacks containing a `Parsec` somewhere. -/ -class MonadParsec (μ : outParam Type) (m : Type → Type) := --- analogous to e.g. `MonadReader.lift` before simplification (see there) -(lift {} {α : Type} : Parsec μ α → m α) --- Analogous to e.g. `MonadReaderAdapter.map` before simplification (see there). --- Its usage seems to be way too common to justify moving it into a separate type class. -(map {} {α : Type} : (∀ {m'} [Monad m'] {α}, ParsecT μ m' α → ParsecT μ m' α) → m α → m α) - -/-- `Parsec` without custom error Message Type -/ -abbrev MonadParsec' := MonadParsec Unit - -variables {μ : Type} - -instance {m : Type → Type} [Monad m] : MonadParsec μ (ParsecT μ m) := -{ lift := λ α p it, pure (p it), - map := λ α f x, f x } - -instance monadParsecTrans {m n : Type → Type} [HasMonadLift m n] [MonadFunctor m m n n] [MonadParsec μ m] : MonadParsec μ n := -{ lift := λ α p, monadLift (MonadParsec.lift p : m α), - map := λ α f x, monadMap (λ β x, (MonadParsec.map @f x : m β)) x } - -namespace MonadParsec -open ParsecT -variables {m : Type → Type} [Monad m] [MonadParsec μ m] {α β : Type} - -def error {α : Type} (unexpected : String) (expected : DList String := ∅) - (it : Option OldIterator := none) (custom : Option μ := none) : m α := -lift $ λ it', Result.error { unexpected := unexpected, expected := expected, it := it.getOrElse it', custom := custom } false - -@[inline] def leftOver : m OldIterator := -lift $ λ it, Result.mkEps it it - -/-- Return the number of characters left to be parsed. -/ -@[inline] def remaining : m Nat := -String.OldIterator.remaining <$> leftOver - -@[inline] def labels (p : m α) (lbls : DList String) : m α := -map (λ m' inst β p, @ParsecT.labels m' inst μ β p lbls) p - -@[inline] def label (p : m α) (lbl : String) : m α := -labels p (DList.singleton lbl) - -infixr ` `:2 := label - -@[inline] def hidden (p : m α) : m α := -labels p ∅ - -/-- -`try p` behaves like `p`, but it pretends `p` hasn't -consumed any input when `p` fails. - -It is useful for implementing infinite lookahead. -The Parser `try p <|> q` will try `q` even when -`p` has consumed input. - -It is also useful for specifying both the lexer and Parser -together. -``` - (do try (ch 'l' >> ch 'e' >> ch 't'), whitespace, ...) - <|> - ... -``` -Without the `try` Combinator we will not be able to backtrack on the `let` keyword. --/ - -@[inline] def try (p : m α) : m α := -map (λ m' inst β p, @ParsecT.try m' inst μ β p) p - -/-- Parse `p` without consuming any input. -/ -@[inline] def lookahead (p : m α) : m α := -map (λ m' inst β p, @ParsecT.lookahead m' inst μ β p) p - -/-- Faster version of `notFollowedBy (satisfy p)` -/ -@[inline] def notFollowedBySat (p : Char → Bool) : m Unit := -do it ← leftOver, - if !it.hasNext then pure () - else let c := it.curr in - if p c then error (repr c) - else pure () - -def eoiError (it : OldIterator) : Result μ α := -Result.error { it := it, unexpected := "end of input", custom := default _ } false - -def curr : m Char := -String.OldIterator.curr <$> leftOver - -@[inline] def cond (p : Char → Bool) (t : m α) (e : m α) : m α := -mcond (p <$> curr) t e - -/-- -If the next character `c` satisfies `p`, then -update Position and return `c`. Otherwise, -generate error Message with current Position and character. -/ -@[inline] def satisfy (p : Char → Bool) : m Char := -do it ← leftOver, - if !it.hasNext then error "end of input" - else let c := it.curr in - if p c then lift $ λ _, Result.ok c it.next none - else error (repr c) - -def ch (c : Char) : m Char := -satisfy (= c) - -def alpha : m Char := -satisfy Char.isAlpha - -def digit : m Char := -satisfy Char.isDigit - -def upper : m Char := -satisfy Char.isUpper - -def lower : m Char := -satisfy Char.isLower - -def any : m Char := -satisfy (λ _, True) - -private def strAux : Nat → OldIterator → OldIterator → Option OldIterator -| 0 _ it := some it -| (n+1) sIt it := - if it.hasNext ∧ sIt.curr = it.curr then strAux n sIt.next it.next - else none - -/-- -`str s` parses a sequence of elements that match `s`. Returns the parsed String (i.e. `s`). -This Parser consumes no input if it fails (even if a partial match). -Note: The behaviour of this Parser is different to that the `String` Parser in the ParsecT Μ M Haskell library, -as this one is all-or-nothing. --/ -def strCore (s : String) (ex : DList String) : m String := -if s.isEmpty then pure "" -else lift $ λ it, match strAux s.length s.mkOldIterator it with - | some it' := Result.ok s it' none - | none := Result.error { it := it, expected := ex, custom := none } false - -@[inline] def str (s : String) : m String := -strCore s (DList.singleton (repr s)) - -private def takeAux : Nat → String → OldIterator → Result μ String -| 0 r it := Result.ok r it none -| (n+1) r it := - if !it.hasNext then eoiError it - else takeAux n (r.push (it.curr)) it.next - -/-- Consume `n` characters. -/ -def take (n : Nat) : m String := -if n = 0 then pure "" -else lift $ takeAux n "" - -private def mkStringResult (r : String) (it : OldIterator) : Result μ String := -if r.isEmpty then Result.mkEps r it -else Result.ok r it none - -@[specialize] -private def takeWhileAux (p : Char → Bool) : Nat → String → OldIterator → Result μ String -| 0 r it := mkStringResult r it -| (n+1) r it := - if !it.hasNext then mkStringResult r it - else let c := it.curr in - if p c then takeWhileAux n (r.push c) it.next - else mkStringResult r it - -/-- -Consume input as long as the predicate returns `true`, and return the consumed input. -This Parser does not fail. It will return an Empty String if the predicate -returns `false` on the current character. -/ -@[specialize] def takeWhile (p : Char → Bool) : m String := -lift $ λ it, takeWhileAux p it.remaining "" it - -@[specialize] def takeWhileCont (p : Char → Bool) (ini : String) : m String := -lift $ λ it, takeWhileAux p it.remaining ini it - -/-- -Consume input as long as the predicate returns `true`, and return the consumed input. -This Parser requires the predicate to succeed on at least once. -/ -@[specialize] def takeWhile1 (p : Char → Bool) : m String := -do c ← satisfy p, - takeWhileCont p (toString c) - -/-- -Consume input as long as the predicate returns `false` (i.e. until it returns `true`), and return the consumed input. -This Parser does not fail. -/ -@[inline] def takeUntil (p : Char → Bool) : m String := -takeWhile (λ c, !p c) - -@[inline] def takeUntil1 (p : Char → Bool) : m String := -takeWhile1 (λ c, !p c) - -private def mkConsumedResult (consumed : Bool) (it : OldIterator) : Result μ Unit := -if consumed then Result.ok () it none -else Result.mkEps () it - -@[specialize] private def takeWhileAux' (p : Char → Bool) : Nat → Bool → OldIterator → Result μ Unit -| 0 consumed it := mkConsumedResult consumed it -| (n+1) consumed it := - if !it.hasNext then mkConsumedResult consumed it - else let c := it.curr in - if p c then takeWhileAux' n true it.next - else mkConsumedResult consumed it - -/-- Similar to `takeWhile` but it does not return the consumed input. -/ -@[specialize] def takeWhile' (p : Char → Bool) : m Unit := -lift $ λ it, takeWhileAux' p it.remaining false it - -/-- Similar to `takeWhile1` but it does not return the consumed input. -/ -@[specialize] def takeWhile1' (p : Char → Bool) : m Unit := -satisfy p *> takeWhile' p - -/-- Consume zero or more whitespaces. -/ -@[noinline] def whitespace : m Unit := -takeWhile' Char.isWhitespace - -/-- Shorthand for `p <* whitespace` -/ -@[inline] def lexeme (p : m α) : m α := -p <* whitespace - -/-- Parse a numeral in decimal. -/ -@[noinline] def num : m Nat := -String.toNat <$> (takeWhile1 Char.isDigit) - -/-- Succeed only if there are at least `n` characters left. -/ -def ensure (n : Nat) : m Unit := -do it ← leftOver, - if n ≤ it.remaining then pure () - else error "end of input" (DList.singleton ("at least " ++ toString n ++ " characters")) - -/-- Return the current Position. -/ -def pos : m Position := -String.OldIterator.offset <$> leftOver - - -/-- `notFollowedBy p` succeeds when Parser `p` fails -/ -@[inline] def notFollowedBy [MonadExcept (Message μ) m] (p : m α) (msg : String := "input") : m Unit := -do it ← leftOver, - b ← lookahead $ catch (p *> pure false) (λ _, pure true), - if b then pure () else error msg ∅ it - -def eoi : m Unit := -do it ← leftOver, - if it.remaining = 0 then pure () - else error (repr it.curr) (DList.singleton ("end of input")) - -@[specialize] def many1Aux [Alternative m] (p : m α) : Nat → m (List α) -| 0 := do a ← p, pure [a] -| (n+1) := do a ← p, - as ← (many1Aux n <|> pure []), - pure (a::as) - -@[specialize] def many1 [Alternative m] (p : m α) : m (List α) := -do r ← remaining, many1Aux p r - -@[specialize] def many [Alternative m] (p : m α) : m (List α) := -many1 p <|> pure [] - -@[specialize] def many1Aux' [Alternative m] (p : m α) : Nat → m Unit -| 0 := p *> pure () -| (n+1) := p *> (many1Aux' n <|> pure ()) - -@[inline] def many1' [Alternative m] (p : m α) : m Unit := -do r ← remaining, many1Aux' p r - -@[specialize] def many' [Alternative m] (p : m α) : m Unit := -many1' p <|> pure () - -@[specialize] def sepBy1 [Alternative m] (p : m α) (sep : m β) : m (List α) := -(::) <$> p <*> many (sep *> p) - -@[specialize] def SepBy [Alternative m] (p : m α) (sep : m β) : m (List α) := -sepBy1 p sep <|> pure [] - -@[specialize] def fixAux [Alternative m] (f : m α → m α) : Nat → m α -| 0 := error "fixAux: no progress" -| (n+1) := f (fixAux n) - -@[specialize] def fix [Alternative m] (f : m α → m α) : m α := -do n ← remaining, fixAux f (n+1) - -@[specialize] def foldrAux [Alternative m] (f : α → β → β) (p : m α) (b : β) : Nat → m β -| 0 := pure b -| (n+1) := (f <$> p <*> foldrAux n) <|> pure b - -/-- Matches zero or more occurrences of `p`, and folds the Result. -/ -@[specialize] def foldr [Alternative m] (f : α → β → β) (p : m α) (b : β) : m β := -do it ← leftOver, - foldrAux f p b it.remaining - -@[specialize] def foldlAux [Alternative m] (f : α → β → α) (p : m β) : α → Nat → m α -| a 0 := pure a -| a (n+1) := (do x ← p, foldlAux (f a x) n) <|> pure a - -/-- Matches zero or more occurrences of `p`, and folds the Result. -/ -@[specialize] def foldl [Alternative m] (f : α → β → α) (a : α) (p : m β) : m α := -do it ← leftOver, - foldlAux f p a it.remaining - -def unexpected (msg : String) : m α := -error msg - -def unexpectedAt (msg : String) (it : OldIterator) : m α := -error msg ∅ it - -/- Execute all parsers in `ps` and return the Result of the longest parse(s) if any, - or else the Result of the furthest error. If there are two parses of - equal length, the first parse wins. -/ -@[specialize] -def longestMatch [MonadExcept (Message μ) m] (ps : List (m α)) : m (List α) := -do it ← leftOver, - r ← ps.mfoldr (λ p (r : Result μ (List α)), - lookahead $ catch - (do - a ← p, - it ← leftOver, - pure $ match r with - | Result.ok as it' none := if it'.offset > it.offset then r - else if it.offset > it'.offset then Result.ok [a] it none - else Result.ok (a::as) it none - | _ := Result.ok [a] it none) - (λ msg, pure $ match r with - | Result.error msg' _ := if msg'.it.offset > msg.it.offset then r - else if msg.it.offset > msg'.it.offset then Result.error msg true - else Result.error (merge msg msg') (msg.it.offset > it.offset) - | _ := r)) - ((error "longestMatch: Empty List" : Parsec _ _) it), - lift $ λ _, r - -@[specialize] -def observing [MonadExcept (Message μ) m] (p : m α) : m (Except (Message μ) α) := -catch (Except.ok <$> p) $ λ msg, pure (Except.error msg) - -end MonadParsec - -namespace MonadParsec -open ParsecT -variables {m : Type → Type} [Monad m] [MonadParsec Unit m] {α β : Type} - -end MonadParsec - -namespace ParsecT -open MonadParsec -variables {m : Type → Type} [Monad m] {α β : Type} - -def parse (p : ParsecT μ m α) (s : String) (fname := "") : m (Except (Message μ) α) := -run p s fname - -def parseWithEoi (p : ParsecT μ m α) (s : String) (fname := "") : m (Except (Message μ) α) := -run (p <* eoi) s fname - -def parseWithLeftOver (p : ParsecT μ m α) (s : String) (fname := "") : m (Except (Message μ) (α × OldIterator)) := -run (Prod.mk <$> p <*> leftOver) s fname - -end ParsecT - -def Parsec.parse {α : Type} (p : Parsec μ α) (s : String) (fname := "") : Except (Message μ) α := -ParsecT.parse p s fname - -end Parser -end Lean diff --git a/tmp/new-frontend/parser/pratt.lean b/tmp/new-frontend/parser/pratt.lean deleted file mode 100644 index 842c5e7ce0..0000000000 --- a/tmp/new-frontend/parser/pratt.lean +++ /dev/null @@ -1,56 +0,0 @@ -/- -Copyright (c) 2018 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Author: Sebastian Ullrich - -A Combinator for building Pratt parsers --/ -prelude -import init.lean.parser.token - -namespace Lean.Parser -open MonadParsec Combinators - -variables {baseM : Type → Type} -variables [Monad baseM] [monadBasicParser baseM] [MonadParsec Syntax baseM] [MonadReader ParserConfig baseM] - -local notation `m` := RecT Nat Syntax baseM -local notation `Parser` := m Syntax - -def currLbp : m Nat := -do Except.ok tk ← monadLift peekToken | pure 0, - match tk with - | Syntax.atom ⟨_, sym⟩ := do - cfg ← read, - some ⟨_, tkCfg⟩ ← pure (cfg.tokens.oldMatchPrefix sym.mkOldIterator) | error "currLbp: unreachable", - pure tkCfg.lbp - | Syntax.ident _ := pure maxPrec - | Syntax.rawNode {kind := @number, ..} := pure maxPrec - | Syntax.rawNode {kind := @stringLit, ..} := pure maxPrec - | _ := error "currLbp: unknown token kind" - -private def trailingLoop (trailing : ReaderT Syntax m Syntax) (rbp : Nat) : Nat → Syntax → Parser -| 0 _ := error "unreachable" -| (n+1) left := do -lbp ← currLbp, -if rbp < lbp then do - left ← trailing.run left, - trailingLoop n left -else - pure left - -variables [MonadExcept (Parsec.Message Syntax) baseM] [Alternative baseM] -variables (leading : m Syntax) (trailing : ReaderT Syntax m Syntax) (p : m Syntax) - -def prattParser : baseM Syntax := -RecT.runParsec p $ λ rbp, do -left ← leading, -n ← remaining, -trailingLoop trailing rbp (n+1) left - -instance prattParser.tokens [HasTokens leading] [HasTokens trailing] : HasTokens (prattParser leading trailing p) := -⟨HasTokens.tokens leading ++ HasTokens.tokens trailing⟩ -instance prattParser.View : HasView Syntax (prattParser leading trailing p) := -default _ - -end Lean.Parser diff --git a/tmp/new-frontend/parser/rec.lean b/tmp/new-frontend/parser/rec.lean deleted file mode 100644 index 69f4e50d98..0000000000 --- a/tmp/new-frontend/parser/rec.lean +++ /dev/null @@ -1,56 +0,0 @@ -/- -Copyright (c) 2018 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Author: Sebastian Ullrich - -Recursion monad transformer --/ -prelude -import init.control.reader init.lean.parser.parsec init.fix - -namespace Lean.Parser - -/-- A small wrapper of `ReaderT` that simplifies introducing and invoking - recursion points in a computation. -/ -def RecT (α δ : Type) (m : Type → Type) (β : Type) := -ReaderT (α → m δ) m β - -namespace RecT -variables {m : Type → Type} {α δ β : Type} [Monad m] -local attribute [reducible] RecT - -/-- Continue at the recursion point stored at `run`. -/ -@[inline] def recurse (a : α) : RecT α δ m δ := -λ f, f a - -/-- Execute `x`, executing `rec a` whenever `recurse a` is called. - After `maxRec` recursion steps, `base` is executed instead. -/ -@[inline] protected def run (x : RecT α δ m β) (base : α → m δ) (rec : α → RecT α δ m δ) : m β := -x (fixCore base (λ a f, rec f a)) - -@[inline] protected def runParsec {γ : Type} [MonadParsec γ m] (x : RecT α δ m β) (rec : α → RecT α δ m δ) : m β := -RecT.run x (λ _, MonadParsec.error "RecT.runParsec: no progress") rec - --- not clear how to auto-derive these given the additional constraints -instance : Monad (RecT α δ m) := inferInstance -instance [Alternative m] : Alternative (RecT α δ m) := inferInstance -instance : HasMonadLift m (RecT α δ m) := inferInstance -instance (ε) [MonadExcept ε m] : MonadExcept ε (RecT α δ m) := inferInstance -instance (μ) [MonadParsec μ m] : MonadParsec μ (RecT α δ m) := -inferInstance --- NOTE: does not allow to vary `m` because of its occurrence in the Reader State -instance [Monad m] : MonadFunctor m m (RecT α δ m) (RecT α δ m) := -inferInstance -end RecT - -class MonadRec (α δ : outParam Type) (m : Type → Type) := -(recurse {} : α → m δ) -export MonadRec (recurse) - -instance MonadRec.trans (α δ m m') [HasMonadLift m m'] [MonadRec α δ m] [Monad m] : MonadRec α δ m' := -{ recurse := λ a, monadLift (recurse a : m δ) } - -instance MonadRec.base (α δ m) [Monad m] : MonadRec α δ (RecT α δ m) := -{ recurse := RecT.recurse } - -end Lean.Parser diff --git a/tmp/new-frontend/parser/stringliteral.lean b/tmp/new-frontend/parser/stringliteral.lean deleted file mode 100644 index 0440387bf3..0000000000 --- a/tmp/new-frontend/parser/stringliteral.lean +++ /dev/null @@ -1,54 +0,0 @@ -/- -Copyright (c) 2018 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Leonardo de Moura --/ -prelude -import init.lean.parser.parsec - -namespace Lean -namespace Parser -open MonadParsec -variables {m : Type → Type} {μ : Type} [Monad m] [MonadParsec μ m] [Alternative m] - -def parseHexDigit : m Nat := -( (do d ← digit, pure $ d.toNat - '0'.toNat) - <|> (do c ← satisfy (λ c, 'a'.val ≤ c.val && c.val ≤ 'f'.val), pure $ 10 + (c.toNat - 'a'.toNat)) - <|> (do c ← satisfy (λ c, 'A'.val ≤ c.val && c.val ≤ 'F'.val), pure $ 10 + (c.toNat - 'A'.toNat))) - "hexadecimal" - -def parseQuotedChar : m Char := -do it ← leftOver, - c ← any, - if c = '\\' then pure '\\' - else if c = '\"' then pure '\"' - else if c = '\'' then pure '\'' - else if c = 'n' then pure '\n' - else if c = 't' then pure '\t' - else if c = 'x' then do { - d₁ ← parseHexDigit, - d₂ ← parseHexDigit, - pure $ Char.ofNat (16*d₁ + d₂) } - else if c = 'u' then do { - d₁ ← parseHexDigit, - d₂ ← parseHexDigit, - d₃ ← parseHexDigit, - d₄ ← parseHexDigit, - pure $ Char.ofNat (16*(16*(16*d₁ + d₂) + d₃) + d₄) } - else unexpectedAt "quoted character" it - -def parseStringLiteralAux : Nat → String → m String -| 0 s := ch '\"' *> pure s -| (n+1) s := do - c ← any, - if c = '\\' then do c ← parseQuotedChar, parseStringLiteralAux n (s.push c) - else if c = '\"' then pure s - else parseStringLiteralAux n (s.push c) - -def parseStringLiteral : m String := -do ch '\"', - r ← remaining, - parseStringLiteralAux r "" - -end Parser -end Lean diff --git a/tmp/new-frontend/parser/syntax.lean b/tmp/new-frontend/parser/syntax.lean deleted file mode 100644 index 7d30188424..0000000000 --- a/tmp/new-frontend/parser/syntax.lean +++ /dev/null @@ -1,222 +0,0 @@ -/- -Copyright (c) 2018 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Author: Sebastian Ullrich --/ -prelude -import init.lean.name init.lean.parser.parsec - -namespace Lean -namespace Parser - ---TODO(Sebastian): move -structure Substring := -(start : String.OldIterator) -(stop : String.OldIterator) - -structure SourceInfo := -/- Will be inferred after parsing by `Syntax.updateLeading`. During parsing, - it is not at all clear what the preceding token was, especially with backtracking. -/ -(leading : Substring) -(pos : Parsec.Position) -(trailing : Substring) - -structure SyntaxAtom := -(info : Option SourceInfo := none) (val : String) - -/-- A simple wrapper that should remind you to use the static declaration instead - of hard-coding the Node Name. -/ -structure SyntaxNodeKind := --- should be equal to the Name of the declaration this structure instance was bound to -(name : Name) - -/-- Signifies ambiguous Syntax to be disambiguated by the Elaborator. Should have at least two children. - - This Node kind is special-cased by `Syntax.reprint` since its children's outputs should not be concatenated. -/ -@[pattern] def choice : SyntaxNodeKind := ⟨`Lean.Parser.choice⟩ -/-- A nondescriptive kind that can be used for merely grouping Syntax trees into a Node. - - This Node kind is special-cased by `Syntax.Format` to be printed as brackets `[...]` without a Node kind. -/ -@[pattern] def noKind : SyntaxNodeKind := ⟨`Lean.Parser.noKind⟩ - -/-- A hygiene marker introduced by a macro expansion. -/ -@[derive DecidableEq HasFormat] -def MacroScope := Nat -abbrev macroScopes := List MacroScope - -/- -Parsers create `SyntaxNode`'s with the following properties (see implementation of `Combinators.Node`): -- If `args` contains a `Syntax.missing`, then all subsequent elements are also `Syntax.missing`. -- The first argument in `args` is not `Syntax.missing` - -Remark: We do create `SyntaxNode`'s with an Empty `args` field (e.g. for representing `Option.none`). --/ -structure SyntaxNode (Syntax : Type) := -(kind : SyntaxNodeKind) -(args : List Syntax) --- Lazily propagated scopes. Scopes are pushed inwards when a Node is destructed via `Syntax.asNode`, --- until an ident or an atom (in which the scopes vanish) is reached. --- Scopes are stored in a stack with the most recent Scope at the top. -(scopes : macroScopes := []) - -structure SyntaxIdent := -(info : Option SourceInfo := none) -(rawVal : Substring) -(val : Name) -/- A List of overloaded, global names that this identifier could have referred to in the lexical context - where it was parsed. - If the identifier does not resolve to a local binding, it should instead resolve to one of - these preresolved constants. -/ -(preresolved : List Name := []) -(scopes : macroScopes := []) - -inductive Syntax -| atom (val : SyntaxAtom) -| ident (val : SyntaxIdent) --- note: use `Syntax.asNode` instead of matching against this Constructor so that --- macro scopes are propagated -| rawNode (val : SyntaxNode Syntax) -| missing - -instance : Inhabited Syntax := -⟨Syntax.missing⟩ - -def Substring.toString (s : Substring) : String := -s.start.extract s.stop - -def Substring.ofString (s : String) : Substring := -⟨s.mkOldIterator, s.mkOldIterator.toEnd⟩ - -instance Substring.HasToString : HasToString Substring := -⟨Substring.toString⟩ - --- TODO(Sebastian): exhaustively argue why (if?) this is correct --- The basic idea is List concatenation with elimination of adjacent identical scopes -def macroScopes.flip : macroScopes → macroScopes → macroScopes -| ys (x::xs) := match macroScopes.flip ys xs with - | y::ys := if x = y then ys else x::y::ys - | [] := [x] -| ys [] := ys - -namespace Syntax -open Lean.Format - -def flipScopes (scopes : macroScopes) : Syntax → Syntax -| (Syntax.ident n) := Syntax.ident {n with scopes := n.scopes.flip scopes} -| (Syntax.rawNode n) := Syntax.rawNode {n with scopes := n.scopes.flip scopes} -| stx := stx - -def mkNode (kind : SyntaxNodeKind) (args : List Syntax) := -Syntax.rawNode { kind := kind, args := args } - -/-- Match against `Syntax.rawNode`, propagating lazy macro scopes. -/ -def asNode : Syntax → Option (SyntaxNode Syntax) -| (Syntax.rawNode n) := some {n with args := n.args.map (flipScopes n.scopes), scopes := []} -| _ := none - -protected def list (args : List Syntax) := -mkNode noKind args - -def kind : Syntax → Option SyntaxNodeKind -| (Syntax.rawNode n) := some n.kind -| _ := none - -def isOfKind (k : SyntaxNodeKind) : Syntax → Bool -| (Syntax.rawNode n) := k.name = n.kind.name -| _ := false - -section -variables {m : Type → Type} [Monad m] (r : Syntax → m (Option Syntax)) - -partial def mreplace : Syntax → m Syntax -| stx@(rawNode n) := do - o ← r stx, - match o with - | some stx' := pure stx' - | none := do args' ← n.args.mmap mreplace, pure $ rawNode {n with args := args'} -| stx := do - o ← r stx, - pure $ o.getOrElse stx - -def replace := @mreplace Id _ -end - -/- Remark: the State `String.Iterator` is the `SourceInfo.trailing.stop` of the previous token, - or the beginning of the String. -/ -private def updateLeadingAux : Syntax → State String.OldIterator (Option Syntax) -| (atom a@{info := some info, ..}) := do - last ← get, - set info.trailing.stop, - pure $ some $ atom {a with info := some {info with leading := ⟨last, last.nextn (info.pos - last.offset)⟩}} -| (ident id@{info := some info, ..}) := do - last ← get, - set info.trailing.stop, - pure $ some $ ident {id with info := some {info with leading := ⟨last, last.nextn (info.pos - last.offset)⟩}} -| _ := pure none - -/-- Set `SourceInfo.leading` according to the trailing stop of the preceding token. - The Result is a round-tripping Syntax tree IF, in the input Syntax tree, - * all leading stops, atom contents, and trailing starts are correct - * trailing stops are between the trailing start and the next leading stop. - - Remark: after parsing all `SourceInfo.leading` fields are Empty. - The Syntax argument is the output produced by the Parser for `source`. - This Function "fixes" the `source.leanding` field. - - Note that, the `SourceInfo.trailing` fields are correct. - The implementation of this Function relies on this property. -/ -def updateLeading (source : String) : Syntax → Syntax := -λ stx, Prod.fst $ (mreplace updateLeadingAux stx).run source.mkOldIterator - -/-- Retrieve the left-most leaf's info in the Syntax tree. -/ -partial def getHeadInfo : Syntax → Option SourceInfo -| (atom a) := a.info -| (ident id) := id.info -| (rawNode n) := n.args.foldr (λ s r, getHeadInfo s <|> r) none -| _ := none - -def getPos (stx : Syntax) : Option Parsec.Position := -do i ← stx.getHeadInfo, - pure i.pos - -def reprintAtom : SyntaxAtom → String -| ⟨some info, s⟩ := info.leading.toString ++ s ++ info.trailing.toString -| ⟨none, s⟩ := s - -partial def reprint : Syntax → Option String -| (atom ⟨some info, s⟩) := pure $ info.leading.toString ++ s ++ info.trailing.toString -| (atom ⟨none, s⟩) := pure s -| (ident id@{info := some info, ..}) := pure $ info.leading.toString ++ id.rawVal.toString ++ info.trailing.toString -| (ident id@{info := none, ..}) := pure id.rawVal.toString -| (rawNode n) := - if n.kind.name = choice.name then match n.args with - -- should never happen - | [] := failure - -- check that every choice prints the same - | n::ns := do - s ← reprint n, - ss ← ns.mmap reprint, - guard $ ss.all (= s), - pure s - else String.join <$> n.args.mmap reprint -| missing := "" - -protected partial def format : Syntax → Format -| (atom ⟨_, s⟩) := fmt $ repr s -| (ident id) := - let scopes := id.preresolved.map fmt ++ id.scopes.reverse.map fmt in - let scopes := match scopes with [] := fmt "" | _ := bracket "{" (joinSep scopes ", ") "}" in - fmt "`" ++ fmt id.val ++ scopes -| stx@(rawNode n) := - let scopes := match n.scopes with [] := fmt "" | _ := bracket "{" (joinSep n.scopes.reverse ", ") "}" in - if n.kind.name = `Lean.Parser.noKind then sbracket $ scopes ++ joinSep (n.args.map format) line - else let shorterName := n.kind.name.replacePrefix `Lean.Parser Name.anonymous - in paren $ joinSep ((fmt shorterName ++ scopes) :: n.args.map format) line -| missing := "" - -instance : HasFormat Syntax := ⟨Syntax.format⟩ -instance : HasToString Syntax := ⟨toString ∘ fmt⟩ -end Syntax - -end Parser -end Lean diff --git a/tmp/new-frontend/parser/term.lean b/tmp/new-frontend/parser/term.lean deleted file mode 100644 index a92f69cbcc..0000000000 --- a/tmp/new-frontend/parser/term.lean +++ /dev/null @@ -1,455 +0,0 @@ -/- -Copyright (c) 2018 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Author: Sebastian Ullrich - -Term-Level parsers --/ -prelude -import init.lean.parser.level init.lean.parser.notation -import init.lean.expr - -namespace Lean -namespace Parser -open Combinators Parser.HasView MonadParsec - -local postfix `?`:10000 := optional -local postfix *:10000 := Combinators.many -local postfix +:10000 := Combinators.many1 - -set_option class.instance_max_depth 200 - -@[derive Parser.HasTokens Parser.HasView] -def identUnivSpec.Parser : basicParser := -node! identUnivSpec [".{", levels: Level.Parser+, "}"] - -@[derive Parser.HasTokens Parser.HasView] -def identUnivs.Parser : termParser := -node! identUnivs [id: ident.Parser, univs: (monadLift identUnivSpec.Parser)?] - -namespace Term -/-- Access leading Term -/ -def getLeading : trailingTermParser := read -instance : HasTokens getLeading := default _ -instance : HasView Syntax getLeading := default _ - -@[derive Parser.HasTokens Parser.HasView] -def paren.Parser : termParser := -node! «paren» ["(":maxPrec, - content: node! parenContent [ - Term: Term.Parser, - special: nodeChoice! parenSpecial { - /- Do not allow trailing comma. Looks a bit weird and would clash with - adding support for tuple sections (https://downloads.haskell.org/~ghc/8.2.1/docs/html/usersGuide/glasgowExts.html#tuple-sections). -/ - tuple: node! tuple [", ", tail: sepBy (Term.Parser 0) (symbol ", ") false], - typed: node! typed [" : ", type: Term.Parser], - }?, - ]?, - ")" -] - -@[derive Parser.HasTokens Parser.HasView] -def hole.Parser : termParser := -node! hole [hole: symbol "_" maxPrec] - -@[derive Parser.HasTokens Parser.HasView] -def sort.Parser : termParser := -nodeChoice! sort {"Sort":maxPrec, "Type":maxPrec} - -@[derive HasTokens HasView] -def typeSpec.Parser : termParser := -node! typeSpec [" : ", type: Term.Parser 0] - -@[derive HasTokens HasView] -def optType.Parser : termParser := -typeSpec.Parser? - -instance optType.viewDefault : HasViewDefault optType.Parser _ none := ⟨⟩ - -section binder -@[derive HasTokens HasView] -def binderIdent.Parser : termParser := -nodeChoice! binderIdent {id: ident.Parser, hole: hole.Parser} - -@[derive HasTokens HasView] -def binderDefault.Parser : termParser := -nodeChoice! binderDefault { - val: node! binderDefaultVal [":=", Term: Term.Parser 0], - tac: node! binderDefaultTac [".", Term: Term.Parser 0], -} - -@[derive HasTokens HasView] -def binderContent.Parser (requireType := false) : termParser := -node! binderContent [ - ids: binderIdent.Parser+, - type: optional typeSpec.Parser requireType, - default: binderDefault.Parser? -] - -@[derive HasTokens HasView] -def simpleBinder.Parser : termParser := -nodeChoice! simpleBinder { - explicit: node! simpleExplicitBinder ["(", id: ident.Parser, " : ", type: Term.Parser 0, right: symbol ")"], - implicit: node! simpleImplicitBinder ["{", id: ident.Parser, " : ", type: Term.Parser 0, right: symbol "}"], - strictImplicit: node! simpleStrictImplicitBinder ["⦃", id: ident.Parser, " : ", type: Term.Parser 0, right: symbol "⦄"], - instImplicit: node! simpleInstImplicitBinder ["[", id: ident.Parser, " : ", type: Term.Parser 0, right: symbol "]"], -} - -def simpleBinder.View.toBinderInfo : simpleBinder.View → (BinderInfo × SyntaxIdent × Syntax) -| (simpleBinder.View.explicit {id := id, type := type}) := (BinderInfo.default, id, type) -| (simpleBinder.View.implicit {id := id, type := type}) := (BinderInfo.implicit, id, type) -| (simpleBinder.View.strictImplicit {id := id, type := type}) := (BinderInfo.strictImplicit, id, type) -| (simpleBinder.View.instImplicit {id := id, type := type}) := (BinderInfo.instImplicit, id, type) - -@[derive Parser.HasTokens Parser.HasView] -def anonymousConstructor.Parser : termParser := -node! anonymousConstructor ["⟨":maxPrec, args: sepBy (Term.Parser 0) (symbol ","), "⟩"] - -/- All binders must be surrounded with some kind of bracket. (e.g., '()', '{}', '[]'). - We use this feature when parsing examples/definitions/theorems. The goal is to avoid counter-intuitive - declarations such as: - - example p : False := trivial - def main proof : False := trivial - - which would be parsed as - - example (p : False) : _ := trivial - - def main (proof : False) : _ := trivial - - where `_` in both cases is elaborated into `True`. This issue was raised by @gebner in the slack channel. - - - Remark: we still want implicit delimiters for lambda/pi expressions. That is, we want to - write - - fun x : t, s - or - fun x, s - - instead of - - fun (x : t), s -/ -@[derive HasTokens HasView] -def bracketedBinder.Parser (requireType := false) : termParser := -nodeChoice! bracketedBinder { - explicit: node! explicitBinder ["(", content: nodeChoice! explicitBinderContent { - «notation»: command.notationLike.Parser, - other: binderContent.Parser requireType - }, right: symbol ")"], - implicit: node! implicitBinder ["{", content: binderContent.Parser, "}"], - strictImplicit: node! strictImplicitBinder ["⦃", content: binderContent.Parser, "⦄"], - instImplicit: node! instImplicitBinder ["[", content: nodeLongestChoice! instImplicitBinderContent { - named: node! instImplicitNamedBinder [id: ident.Parser, " : ", type: Term.Parser 0], - anonymous: node! instImplicitAnonymousBinder [type: Term.Parser 0] - }, "]"], - anonymousConstructor: anonymousConstructor.Parser, -} - -@[derive HasTokens HasView] -def binder.Parser : termParser := -nodeChoice! binder { - bracketed: bracketedBinder.Parser, - unbracketed: binderContent.Parser, -} - -@[derive HasTokens HasView] -def bindersExt.Parser : termParser := -node! bindersExt [ - leadingIds: binderIdent.Parser*, - remainder: nodeChoice! bindersRemainder { - type: node! bindersTypes [":", type: Term.Parser 0], - -- we allow mixing like in `a (b : β) c`, but not `a : α (b : β) c : γ` - mixed: nodeChoice! mixedBinder { - bracketed: bracketedBinder.Parser, - id: binderIdent.Parser, - }+, - }? -] - -/-- We normalize binders to simpler singleton ones during expansion. -/ -@[derive HasTokens HasView] -def binders.Parser : termParser := -nodeChoice! binders { - extended: bindersExt.Parser, - -- a strict subset of `extended`, so only useful after parsing - simple: simpleBinder.Parser, -} - -/-- We normalize binders to simpler ones during expansion. These always-bracketed - binders are used in declarations and cannot be reduced to nested singleton binders. -/ -@[derive HasTokens HasView] -def bracketedBinders.Parser : termParser := -nodeChoice! bracketedBinders { - extended: bracketedBinder.Parser*, - -- a strict subset of `extended`, so only useful after parsing - simple: simpleBinder.Parser*, -} -end binder - -@[derive Parser.HasTokens Parser.HasView] -def lambda.Parser : termParser := -node! lambda [ - op: unicodeSymbol "λ" "fun" maxPrec, - binders: binders.Parser, - ",", - body: Term.Parser 0 -] - -@[derive Parser.HasTokens Parser.HasView] -def assume.Parser : termParser := -node! «assume» [ - "assume ":maxPrec, - binders: nodeChoice! assumeBinders { - anonymous: node! assumeAnonymous [": ", type: Term.Parser], - binders: binders.Parser - }, - ", ", - body: Term.Parser 0 -] - -@[derive Parser.HasTokens Parser.HasView] -def pi.Parser : termParser := -node! pi [ - op: anyOf [unicodeSymbol "Π" "Pi" maxPrec, unicodeSymbol "∀" "forall" maxPrec], - binders: binders.Parser, - ",", - range: Term.Parser 0 -] - -@[derive Parser.HasTokens Parser.HasView] -def explicit.Parser : termParser := -node! explicit [ - mod: nodeChoice! explicitModifier { - explicit: symbol "@" maxPrec, - partialExplicit: symbol "@@" maxPrec - }, - id: identUnivs.Parser -] - -@[derive Parser.HasTokens Parser.HasView] -def from.Parser : termParser := -node! «from» ["from ", proof: Term.Parser] - -@[derive Parser.HasTokens Parser.HasView] -def let.Parser : termParser := -node! «let» [ - "let ", - lhs: nodeChoice! letLhs { - id: node! letLhsId [ - id: ident.Parser, - -- NOTE: after expansion, binders are Empty - binders: bracketedBinder.Parser*, - type: optType.Parser, - ], - pattern: Term.Parser - }, - " := ", - value: Term.Parser, - " in ", - body: Term.Parser, -] - -@[derive Parser.HasTokens Parser.HasView] -def optIdent.Parser : termParser := -(try node! optIdent [id: ident.Parser, " : "])? - -@[derive Parser.HasTokens Parser.HasView] -def have.Parser : termParser := -node! «have» [ - "have ", - id: optIdent.Parser, - prop: Term.Parser, - proof: nodeChoice! haveProof { - Term: node! haveTerm [" := ", Term: Term.Parser], - «from»: node! haveFrom [", ", «from»: from.Parser], - }, - ", ", - body: Term.Parser, -] - -@[derive Parser.HasTokens Parser.HasView] -def show.Parser : termParser := -node! «show» [ - "show ", - prop: Term.Parser, - ", ", - «from»: from.Parser, -] - -@[derive Parser.HasTokens Parser.HasView] -def match.Parser : termParser := -node! «match» [ - "match ", - scrutinees: sepBy1 Term.Parser (symbol ", ") false, - type: optType.Parser, - " with ", - optBar: (symbol " | ")?, - equations: sepBy1 - node! «matchEquation» [ - lhs: sepBy1 Term.Parser (symbol ", ") false, ":=", rhs: Term.Parser] - (symbol " | ") false, -] - -@[derive Parser.HasTokens Parser.HasView] -def if.Parser : termParser := -node! «if» [ - "if ", - id: optIdent.Parser, - prop: Term.Parser, - " then ", - thenBranch: Term.Parser, - " else ", - elseBranch: Term.Parser, -] - -@[derive Parser.HasTokens Parser.HasView] -def structInst.Parser : termParser := -node! structInst [ - "{":maxPrec, - type: (try node! structInstType [id: ident.Parser, " . "])?, - «with»: (try node! structInstWith [source: Term.Parser, " with "])?, - items: sepBy nodeChoice! structInstItem { - field: node! structInstField [id: ident.Parser, " := ", val: Term.Parser], - source: node! structInstSource ["..", source: Term.Parser?], - } (symbol ", "), - "}", -] - -@[derive Parser.HasTokens Parser.HasView] -def Subtype.Parser : termParser := -node! Subtype [ - "{":maxPrec, - id: ident.Parser, - type: optType.Parser, - "//", - prop: Term.Parser, - "}" -] - -@[derive Parser.HasTokens Parser.HasView] -def inaccessible.Parser : termParser := -node! inaccessible [".(":maxPrec, Term: Term.Parser, ")"] - -@[derive Parser.HasTokens Parser.HasView] -def anonymousInaccessible.Parser : termParser := -node! anonymousInaccessible ["._":maxPrec] - -@[derive Parser.HasTokens Parser.HasView] -def sorry.Parser : termParser := -node! «sorry» ["sorry":maxPrec] - -def borrowPrec := maxPrec - 1 -@[derive Parser.HasTokens Parser.HasView] -def borrowed.Parser : termParser := -node! borrowed ["@&":maxPrec, Term: Term.Parser borrowPrec] - ---- Agda's `(x : e) → f` -@[derive Parser.HasTokens Parser.HasView] -def depArrow.Parser : termParser := -node! depArrow [binder: bracketedBinder.Parser true, op: unicodeSymbol "→" "->" 25, range: Term.Parser 24] - --- TODO(Sebastian): replace with attribute -@[derive HasTokens] -def builtinLeadingParsers : TokenMap termParser := TokenMap.ofList [ - (`ident, identUnivs.Parser), - (number.name, number.Parser), - (stringLit.name, stringLit.Parser), - ("(", paren.Parser), - ("(", depArrow.Parser), - ("_", hole.Parser), - ("Sort", sort.Parser), - ("Type", sort.Parser), - ("λ", lambda.Parser), - ("fun", lambda.Parser), - ("Π", pi.Parser), - ("Pi", pi.Parser), - ("∀", pi.Parser), - ("forall", pi.Parser), - ("⟨", anonymousConstructor.Parser), - ("@", explicit.Parser), - ("@@", explicit.Parser), - ("let", let.Parser), - ("have", have.Parser), - ("show", show.Parser), - ("assume", assume.Parser), - ("match", match.Parser), - ("if", if.Parser), - ("{", structInst.Parser), - ("{", Subtype.Parser), - ("{", depArrow.Parser), - ("[", depArrow.Parser), - (".(", inaccessible.Parser), - ("._", anonymousInaccessible.Parser), - ("sorry", sorry.Parser), - ("@&", borrowed.Parser) -] - -@[derive Parser.HasTokens Parser.HasView] -def sortApp.Parser : trailingTermParser := -do { l ← getLeading, guard $ l.isOfKind sort } *> -node! sortApp [fn: getLeading, Arg: monadLift (Level.Parser maxPrec).run] - -@[derive Parser.HasTokens Parser.HasView] -def app.Parser : trailingTermParser := -node! app [fn: getLeading, Arg: Term.Parser maxPrec] - -def mkApp (fn : Syntax) (args : List Syntax) : Syntax := -args.foldl (λ fn Arg, Syntax.mkNode app [fn, Arg]) fn - -@[derive Parser.HasTokens Parser.HasView] -def arrow.Parser : trailingTermParser := -node! arrow [dom: getLeading, op: unicodeSymbol "→" "->" 25, range: Term.Parser 24] - -@[derive Parser.HasView] -def projection.Parser : trailingTermParser := -try $ node! projection [ - Term: getLeading, - -- do not consume trailing whitespace - «.»: rawStr ".", - proj: nodeChoice! projectionSpec { - id: Parser.ident.Parser, - num: number.Parser, - }, -] - --- register '.' manually because of `rawStr` -instance projection.tokens : HasTokens projection.Parser := -/- Use maxPrec + 1 so that it bind more tightly than application: - `a (b).c` should be parsed as `a ((b).c)`. -/ -⟨[{«prefix» := ".", lbp := maxPrec.succ}]⟩ - -@[derive HasTokens] -def builtinTrailingParsers : TokenMap trailingTermParser := TokenMap.ofList [ - ("→", arrow.Parser), - ("->", arrow.Parser), - (".", projection.Parser) -] - -end Term - -private def trailing (cfg : CommandParserConfig) : trailingTermParser := --- try local parsers first, starting with the newest one -(do ps ← indexed cfg.localTrailingTermParsers, ps.foldr (<|>) (error "")) -<|> --- next try all non-local parsers -(do ps ← indexed cfg.trailingTermParsers, longestMatch ps) -<|> --- The application parsers should only be tried as a fall-back; --- e.g. `a + b` should not be parsed as `a (+ b)`. --- TODO(Sebastian): We should be able to remove this workaround using --- the proposed more robust precedence handling -anyOf [Term.sortApp.Parser, Term.app.Parser] - -private def leading (cfg : CommandParserConfig) : termParser := -(do ps ← indexed cfg.localLeadingTermParsers, ps.foldr (<|>) (error "")) -<|> -(do ps ← indexed cfg.leadingTermParsers, longestMatch ps) - -def termParser.run (p : termParser) : commandParser := -do cfg ← read, - adaptReader coe $ prattParser (leading cfg) (trailing cfg) p - -end Parser -end Lean diff --git a/tmp/new-frontend/parser/token.lean b/tmp/new-frontend/parser/token.lean deleted file mode 100644 index c1dc404260..0000000000 --- a/tmp/new-frontend/parser/token.lean +++ /dev/null @@ -1,379 +0,0 @@ -/- -Copyright (c) 2018 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Author: Sebastian Ullrich - -Tokenizer for the Lean language - -Even though our Parser architecture does not statically depend on a tokenizer but works directly on -the input String, we still use a "tokenizer" Parser in the Lean Parser in some circumstances: -* to distinguish between identifiers and keywords -* for error recovery: advance until next command token -* ...? --/ - -prelude -import init.lean.parser.combinators init.lean.parser.stringliteral - -namespace Lean -namespace Parser -open MonadParsec Combinators String HasView - -def matchToken : BasicParserM (Option TokenConfig) := -do cfg ← read, - it ← leftOver, - pure $ Prod.snd <$> cfg.tokens.oldMatchPrefix it - -private def finishCommentBlockAux : Nat → Nat → BasicParserM Unit -| nesting (n+1) := - str "/-" *> finishCommentBlockAux (nesting + 1) n - <|> - str "-/" *> (if nesting = 1 then pure () else finishCommentBlockAux (nesting - 1) n) - <|> - any *> finishCommentBlockAux nesting n -| _ _ := error "unreachable" - -def finishCommentBlock (nesting := 1) : BasicParserM Unit := -do r ← remaining, - finishCommentBlockAux nesting (r+1) "end of comment block" - -private def whitespaceAux : Nat → BasicParserM Unit -| (n+1) := -do whitespace, - str "--" *> takeWhile' (≠ '\n') *> whitespaceAux n - <|> - -- a "/--" doc comment is an actual token, not whitespace - try (str "/-" *> notFollowedBy (str "-")) *> finishCommentBlock *> whitespaceAux n - <|> - pure () -| 0 := error "unreachable" - -variables {m : Type → Type} -local notation `Parser` := m Syntax -local notation `lift` := @monadLift BasicParserM _ _ _ - -/-- Skip whitespace and comments. -/ -def whitespace : BasicParserM Unit := -hidden $ do - start ← leftOver, - -- every `whitespaceAux` loop reads at least one Char - whitespaceAux (start.remaining+1) - -section -variables [Monad m] [MonadParsec Syntax m] - -@[inline] def asSubstring {α : Type} (p : m α) : m Substring := -do start ← leftOver, - p, - stop ← leftOver, - pure ⟨start, stop⟩ - -variables [monadBasicParser m] - -@[specialize] def updateLast (f : Syntax → Syntax) (trailing : Substring) : List Syntax → List Syntax -| [] := [] -| [stx] := [f stx] -| (stx::stxs) := stx :: updateLast stxs - -private partial def updateTrailing : Substring → Syntax → Syntax -| trailing (Syntax.atom a@⟨some info, _⟩) := Syntax.atom {a with info := some {info with trailing := trailing}} -| trailing (Syntax.ident id@{info := some info, ..}) := Syntax.ident {id with info := some {info with trailing := trailing}} -| trailing (Syntax.rawNode n) := Syntax.rawNode {n with args := updateLast (updateTrailing trailing) trailing n.args} -| trailing stx := stx - -def withTrailing (stx : Syntax) : m Syntax := -do -- TODO(Sebastian): less greedy, more natural whitespace assignment - -- E.g. only read up to the next line break - trailing ← lift $ asSubstring $ whitespace, - pure $ updateTrailing trailing stx - -def mkRawRes (start stop : String.OldIterator) : Syntax := -let ss : Substring := ⟨start, stop⟩ in -Syntax.atom ⟨some {leading := ⟨start, start⟩, pos := start.offset, trailing := ⟨stop, stop⟩}, ss.toString⟩ - -/-- Match an arbitrary Parser and return the consumed String in a `Syntax.atom`. -/ -@[inline] def raw {α : Type} (p : m α) (trailingWs := false) : Parser := do - start ← leftOver, - p, - stop ← leftOver, - let stx := mkRawRes start stop, - if trailingWs then withTrailing stx else pure stx - -instance raw.tokens {α} (p : m α) (t) : Parser.HasTokens (raw p t : Parser) := default _ -instance raw.view {α} (p : m α) (t) : Parser.HasView (Option SyntaxAtom) (raw p t : Parser) := -{ view := λ stx, match stx with - | Syntax.atom atom := some atom - | _ := none, - review := λ a, (Syntax.atom <$> a).getOrElse Syntax.missing } - -/-- Like `raw (str s)`, but default to `s` in views. -/ -@[inline, derive HasTokens HasView] -def rawStr (s : String) (trailingWs := false) : Parser := -raw (str s) trailingWs - -instance rawStr.viewDefault (s) (t) : Parser.HasViewDefault (rawStr s t : Parser) (Option SyntaxAtom) (some {val := s}) := -⟨⟩ - -end - -set_option class.instance_max_depth 200 - -@[derive HasTokens HasView] -def detailIdentPart.Parser : BasicParserM Syntax := -nodeChoice! detailIdentPart { - escaped: node! detailIdentPartEscaped [ - escBegin: rawStr idBeginEscape.toString, - escaped: raw $ takeUntil1 isIdEndEscape, - escEnd: rawStr idEndEscape.toString, - ], - default: raw $ satisfy isIdFirst *> takeWhile isIdRest -} - -@[derive HasTokens HasView] -def detailIdentSuffix.Parser : RecT Unit Syntax BasicParserM Syntax := --- consume '.' only when followed by a character starting an detailIdentPart -try (lookahead (ch '.' *> (ch idBeginEscape <|> satisfy isIdFirst))) -*> node! detailIdentSuffix [«.»: rawStr ".", ident: recurse ()] - -def detailIdent' : RecT Unit Syntax BasicParserM Syntax := -node! detailIdent [part: monadLift detailIdentPart.Parser, suffix: optional detailIdentSuffix.Parser] - -/-- A Parser that gives a more detailed View of `SyntaxIdent.rawVal`. Not used by default for - performance reasons. -/ -def detailIdent.Parser : BasicParserM Syntax := -RecT.runParsec detailIdent' $ λ _, detailIdent' - -private def ident' : basicParser := -do - start ← leftOver, - s ← idPart, - n ← foldl Name.mkString (mkSimpleName s) $ do { - -- consume '.' only when followed by a character starting an detailIdentPart - try (lookahead (ch '.' *> (ch idBeginEscape <|> satisfy isIdFirst))), - ch '.', - idPart - }, - stop ← leftOver, - pure $ Syntax.ident { - info := some {leading := ⟨start, start⟩, pos := start.offset, trailing := ⟨stop, stop⟩}, - rawVal := ⟨start, stop⟩, - val := n - } - --- the Node macro doesn't seem to like these... ---TODO(Sebastian): these should probably generate better error messages -def parseBinLit : BasicParserM Unit := -ch '0' *> (ch 'b' <|> ch 'B') *> many1' (ch '0' <|> ch '1') - -def parseOctLit : BasicParserM String := -ch '0' *> (ch 'o' <|> ch 'O') *> takeWhile1 (λ c, c ≥ '0' && c < '8') - -def parseHexLit : BasicParserM String := -ch '0' *> (ch 'x' <|> ch 'X') *> takeWhile1 (λ c, c.isDigit || c.isAlpha) - ---TODO(Sebastian): other bases -def number' : basicParser := -nodeLongestChoice! number { - base10: raw $ takeWhile1 Char.isDigit, - base2: raw parseBinLit, - base8: raw parseOctLit, - base16: raw parseHexLit, -} - -def stringLit' : basicParser := -node! stringLit [val: raw parseStringLiteral] - -private def mkConsumeToken (tk : TokenConfig) (it : String.OldIterator) : basicParser := -let it' := it.nextn tk.prefix.length in -MonadParsec.lift $ λ _, Parsec.Result.ok (mkRawRes it it') it' none - -def numberOrStringLit : basicParser := -number' <|> stringLit' - -def tokenCont (it : String.OldIterator) (tk : TokenConfig) : basicParser := -do id ← ident', - it' ← leftOver, - -- if a token is both a symbol and a valid identifier (i.e. a keyword), - -- we want it to be recognized as a symbol - if it.offset + tk.prefix.length ≥ it'.offset then - mkConsumeToken tk it - else pure id - -def token : basicParser := -do it ← leftOver, - cache ← getCache, - -- NOTE: using `catch` instead of `<|>` so that error messages from the second block are preferred - catch (do - -- check token cache - some tkc ← pure cache.tokenCache | failure, - guard (it.offset = tkc.startIt.offset), - -- hackishly update Parsec Position - MonadParsec.lift (λ it, Parsec.Result.ok () tkc.stopIt none), - putCache {cache with hit := cache.hit + 1}, - pure tkc.tk - ) (λ _, do - -- cache failed, update cache - - identStart ← observing $ lookahead (satisfy isIdFirst <|> ch idBeginEscape), - tk ← matchToken, - tk ← match tk, identStart with - | some tk@{suffixParser := some _, ..}, _ := - error "token: not implemented" --str tk *> MonadParsec.lift r - | some tk, Except.ok _ := tokenCont it tk - | some tk, Except.error _ := mkConsumeToken tk it - | none, Except.ok _ := ident' - | none, Except.error _ := numberOrStringLit, - tk ← withTrailing tk, - newIt ← leftOver, - putCache {cache with tokenCache := some ⟨it, newIt, tk⟩, miss := cache.miss + 1}, - pure tk - ) - -def peekToken : BasicParserM (Except (Parsec.Message Syntax) Syntax) := -observing (try (lookahead token)) - -variable [monadBasicParser m] - -def symbolCore (sym : String) (lbp : Nat) (ex : DList String) : Parser := -lift $ try $ do { - it ← leftOver, - stx@(Syntax.atom ⟨_, sym'⟩) ← token | error "" ex it, - when (sym ≠ sym') $ - error sym' ex it, - pure stx -} sym - -@[inline] def symbol (sym : String) (lbp := 0) : Parser := -let sym := sym.trim in -symbolCore sym lbp (DList.singleton sym) - -instance symbol.tokens (sym lbp) : Parser.HasTokens (symbol sym lbp : Parser) := -⟨[⟨sym.trim, lbp, none⟩]⟩ -instance symbol.View (sym lbp) : Parser.HasView (Option SyntaxAtom) (symbol sym lbp : Parser) := -{ view := λ stx, match stx with - | Syntax.atom atom := some atom - | _ := none, - review := λ a, (Syntax.atom <$> a).getOrElse Syntax.missing } -instance symbol.viewDefault (sym lbp) : Parser.HasViewDefault (symbol sym lbp : Parser) _ - (some {info := none, val := sym.trim}) := ⟨⟩ - -def number.Parser : Parser := -lift $ try $ do { - it ← leftOver, - stx ← token, - if stx.isOfKind number then pure stx - else error "" (DList.singleton "number") it -} - -instance number.Parser.tokens : Parser.HasTokens (number.Parser : Parser) := default _ -instance number.Parser.view : Parser.HasView number.View (number.Parser : Parser) := -{..number.HasView} - -private def toNatCore (base : Nat) : String.OldIterator → Nat → Nat → Nat -| it 0 r := r -| it (i+1) r := - let c := it.curr in - let val := if c.isDigit then - c.toNat - '0'.toNat - else if c ≥ 'a' ∧ c ≤ 'f' then - c.toNat - 'a'.toNat - else - c.toNat - 'A'.toNat in - let r := r*base + val in - toNatCore it.next i r - -private def toNatBase (s : String) (base : Nat) : Nat := -toNatCore base s.mkOldIterator s.length 0 - -def number.View.toNat : number.View → Nat -| (number.View.base10 (some atom)) := atom.val.toNat -| (number.View.base2 (some atom)) := toNatBase atom.val 2 -| (number.View.base8 (some atom)) := toNatBase atom.val 8 -| (number.View.base16 (some atom)) := toNatBase atom.val 16 -| _ := 1138 -- should never happen, but let's still choose a grep-able number - -def number.View.ofNat (n : Nat) : number.View := -number.View.base10 (some {val := toString n}) - -def stringLit.Parser : Parser := -lift $ try $ do { - it ← leftOver, - stx ← token, - some _ ← pure $ tryView stringLit stx | error "" (DList.singleton "String") it, - pure stx -} "String" - -instance stringLit.Parser.tokens : Parser.HasTokens (stringLit.Parser : Parser) := default _ -instance stringLit.Parser.View : Parser.HasView stringLit.View (stringLit.Parser : Parser) := -{..stringLit.HasView} - -def stringLit.View.value (lit : stringLit.View) : Option String := do - atom ← lit.val, - Except.ok s ← pure $ Parsec.parse (parseStringLiteral : Parsec' _) atom.val - | failure, - pure s - -def ident.Parser : Parser := -lift $ try $ do { - it ← leftOver, - stx@(Syntax.ident _) ← token | error "" (DList.singleton "identifier") it, - pure stx -} "identifier" - -instance ident.Parser.tokens : Parser.HasTokens (ident.Parser : Parser) := default _ -instance ident.Parser.View : Parser.HasView SyntaxIdent (ident.Parser : Parser) := -{ view := λ stx, match stx with - | Syntax.ident id := id - | _ := {rawVal := Substring.ofString "NOTAnIdent", val := `NOTAnIdent}, - review := Syntax.ident } - -/-- Read identifier without consulting the token table. -/ -def rawIdent.Parser : Parser := -lift $ ident' >>= withTrailing - -instance rawIdent.Parser.tokens : Parser.HasTokens (rawIdent.Parser : Parser) := default _ -instance rawIdent.Parser.View : Parser.HasView SyntaxIdent (rawIdent.Parser : Parser) := -{..(ident.Parser.View : HasView _ (_ : Parser))} - -/-- Check if the following token is the symbol _or_ identifier `sym`. Useful for - parsing local tokens that have not been added to the token table (but may have - been so by some unrelated code). - - For example, the universe `max` Function is parsed using this Combinator so that - it can still be used as an identifier outside of universes (but registering it - as a token in a Term Syntax would not break the universe Parser). -/ -def symbolOrIdent (sym : String) : Parser := -lift $ try $ do - it ← leftOver, - stx ← token, - let sym' := match stx with - | Syntax.atom ⟨_, sym'⟩ := some sym' - | Syntax.ident id := some id.rawVal.toString - | _ := none, - when (sym' ≠ some sym) $ - error "" (DList.singleton (repr sym)) it, - pure stx - -instance symbolOrIdent.tokens (sym) : Parser.HasTokens (symbolOrIdent sym : Parser) := -default _ -instance symbolOrIdent.View (sym) : Parser.HasView Syntax (symbolOrIdent sym : Parser) := default _ - -/-- A unicode symbol with an ASCII fallback -/ -@[derive HasTokens HasView] -def unicodeSymbol (unicode ascii : String) (lbp := 0) : Parser := -lift $ anyOf [symbol unicode lbp, symbol ascii lbp] --- use unicode variant by default -instance unicodeSymbol.viewDefault (u a lbp) : Parser.HasViewDefault (unicodeSymbol u a lbp : Parser) _ (Syntax.atom ⟨none, u⟩) := ⟨⟩ - -def indexed {α : Type} (map : TokenMap α) : m (List α) := -lift $ do - Except.ok tk ← peekToken | error "", - n ← match tk with - | Syntax.atom ⟨_, s⟩ := pure $ mkSimpleName s - | Syntax.ident _ := pure `ident - | Syntax.rawNode n := pure n.kind.name - | _ := error "", - Option.toMonad $ map.find n - -end «Parser» -end Lean diff --git a/tmp/new-frontend/parser/trie.lean b/tmp/new-frontend/parser/trie.lean deleted file mode 100644 index 16b4baad8a..0000000000 --- a/tmp/new-frontend/parser/trie.lean +++ /dev/null @@ -1,109 +0,0 @@ -/- -Copyright (c) 2018 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Author: Sebastian Ullrich, Leonardo de Moura - -Trie for tokenizing the Lean language --/ -prelude -import init.data.rbmap -import init.lean.format init.lean.parser.parsec - -namespace Lean -namespace Parser - -inductive Trie (α : Type) -| Node : Option α → RBNode Char (λ _, Trie) → Trie - -namespace Trie -variables {α : Type} - -def empty : Trie α := -⟨none, RBNode.leaf⟩ - -instance : HasEmptyc (Trie α) := -⟨empty⟩ - -instance : Inhabited (Trie α) := -⟨Node none RBNode.leaf⟩ - -private partial def insertEmptyAux (s : String) (val : α) : String.Pos → Trie α -| i := match s.atEnd i with - | true := Trie.Node (some val) RBNode.leaf - | false := - let c := s.get i in - let t := insertEmptyAux (s.next i) in - Trie.Node none (RBNode.singleton c t) - -private partial def insertAux (s : String) (val : α) : Trie α → String.Pos → Trie α -| (Trie.Node v m) i := - match s.atEnd i with - | true := Trie.Node (some val) m -- overrides old value - | false := - let c := s.get i in - let i := s.next i in - let t := match RBNode.find Char.lt m c with - | none := insertEmptyAux s val i - | some t := insertAux t i in - Trie.Node v (RBNode.insert Char.lt m c t) - -def insert (t : Trie α) (s : String) (val : α) : Trie α := -insertAux s val t 0 - -private partial def findAux (s : String) : Trie α → String.Pos → Option α -| (Trie.Node val m) i := - match s.atEnd i with - | true := val - | false := - let c := s.get i in - let i := s.next i in - match RBNode.find Char.lt m c with - | none := none - | some t := findAux t i - -def find (t : Trie α) (s : String) : Option α := -findAux s t 0 - -private def updtAcc (v : Option α) (i : String.Pos) (acc : String.Pos × Option α) : String.Pos × Option α := -match v, acc with -| some v, (j, w) := (i, some v) -- we pattern match on `acc` to enable memory reuse -| none, acc := acc - -private partial def matchPrefixAux (s : String) : Trie α → String.Pos → (String.Pos × Option α) → String.Pos × Option α -| (Trie.Node v m) i acc := - match s.atEnd i with - | true := updtAcc v i acc - | false := - let acc := updtAcc v i acc in - let c := s.get i in - let i := s.next i in - match RBNode.find Char.lt m c with - | some t := matchPrefixAux t i acc - | none := acc - -def matchPrefix (s : String) (t : Trie α) (i : String.Pos) : String.Pos × Option α := -matchPrefixAux s t i (i, none) - --- TODO: delete -private def oldMatchPrefixAux : Nat → Trie α → String.OldIterator → Option (String.OldIterator × α) → Option (String.OldIterator × α) -| 0 (Trie.Node val map) it Acc := Prod.mk it <$> val <|> Acc -| (n+1) (Trie.Node val map) it Acc := - let Acc' := Prod.mk it <$> val <|> Acc in - match RBNode.find Char.lt map it.curr with - | some t := oldMatchPrefixAux n t it.next Acc' - | none := Acc' - --- TODO: delete -def oldMatchPrefix {α : Type} (t : Trie α) (it : String.OldIterator) : Option (String.OldIterator × α) := -oldMatchPrefixAux it.remaining t it none - -private partial def toStringAux {α : Type} : Trie α → List Format -| (Trie.Node val map) := map.fold (λ Fs c t, - format (repr c) :: (Format.group $ Format.nest 2 $ flip Format.joinSep Format.line $ toStringAux t) :: Fs) [] - -instance {α : Type} : HasToString (Trie α) := -⟨λ t, (flip Format.joinSep Format.line $ toStringAux t).pretty⟩ -end Trie - -end Parser -end Lean