struct variable type checking, refactoring to avoid circular dependencies

This commit is contained in:
vegowotenks 2025-01-02 10:54:15 +01:00
parent 9f2fad1507
commit 1c1e25a881
15 changed files with 224 additions and 140 deletions

89
src/Ubc/Parse/Struct.hs Normal file
View file

@ -0,0 +1,89 @@
module Ubc.Parse.Struct
( Struct(..)
, parseStruct
)
where
import Data.Functor ( (<&>) )
import Control.Arrow ( Arrow(second) )
import Text.Parsec
( char,
choice,
getState,
lookAhead,
many,
modifyState,
try,
unexpected,
ParsecT )
import Ubc.Parse.ParserState (ParserState)
import Ubc.Parse.Scope.StructScope (StructScope(..))
import Ubc.Parse.Scope (Scope(..))
import Ubc.Parse.Types (checkTypeValidity)
import Ubc.Parse.Data.Struct (Struct(..))
import qualified Ubc.Parse.Language as UbcLanguage
import qualified Ubc.Parse.Scope.StructScope as StructScope
import qualified Ubc.Parse.ParserState as ParserState
import qualified Ubc.Parse.Scope as Scope
import qualified Ubc.Parse.VariableType as VariableType
import qualified Data.Map as Map
parseStruct :: Monad m => ParsecT String ParserState m Struct
parseStruct = do
_ <- UbcLanguage.reserved "struct"
structIdentifier <- UbcLanguage.identifier
let structScope = StructScope
{ structName = structIdentifier
, variables = Map.empty
}
modifyState (ParserState.pushScope . ScopeStruct $ structScope)
_ <- UbcLanguage.braces (many structMember)
structScope' <- getState <&> Scope.expectScopeStruct . snd . ParserState.popScope
return $ Struct (StructScope.structName structScope') (StructScope.variables structScope')
structMember :: Monad m => ParsecT String ParserState m ()
structMember = choice [ structVariableOrFunction ]
structVariableOrFunction :: Monad m => ParsecT String ParserState m ()
structVariableOrFunction = do
(typeName, identifier) <- try $ do
typeName <- UbcLanguage.typeName
objectIdentifier <- UbcLanguage.identifier
return (typeName, objectIdentifier)
choice
[ lookAhead (char ';') *> parseVariable typeName identifier
] -- TODO: Functions on structs
parseVariable :: Monad m => String -> String -> ParsecT String ParserState m ()
parseVariable variableType variableName = do
_ <- UbcLanguage.semicolon
-- TODO: Validate type
(_, structScope) <- getState <&> second Scope.expectScopeStruct . ParserState.popScope
-- check variable name
if (/= Nothing) . Map.lookup variableName . StructScope.variables $ structScope
then do
unexpected $ "variable name: \"" ++ variableName ++ "\", this name is already defined"
else do
return ()
-- check type
isKnownType <- checkTypeValidity variableType
if not isKnownType
then do
unexpected $ "variable type: \"" ++ variableType ++ "\", this type is not defined"
else do
return ()
let structScope' = StructScope.modifyVariables (Map.insert variableName (VariableType.fromString variableType)) structScope
modifyState (ParserState.pushScope $ ScopeStruct structScope')