159 lines
6.1 KiB
Text
159 lines
6.1 KiB
Text
/-
|
||
Copyright (c) 2019 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.String.Basic
|
||
import Init.Data.Array.Basic
|
||
import Init.Data.UInt
|
||
import Init.Data.Hashable
|
||
|
||
namespace Lean
|
||
/-
|
||
Basic Lean types used to implement builtin commands and extensions.
|
||
Note that this file is part of the Lean `Init` library instead of
|
||
`Lean` actual implementation.
|
||
The idea is to allow users to implement simple parsers, macros and tactics
|
||
without importing the whole `Lean` module.
|
||
It also allow us to use extensions to develop the `Init` library.
|
||
-/
|
||
|
||
/- Hierarchical names -/
|
||
inductive Name
|
||
| anonymous : Name
|
||
| str : Name → String → USize → Name
|
||
| num : Name → Nat → USize → Name
|
||
|
||
instance Name.inhabited : Inhabited Name :=
|
||
⟨Name.anonymous⟩
|
||
|
||
def Name.hash : Name → USize
|
||
| Name.anonymous => 1723
|
||
| Name.str p s h => h
|
||
| Name.num p v h => h
|
||
|
||
instance Name.hashable : Hashable Name := ⟨Name.hash⟩
|
||
|
||
@[export lean_name_hash] def Name.hashEx : Name → USize := 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) (hash v)
|
||
|
||
def mkNameSimple (s : String) : Name :=
|
||
mkNameStr Name.anonymous s
|
||
|
||
@[extern "lean_name_eq"]
|
||
protected def Name.beq : (@& Name) → (@& Name) → Bool
|
||
| Name.anonymous, Name.anonymous => true
|
||
| Name.str p₁ s₁ _, Name.str p₂ s₂ _ => s₁ == s₂ && Name.beq p₁ p₂
|
||
| Name.num p₁ n₁ _, Name.num p₂ n₂ _ => n₁ == n₂ && Name.beq p₁ p₂
|
||
| _, _ => false
|
||
|
||
instance : HasBeq Name := ⟨Name.beq⟩
|
||
|
||
inductive ParserKind
|
||
| leading | trailing
|
||
|
||
/-
|
||
Small DSL for describing parsers. We implement an interpreter for it
|
||
at `Parser.lean` -/
|
||
inductive ParserDescrCore : ParserKind → Type
|
||
| andthen {k : ParserKind} : ParserDescrCore k → ParserDescrCore k → ParserDescrCore k
|
||
| orelse {k : ParserKind} : ParserDescrCore k → ParserDescrCore k → ParserDescrCore k
|
||
| optional {k : ParserKind} : ParserDescrCore k → ParserDescrCore k
|
||
| lookahead {k : ParserKind} : ParserDescrCore k → ParserDescrCore k
|
||
| try {k : ParserKind} : ParserDescrCore k → ParserDescrCore k
|
||
| many {k : ParserKind} : ParserDescrCore k → ParserDescrCore k
|
||
| many1 {k : ParserKind} : ParserDescrCore k → ParserDescrCore k
|
||
| sepBy {k : ParserKind} : ParserDescrCore k → ParserDescrCore k → ParserDescrCore k
|
||
| sepBy1 {k : ParserKind} : ParserDescrCore k → ParserDescrCore k → ParserDescrCore k
|
||
| node {k : ParserKind} : Name → ParserDescrCore k → ParserDescrCore k
|
||
| symbol {k : ParserKind} : String → Option Nat → ParserDescrCore k
|
||
| nonReservedSymbol : String → Bool → ParserDescrCore ParserKind.leading
|
||
| num {k : ParserKind} : ParserDescrCore k
|
||
| str {k : ParserKind} : ParserDescrCore k
|
||
| char {k : ParserKind} : ParserDescrCore k
|
||
| ident {k : ParserKind} : ParserDescrCore k
|
||
| pushLeading : ParserDescrCore ParserKind.trailing
|
||
| parser : Name → Nat → ParserDescrCore ParserKind.leading
|
||
|
||
instance ParserDescrCore.inhabited {k} : Inhabited (ParserDescrCore k) := ⟨ParserDescrCore.symbol "" none⟩
|
||
|
||
abbrev ParserDescr := ParserDescrCore ParserKind.leading
|
||
abbrev TrailingParserDescr := ParserDescrCore ParserKind.trailing
|
||
|
||
@[matchPattern] abbrev ParserDescr.andthen := @ParserDescrCore.andthen
|
||
@[matchPattern] abbrev ParserDescr.orelse := @ParserDescrCore.orelse
|
||
@[matchPattern] abbrev ParserDescr.optional := @ParserDescrCore.optional
|
||
@[matchPattern] abbrev ParserDescr.lookahead := @ParserDescrCore.lookahead
|
||
@[matchPattern] abbrev ParserDescr.try := @ParserDescrCore.try
|
||
@[matchPattern] abbrev ParserDescr.many := @ParserDescrCore.many
|
||
@[matchPattern] abbrev ParserDescr.many1 := @ParserDescrCore.many1
|
||
@[matchPattern] abbrev ParserDescr.sepBy := @ParserDescrCore.sepBy
|
||
@[matchPattern] abbrev ParserDescr.sepBy1 := @ParserDescrCore.sepBy1
|
||
@[matchPattern] abbrev ParserDescr.node := @ParserDescrCore.node
|
||
@[matchPattern] abbrev ParserDescr.symbol := @ParserDescrCore.symbol
|
||
@[matchPattern] abbrev ParserDescr.num := @ParserDescrCore.num
|
||
@[matchPattern] abbrev ParserDescr.str := @ParserDescrCore.str
|
||
@[matchPattern] abbrev ParserDescr.char := @ParserDescrCore.char
|
||
@[matchPattern] abbrev ParserDescr.ident := @ParserDescrCore.ident
|
||
@[matchPattern] abbrev ParserDescr.nonReservedSymbol := @ParserDescrCore.nonReservedSymbol
|
||
@[matchPattern] abbrev ParserDescr.pushLeading := @ParserDescrCore.pushLeading
|
||
@[matchPattern] abbrev ParserDescr.parser := @ParserDescrCore.parser
|
||
|
||
/- Syntax -/
|
||
|
||
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 : String.Pos)
|
||
(trailing : Substring)
|
||
|
||
abbrev SyntaxNodeKind := Name
|
||
|
||
/- Syntax AST -/
|
||
|
||
inductive Syntax
|
||
| missing {} : Syntax
|
||
| node (kind : SyntaxNodeKind) (args : Array Syntax) : Syntax
|
||
| atom {} (info : Option SourceInfo) (val : String) : Syntax
|
||
| ident {} (info : Option SourceInfo) (rawVal : Substring) (val : Name) (preresolved : List (Name × List String)) : Syntax
|
||
|
||
instance Syntax.inhabited : Inhabited Syntax :=
|
||
⟨Syntax.missing⟩
|
||
|
||
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 _ _ _ _ => `ident
|
||
|
||
def isOfKind : Syntax → SyntaxNodeKind → Bool
|
||
| stx, k => stx.getKind == k
|
||
|
||
def getArg (stx : Syntax) (i : Nat) : Syntax :=
|
||
match stx with
|
||
| Syntax.node _ args => args.get! i
|
||
| _ => arbitrary _
|
||
|
||
def getArgs (stx : Syntax) : Array Syntax :=
|
||
match stx with
|
||
| Syntax.node _ args => args
|
||
| _ => #[]
|
||
|
||
end Syntax
|
||
|
||
end Lean
|