refactor: move basic Syntax API to LeanInit

We want to make them available for `macro`-building
This commit is contained in:
Leonardo de Moura 2020-01-19 14:44:03 -08:00
parent b2c92d57b3
commit e57d3431ee
5 changed files with 128 additions and 121 deletions

View file

@ -19,6 +19,9 @@ instance stringToName : HasCoe String Name :=
namespace Name
@[export lean_name_hash] def hashEx : Name → USize :=
Name.hash
def getPrefix : Name → Name
| anonymous => anonymous
| str p s _ => p
@ -46,14 +49,6 @@ def eqStr : Name → String → Bool
| str anonymous s _, s' => s == s'
| _, _ => false
protected def append : Name → Name → Name
| n, anonymous => n
| n, str p s _ => mkNameStr (append n p) s
| n, num p d _ => mkNameNum (append n p) d
instance : HasAppend Name :=
⟨Name.append⟩
def replacePrefix : Name → Name → Name → Name
| anonymous, anonymous, newP => newP
| anonymous, _, _ => anonymous
@ -100,19 +95,6 @@ else quickLtAux n₁ n₂
@[inline] instance : DecidableRel (@HasLess.Less Name Name.hasLtQuick) :=
inferInstanceAs (DecidableRel (fun a b => Name.quickLt a b = true))
def toStringWithSep (sep : String) : Name → String
| anonymous => "[anonymous]"
| str anonymous s _ => s
| num anonymous v _ => toString v
| str n s _ => toStringWithSep n ++ sep ++ s
| num n v _ => toStringWithSep n ++ sep ++ repr v
protected def toString : Name → String :=
toStringWithSep "."
instance : HasToString Name :=
⟨Name.toString⟩
def appendAfter : Name → String → Name
| str p s _, suffix => mkNameStr p (s ++ suffix)
| n, suffix => mkNameStr n suffix

View file

@ -180,7 +180,7 @@ adaptExpander $ fun stx => match_syntax stx with
| `(`($quot)) => pure quot.getKind
| stx => throwUnsupportedSyntax;
-- TODO: meaningful, unhygienic def name for selective macro `open`ing?
`(@[macro $(Lean.mkSimpleIdent k)] def myMacro : Macro := fun stx => match_syntax stx with $alts* | _ => throw ())
`(@[macro $(Lean.mkIdent k)] def myMacro : Macro := fun stx => match_syntax stx with $alts* | _ => throw ())
| _ => throwUnsupportedSyntax
/- We just ignore Lean3 notation declaration commands. -/

View file

