Add typeExpression to type converter

This commit is contained in:
Eugen Wissner 2024-07-29 08:26:47 +03:00
parent ce7652c618
commit 92990e52f0
5 changed files with 134 additions and 35 deletions

11
TODO
View File

@ -1,4 +1,9 @@
# AST missing # Name analysis
- Import - Collect all global type and procedure definitions.
- Record and Union initialization Give errors if:
- The type is already defined.
- Base type is not defined.
- Circular type reference.
- Check definitions inside procedures.

View File

@ -1,4 +1,4 @@
cabal-version: 3.0 cabal-version: 3.4
name: elna name: elna
version: 0.1.0.0 version: 0.1.0.0
synopsis: synopsis:
@ -16,13 +16,14 @@ extra-doc-files: TODO README
common warnings common warnings
build-depends: build-depends:
base ^>=4.17.2.1, base >=4.7 && <5,
megaparsec ^>= 9.6, megaparsec ^>= 9.6,
text ^>= 2.0 text ^>= 2.0
ghc-options: -Wall ghc-options: -Wall
default-extensions: default-extensions:
ExplicitForAll, ExplicitForAll,
OverloadedStrings OverloadedStrings
default-language: GHC2021
library elna-internal library elna-internal
import: warnings import: warnings
@ -32,9 +33,11 @@ library elna-internal
Language.Elna.NameAnalysis Language.Elna.NameAnalysis
Language.Elna.Parser Language.Elna.Parser
Language.Elna.SymbolTable Language.Elna.SymbolTable
Language.Elna.Types
build-depends: build-depends:
hashable ^>= 1.4.3, hashable ^>= 1.4.3,
parser-combinators ^>= 1.3, parser-combinators ^>= 1.3,
transformers ^>= 0.6.1,
vector ^>= 0.13.1, vector ^>= 0.13.1,
unordered-containers ^>= 0.2.20 unordered-containers ^>= 0.2.20
hs-source-dirs: lib hs-source-dirs: lib
@ -43,9 +46,8 @@ executable elna
import: warnings import: warnings
main-is: Main.hs main-is: Main.hs
build-depends: build-depends:
elna-internal elna:elna-internal
hs-source-dirs: src hs-source-dirs: src
default-language: GHC2021
test-suite elna-test test-suite elna-test
import: warnings import: warnings
@ -58,11 +60,10 @@ test-suite elna-test
ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall
build-depends: build-depends:
elna-internal, elna:elna-internal,
hspec >= 2.10.9 && < 2.12, hspec >= 2.10.9 && < 2.12,
hspec-expectations ^>= 0.8.2, hspec-expectations ^>= 0.8.2,
hspec-megaparsec ^>= 2.2.0, hspec-megaparsec ^>= 2.2.0,
text text
build-tool-depends: build-tool-depends:
hspec-discover:hspec-discover hspec-discover:hspec-discover
default-language: GHC2021

View File

