lean4-htt/tests/playground/parser/parser2.lean
Leonardo de Moura 0c9fe3c7d4 feat(library/compiler): add [inline2] attribute, and stage2 inlining
This feature is useful since it allows us to perform inlining
after lambda lifting has been performed.
2019-04-06 08:00:58 -07:00

208 lines
6.4 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import init.lean.name
open Lean
/-
We need the following compiler improvement for this experiment:
- The cases-merging optimization does not work when scrutinee is a constant.
We need more tests for cases-merging.
-/
def ParserCache := Nat -- TODO
def Syntax := String -- TODO
structure ParserData :=
(stxStack : Array Syntax) (pos : String.Pos) (cache : ParserCache) (errorMsg : Option String)
@[inline] def ParserData.hasError (d : ParserData) : Bool :=
d.errorMsg != none
@[inline] def ParserData.stackSize (d : ParserData) : Nat :=
d.stxStack.size
@[inline] def Array.shrink {α : Type} (a : Array α) (sz : Nat) : Array α :=
a -- TODO
@[inline] def ParserData.restore : ParserData → Nat → ParserData
| ⟨stack, pos, cache, _⟩ sz := ⟨stack.shrink sz, pos, cache, none⟩
def ParserFn := String → ParserData → ParserData
def ParserConfig := List String -- TODO
def CommandParserConfig := List String -- TODO
structure TokenConfig :=
(val : String) (lbp : Nat := 0)
structure ParserInfo :=
(updateTokens : NameSet → NameSet := λ m, m)
(firstToken : Option TokenConfig := none)
@[inline] def ParserFn.eps : ParserFn :=
λ s d, d
@[inline] def andthenFn (p q : ParserFn) : ParserFn :=
λ s d,
let d := p s d in
if d.hasError then d else q s d
@[noinline] def andthenInfo (p q : ParserInfo) : ParserInfo :=
{ updateTokens := q.updateTokens ∘ p.updateTokens,
firstToken := p.firstToken }
@[inline] def orelseFn (p q : ParserFn) : ParserFn :=
λ s d,
let iniPos := d.pos in
let iniSz := d.stackSize in
let d := p s d in
if d.hasError && d.pos == iniPos then q s (d.restore iniSz) else d
@[noinline] def orelseInfo (p q : ParserInfo) : ParserInfo :=
{ updateTokens := q.updateTokens ∘ p.updateTokens,
firstToken := none }
def ParserData.resetPos : ParserData → String.Pos → ParserData
| ⟨stack, _, cache, errorMsg⟩ pos := ⟨stack, pos, cache, errorMsg⟩
@[inline] def tryFn (p : ParserFn) : ParserFn :=
λ s d,
let iniPos := d.pos in
let d := p s d in
if d.hasError then d.resetPos iniPos else d
@[noinline] def tryInfo (p : ParserInfo) : ParserInfo :=
{ updateTokens := p.updateTokens,
firstToken := none }
instance : Inhabited ParserFn :=
⟨λ s, id⟩
structure AbsParser (ρ : Type) :=
(info : Thunk ParserInfo) (fn : ρ)
abbrev Parser := AbsParser ParserFn
class ParserFnLift (ρ : Type) :=
(lift {} : ParserFn → ρ)
(map : (ParserFn → ParserFn) → ρρ)
(map₂ : (ParserFn → ParserFn → ParserFn) → ρρρ)
instance parserLiftInhabited {ρ : Type} [ParserFnLift ρ] : Inhabited ρ :=
⟨ParserFnLift.lift (default _)⟩
instance : ParserFnLift ParserFn :=
{ lift := λ p, p,
map := λ m p, m p,
map₂ := λ m p1 p2, m p1 p2 }
@[inline]
def liftParser {ρ : Type} [ParserFnLift ρ] (info : Thunk ParserInfo) (fn : ParserFn) : AbsParser ρ :=
{ info := info, fn := ParserFnLift.lift fn }
@[inline]
def mapParser {ρ : Type} [ParserFnLift ρ] (infoFn : ParserInfo → ParserInfo) (pFn : ParserFn → ParserFn) : AbsParser ρ → AbsParser ρ :=
λ p, { info := Thunk.mk (λ _, infoFn p.info.get), fn := ParserFnLift.map pFn p.fn }
@[inline]
def mapParser₂ {ρ : Type} [ParserFnLift ρ] (infoFn : ParserInfo → ParserInfo → ParserInfo) (pFn : ParserFn → ParserFn → ParserFn)
: AbsParser ρ → AbsParser ρ → AbsParser ρ :=
λ p q, { info := Thunk.mk (λ _, infoFn p.info.get q.info.get), fn := ParserFnLift.map₂ pFn p.fn q.fn }
def EnvParserFn (α : Type) (ρ : Type) :=
αρ
def RecParserFn (α ρ : Type) :=
EnvParserFn (αρ) ρ
instance (α ρ : Type) [ParserFnLift ρ] : ParserFnLift (EnvParserFn α ρ) :=
{ lift := λ p a, ParserFnLift.lift p,
map := λ m p a, ParserFnLift.map m (p a),
map₂ := λ m p1 p2 a, ParserFnLift.map₂ m (p1 a) (p2 a) }
instance (α ρ : Type) [ParserFnLift ρ] : ParserFnLift (RecParserFn α ρ) :=
inferInstanceAs (ParserFnLift (EnvParserFn (αρ) ρ))
namespace RecParserFn
variables {α ρ : Type}
@[inline] def recurse (a : α) : RecParserFn α ρ :=
λ p, p a
@[inline] def run [ParserFnLift ρ] (x : RecParserFn α ρ) (rec : α → RecParserFn α ρ) : ρ :=
x (fix (λ f a, rec a f))
end RecParserFn
@[noinline] def tokenFn (tk : String) : ParserFn :=
λ s d, { errorMsg := some (s ++ tk), .. d}
@[noinline] def tokenInfo (s : String) : ParserInfo :=
{ updateTokens := λ m, m.insert (mkSimpleName s),
firstToken := some { val := s } }
@[inline] def token {ρ : Type} [ParserFnLift ρ] (s : String) : AbsParser ρ :=
liftParser (tokenInfo s) (tokenFn s)
@[inline] def andthen {ρ : Type} [ParserFnLift ρ] : AbsParser ρ → AbsParser ρ → AbsParser ρ :=
mapParser₂ andthenInfo andthenFn
@[inline] def orelse {ρ : Type} [ParserFnLift ρ] : AbsParser ρ → AbsParser ρ → AbsParser ρ :=
mapParser₂ orelseInfo orelseFn
@[inline] def try {ρ : Type} [ParserFnLift ρ] : AbsParser ρ → AbsParser ρ :=
mapParser tryInfo tryFn
abbrev BasicParser : Type := AbsParser (EnvParserFn ParserConfig ParserFn)
abbrev CmdParserFn (ρ : Type) : Type := EnvParserFn ρ (RecParserFn Unit ParserFn)
abbrev TermParserFn : Type := RecParserFn Nat (CmdParserFn ParserConfig)
abbrev TermParser : Type := AbsParser TermParserFn
abbrev TrailingTermParser : Type := AbsParser (EnvParserFn Syntax TermParserFn)
abbrev CommandParser : Type := AbsParser (CmdParserFn CommandParserConfig)
@[inline] def basicParser2TermParser (p : BasicParser) : TermParser :=
{ info := Thunk.mk (λ _, p.info.get), fn := λ _ cfg _, p.fn cfg }
instance basic2term : HasCoe BasicParser TermParser :=
⟨basicParser2TermParser⟩
local infix ` ; `:10 := _root_.andthen
local infix ` || `:5 := _root_.orelse
@[inline2]
def p0 : BasicParser :=
token "foo"; token "boo"
@[inline2]
def p1 (s : String) : TermParser :=
token "hello"; token "world"; token "boo"
||
token s
||
token "opt3"; token "boo"
set_option pp.implicit true
set_option pp.binder_types false
set_option trace.compiler.stage2 true
-- set_option trace.compiler.boxed true
-- set_option trace.compiler.stage1 true
-- set_option trace.compiler.lcnf true
-- set_option trace.compiler.lcnf true
-- set_option trace.compiler.simp true
@[inline2]
def p2 (s : String) : TermParser :=
-- token "boo"; p1; p1; p0
p1 "hello"; p0; p1 s
@[inline2]
def p3 (s : String) : TermParser :=
p1 s
||
p2 s
||
token "boo"; p2 s
@[inline2]
def p4 (s : String) : CommandParser :=
token s; token "boo"