packages feed

language-oberon 0.2.1 → 0.3

raw patch · 20 files changed

+3686/−2180 lines, 20 filesdep +base-orphansdep +deep-transformationsdep +input-parsersdep ~basedep ~grammatical-parsersdep ~prettyprinter

Dependencies added: base-orphans, deep-transformations, input-parsers

Dependency ranges changed: base, grammatical-parsers, prettyprinter, rank2classes, template-haskell

Files

ChangeLog.md view
@@ -1,5 +1,14 @@ # Revision history for language-oberon +## 0.3  -- 2020-11-01++* Preserving the parsed start and end positions and lexemes of every node+* Added the `Reserializer` module and the `--original` command-line option+* Added the `ConstantFolder` module+* Moved the `Transformation` modules into the new `deep-transformations` package+* Eliminated many of the attribute grammar rules using `Tranformation.AG.Generics`+* Added the `README`+ ## 0.2.1  -- 2019-01-27  * Pretty-printer fixes
+ README.md view
@@ -0,0 +1,18 @@+language-oberon - Oberon parser, pretty-printer, and more+---------------------------------------------------------++This package provides a library and executable for parsing and processing the source code in programming language+Oberon. The following functionality is presently available:++* Parsing with the grammars specified in the+  [Grammar](http://hackage.haskell.org/package/language-oberon/docs/Language-Oberon-Grammar.html) module.+* Resolution of identifiers and disambiguation of a parsed AST with the+  [Resolver](http://hackage.haskell.org/package/language-oberon/docs/Language-Oberon-Resolver.html) module.+* Checking and reporting of type errors with the+  [TypeChecker](http://hackage.haskell.org/package/language-oberon/docs/Language-Oberon-TypeChecker.html) module.+* Constant folding with the+  [ConstantFolder](http://hackage.haskell.org/package/language-oberon/docs/Language-Oberon-ConstantFolder.html) module.+* Re-printing of a parsed AST in its original form, preserving the whitespace and comments, with the+  [Reserializer](http://hackage.haskell.org/package/language-oberon/docs/Language-Oberon-Reserializer.html) module.+* Pretty-printing of a parsed AST with the+  [Pretty](http://hackage.haskell.org/package/language-oberon/docs/Language-Oberon-Pretty.html) module.
app/Parse.hs view
@@ -1,49 +1,59 @@-{-# LANGUAGE FlexibleInstances, RankNTypes, RecordWildCards, ScopedTypeVariables #-}+{-# LANGUAGE FlexibleContexts, FlexibleInstances, RankNTypes, RecordWildCards, ScopedTypeVariables, TypeFamilies #-}  module Main where -import Language.Oberon (parseAndResolveModule)-import Language.Oberon.AST (Module(..), StatementSequence, Statement, Expression)+import Language.Oberon (Placed, LanguageVersion(Oberon1, Oberon2), Options(..), parseAndResolveModule)+import Language.Oberon.AST (Language, Module(..), StatementSequence, Statement, Expression)+import qualified Language.Oberon.AST as AST import qualified Language.Oberon.Grammar as Grammar-import qualified Language.Oberon.Resolver as Resolver import qualified Language.Oberon.Pretty ()+import qualified Language.Oberon.Reserializer as Reserializer+import qualified Language.Oberon.Resolver as Resolver+import qualified Language.Oberon.TypeChecker as TypeChecker++import qualified Transformation.Rank2 as Rank2+import qualified Transformation.Deep as Deep+ import Data.Text.Prettyprint.Doc (Pretty(pretty)) import Data.Text.Prettyprint.Doc.Util (putDocW) +import Control.Arrow (second) import Control.Monad import Data.Data (Data) import Data.Either.Validation (Validation(..), validationToEither)-import Data.Functor.Identity (Identity)-import Data.Functor.Compose (getCompose)+import Data.Functor.Identity (Identity(Identity))+import Data.Functor.Compose (Compose(..)) import Data.List.NonEmpty (NonEmpty((:|)))-import qualified Data.Map.Lazy as Map import Data.Maybe (fromMaybe) import Data.Monoid ((<>)) import Data.Text (Text, unpack) import Data.Text.IO (getLine, readFile, getContents)-import Data.Typeable (Typeable)+import qualified Data.Text.IO as Text import Options.Applicative-import Text.Grampa (Ambiguous, Grammar, ParseResults, parseComplete, showFailure)+import qualified Text.Parser.Input.Position as Position+import Text.Grampa (Ambiguous, Grammar, parseComplete, failureDescription) import qualified Text.Grampa.ContextFree.LeftRecursive as LeftRecursive import ReprTree-import System.FilePath (FilePath, takeDirectory)+import System.FilePath (FilePath, addExtension, combine, takeDirectory)  import Prelude hiding (getLine, getContents, readFile) -data GrammarMode = TypeCheckedModuleMode | ModuleWithImportsMode | ModuleMode | AmbiguousModuleMode | DefinitionMode-                 | StatementsMode | StatementMode | ExpressionMode+data GrammarMode = ModuleWithImportsMode | ModuleMode | AmbiguousModuleMode | DefinitionMode+                 | StatementMode | ExpressionMode     deriving Show -data Output = Plain | Pretty Int | Tree+data Output = Original | Plain | Pretty Int | Tree             deriving Show  data Opts = Opts-    { optsMode        :: GrammarMode-    , optsOberon2     :: Bool-    , optsIndex       :: Int-    , optsOutput      :: Output-    , optsInclude     :: Maybe FilePath-    , optsFile        :: Maybe FilePath+    { optsMode          :: GrammarMode+    , optsVersion       :: LanguageVersion+    , optsCheckTypes    :: Bool+    , optsFoldConstants :: Bool+    , optsIndex         :: Int+    , optsOutput        :: Output+    , optsInclude       :: Maybe FilePath+    , optsFile          :: Maybe FilePath     } deriving Show  main :: IO ()@@ -57,10 +67,15 @@     p :: Parser Opts     p = Opts         <$> mode-        <*> (switch (long "oberon2"))+        <*> (flag' Oberon2 (long "oberon2")+             <|> flag' Oberon1 (long "oberon1")+             <|> pure Oberon2)+        <*> (switch (long "check-types"))+        <*> (switch (long "fold-constants"))         <*> (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")-             <|> Tree <$ switch (long "tree" <> help "Print the output as an abstract syntax tree")+             <|> flag' Tree (long "tree" <> help "Print the output as an abstract syntax tree")+             <|> flag' Original (long "original" <> help "Print the output with the original tokens and whitespace")              <|> pure Plain)         <*> optional (strOption (short 'i' <> long "include" <> metavar "DIRECTORY"                                  <> help "Where to look for imports"))@@ -69,79 +84,120 @@               <> help "Oberon file to parse"))      mode :: Parser GrammarMode-    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")-       <|> StatementMode       <$ switch (long "statement")-       <|> StatementsMode      <$ switch (long "statements")-       <|> ExpressionMode      <$ switch (long "expression")+    mode = flag' ModuleWithImportsMode (long "module-with-imports")+       <|> flag' ModuleMode            (long "module")+       <|> flag' AmbiguousModuleMode   (long "module-ambiguous")+       <|> flag' DefinitionMode        (long "definition")+       <|> flag' StatementMode         (long "statement")+       <|> flag' ExpressionMode        (long "expression")  main' :: Opts -> IO () main' Opts{..} =     case optsFile of         Just file -> (if file == "-" then getContents else readFile file)                      >>= case optsMode-                         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-                                                   Grammar.oberonDefinitionGrammar file-                            AmbiguousModuleMode -> go pure Grammar.module_prod chosenGrammar file-                            _                   -> error "A file usually contains a whole module."+                         of ModuleWithImportsMode ->+                               let dir = fromMaybe (takeDirectory file) optsInclude+                               in \source-> parseAndResolveModule Options{checkTypes= optsCheckTypes,+                                                                          foldConstants= optsFoldConstants,+                                                                          version= optsVersion} dir source+                                            >>= succeed optsOutput (reportTypeErrorIn dir) id+                            ModuleMode ->+                              go (Resolver.resolveModule predefined mempty) Grammar.module_prod chosenGrammar file+                            DefinitionMode ->+                              go (Resolver.resolveModule predefined mempty) Grammar.module_prod+                                 Grammar.oberonDefinitionGrammar file+                            AmbiguousModuleMode ->+                              go pure Grammar.module_prod chosenGrammar file+                            _ -> error "A file usually contains a whole module."          Nothing ->             forever $             getLine >>=             case optsMode of+                ModuleWithImportsMode ->+                    let dir = fromMaybe "." optsInclude+                    in \source-> parseAndResolveModule Options{checkTypes= optsCheckTypes,+                                                               foldConstants= optsFoldConstants,+                                                               version= optsVersion} dir source+                                 >>= succeed optsOutput (reportTypeErrorIn dir) id                 ModuleMode          -> go (Resolver.resolveModule predefined mempty) Grammar.module_prod                                           chosenGrammar "<stdin>"                 AmbiguousModuleMode -> go pure Grammar.module_prod chosenGrammar "<stdin>"                 DefinitionMode      -> go (Resolver.resolveModule predefined mempty) Grammar.module_prod                                           Grammar.oberonDefinitionGrammar "<stdin>"                 StatementMode       -> go pure Grammar.statement chosenGrammar "<stdin>"-                StatementsMode      -> go pure Grammar.statementSequence chosenGrammar "<stdin>"                 ExpressionMode      -> go pure Grammar.expression chosenGrammar "<stdin>"+   where-    chosenGrammar = if optsOberon2 then Grammar.oberon2Grammar else Grammar.oberonGrammar-    predefined = if optsOberon2 then Resolver.predefined2 else Resolver.predefined-    go :: (Show f, Data f, Pretty f) => -          (f' -> Validation (NonEmpty Resolver.Error) f)-       -> (forall p. Grammar.OberonGrammar Ambiguous p -> p f')-       -> (Grammar (Grammar.OberonGrammar Ambiguous) LeftRecursive.Parser Text)+    chosenGrammar = case optsVersion +                    of Oberon1 -> Grammar.oberonGrammar+                       Oberon2 -> Grammar.oberon2Grammar +    predefined = case optsVersion +                 of Oberon1 -> Resolver.predefined+                    Oberon2 -> Resolver.predefined2+    go :: (Data a, Flattenable a, Pretty a, Show a, a ~ f (g f f),+           Deep.Functor (Rank2.Map Grammar.NodeWrap NodeWrap) g) =>+          (NodeWrap (g NodeWrap NodeWrap) -> Validation (NonEmpty (Resolver.Error Language)) a)+       -> (forall p. Grammar.OberonGrammar AST.Language Grammar.NodeWrap p+                  -> p (Grammar.NodeWrap (g Grammar.NodeWrap Grammar.NodeWrap)))+       -> (Grammar (Grammar.OberonGrammar AST.Language Grammar.NodeWrap) Grammar.Parser Text)        -> String -> Text -> IO ()     go resolve production grammar filename contents =-       case getCompose (production $ parseComplete grammar contents)-       of Right [x] -> succeed optsOutput contents (resolve x)+       case getCompose (second (Resolver.resolvePositions contents)+            <$> getCompose (production $ parseComplete grammar contents))+       of Right [(s, x)] -> succeed optsOutput (reportTypeErrorIn $ takeDirectory filename) Left (resolve x)           Right l -> putStrLn ("Ambiguous: " ++ show optsIndex ++ "/" ++ show (length l) ++ " parses")-                     >> succeed optsOutput contents (resolve $ l !! optsIndex)-          Left err -> putStrLn (showFailure contents err 3)+                     >> succeed optsOutput (reportTypeErrorIn $ takeDirectory filename) Left (resolve . snd $ l !! optsIndex)+          Left err -> Text.putStrLn (failureDescription contents err 4) -succeed out contents x = either reportFailure showSuccess (validationToEither x)-   where reportFailure (Resolver.UnparseableModule err :| []) = putStrLn (showFailure contents err 3)-         reportFailure errs = print errs+type NodeWrap = Compose ((,) (Int, Int)) (Compose Ambiguous ((,) Grammar.ParsedLexemes))++succeed :: (Data a, Flattenable a, Pretty a, Show a)+        => Output -> (TypeChecker.Error Language -> IO ())+        -> (err -> Either (NonEmpty (Resolver.Error Language)) (NonEmpty (TypeChecker.Error Language)))+        -> Validation err a -> IO ()+succeed out reportTypeError prepare x = either (reportFailure . prepare) showSuccess (validationToEither x)+   where reportFailure (Left (Resolver.UnparseableModule err :| [])) = Text.putStrLn err+         reportFailure (Left errs) = print errs+         reportFailure (Right errs) = mapM_ reportTypeError errs          showSuccess = case out-                       of Pretty width -> putDocW width . pretty+                       of Original -> Text.putStr . flatten+                          Pretty width -> putDocW width . pretty                           Tree -> putStrLn . reprTreeString                           Plain -> print -instance Pretty (Module Ambiguous Ambiguous) where-   pretty _ = error "Disambiguate before pretty-printing"-instance Pretty (StatementSequence Ambiguous Ambiguous) where+reportTypeErrorIn directory (moduleName, (pos, _, _), err) =+   do contents <- readFile (combine directory $ addExtension (unpack moduleName) "Mod")+      putStrLn ("Type error: " ++ TypeChecker.errorMessage err)+      Text.putStrLn (Position.context contents (Position.fromStart pos) 4)++class Flattenable a where+   flatten :: a -> Text++instance Flattenable (Placed (Module Language Language Placed Placed)) where+   flatten = Reserializer.reserialize+instance Flattenable (Placed (StatementSequence Language Language Placed Placed)) where+   flatten = Reserializer.reserialize+instance Flattenable (Placed (Statement Language Language Placed Placed)) where+   flatten = Reserializer.reserialize+instance Flattenable (Placed (Expression Language Language Placed Placed)) where+   flatten = Reserializer.reserialize++instance Flattenable (NodeWrap a) where+   flatten = error "Disambiguate before serializing"++instance {-# overlaps #-} Pretty a => Pretty (Placed a) where+   pretty = pretty . snd+instance Pretty (Module Language Language Placed Placed) where+   pretty m = pretty ((Identity . snd) Rank2.<$> m)+instance Pretty (Module Language Language NodeWrap NodeWrap) where    pretty _ = error "Disambiguate before pretty-printing"-instance Pretty (Ambiguous (Statement Ambiguous Ambiguous)) where+instance Pretty (StatementSequence Language Language NodeWrap NodeWrap) where    pretty _ = error "Disambiguate before pretty-printing"-instance Pretty (Statement Ambiguous Ambiguous) where+instance Pretty (Statement Language Language NodeWrap NodeWrap) where    pretty _ = error "Disambiguate before pretty-printing"-instance Pretty (Expression Ambiguous Ambiguous) where+instance Pretty (Expression Language Language NodeWrap NodeWrap) where    pretty _ = error "Disambiguate before pretty-printing"-instance Pretty (Ambiguous (Expression Ambiguous Ambiguous)) where+instance Pretty (NodeWrap a) where    pretty _ = error "Disambiguate before pretty-printing"
examples/AGRS/Texts.Def view
@@ -38,7 +38,27 @@    pos: LONGINT; (* Offset of Finder in text. *)   END; +  Handler* = PROCEDURE (e: Elem; VAR msg: ElemMsg);+  ElemMsg* = RECORD END ;++  Run = POINTER TO RunDesc;+  RunDesc = RECORD+   prev, next: Run;+   len: LONGINT;+   fnt: Fonts.Font;+   col, voff: SHORTINT;+   ascii: BOOLEAN+  END ;++  Elem* = POINTER TO ElemDesc;+  ElemDesc* = RECORD (RunDesc)+   W*, H*: LONGINT;+   handle*: Handler;+   base: Text+  END ;+   Reader = RECORD (* Character-wise reader of a text stream. *)+   elem*: Elem;    lib: Objects.Library; (* Library of last character/object read. *)    col: SHORTINT; (* Color index of last character read. *)    voff: SHORTINT; (* vertical offset of last character read. *)
language-oberon.cabal view
@@ -2,20 +2,15 @@ -- documentation, see http://haskell.org/cabal/users-guide/  name:                language-oberon-version:             0.2.1-synopsis:            Parser, pretty-printer, and type checker for the Oberon programming language+version:             0.3+synopsis:            Parser, pretty-printer, and more 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>.    .-   The grammars in "Language.Oberon.Grammar" attempt to follow the language grammars from the reports, while-   generating a semantically meaningful abstract syntax tree; the latter is defined in "Language.Oberon.AST". As the-   grammars are ambiguous, it is necessary to resolve the ambiguities after parsing all Oberon modules in use.-   "Language.Oberon.Resolver" provides this functionality. Only after the ambiguity resolution can the abstract syntax-   tree be pretty-printed using the instances from "Language.Oberon.Pretty".-   .    The original purpose for the library was to be a test of the underlying-   <http://hackage.haskell.org/package/grammatical-parsers grammatical-parsers> library. The experiment succeeded, so    the package can be used in practice.+   <http://hackage.haskell.org/package/grammatical-parsers grammatical-parsers> library. The experiment succeeded, so+   the package can be used in practice.  homepage:            https://github.com/blamario/language-oberon bug-reports:         https://github.com/blamario/language-oberon/issues@@ -23,39 +18,43 @@ license-file:        LICENSE author:              Mario Blažević maintainer:          blamario@protonmail.com--- copyright:+copyright:           (c) 2018 Mario Blažević category:            Language build-type:          Simple-extra-source-files:  ChangeLog.md, examples/AGRS/*.Def, examples/AGRS/*.Mod+extra-source-files:  README.md, ChangeLog.md, examples/AGRS/*.Def, examples/AGRS/*.Mod cabal-version:       >=1.10  library   hs-source-dirs:       src   exposed-modules:      Language.Oberon,-                        Language.Oberon.AST, Language.Oberon.Grammar,-                        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.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+                        Language.Oberon.Abstract, Language.Oberon.AST, Language.Oberon.ConstantFolder,+                        Language.Oberon.Grammar, Language.Oberon.Pretty, Language.Oberon.Reserializer,+                        Language.Oberon.Resolver, Language.Oberon.TypeChecker+  build-depends:        base >= 4.12 && < 5, base-orphans >= 0.8.2 && < 1.0,+                        text < 1.3, containers >= 0.5 && < 1.0, filepath < 1.5, directory < 1.4,+                        parsers >= 0.12.7 && < 0.13, input-parsers < 0.2,+                        prettyprinter >= 1.2.1 && < 1.8, either == 5.*,+                        rank2classes >= 1.3 && < 1.5, grammatical-parsers >= 0.5 && < 0.6, deep-transformations < 0.2,+                        transformers == 0.5.*,+                        template-haskell >= 2.11 && < 2.17   default-language:     Haskell2010  executable parse   main-is:             app/Parse.hs   -- 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.2.1 && < 1.3,-                       rank2classes < 1.3, grammatical-parsers > 0.3.1 && < 0.4, language-oberon,+  build-depends:       base >= 4.12 && < 5, text < 1.3, either == 5.*, containers >= 0.5 && < 1.0,+                       repr-tree-syb < 0.2, filepath < 1.5, prettyprinter,+                       rank2classes, input-parsers, grammatical-parsers, deep-transformations < 0.2,+                       language-oberon,                        optparse-applicative   default-language:    Haskell2010  test-suite             examples   type:                exitcode-stdio-1.0-  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,+  build-depends:       base >= 4.12 && < 5, text < 1.3, grammatical-parsers,+                       either == 5.*, directory < 2, filepath < 1.5, prettyprinter,+                       deep-transformations < 0.2,                        tasty >= 0.7, tasty-hunit,                        language-oberon   main-is:             test/Test.hs
src/Language/Oberon.hs view
@@ -1,85 +1,131 @@--- | Every function in this module takes a flag that determines whether the input is an Oberon or Oberon-2 module.+{-# Language FlexibleContexts, RecordWildCards, TypeFamilies #-} -module Language.Oberon (parseModule, parseAndResolveModule, parseAndResolveModuleFile) where+-- | The programming languages Oberon and Oberon-2 -import Language.Oberon.AST (Module(..))+module Language.Oberon (parseModule, parseAndResolveModule, parseAndResolveModuleFile,+                        LanguageVersion(..), Options(..), NodeWrap, Placed) where++import Language.Oberon.AST (Language, Module(..)) import qualified Language.Oberon.Grammar as Grammar import qualified Language.Oberon.Resolver as Resolver+import qualified Language.Oberon.Reserializer as Reserializer+import qualified Language.Oberon.ConstantFolder as ConstantFolder import qualified Language.Oberon.TypeChecker as TypeChecker+import Language.Oberon.Resolver (NodeWrap, Placed) -import Control.Monad (when)+import qualified Transformation.Deep as Deep+import qualified Transformation.Full as Full++import Control.Monad (guard) import Data.Either.Validation (Validation(..))-import Data.Functor.Identity (Identity)-import Data.Functor.Compose (getCompose)+import Data.Functor.Compose (Compose(Compose, getCompose)) import Data.List.NonEmpty (NonEmpty((:|)))+import qualified Data.List.NonEmpty as NonEmpty import qualified Data.Map.Lazy as Map import Data.Map.Lazy (Map) import Data.Monoid ((<>)) import Data.Text (Text, unpack) import Data.Text.IO (readFile)-import Text.Grampa (Ambiguous, Grammar, ParseResults, parseComplete)+import Text.Grampa (Ambiguous(Ambiguous), Grammar, ParseResults, parseComplete, failureDescription) import qualified Text.Grampa.ContextFree.LeftRecursive as LeftRecursive import System.Directory (doesFileExist) import System.FilePath (FilePath, addExtension, combine, takeDirectory)  import Prelude hiding (readFile) +data LanguageVersion = Oberon1 | Oberon2 deriving (Eq, Ord, Show)++-- | choice of modes of operation+data Options = Options{+   -- | whether to fold the constants+   foldConstants :: Bool,+   -- | whether to verify the types+   checkTypes :: Bool,+   -- | which language version?+   version :: LanguageVersion}++moduleGrammar Oberon1 = Grammar.oberonGrammar+moduleGrammar Oberon2 = Grammar.oberon2Grammar ++definitionGrammar Oberon1 = Grammar.oberonDefinitionGrammar+definitionGrammar Oberon2 = Grammar.oberon2DefinitionGrammar + -- | Parse the given text of a single module, without resolving the syntactic ambiguities.-parseModule :: Bool -> Text -> ParseResults [Module Ambiguous Ambiguous]-parseModule oberon2 = getCompose . Grammar.module_prod-                      . parseComplete (if oberon2 then Grammar.oberon2Grammar else Grammar.oberonGrammar)+parseModule :: LanguageVersion -> Text -> ParseResults Text [NodeWrap (Module Language Language NodeWrap NodeWrap)]+parseModule version src =+  getCompose (Resolver.resolvePositions src . snd+              <$> (getCompose $ Grammar.module_prod $ parseComplete (moduleGrammar version) src))  -- | Parse the given text of a single /definition/ module, without resolving the syntactic ambiguities.-parseDefinitionModule :: Bool -> Text -> ParseResults [Module Ambiguous Ambiguous]-parseDefinitionModule oberon2 = getCompose . Grammar.module_prod-                                . parseComplete (if oberon2 then Grammar.oberon2DefinitionGrammar-                                                 else Grammar.oberonDefinitionGrammar)+parseDefinitionModule :: LanguageVersion -> Text+                      -> ParseResults Text [NodeWrap (Module Language Language NodeWrap NodeWrap)]+parseDefinitionModule version src =+  getCompose (Resolver.resolvePositions src . snd+              <$> (getCompose $ Grammar.module_prod $ parseComplete (definitionGrammar version) src)) -parseNamedModule :: Bool -> FilePath -> Text -> IO (ParseResults [Module Ambiguous Ambiguous])-parseNamedModule oberon2 path name =+parseNamedModule :: LanguageVersion -> FilePath -> Text+                 -> IO (ParseResults Text [NodeWrap (Module Language Language NodeWrap NodeWrap)])+parseNamedModule version path name =    do let basePath = combine path (unpack name)       isDefn <- doesFileExist (addExtension basePath "Def")-      let grammar = if oberon2-                    then if isDefn then Grammar.oberon2DefinitionGrammar else Grammar.oberon2Grammar-                    else if isDefn then Grammar.oberonDefinitionGrammar else Grammar.oberonGrammar-      getCompose . Grammar.module_prod . parseComplete grammar-         <$> readFile (addExtension basePath $ if isDefn then "Def" else "Mod")+      let grammar = (if isDefn then definitionGrammar else moduleGrammar) version+      src <- readFile (addExtension basePath $ if isDefn then "Def" else "Mod")+      return (getCompose $ Resolver.resolvePositions src . snd+                           <$> (getCompose $ Grammar.module_prod $ parseComplete grammar src)) -parseImportsOf :: Bool -> FilePath -> Map Text (Module Ambiguous Ambiguous) -> IO (Map Text (Module Ambiguous Ambiguous))-parseImportsOf oberon2 path modules =+parseImportsOf :: LanguageVersion -> FilePath -> Map Text (NodeWrap (Module Language Language NodeWrap NodeWrap))+               -> IO (Map Text (NodeWrap (Module Language Language NodeWrap NodeWrap)))+parseImportsOf version path modules =    case filter (`Map.notMember` modules) moduleImports    of [] -> return modules       newImports -> (((modules <>) . Map.fromList . map assertSuccess) <$>-                     (traverse . traverse) (parseNamedModule oberon2 path) [(p, p) | p <- newImports])-                    >>= parseImportsOf oberon2 path-   where moduleImports = foldMap importsOf modules-         importsOf (Module _ imports _ _ _) = snd <$> imports-         assertSuccess (m, Left err) = error ("Parse error in module " <> unpack m <> ":" <> show err)+                     (traverse . traverse) (parseNamedModule version path) [(p, p) | p <- newImports])+                    >>= parseImportsOf version path+   where moduleImports = foldMap importsOf (Compose modules)+         importsOf (Module _ imports _) = snd <$> imports+         assertSuccess (m, Left err) = error ("Parse error in module " <> unpack m)          assertSuccess (m, Right [p]) = (m, p)          assertSuccess (m, Right _) = error ("Ambiguous parses of module " <> unpack m)  -- | 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 -> 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)+parseAndResolveModule :: Options -> FilePath -> Text+                      -> IO (Validation (Either (NonEmpty (Resolver.Error Language))+                                                (NonEmpty (TypeChecker.Error Language)))+                                        (Placed (Module Language Language Placed Placed)))+parseAndResolveModule Options{..} path source =+   case parseModule version source+   of Left err -> return (Failure $ Left $ Resolver.UnparseableModule (failureDescription source err 4) :| [])+      Right [rootModule@(Compose (pos, Compose (Ambiguous ((_, Module moduleName imports _) :| []))))] ->+         do importedModules <- parseImportsOf version path (Map.singleton moduleName rootModule)             let resolvedImportMap = Resolver.resolveModule predefinedScope resolvedImportMap <$> importedModules-                predefinedScope = if oberon2 then Resolver.predefined2 else Resolver.predefined+                predefinedScope = case version +                                  of Oberon1 -> Resolver.predefined+                                     Oberon2 -> Resolver.predefined2                 successful (Success a) = Just a                 successful _ = Nothing+                addLeft (Failure resolutionErrors) = Failure (Left resolutionErrors)+                addLeft (Success result) = Success result+                constantFolded = Reserializer.adjustPositions <$>+                                 ConstantFolder.foldConstants+                                    (case version+                                     of Oberon1 -> ConstantFolder.predefined+                                        Oberon2 -> ConstantFolder.predefined2)+                                    (Map.mapMaybe successful resolvedImportMap)                 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 :| [])+                                (case version +                                 of Oberon1 -> TypeChecker.predefined+                                    Oberon2 -> TypeChecker.predefined2)+                                constantFolded+            return (if checkTypes && not (null typeErrors)+                    then Failure (Right (NonEmpty.fromList typeErrors))+                    else maybe (addLeft $ resolvedImportMap Map.! moduleName) Success+                         (guard foldConstants *> Map.lookup moduleName constantFolded))+      Right _ -> return (Failure $ Left $ Resolver.AmbiguousParses :| [])  -- | Parse the module file at the given path, assuming all its imports are in the same directory.-parseAndResolveModuleFile :: Bool -> Bool -> FilePath-                          -> IO (Validation (NonEmpty Resolver.Error) (Module Identity Identity))-parseAndResolveModuleFile checkTypes oberon2 path =-  readFile path >>= parseAndResolveModule checkTypes oberon2 (takeDirectory path)+parseAndResolveModuleFile :: Options -> FilePath+                          -> IO (Validation (Either (NonEmpty (Resolver.Error Language)) (NonEmpty (TypeChecker.Error Language)))+                                            (Placed (Module Language Language Placed Placed)))+parseAndResolveModuleFile options path =+  readFile path >>= parseAndResolveModule options (takeDirectory path)
src/Language/Oberon/AST.hs view
@@ -1,198 +1,466 @@ {-# LANGUAGE DeriveDataTypeable, FlexibleInstances, MultiParamTypeClasses, UndecidableInstances,-             StandaloneDeriving, TemplateHaskell #-}+             OverloadedStrings, StandaloneDeriving, TemplateHaskell, TypeFamilies #-} {-# OPTIONS_GHC -Wno-simplifiable-class-constraints #-} --- | Oberon Abstract Syntax Tree definitions+-- | Concrete data types for Oberon constructs that make up its Abstract Syntax Tree. Every data type from this module+-- is an instance of a type family declared in "Language.Oberon.Abstract". This way it can be replaced by another data+-- type for another language while leaving other types to be reused. -module Language.Oberon.AST where+module Language.Oberon.AST (module Language.Oberon.AST, RelOp(..)) where +import Control.Applicative (ZipList(ZipList, getZipList))+import Control.Monad (forM, mapM) import Data.Data (Data, Typeable)-import Data.Functor.Identity (Identity)-import Data.List.NonEmpty+import Data.List.NonEmpty (NonEmpty((:|))) import Data.Text (Text) -import Transformation.Deep (Product)+import qualified Transformation+import qualified Transformation.Shallow as Shallow+import qualified Transformation.Shallow.TH import qualified Transformation.Deep.TH+import qualified Transformation.AG as AG import qualified Rank2.TH -data Module f' f = Module Ident [Import] ([f (Declaration f' f')]) (Maybe (f (StatementSequence f' f'))) Ident+import qualified Language.Oberon.Abstract as Abstract+import Language.Oberon.Abstract (RelOp(..)) -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)+-- | Data type representing the Oberon language, both versions of it.+data Language = Language deriving (Data, Typeable) +instance Abstract.Wirthy Language where+   type Module Language = Module Language+   type Declaration Language = Declaration Language+   type Type Language = Type Language+   type Statement Language = Statement Language+   type Expression Language = Expression Language+   type Designator Language = Designator Language+   type Value Language = Value Language++   type Import Language = Import Language+   type FieldList Language = FieldList Language+   type ProcedureHeading Language = ProcedureHeading Language+   type FormalParameters Language = FormalParameters Language+   type FPSection Language = FPSection Language+   type Block Language = Block Language+   type StatementSequence Language = StatementSequence Language+   type Case Language = Case Language+   type CaseLabels Language = CaseLabels Language+   type ConditionalBranch Language = ConditionalBranch Language+   type Element Language = Element Language++   type IdentDef Language = IdentDef Language+   type QualIdent Language = QualIdent Language++   -- Declaration+   constantDeclaration = ConstantDeclaration+   typeDeclaration = TypeDeclaration+   variableDeclaration = VariableDeclaration+   procedureDeclaration = ProcedureDeclaration++   formalParameters = FormalParameters . ZipList+   fpSection = FPSection+   block = Block . ZipList+   +   fieldList = FieldList++   -- Type+   pointerType = PointerType+   procedureType = ProcedureType+   typeReference = TypeReference++   -- Statement+   assignment = Assignment+   caseStatement scrutinee cases = CaseStatement scrutinee (ZipList cases)+   emptyStatement = EmptyStatement+   exitStatement = Exit+   ifStatement (branch :| branches) = If branch (ZipList branches)+   loopStatement = Loop+   procedureCall proc args = ProcedureCall proc (ZipList <$> args)+   repeatStatement = Repeat+   returnStatement = Return+   whileStatement = While++   conditionalBranch = ConditionalBranch+   caseAlternative (c :| cs) = Case c (ZipList cs)+   labelRange = LabelRange+   singleLabel = SingleLabel+   +   statementSequence = StatementSequence . ZipList++   -- Expression+   add = Add+   and = And+   divide = Divide+   functionCall fun args = FunctionCall fun (ZipList args)+   integerDivide = IntegerDivide+   literal = Literal+   modulo = Modulo+   multiply = Multiply+   negative = Negative+   not = Not+   or = Or+   positive = Positive+   read = Read+   relation = Relation+   subtract = Subtract++   element = Element+   range = Range++   -- Value+   builtin = Builtin+   charCode = CharCode+   false = Boolean False+   integer = Integer+   nil = Nil+   real = Real+   string = String+   true = Boolean True++   -- Designator+   variable = Variable+   field = Field+   index array (i :| is) = Index array i (ZipList is)+   dereference = Dereference++   -- Identifier+   identDef = flip IdentDef PrivateOnly+   nonQualIdent = NonQualIdent++instance Abstract.CoWirthy Language where+   type TargetClass Language = Abstract.Oberon2+   coDeclaration (ConstantDeclaration name value) = Abstract.constantDeclaration name value+   coDeclaration (TypeDeclaration name ty) = Abstract.typeDeclaration name ty+   coDeclaration (VariableDeclaration name ty) = Abstract.variableDeclaration name ty+   coDeclaration (ProcedureDeclaration heading body) = Abstract.procedureDeclaration heading body+   coDeclaration (ForwardDeclaration name params) = Abstract.forwardDeclaration name params+   +   coType (TypeReference q) = Abstract.typeReference q+   coType (ProcedureType params) = Abstract.procedureType params+   coType (PointerType destination) = Abstract.pointerType destination+   coType (ArrayType dimensions itemType) = Abstract.arrayType (getZipList dimensions) itemType+   coType (RecordType baseType fields) = Abstract.recordType baseType (getZipList fields)+   +   coStatement EmptyStatement = Abstract.emptyStatement+   coStatement (Assignment destination expression) = Abstract.assignment destination expression+   coStatement (ProcedureCall procedure parameters) = Abstract.procedureCall procedure $ getZipList <$> parameters+   coStatement (If branch elsifs fallback) = Abstract.ifStatement (branch :| getZipList elsifs) fallback+   coStatement (CaseStatement scrutinee cases fallback) = Abstract.caseStatement scrutinee (getZipList cases) fallback+   coStatement (While condition body) = Abstract.whileStatement condition body+   coStatement (Repeat body condition) = Abstract.repeatStatement body condition+   coStatement (For index from to by body) = Abstract.forStatement index from to by body+   coStatement (Loop body) = Abstract.loopStatement body+   coStatement (With alternative alternatives fallback) =+      Abstract.variantWithStatement (alternative :| getZipList alternatives) fallback+   coStatement Exit = Abstract.exitStatement+   coStatement (Return result) = Abstract.returnStatement result+   +   coExpression (Relation op left right) = Abstract.relation op left right+   coExpression (IsA scrutinee typeName) = Abstract.is scrutinee typeName+   coExpression (Positive e) = Abstract.positive e+   coExpression (Negative e) = Abstract.negative e+   coExpression (Add left right) = Abstract.add left right+   coExpression (Subtract left right) = Abstract.subtract left right+   coExpression (Or left right) = Abstract.or left right+   coExpression (Multiply left right) = Abstract.multiply left right+   coExpression (Divide left right) = Abstract.divide left right+   coExpression (IntegerDivide left right) = Abstract.integerDivide left right+   coExpression (Modulo left right) = Abstract.modulo left right+   coExpression (And left right) = Abstract.and left right+   coExpression (Set elements) = Abstract.set (getZipList elements)+   coExpression (Read var) = Abstract.read var+   coExpression (FunctionCall function parameters) = Abstract.functionCall function $ getZipList parameters+   coExpression (Not e) = Abstract.not e++   coValue Nil = Abstract.nil+   coValue (Boolean False) = Abstract.false+   coValue (Boolean True) = Abstract.true+   coValue (Builtin name) = Abstract.builtin name+   coValue (Integer n) = Abstract.integer n+   coValue (Real r) = Abstract.real r+   coValue (String s) = Abstract.string s+   coValue (CharCode c) = Abstract.charCode c+   +   coDesignator (Variable q) = Abstract.variable q+   coDesignator (Field record name) = Abstract.field record name+   coDesignator (Index array index indexes) = Abstract.index array (index :| getZipList indexes)+   coDesignator (TypeGuard scrutinee typeName) = Abstract.typeGuard scrutinee typeName+   coDesignator (Dereference pointer) = Abstract.dereference pointer++instance Abstract.Nameable Language where+   getProcedureName (ProcedureHeading _ iddef _) = Abstract.getIdentDefName iddef+   getProcedureName (TypeBoundHeading _ _ _ _ iddef _) = Abstract.getIdentDefName iddef+   getIdentDefName (IdentDef name _) = name+   getNonQualIdentName (NonQualIdent name) = Just name+   getNonQualIdentName _ = Nothing++isNamedVar :: Abstract.Nameable l => Ident -> Maybe (Designator Language l f f) -> Bool+isNamedVar name (Just (Variable q)) | Abstract.getNonQualIdentName q == Just name = True+isNamedVar _ _ = False++instance Abstract.Oberon Language where+   type WithAlternative Language = WithAlternative Language+   moduleUnit = Module+   moduleImport = (,)+   exported = flip IdentDef Exported+   qualIdent = QualIdent+   getQualIdentNames (QualIdent moduleName name) = Just (moduleName, name)+   getQualIdentNames _ = Nothing++   arrayType = ArrayType . ZipList+   recordType base fields = RecordType base (ZipList fields)+   procedureHeading = ProcedureHeading+   forwardDeclaration = ForwardDeclaration+   withStatement alt = With alt (ZipList []) Nothing+   withAlternative = WithAlternative+   is = IsA+   set = Set . ZipList+   typeGuard = TypeGuard++instance Abstract.Oberon2 Language where+   readOnly = flip IdentDef ReadOnly+   typeBoundHeading = TypeBoundHeading+   forStatement = For+   variantWithStatement (variant :| variants) = With variant (ZipList variants)++data Module λ l f' f = Module Ident [Import l] (f (Abstract.Block l l f' f'))++deriving instance (Typeable λ, Typeable l, Typeable f, Typeable f', Data (Abstract.Import l),+                   Data (f (Abstract.Block l l f' f'))) =>+                  Data (Module λ l f' f)+deriving instance (Show (Abstract.Import l), Show (f (Abstract.Block l l f' f'))) => Show (Module λ l f' f)+ type Ident = Text -type Import = (Maybe Ident, Ident)+type Import l = (Maybe Ident, Ident) -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')))+data Declaration λ l f' f = ConstantDeclaration (Abstract.IdentDef l) (f (Abstract.ConstExpression l l f' f'))+                          | TypeDeclaration (Abstract.IdentDef l) (f (Abstract.Type l l f' f'))+                          | VariableDeclaration (Abstract.IdentList l) (f (Abstract.Type l l f' f'))+                          | ProcedureDeclaration (f (Abstract.ProcedureHeading l l f' f'))+                                                 (f (Abstract.Block l l f' f'))+                          | ForwardDeclaration (Abstract.IdentDef l) (Maybe (f (Abstract.FormalParameters l l f' 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)+deriving instance (Typeable λ, Typeable l, Typeable f, Typeable f',+                   Data (f (Abstract.Type l l f' f')), Data (f (Abstract.ConstExpression l l f' f')),+                   Data (f (Abstract.FormalParameters l l f' f')), Data (f (Abstract.ProcedureHeading l l f' f')),+                   Data (f (Abstract.Block l l f' f')), Data (Abstract.IdentDef l)) => Data (Declaration λ l f' f)+deriving instance (Show (f (Abstract.Type l l f' f')), Show (f (Abstract.ConstExpression l l f' f')),+                   Show (f (Abstract.FormalParameters l l f' f')), Show (f (Abstract.ProcedureHeading l l f' f')),+                   Show (f (Abstract.Block l l f' f')), Show (Abstract.IdentDef l)) => Show (Declaration λ l f' f) -data IdentDef = IdentDef Ident AccessMode+data QualIdent l = QualIdent Ident Ident +                 | NonQualIdent Ident    deriving (Data, Eq, Ord, Show) +data IdentDef l = IdentDef Ident AccessMode+   deriving (Data, Eq, Ord, Show)+ data AccessMode = Exported | ReadOnly | PrivateOnly    deriving (Data, Eq, Ord, Show) -type ConstExpression = Expression+data Expression λ l f' f = Relation RelOp (f (Abstract.Expression l l f' f')) (f (Abstract.Expression l l f' f'))+                         | IsA (f (Abstract.Expression l l f' f')) (Abstract.QualIdent l)+                         | Positive (f (Abstract.Expression l l f' f'))+                         | Negative (f (Abstract.Expression l l f' f'))+                         | Add (f (Abstract.Expression l l f' f')) (f (Abstract.Expression l l f' f'))+                         | Subtract (f (Abstract.Expression l l f' f')) (f (Abstract.Expression l l f' f'))+                         | Or (f (Abstract.Expression l l f' f')) (f (Abstract.Expression l l f' f'))+                         | Multiply (f (Abstract.Expression l l f' f')) (f (Abstract.Expression l l f' f'))+                         | Divide (f (Abstract.Expression l l f' f')) (f (Abstract.Expression l l f' f'))+                         | IntegerDivide (f (Abstract.Expression l l f' f')) (f (Abstract.Expression l l f' f'))+                         | Modulo (f (Abstract.Expression l l f' f')) (f (Abstract.Expression l l f' f'))+                         | And (f (Abstract.Expression l l f' f')) (f (Abstract.Expression l l f' f'))+                         | Set (ZipList (f (Abstract.Element l l f' f')))+                         | Read (f (Abstract.Designator l l f' f'))+                         | FunctionCall (f (Abstract.Designator l l f' f')) (ZipList (f (Abstract.Expression l l f' f')))+                         | Not (f (Abstract.Expression l l f' f'))+                         | Literal (f (Abstract.Value l l f' 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 λ, Typeable l, Typeable f, Typeable f',+                   Data (Abstract.QualIdent l), Data (f (Abstract.Value l l f' f')),+                   Data (f (Abstract.Designator l l f' f')), Data (f (Abstract.Element l l f' f')),+                   Data (f (Abstract.Expression l l f' f'))) =>+                  Data (Expression λ l f' f)+deriving instance (Show (Abstract.QualIdent l), Show (f (Abstract.Value l l f' f')), Show (f (Abstract.Designator l l f' f')),+                   Show (f (Abstract.Element l l f' f')), Show (f (Abstract.Expression l l f' f'))) =>+                  Show (Expression λ l f' f)+deriving instance (Eq (Abstract.QualIdent l), Eq (f (Abstract.Value l l f' f')),+                   Eq (f (Abstract.Designator l l f' f')), Eq (f (Abstract.Element l l f' f')),+                   Eq (f (Abstract.Expression l l f' f'))) => Eq (Expression λ l f' 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 Element λ l f' f = Element (f (Abstract.Expression l l f' f'))+                      | Range (f (Abstract.Expression l l f' f')) (f (Abstract.Expression l l f' f')) -data RelOp = Equal | Unequal | Less | LessOrEqual | Greater | GreaterOrEqual | In | Is-   deriving (Data, Show)+deriving instance (Typeable λ, Typeable l, Typeable f, Typeable f', Data (f (Abstract.Expression l l f' f'))) =>+                  Data (Element λ l f' f)+deriving instance Show (f (Abstract.Expression l l f' f')) => Show (Element λ l f' f)+deriving instance Eq (f (Abstract.Expression l l f' f')) => Eq (Element λ l f' f) -data Element f' f = Element (f (Expression f' f'))-                  | Range (f (Expression f' f')) (f (Expression f' f'))+data Value λ l (f' :: * -> *) (f :: * -> *) = Boolean Bool+                                            | Builtin Text+                                            | CharCode Int+                                            | Integer Integer+                                            | Nil+                                            | Real Double+                                            | String Text+                                            deriving (Eq, Show) -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 λ, Typeable l, Typeable f, Typeable f') => Data (Value λ l f' 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'))+data Designator λ l f' f = Variable (Abstract.QualIdent l)+                         | Field (f (Abstract.Designator l l f' f')) Ident +                         | Index (f (Abstract.Designator l l f' f'))+                                 (f (Abstract.Expression l l f' f')) (ZipList (f (Abstract.Expression l l f' f')))+                         | TypeGuard (f (Abstract.Designator l l f' f')) (Abstract.QualIdent l)+                         | Dereference (f (Abstract.Designator l l f' 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)+deriving instance (Typeable λ, Typeable l, Typeable f, Typeable f', Data (Abstract.QualIdent l),+                   Data (f (Abstract.Designator l l f' f')), Data (f (Abstract.Expression l l f' f'))) =>+                  Data (Designator λ l f' f)+deriving instance (Show (Abstract.QualIdent l), Show (f (Abstract.Designator l l f' f')),+                   Show (f (Abstract.Expression l l f' f'))) => Show (Designator λ l f' f)+deriving instance (Eq (Abstract.QualIdent l), Eq (f (Abstract.Designator l l f' f')),+                   Eq (f (Abstract.Expression l l f' f'))) => Eq (Designator λ l f' 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')))+data Type λ l f' f = TypeReference (Abstract.QualIdent l)+                   | ArrayType (ZipList (f (Abstract.ConstExpression l l f' f'))) (f (Abstract.Type l l f' f'))+                   | RecordType (Maybe (Abstract.BaseType l)) (ZipList (f (Abstract.FieldList l l f' f')))+                   | PointerType (f (Abstract.Type l l f' f'))+                   | ProcedureType (Maybe (f (Abstract.FormalParameters l l f' 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)+deriving instance (Typeable λ, Typeable l, Typeable f, Typeable f', Data (Abstract.QualIdent l), Data (f (Abstract.Type l l f' f')),+                   Data (f (Abstract.ConstExpression l l f' f')), Data (f (Abstract.FormalParameters l l f' f')),+                   Data (f (Abstract.FieldList l l f' f'))) =>+                  Data (Type λ l f' f)+deriving instance (Show (Abstract.QualIdent l), Show (f (Abstract.Type l l f' f')),+                   Show (f (Abstract.ConstExpression l l f' f')), Show (f (Abstract.FormalParameters l l f' f')),+                   Show (f (Abstract.FieldList l l f' f'))) =>+                  Show (Type λ l f' f) -data QualIdent = QualIdent Ident Ident -               | NonQualIdent Ident-   deriving (Data, Eq, Ord, Show)+data FieldList λ l f' f = FieldList (Abstract.IdentList l) (f (Abstract.Type l l f' f')) -type BaseType  = QualIdent+deriving instance (Typeable λ, Typeable l, Typeable f, Typeable f', Data (Abstract.IdentDef l), Data (f (Abstract.Type l l f' f')),+                   Data (f (Abstract.Expression l l f' f'))) => Data (FieldList λ l f' f)+deriving instance (Show (Abstract.IdentDef l), Show (f (Abstract.Type l l f' f')), Show (f (Abstract.Expression l l f' f'))) =>+                  Show (FieldList λ l f' f) -data FieldList f' f = FieldList IdentList (f (Type f' f'))-                    | EmptyFieldList+data ProcedureHeading λ l f' f =+   ProcedureHeading                    Bool (Abstract.IdentDef l) (Maybe (f (Abstract.FormalParameters l l f' f')))+   | TypeBoundHeading Bool Ident Ident Bool (Abstract.IdentDef l) (Maybe (f (Abstract.FormalParameters l l f' 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)+data FormalParameters λ l f' f = FormalParameters (ZipList (f (Abstract.FPSection l l f' f'))) (Maybe (Abstract.ReturnType l)) -type IdentList = NonEmpty IdentDef+data FPSection λ l f' f = FPSection Bool [Ident] (f (Abstract.Type l l f' 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 λ, Typeable l, Typeable f, Typeable f', Data (Abstract.IdentDef l),+                   Data (f (Abstract.FormalParameters l l f' f'))) => Data (ProcedureHeading λ l f' f)+deriving instance (Show (Abstract.IdentDef l), Show (f (Abstract.FormalParameters l l f' f'))) =>+                  Show (ProcedureHeading λ l f' f) -data FPSection f' f = FPSection Bool (NonEmpty Ident) (f (Type f' f'))+deriving instance (Typeable λ, Typeable l, Typeable f, Typeable f', Data (Abstract.ReturnType l),+                   Data (f (Abstract.FPSection l l f' f')),  Data (f (Abstract.Expression l l f' f'))) =>+                  Data (FormalParameters λ l f' f)+deriving instance (Show (f (Abstract.FPSection l l f' f')), Show (Abstract.ReturnType l),+                   Show (f (Abstract.Expression l l f' f'))) => Show (FormalParameters λ l f' 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 λ, Typeable l, Typeable f, Typeable f', Data (f (Abstract.Type l l f' f')),+                   Data (f (Abstract.Expression l l f' f'))) => Data (FPSection λ l f' f)+deriving instance (Show (f (Abstract.Type l l f' f')), Show (f (Abstract.Expression l l f' f'))) => Show (FPSection λ l f' 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 Block λ l f' f = Block (ZipList (f (Abstract.Declaration l l f' f'))) (Maybe (f (Abstract.StatementSequence l l f' 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 λ, Typeable l, Typeable f, Typeable f', Data (f (Abstract.Declaration l l f' f')),+                   Data (f (Abstract.Designator l l f' f')), Data (f (Abstract.Expression l l f' f')),+                   Data (f (Abstract.StatementSequence l l f' f'))) =>+                  Data (Block λ l f' f)+deriving instance (Show (f (Abstract.Declaration l l f' f')), Show (f (Abstract.Designator l l f' f')),+                   Show (f (Abstract.Expression l l f' f')), Show (f (Abstract.StatementSequence l l f' f'))) =>+                  Show (Block λ l f' f) -data ProcedureBody f' f =  ProcedureBody [f (Declaration f' f')] (Maybe (f (StatementSequence f' f')))+newtype StatementSequence λ l f' f = StatementSequence (ZipList (f (Abstract.Statement l l f' 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)+deriving instance (Typeable λ, Typeable l, Typeable f, Typeable f', Data (f (Abstract.Statement l l f' f'))) =>+                  Data (StatementSequence λ l f' f)+deriving instance Show (f (Abstract.Statement l l f' f')) => Show (StatementSequence λ l f' f) -newtype StatementSequence f' f = StatementSequence (NonEmpty (f (Statement f' f')))+data Statement λ l f' f = EmptyStatement+                        | Assignment (f (Abstract.Designator l l f' f')) (f (Abstract.Expression l l f' f'))+                        | ProcedureCall (f (Abstract.Designator l l f' f')) (Maybe (ZipList (f (Abstract.Expression l l f' f'))))+                        | If (f (Abstract.ConditionalBranch l l f' f'))+                             (ZipList (f (Abstract.ConditionalBranch l l f' f')))+                             (Maybe (f (Abstract.StatementSequence l l f' f')))+                        | CaseStatement (f (Abstract.Expression l l f' f')) +                                        (ZipList (f (Abstract.Case l l f' f')))+                                        (Maybe (f (Abstract.StatementSequence l l f' f')))+                        | While (f (Abstract.Expression l l f' f')) (f (Abstract.StatementSequence l l f' f'))+                        | Repeat (f (Abstract.StatementSequence l l f' f')) (f (Abstract.Expression l l f' f'))+                        | For Ident (f (Abstract.Expression l l f' f')) (f (Abstract.Expression l l f' f')) +                              (Maybe (f (Abstract.Expression l l f' f'))) (f (Abstract.StatementSequence l l f' f'))  -- Oberon2+                        | Loop (f (Abstract.StatementSequence l l f' f'))+                        | With (f (Abstract.WithAlternative l l f' f'))+                               (ZipList (f (Abstract.WithAlternative l l f' f')))+                               (Maybe (f (Abstract.StatementSequence l l f' f')))+                        | Exit+                        | Return (Maybe (f (Abstract.Expression l l f' 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)+deriving instance (Typeable λ, Typeable l, Typeable f, Typeable f',+                   Data (f (Abstract.Designator l l f' f')), Data (f (Abstract.Expression l l f' f')),+                   Data (f (Abstract.Case l l f' f')), Data (f (Abstract.WithAlternative l l f' f')),+                   Data (f (Abstract.ConditionalBranch l l f' f')),+                   Data (f (Abstract.StatementSequence l l f' f'))) => Data (Statement λ l f' f)+deriving instance (Show (f (Abstract.Designator l l f' f')), Show (f (Abstract.Expression l l f' f')),+                   Show (f (Abstract.Case l l f' f')), Show (f (Abstract.WithAlternative l l f' f')),+                   Show (f (Abstract.ConditionalBranch l l f' f')),+                   Show (f (Abstract.StatementSequence l l f' f'))) => Show (Statement λ l f' 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 WithAlternative λ l f' f = WithAlternative (Abstract.QualIdent l) (Abstract.QualIdent l)+                                                (f (Abstract.StatementSequence l l f' f')) -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 Case λ l f' f = Case (f (Abstract.CaseLabels l l f' f')) (ZipList (f (Abstract.CaseLabels l l f' f')))+                          (f (Abstract.StatementSequence l l f' f')) -data WithAlternative f' f = WithAlternative QualIdent QualIdent (f (StatementSequence f' f'))+data CaseLabels λ l f' f = SingleLabel (f (Abstract.ConstExpression l l f' f'))+                         | LabelRange (f (Abstract.ConstExpression l l f' f')) (f (Abstract.ConstExpression l l f' f')) -data Case f' f = Case (NonEmpty (f (CaseLabels f' f'))) (f (StatementSequence f' f'))-               | EmptyCase+data ConditionalBranch λ l f' f =+   ConditionalBranch (f (Abstract.Expression l l f' f')) (f (Abstract.StatementSequence l l f' f')) -data CaseLabels f' f = SingleLabel (f (ConstExpression f' f'))-                     | LabelRange (f (ConstExpression f' f')) (f (ConstExpression f' f'))+deriving instance (Typeable λ, Typeable l, Typeable f, Typeable f', Data (Abstract.QualIdent l),+                   Data (f (Abstract.Designator l l f' f')), Data (f (Abstract.StatementSequence l l f' f'))) =>+                  Data (WithAlternative λ l f' f)+deriving instance (Show (Abstract.QualIdent l), Show (f (Abstract.StatementSequence l l f' f'))) =>+                  Show (WithAlternative λ l f' 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 λ, Typeable l, Typeable f, Typeable f',+                   Data (f (Abstract.CaseLabels l l f' f')), Data (f (Abstract.StatementSequence l l f' f'))) =>+                  Data (Case λ l f' f)+deriving instance (Show (f (Abstract.CaseLabels l l f' f')), Show (f (Abstract.StatementSequence l l f' f'))) =>+                  Show (Case λ l 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 λ, Typeable l, Typeable f, Typeable f',+                   Data (f (Abstract.Expression l l f' f')), Data (f (Abstract.StatementSequence l l f' f'))) =>+                  Data (ConditionalBranch λ l f' f)+deriving instance (Show (f (Abstract.Expression l l f' f')), Show (f (Abstract.StatementSequence l l f' f'))) =>+                  Show (ConditionalBranch λ l 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)+deriving instance (Typeable λ, Typeable l, Typeable f, Typeable f', Data (f (Abstract.ConstExpression l l f' f'))) =>+                  Data (CaseLabels λ l f' f)+deriving instance Show (f (Abstract.ConstExpression l l f' f')) => Show (CaseLabels λ l f' f) -$(mconcat <$> mapM Transformation.Deep.TH.deriveAll-  [''Module, ''Declaration, ''Type, ''Expression,+$(concat <$>+  (forM [Rank2.TH.deriveFunctor, Rank2.TH.deriveFoldable, Rank2.TH.deriveTraversable,+         Transformation.Shallow.TH.deriveAll, Transformation.Deep.TH.deriveAll] $+   \derive-> mconcat <$> mapM derive+             [''Module, ''Declaration, ''Type, ''Expression, ''Value,+              ''Element, ''Designator, ''FieldList,+              ''ProcedureHeading, ''FormalParameters, ''FPSection, ''Block,+              ''Statement, ''StatementSequence,+              ''Case, ''CaseLabels, ''ConditionalBranch, ''WithAlternative]))++$(mconcat <$> mapM Rank2.TH.unsafeDeriveApply+  [''Declaration, ''Type, ''Expression, ''Value,    ''Element, ''Designator, ''FieldList,-   ''ProcedureHeading, ''FormalParameters, ''FPSection, ''ProcedureBody,-   ''Statement, ''StatementSequence, ''WithAlternative, ''Case, ''CaseLabels])+   ''ProcedureHeading, ''FormalParameters, ''FPSection, ''Block,+   ''Statement, ''StatementSequence,+   ''Case, ''CaseLabels, ''ConditionalBranch, ''WithAlternative])
+ src/Language/Oberon/Abstract.hs view
@@ -0,0 +1,333 @@+{-# LANGUAGE DeriveDataTypeable, KindSignatures, PolyKinds, RankNTypes, ScopedTypeVariables,+             TypeApplications, TypeFamilies, TypeFamilyDependencies, UndecidableInstances #-}+{-# OPTIONS_GHC -Wno-simplifiable-class-constraints #-}++-- | Finally Tagless Abstract Syntax Tree definitions for the programming language Oberon++module Language.Oberon.Abstract (-- * Language classes+                                 Wirthy(..), CoWirthy(..), Oberon(..), Oberon2(..), Nameable(..),+                                 -- * Type synonyms+                                 Ident, IdentList, BaseType, ReturnType, ConstExpression,+                                 -- * Auxiliary data types+                                 RelOp(..), WirthySubsetOf(..), Maybe3(..),+                                 -- * Utilities+                                 just3, nothing3, maybe3, +                                 ) where++import Data.Data (Data)+import Data.Kind (Constraint)+import Data.List.NonEmpty+import Data.Text (Text)++import Prelude hiding (and, not, or, read, subtract)++type Ident = Text++-- | Relational operators+data RelOp = Equal | Unequal | Less | LessOrEqual | Greater | GreaterOrEqual | In+   deriving (Data, Eq, Show)++-- | The finally-tagless associated types and methods relevant to all programming languages designed by Niklaus+-- Wirth. Every non-leaf node type has four type variables:+--+-- * type variable @l@ represents the language of the constructs built by the methods,+-- * @l'@ is the language of the child node constructs,+-- * @f'@ wraps all descendant nodes, except+-- * @f@ wraps all direct children of the node.+class Wirthy l where+   type Module l      = (m :: * -> (* -> *) -> (* -> *) -> *) | m -> l+   type Declaration l = (d :: * -> (* -> *) -> (* -> *) -> *) | d -> l+   type Type l        = (t :: * -> (* -> *) -> (* -> *) -> *) | t -> l+   type Statement l   = (s :: * -> (* -> *) -> (* -> *) -> *) | s -> l+   type Expression l  = (e :: * -> (* -> *) -> (* -> *) -> *) | e -> l+   type Designator l  = (d :: * -> (* -> *) -> (* -> *) -> *) | d -> l+   type Value l       = (v :: * -> (* -> *) -> (* -> *) -> *) | v -> l++   type FieldList l         = (x :: * -> (* -> *) -> (* -> *) -> *) | x -> l+   type ProcedureHeading l  = (x :: * -> (* -> *) -> (* -> *) -> *) | x -> l+   type FormalParameters l  = (x :: * -> (* -> *) -> (* -> *) -> *) | x -> l+   type FPSection l         = (x :: * -> (* -> *) -> (* -> *) -> *) | x -> l+   type Block l             = (x :: * -> (* -> *) -> (* -> *) -> *) | x -> l+   type StatementSequence l = (x :: * -> (* -> *) -> (* -> *) -> *) | x -> l+   type Case l              = (x :: * -> (* -> *) -> (* -> *) -> *) | x -> l+   type CaseLabels l        = (x :: * -> (* -> *) -> (* -> *) -> *) | x -> l+   type ConditionalBranch l = (x :: * -> (* -> *) -> (* -> *) -> *) | x -> l+   type Element l           = (x :: * -> (* -> *) -> (* -> *) -> *) | x -> l+   +   type Import l  = x | x -> l+   type IdentDef l  = x | x -> l+   type QualIdent l = x | x -> l++   -- Declaration+   constantDeclaration :: IdentDef l' -> f (ConstExpression l' l' f' f') -> Declaration l l' f' f+   typeDeclaration :: IdentDef l' -> f (Type l' l' f' f') -> Declaration l l' f' f+   variableDeclaration :: IdentList l' -> f (Type l' l' f' f') -> Declaration l l' f' f+   procedureDeclaration :: f (ProcedureHeading l' l' f' f') -> f (Block l' l' f' f') -> Declaration l l' f' f++   formalParameters :: [f (FPSection l' l' f' f')] -> Maybe (ReturnType l') -> FormalParameters l l' f' f+   fpSection :: Bool -> [Ident] -> f (Type l' l' f' f') -> FPSection l l' f' f+   block :: [f (Declaration l' l' f' f')] -> Maybe (f (StatementSequence l' l' f' f')) -> Block l l' f' f++   fieldList :: NonEmpty (IdentDef l') -> f (Type l' l' f' f') -> FieldList l l' f' f++   -- Type+   pointerType :: f (Type l' l' f' f') -> Type l l' f' f+   procedureType :: Maybe (f (FormalParameters l' l' f' f')) -> Type l l' f' f+   typeReference :: QualIdent l' -> Type l l' f' f++   -- Statement+   assignment :: f (Designator l' l' f' f') -> f (Expression l' l' f' f') -> Statement l l' f' f+   caseStatement :: f (Expression l' l' f' f') -> [f (Case l' l' f' f')] -> Maybe (f (StatementSequence l' l' f' f')) +                 -> Statement l l' f' f+   emptyStatement :: Statement l l' f' f+   exitStatement :: Statement l l' f' f+   ifStatement :: NonEmpty (f (ConditionalBranch l' l' f' f'))+               -> Maybe (f (StatementSequence l' l' f' f')) +               -> Statement l l' f' f+   loopStatement :: f (StatementSequence l' l' f' f') -> Statement l l' f' f+   procedureCall :: f (Designator l' l' f' f') -> Maybe [f (Expression l' l' f' f')] -> Statement l l' f' f+   repeatStatement :: f (StatementSequence l' l' f' f') -> f (Expression l' l' f' f') -> Statement l l' f' f+   returnStatement :: Maybe (f (Expression l' l' f' f')) -> Statement l l' f' f+   whileStatement :: f (Expression l' l' f' f') -> f (StatementSequence l' l' f' f') -> Statement l l' f' f++   conditionalBranch :: f (Expression l' l' f' f') -> f (StatementSequence l' l' f' f') -> ConditionalBranch l l' f' f+   caseAlternative :: NonEmpty (f (CaseLabels l' l' f' f')) -> f (StatementSequence l' l' f' f') -> Case l l' f' f++   singleLabel :: f (ConstExpression l' l' f' f') -> CaseLabels l l' f' f+   labelRange :: f (ConstExpression l' l' f' f') -> f (ConstExpression l' l' f' f') -> CaseLabels l l' f' f++   statementSequence :: [f (Statement l' l' f' f')] -> StatementSequence l l' f' f++   -- Expression+   add, subtract :: f (Expression l' l' f' f') -> f (Expression l' l' f' f') -> Expression l l' f' f+   and, or :: f (Expression l' l' f' f') -> f (Expression l' l' f' f') -> Expression l l' f' f+   divide, integerDivide, modulo, multiply :: f (Expression l' l' f' f') -> f (Expression l' l' f' f') -> Expression l l' f' f+   functionCall :: f (Designator l' l' f' f') -> [f (Expression l' l' f' f')] -> Expression l l' f' f+   literal :: f (Value l' l' f' f') -> Expression l l' f' f+   negative, positive :: f (Expression l' l' f' f') -> Expression l l' f' f+   not :: f (Expression l' l' f' f') -> Expression l l' f' f+   read :: f (Designator l' l' f' f') -> Expression l l' f' f+   relation :: RelOp -> f (Expression l' l' f' f') -> f (Expression l' l' f' f') -> Expression l l' f' f++   element :: f (Expression l' l' f' f') -> Element l l' f' f+   range :: f (Expression l' l' f' f') -> f (Expression l' l' f' f') -> Element l l' f' f++   -- Value+   integer :: Integer -> Value l l' f' f+   nil, false, true :: Value l l' f' f+   real :: Double -> Value l l' f' f+   string :: Text -> Value l l' f' f+   charCode :: Int -> Value l l' f' f+   builtin :: Text -> Value l l' f' f++   -- Designator+   variable :: QualIdent l' -> Designator l l' f' f+   field :: f (Designator l' l' f' f') -> Ident -> Designator l l' f' f+   index :: f (Designator l' l' f' f') -> NonEmpty (f (Expression l' l' f' f')) -> Designator l l' f' f+   dereference :: f (Designator l' l' f' f') -> Designator l l' f' f++   -- Identifier+   identDef :: Ident -> IdentDef l+   nonQualIdent :: Ident -> QualIdent l++-- | An instance of this type can convert its own constructs to another language that's an instance of 'TargetClass'.+class Wirthy l => CoWirthy l where+   type TargetClass l :: * -> Constraint+   type TargetClass l = Wirthy+   coDeclaration :: TargetClass l l' => Declaration l l'' f' f -> Declaration l' l'' f' f+   coType        :: TargetClass l l' => Type l l'' f' f        -> Type l' l'' f' f+   coStatement   :: TargetClass l l' => Statement l l'' f' f   -> Statement l' l'' f' f+   coExpression  :: TargetClass l l' => Expression l l'' f' f  -> Expression l' l'' f' f+   coDesignator  :: TargetClass l l' => Designator l l'' f' f  -> Designator l' l'' f' f+   coValue       :: TargetClass l l' => Value l l'' f' f       -> Value l' l'' f' f++-- | A language with constructs beyond the base 'Wirthy' class will have constructs that cannot be converted to a+-- | 'Wirthy' target. It can declare its 'TargetClass' to be this transformed language instead, whose language+-- | constructs are all wrapped in 'Maybe' or 'Maybe3'.+data WirthySubsetOf l = WirthySubsetOf l++-- | A modified 'Maybe' with kind that fits the types associated with 'Wirthy'.+newtype Maybe3 f a b c = Maybe3 (Maybe (f a b c)) deriving (Eq, Ord, Read, Show)++-- | Smart 'Maybe3' constructor corresponding to 'Just'+just3 = Maybe3 . Just+-- | Smart 'Maybe3' constructor corresponding to 'Nothing'+nothing3 = Maybe3 Nothing+-- | Smart 'Maybe3' destructor corresponding to 'maybe'+maybe3 n f (Maybe3 x) = maybe n f x++instance Wirthy l => Wirthy (WirthySubsetOf l) where+   type Module (WirthySubsetOf l)            = Maybe3 (Module l)+   type Declaration (WirthySubsetOf l)       = Maybe3 (Declaration l)+   type Type (WirthySubsetOf l)              = Maybe3 (Type l)+   type Statement (WirthySubsetOf l)         = Maybe3 (Statement l)+   type Expression (WirthySubsetOf l)        = Maybe3 (Expression l)+   type Designator (WirthySubsetOf l)        = Maybe3 (Designator l)+   type Value (WirthySubsetOf l)             = Maybe3 (Value l)++   type FieldList (WirthySubsetOf l)         = Maybe3 (FieldList l)+   type ProcedureHeading (WirthySubsetOf l)  = Maybe3 (ProcedureHeading l)+   type FormalParameters (WirthySubsetOf l)  = Maybe3 (FormalParameters l)+   type FPSection (WirthySubsetOf l)         = Maybe3 (FPSection l)+   type Block (WirthySubsetOf l)             = Maybe3 (Block l)+   type StatementSequence (WirthySubsetOf l) = Maybe3 (StatementSequence l)+   type Case (WirthySubsetOf l)              = Maybe3 (Case l)+   type CaseLabels (WirthySubsetOf l)        = Maybe3 (CaseLabels l)+   type ConditionalBranch (WirthySubsetOf l) = Maybe3 (ConditionalBranch l)+   type Element (WirthySubsetOf l)           = Maybe3 (Element l)+   +   type Import (WirthySubsetOf l)            = Maybe (Import l)+   type IdentDef (WirthySubsetOf l)          = Maybe (IdentDef l)+   type QualIdent (WirthySubsetOf l)         = Maybe (QualIdent l)++   -- Declaration+   constantDeclaration = (just3 .) . constantDeclaration @l+   typeDeclaration = (just3 .) . typeDeclaration @l+   variableDeclaration = (just3 .) . variableDeclaration @l+   procedureDeclaration = (just3 .) . procedureDeclaration @l++   formalParameters = (just3 .) . formalParameters @l+   fpSection = ((just3 .) .) . fpSection @l+   block = (just3 .) . block @l++   fieldList = (just3 .) . fieldList @l++   -- Type+   pointerType = just3 . pointerType @l+   procedureType = just3 . procedureType @l+   typeReference = just3 . typeReference @l++   -- Statement+   assignment = (just3 .) . assignment @l+   caseStatement = ((just3 .) .) . caseStatement @l+   emptyStatement = just3 (emptyStatement @l)+   exitStatement = just3 (exitStatement @l)+   ifStatement = (just3 .) . ifStatement @l+   loopStatement = just3 . loopStatement @l+   procedureCall = (just3 .) . procedureCall @l+   repeatStatement = (just3 .) . repeatStatement @l+   returnStatement = just3 . returnStatement @l+   whileStatement = (just3 .) . whileStatement @l++   conditionalBranch = (just3 .) . conditionalBranch @l+   caseAlternative = (just3 .) . caseAlternative @l++   singleLabel = just3 . singleLabel @l+   labelRange = (just3 .) . labelRange @l++   statementSequence = just3 . statementSequence @l++   -- Expression+   add = (just3 .) . add @l+   subtract = (just3 .) . subtract @l+   and = (just3 .) . and @l+   or = (just3 .) . or @l+   divide = (just3 .) . divide @l+   integerDivide = (just3 .) . integerDivide @l+   modulo = (just3 .) . modulo @l+   multiply = (just3 .) . multiply @l+   functionCall = (just3 .) . functionCall @l+   literal = just3 . literal @l+   negative = just3 . negative @l+   positive = just3 . positive @l+   not = just3 . not @l+   read = just3 . read @l+   relation = ((just3 .) .) . relation @l++   element = just3 . element @l+   range = (just3 .) . range @l++   -- Value+   integer = just3 . integer @l+   nil = just3 (nil @l)+   false = just3 (false @l)+   true = just3 (true @l)+   real = just3 . real @l+   string = just3 . string @l+   charCode = just3 . charCode @l+   builtin = just3 . builtin @l++   -- Designator+   variable = just3 . variable @l+   field = (just3 .) . field @l+   index = (just3 .) . index @l+   dereference = just3 . dereference @l++   -- Identifier+   identDef = Just . identDef @l+   nonQualIdent = Just . nonQualIdent @l++-- | Ability to deconstruct named constructs and obtain their 'Ident'.+class Wirthy l => Nameable l where+   getProcedureName :: Nameable l' => ProcedureHeading l l' f' f -> Ident+   getIdentDefName :: IdentDef l -> Ident+   getNonQualIdentName :: QualIdent l -> Maybe Ident++-- | The finally-tagless associated types and methods relevant to both versions of the Oberon language.+class Wirthy l => Oberon l where+   type WithAlternative l = (x :: * -> (* -> *) -> (* -> *) -> *) | x -> l++   moduleUnit :: Ident -> [Import l] -> f (Block l' l' f' f') -> Module l l' f' f+   moduleImport :: Maybe Ident -> Ident -> Import l+   qualIdent :: Ident -> Ident -> QualIdent l+   getQualIdentNames :: QualIdent l -> Maybe (Ident, Ident)+   exported :: Ident -> IdentDef l++   forwardDeclaration :: IdentDef l' -> Maybe (f (FormalParameters l' l' f' f')) -> Declaration l l' f' f+   procedureHeading :: Bool -> IdentDef l' -> Maybe (f (FormalParameters l' l' f' f')) -> ProcedureHeading l l' f' f++   arrayType :: [f (ConstExpression l' l' f' f')] -> f (Type l' l' f' f') -> Type l l' f' f+   recordType :: Maybe (BaseType l') -> [f (FieldList l' l' f' f')] -> Type l l' f' f++   withStatement :: f (WithAlternative l' l' f' f') -> Statement l l' f' f+   withAlternative :: QualIdent l' -> QualIdent l' -> f (StatementSequence l' l' f' f') -> WithAlternative l l' f' f++   is :: f (Expression l' l' f' f') -> QualIdent l' -> Expression l l' f' f+   set :: [f (Element l' l' f' f')] -> Expression l l' f' f++   typeGuard :: f (Designator l' l' f' f') -> QualIdent l' -> Designator l l' f' f++instance Wirthy l => Oberon (WirthySubsetOf l) where+   type WithAlternative (WirthySubsetOf l) = Maybe3 (WithAlternative l)+   moduleUnit = const $ const $ const nothing3+   moduleImport = const $ const Nothing+   qualIdent = const $ const Nothing+   getQualIdentNames = const Nothing+   exported = const Nothing++   forwardDeclaration = const $ const nothing3+   procedureHeading = const $ const $ const nothing3++   arrayType = const $ const nothing3+   recordType = const $ const nothing3++   withStatement = const nothing3+   withAlternative = const $ const $ const nothing3++   is = const $ const nothing3+   set = const nothing3++   typeGuard = const $ const nothing3++-- | The finally-tagless associated types and methods relevant to the Oberon 2 language.+class Oberon l => Oberon2 l where+   readOnly :: Ident -> IdentDef l+   typeBoundHeading :: Bool -> Ident -> Ident -> Bool -> IdentDef l' -> Maybe (f (FormalParameters l' l' f' f'))+                    -> ProcedureHeading l l' f' f+   forStatement :: Ident -> f (Expression l' l' f' f') -> f (Expression l' l' f' f')+                -> Maybe (f (Expression l' l' f' f'))+                -> f (StatementSequence l' l' f' f') +                -> Statement l l' f' f+   variantWithStatement :: NonEmpty (f (WithAlternative l' l' f' f')) -> Maybe (f (StatementSequence l' l' f' f'))+                        -> Statement l l' f' f++instance Wirthy l => Oberon2 (WirthySubsetOf l) where+   readOnly = const Nothing+   typeBoundHeading = const $ const $ const $ const $ const $ const nothing3+   forStatement = const $ const $ const $ const $ const nothing3+   variantWithStatement = const $ const nothing3++type BaseType l = QualIdent l+type ReturnType l = QualIdent l+type ConstExpression l = Expression l+type IdentList l = NonEmpty (IdentDef l)
+ src/Language/Oberon/ConstantFolder.hs view
@@ -0,0 +1,532 @@+{-# LANGUAGE DataKinds, DeriveGeneric, DuplicateRecordFields, FlexibleContexts, FlexibleInstances,+             MultiParamTypeClasses, OverloadedStrings, RankNTypes, ScopedTypeVariables,+             TemplateHaskell, TypeFamilies, UndecidableInstances #-}++-- | The main export of this module is the function 'foldConstants' that folds the constants in Oberon AST using a+-- attribute grammar. Other exports are helper functions and attribute types that can be reused for other languages or+-- attribute grammars.+-- +-- This module expects the ambiguities in the AST to be already resolved by the "Language.Oberon.Resolver" module.++module Language.Oberon.ConstantFolder where++import Control.Applicative (liftA2, ZipList(ZipList, getZipList))+import Control.Arrow (first)+import Control.Monad (join)+import Data.Bits (shift)+import Data.Char (chr, ord, toUpper)+import Data.Functor.Identity (Identity(..))+import Data.Int (Int32)+import Data.Map.Lazy (Map)+import qualified Data.Map.Lazy as Map+import Data.Semigroup (Semigroup(..))+import qualified Data.Text as Text+import Foreign.Storable (sizeOf)+import GHC.Generics (Generic)+import Language.Haskell.TH (appT, conT, varT, varE, newName)+import Data.Text.Prettyprint.Doc (layoutCompact, Pretty(pretty))+import Data.Text.Prettyprint.Doc.Render.Text (renderStrict)++import qualified Rank2+import qualified Transformation+import qualified Transformation.Rank2+import qualified Transformation.Deep as Deep+import qualified Transformation.Full as Full+import qualified Transformation.Full.TH+import qualified Transformation.Shallow as Shallow+import qualified Transformation.AG as AG+import Transformation.AG (Attribution(..), Atts, Inherited(..), Synthesized(..), Semantics)+import Transformation.AG.Generics (Auto(Auto), Bequether(..), Synthesizer(..), SynthesizedField(..), Mapped(..))++import qualified Language.Oberon.Abstract as Abstract+import qualified Language.Oberon.AST as AST+import qualified Language.Oberon.Pretty ()+import Language.Oberon.Grammar (ParsedLexemes(Trailing), Lexeme(Token, WhiteSpace, lexemeType, lexemeText),+                                TokenType(Other))++-- | Fold the constants in the given collection of Oberon modules (a 'Map' of modules keyed by module name). It uses+-- the constant declarations from the modules as well as the given 'Environment' of predefined constants and+-- functions. The value of the latter argument is typically 'predefined' or 'predefined2'.+foldConstants :: (Abstract.Oberon l, Abstract.Nameable l,+                  Ord (Abstract.QualIdent l), Show (Abstract.QualIdent l),+                  Atts (Inherited (Auto ConstantFold)) (Abstract.Block l l Sem Sem) ~ InhCF l,+                  Atts (Synthesized (Auto ConstantFold)) (Abstract.Block l l Sem Sem)+                  ~ SynCFMod' l (Abstract.Block l l),+                  Full.Functor (Auto ConstantFold) (Abstract.Block l l),+                  Deep.Functor (Auto ConstantFold) (Abstract.Block l l))+              => Environment l -> Map AST.Ident (Placed (AST.Module l l Placed Placed))+              -> Map AST.Ident (Placed (AST.Module l l Placed Placed))+foldConstants predef modules =+   getModules (modulesFolded $+               syn (Transformation.apply (Auto ConstantFold)+                                         (wrap (Auto ConstantFold Deep.<$> Modules modules))+                    `Rank2.apply`+                    Inherited (InhCFRoot predef)))+   where wrap = (,) (0, Trailing [], 0)++type Placed = (,) (Int, ParsedLexemes, Int)++type Environment l = Map (Abstract.QualIdent l) (Maybe (Abstract.Value l l Placed Placed))++newtype Modules l f' f = Modules {getModules :: Map AST.Ident (f (AST.Module l l f' f'))}++data ConstantFold = ConstantFold++type Sem = Semantics (Auto ConstantFold)++instance Transformation.Transformation (Auto ConstantFold) where+   type Domain (Auto ConstantFold) = Placed+   type Codomain (Auto ConstantFold) = Semantics (Auto ConstantFold)++data InhCFRoot l = InhCFRoot{rootEnv :: Environment l} deriving Generic++data InhCF l = InhCF{env           :: Environment l,+                     currentModule :: AST.Ident}+               deriving Generic++data SynCF a = SynCF{folded :: Mapped Placed a} deriving Generic++data SynCFMod l a = SynCFMod{moduleEnv :: Environment l,+                             folded    :: Mapped Placed a}+                    deriving Generic++data SynCFExp λ l = SynCFExp{folded   :: Mapped Placed (Abstract.Expression λ l Placed Placed),+                             foldedValue :: Maybe (Placed (Abstract.Value l l Placed Placed))}++data SynCFDesignator l = SynCFDesignator{folded :: Mapped Placed (Abstract.Designator l l Placed Placed),+                                         designatorValue :: Maybe (Placed (Abstract.Value l l Placed Placed))}+                         deriving Generic++data SynCFRoot a = SynCFRoot{modulesFolded :: a}++-- * Modules instances, TH candidates+instance (Transformation.Transformation t, Functor (Transformation.Domain t), Deep.Functor t (AST.Module l l),+          Transformation.At t (AST.Module l l (Transformation.Codomain t) (Transformation.Codomain t))) =>+         Deep.Functor t (Modules l) where+   t <$> ~(Modules ms) = Modules (mapModule <$> ms)+      where mapModule m = t Transformation.$ ((t Deep.<$>) <$> m)++instance Rank2.Functor (Modules l f') where+   f <$> ~(Modules ms) = Modules (f <$> ms)++instance Rank2.Apply (Modules l f') where+   ~(Modules fs) <*> ~(Modules ms) = Modules (Map.intersectionWith Rank2.apply fs ms)++instance (Transformation.Transformation t, Transformation.At t (AST.Module l l f f)) =>+         Shallow.Functor t (Modules l f) where+   t <$> ~(Modules ms) = Modules ((t Transformation.$) <$> ms)++-- * Boring attribute types+type instance Atts (Synthesized (Auto ConstantFold)) (Modules l _ _) = SynCFRoot (Modules l Placed Placed)+type instance Atts (Synthesized (Auto ConstantFold)) (AST.Module l l _ _) = SynCFMod' l (AST.Module l l)+type instance Atts (Synthesized (Auto ConstantFold)) (AST.Declaration l l _ _) = SynCFMod' l (AST.Declaration l l)+type instance Atts (Synthesized (Auto ConstantFold)) (AST.ProcedureHeading l l _ _) = SynCF' (AST.ProcedureHeading l l)+type instance Atts (Synthesized (Auto ConstantFold)) (AST.Block l l _ _) = SynCFMod' l (AST.Block l l)+type instance Atts (Synthesized (Auto ConstantFold)) (AST.FormalParameters l l _ _) = SynCF' (AST.FormalParameters l l)+type instance Atts (Synthesized (Auto ConstantFold)) (AST.FPSection l l _ _) = SynCF' (AST.FPSection l l)+type instance Atts (Synthesized (Auto ConstantFold)) (AST.Type l l _ _) = SynCF' (AST.Type l l)+type instance Atts (Synthesized (Auto ConstantFold)) (AST.FieldList l l _ _) = SynCF' (AST.FieldList l l)+type instance Atts (Synthesized (Auto ConstantFold)) (AST.StatementSequence l l _ _) =+   SynCF' (AST.StatementSequence l l)+type instance Atts (Synthesized (Auto ConstantFold)) (AST.Expression λ l _ _) = SynCFExp λ l+type instance Atts (Synthesized (Auto ConstantFold)) (AST.Element l l _ _) = SynCF' (AST.Element l l)+type instance Atts (Synthesized (Auto ConstantFold)) (AST.Value l l _ _) = SynCF' (AST.Value l l)+type instance Atts (Synthesized (Auto ConstantFold)) (AST.Designator l l _ _) = SynCFDesignator l+type instance Atts (Synthesized (Auto ConstantFold)) (AST.Statement l l _ _) = SynCF' (AST.Statement l l)+type instance Atts (Synthesized (Auto ConstantFold)) (AST.Case l l _ _) = SynCF' (AST.Case l l)+type instance Atts (Synthesized (Auto ConstantFold)) (AST.CaseLabels l l _ _) = SynCF' (AST.CaseLabels l l)+type instance Atts (Synthesized (Auto ConstantFold)) (AST.ConditionalBranch l l _ _) =+   SynCF' (AST.ConditionalBranch l l)+type instance Atts (Synthesized (Auto ConstantFold)) (AST.WithAlternative l l _ _) = SynCF' (AST.WithAlternative l l)++type instance Atts (Inherited (Auto ConstantFold)) (Modules l _ _) = InhCFRoot l+type instance Atts (Inherited (Auto ConstantFold)) (AST.Module l l _ _) = InhCF l+type instance Atts (Inherited (Auto ConstantFold)) (AST.Declaration l l _ _) = InhCF l+type instance Atts (Inherited (Auto ConstantFold)) (AST.ProcedureHeading l l _ _) = InhCF l+type instance Atts (Inherited (Auto ConstantFold)) (AST.Block l l _ _) = InhCF l+type instance Atts (Inherited (Auto ConstantFold)) (AST.FormalParameters l l _ _) = InhCF l+type instance Atts (Inherited (Auto ConstantFold)) (AST.FPSection l l _ _) = InhCF l+type instance Atts (Inherited (Auto ConstantFold)) (AST.Type l l _ _) = InhCF l+type instance Atts (Inherited (Auto ConstantFold)) (AST.FieldList l l _ _) = InhCF l+type instance Atts (Inherited (Auto ConstantFold)) (AST.StatementSequence l l _ _) = InhCF l+type instance Atts (Inherited (Auto ConstantFold)) (AST.Expression l l _ _) = InhCF l+type instance Atts (Inherited (Auto ConstantFold)) (AST.Element l l _ _) = InhCF l+type instance Atts (Inherited (Auto ConstantFold)) (AST.Value l l _ _) = InhCF l+type instance Atts (Inherited (Auto ConstantFold)) (AST.Designator l l _ _) = InhCF l+type instance Atts (Inherited (Auto ConstantFold)) (AST.Statement l l _ _) = InhCF l+type instance Atts (Inherited (Auto ConstantFold)) (AST.Case l l _ _) = InhCF l+type instance Atts (Inherited (Auto ConstantFold)) (AST.CaseLabels l l _ _) = InhCF l+type instance Atts (Inherited (Auto ConstantFold)) (AST.ConditionalBranch l l _ _) = InhCF l+type instance Atts (Inherited (Auto ConstantFold)) (AST.WithAlternative l l _ _) = InhCF l++type SynCF' node = SynCF (node Placed Placed)+type SynCFMod' l node = SynCFMod l (node Placed Placed)+++-- * Disambiguation++folded' :: SynCF' node -> Mapped Placed (node Placed Placed)+foldedExp  :: SynCFExp λ l -> Mapped Placed (Abstract.Expression λ l Placed Placed)+foldedExp' :: SynCFExp λ l -> Placed (Abstract.Expression λ l Placed Placed)++folded' = folded+foldedExp = folded+foldedExp' = getMapped . foldedExp++-- * Rules++instance {-# overlaps #-} Ord (Abstract.QualIdent l) =>+                          Synthesizer (Auto ConstantFold) (Modules l) Sem Placed where+   synthesis _ (_, Modules self) inheritance (Modules ms) =+      SynCFRoot{modulesFolded= (Modules (getMapped . foldedModule . syn <$> ms))}+      where foldedModule :: SynCFMod' l (AST.Module l l) -> Mapped Placed (AST.Module l l Placed Placed)+            foldedModule = folded++instance {-# overlaps #-} Ord (Abstract.QualIdent l) =>+                          Bequether (Auto ConstantFold) (Modules l) Sem Placed where+   bequest _ (_, Modules self) inheritance (Modules ms) = Modules (Map.mapWithKey moduleInheritance self)+      where moduleInheritance name mod = Inherited InhCF{env= rootEnv inheritance <> foldMap (moduleEnv . syn) ms,+                                                         currentModule= name}++instance {-# overlaps #-} (Abstract.Oberon l, Abstract.Nameable l, Ord (Abstract.QualIdent l), Show (Abstract.QualIdent l),+                           Atts (Synthesized (Auto ConstantFold)) (Abstract.Block l l Sem Sem) ~ SynCFMod' l (Abstract.Block l l)) =>+                          Synthesizer (Auto ConstantFold) (AST.Module l l) Sem Placed where+   synthesis _ (pos, AST.Module moduleName imports _body) inheritance (AST.Module _ _ body) =+      SynCFMod{moduleEnv= exportedEnv,+               folded= Mapped (pos,+                               AST.Module moduleName imports $ getMapped+                               $ folded (syn body :: SynCFMod' l (Abstract.Block l l)))}+      where exportedEnv = Map.mapKeysMonotonic export newEnv+            newEnv = moduleEnv (syn body)+            export q+               | Just name <- Abstract.getNonQualIdentName q = Abstract.qualIdent moduleName name+               | otherwise = q++instance (Abstract.Nameable l, Ord (Abstract.QualIdent l),+          Atts (Synthesized (Auto ConstantFold)) (Abstract.Declaration l l Sem Sem) ~ SynCFMod' l (Abstract.Declaration l l),+          Atts (Inherited (Auto ConstantFold)) (Abstract.StatementSequence l l Sem Sem) ~ InhCF l,+          Atts (Inherited (Auto ConstantFold)) (Abstract.Declaration l l Sem Sem) ~ InhCF l) =>+         Bequether (Auto ConstantFold) (AST.Block l l) Sem Placed where+   bequest _ (pos, AST.Block _decls _stats) inheritance (AST.Block decls stats) =+      AST.Block (pure $ Inherited localEnv) (pure $ Inherited localEnv)+      where newEnv = Map.unions (moduleEnv . syn <$> decls)+            localEnv = InhCF (newEnv `Map.union` env inheritance) (currentModule inheritance)++instance (Abstract.Nameable l, k ~ Abstract.QualIdent l, v ~ Abstract.Value l l Placed Placed, Ord k,+          Atts (Synthesized (Auto ConstantFold)) (Abstract.Declaration l l Sem Sem)+          ~ SynCFMod' l (Abstract.Declaration l l)) =>+         SynthesizedField "moduleEnv" (Map k (Maybe v)) (Auto ConstantFold) (AST.Block l l) Sem Placed where+   synthesizedField _ _ (_, AST.Block{}) _ (AST.Block decls _stats) = Map.unions (moduleEnv . syn <$> decls)++instance (Abstract.Nameable l, k ~ Abstract.QualIdent l, v ~ Abstract.Value l l Placed Placed, Ord k,+          Atts (Synthesized (Auto ConstantFold)) (Abstract.ConstExpression l l Sem Sem) ~ SynCFExp l l) =>+         SynthesizedField "moduleEnv" (Map k (Maybe v)) (Auto ConstantFold) (AST.Declaration l l) Sem Placed where+   synthesizedField _ _ (_, AST.ConstantDeclaration namedef _) _ (AST.ConstantDeclaration _ expression) =+      Map.singleton (Abstract.nonQualIdent $ Abstract.getIdentDefName namedef)+                    ((snd <$>) . foldedValue $ syn expression)+   synthesizedField _ _ _ _ _ = mempty++instance {-# overlaps #-}+   (Abstract.Oberon l, Abstract.Nameable l, Ord (Abstract.QualIdent l),+    Abstract.Value l ~ AST.Value l, InhCF l ~ InhCF λ,+    Pretty (AST.Value λ λ Identity Identity),+    Atts (Synthesized (Auto ConstantFold)) (Abstract.Expression l l Sem Sem) ~ SynCFExp l l,+    Atts (Synthesized (Auto ConstantFold)) (Abstract.Element l l Sem Sem) ~ SynCF' (Abstract.Element l l),+    Atts (Synthesized (Auto ConstantFold)) (Abstract.Designator l l Sem Sem) ~ SynCFDesignator l) =>+   Synthesizer (Auto ConstantFold) (AST.Expression λ l) Sem Placed where+   synthesis _ (pos@(start, ls, end), AST.Relation op _ _) _ (AST.Relation _op left right) =+      case join (compareValues <$> foldedValue (syn left) <*> foldedValue (syn right))+      of Just value -> literalSynthesis value+         Nothing -> SynCFExp{folded= Mapped (pos,+                                             Abstract.relation op (foldedExp' $ syn left) (foldedExp' $ syn right)),+                             foldedValue= Nothing}+      where compareValues (_, AST.Boolean l) (ls, AST.Boolean r)   = repos ls <$> relate op (compare l r)+            compareValues (_, AST.Integer l) (ls, AST.Integer r)   = repos ls <$> relate op (compare l r)+            compareValues (_, AST.Real l) (ls, AST.Real r)         = repos ls <$> relate op (compare l r)+            compareValues (_, AST.Integer l) (ls, AST.Real r)      = repos ls <$> relate op (compare (fromIntegral l) r)+            compareValues (_, AST.Real l) (ls, AST.Integer r)      = repos ls <$> relate op (compare l (fromIntegral r))+            compareValues (_, AST.CharCode l) (ls, AST.CharCode r) = repos ls <$> relate op (compare l r)+            compareValues (_, AST.String l) (ls, AST.String r)     = repos ls <$> relate op (compare l r)+            compareValues (_, AST.CharCode l) (ls, AST.String r) = repos ls+                                                                   <$> relate op (compare (Text.singleton $ chr l) r)+            compareValues (_, AST.String l) (ls, AST.CharCode r) = repos ls+                                                                   <$> relate op (compare l (Text.singleton $ chr r))+            compareValues _ _                               = Nothing+            repos (_, ls', _) v = ((start, anyWhitespace ls ls', end), v)+            relate Abstract.Equal EQ          = Just Abstract.true+            relate Abstract.Equal _           = Just Abstract.false+            relate Abstract.Unequal EQ        = Just Abstract.false+            relate Abstract.Unequal _         = Just Abstract.true+            relate Abstract.Less LT           = Just Abstract.true+            relate Abstract.Less _            = Just Abstract.false+            relate Abstract.LessOrEqual GT    = Just Abstract.false+            relate Abstract.LessOrEqual _     = Just Abstract.true+            relate Abstract.Greater GT        = Just Abstract.true+            relate Abstract.Greater _         = Just Abstract.false+            relate Abstract.GreaterOrEqual LT = Just Abstract.false+            relate Abstract.GreaterOrEqual _  = Just Abstract.true+            relate Abstract.In _              = Nothing+   synthesis _ (pos@(start, ls, end), _) _ (AST.Positive expr) =+      case foldedValue (syn expr)+      of Just ((_, ls', _), AST.Integer n) -> literalSynthesis ((start, anyWhitespace ls ls', end), AST.Integer n)+         Just ((_, ls', _), AST.Real n) -> literalSynthesis ((start, anyWhitespace ls ls', end), AST.Real n)+         _ -> SynCFExp{folded= Mapped (pos, Abstract.positive $ foldedExp' $ syn expr),+                       foldedValue= Nothing}+   synthesis _ (pos@(start, ls, end), _) _ (AST.Negative expr) =+      case foldedValue (syn expr)+      of Just ((_, ls', _), AST.Integer n) -> literalSynthesis ((start, anyWhitespace ls ls', end),+                                                                AST.Integer $ negate n)+         Just ((_, ls', _), AST.Real n) -> literalSynthesis ((start, anyWhitespace ls ls', end), AST.Real $ negate n)+         _ -> SynCFExp{folded= Mapped (pos, Abstract.negative $ foldedExp' $ syn expr),+                       foldedValue= Nothing}+   synthesis _ (pos, _) _ (AST.Add left right) =+      foldBinaryArithmetic pos Abstract.add (+) (syn left) (syn right)+   synthesis _ (pos, _) _ (AST.Subtract left right) =+      foldBinaryArithmetic pos Abstract.subtract (-) (syn left) (syn right)+   synthesis _ (pos, _) _ (AST.Or left right) =+      foldBinaryBoolean pos Abstract.or (||) (syn left) (syn right)+   synthesis _ (pos, _) _ (AST.Multiply left right) =+      foldBinaryArithmetic pos Abstract.multiply (*) (syn left) (syn right)+   synthesis _ (pos, _) _ (AST.Divide left right) =+      foldBinaryFractional pos Abstract.divide (/) (syn left) (syn right)+   synthesis _ (pos, _) _ (AST.IntegerDivide left right) =+      foldBinaryInteger pos Abstract.integerDivide div (syn left) (syn right)+   synthesis _ (pos, _) _ (AST.Modulo left right) =+      foldBinaryInteger pos Abstract.modulo mod (syn left) (syn right)+   synthesis _ (pos, _) _ (AST.And left right) =+      foldBinaryBoolean pos Abstract.and (&&) (syn left) (syn right)+   synthesis _ (pos@(start, ls, end), _) _ (AST.Not expr) =+      case foldedValue (syn expr)+      of Just ((_, ls', _), AST.Boolean b) -> literalSynthesis ((start, anyWhitespace ls ls', end),+                                                                if b then Abstract.false else Abstract.true)+         _ -> SynCFExp{folded= Mapped (pos, Abstract.not $ foldedExp' $ syn expr),+                       foldedValue= Nothing}+   synthesis _ (pos, AST.IsA _ right) _ (AST.IsA left _) =+      SynCFExp{folded= Mapped (pos, Abstract.is (foldedExp' $ syn left) right),+               foldedValue= Nothing}+   synthesis _ (pos, _) _ (AST.Set elements) =+      SynCFExp{folded= Mapped (pos, Abstract.set (getMapped . folded' . syn <$> getZipList elements)),+               foldedValue= Nothing}+   synthesis _ (pos, _) _ (AST.Read des) =+      case syn des :: SynCFDesignator l+      of SynCFDesignator{designatorValue= Just val} -> literalSynthesis val+         SynCFDesignator{folded= Mapped (pos', des'),+                         designatorValue= Nothing} -> SynCFExp{folded= Mapped (pos, Abstract.read (pos', des')),+                                                               foldedValue= Nothing}+   synthesis _ (pos, _) _ (AST.FunctionCall fn args) =+      case (snd <$> designatorValue (syn fn :: SynCFDesignator l), (snd <$>) . foldedValue . syn <$> getZipList args)+      of (Just (AST.Builtin "CAP"), [Just (AST.String s)])+            | Text.length s == 1, capital <- Text.toUpper s -> fromValue (Abstract.string capital)+         (Just (AST.Builtin "CAP"), [Just (AST.CharCode c)])+            | capital <- ord (toUpper $ chr c) -> fromValue (Abstract.charCode capital)+         (Just (AST.Builtin "CHR"), [Just (AST.Integer code)]) -> fromValue (Abstract.charCode $ fromIntegral code)+         (Just (AST.Builtin "ORD"), [Just (AST.String s)])+            | Text.length s == 1, code <- ord (Text.head s) -> fromValue (Abstract.integer $ toInteger code)+         (Just (AST.Builtin "ORD"), [Just (AST.CharCode code)]) -> fromValue (Abstract.integer $ toInteger code)+         (Just (AST.Builtin "ABS"), [Just (AST.Integer i)]) -> fromValue (Abstract.integer $ abs i)+         (Just (AST.Builtin "ABS"), [Just (AST.Real r)]) -> fromValue (Abstract.real $ abs r)+         (Just (AST.Builtin "ASH"), [Just (AST.Integer i), Just (AST.Integer j)])+            | shifted <- shift i (fromIntegral j) -> fromValue (Abstract.integer shifted)+         (Just (AST.Builtin "ENTIER"), [Just (AST.Real x)]) -> fromValue (Abstract.integer $ ceiling x)+         (Just (AST.Builtin "LEN"), [Just (AST.String s)]) -> fromValue (Abstract.integer+                                                                            $ toInteger $ Text.length s)+         (Just (AST.Builtin "LONG"), [Just (AST.Integer x)]) -> fromValue (Abstract.integer x)+         (Just (AST.Builtin "LONG"), [Just (AST.Real x)]) -> fromValue (Abstract.real x)+         (Just (AST.Builtin "SHORT"), [Just (AST.Integer x)]) -> fromValue (Abstract.integer x)+         (Just (AST.Builtin "SHORT"), [Just (AST.Real x)]) -> fromValue (Abstract.real x)+         (Just (AST.Builtin "ODD"), [Just (AST.Integer x)]) ->+            fromValue (if x `mod` 2 == 1 then Abstract.true else Abstract.false)+         (Just (AST.Builtin "SIZE"), [Just (AST.Builtin "INTEGER")]) -> fromValue (Abstract.integer intSize)+         (Just (AST.Builtin "SIZE"), [Just (AST.Builtin "LONGINT")]) -> fromValue (Abstract.integer intSize)+         (Just (AST.Builtin "SIZE"), [Just (AST.Builtin "SHORTINT")]) -> fromValue (Abstract.integer int32Size)+         (Just (AST.Builtin "SIZE"), [Just (AST.Builtin "REAL")]) -> fromValue (Abstract.integer doubleSize)+         (Just (AST.Builtin "SIZE"), [Just (AST.Builtin "LONGREAL")]) -> fromValue (Abstract.integer doubleSize)+         (Just (AST.Builtin "SIZE"), [Just (AST.Builtin "SHORTREAL")]) -> fromValue (Abstract.integer floatSize)+         (Just (AST.Builtin "MAX"), [Just (AST.Builtin "CHAR")]) -> fromValue (Abstract.charCode 0xff)+         (Just (AST.Builtin "MAX"), [Just (AST.Builtin "INTEGER")]) -> fromValue (Abstract.integer maxInteger)+         (Just (AST.Builtin "MAX"), [Just (AST.Builtin "LONGINT")]) -> fromValue (Abstract.integer maxInteger)+         (Just (AST.Builtin "MAX"), [Just (AST.Builtin "SHORTINT")]) -> fromValue (Abstract.integer maxInt32)+         (Just (AST.Builtin "MAX"), [Just (AST.Builtin "SET")]) -> fromValue (Abstract.integer maxSet)+         (Just (AST.Builtin "MAX"), [Just (AST.Builtin "REAL")]) -> fromValue (Abstract.real maxReal)+         (Just (AST.Builtin "MAX"), [Just (AST.Builtin "LONGREAL")]) -> fromValue (Abstract.real maxReal)+         (Just (AST.Builtin "MIN"), [Just (AST.Builtin "CHAR")]) -> fromValue (Abstract.charCode 0)+         (Just (AST.Builtin "MIN"), [Just (AST.Builtin "INTEGER")]) -> fromValue (Abstract.integer minInteger)+         (Just (AST.Builtin "MIN"), [Just (AST.Builtin "LONGINT")]) -> fromValue (Abstract.integer minInteger)+         (Just (AST.Builtin "MIN"), [Just (AST.Builtin "SHORTINT")]) -> fromValue (Abstract.integer minInt32)+         (Just (AST.Builtin "MIN"), [Just (AST.Builtin "SET")]) -> fromValue (Abstract.integer minSet)+         (Just (AST.Builtin "MIN"), [Just (AST.Builtin "REAL")]) -> fromValue (Abstract.real minReal)+         (Just (AST.Builtin "MIN"), [Just (AST.Builtin "LONGREAL")]) -> fromValue (Abstract.real minReal)+         _ -> SynCFExp{folded= Mapped (pos,+                                       Abstract.functionCall (getMapped $ folded (syn fn :: SynCFDesignator l))+                                                             (foldedExp' . syn <$> getZipList args)),+                       foldedValue= Nothing}+      where fromValue v = literalSynthesis (pos, v)+   synthesis _ (pos, _) _ (AST.Literal val) =+      SynCFExp{folded= Mapped (pos, Abstract.literal $ getMapped $ folded' $ syn val),+               foldedValue= Just (pos, snd $ getMapped $ folded' $ syn val)}++literalSynthesis :: (Abstract.Wirthy λ, Deep.Functor (Transformation.Rank2.Map Placed Identity) (Abstract.Value l l),+                     Pretty (Abstract.Value l l Identity Identity)) =>+                    Placed (Abstract.Value l l Placed Placed) -> SynCFExp λ l+literalSynthesis v@((start, Trailing l, end), value) =+   SynCFExp{folded= Mapped ((start, mempty, end),+                            Abstract.literal ((start, lexemes, end), value)),+            foldedValue= Just v}+   where lexemes = Trailing ([Token{lexemeType= Other,+                                    lexemeText= renderStrict $ layoutCompact $ pretty+                                                $ (Identity . snd) Transformation.Rank2.<$> value}]+                             <> filter isWhiteSpace l)+         isWhiteSpace WhiteSpace{} = True+         isWhiteSpace _ = False++maxInteger, minInteger, maxInt32, minInt32, maxSet, minSet :: Integer+maxInteger = toInteger (maxBound :: Int)+minInteger = toInteger (minBound :: Int)+maxInt32 = toInteger (maxBound :: Int32)+minInt32 = toInteger (minBound :: Int32)+maxSet = 63+minSet = 0++doubleSize, floatSize, intSize, int32Size :: Integer+doubleSize = toInteger (sizeOf (0 :: Double))+floatSize = toInteger (sizeOf (0 :: Float))+intSize = toInteger (sizeOf (0 :: Int))+int32Size = toInteger (sizeOf (0 :: Int32))++maxReal, minReal :: Double+maxReal = encodeFloat (floatRadix x - 1) (snd (floatRange x) - 1)+   where x = 0 :: Double+minReal = encodeFloat (floatRadix x - 1) (fst (floatRange x))+   where x = 0 :: Double++foldBinaryArithmetic :: forall λ l f. (f ~ Placed, Abstract.Value l ~ AST.Value l, Abstract.Wirthy λ,+                                  Pretty (Abstract.Value l l Identity Identity)) =>+                        (Int, ParsedLexemes, Int)+                     -> (f (Abstract.Expression l l f f) -> f (Abstract.Expression l l f f) -> Abstract.Expression λ l f f)+                     -> (forall n. Num n => n -> n -> n)+                     -> SynCFExp l l -> SynCFExp l l -> SynCFExp λ l+foldBinaryArithmetic pos@(start, ls, end) node op l r =+   case join (foldValues <$> foldedValue l <*> foldedValue r)+   of Just v -> literalSynthesis v+      Nothing -> SynCFExp{folded= Mapped (pos, node (foldedExp' l) (foldedExp' r)),+                          foldedValue= Nothing}+   where foldValues :: Placed (AST.Value l l f f) -> Placed (AST.Value l l f f) -> Maybe (Placed (AST.Value l l f f))+         foldBareValues :: AST.Value l l f f -> AST.Value l l f f -> Maybe (AST.Value l l f f)+         foldValues (_, l') ((_, ls', _), r') = (,) (start, anyWhitespace ls ls', end) <$> foldBareValues l' r'+         foldBareValues (AST.Integer l') (AST.Integer r') = Just (AST.Integer $ op l' r')+         foldBareValues (AST.Real l')    (AST.Real r')    = Just (AST.Real $ op l' r')+         foldBareValues (AST.Integer l') (AST.Real r')    = Just (AST.Real $ op (fromIntegral l') r')+         foldBareValues (AST.Real l')    (AST.Integer r') = Just (AST.Real $ op l' (fromIntegral r'))+         foldBareValues _ _ = Nothing++foldBinaryFractional :: forall λ l f. (f ~ Placed, Abstract.Value l ~ AST.Value l, Abstract.Wirthy λ,+                                  Pretty (Abstract.Value l l Identity Identity)) =>+                        (Int, ParsedLexemes, Int)+                     -> (f (Abstract.Expression l l f f) -> f (Abstract.Expression l l f f) -> Abstract.Expression λ l f f)+                     -> (forall n. Fractional n => n -> n -> n)+                     -> SynCFExp l l -> SynCFExp l l -> SynCFExp λ l+foldBinaryFractional pos@(start, ls, end) node op l r =+   case join (foldValues <$> foldedValue l <*> foldedValue r)+   of Just v -> literalSynthesis v+      Nothing -> SynCFExp{folded= Mapped (pos, node (foldedExp' l) (foldedExp' r)),+                          foldedValue= Nothing}+   where foldValues :: Placed (AST.Value l l f f) -> Placed (AST.Value l l f f) -> Maybe (Placed (AST.Value l l f f))+         foldValues (_, AST.Real l') ((_, ls', _), AST.Real r') = Just ((start, anyWhitespace ls ls', end),+                                                                        AST.Real $ op l' r')+         foldValues _ _ = Nothing++foldBinaryInteger :: forall λ l f. (f ~ Placed, Abstract.Value l ~ AST.Value l, Abstract.Wirthy λ,+                               Pretty (Abstract.Value l l Identity Identity)) =>+                        (Int, ParsedLexemes, Int)+                     -> (f (Abstract.Expression l l f f) -> f (Abstract.Expression l l f f) -> Abstract.Expression λ l f f)+                     -> (forall n. Integral n => n -> n -> n)+                     -> SynCFExp l l -> SynCFExp l l -> SynCFExp λ l+foldBinaryInteger pos@(start, ls, end) node op l r =+   case join (foldValues <$> foldedValue l <*> foldedValue r)+   of Just v -> literalSynthesis v+      Nothing -> SynCFExp{folded= Mapped (pos, node (foldedExp' l) (foldedExp' r)),+                          foldedValue= Nothing}+   where foldValues :: Placed (AST.Value l l f f) -> Placed (AST.Value l l f f) -> Maybe (Placed (AST.Value l l f f))+         foldValues (_, AST.Integer l') ((_, ls', _), AST.Integer r') = Just ((start, anyWhitespace ls ls', end),+                                                                              AST.Integer $ op l' r')+         foldValues _ _ = Nothing++foldBinaryBoolean :: forall λ l f. (f ~ Placed, Abstract.Value l ~ AST.Value l, Abstract.Wirthy λ,+                               Pretty (Abstract.Value l l Identity Identity)) =>+                     (Int, ParsedLexemes, Int)+                  -> (f (Abstract.Expression l l f f) -> f (Abstract.Expression l l f f) -> Abstract.Expression λ l f f)+                  -> (Bool -> Bool -> Bool)+                  -> SynCFExp l l -> SynCFExp l l -> SynCFExp λ l+foldBinaryBoolean pos@(start, ls, end) node op l r =+   case join (foldValues <$> foldedValue l <*> foldedValue r)+   of Just v -> literalSynthesis v+      Nothing -> SynCFExp{folded= Mapped (pos, node (foldedExp' l) (foldedExp' r)),+                          foldedValue= Nothing}+   where foldValues :: Placed (AST.Value l l f f) -> Placed (AST.Value l l f f) -> Maybe (Placed (AST.Value l l f f))+         foldValues (_, AST.Boolean l') ((_, ls', _), AST.Boolean r') = Just ((start, anyWhitespace ls ls', end),+                                                                              AST.Boolean $ op l' r')+         foldValues _ _ = Nothing++instance (Ord (Abstract.QualIdent l), v ~ Abstract.Value l l Placed Placed) =>+         SynthesizedField "designatorValue" (Maybe (Placed v)) (Auto ConstantFold) (AST.Designator l l) Sem Placed where+   synthesizedField _ _ (pos, AST.Variable q) inheritance _ = (,) pos <$> join (Map.lookup q $ env inheritance)+   synthesizedField _ _ _ _ _ = Nothing++instance {-# overlaps #-} Ord (Abstract.QualIdent l) => Transformation.At (Auto ConstantFold) (Modules l Sem Sem) where+   ($) = AG.applyDefault snd++anyWhitespace :: ParsedLexemes -> ParsedLexemes -> ParsedLexemes+anyWhitespace outer inner@(Trailing ls)+   | any isWhitespace ls = inner+   | otherwise = inner <> lastWhitespace outer+   where isWhitespace WhiteSpace{} = True+         isWhitespace _ = False++lastWhitespace :: ParsedLexemes -> ParsedLexemes+lastWhitespace ls@(Trailing []) = ls+lastWhitespace ls@(Trailing [WhiteSpace{}]) = ls+lastWhitespace (Trailing [_]) = mempty+lastWhitespace (Trailing (l:ls)) = lastWhitespace (Trailing ls)++--- * Shortcut++instance Full.Functor (Auto ConstantFold) (AST.Value l l) where+   Auto ConstantFold <$> (pos, val) = Rank2.Arrow sem+      where sem _inherited = Synthesized (SynCF $ Mapped (pos, val))++-- * Unsafe Rank2 AST instances++instance Rank2.Apply (AST.Module l l f') where+   AST.Module name1 imports1 body1 <*> ~(AST.Module _name _imports body2) =+      AST.Module name1 imports1 (Rank2.apply body1 body2)++predefined, predefined2 :: (Abstract.Wirthy l, Ord (Abstract.QualIdent l)) => Environment l+-- | The set of predefined types and procedures defined in the Oberon Language Report.+predefined = Map.fromList $ map (first Abstract.nonQualIdent) $+   [("TRUE", Just Abstract.true),+    ("FALSE", Just Abstract.false)]+   ++ map builtin ["BOOLEAN", "CHAR", "SHORTINT", "INTEGER", "LONGINT", "REAL", "LONGREAL", "SET",+                   "ABS", "ASH", "CAP", "LEN", "MAX", "MIN",+                   "ODD", "SIZE", "ORD", "CHR", "SHORT", "LONG", "ENTIER"]+   where builtin name = (name, Just $ Abstract.builtin name)+predefined2 = predefined++$(do l <- varT  <$> newName "l"+     mconcat <$> mapM (\g-> Transformation.Full.TH.deriveUpFunctor (conT ''Auto `appT` conT ''ConstantFold)+                            $ conT g `appT` l `appT` l)+        [''AST.Declaration, ''AST.Type, ''AST.FieldList,+         ''AST.ProcedureHeading, ''AST.FormalParameters, ''AST.FPSection,+         ''AST.Expression, ''AST.Element, ''AST.Designator,+         ''AST.Block, ''AST.StatementSequence, ''AST.Statement,+         ''AST.Case, ''AST.CaseLabels, ''AST.ConditionalBranch, ''AST.WithAlternative])++$(do let sem = [t|Semantics (Auto ConstantFold)|]+     let inst g = [d| instance Attribution (Auto ConstantFold) ($g l l) Sem Placed =>+                               Transformation.At (Auto ConstantFold) ($g l l $sem $sem)+                         where ($) = AG.applyDefault snd |]+     mconcat <$> mapM (inst . conT)+        [''AST.Module, ''AST.Block, ''AST.Declaration, ''AST.Type, ''AST.FieldList,+         ''AST.ProcedureHeading, ''AST.FormalParameters, ''AST.FPSection,+         ''AST.StatementSequence, ''AST.Statement,+         ''AST.Case, ''AST.CaseLabels, ''AST.ConditionalBranch, ''AST.WithAlternative,+         ''AST.Element, ''AST.Expression, ''AST.Designator])
src/Language/Oberon/Grammar.hs view
@@ -1,120 +1,181 @@-{-# Language OverloadedStrings, Rank2Types, RecordWildCards, TypeFamilies, TemplateHaskell #-}+{-# Language DeriveDataTypeable, FlexibleContexts, FlexibleInstances, GeneralizedNewtypeDeriving,+             OverloadedStrings, Rank2Types, RecordWildCards, ScopedTypeVariables,+             TypeApplications, TypeFamilies, TypeSynonymInstances, TemplateHaskell #-}  -- | Oberon grammar adapted from http://www.ethoberon.ethz.ch/EBNF.html--- Extracted from the book Programmieren in Oberon - Das neue Pascal by N. Wirth and M. Reiser and translated by J. Templ.+-- +-- Extracted from the book Programmieren in Oberon - Das neue Pascal by N. Wirth and M. Reiser and translated by+-- J. Templ.+--+-- The grammars in this module attempt to follow the language grammars from the reports, while generating a+-- semantically meaningful abstract syntax tree; the latter is defined in "Language.Oberon.AST". As the grammars are+-- ambiguous, it is necessary to resolve the ambiguities after parsing all Oberon modules in use.+-- "Language.Oberon.Resolver" provides this functionality. Only after the ambiguity resolution can the abstract syntax+-- tree be pretty-printed using the instances from "Language.Oberon.Pretty". Alternatively, since the parsing+-- preserves the original parsed lexemes including comments in the AST, you can use "Language.Oberon.Reserializer" to+-- reproduce the original source code from the AST. -module Language.Oberon.Grammar (OberonGrammar(..),+module Language.Oberon.Grammar (OberonGrammar(..), Parser, NodeWrap, ParsedLexemes(..), Lexeme(..), TokenType(..),                                 oberonGrammar, oberon2Grammar, oberonDefinitionGrammar, oberon2DefinitionGrammar) where  import Control.Applicative+import Control.Arrow (first) import Control.Monad (guard) import Data.Char-import Data.List.NonEmpty (NonEmpty((:|)), fromList, toList)-import Data.Monoid ((<>), Endo(Endo, appEndo))-import Numeric (readHex)+import Data.Data (Data)+import Data.Functor.Compose (Compose(..))+import Data.List.NonEmpty (NonEmpty)+import Data.Maybe (catMaybes)+import Data.Monoid ((<>), Dual(Dual, getDual), Endo(Endo, appEndo))+import Numeric (readDec, readHex, readFloat) import Data.Text (Text, unpack) import Text.Grampa-import Text.Grampa.ContextFree.LeftRecursive (Parser) import Text.Parser.Combinators (sepBy, sepBy1, sepByNonEmpty, try)+import Text.Grampa.ContextFree.LeftRecursive.Transformer (ParserT, lift, tmap) import Text.Parser.Token (braces, brackets, parens) -import Transformation.Deep as Deep (Product(Pair))-import qualified Rank2 import qualified Rank2.TH -import Language.Oberon.AST+import qualified Language.Oberon.Abstract as Abstract+import qualified Language.Oberon.AST as AST  import Prelude hiding (length, takeWhile)  -- | All the productions of the Oberon grammar-data OberonGrammar f p = OberonGrammar {-   module_prod :: p (Module f f),-   ident :: p Ident,+data OberonGrammar l f p = OberonGrammar {+   module_prod :: p (f (Abstract.Module l l f f)),+   ident :: p Abstract.Ident,    letter :: p Text,    digit :: p Text,-   importList :: p [Import],-   import_prod :: p Import,-   declarationSequence :: p [f (Declaration f f)],-   constantDeclaration :: p (Declaration f f),-   identdef :: p IdentDef,-   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),+   importList :: p [Abstract.Import l],+   import_prod :: p (Abstract.Import l),+   declarationSequence :: p [f (Abstract.Declaration l l f f)],+   constantDeclaration :: p (Abstract.Declaration l l f f),+   identdef :: p (Abstract.IdentDef l),+   constExpression :: p (f (Abstract.Expression l l f f)),+   expression :: p (f (Abstract.Expression l l f f)),+   simpleExpression :: p (f (Abstract.Expression l l f f)),+   term :: p (f (Abstract.Expression l l f f)),+   factor :: p (f (Abstract.Expression l l f f)),+   number :: p (Abstract.Value l l f f),+   integer :: p (Abstract.Value l l f f),    hexDigit :: p Text,-   real :: p (Expression f f),+   real :: p (Abstract.Value l l f f),    scaleFactor :: p Text,-   charConstant :: p (Expression f f),+   charConstant :: p (Abstract.Value l l f f),    string_prod :: p Text,-   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 f),-   type_prod :: p (Type f f),-   qualident :: p QualIdent,-   arrayType :: p (Type f f),-   length :: p (f (Expression f f)),-   recordType :: p (Type f f),-   baseType :: p QualIdent,-   fieldListSequence :: p (NonEmpty (f (FieldList f f))),-   fieldList :: p (FieldList f f),-   identList :: p IdentList,-   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)}+   set :: p (Abstract.Expression l l f f),+   element :: p (Abstract.Element l l f f),+   designator :: p (f (Abstract.Designator l l f f)),+   unguardedDesignator :: p (Abstract.Designator l l f f),+   expList :: p (NonEmpty (f (Abstract.Expression l l f f))),+   actualParameters :: p [f (Abstract.Expression l l f f)],+   mulOperator :: p (BinOp l f),+   addOperator :: p (BinOp l f),+   relation :: p Abstract.RelOp,+   typeDeclaration :: p (Abstract.Declaration l l f f),+   type_prod :: p (Abstract.Type l l f f),+   qualident :: p (Abstract.QualIdent l),+   arrayType :: p (Abstract.Type l l f f),+   length :: p (f (Abstract.Expression l l f f)),+   recordType :: p (Abstract.Type l l f f),+   baseType :: p (Abstract.BaseType l),+   fieldListSequence :: p [f (Abstract.FieldList l l f f)],+   fieldList :: p (Abstract.FieldList l l f f),+   identList :: p (Abstract.IdentList l),+   pointerType :: p (Abstract.Type l l f f),+   procedureType :: p (Abstract.Type l l f f),+   variableDeclaration :: p (Abstract.Declaration l l f f),+   procedureDeclaration :: p (Abstract.Declaration l l f f),+   procedureHeading :: p (Abstract.Ident, Abstract.ProcedureHeading l l f f),+   formalParameters :: p (Abstract.FormalParameters l l f f),+   fPSection :: p (Abstract.FPSection l l f f),+   formalType :: p (Abstract.Type l l f f),+   procedureBody :: p (Abstract.Block l l f f),+   forwardDeclaration :: p (Abstract.Declaration l l f f),+   statementSequence :: p (Abstract.StatementSequence l l f f),+   statement :: p (f (Abstract.Statement l l f f)),+   assignment :: p (Abstract.Statement l l f f),+   procedureCall :: p (Abstract.Statement l l f f),+   ifStatement :: p (Abstract.Statement l l f f),+   caseStatement :: p (Abstract.Statement l l f f),+   case_prod :: p (Abstract.Case l l f f),+   caseLabelList :: p (NonEmpty (f (Abstract.CaseLabels l l f f))),+   caseLabels :: p (Abstract.CaseLabels l l f f),+   whileStatement :: p (Abstract.Statement l l f f),+   repeatStatement :: p (Abstract.Statement l l f f),+   forStatement :: p (Abstract.Statement l l f f),+   loopStatement :: p (Abstract.Statement l l f f),+   withStatement :: p (Abstract.Statement l l f f)} -newtype BinOp f = BinOp {applyBinOp :: (f (Expression f f) -> f (Expression f f) -> Expression f f)}+newtype BinOp l f = BinOp {applyBinOp :: (f (Abstract.Expression l l f f)+                                          -> f (Abstract.Expression l l f f)+                                          -> f (Abstract.Expression l l f f))} -instance Show (BinOp f) where+instance Show (BinOp l f) where    show = const "BinOp{}"  $(Rank2.TH.deriveAll ''OberonGrammar) -instance Lexical (OberonGrammar f) where-   type LexicalConstraint p (OberonGrammar f) s = (s ~ Text, p ~ Parser)-   lexicalComment = try (string "(*"-                         *> skipMany (lexicalComment-                                      <|> notFollowedBy (string "*)") <* anyToken <* takeCharsWhile isCommentChar)-                         <* string "*)")-      where isCommentChar c = c /= '*' && c /= '('-   lexicalWhiteSpace = takeCharsWhile isSpace *> skipMany (lexicalComment *> takeCharsWhile isSpace)+type Parser = ParserT ((,) [[Lexeme]])+data Lexeme = WhiteSpace{lexemeText :: Text}+            | Comment{lexemeText :: Text}+            | Token{lexemeType :: TokenType,+                    lexemeText :: Text}+            deriving (Data, Eq, Show)++data TokenType = Delimiter | Keyword | Operator | Other+               deriving (Data, Eq, Show)++-- | Every node in the parsed AST will be wrapped in this data type.+type NodeWrap = Compose ((,) (Position, Position)) (Compose Ambiguous ((,) ParsedLexemes))++newtype ParsedLexemes = Trailing [Lexeme]+                      deriving (Data, Show, Semigroup, Monoid)++instance TokenParsing (Parser (OberonGrammar l f) Text) where+   someSpace = someLexicalSpace+   token = lexicalToken++instance LexicalParsing (Parser (OberonGrammar l f) Text) where+   lexicalComment = do c <- comment+                       lift ([[Comment c]], ())+   lexicalWhiteSpace = whiteSpace    isIdentifierStartChar = isLetter    isIdentifierFollowChar = isAlphaNum    identifierToken word = lexicalToken (do w <- word                                            guard (w `notElem` reservedWords)                                            return w)+   lexicalToken p = snd <$> tmap addOtherToken (match p) <* lexicalWhiteSpace+      where addOtherToken ([], (i, x)) = ([[Token Other i]], (i, x))+            addOtherToken (t, (i, x)) = (t, (i, x))+   keyword s = lexicalToken (string s+                             *> notSatisfyChar (isIdentifierFollowChar @(Parser (OberonGrammar l f) Text))+                             <* lift ([[Token Keyword s]], ()))+               <?> ("keyword " <> show s) +comment :: Parser g Text Text+comment = try (string "(*"+               <> concatMany (comment <<|> notFollowedBy (string "*)") *> anyToken <> takeCharsWhile isCommentChar)+               <> string "*)")+   where isCommentChar c = c /= '*' && c /= '('++whiteSpace :: LexicalParsing (Parser g Text) => Parser g Text ()+whiteSpace = spaceChars *> skipMany (lexicalComment *> spaceChars) <?> "whitespace"+   where spaceChars = (takeCharsWhile1 isSpace >>= \ws-> lift ([[WhiteSpace ws]], ())) <<|> pure ()++clearConsumed = tmap clear+   where clear (_, x) = ([], x)++wrapAmbiguous, wrap :: Parser g Text a -> Parser g Text (NodeWrap a)+wrapAmbiguous = wrap+wrap = (Compose <$>) . (\p-> liftA3 surround getSourcePos p getSourcePos)+         . (Compose <$>) . (ambiguous . tmap store) . ((,) (Trailing []) <$>)+   where store (wss, (Trailing [], a)) = (mempty, (Trailing (concat wss), a))+         surround start val end = ((start, end), val)+ oberonGrammar, oberon2Grammar, oberonDefinitionGrammar, oberon2DefinitionGrammar-   :: Grammar (OberonGrammar Ambiguous) Parser Text+   :: Grammar (OberonGrammar AST.Language NodeWrap) Parser Text -- | Grammar of an Oberon module oberonGrammar = fixGrammar grammar -- | Grammar of an Oberon-2 module@@ -124,179 +185,229 @@ -- | Grammar of an Oberon-2 definition module oberon2DefinitionGrammar = fixGrammar definitionGrammar2 -grammar, definitionGrammar :: GrammarBuilder (OberonGrammar Ambiguous) (OberonGrammar Ambiguous) Parser Text+grammar, definitionGrammar :: forall l. Abstract.Oberon l+                           => GrammarBuilder (OberonGrammar l NodeWrap) (OberonGrammar l NodeWrap) Parser Text+grammar2, definitionGrammar2 :: forall l. Abstract.Oberon2 l+                             => GrammarBuilder (OberonGrammar l NodeWrap) (OberonGrammar l NodeWrap) Parser Text  definitionGrammar g@OberonGrammar{..} = definitionMixin (grammar g)  definitionGrammar2 g@OberonGrammar{..} = definitionMixin (grammar2 g) +definitionMixin :: Abstract.Oberon l => GrammarBuilder (OberonGrammar l NodeWrap) (OberonGrammar l NodeWrap) Parser Text definitionMixin g@OberonGrammar{..} = g{-   module_prod = Module <$ (lexicalWhiteSpace *> keyword "DEFINITION") <*> ident <* delimiter ";"-                 <*> moptional importList <*> declarationSequence-                 <*> pure Nothing <* keyword "END" <*> ident <* delimiter ".",-   procedureDeclaration = ProcedureDeclaration <$> procedureHeading-                          <*> (pure $ ProcedureBody [] Nothing) <*> pure mempty,-   identdef = IdentDef <$> ident <*> pure Exported <* optional (delimiter "*")}+   module_prod = wrap $+                 do lexicalWhiteSpace +                    keyword "DEFINITION"+                    name <- ident+                    delimiter ";"+                    imports <- moptional importList+                    block <- wrap (Abstract.block <$> declarationSequence <*> pure Nothing)+                    keyword "END"+                    lexicalToken (string name)+                    delimiter "."+                    return (Abstract.moduleUnit name imports block),+   procedureDeclaration = Abstract.procedureDeclaration . snd . sequenceA +                          <$> wrap procedureHeading +                          <*> wrap (pure $ Abstract.block [] Nothing),+   identdef = Abstract.exported <$> ident <* optional (delimiter "*")}  grammar2 g@OberonGrammar{..} = g1{-   identdef = IdentDef <$> ident <*> (Exported <$ delimiter "*" <|> ReadOnly <$ delimiter "-" <|> pure PrivateOnly),+   identdef = ident +              <**> (Abstract.exported <$ delimiter "*" +                    <|> Abstract.readOnly <$ delimiter "-" +                    <|> pure Abstract.identDef),        string_prod = string_prod1 <|> lexicalToken (char '\'' *> takeWhile (/= "'") <* char '\''),-   procedureHeading = ProcedureHeading <$ keyword "PROCEDURE"-                      <*> optional (parens-                                    ((,,) <$> (True <$ keyword "VAR" <|> pure False)-                                          <*> ident <* delimiter ":" <*> ident))-                      <*> (True <$ delimiter "*" <|> pure False) -                      <*> identdef <*> optional (wrap formalParameters),-   arrayType = -      ArrayType <$ keyword "ARRAY" <*> sepBy length (delimiter ",") <* keyword "OF" <*> wrap type_prod,-   statement = statement1 <|> forStatement,+   procedureHeading = procedureHeading1+                      <|> Abstract.typeBoundHeading <$ keyword "PROCEDURE"+                          <* delimiter "("+                          <*> (True <$ keyword "VAR" <|> pure False)+                          <*> ident+                          <* delimiter ":"+                          <*> ident+                          <* delimiter ")"+                          <*> (True <$ delimiter "*" <|> pure False)+                          <**> do n <- clearConsumed (lookAhead ident)+                                  idd <- identdef+                                  params <- optional (wrap formalParameters)+                                  pure (\proc-> (n, proc idd params)),+   arrayType =+      Abstract.arrayType <$ keyword "ARRAY" <*> sepBy length (delimiter ",") <* keyword "OF" <*> wrap type_prod,    forStatement = -      For <$ keyword "FOR" <*> ident <* delimiter ":=" <*> expression <* keyword "TO" <*> expression+      Abstract.forStatement <$ 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" <*> wrap statementSequence-   +   withStatement = Abstract.variantWithStatement <$ keyword "WITH"+                      <*> sepByNonEmpty (wrap withAlternative) (delimiter "|")+                      <*> optional (keyword "ELSE" *> wrap statementSequence) <* keyword "END"}+   where g1@OberonGrammar{string_prod= string_prod1, procedureHeading= procedureHeading1} = grammar g+         withAlternative = Abstract.withAlternative <$> qualident <* delimiter ":" <*> qualident+                                                    <*  keyword "DO" <*> wrap statementSequence+ grammar OberonGrammar{..} = OberonGrammar{-   module_prod = Module <$ (lexicalWhiteSpace *> keyword "MODULE") <*> ident <* delimiter ";"-                 <*> moptional importList <*> declarationSequence-                 <*> optional (keyword "BEGIN" *> wrap statementSequence) <* keyword "END" <*> ident <* delimiter ".",+   module_prod = wrap $+                 do lexicalWhiteSpace+                    keyword "MODULE"+                    name <- ident+                    delimiter ";"+                    imports <- moptional importList+                    body <- wrap (Abstract.block <$> declarationSequence+                                                 <*> optional (wrap (keyword "BEGIN" *> statementSequence)))+                    keyword "END"+                    lexicalToken (string name)+                    delimiter "."+                    return (Abstract.moduleUnit name imports body),    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 (wrap constantDeclaration <* delimiter ";")-                                     <|> keyword "TYPE" *> many (wrap typeDeclaration <* delimiter ";")-                                     <|> keyword "VAR" *> many (wrap variableDeclaration <* delimiter ";"))-                         <> many (wrap procedureDeclaration <* delimiter ";"-                                  <|> wrap forwardDeclaration <* delimiter ";")+   import_prod = Abstract.moduleImport <$> optional (ident <* delimiter ":=") <*> ident,+   declarationSequence = concatMany (((:) <$> wrap (keyword "CONST" *> constantDeclaration)+                                          <*> many (wrap constantDeclaration)+                                      <|> (:) <$> wrap (keyword "TYPE" *> typeDeclaration)+                                              <*> many (wrap typeDeclaration)+                                      <|> (:) <$> wrap (keyword "VAR" *> variableDeclaration)+                                              <*> many (wrap variableDeclaration))+                                     <<|> [] <$ (keyword "CONST" <|> keyword "TYPE" <|> keyword "VAR"))+                         <> many (wrap (procedureDeclaration <* delimiter ";")+                                  <|> wrap (forwardDeclaration <* delimiter ";"))                          <?> "declarations",-   constantDeclaration = ConstantDeclaration <$> identdef <* delimiter "=" <*> constExpression,-   identdef = IdentDef <$> ident <*> (Exported <$ delimiter "*" <|> pure PrivateOnly),+   constantDeclaration = Abstract.constantDeclaration <$> identdef <* delimiter "=" <*> constExpression <* delimiter ";",+   identdef = ident <**> (Abstract.exported <$ delimiter "*" <|> pure Abstract.identDef),    constExpression = expression,-   expression = simpleExpression <**> (pure id <|> (pure .) <$> ((flip . Relation) <$> relation <*> simpleExpression))+   expression = simpleExpression+                <|> wrap (flip Abstract.relation <$> simpleExpression <*> relation <*> simpleExpression)+                <|> wrap (Abstract.is <$> simpleExpression <* keyword "IS" <*> qualident)                 <?> "expression",    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)+      (wrap (Abstract.positive <$ operator "+" <*> term) <|> wrap (Abstract.negative <$ operator "-" <*> term :: Parser (OberonGrammar l NodeWrap) Text (Abstract.Expression l l NodeWrap NodeWrap)) <|> term)+      <**> (appEndo . getDual <$> concatMany (Dual . Endo <$> (flip . applyBinOp <$> addOperator <*> term))),+   term = factor <**> (appEndo . getDual <$> concatMany (Dual . Endo <$> (flip . applyBinOp <$> mulOperator <*> factor))),+   factor = wrapAmbiguous (Abstract.literal <$> wrap (number+                                                      <|> charConstant+                                                      <|> Abstract.string <$> string_prod+                                                      <|> Abstract.nil <$ keyword "NIL")+                           <|> set+                           <|> Abstract.read <$> designator+                           <|> Abstract.functionCall <$> wrapAmbiguous unguardedDesignator <*> actualParameters+                           <|> (Abstract.not <$ operator "~" <*> factor :: Parser (OberonGrammar l NodeWrap) Text (Abstract.Expression l l NodeWrap NodeWrap)))             <|> parens expression,    number  =  integer <|> real,-   integer = Integer <$> lexicalToken (digit <> (takeCharsWhile isDigit <|> takeCharsWhile isHexDigit <> string "H")),+   integer = Abstract.integer . fst . head+             <$> lexicalToken (readDec . unpack <$> takeCharsWhile1 isDigit+                               <|> readHex . unpack <$> (digit <> takeCharsWhile isHexDigit <* string "H")),    hexDigit = satisfyCharInput isHexDigit,-   real = Real <$> lexicalToken (digit <> takeCharsWhile isDigit <> string "."-                                 *> takeCharsWhile isDigit <> moptional scaleFactor),-   scaleFactor = (string "E" <|> string "D") <> moptional (string "+" <|> string "-") <> digit <> takeCharsWhile isDigit,-   charConstant = lexicalToken (empty -- CharConstant <$ char '"' <*> anyChar <* char '"'-                                <|> CharCode . fst . head . readHex . unpack+   real = Abstract.real . fst . head . readFloat . unpack+          <$> lexicalToken (takeCharsWhile1 isDigit <> string "." <> takeCharsWhile isDigit <> moptional scaleFactor),+   scaleFactor = (string "E" <|> "E" <$ string "D") <> moptional (string "+" <|> string "-") <> takeCharsWhile1 isDigit,+   charConstant = lexicalToken (Abstract.charCode . fst . head . readHex . unpack                                 <$> (digit <> takeCharsWhile isHexDigit <* string "X")),    string_prod = lexicalToken (char '"' *> takeWhile (/= "\"") <* char '"'),-   set = Set <$> braces (sepBy (wrap element) (delimiter ",")),-   element = Element <$> expression-             <|> Range <$> expression <* delimiter ".." <*> expression,-   designator = ambiguous $-                    Variable <$> qualident-                <|> Field <$> designator <* delimiter "." <*> ident-                <|> Index <$> designator <*> brackets expList-                <|> TypeGuard <$> designator <*> parens qualident-                <|> Dereference <$> designator <* operator "^",+   set = Abstract.set <$> braces (sepBy (wrap element) (delimiter ",")),+   element = Abstract.element <$> expression+             <|> Abstract.range <$> expression <* delimiter ".." <*> expression,+   designator = wrapAmbiguous (unguardedDesignator+                               <|> Abstract.typeGuard <$> designator <*> parens qualident),+   unguardedDesignator = Abstract.variable <$> qualident+                         <|> Abstract.field <$> designator <* delimiter "." <*> ident+                         <|> Abstract.index @l <$> designator <*> brackets expList+                         <|> Abstract.dereference <$> designator <* operator "^",    expList = sepByNonEmpty expression (delimiter ","),    actualParameters = parens (sepBy expression (delimiter ",")),-   mulOperator = BinOp <$> (Multiply <$ operator "*" <|> Divide <$ operator "/"-                            <|> IntegerDivide <$ keyword "DIV" <|> Modulo <$ keyword "MOD" <|> And <$ operator "&"),-   addOperator = BinOp <$> (Add <$ operator "+" <|> Subtract <$ operator "-" <|> Or <$ keyword "OR"),-   relation = Equal <$ operator "=" <|> Unequal <$ operator "#" -              <|> Less <$ operator "<" <|> LessOrEqual <$ operator "<=" -              <|> Greater <$ operator ">" <|> GreaterOrEqual <$ operator ">=" -              <|> In <$ keyword "IN" <|> Is <$ keyword "IS",-   typeDeclaration = TypeDeclaration <$> identdef <* delimiter "=" <*> wrap type_prod,-   type_prod = TypeReference <$> qualident +   mulOperator = BinOp . wrapBinary+                 <$> (Abstract.multiply <$ operator "*" <|> Abstract.divide <$ operator "/"+                      <|> Abstract.integerDivide <$ keyword "DIV" <|> Abstract.modulo <$ keyword "MOD" +                      <|> Abstract.and <$ operator "&"),+   addOperator = BinOp . wrapBinary +                 <$> (Abstract.add <$ operator "+" <|> Abstract.subtract <$ operator "-" +                      <|> Abstract.or <$ keyword "OR"),+   relation = Abstract.Equal <$ operator "=" <|> Abstract.Unequal <$ operator "#" +              <|> Abstract.Less <$ operator "<" <|> Abstract.LessOrEqual <$ operator "<=" +              <|> Abstract.Greater <$ operator ">" <|> Abstract.GreaterOrEqual <$ operator ">=" +              <|> Abstract.In <$ keyword "IN",+   typeDeclaration = Abstract.typeDeclaration <$> identdef <* delimiter "=" <*> wrap type_prod <* delimiter ";",+   type_prod = Abstract.typeReference <$> qualident                 <|> arrayType                 <|> recordType -               <|> pointerType +               <|> pointerType                <|> procedureType,-   qualident = QualIdent <$> ident <* delimiter "." <*> ident-               <|> NonQualIdent <$> ident,-   arrayType = ArrayType <$ keyword "ARRAY" <*> sepBy1 length (delimiter ",") <* keyword "OF" <*> wrap type_prod,+   qualident = Abstract.qualIdent <$> ident <* delimiter "." <*> ident+               <|> Abstract.nonQualIdent <$> ident,+   arrayType = Abstract.arrayType <$ keyword "ARRAY" <*> sepBy1 length (delimiter ",") <* keyword "OF" <*> wrap type_prod,    length = constExpression,-   recordType = RecordType <$ keyword "RECORD" <*> optional (parens baseType)+   recordType = Abstract.recordType <$ keyword "RECORD" <*> optional (parens baseType)                 <*> fieldListSequence <* keyword "END",    baseType = qualident,-   fieldListSequence = sepByNonEmpty (wrap fieldList) (delimiter ";"),-   fieldList = (FieldList <$> identList <* delimiter ":" <*> wrap type_prod <?> "record field declarations")-               <|> pure EmptyFieldList,+   fieldListSequence = catMaybes <$> sepBy1 (optional $ wrap fieldList) (delimiter ";"),+   fieldList = Abstract.fieldList <$> identList <* delimiter ":" <*> wrap type_prod <?> "record field declarations",    identList = sepByNonEmpty identdef (delimiter ","),-   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 (wrap formalParameters),-   formalParameters = FormalParameters <$> parens (sepBy (wrap fPSection) (delimiter ";"))+   pointerType = Abstract.pointerType <$ keyword "POINTER" <* keyword "TO" <*> wrap type_prod,+   procedureType = Abstract.procedureType <$ keyword "PROCEDURE" <*> optional (wrap formalParameters),+   variableDeclaration = Abstract.variableDeclaration <$> identList <* delimiter ":" <*> wrap type_prod <* delimiter ";",+   procedureDeclaration = do (procedureName, heading) <- sequenceA <$> wrap procedureHeading+                             delimiter ";"+                             body <- wrap procedureBody+                             lexicalToken (string procedureName)+                             return (Abstract.procedureDeclaration heading body),+   procedureHeading = Abstract.procedureHeading <$ keyword "PROCEDURE" <*> (True <$ delimiter "*" <|> pure False)+                      <**> do n <- clearConsumed (lookAhead ident)+                              idd <- identdef+                              params <- optional (wrap formalParameters)+                              return (\proc-> (n, proc idd params)),+   formalParameters = Abstract.formalParameters <$> parens (sepBy (wrap fPSection) (delimiter ";"))                       <*> optional (delimiter ":" *> qualident),-   fPSection = FPSection <$> (True <$ keyword "VAR" <|> pure False) -               <*> 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+   fPSection = Abstract.fpSection <$> (True <$ keyword "VAR" <|> pure False) +               <*> sepBy1 ident (delimiter ",") <* delimiter ":" <*> wrap formalType,+   formalType = Abstract.arrayType [] <$ keyword "ARRAY" <* keyword "OF" <*> wrap formalType +                <|> Abstract.typeReference <$> qualident+                <|> Abstract.procedureType <$ keyword "PROCEDURE" <*> optional (wrap formalParameters),+   procedureBody = Abstract.block <$> declarationSequence                    <*> optional (keyword "BEGIN" *> wrap statementSequence) <* keyword "END",-   forwardDeclaration = ForwardDeclaration <$ keyword "PROCEDURE" <* delimiter "^"+   forwardDeclaration = Abstract.forwardDeclaration <$ keyword "PROCEDURE" <* 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+   statementSequence = Abstract.statementSequence <$> sepBy1 statement (delimiter ";"),+   statement = wrapAmbiguous (assignment <|> procedureCall <|> ifStatement <|> caseStatement +                              <|> whileStatement <|> repeatStatement <|> loopStatement+                              <|> forStatement <|> withStatement +                              <|> Abstract.exitStatement <$ keyword "EXIT" +                              <|> Abstract.returnStatement <$ keyword "RETURN" <*> optional expression+                              <|> pure Abstract.emptyStatement)                <?> "statement",-   assignment  =  Assignment <$> designator <* delimiter ":=" <*> expression,-   procedureCall = ProcedureCall <$> designator <*> optional actualParameters,-   ifStatement = If <$ keyword "IF"-       <*> sepByNonEmpty (wrap $ Deep.Pair <$> expression <* keyword "THEN" <*> wrap statementSequence)+   assignment  =  Abstract.assignment <$> designator <* delimiter ":=" <*> expression,+   procedureCall = Abstract.procedureCall <$> wrapAmbiguous unguardedDesignator <*> optional actualParameters,+   ifStatement = Abstract.ifStatement <$ keyword "IF"+       <*> sepByNonEmpty (wrap $ Abstract.conditionalBranch <$> expression <* keyword "THEN" <*> wrap statementSequence)                          (keyword "ELSIF")        <*> optional (keyword "ELSE" *> wrap statementSequence) <* keyword "END",-   caseStatement = CaseStatement <$ keyword "CASE" <*> expression-       <*  keyword "OF" <*> sepByNonEmpty (wrap case_prod) (delimiter "|")+   caseStatement = Abstract.caseStatement <$ keyword "CASE" <*> expression+       <*  keyword "OF" <*> (catMaybes <$> sepBy1 (optional $ wrap case_prod) (delimiter "|"))        <*> optional (keyword "ELSE" *> wrap statementSequence) <* keyword "END",-   case_prod  =  Case <$> caseLabelList <* delimiter ":" <*> wrap statementSequence-                 <|> pure EmptyCase,-   caseLabelList  =  sepByNonEmpty (wrap caseLabels) (delimiter ","),-   caseLabels = SingleLabel <$> constExpression-                <|> LabelRange <$> constExpression <* delimiter ".." <*> constExpression,-   whileStatement = While <$ keyword "WHILE" <*> expression <* keyword "DO"+   case_prod = Abstract.caseAlternative <$> caseLabelList <* delimiter ":" <*> wrap statementSequence,+   caseLabelList = sepByNonEmpty (wrap caseLabels) (delimiter ","),+   caseLabels = Abstract.singleLabel <$> constExpression+                <|> Abstract.labelRange <$> constExpression <* delimiter ".." <*> constExpression,+   whileStatement = Abstract.whileStatement <$ 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",+   repeatStatement = Abstract.repeatStatement <$ keyword "REPEAT"+                     <*> wrap statementSequence <* keyword "UNTIL" <*> expression,+   loopStatement = Abstract.loopStatement <$ keyword "LOOP" <*> wrap statementSequence <* keyword "END",    forStatement = empty,-   withStatement = With <$ keyword "WITH"-                        <*> ((:| [])-                             <$> wrap (WithAlternative <$> qualident <* delimiter ":" <*> qualident-                                       <* keyword "DO" <*> wrap statementSequence))-                        <*> pure Nothing <* keyword "END"}+   withStatement = Abstract.withStatement <$ keyword "WITH"+                   <*> wrap (Abstract.withAlternative <$> qualident <* delimiter ":" <*> qualident+                             <* keyword "DO" <*> wrap statementSequence)+                   <* keyword "END"} -wrap = ambiguous+wrapBinary :: (NodeWrap a -> NodeWrap a -> a) -> (NodeWrap a -> NodeWrap a -> NodeWrap a)+wrapBinary op a@(Compose (pos, _)) b = Compose (pos, Compose $ pure (Trailing [], op a b)) +moptional :: (Alternative f, Monoid (f a)) => f a -> f a moptional p = p <|> mempty -delimiter, operator :: Text -> Parser (OberonGrammar f) Text Text+delimiter, operator :: Abstract.Oberon l => Text -> Parser (OberonGrammar l f) Text Text -delimiter s = lexicalToken (string s) <?> ("delimiter " <> show s)-operator s = lexicalToken (string s) <?> ("operator " <> show s)+delimiter s = lexicalToken (string s <* lift ([[Token Delimiter s]], ())) <?> ("delimiter " <> show s)+operator s = lexicalToken (string s <* lift ([[Token Operator s]], ())) <?> ("operator " <> show s)  reservedWords :: [Text] reservedWords = ["ARRAY", "IMPORT", "RETURN",
src/Language/Oberon/Pretty.hs view
@@ -1,77 +1,94 @@-{-# LANGUAGE FlexibleInstances, OverloadedStrings #-}+{-# LANGUAGE FlexibleContexts, FlexibleInstances, OverloadedStrings, UndecidableInstances #-}  -- | This module exports the instances of the 'Pretty' type class necessary for printing of an Oberon abstract syntax -- tree. Note that the AST cannot be ambiguous to be pretty-printed, so it must be resolved after parsing. -module Language.Oberon.Pretty () where+module Language.Oberon.Pretty (Precedence(Precedence)) where +import Control.Applicative (ZipList(ZipList, getZipList))+import Data.Char (toUpper) import Data.Functor.Identity (Identity(..)) import Data.List (intersperse)-import Data.List.NonEmpty (NonEmpty((:|)), fromList, toList)+import Data.List.NonEmpty (NonEmpty((:|)), toList) import qualified Data.Text as Text import Data.Text.Prettyprint.Doc import Numeric (showHex)-import Transformation.Deep as Deep (Product(Pair)) +import qualified Language.Oberon.Abstract as Abstract import Language.Oberon.AST -instance Pretty (Module Identity Identity) where-   pretty (Module name imports declarations body name') =+data Precedence e = Precedence Int e++instance (Pretty (Abstract.Import l), Pretty (Abstract.Block l l Identity Identity)) =>+         Pretty (Module λ l Identity Identity) where+   pretty (Module name imports body) =       vsep $ intersperse mempty $       ["MODULE" <+> pretty name <> semi,        if null imports then mempty-       else "IMPORT" <+> align (fillSep (punctuate comma $ prettyImport <$> imports)) <> semi]-      <> (pretty <$> declarations)-      <> [vsep (foldMap (\statements-> ["BEGIN" <#> prettyBlock statements]) body-                <> ["END" <+> pretty name' <> "." <> line])]+       else "IMPORT" <+> align (fillSep (punctuate comma $ prettyImport <$> imports)) <> semi,+       pretty body,+       "END" <+> pretty name <> "." <> line]       where prettyImport (Nothing, mod) = pretty mod             prettyImport (Just inner, mod) = pretty inner <> ":=" <+> pretty mod -instance Pretty (Declaration Identity Identity) where+instance (Abstract.Nameable l, Pretty (Abstract.IdentDef l), Pretty (Abstract.Type l l Identity Identity),+          Pretty (Abstract.Declaration l l Identity Identity),+          Pretty (Abstract.Expression l l Identity Identity), Pretty (Abstract.FormalParameters l l Identity Identity),+          Pretty (Abstract.ProcedureHeading l l Identity Identity),+          Pretty (Abstract.Block l l Identity Identity)) =>+         Pretty (Declaration λ l 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) =-      "VAR" <+> hsep (punctuate comma $ pretty <$> toList idents) <+> colon <+> pretty varType <> semi-   pretty (ProcedureDeclaration heading body name) = vsep [pretty heading <> semi,-                                                           pretty body,-                                                           "END" <+> pretty name <> semi]+      "VAR" <+> hsep (punctuate comma $ pretty <$> toList idents) <> colon <+> pretty varType <> semi+   pretty (ProcedureDeclaration heading body) = vsep [pretty heading <> semi,+                                                      pretty body,+                                                      "END" <+> pretty (Abstract.getProcedureName $ runIdentity heading)+                                                      <> semi]    pretty (ForwardDeclaration ident parameters) = "PROCEDURE" <+> "^" <+> pretty ident <+> pretty parameters <> semi -instance Pretty IdentDef where+instance Pretty (IdentDef l) where    pretty (IdentDef name Exported) = pretty name <> "*"    pretty (IdentDef name ReadOnly) = pretty name <> "-"    pretty (IdentDef name PrivateOnly) = pretty name -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-            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)-               | 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 e = parens (prettyPrec 0 e)-            prettyPrec' p (Identity e) = prettyPrec p e+instance  (Pretty (Precedence (Abstract.Expression l l Identity Identity)),+           Pretty (Abstract.Expression l l Identity Identity),+           Pretty (Abstract.Element l l Identity Identity),+           Pretty (Abstract.Designator l l Identity Identity),+           Pretty (Abstract.Value l l Identity Identity),+           Pretty (Abstract.QualIdent l)) => Pretty (Expression λ l Identity Identity) where+   pretty e = pretty (Precedence 0 e)+   +instance  (Pretty (Precedence (Abstract.Expression l l Identity Identity)),+           Pretty (Abstract.Expression l l Identity Identity),+           Pretty (Abstract.Element l l Identity Identity),+           Pretty (Abstract.Designator l l Identity Identity),+           Pretty (Abstract.QualIdent l),+           Pretty (Abstract.Value l l Identity Identity)) =>+          Pretty (Precedence (Expression λ l Identity Identity)) where+   pretty (Precedence 0 (Relation op left right)) = prettyPrec' 1 left <+> pretty op <+> prettyPrec' 1 right+   pretty (Precedence 0 (IsA left right)) = prettyPrec' 1 left <+> "IS" <+> pretty right+   pretty (Precedence p (Add left right)) | p < 2 = prettyPrec' 2 left <> "+" <> prettyPrec' 2 right+   pretty (Precedence p (Subtract left right)) | p < 2 = prettyPrec' 2 left <> "-" <> prettyPrec' 2 right+   pretty (Precedence p (Or left right)) | p < 2 = prettyPrec' 2 left <+> "OR" <+> prettyPrec' 2 right+   pretty (Precedence p (Positive e)) | p < 3 = "+" <> prettyPrec' 3 e+   pretty (Precedence p (Negative e)) | p < 3 = "-" <> prettyPrec' 3 e+   pretty (Precedence p (Multiply left right)) | p < 4 = prettyPrec' 4 left <> "*" <> prettyPrec' 4 right+   pretty (Precedence p (Divide left right)) | p < 4 = prettyPrec' 4 left <> "/" <> prettyPrec' 4 right+   pretty (Precedence p (IntegerDivide left right)) | p < 4 = prettyPrec' 4 left <+> "DIV" <+> prettyPrec' 4 right+   pretty (Precedence p (Modulo left right)) | p < 4 = prettyPrec' 4 left <+> "MOD" <+> prettyPrec' 4 right+   pretty (Precedence p (And left right)) | p < 4 = prettyPrec' 4 left <+> "&" <+> prettyPrec' 4 right+   pretty (Precedence _ (Set elements)) = braces (hsep $ punctuate comma $ pretty . runIdentity <$> getZipList elements)+   pretty (Precedence _ (Read (Identity var))) = pretty var+   pretty (Precedence _ (FunctionCall (Identity fun) parameters)) =+      pretty fun <> parens (hsep $ punctuate comma $ pretty . runIdentity <$> getZipList parameters)+   pretty (Precedence _ (Literal (Identity val))) = pretty val+   pretty (Precedence p (Not e)) | p < 5 = "~" <> prettyPrec' 5 e+   pretty (Precedence _ e) = parens (pretty e) +prettyPrec' p (Identity e) = pretty (Precedence p e)+ instance Pretty RelOp where    pretty Equal = "="    pretty Unequal = "#"@@ -80,62 +97,87 @@    pretty Greater = ">"    pretty GreaterOrEqual = ">="    pretty In = "IN"-   pretty Is = "IS" -instance Pretty (Element Identity Identity) where+instance Pretty (Abstract.Expression l l Identity Identity) => Pretty (Element λ l Identity Identity) where    pretty (Element e) = pretty e    pretty (Range from to) = pretty from <+> ".." <+> pretty to -instance Pretty (Designator Identity Identity) where+instance Pretty (Value Language l Identity Identity) where+   pretty (Boolean False) = "FALSE"+   pretty (Boolean True) = "TRUE"+   pretty (Integer n) = pretty n+   pretty (Real r) = pretty (map toUpper $ show r)+   pretty (CharCode c) = "0" <> pretty (showHex c "") <> "X"+   pretty (String s)+      | Text.any (== '"') s = squotes (pretty s)+      | otherwise = dquotes (pretty s)+   pretty Nil = "NIL"+   pretty (Builtin name) = pretty name+++instance (Pretty (Abstract.QualIdent l), Pretty (Abstract.Designator l l Identity Identity),+          Pretty (Abstract.Expression l l Identity Identity)) => Pretty (Designator λ l 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 (Index array index indexes) = pretty array <> brackets (hsep $ punctuate comma+                                                                  $ pretty <$> index : getZipList indexes)    pretty (TypeGuard scrutinee typeName) = pretty scrutinee <> parens (pretty typeName)    pretty (Dereference pointer) = pretty pointer <> "^" -instance Pretty (Type Identity Identity) where+instance (Pretty (Abstract.FormalParameters l l Identity Identity), Pretty (Abstract.FieldList l l Identity Identity),+          Pretty (Abstract.ConstExpression l l Identity Identity), Pretty (Abstract.Type l l Identity Identity),+          Pretty (Abstract.BaseType l)) => Pretty (Type λ l Identity Identity) where    pretty (TypeReference q) = pretty q    pretty (ArrayType dimensions itemType) =-      "ARRAY" <+> hsep (punctuate comma $ pretty . runIdentity <$> dimensions) <+> "OF" <+> pretty itemType+      hsep ("ARRAY" : punctuate comma (pretty . runIdentity <$> getZipList dimensions)) <+> "OF" <+> pretty itemType    pretty (RecordType baseType fields) = vsep ["RECORD" <+> foldMap (parens . pretty) baseType,-                                               indent 3 (vsep $ punctuate semi $ pretty <$> toList fields),+                                               indent 3 (vsep $ punctuate semi $ pretty <$> getZipList fields),                                                "END"]    pretty (PointerType pointed) = "POINTER" <+> "TO" <+> pretty pointed    pretty (ProcedureType parameters) = "PROCEDURE" <+> pretty parameters -instance Pretty QualIdent where+instance Pretty (QualIdent l) where    pretty (QualIdent moduleName memberName) = pretty moduleName <> "." <> pretty memberName    pretty (NonQualIdent localName) = pretty localName -instance Pretty (FieldList Identity Identity) where-   pretty (FieldList names t) = hsep (punctuate comma $ pretty <$> toList names) <+> ":" <+> pretty t-   pretty EmptyFieldList = mempty+instance (Pretty (Abstract.IdentDef l), Pretty (Abstract.Type l l Identity Identity)) =>+         Pretty (FieldList λ l Identity Identity) where+   pretty (FieldList names t) = hsep (punctuate comma $ pretty <$> toList names) <> colon <+> pretty t -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-      where prettyReceiver (var, name, t) = parens ((if var then "VAR " else mempty)-                                                        <> pretty name <> colon <+> pretty t)-                                            <> space+instance (Pretty (Abstract.IdentDef l), Pretty (Abstract.FormalParameters l l Identity Identity),+          Pretty (Abstract.Type l l Identity Identity)) =>+         Pretty (ProcedureHeading λ l Identity Identity) where+   pretty (ProcedureHeading indirect ident parameters) =+      "PROCEDURE" <> (if indirect then "* " else space) <> pretty ident <> pretty parameters+   pretty (TypeBoundHeading var receiverName receiverType indirect ident parameters) =+      "PROCEDURE" <> space +      <> parens ((if var then "VAR " else mempty) <> pretty receiverName <> colon <+> pretty receiverType)+      <> space <> (if indirect then "* " else space) <> pretty ident <> pretty parameters -instance Pretty (FormalParameters Identity Identity) where+instance (Pretty (Abstract.FPSection l l Identity Identity),+          Pretty (Abstract.ReturnType l)) => Pretty (FormalParameters λ l Identity Identity) where    pretty (FormalParameters sections result) =-      lparen <> hsep (punctuate semi $ pretty <$> sections) <> rparen <> foldMap (colon <+>) (pretty <$> result)+      lparen <> hsep (punctuate semi $ pretty <$> getZipList sections) <> rparen <> foldMap (colon <+>) (pretty <$> result) -instance Pretty (FPSection Identity Identity) where+instance Pretty (Abstract.Type l l Identity Identity) => Pretty (FPSection λ l Identity Identity) where    pretty (FPSection var names t) =-      (if var then ("VAR" <+>) else id) $ hsep (punctuate comma $ pretty <$> toList names) <+> colon <+> pretty t+      (if var then ("VAR" <+>) else id) $ hsep (punctuate comma $ pretty <$> names) <+> (colon <+> pretty t)    -instance Pretty (ProcedureBody Identity Identity) where-   pretty (ProcedureBody declarations body) =-      vsep ((indent 3 . pretty <$> declarations)+instance (Pretty (Abstract.Declaration l l Identity Identity), Pretty (Abstract.StatementSequence l l Identity Identity)) =>+         Pretty (Block λ l Identity Identity) where+   pretty (Block declarations body) =+      vsep ((indent 3 . pretty <$> getZipList declarations)             ++ foldMap (\statements-> ["BEGIN", prettyBlock statements]) body) -instance Pretty (StatementSequence Identity Identity) where-   pretty (StatementSequence statements) = pretty (runIdentity <$> statements)+instance Pretty (Abstract.Statement l l Identity Identity) => Pretty (StatementSequence λ l Identity Identity) where+   pretty (StatementSequence statements) = pretty (runIdentity <$> getZipList statements) -instance Pretty (Statement Identity Identity) where+instance (Pretty (Abstract.ConstExpression l l Identity Identity),+          Pretty (Abstract.Designator l l Identity Identity),+          Pretty (Abstract.Case l l Identity Identity),+          Pretty (Abstract.ConditionalBranch l l Identity Identity),+          Pretty (Abstract.WithAlternative l l Identity Identity),+          Pretty (Abstract.StatementSequence l l Identity Identity)) => Pretty (Statement λ l Identity Identity) where    prettyList l = vsep (dropEmptyTail $ punctuate semi $ pretty <$> l)       where dropEmptyTail                | not (null l), EmptyStatement <- last l = init@@ -143,20 +185,16 @@    pretty EmptyStatement = mempty    pretty (Assignment (Identity destination) expression) = pretty destination <+> ":=" <+> pretty expression    pretty (ProcedureCall (Identity procedure) parameters) =-      pretty procedure <> foldMap (parens . hsep . punctuate comma . (pretty <$>)) parameters-   pretty (If (ifThen :| elsifs) fallback) = vsep (branch "IF" ifThen-                                                   : (branch "ELSIF" <$> elsifs)-                                                    ++ foldMap (\x-> ["ELSE", prettyBlock x]) fallback-                                                    ++ ["END"])-      where branch kwd (Identity (Deep.Pair (Identity condition) (Identity body))) =-               vsep [kwd <+> pretty condition <+> "THEN",-                     prettyBlock (Identity body)]+      pretty procedure <> foldMap (parens . hsep . punctuate comma . (pretty <$>)) (getZipList <$> parameters)+   pretty (If ifThen (ZipList elsifs) fallback) = vsep ("IF" <+> pretty ifThen+                                                        : ((("ELSIF" <+>) . pretty) <$> elsifs)+                                                        ++ foldMap (\x-> ["ELSE", prettyBlock x]) fallback+                                                        ++ ["END"])    pretty (CaseStatement scrutinee cases fallback) = vsep ["CASE" <+> pretty scrutinee <+> "OF",                                                            align (encloseSep mempty mempty "| "-                                                                  $ pretty <$> toList cases),+                                                                  $ pretty <$> getZipList cases),                                                            foldMap ("ELSE" <#>) (prettyBlock <$> fallback),                                                            "END"]-                                                               pretty (While condition body) = vsep ["WHILE" <+> pretty condition <+> "DO",                                          prettyBlock body,                                          "END"]@@ -170,28 +208,37 @@    pretty (Loop body) = vsep ["LOOP",                               prettyBlock body,                               "END"]-   pretty (With alternatives fallback) =+   pretty (With alternative (ZipList alternatives) fallback) =       "WITH" <+>-      vsep (punctuate pipe (pretty <$> toList alternatives) ++ +      vsep (punctuate pipe (pretty <$> alternative : alternatives) ++              foldMap (\x-> ["ELSE", prettyBlock x]) fallback ++             ["END"])    pretty Exit = "EXIT"    pretty (Return result) = "RETURN" <+> foldMap pretty result++instance (Pretty (Abstract.Expression l l Identity Identity),+          Pretty (Abstract.StatementSequence l l Identity Identity)) =>+         Pretty (ConditionalBranch λ l Identity Identity) where+   pretty (ConditionalBranch condition body) = vsep [pretty condition <+> "THEN",+                                                     prettyBlock body]    -instance Pretty (Case Identity Identity) where-   pretty (Case labels body) = vsep [hsep (punctuate comma (pretty <$> toList labels)) <+> colon,+instance (Pretty (Abstract.CaseLabels l l Identity Identity),+          Pretty (Abstract.ConstExpression l l Identity Identity),+          Pretty (Abstract.StatementSequence l l Identity Identity)) => Pretty (Case λ l Identity Identity) where+   pretty (Case label labels body) = vsep [hsep (punctuate comma (pretty <$> label : getZipList labels)) <> colon,                                      prettyBlock body]-   pretty EmptyCase = mempty    -instance Pretty (WithAlternative Identity Identity) where-   pretty (WithAlternative name t body) = vsep [pretty name <+> colon <+> pretty t <+> "DO",+instance (Pretty (Abstract.QualIdent l), Pretty (Abstract.StatementSequence l l Identity Identity)) =>+         Pretty (WithAlternative λ l Identity Identity) where+   pretty (WithAlternative name t body) = vsep [pretty name <> colon <+> pretty t <+> "DO",                                                 prettyBlock body] -instance Pretty (CaseLabels Identity Identity) where+instance Pretty (Abstract.ConstExpression l l Identity Identity) => Pretty (CaseLabels λ l Identity Identity) where    pretty (SingleLabel expression) = pretty expression    pretty (LabelRange from to) = pretty from <+> ".." <+> pretty to -prettyBlock :: Identity (StatementSequence Identity Identity) -> Doc ann-prettyBlock (Identity (StatementSequence statements)) = indent 3 (pretty $ runIdentity <$> statements)+prettyBlock :: Pretty (Abstract.StatementSequence l l Identity Identity) =>+               Identity (Abstract.StatementSequence l l Identity Identity) -> Doc ann+prettyBlock (Identity statements) = indent 3 (pretty statements)  a <#> b = vsep [a, b]
+ src/Language/Oberon/Reserializer.hs view
@@ -0,0 +1,99 @@+{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses,+             ScopedTypeVariables, TemplateHaskell, TypeFamilies, TypeOperators, UndecidableInstances #-}+{-# OPTIONS_GHC -Wno-simplifiable-class-constraints #-}++-- | This module exports functions for reserializing the parsed tree from the tokens stored with every node.++module Language.Oberon.Reserializer (adjustPositions, reserialize, sourceLength, PositionAdjustment, Serialization) where++import Control.Arrow (first)+import Control.Monad.Trans.State.Strict (State, StateT(..), evalState, runState, state)+import Data.Either (partitionEithers)+import Data.Either.Validation (Validation(..), validationToEither)+import Data.Foldable (toList)+import Data.Functor.Compose (Compose(..))+import Data.Functor.Const (Const(..))+import Data.Monoid (Ap(Ap, getAp), Sum(Sum, getSum))+import Data.Text (Text)+import qualified Data.Text as Text++import qualified Rank2+import qualified Transformation+import qualified Transformation.Rank2+import qualified Transformation.Deep as Deep+import qualified Transformation.Full as Full++import qualified Language.Oberon.Abstract as Abstract+import Language.Oberon.AST+import Language.Oberon.Grammar (ParsedLexemes(Trailing), Lexeme(..))++-- | Re-calculates the position of every node in the parse tree from the tokens stored with it and its children.+adjustPositions :: (Rank2.Foldable (g (Const (Sum Int))),+                    Deep.Foldable (Transformation.Rank2.Fold Parsed (Sum Int)) g,+                    Deep.Traversable PositionAdjustment g) => Parsed (g Parsed Parsed) -> Parsed (g Parsed Parsed)+adjustPositions node@((pos, _, _), _) = evalState (Full.traverse PositionAdjustment node) 0++-- | Serializes the tree back into the text it was parsed from.+reserialize :: Deep.Foldable Serialization g => Parsed (g Parsed Parsed) -> Text+reserialize = finalize . (`runState` (0, [])) . getAp . Full.foldMap Serialization+   where finalize (s, (_pos, rest)) = s <> foldMap lexemeText rest++-- | The length of the source code parsed into the argument node+sourceLength :: (Rank2.Foldable (g (Const (Sum Int))),+                 Deep.Foldable (Transformation.Rank2.Fold Parsed (Sum Int)) g) => Parsed (g Parsed Parsed) -> Int+sourceLength root@((_, Trailing rootLexemes, _), node) = getSum (nodeLength root+                                                                 <> Transformation.Rank2.foldMap nodeLength node)+   where nodeLength ((_, Trailing lexemes, _), _) = foldMap (Sum . Text.length . lexemeText) lexemes++type Parsed = (,) (Int, ParsedLexemes, Int)++-- | Transformation type used by 'reserialize'+data Serialization = Serialization+-- | Transformation type used by 'adjustPositions'+data PositionAdjustment = PositionAdjustment++instance Transformation.Transformation Serialization where+    type Domain Serialization = Parsed+    type Codomain Serialization = Const (Ap (State (Int, [Lexeme])) Text)++instance Transformation.Transformation PositionAdjustment where+    type Domain PositionAdjustment = Parsed+    type Codomain PositionAdjustment = Compose (State Int) Parsed++instance Serialization `Transformation.At` g Parsed Parsed where+   Serialization $ ((nodePos, Trailing nodeLexemes, _), _) = Const (Ap $ state f)+      where f :: (Int, [Lexeme]) -> (Text, (Int, [Lexeme]))+            f (pos, lexemes)+               | nodePos > pos, l:ls <- lexemes, t <- lexemeText l = first (t <>) (f (pos + Text.length t, ls))+               | otherwise = (mempty, (pos, nodeLexemes <> lexemes))++instance (Rank2.Foldable (g Parsed), Deep.Foldable Serialization g) => Full.Foldable Serialization g where+   foldMap trans ((nodeStart, Trailing nodeLexemes, _), node) = Ap (state f)+      where f :: (Int, [Lexeme]) -> (Text, (Int, [Lexeme]))+            f (pos, lexemes)+               | nodeStart > pos, l:ls <- lexemes, t <- lexemeText l = first (t <>) (f (pos + Text.length t, ls))+               | otherwise = let (t, (pos', lexemes')) = runState (getAp $ Deep.foldMap trans node) (pos, nodeLexemes)+                                 t' = foldMap lexemeText lexemes'+                             in (t <> t', (pos' + Text.length t', lexemes))++instance (Rank2.Foldable (g (Const (Sum Int))),+          Deep.Foldable (Transformation.Rank2.Fold Parsed (Sum Int)) g) =>+         PositionAdjustment `Transformation.At` g Parsed Parsed where+   PositionAdjustment $ root@((nodeStart, lexemes, nodeEnd), node) = Compose (state f)+      where f adjustment = (((nodeStart + adjustment, lexemes, nodeEnd' + adjustment), node),+                            adjustment + nodeEnd' - nodeEnd)+               where nodeEnd' = nodeStart + sourceLength root++instance (Rank2.Foldable (g (Const (Sum Int))),+          Deep.Foldable (Transformation.Rank2.Fold Parsed (Sum Int)) g,+          Deep.Traversable PositionAdjustment g) => Full.Traversable PositionAdjustment g where+   traverse PositionAdjustment root@((nodeStart, lexemes, nodeEnd), node) = state f+      where f adjustment = (((nodeStart + adjustment, lexemes, nodeEnd' + adjustment),+                             evalState (Deep.traverse PositionAdjustment node) adjustment),+                            adjustment + nodeEnd' - nodeEnd)+               where nodeEnd' = nodeStart + sourceLength root++instance (Rank2.Foldable (g Parsed),+          Deep.Foldable (Transformation.Rank2.Fold Parsed (Sum Int)) g) =>+         Full.Foldable (Transformation.Rank2.Fold Parsed (Sum Int)) g where+   foldMap = Full.foldMapDownDefault
src/Language/Oberon/Resolver.hs view
@@ -1,74 +1,107 @@-{-# LANGUAGE FlexibleContexts, FlexibleInstances, KindSignatures, MultiParamTypeClasses,-             OverloadedStrings, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, UndecidableInstances #-}+{-# LANGUAGE FlexibleContexts, FlexibleInstances, KindSignatures, MultiParamTypeClasses, OverloadedStrings,+             ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, TypeFamilies, TypeOperators,+             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 -- @foo@ casting it to type @bar@. -module Language.Oberon.Resolver (Error(..),-                                 Predefined, predefined, predefined2, resolveModule, resolveModules) where+module Language.Oberon.Resolver (resolveModules, resolveModule, resolvePositions, resolvePosition,+                                 Error(..), Predefined, Placed, NodeWrap, predefined, predefined2) where -import Control.Applicative (Alternative)-import Control.Monad ((>=>))-import Control.Monad.Trans.State (StateT(..), evalStateT)+import Control.Applicative (ZipList(ZipList, getZipList))+import Control.Arrow (first)+import Control.Monad.Trans.State (StateT(..), evalStateT, execStateT, get, put) import Data.Either (partitionEithers) import Data.Either.Validation (Validation(..), validationToEither) import Data.Foldable (toList)-import Data.Functor.Identity (Identity(..))+import Data.Functor.Compose (Compose(..)) import Data.List.NonEmpty (NonEmpty(..)) import qualified Data.List.NonEmpty as NonEmpty import qualified Data.List as List-import Data.Monoid (Alt(..)) import Data.Map.Lazy (Map, traverseWithKey) import qualified Data.Map.Lazy as Map import Data.Semigroup (Semigroup(..), sconcat)+import Data.Text (Text)+import Language.Haskell.TH (appT, conT, varT, newName) +import qualified Text.Parser.Input.Position as Position import qualified Rank2.TH-import qualified Transformation as Shallow+import qualified Transformation import qualified Transformation.Deep as Deep import qualified Transformation.Deep.TH+import qualified Transformation.Full as Full+import qualified Transformation.Full.TH import qualified Transformation.Rank2 as Rank2-import Text.Grampa (Ambiguous(..), ParseFailure)+import Text.Grampa (Ambiguous(..)) +import qualified Language.Oberon.Abstract as Abstract import Language.Oberon.AST+import Language.Oberon.Grammar (ParsedLexemes(Trailing))+import qualified Language.Oberon.Grammar as Grammar -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)+-- | Replace the stored positions in the entire ambiguous parsed tree, as obtained from "Language.Oberon.Grammar",+-- | with offsets from the start of the given source text+resolvePositions :: (p ~ Grammar.NodeWrap, q ~ NodeWrap, Deep.Functor (Rank2.Map p q) g)+                 => Text -> p (g p p) -> q (g q q)+resolvePositions src t = Rank2.Map (resolvePosition src) Full.<$> t +-- | Replace the stored positions of the given node, as obtained from "Language.Oberon.Grammar", with offset from the+-- | start of the given source text+resolvePosition :: Text -> Grammar.NodeWrap a -> NodeWrap a+resolvePosition src = \(Compose ((start, end), a))-> Compose ((Position.offset src start, Position.offset src end), a)++data DeclarationRHS l f' f = DeclaredConstant (f (Abstract.ConstExpression l l f' f'))+                           | DeclaredType (f (Abstract.Type l l f' f'))+                           | DeclaredVariable (f (Abstract.Type l l f' f'))+                           | DeclaredProcedure Bool (Maybe (f (Abstract.FormalParameters l l f' f')))+deriving instance (Show (Abstract.FormalParameters l l Placed Placed), Show (Abstract.Type l l Placed Placed),+                   Show (Abstract.ConstExpression l l Placed Placed)) =>+                  Show (DeclarationRHS l Placed Placed)+deriving instance (Show (Abstract.FormalParameters l l NodeWrap NodeWrap), Show (Abstract.Type l l NodeWrap NodeWrap),+                   Show (Abstract.ConstExpression l l NodeWrap NodeWrap)) =>+                  Show (DeclarationRHS l NodeWrap NodeWrap)+ -- | All possible resolution errors-data Error = UnknownModule QualIdent-           | UnknownLocal Ident-           | UnknownImport QualIdent-           | AmbiguousParses-           | 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)-           | NotARecord QualIdent-           | NotAType QualIdent-           | NotAValue QualIdent-           | ClashingImports-           | UnparseableModule ParseFailure-           deriving (Show)+data Error l = UnknownModule (Abstract.QualIdent l)+             | UnknownLocal Ident+             | UnknownImport (Abstract.QualIdent l)+             | AmbiguousParses+             | AmbiguousDeclaration [Declaration l l NodeWrap NodeWrap]+             | AmbiguousDesignator [Designator l l NodeWrap NodeWrap]+             | AmbiguousExpression [Expression l l NodeWrap NodeWrap]+             | AmbiguousRecord [Designator l l NodeWrap NodeWrap]+             | AmbiguousStatement [Statement l l NodeWrap NodeWrap]+             | InvalidExpression (NonEmpty (Error l))+             | InvalidFunctionParameters [NodeWrap (Abstract.Expression l l NodeWrap NodeWrap)]+             | InvalidRecord (NonEmpty (Error l))+             | InvalidStatement (NonEmpty (Error l))+             | NotARecord (Abstract.QualIdent l)+             | NotAType (Abstract.QualIdent l)+             | NotAValue (Abstract.QualIdent l)+             | ClashingImports+             | UnparseableModule Text+deriving instance (Show (Abstract.QualIdent l),+                   Show (Declaration l l NodeWrap NodeWrap), Show (Statement l l NodeWrap NodeWrap),+                   Show (Expression l l NodeWrap NodeWrap), Show (Abstract.Expression l l NodeWrap NodeWrap),+                   Show (Designator l l NodeWrap NodeWrap)) => Show (Error l) -type Scope = Map Ident (Validation (NonEmpty Error) (DeclarationRHS Identity Identity))+-- | The node wrapper in a fully resolved AST+type Placed = (,) (Int, ParsedLexemes, Int) +-- | The node wrapper in an ambiguous, freshly parsed AST, only with 'Position.Position' replaced with an offset from+-- the beginning of the source.+type NodeWrap = Compose ((,) (Int, Int)) (Compose Ambiguous ((,) ParsedLexemes))++type Scope l = Map Ident (Validation (NonEmpty (Error l)) (DeclarationRHS l Placed Placed))+ -- | A set of predefined declarations.-type Predefined = Scope+type Predefined l = Scope l -data Resolution = Resolution{_modules :: Map Ident Scope}+data Resolution l = Resolution{_modules :: Map Ident (Scope l)} -type Resolved = StateT (Scope, ResolutionState) (Validation (NonEmpty Error))+type Resolved l = StateT (Scope l, ResolutionState) (Validation (NonEmpty (Error l)))  data ResolutionState = ModuleState                      | DeclarationState@@ -77,158 +110,274 @@                      | ExpressionOrTypeState                      deriving (Eq, Show) -instance Monad (Validation (NonEmpty Error)) where+instance Monad (Validation (NonEmpty (Error l))) where    Success s >>= f = f s    Failure errors >>= _ = Failure errors -instance Shallow.Functor Resolution Ambiguous Resolved (Module Resolved Resolved) where-   (<$>) = mapResolveDefault+instance Transformation.Transformation (Resolution l) where+    type Domain (Resolution l) = NodeWrap+    type Codomain (Resolution l) = Compose (Resolved l) Placed -instance {-# overlappable #-} Show (g Identity Identity) =>-                              Shallow.Traversable Resolution Ambiguous Identity Resolved (g Identity Identity) where-   traverse = traverseResolveDefault+instance {-# overlappable #-} Resolution l `Transformation.At` g Placed Placed where+   ($) = traverseResolveDefault -instance {-# overlappable #-} Show (g Ambiguous Ambiguous) =>-                              Shallow.Traversable Resolution Ambiguous Identity Resolved (g Ambiguous Ambiguous) where-   traverse = traverseResolveDefault+instance {-# overlappable #-} Resolution l `Transformation.At` g NodeWrap NodeWrap where+   ($) = traverseResolveDefault -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)+instance {-# overlaps #-} Resolvable l => Resolution l `Transformation.At` Designator l l NodeWrap NodeWrap where+   res $ Compose ((start, end), Compose (Ambiguous designators)) = Compose $ StateT $ \s@(scope, state)->+      case partitionEithers (NonEmpty.toList (traverse (validationToEither . resolveDesignator res scope state)+                                              <$> designators))+      of (_, [(ws, x)]) -> Success (((start, ws, end), x), s)          (errors, []) -> Failure (sconcat $ NonEmpty.fromList errors)-         (_, multi) -> Failure (AmbiguousDesignator multi :| [])+         (_, multi) -> Failure (AmbiguousDesignator (snd <$> multi) :| []) -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)+class Readable l where+   getVariableName :: Abstract.Designator l l f' f -> Maybe (Abstract.QualIdent l)++instance Readable Language where+   getVariableName (Variable q) = Just q+   getVariableName _ = Nothing++instance {-# overlaps #-}+   (Readable l, Abstract.Nameable l, Abstract.Oberon l,+    Deep.Traversable (Resolution l) (Abstract.Expression l l),+    Deep.Traversable (Resolution l) (Abstract.Designator l l),+    Resolution l `Transformation.At` Abstract.Expression l l NodeWrap NodeWrap,+    Resolution l `Transformation.At` Abstract.Designator l l NodeWrap NodeWrap) =>+   Resolution l `Transformation.At` Expression l l NodeWrap NodeWrap where+   res $ expressions = Compose $ StateT $ \s@(scope, state)->+      let resolveExpression :: Expression l l NodeWrap NodeWrap+                            -> Validation (NonEmpty (Error l)) (Expression l l NodeWrap NodeWrap, ResolutionState)           resolveExpression e@(Read designators) =-             case evalStateT (Shallow.traverse res designators) s+             case evalStateT (getCompose $ res Transformation.$ designators) s              of Failure errors -> Failure errors                 Success{} -> pure (e, state)           resolveExpression e@(FunctionCall functions parameters) =-             case evalStateT (Shallow.traverse res functions) s+             case evalStateT (getCompose $ res Transformation.$ functions) s              of Failure errors -> Failure errors-                Success (Identity d)-                   | Variable q <- d, Success (DeclaredProcedure True _) <- resolveName res scope q+                Success (_pos, d)+                   | Just q <- getVariableName d, Success (DeclaredProcedure True _) <- resolveName res scope q                      -> pure (e, ExpressionOrTypeState)-                   | Success{} <- evalStateT (traverse (Shallow.traverse res) parameters) (scope, ExpressionState)+                   | Success{} <- evalStateT (traverse (getCompose . (res Transformation.$)) parameters)+                                             (scope, ExpressionState)                      -> pure (e, ExpressionState)-                   | otherwise -> Failure (pure $ InvalidFunctionParameters parameters)-          resolveExpression e@(Relation Is lefts rights) = pure (e, ExpressionOrTypeState)+                   | otherwise -> Failure (pure $ InvalidFunctionParameters $ getZipList parameters)+          resolveExpression e@(IsA _lefts q) =+            case resolveName res scope q+            of Failure err ->  Failure err+               Success DeclaredType{} -> pure (e, ExpressionState)+               Success _ -> Failure (NotAType q :| [])           resolveExpression e = pure (e, state)-      in (\(r, s)-> (Identity r, (scope, s)))+      in (\(pos, (r, s'))-> ((pos, r), (scope, s')))          <$> unique InvalidExpression (AmbiguousExpression . (fst <$>)) (resolveExpression <$> expressions) -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)+instance {-# overlaps #-}+   (BindableDeclaration l, CoFormalParameters l, Abstract.Wirthy l,+    Full.Traversable (Resolution l) (Abstract.Type l l),+    Full.Traversable (Resolution l) (Abstract.FormalParameters l l),+    Full.Traversable (Resolution l) (Abstract.ConstExpression l l),+    Deep.Traversable (Resolution l) (Abstract.Type l l),+    Deep.Traversable (Resolution l) (Abstract.ProcedureHeading l l),+    Deep.Traversable (Resolution l) (Abstract.FormalParameters l l),+    Deep.Traversable (Resolution l) (Abstract.ConstExpression l l),+    Resolution l `Transformation.At` Abstract.ProcedureHeading l l NodeWrap NodeWrap,+    Resolution l `Transformation.At` Abstract.Block l l NodeWrap NodeWrap) =>+   Resolution l `Transformation.At` Declaration l l NodeWrap NodeWrap where+   res $ Compose ((start, end), Compose (Ambiguous ((ws, proc@(ProcedureDeclaration heading body)) :| []))) =+      Compose $+      do s@(scope, state) <- get+         let Success (headingScope, _) = execStateT (getCompose $ res Transformation.$ heading) s+             Success (_, body') = evalStateT (getCompose $ res Transformation.$ body) s+             innerScope = localScope res "" (getLocalDeclarations body') (headingScope `Map.union` scope)+         put (innerScope, state)+         return ((start, ws, end), proc)+   _ $ Compose ((start, end), Compose (Ambiguous ((ws, dec) :| []))) = Compose (pure ((start, ws, end), dec))+   _ $ declarations = Compose (StateT $ const $ Failure $ pure $ AmbiguousDeclaration $ toList declarations)++class CoFormalParameters l where+   getFPSections :: Abstract.FormalParameters l l f' f -> [f (Abstract.FPSection l l f' f')]+   evalFPSection :: Abstract.FPSection l l f' f -> (Bool -> [Ident] -> f (Abstract.Type l l f' f') -> r) -> r+   getLocalDeclarations :: Abstract.Block l l f' f -> [f (Abstract.Declaration l l f' f')]++instance CoFormalParameters Language where+   getFPSections (FormalParameters sections _) = getZipList sections+   evalFPSection (FPSection var names types) f = f var names types+   getLocalDeclarations (Block declarations _statements) = getZipList declarations++instance {-# overlaps #-}+   (Abstract.Wirthy l, CoFormalParameters l,+    Full.Traversable (Resolution l) (Abstract.Type l l),+    Full.Traversable (Resolution l) (Abstract.FormalParameters l l),+    Full.Traversable (Resolution l) (Abstract.ConstExpression l l),+    Deep.Traversable (Resolution l) (Abstract.Type l l),+    Deep.Traversable (Resolution l) (Abstract.FormalParameters l l),+    Deep.Traversable (Resolution l) (Abstract.ConstExpression l l)) =>+   Resolution l `Transformation.At` ProcedureHeading l l NodeWrap NodeWrap where+   res $ Compose ((start, end), Compose (Ambiguous ((ws, proc@(ProcedureHeading _ _ parameters)) :| []))) =+      Compose $ StateT $ \s@(scope, state)->+         let innerScope = parameterScope `Map.union` scope              parameterScope = case parameters                               of Nothing -> mempty-                                 Just (Ambiguous (FormalParameters sections _ :| []))+                                 Just (Compose (_, Compose (Ambiguous ((ws, fp) :| [])))) | sections <- getFPSections fp                                     -> 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)+             binding (Compose (_, Compose (Ambiguous ((_, section) :| [])))) = evalFPSection section $ \ _ names types->+                [(v, evalStateT (Deep.traverse res $ DeclaredVariable types) s) | v <- names]+         in Success (((start, ws, end), proc), (innerScope, state))+   res $ Compose ((start, end),+                  Compose (Ambiguous ((ws, proc@(TypeBoundHeading _var receiverName receiverType _ _ parameters))+                                      :| []))) =+      Compose $ StateT $ \s@(scope, state)->+         let innerScope = parameterScope `Map.union` receiverBinding `Map.union` scope+             receiverBinding :: Map Ident (Validation e (DeclarationRHS l f' Placed))+             receiverBinding = Map.singleton receiverName (Success $ DeclaredVariable $ (,) (start, ws, end)+                                                           $ Abstract.typeReference+                                                           $ Abstract.nonQualIdent receiverType)+             parameterScope = case parameters+                              of Nothing -> mempty+                                 Just (Compose (_, Compose (Ambiguous ((ws, fp) :| [])))) | sections <- getFPSections fp+                                    -> Map.fromList (concatMap binding sections)+             binding (Compose (_, Compose (Ambiguous ((_, section) :| [])))) = evalFPSection section $ \ _ names types->+                [(v, evalStateT (Deep.traverse res $ DeclaredVariable types) s) | v <- names]+         in Success (((start, ws, end), proc), (innerScope, state)) -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)+instance {-# overlaps #-}+   (BindableDeclaration l,+    Full.Traversable (Resolution l) (Abstract.Type l l),+    Full.Traversable (Resolution l) (Abstract.FormalParameters l l),+    Full.Traversable (Resolution l) (Abstract.ConstExpression l l),+    Deep.Traversable (Resolution l) (Abstract.Type l l),+    Deep.Traversable (Resolution l) (Abstract.FormalParameters l l),+    Deep.Traversable (Resolution l) (Abstract.ConstExpression l l)) =>+   Resolution l `Transformation.At` Block l l NodeWrap NodeWrap where+   res $ Compose ((start, end), Compose (Ambiguous ((ws, body@(Block (ZipList declarations) _statements)) :| []))) =+     Compose $ StateT $ \(scope, state)-> Success (((start, ws, end), body),+                                                   (localScope res "" declarations scope, state))+   _ $ _ = Compose (StateT $ const $ Failure $ pure AmbiguousParses) -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+instance {-# overlaps #-}+    (Deep.Traversable (Resolution l) (Abstract.Designator l l),+     Resolution l `Transformation.At` Abstract.Designator l l NodeWrap NodeWrap) =>+    Resolution l `Transformation.At` Statement l l NodeWrap NodeWrap where+   res $ statements = Compose $ StateT $ \s@(scope, _state)->+      let resolveStatement :: Statement l l NodeWrap NodeWrap+                            -> Validation (NonEmpty (Error l)) (Statement l l NodeWrap NodeWrap, ResolutionState)+          resolveStatement p@(ProcedureCall procedures _parameters) =+             case evalStateT (getCompose $ res Transformation.$ procedures) s              of Failure errors -> Failure errors                 Success{} -> pure (p, StatementState)           resolveStatement stat = pure (stat, StatementState)-      in (\(r, s)-> (Identity r, (scope, s)))+      in (\(pos, (r, s'))-> ((pos, r), (scope, s')))          <$> unique InvalidStatement (AmbiguousStatement . (fst <$>)) (resolveStatement <$> statements) -mapResolveDefault :: Resolution -> Ambiguous (g Resolved Resolved) -> Resolved (g Resolved Resolved)-mapResolveDefault Resolution{} (Ambiguous (x :| [])) = pure x-mapResolveDefault Resolution{} _ = StateT (const $ Failure $ pure AmbiguousParses)+traverseResolveDefault :: Resolution l -> NodeWrap (g (f :: * -> *) f) -> Compose (Resolved l) Placed (g f f)+traverseResolveDefault Resolution{} (Compose ((start, end), Compose (Ambiguous ((ws, x) :| [])))) =+   Compose (StateT $ \s-> Success (((start, ws, end), x), s))+traverseResolveDefault Resolution{} _ = Compose (StateT $ const $ Failure $ pure AmbiguousParses) -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)+class Resolvable l where+   resolveDesignator :: Resolution l -> Scope l -> ResolutionState -> (Designator l l NodeWrap NodeWrap)+                     -> Validation (NonEmpty (Error l)) (Designator l l NodeWrap NodeWrap)+   resolveRecord :: Resolution l -> Scope l -> ResolutionState -> (Designator l l NodeWrap NodeWrap)+                 -> Validation (NonEmpty (Error l)) (Designator l l NodeWrap NodeWrap) -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{} | state /= ExpressionOrTypeState -> Failure (NotAValue q :| [])-               Success _ -> Success (Variable q)-         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+instance Resolvable Language where+   resolveDesignator res scope state (Variable q) =+      case resolveName res scope q+      of Failure err ->  Failure err+         Success DeclaredType{} | state /= ExpressionOrTypeState -> Failure (NotAValue q :| [])+         Success _ -> Success (Variable q)+   resolveDesignator res scope state d@(Field records field) =+      case evalStateT (getCompose $ res Transformation.$ records) (scope, state)+      of Failure errors -> Failure errors+         Success{} -> pure d+   resolveDesignator res scope state (TypeGuard records subtypes) =+      case unique InvalidRecord AmbiguousRecord (resolveRecord res scope state <$> records)+      of Failure errors -> Failure errors+         Success{} -> TypeGuard records <$> resolveTypeName res scope subtypes+   resolveDesignator res scope state d@(Dereference pointers) =+      case evalStateT (getCompose $ res Transformation.$ pointers) (scope, state)+      of Failure errors -> Failure errors+         Success{} -> pure d+   resolveDesignator _ _ _ d = pure d -         resolveTypeName q =-            case resolveName res scope q-            of Failure err ->  Failure err-               Success DeclaredType{} -> Success q-               Success _ -> Failure (NotAType q :| [])+   resolveRecord res scope state 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{} -> resolveDesignator res scope state d+   resolveRecord res scope state d = resolveDesignator res scope state 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 :| [])+resolveTypeName res scope q =+   case resolveName res scope q+   of Failure err ->  Failure err+      Success DeclaredType{} -> Success q+      Success _ -> Failure (NotAType q :| []) -resolveModules :: Predefined -> Map Ident (Module Ambiguous Ambiguous)-                -> Validation (NonEmpty (Ident, NonEmpty Error)) (Map Ident (Module Identity Identity))+resolveName :: (Abstract.Nameable l, Abstract.Oberon l)+            => Resolution l -> Scope l -> Abstract.QualIdent l+            -> Validation (NonEmpty (Error l)) (DeclarationRHS l Placed Placed)+resolveName res scope q+   | Just (moduleName, name) <- Abstract.getQualIdentNames q =+     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 :| [])+   | Just name <- Abstract.getNonQualIdentName q =+     case Map.lookup name scope+     of Just (Success rhs) -> Success rhs+        _ -> Failure (UnknownLocal name :| [])++-- | Resolve ambiguities in the given collection of modules, a 'Map' keyed by module name. The value for the first+-- argument is typically 'predefined' or 'predefined2'. Note that all class constraints in the function's type+-- signature are satisfied by the Oberon 'Language'.+resolveModules :: forall l. (BindableDeclaration l, CoFormalParameters l, Abstract.Wirthy l,+                             Deep.Traversable (Resolution l) (Abstract.Declaration l l),+                             Deep.Traversable (Resolution l) (Abstract.Type l l),+                             Deep.Traversable (Resolution l) (Abstract.ProcedureHeading l l),+                             Deep.Traversable (Resolution l) (Abstract.FormalParameters l l),+                             Deep.Traversable (Resolution l) (Abstract.Expression l l),+                             Deep.Traversable (Resolution l) (Abstract.Block l l),+                             Deep.Traversable (Resolution l) (Abstract.StatementSequence l l),+                             Full.Traversable (Resolution l) (Abstract.Declaration l l),+                             Full.Traversable (Resolution l) (Abstract.Type l l),+                             Full.Traversable (Resolution l) (Abstract.ProcedureHeading l l),+                             Full.Traversable (Resolution l) (Abstract.FormalParameters l l),+                             Full.Traversable (Resolution l) (Abstract.Expression l l),+                             Full.Traversable (Resolution l) (Abstract.Block l l),+                             Full.Traversable (Resolution l) (Abstract.StatementSequence l l),+                             Resolution l `Transformation.At` Abstract.Block l l NodeWrap NodeWrap) =>+                  Predefined l -> Map Ident (NodeWrap (Module l l NodeWrap NodeWrap))+                -> Validation (NonEmpty (Ident, NonEmpty (Error l))) (Map Ident (Placed (Module l l Placed Placed))) resolveModules predefinedScope modules = traverseWithKey extractErrors modules'    where modules' = resolveModule predefinedScope modules' <$> modules          extractErrors moduleKey (Failure e)   = Failure ((moduleKey, e) :| [])          extractErrors _         (Success mod) = Success mod -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)+-- | Resolve ambiguities in a single module. The value for the first argument is typically 'predefined' or+-- 'predefined2'. The imports are resolved using the given map of already resolved modules. Note that all class+-- constraints in the function's type signature are satisfied by the Oberon 'Language'.+resolveModule :: forall l. (BindableDeclaration l, CoFormalParameters l,+                            Full.Traversable (Resolution l) (Abstract.Block l l),+                            Full.Traversable (Resolution l) (Abstract.Declaration l l),+                            Full.Traversable (Resolution l) (Abstract.Type l l),+                            Full.Traversable (Resolution l) (Abstract.FormalParameters l l),+                            Full.Traversable (Resolution l) (Abstract.ConstExpression l l),+                            Full.Traversable (Resolution l) (Abstract.StatementSequence l l),+                            Deep.Traversable (Resolution l) (Declaration l l),+                            Deep.Traversable (Resolution l) (Abstract.Declaration l l),+                            Deep.Traversable (Resolution l) (Abstract.StatementSequence l l),+                            Deep.Traversable (Resolution l) (Abstract.Type l l),+                            Deep.Traversable (Resolution l) (Abstract.FormalParameters l l),+                            Deep.Traversable (Resolution l) (Abstract.ConstExpression l l),+                            Resolution l `Transformation.At` Abstract.Block l l NodeWrap NodeWrap) =>+                 Scope l -> Map Ident (Validation (NonEmpty (Error l)) (Placed (Module l l Placed Placed)))+              -> NodeWrap (Module l l NodeWrap NodeWrap)+              -> Validation (NonEmpty (Error l)) (Placed (Module l l Placed Placed))+resolveModule predefined modules m@(Compose (pos, Compose (Ambiguous ((ls, Module moduleName imports body) :| [])))) =+   evalStateT (Full.traverse 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@@ -236,129 +385,177 @@                                              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+         resolveDeclaration :: NodeWrap (Declaration l l NodeWrap NodeWrap) -> Resolved l (Declaration l l Placed Placed)+         resolveDeclaration d = snd <$> (traverse (Deep.traverse res) d >>= getCompose . (res Transformation.$))+         moduleExports = foldMap (exportsOfModule . snd) <$> importedModules+         Success (_, body') = evalStateT (getCompose $ res Transformation.$ body) (predefined, ModuleState)+         moduleGlobalScope = localScope res moduleName (getLocalDeclarations body') predefined -localScope :: Resolution -> Ident -> [Ambiguous (Declaration Ambiguous Ambiguous)] -> Scope -> Scope+localScope :: forall l. (BindableDeclaration l,+                         Full.Traversable (Resolution l) (Abstract.Type l l),+                         Full.Traversable (Resolution l) (Abstract.FormalParameters l l),+                         Full.Traversable (Resolution l) (Abstract.ConstExpression l l)) =>+              Resolution l -> Ident -> [NodeWrap (Abstract.Declaration l l NodeWrap NodeWrap)] -> Scope l -> Scope l 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)+         unamb (Compose (offset, Compose (Ambiguous ((_, x) :| [])))) = x+         resolveBinding     :: Resolution l -> Scope l -> DeclarationRHS l NodeWrap NodeWrap+                            -> Validation (NonEmpty (Error l)) (DeclarationRHS l Placed Placed)+         resolveBinding res scope dr = evalStateT (Deep.traverse res dr) (scope, DeclarationState) -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) =-   [(name, (export, DeclaredType typeDef))]-declarationBinding _ (VariableDeclaration names typeDef) =-   [(name, (export, DeclaredVariable typeDef)) | (IdentDef name export) <- NonEmpty.toList names]-declarationBinding moduleName (ProcedureDeclaration (ProcedureHeading _ _ (IdentDef name export) parameters) _ _) =-   [(name, (export, DeclaredProcedure (moduleName == "SYSTEM") parameters))]-declarationBinding _ (ForwardDeclaration (IdentDef name export) parameters) =-   [(name, (export, DeclaredProcedure False parameters))]+class BindableDeclaration l where+   declarationBinding :: Foldable f => Ident -> Abstract.Declaration l l f f -> [(Ident, (AccessMode, DeclarationRHS l f f))]+   +instance BindableDeclaration Language where+   declarationBinding _ (ConstantDeclaration (IdentDef name export) expr) =+      [(name, (export, DeclaredConstant expr))]+   declarationBinding _ (TypeDeclaration (IdentDef name export) typeDef) =+      [(name, (export, DeclaredType typeDef))]+   declarationBinding _ (VariableDeclaration names typeDef) =+      [(name, (export, DeclaredVariable typeDef)) | (IdentDef name export) <- NonEmpty.toList names]+   declarationBinding moduleName (ProcedureDeclaration heading _) = procedureHeadBinding (foldr1 const heading)+      where procedureHeadBinding (ProcedureHeading _ (IdentDef name export) parameters) =+               [(name, (export, DeclaredProcedure (moduleName == "SYSTEM") parameters))]+            procedureHeadBinding (TypeBoundHeading _ _ _ _ (IdentDef name export) parameters) =+               [(name, (export, DeclaredProcedure (moduleName == "SYSTEM") parameters))]+   declarationBinding _ (ForwardDeclaration (IdentDef name export) parameters) =+      [(name, (export, DeclaredProcedure False parameters))] -predefined, predefined2 :: Predefined+predefined, predefined2 :: Abstract.Oberon l => Predefined l -- | The set of 'Predefined' types and procedures defined in the Oberon Language Report. predefined = Success <$> Map.fromList-   [("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 $ Identity $-            FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "INTEGER"] $-            Just $ NonQualIdent "INTEGER"),-    ("ASH", DeclaredProcedure False $ Just $ Identity $-            FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "INTEGER"] $-            Just $ NonQualIdent "INTEGER"),-    ("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 $ Identity $-            FormalParameters [Identity $ FPSection False (pure "c") $ Identity $ TypeReference $ NonQualIdent "SET"] $-            Just $ NonQualIdent "INTEGER"),-    ("MIN", DeclaredProcedure True $ Just $ Identity $-            FormalParameters [Identity $ FPSection False (pure "c") $ Identity $ TypeReference $ NonQualIdent "SET"] $-            Just $ NonQualIdent "INTEGER"),-    ("ODD", DeclaredProcedure False $ Just $ Identity $-            FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "CHAR"] $-            Just $ NonQualIdent "BOOLEAN"),-    ("SIZE", DeclaredProcedure True $ Just $ Identity $-             FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "CHAR"] $-             Just $ NonQualIdent "INTEGER"),-    ("ORD", DeclaredProcedure False $ Just $ Identity $-            FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "CHAR"] $-            Just $ NonQualIdent "INTEGER"),-    ("CHR", DeclaredProcedure False $ Just $ Identity $-            FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "INTEGER"] $-            Just $ NonQualIdent "CHAR"),-    ("SHORT", DeclaredProcedure False $ Just $ Identity $-              FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "INTEGER"] $-              Just $ NonQualIdent "INTEGER"),-    ("LONG", DeclaredProcedure False $ Just $ Identity $-             FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "INTEGER"] $-             Just $ NonQualIdent "INTEGER"),-    ("ENTIER", DeclaredProcedure False $ Just $ Identity $-               FormalParameters [Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "REAL"] $-               Just $ NonQualIdent "INTEGER"),-    ("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)]+   [("BOOLEAN", DeclaredType (wrap $ Abstract.typeReference $ Abstract.nonQualIdent "BOOLEAN")),+    ("CHAR", DeclaredType (wrap $ Abstract.typeReference $ Abstract.nonQualIdent "CHAR")),+    ("SHORTINT", DeclaredType (wrap $ Abstract.typeReference $ Abstract.nonQualIdent "SHORTINT")),+    ("INTEGER", DeclaredType (wrap $ Abstract.typeReference $ Abstract.nonQualIdent "INTEGER")),+    ("LONGINT", DeclaredType (wrap $ Abstract.typeReference $ Abstract.nonQualIdent "LONGINT")),+    ("REAL", DeclaredType (wrap $ Abstract.typeReference $ Abstract.nonQualIdent "REAL")),+    ("LONGREAL", DeclaredType (wrap $ Abstract.typeReference $ Abstract.nonQualIdent "LONGREAL")),+    ("SET", DeclaredType (wrap $ Abstract.typeReference $ Abstract.nonQualIdent "SET")),+    ("TRUE", DeclaredConstant (wrap $ Abstract.read $ wrap $ Abstract.variable $ Abstract.nonQualIdent "TRUE")),+    ("FALSE", DeclaredConstant (wrap $ Abstract.read $ wrap $ Abstract.variable $ Abstract.nonQualIdent "FALSE")),+    ("ABS", DeclaredProcedure False $ Just $ wrap $+            Abstract.formalParameters [wrap $ Abstract.fpSection False (pure "n") $ wrap+                                       $ Abstract.typeReference $ Abstract.nonQualIdent "INTEGER"] $+            Just $ Abstract.nonQualIdent "INTEGER"),+    ("ASH", DeclaredProcedure False $ Just $ wrap $+            Abstract.formalParameters [wrap $ Abstract.fpSection False (pure "n") $ wrap+                                       $ Abstract.typeReference $ Abstract.nonQualIdent "INTEGER"] $+            Just $ Abstract.nonQualIdent "INTEGER"),+    ("CAP", DeclaredProcedure False $ Just $ wrap $+            Abstract.formalParameters [wrap $ Abstract.fpSection False (pure "c") $ wrap+                                       $ Abstract.typeReference $ Abstract.nonQualIdent "CHAR"] $+            Just $ Abstract.nonQualIdent "CHAR"),+    ("LEN", DeclaredProcedure False $ Just $ wrap $+            Abstract.formalParameters [wrap $ Abstract.fpSection False (pure "c") $ wrap+                                       $ Abstract.typeReference $ Abstract.nonQualIdent "ARRAY"] $+            Just $ Abstract.nonQualIdent "LONGINT"),+    ("MAX", DeclaredProcedure True $ Just $ wrap $+            Abstract.formalParameters [wrap $ Abstract.fpSection False (pure "c") $ wrap+                                       $ Abstract.typeReference $ Abstract.nonQualIdent "SET"] $+            Just $ Abstract.nonQualIdent "INTEGER"),+    ("MIN", DeclaredProcedure True $ Just $ wrap $+            Abstract.formalParameters [wrap $ Abstract.fpSection False (pure "c") $ wrap+                                       $ Abstract.typeReference $ Abstract.nonQualIdent "SET"] $+            Just $ Abstract.nonQualIdent "INTEGER"),+    ("ODD", DeclaredProcedure False $ Just $ wrap $+            Abstract.formalParameters [wrap $ Abstract.fpSection False (pure "n") $ wrap+                                       $ Abstract.typeReference $ Abstract.nonQualIdent "CHAR"] $+            Just $ Abstract.nonQualIdent "BOOLEAN"),+    ("SIZE", DeclaredProcedure True $ Just $ wrap $+             Abstract.formalParameters [wrap $ Abstract.fpSection False (pure "n") $ wrap+                                        $ Abstract.typeReference $ Abstract.nonQualIdent "CHAR"] $+             Just $ Abstract.nonQualIdent "INTEGER"),+    ("ORD", DeclaredProcedure False $ Just $ wrap $+            Abstract.formalParameters [wrap $ Abstract.fpSection False (pure "n") $ wrap+                                       $ Abstract.typeReference $ Abstract.nonQualIdent "CHAR"] $+            Just $ Abstract.nonQualIdent "INTEGER"),+    ("CHR", DeclaredProcedure False $ Just $ wrap $+            Abstract.formalParameters [wrap $ Abstract.fpSection False (pure "n") $ wrap+                                       $ Abstract.typeReference $ Abstract.nonQualIdent "INTEGER"] $+            Just $ Abstract.nonQualIdent "CHAR"),+    ("SHORT", DeclaredProcedure False $ Just $ wrap $+              Abstract.formalParameters [wrap $ Abstract.fpSection False (pure "n") $ wrap+                                         $ Abstract.typeReference $ Abstract.nonQualIdent "INTEGER"] $+              Just $ Abstract.nonQualIdent "INTEGER"),+    ("LONG", DeclaredProcedure False $ Just $ wrap $+             Abstract.formalParameters [wrap $ Abstract.fpSection False (pure "n") $ wrap+                                        $ Abstract.typeReference $ Abstract.nonQualIdent "INTEGER"] $+             Just $ Abstract.nonQualIdent "INTEGER"),+    ("ENTIER", DeclaredProcedure False $ Just $ wrap $+               Abstract.formalParameters [wrap $ Abstract.fpSection False (pure "n") $ wrap+                                          $ Abstract.typeReference $ Abstract.nonQualIdent "REAL"] $+               Just $ Abstract.nonQualIdent "INTEGER"),+    ("INC", DeclaredProcedure False $ Just $ wrap $+            Abstract.formalParameters [wrap $ Abstract.fpSection False (pure "n") $ wrap+                                       $ Abstract.typeReference $ Abstract.nonQualIdent "INTEGER"] Nothing),+    ("DEC", DeclaredProcedure False $ Just $ wrap $+            Abstract.formalParameters [wrap $ Abstract.fpSection False (pure "n") $ wrap+                                       $ Abstract.typeReference $ Abstract.nonQualIdent "INTEGER"] Nothing),+    ("INCL", DeclaredProcedure False $ Just $ wrap $+             Abstract.formalParameters [wrap $ Abstract.fpSection False (pure "s") $ wrap+                                        $ Abstract.typeReference $ Abstract.nonQualIdent "SET",+                               wrap $ Abstract.fpSection False (pure "n") $ wrap+                               $ Abstract.typeReference $ Abstract.nonQualIdent "INTEGER"] Nothing),+    ("EXCL", DeclaredProcedure False $ Just $ wrap $+             Abstract.formalParameters [wrap $ Abstract.fpSection False (pure "s") $ wrap+                                        $ Abstract.typeReference $ Abstract.nonQualIdent "SET",+                               wrap $ Abstract.fpSection False (pure "n") $ wrap+                               $ Abstract.typeReference $ Abstract.nonQualIdent "INTEGER"] Nothing),+    ("COPY", DeclaredProcedure False $ Just $ wrap $+             Abstract.formalParameters [wrap $ Abstract.fpSection False (pure "s") $ wrap+                                        $ Abstract.typeReference $ Abstract.nonQualIdent "ARRAY",+                               wrap $ Abstract.fpSection False (pure "n") $ wrap+                               $ Abstract.typeReference $ Abstract.nonQualIdent "ARRAY"] Nothing),+    ("NEW", DeclaredProcedure False $ Just $ wrap $+            Abstract.formalParameters [wrap $ Abstract.fpSection False (pure "n") $ wrap+                                       $ Abstract.typeReference $ Abstract.nonQualIdent "POINTER"] Nothing),+    ("HALT", DeclaredProcedure False $ Just $ wrap $+             Abstract.formalParameters [wrap $ Abstract.fpSection False (pure "n") $ wrap+                                        $ Abstract.typeReference $ Abstract.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 $ Identity $-             FormalParameters [Identity $ FPSection False (pure "s") $ Identity $ TypeReference $ NonQualIdent "ARRAY",-                               Identity $ FPSection False (pure "n") $ Identity $ TypeReference $ NonQualIdent "ARRAY"] Nothing)])+    [("ASSERT",+      DeclaredProcedure False $ Just $ wrap $ Abstract.formalParameters+       [wrap $ Abstract.fpSection False (pure "s") $ wrap $ Abstract.typeReference $ Abstract.nonQualIdent "ARRAY",+        wrap $ Abstract.fpSection False (pure "n") $ wrap $ Abstract.typeReference $ Abstract.nonQualIdent "ARRAY"]+      Nothing)]) -exportsOfModule :: Module Identity Identity -> Scope+wrap = (,) (0, Trailing [], 0)++exportsOfModule :: (BindableDeclaration l, CoFormalParameters l) => Module l l Placed Placed -> Scope l exportsOfModule = fmap Success . Map.mapMaybe isExported . globalsOfModule    where isExported (PrivateOnly, _) = Nothing          isExported (_, binding) = Just binding -globalsOfModule :: Module Identity Identity -> Map Ident (AccessMode, DeclarationRHS Identity Identity)-globalsOfModule (Module name imports declarations _ _) =-   Map.fromList (concatMap (declarationBinding name . runIdentity) declarations)+globalsOfModule :: forall l. (BindableDeclaration l, CoFormalParameters l) =>+                   Module l l Placed Placed -> Map Ident (AccessMode, DeclarationRHS l Placed Placed)+globalsOfModule (Module name imports (_, body)) =+   Map.fromList (concatMap (declarationBinding name . snd) (getLocalDeclarations body)) -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+unique :: (NonEmpty (Error l) -> Error l) -> ([a] -> Error l) -> NodeWrap (Validation (NonEmpty (Error l)) a)+       -> Validation (NonEmpty (Error l)) (Placed a)+unique _ _ (Compose ((start, end), Compose (Ambiguous (x :| [])))) = first (flip ((,,) start) end) <$> (sequenceA x)+unique inv amb (Compose ((start, end), Compose (Ambiguous xs))) =+   case partitionEithers (traverse validationToEither <$> NonEmpty.toList xs)+   of (_, [(ws, x)]) -> Success ((start, ws, end), x)       (errors, []) -> Failure (inv (sconcat $ NonEmpty.fromList errors) :| [])-      (_, multi) -> Failure (amb multi :| [])+      (_, multi) -> Failure (amb (snd <$> multi) :| [])  $(Rank2.TH.deriveFunctor ''DeclarationRHS) $(Rank2.TH.deriveFoldable ''DeclarationRHS) $(Rank2.TH.deriveTraversable ''DeclarationRHS)-$(Transformation.Deep.TH.deriveDownTraversable ''DeclarationRHS)+$(Transformation.Deep.TH.deriveTraversable ''DeclarationRHS)++$(do l <- varT <$> newName "l"+     mconcat <$> mapM (\t-> Transformation.Full.TH.deriveDownTraversable (conT ''Resolution `appT` l)+                            $ conT t `appT` l `appT` l)+        [''Module, ''Declaration, ''Type, ''FieldList,+         ''ProcedureHeading, ''FormalParameters, ''FPSection,+         ''Expression, ''Element, ''Designator,+         ''Block, ''StatementSequence, ''Statement,+         ''Case, ''CaseLabels, ''ConditionalBranch, ''Value, ''WithAlternative])
src/Language/Oberon/TypeChecker.hs view
@@ -1,880 +1,1099 @@-{-# 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])+{-# LANGUAGE DataKinds, DeriveGeneric, DuplicateRecordFields, FlexibleContexts, FlexibleInstances,+             MultiParamTypeClasses, OverloadedStrings, ScopedTypeVariables,+             TemplateHaskell, TypeFamilies, TypeOperators, UndecidableInstances, ViewPatterns #-}++-- | Type checker for Oberon AST. The AST must have its ambiguities previously resolved by "Language.Oberon.Resolver".+module Language.Oberon.TypeChecker (checkModules, errorMessage, Error, ErrorType(..), predefined, predefined2) where++import Control.Applicative (liftA2, (<|>), ZipList(ZipList, getZipList))+import Control.Arrow (first)+import Data.Coerce (coerce)+import Data.Proxy (Proxy(..))+import qualified Data.List as List+import Data.Functor.Const (Const(..))+import Data.Maybe (fromMaybe)+import Data.Map.Lazy (Map)+import qualified Data.Map.Lazy as Map+import Data.Semigroup (Semigroup(..))+import qualified Data.Text as Text+import GHC.Generics (Generic)+import Language.Haskell.TH (appT, conT, varT, newName)++import qualified Rank2+import qualified Transformation+import qualified Transformation.Shallow as Shallow+import qualified Transformation.Deep as Deep+import qualified Transformation.Full as Full+import qualified Transformation.Full.TH+import qualified Transformation.AG as AG+import qualified Transformation.AG.Generics as AG+import Transformation.AG (Attribution(..), Atts, Inherited(..), Synthesized(..), Semantics)+import Transformation.AG.Generics (Auto(Auto), Folded(..), Bequether(..), Synthesizer(..), SynthesizedField)++import qualified Language.Oberon.Abstract as Abstract+import qualified Language.Oberon.AST as AST+import Language.Oberon.Grammar (ParsedLexemes(Trailing))+import Language.Oberon.Resolver (Placed)++data Type l = NominalType (Abstract.QualIdent l) (Maybe (Type l))+            | RecordType{ancestry :: [Abstract.QualIdent l],+                         recordFields :: Map AST.Ident (Type l)}+            | NilType+            | IntegerType Int+            | StringType Int+            | ArrayType [Int] (Type l)+            | PointerType (Type l)+            | ReceiverType (Type l)+            | ProcedureType Bool [(Bool, Type l)] (Maybe (Type l))+            | BuiltinType Text.Text+            | UnknownType++data ErrorType l = ArgumentCountMismatch Int Int+                 | ExtraDimensionalIndex Int Int+                 | IncomparableTypes (Type l) (Type l)+                 | IncompatibleTypes (Type l) (Type l)+                 | TooSmallArrayType Int Int+                 | OpenArrayVariable+                 | NonArrayType (Type l)+                 | NonBooleanType (Type l)+                 | NonFunctionType (Type l)+                 | NonIntegerType (Type l)+                 | NonNumericType (Type l)+                 | NonPointerType (Type l)+                 | NonProcedureType (Type l)+                 | NonRecordType (Type l)+                 | TypeMismatch (Type l) (Type l)+                 | UnequalTypes (Type l) (Type l)+                 | UnrealType (Type l)+                 | UnknownName (Abstract.QualIdent l)+                 | UnknownField AST.Ident (Type l)++type Error l = (AST.Ident, (Int, ParsedLexemes, Int), ErrorType l)++instance Eq (Abstract.QualIdent l) => Eq (Type l) where+  NominalType q1 (Just t1) == t2@(NominalType q2 _) = q1 == q2 || t1 == t2+  t1@(NominalType q1 _) == NominalType q2 (Just t2) = q1 == q2 || t1 == t2+  NominalType q1 Nothing == NominalType q2 Nothing = 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+  BuiltinType name1 == BuiltinType name2 = name1 == name2+  ReceiverType t1 == t2 = t1 == t2+  t1 == ReceiverType t2 = t1 == t2+  _ == _ = False++instance Show (Abstract.QualIdent l) => Show (Type l) where+  show (NominalType q t) = "Nominal " ++ show q ++ " (" ++ shows t ")"+  show (RecordType ancestry fields) = "RecordType " ++ show ancestry ++ show (fst <$> Map.toList fields)+  show (ArrayType dimensions itemType) = "ArrayType " ++ show dimensions ++ " (" ++ shows itemType ")"+  show (PointerType targetType) = "PointerType " ++ show targetType+  show (ProcedureType _ parameters result) = "ProcedureType (" ++ show parameters ++ "): " ++ show result+  show (ReceiverType t) = "ReceiverType " ++ show t+  show (IntegerType n) = "IntegerType " ++ show n+  show (StringType len) = "StringType " ++ show len+  show (BuiltinType name) = "BuiltinType " ++ show name+  show NilType = "NilType"+  show UnknownType = "UnknownType"++errorMessage :: (Abstract.Nameable l, Abstract.Oberon l, Show (Abstract.QualIdent l)) => ErrorType l -> String+errorMessage (ArgumentCountMismatch expected actual) =+   "Expected " <> show expected <> ", received " <> show actual <> " arguments"+errorMessage (ExtraDimensionalIndex expected actual) =+   "Expected " <> show expected <> ", received " <> show actual <> " indexes"+errorMessage (IncomparableTypes left right) = +   "Values of types " <> typeMessage left <> " and " <> typeMessage right <> " cannot be compared"+errorMessage (IncompatibleTypes left right) =+   "Incompatible types " <> typeMessage left <> " and " <> typeMessage right+errorMessage (TooSmallArrayType expected actual) = +   "The array of length " <> show expected <> " cannot contain " <> show actual <> " items"+errorMessage OpenArrayVariable = "A variable cannot be declared an open array"+errorMessage (NonArrayType t) = "Trying to index a non-array type " <> typeMessage t+errorMessage (NonBooleanType t) = "Type " <> typeMessage t <> " is not Boolean"+errorMessage (NonFunctionType t) = "Trying to invoke a " <> typeMessage t <> " as a function"+errorMessage (NonIntegerType t) = "Type " <> typeMessage t <> " is not an integer type"+errorMessage (NonNumericType t) = "Type " <> typeMessage t <> " is not a numeric type"+errorMessage (NonPointerType t) = "Trying to dereference a non-pointer type " <> typeMessage t+errorMessage (NonProcedureType t) = "Trying to invoke a " <> typeMessage t <> " as a procedure"+errorMessage (NonRecordType t) = "Non-record type " <> typeMessage t+errorMessage (TypeMismatch t1 t2) = "Type mismatch between " <> typeMessage t1 <> " and " <> typeMessage t2+errorMessage (UnequalTypes t1 t2) = "Unequal types " <> typeMessage t1 <> " and " <> typeMessage t2+errorMessage (UnrealType t) = "Type " <> typeMessage t <> " is not a numeric real type"+errorMessage (UnknownName q) = "Unknown name " <> show q+errorMessage (UnknownField name t) = "Record type " <> typeMessage t <> " has no field " <> show name++typeMessage :: (Abstract.Nameable l, Abstract.Oberon l) => Type l -> String+typeMessage (BuiltinType name) = Text.unpack name+typeMessage (NominalType name _) = nameMessage name+typeMessage (RecordType ancestry fields) = +   "RECORD " ++ foldMap (("(" ++) . (++ ") ") . nameMessage) ancestry+   ++ List.intercalate ";\n" (fieldMessage <$> Map.toList fields) ++ "END"+   where fieldMessage (name, t) = "\n  " <> Text.unpack name <> ": " <> typeMessage t+typeMessage (ArrayType dimensions itemType) = +   "ARRAY " ++ List.intercalate ", " (show <$> dimensions) ++ " OF " ++ typeMessage itemType+typeMessage (PointerType targetType) = "POINTER TO " ++ typeMessage targetType+typeMessage (ProcedureType _ parameters result) =+   "PROCEDURE (" ++ List.intercalate ", " (argMessage <$> parameters) ++ "): " ++ foldMap typeMessage result+   where argMessage (True, t) = "VAR " <> typeMessage t+         argMessage (False, t) = typeMessage t+typeMessage (ReceiverType t) = typeMessage t+typeMessage (IntegerType n) = "INTEGER"+typeMessage (StringType len) = "STRING [" ++ shows len "]"+typeMessage NilType = "NIL"+typeMessage UnknownType = "[Unknown]"++nameMessage :: (Abstract.Nameable l, Abstract.Oberon l) => Abstract.QualIdent l -> String+nameMessage q+   | Just (mod, name) <- Abstract.getQualIdentNames q = Text.unpack mod <> "." <> Text.unpack name+   | Just name <- Abstract.getNonQualIdentName q = Text.unpack name++type Environment l = Map (Abstract.QualIdent l) (Type l)++newtype Modules l f' f = Modules (Map AST.Ident (f (AST.Module l l f' f')))++data TypeCheck = TypeCheck++type Sem = Semantics (Auto TypeCheck)++data InhTCRoot l = InhTCRoot{rootEnv :: Environment l}++data InhTC l = InhTC{env           :: Environment l,+                     currentModule :: AST.Ident}+               deriving Generic++data InhTCExp l = InhTCExp{env           :: Environment l,+                           currentModule :: AST.Ident,+                           expectedType  :: Type l}+                  deriving Generic++data InhTCDecl l = InhTCDecl{env           :: Environment l,+                             currentModule :: AST.Ident,+                             pointerTargets :: Map AST.Ident AST.Ident}+                   deriving Generic++data SynTC l = SynTC{errors :: Folded [Error l]}+               deriving Generic++data SynTCMod l = SynTCMod{errors :: Folded [Error l],+                           moduleEnv :: Environment l,+                           pointerTargets :: Folded (Map AST.Ident AST.Ident)}+                  deriving Generic++data SynTCType l = SynTCType{errors :: Folded [Error l],+                             typeName   :: Maybe AST.Ident,+                             definedType :: Type l,+                             pointerTarget :: Maybe AST.Ident}+                   deriving Generic++data SynTCFields l = SynTCFields{errors :: Folded [Error l],+                                 fieldEnv :: Map AST.Ident (Type l)}+                     deriving Generic++data SynTCHead l = SynTCHead{errors :: Folded [Error l],+                             insideEnv :: Environment l,+                             outsideEnv :: Environment l}+                   deriving Generic++data SynTCSig l = SynTCSig{errors :: Folded [Error l],+                           signatureEnv :: Environment l,+                           signatureType :: Type l}+                  deriving Generic++data SynTCSec l = SynTCSec{errors :: Folded [Error l],+                           sectionEnv :: Environment l,+                           sectionParameters :: [(Bool, Type l)]}+                  deriving Generic++data SynTCDes l = SynTCDes{errors :: Folded [Error l],+                           designatorName   :: Maybe (Maybe Abstract.Ident, Abstract.Ident),+                           designatorType :: Type l}+                  deriving Generic++data SynTCExp l = SynTCExp{errors :: Folded [Error l],+                           inferredType :: Type l}+                  deriving Generic++-- * Modules instances, TH candidates+instance (Transformation.Transformation t, Functor (Transformation.Domain t), Deep.Functor t (AST.Module l l),+          Transformation.At t (AST.Module l l (Transformation.Codomain t) (Transformation.Codomain t))) =>+         Deep.Functor t (Modules l) where+   t <$> ~(Modules ms) = Modules (mapModule <$> ms)+      where mapModule m = t Transformation.$ ((t Deep.<$>) <$> m)+instance (Transformation.Transformation t, Functor (Transformation.Domain t),+          Transformation.At t (AST.Module l l f f)) =>+         Shallow.Functor t (Modules l f) where+   t <$> ~(Modules ms) = Modules ((t Transformation.$) <$> ms)+instance (Transformation.Transformation t, Functor (Transformation.Domain t), Shallow.Foldable t (AST.Module l l f),+          Transformation.At t (AST.Module l l f f)) =>+         Shallow.Foldable t (Modules l f) where+   foldMap t ~(Modules ms) = getConst (foldMap (t Transformation.$) ms)++instance Rank2.Functor (Modules l f') where+   f <$> ~(Modules ms) = Modules (f <$> ms)+instance Rank2.Foldable (Modules l f) where+   foldMap f ~(Modules ms) = foldMap f ms+instance Rank2.Apply (Modules l f') where+   ~(Modules fs) <*> ~(Modules ms) = Modules (Map.intersectionWith Rank2.apply fs ms)++-- * Boring attribute types+type instance Atts (Inherited (Auto TypeCheck)) (Modules l _ _) = InhTCRoot l+type instance Atts (Synthesized (Auto TypeCheck)) (Modules l _ _) = SynTC l+type instance Atts (Inherited (Auto TypeCheck)) (AST.Module l l _ _) = InhTC l+type instance Atts (Synthesized (Auto TypeCheck)) (AST.Module l l _ _) = SynTCMod l+type instance Atts (Inherited (Auto TypeCheck)) (AST.Declaration l l _ _) = InhTCDecl l+type instance Atts (Synthesized (Auto TypeCheck)) (AST.Declaration l l _ _) = SynTCMod l+type instance Atts (Inherited (Auto TypeCheck)) (AST.ProcedureHeading l l _ _) = InhTCDecl l+type instance Atts (Synthesized (Auto TypeCheck)) (AST.ProcedureHeading l l _ _) = SynTCHead l+type instance Atts (Inherited (Auto TypeCheck)) (AST.Block l l _ _) = InhTC l+type instance Atts (Synthesized (Auto TypeCheck)) (AST.Block l l _ _) = SynTCMod l+type instance Atts (Inherited (Auto TypeCheck)) (AST.FormalParameters l l _ _) = InhTC l+type instance Atts (Synthesized (Auto TypeCheck)) (AST.FormalParameters l l _ _) = SynTCSig l+type instance Atts (Inherited (Auto TypeCheck)) (AST.FPSection l l _ _) = InhTC l+type instance Atts (Synthesized (Auto TypeCheck)) (AST.FPSection l l _ _) = SynTCSec l+type instance Atts (Inherited (Auto TypeCheck)) (AST.Type l l _ _) = InhTC l+type instance Atts (Synthesized (Auto TypeCheck)) (AST.Type l l _ _) = SynTCType l+type instance Atts (Inherited (Auto TypeCheck)) (AST.FieldList l l _ _) = InhTC l+type instance Atts (Synthesized (Auto TypeCheck)) (AST.FieldList l l _ _) = SynTCFields l+type instance Atts (Inherited (Auto TypeCheck)) (AST.StatementSequence l l _ _) = InhTC l+type instance Atts (Synthesized (Auto TypeCheck)) (AST.StatementSequence l l _ _) = SynTC l+type instance Atts (Inherited (Auto TypeCheck)) (AST.Expression l l _ _) = InhTC l+type instance Atts (Synthesized (Auto TypeCheck)) (AST.Expression l l _ _) = SynTCExp l+type instance Atts (Inherited (Auto TypeCheck)) (AST.Element l l _ _) = InhTC l+type instance Atts (Synthesized (Auto TypeCheck)) (AST.Element l l _ _) = SynTCExp l+type instance Atts (Inherited (Auto TypeCheck)) (AST.Value l l _ _) = InhTC l+type instance Atts (Synthesized (Auto TypeCheck)) (AST.Value l l _ _) = SynTCExp l+type instance Atts (Inherited (Auto TypeCheck)) (AST.Designator l l _ _) = InhTC l+type instance Atts (Synthesized (Auto TypeCheck)) (AST.Designator l l _ _) = SynTCDes l+type instance Atts (Inherited (Auto TypeCheck)) (AST.Statement l l _ _) = InhTC l+type instance Atts (Synthesized (Auto TypeCheck)) (AST.Statement l l _ _) = SynTC l+type instance Atts (Inherited (Auto TypeCheck)) (AST.ConditionalBranch l l _ _) = InhTC l+type instance Atts (Synthesized (Auto TypeCheck)) (AST.ConditionalBranch l l _ _) = SynTC l+type instance Atts (Inherited (Auto TypeCheck)) (AST.Case l l _ _) = InhTCExp l+type instance Atts (Synthesized (Auto TypeCheck)) (AST.Case l l _ _) = SynTC l+type instance Atts (Inherited (Auto TypeCheck)) (AST.CaseLabels l l _ _) = InhTCExp l+type instance Atts (Synthesized (Auto TypeCheck)) (AST.CaseLabels l l _ _) = SynTC l+type instance Atts (Inherited (Auto TypeCheck)) (AST.WithAlternative l l _ _) = InhTC l+type instance Atts (Synthesized (Auto TypeCheck)) (AST.WithAlternative l l _ _) = SynTC l++-- * Rules++instance Ord (Abstract.QualIdent l) => Bequether (Auto TypeCheck) (Modules l) Sem Placed where+   bequest _ (_, Modules self) inheritance (Modules ms) =+     Modules (Map.mapWithKey moduleInheritance self)+     where moduleInheritance name mod = Inherited InhTC{env= rootEnv inheritance <> foldMap (moduleEnv . syn) ms,+                                                        currentModule= name}+instance Ord (Abstract.QualIdent l) => Synthesizer (Auto TypeCheck) (Modules l) Sem Placed where+  synthesis _ _ _ (Modules ms) = SynTC{errors= foldMap (\m-> errors (syn m :: SynTCMod l)) ms}++instance (Abstract.Oberon l, Abstract.Nameable l, k ~ Abstract.QualIdent l, Ord k,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.Block l l Sem Sem) ~ SynTCMod l) =>+         SynthesizedField "moduleEnv" (Map k (Type l)) (Auto TypeCheck) (AST.Module l l) Sem Placed where+   synthesizedField _ _ (pos, AST.Module moduleName imports body) _inheritance (AST.Module _ _ body') = exportedEnv+      where exportedEnv = exportNominal <$> Map.mapKeysMonotonic export (moduleEnv $ syn body')+            export q+               | Just name <- Abstract.getNonQualIdentName q = Abstract.qualIdent moduleName name+               | otherwise = q+            exportNominal (NominalType q (Just t))+               | Just name <- Abstract.getNonQualIdentName q =+                 NominalType (Abstract.qualIdent moduleName name) (Just $ exportNominal' t)+            exportNominal t = exportNominal' t+            exportNominal' (RecordType ancestry fields) = RecordType (export <$> ancestry) (exportNominal' <$> fields)+            exportNominal' (ProcedureType False parameters result) =+              ProcedureType False ((exportNominal' <$>) <$> parameters) (exportNominal' <$> result)+            exportNominal' (PointerType target) = PointerType (exportNominal' target)+            exportNominal' (ArrayType dimensions itemType) = ArrayType dimensions (exportNominal' itemType)+            exportNominal' (NominalType q (Just t))+              | Just name <- Abstract.getNonQualIdentName q =+                fromMaybe (NominalType (Abstract.qualIdent moduleName name) $ Just $ exportNominal' t)+                          (Map.lookup q exportedEnv)+            exportNominal' t = t++instance (Abstract.Nameable l, Ord (Abstract.QualIdent l),+          Atts (Inherited (Auto TypeCheck)) (Abstract.Declaration l l Sem Sem) ~ InhTCDecl l,+          Atts (Inherited (Auto TypeCheck)) (Abstract.Type l l Sem Sem) ~ InhTC l,+          Atts (Inherited (Auto TypeCheck)) (Abstract.ProcedureHeading l l Sem Sem) ~ InhTCDecl l,+          Atts (Inherited (Auto TypeCheck)) (Abstract.Block l l Sem Sem) ~ InhTC l,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.ProcedureHeading l l Sem Sem) ~ SynTCHead l,+          Atts (Inherited (Auto TypeCheck)) (Abstract.FormalParameters l l Sem Sem) ~ InhTC l,+          Atts (Inherited (Auto TypeCheck)) (Abstract.ConstExpression l l Sem Sem) ~ InhTC l,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.Declaration l l Sem Sem) ~ SynTCMod l) =>+         Bequether (Auto TypeCheck) (AST.Declaration l l) Sem Placed where+   bequest _ (pos, AST.ProcedureDeclaration{})+           inheritance@InhTCDecl{env= declEnv, currentModule= m} (AST.ProcedureDeclaration heading body) =+      AST.ProcedureDeclaration (Inherited inheritance) (Inherited bodyInherited)+      where bodyInherited = InhTC{env= insideEnv (syn heading) `Map.union` declEnv, currentModule= m}+   bequest t local inheritance synthesized = AG.bequestDefault t local inheritance synthesized++instance (Abstract.Nameable l, k ~ Abstract.QualIdent l, Ord k,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.Declaration l l Sem Sem) ~ SynTCMod l,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.Type l l Sem Sem) ~ SynTCType l,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.FormalParameters l l Sem Sem) ~ SynTCSig l,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.ProcedureHeading l l Sem Sem) ~ SynTCHead l,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.Block l l Sem Sem) ~ SynTCMod l,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.ConstExpression l l Sem Sem) ~ SynTCExp l) =>+         SynthesizedField "moduleEnv" (Map k (Type l)) (Auto TypeCheck) (AST.Declaration l l) Sem Placed where+   synthesizedField _ _ (pos, AST.ConstantDeclaration namedef _) _ (AST.ConstantDeclaration _ expression) =+      Map.singleton (Abstract.nonQualIdent $ Abstract.getIdentDefName namedef) (inferredType $ syn expression)+   synthesizedField _ _ (pos, AST.TypeDeclaration namedef _) _ (AST.TypeDeclaration _ definition) =+      Map.singleton qname (nominal $ definedType $ syn definition)+      where nominal t@BuiltinType{} = t+            nominal t@NominalType{} = t+            nominal (PointerType t@RecordType{}) =+               NominalType qname (Just $ PointerType $ NominalType (Abstract.nonQualIdent $ name<>"^") (Just t))+            nominal t = NominalType qname (Just t)+            qname = Abstract.nonQualIdent name+            name = Abstract.getIdentDefName namedef+   synthesizedField _ _ (pos, AST.VariableDeclaration names _) _ (AST.VariableDeclaration _names declaredType) =+      foldMap binding names+      where binding name = Map.singleton (Abstract.nonQualIdent $ Abstract.getIdentDefName name)+                                         (definedType $ syn declaredType)+   synthesizedField _ _ (pos, AST.ProcedureDeclaration{}) _ (AST.ProcedureDeclaration heading body) =+      outsideEnv (syn heading)+   synthesizedField _ _ (pos, AST.ForwardDeclaration namedef _sig) _ (AST.ForwardDeclaration _namedef sig) =+      foldMap (Map.singleton (Abstract.nonQualIdent $ Abstract.getIdentDefName namedef) . signatureType . syn) sig++instance (Abstract.Nameable l, k ~ Abstract.QualIdent l, Ord k,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.Declaration l l Sem Sem) ~ SynTCMod l,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.Type l l Sem Sem) ~ SynTCType l,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.FormalParameters l l Sem Sem) ~ SynTCSig l,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.ProcedureHeading l l Sem Sem) ~ SynTCHead l,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.Block l l Sem Sem) ~ SynTCMod l,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.ConstExpression l l Sem Sem) ~ SynTCExp l) =>+         SynthesizedField "pointerTargets" (Folded (Map AST.Ident AST.Ident)) (Auto TypeCheck)+                                           (AST.Declaration l l) Sem Placed where+   synthesizedField _ _ (pos, AST.TypeDeclaration namedef _) _ (AST.TypeDeclaration _ definition) =+      foldMap (Folded . Map.singleton name) (pointerTarget $ syn definition)+      where name = Abstract.getIdentDefName namedef+   synthesizedField _ _ _ _ _ = mempty++instance (Abstract.Nameable l, Ord (Abstract.QualIdent l),+          Atts (Synthesized (Auto TypeCheck)) (Abstract.FormalParameters l l Sem Sem) ~ SynTCSig l) =>+         Synthesizer (Auto TypeCheck) (AST.ProcedureHeading l l) Sem Placed where+   synthesis _ (pos, AST.ProcedureHeading indirect namedef _sig) inheritance (AST.ProcedureHeading _indirect _ sig) =+      SynTCHead{errors= foldMap (\s-> errors (syn s :: SynTCSig l)) sig,+                outsideEnv= Map.singleton (Abstract.nonQualIdent name) $+                            maybe (ProcedureType False [] Nothing) (signatureType . syn) sig,+                insideEnv= foldMap (signatureEnv . syn) sig}+      where name = Abstract.getIdentDefName namedef+   synthesis _ (pos, AST.TypeBoundHeading var receiverName receiverType indirect namedef _sig)+      inheritance (AST.TypeBoundHeading _var _name _type _indirect _ sig) =+      SynTCHead{errors= receiverError <> foldMap (\s-> errors (syn s :: SynTCSig l)) sig,+                outsideEnv= case Map.lookup receiverType (pointerTargets (inheritance :: InhTCDecl l))+                            of Just targetName -> Map.singleton (Abstract.nonQualIdent targetName) methodType+                               Nothing -> Map.singleton (Abstract.nonQualIdent receiverType) methodType,+                insideEnv= receiverEnv `Map.union` foldMap (signatureEnv . syn) sig}+      where receiverEnv =+               foldMap (Map.singleton (Abstract.nonQualIdent receiverName) . ReceiverType)+                       (Map.lookup (Abstract.nonQualIdent receiverType) $ env (inheritance :: InhTCDecl l))+            methodType = NominalType (Abstract.nonQualIdent "")+                                     (Just $ RecordType [] $ Map.singleton name procedureType)+            name = Abstract.getIdentDefName namedef+            procedureType = maybe (ProcedureType False [] Nothing) (signatureType . syn) sig+            receiverError =+               case Map.lookup (Abstract.nonQualIdent receiverType) (env (inheritance :: InhTCDecl l))+               of Nothing -> Folded [(currentModule (inheritance :: InhTCDecl l), pos,+                                      UnknownName $ Abstract.nonQualIdent receiverType)]+                  Just t +                     | RecordType{} <- ultimate t -> mempty+                     | PointerType t' <- ultimate t, RecordType{} <- ultimate t' -> mempty+                     | otherwise -> Folded [(currentModule (inheritance :: InhTCDecl l), pos, NonRecordType t)]++instance (Abstract.Nameable l, Ord (Abstract.QualIdent l), Show (Abstract.QualIdent l),+          Atts (Synthesized (Auto TypeCheck)) (Abstract.Declaration l l Sem Sem) ~ SynTCMod l,+          Atts (Inherited (Auto TypeCheck)) (Abstract.Declaration l l Sem Sem) ~ InhTCDecl l,+          Atts (Inherited (Auto TypeCheck)) (Abstract.StatementSequence l l Sem Sem) ~ InhTC l) =>+         Bequether (Auto TypeCheck) (AST.Block l l) Sem Placed where+   bequest _ (pos, AST.Block{}) inheritance (AST.Block declarations statements) =+      AST.Block (pure $ Inherited InhTCDecl{env= localEnv,+                                            currentModule= currentModule (inheritance :: InhTC l),+                                            pointerTargets= getFolded pointers})+                (pure $ Inherited localInherited)+      where localInherited = (inheritance :: InhTC l){env= localEnv} -- (currentModule (inheritance :: InhTC l))+            localEnv = newEnv declarations <> env (inheritance :: InhTC l)+            pointers= foldMap (\d-> pointerTargets (syn d :: SynTCMod l)) declarations++instance (Abstract.Nameable l, k ~ Abstract.QualIdent l, Ord k, Show k,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.Declaration l l Sem Sem) ~ SynTCMod l) =>+         SynthesizedField "moduleEnv" (Map k (Type l)) (Auto TypeCheck) (AST.Block l l) Sem Placed where+   synthesizedField _ _ (pos, AST.Block{}) inheritance (AST.Block declarations _statements) = newEnv declarations++newEnv :: (Abstract.Nameable l, Ord (Abstract.QualIdent l), Show (Abstract.QualIdent l),+           Atts (Synthesized (Auto TypeCheck)) (Abstract.Declaration l l Sem Sem) ~ SynTCMod l) =>+          ZipList (Synthesized (Auto TypeCheck) (Abstract.Declaration l l Sem Sem)) -> Environment l+newEnv declarations = Map.unionsWith mergeTypeBoundProcedures (moduleEnv . syn <$> declarations)+   where mergeTypeBoundProcedures (NominalType q (Just t1)) t2+            | Abstract.getNonQualIdentName q == Just "" = mergeTypeBoundProcedures t1 t2+            | otherwise = NominalType q (Just $ mergeTypeBoundProcedures t1 t2)+         mergeTypeBoundProcedures t1 (NominalType q (Just t2))+            | Abstract.getNonQualIdentName q == Just "" = mergeTypeBoundProcedures t1 t2+            | otherwise = 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 (PointerType (NominalType q (Just (RecordType ancestry1 fields1))))+                                  (RecordType ancestry2 fields2) =+            PointerType (NominalType q $ Just $ RecordType (ancestry1 <> ancestry2) (fields1 <> fields2))+         mergeTypeBoundProcedures (RecordType ancestry1 fields1)+                                  (PointerType (NominalType q (Just (RecordType ancestry2 fields2)))) =+            PointerType (NominalType q $ Just $ RecordType (ancestry1 <> ancestry2) (fields1 <> fields2))+         mergeTypeBoundProcedures t1 t2 = error (take 90 $ show t1)+            +instance (Ord (Abstract.QualIdent l),+          Atts (Synthesized (Auto TypeCheck)) (Abstract.FPSection l l Sem Sem) ~ SynTCSec l) =>+         Synthesizer (Auto TypeCheck) (AST.FormalParameters l l) Sem Placed where+   synthesis _ (pos, AST.FormalParameters sections returnType) inheritance (AST.FormalParameters sections' _) =+      SynTCSig{errors= foldMap (\s-> errors (syn s :: SynTCSec l)) sections'+                       <> foldMap typeRefErrors returnType,+               signatureType= ProcedureType False (foldMap (sectionParameters . syn) sections')+                              $ returnType >>= (`Map.lookup` env (inheritance :: InhTC l)),+               signatureEnv= foldMap (sectionEnv . syn) sections'}+      where typeRefErrors q+               | Map.member q (env (inheritance :: InhTC l)) = mempty+               | otherwise = Folded [(currentModule (inheritance :: InhTC l), pos, UnknownName q)]++instance (Abstract.Wirthy l, Ord (Abstract.QualIdent l),+          Atts (Synthesized (Auto TypeCheck)) (Abstract.Type l l Sem Sem) ~ SynTCType l) =>+         Synthesizer (Auto TypeCheck) (AST.FPSection l l) Sem Placed where+   synthesis _ (pos, AST.FPSection var names _typeDef) _inheritance (AST.FPSection _var _names typeDef) =+      SynTCSec{errors= errors (syn typeDef :: SynTCType l),+               sectionParameters= (var, definedType (syn typeDef)) <$ names,+               sectionEnv= Map.fromList (flip (,) (definedType $ syn typeDef) . Abstract.nonQualIdent <$> names)}++instance (Abstract.Nameable l, Ord (Abstract.QualIdent l),+          Atts (Synthesized (Auto TypeCheck)) (Abstract.FormalParameters l l Sem Sem) ~ SynTCSig l,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.FieldList l l Sem Sem) ~ SynTCFields l,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.Type l l Sem Sem) ~ SynTCType l,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.ConstExpression l l Sem Sem) ~ SynTCExp l) =>+         Synthesizer (Auto TypeCheck) (AST.Type l l) Sem Placed where+   synthesis _ (pos, AST.TypeReference q) inheritance _ = +      SynTCType{errors= if Map.member q (env (inheritance :: InhTC l)) then mempty+                        else Folded [(currentModule (inheritance :: InhTC l), pos, UnknownName q)],+                typeName= Abstract.getNonQualIdentName q,+                pointerTarget= Nothing,+                definedType= fromMaybe UnknownType (Map.lookup q $ env (inheritance :: InhTC l))}+   synthesis _ (pos, AST.ArrayType _dims _itemType) inheritance (AST.ArrayType dimensions itemType) = +      SynTCType{errors= foldMap (\d-> errors (syn d :: SynTCExp l)) dimensions+                        <> errors (syn itemType :: SynTCType l)+                        <> foldMap (expectInteger . syn) dimensions,+                typeName= Nothing,+                pointerTarget= Nothing,+                definedType= ArrayType (integerValue . syn <$> getZipList dimensions) (definedType $ syn itemType)}+     where expectInteger SynTCExp{inferredType= IntegerType{}} = mempty+           expectInteger SynTCExp{inferredType= t} =+              Folded [(currentModule (inheritance :: InhTC l), pos, NonIntegerType t)]+           integerValue SynTCExp{inferredType= IntegerType n} = n+           integerValue _ = 0+   synthesis _ (pos, AST.RecordType base fields) inheritance (AST.RecordType _base fields') =+      SynTCType{errors= fst baseRecord <> foldMap (\f-> errors (syn f :: SynTCFields l)) fields',+                typeName= Nothing,+                pointerTarget= Nothing,+                definedType= RecordType (maybe [] (maybe id (:) base . ancestry) $ snd baseRecord)+                                        (maybe Map.empty recordFields (snd baseRecord)+                                         <> foldMap (fieldEnv . syn) fields')}+     where baseRecord = case flip Map.lookup (env (inheritance :: InhTC l)) <$> base+                        of Just (Just t@RecordType{}) -> (mempty, Just t)+                           Just (Just (NominalType _ (Just t@RecordType{}))) -> (mempty, Just t)+                           Just (Just t) ->+                              (Folded [(currentModule (inheritance :: InhTC l), pos, NonRecordType t)], Nothing)+                           Just Nothing ->+                              (foldMap (Folded . (:[])+                                        . (,,) (currentModule (inheritance :: InhTC l)) pos . UnknownName) base,+                               Nothing)+                           Nothing -> (mempty, Nothing)+   synthesis (Auto TypeCheck) _self inheritance (AST.PointerType targetType') =+      SynTCType{errors= errors (syn targetType' :: SynTCType l),+                typeName= Nothing,+                pointerTarget= typeName (syn targetType'),+                definedType= PointerType (definedType $ syn targetType')}+   synthesis _ (pos, AST.ProcedureType signature) inheritance (AST.ProcedureType signature') = +      SynTCType{errors= foldMap (\s-> errors (syn s :: SynTCSig l)) signature',+                typeName= Nothing,+                pointerTarget= Nothing,+                definedType= maybe (ProcedureType False [] Nothing) (signatureType . syn) signature'}++instance (Abstract.Nameable l,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.Type l l Sem Sem) ~ SynTCType l) =>+         SynthesizedField "fieldEnv" (Map AST.Ident (Type l)) (Auto TypeCheck) (AST.FieldList l l) Sem Placed where+   synthesizedField _ _ (_, AST.FieldList names _declaredType) _inheritance (AST.FieldList _names declaredType) =+      foldMap (\name-> Map.singleton (Abstract.getIdentDefName name) (definedType $ syn declaredType)) names++instance (Abstract.Wirthy l, Abstract.Nameable l, Ord (Abstract.QualIdent l),+          Atts (Inherited (Auto TypeCheck)) (Abstract.StatementSequence l l Sem Sem) ~ InhTC l,+          Atts (Inherited (Auto TypeCheck)) (Abstract.ConditionalBranch l l Sem Sem) ~ InhTC l,+          Atts (Inherited (Auto TypeCheck)) (Abstract.Case l l Sem Sem) ~ InhTCExp l,+          Atts (Inherited (Auto TypeCheck)) (Abstract.WithAlternative l l Sem Sem) ~ InhTC l,+          Atts (Inherited (Auto TypeCheck)) (Abstract.Expression l l Sem Sem) ~ InhTC l,+          Atts (Inherited (Auto TypeCheck)) (Abstract.Designator l l Sem Sem) ~ InhTC l,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.Expression l l Sem Sem) ~ SynTCExp l) =>+         Bequether (Auto TypeCheck) (AST.Statement l l) Sem Placed where+   bequest _ (_pos, AST.EmptyStatement) i _   = AST.EmptyStatement+   bequest _ (_pos, AST.Assignment{}) i _     = AST.Assignment (AG.Inherited i) (AG.Inherited i)+   bequest _ (_pos, AST.ProcedureCall proc args) i _  =+      AST.ProcedureCall (AG.Inherited i) ((AG.Inherited i <$) <$> args)+   bequest _ (_pos, AST.If _branch branches _fallback) i _ =+      AST.If (AG.Inherited i) (AG.Inherited i <$ branches) (Just $ AG.Inherited i)+   bequest _ (_pos, AST.CaseStatement{}) i (AST.CaseStatement value _branches _fallback) =+      AST.CaseStatement (Inherited i) (pure $ Inherited InhTCExp{currentModule= currentModule (i :: InhTC l),+                                                                 env= env (i :: InhTC l),+                                                                 expectedType= inferredType $ syn value})+                        (Just $ Inherited i)+   bequest _ (_pos, AST.While{}) i _          = AST.While (AG.Inherited i) (AG.Inherited i)+   bequest _ (_pos, AST.Repeat{}) i _         = AST.Repeat (AG.Inherited i) (AG.Inherited i)+   bequest _ (_pos, AST.For name _ _ _ _) i _ =+      AST.For name (AG.Inherited i) (AG.Inherited i) (pure $ AG.Inherited i) (AG.Inherited i)  -- Oberon2+   bequest _ (_pos, AST.Loop{}) i _           = AST.Loop (AG.Inherited i)+   bequest _ (_pos, AST.With{}) i _           =+      AST.With (AG.Inherited i) (pure $ AG.Inherited i) (Just $ AG.Inherited i)+   bequest _ (_pos, AST.Exit{}) i _           = AST.Exit+   bequest _ (_pos, AST.Return{}) i _         = AST.Return (Just $ AG.Inherited i)++instance {-# overlaps #-} (Abstract.Wirthy l, Abstract.Nameable l, Ord (Abstract.QualIdent l),+                           Atts (Synthesized (Auto TypeCheck)) (Abstract.StatementSequence l l Sem Sem) ~ SynTC l,+                           Atts (Synthesized (Auto TypeCheck)) (Abstract.Expression l l Sem Sem) ~ SynTCExp l,+                           Atts (Synthesized (Auto TypeCheck)) (Abstract.Designator l l Sem Sem) ~ SynTCDes l,+                           Atts (Synthesized (Auto TypeCheck)) (Abstract.Case l l Sem Sem) ~ SynTC l,+                           Atts (Synthesized (Auto TypeCheck)) (Abstract.ConditionalBranch l l Sem Sem) ~ SynTC l,+                           Atts (Synthesized (Auto TypeCheck)) (Abstract.WithAlternative l l Sem Sem) ~ SynTC l) =>+                          Synthesizer (Auto TypeCheck) (AST.Statement l l) Sem Placed where+   synthesis t (pos, _) inheritance statement@(AST.Assignment var value) = {-# SCC "Assignment" #-}+      SynTC{errors= assignmentCompatible (currentModule (inheritance :: InhTC l)) pos+                                         (designatorType $ syn var) (inferredType $ syn value)+                    <> AG.foldedField (Proxy :: Proxy "errors") t statement}+   synthesis _ (pos, AST.ProcedureCall _proc parameters) inheritance (AST.ProcedureCall procedure' parameters') =+      SynTC{errors= (case syn procedure'+                     of SynTCDes{errors= Folded [],+                                 designatorType= t} -> procedureErrors t+                        SynTCDes{errors= errs} -> errs)+                    <> foldMap (foldMap (\p-> errors (syn p :: SynTCExp l))) parameters'}+     where procedureErrors (ProcedureType _ formalTypes Nothing)+             | length formalTypes /= maybe 0 (length . getZipList) parameters,+               not (length formalTypes == 2 && (length . getZipList <$> parameters) == Just 1+                    && designatorName (syn procedure') == Just (Nothing, "ASSERT")+                    || length formalTypes == 1 && (length . getZipList <$> parameters) == Just 2+                    && designatorName (syn procedure') == Just (Nothing, "NEW")+                    && all (all (isIntegerType . inferredType . syn) . tail . getZipList) parameters') =+                 Folded [(currentModule (inheritance :: InhTC l), pos,+                          ArgumentCountMismatch (length formalTypes) $ maybe 0 (length . getZipList) parameters)]+             | otherwise = mconcat (zipWith (parameterCompatible inheritance pos) formalTypes+                                    $ maybe [] ((inferredType . syn <$>) . getZipList) parameters')+           procedureErrors (NominalType _ (Just t)) = procedureErrors t+           procedureErrors t = Folded [(currentModule (inheritance :: InhTC l), pos, NonProcedureType t)]+   synthesis _ (pos, _) inheritance (AST.While condition body) =+      SynTC{errors= booleanExpressionErrors inheritance pos (syn condition) <> errors (syn body :: SynTC l)}+   synthesis _ (pos, _) inheritance (AST.Repeat body condition) =+      SynTC{errors= booleanExpressionErrors inheritance pos (syn condition) <> errors (syn body :: SynTC l)}+   synthesis _ (pos, _) inheritance (AST.For _counter start end step body) =+      SynTC{errors= integerExpressionErrors inheritance pos (syn start) +                    <> integerExpressionErrors inheritance pos (syn end)+                    <> foldMap (integerExpressionErrors inheritance pos . syn) step <> errors (syn body :: SynTC l)}+   synthesis t self _ statement = SynTC{errors= AG.foldedField (Proxy :: Proxy "errors") t statement}++instance (Abstract.Nameable l, Ord (Abstract.QualIdent l),+          Atts (Inherited (Auto TypeCheck)) (Abstract.StatementSequence l l Sem Sem) ~ InhTC l,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.StatementSequence l l Sem Sem) ~ SynTC l) =>+         Attribution (Auto TypeCheck) (AST.WithAlternative l l) Sem Placed where+   attribution _ (pos, AST.WithAlternative var subtype _body)+                         (Inherited inheritance, AST.WithAlternative _var _subtype body) =+      (Synthesized SynTC{errors= case (Map.lookup var $ env (inheritance :: InhTC l),+                                       Map.lookup subtype $ env (inheritance :: InhTC l))+                                 of (Just supertype, Just subtypeDef) ->+                                      assignmentCompatible (currentModule (inheritance :: InhTC l)) pos+                                                           supertype subtypeDef+                                    (Nothing, _) ->+                                      Folded [(currentModule (inheritance :: InhTC l), pos, UnknownName var)]+                                    (_, Nothing) ->+                                      Folded [(currentModule (inheritance :: InhTC l), pos, UnknownName subtype)]+                                 <> errors (syn body :: SynTC l)},+       AST.WithAlternative var subtype (Inherited $ +                                        InhTC (maybe id (Map.insert var) (Map.lookup subtype+                                                                          $ env (inheritance :: InhTC l)) +                                               $ env (inheritance :: InhTC l))+                                              (currentModule (inheritance :: InhTC l))))++instance (Abstract.Nameable l,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.Expression l l Sem Sem) ~ SynTCExp l,+          Atts (Synthesized (Auto TypeCheck)) (Abstract.StatementSequence l l Sem Sem) ~ SynTC l) =>+         Synthesizer (Auto TypeCheck) (AST.ConditionalBranch l l) Sem Placed where+   synthesis _ (pos, _) inheritance (AST.ConditionalBranch condition body) =+      SynTC{errors= booleanExpressionErrors inheritance pos (syn condition) <> errors (syn body :: SynTC l)}++instance {-# overlaps #-} (Abstract.Nameable l, Eq (Abstract.QualIdent l),+                           Atts (Synthesized (Auto TypeCheck)) (Abstract.ConstExpression l l Sem Sem) ~ SynTCExp l) =>+                          Synthesizer (Auto TypeCheck) (AST.CaseLabels l l) Sem Placed where+   synthesis _ (pos, _) inheritance (AST.SingleLabel value) =+      SynTC{errors= assignmentCompatibleIn inheritance pos (inferredType $ syn value)}+   synthesis _ (pos, _) inheritance (AST.LabelRange start end) =+      SynTC{errors= assignmentCompatibleIn inheritance pos (inferredType $ syn start)+                    <> assignmentCompatibleIn inheritance pos (inferredType $ syn end)}++instance {-# overlaps #-} (Abstract.Nameable l, Ord (Abstract.QualIdent l),+                           Atts (Inherited (Auto TypeCheck)) (Abstract.Expression l l Sem Sem) ~ InhTC l,+                           Atts (Synthesized (Auto TypeCheck)) (Abstract.Expression l l Sem Sem) ~ SynTCExp l,+                           Atts (Synthesized (Auto TypeCheck)) (Abstract.Element l l Sem Sem) ~ SynTCExp l,+                           Atts (Synthesized (Auto TypeCheck)) (Abstract.Value l l Sem Sem) ~ SynTCExp l,+                           Atts (Synthesized (Auto TypeCheck)) (Abstract.Designator l l Sem Sem) ~ SynTCDes l) =>+                          Synthesizer (Auto TypeCheck) (AST.Expression l l) Sem Placed where+   synthesis _ (pos, AST.Relation op _ _) inheritance (AST.Relation _op left right) =+      SynTCExp{errors= case errors (syn left :: SynTCExp l) <> errors (syn right :: SynTCExp l)+                       of Folded []+                            | t1 == t2 -> mempty+                            | AST.In <- op -> membershipCompatible (ultimate t1) (ultimate t2)+                            | equality op,+                              Folded [] <- assignmentCompatible (currentModule (inheritance :: InhTC l)) pos t1 t2+                              -> mempty+                            | equality op,+                              Folded [] <- assignmentCompatible (currentModule (inheritance :: InhTC l)) pos t2 t1+                              -> mempty+                            | otherwise -> comparable (ultimate t1) (ultimate t2)+                          errs -> errs,+               inferredType= BuiltinType "BOOLEAN"}+      where t1 = inferredType (syn left)+            t2 = inferredType (syn right)+            equality AST.Equal = True+            equality AST.Unequal = True+            equality _ = False+            comparable (BuiltinType "BOOLEAN") (BuiltinType "BOOLEAN") = mempty+            comparable (BuiltinType "CHAR") (BuiltinType "CHAR") = mempty+            comparable StringType{} StringType{} = mempty+            comparable (StringType 1) (BuiltinType "CHAR") = mempty+            comparable (BuiltinType "CHAR") (StringType 1) = mempty+            comparable StringType{} (ArrayType _ (BuiltinType "CHAR")) = mempty+            comparable (ArrayType _ (BuiltinType "CHAR")) StringType{} = mempty+            comparable (ArrayType _ (BuiltinType "CHAR")) (ArrayType _ (BuiltinType "CHAR")) = mempty+            comparable (BuiltinType t1) (BuiltinType t2)+               | isNumerical t1 && isNumerical t2 = mempty+            comparable (BuiltinType t1) IntegerType{}+               | isNumerical t1 = mempty+            comparable IntegerType{} (BuiltinType t2)+               | isNumerical t2 = mempty+            comparable t1 t2 = Folded [(currentModule (inheritance :: InhTC l), pos, IncomparableTypes t1 t2)]+            membershipCompatible IntegerType{} (BuiltinType "SET") = mempty+            membershipCompatible (BuiltinType t1) (BuiltinType "SET")+               | isNumerical t1 = mempty+   synthesis _ (pos, AST.IsA _ q) inheritance (AST.IsA left _) =+      SynTCExp{errors= case Map.lookup q (env (inheritance :: InhTC l))+                       of Nothing -> Folded [(currentModule (inheritance :: InhTC l), pos, UnknownName q)]+                          Just t -> assignmentCompatible (currentModule (inheritance :: InhTC l)) pos+                                    (inferredType $ syn left) t,+               inferredType= BuiltinType "BOOLEAN"}+   synthesis _ (pos, _) inheritance (AST.Positive expr) =+      SynTCExp{errors= unaryNumericOrSetOperatorErrors inheritance pos (syn expr),+               inferredType= inferredType (syn expr)}+   synthesis _ (pos, _) inheritance (AST.Negative expr) =+      SynTCExp{errors= unaryNumericOrSetOperatorErrors inheritance pos (syn expr),+               inferredType= unaryNumericOrSetOperatorType negate (syn expr)}+   synthesis _ (pos, _) inheritance (AST.Add left right) =+      binaryNumericOrSetSynthesis inheritance pos left right+   synthesis _ (pos, _) inheritance (AST.Subtract left right) =+      binaryNumericOrSetSynthesis inheritance pos left right+   synthesis _ (pos, _) inheritance (AST.Or left right) = binaryBooleanSynthesis inheritance pos left right+   synthesis _ (pos, _) inheritance (AST.Multiply left right) =+      binaryNumericOrSetSynthesis inheritance pos left right+   synthesis _ (pos, _) inheritance (AST.Divide left right) =+      SynTCExp{errors=+                  case (syn left, syn right)+                  of (SynTCExp{errors= Folded [], inferredType= BuiltinType t1},+                      SynTCExp{errors= Folded [], inferredType= BuiltinType t2})+                        | t1 == "REAL", t2 == "REAL" -> mempty+                        | t1 == "SET", t2 == "SET" -> mempty+                     (SynTCExp{errors= Folded [], inferredType= t1},+                      SynTCExp{errors= Folded [], inferredType= t2})+                       | t1 == t2 -> Folded [(currentModule (inheritance :: InhTC l), pos, UnrealType t1)]+                       | otherwise -> Folded [(currentModule (inheritance :: InhTC l), pos, TypeMismatch t1 t2)],+               inferredType= BuiltinType "REAL"}+   synthesis _ (pos, _) inheritance (AST.IntegerDivide left right) =+      binaryIntegerSynthesis inheritance pos left right+   synthesis _ (pos, _) inheritance (AST.Modulo left right) = binaryIntegerSynthesis inheritance pos left right+   synthesis _ (pos, _) inheritance (AST.And left right) = binaryBooleanSynthesis inheritance pos left right+   synthesis (Auto TypeCheck) _self _ (AST.Set elements) =+      SynTCExp{errors= mempty,+               inferredType= BuiltinType "SET"}+   synthesis (Auto TypeCheck) _self _ (AST.Read designator) =+      SynTCExp{errors= errors (syn designator :: SynTCDes l),+               inferredType= designatorType (syn designator)}+   synthesis (Auto TypeCheck) _self _ (AST.Literal value) =+      SynTCExp{errors= errors (syn value :: SynTCExp l),+               inferredType= inferredType (syn value)}+   synthesis _ (pos, AST.FunctionCall _designator (ZipList parameters)) inheritance+             (AST.FunctionCall designator (ZipList parameters')) =+      SynTCExp{errors=+                   case {-# SCC "FunctionCall" #-} syn designator+                   of SynTCDes{errors= Folded [],+                               designatorName= name,+                               designatorType= ultimate -> ProcedureType _ formalTypes Just{}}+                        | length formalTypes /= length parameters ->+                            Folded [(currentModule (inheritance :: InhTC l), pos,+                                     ArgumentCountMismatch (length formalTypes) (length parameters))]+                        | name == Just (Just "SYSTEM", "VAL") -> mempty+                        | otherwise -> mconcat (zipWith (parameterCompatible inheritance pos) formalTypes+                                                $ inferredType . syn <$> parameters')+                      SynTCDes{errors= Folded [],+                               designatorType= t} -> Folded [(currentModule (inheritance :: InhTC l),+                                                              pos, NonFunctionType t)]+                      SynTCDes{errors= errs} -> errs+                   <> foldMap (\p-> errors (syn p :: SynTCExp l)) parameters',+               inferredType=+                   case syn designator+                   of SynTCDes{designatorName= Just (Just "SYSTEM", name)}+                        | Just t <- systemCallType name (inferredType . syn <$> parameters') -> t+                      SynTCDes{designatorName= d, designatorType= t}+                        | ProcedureType _ _ (Just returnType) <- ultimate t -> returnType+                      _ -> UnknownType}+     where systemCallType "VAL" [t1, t2] = Just t1+           systemCallType _ _ = Nothing+   synthesis _ (pos, _) inheritance (AST.Not expr) =+      SynTCExp{errors= booleanExpressionErrors inheritance pos (syn expr),+               inferredType= BuiltinType "BOOLEAN"}++instance SynthesizedField "errors" (Folded [Error l]) (Auto TypeCheck) (AST.Value l l) Sem Placed where+   synthesizedField = mempty+  +instance Abstract.Wirthy l => SynthesizedField "inferredType" (Type l) (Auto TypeCheck) (AST.Value l l) Sem Placed where+   synthesizedField _ _ (_, AST.Integer x) _ _  = IntegerType (fromIntegral x)+   synthesizedField _ _ (_, AST.Real x) _ _     = BuiltinType "REAL"+   synthesizedField _ _ (_, AST.Boolean x) _ _  = BuiltinType "BOOLEAN"+   synthesizedField _ _ (_, AST.CharCode x) _ _ = BuiltinType "CHAR"+   synthesizedField _ _ (_, AST.String x) _ _   = StringType (Text.length x)+   synthesizedField _ _ (_, AST.Nil) _ _        = NilType+   synthesizedField _ _ (_, AST.Builtin x) _ _  = BuiltinType x++instance (Atts (Synthesized (Auto TypeCheck)) (Abstract.Expression l l Sem Sem) ~ SynTCExp l) =>+         SynthesizedField "errors" (Folded [Error l]) (Auto TypeCheck) (AST.Element l l) Sem Placed where+   synthesizedField _ _ (pos, _) inheritance (AST.Element expr) = integerExpressionErrors inheritance pos (syn expr)+   synthesizedField _ _ (pos, _) inheritance (AST.Range low high) = integerExpressionErrors inheritance pos (syn high)+                                                                    <> integerExpressionErrors inheritance pos (syn low)++instance SynthesizedField "inferredType" (Type l) (Auto TypeCheck) (AST.Element l l) Sem Placed where+   synthesizedField _ _ _ _ _ = BuiltinType "SET"++instance {-# overlaps #-} (Abstract.Nameable l, Abstract.Oberon l, Ord (Abstract.QualIdent l),+                           Show (Abstract.QualIdent l),+                           Atts (Inherited (Auto TypeCheck)) (Abstract.Designator l l Sem Sem) ~ InhTC l,+                           Atts (Synthesized (Auto TypeCheck)) (Abstract.Expression l l Sem Sem) ~ SynTCExp l,+                           Atts (Synthesized (Auto TypeCheck)) (Abstract.Designator l l Sem Sem) ~ SynTCDes l) =>+                          Synthesizer (Auto TypeCheck) (AST.Designator l l) Sem Placed where+   synthesis _ (pos, AST.Variable q) inheritance _ =+      SynTCDes{errors= case designatorType+                       of Nothing -> Folded [(currentModule (inheritance :: InhTC l), pos, UnknownName q)]+                          Just{} -> mempty,+               designatorName= (,) Nothing <$> Abstract.getNonQualIdentName q+                               <|> first Just <$> Abstract.getQualIdentNames q,+               designatorType= fromMaybe UnknownType designatorType}+      where designatorType = Map.lookup q (env (inheritance :: InhTC l))+   synthesis _ (pos, AST.Field _record fieldName) inheritance (AST.Field record _fieldName) =+      SynTCDes{errors= case syn record+                       of SynTCDes{errors= Folded [],+                                   designatorType= t} ->+                             maybe (Folded [(currentModule (inheritance :: InhTC l), pos, NonRecordType t)])+                                   (maybe (Folded [(currentModule (inheritance :: InhTC l), pos,+                                                    UnknownField fieldName t)])+                                    $ const mempty)+                                   (access True t)+                          SynTCDes{errors= errors} -> errors,+               designatorName= Nothing,+               designatorType= fromMaybe UnknownType (fromMaybe Nothing $ access True+                                                      $ designatorType $ syn record)}+     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 allowPtr (ReceiverType t) = (receive <$>) <$> access allowPtr t+           access _ _ = Nothing+           receive (ProcedureType _ params result) = ProcedureType True params result+           receive t = t+   synthesis _ (pos, AST.Index _array index indexes) inheritance (AST.Index array _index _indexes) =+      SynTCDes{errors= case syn array+                       of SynTCDes{errors= Folded [],+                                   designatorType= t} -> either id (const mempty) (access True t)+                          SynTCDes{errors= errors} -> errors,+               designatorType= either (const UnknownType) id (access True $ designatorType $ syn array)}+      where access _ (ArrayType dimensions t)+              | length dimensions == length indexes + 1 = Right t+              | length dimensions == 0 && length indexes == 0 = Right t+              | otherwise = Left (Folded [(currentModule (inheritance :: InhTC l), pos,+                                           ExtraDimensionalIndex (length dimensions) (1 + length indexes))])+            access allowPtr (NominalType _ (Just t)) = access allowPtr t+            access allowPtr (ReceiverType t) = access allowPtr t+            access True (PointerType t) = access False t+            access _ t = Left (Folded [(currentModule (inheritance :: InhTC l), pos, NonArrayType t)])+   synthesis _ (pos, AST.TypeGuard _designator q) inheritance (AST.TypeGuard designator _q) =+      SynTCDes{errors= case (syn designator, targetType)+                                 of (SynTCDes{errors= Folded [],+                                              designatorType= t}, +                                     Just t') -> assignmentCompatible (currentModule (inheritance :: InhTC l)) pos t t'+                                    (SynTCDes{errors= errors}, +                                     Nothing) -> Folded ((currentModule (inheritance :: InhTC l),+                                                          pos, UnknownName q) : getFolded errors)+                                    (SynTCDes{errors= errors}, _) -> errors,+               designatorType= fromMaybe UnknownType targetType}+      where targetType = Map.lookup q (env (inheritance :: InhTC l))+   synthesis _ (pos, _) inheritance (AST.Dereference pointer) =+      SynTCDes{errors= case syn pointer+                       of SynTCDes{errors= Folded [],+                                   designatorType= PointerType{}} -> mempty+                          SynTCDes{errors= Folded [],+                                   designatorType= NominalType _ (Just PointerType{})} -> mempty+                          SynTCDes{errors= Folded [],+                                   designatorType= ProcedureType True _ _} -> mempty+                          SynTCDes{errors= Folded [],+                                   designatorType= t} -> Folded [(currentModule (inheritance :: InhTC l),+                                                                  pos, NonPointerType t)]+                          SynTCDes{errors= es} -> es,+               designatorType= case designatorType (syn pointer)+                               of NominalType _ (Just (PointerType t)) -> t+                                  ProcedureType True params result -> ProcedureType False params result+                                  PointerType t -> t+                                  _ -> UnknownType}++binaryNumericOrSetSynthesis inheritance pos left right =+   SynTCExp{errors= binarySetOrNumericOperatorErrors inheritance pos (syn left) (syn right),+            inferredType= binaryNumericOperatorType (syn left) (syn right)}++binaryIntegerSynthesis inheritance pos left right =+   SynTCExp{errors= binaryIntegerOperatorErrors inheritance pos (syn left) (syn right),+            inferredType= binaryNumericOperatorType (syn left) (syn right)}++binaryBooleanSynthesis inheritance pos left right =+   SynTCExp{errors= binaryBooleanOperatorErrors inheritance pos (syn left) (syn right),+            inferredType= BuiltinType "BOOLEAN"}++unaryNumericOrSetOperatorErrors :: forall l. Abstract.Nameable l =>+                                   InhTC l -> (Int, ParsedLexemes, Int) -> SynTCExp l -> Folded [Error l]+unaryNumericOrSetOperatorErrors _ _ SynTCExp{errors= Folded [], inferredType= IntegerType{}} = mempty+unaryNumericOrSetOperatorErrors _ _ SynTCExp{errors= Folded [],+                                             inferredType= BuiltinType name}+  | isNumerical name = mempty+  | name == "SET" = mempty+unaryNumericOrSetOperatorErrors inheritance pos SynTCExp{errors= Folded [], inferredType= t} =+   Folded [(currentModule (inheritance :: InhTC l), pos, NonNumericType t)]+unaryNumericOrSetOperatorErrors _ _ SynTCExp{errors= errs} = errs++unaryNumericOrSetOperatorType :: (Int -> Int) -> SynTCExp l -> Type l+unaryNumericOrSetOperatorType f SynTCExp{inferredType= IntegerType x} = IntegerType (f x)+unaryNumericOrSetOperatorType _ SynTCExp{inferredType= t} = t++binarySetOrNumericOperatorErrors :: forall l. (Abstract.Nameable l, Eq (Abstract.QualIdent l))+                                 => InhTC l -> (Int, ParsedLexemes, Int) -> SynTCExp l -> SynTCExp l -> Folded [Error l]+binarySetOrNumericOperatorErrors _ _+  SynTCExp{errors= Folded [], inferredType= BuiltinType name1}+  SynTCExp{errors= Folded [], inferredType= BuiltinType name2}+  | isNumerical name1 && isNumerical name2 || name1 == "SET" && name2 == "SET" = mempty+binarySetOrNumericOperatorErrors _ _+  SynTCExp{errors= Folded [], inferredType= IntegerType{}}+  SynTCExp{errors= Folded [], inferredType= BuiltinType name}+  | isNumerical name = mempty+binarySetOrNumericOperatorErrors _ _+  SynTCExp{errors= Folded [], inferredType= BuiltinType name}+  SynTCExp{errors= Folded [], inferredType= IntegerType{}}+  | isNumerical name = mempty+binarySetOrNumericOperatorErrors _ _+  SynTCExp{errors= Folded [], inferredType= IntegerType{}}+  SynTCExp{errors= Folded [], inferredType= IntegerType{}} = mempty+binarySetOrNumericOperatorErrors inheritance pos SynTCExp{errors= Folded [], inferredType= t1}+                                 SynTCExp{errors= Folded [], inferredType= t2}+  | t1 == t2 = Folded [(currentModule (inheritance :: InhTC l), pos, NonNumericType t1)]+  | otherwise = Folded [(currentModule (inheritance :: InhTC l), pos, TypeMismatch t1 t2)]+binarySetOrNumericOperatorErrors _ _ SynTCExp{errors= errs1} SynTCExp{errors= errs2} = errs1 <> errs2++binaryNumericOperatorType :: (Abstract.Nameable l, Eq (Abstract.QualIdent l)) => SynTCExp l -> SynTCExp l -> Type l+binaryNumericOperatorType SynTCExp{inferredType= t1} SynTCExp{inferredType= t2}+  | t1 == t2 = t1+  | IntegerType{} <- t1 = t2+  | IntegerType{} <- t2 = t1+  | BuiltinType name1 <- t1, BuiltinType name2 <- t2,+    Just index1 <- List.elemIndex name1 numericTypeNames,+    Just index2 <- List.elemIndex name2 numericTypeNames = BuiltinType (numericTypeNames !! max index1 index2)+  | otherwise = t1++binaryIntegerOperatorErrors :: Abstract.Nameable l =>+                               InhTC l -> (Int, ParsedLexemes, Int) ->  SynTCExp l -> SynTCExp l -> Folded [Error l]+binaryIntegerOperatorErrors inheritance pos syn1 syn2 = integerExpressionErrors inheritance pos syn1 +                                                      <> integerExpressionErrors inheritance pos syn2++integerExpressionErrors :: forall l. InhTC l -> (Int, ParsedLexemes, Int) -> SynTCExp l -> Folded [Error l]+integerExpressionErrors inheritance pos SynTCExp{errors= Folded [], inferredType= t}+  | isIntegerType t = mempty+  | otherwise = Folded [(currentModule (inheritance :: InhTC l), pos, NonIntegerType t)]+integerExpressionErrors _ _ SynTCExp{errors= errs} = errs++isIntegerType IntegerType{} = True+isIntegerType (BuiltinType "SHORTINT") = True+isIntegerType (BuiltinType "INTEGER") = True+isIntegerType (BuiltinType "LONGINT") = True+isIntegerType t = False++booleanExpressionErrors :: forall l. InhTC l -> (Int, ParsedLexemes, Int) -> SynTCExp l -> Folded [Error l]+booleanExpressionErrors _ _ SynTCExp{errors= Folded [],+                                     inferredType= BuiltinType "BOOLEAN"} = mempty+booleanExpressionErrors inheritance pos SynTCExp{errors= Folded [], inferredType= t} = +   Folded [(currentModule (inheritance :: InhTC l), pos, NonBooleanType t)]+booleanExpressionErrors _ _ SynTCExp{errors= errs} = errs++binaryBooleanOperatorErrors :: forall l. (Abstract.Nameable l, Eq (Abstract.QualIdent l))+                            => InhTC l -> (Int, ParsedLexemes, Int) -> SynTCExp l -> SynTCExp l -> Folded [Error l]+binaryBooleanOperatorErrors _inh _pos+  SynTCExp{errors= Folded [], inferredType= BuiltinType "BOOLEAN"}+  SynTCExp{errors= Folded [], inferredType= BuiltinType "BOOLEAN"} = mempty+binaryBooleanOperatorErrors inheritance pos+  SynTCExp{errors= Folded [], inferredType= t1}+  SynTCExp{errors= Folded [], inferredType= t2}+  | t1 == t2 = Folded [(currentModule (inheritance :: InhTC l), pos, NonBooleanType t1)]+  | otherwise = Folded [(currentModule (inheritance :: InhTC l), pos, TypeMismatch t1 t2)]+binaryBooleanOperatorErrors _ _ SynTCExp{errors= errs1} SynTCExp{errors= errs2} = errs1 <> errs2++parameterCompatible :: forall l. (Abstract.Nameable l, Eq (Abstract.QualIdent l))+                    => InhTC l -> (Int, ParsedLexemes, Int) -> (Bool, Type l) -> Type l -> Folded [Error l]+parameterCompatible _ _ (_, expected@(ArrayType [] _)) actual+  | arrayCompatible expected actual = mempty+parameterCompatible inheritance pos (True, expected) actual+  | expected == actual = mempty+  | otherwise = Folded [(currentModule (inheritance :: InhTC l), pos, UnequalTypes expected actual)]+parameterCompatible inheritance pos (False, expected) actual+  | BuiltinType "ARRAY" <- expected, ArrayType{} <- actual = mempty+  | otherwise = assignmentCompatible (currentModule (inheritance :: InhTC l)) pos expected actual++assignmentCompatibleIn :: forall l. (Abstract.Nameable l, Eq (Abstract.QualIdent l))+                       => InhTCExp l -> (Int, ParsedLexemes, Int) -> Type l -> Folded [Error l]+assignmentCompatibleIn inheritance pos =+  assignmentCompatible (currentModule (inheritance :: InhTCExp l)) pos (expectedType (inheritance :: InhTCExp l))++assignmentCompatible :: forall l. (Abstract.Nameable l, Eq (Abstract.QualIdent l))+                     => AST.Ident -> (Int, ParsedLexemes, Int) -> Type l -> Type l -> Folded [Error l]+assignmentCompatible currModule pos expected actual+   | expected == actual = mempty+   | BuiltinType name1 <- expected, BuiltinType name2 <- actual,+     Just index1 <- List.elemIndex name1 numericTypeNames,+     Just index2 <- List.elemIndex name2 numericTypeNames, +     index1 >= index2 = mempty+   | BuiltinType name <- expected, IntegerType{} <- actual, isNumerical name = mempty+   | BuiltinType "BASIC TYPE" <- expected, BuiltinType name <- actual,+     name `elem` ["BOOLEAN", "CHAR", "SHORTINT", "INTEGER", "LONGINT", "REAL", "LONGREAL", "SET"] = mempty+   | BuiltinType "POINTER" <- expected, PointerType{} <- actual = mempty+   | BuiltinType "POINTER" <- expected, NominalType _ (Just t) <- actual =+       assignmentCompatible currModule pos expected t+   | BuiltinType "CHAR" <- expected, actual == StringType 1 = mempty+   | ReceiverType t <- actual = assignmentCompatible currModule pos expected t+   | ReceiverType t <- expected = assignmentCompatible currModule pos t actual+   | NilType <- actual, PointerType{} <- expected = mempty+   | NilType <- actual, ProcedureType{} <- expected = mempty+   | NilType <- actual, NominalType _ (Just t) <- expected = assignmentCompatible currModule pos t actual+--   | ArrayType [] (BuiltinType "CHAR") <- expected, StringType{} <- actual = mempty+   | ArrayType [m] (BuiltinType "CHAR") <- expected, StringType n <- actual =+       Folded (if m < n then [(currModule, pos, TooSmallArrayType m n)] else [])+   | targetExtends actual expected = mempty+   | NominalType _ (Just t) <- expected, ProcedureType{} <- actual = assignmentCompatible currModule pos t actual+   | otherwise = Folded [(currModule, pos, IncompatibleTypes expected actual)]++arrayCompatible (ArrayType [] t1) (ArrayType _ t2) = t1 == t2 || arrayCompatible t1 t2+arrayCompatible (ArrayType [] (BuiltinType "CHAR")) StringType{} = True+arrayCompatible (NominalType _ (Just t1)) t2 = arrayCompatible t1 t2+arrayCompatible t1 (NominalType _ (Just t2)) = arrayCompatible t1 t2+arrayCompatible _ _ = False++extends, targetExtends :: Eq (Abstract.QualIdent l) => Type l -> Type l -> 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))++ultimate :: Type l -> Type l+ultimate (NominalType _ (Just t)) = ultimate t+ultimate t = t++isNumerical t = t `elem` numericTypeNames+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++instance Transformation.Transformation (Auto TypeCheck) where+   type Domain (Auto TypeCheck) = Placed+   type Codomain (Auto TypeCheck) = Semantics (Auto TypeCheck)++instance Ord (Abstract.QualIdent l) => Transformation.At (Auto TypeCheck) (Modules l Sem Sem) where+   ($) = AG.applyDefault snd++-- * Unsafe Rank2 AST instances++instance Rank2.Apply (AST.Module l l f') where+   AST.Module name1 imports1 body1 <*> ~(AST.Module name2 imports2 body2) =+      AST.Module name1 imports1 (Rank2.apply body1 body2)++-- | Check if the given collection of modules is well typed and return all type errors found. The collection is a+-- 'Map' keyed by module name. The first argument's value is typically 'predefined' or 'predefined2'.+checkModules :: forall l. (Abstract.Oberon l, Abstract.Nameable l,+                           Ord (Abstract.QualIdent l), Show (Abstract.QualIdent l),+                           Atts (Inherited (Auto TypeCheck)) (Abstract.Block l l Sem Sem) ~ InhTC l,+                           Atts (Synthesized (Auto TypeCheck)) (Abstract.Block l l Sem Sem) ~ SynTCMod l,+                           Full.Functor (Auto TypeCheck) (Abstract.Block l l))+             => Environment l -> Map AST.Ident (Placed (AST.Module l l Placed Placed)) -> [Error l]+checkModules predef modules =+   getFolded (errors (syn (Transformation.apply (Auto TypeCheck) (wrap $ Auto TypeCheck Deep.<$> Modules modules)+                           `Rank2.apply`+                           Inherited (InhTCRoot predef)) :: SynTC l))+   where wrap = (,) (0, Trailing [], 0)++predefined, predefined2 :: (Abstract.Wirthy l, Ord (Abstract.QualIdent l)) => Environment l+-- | The set of 'Predefined' types and procedures defined in the Oberon Language Report.+predefined = Map.fromList $ map (first Abstract.nonQualIdent) $+   [("BOOLEAN", BuiltinType "BOOLEAN"),+    ("CHAR", BuiltinType "CHAR"),+    ("SHORTINT", BuiltinType "SHORTINT"),+    ("INTEGER", BuiltinType "INTEGER"),+    ("LONGINT", BuiltinType "LONGINT"),+    ("REAL", BuiltinType "REAL"),+    ("LONGREAL", BuiltinType "LONGREAL"),+    ("SET", BuiltinType "SET"),+    ("TRUE", BuiltinType "BOOLEAN"),+    ("FALSE", BuiltinType "BOOLEAN"),+    ("ABS", ProcedureType False [(False, BuiltinType "INTEGER")] $ Just $ BuiltinType "INTEGER"),+    ("ASH", ProcedureType False [(False, BuiltinType "INTEGER")] $ Just $ BuiltinType "INTEGER"),+    ("CAP", ProcedureType False [(False, BuiltinType "CHAR")] $ Just $ BuiltinType "CHAR"),+    ("LEN", ProcedureType False [(False, BuiltinType "ARRAY")] $ Just $ BuiltinType "LONGINT"),+    ("MAX", ProcedureType False [(False, BuiltinType "BASIC TYPE")] $ Just UnknownType),+    ("MIN", ProcedureType False [(False, BuiltinType "BASIC TYPE")] $ Just UnknownType),+    ("ODD", ProcedureType False [(False, BuiltinType "CHAR")] $ Just $ BuiltinType "BOOLEAN"),+    ("SIZE", ProcedureType False [(False, BuiltinType "CHAR")] $ Just $ BuiltinType "INTEGER"),+    ("ORD", ProcedureType False [(False, BuiltinType "CHAR")] $ Just $ BuiltinType "INTEGER"),+    ("CHR", ProcedureType False [(False, BuiltinType "LONGINT")] $ Just $ BuiltinType "CHAR"),+    ("SHORT", ProcedureType False [(False, BuiltinType "LONGINT")] $ Just $ BuiltinType "SHORTINT"),+    ("LONG", ProcedureType False [(False, BuiltinType "INTEGER")] $ Just $ BuiltinType "INTEGER"),+    ("ENTIER", ProcedureType False [(False, BuiltinType "REAL")] $ Just $ BuiltinType "INTEGER"),+    ("INC", ProcedureType False [(False, BuiltinType "LONGINT")] Nothing),+    ("DEC", ProcedureType False [(False, BuiltinType "LONGINT")] Nothing),+    ("INCL", ProcedureType False [(False, BuiltinType "SET"), (False, BuiltinType "INTEGER")] Nothing),+    ("EXCL", ProcedureType False [(False, BuiltinType "SET"), (False, BuiltinType "INTEGER")] Nothing),+    ("COPY", ProcedureType False [(False, BuiltinType "ARRAY"), (False, BuiltinType "ARRAY")] Nothing),+    ("NEW", ProcedureType False [(False, BuiltinType "POINTER")] Nothing),+    ("HALT", ProcedureType False [(False, BuiltinType "INTEGER")] Nothing)]++-- | The set of 'Predefined' types and procedures defined in the Oberon-2 Language Report.+predefined2 = predefined <>+   Map.fromList (first Abstract.nonQualIdent <$>+                 [("ASSERT", ProcedureType False [(False, BuiltinType "BOOLEAN"),+                                                  (False, BuiltinType "INTEGER")] Nothing)])++$(do l <- varT <$> newName "l"+     mconcat <$> mapM (\t-> Transformation.Full.TH.deriveUpFunctor (conT ''Auto `appT` conT ''TypeCheck)+                            $ conT t `appT` l `appT` l)+        [''AST.Declaration, ''AST.Type, ''AST.FieldList,+         ''AST.ProcedureHeading, ''AST.FormalParameters, ''AST.FPSection,+         ''AST.Expression, ''AST.Element, ''AST.Designator,+         ''AST.Block, ''AST.StatementSequence, ''AST.Statement,+         ''AST.Case, ''AST.CaseLabels, ''AST.ConditionalBranch, ''AST.Value, ''AST.WithAlternative])++$(do let sem = [t|Semantics (Auto TypeCheck)|]+     let inst g = [d| instance Attribution (Auto TypeCheck) ($g l l) Sem Placed =>+                               Transformation.At (Auto TypeCheck) ($g l l $sem $sem)+                         where ($) = AG.applyDefault snd |]+     mconcat <$> mapM (inst . conT)+        [''AST.Module, ''AST.Declaration, ''AST.Type, ''AST.FieldList,+         ''AST.ProcedureHeading, ''AST.FormalParameters, ''AST.FPSection,+         ''AST.Block, ''AST.StatementSequence, ''AST.Statement,+         ''AST.Case, ''AST.CaseLabels, ''AST.ConditionalBranch, ''AST.WithAlternative,+         ''AST.Expression, ''AST.Element, ''AST.Designator, ''AST.Value])
− src/Transformation.hs
@@ -1,23 +0,0 @@-{-# 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
@@ -1,37 +0,0 @@-{-# 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
@@ -1,83 +0,0 @@-{-# 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
@@ -1,287 +0,0 @@--- | 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
@@ -1,36 +0,0 @@-{-# 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
@@ -1,22 +1,32 @@+{-# Language FlexibleInstances #-} module Main where  import Data.Either.Validation (Validation(..))+import Data.Functor.Identity (Identity(Identity)) import Data.List (isSuffixOf) import Data.List.NonEmpty (NonEmpty((:|)))-import Data.Text (Text)+import Data.Text (Text, unpack) 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, assertEqual, testCase) -import Language.Oberon (parseAndResolveModule)+import qualified Transformation.Rank2 as Rank2++import Language.Oberon (parseAndResolveModule, LanguageVersion(Oberon2), Options(..), Placed)+import Language.Oberon.AST (Language, Module) import Language.Oberon.Pretty () import qualified Language.Oberon.Resolver as Resolver+import qualified Language.Oberon.TypeChecker as TypeChecker +import qualified Language.Oberon.AST as AST+import qualified Language.Oberon.Grammar as Grammar+import qualified Language.Oberon.Reserializer as Reserializer+import qualified Transformation.Deep as Deep+ import Prelude hiding (readFile)  main = exampleTree "" "examples" >>= defaultMain . testGroup "Oberon"@@ -40,8 +50,16 @@  prettyFile :: FilePath -> Text -> IO Text prettyFile dirPath source = do-   resolvedModule <- parseAndResolveModule True True dirPath source+   resolvedModule <- parseAndResolveModule Options{foldConstants= True,+                                                   checkTypes= True,+                                                   version= Oberon2}+                     dirPath source    case resolvedModule-      of Failure (Resolver.UnparseableModule err :| []) -> assertFailure (showFailure source err contextLines)-         Failure errs -> assertFailure (show errs)+      of Failure (Left (Resolver.UnparseableModule err :| [])) -> assertFailure (unpack err)+         Failure errs -> assertFailure (show $ (onLastOfThree TypeChecker.errorMessage <$>) <$> errs)          Success mod -> return (renderStrict $ layoutPretty defaultLayoutOptions $ pretty mod)++onLastOfThree f (a, b, c) = (a, b, f c)++instance {-# overlaps #-} Pretty (Placed (Module Language Language Placed Placed)) where+   pretty (_, m) = pretty ((Identity . snd) Rank2.<$> m)