Skip to content

Commit

Permalink
Merge pull request #125 from EpitechPromo2027/122-parse-function-type…
Browse files Browse the repository at this point in the history
…-without

parse function type without `()`
  • Loading branch information
oriollinan authored Jan 9, 2025
2 parents 4419aad + e29d5d4 commit 6115e63
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 23 deletions.
1 change: 0 additions & 1 deletion lib/Ast/Parser/Expr.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import qualified Text.Megaparsec.Char.Lexer as ML
parseExpr :: PU.Parser AT.Expr
parseExpr = CE.makeExprParser (PU.lexeme parseTerm) PO.operationTable

-- TODO: rethink order
parseTerm :: PU.Parser AT.Expr
parseTerm =
M.choice
Expand Down
2 changes: 1 addition & 1 deletion lib/Ast/Parser/Program.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import qualified Text.Megaparsec as M

parseProgram :: String -> PU.Parser AT.Program
parseProgram sourceFile = do
types <- M.many $ M.try PT.parseTypeDefinition
exprs <- M.many PE.parseExpr
types <- M.many PT.parseTypeDefinition
return $ AT.Program {AT.globals = map globalExpr exprs, AT.types = map globalType types, AT.sourceFile = sourceFile}

globalExpr :: AT.Expr -> (String, AT.Expr)
Expand Down
20 changes: 15 additions & 5 deletions lib/Ast/Parser/Type.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,18 @@ import qualified Text.Megaparsec.Char.Lexer as ML
-- | Parse a general type. This function combines multiple specific type parsers.
-- It tries to match typedefs, structs, unions, functions, mutable types, pointers, and base types.
parseType :: PU.Parser AT.Type
parseType = PU.triedChoice [functionType, mutableType, arrayType, pointerType, customIntType, baseType, customType]
parseType = M.choice [M.try functionType, parseTermType]

parseTermType :: PU.Parser AT.Type
parseTermType =
M.choice
[ M.try customIntType,
baseType,
mutableType,
arrayType,
pointerType,
customType
]

-- | A list of predefined base types along with their associated keywords.
-- These include basic types such as int, float, double, char, bool, and void.
Expand Down Expand Up @@ -60,13 +71,12 @@ arrayType = do

-- | Parses a function type.
-- A function type is defined by its parameter types enclosed in parentheses, followed by "->", and the return type also enclosed in parentheses.
-- Example: "(int) -> (float)" or "(int int) -> (void)".
-- Example: "int -> float" or "int int -> void".
-- TODO: find a way to do it without the parenthesis and avoid the infinite loop of parseType
functionType :: PU.Parser AT.Type
functionType = do
paramTypes <- M.between (PU.symbol "(") (PU.symbol ")") $ M.some (PU.lexeme parseType)
_ <- PU.sc *> PU.symbol "->"
returnType <- M.between (PU.symbol "(") (PU.symbol ")") parseType
paramTypes <- M.some $ PU.lexeme (M.between (PU.symbol "(") (PU.symbol ")") functionType M.<|> parseTermType)
returnType <- PU.symbol "->" *> PU.lexeme parseTermType
return $ AT.TFunction {AT.returnType = returnType, AT.paramTypes = paramTypes, AT.isVariadic = False}

customType :: PU.Parser AT.Type
Expand Down
33 changes: 19 additions & 14 deletions test/Ast/Parser/ExprSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ spec = do
_ -> error "Expected failure"

it "parses a function declaration" $ do
let input = "add: (int int) -> (int) = x y { ret 1 }"
let input = "add: int int -> int = x y { ret 1 }"
let expected =
Right $
AT.Function
Expand All @@ -48,18 +48,6 @@ spec = do
let result = normalizeExpr <$> parseWithEnv input
result `shouldBe` expected

it "parses fibonacci" $ do
let input = "add: (int int) -> (int) = x y { ret 1 }"
let result = normalizeExpr <$> parseWithEnv input
let expected =
AT.Function
normalizeLoc
"add"
(AT.TFunction {AT.returnType = AT.TInt 32, AT.paramTypes = [AT.TInt 32, AT.TInt 32], AT.isVariadic = False})
["x", "y"]
(AT.Block [AT.Return normalizeLoc (Just (AT.Lit normalizeLoc (AT.LInt 1)))])
result `shouldBe` Right expected

it "parses a variable declaration with initialization" $
do
let input = "x : int = 42"
Expand Down Expand Up @@ -103,7 +91,7 @@ spec = do
result `shouldBe` expected

it "parses an if-else expression with implicit returns" $ do
let input = "main: (never) -> (never) = { if x { 1 } else { 0 } }"
let input = "main: never -> never = { if x { 1 } else { 0 } }"
let env = E.insertVar "x" AT.TBoolean initialEnv
let result = normalizeExpr <$> fst (S.runState (M.runParserT PE.parseExpr "" input) env)
let expected =
Expand Down Expand Up @@ -396,6 +384,23 @@ spec = do
(AT.Lit normalizeLoc $ AT.LInt 1)
result `shouldBe` expected

it "parses a higher order function" $ do
let input = "map: (int -> char) int -> char = f x { f(x) }"
let functionType = AT.TFunction AT.TChar [AT.TInt 32] False
let result = normalizeExpr <$> parseWithEnv input
let expected =
Right $
AT.Function
normalizeLoc
"map"
(AT.TFunction AT.TChar [functionType, AT.TInt 32] False)
["f", "x"]
( AT.Block
[ AT.Return normalizeLoc $ Just $ AT.Call normalizeLoc (AT.Var normalizeLoc "f" functionType) [AT.Var normalizeLoc "x" $ AT.TInt 32]
]
)
result `shouldBe` expected

normalizeLoc :: AT.SrcLoc
normalizeLoc = AT.SrcLoc "" 0 0

Expand Down
3 changes: 3 additions & 0 deletions test/Ast/Parser/TypeDefinitionSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,6 @@ spec = do
describe "Typedefs" $ do
it "parses typedef alias" $ do
parseWithEnv "Alias :: int" `shouldBe` Right (AT.TTypedef "Alias" (AT.TInt 32))

it "parses typedef for a function" $ do
parseWithEnv "Alias :: int -> char" `shouldBe` Right (AT.TTypedef "Alias" (AT.TFunction AT.TChar [AT.TInt 32] False))
4 changes: 2 additions & 2 deletions test/Ast/Parser/TypeSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,10 @@ spec = do

describe "Function Types" $ do
it "parses int -> float" $ do
parseWithEnv "(int) -> (float)" `shouldBe` Right (AT.TFunction {AT.returnType = AT.TFloat, AT.paramTypes = [AT.TInt 32], AT.isVariadic = False})
parseWithEnv "int -> float" `shouldBe` Right (AT.TFunction {AT.returnType = AT.TFloat, AT.paramTypes = [AT.TInt 32], AT.isVariadic = False})

it "parses int int -> never" $ do
parseWithEnv "(int int) -> (never)" `shouldBe` Right (AT.TFunction {AT.returnType = AT.TVoid, AT.paramTypes = [AT.TInt 32, AT.TInt 32], AT.isVariadic = False})
parseWithEnv "int int -> never" `shouldBe` Right (AT.TFunction {AT.returnType = AT.TVoid, AT.paramTypes = [AT.TInt 32, AT.TInt 32], AT.isVariadic = False})

describe "Custom Types" $ do
it "parses a defined custom struct type" $ do
Expand Down

0 comments on commit 6115e63

Please # to comment.