-----------------------------------------------------------
-- Daan Leijen (c) 1999-2000, daan@cs.uu.nl
-----------------------------------------------------------
module MonParser ( parseMondrian
, parseMondrianFromFile
, prettyFile
, ParseError
) where
import Char
import Monad
import Mondrian
import Utils (groupLambdas)
-- Parsec
import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Expr
import qualified Text.ParserCombinators.Parsec.Token as P
import Text.ParserCombinators.Parsec.Language (mondrianDef)
--testing
import qualified SimpleMondrianPrinter as Pretty
-----------------------------------------------------------
--
-----------------------------------------------------------
parseMondrianFromFile :: String -> IO (Either ParseError CompilationUnit)
parseMondrianFromFile fname =
parseFromFile compilationUnit fname
parseMondrian sourceName source =
parse compilationUnit sourceName source
-- testing
prettyFile fname
= do{ result <- parseMondrianFromFile fname
; case result of
Left err -> putStr ("parse error at: " ++ show err)
Right x -> print (Pretty.compilationUnit x)
}
-----------------------------------------------------------
-- GRAMMAR ELEMENTS
-----------------------------------------------------------
compilationUnit :: Parser CompilationUnit
compilationUnit =
do{ whiteSpace
; reserved "package"
; name <- option [""] packageName
; decls <- option [] declarations
; eof
; return $ Package name decls
}
-----------------------------------------------------------
-- Declarations
-----------------------------------------------------------
declarations =
braces (semiSep1 declaration)
declaration =
importDeclaration
<|> classDeclaration
<|> variableSignatureDeclaration
<?> "declaration"
variableSignatureDeclaration =
do{ name <- variableName
; variableDeclaration name <|> signatureDeclaration name
}
variableDeclaration name =
do{ symbol "="
; expr <- expression
; return $ VarDecl name expr
}
<?> "variable declaration"
importDeclaration =
do{ reserved "import"
; name <- packageName
; star <- option [] (do{ symbol "."
; symbol "*"
; return ["*"]
})
; return $ ImportDecl (name ++ star)
}
classDeclaration =
do{ reserved "class"
; name <- className
; extends <- option [] (do{ reserved "extends"
; n <- className
; return [n]
})
; decls <- option [] declarations
; return $ ClassDecl name extends decls
}
signatureDeclaration name =
do{ symbol "::"
; texpr <- typeExpression
; return $ SigDecl name texpr
}
<?> "type declaration"
-----------------------------------------------------------
-- Expressions
-----------------------------------------------------------
expression :: Parser Expr
expression =
lambdaExpression
<|> letExpression
<|> newExpression
<|> infixExpression
<?> "expression"
lambdaExpression =
do{ symbol "\\"
; name <- variableName
; symbol "->"
; expr <- expression
; return $ groupLambdas (Lambda [name] expr)
}
letExpression =
do{ reserved "let"
; decls <- declarations
; reserved "in"
; expr <- expression
; return $ Let decls expr
}
newExpression =
do{ reserved "new"
; name <- className
; decls <- option [] declarations
; return $ New name decls
}
-----------------------------------------------------------
-- Infix expression
-----------------------------------------------------------
infixExpression =
buildExpressionParser operators applyExpression
operators =
[ [ prefix "-", prefix "+" ]
, [ op "^" AssocRight ]
, [ op "*" AssocLeft, op "/" AssocLeft ]
, [ op "+" AssocLeft, op "-" AssocLeft ]
, [ op "==" AssocNone, op "/=" AssocNone, op "<" AssocNone
, op "<=" AssocNone, op ">" AssocNone, op ">=" AssocNone ]
, [ op "&&" AssocNone ]
, [ op "||" AssocNone ]
]
where
op name assoc = Infix (do{ var <- try (symbol name)
; return (\x y -> App (App (Var [var]) x) y)
}) assoc
prefix name = Prefix (do{ var <- try (symbol name)
; return (\x -> App (Var [var,"unary"]) x)
})
applyExpression =
do{ exprs <- many1 simpleExpression
; return (foldl1 App exprs)
}
{-
infixExpression =
do{ (e,es) <- chain simpleExpression operator "infix expression"
; return $ if null es then e else (unChain (Chain e es))
}
-}
simpleExpression :: Parser Expr
simpleExpression =
literal
<|> parens expression
<|> caseExpression
<|> variable
<?> "simple expression"
-----------------------------------------------------------
-- Case expression
-----------------------------------------------------------
caseExpression =
do{ reserved "case"
; expr <- variable
; reserved "of"
; alts <- alternatives
; return $ Case expr alts
}
alternatives =
braces (semiSep1 arm)
arm =
do{ pat <- pattern
; symbol "->"
; expr <- expression
; return (pat,expr)
}
pattern =
do{ reserved "default"
; return Default
}
<|> do{ name <- patternName
; decls <- option [] declarations
; return $ Pattern name decls
}
<?> "pattern"
-----------------------------------------------------------
-- Type expression
-----------------------------------------------------------
{-
typeExpression =
do{ (e,es) <- chain simpleType typeOperator "type expression"
; return $ if null es then e else Chain e es
}
<?> "type expression"
-}
typeExpression :: Parser Expr
typeExpression =
do{ exprs <- sepBy1 simpleType (symbol "->")
; return (foldl1 (\x y -> App (App (Var ["->"]) x) y) exprs)
}
simpleType :: Parser Expr
simpleType =
parens typeExpression
<|> variable
<?> "simple type"
-----------------------------------------------------------
-- LEXICAL ELEMENTS
-----------------------------------------------------------
-----------------------------------------------------------
-- Identifiers & Reserved words
-----------------------------------------------------------
variable =
do{ name <- variableName
; return $ Var name
}
patternName = qualifiedName <?> "pattern variable"
variableName = qualifiedName <?> "identifier"
className = qualifiedName <?> "class name"
packageName = qualifiedName <?> "package name"
qualifiedName =
identifier `sepBy1` (symbol "." <?> "")
-----------------------------------------------------------
-- Literals
-----------------------------------------------------------
literal =
do{ v <- intLiteral <|> chrLiteral <|> strLiteral
; return $ Lit v
}
<?> "literal"
intLiteral = do{ n <- natural; return (IntLit n) }
chrLiteral = do{ c <- charLiteral; return (CharLit c) }
strLiteral = do{ s <- stringLiteral; return (StringLit s) }
-----------------------------------------------------------
-- Tokens
-- Use qualified import to have token parsers on toplevel
-----------------------------------------------------------
mondrian = P.makeTokenParser mondrianDef
parens = P.parens mondrian
braces = P.braces mondrian
semiSep1 = P.semiSep1 mondrian
whiteSpace = P.whiteSpace mondrian
symbol = P.symbol mondrian
identifier = P.identifier mondrian
reserved = P.reserved mondrian
natural = P.natural mondrian
charLiteral = P.charLiteral mondrian
stringLiteral = P.stringLiteral mondrian
|