aboutsummaryrefslogtreecommitdiff
path: root/parser
diff options
context:
space:
mode:
Diffstat (limited to 'parser')
-rw-r--r--parser/CC/Parser.hs114
1 files changed, 114 insertions, 0 deletions
diff --git a/parser/CC/Parser.hs b/parser/CC/Parser.hs
new file mode 100644
index 0000000..0088956
--- /dev/null
+++ b/parser/CC/Parser.hs
@@ -0,0 +1,114 @@
+module CC.Parser(runPass, parseProgram) where
+
+import Control.Monad
+import Text.Parsec hiding (State, SourcePos, getPosition, token)
+import qualified Text.Parsec
+
+import CC.Source
+
+
+type Parser a = Parsec String State a
+type State = Int -- base indentation level; hanging lines should be > this
+
+runPass :: Context -> RawString -> Either ParseError Program
+runPass (Context path) (RawString src) = parseProgram path src
+
+parseProgram :: FilePath -> String -> Either ParseError Program
+parseProgram fname src = runParser pProgram 0 fname src
+
+pProgram :: Parser Program
+pProgram = do
+ prog <- Program <$> many pDecl
+ emptyLines
+ eof
+ return prog
+
+pDecl :: Parser Decl
+pDecl = Def <$> pDef
+
+pDef :: Parser Def
+pDef = do
+ func <- try $ do
+ emptyLines
+ putState 0
+ name <- pName0 <?> "declaration head name"
+ return name
+ mtyp <- optionMaybe $ do
+ symbol "::"
+ typ <- pType
+ whitespace >> void newline
+ emptyLines
+ func' <- fst <$> pName0
+ guard (fst func == func')
+ return typ
+ args <- many pName
+ symbol "="
+ expr <- pExpr
+ return (Function mtyp func args expr)
+
+pType :: Parser Type
+pType = chainr1 pTypeAtom (symbol "->" >> return TFun)
+
+pTypeAtom :: Parser Type
+pTypeAtom = (wordToken "Int" >> return TInt) <|> between (token "(") (token ")") pType
+
+pExpr :: Parser Expr
+pExpr = lab "expression" $ do
+ atoms <- many1 pExprAtom
+ return (foldl1 (\a b -> Call (mergeRange (range a) (range b)) a b) atoms)
+
+pExprAtom :: Parser Expr
+pExprAtom =
+ choice [ uncurry (flip Int) <$> pInt
+ , uncurry (flip Var) <$> pName
+ , between (token "(") (token ")") pExpr ]
+
+pInt :: Parser (Int, SourceRange)
+pInt = try (whitespace >> pInt0)
+ where
+ pInt0 = do
+ p1 <- getPosition
+ num <- read <$> many1 digit
+ p2 <- getPosition
+ return (num, SourceRange p1 p2)
+
+pName0 :: Parser (Name, SourceRange)
+pName0 = do
+ p1 <- getPosition
+ c <- pWordFirstChar
+ cs <- many pWordMidChar
+ p2 <- getPosition
+ notFollowedBy pWordMidChar
+ return (c : cs, SourceRange p1 p2)
+
+pWordFirstChar :: Parser Char
+pWordFirstChar = letter <|> oneOf "_$#!"
+
+pWordMidChar :: Parser Char
+pWordMidChar = alphaNum <|> oneOf "_$#!"
+
+pName :: Parser (Name, SourceRange)
+pName = try (whitespace >> pName0)
+
+symbol :: String -> Parser ()
+symbol s = token s >> (eof <|> void space <|> void (oneOf "(){}[]"))
+
+wordToken :: String -> Parser ()
+wordToken s = token s >> notFollowedBy pWordMidChar
+
+token :: String -> Parser ()
+token s = try (whitespace >> void (string s))
+
+emptyLines :: Parser ()
+emptyLines = (try (whitespace >> newline) >> emptyLines) <|> try (whitespace >> eof) <|> return ()
+
+whitespace :: Parser ()
+whitespace = void (many (char ' '))
+
+lab :: String -> Parser a -> Parser a
+lab = flip label
+
+getPosition :: Parser SourcePos
+getPosition = do
+ pos <- Text.Parsec.getPosition
+ return (SourcePos (sourceLine pos) (sourceColumn pos))