language-oberon 0.2 → 0.2.1
raw patch · 16 files changed
+2015/−631 lines, 16 filesdep +template-haskelldep +transformersdep ~grammatical-parsersdep ~prettyprinterdep ~rank2classes
Dependencies added: template-haskell, transformers
Dependency ranges changed: grammatical-parsers, prettyprinter, rank2classes
Files
- ChangeLog.md +15/−2
- app/Parse.hs +20/−10
- examples/AGRS/OFS.Def +4/−0
- language-oberon.cabal +13/−10
- src/Language/Oberon.hs +20/−9
- src/Language/Oberon/AST.hs +139/−106
- src/Language/Oberon/Grammar.hs +122/−112
- src/Language/Oberon/Pretty.hs +47/−35
- src/Language/Oberon/Resolver.hs +261/−341
- src/Language/Oberon/TypeChecker.hs +880/−0
- src/Transformation.hs +23/−0
- src/Transformation/AG.hs +37/−0
- src/Transformation/Deep.hs +83/−0
- src/Transformation/Deep/TH.hs +287/−0
- src/Transformation/Rank2.hs +36/−0
- test/Test.hs +28/−6
ChangeLog.md view
@@ -1,9 +1,22 @@ # Revision history for language-oberon -## 0.1 -- 2018-04-08+## 0.2.1 -- 2019-01-27 -* First version, but complete enough to be released on an unsuspecting world...+* Pretty-printer fixes+* Testing the idempotence of parse&pretty-print+* Two type parameters for each AST node type, wrapping every field+* Added the Transformation modules+* Added the TypeChecker module +## 0.2 -- 2018-07-09++* Improved error reporting+* Fixed compilation with GHC 8.0.2+ ## 0.1.1 -- 2018-04-08 * except for the missing Oberon module examples the test suite depends on.++## 0.1 -- 2018-04-08++* First version, but complete enough to be released on an unsuspecting world...
app/Parse.hs view
@@ -3,7 +3,7 @@ module Main where import Language.Oberon (parseAndResolveModule)-import Language.Oberon.AST (Module(..), Statement, Expression)+import Language.Oberon.AST (Module(..), StatementSequence, Statement, Expression) import qualified Language.Oberon.Grammar as Grammar import qualified Language.Oberon.Resolver as Resolver import qualified Language.Oberon.Pretty ()@@ -30,7 +30,8 @@ import Prelude hiding (getLine, getContents, readFile) -data GrammarMode = ModuleWithImportsMode | ModuleMode | AmbiguousModuleMode | DefinitionMode | StatementsMode | StatementMode | ExpressionMode+data GrammarMode = TypeCheckedModuleMode | ModuleWithImportsMode | ModuleMode | AmbiguousModuleMode | DefinitionMode+ | StatementsMode | StatementMode | ExpressionMode deriving Show data Output = Plain | Pretty Int | Tree@@ -55,7 +56,7 @@ p :: Parser Opts p = Opts- <$> (mode <|> pure ModuleWithImportsMode)+ <$> mode <*> (switch (long "oberon2")) <*> (option auto (long "index" <> help "Index of ambiguous parse" <> showDefault <> value 0 <> metavar "INT")) <*> (Pretty <$> option auto (long "pretty" <> help "Pretty-print output" <> metavar "WIDTH")@@ -68,7 +69,8 @@ <> help "Oberon file to parse")) mode :: Parser GrammarMode- mode = ModuleWithImportsMode <$ switch (long "module-with-imports")+ mode = TypeCheckedModuleMode <$ switch (long "type-checked-module")+ <|> ModuleWithImportsMode <$ switch (long "module-with-imports") <|> ModuleMode <$ switch (long "module") <|> AmbiguousModuleMode <$ switch (long "module-ambiguous") <|> DefinitionMode <$ switch (long "definition")@@ -81,10 +83,14 @@ case optsFile of Just file -> (if file == "-" then getContents else readFile file) >>= case optsMode- of ModuleWithImportsMode ->- \source-> parseAndResolveModule optsOberon2+ of TypeCheckedModuleMode ->+ \source-> parseAndResolveModule True optsOberon2 (fromMaybe (takeDirectory file) optsInclude) source >>= succeed optsOutput source+ ModuleWithImportsMode ->+ \source-> parseAndResolveModule False optsOberon2+ (fromMaybe (takeDirectory file) optsInclude) source+ >>= succeed optsOutput source ModuleMode -> go (Resolver.resolveModule predefined mempty) Grammar.module_prod chosenGrammar file DefinitionMode -> go (Resolver.resolveModule predefined mempty) Grammar.module_prod@@ -127,11 +133,15 @@ Tree -> putStrLn . reprTreeString Plain -> print -instance Pretty (Module Ambiguous) where+instance Pretty (Module Ambiguous Ambiguous) where pretty _ = error "Disambiguate before pretty-printing"-instance Pretty (Ambiguous (Statement Ambiguous)) where+instance Pretty (StatementSequence Ambiguous Ambiguous) where pretty _ = error "Disambiguate before pretty-printing"-instance Pretty (Statement Ambiguous) where+instance Pretty (Ambiguous (Statement Ambiguous Ambiguous)) where pretty _ = error "Disambiguate before pretty-printing"-instance Pretty (Expression Ambiguous) where+instance Pretty (Statement Ambiguous Ambiguous) where+ pretty _ = error "Disambiguate before pretty-printing"+instance Pretty (Expression Ambiguous Ambiguous) where+ pretty _ = error "Disambiguate before pretty-printing"+instance Pretty (Ambiguous (Expression Ambiguous Ambiguous)) where pretty _ = error "Disambiguate before pretty-printing"
examples/AGRS/OFS.Def view
@@ -1,3 +1,7 @@ DEFINITION OFS; + TYPE+ File *= RECORD END;+ Rider *= RECORD END;+ END OFS.
language-oberon.cabal view
@@ -2,8 +2,8 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: language-oberon-version: 0.2-synopsis: Parser and pretty-printer for the Oberon programming language+version: 0.2.1+synopsis: Parser, pretty-printer, and type checker for the Oberon programming language description: The library and the executable support both the original Oberon and the Oberon-2 programming language, as described in the respective <http://www.ethoberon.ethz.ch/compiler/index.html#report language reports>.@@ -23,7 +23,7 @@ license-file: LICENSE author: Mario Blažević maintainer: blamario@protonmail.com--- copyright: +-- copyright: category: Language build-type: Simple extra-source-files: ChangeLog.md, examples/AGRS/*.Def, examples/AGRS/*.Mod@@ -33,10 +33,13 @@ hs-source-dirs: src exposed-modules: Language.Oberon, Language.Oberon.AST, Language.Oberon.Grammar,- Language.Oberon.Pretty, Language.Oberon.Resolver+ Language.Oberon.Pretty, Language.Oberon.Resolver, Language.Oberon.TypeChecker,+ Transformation, Transformation.Deep, Transformation.Deep.TH,+ Transformation.Rank2, Transformation.AG build-depends: base >= 4.7 && < 5, text < 1.3, containers >= 0.5 && < 1.0, filepath < 1.5, directory < 1.4,- parsers >= 0.12.7 && < 0.13, prettyprinter >= 1 && < 1.3, either == 5.*,- rank2classes < 1.2, grammatical-parsers >= 0.3.1 && < 0.4+ parsers >= 0.12.7 && < 0.13, prettyprinter >= 1.2.1 && < 1.3, either == 5.*,+ rank2classes < 1.3, grammatical-parsers > 0.3.1 && < 0.4, transformers == 0.5.*,+ template-haskell >= 2.11 && < 2.15 default-language: Haskell2010 executable parse@@ -44,15 +47,15 @@ -- other-modules: other-extensions: RankNTypes, RecordWildCards, ScopedTypeVariables, FlexibleInstances, DeriveDataTypeable build-depends: base >= 4.7 && < 5, text < 1.3, either == 5.*, containers >= 0.5 && < 1.0,- repr-tree-syb < 0.2, filepath < 1.5, prettyprinter >= 1 && < 1.3,- rank2classes < 1.2, grammatical-parsers >= 0.3.1 && < 0.4, language-oberon,+ repr-tree-syb < 0.2, filepath < 1.5, prettyprinter >= 1.2.1 && < 1.3,+ rank2classes < 1.3, grammatical-parsers > 0.3.1 && < 0.4, language-oberon, optparse-applicative default-language: Haskell2010 test-suite examples type: exitcode-stdio-1.0- build-depends: base >= 4.7 && < 5,- either == 5.*, directory < 2, filepath < 1.5,+ build-depends: base >= 4.7 && < 5, text < 1.3, grammatical-parsers > 0.3.1 && < 0.4,+ either == 5.*, directory < 2, filepath < 1.5, prettyprinter >= 1.2.1 && < 1.3, tasty >= 0.7, tasty-hunit, language-oberon main-is: test/Test.hs
src/Language/Oberon.hs view
@@ -5,7 +5,9 @@ import Language.Oberon.AST (Module(..)) import qualified Language.Oberon.Grammar as Grammar import qualified Language.Oberon.Resolver as Resolver+import qualified Language.Oberon.TypeChecker as TypeChecker +import Control.Monad (when) import Data.Either.Validation (Validation(..)) import Data.Functor.Identity (Identity) import Data.Functor.Compose (getCompose)@@ -23,17 +25,17 @@ import Prelude hiding (readFile) -- | Parse the given text of a single module, without resolving the syntactic ambiguities.-parseModule :: Bool -> Text -> ParseResults [Module Ambiguous]+parseModule :: Bool -> Text -> ParseResults [Module Ambiguous Ambiguous] parseModule oberon2 = getCompose . Grammar.module_prod . parseComplete (if oberon2 then Grammar.oberon2Grammar else Grammar.oberonGrammar) -- | Parse the given text of a single /definition/ module, without resolving the syntactic ambiguities.-parseDefinitionModule :: Bool -> Text -> ParseResults [Module Ambiguous]+parseDefinitionModule :: Bool -> Text -> ParseResults [Module Ambiguous Ambiguous] parseDefinitionModule oberon2 = getCompose . Grammar.module_prod . parseComplete (if oberon2 then Grammar.oberon2DefinitionGrammar else Grammar.oberonDefinitionGrammar) -parseNamedModule :: Bool -> FilePath -> Text -> IO (ParseResults [Module Ambiguous])+parseNamedModule :: Bool -> FilePath -> Text -> IO (ParseResults [Module Ambiguous Ambiguous]) parseNamedModule oberon2 path name = do let basePath = combine path (unpack name) isDefn <- doesFileExist (addExtension basePath "Def")@@ -43,7 +45,7 @@ getCompose . Grammar.module_prod . parseComplete grammar <$> readFile (addExtension basePath $ if isDefn then "Def" else "Mod") -parseImportsOf :: Bool -> FilePath -> Map Text (Module Ambiguous) -> IO (Map Text (Module Ambiguous))+parseImportsOf :: Bool -> FilePath -> Map Text (Module Ambiguous Ambiguous) -> IO (Map Text (Module Ambiguous Ambiguous)) parseImportsOf oberon2 path modules = case filter (`Map.notMember` modules) moduleImports of [] -> return modules@@ -58,17 +60,26 @@ -- | Given a directory path for module imports, parse the given module text and all the module files it imports, then -- use all the information to resolve the syntactic ambiguities.-parseAndResolveModule :: Bool -> FilePath -> Text -> IO (Validation (NonEmpty Resolver.Error) (Module Identity))-parseAndResolveModule oberon2 path source =+parseAndResolveModule :: Bool -> Bool -> FilePath -> Text+ -> IO (Validation (NonEmpty Resolver.Error) (Module Identity Identity))+parseAndResolveModule checkTypes oberon2 path source = case parseModule oberon2 source of Left err -> return (Failure $ Resolver.UnparseableModule err :| []) Right [rootModule@(Module moduleName imports _ _ _)] -> do importedModules <- parseImportsOf oberon2 path (Map.singleton moduleName rootModule) let resolvedImportMap = Resolver.resolveModule predefinedScope resolvedImportMap <$> importedModules predefinedScope = if oberon2 then Resolver.predefined2 else Resolver.predefined- return $ Resolver.resolveModule predefinedScope resolvedImportMap rootModule+ successful (Success a) = Just a+ successful _ = Nothing+ typeErrors = TypeChecker.checkModules+ (if oberon2 then TypeChecker.predefined2 else TypeChecker.predefined)+ (Map.mapMaybe successful resolvedImportMap)+ when (checkTypes && not (null typeErrors)) (error $ show typeErrors)+ return $ resolvedImportMap Map.! moduleName Right _ -> return (Failure $ Resolver.AmbiguousParses :| []) -- | Parse the module file at the given path, assuming all its imports are in the same directory.-parseAndResolveModuleFile :: Bool -> FilePath -> IO (Validation (NonEmpty Resolver.Error) (Module Identity))-parseAndResolveModuleFile oberon2 path = readFile path >>= parseAndResolveModule oberon2 (takeDirectory path)+parseAndResolveModuleFile :: Bool -> Bool -> FilePath+ -> IO (Validation (NonEmpty Resolver.Error) (Module Identity Identity))+parseAndResolveModuleFile checkTypes oberon2 path =+ readFile path >>= parseAndResolveModule checkTypes oberon2 (takeDirectory path)
src/Language/Oberon/AST.hs view
@@ -1,4 +1,6 @@-{-# LANGUAGE DeriveDataTypeable, FlexibleInstances, UndecidableInstances, StandaloneDeriving #-}+{-# LANGUAGE DeriveDataTypeable, FlexibleInstances, MultiParamTypeClasses, UndecidableInstances,+ StandaloneDeriving, TemplateHaskell #-}+{-# OPTIONS_GHC -Wno-simplifiable-class-constraints #-} -- | Oberon Abstract Syntax Tree definitions @@ -7,28 +9,33 @@ import Data.Data (Data, Typeable) import Data.Functor.Identity (Identity) import Data.List.NonEmpty-import Data.Text-import Text.Grampa (Ambiguous)+import Data.Text (Text) -data Module f = Module Ident [Import] [Declaration f] (Maybe (StatementSequence f)) Ident+import Transformation.Deep (Product)+import qualified Transformation.Deep.TH+import qualified Rank2.TH -deriving instance (Typeable f, Data (f (Designator f)), Data (f (Expression f)), Data (f (Statement f))) =>- Data (Module f)-deriving instance (Show (f (Designator f)), Show (f (Expression f)), Show (f (Statement f))) => Show (Module f)+data Module f' f = Module Ident [Import] ([f (Declaration f' f')]) (Maybe (f (StatementSequence f' f'))) Ident +deriving instance (Typeable f, Typeable f',+ Data (f (Declaration f' f')), Data (f (StatementSequence f' f'))) => Data (Module f' f)+deriving instance (Show (f (Declaration f' f')), Show (f (StatementSequence f' f'))) => Show (Module f' f)+ type Ident = Text type Import = (Maybe Ident, Ident) -data Declaration f = ConstantDeclaration IdentDef (f (ConstExpression f))- | TypeDeclaration IdentDef (Type f)- | VariableDeclaration IdentList (Type f)- | ProcedureDeclaration (ProcedureHeading f) (ProcedureBody f) Ident- | ForwardDeclaration IdentDef (Maybe (FormalParameters f))+data Declaration f' f = ConstantDeclaration IdentDef (f (ConstExpression f' f'))+ | TypeDeclaration IdentDef (f (Type f' f'))+ | VariableDeclaration IdentList (f (Type f' f'))+ | ProcedureDeclaration (ProcedureHeading f' f) (ProcedureBody f' f) Ident+ | ForwardDeclaration IdentDef (Maybe (f (FormalParameters f' f'))) -deriving instance (Typeable f, Data (f (Designator f)), Data (f (Expression f)), Data (f (Statement f))) =>- Data (Declaration f)-deriving instance (Show (f (Designator f)), Show (f (Expression f)), Show (f (Statement f))) => Show (Declaration f)+deriving instance (Typeable f, Typeable f',+ Data (f (Type f' f')), Data (f (ConstExpression f' f')), Data (f (FormalParameters f' f')),+ Data (ProcedureHeading f' f), Data (ProcedureBody f' f)) => Data (Declaration f' f)+deriving instance (Show (f (Type f' f')), Show (f (ConstExpression f' f')), Show (f (FormalParameters f' f')),+ Show (ProcedureHeading f' f), Show (ProcedureBody f' f)) => Show (Declaration f' f) data IdentDef = IdentDef Ident AccessMode deriving (Data, Eq, Ord, Show)@@ -38,128 +45,154 @@ type ConstExpression = Expression -data Expression f = Relation RelOp (Expression f) (Expression f)- | Positive (Expression f)- | Negative (Expression f)- | Add (Expression f) (Expression f)- | Subtract (Expression f) (Expression f)- | Or (Expression f) (Expression f)- | Multiply (Expression f) (Expression f)- | Divide (Expression f) (Expression f)- | IntegerDivide (Expression f) (Expression f)- | Modulo (Expression f) (Expression f)- | And (Expression f) (Expression f)- | Integer Text- | Real Text- | CharConstant Char- | CharCode Int- | String Text- | Nil - | Set [Element f]- | Read (AmbDesignator f)- | FunctionCall (AmbDesignator f) (ActualParameters f)- | Not (Expression f)+data Expression f' f = Relation RelOp (f (Expression f' f')) (f (Expression f' f'))+ | Positive (f (Expression f' f'))+ | Negative (f (Expression f' f'))+ | Add (f (Expression f' f')) (f (Expression f' f'))+ | Subtract (f (Expression f' f')) (f (Expression f' f'))+ | Or (f (Expression f' f')) (f (Expression f' f'))+ | Multiply (f (Expression f' f')) (f (Expression f' f'))+ | Divide (f (Expression f' f')) (f (Expression f' f'))+ | IntegerDivide (f (Expression f' f')) (f (Expression f' f'))+ | Modulo (f (Expression f' f')) (f (Expression f' f'))+ | And (f (Expression f' f')) (f (Expression f' f'))+ | Integer Text+ | Real Text+ | CharConstant Char+ | CharCode Int+ | String Text+ | Nil + | Set [f (Element f' f')]+ | Read (f (Designator f' f'))+ | FunctionCall (f (Designator f' f')) [f (Expression f' f')]+ | Not (f (Expression f' f')) -deriving instance (Typeable f, Data (f (Designator f))) => Data (Expression f)-deriving instance Show (f (Designator f)) => Show (Expression f)+deriving instance (Typeable f, Typeable f', Data (f (Designator f' f')),+ Data (f (Element f' f')), Data (f (Expression f' f'))) => Data (Expression f' f)+deriving instance (Show (f (Designator f' f')),+ Show (f (Element f' f')), Show (f (Expression f' f'))) => Show (Expression f' f) data RelOp = Equal | Unequal | Less | LessOrEqual | Greater | GreaterOrEqual | In | Is deriving (Data, Show) -data Element f = Element (Expression f)- | Range (Expression f) (Expression f)--deriving instance (Typeable f, Data (f (Designator f))) => Data (Element f)-deriving instance Show (f (Designator f)) => Show (Element f)--type AmbDesignator f = f (Designator f)+data Element f' f = Element (f (Expression f' f'))+ | Range (f (Expression f' f')) (f (Expression f' f')) -data Designator f = Variable QualIdent- | Field (Designator f) Ident - | Index (Designator f) (NonEmpty (Expression f))- | TypeGuard (Designator f) QualIdent - | Dereference (Designator f)+deriving instance (Typeable f, Typeable f', Data (f (Expression f' f'))) => Data (Element f' f)+deriving instance Show (f (Expression f' f')) => Show (Element f' f) -deriving instance (Typeable f, Data (f (Designator f))) => Data (Designator f)-deriving instance Show (f (Designator f)) => Show (Designator f)+data Designator f' f = Variable QualIdent+ | Field (f (Designator f' f')) Ident + | Index (f (Designator f' f')) (NonEmpty (f (Expression f' f')))+ | TypeGuard (f (Designator f' f')) QualIdent + | Dereference (f (Designator f' f')) -type ActualParameters f = [Expression f]+deriving instance (Typeable f, Typeable f', Data (f (Designator f' f')), Data (f (Expression f' f'))) =>+ Data (Designator f' f)+deriving instance (Show (f (Designator f' f')), Show (f (Expression f' f'))) => Show (Designator f' f) -data Type f = TypeReference QualIdent - | ArrayType [f (ConstExpression f)] (Type f)- | RecordType (Maybe BaseType) (FieldListSequence f)- | PointerType (Type f)- | ProcedureType (Maybe (FormalParameters f))+data Type f' f = TypeReference QualIdent + | ArrayType [f (ConstExpression f' f')] (f (Type f' f'))+ | RecordType (Maybe BaseType) (NonEmpty (f (FieldList f' f')))+ | PointerType (f (Type f' f'))+ | ProcedureType (Maybe (f (FormalParameters f' f'))) -deriving instance (Typeable f, Data (f (Designator f)), Data (f (Expression f))) => Data (Type f)-deriving instance (Show (f (Designator f)), Show (f (Expression f))) => Show (Type f)+deriving instance (Typeable f, Typeable f', Data (f (Type f' f')), Data (f (ConstExpression f' f')),+ Data (f (FormalParameters f' f')), Data (f (FieldList f' f'))) => Data (Type f' f)+deriving instance (Show (f (Type f' f')), Show (f (ConstExpression f' f')),+ Show (f (FormalParameters f' f')), Show (f (FieldList f' f'))) => Show (Type f' f) data QualIdent = QualIdent Ident Ident | NonQualIdent Ident deriving (Data, Eq, Ord, Show) -type BaseType = QualIdent--type FieldListSequence f = NonEmpty (FieldList f)+type BaseType = QualIdent -data FieldList f = FieldList IdentList (Type f)- | EmptyFieldList+data FieldList f' f = FieldList IdentList (f (Type f' f'))+ | EmptyFieldList -deriving instance (Typeable f, Data (f (Designator f)), Data (f (Expression f))) => Data (FieldList f)-deriving instance (Show (f (Designator f)), Show (f (Expression f))) => Show (FieldList f)+deriving instance (Typeable f, Typeable f', Data (f (Type f' f')), Data (f (Expression f' f'))) => Data (FieldList f' f)+deriving instance (Show (f (Type f' f')), Show (f (Expression f' f'))) => Show (FieldList f' f) type IdentList = NonEmpty IdentDef -data ProcedureHeading f = ProcedureHeading (Maybe (Bool, Ident, Ident)) Bool IdentDef (Maybe (FormalParameters f))-data FormalParameters f = FormalParameters [FPSection f] (Maybe QualIdent)-data FPSection f = FPSection Bool (NonEmpty Ident) (Type f)+data ProcedureHeading f' f = + ProcedureHeading (Maybe (Bool, Ident, Ident)) Bool IdentDef (Maybe (f (FormalParameters f' f')))+data FormalParameters f' f = FormalParameters [f (FPSection f' f')] (Maybe QualIdent) -deriving instance (Typeable f, Data (f (Designator f)), Data (f (Expression f))) => Data (ProcedureHeading f)-deriving instance (Show (f (Designator f)), Show (f (Expression f))) => Show (ProcedureHeading f)+data FPSection f' f = FPSection Bool (NonEmpty Ident) (f (Type f' f')) -deriving instance (Typeable f, Data (f (Designator f)), Data (f (Expression f))) => Data (FormalParameters f)-deriving instance (Show (f (Designator f)), Show (f (Expression f))) => Show (FormalParameters f)+deriving instance (Typeable f, Typeable f', Data (f (FormalParameters f' f'))) => Data (ProcedureHeading f' f)+deriving instance (Show (f (FormalParameters f' f'))) => Show (ProcedureHeading f' f) -deriving instance (Typeable f, Data (f (Designator f)), Data (f (Expression f))) => Data (FPSection f)-deriving instance (Show (f (Designator f)), Show (f (Expression f))) => Show (FPSection f)+deriving instance (Typeable f, Typeable f', Data (f (FPSection f' f')), Data (f (Expression f' f'))) =>+ Data (FormalParameters f' f)+deriving instance (Show (f (FPSection f' f')), Show (f (Expression f' f'))) => Show (FormalParameters f' f) -data ProcedureBody f = ProcedureBody [Declaration f] (Maybe (StatementSequence f))+deriving instance (Typeable f, Typeable f', Data (f (Type f' f')), Data (f (Expression f' f'))) =>+ Data (FPSection f' f)+deriving instance (Show (f (Type f' f')), Show (f (Expression f' f'))) => Show (FPSection f' f) -deriving instance (Typeable f, Data (f (Designator f)), Data (f (Expression f)), Data (f (Statement f))) =>- Data (ProcedureBody f)-deriving instance (Show (f (Designator f)), Show (f (Expression f)), Show (f (Statement f))) => Show (ProcedureBody f)+data ProcedureBody f' f = ProcedureBody [f (Declaration f' f')] (Maybe (f (StatementSequence f' f'))) -type StatementSequence f = NonEmpty (f (Statement f))+deriving instance (Typeable f, Typeable f', Data (f (Declaration f' f')), Data (f (Designator f' f')),+ Data (f (Expression f' f')), Data (f (StatementSequence f' f'))) =>+ Data (ProcedureBody f' f)+deriving instance (Show (f (Declaration f' f')), Show (f (Designator f' f')),+ Show (f (Expression f' f')), Show (f (StatementSequence f' f'))) => Show (ProcedureBody f' f) -data Statement f = EmptyStatement- | Assignment (AmbDesignator f) (Expression f)- | ProcedureCall (AmbDesignator f) (Maybe (ActualParameters f))- | If (NonEmpty (Expression f, StatementSequence f)) (Maybe (StatementSequence f))- | CaseStatement (Expression f) (NonEmpty (Case f)) (Maybe (StatementSequence f))- | While (Expression f) (StatementSequence f)- | Repeat (StatementSequence f) (Expression f)- | For Ident (Expression f) (Expression f) (Maybe (Expression f)) (StatementSequence f) -- Oberon2- | Loop (StatementSequence f)- | With (NonEmpty (WithAlternative f)) (Maybe (StatementSequence f))- | Exit - | Return (Maybe (Expression f))+newtype StatementSequence f' f = StatementSequence (NonEmpty (f (Statement f' f'))) -deriving instance (Typeable f, Data (f (Designator f)), Data (f (Statement f))) => Data (Statement f)-deriving instance (Show (f (Designator f)), Show (f (Statement f))) => Show (Statement f)+deriving instance (Typeable f, Typeable f', Data (f (Statement f' f'))) => Data (StatementSequence f' f)+deriving instance Show (f (Statement f' f')) => Show (StatementSequence f' f) -data WithAlternative f = WithAlternative QualIdent QualIdent (StatementSequence f)+data Statement f' f = EmptyStatement+ | Assignment (f (Designator f' f')) (f (Expression f' f'))+ | ProcedureCall (f (Designator f' f')) (Maybe [f (Expression f' f')])+ | If (NonEmpty (f (Product Expression StatementSequence f' f')))+ (Maybe (f (StatementSequence f' f')))+ | CaseStatement (f (Expression f' f')) + (NonEmpty (f (Case f' f'))) + (Maybe (f (StatementSequence f' f')))+ | While (f (Expression f' f')) (f (StatementSequence f' f'))+ | Repeat (f (StatementSequence f' f')) (f (Expression f' f'))+ | For Ident (f (Expression f' f')) (f (Expression f' f')) + (Maybe (f (Expression f' f'))) (f (StatementSequence f' f')) -- Oberon2+ | Loop (f (StatementSequence f' f'))+ | With (NonEmpty (f (WithAlternative f' f'))) (Maybe (f (StatementSequence f' f')))+ | Exit + | Return (Maybe (f (Expression f' f'))) -data Case f = Case (NonEmpty (CaseLabels f)) (StatementSequence f)- | EmptyCase+deriving instance (Typeable f, Typeable f', Data (f (Designator f' f')), Data (f (Expression f' f')),+ Data (f (Product Expression StatementSequence f' f')),+ Data (f (Case f' f')), Data (f (WithAlternative f' f')),+ Data (f (Statement f' f')), Data (f (StatementSequence f' f'))) => Data (Statement f' f)+deriving instance (Show (f (Designator f' f')), Show (f (Expression f' f')),+ Show (f (Product Expression StatementSequence f' f')),+ Show (f (Case f' f')), Show (f (WithAlternative f' f')),+ Show (f (Statement f' f')), Show (f (StatementSequence f' f'))) => Show (Statement f' f) -data CaseLabels f = SingleLabel (ConstExpression f)- | LabelRange (ConstExpression f) (ConstExpression f)+data WithAlternative f' f = WithAlternative QualIdent QualIdent (f (StatementSequence f' f')) -deriving instance (Typeable f, Data (f (Designator f)), Data (f (Statement f))) => Data (WithAlternative f)-deriving instance (Show (f (Designator f)), Show (f (Statement f))) => Show (WithAlternative f)+data Case f' f = Case (NonEmpty (f (CaseLabels f' f'))) (f (StatementSequence f' f'))+ | EmptyCase -deriving instance (Typeable f, Data (f (Designator f)), Data (f (Statement f))) => Data (Case f)-deriving instance (Show (f (Designator f)), Show (f (Statement f))) => Show (Case f)+data CaseLabels f' f = SingleLabel (f (ConstExpression f' f'))+ | LabelRange (f (ConstExpression f' f')) (f (ConstExpression f' f')) -deriving instance (Typeable f, Data (f (Designator f))) => Data (CaseLabels f)-deriving instance Show (f (Designator f)) => Show (CaseLabels f)+deriving instance (Typeable f, Typeable f', Data (f (Designator f' f')), Data (f (StatementSequence f' f'))) =>+ Data (WithAlternative f' f)+deriving instance (Show (f (StatementSequence f' f'))) => Show (WithAlternative f' f)++deriving instance (Typeable f, Typeable f', Data (f (CaseLabels f' f')), Data (f (StatementSequence f' f'))) =>+ Data (Case f' f)+deriving instance (Show (f (CaseLabels f' f')), Show (f (StatementSequence f' f'))) => Show (Case f' f)++deriving instance (Typeable f, Typeable f', Data (f (ConstExpression f' f'))) => Data (CaseLabels f' f)+deriving instance Show (f (ConstExpression f' f')) => Show (CaseLabels f' f)++$(mconcat <$> mapM Transformation.Deep.TH.deriveAll+ [''Module, ''Declaration, ''Type, ''Expression,+ ''Element, ''Designator, ''FieldList,+ ''ProcedureHeading, ''FormalParameters, ''FPSection, ''ProcedureBody,+ ''Statement, ''StatementSequence, ''WithAlternative, ''Case, ''CaseLabels])
src/Language/Oberon/Grammar.hs view
@@ -18,6 +18,7 @@ import Text.Parser.Combinators (sepBy, sepBy1, sepByNonEmpty, try) import Text.Parser.Token (braces, brackets, parens) +import Transformation.Deep as Deep (Product(Pair)) import qualified Rank2 import qualified Rank2.TH @@ -27,71 +28,71 @@ -- | All the productions of the Oberon grammar data OberonGrammar f p = OberonGrammar {- module_prod :: p (Module f),+ module_prod :: p (Module f f), ident :: p Ident, letter :: p Text, digit :: p Text, importList :: p [Import], import_prod :: p Import,- declarationSequence :: p [Declaration f],- constantDeclaration :: p (Declaration f),+ declarationSequence :: p [f (Declaration f f)],+ constantDeclaration :: p (Declaration f f), identdef :: p IdentDef,- constExpression :: p (Expression f),- expression :: p (Expression f),- simpleExpression :: p (Expression f),- term :: p (Expression f),- factor :: p (Expression f),- number :: p (Expression f),- integer :: p (Expression f),+ constExpression :: p (f (Expression f f)),+ expression :: p (f (Expression f f)),+ simpleExpression :: p (f (Expression f f)),+ term :: p (f (Expression f f)),+ factor :: p (f (Expression f f)),+ number :: p (Expression f f),+ integer :: p (Expression f f), hexDigit :: p Text,- real :: p (Expression f),+ real :: p (Expression f f), scaleFactor :: p Text,- charConstant :: p (Expression f),+ charConstant :: p (Expression f f), string_prod :: p Text,- set :: p (Expression f),- element :: p (Element f),- designator :: p (Designator f),- expList :: p (NonEmpty (Expression f)),- actualParameters :: p [(Expression f)],+ set :: p (Expression f f),+ element :: p (Element f f),+ designator :: p (f (Designator f f)),+ expList :: p (NonEmpty (f (Expression f f))),+ actualParameters :: p [f (Expression f f)], mulOperator :: p (BinOp f), addOperator :: p (BinOp f), relation :: p RelOp,- typeDeclaration :: p (Declaration f),- type_prod :: p (Type f),+ typeDeclaration :: p (Declaration f f),+ type_prod :: p (Type f f), qualident :: p QualIdent,- arrayType :: p (Type f),- length :: p (Expression f),- recordType :: p (Type f),+ arrayType :: p (Type f f),+ length :: p (f (Expression f f)),+ recordType :: p (Type f f), baseType :: p QualIdent,- fieldListSequence :: p (FieldListSequence f),- fieldList :: p (FieldList f),+ fieldListSequence :: p (NonEmpty (f (FieldList f f))),+ fieldList :: p (FieldList f f), identList :: p IdentList,- pointerType :: p (Type f),- procedureType :: p (Type f),- variableDeclaration :: p (Declaration f),- procedureDeclaration :: p (Declaration f),- procedureHeading :: p (ProcedureHeading f),- formalParameters :: p (FormalParameters f),- fPSection :: p (FPSection f),- formalType :: p (Type f),- procedureBody :: p (ProcedureBody f),- forwardDeclaration :: p (Declaration f),- statementSequence :: p (NonEmpty (Ambiguous (Statement f))),- statement :: p (Statement f),- assignment :: p (Statement f),- procedureCall :: p (Statement f),- ifStatement :: p (Statement f),- caseStatement :: p (Statement f),- case_prod :: p (Case f),- caseLabelList :: p (NonEmpty (CaseLabels f)),- caseLabels :: p (CaseLabels f),- whileStatement :: p (Statement f),- repeatStatement :: p (Statement f),- forStatement :: p (Statement f),- loopStatement :: p (Statement f),- withStatement :: p (Statement f)}+ pointerType :: p (Type f f),+ procedureType :: p (Type f f),+ variableDeclaration :: p (Declaration f f),+ procedureDeclaration :: p (Declaration f f),+ procedureHeading :: p (ProcedureHeading f f),+ formalParameters :: p (FormalParameters f f),+ fPSection :: p (FPSection f f),+ formalType :: p (Type f f),+ procedureBody :: p (ProcedureBody f f),+ forwardDeclaration :: p (Declaration f f),+ statementSequence :: p (StatementSequence f f),+ statement :: p (Statement f f),+ assignment :: p (Statement f f),+ procedureCall :: p (Statement f f),+ ifStatement :: p (Statement f f),+ caseStatement :: p (Statement f f),+ case_prod :: p (Case f f),+ caseLabelList :: p (NonEmpty (f (CaseLabels f f))),+ caseLabels :: p (CaseLabels f f),+ whileStatement :: p (Statement f f),+ repeatStatement :: p (Statement f f),+ forStatement :: p (Statement f f),+ loopStatement :: p (Statement f f),+ withStatement :: p (Statement f f)} -newtype BinOp f = BinOp {applyBinOp :: (Expression f -> Expression f -> Expression f)}+newtype BinOp f = BinOp {applyBinOp :: (f (Expression f f) -> f (Expression f f) -> Expression f f)} instance Show (BinOp f) where show = const "BinOp{}"@@ -146,50 +147,54 @@ ((,,) <$> (True <$ keyword "VAR" <|> pure False) <*> ident <* delimiter ":" <*> ident)) <*> (True <$ delimiter "*" <|> pure False) - <*> identdef <*> optional formalParameters,- arrayType = ArrayType <$ keyword "ARRAY" <*> sepBy (ambiguous length) (delimiter ",") <* keyword "OF" <*> type_prod,+ <*> identdef <*> optional (wrap formalParameters),+ arrayType = + ArrayType <$ keyword "ARRAY" <*> sepBy length (delimiter ",") <* keyword "OF" <*> wrap type_prod, statement = statement1 <|> forStatement,- forStatement = For <$ keyword "FOR" <*> ident <* delimiter ":=" <*> expression <* keyword "TO" <*> expression - <*> optional (keyword "BY" *> constExpression) <* keyword "DO"- <*> statementSequence <* keyword "END",- withStatement = With <$ keyword "WITH" <*> sepByNonEmpty withAlternative (delimiter "|")- <*> optional (keyword "ELSE" *> statementSequence) <* keyword "END"}+ forStatement = + For <$ keyword "FOR" <*> ident <* delimiter ":=" <*> expression <* keyword "TO" <*> expression+ <*> optional (keyword "BY" *> constExpression) <* keyword "DO"+ <*> wrap statementSequence <* keyword "END",+ withStatement = With <$ keyword "WITH" <*> sepByNonEmpty (wrap withAlternative) (delimiter "|")+ <*> optional (keyword "ELSE" *> wrap statementSequence) <* keyword "END"} where g1@OberonGrammar{statement= statement1, string_prod= string_prod1} = grammar g withAlternative = WithAlternative <$> qualident <* delimiter ":" <*> qualident- <* keyword "DO" <*> statementSequence+ <* keyword "DO" <*> wrap statementSequence grammar OberonGrammar{..} = OberonGrammar{ module_prod = Module <$ (lexicalWhiteSpace *> keyword "MODULE") <*> ident <* delimiter ";" <*> moptional importList <*> declarationSequence- <*> optional (keyword "BEGIN" *> statementSequence) <* keyword "END" <*> ident <* delimiter ".",+ <*> optional (keyword "BEGIN" *> wrap statementSequence) <* keyword "END" <*> ident <* delimiter ".", ident = identifier, letter = satisfyCharInput isLetter, digit = satisfyCharInput isDigit, importList = keyword "IMPORT" *> sepBy1 import_prod (delimiter ",") <* delimiter ";", import_prod = (,) <$> optional (ident <* delimiter ":=") <*> ident,- declarationSequence = concatMany (keyword "CONST" *> many (constantDeclaration <* delimiter ";")- <|> keyword "TYPE" *> many (typeDeclaration <* delimiter ";")- <|> keyword "VAR" *> many (variableDeclaration <* delimiter ";"))- <> many (procedureDeclaration <* delimiter ";"- <|> forwardDeclaration <* delimiter ";")+ declarationSequence = concatMany (keyword "CONST" *> many (wrap constantDeclaration <* delimiter ";")+ <|> keyword "TYPE" *> many (wrap typeDeclaration <* delimiter ";")+ <|> keyword "VAR" *> many (wrap variableDeclaration <* delimiter ";"))+ <> many (wrap procedureDeclaration <* delimiter ";"+ <|> wrap forwardDeclaration <* delimiter ";") <?> "declarations",- constantDeclaration = ConstantDeclaration <$> identdef <* delimiter "=" <*> ambiguous constExpression,+ constantDeclaration = ConstantDeclaration <$> identdef <* delimiter "=" <*> constExpression, identdef = IdentDef <$> ident <*> (Exported <$ delimiter "*" <|> pure PrivateOnly), constExpression = expression,- expression = simpleExpression <**> (pure id <|> (flip . Relation) <$> relation <*> simpleExpression)+ expression = simpleExpression <**> (pure id <|> (pure .) <$> ((flip . Relation) <$> relation <*> simpleExpression)) <?> "expression",- simpleExpression = (Positive <$ operator "+" <|> Negative <$ operator "-" <|> pure id)- <*> (term <**> (appEndo <$> concatMany (Endo <$> (flip . applyBinOp <$> addOperator <*> term)))),- term = factor <**> (appEndo <$> concatMany (Endo <$> (flip . applyBinOp <$> mulOperator <*> factor))),- factor = number- <|> charConstant- <|> String <$> string_prod- <|> Nil <$ keyword "NIL"- <|> set- <|> Read <$> ambiguous designator- <|> FunctionCall <$> ambiguous designator <*> actualParameters- <|> parens expression- <|> Not <$ operator "~" <*> factor,+ simpleExpression = + (((pure .) <$> (Positive <$ operator "+" <|> Negative <$ operator "-") <|> pure id)+ <*> term)+ <**> (appEndo <$> concatMany (Endo . (pure .) <$> (flip . applyBinOp <$> addOperator <*> term))),+ term = factor <**> (appEndo <$> concatMany (Endo . (pure .) <$> (flip . applyBinOp <$> mulOperator <*> factor))),+ factor = ambiguous (number+ <|> charConstant+ <|> String <$> string_prod+ <|> Nil <$ keyword "NIL"+ <|> set+ <|> Read <$> designator+ <|> FunctionCall <$> designator <*> actualParameters+ <|> Not <$ operator "~" <*> factor)+ <|> parens expression, number = integer <|> real, integer = Integer <$> lexicalToken (digit <> (takeCharsWhile isDigit <|> takeCharsWhile isHexDigit <> string "H")), hexDigit = satisfyCharInput isHexDigit,@@ -200,10 +205,11 @@ <|> CharCode . fst . head . readHex . unpack <$> (digit <> takeCharsWhile isHexDigit <* string "X")), string_prod = lexicalToken (char '"' *> takeWhile (/= "\"") <* char '"'),- set = Set <$> braces (sepBy element (delimiter ",")),- element = Element <$> expression + set = Set <$> braces (sepBy (wrap element) (delimiter ",")),+ element = Element <$> expression <|> Range <$> expression <* delimiter ".." <*> expression,- designator = Variable <$> qualident + designator = ambiguous $+ Variable <$> qualident <|> Field <$> designator <* delimiter "." <*> ident <|> Index <$> designator <*> brackets expList <|> TypeGuard <$> designator <*> parens qualident@@ -217,69 +223,73 @@ <|> Less <$ operator "<" <|> LessOrEqual <$ operator "<=" <|> Greater <$ operator ">" <|> GreaterOrEqual <$ operator ">=" <|> In <$ keyword "IN" <|> Is <$ keyword "IS",- typeDeclaration = TypeDeclaration <$> identdef <* delimiter "=" <*> type_prod,+ typeDeclaration = TypeDeclaration <$> identdef <* delimiter "=" <*> wrap type_prod, type_prod = TypeReference <$> qualident <|> arrayType <|> recordType <|> pointerType <|> procedureType,- qualident = QualIdent <$> ident <* delimiter "." <*> ident + qualident = QualIdent <$> ident <* delimiter "." <*> ident <|> NonQualIdent <$> ident,- arrayType = ArrayType <$ keyword "ARRAY" <*> sepBy1 (ambiguous length) (delimiter ",") <* keyword "OF" <*> type_prod,+ arrayType = ArrayType <$ keyword "ARRAY" <*> sepBy1 length (delimiter ",") <* keyword "OF" <*> wrap type_prod, length = constExpression, recordType = RecordType <$ keyword "RECORD" <*> optional (parens baseType) <*> fieldListSequence <* keyword "END", baseType = qualident,- fieldListSequence = sepByNonEmpty fieldList (delimiter ";"),- fieldList = (FieldList <$> identList <* delimiter ":" <*> type_prod <?> "record field declarations")+ fieldListSequence = sepByNonEmpty (wrap fieldList) (delimiter ";"),+ fieldList = (FieldList <$> identList <* delimiter ":" <*> wrap type_prod <?> "record field declarations") <|> pure EmptyFieldList, identList = sepByNonEmpty identdef (delimiter ","),- pointerType = PointerType <$ keyword "POINTER" <* keyword "TO" <*> type_prod,- procedureType = ProcedureType <$ keyword "PROCEDURE" <*> optional formalParameters,- variableDeclaration = VariableDeclaration <$> identList <* delimiter ":" <*> type_prod,+ pointerType = PointerType <$ keyword "POINTER" <* keyword "TO" <*> wrap type_prod,+ procedureType = ProcedureType <$ keyword "PROCEDURE" <*> optional (wrap formalParameters),+ variableDeclaration = VariableDeclaration <$> identList <* delimiter ":" <*> wrap type_prod, procedureDeclaration = ProcedureDeclaration <$> procedureHeading <* delimiter ";" <*> procedureBody <*> ident, procedureHeading = ProcedureHeading Nothing <$ keyword "PROCEDURE" <*> (True <$ delimiter "*" <|> pure False) - <*> identdef <*> optional formalParameters,- formalParameters = FormalParameters <$> parens (sepBy fPSection (delimiter ";"))+ <*> identdef <*> optional (wrap formalParameters),+ formalParameters = FormalParameters <$> parens (sepBy (wrap fPSection) (delimiter ";")) <*> optional (delimiter ":" *> qualident), fPSection = FPSection <$> (True <$ keyword "VAR" <|> pure False) - <*> sepByNonEmpty ident (delimiter ",") <* delimiter ":" <*> formalType,- formalType = ArrayType [] <$ keyword "ARRAY" <* keyword "OF" <*> formalType - <|> TypeReference <$> qualident - <|> ProcedureType <$ keyword "PROCEDURE" <*> optional formalParameters,- procedureBody = ProcedureBody <$> declarationSequence - <*> optional (keyword "BEGIN" *> statementSequence) <* keyword "END",+ <*> sepByNonEmpty ident (delimiter ",") <* delimiter ":" <*> wrap formalType,+ formalType = ArrayType [] <$ keyword "ARRAY" <* keyword "OF" <*> wrap formalType + <|> TypeReference <$> qualident+ <|> ProcedureType <$ keyword "PROCEDURE" <*> optional (wrap formalParameters),+ procedureBody = ProcedureBody <$> declarationSequence+ <*> optional (keyword "BEGIN" *> wrap statementSequence) <* keyword "END", forwardDeclaration = ForwardDeclaration <$ keyword "PROCEDURE" <* delimiter "^"- <*> identdef <*> optional formalParameters,- statementSequence = sepByNonEmpty (ambiguous statement) (delimiter ";"),+ <*> identdef <*> optional (wrap formalParameters),+ statementSequence = StatementSequence <$> sepByNonEmpty (ambiguous statement) (delimiter ";"), statement = assignment <|> procedureCall <|> ifStatement <|> caseStatement <|> whileStatement <|> repeatStatement <|> loopStatement <|> withStatement <|> Exit <$ keyword "EXIT" <|> Return <$ keyword "RETURN" <*> optional expression <|> pure EmptyStatement <?> "statement",- assignment = Assignment <$> ambiguous designator <* delimiter ":=" <*> expression,- procedureCall = ProcedureCall <$> ambiguous designator <*> optional actualParameters,+ assignment = Assignment <$> designator <* delimiter ":=" <*> expression,+ procedureCall = ProcedureCall <$> designator <*> optional actualParameters, ifStatement = If <$ keyword "IF"- <*> sepByNonEmpty ((,) <$> expression <* keyword "THEN" <*> statementSequence) (keyword "ELSIF")- <*> optional (keyword "ELSE" *> statementSequence) <* keyword "END",+ <*> sepByNonEmpty (wrap $ Deep.Pair <$> expression <* keyword "THEN" <*> wrap statementSequence)+ (keyword "ELSIF")+ <*> optional (keyword "ELSE" *> wrap statementSequence) <* keyword "END", caseStatement = CaseStatement <$ keyword "CASE" <*> expression- <* keyword "OF" <*> sepByNonEmpty case_prod (delimiter "|")- <*> optional (keyword "ELSE" *> statementSequence) <* keyword "END",- case_prod = Case <$> caseLabelList <* delimiter ":" <*> statementSequence+ <* keyword "OF" <*> sepByNonEmpty (wrap case_prod) (delimiter "|")+ <*> optional (keyword "ELSE" *> wrap statementSequence) <* keyword "END",+ case_prod = Case <$> caseLabelList <* delimiter ":" <*> wrap statementSequence <|> pure EmptyCase,- caseLabelList = sepByNonEmpty caseLabels (delimiter ","),- caseLabels = SingleLabel <$> constExpression + caseLabelList = sepByNonEmpty (wrap caseLabels) (delimiter ","),+ caseLabels = SingleLabel <$> constExpression <|> LabelRange <$> constExpression <* delimiter ".." <*> constExpression,- whileStatement = While <$ keyword "WHILE" <*> expression <* keyword "DO" <*> statementSequence <* keyword "END",- repeatStatement = Repeat <$ keyword "REPEAT" <*> statementSequence <* keyword "UNTIL" <*> expression,- loopStatement = Loop <$ keyword "LOOP" <*> statementSequence <* keyword "END",+ whileStatement = While <$ keyword "WHILE" <*> expression <* keyword "DO"+ <*> wrap statementSequence <* keyword "END",+ repeatStatement = Repeat <$ keyword "REPEAT" <*> wrap statementSequence <* keyword "UNTIL" <*> expression,+ loopStatement = Loop <$ keyword "LOOP" <*> wrap statementSequence <* keyword "END", forStatement = empty, withStatement = With <$ keyword "WITH" <*> ((:| [])- <$> (WithAlternative <$> qualident <* delimiter ":" <*> qualident- <* keyword "DO" <*> statementSequence))+ <$> wrap (WithAlternative <$> qualident <* delimiter ":" <*> qualident+ <* keyword "DO" <*> wrap statementSequence)) <*> pure Nothing <* keyword "END"}++wrap = ambiguous moptional p = p <|> mempty
src/Language/Oberon/Pretty.hs view
@@ -8,12 +8,14 @@ import Data.Functor.Identity (Identity(..)) import Data.List (intersperse) import Data.List.NonEmpty (NonEmpty((:|)), fromList, toList)+import qualified Data.Text as Text import Data.Text.Prettyprint.Doc import Numeric (showHex)+import Transformation.Deep as Deep (Product(Pair)) import Language.Oberon.AST -instance Pretty (Module Identity) where+instance Pretty (Module Identity Identity) where pretty (Module name imports declarations body name') = vsep $ intersperse mempty $ ["MODULE" <+> pretty name <> semi,@@ -25,7 +27,7 @@ where prettyImport (Nothing, mod) = pretty mod prettyImport (Just inner, mod) = pretty inner <> ":=" <+> pretty mod -instance Pretty (Declaration Identity) where+instance Pretty (Declaration Identity Identity) where pretty (ConstantDeclaration ident (Identity expr)) = "CONST" <+> pretty ident <+> "=" <+> pretty expr <> semi pretty (TypeDeclaration ident typeDef) = "TYPE" <+> pretty ident <+> "=" <+> pretty typeDef <> semi pretty (VariableDeclaration idents varType) =@@ -40,31 +42,35 @@ pretty (IdentDef name ReadOnly) = pretty name <> "-" pretty (IdentDef name PrivateOnly) = pretty name -instance Pretty (Expression Identity) where+instance Pretty (Expression Identity Identity) where pretty = prettyPrec 0- where prettyPrec 0 (Relation op left right) = prettyPrec 1 left <+> pretty op <+> prettyPrec 1 right- prettyPrec p (Positive e) | p < 2 = "+" <> prettyPrec 2 e- prettyPrec p (Negative e) | p < 2 = "-" <> prettyPrec 2 e- prettyPrec p (Add left right) | p < 3 = prettyPrec 3 left <> "+" <> prettyPrec 3 right- prettyPrec p (Subtract left right) | p < 3 = prettyPrec 3 left <> "-" <> prettyPrec 3 right- prettyPrec p (Or left right) | p < 3 = prettyPrec 3 left <+> "OR" <+> prettyPrec 3 right- prettyPrec p (Multiply left right) | p < 4 = prettyPrec 4 left <> "*" <> prettyPrec 4 right- prettyPrec p (Divide left right) | p < 4 = prettyPrec 4 left <> "/" <> prettyPrec 4 right- prettyPrec p (IntegerDivide left right) | p < 4 = prettyPrec 4 left <+> "DIV" <+> prettyPrec 4 right- prettyPrec p (Modulo left right) | p < 4 = prettyPrec 4 left <+> "MOD" <+> prettyPrec 4 right- prettyPrec p (And left right) | p < 4 = prettyPrec 4 left <+> "&" <+> prettyPrec 4 right+ where prettyPrec 0 (Relation op left right) = prettyPrec' 1 left <+> pretty op <+> prettyPrec' 1 right+ prettyPrec p (Positive e) | p < 2 = "+" <> prettyPrec' 2 e+ prettyPrec p (Negative e) | p < 2 = "-" <> prettyPrec' 2 e+ prettyPrec p (Add left right) | p < 3 = prettyPrec' 3 left <> "+" <> prettyPrec' 3 right+ prettyPrec p (Subtract left right) | p < 3 = prettyPrec' 3 left <> "-" <> prettyPrec' 3 right+ prettyPrec p (Or left right) | p < 3 = prettyPrec' 3 left <+> "OR" <+> prettyPrec' 3 right+ prettyPrec p (Multiply left right) | p < 4 = prettyPrec' 4 left <> "*" <> prettyPrec' 4 right+ prettyPrec p (Divide left right) | p < 4 = prettyPrec' 4 left <> "/" <> prettyPrec' 4 right+ prettyPrec p (IntegerDivide left right) | p < 4 = prettyPrec' 4 left <+> "DIV" <+> prettyPrec' 4 right+ prettyPrec p (Modulo left right) | p < 4 = prettyPrec' 4 left <+> "MOD" <+> prettyPrec' 4 right+ prettyPrec p (And left right) | p < 4 = prettyPrec' 4 left <+> "&" <+> prettyPrec' 4 right prettyPrec _ (Integer n) = pretty n prettyPrec _ (Real r) = pretty r+ prettyPrec _ (CharConstant c@'"') = squotes (pretty c) prettyPrec _ (CharConstant c) = dquotes (pretty c) prettyPrec _ (CharCode c) = "0" <> pretty (showHex c "") <> "X"- prettyPrec _ (String s) = dquotes (pretty s)+ prettyPrec _ (String s)+ | Text.any (== '"') s = squotes (pretty s)+ | otherwise = dquotes (pretty s) prettyPrec _ Nil = "NIL" prettyPrec _ (Set elements) = braces (hsep $ punctuate comma $ pretty <$> elements) prettyPrec _ (Read (Identity var)) = pretty var prettyPrec _ (FunctionCall (Identity fun) parameters) = pretty fun <> parens (hsep $ punctuate comma $ pretty <$> parameters)- prettyPrec p (Not e) | p < 5 = "~" <> prettyPrec 5 e+ prettyPrec p (Not e) | p < 5 = "~" <> prettyPrec' 5 e prettyPrec p e = parens (prettyPrec 0 e)+ prettyPrec' p (Identity e) = prettyPrec p e instance Pretty RelOp where pretty Equal = "="@@ -76,18 +82,18 @@ pretty In = "IN" pretty Is = "IS" -instance Pretty (Element Identity) where+instance Pretty (Element Identity Identity) where pretty (Element e) = pretty e pretty (Range from to) = pretty from <+> ".." <+> pretty to -instance Pretty (Designator Identity) where+instance Pretty (Designator Identity Identity) where pretty (Variable q) = pretty q pretty (Field record name) = pretty record <> dot <> pretty name pretty (Index array indexes) = pretty array <> brackets (hsep $ punctuate comma $ pretty <$> toList indexes) pretty (TypeGuard scrutinee typeName) = pretty scrutinee <> parens (pretty typeName) pretty (Dereference pointer) = pretty pointer <> "^" -instance Pretty (Type Identity) where+instance Pretty (Type Identity Identity) where pretty (TypeReference q) = pretty q pretty (ArrayType dimensions itemType) = "ARRAY" <+> hsep (punctuate comma $ pretty . runIdentity <$> dimensions) <+> "OF" <+> pretty itemType@@ -101,11 +107,11 @@ pretty (QualIdent moduleName memberName) = pretty moduleName <> "." <> pretty memberName pretty (NonQualIdent localName) = pretty localName -instance Pretty (FieldList Identity) where+instance Pretty (FieldList Identity Identity) where pretty (FieldList names t) = hsep (punctuate comma $ pretty <$> toList names) <+> ":" <+> pretty t pretty EmptyFieldList = mempty -instance Pretty (ProcedureHeading Identity) where+instance Pretty (ProcedureHeading Identity Identity) where pretty (ProcedureHeading receiver indirect ident parameters) = "PROCEDURE" <> (if indirect then "* " else space) <> foldMap prettyReceiver receiver <> pretty ident <> pretty parameters@@ -113,21 +119,23 @@ <> pretty name <> colon <+> pretty t) <> space -instance Pretty (FormalParameters Identity) where+instance Pretty (FormalParameters Identity Identity) where pretty (FormalParameters sections result) =- prettyList sections <> foldMap (colon <+>) (pretty <$> result)+ lparen <> hsep (punctuate semi $ pretty <$> sections) <> rparen <> foldMap (colon <+>) (pretty <$> result) -instance Pretty (FPSection Identity) where- prettyList sections = lparen <> hsep (punctuate semi $ pretty <$> sections) <> rparen+instance Pretty (FPSection Identity Identity) where pretty (FPSection var names t) = (if var then ("VAR" <+>) else id) $ hsep (punctuate comma $ pretty <$> toList names) <+> colon <+> pretty t -instance Pretty (ProcedureBody Identity) where+instance Pretty (ProcedureBody Identity Identity) where pretty (ProcedureBody declarations body) = vsep ((indent 3 . pretty <$> declarations) ++ foldMap (\statements-> ["BEGIN", prettyBlock statements]) body) -instance Pretty (Statement Identity) where+instance Pretty (StatementSequence Identity Identity) where+ pretty (StatementSequence statements) = pretty (runIdentity <$> statements)++instance Pretty (Statement Identity Identity) where prettyList l = vsep (dropEmptyTail $ punctuate semi $ pretty <$> l) where dropEmptyTail | not (null l), EmptyStatement <- last l = init@@ -140,10 +148,12 @@ : (branch "ELSIF" <$> elsifs) ++ foldMap (\x-> ["ELSE", prettyBlock x]) fallback ++ ["END"])- where branch kwd (condition, body) = vsep [kwd <+> pretty condition <+> "THEN",- prettyBlock body]+ where branch kwd (Identity (Deep.Pair (Identity condition) (Identity body))) =+ vsep [kwd <+> pretty condition <+> "THEN",+ prettyBlock (Identity body)] pretty (CaseStatement scrutinee cases fallback) = vsep ["CASE" <+> pretty scrutinee <+> "OF",- pretty cases,+ align (encloseSep mempty mempty "| "+ $ pretty <$> toList cases), foldMap ("ELSE" <#>) (prettyBlock <$> fallback), "END"] @@ -168,18 +178,20 @@ pretty Exit = "EXIT" pretty (Return result) = "RETURN" <+> foldMap pretty result -instance Pretty (Case Identity) where- pretty (Case labels body) = vsep ["|" <+> pretty labels <+> colon,+instance Pretty (Case Identity Identity) where+ pretty (Case labels body) = vsep [hsep (punctuate comma (pretty <$> toList labels)) <+> colon, prettyBlock body] pretty EmptyCase = mempty -instance Pretty (WithAlternative Identity) where+instance Pretty (WithAlternative Identity Identity) where pretty (WithAlternative name t body) = vsep [pretty name <+> colon <+> pretty t <+> "DO", prettyBlock body] -instance Pretty (CaseLabels Identity) where+instance Pretty (CaseLabels Identity Identity) where pretty (SingleLabel expression) = pretty expression pretty (LabelRange from to) = pretty from <+> ".." <+> pretty to -prettyBlock statements = indent 3 (pretty $ runIdentity <$> statements)+prettyBlock :: Identity (StatementSequence Identity Identity) -> Doc ann+prettyBlock (Identity (StatementSequence statements)) = indent 3 (pretty $ runIdentity <$> statements)+ a <#> b = vsep [a, b]
src/Language/Oberon/Resolver.hs view
@@ -1,4 +1,6 @@-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleContexts, FlexibleInstances, KindSignatures, MultiParamTypeClasses,+ OverloadedStrings, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, UndecidableInstances #-}+{-# OPTIONS_GHC -Wno-simplifiable-class-constraints #-} -- | This module exports functions for resolving the syntactic ambiguities in a parsed module. For example, an Oberon -- expression @foo(bar)@ may be a call to function @foo@ with a parameter @bar@, or it may be type guard on variable@@ -9,8 +11,10 @@ import Control.Applicative (Alternative) import Control.Monad ((>=>))+import Control.Monad.Trans.State (StateT(..), evalStateT) import Data.Either (partitionEithers) import Data.Either.Validation (Validation(..), validationToEither)+import Data.Foldable (toList) import Data.Functor.Identity (Identity(..)) import Data.List.NonEmpty (NonEmpty(..)) import qualified Data.List.NonEmpty as NonEmpty@@ -20,304 +24,234 @@ import qualified Data.Map.Lazy as Map import Data.Semigroup (Semigroup(..), sconcat) +import qualified Rank2.TH+import qualified Transformation as Shallow+import qualified Transformation.Deep as Deep+import qualified Transformation.Deep.TH+import qualified Transformation.Rank2 as Rank2 import Text.Grampa (Ambiguous(..), ParseFailure) import Language.Oberon.AST -data DeclarationRHS f = DeclaredConstant (f (ConstExpression f))- | DeclaredType (Type f)- | DeclaredVariable (Type f)- | DeclaredProcedure Bool (Maybe (FormalParameters f))+data DeclarationRHS f' f = DeclaredConstant (f (ConstExpression f' f'))+ | DeclaredType (f (Type f' f'))+ | DeclaredVariable (f (Type f' f'))+ | DeclaredProcedure Bool (Maybe (f (FormalParameters f' f')))+deriving instance Show (DeclarationRHS Identity Identity)+deriving instance Show (DeclarationRHS Ambiguous Ambiguous) --- | All possible resultion errors-data Error = UnknownModule Ident+-- | All possible resolution errors+data Error = UnknownModule QualIdent | UnknownLocal Ident | UnknownImport QualIdent | AmbiguousParses- | AmbiguousDesignator [Designator Identity]- | AmbiguousExpression [Expression Identity]- | AmbiguousStatement [Statement Identity]- | InvalidDesignator (NonEmpty Error)+ | AmbiguousDeclaration [Declaration Ambiguous Ambiguous]+ | AmbiguousDesignator [Designator Ambiguous Ambiguous]+ | AmbiguousExpression [Expression Ambiguous Ambiguous]+ | AmbiguousRecord [Designator Ambiguous Ambiguous]+ | AmbiguousStatement [Statement Ambiguous Ambiguous] | InvalidExpression (NonEmpty Error)+ | InvalidFunctionParameters [Ambiguous (Expression Ambiguous Ambiguous)]+ | InvalidRecord (NonEmpty Error) | InvalidStatement (NonEmpty Error)- | NotAProcedure QualIdent | NotARecord QualIdent | NotAType QualIdent- | NotATypeDesignator (Designator Ambiguous) | NotAValue QualIdent- | NotWriteable QualIdent | ClashingImports | UnparseableModule ParseFailure deriving (Show) -type Scope = Predefined+type Scope = Map Ident (Validation (NonEmpty Error) (DeclarationRHS Identity Identity)) --- | A set of 'Predefined' declarations.-type Predefined = Map Ident (Validation (NonEmpty Error) (DeclarationRHS Identity))+-- | A set of predefined declarations.+type Predefined = Scope --- | Eliminate the ambiguites in the given map of module names to their parsed syntax trees. The first argument is a set--- of 'Predefined' declarations, such as 'predefined' or 'predefined2'.-resolveModules :: Predefined -> Map Ident (Module Ambiguous)- -> Validation (NonEmpty (Ident, NonEmpty Error)) (Map Ident (Module Identity))-resolveModules predefinedScope modules = traverseWithKey extractErrors modules'- where modules' = resolveModule predefinedScope modules' <$> modules- extractErrors moduleKey (Failure e) = Failure ((moduleKey, e) :| [])- extractErrors _ (Success mod) = Success mod+data Resolution = Resolution{_modules :: Map Ident Scope} --- | Eliminate the ambiguites in the parsed syntax tree of a single module. The first argument is a set of 'Predefined'--- declarations, such as 'predefined' or 'predefined2'. The second is a mapping of imported module names to their--- already resolved syntax trees.-resolveModule :: Predefined -> Map Ident (Validation (NonEmpty Error) (Module Identity)) -> Module Ambiguous- -> Validation (NonEmpty Error) (Module Identity)-resolveModule predefinedScope modules (Module moduleName imports declarations body name') = module'- where moduleExports :: Map Ident Scope- moduleGlobals :: Map Ident (AccessMode, Validation (NonEmpty Error) (DeclarationRHS Identity))- importedModules :: Map Ident (Validation (NonEmpty Error) (Module Identity))- resolveBinding :: Scope -> DeclarationRHS Ambiguous- -> Validation (NonEmpty Error) (DeclarationRHS Identity)- resolveDeclaration :: Scope -> Declaration Ambiguous -> Validation (NonEmpty Error) (Declaration Identity)- resolveType :: Scope -> Type Ambiguous -> Validation (NonEmpty Error) (Type Identity)- resolveFields :: Scope -> FieldList Ambiguous -> Validation (NonEmpty Error) (FieldList Identity)- resolveStatements :: Scope -> StatementSequence Ambiguous- -> Validation (NonEmpty Error) (StatementSequence Identity)- resolveStatement :: Scope -> Statement Ambiguous -> Validation (NonEmpty Error) (Statement Identity)- resolveExpression :: Scope -> Expression Ambiguous -> Validation (NonEmpty Error) (Expression Identity)- resolveElement :: Scope -> Element Ambiguous -> Validation (NonEmpty Error) (Element Identity)- resolveDesignator, resolveWriteable, resolveProcedure, resolveRecord, resolvePointer- :: Scope -> Designator Ambiguous -> Validation (NonEmpty Error) (Designator Identity)- resolveName :: Scope -> QualIdent -> Validation (NonEmpty Error) (DeclarationRHS Identity)- resolveTypeName :: Scope -> QualIdent -> Validation (NonEmpty Error) QualIdent+type Resolved = StateT (Scope, ResolutionState) (Validation (NonEmpty Error)) - module' = Module moduleName imports- <$> traverse (resolveDeclaration moduleGlobalScope) declarations- <*> traverse (resolveStatements moduleGlobalScope) body- <*> pure name'- importedModules = Map.delete mempty (Map.mapKeysWith clashingRenames importedAs modules)- where importedAs moduleName = case List.find ((== moduleName) . snd) imports- of Just (Nothing, moduleKey) -> moduleKey- Just (Just innerKey, _) -> innerKey- Nothing -> mempty- clashingRenames _ _ = Failure (ClashingImports :| [])+data ResolutionState = ModuleState+ | DeclarationState+ | StatementState+ | ExpressionState+ | ExpressionOrTypeState+ deriving (Eq, Show) - moduleExports = foldMap exportsOfModule <$> importedModules- moduleGlobals = (resolveBinding moduleGlobalScope <$>)- <$> Map.fromList (concatMap (declarationBinding moduleName) declarations)- moduleGlobalScope = Map.union (snd <$> moduleGlobals) predefinedScope+instance Monad (Validation (NonEmpty Error)) where+ Success s >>= f = f s+ Failure errors >>= _ = Failure errors - resolveDeclaration scope (ConstantDeclaration name (Ambiguous expr)) =- ConstantDeclaration name . Identity <$> uniqueExpression (resolveExpression scope <$> expr)- resolveDeclaration scope (TypeDeclaration name typeDef) =- TypeDeclaration name <$> resolveType scope typeDef- resolveDeclaration scope (VariableDeclaration name typeDef) =- VariableDeclaration name <$> resolveType scope typeDef- resolveDeclaration scope (ProcedureDeclaration head (ProcedureBody declarations statements) name) =- ProcedureDeclaration <$> resolveHeading head- <*> (ProcedureBody <$> sequenceA declarations'- <*> (traverse (resolveStatements scope'') statements))- <*> pure name- where scope'' = Map.union (resolveBinding scope . snd <$> Map.fromList declarationBindings) scope'- scope' = Map.union (headBindings head) scope- headBindings (ProcedureHeading receiver indirect name parameters) =- Map.union (foldMap receiverBinding receiver) (foldMap parametersBinding parameters)- receiverBinding (_, name, t) =- Map.singleton name (DeclaredVariable <$> resolveType scope (TypeReference $ NonQualIdent t))- parametersBinding (FormalParameters sections _return) = foldMap sectionBinding sections- sectionBinding (FPSection var names t) = foldMap parameterBinding names- where parameterBinding name = Map.singleton name (DeclaredVariable <$> resolveType scope t)- - declarationBindings = concatMap (declarationBinding moduleName) declarations- declarations' = resolveDeclaration scope'' <$> declarations- resolveHeading (ProcedureHeading receiver indirect name parameters) =- ProcedureHeading receiver indirect name <$> traverse (resolveParameters scope) parameters- resolveDeclaration scope (ForwardDeclaration name parameters) =- ForwardDeclaration name <$> traverse (resolveParameters scope) parameters+instance Shallow.Functor Resolution Ambiguous Resolved (Module Resolved Resolved) where+ (<$>) = mapResolveDefault - resolveType scope (TypeReference name) = pure (TypeReference name)- resolveType scope (ArrayType dimensions itemType) =- ArrayType <$> (traverse (fmap Identity . uniqueExpression . (resolveExpression scope <$>) . unA) dimensions)- <*> resolveType scope itemType- where unA (Ambiguous a) = a- resolveType scope (RecordType baseType fields) = RecordType baseType <$> traverse (resolveFields scope) fields- resolveType scope (PointerType baseType) = PointerType <$> resolveType scope baseType- resolveType scope (ProcedureType parameters) = ProcedureType <$> traverse (resolveParameters scope) parameters+instance {-# overlappable #-} Show (g Identity Identity) =>+ Shallow.Traversable Resolution Ambiguous Identity Resolved (g Identity Identity) where+ traverse = traverseResolveDefault - resolveFields scope (FieldList names fieldType) = FieldList names <$> resolveType scope fieldType- resolveFields scope EmptyFieldList = pure EmptyFieldList+instance {-# overlappable #-} Show (g Ambiguous Ambiguous) =>+ Shallow.Traversable Resolution Ambiguous Identity Resolved (g Ambiguous Ambiguous) where+ traverse = traverseResolveDefault - resolveParameters scope (FormalParameters sections result) =- FormalParameters <$> traverse resolveSection sections <*> pure result- where resolveSection (FPSection var names t) = FPSection var names <$> resolveType scope t+instance {-# overlaps #-} Shallow.Traversable+ Resolution Ambiguous Identity Resolved (Designator Ambiguous Ambiguous) where+ traverse res (Ambiguous designators) = StateT $ \s@(scope, state)->+ case partitionEithers (NonEmpty.toList (validationToEither . resolveDesignator res scope state <$> designators))+ of (_, [x]) -> Success (Identity x, s)+ (errors, []) -> Failure (sconcat $ NonEmpty.fromList errors)+ (_, multi) -> Failure (AmbiguousDesignator multi :| []) - resolveStatements scope = traverse (fmap Identity . resolveOne)- where resolveOne :: Ambiguous (Statement Ambiguous) -> Validation (NonEmpty Error) (Statement Identity)- resolveOne (Ambiguous statements) = uniqueStatement (resolveStatement scope <$> statements)+instance {-# overlaps #-} Shallow.Traversable+ Resolution Ambiguous Identity Resolved (Expression Ambiguous Ambiguous) where+ traverse res expressions = StateT $ \s@(scope, state)->+ let resolveExpression :: Expression Ambiguous Ambiguous+ -> Validation (NonEmpty Error) (Expression Ambiguous Ambiguous, ResolutionState)+ resolveExpression e@(Read designators) =+ case evalStateT (Shallow.traverse res designators) s+ of Failure errors -> Failure errors+ Success{} -> pure (e, state)+ resolveExpression e@(FunctionCall functions parameters) =+ case evalStateT (Shallow.traverse res functions) s+ of Failure errors -> Failure errors+ Success (Identity d)+ | Variable q <- d, Success (DeclaredProcedure True _) <- resolveName res scope q+ -> pure (e, ExpressionOrTypeState)+ | Success{} <- evalStateT (traverse (Shallow.traverse res) parameters) (scope, ExpressionState)+ -> pure (e, ExpressionState)+ | otherwise -> Failure (pure $ InvalidFunctionParameters parameters)+ resolveExpression e@(Relation Is lefts rights) = pure (e, ExpressionOrTypeState)+ resolveExpression e = pure (e, state)+ in (\(r, s)-> (Identity r, (scope, s)))+ <$> unique InvalidExpression (AmbiguousExpression . (fst <$>)) (resolveExpression <$> expressions) - resolveStatement _ EmptyStatement = pure EmptyStatement- resolveStatement scope (Assignment (Ambiguous designators) exp) =- Assignment <$> (Identity <$> uniqueDesignator (resolveWriteable scope <$> designators))- <*> resolveExpression scope exp- resolveStatement scope (ProcedureCall (Ambiguous designators) parameters) =- ProcedureCall <$> (Identity <$> uniqueDesignator (resolveProcedure scope <$> designators))- <*> (traverse . traverse) (resolveExpression scope) parameters- resolveStatement scope (If branches fallback) =- If <$> traverse resolveBranch branches <*> traverse (resolveStatements scope) fallback- where resolveBranch (condition, action) = (,) <$> resolveExpression scope condition- <*> resolveStatements scope action- resolveStatement scope (CaseStatement expression cases fallback) =- CaseStatement <$> resolveExpression scope expression- <*> traverse resolveCase cases- <*> traverse (resolveStatements scope) fallback- where resolveCase (Case caseLabels action) =- Case <$> traverse resolveLabels caseLabels <*> resolveStatements scope action- resolveCase EmptyCase = pure EmptyCase- resolveLabels (SingleLabel expression) = SingleLabel <$> resolveExpression scope expression- resolveLabels (LabelRange low high) =- LabelRange <$> resolveExpression scope low <*> resolveExpression scope high- resolveStatement scope (While condition body) =- While <$> resolveExpression scope condition <*> resolveStatements scope body- resolveStatement scope (Repeat body condition) =- Repeat <$> resolveStatements scope body <*> resolveExpression scope condition- resolveStatement scope (For index from to by body) =- For index <$> resolveExpression scope from <*> resolveExpression scope to - <*> traverse (resolveExpression scope) by <*> resolveStatements scope body- resolveStatement scope (Loop body) = Loop <$> resolveStatements scope body- resolveStatement scope (With alternatives fallback) = With <$> traverse resolveAlt alternatives- <*> traverse (resolveStatements scope) fallback- where resolveAlt (WithAlternative name t action) =- WithAlternative name t <$> resolveStatements scope action- resolveStatement scope Exit = pure Exit- resolveStatement scope (Return expression) = Return <$> traverse (resolveExpression scope) expression+instance {-# overlaps #-} Shallow.Traversable+ Resolution Ambiguous Identity Resolved (Declaration Ambiguous Ambiguous) where+ traverse res (Ambiguous (proc@(ProcedureDeclaration heading body _) :| [])) =+ StateT $ \s@(scope, state)->+ let ProcedureHeading receiver _indirect _name parameters = heading+ ProcedureBody declarations statements = body+ innerScope = localScope res "" declarations (parameterScope `Map.union` receiverScope `Map.union` scope)+ receiverScope = maybe mempty receiverBinding receiver+ receiverBinding (_, name, ty) = Map.singleton name (Success $ DeclaredVariable $ pure $ TypeReference+ $ NonQualIdent ty)+ parameterScope = case parameters+ of Nothing -> mempty+ Just (Ambiguous (FormalParameters sections _ :| []))+ -> Map.fromList (concatMap binding sections)+ binding (Ambiguous (FPSection _ names types :| [])) =+ [(v, evalStateT (Deep.traverseDown res $ DeclaredVariable types) s) | v <- NonEmpty.toList names]+ in Success (Identity proc, (innerScope, state))+ traverse res (Ambiguous (dec :| [])) = pure (Identity dec)+ traverse _ declarations = StateT (const $ Failure $ pure $ AmbiguousDeclaration $ toList declarations) - resolveExpression scope (Relation Is left (Read (Ambiguous rights))) =- Relation Is <$> resolveExpression scope left- <*> (typeToValue <$> sconcat (designatorToType <$> rights))- where typeToValue (TypeReference n) = Read (Identity (Variable n))- designatorToType (Variable q) = resolveType scope (TypeReference q)- designatorToType d = Failure (NotATypeDesignator d :| [])- resolveExpression scope (Relation op left right) =- Relation op <$> resolveExpression scope left <*> resolveExpression scope right- resolveExpression scope (Positive e) = Positive <$> resolveExpression scope e- resolveExpression scope (Negative e) = Negative <$> resolveExpression scope e- resolveExpression scope (Add left right) =- Add <$> resolveExpression scope left <*> resolveExpression scope right- resolveExpression scope (Subtract left right) =- Subtract <$> resolveExpression scope left <*> resolveExpression scope right- resolveExpression scope (Or left right) =- Or <$> resolveExpression scope left <*> resolveExpression scope right- resolveExpression scope (Multiply left right) =- Multiply <$> resolveExpression scope left <*> resolveExpression scope right- resolveExpression scope (Divide left right) =- Divide <$> resolveExpression scope left <*> resolveExpression scope right- resolveExpression scope (IntegerDivide left right) =- IntegerDivide <$> resolveExpression scope left <*> resolveExpression scope right- resolveExpression scope (Modulo left right) = - Modulo <$> resolveExpression scope left <*> resolveExpression scope right- resolveExpression scope (And left right) =- And <$> resolveExpression scope left <*> resolveExpression scope right- resolveExpression scope (Integer x) = pure (Integer x)- resolveExpression scope (Real x) = pure (Real x)- resolveExpression scope (CharConstant x) = pure (CharConstant x)- resolveExpression scope (CharCode x) = pure (CharCode x)- resolveExpression scope (String x) = pure (String x)- resolveExpression scope Nil = pure Nil- resolveExpression scope (Set elements) = Set <$> traverse (resolveElement scope) elements- resolveExpression scope (Read (Ambiguous designators)) =- Read . Identity <$> uniqueDesignator (resolveDesignator scope <$> designators)- resolveExpression scope (FunctionCall (Ambiguous functions) parameters)- | Success (Variable q) <- uniqueDesignator (resolveProcedure scope <$> functions),- Success (DeclaredProcedure True _) <- resolveName scope q =- FunctionCall (Identity $ Variable q)- <$> traverse (resolveExpressionOrType scope) parameters- | otherwise =- FunctionCall . Identity- <$> uniqueDesignator (resolveProcedure scope <$> functions)- <*> traverse (resolveExpression scope) parameters- resolveExpression scope (Not e) = Negative <$> resolveExpression scope e+instance {-# overlaps #-} Shallow.Traversable+ Resolution Ambiguous Identity Resolved (ProcedureBody Ambiguous Ambiguous) where+ traverse res (Ambiguous (body@(ProcedureBody declarations statements) :| [])) = StateT $ \(scope, state)->+ Success (Identity body, (localScope res "" declarations scope, state))+ traverse _ b = StateT (const $ Failure $ pure AmbiguousParses) - resolveExpressionOrType scope (Read (Ambiguous designators)) =- Read . Identity <$> uniqueDesignator (resolveDesignatorOrType scope <$> designators)- resolveExpressionOrType scope e = resolveExpression scope e+instance {-# overlaps #-} Shallow.Traversable+ Resolution Ambiguous Identity Resolved (Statement Ambiguous Ambiguous) where+ traverse res statements = StateT $ \s@(scope, state)->+ let resolveStatement :: Statement Ambiguous Ambiguous+ -> Validation (NonEmpty Error) (Statement Ambiguous Ambiguous, ResolutionState)+ resolveStatement p@(ProcedureCall procedures parameters) =+ case evalStateT (Shallow.traverse res procedures) s+ of Failure errors -> Failure errors+ Success{} -> pure (p, StatementState)+ resolveStatement stat = pure (stat, StatementState)+ in (\(r, s)-> (Identity r, (scope, s)))+ <$> unique InvalidStatement (AmbiguousStatement . (fst <$>)) (resolveStatement <$> statements) - resolveDesignatorOrType scope (Variable q)- | Success DeclaredType{} <- resolveName scope q = Success (Variable q)- resolveDesignatorOrType scope e = resolveDesignator scope e+mapResolveDefault :: Resolution -> Ambiguous (g Resolved Resolved) -> Resolved (g Resolved Resolved)+mapResolveDefault Resolution{} (Ambiguous (x :| [])) = pure x+mapResolveDefault Resolution{} _ = StateT (const $ Failure $ pure AmbiguousParses) - resolveElement scope (Element e) = Element <$> resolveExpression scope e- resolveElement scope (Range left right) =- Range <$> resolveExpression scope left <*> resolveExpression scope right+traverseResolveDefault :: Show (g f f) => Resolution -> Ambiguous (g (f :: * -> *) f) -> Resolved (Identity (g f f))+traverseResolveDefault Resolution{} (Ambiguous (x :| [])) = StateT (\s-> Success (Identity x, s))+traverseResolveDefault Resolution{} x@(Ambiguous _) = StateT (const $ Failure $ pure AmbiguousParses) - resolveDesignator scope (Variable q) =- case resolveName scope q+resolveDesignator :: Resolution -> Scope -> ResolutionState -> Designator Ambiguous Ambiguous+ -> Validation (NonEmpty Error) (Designator Ambiguous Ambiguous)+resolveDesignator res scope state = resolveDesignator'+ where resolveTypeName :: QualIdent -> Validation (NonEmpty Error) QualIdent+ resolveDesignator' (Variable q) =+ case resolveName res scope q of Failure err -> Failure err- Success DeclaredType{} -> Failure (NotAValue q :| [])+ Success DeclaredType{} | state /= ExpressionOrTypeState -> Failure (NotAValue q :| []) Success _ -> Success (Variable q)- resolveDesignator scope (Field record field) = Field <$> resolveRecord scope record <*> pure field- resolveDesignator scope (Index array indexes) = Index <$> resolveArray scope array- <*> traverse (resolveExpression scope) indexes- resolveDesignator scope (TypeGuard designator subtype) = TypeGuard <$> resolveRecord scope designator- <*> resolveTypeName scope subtype- resolveDesignator scope (Dereference pointer) = Dereference <$> resolvePointer scope pointer+ resolveDesignator' d@(Field records field) =+ case evalStateT (Shallow.traverse res records) (scope, state)+ of Failure errors -> Failure errors+ Success{} -> pure d+ resolveDesignator' (TypeGuard records subtypes) =+ case unique InvalidRecord AmbiguousRecord (resolveRecord <$> records)+ of Failure errors -> Failure errors+ Success{} -> TypeGuard records <$> resolveTypeName subtypes+ resolveDesignator' d@(Dereference pointers) =+ case evalStateT (Shallow.traverse res pointers) (scope, state)+ of Failure errors -> Failure errors+ Success{} -> pure d+ resolveDesignator' d = pure d+ resolveRecord d@(Variable q) =+ case resolveName res scope q+ of Failure err -> Failure err+ Success DeclaredType{} -> Failure (NotAValue q :| [])+ Success DeclaredProcedure{} -> Failure (NotARecord q :| [])+ Success (DeclaredVariable t) -> resolveDesignator' d+ resolveRecord d = resolveDesignator' d - resolveTypeName scope q =- case resolveName scope q+ resolveTypeName q =+ case resolveName res scope q of Failure err -> Failure err Success DeclaredType{} -> Success q Success _ -> Failure (NotAType q :| []) - resolveBaseType scope t = case resolveType scope t- of Failure err -> Failure err- Success t' -> resolveTypeReference scope t'-- resolveProcedure scope d@(Variable q) =- case resolveName scope q- of Failure err -> Failure err- Success DeclaredType{} -> Failure (NotAValue q :| [])- Success DeclaredProcedure{} -> resolveDesignator scope d- Success (DeclaredVariable t)- | Success ProcedureType{} <- resolveTypeReference scope t -> resolveDesignator scope d- | otherwise -> Failure (NotAProcedure q :| [])- resolveProcedure scope d = resolveDesignator scope d+resolveName :: Resolution -> Scope -> QualIdent -> Validation (NonEmpty Error) (DeclarationRHS Identity Identity)+resolveName res scope q@(QualIdent moduleName name) =+ case Map.lookup moduleName (_modules res)+ of Nothing -> Failure (UnknownModule q :| [])+ Just exports -> case Map.lookup name exports+ of Just rhs -> rhs+ Nothing -> Failure (UnknownImport q :| [])+resolveName res scope (NonQualIdent name) =+ case Map.lookup name scope+ of Just (Success rhs) -> Success rhs+ _ -> Failure (UnknownLocal name :| []) - resolveWriteable scope d@(Variable q) =- case resolveName scope q- of Failure err -> Failure err- Success DeclaredType{} -> Failure (NotAValue q :| [])- Success DeclaredProcedure{} -> Failure (NotWriteable q :| [])- Success DeclaredConstant{} -> Failure (NotWriteable q :| [])- Success DeclaredVariable{} -> resolveDesignator scope d- resolveWriteable scope d = resolveDesignator scope d+resolveModules :: Predefined -> Map Ident (Module Ambiguous Ambiguous)+ -> Validation (NonEmpty (Ident, NonEmpty Error)) (Map Ident (Module Identity Identity))+resolveModules predefinedScope modules = traverseWithKey extractErrors modules'+ where modules' = resolveModule predefinedScope modules' <$> modules+ extractErrors moduleKey (Failure e) = Failure ((moduleKey, e) :| [])+ extractErrors _ (Success mod) = Success mod - resolveRecord scope d@(Variable q) =- case resolveName scope q- of Failure err -> Failure err- Success DeclaredType{} -> Failure (NotAValue q :| [])- Success DeclaredProcedure{} -> Failure (NotAValue q :| [])- Success (DeclaredVariable t) -> resolveDesignator scope d- resolveRecord scope d = resolveDesignator scope d+resolveModule :: Scope -> Map Ident (Validation (NonEmpty Error) (Module Identity Identity))+ -> Module Ambiguous Ambiguous -> Validation (NonEmpty Error) (Module Identity Identity)+resolveModule predefined modules m@(Module moduleName imports declarations body _) =+ evalStateT (Deep.traverseDown res m) (moduleGlobalScope, ModuleState)+ where res = Resolution moduleExports+ importedModules = Map.delete mempty (Map.mapKeysWith clashingRenames importedAs modules)+ where importedAs moduleName = case List.find ((== moduleName) . snd) imports+ of Just (Nothing, moduleKey) -> moduleKey+ Just (Just innerKey, _) -> innerKey+ Nothing -> mempty+ clashingRenames _ _ = Failure (ClashingImports :| [])+ resolveDeclaration :: Ambiguous (Declaration Ambiguous Ambiguous) -> Resolved (Declaration Identity Identity)+ resolveDeclaration d = runIdentity <$> (traverse (Deep.traverseDown res) d >>= Shallow.traverse res)+ moduleExports = foldMap exportsOfModule <$> importedModules+ moduleGlobalScope = localScope res moduleName declarations predefined - resolveArray = resolveDesignator- resolvePointer = resolveDesignator+localScope :: Resolution -> Ident -> [Ambiguous (Declaration Ambiguous Ambiguous)] -> Scope -> Scope+localScope res qual declarations outerScope = innerScope+ where innerScope = Map.union (snd <$> scopeAdditions) outerScope+ scopeAdditions = (resolveBinding res innerScope <$>)+ <$> Map.fromList (concatMap (declarationBinding qual . unamb) declarations)+ unamb (Ambiguous (x :| [])) = x+ resolveBinding :: Resolution -> Scope -> DeclarationRHS Ambiguous Ambiguous+ -> Validation (NonEmpty Error) (DeclarationRHS Identity Identity)+ resolveBinding res scope dr = evalStateT (Deep.traverseDown res dr) (scope, DeclarationState) - resolveName scope q@(QualIdent moduleName name) =- case Map.lookup moduleName moduleExports- of Nothing -> Failure (UnknownModule moduleName :| [])- Just exports -> case Map.lookup name exports- of Just (Success rhs) -> Success rhs- Just (Failure err) -> Failure err- Nothing -> Failure (UnknownImport q :| [])- resolveName scope (NonQualIdent name) =- case Map.lookup name scope- of Just (Success rhs) -> Success rhs- _ -> Failure (UnknownLocal name :| [])- - resolveBinding scope (DeclaredConstant (Ambiguous expression)) =- DeclaredConstant . Identity <$> uniqueExpression (resolveExpression scope <$> expression)- resolveBinding scope (DeclaredType typeDef) = DeclaredType <$> resolveBaseType scope typeDef- resolveBinding scope (DeclaredVariable typeDef) = DeclaredVariable <$> resolveBaseType scope typeDef- resolveBinding scope (DeclaredProcedure special parameters) =- DeclaredProcedure special <$> traverse (resolveParameters scope) parameters- -declarationBinding :: Ident -> Declaration f -> [(Ident, (AccessMode, DeclarationRHS f))]+declarationBinding :: Ident -> Declaration f f -> [(Ident, (AccessMode, DeclarationRHS f f))] declarationBinding _ (ConstantDeclaration (IdentDef name export) expr) = [(name, (export, DeclaredConstant expr))] declarationBinding _ (TypeDeclaration (IdentDef name export) typeDef) =@@ -332,113 +266,99 @@ predefined, predefined2 :: Predefined -- | The set of 'Predefined' types and procedures defined in the Oberon Language Report. predefined = Success <$> Map.fromList- [("BOOLEAN", DeclaredType (TypeReference $ NonQualIdent "BOOLEAN")),- ("CHAR", DeclaredType (TypeReference $ NonQualIdent "CHAR")),- ("SHORTINT", DeclaredType (TypeReference $ NonQualIdent "SHORTINT")),- ("INTEGER", DeclaredType (TypeReference $ NonQualIdent "INTEGER")),- ("LONGINT", DeclaredType (TypeReference $ NonQualIdent "LONGINT")),- ("REAL", DeclaredType (TypeReference $ NonQualIdent "REAL")),- ("LONGREAL", DeclaredType (TypeReference $ NonQualIdent "LONGREAL")),- ("SET", DeclaredType (TypeReference $ NonQualIdent "SET")),+ [("BOOLEAN", DeclaredType (Identity $ TypeReference $ NonQualIdent "BOOLEAN")),+ ("CHAR", DeclaredType (Identity $ TypeReference $ NonQualIdent "CHAR")),+ ("SHORTINT", DeclaredType (Identity $ TypeReference $ NonQualIdent "SHORTINT")),+ ("INTEGER", DeclaredType (Identity $ TypeReference $ NonQualIdent "INTEGER")),+ ("LONGINT", DeclaredType (Identity $ TypeReference $ NonQualIdent "LONGINT")),+ ("REAL", DeclaredType (Identity $ TypeReference $ NonQualIdent "REAL")),+ ("LONGREAL", DeclaredType (Identity $ TypeReference $ NonQualIdent "LONGREAL")),+ ("SET", DeclaredType (Identity $ TypeReference $ NonQualIdent "SET")), ("TRUE", DeclaredConstant (Identity $ Read $ Identity $ Variable $ NonQualIdent "TRUE")), ("FALSE", DeclaredConstant (Identity $ Read $ Identity $ Variable $ NonQualIdent "FALSE")),- ("ABS", DeclaredProcedure False $ Just $- FormalParameters [FPSection False (pure "n") $ TypeReference $ NonQualIdent "INTEGER"] $+ ("ABS", DeclaredProcedure False $ Just $ Identity $+ FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "INTEGER"] $ Just $ NonQualIdent "INTEGER"),- ("ASH", DeclaredProcedure False $ Just $- FormalParameters [FPSection False (pure "n") $ TypeReference $ NonQualIdent "INTEGER"] $+ ("ASH", DeclaredProcedure False $ Just $ Identity $+ FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "INTEGER"] $ Just $ NonQualIdent "INTEGER"),- ("CAP", DeclaredProcedure False $ Just $- FormalParameters [FPSection False (pure "c") $ TypeReference $ NonQualIdent "INTEGER"] $- Just $ NonQualIdent "CAP"),- ("LEN", DeclaredProcedure False $ Just $- FormalParameters [FPSection False (pure "c") $ TypeReference $ NonQualIdent "ARRAY"] $+ ("CAP", DeclaredProcedure False $ Just $ Identity $+ FormalParameters [Identity $ FPSection False (pure "c") $ Identity $ TypeReference $ NonQualIdent "CHAR"] $+ Just $ NonQualIdent "CHAR"),+ ("LEN", DeclaredProcedure False $ Just $ Identity $+ FormalParameters [Identity $ FPSection False (pure "c") $ Identity $ TypeReference $ NonQualIdent "ARRAY"] $ Just $ NonQualIdent "LONGINT"),- ("MAX", DeclaredProcedure True $ Just $- FormalParameters [FPSection False (pure "c") $ TypeReference $ NonQualIdent "SET"] $+ ("MAX", DeclaredProcedure True $ Just $ Identity $+ FormalParameters [Identity $ FPSection False (pure "c") $ Identity $ TypeReference $ NonQualIdent "SET"] $ Just $ NonQualIdent "INTEGER"),- ("MIN", DeclaredProcedure True $ Just $- FormalParameters [FPSection False (pure "c") $ TypeReference $ NonQualIdent "SET"] $+ ("MIN", DeclaredProcedure True $ Just $ Identity $+ FormalParameters [Identity $ FPSection False (pure "c") $ Identity $ TypeReference $ NonQualIdent "SET"] $ Just $ NonQualIdent "INTEGER"),- ("ODD", DeclaredProcedure False $ Just $- FormalParameters [FPSection False (pure "n") $ TypeReference $ NonQualIdent "CHAR"] $+ ("ODD", DeclaredProcedure False $ Just $ Identity $+ FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "CHAR"] $ Just $ NonQualIdent "BOOLEAN"),- ("SIZE", DeclaredProcedure True $ Just $- FormalParameters [FPSection False (pure "n") $ TypeReference $ NonQualIdent "CHAR"] $+ ("SIZE", DeclaredProcedure True $ Just $ Identity $+ FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "CHAR"] $ Just $ NonQualIdent "INTEGER"),- ("ORD", DeclaredProcedure False $ Just $- FormalParameters [FPSection False (pure "n") $ TypeReference $ NonQualIdent "CHAR"] $+ ("ORD", DeclaredProcedure False $ Just $ Identity $+ FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "CHAR"] $ Just $ NonQualIdent "INTEGER"),- ("CHR", DeclaredProcedure False $ Just $- FormalParameters [FPSection False (pure "n") $ TypeReference $ NonQualIdent "INTEGER"] $+ ("CHR", DeclaredProcedure False $ Just $ Identity $+ FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "INTEGER"] $ Just $ NonQualIdent "CHAR"),- ("SHORT", DeclaredProcedure False $ Just $- FormalParameters [FPSection False (pure "n") $ TypeReference $ NonQualIdent "INTEGER"] $+ ("SHORT", DeclaredProcedure False $ Just $ Identity $+ FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "INTEGER"] $ Just $ NonQualIdent "INTEGER"),- ("LONG", DeclaredProcedure False $ Just $- FormalParameters [FPSection False (pure "n") $ TypeReference $ NonQualIdent "INTEGER"] $+ ("LONG", DeclaredProcedure False $ Just $ Identity $+ FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "INTEGER"] $ Just $ NonQualIdent "INTEGER"),- ("ENTIER", DeclaredProcedure False $ Just $- FormalParameters [FPSection False (pure "n") $ TypeReference $ NonQualIdent "REAL"] $+ ("ENTIER", DeclaredProcedure False $ Just $ Identity $+ FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "REAL"] $ Just $ NonQualIdent "INTEGER"),- ("INC", DeclaredProcedure False $ Just $- FormalParameters [FPSection False (pure "n") $ TypeReference $ NonQualIdent "INTEGER"] Nothing),- ("DEC", DeclaredProcedure False $ Just $- FormalParameters [FPSection False (pure "n") $ TypeReference $ NonQualIdent "INTEGER"] Nothing),- ("INCL", DeclaredProcedure False $ Just $- FormalParameters [FPSection False (pure "s") $ TypeReference $ NonQualIdent "SET",- FPSection False (pure "n") $ TypeReference $ NonQualIdent "INTEGER"] Nothing),- ("EXCL", DeclaredProcedure False $ Just $- FormalParameters [FPSection False (pure "s") $ TypeReference $ NonQualIdent "SET",- FPSection False (pure "n") $ TypeReference $ NonQualIdent "INTEGER"] Nothing),- ("COPY", DeclaredProcedure False $ Just $- FormalParameters [FPSection False (pure "s") $ TypeReference $ NonQualIdent "ARRAY",- FPSection False (pure "n") $ TypeReference $ NonQualIdent "ARRAY"] Nothing),- ("NEW", DeclaredProcedure False $ Just $- FormalParameters [FPSection False (pure "n") $ TypeReference $ NonQualIdent "POINTER"] Nothing),- ("HALT", DeclaredProcedure False $ Just $- FormalParameters [FPSection False (pure "n") $ TypeReference $ NonQualIdent "INTEGER"] Nothing)]+ ("INC", DeclaredProcedure False $ Just $ Identity $+ FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "INTEGER"] Nothing),+ ("DEC", DeclaredProcedure False $ Just $ Identity $+ FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "INTEGER"] Nothing),+ ("INCL", DeclaredProcedure False $ Just $ Identity $+ FormalParameters [Identity $ FPSection False (pure "s") $ Identity $ TypeReference $ NonQualIdent "SET",+ Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "INTEGER"] Nothing),+ ("EXCL", DeclaredProcedure False $ Just $ Identity $+ FormalParameters [Identity $ FPSection False (pure "s") $ Identity $ TypeReference $ NonQualIdent "SET",+ Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "INTEGER"] Nothing),+ ("COPY", DeclaredProcedure False $ Just $ Identity $+ FormalParameters [Identity $ FPSection False (pure "s") $ Identity $ TypeReference $ NonQualIdent "ARRAY",+ Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "ARRAY"] Nothing),+ ("NEW", DeclaredProcedure False $ Just $ Identity $+ FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "POINTER"] Nothing),+ ("HALT", DeclaredProcedure False $ Just $ Identity $+ FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "INTEGER"] Nothing)] -- | The set of 'Predefined' types and procedures defined in the Oberon-2 Language Report. predefined2 = predefined <> (Success <$> Map.fromList- [("ASSERT", DeclaredProcedure False $ Just $- FormalParameters [FPSection False (pure "s") $ TypeReference $ NonQualIdent "ARRAY",- FPSection False (pure "n") $ TypeReference $ NonQualIdent "ARRAY"] Nothing)])--resolveTypeReferenceIn scope (DeclaredType t) = DeclaredType <$> resolveTypeReference scope t-resolveTypeReferenceIn scope (DeclaredVariable t) = DeclaredVariable <$> resolveTypeReference scope t-resolveTypeReferenceIn scope d = pure d--resolveTypeReference scope t@(TypeReference q@(NonQualIdent name)) =- case Map.lookup name scope- of Nothing -> pure t- Just (Failure err) -> Failure err- Just (Success (DeclaredType t'@(TypeReference q')))- | q == q' -> pure t' -- built-in type- Just (Success (DeclaredType t')) -> resolveTypeReference scope t'- Just {} -> Failure (NotAType q :| [])-resolveTypeReference scope t = pure t+ [("ASSERT", DeclaredProcedure False $ Just $ Identity $+ FormalParameters [Identity $ FPSection False (pure "s") $ Identity $ TypeReference $ NonQualIdent "ARRAY",+ Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "ARRAY"] Nothing)]) -exportsOfModule :: Module Identity -> Scope-exportsOfModule = Map.mapMaybe isExported . globalsOfModule+exportsOfModule :: Module Identity Identity -> Scope+exportsOfModule = fmap Success . Map.mapMaybe isExported . globalsOfModule where isExported (PrivateOnly, _) = Nothing isExported (_, binding) = Just binding -globalsOfModule :: Module Identity -> Map Ident (AccessMode, Validation (NonEmpty Error) (DeclarationRHS Identity))-globalsOfModule (Module name imports declarations _ _) = scope- where scope = (resolveTypeReferenceIn scope' <$>) <$> Map.fromList declarationBindings- scope' = snd <$> scope- declarationBindings = concatMap (declarationBinding name) declarations+globalsOfModule :: Module Identity Identity -> Map Ident (AccessMode, DeclarationRHS Identity Identity)+globalsOfModule (Module name imports declarations _ _) =+ Map.fromList (concatMap (declarationBinding name . runIdentity) declarations) -uniqueDesignator = unique InvalidDesignator AmbiguousDesignator-uniqueExpression = unique InvalidExpression AmbiguousExpression-uniqueStatement = unique InvalidStatement AmbiguousStatement+unique :: (NonEmpty Error -> Error) -> ([a] -> Error) -> Ambiguous (Validation (NonEmpty Error) a)+ -> Validation (NonEmpty Error) a+unique _ _ (Ambiguous (x :| [])) = x+unique inv amb (Ambiguous xs) =+ case partitionEithers (validationToEither <$> NonEmpty.toList xs)+ of (_, [x]) -> Success x+ (errors, []) -> Failure (inv (sconcat $ NonEmpty.fromList errors) :| [])+ (_, multi) -> Failure (amb multi :| []) -unique :: (NonEmpty Error -> Error) -> ([a] -> Error) - -> NonEmpty (Validation (NonEmpty Error) a) -> Validation (NonEmpty Error) a-unique _ _ (x :| []) = x-unique inv amb xs = case partitionEithers (validationToEither <$> NonEmpty.toList xs)- of (_, [x]) -> Success x- (errors, []) -> Failure (inv (sconcat $ NonEmpty.fromList errors) :| [])- (_, stats) -> Failure (amb stats :| [])+$(Rank2.TH.deriveFunctor ''DeclarationRHS)+$(Rank2.TH.deriveFoldable ''DeclarationRHS)+$(Rank2.TH.deriveTraversable ''DeclarationRHS)+$(Transformation.Deep.TH.deriveDownTraversable ''DeclarationRHS)
+ src/Language/Oberon/TypeChecker.hs view
@@ -0,0 +1,880 @@+{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, OverloadedStrings,+ TemplateHaskell, TypeFamilies, UndecidableInstances #-}++module Language.Oberon.TypeChecker (Error(..), checkModules, predefined, predefined2) where++import Control.Applicative (liftA2)+import Control.Arrow (first)+import Data.Coerce (coerce)+import Data.Either (partitionEithers)+import Data.Either.Validation (Validation(..), validationToEither)+import Data.Foldable (toList)+import Data.Functor.Identity (Identity(..))+import Data.List.NonEmpty (NonEmpty(..))+import qualified Data.List.NonEmpty as NonEmpty+import qualified Data.List as List+import Data.Maybe (fromMaybe)+import Data.Map.Lazy (Map)+import qualified Data.Map.Lazy as Map+import Data.Semigroup (Semigroup(..), sconcat)+import qualified Data.Text as Text++import qualified Rank2+import qualified Rank2.TH+import qualified Transformation as Shallow+import qualified Transformation.Deep as Deep+import qualified Transformation.AG as AG+import Transformation.AG (Attribution(..), Atts, Inherited(..), Synthesized(..), Semantics)++import qualified Language.Oberon.AST as AST++import Debug.Trace++data Type = NominalType AST.QualIdent (Maybe Type)+ | RecordType{ancestry :: [AST.QualIdent],+ recordFields :: Map AST.Ident Type}+ | NilType+ | IntegerType Int+ | StringType Int+ | ArrayType [Int] Type+ | PointerType Type+ | ProcedureType [(Bool, Type)] (Maybe Type)+ | UnknownType++data Error = TypeMismatch Type Type+ | ArgumentCountMismatch Int Int+ | DuplicateBinding AST.Ident+ | ExtraDimensionalIndex Type+ | TooSmallArrayType Type+ | OpenArrayVariable+ | NonArrayType Type+ | NonBooleanType Type+ | NonFunctionType Type+ | NonIntegerType Type+ | NonNumericType Type+ | NonPointerType Type+ | NonProcedureType Type+ | NonRecordType Type+ | UnequalTypes Type Type+ | UnrealType Type+ | UnknownName AST.QualIdent+ | UnknownField AST.Ident Type+ deriving Show++instance Eq Type where+ NominalType q1 _ == NominalType q2 _ = q1 == q2+ ArrayType [] t1 == ArrayType [] t2 = t1 == t2+ ProcedureType p1 r1 == ProcedureType p2 r2 = r1 == r2 && p1 == p2+ StringType len1 == StringType len2 = len1 == len2+ NilType == NilType = True+ _ == _ = False++instance Show Type where+ show (NominalType q t) = "Nominal " ++ show q ++ " " ++ show t+ show (RecordType ancestry fields) = "RecordType " ++ show ancestry ++ show (fst <$> Map.toList fields)+ show (ArrayType dimensions itemType) = "ArrayType " ++ show dimensions ++ " " ++ show itemType+ show (PointerType targetType) = "PointerType " ++ show targetType+ show (ProcedureType parameters result) = "ProcedureType " ++ show parameters ++ " " ++ show result+ show (IntegerType n) = "IntegerType " ++ show n+ show (StringType len) = "StringType " ++ show len+ show NilType = "NilType"+ show UnknownType = "UnknownType"++type Environment = Map AST.QualIdent Type++newtype Modules f' f = Modules (Map AST.Ident (f (AST.Module f' f')))++data TypeCheck = TypeCheck++data InhTC = InhTC{env :: Environment} deriving Show++data SynTC = SynTC{errors :: [Error]} deriving Show++data SynTC' = SynTC'{errors' :: [Error],+ env' :: Environment} deriving Show++data SynTCMod = SynTCMod{moduleErrors :: [Error],+ moduleEnv :: Environment,+ pointerTargets :: Map AST.Ident AST.Ident} deriving Show++data SynTCType = SynTCType{typeErrors :: [Error],+ typeName :: Maybe AST.Ident,+ definedType :: Type,+ pointerTarget :: Maybe AST.Ident} deriving Show++data SynTCFields = SynTCFields{fieldErrors :: [Error],+ fieldEnv :: Map AST.Ident Type} deriving Show++data SynTCSig = SynTCSig{signatureErrors :: [Error],+ signatureEnv :: Environment,+ signatureType :: Type} deriving Show++data SynTCSec = SynTCSec{sectionErrors :: [Error],+ sectionEnv :: Environment,+ sectionParameters :: [(Bool, Type)]} deriving Show++data SynTCDes = SynTCDes{designatorErrors :: [Error],+ designatorSelf :: AST.Designator Identity Identity,+ designatorType :: Type} deriving Show++data SynTCExp = SynTCExp{expressionErrors :: [Error],+ inferredType :: Type} deriving Show++-- * Modules instances, TH candidates+instance (Functor p, Deep.Functor t AST.Module p q, Shallow.Functor t p q (AST.Module q q)) =>+ Deep.Functor t Modules p q where+ t <$> ~(Modules ms) = Modules (mapModule <$> ms)+ where mapModule m = t Shallow.<$> ((t Deep.<$>) <$> m)++instance Rank2.Functor (Modules f') where+ f <$> ~(Modules ms) = Modules (f <$> ms)++instance Rank2.Apply (Modules f') where+ ~(Modules fs) <*> ~(Modules ms) = Modules (Map.intersectionWith Rank2.apply fs ms)++-- * Boring attribute types+type instance Atts (Inherited TypeCheck) (Modules f' f) = InhTC+type instance Atts (Synthesized TypeCheck) (Modules f' f) = SynTC+type instance Atts (Inherited TypeCheck) (AST.Module f' f) = InhTC+type instance Atts (Synthesized TypeCheck) (AST.Module f' f) = SynTCMod+type instance Atts (Inherited TypeCheck) (AST.Declaration f' f) = (InhTC, Map AST.Ident AST.Ident)+type instance Atts (Synthesized TypeCheck) (AST.Declaration f' f) = SynTCMod+type instance Atts (Inherited TypeCheck) (AST.FormalParameters f' f) = InhTC+type instance Atts (Synthesized TypeCheck) (AST.FormalParameters f' f) = SynTCSig+type instance Atts (Inherited TypeCheck) (AST.FPSection f' f) = InhTC+type instance Atts (Synthesized TypeCheck) (AST.FPSection f' f) = SynTCSec+type instance Atts (Inherited TypeCheck) (AST.Type f' f) = InhTC+type instance Atts (Synthesized TypeCheck) (AST.Type f' f) = SynTCType+type instance Atts (Inherited TypeCheck) (AST.FieldList f' f) = InhTC+type instance Atts (Synthesized TypeCheck) (AST.FieldList f' f) = SynTCFields+type instance Atts (Inherited TypeCheck) (AST.StatementSequence f' f) = InhTC+type instance Atts (Synthesized TypeCheck) (AST.StatementSequence f' f) = SynTC+type instance Atts (Inherited TypeCheck) (AST.Expression f' f) = InhTC+type instance Atts (Synthesized TypeCheck) (AST.Expression f' f) = SynTCExp+type instance Atts (Inherited TypeCheck) (AST.Element f' f) = InhTC+type instance Atts (Synthesized TypeCheck) (AST.Element f' f) = SynTCExp+type instance Atts (Inherited TypeCheck) (AST.Designator f' f) = InhTC+type instance Atts (Synthesized TypeCheck) (AST.Designator f' f) = SynTCDes+type instance Atts (Inherited TypeCheck) (Deep.Product AST.Expression AST.StatementSequence f' f) = InhTC+type instance Atts (Synthesized TypeCheck) (Deep.Product AST.Expression AST.StatementSequence f' f) = SynTC+type instance Atts (Inherited TypeCheck) (AST.Statement f' f) = InhTC+type instance Atts (Synthesized TypeCheck) (AST.Statement f' f) = SynTC+type instance Atts (Inherited TypeCheck) (AST.Case f' f) = InhTC+type instance Atts (Synthesized TypeCheck) (AST.Case f' f) = SynTC+type instance Atts (Inherited TypeCheck) (AST.CaseLabels f' f) = InhTC+type instance Atts (Synthesized TypeCheck) (AST.CaseLabels f' f) = SynTC+type instance Atts (Inherited TypeCheck) (AST.WithAlternative f' f) = InhTC+type instance Atts (Synthesized TypeCheck) (AST.WithAlternative f' f) = SynTC++-- * Rules++instance Attribution TypeCheck Modules where+ attribution TypeCheck (Modules self) (inherited, Modules ms) =+ (Synthesized SynTC{errors= foldMap (moduleErrors . syn) ms},+ Modules (Inherited InhTC{env= env (inh inherited) <> foldMap (moduleEnv . syn) ms} <$ self))++instance Attribution TypeCheck AST.Module where+ attribution TypeCheck (AST.Module ident1 imports decls body ident2) (inherited, AST.Module _ _ decls' body' _) =+ (Synthesized SynTCMod{moduleErrors= foldMap (moduleErrors . syn) decls' <> foldMap (errors . syn) body',+ moduleEnv= exportedEnv,+ pointerTargets= pointers},+ AST.Module ident1 imports [Inherited (localEnv, pointers)] (Inherited localEnv <$ body) ident2)+ where exportedEnv = exportNominal <$> Map.mapKeysMonotonic export newEnv+ newEnv = Map.unionsWith mergeTypeBoundProcedures (moduleEnv . syn <$> decls')+ localEnv = InhTC (newEnv `Map.union` env (inh inherited))+ export (AST.NonQualIdent name) = AST.QualIdent ident1 name+ export q = q+ exportNominal (NominalType (AST.NonQualIdent name) t) =+ NominalType (AST.QualIdent ident1 name) (exportNominal' <$> t)+ exportNominal t = exportNominal' t+ exportNominal' (RecordType ancestry fields) = RecordType (export <$> ancestry) (exportNominal' <$> fields)+ exportNominal' (ProcedureType parameters result) =+ ProcedureType ((exportNominal' <$>) <$> parameters) (exportNominal' <$> result)+ exportNominal' (PointerType target) = PointerType (exportNominal' target)+ exportNominal' (ArrayType dimensions itemType) = ArrayType dimensions (exportNominal' itemType)+ exportNominal' (NominalType q@(AST.NonQualIdent name) (Just t)) =+ fromMaybe (NominalType (AST.QualIdent ident1 name) $ Just $ exportNominal' t) (Map.lookup q exportedEnv)+ exportNominal' t = t+ pointers= foldMap (pointerTargets . syn) decls'+ mergeTypeBoundProcedures' t1 t2 = mergeTypeBoundProcedures t1 t2+ mergeTypeBoundProcedures (NominalType (AST.NonQualIdent "") (Just t1)) t2 = mergeTypeBoundProcedures t1 t2+ mergeTypeBoundProcedures (NominalType q (Just t1)) t2 = NominalType q (Just $ mergeTypeBoundProcedures t1 t2)+ mergeTypeBoundProcedures t1 (NominalType (AST.NonQualIdent "") (Just t2)) = mergeTypeBoundProcedures t1 t2+ mergeTypeBoundProcedures t1 (NominalType q (Just t2)) = NominalType q (Just $ mergeTypeBoundProcedures t1 t2)+ mergeTypeBoundProcedures (RecordType ancestry1 fields1) (RecordType ancestry2 fields2) =+ RecordType (ancestry1 <> ancestry2) (fields1 <> fields2)+ mergeTypeBoundProcedures (PointerType (RecordType ancestry1 fields1)) (RecordType ancestry2 fields2) =+ PointerType (RecordType (ancestry1 <> ancestry2) (fields1 <> fields2))+ mergeTypeBoundProcedures (RecordType ancestry1 fields1) (PointerType (RecordType ancestry2 fields2)) =+ PointerType (RecordType (ancestry1 <> ancestry2) (fields1 <> fields2))+ mergeTypeBoundProcedures t1 t2 = error (take 90 $ show t1)++instance Attribution TypeCheck AST.Declaration where+ attribution TypeCheck (AST.ConstantDeclaration namedef@(AST.IdentDef name _) _)+ (inherited, AST.ConstantDeclaration _ expression) =+ (Synthesized SynTCMod{moduleErrors= expressionErrors (syn expression),+ moduleEnv= Map.singleton (AST.NonQualIdent name) (inferredType $ syn expression),+ pointerTargets= mempty},+ AST.ConstantDeclaration namedef (Inherited $ fst $ inh inherited))+ attribution TypeCheck (AST.TypeDeclaration namedef@(AST.IdentDef name _) _) (inherited,+ AST.TypeDeclaration _ definition) =+ (Synthesized SynTCMod{moduleErrors= typeErrors (syn definition),+ moduleEnv= Map.singleton qname (nominal $ definedType $ syn definition),+ pointerTargets= foldMap (Map.singleton name) (pointerTarget $ syn definition)},+ AST.TypeDeclaration namedef (Inherited $ fst $ inh inherited))+ where nominal t@NominalType{} = t+ nominal t = NominalType qname (Just t)+ qname = AST.NonQualIdent name+ attribution TypeCheck (AST.VariableDeclaration names _declaredType)+ (inherited, AST.VariableDeclaration _names declaredType) =+ (Synthesized SynTCMod{moduleErrors= typeErrors (syn declaredType) + <> case definedType (syn declaredType)+ of ArrayType [] _ -> [OpenArrayVariable]+ _ -> [],+ moduleEnv= foldMap (\name-> Map.singleton (AST.NonQualIdent $ defName name)+ (definedType $ syn declaredType))+ names,+ pointerTargets= mempty},+ AST.VariableDeclaration names (Inherited $ fst $ inh inherited))+ where defName (AST.IdentDef name _) = name+ attribution TypeCheck (AST.ProcedureDeclaration (AST.ProcedureHeading receiver indirect+ namedef@(AST.IdentDef name _) signature) + _body name')+ (inherited,+ AST.ProcedureDeclaration (AST.ProcedureHeading _receiver _indirect _ signature') + body@(AST.ProcedureBody declarations statements) _name') =+ (Synthesized SynTCMod{moduleErrors= foldMap (signatureErrors . syn) signature',+ moduleEnv= case receiver+ of Just (_, _, typeName)+ | Just targetName <- Map.lookup typeName (snd $ inh inherited) ->+ Map.singleton (AST.NonQualIdent targetName) methodType+ | otherwise -> Map.singleton (AST.NonQualIdent typeName) methodType+ + Nothing -> Map.singleton (AST.NonQualIdent name) procedureType,+ pointerTargets= mempty},+ AST.ProcedureDeclaration+ (AST.ProcedureHeading receiver indirect namedef (Inherited (fst $ inh inherited) <$ signature))+ (AST.ProcedureBody [Inherited (localInherited, mempty)] (Inherited localInherited <$ statements))+ name')+ where receiverEnv (_, formalName, typeName) =+ foldMap (Map.singleton $ AST.NonQualIdent formalName) (Map.lookup (AST.NonQualIdent typeName) + $ env $ fst $ inh inherited)+ methodType = NominalType (AST.NonQualIdent "") (Just $ RecordType [] $ Map.singleton name procedureType)+ procedureType = maybe (ProcedureType [] Nothing) (signatureType . syn) signature'+ receiverError (_, formalName, typeName) =+ case Map.lookup (AST.NonQualIdent typeName) (env $ fst $ inh inherited)+ of Nothing -> [UnknownName $ AST.NonQualIdent typeName]+ Just RecordType{} -> []+ Just (PointerType RecordType{}) -> []+ Just (NominalType _ (Just RecordType{})) -> []+ Just (NominalType _ (Just (PointerType RecordType{}))) -> []+ Just t -> [NonRecordType t]+ localInherited = InhTC (foldMap receiverEnv receiver+ `Map.union` foldMap (signatureEnv . syn) signature'+ `Map.union` env (fst $ inh inherited))+ attribution TypeCheck (AST.ForwardDeclaration namedef@(AST.IdentDef name _) signature)+ (inherited, AST.ForwardDeclaration _namedef signature') =+ (Synthesized SynTCMod{moduleErrors= foldMap (signatureErrors . syn) signature',+ moduleEnv= foldMap (Map.singleton (AST.NonQualIdent name) . signatureType . syn) signature',+ pointerTargets= mempty},+ AST.ForwardDeclaration namedef (Inherited (fst $ inh inherited) <$ signature))++instance Attribution TypeCheck AST.FormalParameters where+ attribution TypeCheck (AST.FormalParameters sections returnType)+ (inherited, AST.FormalParameters sections' _returnType) =+ (Synthesized SynTCSig{signatureErrors= foldMap (sectionErrors . syn) sections' <> foldMap typeRefErrors returnType,+ signatureType= ProcedureType (foldMap (sectionParameters . syn) sections')+ $ returnType >>= (`Map.lookup` env (inh inherited)),+ signatureEnv= foldMap (sectionEnv . syn) sections'},+ AST.FormalParameters (pure $ Inherited $ inh inherited) returnType)+ where typeRefErrors q+ | Map.member q (env $ inh inherited) = []+ | otherwise = [UnknownName q]++instance Attribution TypeCheck AST.FPSection where+ attribution TypeCheck (AST.FPSection var names _typeDef) (inherited, AST.FPSection _var _names typeDef) =+ (Synthesized SynTCSec{sectionErrors= typeErrors (syn typeDef),+ sectionParameters= (var, definedType (syn typeDef)) <$ toList names,+ sectionEnv= Map.fromList (toList+ $ flip (,) (definedType $ syn typeDef) . AST.NonQualIdent + <$> names)},+ AST.FPSection var names (Inherited $ inh inherited))++instance Attribution TypeCheck AST.Type where+ attribution TypeCheck (AST.TypeReference q) (inherited, _) = + (Synthesized SynTCType{typeErrors= if Map.member q (env $ inh inherited) then [] else [UnknownName q],+ typeName= case q + of AST.NonQualIdent name -> Just name+ _ -> Nothing,+ pointerTarget= Nothing,+ definedType= fromMaybe UnknownType (Map.lookup q $ env $ inh inherited)},+ AST.TypeReference q)+ attribution TypeCheck (AST.ArrayType dimensions _itemType) (inherited, AST.ArrayType dimensions' itemType) = + (Synthesized SynTCType{typeErrors= foldMap (expressionErrors . syn) dimensions' <> typeErrors (syn itemType)+ <> foldMap (expectInteger . syn) dimensions',+ typeName= Nothing,+ pointerTarget= Nothing,+ definedType= ArrayType (integerValue . syn <$> dimensions') (definedType $ syn itemType)},+ AST.ArrayType [Inherited (inh inherited)] (Inherited $ inh inherited))+ where expectInteger SynTCExp{inferredType= IntegerType{}} = []+ expectInteger SynTCExp{inferredType= t} = [NonIntegerType t]+ integerValue SynTCExp{inferredType= IntegerType n} = n+ integerValue _ = 0+ attribution TypeCheck (AST.RecordType base fields) (inherited, AST.RecordType _base fields') =+ (Synthesized SynTCType{typeErrors= fst baseRecord <> foldMap (fieldErrors . syn) fields',+ typeName= Nothing,+ pointerTarget= Nothing,+ definedType= RecordType (maybe [] (maybe id (:) base . ancestry) $ snd baseRecord)+ (maybe Map.empty recordFields (snd baseRecord)+ <> foldMap (fieldEnv . syn) fields')},+ AST.RecordType base (pure $ Inherited $ inh inherited))+ where baseRecord = case flip Map.lookup (env $ inh inherited) <$> base+ of Just (Just t@RecordType{}) -> ([], Just t)+ Just (Just (NominalType _ (Just t@RecordType{}))) -> ([], Just t)+ Just (Just t) -> ([NonRecordType t], Nothing)+ Just Nothing -> (foldMap ((:[]) . UnknownName) base, Nothing)+ Nothing -> ([], Nothing)+ attribution TypeCheck _self (inherited, AST.PointerType targetType') =+ (Synthesized SynTCType{typeErrors= typeErrors (syn targetType'),+ typeName= Nothing,+ pointerTarget= typeName (syn targetType'),+ definedType= PointerType (definedType $ syn targetType')},+ AST.PointerType (Inherited $ inh inherited))+ attribution TypeCheck (AST.ProcedureType signature) (inherited, AST.ProcedureType signature') = + (Synthesized SynTCType{typeErrors= foldMap (signatureErrors . syn) signature',+ typeName= Nothing,+ pointerTarget= Nothing,+ definedType= maybe (ProcedureType [] Nothing) (signatureType . syn) signature'},+ AST.ProcedureType (Inherited (inh inherited) <$ signature))++instance Attribution TypeCheck AST.FieldList where+ attribution TypeCheck (AST.FieldList names _declaredType) (inherited, AST.FieldList _names declaredType) =+ (Synthesized SynTCFields{fieldErrors= typeErrors (syn declaredType),+ fieldEnv= foldMap (\name-> Map.singleton (defName name) (definedType $ syn declaredType)) + names},+ AST.FieldList names (Inherited $ inh inherited))+ where defName (AST.IdentDef name _) = name+ attribution TypeCheck self (inherited, AST.EmptyFieldList) =+ (Synthesized SynTCFields{fieldErrors= [], fieldEnv= mempty},+ AST.EmptyFieldList)++instance Attribution TypeCheck (Deep.Product AST.Expression AST.StatementSequence) where+ attribution TypeCheck self (inherited, Deep.Pair condition statements) =+ (Synthesized SynTC{errors= booleanExpressionErrors (syn condition) <> errors (syn statements)},+ Deep.Pair (Inherited $ inh inherited) (Inherited $ inh inherited))++instance Attribution TypeCheck AST.StatementSequence where+ attribution TypeCheck (AST.StatementSequence statements) (inherited, AST.StatementSequence statements') =+ (Synthesized SynTC{errors= foldMap (errors . syn) statements'},+ AST.StatementSequence (pure $ Inherited $ inh inherited))++instance Attribution TypeCheck AST.Statement where+ attribution TypeCheck self (inherited, AST.EmptyStatement) = (Synthesized SynTC{errors= []}, AST.EmptyStatement)+ attribution TypeCheck self (inherited, AST.Assignment var value) = {-# SCC "Assignment" #-}+ (Synthesized SynTC{errors= assignmentCompatible (designatorType $ syn var) (inferredType $ syn value)},+ AST.Assignment (Inherited $ inh inherited) (Inherited $ inh inherited))+ attribution TypeCheck (AST.ProcedureCall _proc parameters) (inherited, AST.ProcedureCall procedure' parameters') =+ (Synthesized SynTC{errors= case syn procedure'+ of SynTCDes{designatorErrors= [],+ designatorType= t} -> {-# SCC "ProcedureCall" #-} procedureErrors t+ SynTCDes{designatorErrors= errs} -> errs+ <> foldMap (foldMap (expressionErrors . syn)) parameters'},+ AST.ProcedureCall (Inherited $ inh inherited) (Just [Inherited $ inh inherited]))+ where procedureErrors (ProcedureType formalTypes Nothing)+ | length formalTypes /= maybe 0 length parameters =+ [ArgumentCountMismatch (length formalTypes) $ maybe 0 length parameters]+ | otherwise = concat (zipWith parameterCompatible formalTypes $ maybe [] (inferredType . syn <$>) parameters')+ procedureErrors (NominalType _ (Just t)) = procedureErrors t+ procedureErrors t = [NonProcedureType t]+ attribution TypeCheck self (inherited, AST.If branches fallback) =+ (Synthesized SynTC{errors= foldMap (errors . syn) branches <> foldMap (errors . syn) fallback},+ AST.If (pure $ Inherited $ inh inherited) (Inherited (inh inherited) <$ fallback))+ attribution TypeCheck self (inherited, AST.CaseStatement value branches fallback) =+ (Synthesized SynTC{errors= expressionErrors (syn value) <> foldMap (errors . syn) branches+ <> foldMap (errors . syn) fallback},+ AST.CaseStatement (Inherited $ inh inherited) (pure $ Inherited $ inh inherited)+ (Inherited (inh inherited) <$ fallback))+ attribution TypeCheck self (inherited, AST.While condition body) =+ (Synthesized SynTC{errors= booleanExpressionErrors (syn condition) <> errors (syn body)},+ AST.While (Inherited $ inh inherited) (Inherited $ inh inherited))+ attribution TypeCheck self (inherited, AST.Repeat body condition) =+ (Synthesized SynTC{errors= booleanExpressionErrors (syn condition) <> errors (syn body)},+ AST.Repeat (Inherited $ inh inherited) (Inherited $ inh inherited))+ attribution TypeCheck (AST.For counter _start _end _step _body) (inherited, AST.For _counter start end step body) =+ (Synthesized SynTC{errors= integerExpressionErrors (syn start) <> integerExpressionErrors (syn end)+ <> foldMap (integerExpressionErrors . syn) step <> errors (syn body)},+ AST.For counter (Inherited $ inh inherited) (Inherited $ inh inherited) (Inherited (inh inherited) <$ step)+ (Inherited $ InhTC $+ Map.insert (AST.NonQualIdent counter) (NominalType (AST.NonQualIdent "INTEGER") Nothing)+ $ env $ inh inherited))+ attribution TypeCheck self (inherited, AST.Loop body) = (Synthesized SynTC{errors= errors (syn body)},+ AST.Loop (Inherited $ inh inherited))+ attribution TypeCheck self (inherited, AST.With branches fallback) =+ (Synthesized SynTC{errors= foldMap (errors . syn) branches <> foldMap (errors . syn) fallback},+ AST.With (pure $ Inherited $ inh inherited) (Inherited (inh inherited) <$ fallback))+ attribution TypeCheck self (inherited, AST.Exit) = (Synthesized SynTC{errors= []}, AST.Exit)+ attribution TypeCheck self (inherited, AST.Return value) =+ (Synthesized SynTC{errors= foldMap (expressionErrors . syn) value}, + AST.Return (Inherited (inh inherited) <$ value))++instance Attribution TypeCheck AST.WithAlternative where+ attribution TypeCheck self (inherited, AST.WithAlternative var subtype body) = {-# SCC "WithAlternative" #-}+ (Synthesized SynTC{errors= case (Map.lookup var (env $ inh inherited),+ Map.lookup subtype (env $ inh inherited))+ of (Just supertype, Just subtypeDef) -> assignmentCompatible supertype subtypeDef+ (Nothing, _) -> [UnknownName var]+ (_, Nothing) -> [UnknownName subtype]+ <> errors (syn body)},+ AST.WithAlternative var subtype (Inherited $ InhTC $+ maybe id (Map.insert var) (Map.lookup subtype $ env $ inh inherited) + $ env $ inh inherited))++instance Attribution TypeCheck AST.Case where+ attribution TypeCheck self (inherited, AST.Case labels body) =+ (Synthesized SynTC{errors= foldMap (errors . syn) labels <> errors (syn body)},+ AST.Case (pure $ Inherited $ inh inherited) (Inherited $ inh inherited))+ attribution TypeCheck self (inherited, AST.EmptyCase) = (Synthesized SynTC{errors= []}, AST.EmptyCase)++instance Attribution TypeCheck AST.CaseLabels where+ attribution TypeCheck self (inherited, AST.SingleLabel value) =+ (Synthesized SynTC{errors= integerExpressionErrors (syn value)},+ AST.SingleLabel (Inherited $ inh inherited))+ attribution TypeCheck self (inherited, AST.LabelRange start end) =+ (Synthesized SynTC{errors= integerExpressionErrors (syn start) <> integerExpressionErrors (syn end)},+ AST.LabelRange (Inherited $ inh inherited) (Inherited $ inh inherited))++instance Attribution TypeCheck AST.Expression where+ attribution TypeCheck self (inherited, AST.Relation op left right) =+ (Synthesized SynTCExp{expressionErrors= case expressionErrors (syn left) <> expressionErrors (syn right)+ of [] | inferredType (syn left) == inferredType (syn right) -> []+ | otherwise -> [TypeMismatch+ (inferredType $ syn left)+ (inferredType $ syn right)]+ errs -> errs,+ inferredType= NominalType (AST.NonQualIdent "BOOLEAN") Nothing},+ AST.Relation op (Inherited $ inh inherited) (Inherited $ inh inherited))+ attribution TypeCheck self (inherited, AST.Positive expr) =+ (Synthesized SynTCExp{expressionErrors= unaryNumericOperatorErrors (syn expr),+ inferredType= inferredType (syn expr)},+ AST.Positive (Inherited $ inh inherited))+ attribution TypeCheck self (inherited, AST.Negative expr) = + (Synthesized SynTCExp{expressionErrors= unaryNumericOperatorErrors (syn expr),+ inferredType= unaryNumericOperatorType negate (syn expr)},+ AST.Negative (Inherited $ inh inherited))+ attribution TypeCheck self (inherited, AST.Add left right) =+ (Synthesized SynTCExp{expressionErrors= binaryNumericOperatorErrors (syn left) (syn right),+ inferredType= binaryNumericOperatorType div (syn left) (syn right)},+ AST.Add (Inherited $ inh inherited) (Inherited $ inh inherited))+ attribution TypeCheck self (inherited, AST.Subtract left right) =+ (Synthesized SynTCExp{expressionErrors= binaryNumericOperatorErrors (syn left) (syn right),+ inferredType= binaryNumericOperatorType div (syn left) (syn right)},+ AST.Subtract (Inherited $ inh inherited) (Inherited $ inh inherited))+ attribution TypeCheck self (inherited, AST.Or left right) =+ (Synthesized SynTCExp{expressionErrors= binaryBooleanOperatorErrors (syn left) (syn right),+ inferredType= NominalType (AST.NonQualIdent "BOOLEAN") Nothing},+ AST.Or (Inherited $ inh inherited) (Inherited $ inh inherited))+ attribution TypeCheck self (inherited, AST.Multiply left right) =+ (Synthesized SynTCExp{expressionErrors= binaryNumericOperatorErrors (syn left) (syn right),+ inferredType= binaryNumericOperatorType div (syn left) (syn right)},+ AST.Multiply (Inherited $ inh inherited) (Inherited $ inh inherited))+ attribution TypeCheck self (inherited, AST.Divide left right) =+ (Synthesized SynTCExp{expressionErrors=+ case (syn left, syn right)+ of (SynTCExp{expressionErrors= [],+ inferredType= NominalType (AST.NonQualIdent "REAL") Nothing},+ SynTCExp{expressionErrors= [],+ inferredType= NominalType (AST.NonQualIdent "REAL") Nothing}) -> []+ (SynTCExp{expressionErrors= [], inferredType= t1},+ SynTCExp{expressionErrors= [], inferredType= t2})+ | t1 == t2 -> [UnrealType t1]+ | otherwise -> [TypeMismatch t1 t2],+ inferredType= NominalType (AST.NonQualIdent "REAL") Nothing},+ AST.Divide (Inherited $ inh inherited) (Inherited $ inh inherited))+ attribution TypeCheck self (inherited, AST.IntegerDivide left right) =+ (Synthesized SynTCExp{expressionErrors= binaryIntegerOperatorErrors (syn left) (syn right),+ inferredType= binaryNumericOperatorType div (syn left) (syn right)},+ AST.IntegerDivide (Inherited $ inh inherited) (Inherited $ inh inherited))+ attribution TypeCheck self (inherited, AST.Modulo left right) =+ (Synthesized SynTCExp{expressionErrors= binaryIntegerOperatorErrors (syn left) (syn right),+ inferredType= binaryNumericOperatorType mod (syn left) (syn right)},+ AST.Modulo (Inherited $ inh inherited) (Inherited $ inh inherited))+ attribution TypeCheck self (inherited, AST.And left right) =+ (Synthesized SynTCExp{expressionErrors= binaryBooleanOperatorErrors (syn left) (syn right),+ inferredType= NominalType (AST.NonQualIdent "BOOLEAN") Nothing},+ AST.And (Inherited $ inh inherited) (Inherited $ inh inherited))+ attribution TypeCheck (AST.Integer x) (inherited, _) =+ (Synthesized SynTCExp{expressionErrors= mempty,+ inferredType= IntegerType (read $ Text.unpack x)},+ AST.Integer x)+ attribution TypeCheck self (inherited, AST.Real x) =+ (Synthesized SynTCExp{expressionErrors= mempty,+ inferredType= NominalType (AST.NonQualIdent "REAL") Nothing},+ AST.Real x)+ attribution TypeCheck self (inherited, AST.CharConstant x) =+ (Synthesized SynTCExp{expressionErrors= mempty,+ inferredType= NominalType (AST.NonQualIdent "CHAR") Nothing},+ AST.CharConstant x)+ attribution TypeCheck self (inherited, AST.CharCode x) =+ (Synthesized SynTCExp{expressionErrors= mempty,+ inferredType= NominalType (AST.NonQualIdent "CHAR") Nothing},+ AST.CharCode x)+ attribution TypeCheck (AST.String x) (inherited, _) =+ (Synthesized SynTCExp{expressionErrors= mempty,+ inferredType= StringType (Text.length x)},+ AST.String x)+ attribution TypeCheck self (inherited, AST.Nil) =+ (Synthesized SynTCExp{expressionErrors= mempty,+ inferredType= NilType},+ AST.Nil)+ attribution TypeCheck self (inherited, AST.Set elements) =+ (Synthesized SynTCExp{expressionErrors= mempty,+ inferredType= NominalType (AST.NonQualIdent "SET") Nothing},+ AST.Set [Inherited $ inh inherited])+ attribution TypeCheck self (inherited, AST.Read designator) =+ (Synthesized SynTCExp{expressionErrors= designatorErrors (syn designator),+ inferredType= designatorType (syn designator)},+ AST.Read (Inherited $ inh inherited))+ attribution TypeCheck (AST.FunctionCall _designator parameters)+ (inherited, AST.FunctionCall designator parameters') =+ (Synthesized SynTCExp{expressionErrors= case {-# SCC "FunctionCall" #-} syn designator+ of SynTCDes{designatorErrors= [],+ designatorType= ProcedureType formalTypes Just{}}+ | length formalTypes /= length parameters ->+ [ArgumentCountMismatch (length formalTypes) (length parameters)]+ | otherwise -> concat (zipWith parameterCompatible formalTypes $+ inferredType . syn <$> parameters')+ SynTCDes{designatorErrors= [],+ designatorType= t} -> [NonFunctionType t]+ SynTCDes{designatorErrors= errs} -> errs+ <> foldMap (expressionErrors . syn) parameters',+ inferredType= case syn designator+ of SynTCDes{designatorSelf= d,+ designatorType= ProcedureType _ (Just returnType)}+ | IntegerType{} <- returnType ->+ IntegerType (callValue d $ inferredType . syn <$> parameters')+ | otherwise -> returnType+ _ -> UnknownType},+ AST.FunctionCall (Inherited $ inh inherited) [Inherited $ inh inherited])+ where callValue (AST.Variable (AST.NonQualIdent "MAX"))+ [NominalType (AST.NonQualIdent "SET") Nothing] = 63+ callValue (AST.Variable (AST.NonQualIdent "MIN"))+ [NominalType (AST.NonQualIdent "SET") Nothing] = 0+ attribution TypeCheck self (inherited, AST.Not expr) =+ (Synthesized SynTCExp{expressionErrors= booleanExpressionErrors (syn expr),+ inferredType= NominalType (AST.NonQualIdent "BOOLEAN") Nothing},+ AST.Not (Inherited $ inh inherited))++instance Attribution TypeCheck AST.Element where+ attribution TypeCheck self (inherited, AST.Element expr) =+ (Synthesized SynTCExp{expressionErrors= integerExpressionErrors (syn expr),+ inferredType= NominalType (AST.NonQualIdent "SET") Nothing},+ AST.Element (Inherited $ inh inherited))+ attribution TypeCheck self (inherited, AST.Range low high) =+ (Synthesized SynTCExp{expressionErrors= integerExpressionErrors (syn low) <> integerExpressionErrors (syn high),+ inferredType= NominalType (AST.NonQualIdent "SET") Nothing},+ AST.Range (Inherited $ inh inherited) (Inherited $ inh inherited))++instance Attribution TypeCheck AST.Designator where+ attribution TypeCheck (AST.Variable q) (inherited, _) =+ (Synthesized SynTCDes{designatorErrors= case designatorType+ of Nothing -> [UnknownName q]+ Just{} -> [],+ designatorSelf= AST.Variable q,+ designatorType= fromMaybe UnknownType designatorType},+ AST.Variable q)+ where designatorType = Map.lookup q (env $ inh inherited)+ attribution TypeCheck (AST.Field _record fieldName) (inherited, AST.Field record _fieldName) =+ (Synthesized SynTCDes{designatorErrors= case syn record+ of SynTCDes{designatorErrors= [],+ designatorType= t} ->+ maybe [NonRecordType t]+ (maybe [UnknownField fieldName t] $ const []) (access True t)+ SynTCDes{designatorErrors= errors} -> errors,+ designatorSelf= AST.Field (Identity $ designatorSelf $ syn record) fieldName,+ designatorType= fromMaybe UnknownType (fromMaybe Nothing $ access True+ $ designatorType $ syn record)},+ AST.Field (Inherited $ inh inherited) fieldName)+ where access _ (RecordType _ fields) = Just (Map.lookup fieldName fields)+ access True (PointerType t) = access False t+ access allowPtr (NominalType _ (Just t)) = access allowPtr t+ access _ _ = Nothing+ attribution TypeCheck (AST.Index _array indexes) (inherited, AST.Index array _indexes) =+ (Synthesized SynTCDes{designatorErrors= case syn array+ of SynTCDes{designatorErrors= [],+ designatorType= t@(ArrayType dimensions _)}+ | length dimensions == length indexes -> []+ | length dimensions == 0 && length indexes == 1 -> []+ | otherwise -> [ExtraDimensionalIndex t]+ SynTCDes{designatorErrors= [],+ designatorType= t} -> [NonArrayType t]+ SynTCDes{designatorErrors= errors} -> errors,+ designatorType= case designatorType (syn array)+ of ArrayType _ itemType -> itemType+ _ -> UnknownType},+ AST.Index (Inherited $ inh inherited) (pure $ Inherited $ inh inherited))+ attribution TypeCheck self (inherited, AST.TypeGuard designator q) = {-# SCC "TypeGuard" #-}+ (Synthesized SynTCDes{designatorErrors= case (syn designator, targetType)+ of (SynTCDes{designatorErrors= [],+ designatorType= t}, + Just t') -> assignmentCompatible t' t+ (SynTCDes{designatorErrors= errors}, + Nothing) -> UnknownName q : errors+ (SynTCDes{designatorErrors= errors}, _) -> errors,+ designatorType= fromMaybe UnknownType targetType},+ AST.TypeGuard (Inherited $ inh inherited) q)+ where targetType = Map.lookup q (env $ inh inherited)+ attribution TypeCheck self (inherited, AST.Dereference pointer) =+ (Synthesized SynTCDes{designatorErrors= case syn pointer+ of SynTCDes{designatorErrors= [],+ designatorType= PointerType{}} -> []+ SynTCDes{designatorErrors= [],+ designatorType= NominalType _ (Just PointerType{})} -> []+ SynTCDes{designatorErrors= [],+ designatorType= t} -> [NonPointerType t]+ SynTCDes{designatorErrors= errors} -> errors,+ designatorType= case designatorType (syn pointer)+ of NominalType _ (Just (PointerType t)) -> t+ PointerType t -> t+ _ -> UnknownType},+ AST.Dereference (Inherited $ inh inherited))++unaryNumericOperatorErrors :: SynTCExp -> [Error]+unaryNumericOperatorErrors SynTCExp{expressionErrors= [], inferredType= IntegerType{}} = []+unaryNumericOperatorErrors SynTCExp{expressionErrors= [],+ inferredType= NominalType (AST.NonQualIdent name) Nothing}+ | name `elem` numericTypeNames = []+unaryNumericOperatorErrors SynTCExp{expressionErrors= [], inferredType= t} = [NonNumericType t]+unaryNumericOperatorErrors SynTCExp{expressionErrors= errs} = errs++unaryNumericOperatorType :: (Int -> Int) -> SynTCExp -> Type+unaryNumericOperatorType f SynTCExp{inferredType= IntegerType x} = IntegerType (f x)+unaryNumericOperatorType _ SynTCExp{inferredType= t} = t++binaryNumericOperatorErrors :: SynTCExp -> SynTCExp -> [Error]+binaryNumericOperatorErrors+ SynTCExp{expressionErrors= [], inferredType= NominalType (AST.NonQualIdent name1) Nothing}+ SynTCExp{expressionErrors= [], inferredType= NominalType (AST.NonQualIdent name2) Nothing}+ | name1 `elem` numericTypeNames, name2 `elem` numericTypeNames = []+binaryNumericOperatorErrors+ SynTCExp{expressionErrors= [], inferredType= IntegerType{}}+ SynTCExp{expressionErrors= [], inferredType= NominalType (AST.NonQualIdent name) Nothing}+ | name `elem` numericTypeNames = []+binaryNumericOperatorErrors+ SynTCExp{expressionErrors= [], inferredType= NominalType (AST.NonQualIdent name) Nothing}+ SynTCExp{expressionErrors= [], inferredType= IntegerType{}}+ | name `elem` numericTypeNames = []+binaryNumericOperatorErrors SynTCExp{expressionErrors= [], inferredType= IntegerType{}}+ SynTCExp{expressionErrors= [], inferredType= IntegerType{}} = []+binaryNumericOperatorErrors SynTCExp{expressionErrors= [], inferredType= t1}+ SynTCExp{expressionErrors= [], inferredType= t2}+ | t1 == t2 = [NonNumericType t1]+ | otherwise = [TypeMismatch t1 t2]+binaryNumericOperatorErrors SynTCExp{expressionErrors= errs1} SynTCExp{expressionErrors= errs2} = errs1 <> errs2++binaryNumericOperatorType :: (Int -> Int -> Int) -> SynTCExp -> SynTCExp -> Type+binaryNumericOperatorType f SynTCExp{inferredType= IntegerType x} SynTCExp{inferredType= IntegerType y} =+ IntegerType (f x y)+binaryNumericOperatorType _ SynTCExp{inferredType= t1} SynTCExp{inferredType= t2}+ | t1 == t2 = t1+ | IntegerType{} <- t1 = t2+ | IntegerType{} <- t2 = t1+ | NominalType (AST.NonQualIdent name1) Nothing <- t1,+ NominalType (AST.NonQualIdent name2) Nothing <- t2,+ Just index1 <- List.elemIndex name1 numericTypeNames,+ Just index2 <- List.elemIndex name2 numericTypeNames =+ NominalType (AST.NonQualIdent $ numericTypeNames !! max index1 index2) Nothing+ | otherwise = t1++binaryIntegerOperatorErrors :: SynTCExp -> SynTCExp -> [Error]+binaryIntegerOperatorErrors syn1 syn2 = integerExpressionErrors syn1 <> integerExpressionErrors syn2++integerExpressionErrors SynTCExp{expressionErrors= [], inferredType= t} = expectInteger t+ where expectInteger IntegerType{} = []+ expectInteger (NominalType (AST.NonQualIdent "SHORTINT") Nothing) = []+ expectInteger (NominalType (AST.NonQualIdent "INTEGER") Nothing) = []+ expectInteger (NominalType (AST.NonQualIdent "LONGINT") Nothing) = []+ expectInteger t = [NonIntegerType t]+integerExpressionErrors SynTCExp{expressionErrors= errs} = errs++booleanExpressionErrors SynTCExp{expressionErrors= [],+ inferredType= NominalType (AST.NonQualIdent "BOOLEAN") Nothing} = []+booleanExpressionErrors SynTCExp{expressionErrors= [], inferredType= t} = [NonBooleanType t]+booleanExpressionErrors SynTCExp{expressionErrors= errs} = errs++binaryBooleanOperatorErrors :: SynTCExp -> SynTCExp -> [Error]+binaryBooleanOperatorErrors+ SynTCExp{expressionErrors= [], inferredType= NominalType (AST.NonQualIdent "BOOLEAN") Nothing}+ SynTCExp{expressionErrors= [], inferredType= NominalType (AST.NonQualIdent "BOOLEAN") Nothing} = []+binaryBooleanOperatorErrors SynTCExp{expressionErrors= [], inferredType= t1}+ SynTCExp{expressionErrors= [], inferredType= t2}+ | t1 == t2 = [NonBooleanType t1]+ | otherwise = [TypeMismatch t1 t2]++parameterCompatible :: (Bool, Type) -> Type -> [Error]+parameterCompatible (True, expected) actual+ | expected == actual = []+ | otherwise = [UnequalTypes expected actual]+parameterCompatible (False, expected) actual = assignmentCompatible expected actual++assignmentCompatible :: Type -> Type -> [Error]+assignmentCompatible expected actual+ | expected == actual = []+ | NominalType (AST.NonQualIdent name1) Nothing <- expected,+ NominalType (AST.NonQualIdent name2) Nothing <- actual,+ Just index1 <- List.elemIndex name1 numericTypeNames,+ Just index2 <- List.elemIndex name2 numericTypeNames, + index1 >= index2 = []+ | NominalType (AST.NonQualIdent name) Nothing <- expected,+ IntegerType{} <- actual, name `elem` numericTypeNames = []+ | expected == NominalType (AST.NonQualIdent "BASIC TYPE") Nothing,+ NominalType (AST.NonQualIdent q) Nothing <- actual,+ q `elem` ["BOOLEAN", "CHAR", "SHORTINT", "INTEGER", "LONGINT", "REAL", "LONGREAL", "SET"] = []+ | expected == NominalType (AST.NonQualIdent "POINTER") Nothing, PointerType{} <- actual = []+ | expected == NominalType (AST.NonQualIdent "POINTER") Nothing, NominalType _ (Just t) <- actual =+ assignmentCompatible expected t+ | expected == NominalType (AST.NonQualIdent "CHAR") Nothing, actual == StringType 1 = []+ | NilType <- actual, PointerType{} <- expected = []+ | NilType <- actual, ProcedureType{} <- expected = []+ | NilType <- actual, NominalType _ (Just t) <- expected = assignmentCompatible t actual+ | ArrayType [] (NominalType (AST.NonQualIdent "CHAR") Nothing) <- expected, StringType{} <- actual = []+ | ArrayType [m] (NominalType (AST.NonQualIdent "CHAR") Nothing) <- expected, StringType n <- actual = + if m < n then [TooSmallArrayType expected] else []+ | targetExtends actual expected = []+ | NominalType _ (Just t) <- expected, ProcedureType{} <- actual = assignmentCompatible t actual+ | otherwise = error (show (expected, actual))++extends, targetExtends :: Type -> Type -> Bool+t1 `extends` t2 | t1 == t2 = True+RecordType ancestry _ `extends` NominalType q _ = q `elem` ancestry+NominalType _ (Just t1) `extends` t2 = t1 `extends` t2+t1 `extends` t2 = False -- error (show (t1, t2))++numericTypeNames = ["SHORTINT", "INTEGER", "LONGINT", "REAL", "LONGREAL"]++PointerType t1 `targetExtends` PointerType t2 = t1 `extends` t2+NominalType _ (Just t1) `targetExtends` t2 = t1 `targetExtends` t2+t1 `targetExtends` NominalType _ (Just t2) = t1 `targetExtends` t2+t1 `targetExtends` t2 | t1 == t2 = True+t1 `targetExtends` t2 = False++-- * More boring Shallow.Functor instances, TH candidates+instance Shallow.Functor TypeCheck Identity (Semantics TypeCheck)+ (Modules (Semantics TypeCheck) (Semantics TypeCheck)) where+ (<$>) = AG.mapDefault runIdentity+instance Shallow.Functor TypeCheck Identity (Semantics TypeCheck)+ (AST.Module (Semantics TypeCheck) (Semantics TypeCheck)) where+ (<$>) = AG.mapDefault runIdentity+instance Shallow.Functor TypeCheck Identity (Semantics TypeCheck)+ (AST.Declaration (Semantics TypeCheck) (Semantics TypeCheck)) where+ (<$>) = AG.mapDefault runIdentity+instance Shallow.Functor TypeCheck Identity (Semantics TypeCheck)+ (AST.FormalParameters (Semantics TypeCheck) (Semantics TypeCheck)) where+ (<$>) = AG.mapDefault runIdentity+instance Shallow.Functor TypeCheck Identity (Semantics TypeCheck)+ (AST.FPSection (Semantics TypeCheck) (Semantics TypeCheck)) where+ (<$>) = AG.mapDefault runIdentity+instance Shallow.Functor TypeCheck Identity (Semantics TypeCheck)+ (Deep.Product AST.Expression AST.StatementSequence (Semantics TypeCheck) (Semantics TypeCheck)) where+ (<$>) = AG.mapDefault runIdentity+instance Shallow.Functor TypeCheck Identity (Semantics TypeCheck)+ (AST.StatementSequence (Semantics TypeCheck) (Semantics TypeCheck)) where+ (<$>) = AG.mapDefault runIdentity+instance Shallow.Functor TypeCheck Identity (Semantics TypeCheck)+ (AST.Statement (Semantics TypeCheck) (Semantics TypeCheck)) where+ (<$>) = AG.mapDefault runIdentity+instance Shallow.Functor TypeCheck Identity (Semantics TypeCheck)+ (AST.Case (Semantics TypeCheck) (Semantics TypeCheck)) where+ (<$>) = AG.mapDefault runIdentity+instance Shallow.Functor TypeCheck Identity (Semantics TypeCheck)+ (AST.CaseLabels (Semantics TypeCheck) (Semantics TypeCheck)) where+ (<$>) = AG.mapDefault runIdentity+instance Shallow.Functor TypeCheck Identity (Semantics TypeCheck)+ (AST.WithAlternative (Semantics TypeCheck) (Semantics TypeCheck)) where+ (<$>) = AG.mapDefault runIdentity+instance Shallow.Functor TypeCheck Identity (Semantics TypeCheck)+ (AST.Expression (Semantics TypeCheck) (Semantics TypeCheck)) where+ (<$>) = AG.mapDefault runIdentity+instance Shallow.Functor TypeCheck Identity (Semantics TypeCheck)+ (AST.Element (Semantics TypeCheck) (Semantics TypeCheck)) where+ (<$>) = AG.mapDefault runIdentity+instance Shallow.Functor TypeCheck Identity (Semantics TypeCheck)+ (AST.Designator (Semantics TypeCheck) (Semantics TypeCheck)) where+ (<$>) = AG.mapDefault runIdentity+instance Shallow.Functor TypeCheck Identity (Semantics TypeCheck)+ (AST.Type (Semantics TypeCheck) (Semantics TypeCheck)) where+ (<$>) = AG.mapDefault runIdentity+instance Shallow.Functor TypeCheck Identity (Semantics TypeCheck)+ (AST.FieldList (Semantics TypeCheck) (Semantics TypeCheck)) where+ (<$>) = AG.mapDefault runIdentity++-- * Unsafe Rank2 AST instances++instance Rank2.Apply (AST.Module f') where+ AST.Module ident1a imports1 decls1 body1 ident1b <*> ~(AST.Module ident2a imports2 decls2 body2 ident2b) =+ AST.Module ident1a imports1 (liftA2 Rank2.apply decls1 decls2) (liftA2 Rank2.apply body1 body2) ident1b++checkModules :: Environment -> Map AST.Ident (AST.Module Identity Identity) -> [Error]+checkModules predef modules = + errors (syn (TypeCheck Shallow.<$> Identity (TypeCheck Deep.<$> Modules (Identity <$> modules))+ `Rank2.apply`+ Inherited (InhTC predef)))++predefined, predefined2 :: Environment+-- | The set of 'Predefined' types and procedures defined in the Oberon Language Report.+predefined = Map.fromList $ map (first AST.NonQualIdent) $+ [("BOOLEAN", NominalType (AST.NonQualIdent "BOOLEAN") Nothing),+ ("CHAR", NominalType (AST.NonQualIdent "CHAR") Nothing),+ ("SHORTINT", NominalType (AST.NonQualIdent "SHORTINT") Nothing),+ ("INTEGER", NominalType (AST.NonQualIdent "INTEGER") Nothing),+ ("LONGINT", NominalType (AST.NonQualIdent "LONGINT") Nothing),+ ("REAL", NominalType (AST.NonQualIdent "REAL") Nothing),+ ("LONGREAL", NominalType (AST.NonQualIdent "LONGREAL") Nothing),+ ("SET", NominalType (AST.NonQualIdent "SET") Nothing),+ ("TRUE", NominalType (AST.NonQualIdent "BOOLEAN") Nothing),+ ("FALSE", NominalType (AST.NonQualIdent "BOOLEAN") Nothing),+ ("ABS", ProcedureType [(False, NominalType (AST.NonQualIdent "INTEGER") Nothing)] $+ Just $ NominalType (AST.NonQualIdent "INTEGER") Nothing),+ ("ASH", ProcedureType [(False, NominalType (AST.NonQualIdent "INTEGER") Nothing)] $+ Just $ NominalType (AST.NonQualIdent "INTEGER") Nothing),+ ("CAP", ProcedureType [(False, NominalType (AST.NonQualIdent "CHAR") Nothing)] $+ Just $ NominalType (AST.NonQualIdent "CHAR") Nothing),+ ("LEN", ProcedureType [(False, NominalType (AST.NonQualIdent "ARRAY") Nothing)] $+ Just $ NominalType (AST.NonQualIdent "LONGINT") Nothing),+ ("MAX", ProcedureType [(False, NominalType (AST.NonQualIdent "BASIC TYPE") Nothing)] $ Just $ IntegerType 0),+ ("MIN", ProcedureType [(False, NominalType (AST.NonQualIdent "BASIC TYPE") Nothing)] $ Just $ IntegerType 0),+ ("ODD", ProcedureType [(False, NominalType (AST.NonQualIdent "CHAR") Nothing)] $+ Just $ NominalType (AST.NonQualIdent "BOOLEAN") Nothing),+ ("SIZE", ProcedureType [(False, NominalType (AST.NonQualIdent "CHAR") Nothing)] $+ Just $ NominalType (AST.NonQualIdent "INTEGER") Nothing),+ ("ORD", ProcedureType [(False, NominalType (AST.NonQualIdent "CHAR") Nothing)] $+ Just $ NominalType (AST.NonQualIdent "INTEGER") Nothing),+ ("CHR", ProcedureType [(False, NominalType (AST.NonQualIdent "INTEGER") Nothing)] $+ Just $ NominalType (AST.NonQualIdent "CHAR") Nothing),+ ("SHORT", ProcedureType [(False, NominalType (AST.NonQualIdent "INTEGER") Nothing)]+ $ Just $ NominalType (AST.NonQualIdent "INTEGER") Nothing),+ ("LONG", ProcedureType [(False, NominalType (AST.NonQualIdent "INTEGER") Nothing)] $+ Just $ NominalType (AST.NonQualIdent "INTEGER") Nothing),+ ("ENTIER", ProcedureType [(False, NominalType (AST.NonQualIdent "REAL") Nothing)] $+ Just $ NominalType (AST.NonQualIdent "INTEGER") Nothing),+ ("INC", ProcedureType [(False, NominalType (AST.NonQualIdent "INTEGER") Nothing)] Nothing),+ ("DEC", ProcedureType [(False, NominalType (AST.NonQualIdent "INTEGER") Nothing)] Nothing),+ ("INCL", ProcedureType [(False, NominalType (AST.NonQualIdent "SET") Nothing),+ (False, NominalType (AST.NonQualIdent "INTEGER") Nothing)] Nothing),+ ("EXCL", ProcedureType [(False, NominalType (AST.NonQualIdent "SET") Nothing),+ (False, NominalType (AST.NonQualIdent "INTEGER") Nothing)] Nothing),+ ("COPY", ProcedureType [(False, NominalType (AST.NonQualIdent "ARRAY") Nothing),+ (False, NominalType (AST.NonQualIdent "ARRAY") Nothing)] Nothing),+ ("NEW", ProcedureType [(False, NominalType (AST.NonQualIdent "POINTER") Nothing)] Nothing),+ ("HALT", ProcedureType [(False, NominalType (AST.NonQualIdent "INTEGER") Nothing)] Nothing)]++-- | The set of 'Predefined' types and procedures defined in the Oberon-2 Language Report.+predefined2 = predefined <>+ Map.fromList (first AST.NonQualIdent <$>+ [("ASSERT", ProcedureType [(False, NominalType (AST.NonQualIdent "BOOL") Nothing),+ (False, NominalType (AST.NonQualIdent "INTEGER") Nothing)] Nothing)])++$(mconcat <$> mapM Rank2.TH.unsafeDeriveApply+ [''AST.Declaration, ''AST.Type, ''AST.Expression,+ ''AST.Element, ''AST.Designator, ''AST.FieldList,+ ''AST.ProcedureHeading, ''AST.FormalParameters, ''AST.FPSection, ''AST.ProcedureBody,+ ''AST.Statement, ''AST.StatementSequence, ''AST.WithAlternative, ''AST.Case, ''AST.CaseLabels])
+ src/Transformation.hs view
@@ -0,0 +1,23 @@+{-# Language DeriveDataTypeable, FlexibleContexts, FlexibleInstances, FunctionalDependencies, MultiParamTypeClasses, + PolyKinds, RankNTypes, StandaloneDeriving, TypeFamilies, TypeOperators, UndecidableInstances #-}++module Transformation where++import qualified Rank2++import Prelude hiding (Foldable(..), Traversable(..), Functor(..), Applicative(..), (<$>), fst, snd)++class Functor t p q x | t -> p q where+ (<$>) :: t -> p x -> q x++class Foldable t p m x | t -> p m where+ foldMap :: t -> p x -> m++class Traversable t p q m x | t -> p q m where+ traverse :: t -> p x -> m (q x)++fmap :: Functor t p q x => t -> p x -> q x+fmap = (<$>)++instance Functor (Rank2.Arrow p q x) p q x where+ (<$>) = Rank2.apply
+ src/Transformation/AG.hs view
@@ -0,0 +1,37 @@+{-# Language DefaultSignatures, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, StandaloneDeriving,+ TypeFamilies, TypeOperators, UndecidableInstances #-}++module Transformation.AG where++import Data.Functor.Identity+import qualified Rank2+import qualified Transformation as Shallow+import qualified Transformation.Deep as Deep++data Inherited a g = Inherited{inh :: Atts (Inherited a) g}+data Synthesized a g = Synthesized{syn :: Atts (Synthesized a) g}++type family Atts (f :: * -> *) x+deriving instance (Show (Atts (Inherited a) g)) => Show (Inherited a g)+deriving instance (Show (Atts (Synthesized a) g)) => Show (Synthesized a g)+-- type instance Atts Identity f = f Identity+-- type instance Atts (Inherited a Rank2.~> Synthesized a) g = Atts (Inherited a) g -> Atts (Synthesized a) g++type Semantics a = Inherited a Rank2.~> Synthesized a++type Rule a g (f :: * -> *) = g f (Semantics a)+ -> (Inherited a (g f (Semantics a)), g f (Synthesized a))+ -> (Synthesized a (g f (Semantics a)), g f (Inherited a))++knit :: Rank2.Apply (g f) => Rule a g f -> g f (Semantics a) -> Semantics a (g f (Semantics a))+knit r chSem = Rank2.Arrow knit'+ where knit' inh = syn+ where (syn, chInh) = r chSem (inh, chSyn)+ chSyn = chSem Rank2.<*> chInh++class Shallow.Functor t Identity (Semantics t) (g (Semantics t) (Semantics t)) => Attribution t g where+ attribution :: t -> Rule t g (Semantics t)++mapDefault :: (q ~ Semantics t, x ~ g q q, Rank2.Apply (g q), Attribution t g) => (p x -> x) -> t -> p x -> q x+mapDefault extract t sem = knit (attribution t) (extract sem)+{-# INLINE mapDefault #-}
+ src/Transformation/Deep.hs view
@@ -0,0 +1,83 @@+{-# Language DeriveDataTypeable, FlexibleContexts, FlexibleInstances, FunctionalDependencies, MultiParamTypeClasses,+ PolyKinds, RankNTypes, StandaloneDeriving, TypeFamilies, TypeOperators, UndecidableInstances #-}++module Transformation.Deep where++import Control.Applicative ((<*>), liftA2)+import Data.Data (Data, Typeable)+import Data.Monoid (Monoid, (<>))+import qualified Rank2+import qualified Data.Foldable+import qualified Data.Functor+import qualified Data.Traversable+import qualified Transformation as Shallow++import Prelude hiding (Foldable(..), Traversable(..), Functor(..), Applicative(..), (<$>), fst, snd)++class Rank2.Functor (g p) => Functor t g (p :: * -> *) (q :: * -> *) where+ (<$>) :: t -> g p p -> g q q++class Rank2.Foldable (g p) => Foldable t g p m where+ foldMap :: t -> g p p -> m++class Rank2.Traversable (g p) => UpTraversable t g (p :: * -> *) (q :: * -> *) m where+ traverseUp :: t -> g p p -> m (g q q)++class Rank2.Traversable (g p) => DownTraversable t g (p :: * -> *) (q :: * -> *) m where+ traverseDown :: t -> g p p -> m (g q q)++data Product g1 g2 (p :: * -> *) (q :: * -> *) = Pair{fst :: q (g1 p p),+ snd :: q (g2 p p)}++instance Rank2.Functor (Product g1 g2 p) where+ f <$> ~(Pair left right) = Pair (f left) (f right)++instance Rank2.Apply (Product g h p) where+ ~(Pair g1 h1) <*> ~(Pair g2 h2) = Pair (Rank2.apply g1 g2) (Rank2.apply h1 h2)+ liftA2 f ~(Pair g1 h1) ~(Pair g2 h2) = Pair (f g1 g2) (f h1 h2)++instance Rank2.Applicative (Product g h p) where+ pure f = Pair f f++instance Rank2.Foldable (Product g h p) where+ foldMap f ~(Pair g h) = f g `mappend` f h++instance Rank2.Traversable (Product g h p) where+ traverse f ~(Pair g h) = liftA2 Pair (f g) (f h)++instance Rank2.DistributiveTraversable (Product g h p)++instance Rank2.Distributive (Product g h p) where+ cotraverse w f = Pair{fst= w (fst Data.Functor.<$> f),+ snd= w (snd Data.Functor.<$> f)}++instance (Data.Functor.Functor p, Shallow.Functor t p q (g1 q q), Shallow.Functor t p q (g2 q q),+ Functor t g1 p q, Functor t g2 p q) => Functor t (Product g1 g2) p q where+ t <$> Pair left right = Pair (t Shallow.<$> ((t <$>) Data.Functor.<$> left)) + (t Shallow.<$> ((t <$>) Data.Functor.<$> right))++instance (Monoid m, Data.Foldable.Foldable p,+ Foldable t g1 p m, Foldable t g2 p m) => Foldable t (Product g1 g2) p m where+ foldMap t (Pair left right) = Data.Foldable.foldMap (foldMap t) left+ <> Data.Foldable.foldMap (foldMap t) right++instance (Monad m, Data.Traversable.Traversable p,+ Shallow.Traversable t p q m (g1 q q), Shallow.Traversable t p q m (g2 q q),+ UpTraversable t g1 p q m, UpTraversable t g2 p q m) => UpTraversable t (Product g1 g2) p q m where+ traverseUp t (Pair left right) =+ Pair Data.Functor.<$> (Data.Traversable.traverse (traverseUp t) left >>= Shallow.traverse t)+ Control.Applicative.<*> (Data.Traversable.traverse (traverseUp t) right >>= Shallow.traverse t)++instance (Monad m, Data.Traversable.Traversable q,+ Shallow.Traversable t p q m (g1 p p), Shallow.Traversable t p q m (g2 p p),+ DownTraversable t g1 p q m, DownTraversable t g2 p q m) => DownTraversable t (Product g1 g2) p q m where+ traverseDown t (Pair left right) =+ Pair Data.Functor.<$> (Shallow.traverse t left >>= Data.Traversable.traverse (traverseDown t))+ Control.Applicative.<*> (Shallow.traverse t right >>= Data.Traversable.traverse (traverseDown t))++deriving instance (Typeable p, Typeable q, Typeable g1, Typeable g2,+ Data (q (g1 p p)), Data (q (g2 p p))) => Data (Product g1 g2 p q)+deriving instance (Show (q (g1 p p)), Show (q (g2 p p))) => Show (Product g1 g2 p q)++fmap :: Functor t g p q => t -> g p p -> g q q+fmap = (<$>)
+ src/Transformation/Deep/TH.hs view
@@ -0,0 +1,287 @@+-- | This module exports the templates for automatic instance deriving of "Transformation.Deep" type classes. The most+-- common way to use it would be+--+-- > import qualified Transformation.Deep.TH+-- > data MyDataType f' f = ...+-- > $(Transformation.Deep.TH.deriveFunctor ''MyDataType)+--++{-# Language TemplateHaskell #-}+-- Adapted from https://wiki.haskell.org/A_practical_Template_Haskell_Tutorial++module Transformation.Deep.TH (deriveAll, deriveFunctor, deriveFoldable, deriveDownTraversable, deriveUpTraversable)+where++import Control.Monad (replicateM)+import Data.Monoid ((<>))+import Language.Haskell.TH+import Language.Haskell.TH.Syntax (BangType, VarBangType, getQ, putQ)++import qualified Transformation+import qualified Transformation.Deep+import qualified Rank2.TH+++data Deriving = Deriving { _constructor :: Name, _variableN :: Name, _variable1 :: Name }++deriveAll :: Name -> Q [Dec]+deriveAll ty = foldr f (pure []) [Rank2.TH.deriveFunctor, Rank2.TH.deriveFoldable, Rank2.TH.deriveTraversable,+ Transformation.Deep.TH.deriveFunctor, Transformation.Deep.TH.deriveFoldable,+ Transformation.Deep.TH.deriveDownTraversable,+ Transformation.Deep.TH.deriveUpTraversable]+ where f derive rest = (<>) <$> derive ty <*> rest++deriveFunctor :: Name -> Q [Dec]+deriveFunctor ty = do+ t <- varT <$> newName "t"+ p <- varT <$> newName "p"+ q <- varT <$> newName "q"+ let deepConstraint ty = conT ''Transformation.Deep.Functor `appT` t `appT` ty `appT` p `appT` q+ shallowConstraint ty =+ conT ''Transformation.Functor `appT` t `appT` p `appT` q `appT` (ty `appT` q `appT` q)+ (instanceType, cs) <- reifyConstructors ty+ (constraints, dec) <- genDeepmap deepConstraint shallowConstraint cs+ sequence [instanceD (cxt (appT (conT ''Functor) p : map pure constraints))+ (deepConstraint instanceType)+ [pure dec]]++deriveFoldable :: Name -> Q [Dec]+deriveFoldable ty = do+ t <- varT <$> newName "t"+ f <- varT <$> newName "f"+ m <- varT <$> newName "m"+ let deepConstraint ty = conT ''Transformation.Deep.Foldable `appT` t `appT` ty `appT` f `appT` m+ shallowConstraint ty =+ conT ''Transformation.Foldable `appT` t `appT` f `appT` m `appT` (ty `appT` f `appT` f)+ (instanceType, cs) <- reifyConstructors ty+ (constraints, dec) <- genFoldMap deepConstraint shallowConstraint cs+ sequence [instanceD (cxt (appT (conT ''Monoid) m : appT (conT ''Foldable) f : map pure constraints))+ (deepConstraint instanceType)+ [pure dec]]++deriveDownTraversable :: Name -> Q [Dec]+deriveDownTraversable ty = do+ t <- varT <$> newName "t"+ p <- varT <$> newName "p"+ q <- varT <$> newName "q"+ m <- varT <$> newName "m"+ let deepConstraint ty = conT ''Transformation.Deep.DownTraversable `appT` t `appT` ty `appT` p `appT` q `appT` m+ shallowConstraint ty =+ conT ''Transformation.Traversable `appT` t `appT` p `appT` q `appT` m `appT` (ty `appT` p `appT` p)+ (instanceType, cs) <- reifyConstructors ty+ (constraints, dec) <- genTraverseDown deepConstraint shallowConstraint cs+ sequence [instanceD (cxt (appT (conT ''Monad) m : appT (conT ''Traversable) q : map pure constraints))+ (deepConstraint instanceType)+ [pure dec]]++deriveUpTraversable :: Name -> Q [Dec]+deriveUpTraversable ty = do+ t <- varT <$> newName "t"+ p <- varT <$> newName "p"+ q <- varT <$> newName "q"+ m <- varT <$> newName "m"+ let deepConstraint ty = conT ''Transformation.Deep.UpTraversable `appT` t `appT` ty `appT` p `appT` q `appT` m+ shallowConstraint ty =+ conT ''Transformation.Traversable `appT` t `appT` p `appT` q `appT` m `appT` (ty `appT` q `appT` q)+ (instanceType, cs) <- reifyConstructors ty+ (constraints, dec) <- genTraverseUp deepConstraint shallowConstraint cs+ sequence [instanceD (cxt (appT (conT ''Monad) m : appT (conT ''Traversable) p : map pure constraints))+ (deepConstraint instanceType)+ [pure dec]]++reifyConstructors :: Name -> Q (TypeQ, [Con])+reifyConstructors ty = do+ (TyConI tyCon) <- reify ty+ (tyConName, tyVars, _kind, cs) <- case tyCon of+ DataD _ nm tyVars kind cs _ -> return (nm, tyVars, kind, cs)+ NewtypeD _ nm tyVars kind c _ -> return (nm, tyVars, kind, [c])+ _ -> fail "deriveApply: tyCon may not be a type synonym."++ let (KindedTV tyVar (AppT (AppT ArrowT StarT) StarT) :+ KindedTV tyVar' (AppT (AppT ArrowT StarT) StarT) : _) = reverse tyVars+ instanceType = foldl apply (conT tyConName) (reverse $ drop 2 $ reverse tyVars)+ apply t (PlainTV name) = appT t (varT name)+ apply t (KindedTV name _) = appT t (varT name)++ putQ (Deriving tyConName tyVar' tyVar)+ return (instanceType, cs)++genDeepmap :: (Q Type -> Q Type) -> (Q Type -> Q Type) -> [Con] -> Q ([Type], Dec)+genDeepmap deepConstraint shallowConstraint cs = do+ (constraints, clauses) <- unzip <$> mapM (genDeepmapClause deepConstraint shallowConstraint) cs+ return (concat constraints, FunD '(Transformation.Deep.<$>) clauses)++genFoldMap :: (Q Type -> Q Type) -> (Q Type -> Q Type) -> [Con] -> Q ([Type], Dec)+genFoldMap deepConstraint shallowConstraint cs = do+ (constraints, clauses) <- unzip <$> mapM (genFoldMapClause deepConstraint shallowConstraint) cs+ return (concat constraints, FunD 'Transformation.Deep.foldMap clauses)++genTraverseDown :: (Q Type -> Q Type) -> (Q Type -> Q Type) -> [Con] -> Q ([Type], Dec)+genTraverseDown deepConstraint shallowConstraint cs = do+ (constraints, clauses) <- unzip <$> mapM (genTraverseClause genTraverseDownField deepConstraint shallowConstraint) cs+ return (concat constraints, FunD 'Transformation.Deep.traverseDown clauses)++genTraverseUp :: (Q Type -> Q Type) -> (Q Type -> Q Type) -> [Con] -> Q ([Type], Dec)+genTraverseUp deepConstraint shallowConstraint cs = do+ (constraints, clauses) <- unzip <$> mapM (genTraverseClause genTraverseUpField deepConstraint shallowConstraint) cs+ return (concat constraints, FunD 'Transformation.Deep.traverseUp clauses)++genDeepmapClause :: (Q Type -> Q Type) -> (Q Type -> Q Type) -> Con -> Q ([Type], Clause)+genDeepmapClause deepConstraint shallowConstraint (NormalC name fieldTypes) = do+ t <- newName "t"+ fieldNames <- replicateM (length fieldTypes) (newName "x")+ let pats = [varP t, parensP (conP name $ map varP fieldNames)]+ constraintsAndFields = zipWith newField fieldNames fieldTypes+ newFields = map (snd <$>) constraintsAndFields+ body = normalB $ appsE $ conE name : newFields+ newField :: Name -> BangType -> Q ([Type], Exp)+ newField x (_, fieldType) = genDeepmapField (varE t) fieldType deepConstraint shallowConstraint (varE x) id+ constraints <- (concat . (fst <$>)) <$> sequence constraintsAndFields+ (,) constraints <$> clause pats body []+genDeepmapClause deepConstraint shallowConstraint (RecC name fields) = do+ f <- newName "f"+ x <- newName "x"+ let body = normalB $ recConE name $ (snd <$>) <$> constraintsAndFields+ constraintsAndFields = map newNamedField fields+ newNamedField :: VarBangType -> Q ([Type], (Name, Exp))+ newNamedField (fieldName, _, fieldType) =+ ((,) fieldName <$>)+ <$> genDeepmapField (varE f) fieldType deepConstraint shallowConstraint (appE (varE fieldName) (varE x)) id+ constraints <- (concat . (fst <$>)) <$> sequence constraintsAndFields+ (,) constraints <$> clause [varP f, varP x] body []++genFoldMapClause :: (Q Type -> Q Type) -> (Q Type -> Q Type) -> Con -> Q ([Type], Clause)+genFoldMapClause deepConstraint shallowConstraint (NormalC name fieldTypes) = do+ t <- newName "t"+ fieldNames <- replicateM (length fieldTypes) (newName "x")+ let pats = [varP t, parensP (conP name $ map varP fieldNames)]+ constraintsAndFields = zipWith newField fieldNames fieldTypes+ newFields = map (snd <$>) constraintsAndFields+ body | null newFields = [| mempty |]+ | otherwise = foldr1 append newFields+ append a b = [| $(a) <> $(b) |]+ newField :: Name -> BangType -> Q ([Type], Exp)+ newField x (_, fieldType) = genFoldMapField (varE t) fieldType deepConstraint shallowConstraint (varE x) id+ constraints <- (concat . (fst <$>)) <$> sequence constraintsAndFields+ (,) constraints <$> clause pats (normalB body) []+genFoldMapClause deepConstraint shallowConstraint (RecC _name fields) = do+ t <- newName "t"+ x <- newName "x"+ let body | null fields = [| mempty |]+ | otherwise = foldr1 append $ (snd <$>) <$> constraintsAndFields+ append a b = [| $(a) <> $(b) |]+ constraintsAndFields = map newNamedField fields+ newNamedField :: VarBangType -> Q ([Type], Exp)+ newNamedField (fieldName, _, fieldType) =+ genFoldMapField (varE t) fieldType deepConstraint shallowConstraint (appE (varE fieldName) (varE x)) id+ constraints <- (concat . (fst <$>)) <$> sequence constraintsAndFields+ (,) constraints <$> clause [varP t, varP x] (normalB body) []++type GenTraverseFieldType = Q Exp -> Type -> (Q Type -> Q Type) -> (Q Type -> Q Type) -> Q Exp -> (Q Exp -> Q Exp)+ -> Q ([Type], Exp)++genTraverseClause :: GenTraverseFieldType -> (Q Type -> Q Type) -> (Q Type -> Q Type) -> Con -> Q ([Type], Clause)+genTraverseClause genTraverseField deepConstraint shallowConstraint (NormalC name fieldTypes) = do+ t <- newName "t"+ fieldNames <- replicateM (length fieldTypes) (newName "x")+ let pats = [varP t, parensP (conP name $ map varP fieldNames)]+ constraintsAndFields = zipWith newField fieldNames fieldTypes+ newFields = map (snd <$>) constraintsAndFields+ body | null fieldTypes = [| pure $(conE name) |]+ | otherwise = fst $ foldl apply (conE name, False) newFields+ apply (a, False) b = ([| $(a) <$> $(b) |], True)+ apply (a, True) b = ([| $(a) <*> $(b) |], True)+ newField :: Name -> BangType -> Q ([Type], Exp)+ newField x (_, fieldType) = genTraverseField (varE t) fieldType deepConstraint shallowConstraint (varE x) id+ constraints <- (concat . (fst <$>)) <$> sequence constraintsAndFields+ (,) constraints <$> clause pats (normalB body) []+genTraverseClause genTraverseField deepConstraint shallowConstraint (RecC name fields) = do+ f <- newName "f"+ x <- newName "x"+ let constraintsAndFields = map newNamedField fields+ body | null fields = [| pure $(conE name) |]+ | otherwise = fst (foldl apply (conE name, False) $ map (snd . snd <$>) constraintsAndFields)+ apply (a, False) b = ([| $(a) <$> $(b) |], True)+ apply (a, True) b = ([| $(a) <*> $(b) |], True)+ newNamedField :: VarBangType -> Q ([Type], (Name, Exp))+ newNamedField (fieldName, _, fieldType) =+ ((,) fieldName <$>)+ <$> genTraverseField (varE f) fieldType deepConstraint shallowConstraint (appE (varE fieldName) (varE x)) id+ constraints <- (concat . (fst <$>)) <$> sequence constraintsAndFields+ (,) constraints <$> clause [varP f, varP x] (normalB body) []++genDeepmapField :: Q Exp -> Type -> (Q Type -> Q Type) -> (Q Type -> Q Type) -> Q Exp -> (Q Exp -> Q Exp)+ -> Q ([Type], Exp)+genDeepmapField trans fieldType deepConstraint shallowConstraint fieldAccess wrap = do+ Just (Deriving _ typeVarN typeVar1) <- getQ+ case fieldType of+ AppT ty (AppT (AppT con v1) v2) | ty == VarT typeVar1, v1 == VarT typeVarN, v2 == VarT typeVarN ->+ (,) <$> ((:) <$> deepConstraint (pure con) <*> ((:[]) <$> shallowConstraint (pure con)))+ <*> appE (wrap [| (Transformation.fmap $trans . (Transformation.Deep.fmap $trans <$>)) |]) fieldAccess+ AppT ty _ | ty == VarT typeVar1 ->+ (,) [] <$> (wrap (varE 'Transformation.fmap `appE` trans) `appE` fieldAccess)+ AppT (AppT con v1) v2 | v1 == VarT typeVarN, v2 == VarT typeVar1 ->+ (,) <$> ((:[]) <$> deepConstraint (pure con))+ <*> appE (wrap [| Transformation.Deep.fmap $trans |]) fieldAccess+ AppT t1 t2 | t1 /= VarT typeVar1 ->+ genDeepmapField trans t2 deepConstraint shallowConstraint fieldAccess (wrap . appE (varE '(<$>)))+ SigT ty _kind -> genDeepmapField trans ty deepConstraint shallowConstraint fieldAccess wrap+ ParensT ty -> genDeepmapField trans ty deepConstraint shallowConstraint fieldAccess wrap+ _ -> (,) [] <$> fieldAccess++genFoldMapField :: Q Exp -> Type -> (Q Type -> Q Type) -> (Q Type -> Q Type) -> Q Exp -> (Q Exp -> Q Exp)+ -> Q ([Type], Exp)+genFoldMapField trans fieldType deepConstraint shallowConstraint fieldAccess wrap = do+ Just (Deriving _ typeVarN typeVar1) <- getQ+ case fieldType of+ AppT ty (AppT (AppT con v1) v2) | ty == VarT typeVar1, v1 == VarT typeVarN, v2 == VarT typeVarN ->+ (,) <$> ((:) <$> deepConstraint (pure con) <*> ((:[]) <$> shallowConstraint (pure con)))+ <*> appE (wrap [| foldMap (Transformation.Deep.foldMap $trans) |]) fieldAccess+ AppT ty _ | ty == VarT typeVar1 ->+ (,) [] <$> (wrap (varE 'Transformation.foldMap `appE` trans) `appE` fieldAccess)+ AppT (AppT con v1) v2 | v1 == VarT typeVarN, v2 == VarT typeVar1 ->+ (,) <$> ((:[]) <$> deepConstraint (pure con))+ <*> appE (wrap [| Transformation.Deep.foldMap $trans |]) fieldAccess+ AppT t1 t2 | t1 /= VarT typeVar1 ->+ genFoldMapField trans t2 deepConstraint shallowConstraint fieldAccess (wrap . appE (varE 'foldMap))+ SigT ty _kind -> genFoldMapField trans ty deepConstraint shallowConstraint fieldAccess wrap+ ParensT ty -> genFoldMapField trans ty deepConstraint shallowConstraint fieldAccess wrap+ _ -> (,) [] <$> [| mempty |]++genTraverseDownField :: GenTraverseFieldType+genTraverseDownField trans fieldType deepConstraint shallowConstraint fieldAccess wrap = do+ Just (Deriving _ typeVarN typeVar1) <- getQ+ case fieldType of+ AppT ty (AppT (AppT con v1) v2) | ty == VarT typeVar1, v1 == VarT typeVarN, v2 == VarT typeVarN ->+ (,) <$> ((:) <$> deepConstraint (pure con) <*> ((:[]) <$> shallowConstraint (pure con)))+ <*> appE (wrap [| (>>= traverse (Transformation.Deep.traverseDown $trans)) . Transformation.traverse $trans |])+ fieldAccess+ AppT ty _ | ty == VarT typeVar1 ->+ (,) [] <$> (wrap (varE 'Transformation.traverse `appE` trans) `appE` fieldAccess)+ AppT (AppT con v1) v2 | v1 == VarT typeVarN, v2 == VarT typeVar1 ->+ (,) <$> ((:[]) <$> deepConstraint (pure con))+ <*> appE (wrap [| Transformation.Deep.traverseDown $trans |]) fieldAccess+ AppT t1 t2 | t1 /= VarT typeVar1 ->+ genTraverseDownField trans t2 deepConstraint shallowConstraint fieldAccess (wrap . appE (varE 'traverse))+ SigT ty _kind -> genTraverseDownField trans ty deepConstraint shallowConstraint fieldAccess wrap+ ParensT ty -> genTraverseDownField trans ty deepConstraint shallowConstraint fieldAccess wrap+ _ -> (,) [] <$> [| pure $fieldAccess |]++genTraverseUpField :: GenTraverseFieldType+genTraverseUpField trans fieldType deepConstraint shallowConstraint fieldAccess wrap = do+ Just (Deriving _ typeVarN typeVar1) <- getQ+ case fieldType of+ AppT ty (AppT (AppT con v1) v2) | ty == VarT typeVar1, v1 == VarT typeVarN, v2 == VarT typeVarN ->+ (,) <$> ((:) <$> deepConstraint (pure con) <*> ((:[]) <$> shallowConstraint (pure con)))+ <*> appE (wrap [| (>>= Transformation.traverse $trans) . traverse (Transformation.Deep.traverseUp $trans) |])+ fieldAccess+ AppT ty _ | ty == VarT typeVar1 ->+ (,) [] <$> (wrap (varE 'Transformation.traverse `appE` trans) `appE` fieldAccess)+ AppT (AppT con v1) v2 | v1 == VarT typeVarN, v2 == VarT typeVar1 ->+ (,) <$> ((:[]) <$> deepConstraint (pure con))+ <*> appE (wrap [| Transformation.Deep.traverseUp $trans |]) fieldAccess+ AppT t1 t2 | t1 /= VarT typeVar1 ->+ genTraverseUpField trans t2 deepConstraint shallowConstraint fieldAccess (wrap . appE (varE 'traverse))+ SigT ty _kind -> genTraverseUpField trans ty deepConstraint shallowConstraint fieldAccess wrap+ ParensT ty -> genTraverseUpField trans ty deepConstraint shallowConstraint fieldAccess wrap+ _ -> (,) [] <$> [| pure $fieldAccess |]
+ src/Transformation/Rank2.hs view
@@ -0,0 +1,36 @@+{-# Language DeriveDataTypeable, FlexibleContexts, FlexibleInstances, FunctionalDependencies, MultiParamTypeClasses, + PolyKinds, RankNTypes, StandaloneDeriving, TypeFamilies, TypeOperators, UndecidableInstances #-}++module Transformation.Rank2 where++import qualified Transformation as Shallow+import qualified Transformation.Deep as Deep++import Prelude hiding (Foldable(..), Traversable(..), Functor(..), Applicative(..), (<$>), fst, snd)++newtype Map p q = Map (forall x. p x -> q x)++newtype Fold p m = Fold (forall x. p x -> m)++newtype Traversal p q m = Traversal (forall x. p x -> m (q x))++instance Shallow.Functor (Map p q) p q x where+ (<$>) (Map f) = f++instance Shallow.Foldable (Fold p m) p m x where+ foldMap (Fold f) = f++instance Shallow.Traversable (Traversal p q m) p q m x where+ traverse (Traversal t) = t++(<$>) :: Deep.Functor (Map p q) g p q => (forall a. p a -> q a) -> g p p -> g q q+(<$>) f = (Deep.<$>) (Map f)++foldMap :: (Deep.Foldable (Fold p m) g p m, Monoid m) => (forall a. p a -> m) -> g p p -> m+foldMap f = Deep.foldMap (Fold f)++traverseDown :: Deep.DownTraversable (Traversal p q m) g p q m => (forall a. p a -> m (q a)) -> g p p -> m (g q q)+traverseDown f = Deep.traverseDown (Traversal f)++traverseUp :: Deep.UpTraversable (Traversal p q m) g p q m => (forall a. p a -> m (q a)) -> g p p -> m (g q q)+traverseUp f = Deep.traverseUp (Traversal f)
test/Test.hs view
@@ -2,15 +2,29 @@ import Data.Either.Validation (Validation(..)) import Data.List (isSuffixOf)+import Data.List.NonEmpty (NonEmpty((:|)))+import Data.Text (Text)+import Data.Text.IO (readFile)+import Data.Text.Prettyprint.Doc (Pretty(pretty), layoutPretty, defaultLayoutOptions)+import Data.Text.Prettyprint.Doc.Render.Text (renderStrict) import System.Directory (doesDirectoryExist, listDirectory) import System.FilePath.Posix (combine)+import Text.Grampa (showFailure) import Test.Tasty (TestTree, defaultMain, testGroup)-import Test.Tasty.HUnit (assertFailure, testCase)+import Test.Tasty.HUnit (assertFailure, assertEqual, testCase) -import Language.Oberon (parseAndResolveModuleFile)+import Language.Oberon (parseAndResolveModule)+import Language.Oberon.Pretty ()+import qualified Language.Oberon.Resolver as Resolver +import Prelude hiding (readFile)+ main = exampleTree "" "examples" >>= defaultMain . testGroup "Oberon" +width = 80+contextLines = 3++exampleTree :: FilePath -> FilePath -> IO [TestTree] exampleTree ancestry path = do let fullPath = combine ancestry path isDir <- doesDirectoryExist fullPath@@ -18,8 +32,16 @@ then (:[]) . testGroup path . concat <$> (listDirectory fullPath >>= mapM (exampleTree fullPath)) else if ".Mod" `isSuffixOf` path then return . (:[]) . testCase path $- do resolvedModule <- parseAndResolveModuleFile True fullPath- case resolvedModule- of Failure err -> assertFailure (show err)- Success{} -> pure ()+ do moduleSource <- readFile fullPath+ prettyModule <- prettyFile ancestry moduleSource+ prettyModule' <- prettyFile ancestry prettyModule+ assertEqual "pretty" prettyModule prettyModule' else return []++prettyFile :: FilePath -> Text -> IO Text+prettyFile dirPath source = do+ resolvedModule <- parseAndResolveModule True True dirPath source+ case resolvedModule+ of Failure (Resolver.UnparseableModule err :| []) -> assertFailure (showFailure source err contextLines)+ Failure errs -> assertFailure (show errs)+ Success mod -> return (renderStrict $ layoutPretty defaultLayoutOptions $ pretty mod)