@ -179,40 +179,6 @@ end Parser
open Parser
def mkAppStx (fn : Syntax) (args : Array Syntax) : Syntax :=
Syntax.node `Lean.Parser.Term.app #[fn, mkNullNode args]
-- args.foldl (fun fn arg => Syntax.node `Lean.Parser.Term.app #[fn, arg]) fn
def mkHole (ref : Syntax) := mkNode `Lean.Parser.Term.hole #[mkAtomFrom ref "_"]
/-- Convert a `Syntax.ident` into a `Lean.Parser.Term.id` node -/
def mkTermIdFromIdent (ident : Syntax) : Syntax :=
match ident with
| Syntax.ident _ _ _ _ => mkNode `Lean.Parser.Term.id #[ident, mkNullNode]
| _ => unreachable!
/--
Create a simple `Lean.Parser.Term.id` syntax using position
information from `ref` and name `n`. By simple, we mean that
`optional (explicitUniv <|> namedPattern)` is none.
To refer to a specific constant, use `mkCTermIdFrom` instead. -/
def mkTermIdFrom (ref : Syntax) (n : Name) : Syntax :=
mkTermIdFromIdent (mkIdentFrom ref n)
/-- Variant of `mkTermIdFrom` that makes sure that the identifier cannot accidentally
be captured. -/
def mkCTermIdFrom (ref : Syntax) (c : Name) : Syntax :=
mkTermIdFromIdent (mkCIdentFrom ref c)
def mkTermId (n : Name) : Syntax :=
mkTermIdFrom Syntax.missing n
def mkCTermId (c : Name) : Syntax :=
mkCTermIdFrom Syntax.missing c
def mkCAppStx (fn : Name) (args : Array Syntax) : Syntax :=
mkAppStx (mkCTermId fn) args
def Syntax.isTermId? (stx : Syntax) : Option (Syntax × Syntax) :=
stx.ifNode
(fun node =>

View file

@ -27,15 +27,6 @@ def appendToLeading (info₁ info₂ : SourceInfo) : SourceInfo :=
end SourceInfo
/- Node kind generation -/
@[matchPattern] def choiceKind : SyntaxNodeKind := `choice
@[matchPattern] def nullKind : SyntaxNodeKind := `null
def strLitKind : SyntaxNodeKind := `strLit
def charLitKind : SyntaxNodeKind := `charLit
def numLitKind : SyntaxNodeKind := `numLit
def fieldIdxKind : SyntaxNodeKind := `fieldIdx
/- Syntax AST -/
def Syntax.isMissing : Syntax → Bool
@ -206,13 +197,6 @@ partial def updateTrailing (trailing : Substring) : Syntax → Syntax
Syntax.node k args
| s => s
/-- Retrieve the left-most leaf's info in the Syntax tree. -/
partial def getHeadInfo : Syntax → Option SourceInfo
| atom info _ => info
| ident info _ _ _ => info
| node _ args => args.find? getHeadInfo
| _ => none
def getPos (stx : Syntax) : Option String.Pos :=
SourceInfo.pos <$> stx.getHeadInfo
@ -314,10 +298,6 @@ end SyntaxNode
def mkSimpleAtom (val : String) : Syntax :=
Syntax.atom none val
@[export lean_mk_syntax_ident]
def mkSimpleIdent (val : Name) : Syntax :=
Syntax.ident none (toString val).toSubstring val []
@[export lean_mk_syntax_list]
def mkListNode (args : Array Syntax) : Syntax :=
Syntax.node nullKind args
@ -328,26 +308,6 @@ Syntax.atom none val
@[inline] def mkNode (k : SyntaxNodeKind) (args : Array Syntax) : Syntax :=
Syntax.node k args
@[inline] def mkNullNode (args : Array Syntax := #[]) : Syntax :=
Syntax.node nullKind args
def mkOptionalNode (arg : Option Syntax) : Syntax :=
match arg with
| some arg => Syntax.node nullKind #[arg]
| none => Syntax.node nullKind #[]
/- Helper functions for creating string and numeric literals -/
def mkStxLit (kind : SyntaxNodeKind) (val : String) (info : Option SourceInfo := none) : Syntax :=
let atom : Syntax := Syntax.atom info val;
Syntax.node kind #[atom]
def mkStxStrLit (val : String) (info : Option SourceInfo := none) : Syntax :=
mkStxLit strLitKind (repr val) info
def mkStxNumLit (val : String) (info : Option SourceInfo := none) : Syntax :=
mkStxLit numLitKind val info
@[export lean_mk_syntax_str_lit]
def mkStxStrLitAux (val : String) : Syntax :=
mkStxStrLit val
@ -517,22 +477,4 @@ def hasArgs : Syntax → Bool
| _ => false
end Syntax
/-- Create an identifier using `SourceInfo` from `src`.
To refer to a specific constant, use `mkCIdentFrom` instead. -/
def mkIdentFrom (src : Syntax) (val : Name) : Syntax :=
let info := src.getHeadInfo;
Syntax.ident info (toString val).toSubstring val []
/-- Create an identifier referring to a constant `c` using `SourceInfo` from `src`.
This variant of `mkIdentFrom` makes sure that the identifier cannot accidentally
be captured. -/
def mkCIdentFrom (src : Syntax) (c : Name) : Syntax :=
let info := src.getHeadInfo;
Syntax.ident info (toString c).toSubstring (`_root_ ++ c) [(c, [])]
def mkAtomFrom (src : Syntax) (val : String) : Syntax :=
let info := src.getHeadInfo;
Syntax.atom info val
end Lean

View file

@ -30,15 +30,13 @@ inductive Name
instance Name.inhabited : Inhabited Name :=
⟨Name.anonymous⟩
def Name.hash : Name → USize
protected 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)
@ -50,15 +48,40 @@ Name.num p v $ mixHash (hash p) (hash v)
def mkNameSimple (s : String) : Name :=
mkNameStr Name.anonymous s
namespace Name
@[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
| anonymous, anonymous => true
| str p₁ s₁ _, str p₂ s₂ _ => s₁ == s₂ && Name.beq p₁ p₂
| num p₁ n₁ _, num p₂ n₂ _ => n₁ == n₂ && Name.beq p₁ p₂
| _, _ => false
instance : HasBeq Name := ⟨Name.beq⟩
def toStringWithSep (sep : String) : Name → String
| anonymous => "[anonymous]"
| str anonymous s _ => s
| num anonymous v _ => toString v
| str n s _ => toStringWithSep n ++ sep ++ s
| num n v _ => toStringWithSep n ++ sep ++ repr v
protected def toString : Name → String :=
toStringWithSep "."
instance : HasToString Name :=
⟨Name.toString⟩
protected def append : Name → Name → Name
| n, anonymous => n
| n, str p s _ => mkNameStr (append n p) s
| n, num p d _ => mkNameNum (append n p) d
instance : HasAppend Name :=
⟨Name.append⟩
end Name
inductive ParserKind
| leading | trailing
@ -156,6 +179,13 @@ match stx with
| Syntax.node _ args => args
| _ => #[]
/-- Retrieve the left-most leaf's info in the Syntax tree. -/
partial def getHeadInfo : Syntax → Option SourceInfo
| atom info _ => info
| ident info _ _ _ => info
| node _ args => args.find? getHeadInfo
| _ => none
end Syntax
/-
@ -204,6 +234,93 @@ instance MacroM.monadQuotation : MonadQuotation MacroM :=
abbrev Macro := Syntax → MacroM Syntax
/- Builtin kinds -/
@[matchPattern] def choiceKind : SyntaxNodeKind := `choice
@[matchPattern] def nullKind : SyntaxNodeKind := `null
def strLitKind : SyntaxNodeKind := `strLit
def charLitKind : SyntaxNodeKind := `charLit
def numLitKind : SyntaxNodeKind := `numLit
def fieldIdxKind : SyntaxNodeKind := `fieldIdx
/- Helper functions for processing Syntax programmatically -/
/--
Create an identifier using `SourceInfo` from `src`.
To refer to a specific constant, use `mkCIdentFrom` instead. -/
def mkIdentFrom (src : Syntax) (val : Name) : Syntax :=
let info := src.getHeadInfo;
Syntax.ident info (toString val).toSubstring val []
/--
Create an identifier referring to a constant `c` using `SourceInfo` from `src`.
This variant of `mkIdentFrom` makes sure that the identifier cannot accidentally
be captured. -/
def mkCIdentFrom (src : Syntax) (c : Name) : Syntax :=
let info := src.getHeadInfo;
Syntax.ident info (toString c).toSubstring (`_root_ ++ c) [(c, [])]
def mkAtomFrom (src : Syntax) (val : String) : Syntax :=
let info := src.getHeadInfo;
Syntax.atom info val
@[export lean_mk_syntax_ident]
def mkIdent (val : Name) : Syntax :=
Syntax.ident none (toString val).toSubstring val []
@[inline] def mkNullNode (args : Array Syntax := #[]) : Syntax :=
Syntax.node nullKind args
def mkOptionalNode (arg : Option Syntax) : Syntax :=
match arg with
| some arg => Syntax.node nullKind #[arg]
| none => Syntax.node nullKind #[]
/-- Create syntax representing a Lean term application -/
def mkAppStx (fn : Syntax) (args : Array Syntax) : Syntax :=
Syntax.node `Lean.Parser.Term.app #[fn, mkNullNode args]
def mkHole (ref : Syntax) : Syntax :=
Syntax.node `Lean.Parser.Term.hole #[mkAtomFrom ref "_"]
/-- Convert a `Syntax.ident` into a `Lean.Parser.Term.id` node -/
def mkTermIdFromIdent (ident : Syntax) : Syntax :=
match ident with
| Syntax.ident _ _ _ _ => Syntax.node `Lean.Parser.Term.id #[ident, mkNullNode]
| _ => unreachable!
/--
Create a simple `Lean.Parser.Term.id` syntax using position
information from `ref` and name `n`. By simple, we mean that
`optional (explicitUniv <|> namedPattern)` is none.
To refer to a specific constant, use `mkCTermIdFrom` instead. -/
def mkTermIdFrom (ref : Syntax) (n : Name) : Syntax :=
mkTermIdFromIdent (mkIdentFrom ref n)
/-- Variant of `mkTermIdFrom` that makes sure that the identifier cannot accidentally
be captured. -/
def mkCTermIdFrom (ref : Syntax) (c : Name) : Syntax :=
mkTermIdFromIdent (mkCIdentFrom ref c)
def mkTermId (n : Name) : Syntax :=
mkTermIdFrom Syntax.missing n
def mkCTermId (c : Name) : Syntax :=
mkCTermIdFrom Syntax.missing c
def mkCAppStx (fn : Name) (args : Array Syntax) : Syntax :=
mkAppStx (mkCTermId fn) args
def mkStxLit (kind : SyntaxNodeKind) (val : String) (info : Option SourceInfo := none) : Syntax :=
let atom : Syntax := Syntax.atom info val;
Syntax.node kind #[atom]
def mkStxStrLit (val : String) (info : Option SourceInfo := none) : Syntax :=
mkStxLit strLitKind (repr val) info
def mkStxNumLit (val : String) (info : Option SourceInfo := none) : Syntax :=
mkStxLit numLitKind val info
end Lean
abbrev Array.getSepElems := @Array.getEvenElems