{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE Safe #-}
module Parser.Procedure (
) where
import Text.Parsec
import Text.Parsec.String
import qualified Data.Set as Set
import Parser.Common
import Parser.Pragma
import Parser.TypeCategory ()
import Parser.TypeInstance ()
import Types.Positional
import Types.Pragma
import Types.Procedure
import Types.TypeCategory
import Types.TypeInstance
instance ParseFromSource (ExecutableProcedure SourcePos) where
sourceParser = labeled "executable procedure" $ do
c <- getPosition
n <- try sourceParser
as <- sourceParser
rs <- sourceParser
sepAfter (string_ "{")
pragmas <- parsePragmas [pragmaNoTrace,pragmaTraceCreation]
pp <- sourceParser
c2 <- getPosition
sepAfter (string_ "}")
return $ ExecutableProcedure [c] pragmas [c2] n as rs pp
instance ParseFromSource (ArgValues SourcePos) where
sourceParser = labeled "procedure arguments" $ do
c <- getPosition
as <- between (sepAfter $ string_ "(")
(sepAfter $ string_ ")")
(sepBy sourceParser (sepAfter $ string_ ","))
return $ ArgValues [c] (Positional as)
instance ParseFromSource (ReturnValues SourcePos) where
sourceParser = labeled "procedure returns" $ namedReturns <|> unnamedReturns where
namedReturns = do
c <- getPosition
rs <- between (sepAfter $ string_ "(")
(sepAfter $ string_ ")")
(sepBy sourceParser (sepAfter $ string_ ","))
return $ NamedReturns [c] (Positional rs)
unnamedReturns = do
c <- getPosition
notFollowedBy (string_ "(")
return $ UnnamedReturns [c]
instance ParseFromSource VariableName where
sourceParser = labeled "variable name" $ do
noKeywords
b <- lower
e <- sepAfter $ many alphaNum
return $ VariableName (b:e)
instance ParseFromSource (InputValue SourcePos) where
sourceParser = labeled "input variable" $ variable <|> discard where
variable = do
c <- getPosition
v <- sourceParser
return $ InputValue [c] v
discard = do
c <- getPosition
sepAfter (string_ "_")
return $ DiscardInput [c]
instance ParseFromSource (OutputValue SourcePos) where
sourceParser = labeled "output variable" $ do
c <- getPosition
v <- sourceParser
return $ OutputValue [c] v
instance ParseFromSource (Procedure SourcePos) where
sourceParser = labeled "procedure" $ do
c <- getPosition
rs <- sepBy sourceParser optionalSpace
return $ Procedure [c] rs
instance ParseFromSource (Statement SourcePos) where
sourceParser = parseReturn <|>
parseBreak <|>
parseContinue <|>
parseFailCall <|>
parseVoid <|>
parseAssign <|>
parseIgnore where
parseAssign = labeled "statement" $ do
c <- getPosition
as <- sepBy sourceParser (sepAfter $ string_ ",")
assignOperator
e <- sourceParser
statementEnd
return $ Assignment [c] (Positional as) e
parseBreak = labeled "break" $ do
c <- getPosition
try kwBreak
return $ LoopBreak [c]
parseContinue = labeled "continue" $ do
c <- getPosition
try kwContinue
return $ LoopContinue [c]
parseFailCall = do
c <- getPosition
try kwFail
e <- between (sepAfter $ string_ "(") (sepAfter $ string_ ")") sourceParser
return $ FailCall [c] e
parseIgnore = do
c <- getPosition
statementStart
e <- sourceParser
statementEnd
return $ IgnoreValues [c] e
parseReturn = labeled "return" $ do
c <- getPosition
try kwReturn
emptyReturn c <|> multiReturn c
multiReturn :: SourcePos -> Parser (Statement SourcePos)
multiReturn c = do
rs <- sepBy sourceParser (sepAfter $ string_ ",")
statementEnd
return $ ExplicitReturn [c] (Positional rs)
emptyReturn :: SourcePos -> Parser (Statement SourcePos)
emptyReturn c = do
kwIgnore
statementEnd
return $ EmptyReturn [c]
parseVoid = do
c <- getPosition
e <- sourceParser
return $ NoValueExpression [c] e
instance ParseFromSource (Assignable SourcePos) where
sourceParser = existing <|> create where
create = labeled "variable creation" $ do
t <- sourceParser
strayFuncCall <|> return ()
c <- getPosition
n <- sourceParser
return $ CreateVariable [c] t n
existing = labeled "variable name" $ do
n <- sourceParser
strayFuncCall <|> return ()
return $ ExistingVariable n
strayFuncCall = do
valueSymbolGet <|> try typeSymbolGet <|> categorySymbolGet
fail "function returns must be explicitly handled"
instance ParseFromSource (VoidExpression SourcePos) where
sourceParser = conditional <|> loop <|> scoped where
conditional = do
e <- sourceParser
return $ Conditional e
loop = do
e <- sourceParser
return $ Loop e
scoped = do
e <- sourceParser
return $ WithScope e
instance ParseFromSource (IfElifElse SourcePos) where
sourceParser = labeled "if-elif-else" $ do
c <- getPosition
try kwIf >> parseIf c
where
parseIf c = do
i <- between (sepAfter $ string_ "(") (sepAfter $ string_ ")") sourceParser
p <- between (sepAfter $ string_ "{") (sepAfter $ string_ "}") sourceParser
next <- parseElif <|> parseElse <|> return TerminateConditional
return $ IfStatement [c] i p next
parseElif = do
c <- getPosition
try kwElif >> parseIf c
parseElse = do
c <- getPosition
try kwElse
p <- between (sepAfter $ string_ "{") (sepAfter $ string_ "}") sourceParser
return $ ElseStatement [c] p
instance ParseFromSource (WhileLoop SourcePos) where
sourceParser = labeled "while" $ do
c <- getPosition
try kwWhile
i <- between (sepAfter $ string_ "(") (sepAfter $ string_ ")") sourceParser
p <- between (sepAfter $ string_ "{") (sepAfter $ string_ "}") sourceParser
u <- fmap Just parseUpdate <|> return Nothing
return $ WhileLoop [c] i p u
where
parseUpdate = do
try kwUpdate
between (sepAfter $ string_ "{") (sepAfter $ string_ "}") sourceParser
instance ParseFromSource (ScopedBlock SourcePos) where
sourceParser = scoped <|> justCleanup where
scoped = labeled "scoped" $ do
c <- getPosition
try kwScoped
p <- between (sepAfter $ string_ "{") (sepAfter $ string_ "}") sourceParser
cl <- fmap Just parseCleanup <|> return Nothing
kwIn
s <- unconditional <|> sourceParser
return $ ScopedBlock [c] p cl s
justCleanup = do
c <- getPosition
cl <- parseCleanup
kwIn
s <- sourceParser <|> unconditional
return $ ScopedBlock [c] (Procedure [] []) (Just cl) s
parseCleanup = do
try kwCleanup
between (sepAfter $ string_ "{") (sepAfter $ string_ "}") sourceParser
unconditional = do
c <- getPosition
p <- between (sepAfter $ string_ "{") (sepAfter $ string_ "}") sourceParser
return $ NoValueExpression [c] (Unconditional p)
unaryOperator :: Parser (Operator c)
unaryOperator = op >>= return . NamedOperator where
op = labeled "unary operator" $ foldr (<|>) (fail "empty") $ map (try . operator) ops
ops = logicalUnary ++ arithUnary ++ bitwiseUnary
logicalUnary :: [String]
logicalUnary = ["!"]
arithUnary :: [String]
arithUnary = ["-"]
bitwiseUnary :: [String]
bitwiseUnary = ["~"]
infixOperator :: Parser (Operator c)
infixOperator = op >>= return . NamedOperator where
op = labeled "binary operator" $ foldr (<|>) (fail "empty") $ map (try . operator) ops
ops = compareInfix ++ logicalInfix ++ addInfix ++ subInfix ++ multInfix ++ bitwiseInfix ++ bitshiftInfix
compareInfix :: [String]
compareInfix = ["==","!=","<","<=",">",">="]
logicalInfix :: [String]
logicalInfix = ["&&","||"]
addInfix :: [String]
addInfix = ["+"]
subInfix :: [String]
subInfix = ["-"]
multInfix :: [String]
multInfix = ["*","/","%"]
bitwiseInfix :: [String]
bitwiseInfix = ["&","|","^"]
bitshiftInfix :: [String]
bitshiftInfix = [">>","<<"]
infixBefore :: Operator c -> Operator c -> Bool
infixBefore o1 o2 = (infixOrder o1 :: Int) <= (infixOrder o2 :: Int) where
infixOrder (NamedOperator o)
| o `Set.member` Set.fromList (multInfix ++ bitshiftInfix) = 1
| o `Set.member` Set.fromList (addInfix ++ subInfix ++ bitwiseInfix) = 2
| o `Set.member` Set.fromList compareInfix = 4
| o `Set.member` Set.fromList logicalInfix = 5
infixOrder _ = 3
functionOperator :: Parser (Operator SourcePos)
functionOperator = do
c <- getPosition
infixFuncStart
q <- sourceParser
infixFuncEnd
return $ FunctionOperator [c] q
instance ParseFromSource (Expression SourcePos) where
sourceParser = do
e <- notInfix
asInfix [e] [] <|> return e
where
notInfix = literal <|> unary <|> expression <|> initalize
asInfix es os = do
c <- getPosition
o <- infixOperator <|> functionOperator
e2 <- notInfix
let es' = es ++ [e2]
let os' = os ++ [([c],o)]
asInfix es' os' <|> return (infixToTree [] es' os')
infixToTree [(e1,c1,o1)] [e2] [] = InfixExpression c1 e1 o1 e2
infixToTree [] (e1:es) ((c1,o1):os) = infixToTree [(e1,c1,o1)] es os
infixToTree ((e1,c1,o1):ss) [e2] [] = let e2' = InfixExpression c1 e1 o1 e2 in
infixToTree ss [e2'] []
infixToTree ((e1,c1,o1):ss) (e2:es) ((c2,o2):os)
| o1 `infixBefore` o2 = let e1' = InfixExpression c1 e1 o1 e2 in
infixToTree ss (e1':es) ((c2,o2):os)
| otherwise = infixToTree ((e2,c2,o2):(e1,c1,o1):ss) es os
infixToTree _ _ _ = undefined
literal = do
l <- sourceParser
return $ Literal l
unary = do
c <- getPosition
o <- unaryOperator <|> functionOperator
e <- notInfix
return $ UnaryExpression [c] o e
expression = labeled "expression" $ do
c <- getPosition
s <- try sourceParser
vs <- many sourceParser
return $ Expression [c] s vs
initalize = do
c <- getPosition
t <- try sourceParser :: Parser TypeInstance
sepAfter (string_ "{")
withParams c t <|> withoutParams c t
withParams c t = do
try kwTypes
ps <- between (sepAfter $ string_ "<")
(sepAfter $ string_ ">")
(sepBy sourceParser (sepAfter $ string_ ","))
as <- (sepAfter (string_ ",") >> sepBy sourceParser (sepAfter $ string_ ",")) <|> return []
sepAfter (string_ "}")
return $ InitializeValue [c] t (Positional ps) (Positional as)
withoutParams c t = do
as <- sepBy sourceParser (sepAfter $ string_ ",")
sepAfter (string_ "}")
return $ InitializeValue [c] t (Positional []) (Positional as)
instance ParseFromSource (FunctionQualifier SourcePos) where
sourceParser = try valueFunc <|> try categoryFunc <|> try typeFunc where
categoryFunc = do
c <- getPosition
q <- sourceParser
categorySymbolGet
return $ CategoryFunction [c] q
typeFunc = do
c <- getPosition
q <- sourceParser
typeSymbolGet
return $ TypeFunction [c] q
valueFunc = do
c <- getPosition
q <- sourceParser
valueSymbolGet
return $ ValueFunction [c] q
instance ParseFromSource (FunctionSpec SourcePos) where
sourceParser = try qualified <|> unqualified where
qualified = do
c <- getPosition
q <- sourceParser
n <- sourceParser
ps <- try $ between (sepAfter $ string_ "<")
(sepAfter $ string_ ">")
(sepBy sourceParser (sepAfter $ string_ ",")) <|> return []
return $ FunctionSpec [c] q n (Positional ps)
unqualified = do
c <- getPosition
n <- sourceParser
ps <- try $ between (sepAfter $ string_ "<")
(sepAfter $ string_ ">")
(sepBy sourceParser (sepAfter $ string_ ",")) <|> return []
return $ FunctionSpec [c] UnqualifiedFunction n (Positional ps)
instance ParseFromSource (InstanceOrInferred SourcePos) where
sourceParser = assigned <|> inferred where
assigned = do
c <- getPosition
t <- sourceParser
return $ AssignedInstance [c] t
inferred = do
c <- getPosition
sepAfter_ inferredParam
return $ InferredInstance [c]
parseFunctionCall :: SourcePos -> FunctionName -> Parser (FunctionCall SourcePos)
parseFunctionCall c n = do
ps <- try $ between (sepAfter $ string_ "<")
(sepAfter $ string_ ">")
(sepBy sourceParser (sepAfter $ string_ ",")) <|> return []
es <- between (sepAfter $ string_ "(")
(sepAfter $ string_ ")")
(sepBy sourceParser (sepAfter $ string_ ","))
return $ FunctionCall [c] n (Positional ps) (Positional es)
builtinFunction :: Parser FunctionName
builtinFunction = foldr (<|>) (fail "empty") $ map try [
kwPresent >> return BuiltinPresent,
kwReduce >> return BuiltinReduce,
kwRequire >> return BuiltinRequire,
kwStrong >> return BuiltinStrong,
kwTypename >> return BuiltinTypename
]
instance ParseFromSource (ExpressionStart SourcePos) where
sourceParser = labeled "expression start" $
parens <|>
variableOrUnqualified <|>
builtinCall <|>
builtinValue <|>
exprLookup <|>
try typeOrCategoryCall <|>
typeCall where
parens = do
c <- getPosition
sepAfter (string_ "(")
e <- try (assign c) <|> expr c
sepAfter (string_ ")")
return e
assign :: SourcePos -> Parser (ExpressionStart SourcePos)
assign c = do
n <- sourceParser
assignOperator
e <- sourceParser
return $ InlineAssignment [c] n e
expr :: SourcePos -> Parser (ExpressionStart SourcePos)
expr c = do
e <- sourceParser
return $ ParensExpression [c] e
builtinCall = do
c <- getPosition
n <- builtinFunction
f <- parseFunctionCall c n
return $ BuiltinCall [c] f
builtinValue = do
c <- getPosition
n <- builtinValues
return $ NamedVariable (OutputValue [c] (VariableName n))
exprLookup = do
pragma <- pragmaExprLookup
case pragma of
(PragmaExprLookup c name) -> return $ NamedMacro c name
_ -> undefined
variableOrUnqualified = do
c <- getPosition
n <- sourceParser :: Parser VariableName
asUnqualifiedCall c n <|> asVariable c n
asVariable c n = do
return $ NamedVariable (OutputValue [c] n)
asUnqualifiedCall c n = do
f <- parseFunctionCall c (FunctionName (vnName n))
return $ UnqualifiedCall [c] f
typeOrCategoryCall = do
c <- getPosition
t <- sourceParser :: Parser CategoryName
asType c t <|> asCategory c t
asType c t = do
try typeSymbolGet
n <- sourceParser
f <- parseFunctionCall c n
return $ TypeCall [c] (JustTypeInstance $ TypeInstance t $ Positional []) f
asCategory c t = do
categorySymbolGet
n <- sourceParser
f <- parseFunctionCall c n
return $ CategoryCall [c] t f
typeCall = do
c <- getPosition
t <- try sourceParser
try typeSymbolGet
n <- sourceParser
f <- parseFunctionCall c n
return $ TypeCall [c] t f
instance ParseFromSource (ValueLiteral SourcePos) where
sourceParser = labeled "literal" $
stringLiteral <|>
charLiteral <|>
escapedInteger <|>
integerOrDecimal <|>
boolLiteral <|>
emptyLiteral where
stringLiteral = do
c <- getPosition
string_ "\""
ss <- manyTill stringChar (string_ "\"")
optionalSpace
return $ StringLiteral [c] ss
charLiteral = do
c <- getPosition
string_ "'"
ch <- stringChar <|> char '"'
string_ "'"
optionalSpace
return $ CharLiteral [c] ch
escapedInteger = do
c <- getPosition
escapeStart
b <- oneOf "bBoOdDxX"
d <- case b of
'b' -> parseBin
'B' -> parseBin
'o' -> parseOct
'O' -> parseOct
'd' -> parseDec
'D' -> parseDec
'x' -> parseHex
'X' -> parseHex
_ -> undefined
optionalSpace
return $ IntegerLiteral [c] True d
integerOrDecimal = do
c <- getPosition
d <- parseDec
decimal c d <|> integer c d
decimal c d = do
char_ '.'
(n,d2) <- parseSubOne
e <- decExponent <|> return 0
optionalSpace
return $ DecimalLiteral [c] (d*10^n + d2) (e - n)
decExponent = do
string_ "e" <|> string_ "E"
s <- (string_ "+" >> return 1) <|> (string_ "-" >> return (-1)) <|> return 1
e <- parseDec
return (s*e)
integer c d = do
optionalSpace
return $ IntegerLiteral [c] False d
boolLiteral = do
c <- getPosition
b <- try $ (kwTrue >> return True) <|> (kwFalse >> return False)
return $ BoolLiteral [c] b
emptyLiteral = do
c <- getPosition
try kwEmpty
return $ EmptyLiteral [c]
instance ParseFromSource (ValueOperation SourcePos) where
sourceParser = try valueCall <|> try conversion where
valueCall = labeled "function call" $ do
c <- getPosition
valueSymbolGet
n <- sourceParser
f <- parseFunctionCall c n
return $ ValueCall [c] f
conversion = labeled "type conversion" $ do
c <- getPosition
valueSymbolGet
t <- sourceParser
typeSymbolGet
n <- sourceParser
f <- parseFunctionCall c n
return $ ConvertedCall [c] t f