diff --git a/src/Lean/Elab/Frontend.lean b/src/Lean/Elab/Frontend.lean index 4fea1b91df..df70a9ef3d 100644 --- a/src/Lean/Elab/Frontend.lean +++ b/src/Lean/Elab/Frontend.lean @@ -49,8 +49,10 @@ def processCommand : FrontendM Bool := do let cmdState ← getCommandState let ictx ← getInputContext let pstate ← getParserState + let scope := cmdState.scopes.head! + let pmctx := { env := cmdState.env, currNamespace := scope.currNamespace, openDecls := scope.openDecls } let pos := ictx.fileMap.toPosition pstate.pos - match profileit "parsing" pos fun _ => Parser.parseCommand cmdState.env ictx pstate cmdState.messages with + match profileit "parsing" pos fun _ => Parser.parseCommand ictx pmctx pstate cmdState.messages with | (cmd, ps, messages) => modify fun s => { s with commands := s.commands.push cmd } setParserState ps diff --git a/src/Lean/Parser/Basic.lean b/src/Lean/Parser/Basic.lean index ce19859be4..669e5bc464 100644 --- a/src/Lean/Parser/Basic.lean +++ b/src/Lean/Parser/Basic.lean @@ -62,6 +62,7 @@ import Lean.Environment import Lean.Attributes import Lean.Message import Lean.Compiler.InitAttr +import Lean.ResolveName namespace Lean @@ -120,15 +121,24 @@ instance : Inhabited InputContext := ⟨{ input := "", fileName := "", fileMap := arbitrary }⟩ -structure ParserContext extends InputContext where +/-- Input context derived from elaboration of previous commands. -/ +structure ParserModuleContext where + env : Environment + -- for name lookup + currNamespace : Name := Name.anonymous + openDecls : List OpenDecl := [] + +structure ParserContext extends InputContext, ParserModuleContext where prec : Nat - env : Environment tokens : TokenTable insideQuot : Bool := false suppressInsideQuot : Bool := false savedPos? : Option String.Pos := none forbiddenTk? : Option Token := none +def ParserContext.resolveName (ctx : ParserContext) (id : Name) : List (Name × List String) := + ResolveName.resolveGlobalName ctx.env ctx.currNamespace ctx.openDecls id + structure Error where unexpected : String := "" expected : List String := [] diff --git a/src/Lean/Parser/Extension.lean b/src/Lean/Parser/Extension.lean index fe055579e4..6a6ff6a154 100644 --- a/src/Lean/Parser/Extension.lean +++ b/src/Lean/Parser/Extension.lean @@ -422,11 +422,11 @@ def mkInputContext (input : String) (fileName : String) : InputContext := { fileMap := input.toFileMap } -def mkParserContext (env : Environment) (ctx : InputContext) : ParserContext := { - prec := 0, - toInputContext := ctx, - env := env, - tokens := getTokenTable env +def mkParserContext (ictx : InputContext) (pmctx : ParserModuleContext) : ParserContext := { + prec := 0, + toInputContext := ictx, + toParserModuleContext := pmctx, + tokens := getTokenTable pmctx.env } def mkParserState (input : String) : ParserState := @@ -434,7 +434,7 @@ def mkParserState (input : String) : ParserState := /- convenience function for testing -/ def runParserCategory (env : Environment) (catName : Name) (input : String) (fileName := "") : Except String Syntax := - let c := mkParserContext env (mkInputContext input fileName) + let c := mkParserContext (mkInputContext input fileName) { env := env } let s := mkParserState input let s := whitespace c s let s := categoryParserFnImpl catName c s diff --git a/src/Lean/Parser/Module.lean b/src/Lean/Parser/Module.lean index e414768135..d76de41040 100644 --- a/src/Lean/Parser/Module.lean +++ b/src/Lean/Parser/Module.lean @@ -40,7 +40,7 @@ private def mkErrorMessage (c : ParserContext) (pos : String.Pos) (errorMsg : St def parseHeader (inputCtx : InputContext) : IO (Syntax × ModuleParserState × MessageLog) := do let dummyEnv ← mkEmptyEnvironment - let ctx := mkParserContext dummyEnv inputCtx + let ctx := mkParserContext inputCtx { env := dummyEnv } let ctx := Module.updateTokens ctx let s := mkParserState ctx.input let s := whitespace ctx s @@ -76,13 +76,13 @@ def topLevelCommandParserFn : ParserFn := (andthenFn (lookaheadFn termParser.fn) (errorFn "expected command, but found term; this error may be due to parsing precedence levels, consider parenthesizing the term")) false /- do not merge errors -/ -partial def parseCommand (env : Environment) (inputCtx : InputContext) (s : ModuleParserState) (messages : MessageLog) : Syntax × ModuleParserState × MessageLog := +partial def parseCommand (inputCtx : InputContext) (pmctx : ParserModuleContext) (s : ModuleParserState) (messages : MessageLog) : Syntax × ModuleParserState × MessageLog := let rec parse (s : ModuleParserState) (messages : MessageLog) := let { pos := pos, recovering := recovering } := s if inputCtx.input.atEnd pos then (mkEOI pos, s, messages) else - let c := mkParserContext env inputCtx + let c := mkParserContext inputCtx pmctx let s := { cache := initCacheForInput c.input, pos := pos : ParserState } let s := whitespace c s let s := topLevelCommandParserFn c s @@ -104,29 +104,11 @@ partial def parseCommand (env : Environment) (inputCtx : InputContext) (s : Modu -- (stx, { pos := pos, recovering := true }, messages) parse s messages -private partial def testModuleParserAux (env : Environment) (inputCtx : InputContext) (displayStx : Bool) (s : ModuleParserState) (messages : MessageLog) : IO Bool := - let rec loop (s : ModuleParserState) (messages : MessageLog) := do - match parseCommand env inputCtx s messages with - | (stx, s, messages) => - if isEOI stx || isExitCommand stx then - messages.forM fun msg => msg.toString >>= IO.println - pure (!messages.hasErrors) - else - if displayStx then IO.println stx - loop s messages - loop s messages +-- only useful for testing since most Lean files cannot be parsed without elaboration -@[export lean_test_module_parser] -def testModuleParser (env : Environment) (input : String) (fileName := "") (displayStx := false) : IO Bool := - timeit (fileName ++ " parser") do - let inputCtx := mkInputContext input fileName - let (stx, s, messages) ← parseHeader inputCtx - if displayStx then IO.println stx - testModuleParserAux env inputCtx displayStx s messages - -partial def parseModuleAux (env : Environment) (inputCtx : InputContext) (s : ModuleParserState) (msgs : MessageLog) (stxs : Array Syntax) : IO (Array Syntax) := +partial def testParseModuleAux (env : Environment) (inputCtx : InputContext) (s : ModuleParserState) (msgs : MessageLog) (stxs : Array Syntax) : IO (Array Syntax) := let rec parse (state : ModuleParserState) (msgs : MessageLog) (stxs : Array Syntax) := - match parseCommand env inputCtx state msgs with + match parseCommand inputCtx { env := env } state msgs with | (stx, state, msgs) => if isEOI stx then if msgs.isEmpty then @@ -138,17 +120,17 @@ partial def parseModuleAux (env : Environment) (inputCtx : InputContext) (s : Mo parse state msgs (stxs.push stx) parse s msgs stxs -def parseModule (env : Environment) (fname contents : String) : IO Syntax := do +def testParseModule (env : Environment) (fname contents : String) : IO Syntax := do let fname ← IO.realPath fname let inputCtx := mkInputContext contents fname let (header, state, messages) ← parseHeader inputCtx - let cmds ← parseModuleAux env inputCtx state messages #[] + let cmds ← testParseModuleAux env inputCtx state messages #[] let stx := Syntax.node `Lean.Parser.Module.module #[header, mkListNode cmds] pure stx.updateLeading -def parseFile (env : Environment) (fname : String) : IO Syntax := do +def testParseFile (env : Environment) (fname : String) : IO Syntax := do let contents ← IO.FS.readFile fname - parseModule env fname contents + testParseModule env fname contents end Parser end Lean diff --git a/src/Lean/Server/Snapshots.lean b/src/Lean/Server/Snapshots.lean index da81d2094f..c31cb6c674 100644 --- a/src/Lean/Server/Snapshots.lean +++ b/src/Lean/Server/Snapshots.lean @@ -78,8 +78,11 @@ through the file. -/ -- isServer? conditionals and not be worth it due to how short it is. def compileNextCmd (contents : String) (snap : Snapshot) : IO (Sum Snapshot MessageLog) := do let inputCtx := Parser.mkInputContext contents ""; + let cmdState := snap.toCmdState; + let scope := cmdState.scopes.head! + let pmctx := { env := cmdState.env, currNamespace := scope.currNamespace, openDecls := scope.openDecls } let (cmdStx, cmdParserState, msgLog) := - Parser.parseCommand snap.env inputCtx snap.mpState snap.msgLog; + Parser.parseCommand inputCtx pmctx snap.mpState snap.msgLog; let cmdPos := cmdStx.getHeadInfo.get!.pos.get!; -- TODO(WN): always `some`? if Parser.isEOI cmdStx || Parser.isExitCommand cmdStx then pure $ Sum.inr msgLog diff --git a/src/shell/lean.cpp b/src/shell/lean.cpp index b92a1f8ceb..c77dd8a6d4 100644 --- a/src/shell/lean.cpp +++ b/src/shell/lean.cpp @@ -332,11 +332,6 @@ public: }; namespace lean { -extern "C" object* lean_test_module_parser(object* env, object* input, object* filename, uint8 displayCtx, object* w); -bool test_module_parser(environment const & env, std::string const & input, std::string const & filename) { - return get_io_scalar_result(lean_test_module_parser(env.to_obj_arg(), mk_string(input), mk_string(filename), false, io_mk_world())); -} - typedef list_ref messages; typedef object_ref module_stx; extern "C" object * lean_run_frontend(object * input, object * opts, object * filename, object * main_module_name, object * w); diff --git a/tests/lean/Reformat.lean b/tests/lean/Reformat.lean index 0b64ec31f1..4ffa5c1697 100644 --- a/tests/lean/Reformat.lean +++ b/tests/lean/Reformat.lean @@ -12,10 +12,10 @@ let (debug, f) : Bool × String := match args with | [f] => (false, f) | _ => panic! "usage: file [-d]" let env ← mkEmptyEnvironment -let stx ← Lean.Parser.parseFile env args.head! +let stx ← Lean.Parser.testParseFile env args.head! let (f, _) ← (tryFinally (PrettyPrinter.ppModule stx) printTraces).toIO { options := Options.empty.setBool `trace.PrettyPrinter.format debug } { env := env } IO.print f -let stx' ← Lean.Parser.parseModule env args.head! (toString f) +let stx' ← Lean.Parser.testParseModule env args.head! (toString f) if stx' != stx then let stx := stx.getArg 1 let stx' := stx'.getArg 1 diff --git a/tests/lean/run/Reparen.lean b/tests/lean/run/Reparen.lean index f4f6dc9257..4c2d0d3d3b 100644 --- a/tests/lean/run/Reparen.lean +++ b/tests/lean/run/Reparen.lean @@ -23,7 +23,7 @@ let (debug, f) : Bool × String := match args with | [f] => (false, f) | _ => panic! "usage: file [-d]"; let env ← mkEmptyEnvironment; -let stx ← Lean.Parser.parseFile env args.head!; +let stx ← Lean.Parser.testParseFile env args.head!; let header := stx.getArg 0; let some s ← pure header.reprint | throw $ IO.userError "header reprint failed"; IO.print s; diff --git a/tests/lean/run/parseCore.lean b/tests/lean/run/parsePrelude.lean similarity index 67% rename from tests/lean/run/parseCore.lean rename to tests/lean/run/parsePrelude.lean index 80334957f8..6cc7066877 100644 --- a/tests/lean/run/parseCore.lean +++ b/tests/lean/run/parsePrelude.lean @@ -1,4 +1,3 @@ -#lang lean4 import Lean.Parser def test : IO Unit := @@ -6,7 +5,7 @@ if System.Platform.isWindows then pure () -- TODO investigate why the following doesn't work on Windows else do let env ← Lean.mkEmptyEnvironment; - Lean.Parser.parseFile env (System.mkFilePath ["..", "..", "..", "src", "Init", "Prelude.lean"]); + Lean.Parser.testParseFile env (System.mkFilePath ["..", "..", "..", "src", "Init", "Prelude.lean"]); IO.println "done" #eval test