Determine an expression type
This commit is contained in:
parent
385322235d
commit
573990551c
3
TODO
3
TODO
@ -1 +1,4 @@
|
|||||||
# Type analysis
|
# Type analysis
|
||||||
|
|
||||||
|
- Iterate the tree and apply the expression function on procedure expressions.
|
||||||
|
- Check statement types.
|
||||||
|
@ -22,6 +22,7 @@ common warnings
|
|||||||
ghc-options: -Wall
|
ghc-options: -Wall
|
||||||
default-extensions:
|
default-extensions:
|
||||||
ExplicitForAll,
|
ExplicitForAll,
|
||||||
|
LambdaCase,
|
||||||
OverloadedStrings
|
OverloadedStrings
|
||||||
default-language: GHC2021
|
default-language: GHC2021
|
||||||
|
|
||||||
|
@ -3,12 +3,24 @@ module Language.Elna.TypeAnalysis
|
|||||||
, typeAnalysis
|
, typeAnalysis
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad.Trans.Except (Except, runExcept)
|
import Control.Applicative (Alternative(..))
|
||||||
import Control.Monad.Trans.Reader (ReaderT, runReaderT)
|
import Control.Monad.Trans.Except (Except, runExcept, throwE)
|
||||||
|
import Control.Monad.Trans.Reader (ReaderT, asks, runReaderT)
|
||||||
import qualified Language.Elna.AST as AST
|
import qualified Language.Elna.AST as AST
|
||||||
import Language.Elna.SymbolTable (SymbolTable)
|
import Language.Elna.Location (Identifier(..))
|
||||||
|
import Language.Elna.SymbolTable (Info(..), SymbolTable)
|
||||||
|
import qualified Language.Elna.SymbolTable as SymbolTable
|
||||||
|
import Language.Elna.Types (Type(..), booleanType, intType)
|
||||||
|
import Control.Monad.Trans.Class (MonadTrans(..))
|
||||||
|
import Control.Monad (unless)
|
||||||
|
|
||||||
data Error = Error
|
data Error
|
||||||
|
= ArithmeticExpressionError Type
|
||||||
|
| ComparisonExpressionError Type Type
|
||||||
|
| UnexpectedVariableInfoError Info
|
||||||
|
| UndefinedSymbolError Identifier
|
||||||
|
| ArrayIndexError Type
|
||||||
|
| ArrayAccessError Type
|
||||||
deriving (Eq, Show)
|
deriving (Eq, Show)
|
||||||
|
|
||||||
newtype TypeAnalysis a = TypeAnalysis
|
newtype TypeAnalysis a = TypeAnalysis
|
||||||
@ -37,3 +49,60 @@ typeAnalysis globalTable = either Just (const Nothing)
|
|||||||
|
|
||||||
program :: AST.Program -> TypeAnalysis ()
|
program :: AST.Program -> TypeAnalysis ()
|
||||||
program (AST.Program _declarations) = pure ()
|
program (AST.Program _declarations) = pure ()
|
||||||
|
|
||||||
|
expression :: SymbolTable -> AST.Expression -> TypeAnalysis Type
|
||||||
|
expression globalTable = \case
|
||||||
|
AST.VariableExpression identifier -> do
|
||||||
|
localLookup <- TypeAnalysis $ asks $ SymbolTable.lookup identifier
|
||||||
|
case localLookup <|> SymbolTable.lookup identifier globalTable of
|
||||||
|
Just (VariableInfo variableType _) -> pure variableType
|
||||||
|
Just anotherInfo -> TypeAnalysis $ lift $ throwE
|
||||||
|
$ UnexpectedVariableInfoError anotherInfo
|
||||||
|
Nothing -> TypeAnalysis $ lift $ throwE
|
||||||
|
$ UndefinedSymbolError identifier
|
||||||
|
AST.LiteralExpression literal' -> literal literal'
|
||||||
|
AST.NegationExpression negation -> do
|
||||||
|
operandType <- expression globalTable negation
|
||||||
|
if operandType == intType
|
||||||
|
then pure intType
|
||||||
|
else TypeAnalysis $ lift $ throwE $ ArithmeticExpressionError operandType
|
||||||
|
AST.SumExpression lhs rhs -> arithmeticExpression lhs rhs
|
||||||
|
AST.SubtractionExpression lhs rhs -> arithmeticExpression lhs rhs
|
||||||
|
AST.ProductExpression lhs rhs -> arithmeticExpression lhs rhs
|
||||||
|
AST.DivisionExpression lhs rhs -> arithmeticExpression lhs rhs
|
||||||
|
AST.EqualExpression lhs rhs -> comparisonExpression lhs rhs
|
||||||
|
AST.NonEqualExpression lhs rhs -> comparisonExpression lhs rhs
|
||||||
|
AST.LessExpression lhs rhs -> comparisonExpression lhs rhs
|
||||||
|
AST.GreaterExpression lhs rhs -> comparisonExpression lhs rhs
|
||||||
|
AST.LessOrEqualExpression lhs rhs -> comparisonExpression lhs rhs
|
||||||
|
AST.GreaterOrEqualExpression lhs rhs -> comparisonExpression lhs rhs
|
||||||
|
AST.ArrayExpression arrayExpression indexExpression -> do
|
||||||
|
arrayType <- expression globalTable arrayExpression
|
||||||
|
indexType <- expression globalTable indexExpression
|
||||||
|
unless (indexType == intType)
|
||||||
|
$ TypeAnalysis $ lift $ throwE $ ArrayIndexError indexType
|
||||||
|
case arrayType of
|
||||||
|
ArrayType _ baseType -> pure baseType
|
||||||
|
nonArrayType -> TypeAnalysis $ lift $ throwE
|
||||||
|
$ ArrayAccessError nonArrayType
|
||||||
|
where
|
||||||
|
arithmeticExpression lhs rhs = do
|
||||||
|
lhsType <- expression globalTable lhs
|
||||||
|
unless (lhsType == intType)
|
||||||
|
$ TypeAnalysis $ lift $ throwE $ ArithmeticExpressionError lhsType
|
||||||
|
rhsType <- expression globalTable rhs
|
||||||
|
unless (rhsType == intType)
|
||||||
|
$ TypeAnalysis $ lift $ throwE $ ArithmeticExpressionError rhsType
|
||||||
|
pure intType
|
||||||
|
comparisonExpression lhs rhs = do
|
||||||
|
lhsType <- expression globalTable lhs
|
||||||
|
rhsType <- expression globalTable rhs
|
||||||
|
if lhsType == intType && rhsType ==intType
|
||||||
|
then pure booleanType
|
||||||
|
else TypeAnalysis $ lift $ throwE $ ComparisonExpressionError lhsType rhsType
|
||||||
|
|
||||||
|
literal :: AST.Literal -> TypeAnalysis Type
|
||||||
|
literal (AST.IntegerLiteral _) = pure intType
|
||||||
|
literal (AST.HexadecimalLiteral _) = pure intType
|
||||||
|
literal (AST.CharacterLiteral _) = pure intType
|
||||||
|
literal (AST.BooleanLiteral _) = pure booleanType
|
||||||
|
Loading…
Reference in New Issue
Block a user