@ -1,3 +1,65 @@
module Language.Elna.NameAnalysis module Language.Elna.NameAnalysis
( ( Error(..)
, nameAnalysis
) where ) where
import Control.Monad.Trans.Except (ExceptT(..), runExceptT, throwE)
import Control.Monad.Trans.Reader (Reader, ask, runReader)
import Data.Functor ((<&>))
import qualified Language.Elna.AST as AST
import Language.Elna.Location (Identifier(..))
import Language.Elna.SymbolTable (Info(..), SymbolTable, symbolTable)
import qualified Language.Elna.SymbolTable as SymbolTable
import Language.Elna.Types (Type(..))
import Control.Monad.Trans.Class (MonadTrans(..))
data Error
= UndefinedTypeError Identifier
| UnexpectedTypeInfoError Info
deriving (Eq, Show)
newtype NameAnalysis a = NameAnalysis
{ runNameAnalysis :: ExceptT Error (Reader SymbolTable) a
}
instance Functor NameAnalysis
where
fmap f (NameAnalysis x) = NameAnalysis $ f <$> x
instance Applicative NameAnalysis
where
pure x = NameAnalysis $ pure x
(NameAnalysis f) <*> (NameAnalysis x) = NameAnalysis $ f <*> x
instance Monad NameAnalysis
where
(NameAnalysis x) >>= f = NameAnalysis $ x >>= (runNameAnalysis . f)
nameAnalysis :: AST.Program -> Either Error SymbolTable
nameAnalysis = flip runReader symbolTable
. runExceptT
. runNameAnalysis
. program
program :: AST.Program -> NameAnalysis SymbolTable
program (AST.Program declarations) = do
globalDeclarations <- traverse declaration declarations
NameAnalysis $ lift ask
declaration :: AST.Declaration -> NameAnalysis (Identifier, Info)
declaration (AST.TypeDefinition identifier typeExpression) =
(identifier,) . TypeInfo <$> dataType typeExpression
declaration (AST.ProcedureDefinition identifier _parameters _variables _body) = do
environmentSymbolTable <- NameAnalysis $ lift ask
pure (identifier, ProcedureInfo environmentSymbolTable mempty)
dataType :: AST.TypeExpression -> NameAnalysis Type
dataType (AST.NamedType baseType) = do
environmentSymbolTable <- NameAnalysis $ lift ask
case SymbolTable.lookup baseType environmentSymbolTable of
Just baseInfo
| TypeInfo baseType' <- baseInfo -> pure baseType'
| otherwise -> NameAnalysis $ throwE $ UnexpectedTypeInfoError baseInfo
_ -> NameAnalysis $ throwE $ UndefinedTypeError baseType
dataType (AST.ArrayType arraySize baseType) =
dataType baseType <&> ArrayType arraySize

View File

@ -1,37 +1,43 @@
module Language.Elna.SymbolTable module Language.Elna.SymbolTable
( Info(..) ( Info(..)
, ParameterInfo(..) , ParameterInfo(..)
, SymbolTable(..) , SymbolTable
, Type(..) , enter
, booleanType , lookup
, intType , symbolTable
) where ) where
import Data.HashMap.Strict (HashMap) import Data.HashMap.Strict (HashMap)
import Data.Text (Text) import qualified Data.HashMap.Strict as HashMap
import Data.Vector (Vector) import Data.Vector (Vector)
import Data.Word (Word32) import Language.Elna.Location (Identifier(..))
import Language.Elna.Location (Identifier(..), showArrayType) import Language.Elna.Types (Type(..), intType, booleanType)
import Prelude hiding (lookup)
data Type
= PrimitiveType Text
| ArrayType Word32 Type
deriving Eq
instance Show Type
where
show (PrimitiveType typeName) = show typeName
show (ArrayType elementCount typeName) = showArrayType elementCount typeName
intType :: Type
intType = PrimitiveType "int"
booleanType :: Type
booleanType = PrimitiveType "boolean"
newtype SymbolTable = SymbolTable (HashMap Identifier Info) newtype SymbolTable = SymbolTable (HashMap Identifier Info)
deriving (Eq, Show) deriving (Eq, Show)
instance Semigroup SymbolTable
where
(SymbolTable lhs) <> (SymbolTable rhs) = SymbolTable $ rhs <> lhs
instance Monoid SymbolTable
where
mempty = SymbolTable HashMap.empty
symbolTable :: SymbolTable
symbolTable = SymbolTable $ HashMap.fromList
[ ("boolean", TypeInfo booleanType)
, ("int", TypeInfo intType)
]
enter :: Identifier -> Info -> SymbolTable -> SymbolTable
enter identifier info (SymbolTable table) = SymbolTable
$ HashMap.insert identifier info table
lookup :: Identifier -> SymbolTable -> Maybe Info
lookup identifier (SymbolTable table) = HashMap.lookup identifier table
data ParameterInfo = ParameterInfo data ParameterInfo = ParameterInfo
{ name :: Identifier { name :: Identifier
, type' :: Type , type' :: Type

View File

@ -0,0 +1,25 @@
module Language.Elna.Types
( Type(..)
, booleanType
, intType
) where
import Data.Text (Text)
import Data.Word (Word32)
import Language.Elna.Location (showArrayType)
data Type
= PrimitiveType Text
| ArrayType Word32 Type
deriving Eq
instance Show Type
where
show (PrimitiveType typeName) = show typeName
show (ArrayType elementCount typeName) = showArrayType elementCount typeName
intType :: Type
intType = PrimitiveType "int"
booleanType :: Type
booleanType = PrimitiveType "boolean"