Skip to content

Commit

Permalink
mod: parser State
Browse files Browse the repository at this point in the history
  • Loading branch information
oriollinan committed Jan 9, 2025
1 parent 3d8ad32 commit d10d303
Show file tree
Hide file tree
Showing 11 changed files with 58 additions and 68 deletions.
4 changes: 2 additions & 2 deletions lib/Ast/Parser.hs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Ast.Parser where

import qualified Ast.Parser.Env as E
import qualified Ast.Parser.Program as PP
import qualified Ast.Parser.State as PS
import qualified Ast.Types as AT
import qualified Control.Monad.State as S
import qualified Text.Megaparsec as M
Expand All @@ -10,6 +10,6 @@ import qualified Text.Megaparsec as M
-- The `parse` function takes a filename `String`, and an input `String` as a parameter and returns either an AST or an error message.
parse :: String -> String -> Either String AT.Program
parse sourceFile input =
case S.runState (M.runParserT (PP.parseProgram sourceFile) sourceFile input) E.emptyEnv of
case S.runState (M.runParserT (PP.parseProgram sourceFile) sourceFile input) PS.parserState of
(Left err, _) -> Left (M.errorBundlePretty err)
(Right program, _) -> Right program
14 changes: 7 additions & 7 deletions lib/Ast/Parser/Expr.hs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
module Ast.Parser.Expr where

import qualified Ast.Parser.Env as E
import qualified Ast.Parser.Literal as PL
import qualified Ast.Parser.Operation as PO
import qualified Ast.Parser.State as PS
import qualified Ast.Parser.Type as PT
import qualified Ast.Parser.Utils as AU
import qualified Ast.Parser.Utils as PU
Expand Down Expand Up @@ -48,7 +48,7 @@ parseVar = do
srcLoc <- PU.parseSrcLoc
name <- PU.identifier
env <- S.get
case E.lookupVar name env of
case PS.lookupVar name env of
(Just t) -> return $ AT.Var srcLoc name t
_ -> M.customFailure $ PU.UndefinedVar name

Expand All @@ -60,8 +60,8 @@ parseFunction = do
case ft of
(AT.TFunction {AT.paramTypes = pts}) -> do
params <- PU.symbol "=" *> M.many (PU.lexeme PU.identifier)
mapM_ (\(p, t) -> S.modify (E.insertVar p t)) $ zip params pts
S.modify (E.insertVar name ft)
mapM_ (\(p, t) -> S.modify (PS.insertVar p t)) $ zip params pts
S.modify (PS.insertVar name ft)
block <- parseBlock
let body = implicitReturn block
return $ AT.Function {AT.funcLoc = srcLoc, AT.funcName = name, AT.funcType = ft, AT.funcParams = params, AT.funcBody = body}
Expand Down Expand Up @@ -94,7 +94,7 @@ parseDeclaration = do
name <- PU.identifier
t <- PU.symbol ":" *> PT.parseType
value <- M.optional $ PU.symbol "=" *> parseExpr
S.modify (E.insertVar name t)
S.modify (PS.insertVar name t)
return $ AT.Declaration {AT.declLoc = srcLoc, AT.declName = name, AT.declType = t, AT.declInit = value}

parseAssignment :: PU.Parser AT.Expr
Expand All @@ -110,7 +110,7 @@ parseCall = do
name <- PU.identifier
args <- M.between (PU.symbol "(") (PU.symbol ")") $ M.many parseExpr
env <- S.get
case E.lookupVar name env of
case PS.lookupVar name env of
(Just t@(AT.TFunction {})) -> return $ AT.Call {AT.callLoc = srcLoc, AT.callFunc = AT.Var srcLoc name t, AT.callArgs = args}
_ -> M.customFailure $ PU.UndefinedFunction name

