This feature is useful since it allows us to perform inlining after lambda lifting has been performed.
208 lines
6.4 KiB
Text
208 lines
6.4 KiB
Text
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"
|