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 '_',
|
2013-10-19 08:38:25 +00:00
|
|
|
T.reservedNames = ["do", "end"],
|
2013-10-21 00:24:51 +00:00
|
|
|
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]
|
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-19 09:05:16 +00:00
|
|
|
intPattern = fmap IntP integer
|
|
|
|
varPattern = fmap VarP identifier
|
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
|
|
|
|
symbol "::"
|
|
|
|
y <- pattern
|
|
|
|
return $ ConsP x y
|
|
|
|
|
2013-10-20 23:57:48 +00:00
|
|
|
pattern = try consPattern
|
2013-10-19 09:11:36 +00:00
|
|
|
<|> listPattern
|
2013-10-19 09:05:16 +00:00
|
|
|
<|> varPattern
|
|
|
|
<|> intPattern
|
2013-10-19 08:36:59 +00:00
|
|
|
|
2013-10-19 08:56:14 +00:00
|
|
|
patterns = sepBy pattern (symbol ",")
|
|
|
|
|
2013-10-19 06:22:42 +00:00
|
|
|
funDef = do
|
|
|
|
name <- identifier
|
2013-10-19 08:36:59 +00:00
|
|
|
symbol "("
|
2013-10-19 08:56:14 +00:00
|
|
|
pats <- patterns
|
|
|
|
let pats' = if pats == [] then [UnitP] else pats -- at least Unit
|
2013-10-19 08:36:59 +00:00
|
|
|
symbol ")"
|
|
|
|
symbol "->"
|
2013-10-19 06:22:42 +00:00
|
|
|
lst <- exprparser
|
2013-10-20 23:57:48 +00:00
|
|
|
return $ rewriteFun (FunDef name (pats', lst))
|
2013-10-19 06:22:42 +00:00
|
|
|
|
|
|
|
-- curry FunDef to a definition of lambdas
|
2013-10-19 08:56:14 +00:00
|
|
|
rewriteFun (FunDef name (patterns, body)) =
|
2013-10-20 23:57:48 +00:00
|
|
|
Defun name lam
|
2013-10-19 08:56:14 +00:00
|
|
|
where
|
|
|
|
-- curry it
|
|
|
|
lam = foldr (\pat lam -> Lambda [(pat, [lam])]) body patterns
|
2013-10-19 06:22:42 +00:00
|
|
|
|
|
|
|
call = do
|
|
|
|
name <- identifier
|
|
|
|
whiteSpace
|
2013-10-19 08:36:59 +00:00
|
|
|
symbol "("
|
2013-10-19 08:44:53 +00:00
|
|
|
args <- sepBy exprparser (symbol ",")
|
|
|
|
let args' = if args == [] then [UnitConst] else args -- at least Unit
|
2013-10-19 08:36:59 +00:00
|
|
|
symbol ")"
|
2013-10-19 08:44:53 +00:00
|
|
|
return $ Call name args'
|
2013-10-19 06:22:42 +00:00
|
|
|
|
2013-10-19 08:36:59 +00:00
|
|
|
term = try block
|
2013-10-19 06:22:42 +00:00
|
|
|
<|> try funDef
|
|
|
|
<|> try call
|
|
|
|
<|> parens exprparser
|
2013-10-19 09:09:44 +00:00
|
|
|
<|> listSeq exprparser ListConst
|
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
|
|
|
|
|
2013-10-19 08:38:25 +00:00
|
|
|
seqStmt = sepBy1 statement semi
|
2013-10-19 06:22:42 +00:00
|
|
|
|
|
|
|
program =
|
|
|
|
many1 $ do
|
|
|
|
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"
|