Expand Down Expand Up @@ -142,7 +142,7 @@ parseFor = do
return (name, type')
let init' = AT.Declaration srcLoc name type' (Just from)
let var = AT.Var srcLoc name type'
S.modify (E.insertVar name type')
S.modify (PS.insertVar name type')
body <- parseBlock
let step = case by of
Just n -> AT.Assignment srcLoc var (AT.Op srcLoc AT.Add var (AT.Lit srcLoc (AT.LInt n)))
Expand Down
3 changes: 1 addition & 2 deletions lib/Ast/Parser/Literal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ module Ast.Parser.Literal where

import qualified Ast.Parser.Utils as PU
import qualified Ast.Types as AT
import Text.Megaparsec ((<|>))
import qualified Text.Megaparsec as M
import qualified Text.Megaparsec.Char as MC
import qualified Text.Megaparsec.Char.Lexer as ML
Expand Down Expand Up @@ -32,7 +31,7 @@ parseFloat = AT.LFloat <$> ML.signed (pure ()) ML.float
-- | Parses a boolean literal (`true` or `false`).
-- Returns a `Literal` of type `LBool`.
parseBool :: PU.Parser AT.Literal
parseBool = AT.LBool True <$ PU.symbol trueSymbol <|> AT.LBool False <$ PU.symbol falseSymbol
parseBool = AT.LBool True <$ PU.symbol trueSymbol M.<|> AT.LBool False <$ PU.symbol falseSymbol

-- | Parses a character literal (e.g., 'a').
-- Returns a `Literal` of type `LChar`.
Expand Down
17 changes: 4 additions & 13 deletions lib/Ast/Parser/State.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,13 @@ type TypeState = [(String, AT.Type)]

type VarState = [(String, AT.Type)]

type ExprState = Maybe AT.Expr

data ParserState = ParserState
{ typeState :: TypeState,
varState :: VarState,
exprState :: ExprState
varState :: VarState
}

parserState :: ParserState
parserState = ParserState {typeState = [], varState = [], exprState = Nothing}
parserState = ParserState {typeState = [], varState = []}

-- | Inserts a custom type into the environment.
-- If the type already exists, it overwrites it.
Expand All @@ -24,16 +21,10 @@ insertType name t s = s {typeState = (name, t) : typeState s}

-- | Looks up a custom type in the environment by its name.
lookupType :: String -> ParserState -> Maybe AT.Type
lookupType name (ParserState types _ _) = lookup name types
lookupType name (ParserState types _) = lookup name types

insertVar :: String -> AT.Type -> ParserState -> ParserState
insertVar name t s = s {varState = (name, t) : varState s}

lookupVar :: String -> ParserState -> Maybe AT.Type
lookupVar name (ParserState _ vars _) = lookup name vars

insertExpr :: AT.Expr -> ParserState -> ParserState
insertExpr e s = s {exprState = Just e}

getExpr :: ParserState -> ExprState
getExpr (ParserState _ _ e) = e
lookupVar name (ParserState _ vars) = lookup name vars
4 changes: 2 additions & 2 deletions lib/Ast/Parser/Type.hs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module Ast.Parser.Type where

import qualified Ast.Parser.Env as E
import qualified Ast.Parser.State as PS
import qualified Ast.Parser.Utils as PU
import qualified Ast.Types as AT
import qualified Control.Monad.State as S
Expand Down Expand Up @@ -73,6 +73,6 @@ customType :: PU.Parser AT.Type
customType = do
name <- PU.identifier
env <- S.get
case E.lookupType name env of
case PS.lookupType name env of
Just ty -> return ty
Nothing -> M.customFailure $ PU.UnknownType name
8 changes: 4 additions & 4 deletions lib/Ast/Parser/TypeDefinition.hs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module Ast.Parser.TypeDefinition where

import qualified Ast.Parser.Env as E
import qualified Ast.Parser.State as PS
import qualified Ast.Parser.Type as T
import qualified Ast.Parser.Utils as PU
import qualified Ast.Types as AT
Expand All @@ -22,7 +22,7 @@ structType = do
_ <- PU.symbol "::" <* PU.symbol "struct"
fields <- M.between (PU.symbol "{") (PU.symbol "}") $ M.many parseField
let newStructType = AT.TStruct {AT.structName = name, AT.fields = fields}
S.modify (E.insertType name newStructType)
S.modify (PS.insertType name newStructType)
return newStructType

-- | Parses a union type definition.
Expand All @@ -34,7 +34,7 @@ unionType = do
_ <- PU.symbol "::" <* PU.symbol "union"
variants <- M.between (PU.symbol "{") (PU.symbol "}") $ M.many parseField
let newUnionType = AT.TUnion {AT.unionName = name, AT.variants = variants}
S.modify (E.insertType name newUnionType)
S.modify (PS.insertType name newUnionType)
return newUnionType

-- | Parses a typedef.
Expand All @@ -46,7 +46,7 @@ typedefType = do
_ <- PU.symbol "::"
parentType <- T.parseType
let typedef = AT.TTypedef name parentType
S.modify (E.insertType name typedef)
S.modify (PS.insertType name typedef)
return typedef

-- | Parses a single field within a struct or union.
Expand Down
4 changes: 2 additions & 2 deletions lib/Ast/Parser/Utils.hs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module Ast.Parser.Utils where

import qualified Ast.Parser.Env as E
import qualified Ast.Parser.State as PS
import qualified Ast.Types as AT
import qualified Control.Monad.State as S
import qualified Text.Megaparsec as M
Expand All @@ -9,7 +9,7 @@ import qualified Text.Megaparsec.Char.Lexer as ML
import qualified Text.Megaparsec.Pos as MP

-- | A type alias for the parser, based on `Parsec` with `Void` error type and `String` input.
type Parser = M.ParsecT ParseErrorCustom String (S.State E.Env)
type Parser = M.ParsecT ParseErrorCustom String (S.State PS.ParserState)

data ParseErrorCustom
= UnknownType String
Expand Down
30 changes: 15 additions & 15 deletions test/Ast/Parser/ExprSpec.hs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
module Ast.Parser.ExprSpec (spec) where

import qualified Ast.Parser.Env as E
import qualified Ast.Parser.Expr as PE
import qualified Ast.Parser.State as PS
import qualified Ast.Types as AT
import qualified Control.Monad.State as S
import Test.Hspec
import qualified Text.Megaparsec as M

spec :: Spec
spec = do
let initialEnv = E.emptyEnv
let initialEnv = PS.parserState
let parseWithEnv input =
fst $ S.runState (M.runParserT PE.parseExpr "" input) initialEnv

Expand All @@ -23,7 +23,7 @@ spec = do
it "parses a variable expression" $
do
let input = "x"
let env = E.insertVar "x" (AT.TInt 32) initialEnv
let env = PS.insertVar "x" (AT.TInt 32) initialEnv
let result = normalizeExpr <$> fst (S.runState (M.runParserT PE.parseExpr "" input) env)
let expected = Right (AT.Var normalizeLoc "x" (AT.TInt 32))
result `shouldBe` expected
Expand Down Expand Up @@ -76,21 +76,21 @@ spec = do

it "parses an assignment expression" $ do
let input = "x = 42"
let env = E.insertVar "x" (AT.TInt 0) initialEnv
let env = PS.insertVar "x" (AT.TInt 0) initialEnv
let result = normalizeExpr <$> fst (S.runState (M.runParserT PE.parseExpr "" input) env)
let expected = Right (AT.Assignment normalizeLoc (AT.Var normalizeLoc "x" (AT.TInt 0)) (AT.Lit normalizeLoc (AT.LInt 42)))
result `shouldBe` expected

it "parses a function call" $ do
let env = E.insertVar "foo" (AT.TFunction {AT.returnType = AT.TVoid, AT.paramTypes = [AT.TInt 0], AT.isVariadic = False}) initialEnv
let env = PS.insertVar "foo" (AT.TFunction {AT.returnType = AT.TVoid, AT.paramTypes = [AT.TInt 0], AT.isVariadic = False}) initialEnv
let input = "foo(123)"
normalizeExpr <$> fst (S.runState (M.runParserT PE.parseExpr "" input) env)
`shouldBe` Right
(AT.Call normalizeLoc (AT.Var normalizeLoc "foo" (AT.TFunction {AT.returnType = AT.TVoid, AT.paramTypes = [AT.TInt 0], AT.isVariadic = False})) [AT.Lit normalizeLoc (AT.LInt 123)])

it "parses an if-else expression" $ do
let input = "if x { ret 1 } else { ret 0 }"
let env = E.insertVar "x" AT.TBoolean initialEnv
let env = PS.insertVar "x" AT.TBoolean initialEnv
let result = normalizeExpr <$> fst (S.runState (M.runParserT PE.parseExpr "" input) env)
let expected =
Right $
Expand All @@ -104,7 +104,7 @@ spec = do

it "parses an if-else expression with implicit returns" $ do
let input = "main: (never) -> (never) = { if x { 1 } else { 0 } }"
let env = E.insertVar "x" AT.TBoolean initialEnv
let env = PS.insertVar "x" AT.TBoolean initialEnv
let result = normalizeExpr <$> fst (S.runState (M.runParserT PE.parseExpr "" input) env)
let expected =
Right $
Expand All @@ -126,7 +126,7 @@ spec = do

it "parses a while loop" $ do
let input = "loop z { z = 0 }"
let env = E.insertVar "z" (AT.TInt 32) initialEnv
let env = PS.insertVar "z" (AT.TInt 32) initialEnv
let result = normalizeExpr <$> fst (S.runState (M.runParserT PE.parseExpr "" input) env)
let expected =
Right $
Expand All @@ -148,7 +148,7 @@ spec = do

it "parses a for loop" $ do
let input = "from 0 to 10 by 2 |i: int| { i = 0 }"
let env = E.emptyEnv
let env = PS.parserState
let result = normalizeExpr <$> fst (S.runState (M.runParserT PE.parseExpr "" input) env)
let expected =
Right $
Expand Down Expand Up @@ -189,7 +189,7 @@ spec = do

it "parses a for loop with a dynamic range" $ do
let input = "from 0 to 10 by x |i: int| { i = 0 }"
let env = E.insertVar "x" (AT.TInt 32) E.emptyEnv
let env = PS.insertVar "x" (AT.TInt 32) PS.parserState
let result = normalizeExpr <$> fst (S.runState (M.runParserT PE.parseExpr "" input) env)
let expected =
Right $
Expand Down Expand Up @@ -243,7 +243,7 @@ spec = do
it "parses a struct access" $ do
let input = "myStruct.myField"
let structType = AT.TStruct "Custom" [("myField", AT.TChar)]
let env = E.insertVar "myStruct" structType $ E.insertType "Custom" structType E.emptyEnv
let env = PS.insertVar "myStruct" structType $ PS.insertType "Custom" structType PS.parserState
let result = normalizeExpr <$> fst (S.runState (M.runParserT PE.parseExpr "" input) env)
let expected =
Right $
Expand All @@ -256,7 +256,7 @@ spec = do
it "parses a nested struct access" $ do
let input = "myStruct.innerStruct.field"
let structType = AT.TStruct "Custom" [("innerStruct", AT.TStruct "InnerCustom" [("field", AT.TChar)])]
let env = E.insertVar "myStruct" structType $ E.insertType "Custom" structType E.emptyEnv
let env = PS.insertVar "myStruct" structType $ PS.insertType "Custom" structType PS.parserState
let result = normalizeExpr <$> fst (S.runState (M.runParserT PE.parseExpr "" input) env)
let expected =
Right $
Expand All @@ -273,7 +273,7 @@ spec = do
it "parses an array access" $ do
let input = "myArray.1"
let arrayType = AT.TArray AT.TChar Nothing
let env = E.insertVar "myArray" arrayType E.emptyEnv
let env = PS.insertVar "myArray" arrayType PS.parserState
let result = normalizeExpr <$> fst (S.runState (M.runParserT PE.parseExpr "" input) env)
let expected =
Right $
Expand All @@ -286,7 +286,7 @@ spec = do
it "parses an nested array access" $ do
let input = "myArray.1.1"
let arrayType = AT.TArray (AT.TArray AT.TChar Nothing) Nothing
let env = E.insertVar "myArray" arrayType E.emptyEnv
let env = PS.insertVar "myArray" arrayType PS.parserState
let result = normalizeExpr <$> fst (S.runState (M.runParserT PE.parseExpr "" input) env)
let expected =
Right $
Expand Down Expand Up @@ -342,7 +342,7 @@ spec = do

it "parses an operator with hierarchy and comparisons" $ do
let input = "n is 0 or n is 1"
let env = E.insertVar "n" (AT.TInt 32) E.emptyEnv
let env = PS.insertVar "n" (AT.TInt 32) PS.parserState
let result = normalizeExpr <$> fst (S.runState (M.runParserT PE.parseExpr "" input) env)
let expected =
Right $
Expand Down
Loading

0 comments on commit d10d303

Please # to comment.