summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Brown <greg.brown01@ed.ac.uk>2022-12-17 12:42:09 +0000
committerGreg Brown <greg.brown01@ed.ac.uk>2022-12-17 15:10:17 +0000
commit5a707861fe52e4c969350664beb206daa0e7fd56 (patch)
tree07559705d1b0ad4b25581cb7390a8e226d6dbac5
parent8281e2ea3e531196b8e26ea021ff417670b68bb8 (diff)
Add parser for raw syntax.
-rw-r--r--obs.ipkg3
-rw-r--r--src/Obs/Parser.idr176
2 files changed, 178 insertions, 1 deletions
diff --git a/obs.ipkg b/obs.ipkg
index 3320896..5e7f3d6 100644
--- a/obs.ipkg
+++ b/obs.ipkg
@@ -5,5 +5,6 @@ sourcedir = "src"
depends = contrib
modules
- = Obs.Sort
+ = Obs.Parser
+ , Obs.Sort
, Obs.Syntax
diff --git a/src/Obs/Parser.idr b/src/Obs/Parser.idr
new file mode 100644
index 0000000..2802690
--- /dev/null
+++ b/src/Obs/Parser.idr
@@ -0,0 +1,176 @@
+module Obs.Parser
+
+import Data.String
+
+import Obs.Sort
+import Obs.Syntax
+
+import System
+import System.File
+
+import Text.Lexer
+import Text.Parser
+
+Error : Type -> Type -> Type
+Error tok = Either (List1 (ParsingError tok))
+
+report : List1 (ParsingError tok) -> Error tok a
+report = Left
+
+data ObsTokenKind
+ = OTNewline
+ | OTIgnore
+ | OTIdent
+ | OTSet
+ | OTProp
+ | OTNat
+ | OTPOpen
+ | OTPClose
+ | OTEqual
+ | OTColon
+
+Eq ObsTokenKind where
+ OTNewline == OTNewline = True
+ OTIgnore == OTIgnore = True
+ OTIdent == OTIdent = True
+ OTSet == OTSet = True
+ OTProp == OTProp = True
+ OTNat == OTNat = True
+ OTPOpen == OTPOpen = True
+ OTPClose == OTPClose = True
+ OTEqual == OTEqual = True
+ OTColon == OTColon = True
+ _ == _ = False
+
+TokenKind ObsTokenKind where
+ TokType OTIdent = String
+ TokType OTNat = Nat
+ TokType _ = ()
+
+ tokValue OTNewline s = ()
+ tokValue OTIgnore s = ()
+ tokValue OTIdent s = s
+ tokValue OTSet s = ()
+ tokValue OTProp s = ()
+ tokValue OTNat s = stringToNatOrZ s
+ tokValue OTPOpen s = ()
+ tokValue OTPClose s = ()
+ tokValue OTEqual s = ()
+ tokValue OTColon s = ()
+
+ObsToken : Type
+ObsToken = Token ObsTokenKind
+
+ignored : WithBounds ObsToken -> Bool
+ignored (MkBounded (Tok OTIgnore _) _ _) = True
+ignored _ = False
+
+identifier : Lexer
+identifier = alpha <+> many alphaNum
+
+keywords : List (String, ObsTokenKind)
+keywords =
+ [ ("Set", OTSet)
+ , ("Prop", OTProp)
+ ]
+
+obsTokenMap : TokenMap ObsToken
+obsTokenMap = toTokenMap [(newline, OTNewline), (spaces, OTIgnore)] ++
+ [ (identifier, \s =>
+ case lookup s keywords of
+ (Just kind) => Tok kind s
+ Nothing => Tok OTIdent s)
+ ] ++ toTokenMap
+ [ (digits, OTNat)
+ , (exact "(", OTPOpen)
+ , (exact ")", OTPClose)
+ , (exact "=", OTEqual)
+ , (exact ":", OTColon)
+ ]
+
+parens : {c : _} -> Grammar state ObsToken c a -> Grammar state ObsToken True a
+parens g =
+ match OTPOpen *>
+ many (match OTNewline) *>
+ g <*
+ many (match OTNewline) <*
+ match OTPClose
+
+ident : Grammar state ObsToken True (WithBounds String)
+ident = bounds $ match OTIdent
+
+var : Grammar state ObsToken True Syntax
+var = do
+ id <- ident
+ pure (Var id.bounds id.val)
+
+prop : Grammar state ObsToken True (WithBounds Sort)
+prop = do
+ p <- bounds $ match OTProp
+ pure (map (\_ => Prop) p)
+
+set : Grammar state ObsToken True (WithBounds Sort)
+set = do
+ s <- bounds $ match OTSet
+ i <- bounds $ option 0 (match OTNat)
+ pure (map Set $ mergeBounds s i)
+
+sort : Grammar state ObsToken True Syntax
+sort = do
+ sort <- prop <|> set
+ pure (Sort sort.bounds sort.val)
+
+exp : Grammar state ObsToken True Syntax
+term : Grammar state ObsToken True Syntax
+
+exp = term
+term = var <|> sort <|> parens exp
+
+decl : Grammar state ObsToken True (WithBounds String, Syntax)
+decl = [| MkPair ident (match OTColon *> exp) |]
+
+def : Grammar state ObsToken True (WithBounds String, Syntax)
+def = [| MkPair ident (match OTEqual *> exp) |]
+
+fullDef : Grammar state ObsToken True Definition
+fullDef =
+ seq
+ [| MkPair decl (match OTNewline *> def) |]
+ (\((name, ty), (name', tm)) =>
+ if name.val == name'.val
+ then pure (MkDefinition {bounds = name.bounds, name = name.val, ty, tm})
+ else fatalLoc name.bounds "name mismatch for declaration and definition")
+
+file : Grammar state ObsToken False (List Definition)
+file = many (match OTNewline) *> sepEndBy (some (match OTNewline)) fullDef
+
+export
+parse : String -> Error ObsToken (List Definition)
+parse str = do
+ let (toks, _, _, "") = lex obsTokenMap str
+ | (_, l, c, rem) => report (Error "failed to lex input" (Just $ MkBounds { startLine = l, startCol = c, endLine = l, endCol = c }) ::: [])
+ (defs, []) <- parse file $ filter (not . ignored) toks
+ | (_, (t :: _)) => report (Error "unparsed tokens" (Just t.bounds) ::: [])
+ pure defs
+
+printErr : ParsingError tok -> IO ()
+printErr (Error str Nothing) = putStrLn "error: \{str}"
+printErr (Error str (Just b)) = putStrLn
+ "error: \{show b.startLine}:\{show b.startCol}-\{show b.endLine}:\{show b.endCol}: \{str}"
+
+reportErrs : List (ParsingError tok) -> IO a
+reportErrs [] = exitFailure
+reportErrs (e :: errs) = do
+ () <- printErr e
+ reportErrs errs
+
+export
+parseFile : (fname : String) -> IO (List Definition)
+parseFile fname = do
+ Right str <- readFile fname
+ | Left err => do
+ () <- putStrLn "error: \{show err}"
+ exitFailure
+ let Right defs = parse str
+ | Left err => reportErrs (forget err)
+ pure defs