83 lines
3.0 KiB
Haskell
83 lines
3.0 KiB
Haskell
{- This Source Code Form is subject to the terms of the Mozilla Public License,
|
|
v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
obtain one at https://mozilla.org/MPL/2.0/. -}
|
|
|
|
module Language.Elna.NameAnalysisSpec
|
|
( spec
|
|
) where
|
|
|
|
import Data.Text (Text)
|
|
import Text.Megaparsec (runParser)
|
|
import Test.Hspec
|
|
( Spec
|
|
, describe
|
|
, expectationFailure
|
|
, it
|
|
, shouldBe
|
|
, shouldSatisfy
|
|
)
|
|
import Language.Elna.NameAnalysis (Error(..), nameAnalysis)
|
|
import Language.Elna.SymbolTable (Info(..), SymbolTable)
|
|
import qualified Language.Elna.SymbolTable as SymbolTable
|
|
import qualified Language.Elna.Parser as AST
|
|
import Language.Elna.Types (intType)
|
|
import Control.Exception (throwIO)
|
|
|
|
nameAnalysisOnText :: Text -> IO (Either Error SymbolTable)
|
|
nameAnalysisOnText sourceText = nameAnalysis
|
|
<$> either throwIO pure (runParser AST.programP "" sourceText)
|
|
|
|
spec :: Spec
|
|
spec = describe "nameAnalysis" $ do
|
|
it "adds type to the symbol table" $ do
|
|
let given = "type A = int;"
|
|
expected = Right $ Just $ TypeInfo intType
|
|
actual <- nameAnalysisOnText given
|
|
|
|
actual `shouldSatisfy` (expected ==) . fmap (SymbolTable.lookup "A")
|
|
|
|
it "errors when the aliased type is not defined" $ do
|
|
let given = "type A = B;"
|
|
expected = Left $ UndefinedTypeError "B"
|
|
actual <- nameAnalysisOnText given
|
|
|
|
actual `shouldBe` expected
|
|
|
|
it "errors if the aliased identifier is not a type" $ do
|
|
let given = "proc main() {} type A = main;"
|
|
expected = Left
|
|
$ UnexpectedTypeInfoError
|
|
$ ProcedureInfo mempty mempty
|
|
actual <- nameAnalysisOnText given
|
|
|
|
actual `shouldBe` expected
|
|
|
|
it "replaces the alias with an equivalent base type" $ do
|
|
let given = "type A = int; type B = A; type C = B;"
|
|
expected = Right $ Just $ TypeInfo intType
|
|
actual <- nameAnalysisOnText given
|
|
|
|
actual `shouldSatisfy` (expected ==) . fmap (SymbolTable.lookup "C")
|
|
|
|
it "puts parameters into the local symbol table" $ do
|
|
let given = "proc main(ref param: int) {}"
|
|
expected = SymbolTable.enter "param" (VariableInfo True intType) SymbolTable.empty
|
|
actual <- nameAnalysisOnText given
|
|
|
|
case SymbolTable.lookup "main" <$> actual of
|
|
Right lookupResult
|
|
| Just (ProcedureInfo localTable _) <- lookupResult ->
|
|
Just localTable `shouldBe` expected
|
|
_ -> expectationFailure "Procedure symbol not found"
|
|
|
|
it "puts variables into the local symbol table" $ do
|
|
let given = "proc main() { var var1: int; }"
|
|
expected = SymbolTable.enter "var1" (VariableInfo False intType) SymbolTable.empty
|
|
actual <- nameAnalysisOnText given
|
|
|
|
case SymbolTable.lookup "main" <$> actual of
|
|
Right lookupResult
|
|
| Just (ProcedureInfo localTable _) <- lookupResult ->
|
|
Just localTable `shouldBe` expected
|
|
_ -> expectationFailure "Procedure symbol not found"
|