/- Copyright (c) 2019 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura -/ prelude import Init.Lean.Meta import Init.Lean.Elab.Exception import Init.Lean.Elab.Log namespace Lean namespace Elab namespace Level structure Context := (fileName : String) (fileMap : FileMap) (cmdPos : String.Pos) (levelNames : List Name) structure State := (ngen : NameGenerator) (mctx : MetavarContext) abbrev LevelElabM := ReaderT Context (EStateM Exception State) instance LevelElabM.MonadLog : MonadPosInfo LevelElabM := { getCmdPos := do ctx ← read; pure ctx.cmdPos, getFileMap := do ctx ← read; pure ctx.fileMap, getFileName := do ctx ← read; pure ctx.fileName, addContext := fun msg => pure msg } def mkFreshId : LevelElabM Name := do s ← get; let id := s.ngen.curr; modify $ fun s => { ngen := s.ngen.next, .. s }; pure id def mkFreshLevelMVar : LevelElabM Level := do mvarId ← mkFreshId; modify $ fun s => { mctx := s.mctx.addLevelMVarDecl mvarId, .. s}; pure $ mkLevelMVar mvarId partial def elabLevel : Syntax → LevelElabM Level | stx => do let kind := stx.getKind; if kind == `Lean.Parser.Level.paren then elabLevel (stx.getArg 1) else if kind == `Lean.Parser.Level.max then do let args := (stx.getArg 1).getArgs; lvl ← elabLevel args.back; args.foldrRangeM 0 (args.size - 1) (fun stx lvl => do arg ← elabLevel stx; pure (mkLevelMax lvl arg)) lvl else if kind == `Lean.Parser.Level.imax then do let args := (stx.getArg 1).getArgs; lvl ← elabLevel args.back; args.foldrRangeM 0 (args.size - 1) (fun stx lvl => do arg ← elabLevel stx; pure (mkLevelIMax lvl arg)) lvl else if kind == `Lean.Parser.Level.hole then do mkFreshLevelMVar else if kind == `Lean.Parser.Level.num then do match (stx.getArg 0).isNatLit? with | some val => pure (Level.ofNat val) | none => throwError stx "ill-formed universe level syntax" else if kind == `Lean.Parser.Level.ident then do let paramName := stx.getIdAt 0; ctx ← read; unless (ctx.levelNames.contains paramName) $ throwError stx ("unknown universe level " ++ paramName); pure $ mkLevelParam paramName else if kind == `Lean.Parser.Level.addLit then do lvl ← elabLevel (stx.getArg 0); match (stx.getArg 2).isNatLit? with | some val => pure (lvl.addOffset val) | none => throwError stx "ill-formed universe level syntax" else throwError stx "unexpected universe level syntax kind" end Level export Level (LevelElabM) end Elab end Lean