91 lines
3.8 KiB
Text
91 lines
3.8 KiB
Text
#lang lean4
|
||
/-
|
||
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
|
||
-/
|
||
import Lean.Elab.Import
|
||
import Lean.Elab.Command
|
||
|
||
namespace Lean.Elab.Frontend
|
||
structure State :=
|
||
(commandState : Command.State)
|
||
(parserState : Parser.ModuleParserState)
|
||
(cmdPos : String.Pos)
|
||
|
||
structure Context :=
|
||
(inputCtx : Parser.InputContext)
|
||
|
||
abbrev FrontendM := ReaderT Context $ StateRefT State IO
|
||
|
||
def setCommandState (commandState : Command.State) : FrontendM Unit :=
|
||
modify fun s => { s with commandState := commandState }
|
||
|
||
@[inline] def runCommandElabM (x : Command.CommandElabM Unit) : FrontendM Unit := do
|
||
let ctx ← read
|
||
let s ← get
|
||
let cmdCtx : Command.Context := { cmdPos := s.cmdPos, fileName := ctx.inputCtx.fileName, fileMap := ctx.inputCtx.fileMap }
|
||
let sNew? ← liftM $ EIO.toIO (fun _ => IO.Error.userError "unexpected error") (do (_, s) ← (x cmdCtx).run s.commandState; pure $ some s)
|
||
match sNew? with
|
||
| some sNew => setCommandState sNew
|
||
| none => pure ()
|
||
|
||
def elabCommandAtFrontend (stx : Syntax) : FrontendM Unit :=
|
||
runCommandElabM (Command.elabCommand stx)
|
||
|
||
def updateCmdPos : FrontendM Unit := do
|
||
modify fun s => { s with cmdPos := s.parserState.pos }
|
||
|
||
def getParserState : FrontendM Parser.ModuleParserState := do pure (← get).parserState
|
||
def getCommandState : FrontendM Command.State := do pure (← get).commandState
|
||
def setParserState (ps : Parser.ModuleParserState) : FrontendM Unit := modify fun s => { s with parserState := ps }
|
||
def setMessages (msgs : MessageLog) : FrontendM Unit := modify fun s => { s with commandState := { s.commandState with messages := msgs } }
|
||
def getInputContext : FrontendM Parser.InputContext := do pure (← read).inputCtx
|
||
|
||
def processCommand : FrontendM Bool := do
|
||
updateCmdPos
|
||
let cmdState ← getCommandState
|
||
match Parser.parseCommand cmdState.env (← getInputContext) (← getParserState) cmdState.messages with
|
||
| (cmd, ps, messages) =>
|
||
setParserState ps
|
||
setMessages messages
|
||
if Parser.isEOI cmd || Parser.isExitCommand cmd then
|
||
pure true -- Done
|
||
else
|
||
elabCommandAtFrontend cmd
|
||
pure false
|
||
|
||
partial def processCommands : FrontendM Unit := do
|
||
let done ← processCommand
|
||
unless done do
|
||
processCommands
|
||
|
||
end Frontend
|
||
|
||
open Frontend
|
||
|
||
def IO.processCommands (inputCtx : Parser.InputContext) (parserState : Parser.ModuleParserState) (commandState : Command.State) : IO Command.State := do
|
||
let (_, s) ← (Frontend.processCommands.run { inputCtx := inputCtx }).run { commandState := commandState, parserState := parserState, cmdPos := parserState.pos }
|
||
pure s.commandState
|
||
|
||
def process (input : String) (env : Environment) (opts : Options) (fileName : Option String := none) : IO (Environment × MessageLog) := do
|
||
let fileName := fileName.getD "<input>"
|
||
let inputCtx := Parser.mkInputContext input fileName
|
||
let commandState ← IO.processCommands inputCtx { : Parser.ModuleParserState } (Command.mkState env {} opts)
|
||
pure (commandState.env, commandState.messages)
|
||
|
||
@[export lean_process_input]
|
||
def processExport (env : Environment) (input : String) (opts : Options) (fileName : String) : IO (Environment × List Message) := do
|
||
let (env, messages) ← process input env opts fileName
|
||
pure (env, messages.toList)
|
||
|
||
@[export lean_run_frontend]
|
||
def runFrontend (input : String) (opts : Options) (fileName : String) (mainModuleName : Name) : IO (Environment × List Message) := do
|
||
let inputCtx := Parser.mkInputContext input fileName
|
||
let (header, parserState, messages) ← Parser.parseHeader inputCtx
|
||
let (env, messages) ← processHeader header opts messages inputCtx
|
||
let env := env.setMainModule mainModuleName
|
||
let cmdState ← IO.processCommands inputCtx parserState (Command.mkState env messages opts)
|
||
pure (cmdState.env, cmdState.messages.toList)
|
||
|
||
end Lean.Elab
|