lamb/parser.hs

205 lines
4.4 KiB
Haskell
Raw Normal View History

2013-10-21 00:48:02 +00:00
-- Parser for the Lamb programming language
-- Copyright (c) 2013 darkf
-- Licensed under the terms of the zlib license, see LICENSE for details
2013-10-19 06:22:42 +00:00
module Parser where
import Text.Parsec
import Text.Parsec.String
import Text.Parsec.Expr
import qualified Text.Parsec.Token as T
import Text.Parsec.Language
import AST
languageDef = emptyDef {T.commentStart="{-",
T.commentEnd="-}",
T.commentLine="--",
T.nestedComments=True,
T.identStart = letter <|> char '_',
T.identLetter = alphaNum <|> char '_' <|> char '\'' <|> char '!' <|> char '?',
2013-10-19 08:38:25 +00:00
T.reservedNames = ["do", "end"],
T.reservedOpNames = ["+", "-", "*", "/", "==", "!=", "<", ">"]}
2013-10-19 06:22:42 +00:00
lexer = T.makeTokenParser languageDef
exprparser = buildExpressionParser ops term <?> "expression"
2013-10-21 00:24:51 +00:00
ops = [ [Infix (reservedOp "*" >> return Mul) AssocLeft]
, [Infix (reservedOp "/" >> return Div) AssocLeft]
2013-10-19 06:22:42 +00:00
, [Infix (reservedOp "+" >> return Add) AssocLeft]
2013-10-21 00:24:51 +00:00
, [Infix (reservedOp "-" >> return Sub) AssocLeft]
, [Infix (reservedOp "==" >> return Equals) AssocLeft]
, [Infix (reservedOp "!=" >> return NotEquals) AssocLeft]
, [Infix (reservedOp "<" >> return LessThan) AssocLeft]
, [Infix (reservedOp ">" >> return GreaterThan) AssocLeft]
2013-10-19 06:22:42 +00:00
]
2013-10-20 23:18:05 +00:00
identifier = T.identifier lexer
reserved = T.reserved lexer
reservedOp = T.reservedOp lexer
parens = T.parens lexer
integer = T.integer lexer
semi = T.semi lexer
whiteSpace = T.whiteSpace lexer
2013-10-19 06:22:42 +00:00
symbol = T.symbol lexer
2013-10-19 08:38:25 +00:00
statement = exprparser
2013-10-19 06:22:42 +00:00
2013-10-20 23:18:05 +00:00
-- http://codereview.stackexchange.com/a/2572
stringChar =
escaped <|> noneOf "\""
where
escaped = char '\\' >> choice (zipWith escapedChar codes replacements)
escapedChar code replacement = char code >> return replacement
codes = ['b', 'n', 'f', 'r', 't', '\\', '\"', '/']
replacements = ['\b', '\n', '\f', '\r', '\t', '\\', '\"', '/']
stringLiteral = do
char '"'
x <- many stringChar
char '"'
2013-10-20 23:21:41 +00:00
whiteSpace
2013-10-20 23:18:05 +00:00
return x
2013-10-19 06:22:42 +00:00
block = do
reserved "do"
lst <- seqStmt
reserved "end"
return $ Block lst
2013-10-19 09:09:44 +00:00
listSeq p cons = do
symbol "["
lst <- sepBy p (symbol ",")
symbol "]"
return $ cons lst
2013-10-22 22:10:34 +00:00
tupleSeq p cons = do
symbol "("
lst <- sepBy1 p (symbol ",")
symbol ")"
return $ cons lst
emptyTuple cons = do
symbol "("
symbol ","
2013-10-22 22:10:34 +00:00
symbol ")"
return $ cons []
2013-10-19 09:05:16 +00:00
intPattern = fmap IntP integer
varPattern = fmap VarP identifier
2013-10-23 22:31:37 +00:00
stringPattern = fmap StrP stringLiteral
2013-10-19 09:11:36 +00:00
listPattern = listSeq pattern ListP
2013-10-19 09:05:16 +00:00
consPattern = do
x <- intPattern <|> varPattern <|> stringPattern <|> try (tupleSeq pattern TupleP)
2013-10-19 09:05:16 +00:00
symbol "::"
y <- pattern
return $ ConsP x y
pattern = try consPattern
<|> try (emptyTuple TupleP)
<|> try (tupleSeq pattern TupleP)
2013-10-19 09:11:36 +00:00
<|> listPattern
2013-10-19 09:05:16 +00:00
<|> varPattern
<|> intPattern
2013-10-23 22:31:37 +00:00
<|> stringPattern
patterns = sepBy pattern (symbol ",")
2013-10-19 06:22:42 +00:00
funDef = do
name <- identifier
symbol "("
pats <- patterns
let pat = (case pats of
[] -> UnitP
[a] -> a
otherwise -> TupleP pats)
symbol ")"
symbol "->"
body <- exprparser
return $ Defun name $ Lambda [(pat, body)]
2013-10-19 06:22:42 +00:00
2013-10-25 06:32:15 +00:00
lambda = do
symbol "\\"
pats <- patterns
let pat = (case pats of
[] -> UnitP
[a] -> a
otherwise -> TupleP pats)
symbol "->"
body <- exprparser
return $ Lambda [(pat, body)]
call p argp = do
lhs <- p
2013-10-19 06:22:42 +00:00
whiteSpace
symbol "("
args <- sepBy argp (symbol ",")
let arg = (case args of
[] -> UnitConst
[a] -> a
otherwise -> TupleConst args)
symbol ")"
return $ Call lhs arg
2013-10-19 06:22:42 +00:00
2013-10-21 05:27:27 +00:00
consExpr = do
x <- expr3
2013-10-21 05:27:27 +00:00
symbol "::"
y <- exprparser
return $ Cons x y
2013-10-23 21:36:06 +00:00
ifExpr = do
symbol "if"
cond <- exprparser
symbol "then"
t <- exprparser
symbol "else"
e <- exprparser
return $ IfExpr cond t e
2013-10-23 21:41:44 +00:00
bool = fmap BoolConst $ (symbol "true" >> return True) <|> (symbol "false" >> return False)
2013-10-24 03:54:26 +00:00
def = do
pat <- pattern
2013-10-24 03:54:26 +00:00
whiteSpace
symbol "="
value <- exprparser
return $ Def pat value
2013-10-24 03:54:26 +00:00
-- field access
accessOp = do
symbol "/"
return Access
expr1 = try block
2013-10-25 06:32:15 +00:00
<|> try lambda
<|> try def
<|> try (emptyTuple TupleConst)
<|> try (tupleSeq exprparser TupleConst)
<|> parens exprparser
2013-10-19 09:09:44 +00:00
<|> listSeq exprparser ListConst
2013-10-23 21:36:06 +00:00
<|> try ifExpr
<|> try bool
2013-10-19 06:22:42 +00:00
<|> fmap Var identifier
2013-10-20 23:18:05 +00:00
<|> fmap StrConst stringLiteral
2013-10-19 06:22:42 +00:00
<|> fmap IntConst integer
expr2 = try $ chainl1 expr1 accessOp
<|> expr1
expr3 = try funDef
<|> try (call expr2 exprparser)
<|> expr2
2013-10-21 05:27:27 +00:00
term = try consExpr
<|> expr3
2013-10-21 05:27:27 +00:00
2013-10-19 08:38:25 +00:00
seqStmt = sepBy1 statement semi
2013-10-19 06:22:42 +00:00
program =
many1 $ do
2013-10-23 22:38:11 +00:00
whiteSpace
2013-10-19 06:22:42 +00:00
e <- exprparser
2013-10-19 08:44:53 +00:00
symbol "."
2013-10-19 06:22:42 +00:00
return e
parseProgram = parse program "program"