diff options
| author | Eugen Wissner <belka@caraus.de> | 2024-08-06 17:02:18 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2024-08-06 17:02:18 +0200 |
| commit | 385322235ddabde3a2d5f33d8f258016a9170f83 (patch) | |
| tree | 0b3854573bd024b9817630590542e0b3c3329789 /lib | |
| parent | a1863147f866718c19c8fdefeeb033efab766885 (diff) | |
| download | elna-385322235ddabde3a2d5f33d8f258016a9170f83.tar.gz | |
Look for undefined symbols
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Language/Elna/NameAnalysis.hs | 84 | ||||
| -rw-r--r-- | lib/Language/Elna/TypeAnalysis.hs | 39 |
2 files changed, 119 insertions, 4 deletions
diff --git a/lib/Language/Elna/NameAnalysis.hs b/lib/Language/Elna/NameAnalysis.hs index afb040e..57c41b3 100644 --- a/lib/Language/Elna/NameAnalysis.hs +++ b/lib/Language/Elna/NameAnalysis.hs @@ -4,7 +4,13 @@ module Language.Elna.NameAnalysis ) where import Control.Monad.Trans.Except (Except, runExcept, throwE) -import Control.Monad.Trans.Reader (ReaderT(..), ask, runReaderT, withReaderT) +import Control.Monad.Trans.Reader + ( ReaderT(..) + , ask + , asks + , runReaderT + , withReaderT + ) import Data.Functor ((<&>)) import qualified Language.Elna.AST as AST import Language.Elna.Location (Identifier(..)) @@ -12,13 +18,15 @@ import Language.Elna.SymbolTable (Info(..), SymbolTable, builtInSymbolTable) import qualified Language.Elna.SymbolTable as SymbolTable import Language.Elna.Types (Type(..)) import Control.Monad.Trans.Class (MonadTrans(..)) -import Control.Monad (foldM) +import Control.Monad (foldM, unless) import qualified Data.List.NonEmpty as NonEmpty +import Data.Foldable (traverse_) data Error = UndefinedTypeError Identifier | UnexpectedTypeInfoError Info | IdentifierAlreadyDefinedError Identifier + | UndefinedSymbolError Identifier deriving (Eq, Show) newtype NameAnalysis a = NameAnalysis @@ -53,15 +61,83 @@ declaration :: SymbolTable -> AST.Declaration -> NameAnalysis SymbolTable declaration globalTable (AST.TypeDefinition identifier typeExpression) = withSymbolTable globalTable (dataType typeExpression) >>= flip (enter identifier) globalTable . TypeInfo - -declaration globalTable (AST.ProcedureDefinition identifier parameters variables _body) = do +declaration globalTable (AST.ProcedureDefinition identifier parameters variables body) = do parametersInfo <- mapM parameter parameters variableInfo <- mapM variableDeclaration variables newTable <- either (identifierAlreadyDefinedError . NonEmpty.head) pure $ SymbolTable.fromList $ parametersInfo <> variableInfo + traverse_ (statement globalTable) body enter identifier (ProcedureInfo newTable mempty) globalTable +statement :: SymbolTable -> AST.Statement -> NameAnalysis () +statement _ AST.EmptyStatement = pure () +statement globalTable (AST.AssignmentStatement lvalue rvalue) + = expression globalTable lvalue + >> expression globalTable rvalue +statement globalTable (AST.IfStatement condition ifStatement elseStatement) + = expression globalTable condition + >> statement globalTable ifStatement + >> maybe (pure ()) (statement globalTable) elseStatement +statement globalTable (AST.WhileStatement condition loop) + = expression globalTable condition + >> statement globalTable loop +statement globalTable (AST.CompoundStatement statements) = + traverse_ (statement globalTable) statements +statement globalTable (AST.CallStatement name arguments) + = checkSymbol name globalTable + >> traverse_ (expression globalTable) arguments + +checkSymbol :: Identifier -> SymbolTable -> NameAnalysis () +checkSymbol identifier globalTable = + let undefinedSymbolError = NameAnalysis + $ lift + $ throwE + $ UndefinedSymbolError identifier + isDefined = SymbolTable.member identifier globalTable + in NameAnalysis (asks (SymbolTable.member identifier)) + >>= (flip unless undefinedSymbolError . (isDefined ||)) + +expression :: SymbolTable -> AST.Expression -> NameAnalysis () +expression globalTable (AST.VariableExpression identifier) = + checkSymbol identifier globalTable +expression _ (AST.LiteralExpression _) = pure () +expression globalTable (AST.NegationExpression negation) = + expression globalTable negation +expression globalTable (AST.SumExpression lhs rhs) + = expression globalTable lhs + >> expression globalTable rhs +expression globalTable (AST.SubtractionExpression lhs rhs) + = expression globalTable lhs + >> expression globalTable rhs +expression globalTable (AST.ProductExpression lhs rhs) + = expression globalTable lhs + >> expression globalTable rhs +expression globalTable (AST.DivisionExpression lhs rhs) + = expression globalTable lhs + >> expression globalTable rhs +expression globalTable (AST.EqualExpression lhs rhs) + = expression globalTable lhs + >> expression globalTable rhs +expression globalTable (AST.NonEqualExpression lhs rhs) + = expression globalTable lhs + >> expression globalTable rhs +expression globalTable (AST.LessExpression lhs rhs) + = expression globalTable lhs + >> expression globalTable rhs +expression globalTable (AST.GreaterExpression lhs rhs) + = expression globalTable lhs + >> expression globalTable rhs +expression globalTable (AST.LessOrEqualExpression lhs rhs) + = expression globalTable lhs + >> expression globalTable rhs +expression globalTable (AST.GreaterOrEqualExpression lhs rhs) + = expression globalTable lhs + >> expression globalTable rhs +expression globalTable (AST.ArrayExpression arrayExpression indexExpression) + = expression globalTable arrayExpression + >> expression globalTable indexExpression + enter :: Identifier -> Info -> SymbolTable -> NameAnalysis SymbolTable enter identifier info table = maybe (identifierAlreadyDefinedError identifier) pure diff --git a/lib/Language/Elna/TypeAnalysis.hs b/lib/Language/Elna/TypeAnalysis.hs new file mode 100644 index 0000000..9804753 --- /dev/null +++ b/lib/Language/Elna/TypeAnalysis.hs @@ -0,0 +1,39 @@ +module Language.Elna.TypeAnalysis + ( Error(..) + , typeAnalysis + ) where + +import Control.Monad.Trans.Except (Except, runExcept) +import Control.Monad.Trans.Reader (ReaderT, runReaderT) +import qualified Language.Elna.AST as AST +import Language.Elna.SymbolTable (SymbolTable) + +data Error = Error + deriving (Eq, Show) + +newtype TypeAnalysis a = TypeAnalysis + { runTypeAnalysis :: ReaderT SymbolTable (Except Error) a + } + +instance Functor TypeAnalysis + where + fmap f (TypeAnalysis x) = TypeAnalysis $ f <$> x + +instance Applicative TypeAnalysis + where + pure = TypeAnalysis . pure + (TypeAnalysis f) <*> (TypeAnalysis x) = TypeAnalysis $ f <*> x + +instance Monad TypeAnalysis + where + (TypeAnalysis x) >>= f = TypeAnalysis $ x >>= (runTypeAnalysis . f) + +typeAnalysis :: SymbolTable -> AST.Program -> Maybe Error +typeAnalysis globalTable = either Just (const Nothing) + . runExcept + . flip runReaderT globalTable + . runTypeAnalysis + . program + +program :: AST.Program -> TypeAnalysis () +program (AST.Program _declarations) = pure () |
