curry-frontend 0.2.12 → 2.0.0
raw patch · 170 files changed
Files
- CHANGELOG.md +327/−0
- LICENSE +1/−0
- LIESMICH +0/−172
- README.md +65/−0
- app/cymake.hs +57/−0
- curry-frontend.cabal +199/−63
- data/currysource.css +95/−0
- src/Arity.hs +0/−133
- src/Base.lhs +0/−557
- src/Base/AnnotExpr.hs +124/−0
- src/Base/CurryKinds.hs +45/−0
- src/Base/CurryTypes.hs +213/−0
- src/Base/Expr.hs +212/−0
- src/Base/KindSubst.hs +48/−0
- src/Base/Kinds.hs +62/−0
- src/Base/Messages.hs +78/−0
- src/Base/NestEnv.hs +120/−0
- src/Base/PrettyKinds.hs +22/−0
- src/Base/PrettyTypes.hs +55/−0
- src/Base/SCC.hs +62/−0
- src/Base/Subst.hs +127/−0
- src/Base/TopEnv.hs +181/−0
- src/Base/TypeExpansion.hs +112/−0
- src/Base/TypeSubst.hs +137/−0
- src/Base/Types.hs +478/−0
- src/Base/Typing.hs +190/−0
- src/Base/Utils.hs +94/−0
- src/CaseCompletion.hs +0/−662
- src/Checks.hs +161/−0
- src/Checks/DeriveCheck.hs +111/−0
- src/Checks/ExportCheck.hs +500/−0
- src/Checks/ExtensionCheck.hs +72/−0
- src/Checks/ImportSyntaxCheck.hs +279/−0
- src/Checks/InstanceCheck.hs +414/−0
- src/Checks/InterfaceCheck.hs +321/−0
- src/Checks/InterfaceSyntaxCheck.hs +346/−0
- src/Checks/KindCheck.hs +762/−0
- src/Checks/PrecCheck.hs +515/−0
- src/Checks/SyntaxCheck.hs +1430/−0
- src/Checks/TypeCheck.hs +1874/−0
- src/Checks/TypeSyntaxCheck.hs +498/−0
- src/Checks/WarnCheck.hs +1641/−0
- src/CompilerEnv.hs +117/−0
- src/CompilerOpts.hs +644/−0
- src/CondCompile.hs +26/−0
- src/Curry/AbstractCurry.hs +30/−0
- src/Curry/AbstractCurry/Files.hs +61/−0
- src/Curry/AbstractCurry/Type.hs +329/−0
- src/Curry/Base/Ident.hs +1036/−0
- src/Curry/Base/LLParseComb.hs +380/−0
- src/Curry/Base/LexComb.hs +179/−0
- src/Curry/Base/Message.hs +114/−0
- src/Curry/Base/Monad.hs +95/−0
- src/Curry/Base/Position.hs +128/−0
- src/Curry/Base/Pretty.hs +209/−0
- src/Curry/Base/Span.hs +180/−0
- src/Curry/Base/SpanInfo.hs +139/−0
- src/Curry/CondCompile/Parser.hs +90/−0
- src/Curry/CondCompile/Transform.hs +116/−0
- src/Curry/CondCompile/Type.hs +88/−0
- src/Curry/Files/CymakePath.hs +0/−15
- src/Curry/Files/Filenames.hs +256/−0
- src/Curry/Files/PathUtils.hs +206/−0
- src/Curry/Files/Unlit.hs +124/−0
- src/Curry/FlatCurry.hs +19/−0
- src/Curry/FlatCurry/Annotated/Goodies.hs +685/−0
- src/Curry/FlatCurry/Annotated/Type.hs +132/−0
- src/Curry/FlatCurry/Files.hs +68/−0
- src/Curry/FlatCurry/Goodies.hs +1037/−0
- src/Curry/FlatCurry/InterfaceEquivalence.hs +58/−0
- src/Curry/FlatCurry/Pretty.hs +217/−0
- src/Curry/FlatCurry/Type.hs +521/−0
- src/Curry/FlatCurry/Typeable.hs +22/−0
- src/Curry/FlatCurry/Typed/Goodies.hs +666/−0
- src/Curry/FlatCurry/Typed/Type.hs +146/−0
- src/Curry/Syntax.hs +68/−30
- src/Curry/Syntax/Extension.hs +120/−0
- src/Curry/Syntax/Frontend.hs +0/−202
- src/Curry/Syntax/InterfaceEquivalence.hs +209/−0
- src/Curry/Syntax/LLParseComb.lhs +0/−288
- src/Curry/Syntax/LexComb.lhs +0/−104
- src/Curry/Syntax/Lexer.hs +889/−0
- src/Curry/Syntax/Lexer.lhs +0/−630
- src/Curry/Syntax/Parser.hs +1428/−0
- src/Curry/Syntax/Parser.lhs +0/−806
- src/Curry/Syntax/Pretty.hs +463/−0
- src/Curry/Syntax/Pretty.lhs +0/−368
- src/Curry/Syntax/ShowModule.hs +502/−224
- src/Curry/Syntax/Type.hs +1540/−0
- src/Curry/Syntax/Type.lhs +0/−315
- src/Curry/Syntax/Unlit.hs +0/−61
- src/Curry/Syntax/Utils.hs +282/−214
- src/CurryBuilder.hs +210/−172
- src/CurryCompilerOpts.hs +0/−166
- src/CurryDeps.hs +191/−0
- src/CurryDeps.lhs +0/−144
- src/CurryEnv.hs +0/−181
- src/CurryHtml.hs +0/−190
- src/Desugar.lhs +0/−843
- src/Env/Class.hs +75/−0
- src/Env/Instance.hs +54/−0
- src/Env/Interface.hs +31/−0
- src/Env/ModuleAlias.hs +41/−0
- src/Env/OpPrec.hs +111/−0
- src/Env/Type.hs +70/−0
- src/Env/TypeConstructor.hs +221/−0
- src/Env/Value.hs +207/−0
- src/Eval.lhs +0/−96
- src/Exports.hs +425/−0
- src/Exports.lhs +0/−463
- src/Files/CymakePath.hs +32/−0
- src/GenAbstractCurry.hs +0/−1041
- src/GenFlatCurry.hs +0/−1153
- src/Generators.hs +59/−0
- src/Generators/GenAbstractCurry.hs +541/−0
- src/Generators/GenAnnotatedFlatCurry.hs +488/−0
- src/Generators/GenFlatCurry.hs +56/−0
- src/Generators/GenTypedFlatCurry.hs +53/−0
- src/Html/CurryHtml.hs +185/−0
- src/Html/SyntaxColoring.hs +564/−0
- src/IL.hs +19/−0
- src/IL/CurryToIL.lhs +0/−598
- src/IL/Pretty.hs +189/−0
- src/IL/Pretty.lhs +0/−167
- src/IL/Scope.hs +0/−124
- src/IL/ShowModule.hs +263/−0
- src/IL/Type.hs +155/−0
- src/IL/Type.lhs +0/−112
- src/IL/Typing.hs +44/−0
- src/IL/XML.lhs +0/−518
- src/Imports.hs +402/−0
- src/Imports.lhs +0/−379
- src/InterfaceCheck.hs +0/−142
- src/Interfaces.hs +151/−0
- src/KindCheck.lhs +0/−320
- src/Lift.lhs +0/−307
- src/Modules.hs +453/−0
- src/Modules.lhs +0/−700
- src/NestEnv.lhs +0/−77
- src/OldScopeEnv.hs +0/−165
- src/PatchPrelude.hs +0/−40
- src/PrecCheck.lhs +0/−461
- src/Qual.lhs +0/−165
- src/SCC.lhs +0/−60
- src/ScopeEnv.hs +0/−175
- src/Simplify.lhs +0/−475
- src/Subst.lhs +0/−124
- src/SyntaxCheck.lhs +0/−1149
- src/SyntaxColoring.hs +0/−800
- src/TokenStream.hs +168/−0
- src/TopEnv.lhs +0/−148
- src/Transformations.hs +89/−0
- src/Transformations/CaseCompletion.hs +479/−0
- src/Transformations/CurryToIL.hs +704/−0
- src/Transformations/Derive.hs +729/−0
- src/Transformations/Desugar.hs +1168/−0
- src/Transformations/Dictionary.hs +1143/−0
- src/Transformations/Lift.hs +451/−0
- src/Transformations/Newtypes.hs +113/−0
- src/Transformations/Qual.hs +250/−0
- src/Transformations/Simplify.hs +347/−0
- src/TypeCheck.lhs +0/−1331
- src/TypeSubst.lhs +0/−104
- src/Types.lhs +0/−251
- src/Typing.lhs +0/−406
- src/Utils.lhs +0/−92
- src/WarnCheck.hs +0/−872
- src/currydoc.css +0/−34
- src/cymake.hs +0/−97
- test/TestFrontend.hs +359/−0
+ CHANGELOG.md view
@@ -0,0 +1,327 @@+Change log for curry-frontend+=============================++Version 2.0.0+=============++ * Implemented the "MonadFail-Proposal" for curry+ (see <https://wiki.haskell.org/MonadFail_Proposal>)+ * Data class (see <https://arxiv.org/abs/1908.10607>)+ * Fixed bug with partially imported Typeclasses+ * Fixed bug with parsing of empty blocks+ * Fixed bug with re-export of record labels++Version 1.0.4+=============++ * Fixed bug in type checking of instances+ * Fixed bugs in deriving of `Bounded` instances.++Version 1.0.3+=============++ * Fixed bug in type checking of typeclasses++Version 1.0.2+=============++ * Added 'short-ast' and 'ast' as new compilation targets+ * Fixed bug with wrong type of free variables in the intermediate language.+ * Fixed bug with generated default implementations of nullary class methods.+ * Fixed bug in desugaring of record patterns.+ * Fixed bug that external data declarations weren't considered when+ AbstractCurry was generated++Version 1.0.1+=============++ * Fixed bug with wrong order of super classes in selector functions+ generated by the dictionary transformation.+ * Changed desugaring of numeric literals. It now generates calls to the+ functions `Prelude.fromInt` and `Prelude.fromFloat`.+ * Fixed bug with wrong original names of imported record labels+ * Fixed bug when compiling type constructor classes with super classes+ * Adjusted warning message for potentially unreachable pattern matches++Version 1.0.0+=============++ * Added support for typeclasses as known from Haskell++Version 0.4.2+=============++ * Improved readability of environment information in dumps+ (option dump-simple)+ * Added option to dump all bindings instead of just local ones+ (dump-all-bindings)+ * Introduced annotated FlatCurry as a new output format+ (annotated-flat)++Version 0.4.1+=============++ * Added a simple cabal test suite+ * Split import of interfaces/modules and expansion and checking of+ import specifications into two modules.+ * Improved error messages generated by export check (fixes #1253)+ * Split checking and expansion of export specification into two+ subsequent steps (by Yannik Potdevin, fixes #1335)+ * Consider parenthesized type expressions in the Curry AST (by Katharina Rahf)+ * Added syntax extension `ExistentialQuantification` that allows the use+ of existentially quantified types in data and newtype constructors+ * Fixed bug that type declarations weren't syntax checked++Version 0.4.0+=============++ * Refactored AbstractCurry generation++ * Complete refactoring of FlatCurry generation++ * Removed support for Curry's record syntax and introduced Haskell's record+ syntax instead++ * During desugaring record updates are translated to fcase-expressions instead+ of introducing explicit update functions++ * HTML generation now places HTML files for hierarchical modules into+ files named `<Module>_curry.html`, i.e., no sub-folders reflecting+ the the module name hierarchy are generated. In addition, if the option+ `--html-dir` is not given, the current directory is used as the output+ directory.++ * Removed record type extensions++ * Enabled declaration of (mutually) recursive record types++ * Removed expansion of record types in type error messages++ * Replaced `MessageM` monad with `CYT` monads and moved `CYT` monads+ to package `curry-base`++ * Implemented warnings for overlapping module aliases - fixes #14++ * The check for overlapping rules has been completely refactored and+ improved to now also handle rigid case expressions.++ * The check for missing pattern matching alternatives now correctly handles+ String literals - fixes #1048.++ * Added warnings for top-level functions without type signatures - fixes #769++ * Moved pretty-printing of types from Checks.TypeCheck to Base.CurryTypes++ * Type synonyms in typed expressions are now desugared - fixes #921++ * Declaration of operator precedence is now optional in infix operator+ declarations++ * Moved module `InterfaceEquivalence` to curry-base+ (`Curry.Syntax.InterfaceEquivalence`)++ * Converted literate Haskell files into simple Haskell files++ * Removed support for FlatCurry XML files.++ * Added syntax extension `NegativeLiterals` to translate negated literals+ into negative literals instead of a call to `Prelude.negate` and+ `Prelude.negateFloat`, respectively.++ * The frontend now considers options pragmas of the following form:++ ~~~ {.curry}+ {-# OPTIONS_CYMAKE opt1 ... optn #-}+ ~~~++ The string following `OPTIONS_CYMAKE` will be split at white spaces+ and treated like an ordinary command line argument string.++ If one wishes to provide options containing spaces, e.g., directory+ paths or alike, this can be achieved by quoting the respective argument+ using either `'single quotes'` or `'double quotes'` (may bot be mixed).++ Note that *following options are excluded*:++ * A change of the current mode+ (e.g., change from compilation to HTML generation)+ * A change of the import paths+ * A change of the library paths+ * A change of the compilation targets+ (e.g., change from FlatCurry to AbstractCurry)++ These options can only be set via the command line.++ * Refactored the source code HTML generation.+ The generation now supports full Curry with all supported extensions,+ i.e., it supports pragmas, record types and functional patterns.+ Furthermore, the created HTML has been simplified, and updated towards+ HTML 5.++ * The HTML generation now accepts an option `--htmldir=dir` to specify+ the output directory of the generated HTML files.++Version 0.3.10+==============++ * Various improvements of the internal structure.++ * Improved status messages. The compilation status message are now of the form++ [m of n] Compiling/Skipping <Module> (<source file>, <target file>)++ * Implemented support for custom preprocessors. It is now possible to run+ a custom preprocessor command via the following options:++ * `-F` enables support for a preprocessor+ * `-pgmF <cmd>` set the preprocessor command to `<cmd>`+ * `-optF <arg>` adds an additional argument to the preprocessor command+ (can be repeated to add multiple arguments)++ The preprocessor is applied to all source files which are (re)compiled+ after unliterating *and after determining the import list*.+ Consequently, adding modules via the preprocessor will results in+ compilation errors due to missing imports.+ On the other hand, the frontend will automatically determine changed+ files which are then handed to the preprocessor.++ The command is called with at least three arguments:++ #. The (normalised) file name of the source file currently processed.+ **This name is intended only for reference.**+ #. The name of the file containing the (potentially unliterated)+ contents of the original file.+ **This is the file the preprocessor should read from.**+ #. The name of the file where the preprocessed source code should go to.+ **This is the file the preprocessor should write to.**+ #. Optionally, any additional arguments specified using `-optF`.++Version 0.3.9+=============++ * Simplified verbosity options by merging options "-v1" and "-v2".+ Now only "-v0" and "-v1" are supported.++ * Fixed bug in non-exhaustive pattern matching check which occured+ when retrieving the siblings of a constructor imported using an alias.++ * Fixed bug when using functional patterns in `case`-expressions.+ Functional patterns are only allowed in the patterns of a function+ definition and forbidden elsewhere, i.e., in `case`-expressions,+ `do`-sequences, list comprehensions or lambda expressions.++ * Implementation of module pragmas added. Module pragmas of the following+ types are now parsed and represented in the abstract syntax tree:++ ~~~ {.curry}+ {-# LANGUAGE LANG_EXT+ #-}+ {-# OPTIONS "string" #-}+ {-# OPTIONS_TOOL "string" #-}+ module Main where+ ~~~++ where++ - `LANGEXT+` is a non-empty, comma-separated list of the following+ language extensions: `AnonFreeVars`, `FunctionalPatterns`,+ `NoImplicitPrelude`, `Records`+ - `TOOL` is either `KICS2`, `PAKCS`, or some other tool, represented+ as `Unknown String`.++ While the distinct language pragmas enable the respective language+ extensions, the OPTIONS pragma is ignored.++ All other texts given in the pragma braces is ignored and treated as+ a nested comment.++ * Error message for different arities of function equations now also+ report the corresponding source code positions.++Version 0.3.8+=============++ * Implemented warnings for non-exhaustive pattern matchings+ both in function declarations and `case`-expressions - fixes #349.++ * Extended options to enable/disable certain types of warnings.++ * Fixed problem when defining an operator directly after an import statement+ without import restrictions - fixes #494.++ * Fixed bug w.r.t. polymorphically typed local variables - fixes #480.++ * Fixed missing polymorphism in record labels - fixes #445.++ * Dumping of intermediate structures improved.++ * Fixed bug in type checking w.r.t. recursive type synonyms - fixes 489.++ * Reactivation of Curry interface files.+ During adaption of the MCC frontend to FlatCurry the Curry interface+ files have been deactivated and replaced by FlatCurry's interface+ files. To allow the later addition of type classes to Curry,+ they have now been reactivated.++ * Implemented missing semantics of functional patterns in combination+ with non-linear left-hand-sides and as-patterns.++ * Various improvements.++Version 0.3.7+=============++ * Support for typed FlatCurry expressions added. Now additional type+ information given by the programmer as in++ ~~~ {.curry}+ null (unknown :: [()])+ ~~~++ is represented in FlatCurry and cann therefore be processed by other+ programs like PAKCS or KICS2.++Version 0.3.6+=============++ * Error messages are now sorted according to their source code position.++Version 0.3.5+=============++ * Improved reporting of mutiple type signatures.++Version 0.3.4+=============++ * Bug in renaming phase fixed.++Version 0.3.3+=============++ * Corrected translation of `fcase`-expressions.++Version 0.3.2+=============++ * Non-linear left-hand-sides now work with guarded expressions - fixes #328.++ * Implemented precedence check - fixes #327.++ * Case completion refactored and corrected - fixes #323.++ * Various improvements and refactorings.++Version 0.3.1+=============++ * Corrected renaming of anonymous free variables - fixes #288.++Version 0.3.0+=============++ * Massive refactoring of the previous version.++ * All compiler warnings removed.++ * Fixed various implementation bugs (#9, #16, #19, #29, #289).+
LICENSE view
@@ -1,4 +1,5 @@ Copyright (c) 1998-2004, Wolfgang Lux+Copyright (c) 2005-2016, Michael Hanus All rights reserved. Redistribution and use in source and binary forms, with or without
− LIESMICH
@@ -1,172 +0,0 @@-===============================================================================-==-== Münster-Curry-Compiler-== Distribution zur Anwendung als Frontend in PAKCS-==-== Letztes Update: 27.10.05--Diese Distribution enthält die modifizierte Version des -Münster-Curry-Compilers (MCC) für die Verwendung als Frontend in PAKCS. Dieses -System ist u.a. in der Lage aus Curry-Programmen (entwickelt nach -PAKCS-Standard) Flat-Darstellungen (FlatCurry ".fcy", FlatInterface ".fint" -und FlatXML "_flat.xml"), sowie Abstract-Darstellungen (AbstractCurry ".acy" -und untyped AbstractCurry ".uacy") zu generieren.----1. Installation------------------1.1 Installation der Binary-Distribution--Die Binary-Distribution befindet sich in einem tar-Archiv und wird-durch folgendes Kommando entpackt:-- tar zxvf <Distribution>.tar.gz--Danach steht der Compiler im Verzeichnis 'mcc' zur Verfügung.---1.2 Installation der Source-Distribution--Nach dem Entpacken des tar-Archivs mittels-- tar zxvf <Distribution>.tar.gz--kann der Compiler durch Aufruf von 'make' im Verzeichnis 'mcc' installiert-werden. Bei Recompilierung (z.B. nach Änderungen in der Quelldateien)-wird empfohlen vor einer erneuten Installation 'make clean' auszuführen.----Nach erfolgreicher Installation befindet sich in beiden Fällen im Verzeichnis -'mcc/bin/' folgende ausführbare Datei:-- cymake - der Curry-Programm-Builder--Dieses Tool übersetzt Curry-Programme unter Berücksichtigung der Import--abhängigkeiten.----2. Kommandoübersicht-----------------------In der folgenden Tabelle sind die Optionen zur Generierung der jeweiligen-Darstellungen für das Kommando 'cymake' aufgelistet:-- --flat : Erzeugt FlatCurry- und FlatInterface-Datei- --xml : Erzeugt FlatXML-Datei- --acy : Erzeugt (typinferierte) AbstractCurry-Datei- --uacy : Erzeugt ungetypte AbstractCurry-Datei----3. Erzeugung von FlatCurry- und FlatXML-Programmen-----------------------------------------------------Die Übersetzung eines Curry-Programms 'file.curry', sowie sämtlicher-importierter Module nach FlatCurry bzw. FlatInterface, bewirkt folgendes-Kommando:-- cymake --flat <filename>--Hierdurch werden die Dateien mit den entsprechenden Endungen ".fcy" und-".fint" generiert. Der Dateiname <filename> kann hierbei mit oder ohne -Endung ".curry" bzw. ".lcurry" angegeben werden.--Die analogen Übersetzungen in die FlatXML-Darstellung bewirkt folgendes-Kommando:-- cymake --xml <file name>--Die hierdurch generierte Flat-XML-Datei hat die Endung '_flat.xml'.----4. Erzeugung von AbstractCurry-Programmen--------------------------------------------Die Übersetzung eines Curry-Programms 'file.curry' nach (typgeprüftem)-AbstractCurry bewirkt folgendes Kommando:-- cymake --acy <filename>--Hierdurch wird die entsprechende Datei (mit der Endung ".acy") generiert.-Der Dateiname <filename> kann hierbei mit oder ohne Endung ".curry" bzw.-".lcurry" angegeben werden.--Ungetypte, bzw. typsignierte AbstractCurry-Programme werden mit folgendem-Kommando generiert:-- cymake --uacy <filename>--Die hierdurch generierte Datei besitzt die Endung ".uacy".--Die Generierung des ungetypten AbstractCurry-Programms findet ohne-Typüberprüfung statt (d.h. auch Programme mit Typfehlern werden übersetzt).-Alle Funktionen besitzen entweder die im Quellprogramm angegebenen Typsignatur,-oder, sofern diese nicht vorhanden ist, den Dummy-Typ "prelude.untyped".--In beiden Fällen werden für die Übersetzung FlatCurry-Dateien -für alle importierten Module erzeugt. Dies ist notwendig, da die -entsprechenden Interfaces für die Typinferenz (nur im Fall der getypten -AbstractCurry-Generierung) und die statisch-semantische Analyse benötigt -werden.----5. Anmerkungen------------------ Um die PAKCS-Bibliotheken (insbesondere die Prelude) für Übersetzungen - nutzen zu können muß die Umgebungsvariable 'PAKCS_LIB' auf die- entsprechenden Pfade verweisen, z.B. mittels-- export PAKCS_LIB=<pakcs path>/pacs/lib:<pakcs path>/pacs/lib/meta:...-- wobei <pakcs path> das Verzeichnis ist, das die PAKCS-Distribution- enthält.--- Im Gegensatz zu PAKCS erlaubt das Frontend die Verwendung anonymer- Variablen (dargestellt durch dem Unterstrich '_') in Typdeklarationen,- z.B.-- data T _ = C----Bekannte Probleme---------------------- Lambda-, do-, if-, case-, oder let-Ausdrücke, die in Argumenten von- Funktionsaufrufen verwendet werden, müssen immer geklammert werden.--- 'let'-Anweisungen dürfen nicht folgendes Layout besitzen:-- let x = <expr>- in ...--- Die Regeln einer Funktionsdeklaration müssen immer zusammenstehen, d.h.- nicht durch andere Deklarationen unterbrochen werden.--- Es ist bislang nicht möglich, den Konstruktor für leere Listen [], sowie - den Unit-Konstruktor () zu qualifizieren (z.B. führt 'prelude.[]' zu - einem Fehler). Der Listenkonstruktor (:), sowie Tupel-Konstruktoren- dagegen sind qualifizierbar.--- FlatXML-Übersetzungen können derzeit mittels der Funktionen aus dem- PAKCS-Modul "FlatXML" noch nicht eingelesen werden, da es Unstimmigkeiten- zwischen dem generierten und den erforderlichen Formaten gibt.--- Bei der Erzeugung von typgeprüftem AbstractCurry können die im Quelltext- verwendeten Bezeichner für Typvariablen nicht ins AbstractCurry-Programm- übernommen werden. Stattdessen generiert der Übersetzer neue- Bezeichner.--- Bei der Erzeugung von ungetyptem AbstractCurry werden Typsynonyme in- Typsignaturen von Funktionen nicht dereferenziert.--- Das Frontend gibt derzeit noch keinerlei Warnungen aus.--
+ README.md view
@@ -0,0 +1,65 @@+# Curry Frontend++The frontend lexes, parses, type-checks and transforms Curry source files into a variety of intermediate formats, including++* **FlatCurry** for program analyzers and backends+* **AbstractCurry** for program manipulation tools+* **HTML** for documentation++It is used by the two major Curry compilers, [PAKCS](https://git.ps.informatik.uni-kiel.de/curry/pakcs) and+[KiCS2](https://git.ps.informatik.uni-kiel.de/curry/kics2).++## Requirements++* Make sure that a recent version of Haskell Stack is installed on your computer++## Building++* To build the project, run `make`.+* To test the project, run `make runtests`.++The built executable will be located at `bin/curry-frontend`.++## Usage++For a detailed overview of the available options, you can use the following command:++`curry-frontend --help`++### Available Formats++```+--flat : Generate a FlatCurry (.fcy) and FlatInterface (.fint) file+--xml : Generate a FlatXML (_flat.xml) file+--acy : Generate a (type-inferred) AbstractCurry (.acy) file+--uacy : Generate an untyped AbstractCurry (.uacy) file+```++The generation of an untyped AbstractCurry program is performed without+type checking (i.e. programs with type checks will compile). All functions+will either have the type signature specified in the source or, if not+available, the dummy type `prelude.untyped`.++FlatCurry files will always be generated for the imported modules,+since the interfaces are required for static-semantic analysis and type+inference (only for typed AbstractCurry).++## Remarks++- To use the PAKCS libraries (especially for the `Prelude`), the environment+ variable `PAKCS_LIB` has to point to the correct paths, e.g. using+ + `export PAKCS_LIB=[pakcs path]/pacs/lib:[pakcs path]/pacs/lib/meta:...`++ where `[pakcs path]` is the directory containing the PAKCS distribution.++- In contrast to PAKCS, the frontend allow use of anonymous variables+ (denoted by an underscore `_`) in type declarations, e.g.+ + ```curry+ data T _ = c+ ```++## Known Issues++[See GitLab](https://git.ps.informatik.uni-kiel.de/curry/curry-frontend/-/issues)
+ app/cymake.hs view
@@ -0,0 +1,57 @@+{- |+ Module : $Header$+ Description : Main module+ Copyright : (c) 2005 Martin Engelke+ 2011 - 2016 Björn Peemöller+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ Command line tool for generating Curry representations (e.g. FlatCurry,+ AbstractCurry) for a Curry source file including all imported modules.+-}+module Main (main) where++import Curry.Base.Monad (runCYIO)++import Base.Messages+import Files.CymakePath (cymakeGreeting, cymakeVersion)++import CurryBuilder (buildCurry)+import CompilerOpts (Options (..), CymakeMode (..), getCompilerOpts, usage)++-- |The command line tool cymake+main :: IO ()+main = getCompilerOpts >>= cymake++-- |Invoke the curry builder w.r.t the command line arguments+cymake :: (String, Options, [String], [String]) -> IO ()+cymake (prog, opts, files, errs) = case optMode opts of+ ModeHelp -> printUsage prog+ ModeVersion -> printVersion+ ModeNumericVersion -> printNumericVersion+ ModeMake | not (null errs) -> badUsage prog errs+ | null files -> badUsage prog ["No input files"]+ | otherwise -> runCYIO (mapM_ (buildCurry opts) files) >>=+ either abortWithMessages continueWithMessages+ where continueWithMessages = warnOrAbort (optWarnOpts opts) . snd++-- |Print the usage information of the command line tool+printUsage :: String -> IO ()+printUsage prog = putStrLn $ usage prog++-- |Print the program version+printVersion :: IO ()+printVersion = putStrLn cymakeGreeting++-- |Print the numeric program version+printNumericVersion :: IO ()+printNumericVersion = putStrLn cymakeVersion++-- |Print errors and abort execution on bad parameters+badUsage :: String -> [String] -> IO ()+badUsage prog errs = do+ putErrsLn $ map (\ err -> prog ++ ": " ++ err) errs+ abortWith ["Try '" ++ prog ++ " --help' for more information"]
curry-frontend.cabal view
@@ -1,71 +1,207 @@-Name: curry-frontend-Version: 0.2.12-Cabal-Version: >= 1.6-Synopsis: Compile the functional logic language Curry to several+name: curry-frontend+version: 2.0.0+cabal-version: 2.0+synopsis: Compile the functional logic language Curry to several intermediate formats-Description: The Curry Frontend consists of the executable program "cymake".+description: The Curry front end consists of the executable program+ "curry-frontend". It is used by various backends to compile Curry programs to- an internal representation.+ an intermediate representation. The code is a stripped-down version of an early version of the Muenster Curry Compiler- (<http://danae.uni-muenster.de/~lux/curry/>)-Category: Language-License: OtherLicense-License-File: LICENSE-Author: Wolfgang Lux, Martin Engelke, Bernd Brassel, Holger Siegel-Maintainer: Björn Peemöller-Bug-Reports: http://www-ps.informatik.uni-kiel.de/redmine/projects/curry-frontend-Homepage: http://www.curry-language.org-Build-Type: Simple-Stability: experimental+ (<http://danae.uni-muenster.de/curry/>)+ which has been extended to produce different intermediate+ representations.+ For further information, please check+ <http://curry-language.org>+category: Language+license: BSD3+license-file: LICENSE+author: Wolfgang Lux, Martin Engelke, Bernd Brassel, Holger Siegel,+ Bjoern Peemoeller, Finn Teegen+maintainer: fte@informatik.uni-kiel.de+homepage: http://curry-language.org+build-type: Simple+stability: experimental -Extra-Source-Files: LIESMICH-Data-Files: src/currydoc.css+extra-source-files: README.md CHANGELOG.md -Flag split-syb- Description: Has the syb functionality been split into the package syb?- Default: True+data-dir: data+data-files: currysource.css -Executable cymake- hs-source-dirs: src- Main-is: cymake.hs- if flag(split-syb)- Build-Depends: base == 4.*, syb- else- Build-Depends: base == 3.*- Build-Depends:- curry-base >= 0.2.9 && < 0.3- , mtl, old-time, containers, pretty- ghc-options: -Wall- Other-Modules: Curry.Syntax.Lexer, Curry.Syntax.LexComb- Curry.Syntax.Parser, Curry.Syntax.LLParseComb- Curry.Syntax.ShowModule, Curry.Syntax.Pretty- Curry.Syntax, Curry.Syntax.Type- Curry.Syntax.Unlit,- Curry.Syntax.Utils,- Curry.Syntax.Frontend,- CurryBuilder, IL.Type- CurryCompilerOpts, Modules, Subst, Arity- CurryDeps, Eval, IL.Pretty, NestEnv, SyntaxCheck, Base- Exports, IL.Scope, SyntaxColoring, CurryEnv- IL.CurryToIL, OldScopeEnv, CurryHtml- IL.XML, PatchPrelude, TopEnv, CaseCompletion- Imports,- TypeCheck,- InterfaceCheck,- Types, PrecCheck- TypeSubst, GenAbstractCurry- Typing- GenFlatCurry, KindCheck, Qual- SCC, Utils- Lift, ScopeEnv, WarnCheck- Desugar,- Simplify+source-repository head+ type: git+ location: https://git.ps.informatik.uni-kiel.de/curry/curry-frontend.git -Library- hs-source-dirs: src- Build-Depends: filepath- Exposed-Modules:- Curry.Files.CymakePath- Other-Modules:- Paths_curry_frontend+library+ hs-source-dirs: src+ default-language: Haskell2010+ other-extensions: CPP, TemplateHaskell+ ghc-options: -Wall+ build-depends:+ base >= 4.11 && < 4.15+ , template-haskell >= 2.10 && < 2.16+ , extra >= 1.4.6 && < 1.8+ , transformers >= 0.5 && < 0.6+ , mtl >= 2.2 && < 2.3+ , directory >= 1.2 && < 1.4+ , filepath >= 1.4 && < 1.5+ , file-embed >= 0.0 && < 0.1+ , containers >= 0.6 && < 0.7+ , set-extra >= 1.4 && < 1.5+ , bytestring >= 0.10 && < 0.11+ , process >= 1.6 && < 1.7+ , network-uri >= 2.6 && < 2.7+ , pretty >= 1.1 && < 1.2+ , binary >= 0.8 && < 0.9+ , time >= 1.9 && < 2.0+ , parsec >= 3.1 && < 3.2+ exposed-modules:+ Base.AnnotExpr+ , Base.CurryKinds+ , Base.CurryTypes+ , Base.Expr+ , Base.KindSubst+ , Base.Kinds+ , Base.Messages+ , Base.NestEnv+ , Base.PrettyKinds+ , Base.PrettyTypes+ , Base.SCC+ , Base.Subst+ , Base.TopEnv+ , Base.TypeExpansion+ , Base.TypeSubst+ , Base.Types+ , Base.Typing+ , Base.Utils+ , Checks+ , Checks.DeriveCheck+ , Checks.ExportCheck+ , Checks.ExtensionCheck+ , Checks.ImportSyntaxCheck+ , Checks.InstanceCheck+ , Checks.InterfaceCheck+ , Checks.InterfaceSyntaxCheck+ , Checks.KindCheck+ , Checks.PrecCheck+ , Checks.SyntaxCheck+ , Checks.TypeCheck+ , Checks.TypeSyntaxCheck+ , Checks.WarnCheck+ , Curry.AbstractCurry+ , Curry.AbstractCurry.Files+ , Curry.AbstractCurry.Type+ , Curry.Base.Ident+ , Curry.Base.LexComb+ , Curry.Base.LLParseComb+ , Curry.Base.Message+ , Curry.Base.Monad+ , Curry.Base.Position+ , Curry.Base.Pretty+ , Curry.Base.Span+ , Curry.Base.SpanInfo+ , Curry.CondCompile.Parser+ , Curry.CondCompile.Transform+ , Curry.CondCompile.Type+ , Curry.Files.Filenames+ , Curry.Files.PathUtils+ , Curry.Files.Unlit+ , Curry.FlatCurry+ , Curry.FlatCurry.Files+ , Curry.FlatCurry.Goodies+ , Curry.FlatCurry.InterfaceEquivalence+ , Curry.FlatCurry.Pretty+ , Curry.FlatCurry.Type+ , Curry.FlatCurry.Typeable+ , Curry.FlatCurry.Annotated.Goodies+ , Curry.FlatCurry.Annotated.Type+ , Curry.FlatCurry.Typed.Goodies+ , Curry.FlatCurry.Typed.Type+ , Curry.Syntax+ , Curry.Syntax.Extension+ , Curry.Syntax.InterfaceEquivalence+ , Curry.Syntax.Lexer+ , Curry.Syntax.Parser+ , Curry.Syntax.Pretty+ , Curry.Syntax.ShowModule+ , Curry.Syntax.Type+ , Curry.Syntax.Utils+ , CompilerEnv+ , CompilerOpts+ , CondCompile+ , CurryBuilder+ , CurryDeps+ , Env.Class+ , Env.Instance+ , Env.Interface+ , Env.ModuleAlias+ , Env.OpPrec+ , Env.Type+ , Env.TypeConstructor+ , Env.Value+ , Exports+ , Files.CymakePath+ , Generators+ , Generators.GenAbstractCurry+ , Generators.GenFlatCurry+ , Generators.GenTypedFlatCurry+ , Generators.GenAnnotatedFlatCurry+ , Html.CurryHtml+ , Html.SyntaxColoring+ , IL+ , IL.Pretty+ , IL.ShowModule+ , IL.Type+ , IL.Typing+ , Imports+ , Interfaces+ , Modules+ , TokenStream+ , Transformations+ , Transformations.CaseCompletion+ , Transformations.CurryToIL+ , Transformations.Derive+ , Transformations.Desugar+ , Transformations.Dictionary+ , Transformations.Lift+ , Transformations.Newtypes+ , Transformations.Qual+ , Transformations.Simplify+ , Paths_curry_frontend+ autogen-modules:+ Paths_curry_frontend++executable curry-frontend+ hs-source-dirs: app+ main-is: cymake.hs+ default-language: Haskell2010+ ghc-options: -Wall+ build-depends:+ base >= 4.11+ , curry-frontend++test-suite test-frontend+ type: detailed-0.9+ hs-source-dirs: test+ test-module: TestFrontend+ default-language: Haskell2010+ other-extensions: CPP, TemplateHaskell+ ghc-options: -Wall+ build-depends:+ base >= 4.11+ , Cabal >= 1.20+ , template-haskell >= 2.10+ , extra >= 1.4.6+ , transformers+ , mtl+ , directory >= 1.2.0.1+ , filepath+ , file-embed+ , containers+ , set-extra+ , bytestring >= 0.10+ , process+ , network-uri >= 2.6+ , pretty+ , curry-frontend
+ data/currysource.css view
@@ -0,0 +1,95 @@+:root {+ --link-bg-color: lightyellow;+ --line-number-color: grey;+ --pragma-color: green;+ --comment-color: green;+ --keyword-color: blue;+ --symbol-color: red;+ --type-color: orange;+ --cons-color: magenta;+ --label-color: darkgreen;+ --func-color: purple;+ --ident-color: black;+ --module-color: brown;+ --number-color: teal;+ --string-color: maroon;+ --char-color: maroon;+ color-scheme: light dark;+}++body {+ font-family: monospace;+ text-size-adjust: none;+ -moz-text-size-adjust: none;+ -ms-text-size-adjust: none;+ -webkit-text-size-adjust: none;+}++table {+ border-collapse: collapse;+}++/* Hyperlinks */+a:link,+a:visited,+a:active {+ background: var(--link-bg-color);+ text-decoration: none;+}++/* Line numbers */+.line-numbers {+ border-right: 1px solid var(--line-number-color);+ color: var(--line-number-color);+ min-width: 5ch;+ padding-right: 1em;+ text-align: right;+}++/* Source code */+.source-code {+ padding-left: 1em;+}++/* Code highlighting */+.pragma { color: var(--pragma-color) }+.comment { color: var(--comment-color) }+.keyword { color: var(--keyword-color) }+.symbol { color: var(--symbol-color) }+.type { color: var(--type-color) }+.cons { color: var(--cons-color) }+.label { color: var(--label-color) }+.func { color: var(--func-color) }+.ident { color: var(--ident-color) }+.module { color: var(--module-color) }+.number { color: var(--number-color) }+.string { color: var(--string-color) }+.char { color: var(--char-color) }++@supports not (color-scheme: light dark) {+ @media (prefers-color-scheme: dark) {+ html {+ background: hsl(0, 0%, 12%);+ color: white;+ }+ }+}++@media (prefers-color-scheme: dark) {+ :root {+ --link-bg-color: hsl(0, 0%, 17%);+ --pragma-color: hsl(0, 0%, 60%);+ --comment-color: hsl(0, 0%, 60%);+ --keyword-color: hsl(300, 66%, 70%);+ --symbol-color: hsl(0, 66%, 70%);+ --type-color: hsl(60, 66%, 70%);+ --cons-color: hsl(330, 66%, 70%);+ --label-color: hsl(240, 66%, 70%);+ --func-color: hsl(200, 66%, 70%);+ --ident-color: hsl(0, 0%, 85%);+ --module-color: hsl(20, 66%, 70%);+ --number-color: hsl(180, 66%, 70%);+ --string-color: hsl(120, 66%, 70%);+ --char-color: hsl(120, 66%, 70%);+ }+}
− src/Arity.hs
@@ -1,133 +0,0 @@---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Arity - provides functions for expanding the arity environment 'ArityEnv'--- (see Module "Base")------ September 2005,--- Martin Engelke (men@informatik.uni-kiel.de)----module Arity (bindArities) where--import Curry.Base.Ident-import Curry.Syntax--import Base(ArityEnv, bindArity)-------------------------------------------------------------------------------------- Expands the arity envorinment with (global / local) function arities and--- constructor arities-bindArities :: ArityEnv -> Module -> ArityEnv-bindArities aEnv (Module mid _ decls)- = foldl (visitDecl mid) aEnv decls------------------------------------------------------------------------------------visitDecl :: ModuleIdent -> ArityEnv -> Decl -> ArityEnv-visitDecl mid aEnv (DataDecl _ _ _ cdecls)- = foldl (visitConstrDecl mid) aEnv cdecls-visitDecl mid aEnv (ExternalDecl _ _ _ id texpr)- = bindArity mid id (typeArity texpr) aEnv-visitDecl mid aEnv (FunctionDecl _ id equs)- = let (Equation _ lhs rhs) = head equs- in visitRhs mid (visitLhs mid id aEnv lhs) rhs-visitDecl _ aEnv _ = aEnv---visitConstrDecl :: ModuleIdent -> ArityEnv -> ConstrDecl -> ArityEnv-visitConstrDecl mid aEnv (ConstrDecl _ _ id texprs)- = bindArity mid id (length texprs) aEnv-visitConstrDecl mid aEnv (ConOpDecl _ _ _ id _)- = bindArity mid id 2 aEnv---visitLhs :: ModuleIdent -> Ident -> ArityEnv -> Lhs -> ArityEnv-visitLhs mid _ aEnv (FunLhs id params)- = bindArity mid id (length params) aEnv-visitLhs mid id aEnv (OpLhs _ _ _)- = bindArity mid id 2 aEnv-visitLhs _ _ aEnv _ = aEnv---visitRhs :: ModuleIdent -> ArityEnv -> Rhs -> ArityEnv-visitRhs mid aEnv (SimpleRhs _ expr decls)- = foldl (visitDecl mid) (visitExpression mid aEnv expr) decls-visitRhs mid aEnv (GuardedRhs cexprs decls)- = foldl (visitDecl mid) (foldl (visitCondExpr mid) aEnv cexprs) decls---visitCondExpr :: ModuleIdent -> ArityEnv -> CondExpr -> ArityEnv-visitCondExpr mid aEnv (CondExpr _ cond expr)- = visitExpression mid (visitExpression mid aEnv expr) cond---visitExpression :: ModuleIdent -> ArityEnv -> Expression -> ArityEnv-visitExpression mid aEnv (Paren expr)- = visitExpression mid aEnv expr-visitExpression mid aEnv (Typed expr _)- = visitExpression mid aEnv expr-visitExpression mid aEnv (Tuple _ exprs)- = foldl (visitExpression mid) aEnv exprs-visitExpression mid aEnv (List _ exprs)- = foldl (visitExpression mid) aEnv exprs-visitExpression mid aEnv (ListCompr _ expr stmts)- = foldl (visitStatement mid) (visitExpression mid aEnv expr) stmts-visitExpression mid aEnv (EnumFrom expr)- = visitExpression mid aEnv expr-visitExpression mid aEnv (EnumFromThen expr1 expr2)- = foldl (visitExpression mid) aEnv [expr1,expr2]-visitExpression mid aEnv (EnumFromTo expr1 expr2)- = foldl (visitExpression mid) aEnv [expr1,expr2]-visitExpression mid aEnv (EnumFromThenTo expr1 expr2 expr3)- = foldl (visitExpression mid) aEnv [expr1,expr2,expr3]-visitExpression mid aEnv (UnaryMinus _ expr)- = visitExpression mid aEnv expr-visitExpression mid aEnv (Apply expr1 expr2)- = foldl (visitExpression mid) aEnv [expr1,expr2]-visitExpression mid aEnv (InfixApply expr1 _ expr2)- = foldl (visitExpression mid) aEnv [expr1,expr2]-visitExpression mid aEnv (LeftSection expr _)- = visitExpression mid aEnv expr-visitExpression mid aEnv (RightSection _ expr)- = visitExpression mid aEnv expr-visitExpression mid aEnv (Lambda _ _ expr)- = visitExpression mid aEnv expr-visitExpression mid aEnv (Let decls expr)- = foldl (visitDecl mid) (visitExpression mid aEnv expr) decls-visitExpression mid aEnv (Do stmts expr)- = foldl (visitStatement mid) (visitExpression mid aEnv expr) stmts-visitExpression mid aEnv (IfThenElse _ expr1 expr2 expr3)- = foldl (visitExpression mid) aEnv [expr1,expr2,expr3]-visitExpression mid aEnv (Case _ expr alts)- = visitExpression mid (foldl (visitAlt mid) aEnv alts) expr-visitExpression _ aEnv _ = aEnv---visitStatement :: ModuleIdent -> ArityEnv -> Statement -> ArityEnv-visitStatement mid aEnv (StmtExpr _ expr)- = visitExpression mid aEnv expr-visitStatement mid aEnv (StmtDecl decls)- = foldl (visitDecl mid) aEnv decls-visitStatement mid aEnv (StmtBind _ _ expr)- = visitExpression mid aEnv expr---visitAlt :: ModuleIdent -> ArityEnv -> Alt -> ArityEnv-visitAlt mid aEnv (Alt _ _ rhs)- = visitRhs mid aEnv rhs--------------------------------------------------------------------------------------- Computes the function arity using a type expression-typeArity :: TypeExpr -> Int-typeArity (ArrowType _ t2) = 1 + typeArity t2-typeArity _ = 0------------------------------------------------------------------------------------------------------------------------------------------------------------------
− src/Base.lhs
@@ -1,557 +0,0 @@-% $Id: Base.lhs,v 1.77 2004/02/15 22:10:25 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{Base.lhs}-\section{Common Definitions for the Compiler}--The module Base implements the anti-pattern 'God-object'.-By providing definitions for various unrelated phases of the-compiler, it irrevocably turns the module structure into spaghetti.-(hsi, 2009)--\begin{verbatim}--> module Base where--> import Data.List-> import Control.Monad-> import Data.Maybe-> import qualified Data.Map as Map--> import Curry.Base.Ident -> import Curry.Base.Position-> import Types-> import qualified Curry.Syntax as CS-> import Curry.Syntax.Utils-> import TopEnv-> import Utils----\end{verbatim}-\paragraph{Types}-The functions \texttt{toType}, \texttt{toTypes}, and \texttt{fromType}-convert Curry type expressions into types and vice versa. The-functions \texttt{qualifyType} and \texttt{unqualifyType} add and-remove module qualifiers in a type, respectively.--When Curry type expression are converted with \texttt{toType} or-\texttt{toTypes}, type variables are assigned ascending indices in the-order of their occurrence. It is possible to pass a list of additional-type variables to both functions which are assigned indices before-those variables occurring in the type. This allows preserving the-order of type variables in the left hand side of a type declaration.-\begin{verbatim}--> toQualType :: ModuleIdent -> [Ident] -> CS.TypeExpr -> Type-> toQualType m tvs = qualifyType m . toType tvs--> toQualTypes :: ModuleIdent -> [Ident] -> [CS.TypeExpr] -> [Type]-> toQualTypes m tvs = map (qualifyType m) . toTypes tvs--> toType :: [Ident] -> CS.TypeExpr -> Type-> toType tvs ty = toType' (Map.fromList (zip (tvs ++ tvs') [0..])) ty-> where tvs' = [tv | tv <- nub (fv ty), tv `notElem` tvs]--> toTypes :: [Ident] -> [CS.TypeExpr] -> [Type]-> toTypes tvs tys = map (toType' (Map.fromList (zip (tvs ++ tvs') [0..]))) tys-> where tvs' = [tv | tv <- nub (concatMap fv tys), tv `notElem` tvs]--> toType' :: Map.Map Ident Int -> CS.TypeExpr -> Type-> toType' tvs (CS.ConstructorType tc tys) =-> TypeConstructor tc (map (toType' tvs) tys)-> toType' tvs (CS.VariableType tv) =-> maybe (internalError ("toType " ++ show tv)) TypeVariable (Map.lookup tv tvs)-> toType' tvs (CS.TupleType tys)-> | null tys = TypeConstructor (qualify unitId) []-> | otherwise = TypeConstructor (qualify (tupleId (length tys'))) tys'-> where tys' = map (toType' tvs) tys-> toType' tvs (CS.ListType ty) = TypeConstructor (qualify listId) [toType' tvs ty]-> toType' tvs (CS.ArrowType ty1 ty2) =-> TypeArrow (toType' tvs ty1) (toType' tvs ty2)-> toType' tvs (CS.RecordType fs rty) =-> TypeRecord (concatMap (\ (ls,ty) -> map (\l -> (l, toType' tvs ty)) ls) fs)-> (maybe Nothing -> (\ty -> case toType' tvs ty of-> TypeVariable tv -> Just tv -> _ -> internalError ("toType " ++ show ty))-> rty)--> fromQualType :: ModuleIdent -> Type -> CS.TypeExpr-> fromQualType m = fromType . unqualifyType m--> fromType :: Type -> CS.TypeExpr-> fromType (TypeConstructor tc tys)-> | isTupleId c = CS.TupleType tys'-> | c == listId && length tys == 1 = CS.ListType (head tys')-> | c == unitId && null tys = CS.TupleType []-> | otherwise = CS.ConstructorType tc tys'-> where c = unqualify tc-> tys' = map fromType tys-> fromType (TypeVariable tv) =-> CS.VariableType (if tv >= 0 then nameSupply !! tv-> else mkIdent ('_' : show (-tv)))-> fromType (TypeConstrained tys _) = fromType (head tys)-> fromType (TypeArrow ty1 ty2) = CS.ArrowType (fromType ty1) (fromType ty2)-> fromType (TypeSkolem k) = CS.VariableType (mkIdent ("_?" ++ show k))-> fromType (TypeRecord fs rty) = -> CS.RecordType (map (\ (l,ty) -> ([l], fromType ty)) fs)-> (maybe Nothing (Just . fromType . TypeVariable) rty)----\end{verbatim}-\paragraph{Interfaces}-The compiler maintains a global environment holding all (directly or-indirectly) imported interfaces.--The function \texttt{bindFlatInterface} transforms FlatInterface-information (type \texttt{FlatCurry.Prog} to MCC interface declarations-(type \texttt{CurrySyntax.IDecl}. This is necessary to process-FlatInterfaces instead of ".icurry" files when using MCC as frontend-for PAKCS.-\begin{verbatim}--> type ModuleEnv = Map.Map ModuleIdent [CS.IDecl]--> lookupModule :: ModuleIdent -> ModuleEnv -> Maybe [CS.IDecl]-> lookupModule = Map.lookup---\end{verbatim}-\paragraph{Type constructors}-For all defined types the compiler must maintain kind information. At-present, Curry does not support type classes. Therefore its type-language is first order and the only information that must be recorded-is the arity of each type. For algebraic data types and renaming types-the compiler also records all data constructors belonging to that-type, for alias types the type expression to be expanded is saved. In-order to manage the import and export of types, the names of the-original definitions are also recorded. On import two types are-considered equal if their original names match.--The information for a data constructor comprises the number of-existentially quantified type variables and the list of the argument-types. Note that renaming type constructors have only one type-argument.--Importing and exporting algebraic data types and renaming types is-complicated by the fact that the constructors of the type may be-(partially) hidden in the interface. This facilitates the definition-of abstract data types. An abstract type is always represented as a-data type without constructors in the interface regardless of whether-it is defined as a data type or as a renaming type. When only some-constructors of a data type are hidden, those constructors are-replaced by underscores in the interface. Furthermore, if the-right-most constructors of a data type are hidden, they are not-exported at all in order to make the interface more stable against-changes which are private to the module.-\begin{verbatim}--> data TypeInfo = DataType QualIdent Int [Maybe (Data [Type])]-> | RenamingType QualIdent Int (Data Type)-> | AliasType QualIdent Int Type-> deriving Show--> data Data a = Data Ident Int a deriving Show--> instance Entity TypeInfo where-> origName (DataType tc _ _) = tc-> origName (RenamingType tc _ _) = tc-> origName (AliasType tc _ _) = tc-> merge (DataType tc n cs) (DataType tc' _ cs')-> | tc == tc' = Just (DataType tc n (mergeData cs cs'))-> where mergeData ds [] = ds-> mergeData [] ds = ds-> mergeData (d:ds) (d':ds') = d `mplus` d' : mergeData ds ds'-> merge (DataType tc n _) (RenamingType tc' _ nc)-> | tc == tc' = Just (RenamingType tc n nc)-> merge (RenamingType tc n nc) (DataType tc' _ _)-> | tc == tc' = Just (RenamingType tc n nc)-> merge (RenamingType tc n nc) (RenamingType tc' _ _)-> | tc == tc' = Just (RenamingType tc n nc)-> merge (AliasType tc n ty) (AliasType tc' _ _)-> | tc == tc' = Just (AliasType tc n ty)-> merge _ _ = Nothing--> tcArity :: TypeInfo -> Int-> tcArity (DataType _ n _) = n-> tcArity (RenamingType _ n _) = n-> tcArity (AliasType _ n _) = n--\end{verbatim}-Types can only be defined on the top-level; no nested environments are-needed for them. Tuple types must be handled as a special case because-there is an infinite number of potential tuple types making it-impossible to insert them into the environment in advance.-\begin{verbatim}--> type TCEnv = TopEnv TypeInfo--> bindTypeInfo :: (QualIdent -> Int -> a -> TypeInfo) -> ModuleIdent-> -> Ident -> [Ident] -> a -> TCEnv -> TCEnv-> bindTypeInfo f m tc tvs x -> = bindTopEnv "Base.bindTypeInfo" tc t -> . qualBindTopEnv "Base.bindTypeInfo" tc' t-> where tc' = qualifyWith m tc-> t = f tc' (length tvs) x--> lookupTC :: Ident -> TCEnv -> [TypeInfo]-> lookupTC tc tcEnv = lookupTopEnv tc tcEnv ++! lookupTupleTC tc--> qualLookupTC :: QualIdent -> TCEnv -> [TypeInfo]-> qualLookupTC tc tcEnv =-> qualLookupTopEnv tc tcEnv ++! lookupTupleTC (unqualify tc)--> lookupTupleTC :: Ident -> [TypeInfo]-> lookupTupleTC tc-> | isTupleId tc = [tupleTCs !! (tupleArity tc - 2)]-> | otherwise = []--> tupleTCs :: [TypeInfo]-> tupleTCs = map typeInfo tupleData-> where typeInfo (Data c _ tys) =-> DataType (qualifyWith preludeMIdent c) (length tys)-> [Just (Data c 0 tys)]--> tupleData :: [Data [Type]]-> tupleData = [Data (tupleId n) 0 (take n tvs) | n <- [2..]]-> where tvs = map typeVar [0..]--\end{verbatim}-\paragraph{Function and constructor types}-In order to test the type correctness of a module, the compiler needs-to determine the type of every data constructor, function,-variable, record and label in the module. -For the purpose of type checking there is no-need for distinguishing between variables and functions. For all objects-their original names and their types are saved. Functions also-contain arity information. Labels currently contain the name of their-defining record. On import two values-are considered equal if their original names match.-\begin{verbatim}--> data ValueInfo = DataConstructor QualIdent ExistTypeScheme-> | NewtypeConstructor QualIdent ExistTypeScheme-> | Value QualIdent TypeScheme-> | Label QualIdent QualIdent TypeScheme-> -- Label <label> <record name> <type>-> deriving Show--> instance Entity ValueInfo where-> origName (DataConstructor origName _) = origName-> origName (NewtypeConstructor origName _) = origName-> origName (Value origName _) = origName-> origName (Label origName _ _) = origName-> -> merge (Label l r ty) (Label l' r' ty')-> | l == l' && r == r' = Just (Label l r ty)-> | otherwise = Nothing-> merge x y-> | origName x == origName y = Just x-> | otherwise = Nothing---\end{verbatim}-Even though value declarations may be nested, the compiler uses only-flat environments for saving type information. This is possible-because all identifiers are renamed by the compiler. Here we need-special cases for handling tuple constructors.--\em{Note:} the function \texttt{qualLookupValue} has been extended to-allow the usage of the qualified list constructor \texttt{(Prelude.:)}.-\begin{verbatim}--> type ValueEnv = TopEnv ValueInfo--> bindGlobalInfo :: (QualIdent -> a -> ValueInfo) -> ModuleIdent -> Ident -> a-> -> ValueEnv -> ValueEnv-> bindGlobalInfo f m c ty -> = bindTopEnv "Base.bindGlobalInfo" c v -> . qualBindTopEnv "Base.bindGlobalInfo" c' v-> where c' = qualifyWith m c-> v = f c' ty--> bindFun :: ModuleIdent -> Ident -> TypeScheme -> ValueEnv -> ValueEnv-> bindFun m f ty tyEnv-> | uniqueId f == 0 -> = bindTopEnv "Base.bindFun" f v (qualBindTopEnv "Base.bindFun" f' v tyEnv)-> | otherwise = bindTopEnv "Base.bindFun" f v tyEnv-> where f' = qualifyWith m f-> v = Value f' ty--> rebindFun :: ModuleIdent -> Ident -> TypeScheme -> ValueEnv -> ValueEnv-> rebindFun m f ty-> | uniqueId f == 0 = rebindTopEnv f v . qualRebindTopEnv f' v-> | otherwise = rebindTopEnv f v-> where f' = qualifyWith m f-> v = Value f' ty--> bindLabel :: Ident -> QualIdent -> TypeScheme -> ValueEnv -> ValueEnv-> bindLabel l r ty tyEnv = bindTopEnv "Base.bindLabel" l v tyEnv-> where v = Label (qualify l) r ty--> lookupValue :: Ident -> ValueEnv -> [ValueInfo]-> lookupValue x tyEnv = lookupTopEnv x tyEnv ++! lookupTuple x--> qualLookupValue :: QualIdent -> ValueEnv -> [ValueInfo]-> qualLookupValue x tyEnv =-> qualLookupTopEnv x tyEnv -> ++! qualLookupCons x tyEnv-> ++! lookupTuple (unqualify x)--> qualLookupCons :: QualIdent -> ValueEnv -> [ValueInfo]-> qualLookupCons x tyEnv-> | maybe False ((==) preludeMIdent) mmid && id == consId-> = qualLookupTopEnv (qualify id) tyEnv-> | otherwise = []-> where (mmid, id) = (qualidMod x, qualidId x)--> lookupTuple :: Ident -> [ValueInfo]-> lookupTuple c-> | isTupleId c = [tupleDCs !! (tupleArity c - 2)]-> | otherwise = []--> tupleDCs :: [ValueInfo]-> tupleDCs = map dataInfo tupleTCs-> where dataInfo (DataType tc tvs [Just (Data c _ tys)]) =-> DataConstructor (qualUnqualify preludeMIdent tc)-> (ForAllExist (length tys) 0-> (foldr TypeArrow (tupleType tys) tys))--\end{verbatim}-\paragraph{Arity}-In order to generate correct FlatCurry application it is necessary-to define the number of arguments as the arity value (instead of-using the arity computed from the type). For this reason the compiler-needs a table containing the information for all known functions-and constructors. -\begin{verbatim}--> type ArityEnv = TopEnv ArityInfo--> data ArityInfo = ArityInfo QualIdent Int deriving Show--> instance Entity ArityInfo where-> origName (ArityInfo origName _) = origName--> bindArity :: ModuleIdent -> Ident -> Int -> ArityEnv -> ArityEnv-> bindArity mid id arity aEnv-> | uniqueId id == 0 -> = bindTopEnv "Base.bindArity" id arityInfo -> (qualBindTopEnv "Base.bindArity" qid arityInfo aEnv)-> | otherwise -> = bindTopEnv "Base.bindArity" id arityInfo aEnv-> where-> qid = qualifyWith mid id-> arityInfo = ArityInfo qid arity--> lookupArity :: Ident -> ArityEnv -> [ArityInfo]-> lookupArity id aEnv = lookupTopEnv id aEnv ++! lookupTupleArity id--> qualLookupArity :: QualIdent -> ArityEnv -> [ArityInfo]-> qualLookupArity qid aEnv = qualLookupTopEnv qid aEnv-> ++! qualLookupConsArity qid aEnv-> ++! lookupTupleArity (unqualify qid)--> qualLookupConsArity :: QualIdent -> ArityEnv -> [ArityInfo]-> qualLookupConsArity qid aEnv-> | maybe False ((==) preludeMIdent) mmid && id == consId-> = qualLookupTopEnv (qualify id) aEnv-> | otherwise-> = []-> where (mmid, id) = (qualidMod qid, qualidId qid)--> lookupTupleArity :: Ident -> [ArityInfo]-> lookupTupleArity id -> | isTupleId id -> = [ArityInfo (qualifyWith preludeMIdent id) (tupleArity id)]-> | otherwise-> = []--\end{verbatim}-\paragraph{Module alias}-\begin{verbatim}--> type ImportEnv = Map.Map ModuleIdent ModuleIdent--> bindAlias :: CS.Decl -> ImportEnv -> ImportEnv-> bindAlias (CS.ImportDecl _ mid _ mmid _)-> = Map.insert mid (fromMaybe mid mmid)--> lookupAlias :: ModuleIdent -> ImportEnv -> Maybe ModuleIdent-> lookupAlias = Map.lookup--> sureLookupAlias :: ModuleIdent -> ImportEnv -> ModuleIdent-> sureLookupAlias m = fromMaybe m . lookupAlias m---\end{verbatim}-\paragraph{Operator precedences}-In order to parse infix expressions correctly, the compiler must know-the precedence and fixity of each operator. Operator precedences are-associated with entities and will be checked after renaming was-applied. Nevertheless, we need to save precedences for ambiguous names-in order to handle them correctly while computing the exported-interface of a module.--If no fixity is assigned to an operator, it will be given the default-precedence 9 and assumed to be a left-associative operator.--\em{Note:} this modified version uses Haskell type \texttt{Integer}-for representing the precedence. This change had to be done due to the-introduction of unlimited integer constants in the parser / lexer.-\begin{verbatim}--> data OpPrec = OpPrec CS.Infix Integer deriving Eq--> instance Show OpPrec where-> showsPrec _ (OpPrec fix p) = showString (assoc fix) . shows p-> where assoc CS.InfixL = "left "-> assoc CS.InfixR = "right "-> assoc CS.Infix = "non-assoc "--> defaultP :: OpPrec-> defaultP = OpPrec CS.InfixL 9--\end{verbatim}-The lookup functions for the environment which maintains the operator-precedences are simpler than for the type and value environments-because they do not need to handle tuple constructors.-\begin{verbatim}--> data PrecInfo = PrecInfo QualIdent OpPrec deriving (Eq,Show)--> instance Entity PrecInfo where-> origName (PrecInfo op _) = op--> type PEnv = TopEnv PrecInfo--> bindP :: ModuleIdent -> Ident -> OpPrec -> PEnv -> PEnv-> bindP m op p-> | uniqueId op == 0 -> = bindTopEnv "Base.bindP" op info . qualBindTopEnv "Base.bindP" op' info-> | otherwise = bindTopEnv "Base.bindP" op info-> where op' = qualifyWith m op-> info = PrecInfo op' p--> lookupP :: Ident -> PEnv -> [PrecInfo]-> lookupP = lookupTopEnv--> qualLookupP :: QualIdent -> PEnv -> [PrecInfo]-> qualLookupP = qualLookupTopEnv--\end{verbatim}-\paragraph{Evaluation modes}-The compiler has to collect the evaluation annotations for a program-in an environment. As these annotations affect only local declarations,-a flat environment mapping unqualified names onto annotations is-sufficient.-\begin{verbatim}--> type EvalEnv = Map.Map Ident CS.EvalAnnotation---\end{verbatim}-\paragraph{Predefined types}-The list and unit data types must be predefined because their-definitions-\begin{verbatim}-data () = ()-data [] a = [] | a : [a]-\end{verbatim}-are not allowed by Curry's syntax. The corresponding types-are available in the environments \texttt{initTCEnv} and-\texttt{initDCEnv}. In addition, the precedence of the (infix) list-constructor is available in the environment \texttt{initPEnv}.--Note that only the unqualified names are predefined. This is correct,-because neither \texttt{Prelude.()} nor \texttt{Prelude.[]} are valid-identifiers.-\begin{verbatim}--> initPEnv :: PEnv-> initPEnv =-> predefTopEnv qConsId (PrecInfo qConsId (OpPrec CS.InfixR 5)) emptyTopEnv--> initTCEnv :: TCEnv-> initTCEnv = foldr (uncurry predefTC) emptyTopEnv predefTypes-> where predefTC (TypeConstructor tc tys) =-> predefTopEnv (qualify (unqualify tc)) .-> DataType tc (length tys) . map Just--> initDCEnv :: ValueEnv-> initDCEnv =-> foldr (uncurry predefDC) emptyTopEnv-> [(c,constrType (polyType ty) n' tys)-> | (ty,cs) <- predefTypes, Data c n' tys <- cs]-> where predefDC c ty = predefTopEnv c' (DataConstructor c' ty)-> where c' = qualify c-> constrType (ForAll n ty) n' = ForAllExist n n' . foldr TypeArrow ty--> initAEnv :: ArityEnv-> initAEnv-> = foldr bindPredefArity emptyTopEnv (concatMap snd predefTypes)-> where-> bindPredefArity (Data id _ ts)-> = bindArity preludeMIdent id (length ts)--> initIEnv :: ImportEnv-> initIEnv = Map.empty--> predefTypes :: [(Type,[Data [Type]])]-> predefTypes =-> let a = typeVar 0 in [-> (unitType, [Data unitId 0 []]),-> (listType a, [Data nilId 0 [],Data consId 0 [a,listType a]])-> ]---\end{verbatim}--\paragraph{Miscellany}-Error handling-\begin{verbatim}--> errorAt :: Position -> String -> a-> errorAt p msg = error ("\n" ++ show p ++ ": " ++ msg)--> errorAt' :: (Position,String) -> a-> errorAt' = uncurry errorAt--> internalError :: String -> a-> internalError what = error ("internal error: " ++ what)--\end{verbatim}-Name supply for the generation of (type) variable names.-\begin{verbatim}--> nameSupply :: [Ident]-> nameSupply = map mkIdent [c:showNum i | i <- [0..], c <- ['a'..'z']]-> where showNum 0 = ""-> showNum n = show n--\end{verbatim}-\ToDo{The \texttt{nameSupply} should respect the current case mode, -i.e., use upper case for variables in Prolog mode.}--\end{verbatim}-The function \texttt{findDouble} checks whether a list of entities is-linear, i.e., if every entity in the list occurs only once. If it is-non-linear, the first offending object is returned.-\begin{verbatim}--> findDouble :: Eq a => [a] -> Maybe a-> findDouble (x:xs)-> | x `elem` xs = Just x-> | otherwise = findDouble xs-> findDouble [] = Nothing--\end{verbatim}---
+ src/Base/AnnotExpr.hs view
@@ -0,0 +1,124 @@+{- |+ Module : $Header$+ Description : Extraction of free qualified annotated variables+ Copyright : (c) 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ TODO+-}+module Base.AnnotExpr (QualAnnotExpr (..)) where++import qualified Data.Set as Set (fromList, notMember)++import Curry.Base.Ident+import Curry.Base.SpanInfo+import Curry.Syntax++import Base.Expr+import Base.Types+import Base.Typing++class QualAnnotExpr e where+ -- |Free qualified annotated variables in an 'Expr'+ qafv :: ModuleIdent -> e Type -> [(Type, Ident)]++-- The 'Decl' instance of 'QualAnnotExpr' returns all free+-- variables on the right hand side, regardless of whether they are bound+-- on the left hand side. This is more convenient as declarations are+-- usually processed in a declaration group where the set of free+-- variables cannot be computed independently for each declaration.++instance QualAnnotExpr Decl where+ qafv m (FunctionDecl _ _ _ eqs) = concatMap (qafv m) eqs+ qafv m (PatternDecl _ _ rhs) = qafv m rhs+ qafv m (ClassDecl _ _ _ _ _ ds) = concatMap (qafv m) ds+ qafv m (InstanceDecl _ _ _ _ _ ds) = concatMap (qafv m) ds+ qafv _ _ = []++instance QualAnnotExpr Equation where+ qafv m (Equation _ lhs rhs) = filterBv lhs $ qafv m lhs ++ qafv m rhs++instance QualAnnotExpr Lhs where+ qafv m = concatMap (qafv m) . snd . flatLhs++instance QualAnnotExpr Rhs where+ qafv m (SimpleRhs _ _ e ds) = filterBv ds $ qafv m e ++ concatMap (qafv m) ds+ qafv m (GuardedRhs _ _ es ds) =+ filterBv ds $ concatMap (qafv m) es ++ concatMap (qafv m) ds++instance QualAnnotExpr CondExpr where+ qafv m (CondExpr _ g e) = qafv m g ++ qafv m e++instance QualAnnotExpr Expression where+ qafv _ (Literal _ _ _) = []+ qafv m (Variable _ ty v) =+ maybe [] (return . (\v' -> (ty, v'))) $ localIdent m v+ qafv _ (Constructor _ _ _) = []+ qafv m (Paren _ e) = qafv m e+ qafv m (Typed _ e _) = qafv m e+ qafv m (Record _ _ _ fs) = concatMap (qafvField m) fs+ qafv m (RecordUpdate _ e fs) = qafv m e ++ concatMap (qafvField m) fs+ qafv m (Tuple _ es) = concatMap (qafv m) es+ qafv m (List _ _ es) = concatMap (qafv m) es+ qafv m (ListCompr _ e qs) = foldr (qafvStmt m) (qafv m e) qs+ qafv m (EnumFrom _ e) = qafv m e+ qafv m (EnumFromThen _ e1 e2) = qafv m e1 ++ qafv m e2+ qafv m (EnumFromTo _ e1 e2) = qafv m e1 ++ qafv m e2+ qafv m (EnumFromThenTo _ e1 e2 e3) = qafv m e1 ++ qafv m e2 ++ qafv m e3+ qafv m (UnaryMinus _ e) = qafv m e+ qafv m (Apply _ e1 e2) = qafv m e1 ++ qafv m e2+ qafv m (InfixApply _ e1 op e2) = qafv m op ++ qafv m e1 ++ qafv m e2+ qafv m (LeftSection _ e op) = qafv m op ++ qafv m e+ qafv m (RightSection _ op e) = qafv m op ++ qafv m e+ qafv m (Lambda _ ts e) = filterBv ts $ qafv m e+ qafv m (Let _ _ ds e) =+ filterBv ds $ concatMap (qafv m) ds ++ qafv m e+ qafv m (Do _ _ sts e) = foldr (qafvStmt m) (qafv m e) sts+ qafv m (IfThenElse _ e1 e2 e3) = qafv m e1 ++ qafv m e2 ++ qafv m e3+ qafv m (Case _ _ _ e alts) = qafv m e ++ concatMap (qafv m) alts++qafvField :: QualAnnotExpr e => ModuleIdent -> Field (e Type) -> [(Type, Ident)]+qafvField m (Field _ _ t) = qafv m t++qafvStmt :: ModuleIdent -> Statement Type -> [(Type, Ident)] -> [(Type, Ident)]+qafvStmt m st fvs = qafv m st ++ filterBv st fvs++instance QualAnnotExpr Statement where+ qafv m (StmtExpr _ e) = qafv m e+ qafv m (StmtDecl _ _ ds) = filterBv ds $ concatMap (qafv m) ds+ qafv m (StmtBind _ _ e) = qafv m e++instance QualAnnotExpr Alt where+ qafv m (Alt _ t rhs) = filterBv t $ qafv m rhs++instance QualAnnotExpr InfixOp where+ qafv m (InfixOp ty op) = qafv m $ Variable NoSpanInfo ty op+ qafv _ (InfixConstr _ _ ) = []++instance QualAnnotExpr Pattern where+ qafv _ (LiteralPattern _ _ _) = []+ qafv _ (NegativePattern _ _ _) = []+ qafv _ (VariablePattern _ _ _) = []+ qafv m (ConstructorPattern _ _ _ ts) = concatMap (qafv m) ts+ qafv m (InfixPattern _ _ t1 _ t2) = qafv m t1 ++ qafv m t2+ qafv m (ParenPattern _ t) = qafv m t+ qafv m (RecordPattern _ _ _ fs) = concatMap (qafvField m) fs+ qafv m (TuplePattern _ ts) = concatMap (qafv m) ts+ qafv m (ListPattern _ _ ts) = concatMap (qafv m) ts+ qafv m (AsPattern _ _ t) = qafv m t+ qafv m (LazyPattern _ t) = qafv m t+ qafv m (FunctionPattern _ ty f ts) =+ maybe [] (return . (\f' -> (ty', f'))) (localIdent m f) +++ concatMap (qafv m) ts+ where ty' = foldr TypeArrow ty $ map typeOf ts+ qafv m (InfixFuncPattern _ ty t1 op t2) =+ maybe [] (return . (\op' -> (ty', op'))) (localIdent m op) +++ concatMap (qafv m) [t1, t2]+ where ty' = foldr TypeArrow ty $ map typeOf [t1, t2]++filterBv :: QuantExpr e => e -> [(Type, Ident)] -> [(Type, Ident)]+filterBv e = filter ((`Set.notMember` Set.fromList (bv e)) . snd)
+ src/Base/CurryKinds.hs view
@@ -0,0 +1,45 @@+{- |+ Module : $Header$+ Description : Conversion of kind representation+ Copyright : (c) 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ The functions 'tokind' and 'fromKind' convert Curry kind expressions into+ kinds and vice versa.++ When Curry kinds are converted with 'fromKind', kind variables are+ instantiated with the kind *.+-}++module Base.CurryKinds+ ( toKind, toKind', fromKind, fromKind', ppKind+ ) where++import Curry.Base.Pretty (Doc)+import Curry.Syntax.Pretty (pPrintPrec)+import Curry.Syntax.Type (KindExpr (..))++import Base.Kinds++toKind :: KindExpr -> Kind+toKind Star = KindStar+toKind (ArrowKind k1 k2) = KindArrow (toKind k1) (toKind k2)++toKind' :: Maybe KindExpr -> Int -> Kind+toKind' k n = maybe (simpleKind n) toKind k++fromKind :: Kind -> KindExpr+fromKind KindStar = Star+fromKind (KindVariable _) = Star+fromKind (KindArrow k1 k2) = ArrowKind (fromKind k1) (fromKind k2)++fromKind' :: Kind -> Int -> Maybe KindExpr+fromKind' k n | k == simpleKind n = Nothing+ | otherwise = Just (fromKind k)++ppKind :: Kind -> Doc+ppKind = pPrintPrec 0 . fromKind
+ src/Base/CurryTypes.hs view
@@ -0,0 +1,213 @@+{- |+ Module : $Header$+ Description : Conversion of type representation+ Copyright : (c) Wolfgang Lux+ 2011 - 2012 Björn Peemöller+ 2015 Jan Tikovsky+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ The functions 'toType', 'toTypes', and 'fromType' convert Curry type+ expressions into types and vice versa. The functions 'qualifyType' and+ 'unqualifyType' add and remove module qualifiers in a type, respectively.++ When Curry type expression are converted with 'toType' or 'toTypes',+ type variables are assigned ascending indices in the order of their+ occurrence. It is possible to pass a list of additional type variables+ to both functions which are assigned indices before those variables+ occurring in the type. This allows preserving the order of type variables+ in the left hand side of a type declaration.+-}++module Base.CurryTypes+ ( toType, toTypes, toQualType, toQualTypes+ , toPred, toQualPred, toPredSet, toQualPredSet, toPredType, toQualPredType+ , toConstrType, toMethodType+ , fromType, fromQualType+ , fromPred, fromQualPred, fromPredSet, fromQualPredSet, fromPredType+ , fromQualPredType+ , ppType, ppPred, ppPredType, ppTypeScheme+ ) where++import Data.List (nub)+import qualified Data.Map as Map (Map, fromList, lookup)+import qualified Data.Set as Set++import Curry.Base.Ident+import Curry.Base.Pretty (Doc)+import Curry.Base.SpanInfo+import qualified Curry.Syntax as CS+import Curry.Syntax.Pretty (pPrint, pPrintPrec)++import Base.Expr+import Base.Messages (internalError)+import Base.Types++enumTypeVars :: (Expr a, QuantExpr a) => [Ident] -> a -> Map.Map Ident Int+enumTypeVars tvs ty = Map.fromList $ zip (tvs ++ tvs') [0..]+ where+ tvs' = [tv | tv <- nub (fv ty), tv `notElem` tvs] +++ [tv | tv <- nub (bv ty), tv `notElem` tvs]++toType :: [Ident] -> CS.TypeExpr -> Type+toType tvs ty = toType' (enumTypeVars tvs ty) ty []++toTypes :: [Ident] -> [CS.TypeExpr] -> [Type]+toTypes tvs tys = map ((flip (toType' (enumTypeVars tvs tys))) []) tys++toType' :: Map.Map Ident Int -> CS.TypeExpr -> [Type] -> Type+toType' _ (CS.ConstructorType _ tc) tys = applyType (TypeConstructor tc) tys+toType' tvs (CS.ApplyType _ ty1 ty2) tys =+ toType' tvs ty1 (toType' tvs ty2 [] : tys)+toType' tvs (CS.VariableType _ tv) tys =+ applyType (TypeVariable (toVar tvs tv)) tys+toType' tvs (CS.TupleType _ tys) tys'+ | null tys = internalError "Base.CurryTypes.toType': zero-element tuple"+ | null tys' = tupleType $ map ((flip $ toType' tvs) []) tys+ | otherwise = internalError "Base.CurryTypes.toType': tuple type application"+toType' tvs (CS.ListType _ ty) tys+ | null tys = listType $ toType' tvs ty []+ | otherwise = internalError "Base.CurryTypes.toType': list type application"+toType' tvs (CS.ArrowType _ ty1 ty2) tys+ | null tys = TypeArrow (toType' tvs ty1 []) (toType' tvs ty2 [])+ | otherwise = internalError "Base.CurryTypes.toType': arrow type application"+toType' tvs (CS.ParenType _ ty) tys = toType' tvs ty tys+toType' tvs (CS.ForallType _ tvs' ty) tys+ | null tvs' = toType' tvs ty tys+ | otherwise = applyType (TypeForall (map (toVar tvs) tvs')+ (toType' tvs ty []))+ tys++toVar :: Map.Map Ident Int -> Ident -> Int+toVar tvs tv = case Map.lookup tv tvs of+ Just tv' -> tv'+ Nothing -> internalError "Base.CurryTypes.toVar: unknown type variable"++toQualType :: ModuleIdent -> [Ident] -> CS.TypeExpr -> Type+toQualType m tvs = qualifyType m . toType tvs++toQualTypes :: ModuleIdent -> [Ident] -> [CS.TypeExpr] -> [Type]+toQualTypes m tvs = map (qualifyType m) . toTypes tvs++toPred :: [Ident] -> CS.Constraint -> Pred+toPred tvs c = toPred' (enumTypeVars tvs c) c++toPred' :: Map.Map Ident Int -> CS.Constraint -> Pred+toPred' tvs (CS.Constraint _ qcls ty) = Pred qcls (toType' tvs ty [])++toQualPred :: ModuleIdent -> [Ident] -> CS.Constraint -> Pred+toQualPred m tvs = qualifyPred m . toPred tvs++toPredSet :: [Ident] -> CS.Context -> PredSet+toPredSet tvs cx = toPredSet' (enumTypeVars tvs cx) cx++toPredSet' :: Map.Map Ident Int -> CS.Context -> PredSet+toPredSet' tvs = Set.fromList . map (toPred' tvs)++toQualPredSet :: ModuleIdent -> [Ident] -> CS.Context -> PredSet+toQualPredSet m tvs = qualifyPredSet m . toPredSet tvs++toPredType :: [Ident] -> CS.QualTypeExpr -> PredType+toPredType tvs qty = toPredType' (enumTypeVars tvs qty) qty++toPredType' :: Map.Map Ident Int -> CS.QualTypeExpr -> PredType+toPredType' tvs (CS.QualTypeExpr _ cx ty) =+ PredType (toPredSet' tvs cx) (toType' tvs ty [])++toQualPredType :: ModuleIdent -> [Ident] -> CS.QualTypeExpr -> PredType+toQualPredType m tvs = qualifyPredType m . toPredType tvs++-- The function 'toConstrType' returns the type of a data or newtype+-- constructor. Hereby, it restricts the context to those type variables+-- which are free in the argument types.++toConstrType :: QualIdent -> [Ident] -> [CS.TypeExpr] -> PredType+toConstrType tc tvs tys = toPredType tvs $+ CS.QualTypeExpr NoSpanInfo [] ty'+ where ty' = foldr (CS.ArrowType NoSpanInfo) ty0 tys+ ty0 = foldl (CS.ApplyType NoSpanInfo)+ (CS.ConstructorType NoSpanInfo tc)+ (map (CS.VariableType NoSpanInfo) tvs)++-- The function 'toMethodType' returns the type of a type class method.+-- It adds the implicit type class constraint to the method's type signature+-- and ensures that the class' type variable is always assigned index 0.++toMethodType :: QualIdent -> Ident -> CS.QualTypeExpr -> PredType+toMethodType qcls clsvar (CS.QualTypeExpr spi cx ty) =+ toPredType [clsvar] (CS.QualTypeExpr spi cx' ty)+ where cx' = CS.Constraint NoSpanInfo qcls+ (CS.VariableType NoSpanInfo clsvar) : cx++fromType :: [Ident] -> Type -> CS.TypeExpr+fromType tvs ty = fromType' tvs ty []++fromType' :: [Ident] -> Type -> [CS.TypeExpr] -> CS.TypeExpr+fromType' _ (TypeConstructor tc) tys+ | isQTupleId tc && qTupleArity tc == length tys+ = CS.TupleType NoSpanInfo tys+ | tc == qListId && length tys == 1+ = CS.ListType NoSpanInfo (head tys)+ | otherwise+ = foldl (CS.ApplyType NoSpanInfo) (CS.ConstructorType NoSpanInfo tc) tys+fromType' tvs (TypeApply ty1 ty2) tys =+ fromType' tvs ty1 (fromType tvs ty2 : tys)+fromType' tvs (TypeVariable tv) tys =+ foldl (CS.ApplyType NoSpanInfo) (CS.VariableType NoSpanInfo (fromVar tvs tv))+ tys+fromType' tvs (TypeArrow ty1 ty2) tys =+ foldl (CS.ApplyType NoSpanInfo)+ (CS.ArrowType NoSpanInfo (fromType tvs ty1) (fromType tvs ty2)) tys+fromType' tvs (TypeConstrained tys _) tys' = fromType' tvs (head tys) tys'+fromType' tvs (TypeForall tvs' ty) tys+ | null tvs' = fromType' tvs ty tys+ | otherwise = foldl (CS.ApplyType NoSpanInfo)+ (CS.ForallType NoSpanInfo (map (fromVar tvs) tvs')+ (fromType tvs ty))+ tys++fromVar :: [Ident] -> Int -> Ident+fromVar tvs tv = if tv >= 0 then tvs !! tv else mkIdent ('_' : show (-tv))++fromQualType :: ModuleIdent -> [Ident] -> Type -> CS.TypeExpr+fromQualType m tvs = fromType tvs . unqualifyType m++fromPred :: [Ident] -> Pred -> CS.Constraint+fromPred tvs (Pred qcls ty) = CS.Constraint NoSpanInfo qcls (fromType tvs ty)++fromQualPred :: ModuleIdent -> [Ident] -> Pred -> CS.Constraint+fromQualPred m tvs = fromPred tvs . unqualifyPred m++-- Due to the sorting of the predicate set, the list of constraints is sorted+-- as well.++fromPredSet :: [Ident] -> PredSet -> CS.Context+fromPredSet tvs = map (fromPred tvs) . Set.toAscList++fromQualPredSet :: ModuleIdent -> [Ident] -> PredSet -> CS.Context+fromQualPredSet m tvs = fromPredSet tvs . unqualifyPredSet m++fromPredType :: [Ident] -> PredType -> CS.QualTypeExpr+fromPredType tvs (PredType ps ty) =+ CS.QualTypeExpr NoSpanInfo (fromPredSet tvs ps) (fromType tvs ty)++fromQualPredType :: ModuleIdent -> [Ident] -> PredType -> CS.QualTypeExpr+fromQualPredType m tvs = fromPredType tvs . unqualifyPredType m++-- The following functions implement pretty-printing for types.++ppType :: ModuleIdent -> Type -> Doc+ppType m = pPrintPrec 0 . fromQualType m identSupply++ppPred :: ModuleIdent -> Pred -> Doc+ppPred m = pPrint . fromQualPred m identSupply++ppPredType :: ModuleIdent -> PredType -> Doc+ppPredType m = pPrint . fromQualPredType m identSupply++ppTypeScheme :: ModuleIdent -> TypeScheme -> Doc+ppTypeScheme m (ForAll _ pty) = ppPredType m pty
+ src/Base/Expr.hs view
@@ -0,0 +1,212 @@+{- |+ Module : $Header$+ Description : Extraction of free and bound variables+ Copyright : (c) Wolfgang Lux+ 2011 - 2015 Björn Peemöller+ 2015 Jan Tikovsky+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ The compiler needs to compute the lists of free and bound variables for+ various different entities. We will devote three type classes to that+ purpose. The 'QualExpr' class is expected to take into account+ that it is possible to use a qualified name to refer to a function+ defined in the current module and therefore @M.x@ and @x@, where+ @M@ is the current module name, should be considered the same name.+ However, note that this is correct only after renaming all local+ definitions as @M.x@ always denotes an entity defined at the+ top-level.+-}+module Base.Expr (Expr (..), QualExpr (..), QuantExpr (..)) where++import Data.List (nub)+import qualified Data.Set as Set (fromList, notMember)++import Curry.Base.Ident+import Curry.Base.SpanInfo+import Curry.Syntax++class Expr e where+ -- |Free variables in an 'Expr'+ fv :: e -> [Ident]++class QualExpr e where+ -- |Free qualified variables in an 'Expr'+ qfv :: ModuleIdent -> e -> [Ident]++class QuantExpr e where+ -- |Bounded variables in an 'Expr'+ bv :: e -> [Ident]++instance Expr e => Expr [e] where+ fv = concatMap fv++instance QualExpr e => QualExpr [e] where+ qfv m = concatMap (qfv m)++instance QuantExpr e => QuantExpr [e] where+ bv = concatMap bv++-- The 'Decl' instance of 'QualExpr' returns all free+-- variables on the right hand side, regardless of whether they are bound+-- on the left hand side. This is more convenient as declarations are+-- usually processed in a declaration group where the set of free+-- variables cannot be computed independently for each declaration.++instance QualExpr (Decl a) where+ qfv m (FunctionDecl _ _ _ eqs) = qfv m eqs+ qfv m (PatternDecl _ _ rhs) = qfv m rhs+ qfv m (ClassDecl _ _ _ _ _ ds) = qfv m ds+ qfv m (InstanceDecl _ _ _ _ _ ds) = qfv m ds+ qfv _ _ = []++instance QuantExpr (Decl a) where+ bv (TypeSig _ vs _) = vs+ bv (FunctionDecl _ _ f _) = [f]+ bv (ExternalDecl _ vs) = bv vs+ bv (PatternDecl _ t _) = bv t+ bv (FreeDecl _ vs) = bv vs+ bv (ClassDecl _ _ _ _ _ ds) = concatMap methods ds+ bv _ = []++instance QualExpr (Equation a) where+ qfv m (Equation _ lhs rhs) = filterBv lhs $ qfv m lhs ++ qfv m rhs++instance QuantExpr (Lhs a) where+ bv = bv . snd . flatLhs++instance QualExpr (Lhs a) where+ qfv m lhs = qfv m $ snd $ flatLhs lhs++instance QualExpr (Rhs a) where+ qfv m (SimpleRhs _ _ e ds) = filterBv ds $ qfv m e ++ qfv m ds+ qfv m (GuardedRhs _ _ es ds) = filterBv ds $ qfv m es ++ qfv m ds++instance QualExpr (CondExpr a) where+ qfv m (CondExpr _ g e) = qfv m g ++ qfv m e++instance QualExpr (Expression a) where+ qfv _ (Literal _ _ _) = []+ qfv m (Variable _ _ v) = maybe [] return $ localIdent m v+ qfv _ (Constructor _ _ _) = []+ qfv m (Paren _ e) = qfv m e+ qfv m (Typed _ e _) = qfv m e+ qfv m (Record _ _ _ fs) = qfv m fs+ qfv m (RecordUpdate _ e fs) = qfv m e ++ qfv m fs+ qfv m (Tuple _ es) = qfv m es+ qfv m (List _ _ es) = qfv m es+ qfv m (ListCompr _ e qs) = foldr (qfvStmt m) (qfv m e) qs+ qfv m (EnumFrom _ e) = qfv m e+ qfv m (EnumFromThen _ e1 e2) = qfv m e1 ++ qfv m e2+ qfv m (EnumFromTo _ e1 e2) = qfv m e1 ++ qfv m e2+ qfv m (EnumFromThenTo _ e1 e2 e3) = qfv m e1 ++ qfv m e2 ++ qfv m e3+ qfv m (UnaryMinus _ e) = qfv m e+ qfv m (Apply _ e1 e2) = qfv m e1 ++ qfv m e2+ qfv m (InfixApply _ e1 op e2) = qfv m op ++ qfv m e1 ++ qfv m e2+ qfv m (LeftSection _ e op) = qfv m op ++ qfv m e+ qfv m (RightSection _ op e) = qfv m op ++ qfv m e+ qfv m (Lambda _ ts e) = filterBv ts $ qfv m e+ qfv m (Let _ _ ds e) = filterBv ds $ qfv m ds ++ qfv m e+ qfv m (Do _ _ sts e) = foldr (qfvStmt m) (qfv m e) sts+ qfv m (IfThenElse _ e1 e2 e3) = qfv m e1 ++ qfv m e2 ++ qfv m e3+ qfv m (Case _ _ _ e alts) = qfv m e ++ qfv m alts++qfvStmt :: ModuleIdent -> (Statement a) -> [Ident] -> [Ident]+qfvStmt m st fvs = qfv m st ++ filterBv st fvs++instance QualExpr (Statement a) where+ qfv m (StmtExpr _ e) = qfv m e+ qfv m (StmtDecl _ _ ds) = filterBv ds $ qfv m ds+ qfv m (StmtBind _ _ e) = qfv m e++instance QualExpr (Alt a) where+ qfv m (Alt _ t rhs) = filterBv t $ qfv m rhs++instance QuantExpr (Var a) where+ bv (Var _ v) = [v]++instance QuantExpr a => QuantExpr (Field a) where+ bv (Field _ _ t) = bv t++instance QualExpr a => QualExpr (Field a) where+ qfv m (Field _ _ t) = qfv m t++instance QuantExpr (Statement a) where+ bv (StmtExpr _ _) = []+ bv (StmtBind _ t _) = bv t+ bv (StmtDecl _ _ ds) = bv ds++instance QualExpr (InfixOp a) where+ qfv m (InfixOp a op) = qfv m $ Variable NoSpanInfo a op+ qfv _ (InfixConstr _ _ ) = []++instance QuantExpr (Pattern a) where+ bv (LiteralPattern _ _ _) = []+ bv (NegativePattern _ _ _) = []+ bv (VariablePattern _ _ v) = [v]+ bv (ConstructorPattern _ _ _ ts) = bv ts+ bv (InfixPattern _ _ t1 _ t2) = bv t1 ++ bv t2+ bv (ParenPattern _ t) = bv t+ bv (RecordPattern _ _ _ fs) = bv fs+ bv (TuplePattern _ ts) = bv ts+ bv (ListPattern _ _ ts) = bv ts+ bv (AsPattern _ v t) = v : bv t+ bv (LazyPattern _ t) = bv t+ bv (FunctionPattern _ _ _ ts) = nub $ bv ts+ bv (InfixFuncPattern _ _ t1 _ t2) = nub $ bv t1 ++ bv t2++instance QualExpr (Pattern a) where+ qfv _ (LiteralPattern _ _ _) = []+ qfv _ (NegativePattern _ _ _) = []+ qfv _ (VariablePattern _ _ _) = []+ qfv m (ConstructorPattern _ _ _ ts) = qfv m ts+ qfv m (InfixPattern _ _ t1 _ t2) = qfv m [t1, t2]+ qfv m (ParenPattern _ t) = qfv m t+ qfv m (RecordPattern _ _ _ fs) = qfv m fs+ qfv m (TuplePattern _ ts) = qfv m ts+ qfv m (ListPattern _ _ ts) = qfv m ts+ qfv m (AsPattern _ _ ts) = qfv m ts+ qfv m (LazyPattern _ t) = qfv m t+ qfv m (FunctionPattern _ _ f ts)+ = maybe [] return (localIdent m f) ++ qfv m ts+ qfv m (InfixFuncPattern _ _ t1 op t2)+ = maybe [] return (localIdent m op) ++ qfv m [t1, t2]++instance Expr Constraint where+ fv (Constraint _ _ ty) = fv ty++instance QuantExpr Constraint where+ bv _ = []++instance Expr QualTypeExpr where+ fv (QualTypeExpr _ _ ty) = fv ty++instance QuantExpr QualTypeExpr where+ bv (QualTypeExpr _ _ ty) = bv ty++instance Expr TypeExpr where+ fv (ConstructorType _ _) = []+ fv (ApplyType _ ty1 ty2) = fv ty1 ++ fv ty2+ fv (VariableType _ tv) = [tv]+ fv (TupleType _ tys) = fv tys+ fv (ListType _ ty) = fv ty+ fv (ArrowType _ ty1 ty2) = fv ty1 ++ fv ty2+ fv (ParenType _ ty) = fv ty+ fv (ForallType _ vs ty) = filter (`notElem` vs) $ fv ty++instance QuantExpr TypeExpr where+ bv (ConstructorType _ _) = []+ bv (ApplyType _ ty1 ty2) = bv ty1 ++ bv ty2+ bv (VariableType _ _) = []+ bv (TupleType _ tys) = bv tys+ bv (ListType _ ty) = bv ty+ bv (ArrowType _ ty1 ty2) = bv ty1 ++ bv ty2+ bv (ParenType _ ty) = bv ty+ bv (ForallType _ tvs ty) = tvs ++ bv ty++filterBv :: QuantExpr e => e -> [Ident] -> [Ident]+filterBv e = filter (`Set.notMember` Set.fromList (bv e))
+ src/Base/KindSubst.hs view
@@ -0,0 +1,48 @@+{- |+ Module : $Header$+ Description : Kind substitution+ Copyright : (c) 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module implements substitutions on kinds.+-}++module Base.KindSubst+ ( module Base.KindSubst, idSubst, singleSubst, bindSubst, compose+ ) where++import Base.Kinds+import Base.Subst+import Base.TopEnv++import Env.TypeConstructor++type KindSubst = Subst Int Kind++class SubstKind a where+ subst :: KindSubst -> a -> a++bindVar :: Int -> Kind -> KindSubst -> KindSubst+bindVar kv k = compose (bindSubst kv k idSubst)++substVar :: KindSubst -> Int -> Kind+substVar = substVar' KindVariable subst++instance SubstKind Kind where+ subst _ KindStar = KindStar+ subst sigma (KindVariable kv) = substVar sigma kv+ subst sigma (KindArrow k1 k2) = KindArrow (subst sigma k1) (subst sigma k2)++instance SubstKind TypeInfo where+ subst theta (DataType tc k cs) = DataType tc (subst theta k) cs+ subst theta (RenamingType tc k nc) = RenamingType tc (subst theta k) nc+ subst theta (AliasType tc k n ty) = AliasType tc (subst theta k) n ty+ subst theta (TypeClass cls k ms) = TypeClass cls (subst theta k) ms+ subst theta (TypeVar k) = TypeVar (subst theta k)++instance SubstKind a => SubstKind (TopEnv a) where+ subst = fmap . subst
+ src/Base/Kinds.hs view
@@ -0,0 +1,62 @@+{- |+ Module : $Header$+ Description : Internal representation of kinds+ Copyright : (c) 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module modules provides the definitions for the internal+ representation of kinds in the compiler.+-}++module Base.Kinds where++-- A kind is either *, which is the kind of a value's type, a kind+-- variable, or an arrow kind. Kind variables are used internally during+-- kind inference. Kind variables are not supported in Curry kind+-- expressions and all kind variables that remain free after kind+-- inference are instantiated to *.++data Kind = KindStar+ | KindVariable Int+ | KindArrow Kind Kind+ deriving (Eq, Show)++-- |The function 'kindArity' computes the arity n of a kind.+kindArity :: Kind -> Int+kindArity (KindArrow _ k) = 1 + kindArity k+kindArity _ = 0++-- |The function 'kindVars' returns a list of all kind variables+-- occurring in a kind.+kindVars :: Kind -> [Int]+kindVars k = vars k []+ where+ vars KindStar kvs = kvs+ vars (KindVariable kv) kvs = kv : kvs+ vars (KindArrow k1 k2) kvs = vars k1 $ vars k2 kvs++-- |The function 'defaultKind' instantiates all kind variables+-- occurring in a kind to *.+defaultKind :: Kind -> Kind+defaultKind (KindArrow k1 k2) = KindArrow (defaultKind k1) (defaultKind k2)+defaultKind _ = KindStar++-- |The function 'simpleKind' returns the kind of a type+-- constructor with arity n whose arguments all have kind *.+simpleKind :: Int -> Kind+simpleKind n = foldr KindArrow KindStar $ replicate n KindStar++-- |The function 'isSimpleKind' returns whether a kind is simple or not.+isSimpleKind :: Kind -> Bool+isSimpleKind k = k == simpleKind (kindArity k)++-- |Fetches a kind's 'arguments', i.e. everything before an+-- arrow at the top-level. For example: A kind k1 -> k2 -> k3+-- would have the arguments [k1, k2].+kindArgs :: Kind -> [Kind]+kindArgs (KindArrow k k') = k : kindArgs k'+kindArgs _ = []
+ src/Base/Messages.hs view
@@ -0,0 +1,78 @@+{- |+ Module : $Header$+ Description : Construction and output of compiler messages+ Copyright : (c) 2011 - 2016 Björn Peemöller+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module defines several operations to construct and emit compiler+ messages to the user.+-}+module Base.Messages+ ( -- * Output of user information+ MonadIO (..), status, putMsg, putErrLn, putErrsLn+ -- * program abortion+ , abortWith, abortWithMessage, abortWithMessages, warnOrAbort, internalError+ -- * creating messages+ , Message, message, posMessage, spanInfoMessage+ ) where++import Control.Monad (unless, when)+import Control.Monad.IO.Class (MonadIO(..))+import Data.List (sort)+import System.IO (hFlush, hPutStrLn, stderr, stdout)+import System.Exit (exitFailure)++import Curry.Base.Message ( Message, message, posMessage, spanInfoMessage+ , ppWarning, ppMessagesWithPreviews, ppError)+import Curry.Base.Pretty (Doc, text)+import CompilerOpts (Options (..), WarnOpts (..), Verbosity (..))++-- |Print a status message, depending on the current verbosity+status :: MonadIO m => Options -> String -> m ()+status opts msg = unless (optVerbosity opts < VerbStatus) (putMsg msg)++-- |Print a message on 'stdout'+putMsg :: MonadIO m => String -> m ()+putMsg msg = liftIO (putStrLn msg >> hFlush stdout)++-- |Print an error message on 'stderr'+putErrLn :: MonadIO m => String -> m ()+putErrLn msg = liftIO (hPutStrLn stderr msg >> hFlush stderr)++-- |Print a list of error messages on 'stderr'+putErrsLn :: MonadIO m => [String] -> m ()+putErrsLn = mapM_ putErrLn++-- |Print a list of 'String's as error messages on 'stderr'+-- and abort the program+abortWith :: [String] -> IO a+abortWith errs = putErrsLn errs >> exitFailure++-- |Print a single error message on 'stderr' and abort the program+abortWithMessage :: Message -> IO a+abortWithMessage msg = abortWithMessages [msg]++-- |Print a list of error messages on 'stderr' and abort the program+abortWithMessages :: [Message] -> IO a+abortWithMessages msgs = printMessages ppError msgs >> exitFailure++-- |Print a list of warning messages on 'stderr' and abort the program+-- |if the -Werror option is set+warnOrAbort :: WarnOpts -> [Message] -> IO ()+warnOrAbort opts msgs = when (wnWarn opts && not (null msgs)) $ do+ if wnWarnAsError opts+ then abortWithMessages (msgs ++ [message $ text "Failed due to -Werror"])+ else printMessages ppWarning msgs++-- |Print a list of messages on 'stderr'+printMessages :: (Message -> Doc) -> [Message] -> IO ()+printMessages msgType msgs+ = unless (null msgs) $ putErrLn =<< (fmap show $ ppMessagesWithPreviews msgType $ sort msgs)++-- |Raise an internal error+internalError :: String -> a+internalError msg = error $ "Internal error: " ++ msg
+ src/Base/NestEnv.hs view
@@ -0,0 +1,120 @@+{- |+ Module : $Header$+ Description : Nested Environments+ Copyright : (c) 1999 - 2003 Wolfgang Lux+ 2011 - 2015 Björn Peemöller+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ The 'NestEnv' environment type extends top-level environments to manage+ nested scopes. Local scopes allow only for a single, unambiguous definition.++ As a matter of convenience, the module 'TopEnv' is exported by+ the module 'NestEnv'. Thus, only the latter needs to be imported.+-}++module Base.NestEnv+ ( module Base.TopEnv+ , NestEnv, emptyEnv, bindNestEnv, qualBindNestEnv+ , lookupNestEnv, qualLookupNestEnv+ , rebindNestEnv, qualRebindNestEnv+ , unnestEnv, toplevelEnv, globalEnv, nestEnv, elemNestEnv+ , qualModifyNestEnv, modifyNestEnv, localNestEnv, qualInLocalNestEnv+ ) where++import qualified Data.Map as Map+import Curry.Base.Ident++import Base.Messages (internalError)+import Base.TopEnv++data NestEnv a+ = GlobalEnv (TopEnv a)+ | LocalEnv (NestEnv a) (Map.Map Ident a)+ deriving Show++instance Functor NestEnv where+ fmap f (GlobalEnv env) = GlobalEnv (fmap f env)+ fmap f (LocalEnv genv env) = LocalEnv (fmap f genv) (fmap f env)++globalEnv :: TopEnv a -> NestEnv a+globalEnv = GlobalEnv++emptyEnv :: NestEnv a+emptyEnv = globalEnv emptyTopEnv++nestEnv :: NestEnv a -> NestEnv a+nestEnv env = LocalEnv env Map.empty++unnestEnv :: NestEnv a -> NestEnv a+unnestEnv g@(GlobalEnv _) = g+unnestEnv (LocalEnv genv _) = genv++toplevelEnv :: NestEnv a -> TopEnv a+toplevelEnv (GlobalEnv env) = env+toplevelEnv (LocalEnv genv _) = toplevelEnv genv++bindNestEnv :: Ident -> a -> NestEnv a -> NestEnv a+bindNestEnv x y (GlobalEnv env) = GlobalEnv $ bindTopEnv x y env+bindNestEnv x y (LocalEnv genv env) = case Map.lookup x env of+ Just _ -> internalError $ "NestEnv.bindNestEnv: " ++ show x ++ " is already bound"+ Nothing -> LocalEnv genv $ Map.insert x y env++qualBindNestEnv :: QualIdent -> a -> NestEnv a -> NestEnv a+qualBindNestEnv x y (GlobalEnv env) = GlobalEnv $ qualBindTopEnv x y env+qualBindNestEnv x y (LocalEnv genv env)+ | isQualified x = internalError $ "NestEnv.qualBindNestEnv " ++ show x+ | otherwise = case Map.lookup x' env of+ Just _ -> internalError $ "NestEnv.qualBindNestEnv " ++ show x+ Nothing -> LocalEnv genv $ Map.insert x' y env+ where x' = unqualify x++-- Rebinds a value to a variable, failes if the variable was unbound before+rebindNestEnv :: Ident -> a -> NestEnv a -> NestEnv a+rebindNestEnv = qualRebindNestEnv . qualify++qualRebindNestEnv :: QualIdent -> a -> NestEnv a -> NestEnv a+qualRebindNestEnv x y (GlobalEnv env) = GlobalEnv $ qualRebindTopEnv x y env+qualRebindNestEnv x y (LocalEnv genv env)+ | isQualified x = internalError $ "NestEnv.qualRebindNestEnv " ++ show x+ | otherwise = case Map.lookup x' env of+ Just _ -> LocalEnv genv $ Map.insert x' y env+ Nothing -> LocalEnv (qualRebindNestEnv x y genv) env+ where x' = unqualify x++lookupNestEnv :: Ident -> NestEnv a -> [a]+lookupNestEnv x (GlobalEnv env) = lookupTopEnv x env+lookupNestEnv x (LocalEnv genv env) = case Map.lookup x env of+ Just y -> [y]+ Nothing -> lookupNestEnv x genv++qualLookupNestEnv :: QualIdent -> NestEnv a -> [a]+qualLookupNestEnv x env+ | isQualified x = qualLookupTopEnv x $ toplevelEnv env+ | otherwise = lookupNestEnv (unqualify x) env++elemNestEnv :: Ident -> NestEnv a -> Bool+elemNestEnv x env = not (null (lookupNestEnv x env))++-- Applies a function to a value binding, does nothing if the variable is unbound+modifyNestEnv :: (a -> a) -> Ident -> NestEnv a -> NestEnv a+modifyNestEnv f = qualModifyNestEnv f . qualify++qualModifyNestEnv :: (a -> a) -> QualIdent -> NestEnv a -> NestEnv a+qualModifyNestEnv f x env = case qualLookupNestEnv x env of+ [] -> env+ y : _ -> qualRebindNestEnv x (f y) env++-- Returns the variables and values bound on the bottom (meaning non-top) scope+localNestEnv :: NestEnv a -> [(Ident, a)]+localNestEnv (GlobalEnv env) = localBindings env+localNestEnv (LocalEnv _ env) = Map.toList env++-- Returns wether the variable is bound on the bottom (meaning non-top) scope+qualInLocalNestEnv :: QualIdent -> NestEnv a -> Bool+qualInLocalNestEnv x (GlobalEnv env) = qualElemTopEnv x env+qualInLocalNestEnv x (LocalEnv _ env) = (not (isQualified x))+ && Map.member (unqualify x) env
+ src/Base/PrettyKinds.hs view
@@ -0,0 +1,22 @@+{- |+ Module : $Header$+ Description : TODO+ Copyright : (c) 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ TODO+-}+{-# OPTIONS_GHC -Wno-orphans #-}+module Base.PrettyKinds where++import Curry.Base.Pretty++import Base.CurryKinds+import Base.Kinds++instance Pretty Kind where+ pPrint = ppKind
+ src/Base/PrettyTypes.hs view
@@ -0,0 +1,55 @@+{- |+ Module : $Header$+ Description : TODO+ Copyright : (c) 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ TODO+-}+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -Wno-orphans #-}+module Base.PrettyTypes where++#if __GLASGOW_HASKELL__ >= 804+import Prelude hiding ((<>))+#endif++import Data.Maybe (fromMaybe)+import qualified Data.Set as Set (Set, toAscList)++import Curry.Base.Ident (identSupply)+import Curry.Base.Pretty++import Base.CurryTypes+import Base.Types++instance Pretty Type where+ pPrint = pPrintPrec 0 . fromType identSupply++instance Pretty Pred where+ pPrint = pPrint . fromPred identSupply++instance Pretty a => Pretty (Set.Set a) where+ pPrint = parens . list . map pPrint . Set.toAscList++instance Pretty PredType where+ pPrint = pPrint . fromPredType identSupply++instance Pretty DataConstr where+ pPrint (DataConstr i tys) = pPrint i <+> hsep (map pPrint tys)+ pPrint (RecordConstr i ls tys) = pPrint i+ <+> braces (hsep (punctuate comma pLs))+ where+ pLs = zipWith (\l ty -> pPrint l <+> colon <> colon <+> pPrint ty) ls tys++instance Pretty ClassMethod where+ pPrint (ClassMethod f mar pty) = pPrint f+ <> text "/" <> int (fromMaybe 0 mar)+ <+> colon <> colon <+> pPrint pty++instance Pretty TypeScheme where+ pPrint (ForAll _ ty) = pPrint ty
+ src/Base/SCC.hs view
@@ -0,0 +1,62 @@+{- |+ Module : $Header$+ Description : Computation of strongly connected components+ Copyright : (c) 2000, 2002 - 2003 Wolfgang Lux+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ At various places in the compiler we had to partition a list of+ declarations into strongly connected components. The function+ 'scc' computes this relation in two steps. First, the list is+ topologically sorted downwards using the 'defs' relation.+ Then the resulting list is sorted upwards using the 'uses' relation+ and partitioned into the connected components. Both relations+ are computed within this module using the bound and free names of each+ declaration.++ In order to avoid useless recomputations, the code in the module first+ decorates the declarations with their bound and free names and a+ unique number. The latter is only used to provide a trivial ordering+ so that the declarations can be used as set elements.+-}++module Base.SCC (scc) where++import qualified Data.Set as Set (empty, member, insert)++data Node a b = Node { key :: Int, bvs :: [b], fvs :: [b], node :: a }++instance Eq (Node a b) where+ n1 == n2 = key n1 == key n2++instance Ord (Node b a) where+ n1 `compare` n2 = key n1 `compare` key n2++-- |Computation of strongly connected components+scc :: Eq b => (a -> [b]) -- ^entities defined by node+ -> (a -> [b]) -- ^entities used by node+ -> [a] -- ^list of nodes+ -> [[a]] -- ^strongly connected components+scc bvs' fvs' = map (map node) . tsort' . tsort . zipWith wrap [0 ..]+ where wrap i n = Node i (bvs' n) (fvs' n) n++tsort :: Eq b => [Node a b] -> [Node a b]+tsort xs = snd (dfs xs Set.empty []) where+ dfs [] marks stack = (marks,stack)+ dfs (x : xs') marks stack+ | x `Set.member` marks = dfs xs' marks stack+ | otherwise = dfs xs' marks' (x : stack')+ where (marks',stack') = dfs (defs x) (x `Set.insert` marks) stack+ defs x1 = filter (any (`elem` fvs x1) . bvs) xs++tsort' :: Eq b => [Node a b] -> [[Node a b]]+tsort' xs = snd (dfs xs Set.empty []) where+ dfs [] marks stack = (marks,stack)+ dfs (x : xs') marks stack+ | x `Set.member` marks = dfs xs' marks stack+ | otherwise = dfs xs' marks' ((x : concat stack') : stack)+ where (marks',stack') = dfs (uses x) (x `Set.insert` marks) []+ uses x1 = filter (any (`elem` bvs x1) . fvs) xs
+ src/Base/Subst.hs view
@@ -0,0 +1,127 @@+{- |+ Module : $Header$+ Description : General substitution implementation+ Copyright : (c) 2002 Wolfgang Lux+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ The module Subst implements substitutions. A substitution+ sigma = {x_1 |-> t_1, ... ,x_n |-> t_n} is a finite mapping from+ (finitely many) variables x_1, ... ,x_n to some kind of expression+ or term.++ In order to implement substitutions efficiently,+ composed substitutions are marked with a boolean flag (see below).+-}++module Base.Subst+ ( Subst (..), IntSubst (..), idSubst, singleSubst, bindSubst, unbindSubst+ , substToList, compose, substVar', isubstVar, restrictSubstTo+ ) where++import qualified Data.Map as Map++-- |Data type for substitution+data Subst a b = Subst Bool (Map.Map a b)+ deriving Show++-- |Identity substitution+idSubst :: Subst a b+idSubst = Subst False Map.empty++-- |Convert a substitution to a list of replacements+substToList :: Subst v e -> [(v, e)]+substToList (Subst _ sigma) = Map.toList sigma++-- |Create a substitution for a single replacement+singleSubst :: Ord v => v -> e -> Subst v e+singleSubst v e = bindSubst v e idSubst++-- |Extend a substitution with a single replacement+bindSubst :: Ord v => v -> e -> Subst v e -> Subst v e+bindSubst v e (Subst comp sigma) = Subst comp $ Map.insert v e sigma++-- |Remove a single replacement from a substitution+unbindSubst :: Ord v => v -> Subst v e -> Subst v e+unbindSubst v (Subst comp sigma) = Subst comp $ Map.delete v sigma++-- For any substitution we have the following definitions:+-- sigma(x) = t_i if x = x_i+-- x otherwise+-- Dom(sigma) = {x_1, ... , x_n}+-- Codom(sigma) = {t_1, ... , t_n}+-- Note that obviously the set of variables must be a subset of the set+-- of expressions. Also it is usually possible to extend the substitution+-- to a homomorphism on the codomain of the substitution. This is+-- captured by the following class declaration:++-- class Ord v => Subst v e where+-- var :: v -> e+-- subst :: Subst v e -> e -> e++-- With the help of the injection 'var', we can then compute the+-- substitution for a variable sigma(v) and also the composition of+-- two substitutions sigma1 o sigma2(e) := sigma1(sigma2(e)).+-- A naive implementation of the composition were+--+-- compose sigma sigma' =+-- foldr (uncurry bindSubst) sigma (substToList (fmap (subst sigma) sigma'))+--+-- However, such an implementation is very inefficient because the+-- number of substiutions applied to a variable increases in+-- O(n) of the number of compositions.++-- A more efficient implementation is to apply 'subst' again to+-- the value substituted for a variable in Dom(sigma).+-- However, this is correct only as long as the result of the substitution+-- does not include any variables which are in Dom(sigma). For instance,+-- it is impossible to implement simple variable renamings in this way.++-- Therefore we use the simple strategy to apply 'subst' again+-- only in case of a substitution which was returned from 'compose'.++-- substVar :: Subst v e => Subst v e -> v -> e+-- substVar (Subst comp sigma) v = maybe (var v) subst' (Map.lookup v sigma)+-- where subst' = if comp then subst (Subst comp sigma) else id++-- |Compose two substitutions+compose :: Ord v => Subst v e -> Subst v e -> Subst v e+compose sigma sigma' =+ composed (foldr (uncurry bindSubst) sigma' (substToList sigma))+ where composed (Subst _ sigma'') = Subst True sigma''++-- Unfortunately Haskell does not (yet) support multi-parameter type+-- classes. For that reason we have to define a separate class for each+-- kind of variable type for these functions. We implement+-- 'substVar' as a function that takes the class functions as an+-- additional parameters. As an example for the use of this function the+-- module includes a class 'IntSubst' for substitution whose+-- domain are integer numbers.++-- |Apply a substitution to a variable+substVar' :: Ord v => (v -> e) -> (Subst v e -> e -> e)+ -> Subst v e -> v -> e+substVar' var subst (Subst comp sigma) v =+ maybe (var v) subst' (Map.lookup v sigma)+ where subst' = if comp then subst (Subst comp sigma) else id++-- |Type class for terms where variables are represented as 'Int's+class IntSubst e where+ -- |Construct a variable from an 'Int'+ ivar :: Int -> e+ -- |Apply a substitution to a term+ isubst :: Subst Int e -> e -> e++-- |Apply a substitution to a term with variables represented as 'Int's+isubstVar :: IntSubst e => Subst Int e -> Int -> e+isubstVar = substVar' ivar isubst++-- |The function 'restrictSubstTo' implements the restriction of a+-- substitution to a given subset of its domain.+restrictSubstTo :: Ord v => [v] -> Subst v e -> Subst v e+restrictSubstTo vs (Subst comp sigma) =+ foldr (uncurry bindSubst) (Subst comp Map.empty)+ (filter ((`elem` vs) . fst) (Map.toList sigma))
+ src/Base/TopEnv.hs view
@@ -0,0 +1,181 @@+{- |+ Module : $Header$+ Description : Top-Level Environments+ Copyright : 1999 - 2003 Wolfgang Lux+ 2005 Martin Engelke+ 2011 - 2012 Björn Peemöller+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ The module 'TopEnv' implements environments for qualified and+ possibly ambiguous identifiers. An identifier is ambiguous if two+ different entities are imported under the same name or if a local+ definition uses the same name as an imported entity. Following an idea+ presented in a paper by Diatchki, Jones and Hallgren (2002),+ an identifier is associated with a list of entities in order to handle+ ambiguous names properly.++ In general, two entities are considered equal if the names of their+ original definitions match. However, in the case of algebraic data+ types it is possible to hide some or all of their data constructors on+ import and export, respectively. In this case we have to merge both+ imports such that all data constructors which are visible through any+ import path are visible in the current module. The class+ Entity is used to handle this merge.++ The code in this module ensures that the list of entities returned by+ the functions 'lookupTopEnv' and 'qualLookupTopEnv' contains exactly one+ element for each imported entity regardless of how many times and+ from which module(s) it was imported. Thus, the result of these function+ is a list with exactly one element if and only if the identifier is+ unambiguous. The module names associated with an imported entity identify+ the modules from which the entity was imported.+-}++module Base.TopEnv+ ( -- * Data types+ TopEnv (..), Entity (..)+ -- * creation and insertion+ , emptyTopEnv, predefTopEnv, importTopEnv, qualImportTopEnv+ , bindTopEnv, qualBindTopEnv, rebindTopEnv+ , qualRebindTopEnv, unbindTopEnv, qualUnbindTopEnv+ , lookupTopEnv, qualLookupTopEnv, qualElemTopEnv+ , allImports, moduleImports, localBindings, allLocalBindings, allBindings+ , allEntities+ ) where++import Control.Arrow (second)+import qualified Data.Map as Map+ (Map, empty, insert, findWithDefault, lookup, toList)++import Curry.Base.Ident+import Base.Messages (internalError)++class Entity a where+ origName :: a -> QualIdent+ merge :: a -> a -> Maybe a+ merge x y+ | origName x == origName y = Just x+ | otherwise = Nothing++data Source = Local | Import [ModuleIdent] deriving (Eq, Show)++-- |Top level environment+newtype TopEnv a = TopEnv { topEnvMap :: Map.Map QualIdent [(Source, a)] }+ deriving Show++instance Functor TopEnv where+ fmap f (TopEnv env) = TopEnv (fmap (map (second f)) env)++-- local helper+entities :: QualIdent -> Map.Map QualIdent [(Source, a)] -> [(Source, a)]+entities = Map.findWithDefault []++-- |Empty 'TopEnv'+emptyTopEnv :: TopEnv a+emptyTopEnv = TopEnv Map.empty++-- |Insert an 'Entity' into a 'TopEnv' as a predefined 'Entity'+predefTopEnv :: QualIdent -> a -> TopEnv a -> TopEnv a+predefTopEnv k v (TopEnv env) = case Map.lookup k env of+ Just _ -> internalError $ "TopEnv.predefTopEnv " ++ show k+ Nothing -> TopEnv $ Map.insert k [(Import [], v)] env++-- |Insert an 'Entity' as unqualified into a 'TopEnv'+importTopEnv :: Entity a => ModuleIdent -> Ident -> a -> TopEnv a+ -> TopEnv a+importTopEnv m x y env = addImport m (qualify x) y env++-- |Insert an 'Entity' as qualified into a 'TopEnv'+qualImportTopEnv :: Entity a => ModuleIdent -> Ident -> a -> TopEnv a+ -> TopEnv a+qualImportTopEnv m x y env = addImport m (qualifyWith m x) y env++-- local helper+addImport :: Entity a => ModuleIdent -> QualIdent -> a -> TopEnv a+ -> TopEnv a+addImport m k v (TopEnv env) = TopEnv $+ Map.insert k (mergeImport v (entities k env)) env+ where+ mergeImport :: Entity a => a -> [(Source, a)] -> [(Source, a)]+ mergeImport y [] = [(Import [m], y)]+ mergeImport y (loc@(Local , _) : xs) = loc : mergeImport y xs+ mergeImport y (imp@(Import ms, y') : xs) = case merge y y' of+ Just y'' -> (Import (m : ms), y'') : xs+ Nothing -> imp : mergeImport y xs++bindTopEnv :: Ident -> a -> TopEnv a -> TopEnv a+bindTopEnv x y env = qualBindTopEnv (qualify x) y env++qualBindTopEnv :: QualIdent -> a -> TopEnv a -> TopEnv a+qualBindTopEnv x y (TopEnv env)+ = TopEnv $ Map.insert x (bindLocal y (entities x env)) env+ where+ bindLocal y' ys+ | null [ y'' | (Local, y'') <- ys ] = (Local, y') : ys+ | otherwise = internalError $ "qualBindTopEnv " ++ show x++rebindTopEnv :: Ident -> a -> TopEnv a -> TopEnv a+rebindTopEnv = qualRebindTopEnv . qualify++qualRebindTopEnv :: QualIdent -> a -> TopEnv a -> TopEnv a+qualRebindTopEnv x y (TopEnv env) =+ TopEnv $ Map.insert x (rebindLocal (entities x env)) env+ where+ rebindLocal [] = internalError+ $ "TopEnv.qualRebindTopEnv " ++ show x+ rebindLocal ((Local, _) : ys) = (Local, y) : ys+ rebindLocal (imported : ys) = imported : rebindLocal ys++unbindTopEnv :: Ident -> TopEnv a -> TopEnv a+unbindTopEnv x (TopEnv env) =+ TopEnv $ Map.insert x' (unbindLocal (entities x' env)) env+ where x' = qualify x+ unbindLocal [] = internalError $ "TopEnv.unbindTopEnv " ++ show x+ unbindLocal ((Local, _) : ys) = ys+ unbindLocal (imported : ys) = imported : unbindLocal ys++qualUnbindTopEnv :: QualIdent -> TopEnv a -> TopEnv a+qualUnbindTopEnv x (TopEnv env) =+ TopEnv $ Map.insert x (unbind (entities x env)) env+ where unbind [] = internalError $ "TopEnv.qualUnbindTopEnv " ++ show x+ unbind _ = []++lookupTopEnv :: Ident -> TopEnv a -> [a]+lookupTopEnv = qualLookupTopEnv . qualify++qualLookupTopEnv :: QualIdent -> TopEnv a -> [a]+qualLookupTopEnv x (TopEnv env) = map snd (entities x env)++qualElemTopEnv :: QualIdent -> TopEnv a -> Bool+qualElemTopEnv x env = not (null (qualLookupTopEnv x env))++allImports :: TopEnv a -> [(QualIdent, a)]+allImports (TopEnv env) =+ [ (x, y) | (x, ys) <- Map.toList env, (Import _, y) <- ys ]++unqualBindings :: TopEnv a -> [(Ident, (Source, a))]+unqualBindings (TopEnv env) =+ [ (x', y) | (x, ys) <- filter (not . isQualified . fst) (Map.toList env)+ , let x' = unqualify x, y <- ys]++moduleImports :: ModuleIdent -> TopEnv a -> [(Ident, a)]+moduleImports m env =+ [(x, y) | (x, (Import ms, y)) <- unqualBindings env, m `elem` ms]++localBindings :: TopEnv a -> [(Ident, a)]+localBindings env = [ (x, y) | (x, (Local, y)) <- unqualBindings env ]++allLocalBindings :: TopEnv a -> [(QualIdent, a)]+allLocalBindings (TopEnv env) = [ (x, y) | (x, ys) <- Map.toList env+ , (Local, y) <- ys ]++allBindings :: TopEnv a -> [(QualIdent, a)]+allBindings (TopEnv env) = [(x, y) | (x, ys) <- Map.toList env, (_, y) <- ys]++allEntities :: TopEnv a -> [a]+allEntities (TopEnv env) = [ y | (_, ys) <- Map.toList env, (_, y) <- ys]
+ src/Base/TypeExpansion.hs view
@@ -0,0 +1,112 @@+{- |+ Module : $Header$+ Description : Type expansion+ Copyright : (c) 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module implements expansion of alias types in types and predicates.+-}++module Base.TypeExpansion+ ( module Base.TypeExpansion+ ) where++import qualified Data.Set.Extra as Set (map)++import Curry.Base.Ident+import Curry.Syntax++import Base.CurryTypes+import Base.Messages+import Base.Types+import Base.TypeSubst++import Env.Class+import Env.TypeConstructor++-- The function 'expandType' expands all type synonyms in a type+-- and also qualifies all type constructors with the name of the module+-- in which the type was defined. Similarly, 'expandPred' expands all+-- type synonyms in a predicate and also qualifies all class identifiers+-- with the name of the module in which the class was defined. The+-- function 'expandPredSet' minimizes the predicate set after expansion.++expandType :: ModuleIdent -> TCEnv -> Type -> Type+expandType m tcEnv ty = expandType' m tcEnv ty []++expandType' :: ModuleIdent -> TCEnv -> Type -> [Type] -> Type+expandType' m tcEnv (TypeConstructor tc) tys =+ case qualLookupTypeInfo tc tcEnv of+ [DataType tc' _ _ ] -> applyType (TypeConstructor tc') tys+ [RenamingType tc' _ _ ] -> applyType (TypeConstructor tc') tys+ [AliasType _ _ n ty] -> let (tys', tys'') = splitAt n tys+ in applyType (expandAliasType tys' ty) tys''+ _ -> case qualLookupTypeInfo (qualQualify m tc) tcEnv of+ [DataType tc' _ _ ] -> applyType (TypeConstructor tc') tys+ [RenamingType tc' _ _ ] -> applyType (TypeConstructor tc') tys+ [AliasType _ _ n ty] -> let (tys', tys'') = splitAt n tys+ in applyType (expandAliasType tys' ty) tys''+ _ -> internalError $ "Base.TypeExpansion.expandType: " ++ show tc+expandType' m tcEnv (TypeApply ty1 ty2) tys =+ expandType' m tcEnv ty1 (expandType m tcEnv ty2 : tys)+expandType' _ _ tv@(TypeVariable _) tys = applyType tv tys+expandType' _ _ tc@(TypeConstrained _ _) tys = applyType tc tys+expandType' m tcEnv (TypeArrow ty1 ty2) tys =+ applyType (TypeArrow (expandType m tcEnv ty1) (expandType m tcEnv ty2)) tys+expandType' m tcEnv (TypeForall tvs ty) tys =+ applyType (TypeForall tvs (expandType m tcEnv ty)) tys++expandPred :: ModuleIdent -> TCEnv -> Pred -> Pred+expandPred m tcEnv (Pred qcls ty) = case qualLookupTypeInfo qcls tcEnv of+ [TypeClass ocls _ _] -> Pred ocls (expandType m tcEnv ty)+ _ -> case qualLookupTypeInfo (qualQualify m qcls) tcEnv of+ [TypeClass ocls _ _] -> Pred ocls (expandType m tcEnv ty)+ _ -> internalError $ "Base.TypeExpansion.expandPred: " ++ show qcls++expandPredSet :: ModuleIdent -> TCEnv -> ClassEnv -> PredSet -> PredSet+expandPredSet m tcEnv clsEnv = minPredSet clsEnv . Set.map (expandPred m tcEnv)++expandPredType :: ModuleIdent -> TCEnv -> ClassEnv -> PredType -> PredType+expandPredType m tcEnv clsEnv (PredType ps ty) =+ PredType (expandPredSet m tcEnv clsEnv ps) (expandType m tcEnv ty)++-- The functions 'expandMonoType' and 'expandPolyType' convert (qualified)+-- type expressions into (predicated) types and also expand all type synonyms+-- and qualify all type constructors during the conversion.++expandMonoType :: ModuleIdent -> TCEnv -> [Ident] -> TypeExpr -> Type+expandMonoType m tcEnv tvs = expandType m tcEnv . toType tvs++expandPolyType :: ModuleIdent -> TCEnv -> ClassEnv -> QualTypeExpr -> PredType+expandPolyType m tcEnv clsEnv =+ normalize 0 . expandPredType m tcEnv clsEnv . toPredType []++-- The function 'expandConstrType' computes the predicated type for a data+-- or newtype constructor. Similar to 'toConstrType' from 'CurryTypes', the+-- type's context is restricted to those type variables which are free in+-- the argument types. However, type synonyms are expanded and type constructors+-- and type classes are qualified with the name of the module containing their+-- definition.++expandConstrType :: ModuleIdent -> TCEnv -> ClassEnv -> QualIdent -> [Ident]+ -> [TypeExpr] -> PredType+expandConstrType m tcEnv clsEnv tc tvs tys =+ normalize n $ expandPredType m tcEnv clsEnv pty+ where n = length tvs+ pty = toConstrType tc tvs tys++-- The function 'expandMethodType' converts the type of a type class method+-- Similar to function 'toMethodType' from 'CurryTypes', the implicit class+-- constraint is added to the method's type and the class' type variable is+-- assigned index 0. However, type synonyms are expanded and type constructors+-- and type classes are qualified with the name of the module containing their+-- definition.++expandMethodType :: ModuleIdent -> TCEnv -> ClassEnv -> QualIdent -> Ident+ -> QualTypeExpr -> PredType+expandMethodType m tcEnv clsEnv qcls tv =+ normalize 1 . expandPredType m tcEnv clsEnv . toMethodType qcls tv
+ src/Base/TypeSubst.hs view
@@ -0,0 +1,137 @@+{- |+ Module : $Header$+ Description : Type substitution+ Copyright : (c) 2003 Wolfgang Lux+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module implements substitutions on types.+-}++module Base.TypeSubst+ ( module Base.TypeSubst, idSubst, singleSubst, bindSubst, compose+ ) where++import Data.List (nub)+import Data.Maybe (fromMaybe)+import qualified Data.Set as Set (Set, map)++import Base.Subst+import Base.TopEnv+import Base.Types++import Env.Value (ValueInfo (..))++type TypeSubst = Subst Int Type++class SubstType a where+ subst :: TypeSubst -> a -> a++bindVar :: Int -> Type -> TypeSubst -> TypeSubst+bindVar tv ty = compose (bindSubst tv ty idSubst)++substVar :: TypeSubst -> Int -> Type+substVar = substVar' TypeVariable subst++instance (Ord a, SubstType a) => SubstType (Set.Set a) where+ subst sigma = Set.map (subst sigma)++instance SubstType a => SubstType [a] where+ subst sigma = map (subst sigma)++instance SubstType Type where+ subst sigma ty = subst' sigma ty []++subst' :: TypeSubst -> Type -> [Type] -> Type+subst' _ tc@(TypeConstructor _) = foldl TypeApply tc+subst' sigma (TypeApply ty1 ty2) = subst' sigma ty1 . (subst sigma ty2 :)+subst' sigma (TypeVariable tv) = applyType (substVar sigma tv)+subst' sigma (TypeArrow ty1 ty2) =+ foldl TypeApply (TypeArrow (subst sigma ty1) (subst sigma ty2))+subst' sigma (TypeConstrained tys tv) = case substVar sigma tv of+ TypeVariable tv' -> foldl TypeApply (TypeConstrained tys tv')+ ty -> foldl TypeApply ty+subst' sigma (TypeForall tvs ty) =+ applyType (TypeForall tvs (subst sigma ty))++instance SubstType Pred where+ subst sigma (Pred qcls ty) = Pred qcls (subst sigma ty)++instance SubstType PredType where+ subst sigma (PredType ps ty) = PredType (subst sigma ps) (subst sigma ty)++instance SubstType TypeScheme where+ subst sigma (ForAll n ty) =+ ForAll n (subst (foldr unbindSubst sigma [0 .. n-1]) ty)++instance SubstType ValueInfo where+ subst _ dc@(DataConstructor _ _ _ _) = dc+ subst _ nc@(NewtypeConstructor _ _ _) = nc+ subst theta (Value v cm a ty) = Value v cm a (subst theta ty)+ subst theta (Label l r ty) = Label l r (subst theta ty)++instance SubstType a => SubstType (TopEnv a) where+ subst = fmap . subst++-- The class method 'expandAliasType' expands all occurrences of a+-- type synonym in its second argument.++class ExpandAliasType a where+ expandAliasType :: [Type] -> a -> a++instance ExpandAliasType a => ExpandAliasType [a] where+ expandAliasType tys = map (expandAliasType tys)++instance (Ord a, ExpandAliasType a) => ExpandAliasType (Set.Set a) where+ expandAliasType tys = Set.map (expandAliasType tys)++instance ExpandAliasType Type where+ expandAliasType tys ty = expandAliasType' tys ty []++expandAliasType' :: [Type] -> Type -> [Type] -> Type+expandAliasType' _ tc@(TypeConstructor _) = applyType tc+expandAliasType' tys (TypeApply ty1 ty2) =+ expandAliasType' tys ty1 . (expandAliasType tys ty2 :)+expandAliasType' tys tv@(TypeVariable n)+ | n >= 0 = applyType (tys !! n)+ | otherwise = applyType tv+expandAliasType' _ tc@(TypeConstrained _ _) = applyType tc+expandAliasType' tys (TypeArrow ty1 ty2) =+ applyType (TypeArrow (expandAliasType tys ty1) (expandAliasType tys ty2))+expandAliasType' tys (TypeForall tvs ty) =+ applyType (TypeForall tvs (expandAliasType tys ty))++instance ExpandAliasType Pred where+ expandAliasType tys (Pred qcls ty) = Pred qcls (expandAliasType tys ty)++instance ExpandAliasType PredType where+ expandAliasType tys (PredType ps ty) =+ PredType (expandAliasType tys ps) (expandAliasType tys ty)++-- After the expansion we have to reassign the type indices for all type+-- variables. Otherwise, expanding a type synonym like type 'Pair a b = (b,a)'+-- could break the invariant that the universally quantified type variables+-- are assigned indices in the order of their occurrence. This is handled by+-- the function 'normalize'. The function has a threshold parameter that allows+-- preserving the indices of type variables bound on the left hand side+-- of a type declaration and in the head of a type class declaration,+-- respectively.++normalize :: Int -> PredType -> PredType+normalize n ty = expandAliasType [TypeVariable (occur tv) | tv <- [0..]] ty+ where tvs = zip (nub (filter (>= n) (typeVars ty))) [n..]+ occur tv = fromMaybe tv (lookup tv tvs)++-- The function 'instanceType' computes an instance of a polymorphic type by+-- substituting the first type argument for all occurrences of the type+-- variable with index 0 in the second argument. The function carefully+-- assigns new indices to all other type variables of the second argument+-- so that they do not conflict with the type variables of the first argument.++instanceType :: ExpandAliasType a => Type -> a -> a+instanceType ty = expandAliasType (ty : map TypeVariable [n ..])+ where ForAll n _ = polyType ty
+ src/Base/Types.hs view
@@ -0,0 +1,478 @@+{- |+ Module : $Header$+ Description : Internal representation of types+ Copyright : (c) 2002 - 2004 Wolfgang Lux+ Martin Engelke+ 2015 Jan Tikovsky+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module modules provides the definitions for the internal+ representation of types in the compiler along with some helper functions.+-}++-- TODO: Use MultiParamTypeClasses ?++module Base.Types+ ( -- * Representation of types+ Type (..), applyType, unapplyType, rootOfType+ , isArrowType, arrowArity, arrowArgs, arrowBase, arrowUnapply+ , IsType (..), typeConstrs+ , qualifyType, unqualifyType, qualifyTC+ -- * Representation of predicate, predicate sets and predicated types+ , Pred (..), qualifyPred, unqualifyPred+ , PredSet, emptyPredSet, partitionPredSet, minPredSet, maxPredSet+ , qualifyPredSet, unqualifyPredSet+ , PredType (..), predType, unpredType, qualifyPredType, unqualifyPredType+ -- * Representation of data constructors+ , DataConstr (..), constrIdent, constrTypes, recLabels, recLabelTypes+ , tupleData+ -- * Representation of class methods+ , ClassMethod (..), methodName, methodArity, methodType+ -- * Representation of quantification+ , TypeScheme (..), monoType, polyType, typeScheme+ , rawType+ -- * Predefined types+ , arrowType, unitType, predUnitType, boolType, predBoolType, charType+ , intType, predIntType, floatType, predFloatType, stringType, predStringType+ , listType, consType, ioType, tupleType+ , numTypes, fractionalTypes+ , predefTypes+ ) where++import qualified Data.Set.Extra as Set++import Curry.Base.Ident++import Base.Messages (internalError)++import Env.Class (ClassEnv, allSuperClasses)++-- ---------------------------------------------------------------------------+-- Types+-- ---------------------------------------------------------------------------++-- A type is either a type constructor, a type variable, an application+-- of a type to another type, or an arrow type. Although the latter could+-- be expressed by using 'TypeApply' with the function type constructor,+-- we currently use 'TypeArrow' because arrow types are used so frequently.++-- The 'TypeConstrained' case is used for representing type variables that+-- are restricted to a particular set of types. At present, this is used+-- for typing integer literals, which are restricted to types 'Int' and+-- 'Float'. If the type is not restricted, it defaults to the first type+-- from the constraint list.++-- Type variables are represented with deBruijn style indices. Universally+-- quantified type variables are assigned indices in the order of their+-- occurrence in the type from left to right. This leads to a canonical+-- representation of types where alpha-equivalence of two types+-- coincides with equality of the representation.++-- Note that even though 'TypeConstrained' variables use indices+-- as well, these variables must never be quantified.++-- Note further that the order of constructors is important for the derived+-- 'Ord' instance. In particular, it is essential that the type variable+-- is considered less than the type application (see predicates and predicate+-- sets below for more information).++data Type+ = TypeConstructor QualIdent+ | TypeVariable Int+ | TypeConstrained [Type] Int+ | TypeApply Type Type+ | TypeArrow Type Type+ | TypeForall [Int] Type+ deriving (Eq, Ord, Show)++-- The function 'applyType' applies a type to a list of argument types,+-- whereas applications of the function type constructor to two arguments+-- are converted into an arrow type. The function 'unapplyType' decomposes+-- a type into a root type and a list of argument types.++applyType :: Type -> [Type] -> Type+applyType (TypeConstructor tc) tys+ | tc == qArrowId && length tys == 2 = TypeArrow (tys !! 0) (tys !! 1)+applyType (TypeApply (TypeConstructor tc) ty) tys+ | tc == qArrowId && length tys == 1 = TypeArrow ty (head tys)+applyType ty tys = foldl TypeApply ty tys++unapplyType :: Bool -> Type -> (Type, [Type])+unapplyType dflt ty = unapply ty []+ where+ unapply (TypeConstructor tc) tys = (TypeConstructor tc, tys)+ unapply (TypeApply ty1 ty2) tys = unapply ty1 (ty2 : tys)+ unapply (TypeVariable tv) tys = (TypeVariable tv, tys)+ unapply (TypeArrow ty1 ty2) tys =+ (TypeConstructor qArrowId, ty1 : ty2 : tys)+ unapply (TypeConstrained tys tv) tys'+ | dflt = unapply (head tys) tys'+ | otherwise = (TypeConstrained tys tv, tys')+ unapply (TypeForall tvs ty') tys = (TypeForall tvs ty', tys)++-- The function 'rootOfType' returns the name of the type constructor at the+-- root of a type. This function must not be applied to a type whose root is+-- a type variable or a skolem type.++rootOfType :: Type -> QualIdent+rootOfType ty = case fst (unapplyType True ty) of+ TypeConstructor tc -> tc+ _ -> internalError $ "Base.Types.rootOfType: " ++ show ty++-- The function 'isArrowType' checks whether a type is a function+-- type t_1 -> t_2 -> ... -> t_n. The function 'arrowArity' computes+-- the arity n of a function type, 'arrowArgs' computes the types+-- t_1 ... t_n-1 and 'arrowBase' returns the type t_n. 'arrowUnapply'+-- combines 'arrowArgs' and 'arrowBase' in one call.++isArrowType :: Type -> Bool+isArrowType (TypeArrow _ _) = True+isArrowType _ = False++arrowArity :: Type -> Int+arrowArity = length. arrowArgs++arrowArgs :: Type -> [Type]+arrowArgs = fst . arrowUnapply++arrowBase :: Type -> Type+arrowBase = snd. arrowUnapply++arrowUnapply :: Type -> ([Type], Type)+arrowUnapply (TypeArrow ty1 ty2) = (ty1 : tys, ty)+ where (tys, ty) = arrowUnapply ty2+arrowUnapply ty = ([], ty)++-- The function 'typeConstrs' returns a list of all type constructors+-- occuring in a type t.++typeConstrs :: Type -> [QualIdent]+typeConstrs ty = constrs ty [] where+ constrs (TypeConstructor tc) tcs = tc : tcs+ constrs (TypeApply ty1 ty2) tcs = constrs ty1 (constrs ty2 tcs)+ constrs (TypeVariable _) tcs = tcs+ constrs (TypeConstrained _ _) tcs = tcs+ constrs (TypeArrow ty1 ty2) tcs = constrs ty1 (constrs ty2 tcs)+ constrs (TypeForall _ ty') tcs = constrs ty' tcs++-- The method 'typeVars' returns a list of all type variables occurring in a+-- type t. Note that 'TypeConstrained' variables are not included in the set of+-- type variables because they cannot be generalized.++class IsType t where+ typeVars :: t -> [Int]++instance IsType Type where+ typeVars = typeVars'++typeVars' :: Type -> [Int]+typeVars' ty = vars ty [] where+ vars (TypeConstructor _) tvs = tvs+ vars (TypeApply ty1 ty2) tvs = vars ty1 (vars ty2 tvs)+ vars (TypeVariable tv) tvs = tv : tvs+ vars (TypeConstrained _ _) tvs = tvs+ vars (TypeArrow ty1 ty2) tvs = vars ty1 (vars ty2 tvs)+ vars (TypeForall tvs' ty') tvs = filter (`notElem` tvs') (typeVars' ty') ++ tvs++-- The functions 'qualifyType' and 'unqualifyType' add/remove the+-- qualification with a module identifier for type constructors.++qualifyType :: ModuleIdent -> Type -> Type+qualifyType m (TypeConstructor tc) = TypeConstructor (qualifyTC m tc)+qualifyType m (TypeApply ty1 ty2) =+ TypeApply (qualifyType m ty1) (qualifyType m ty2)+qualifyType _ tv@(TypeVariable _) = tv+qualifyType m (TypeConstrained tys tv) =+ TypeConstrained (map (qualifyType m) tys) tv+qualifyType m (TypeArrow ty1 ty2) =+ TypeArrow (qualifyType m ty1) (qualifyType m ty2)+qualifyType m (TypeForall tvs ty) = TypeForall tvs (qualifyType m ty)++unqualifyType :: ModuleIdent -> Type -> Type+unqualifyType m (TypeConstructor tc) = TypeConstructor (qualUnqualify m tc)+unqualifyType m (TypeApply ty1 ty2) =+ TypeApply (unqualifyType m ty1) (unqualifyType m ty2)+unqualifyType _ tv@(TypeVariable _) = tv+unqualifyType m (TypeConstrained tys tv) =+ TypeConstrained (map (unqualifyType m) tys) tv+unqualifyType m (TypeArrow ty1 ty2) =+ TypeArrow (unqualifyType m ty1) (unqualifyType m ty2)+unqualifyType m (TypeForall tvs ty) = TypeForall tvs (unqualifyType m ty)++qualifyTC :: ModuleIdent -> QualIdent -> QualIdent+qualifyTC m tc | isPrimTypeId tc = tc+ | otherwise = qualQualify m tc++-- ---------------------------------------------------------------------------+-- Predicates+-- ---------------------------------------------------------------------------++data Pred = Pred QualIdent Type+ deriving (Eq, Show)++-- We provide a custom 'Ord' instance for predicates here where we consider+-- the type component of the predicate before the class component. This way,+-- we ensure that a class method's implicit class constraint is always the+-- minimum w.r.t. this order, because the type expression for that constraint+-- is a type variable with index 0 and there are no other class constraints+-- in a predicate set that constraint the same type variable as restrictions+-- on class variables are not allowed (see predicate sets below for more+-- information why this order is relevant).++instance Ord Pred where+ Pred qcls1 ty1 `compare` Pred qcls2 ty2 = case ty1 `compare` ty2 of+ LT -> LT+ EQ -> qcls1 `compare` qcls2+ GT -> GT++instance IsType Pred where+ typeVars (Pred _ ty) = typeVars ty++qualifyPred :: ModuleIdent -> Pred -> Pred+qualifyPred m (Pred qcls ty) = Pred (qualQualify m qcls) (qualifyType m ty)++unqualifyPred :: ModuleIdent -> Pred -> Pred+unqualifyPred m (Pred qcls ty) =+ Pred (qualUnqualify m qcls) (unqualifyType m ty)++-- ---------------------------------------------------------------------------+-- Predicate sets+-- ---------------------------------------------------------------------------++-- A predicate set is an ordered set of predicates. This way, we do not+-- have to manually take care of duplicate predicates and have automatically+-- achieved a canonical representation (as only original names for type classes+-- are used). Having the order on types and predicates in mind, we have also+-- ensured that a class method's implicit class constraint is always the minimum+-- element of a method's predicate set, thus making it very easy to remove it.++type PredSet = Set.Set Pred++instance (IsType a, Ord a) => IsType (Set.Set a) where+ typeVars = concat . Set.toList . Set.map typeVars++emptyPredSet :: PredSet+emptyPredSet = Set.empty++partitionPredSet :: PredSet -> (PredSet, PredSet)+partitionPredSet = Set.partition $ \(Pred _ ty) -> isTypeVariable ty+ where+ isTypeVariable (TypeVariable _) = True+ isTypeVariable (TypeApply ty _) = isTypeVariable ty+ isTypeVariable _ = False++-- The function 'minPredSet' transforms a predicate set by removing all+-- predicates from the predicate set which are implied by other predicates+-- according to the super class hierarchy. Inversely, the function 'maxPredSet'+-- adds all predicates to a predicate set which are implied by the predicates+-- in the given predicate set.++minPredSet :: ClassEnv -> PredSet -> PredSet+minPredSet clsEnv ps =+ ps `Set.difference` Set.concatMap implied ps+ where implied (Pred cls ty) = Set.fromList+ [Pred cls' ty | cls' <- tail (allSuperClasses cls clsEnv)]++maxPredSet :: ClassEnv -> PredSet -> PredSet+maxPredSet clsEnv ps = Set.concatMap implied ps+ where implied (Pred cls ty) = Set.fromList+ [Pred cls' ty | cls' <- allSuperClasses cls clsEnv]++qualifyPredSet :: ModuleIdent -> PredSet -> PredSet+qualifyPredSet m = Set.map (qualifyPred m)++unqualifyPredSet :: ModuleIdent -> PredSet -> PredSet+unqualifyPredSet m = Set.map (unqualifyPred m)++-- ---------------------------------------------------------------------------+-- Predicated types+-- ---------------------------------------------------------------------------++data PredType = PredType PredSet Type+ deriving (Eq, Show)++-- When enumarating the type variables and skolems of a predicated type, we+-- consider the type variables occuring in the predicate set after the ones+-- occuring in the type itself.++instance IsType PredType where+ typeVars (PredType ps ty) = typeVars ty ++ typeVars ps++predType :: Type -> PredType+predType = PredType emptyPredSet++unpredType :: PredType -> Type+unpredType (PredType _ ty) = ty++qualifyPredType :: ModuleIdent -> PredType -> PredType+qualifyPredType m (PredType ps ty) =+ PredType (qualifyPredSet m ps) (qualifyType m ty)++unqualifyPredType :: ModuleIdent -> PredType -> PredType+unqualifyPredType m (PredType ps ty) =+ PredType (unqualifyPredSet m ps) (unqualifyType m ty)++-- ---------------------------------------------------------------------------+-- Data constructors+-- ---------------------------------------------------------------------------++-- The type 'DataConstr' is used to represent value or record constructors+-- introduced by data or newtype declarations.++data DataConstr = DataConstr Ident [Type]+ | RecordConstr Ident [Ident] [Type]+ deriving (Eq, Show)++constrIdent :: DataConstr -> Ident+constrIdent (DataConstr c _) = c+constrIdent (RecordConstr c _ _) = c++constrTypes :: DataConstr -> [Type]+constrTypes (DataConstr _ tys) = tys+constrTypes (RecordConstr _ _ tys) = tys++recLabels :: DataConstr -> [Ident]+recLabels (DataConstr _ _) = []+recLabels (RecordConstr _ ls _) = ls++recLabelTypes :: DataConstr -> [Type]+recLabelTypes (DataConstr _ _) = []+recLabelTypes (RecordConstr _ _ tys) = tys++tupleData :: [DataConstr]+tupleData = [DataConstr (tupleId n) (take n tvs) | n <- [2 ..]]+ where tvs = map TypeVariable [0 ..]++-- ---------------------------------------------------------------------------+-- Class methods+-- ---------------------------------------------------------------------------++-- The type 'ClassMethod' is used to represent class methods introduced+-- by class declarations. The 'Maybe Int' denotes the arity of the provided+-- default implementation.++data ClassMethod = ClassMethod Ident (Maybe Int) PredType+ deriving (Eq, Show)++methodName :: ClassMethod -> Ident+methodName (ClassMethod f _ _) = f++methodArity :: ClassMethod -> Maybe Int+methodArity (ClassMethod _ a _) = a++methodType :: ClassMethod -> PredType+methodType (ClassMethod _ _ pty) = pty++-- ---------------------------------------------------------------------------+-- Quantification+-- ---------------------------------------------------------------------------++-- We support only universally quantified type schemes+-- (forall alpha . tau(alpha)). Quantified type variables are assigned+-- ascending indices starting from 0. Therefore it is sufficient to record the+-- numbers of quantified type variables in the 'ForAll' constructor.++data TypeScheme = ForAll Int PredType deriving (Eq, Show)++instance IsType TypeScheme where+ typeVars (ForAll _ pty) = [tv | tv <- typeVars pty, tv < 0]++-- The functions 'monoType' and 'polyType' translate a type tau into a+-- monomorphic type scheme and a polymorphic type scheme, respectively.+-- 'polyType' assumes that all universally quantified variables in the type are+-- assigned indices starting with 0 and does not renumber the variables.++monoType :: Type -> TypeScheme+monoType = ForAll 0 . predType++polyType :: Type -> TypeScheme+polyType = typeScheme . predType++typeScheme :: PredType -> TypeScheme+typeScheme pty = ForAll (maximum (-1 : typeVars pty) + 1) pty++-- The function 'rawType' strips the quantifier and predicate set from a+-- type scheme.++rawType :: TypeScheme -> Type+rawType (ForAll _ (PredType _ ty)) = ty++-- ---------------------------------------------------------------------------+-- Predefined types+-- ---------------------------------------------------------------------------++primType :: QualIdent -> [Type] -> Type+primType = applyType . TypeConstructor++arrowType :: Type -> Type -> Type+arrowType ty1 ty2 = primType qArrowId [ty1, ty2]++unitType :: Type+unitType = primType qUnitId []++predUnitType :: PredType+predUnitType = predType unitType++boolType :: Type+boolType = primType qBoolId []++predBoolType :: PredType+predBoolType = predType boolType++charType :: Type+charType = primType qCharId []++intType :: Type+intType = primType qIntId []++predIntType :: PredType+predIntType = predType intType++floatType :: Type+floatType = primType qFloatId []++predFloatType :: PredType+predFloatType = predType floatType++stringType :: Type+stringType = listType charType++predStringType :: PredType+predStringType = predType stringType++listType :: Type -> Type+listType ty = primType qListId [ty]++consType :: Type -> Type+consType ty = TypeArrow ty (TypeArrow (listType ty) (listType ty))++ioType :: Type -> Type+ioType ty = primType qIOId [ty]++tupleType :: [Type] -> Type+tupleType tys = primType (qTupleId (length tys)) tys++-- 'numTypes' and 'fractionalTypes' define the eligible types for+-- numeric literals in patterns.++numTypes :: [Type]+numTypes = [intType, floatType]++fractionalTypes :: [Type]+fractionalTypes = drop 1 numTypes++predefTypes :: [(Type, [DataConstr])]+predefTypes =+ [ (arrowType a b, [])+ , (unitType , [ DataConstr unitId [] ])+ , (listType a , [ DataConstr nilId []+ , DataConstr consId [a, listType a]+ ])+ ]+ where a = TypeVariable 0+ b = TypeVariable 1
+ src/Base/Typing.hs view
@@ -0,0 +1,190 @@+{- |+ Module : $Header$+ Description : Type computation of Curry expressions+ Copyright : (c) 2003 - 2006 Wolfgang Lux+ 2014 - 2015 Jan Tikovsky+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ After the compiler has attributed patterns and expressions with type+ information during type inference, it is straightforward to recompute+ the type of every pattern and expression. Since all annotated types+ are monomorphic, there is no need to instantiate any variables or+ perform any (non-trivial) unifications.+-}++module Base.Typing+ ( Typeable (..)+ , withType, matchType+ , bindDecls, bindDecl, bindPatterns, bindPattern, declVars, patternVars+ ) where++import Data.List (nub)+import Data.Maybe (fromMaybe)++import Curry.Base.Ident+import Curry.Syntax++import Base.Messages (internalError)+import Base.Types+import Base.TypeSubst+import Base.Utils (fst3)++import Env.Value++class Typeable a where+ typeOf :: a -> Type++instance Typeable Type where+ typeOf = id++instance Typeable PredType where+ typeOf = unpredType++instance Typeable a => Typeable (Rhs a) where+ typeOf (SimpleRhs _ _ e _ ) = typeOf e+ typeOf (GuardedRhs _ _ es _) = head [typeOf e | CondExpr _ _ e <- es]++instance Typeable a => Typeable (Pattern a) where+ typeOf (LiteralPattern _ a _) = typeOf a+ typeOf (NegativePattern _ a _) = typeOf a+ typeOf (VariablePattern _ a _) = typeOf a+ typeOf (ConstructorPattern _ a _ _) = typeOf a+ typeOf (InfixPattern _ a _ _ _) = typeOf a+ typeOf (ParenPattern _ t) = typeOf t+ typeOf (RecordPattern _ a _ _) = typeOf a+ typeOf (TuplePattern _ ts) = tupleType $ map typeOf ts+ typeOf (ListPattern _ a _) = typeOf a+ typeOf (AsPattern _ _ t) = typeOf t+ typeOf (LazyPattern _ t) = typeOf t+ typeOf (FunctionPattern _ a _ _) = typeOf a+ typeOf (InfixFuncPattern _ a _ _ _) = typeOf a++instance Typeable a => Typeable (Expression a) where+ typeOf (Literal _ a _) = typeOf a+ typeOf (Variable _ a _) = typeOf a+ typeOf (Constructor _ a _) = typeOf a+ typeOf (Paren _ e) = typeOf e+ typeOf (Typed _ e _) = typeOf e+ typeOf (Record _ a _ _) = typeOf a+ typeOf (RecordUpdate _ e _) = typeOf e+ typeOf (Tuple _ es) = tupleType (map typeOf es)+ typeOf (List _ a _) = typeOf a+ typeOf (ListCompr _ e _) = listType (typeOf e)+ typeOf (EnumFrom _ e) = listType (typeOf e)+ typeOf (EnumFromThen _ e _) = listType (typeOf e)+ typeOf (EnumFromTo _ e _) = listType (typeOf e)+ typeOf (EnumFromThenTo _ e _ _) = listType (typeOf e)+ typeOf (UnaryMinus _ e) = typeOf e+ typeOf (Apply _ e _) = case typeOf e of+ TypeArrow _ ty -> ty+ _ -> internalError "Base.Typing.typeOf: application"+ typeOf (InfixApply _ _ op _) = case typeOf (infixOp op) of+ TypeArrow _ (TypeArrow _ ty) -> ty+ _ -> internalError "Base.Typing.typeOf: infix application"+ typeOf (LeftSection _ _ op) = case typeOf (infixOp op) of+ TypeArrow _ ty -> ty+ _ -> internalError "Base.Typing.typeOf: left section"+ typeOf (RightSection _ op _) = case typeOf (infixOp op) of+ TypeArrow ty1 (TypeArrow _ ty2) -> TypeArrow ty1 ty2+ _ -> internalError "Base.Typing.typeOf: right section"+ typeOf (Lambda _ ts e) = foldr (TypeArrow . typeOf) (typeOf e) ts+ typeOf (Let _ _ _ e) = typeOf e+ typeOf (Do _ _ _ e) = typeOf e+ typeOf (IfThenElse _ _ e _) = typeOf e+ typeOf (Case _ _ _ _ as) = typeOf $ head as++instance Typeable a => Typeable (Alt a) where+ typeOf (Alt _ _ rhs) = typeOf rhs++-- When inlining variable and function definitions, the compiler must+-- eventually update the type annotations of the inlined expression. To+-- that end, the variable or function's annotated type and the type of+-- the inlined expression must be unified. Since the program is type+-- correct, this unification is just a simple one way matching where we+-- only need to match the type variables in the inlined expression's type+-- with the corresponding types in the variable or function's annotated+-- type.++withType :: (Functor f, Typeable (f Type)) => Type -> f Type -> f Type+withType ty e = fmap (subst (matchType (typeOf e) ty idSubst)) e++matchType :: Type -> Type -> TypeSubst -> TypeSubst+matchType ty1 ty2 = fromMaybe noMatch (matchType' ty1 ty2)+ where+ noMatch = internalError $ "Base.Typing.matchType: " +++ showsPrec 11 ty1 " " ++ showsPrec 11 ty2 ""++matchType' :: Type -> Type -> Maybe (TypeSubst -> TypeSubst)+matchType' (TypeVariable tv) ty+ | ty == TypeVariable tv = Just id+ | otherwise = Just (bindSubst tv ty)+matchType' (TypeConstructor tc1) (TypeConstructor tc2)+ | tc1 == tc2 = Just id+matchType' (TypeConstrained _ tv1) (TypeConstrained _ tv2)+ | tv1 == tv2 = Just id+matchType' (TypeApply ty11 ty12) (TypeApply ty21 ty22) =+ fmap (. matchType ty12 ty22) (matchType' ty11 ty21)+matchType' (TypeArrow ty11 ty12) (TypeArrow ty21 ty22) =+ Just (matchType ty11 ty21 . matchType ty12 ty22)+matchType' (TypeApply ty11 ty12) (TypeArrow ty21 ty22) =+ fmap (. matchType ty12 ty22)+ (matchType' ty11 (TypeApply (TypeConstructor qArrowId) ty21))+matchType' (TypeArrow ty11 ty12) (TypeApply ty21 ty22) =+ fmap (. matchType ty12 ty22)+ (matchType' (TypeApply (TypeConstructor qArrowId) ty11) ty21)+matchType' (TypeForall _ ty1) (TypeForall _ ty2) = matchType' ty1 ty2+matchType' (TypeForall _ ty1) ty2 = matchType' ty1 ty2+matchType' ty1 (TypeForall _ ty2) = matchType' ty1 ty2+matchType' _ _ = Nothing++-- The functions 'bindDecls', 'bindDecl', 'bindPatterns' and 'bindPattern'+-- augment the value environment with the types of the entities defined in+-- local declaration groups and patterns, respectively, using the types from+-- their type annotations.++bindDecls :: (Eq t, Typeable t, ValueType t) => [Decl t] -> ValueEnv -> ValueEnv+bindDecls = flip $ foldr bindDecl++bindDecl :: (Eq t, Typeable t, ValueType t) => Decl t -> ValueEnv -> ValueEnv+bindDecl d vEnv = bindLocalVars (filter unbound $ declVars d) vEnv+ where unbound v = null $ lookupValue (fst3 v) vEnv++bindPatterns :: (Eq t, Typeable t, ValueType t) => [Pattern t] -> ValueEnv+ -> ValueEnv+bindPatterns = flip $ foldr bindPattern++bindPattern :: (Eq t, Typeable t, ValueType t) => Pattern t -> ValueEnv+ -> ValueEnv+bindPattern t vEnv = bindLocalVars (filter unbound $ patternVars t) vEnv+ where unbound v = null $ lookupValue (fst3 v) vEnv++declVars :: (Eq t, Typeable t, ValueType t) => Decl t -> [(Ident, Int, t)]+declVars (InfixDecl _ _ _ _) = []+declVars (TypeSig _ _ _) = []+declVars (FunctionDecl _ ty f eqs) = [(f, eqnArity $ head eqs, ty)]+declVars (PatternDecl _ t _) = patternVars t+declVars (FreeDecl _ vs) = [(v, 0, ty) | Var ty v <- vs]+declVars _ = internalError "Base.Typing.declVars"++patternVars :: (Eq t, Typeable t, ValueType t) => Pattern t -> [(Ident, Int, t)]+patternVars (LiteralPattern _ _ _) = []+patternVars (NegativePattern _ _ _) = []+patternVars (VariablePattern _ ty v) = [(v, 0, ty)]+patternVars (ConstructorPattern _ _ _ ts) = concatMap patternVars ts+patternVars (InfixPattern _ _ t1 _ t2) = patternVars t1 ++ patternVars t2+patternVars (ParenPattern _ t) = patternVars t+patternVars (RecordPattern _ _ _ fs) =+ concat [patternVars t | Field _ _ t <- fs]+patternVars (TuplePattern _ ts) = concatMap patternVars ts+patternVars (ListPattern _ _ ts) = concatMap patternVars ts+patternVars (AsPattern _ v t) =+ (v, 0, toValueType $ typeOf t) : patternVars t+patternVars (LazyPattern _ t) = patternVars t+patternVars (FunctionPattern _ _ _ ts) = nub $ concatMap patternVars ts+patternVars (InfixFuncPattern _ _ t1 _ t2) =+ nub $ patternVars t1 ++ patternVars t2
+ src/Base/Utils.hs view
@@ -0,0 +1,94 @@+{- |+ Module : $Header$+ Description : Auxiliary functions+ Copyright : (c) 2001 - 2003 Wolfgang Lux+ 2011 - 2015 Björn Peemöler+ 2016 - 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : fte@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ The module Utils provides a few simple functions that are+ commonly used in the compiler, but not implemented in the Haskell+ Prelude or standard library.+-}++module Base.Utils+ ( fst3, snd3, thd3, curry3, uncurry3+ , (++!), foldr2, mapAccumM, findDouble, findMultiples+ ) where++import Control.Monad (MonadPlus, mzero, mplus)++import Data.List (partition)++infixr 5 ++!++-- The Prelude does not contain standard functions for triples.+-- We provide projection, (un-)currying, and mapping for triples here.++fst3 :: (a, b, c) -> a+fst3 (x, _, _) = x++snd3 :: (a, b, c) -> b+snd3 (_, y, _) = y++thd3 :: (a, b, c) -> c+thd3 (_, _, z) = z++curry3 :: ((a, b, c) -> d) -> a -> b -> c -> d+curry3 f x y z = f (x,y,z)++uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d+uncurry3 f (x, y, z) = f x y z++-- The function (++!) is variant of the list concatenation operator (++)+-- that ignores the second argument if the first is a non-empty list.+-- When lists are used to encode non-determinism in Haskell,+-- this operator has the same effect as the cut operator in Prolog,+-- hence the ! in the name.++(++!) :: [a] -> [a] -> [a]+xs ++! ys = if null xs then ys else xs++-- Fold operations with two arguments lists can be defined using+-- zip and foldl or foldr, resp. Our definitions are unfolded for+-- efficiency reasons.++-- foldl2 :: (a -> b -> c -> a) -> a -> [b] -> [c] -> a+-- foldl2 _ z [] _ = z+-- foldl2 _ z _ [] = z+-- foldl2 f z (x : xs) (y : ys) = foldl2 f (f z x y) xs ys++foldr2 :: (a -> b -> c -> c) -> c -> [a] -> [b] -> c+foldr2 _ z [] _ = z+foldr2 _ z _ [] = z+foldr2 f z (x : xs) (y : ys) = f x y (foldr2 f z xs ys)++mapAccumM :: (Monad m, MonadPlus p) => (acc -> x -> m (acc, y)) -> acc -> [x]+ -> m (acc, p y)+mapAccumM _ z [] = return (z, mzero)+mapAccumM f z (x:xs) = do+ (z', y) <- f z x+ (z'', ys) <- mapAccumM f z' xs+ return (z'', return y `mplus` ys)++-- The function 'findDouble' checks whether a list of entities is linear,+-- i.e., if every entity in the list occurs only once. If it is non-linear,+-- the first offending object is returned.++findDouble :: Eq a => [a] -> Maybe a+findDouble [] = Nothing+findDouble (x : xs)+ | x `elem` xs = Just x+ | otherwise = findDouble xs++findMultiples :: Eq a => [a] -> [[a]]+findMultiples [] = []+findMultiples (x : xs)+ | null same = multiples+ | otherwise = (x : same) : multiples+ where (same, other) = partition (==x) xs+ multiples = findMultiples other
− src/CaseCompletion.hs
@@ -1,662 +0,0 @@---------------------------------------------------------------------------------------------------------------------------------------------------------------------- CaseCompletion - expands case branches with missing constructors------ The MMC translates case expressions into the intermediate language--- representation (IL) without completing them (i.e. without generating--- case branches for missing contructors). Because they are necessary for--- the PAKCS back end this module expands all case expressions accordingly.------ May 2005,--- Martin Engelke, (men@informatik.uni-kiel.de)--- -module CaseCompletion (completeCase) where--import Data.Maybe--import Curry.Base.Position (SrcRef)-import Curry.Base.Ident-import qualified Curry.Syntax--import Base (ModuleEnv, lookupModule)-import IL.Type-import OldScopeEnv -- as ScopeEnv-import IL.Scope--------------------------------------------------------------------------------------- Completes case expressions by adding branches for missing constructors.--- The module environment 'menv' is needed to compute these constructors.------ Call:--- completeCase <module environment>--- <IL module>----completeCase :: ModuleEnv -> Module -> Module-completeCase menv mod = let (mod', _) = visitModule menv mod in mod'------------------------------------------------------------------------------------- The following functions run through an IL term searching for--- case expressions-----visitModule :: ModuleEnv -> Module -> (Module, [Message])-visitModule menv (Module mident imports decls)- = ((Module mident (insertUnique preludeMIdent imports) decls'), msgs')- where- (decls', msgs') = visitList (visitDecl (Module mident imports decls) menv)- insertDeclScope- []- (getModuleScope (Module mident imports decls))- decls------visitDecl :: Module -> ModuleEnv -> [Message] -> ScopeEnv -> Decl- -> (Decl, [Message])-visitDecl mod menv msgs senv (DataDecl qident arity cdecls)- = ((DataDecl qident arity cdecls), msgs)--visitDecl mod menv msgs senv (NewtypeDecl qident arity cdecl)- = ((NewtypeDecl qident arity cdecl), msgs)--visitDecl mod menv msgs senv (FunctionDecl qident params typeexpr expr)- = ((FunctionDecl qident params typeexpr expr'), msgs)- where- (expr', _, _) = visitExpr mod menv msgs (insertExprScope senv expr) expr--visitDecl mod menv msgs senv (ExternalDecl qident cconv name typeexpr)- = ((ExternalDecl qident cconv name typeexpr), msgs)------visitExpr :: Module -> ModuleEnv -> [Message] -> ScopeEnv -> Expression - -> (Expression, [Message],ScopeEnv)-visitExpr mod menv msgs senv (Literal lit) - = ((Literal lit), msgs, senv)--visitExpr mod menv msgs senv (Variable ident) - = ((Variable ident), msgs, senv)--visitExpr mod menv msgs senv (Function qident arity) - = ((Function qident arity), msgs, senv)--visitExpr mod menv msgs senv (Constructor qident arity)- = ((Constructor qident arity), msgs, senv)--visitExpr mod menv msgs senv (Apply expr1 expr2)- = ((Apply expr1' expr2'), msgs2, senv2)- where- (expr1', msgs1, senv1) = visitExpr mod menv msgs (insertExprScope senv expr1) expr1- (expr2', msgs2, senv2) = visitExpr mod menv msgs1 (insertExprScope senv1 expr2) expr2--visitExpr mod menv msgs senv (Case r evalannot expr alts)- | null altsR- = intError "visitExpr" "empty alternative list"- | evalannot == Flex -- pattern matching causes flexible case expressions- = (Case r evalannot expr' altsR, msgs, senv1)- | isConstrAlt altR- = (expr2, msgs3, senv3)- | isLitAlt altR- = (completeLitAlts r evalannot expr' altsR, msgs3, senv2)- | isVarAlt altR- = (completeVarAlts expr' altsR, msgs3, senv2)- | otherwise - = intError "visitExpr" "illegal alternative list"- where- altR = head altsR- (expr', _, senv1) = visitExpr mod menv msgs (insertExprScope senv expr) expr- (alts', _, senv2) = visitListWithEnv (visitAlt mod menv) insertAltScope msgs senv1 alts- (altsR, msgs3) = removeRedundantAlts msgs alts'- (expr2, senv3) = completeConsAlts r mod menv senv2 evalannot expr' altsR--visitExpr mod menv msgs senv (Or expr1 expr2)- = ((Or expr1' expr2'), msgs2, senv3)- where- (expr1', msgs1, senv2) = visitExpr mod menv msgs (insertExprScope senv expr1) expr1- (expr2', msgs2, senv3) = visitExpr mod menv msgs1 (insertExprScope senv2 expr2) expr2--visitExpr mod menv msgs senv (Exist ident expr)- = ((Exist ident expr'), msgs', senv2)- where- (expr', msgs', senv2) = visitExpr mod menv msgs (insertExprScope senv expr) expr--visitExpr mod menv msgs senv (Let bind expr)- = ((Let bind' expr'), msgs2, senv3)- where- (expr', _, senv2) = visitExpr mod menv msgs (insertExprScope senv expr) expr- (bind', msgs2, senv3) = visitBinding mod menv msgs (insertBindingScope senv2 bind) bind--visitExpr mod menv msgs senv (Letrec binds expr)- = ((Letrec binds' expr'), msgs2, senv3)- where- (expr', msgs1, senv2) = visitExpr mod menv msgs (insertExprScope senv expr) expr- (binds', msgs2, senv3) = visitListWithEnv (visitBinding mod menv)- const- msgs1- (foldl insertBindingScope senv2 binds)- binds------visitAlt :: Module -> ModuleEnv -> [Message] -> ScopeEnv -> Alt - -> (Alt, [Message], ScopeEnv)-visitAlt mod menv msgs senv (Alt pattern expr)- = ((Alt pattern expr'), msgs', senv2)- where- (expr', msgs', senv2) = visitExpr mod menv msgs (insertExprScope senv expr) expr------visitBinding :: Module -> ModuleEnv -> [Message] -> ScopeEnv -> Binding - -> (Binding, [Message], ScopeEnv)-visitBinding mod menv msgs senv (Binding ident expr)- = ((Binding ident expr'), msgs', senv2)- where- (expr', msgs', senv2) = visitExpr mod menv msgs (insertExprScope senv expr) expr------visitList :: ([Message] -> ScopeEnv -> a -> (a, [Message]))- -> (ScopeEnv -> a -> ScopeEnv)- -> [Message] -> ScopeEnv -> [a]- -> ([a], [Message])-visitList visitTerm insertScope msgs senv []- = ([], msgs)-visitList visitTerm insertScope msgs senv (term:terms)- = ((term':terms'), msgs2)- where- (term', msgs1) = visitTerm msgs (insertScope senv term) term- (terms', msgs2) = visitList visitTerm insertScope msgs1 senv terms--visitListWithEnv :: ([Message] -> ScopeEnv -> a -> (a, [Message], ScopeEnv))- -> (ScopeEnv -> a -> ScopeEnv)- -> [Message] -> ScopeEnv -> [a]- -> ([a], [Message], ScopeEnv)-visitListWithEnv visitTerm insertScope msgs senv []- = ([], msgs, senv)-visitListWithEnv visitTerm insertScope msgs senv (term:terms)- = ((term':terms'), msgs2, senv3)- where- (term', msgs1, senv2) = visitTerm msgs (insertScope senv term) term- (terms', msgs2, senv3) = visitListWithEnv visitTerm insertScope msgs1 senv2 terms-------------------------------------------------------------------------------------------------------------------------------------------------------------------- Functions for completing case alternatives---- Completes a case alternative list which branches via constructor patterns--- by adding alternatives of the form------ comp_pattern -> default_expr------ where "comp_pattern" is a complementary constructor pattern and--- "default_expr" is the expression from the first alternative containing--- a variable pattern. If there is no such alternative the defualt expression--- is set to the prelude function 'failed'.------ This funtions uses a scope environment ('ScopeEnv') to generate fresh--- variables for the arguments of the new constructors.----completeConsAlts :: SrcRef -> Module -> ModuleEnv -> ScopeEnv - -> Eval -> Expression -> [Alt]- -> (Expression, ScopeEnv)-completeConsAlts r mod menv senv evalannot expr alts- = (Case r evalannot expr (alts1 ++ alts2), senv2)- where- (Alt varpatt defaultexpr) = getDefaultAlt alts- (VariablePattern varid) = varpatt- alts1 = filter isConstrAlt alts- constrs = (map p_getConsAltIdent alts1)- cconsinfos = getComplConstrs mod menv constrs- (cconstrs,senv2) = - foldr p_genConstrTerm- ([],senv) - cconsinfos- alts2 = map (\cconstr -> - (Alt cconstr - (replaceVar varid (cterm2expr cconstr) defaultexpr))) - cconstrs-- p_getConsAltIdent (Alt (ConstructorPattern qident _) _) = qident-- p_genConstrTerm (qident, arity) (cconstrs,senv3) =- let args = OldScopeEnv.genIdentList arity "x" senv3- senv4 = foldr OldScopeEnv.insertIdent senv3 args- in (ConstructorPattern qident args : cconstrs, senv4)----- If the alternatives branches via literal pattern complementary--- constructor list cannot be generated because it would become infinite.--- So the function 'completeLitAlts' transforms case expressions like--- case <cexpr> of--- <lit_1> -> <expr_1>--- <lit_2> -> <expr_2>--- :--- <lit_n> -> <expr_n>--- [<var> -> <default_expr>]--- to --- case (<cexpr> == <lit_1>) of--- True -> <expr_1>--- False -> case (<cexpr> == <lit_2>) of--- True -> <expr_2>--- False -> case ...--- :--- -> case (<cexpr> == <lit_n>) of--- True -> <expr_n>--- False -> <default_expr>----completeLitAlts :: SrcRef -> Eval -> Expression -> [Alt] -> Expression-completeLitAlts r evalannot expr [] = failedExpr-completeLitAlts r evalannot expr (alt:alts)- | isLitAlt alt - = (Case r evalannot - (eqExpr expr (p_makeLitExpr alt))- [(Alt truePatt (getAltExpr alt)),- (Alt falsePatt (completeLitAlts r evalannot expr alts))])- | otherwise- = case alt of- Alt (VariablePattern v) expr'- -> replaceVar v expr expr'- _ -> intError "completeLitAlts" "illegal alternative"- where- p_makeLitExpr alt- = case (getAltPatt alt) of- LiteralPattern lit -> Literal lit- _ -> intError "completeLitAlts" - "literal pattern expected"----- For the unusual case of having only one alternative containing a variable--- pattern it is necessary to tranform it to a 'let' term because FlatCurry--- does not support variable patterns in case alternatives. So the--- case expression--- case <ce> of --- x -> <expr>--- is transformed ot--- let x = <ce> in <expr>-completeVarAlts :: Expression -> [Alt] -> Expression-completeVarAlts expr [] = failedExpr-completeVarAlts expr (alt:_)- = (Let (Binding (p_getVarIdent alt) expr) (getAltExpr alt))- where- p_getVarIdent alt- = case (getAltPatt alt) of- VariablePattern ident -> ident- _ -> intError "completeVarAlts" - "variable pattern expected"------------------------------------------------------------------------------------- The function 'removeRedundantAlts' removes case branches which are--- either idle (i.e. they will never be reached) or multiply declared.--- Note: unlike the PAKCS frontend MCC does not support warnings. So--- there will be no messages if alternatives have been removed.- -removeRedundantAlts :: [Message] -> [Alt] -> ([Alt], [Message])-removeRedundantAlts msgs alts- = let- (alts1, msgs1) = removeIdleAlts msgs alts- (alts2, msgs2) = removeMultipleAlts msgs1 alts1- in- (alts2, msgs2)----- An alternative is idle if it occurs anywehere behind another alternative --- which contains a variable pattern. Example:--- case x of--- (y:ys) -> e1--- z -> e2--- [] -> e3--- Here all alternatives behind (z -> e2) are idle and will be removed.-removeIdleAlts :: [Message] -> [Alt] -> ([Alt], [Message])-removeIdleAlts msgs alts - | null alts2 = (alts1, msgs)- | otherwise = (alts1, msgs)- where- (alts1, alts2) = splitAfter isVarAlt alts----- An alternative occures multiply if at least two alternatives--- use the same pattern. Example:--- case x of--- [] -> e1--- (y:ys) -> e2--- [] -> e3--- Here the last alternative occures multiply because its pattern is already--- used in the first alternative. All multiple alternatives will be--- removed except for the first occurrence.-removeMultipleAlts :: [Message] -> [Alt] -> ([Alt], [Message])-removeMultipleAlts msgs alts- = p_remove msgs [] alts- where- p_remove msgs altsR [] = ((reverse altsR), msgs)- p_remove msgs altsR (alt:alts)- | p_containsAlt alt altsR = p_remove msgs altsR alts- | otherwise = p_remove msgs (alt:altsR) alts-- p_containsAlt alt alts = any (p_eqAlt alt) alts-- p_eqAlt (Alt (LiteralPattern lit1) _) alt2- = case alt2 of- (Alt (LiteralPattern lit2) _) -> lit1 == lit2- _ -> False- p_eqAlt (Alt (ConstructorPattern qident1 _) _) alt2- = case alt2 of- (Alt (ConstructorPattern qident2 _) _) -> qident1 == qident2- _ -> False- p_eqAlt (Alt (VariablePattern _) _) alt2- = case alt2 of- (Alt (VariablePattern _) _) -> True- _ -> False------------------------------------------------------------------------------------- Some functions for testing and extracting terms from case alternatives-----isVarAlt :: Alt -> Bool-isVarAlt alt = case (getAltPatt alt) of- VariablePattern _ -> True- _ -> False-----isConstrAlt :: Alt -> Bool-isConstrAlt alt = case (getAltPatt alt) of- ConstructorPattern _ _ -> True- _ -> False-----isLitAlt :: Alt -> Bool-isLitAlt alt = case (getAltPatt alt) of- LiteralPattern _ -> True- _ -> False------getAltExpr :: Alt -> Expression-getAltExpr (Alt _ expr) = expr------getAltPatt :: Alt -> ConstrTerm-getAltPatt (Alt cterm _) = cterm----- Note: the newly generated variable 'x!' is just a dummy and will never--- occur in the transformed program-getDefaultAlt :: [Alt] -> Alt-getDefaultAlt alts - = fromMaybe (Alt (VariablePattern (mkIdent "x!")) failedExpr)- (find isVarAlt alts)------------------------------------------------------------------------------------- This part of the module contains functions for replacing variables--- with expressions. This is necessary in the case of having a default --- alternative like--- v -> <expr>--- where the variable v occurs in the default expression <expr>. When--- building additional alternatives for this default expression the variable--- must be replaced with the newly generated constructors.---- Call:--- replaceVar <variable id>--- <replace-with expression>--- <replace-in expression>----replaceVar :: Ident -> Expression -> Expression -> Expression-replaceVar ident expr (Variable ident')- | ident == ident' = expr- | otherwise = Variable ident'-replaceVar ident expr (Apply expr1 expr2)- = Apply (replaceVar ident expr expr1) (replaceVar ident expr expr2)-replaceVar ident expr (Case r eval expr' alts)- = Case r eval - (replaceVar ident expr expr') - (map (replaceVarInAlt ident expr) alts)-replaceVar ident expr (Or expr1 expr2)- = Or (replaceVar ident expr expr1) (replaceVar ident expr expr2)-replaceVar ident expr (Exist ident' expr')- | ident == ident' = Exist ident' expr'- | otherwise = Exist ident' (replaceVar ident expr expr')-replaceVar ident expr (Let binding expr')- | varOccursInBinding ident binding- = Let binding expr'- | otherwise- = Let (replaceVarInBinding ident expr binding) - (replaceVar ident expr expr')-replaceVar ident expr (Letrec bindings expr')- | any (varOccursInBinding ident) bindings- = Letrec bindings expr'- | otherwise- = Letrec (map (replaceVarInBinding ident expr) bindings)- (replaceVar ident expr expr')-replaceVar _ _ expr'- = expr'------replaceVarInAlt :: Ident -> Expression -> Alt -> Alt-replaceVarInAlt ident expr (Alt patt expr')- | varOccursInPattern ident patt - = Alt patt expr'- | otherwise - = Alt patt (replaceVar ident expr expr')------replaceVarInBinding :: Ident -> Expression -> Binding -> Binding-replaceVarInBinding ident expr (Binding ident' expr')- | ident == ident' = Binding ident' expr'- | otherwise = Binding ident' (replaceVar ident expr expr')------varOccursInPattern :: Ident -> ConstrTerm -> Bool-varOccursInPattern ident (VariablePattern ident')- = ident == ident'-varOccursInPattern ident (ConstructorPattern _ idents)- = elem ident idents-varOccursInPattern _ _- = False------varOccursInBinding :: Ident -> Binding -> Bool-varOccursInBinding ident (Binding ident' _)- = ident == ident'------------------------------------------------------------------------------------- The following functions generate several IL expressions and patterns-----failedExpr :: Expression-failedExpr = Function (qualifyWith preludeMIdent (mkIdent "failed")) 0-----eqExpr :: Expression -> Expression -> Expression-eqExpr e1 e2 = Apply- (Apply - (Function (qualifyWith preludeMIdent (mkIdent "==")) 2)- e1)- e2------truePatt :: ConstrTerm-truePatt = ConstructorPattern qTrueId []-----falsePatt :: ConstrTerm-falsePatt = ConstructorPattern qFalseId []------cterm2expr :: ConstrTerm -> Expression-cterm2expr (LiteralPattern lit) = Literal lit-cterm2expr (ConstructorPattern qident args)- = p_genApplic (Constructor qident (length args)) args- where- p_genApplic expr [] = expr- p_genApplic expr (v:vs) = p_genApplic (Apply expr (Variable v)) vs-cterm2expr (VariablePattern ident) = Variable ident-------------------------------------------------------------------------------------- The folowing functions compute the missing constructors for generating--- new case alternatives---- Computes the complementary constructors for a list of constructors. All--- specified constructors must have the same type.--- This functions uses the module environment 'menv' which contains all known--- constructors, except for those which are declared in the module and--- except for the list constructors.------ Call:--- getComplConstr <IL module>--- <module environment>--- <list of (qualified) constructor ids>----getComplConstrs :: Module -> ModuleEnv -> [QualIdent] -> [(QualIdent, Int)]-getComplConstrs (Module mid _ decls) menv constrs- | null constrs - = intError "getComplConstrs" "empty constructor list"- | cons == qNilId || cons == qConsId- = getCC constrs [(qNilId, 0), (qConsId, 2)]- | mid' == mid- = getCCFromDecls mid constrs decls- | otherwise- = maybe [] -- error ...- (getCCFromIDecls mid' constrs) - (lookupModule mid' menv)- where- cons = head constrs-- mid' = fromMaybe mid (qualidMod cons)----- Find complementary constructors within the declarations of the--- current module-getCCFromDecls :: ModuleIdent -> [QualIdent] -> [Decl] -> [(QualIdent, Int)]-getCCFromDecls _ constrs decls- = let- cdecls = maybe [] -- error ...- p_extractConstrDecls- (find (p_declaresConstr (head constrs)) decls)- cinfos = map p_getConstrDeclInfo cdecls- in- getCC constrs cinfos- where- p_declaresConstr qident decl- = case decl of- DataDecl _ _ cdecls -> any (p_isConstrDecl qident) cdecls- NewtypeDecl _ _ cdecl -> p_isConstrDecl qident cdecl- _ -> False-- p_isConstrDecl qident (ConstrDecl qid _) = qident == qid-- p_extractConstrDecls decl- = case decl of- DataDecl _ _ cdecls -> cdecls- _ -> []-- p_getConstrDeclInfo (ConstrDecl qident types) = (qident, length types)----- Find complementary constructors within the module environment-getCCFromIDecls :: ModuleIdent -> [QualIdent] -> [Curry.Syntax.IDecl] - -> [(QualIdent, Int)]-getCCFromIDecls mident constrs idecls- = let- cdecls = maybe [] -- error ...- p_extractIConstrDecls- (find (p_declaresIConstr (head constrs)) idecls)- cinfos = map (p_getIConstrDeclInfo mident) cdecls- in- getCC constrs cinfos- where- p_declaresIConstr qident idecl- = case idecl of- Curry.Syntax.IDataDecl _ _ _ cdecls- -> any (p_isIConstrDecl qident) - (map fromJust (filter isJust cdecls))- Curry.Syntax.INewtypeDecl _ _ _ ncdecl - -> p_isINewConstrDecl qident ncdecl- _ -> False-- p_isIConstrDecl qident (Curry.Syntax.ConstrDecl _ _ ident _)- = (unqualify qident) == ident- p_isIConstrDecl qident (Curry.Syntax.ConOpDecl _ _ _ ident _)- = (unqualify qident) == ident-- p_isINewConstrDecl qident (Curry.Syntax.NewConstrDecl _ _ ident _)- = (unqualify qident) == ident-- p_extractIConstrDecls idecl- = case idecl of- Curry.Syntax.IDataDecl _ _ _ cdecls - -> map fromJust (filter isJust cdecls)- _ -> []-- p_getIConstrDeclInfo mid (Curry.Syntax.ConstrDecl _ _ ident types)- = (qualifyWith mid ident, length types)- p_getIConstrDeclInfo mid (Curry.Syntax.ConOpDecl _ _ _ ident _)- = (qualifyWith mid ident, 2)----- Compute complementary constructors-getCC :: [QualIdent] -> [(QualIdent, Int)] -> [(QualIdent, Int)]-getCC _ [] = []-getCC constrs ((qident,arity):cis)- | any ((==) qident) constrs = getCC constrs cis- | otherwise = (qident,arity):(getCC constrs cis)------------------------------------------------------------------------------------- Message handling--- Not in use in this version, but intended for further versions--type Message = String------------------------------------------------------------------------------------- Miscellaneous---- Splits a list behind the first element which satify 'cond'-splitAfter :: (a -> Bool) -> [a] -> ([a], [a])-splitAfter cond xs = p_splitAfter cond [] xs- where- p_splitAfter c fs [] = ((reverse fs),[])- p_splitAfter c fs (l:ls) | c l = ((reverse (l:fs)), ls)- | otherwise = p_splitAfter c (l:fs) ls----- Returns the first element which satisfy 'cond'. The returned element is--- embedded in a 'Maybe' term-find :: (a -> Bool) -> [a] -> Maybe a-find _ [] = Nothing-find cond (x:xs) | cond x = Just x- | otherwise = find cond xs----- Prefixes an element to a list if it does not already exit within the--- list-insertUnique :: Eq a => a -> [a] -> [a]-insertUnique x xs | elem x xs = xs- | otherwise = x:xs----- Raises an internal error-intError :: String -> String -> a-intError fun msg = error ("CaseCompletion." ++ fun ++ " - " ++ msg)------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ src/Checks.hs view
@@ -0,0 +1,161 @@+{- |+ Module : $Header$+ Description : Different checks on a Curry module+ Copyright : (c) 2011 - 2013 Björn Peemöller+ 2016 - 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module subsumes the different checks to be performed on a Curry+ module during compilation, e.g. type checking.+-}+module Checks where++import qualified Checks.InstanceCheck as INC (instanceCheck)+import qualified Checks.InterfaceCheck as IC (interfaceCheck)+import qualified Checks.ImportSyntaxCheck as ISC (importCheck)+import qualified Checks.DeriveCheck as DC (deriveCheck)+import qualified Checks.ExportCheck as EC (exportCheck, expandExports)+import qualified Checks.ExtensionCheck as EXC (extensionCheck)+import qualified Checks.KindCheck as KC (kindCheck)+import qualified Checks.PrecCheck as PC (precCheck)+import qualified Checks.SyntaxCheck as SC (syntaxCheck)+import qualified Checks.TypeCheck as TC (typeCheck)+import qualified Checks.TypeSyntaxCheck as TSC (typeSyntaxCheck)+import qualified Checks.WarnCheck as WC (warnCheck)++import Curry.Base.Monad+import Curry.Syntax (Module (..), Interface (..), ImportSpec)++import Base.Messages+import Base.Types++import CompilerEnv+import CompilerOpts++type Check m a = Options -> CompEnv a -> CYT m (CompEnv a)++interfaceCheck :: Monad m => Check m Interface+interfaceCheck _ (env, intf)+ | null msgs = ok (env, intf)+ | otherwise = failMessages msgs+ where msgs = IC.interfaceCheck (opPrecEnv env) (tyConsEnv env) (classEnv env)+ (instEnv env) (valueEnv env) intf++importCheck :: Monad m => Interface -> Maybe ImportSpec+ -> CYT m (Maybe ImportSpec)+importCheck intf is+ | null msgs = ok is'+ | otherwise = failMessages msgs+ where (is', msgs) = ISC.importCheck intf is++-- |Check for enabled language extensions.+--+-- * Declarations: remain unchanged+-- * Environment: The enabled language extensions are updated+extensionCheck :: Monad m => Check m (Module a)+extensionCheck opts (env, mdl)+ | null msgs = ok (env { extensions = exts }, mdl)+ | otherwise = failMessages msgs+ where (exts, msgs) = EXC.extensionCheck opts mdl++-- |Check the type syntax of type definitions and signatures.+--+-- * Declarations: Nullary type constructors and type variables are+-- disambiguated+-- * Environment: remains unchanged+typeSyntaxCheck :: Monad m => Check m (Module a)+typeSyntaxCheck _ (env, mdl)+ | null msgs = ok (env, mdl')+ | otherwise = failMessages msgs+ where (mdl', msgs) = TSC.typeSyntaxCheck (tyConsEnv env) mdl++-- |Check the kinds of type definitions and signatures.+--+-- * Declarations: remain unchanged+-- * Environment: The type constructor and class environment are updated+kindCheck :: Monad m => Check m (Module a)+kindCheck _ (env, mdl)+ | null msgs = ok (env { tyConsEnv = tcEnv', classEnv = clsEnv' }, mdl)+ | otherwise = failMessages msgs+ where ((tcEnv', clsEnv'), msgs) = KC.kindCheck (tyConsEnv env) (classEnv env)+ mdl++-- |Check for a correct syntax.+--+-- * Declarations: Nullary data constructors and variables are+-- disambiguated, variables are renamed+-- * Environment: remains unchanged+syntaxCheck :: Monad m => Check m (Module ())+syntaxCheck _ (env, mdl)+ | null msgs = ok (env { extensions = exts }, mdl')+ | otherwise = failMessages msgs+ where ((mdl', exts), msgs) = SC.syntaxCheck (extensions env) (tyConsEnv env)+ (valueEnv env) mdl++-- |Check the precedences of infix operators.+--+-- * Declarations: Expressions are reordered according to the specified+-- precedences+-- * Environment: The operator precedence environment is updated+precCheck :: Monad m => Check m (Module a)+precCheck _ (env, Module spi li ps m es is ds)+ | null msgs = ok (env { opPrecEnv = pEnv' }, Module spi li ps m es is ds')+ | otherwise = failMessages msgs+ where (ds', pEnv', msgs) = PC.precCheck (moduleIdent env) (opPrecEnv env) ds++-- |Check the deriving clauses.+--+-- * Declarations: remain unchanged+-- * Environment: remain unchanged+deriveCheck :: Monad m => Check m (Module a)+deriveCheck _ (env, mdl) = case DC.deriveCheck (tyConsEnv env) mdl of+ msgs | null msgs -> ok (env, mdl)+ | otherwise -> failMessages msgs++-- |Check the instances.+--+-- * Declarations: remain unchanged+-- * Environment: The instance environment is updated+instanceCheck :: Monad m => Check m (Module a)+instanceCheck _ (env, Module spi li ps m es is ds)+ | null msgs = ok (env { instEnv = inEnv' }, Module spi li ps m es is ds)+ | otherwise = failMessages msgs+ where (inEnv', msgs) = INC.instanceCheck (moduleIdent env) (tyConsEnv env)+ (classEnv env) (instEnv env) ds++-- |Apply the correct typing of the module.+--+-- * Declarations: Type annotations are added to all expressions.+-- * Environment: The value environment is updated.+typeCheck :: Monad m => Options -> CompEnv (Module a)+ -> CYT m (CompEnv (Module PredType))+typeCheck _ (env, Module spi li ps m es is ds)+ | null msgs = ok (env { valueEnv = vEnv' }, Module spi li ps m es is ds')+ | otherwise = failMessages msgs+ where (ds', vEnv', msgs) = TC.typeCheck (moduleIdent env) (tyConsEnv env)+ (valueEnv env) (classEnv env)+ (instEnv env) ds++-- |Check the export specification+exportCheck :: Monad m => Check m (Module a)+exportCheck _ (env, mdl@(Module _ _ _ _ es _ _))+ | null msgs = ok (env, mdl)+ | otherwise = failMessages msgs+ where msgs = EC.exportCheck (moduleIdent env) (aliasEnv env)+ (tyConsEnv env) (valueEnv env) es++-- |Check the export specification+expandExports :: Monad m => Options -> CompEnv (Module a) -> m (CompEnv (Module a))+expandExports _ (env, Module spi li ps m es is ds)+ = return (env, Module spi li ps m (Just es') is ds)+ where es' = EC.expandExports (moduleIdent env) (aliasEnv env)+ (tyConsEnv env) (valueEnv env) es++-- |Check for warnings.+warnCheck :: Options -> CompilerEnv -> Module a -> [Message]+warnCheck opts env mdl = WC.warnCheck (optWarnOpts opts) (optCaseMode opts)+ (aliasEnv env) (valueEnv env) (tyConsEnv env) (classEnv env) mdl
+ src/Checks/DeriveCheck.hs view
@@ -0,0 +1,111 @@+{- |+ Module : $Header$+ Description : Checks deriving clauses+ Copyright : (c) 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ Before entering derived instances into the instance environment, the+ compiler has to ensure that it is not asked for other instances than+ those of supported type classes.+-}+module Checks.DeriveCheck (deriveCheck) where++import Curry.Base.Ident+import Curry.Base.Pretty+import Curry.Base.SpanInfo (HasSpanInfo)+import Curry.Syntax++import Base.Messages (Message, spanInfoMessage)++import Env.TypeConstructor++deriveCheck :: TCEnv -> Module a -> [Message]+deriveCheck tcEnv (Module _ _ _ m _ _ ds) = concatMap (checkDecl m tcEnv) ds++-- No instances can be derived for abstract data types as well as for+-- existential data types.++checkDecl :: ModuleIdent -> TCEnv -> Decl a -> [Message]+checkDecl m tcEnv (DataDecl _ tc _ cs clss)+ | null clss = []+ | null cs = [errNoAbstractDerive tc]+ | otherwise = concatMap (checkDerivable m tcEnv cs) clss+checkDecl m tcEnv (NewtypeDecl _ _ _ nc clss) =+ concatMap (checkDerivable m tcEnv [toConstrDecl nc]) clss+checkDecl _ _ _ = []++checkDerivable :: ModuleIdent -> TCEnv -> [ConstrDecl] -> QualIdent -> [Message]+checkDerivable m tcEnv cs cls+ | ocls == qEnumId && not (isEnum cs) = [errNotEnum cls]+ | ocls == qBoundedId && not (isBounded cs) = [errNotBounded cls]+ | ocls `notElem` derivableClasses = [errNotDerivable cls]+ | ocls == qDataId = [errNoDataDerive cls]+ | otherwise = []+ where ocls = getOrigName m cls tcEnv++derivableClasses :: [QualIdent]+derivableClasses = [qEqId, qOrdId, qEnumId, qBoundedId, qReadId, qShowId, qDataId]++-- Instances of 'Enum' can be derived only for enumeration types, i.e., types+-- where all data constructors are constants.++isEnum :: [ConstrDecl] -> Bool+isEnum = all ((0 ==) . constrArity)++-- Instances of 'Bounded' can be derived only for enumerations and for single+-- constructor types.++isBounded :: [ConstrDecl] -> Bool+isBounded cs = length cs == 1 || isEnum cs++-- ---------------------------------------------------------------------------+-- Auxiliary functions+-- ---------------------------------------------------------------------------++toConstrDecl :: NewConstrDecl -> ConstrDecl+toConstrDecl (NewConstrDecl p c ty) = ConstrDecl p c [ty]+toConstrDecl (NewRecordDecl p c (l, ty)) =+ RecordDecl p c [FieldDecl p [l] ty]++constrArity :: ConstrDecl -> Int+constrArity (ConstrDecl _ _ tys) = length tys+constrArity (ConOpDecl _ _ _ _) = 2+constrArity c@(RecordDecl _ _ _) = length $ recordLabels c++-- ---------------------------------------------------------------------------+-- Error messages+-- ---------------------------------------------------------------------------++errNoAbstractDerive :: HasSpanInfo a => a -> Message+errNoAbstractDerive s = spanInfoMessage s $+ text "Instances can only be derived for data types with" <+>+ text "at least one constructor"++errNotDerivable :: QualIdent -> Message+errNotDerivable cls = spanInfoMessage cls $ hsep $ map text+ ["Instances of type class", escQualName cls, "cannot be derived"]++errNoDataDerive :: QualIdent -> Message+errNoDataDerive qcls = spanInfoMessage qcls $ hsep $ map text+ [ "Instances of type class"+ , escQualName qcls+ , "are automatically derived if possible"+ ]++errNotEnum :: QualIdent -> Message+errNotEnum qcls = spanInfoMessage qcls $ hsep $ map text+ [ "Instances of type class"+ , escQualName qcls+ , "can be derived only for enumeration types"+ ]++errNotBounded :: QualIdent -> Message+errNotBounded qcls = spanInfoMessage qcls $ hsep $ map text+ [ "Instances of type class"+ , escQualName qcls+ , "can be derived only for enumeration and single constructor types"+ ]
+ src/Checks/ExportCheck.hs view
@@ -0,0 +1,500 @@+{- |+ Module : $Header$+ Description : Check the export specification of a module+ Copyright : (c) 1999 - 2004 Wolfgang Lux+ 2011 - 2016 Björn Peemöller+ 2015 - 2016 Yannik Potdevin+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module implements a check and expansion of the export specification.+ Any errors in the specification are reported, and if there are no errors,+ the specification is expanded. The expansion does the following:+ * If there is no export specification, a specification exporting the+ entire module is generated.+ * Otherwise, (re)exports of modules are replaced by an export of all+ respective entities.+ * The export of a type with all constructors and fields is replaced+ by an enumeration of all constructors and fields.+ * The export of types without sub-entities is extended with an empty+ list of sub-entities.+-}+{-# LANGUAGE CPP #-}+module Checks.ExportCheck (exportCheck, expandExports) where++#if __GLASGOW_HASKELL__ >= 804+import Prelude hiding ((<>))+#endif++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative ((<$>))+#endif+import Control.Monad (unless)+import qualified Control.Monad.State as S (State, runState, gets, modify)+import Data.List (nub, union)+import qualified Data.Map as Map ( Map, elems, empty, insert+ , insertWith, lookup, toList )+import Data.Maybe (fromMaybe)+import qualified Data.Set as Set ( Set, empty, fromList, insert+ , member, toList )++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Base.SpanInfo+import Curry.Base.Pretty+import Curry.Syntax++import Base.Messages (Message, internalError, spanInfoMessage)+import Base.TopEnv (allEntities, origName, localBindings, moduleImports)+import Base.Types ( Type (..), unapplyType, arrowBase, PredType (..)+ , DataConstr (..), constrIdent, recLabels+ , ClassMethod, methodName+ , TypeScheme (..), rawType, rootOfType )+import Base.Utils (findMultiples)++import Env.ModuleAlias (AliasEnv)+import Env.TypeConstructor (TCEnv, TypeInfo (..), qualLookupTypeInfoUnique)+import Env.Value (ValueEnv, ValueInfo (..), qualLookupValueUnique)++currentModuleName :: String+currentModuleName = "Checks.ExportCheck"++-- ---------------------------------------------------------------------------+-- Check and expansion of the export statement+-- ---------------------------------------------------------------------------++expandExports :: ModuleIdent -> AliasEnv -> TCEnv -> ValueEnv+ -> Maybe ExportSpec -> ExportSpec+expandExports m aEnv tcEnv tyEnv spec = Exporting (exportSpan spec) es+ where+ exportSpan (Just (Exporting spi _)) = spi+ exportSpan Nothing = NoSpanInfo++ es = expand m aEnv tcEnv tyEnv spec++exportCheck :: ModuleIdent -> AliasEnv -> TCEnv -> ValueEnv+ -> Maybe ExportSpec -> [Message]+exportCheck m aEnv tcEnv tyEnv spec = case check m aEnv tcEnv tyEnv spec of+ [] -> checkNonUniqueness $ expand m aEnv tcEnv tyEnv spec+ ms -> ms++-- -----------------------------------------------------------------------------+-- Export Check Monad+-- -----------------------------------------------------------------------------++data ECState = ECState+ { moduleIdent :: ModuleIdent+ , importedMods :: Set.Set ModuleIdent+ , tyConsEnv :: TCEnv+ , valueEnv :: ValueEnv+ , errors :: [Message]+ }++type ECM a = S.State ECState a++runECM :: ECM a -> ModuleIdent -> AliasEnv -> TCEnv -> ValueEnv -> (a, [Message])+runECM ecm m aEnv tcEnv tyEnv+ = let (a, s') = S.runState ecm initState in (a, reverse $ errors s')+ where+ initState = ECState m imported tcEnv tyEnv []+ imported = Set.fromList (Map.elems aEnv)++getModuleIdent :: ECM ModuleIdent+getModuleIdent = S.gets moduleIdent++getImportedModules :: ECM (Set.Set ModuleIdent)+getImportedModules = S.gets importedMods++getTyConsEnv :: ECM TCEnv+getTyConsEnv = S.gets tyConsEnv++getValueEnv :: ECM ValueEnv+getValueEnv = S.gets valueEnv++report :: Message -> ECM ()+report err = S.modify (\ s -> s { errors = err : errors s })++ok :: ECM ()+ok = return ()++-- -----------------------------------------------------------------------------+-- Check+-- -----------------------------------------------------------------------------++check :: ModuleIdent -> AliasEnv -> TCEnv -> ValueEnv -> Maybe ExportSpec+ -> [Message]+check m aEnv tcEnv tyEnv spec = snd $ runECM (checkSpec spec) m aEnv tcEnv tyEnv++-- |Check export specification.+checkSpec :: Maybe ExportSpec -> ECM ()+checkSpec (Just (Exporting _ es)) = mapM_ checkExport es+checkSpec Nothing = ok++-- |Check single export.+checkExport :: Export -> ECM ()+checkExport (Export _ x ) = checkThing x+checkExport (ExportTypeWith _ tc cs) = checkTypeWith tc cs+checkExport (ExportTypeAll _ tc ) = checkTypeAll tc+checkExport (ExportModule _ em ) = checkModule em++-- |Check export of type constructor / function+checkThing :: QualIdent -> ECM ()+checkThing tc = do+ m <- getModuleIdent+ tcEnv <- getTyConsEnv+ case qualLookupTypeInfoUnique m tc tcEnv of+ [] -> checkThing' tc Nothing+ [t] -> checkThing' tc (Just [ExportTypeWith NoSpanInfo (origName t) []])+ ts -> report (errAmbiguousType tc ts)++-- |Expand export of data cons / function+checkThing' :: QualIdent -> Maybe [Export] -> ECM ()+checkThing' f tcExport = do+ m <- getModuleIdent+ tyEnv <- getValueEnv+ case qualLookupValueUnique m f tyEnv of+ [] -> justTcOr errUndefinedName+ [v] -> case v of+ Value _ _ _ _ -> ok+ Label _ _ _ -> report $ errOutsideTypeLabel f (getTc v)+ _ -> justTcOr $ flip errOutsideTypeConstructor (getTc v)+ fs -> report (errAmbiguousName f fs)+ where+ justTcOr errFun = maybe (report $ errFun f) (const ok) tcExport++ getTc (DataConstructor _ _ _ (ForAll _ (PredType _ ty))) = getTc' ty+ getTc (NewtypeConstructor _ _ (ForAll _ (PredType _ ty))) = getTc' ty+ getTc (Label _ _ (ForAll _ (PredType _ (TypeArrow tc' _)))) =+ let (TypeConstructor tc, _) = unapplyType False tc' in tc+ getTc err = internalError $ currentModuleName ++ ".checkThing'.getTc: " ++ show err++ getTc' ty = let (TypeConstructor tc) = arrowBase ty in tc++checkTypeWith :: QualIdent -> [Ident] -> ECM ()+checkTypeWith tc xs = do+ m <- getModuleIdent+ tcEnv <- getTyConsEnv+ case qualLookupTypeInfoUnique m tc tcEnv of+ [] -> report (errUndefinedTypeOrClass tc)+ [DataType _ _ cs] ->+ mapM_ (checkElement errUndefinedElement (visibleElems cs )) xs'+ [RenamingType _ _ c] ->+ mapM_ (checkElement errUndefinedElement (visibleElems [c])) xs'+ [TypeClass _ _ ms] ->+ mapM_ (checkElement errUndefinedMethod (visibleMethods ms)) xs'+ [_] -> report (errNonDataTypeOrTypeClass tc)+ ts -> report (errAmbiguousType tc ts)+ where+ xs' = nub xs+ -- check if given identifier is constructor/label/method of type/class tc+ checkElement err cs' c = unless (c `elem` cs') $ report $ err tc c++-- |Check type constructor with all data constructors and record labels.+checkTypeAll :: QualIdent -> ECM ()+checkTypeAll tc = do+ m <- getModuleIdent+ tcEnv <- getTyConsEnv+ case qualLookupTypeInfoUnique m tc tcEnv of+ [] -> report (errUndefinedTypeOrClass tc)+ [DataType _ _ _] -> ok+ [RenamingType _ _ _] -> ok+ [TypeClass _ _ _] -> ok+ [_] -> report (errNonDataTypeOrTypeClass tc)+ ts -> report (errAmbiguousType tc ts)++checkModule :: ModuleIdent -> ECM ()+checkModule em = do+ isLocal <- (em ==) <$> getModuleIdent+ isForeign <- (Set.member em) <$> getImportedModules+ unless (isLocal || isForeign) $ report $ errModuleNotImported em++-- Check whether two entities of the same kind (type or constructor/function)+-- share the same unqualified name, which is not allowed since they could+-- not be uniquely resolved at their usage.+-- For instance, consider the following module+-- @+-- module M (Bool, Prelude.Bool) where+-- data Bool = False | True+-- @+-- If this export would be allowed, in a module @M1@ as follows+-- @+-- module M1 where+-- import M (Bool)+-- @+-- the type @Bool@ could not be resolved uniquely to its definition.+-- Naturally, the same applies for constructors or functions.+checkNonUniqueness :: [Export] -> [Message]+checkNonUniqueness es = map errMultipleType (findMultiples types )+ ++ map errMultipleName (findMultiples values)+ where+ types = [ unqualify tc | ExportTypeWith _ tc _ <- es ]+ values = [ c | ExportTypeWith _ _ cs <- es, c <- cs ]+ ++ [ unqualify f | Export _ f <- es ]++-- -----------------------------------------------------------------------------+-- Expansion+-- -----------------------------------------------------------------------------++expand :: ModuleIdent -> AliasEnv -> TCEnv -> ValueEnv -> Maybe ExportSpec+ -> [Export]+expand m aEnv tcEnv tyEnv spec+ = fst $ runECM ((joinExports . canonExports tcEnv) <$> expandSpec spec)+ m aEnv tcEnv tyEnv++-- While checking all export specifications, the compiler expands+-- specifications of the form @T(..)@ into @T(C_1,...,C_m,l_1,...,l_n)@,+-- where @C_1,...,C_m@ are the data constructors of type @T@ and @l_1,...,l_n@+-- its field labels, and replaces an export specification+-- @module M@ by specifications for all entities which are defined+-- in module @M@ and imported into the current module with their+-- unqualified name. In order to distinguish exported type constructors+-- from exported functions, the former are translated into the equivalent+-- form @T()@. Note that the export specification @x@ may+-- export a type constructor @x@ /and/ a global function+-- @x@ at the same time.+--+-- /Note:/ This frontend allows redeclaration and export of imported+-- identifiers.++-- |Expand export specification+expandSpec :: Maybe ExportSpec -> ECM [Export]+expandSpec (Just (Exporting _ es)) = concat <$> mapM expandExport es+expandSpec Nothing = expandLocalModule++-- |Expand single export+expandExport :: Export -> ECM [Export]+expandExport (Export _ x) = expandThing x+expandExport (ExportTypeWith _ tc cs) = expandTypeWith tc cs+expandExport (ExportTypeAll _ tc) = expandTypeAll tc+expandExport (ExportModule _ em) = expandModule em++-- |Expand export of type constructor / function+expandThing :: QualIdent -> ECM [Export]+expandThing tc = do+ m <- getModuleIdent+ tcEnv <- getTyConsEnv+ case qualLookupTypeInfoUnique m tc tcEnv of+ [] -> expandThing' tc Nothing+ [t] -> expandThing' tc+ (Just [ExportTypeWith NoSpanInfo (origName t @> tc) []])+ err -> internalError $ currentModuleName ++ ".expandThing: " ++ show err++-- |Expand export of data cons / function+expandThing' :: QualIdent -> Maybe [Export] -> ECM [Export]+expandThing' f tcExport = do+ m <- getModuleIdent+ tyEnv <- getValueEnv+ case qualLookupValueUnique m f tyEnv of+ [Value f' _ _ _]+ -> return $ Export NoSpanInfo (f' @> f) : fromMaybe [] tcExport+ _+ -> return $ fromMaybe [] tcExport++-- |Expand type constructor with explicit data constructors and record labels+expandTypeWith :: QualIdent -> [Ident] -> ECM [Export]+expandTypeWith tc xs = do+ m <- getModuleIdent+ tcEnv <- getTyConsEnv+ case qualLookupTypeInfoUnique m tc tcEnv of+ [t] -> return [ExportTypeWith NoSpanInfo (origName t @> tc) $ nub xs]+ err -> internalError $ currentModuleName ++ ".expandTypeWith: " ++ show err++-- |Expand type constructor with all data constructors and record labels+expandTypeAll :: QualIdent -> ECM [Export]+expandTypeAll tc = do+ m <- getModuleIdent+ tcEnv <- getTyConsEnv+ case qualLookupTypeInfoUnique m tc tcEnv of+ [t] -> return [exportType t]+ err -> internalError $ currentModuleName ++ ".expandTypeAll: " ++ show err++expandModule :: ModuleIdent -> ECM [Export]+expandModule em = do+ isLocal <- (em ==) <$> getModuleIdent+ isForeign <- (Set.member em) <$> getImportedModules+ locals <- if isLocal then expandLocalModule else return []+ foreigns <- if isForeign then expandImportedModule em else return []+ return $ locals ++ foreigns++expandLocalModule :: ECM [Export]+expandLocalModule = do+ tcEnv <- getTyConsEnv+ tyEnv <- getValueEnv+ return $+ [ exportType t+ | (_, t) <- localBindings tcEnv ]+ ++ [ exportLabel l' ty+ | (l, Label l' _ ty) <- localBindings tyEnv, hasGlobalScope l ]+ ++ [ Export NoSpanInfo f'+ | (f, Value f' _ _ _) <- localBindings tyEnv, hasGlobalScope f ]++-- |Expand a module export+expandImportedModule :: ModuleIdent -> ECM [Export]+expandImportedModule m = do+ tcEnv <- getTyConsEnv+ tyEnv <- getValueEnv+ return $ [exportType t | (_, t) <- moduleImports m tcEnv]+ ++ [exportLabel l ty | (_, Label l _ ty) <- moduleImports m tyEnv]+ ++ [Export NoSpanInfo f | (_, Value f _ _ _) <- moduleImports m tyEnv]++exportType :: TypeInfo -> Export+exportType t = ExportTypeWith NoSpanInfo tc xs+ where tc = origName t+ xs = elements t++exportLabel :: QualIdent -> TypeScheme -> Export+exportLabel qid ty = case rawType ty of+ TypeArrow a _ -> ExportTypeWith NoSpanInfo (rootOfType a) [qidIdent qid]+ _ -> internalError $ "ExportCheck.exportLabel: " ++ show (qid, ty)++-- -----------------------------------------------------------------------------+-- Canonicalization and joining of exports+-- -----------------------------------------------------------------------------++-- In contrast to Haskell, the export of field labels and record constructors+-- without their types is NOT allowed.+-- Thus, given the declaration @data T a = C { l :: a }@+-- the label @l@ and the constructor @C@ can only be exported together with the+-- type @T@, i.e., @(T(C,l))@.+-- Since record update operations are desugared to case expressions matching the+-- corresponding constructors of the record, the export of a label without its+-- type could result in a type error, when it is used for an update operation in+-- another module.++canonExports :: TCEnv -> [Export] -> [Export]+canonExports tcEnv es = map (canonExport (canonLabels tcEnv es)) es++canonExport :: Map.Map QualIdent Export -> Export -> Export+canonExport ls (Export spi x) =+ fromMaybe (Export spi x) (Map.lookup x ls)+canonExport _ (ExportTypeWith spi tc xs) = ExportTypeWith spi tc xs+canonExport _ e = internalError $+ currentModuleName ++ ".canonExport: " ++ show e++canonLabels :: TCEnv -> [Export] -> Map.Map QualIdent Export+canonLabels tcEnv es = foldr bindLabels Map.empty (allEntities tcEnv)+ where+ tcs = [tc | ExportTypeWith _ tc _ <- es]+ bindLabels t ls+ | tc' `elem` tcs = foldr (bindLabel tc') ls (elements t)+ | otherwise = ls+ where+ tc' = origName t+ bindLabel tc x =+ Map.insert (qualifyLike tc x) (ExportTypeWith NoSpanInfo tc [x])++-- The expanded list of exported entities may contain duplicates. These+-- are removed by the function joinExports. In particular, this+-- function removes any field labels from the list of exported values+-- which are also exported along with their types.++joinExports :: [Export] -> [Export]+joinExports es = [ExportTypeWith NoSpanInfo tc cs | (tc, cs) <- joinedTypes]+ ++ [Export NoSpanInfo f | f <- joinedFuncs]+ where joinedTypes = Map.toList $ foldr joinType Map.empty es+ joinedFuncs = Set.toList $ foldr joinFun Set.empty es++joinType :: Export -> Map.Map QualIdent [Ident] -> Map.Map QualIdent [Ident]+joinType (Export _ _) tcs = tcs+joinType (ExportTypeWith _ tc cs) tcs = Map.insertWith union tc cs tcs+joinType export _ = internalError $+ currentModuleName ++ ".joinType: " ++ show export++joinFun :: Export -> Set.Set QualIdent -> Set.Set QualIdent+joinFun (Export _ f) fs = f `Set.insert` fs+joinFun (ExportTypeWith _ _ _) fs = fs+joinFun export _ = internalError $+ currentModuleName ++ ".joinFun: " ++ show export++-- ---------------------------------------------------------------------------+-- Auxiliary definitions+-- ---------------------------------------------------------------------------++elements :: TypeInfo -> [Ident]+elements (DataType _ _ cs) = visibleElems cs+elements (RenamingType _ _ c) = visibleElems [c]+elements (AliasType _ _ _ _) = []+elements (TypeClass _ _ ms) = visibleMethods ms+elements (TypeVar _) =+ error "Checks.ExportCheck.elements: type variable"++-- get visible constructor and label identifiers for given constructor+visibleElems :: [DataConstr] -> [Ident]+visibleElems cs = map constrIdent cs ++ (nub (concatMap recLabels cs))++-- get class method names+visibleMethods :: [ClassMethod] -> [Ident]+visibleMethods = map methodName++-- ---------------------------------------------------------------------------+-- Error messages+-- ---------------------------------------------------------------------------++errAmbiguousName :: QualIdent -> [ValueInfo] -> Message+errAmbiguousName x vs = errAmbiguous "name" x (map origName vs)++errAmbiguousType :: QualIdent -> [TypeInfo] -> Message+errAmbiguousType tc tcs = errAmbiguous "type" tc (map origName tcs)++errAmbiguous :: String -> QualIdent -> [QualIdent] -> Message+errAmbiguous what qn qns = spanInfoMessage qn+ $ text "Ambiguous" <+> text what <+> text (escQualName qn)+ $+$ text "It could refer to:"+ $+$ nest 2 (vcat (map (text . escQualName) qns))++errModuleNotImported :: ModuleIdent -> Message+errModuleNotImported m = spanInfoMessage m $ hsep $ map text+ ["Module", escModuleName m, "not imported"]++errMultipleName :: [Ident] -> Message+errMultipleName = errMultiple "name"++errMultipleType :: [Ident] -> Message+errMultipleType = errMultiple "type"++errMultiple :: String -> [Ident] -> Message+errMultiple _ [] = internalError $+ currentModuleName ++ ".errMultiple: empty list"+errMultiple what (i:is) = spanInfoMessage i $+ text "Multiple exports of" <+> text what <+> text (escName i) <+> text "at:"+ $+$ nest 2 (vcat (map showPos (i:is)))+ where showPos = text . showLine . getPosition++errNonDataTypeOrTypeClass :: QualIdent -> Message+errNonDataTypeOrTypeClass tc = spanInfoMessage tc $ hsep $ map text+ [escQualName tc, "is not a data type or type class"]++errOutsideTypeConstructor :: QualIdent -> QualIdent -> Message+errOutsideTypeConstructor c tc = errOutsideTypeExport "Data constructor" c tc++errOutsideTypeLabel :: QualIdent -> QualIdent -> Message+errOutsideTypeLabel l tc = errOutsideTypeExport "Label" l tc++errOutsideTypeExport :: String -> QualIdent -> QualIdent -> Message+errOutsideTypeExport what q tc = spanInfoMessage q+ $ text what <+> text (escQualName q)+ <+> text "outside type export in export list"+ $+$ text "Use `" <> text (qualName tc) <+> parens (text (qualName q))+ <> text "' instead"++errUndefinedElement :: QualIdent -> Ident -> Message+errUndefinedElement tc c = spanInfoMessage c $ hsep $ map text+ [ escName c, "is not a constructor or label of type", escQualName tc ]++errUndefinedMethod :: QualIdent -> Ident -> Message+errUndefinedMethod cls f = spanInfoMessage f $ hsep $ map text+ [ escName f, "is not a method of class", escQualName cls ]++errUndefinedName :: QualIdent -> Message+errUndefinedName = errUndefined "name"++errUndefinedTypeOrClass :: QualIdent -> Message+errUndefinedTypeOrClass = errUndefined "type or class"++errUndefined :: String -> QualIdent -> Message+errUndefined what tc = spanInfoMessage tc $ hsep $ map text+ ["Undefined", what, escQualName tc, "in export list"]
+ src/Checks/ExtensionCheck.hs view
@@ -0,0 +1,72 @@+{- |+ Module : $Header$+ Description : Checks extensions+ Copyright : (c) 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ First of all, the compiler scans a source file for file-header pragmas+ that may activate language extensions.+-}+module Checks.ExtensionCheck (extensionCheck) where++import qualified Control.Monad.State as S (State, execState, modify)++import Curry.Base.SpanInfo+import Curry.Base.Pretty+import Curry.Syntax++import Base.Messages (Message, spanInfoMessage)++import CompilerOpts++extensionCheck :: Options -> Module a -> ([KnownExtension], [Message])+extensionCheck opts mdl = execEXC (checkModule mdl) initState+ where+ initState = EXCState (optExtensions opts) []++type EXCM = S.State EXCState++data EXCState = EXCState+ { extensions :: [KnownExtension]+ , errors :: [Message]+ }++execEXC :: EXCM a -> EXCState -> ([KnownExtension], [Message])+execEXC ecm s =+ let s' = S.execState ecm s in (extensions s', reverse $ errors s')++enableExtension :: KnownExtension -> EXCM ()+enableExtension e = S.modify $ \s -> s { extensions = e : extensions s }++report :: Message -> EXCM ()+report msg = S.modify $ \s -> s { errors = msg : errors s }++ok :: EXCM ()+ok = return ()++-- The extension check iterates over all given pragmas in the module and+-- gathers all extensions mentioned in a language pragma. An error is reported+-- if an extension is unknown.++checkModule :: Module a -> EXCM ()+checkModule (Module _ _ ps _ _ _ _) = mapM_ checkPragma ps++checkPragma :: ModulePragma -> EXCM ()+checkPragma (LanguagePragma _ exts) = mapM_ checkExtension exts+checkPragma (OptionsPragma _ _ _) = ok++checkExtension :: Extension -> EXCM ()+checkExtension (KnownExtension _ e) = enableExtension e+checkExtension (UnknownExtension p e) = report $ errUnknownExtension p e++-- ---------------------------------------------------------------------------+-- Error messages+-- ---------------------------------------------------------------------------++errUnknownExtension :: SpanInfo -> String -> Message+errUnknownExtension p e = spanInfoMessage p $+ text "Unknown language extension:" <+> text e
+ src/Checks/ImportSyntaxCheck.hs view
@@ -0,0 +1,279 @@+{- |+ Module : $Header$+ Description : Checking import specifications+ Copyright : (c) 2016 Jan Tikovsky+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : jrt@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module provides the function 'importCheck' to check and expand+ the import specifications of all import declarations.+-}+module Checks.ImportSyntaxCheck(importCheck) where++import Control.Monad (liftM, unless)+import qualified Control.Monad.State as S (State, gets, modify, runState)+import Data.List (nub, union)+import qualified Data.Map as Map+import Data.Maybe (fromMaybe)++import Curry.Base.Ident+import Curry.Base.Pretty+import Curry.Base.SpanInfo+import Curry.Syntax hiding (Var (..))++import Base.Messages+import Base.TopEnv++importCheck :: Interface -> Maybe ImportSpec -> (Maybe ImportSpec, [Message])+importCheck (Interface m _ ds) is = runExpand (expandSpecs is) m mTCEnv mTyEnv+ where+ mTCEnv = intfEnv types ds+ mTyEnv = intfEnv values ds++data ITypeInfo = Data QualIdent [Ident]+ | Alias QualIdent+ | Class QualIdent [Ident]+ deriving Show++instance Entity ITypeInfo where+ origName (Data tc _) = tc+ origName (Alias tc ) = tc+ origName (Class cls _) = cls++ merge (Data tc1 cs1) (Data tc2 cs2)+ | tc1 == tc2 && (null cs1 || null cs2 || cs1 == cs2) =+ Just $ Data tc1 (if null cs1 then cs2 else cs1)+ merge l@(Alias tc1) (Alias tc2)+ | tc1 == tc2 = Just l+ merge (Class cls1 ms1) (Class cls2 ms2)+ | cls1 == cls2 && (null ms1 || null ms2 || ms1 == ms2) =+ Just $ Class cls1 (if null ms1 then ms2 else ms1)+ merge _ _ = Nothing++data IValueInfo = Constr QualIdent+ | Var QualIdent [QualIdent]+ deriving Show++instance Entity IValueInfo where+ origName (Constr c) = c+ origName (Var x _) = x++ merge (Constr c1) (Constr c2)+ | c1 == c2 = Just (Constr c1)+ merge (Var x1 cs1) (Var x2 cs2)+ | x1 == x2 = Just (Var x1 (cs1 `union` cs2))+ merge _ _ = Nothing+++intfEnv :: Entity a => (IDecl -> [a]) -> [IDecl] -> IdentMap a+intfEnv idents ds = foldr bindId Map.empty (concatMap idents ds)+ where bindId x = Map.insert (unqualify (origName x)) x++types :: IDecl -> [ITypeInfo]+types (IDataDecl _ tc _ _ cs hs) = [Data tc (filter (`notElem` hs) xs)]+ where xs = map constrId cs ++ nub (concatMap recordLabels cs)+types (INewtypeDecl _ tc _ _ nc hs) = [Data tc (filter (`notElem` hs) xs)]+ where xs = nconstrId nc : nrecordLabels nc+types (ITypeDecl _ tc _ _ _) = [Alias tc]+types (IClassDecl _ _ cls _ _ ms hs) = [Class cls (filter (`notElem` hs) xs)]+ where xs = map imethod ms+types _ = []++values :: IDecl -> [IValueInfo]+values (IDataDecl _ tc _ _ cs hs) =+ cidents tc (map constrId cs) hs +++ lidents tc [(l, lconstrs cs l) | l <- nub (concatMap recordLabels cs)] hs+ where lconstrs cons l = [constrId c | c <- cons, l `elem` recordLabels c]+values (INewtypeDecl _ tc _ _ nc hs) =+ cidents tc [nconstrId nc] hs +++ lidents tc [(l, [c]) | NewRecordDecl _ c (l, _) <- [nc]] hs+values (IFunctionDecl _ f _ _ _) = [Var f []]+values (IClassDecl _ _ cls _ _ ms hs) = midents cls (map imethod ms) hs+values _ = []++cidents :: QualIdent -> [Ident] -> [Ident] -> [IValueInfo]+cidents tc cs hs = [Constr (qualifyLike tc c) | c <- cs, c `notElem` hs]++lidents :: QualIdent -> [(Ident, [Ident])] -> [Ident] -> [IValueInfo]+lidents tc ls hs = [ Var (qualifyLike tc l) (map (qualifyLike tc) cs)+ | (l, cs) <- ls, l `notElem` hs+ ]++midents :: QualIdent -> [Ident] -> [Ident] -> [IValueInfo]+midents cls fs hs = [Var (qualifyLike cls f) [] | f <- fs, f `notElem` hs]++-- ---------------------------------------------------------------------------+-- Expansion of the import specification+-- ---------------------------------------------------------------------------++-- After the environments have been initialized, the optional import+-- specifications can be checked. There are two kinds of import+-- specifications, a ``normal'' one, which names the entities that shall+-- be imported, and a hiding specification, which lists those entities+-- that shall not be imported.+--+-- There is a subtle difference between both kinds of+-- specifications: While it is not allowed to list a data constructor+-- outside of its type in a ``normal'' specification, it is allowed to+-- hide a data constructor explicitly. E.g., if module \texttt{A} exports+-- the data type \texttt{T} with constructor \texttt{C}, the data+-- constructor can be imported with one of the two specifications+--+-- import A (T(C))+-- import A (T(..))+--+-- but can be hidden in three different ways:+--+-- import A hiding (C)+-- import A hiding (T (C))+-- import A hiding (T (..))+--+-- The functions \texttt{expandImport} and \texttt{expandHiding} check+-- that all entities in an import specification are actually exported+-- from the module. In addition, all imports of type constructors are+-- changed into a \texttt{T()} specification and explicit imports for the+-- data constructors are added.++type IdentMap = Map.Map Ident++type ExpTCEnv = IdentMap ITypeInfo+type ExpValueEnv = IdentMap IValueInfo++data ExpandState = ExpandState+ { expModIdent :: ModuleIdent+ , expTCEnv :: ExpTCEnv+ , expValueEnv :: ExpValueEnv+ , errors :: [Message]+ }++type ExpandM a = S.State ExpandState a++getModuleIdent :: ExpandM ModuleIdent+getModuleIdent = S.gets expModIdent++getTyConsEnv :: ExpandM ExpTCEnv+getTyConsEnv = S.gets expTCEnv++getValueEnv :: ExpandM ExpValueEnv+getValueEnv = S.gets expValueEnv++report :: Message -> ExpandM ()+report msg = S.modify $ \ s -> s { errors = msg : errors s }++runExpand :: ExpandM a -> ModuleIdent -> ExpTCEnv -> ExpValueEnv -> (a, [Message])+runExpand expand m tcEnv tyEnv =+ let (r, s) = S.runState expand (ExpandState m tcEnv tyEnv [])+ in (r, reverse $ errors s)++expandSpecs :: Maybe ImportSpec -> ExpandM (Maybe ImportSpec)+expandSpecs Nothing = return Nothing+expandSpecs (Just (Importing p is)) = (Just . Importing p . concat) `liftM` mapM expandImport is+expandSpecs (Just (Hiding p is)) = (Just . Hiding p . concat) `liftM` mapM expandHiding is++expandImport :: Import -> ExpandM [Import]+expandImport (Import spi x ) = expandThing spi x+expandImport (ImportTypeWith spi tc cs) = (:[]) `liftM` expandTypeWith spi tc cs+expandImport (ImportTypeAll spi tc ) = (:[]) `liftM` expandTypeAll spi tc++expandHiding :: Import -> ExpandM [Import]+expandHiding (Import spi x ) = expandHide spi x+expandHiding (ImportTypeWith spi tc cs) = (:[]) `liftM` expandTypeWith spi tc cs+expandHiding (ImportTypeAll spi tc ) = (:[]) `liftM` expandTypeAll spi tc++-- try to expand as type constructor+expandThing :: SpanInfo -> Ident -> ExpandM [Import]+expandThing spi tc = do+ tcEnv <- getTyConsEnv+ case Map.lookup tc tcEnv of+ Just _ -> expandThing' spi tc $ Just [ImportTypeWith spi tc []]+ Nothing -> expandThing' spi tc Nothing++-- try to expand as function / data constructor+expandThing' :: SpanInfo -> Ident -> Maybe [Import] -> ExpandM [Import]+expandThing' spi f tcImport = do+ m <- getModuleIdent+ tyEnv <- getValueEnv+ expand m f (Map.lookup f tyEnv) tcImport+ where+ expand :: ModuleIdent -> Ident+ -> Maybe IValueInfo -> Maybe [Import] -> ExpandM [Import]+ expand m e Nothing Nothing = report (errUndefinedEntity m e) >> return []+ expand _ _ Nothing (Just tc) = return tc+ expand m e (Just v) maybeTc+ | isConstr v = case maybeTc of+ Nothing -> report (errImportDataConstr m e) >> return []+ Just tc -> return tc+ | otherwise = return [Import spi e]++ isConstr (Constr _) = True+ isConstr (Var _ _) = False++-- try to hide as type constructor+expandHide :: SpanInfo -> Ident -> ExpandM [Import]+expandHide spi tc = do+ tcEnv <- getTyConsEnv+ case Map.lookup tc tcEnv of+ Just _ -> expandHide' spi tc $ Just [ImportTypeWith spi tc []]+ Nothing -> expandHide' spi tc Nothing++-- try to hide as function / data constructor+expandHide' :: SpanInfo -> Ident -> Maybe [Import] -> ExpandM [Import]+expandHide' spi f tcImport = do+ m <- getModuleIdent+ tyEnv <- getValueEnv+ case Map.lookup f tyEnv of+ Just _ -> return $ Import spi f : fromMaybe [] tcImport+ Nothing -> case tcImport of+ Nothing -> report (errUndefinedEntity m f) >> return []+ Just tc -> return tc++expandTypeWith :: SpanInfo -> Ident -> [Ident] -> ExpandM Import+expandTypeWith spi tc cs = do+ m <- getModuleIdent+ tcEnv <- getTyConsEnv+ ImportTypeWith spi tc `liftM` case Map.lookup tc tcEnv of+ Just (Data _ xs) -> mapM (checkElement errUndefinedElement xs) cs+ Just (Class _ xs) -> mapM (checkElement errUndefinedMethod xs) cs+ Just (Alias _) -> report (errNonDataTypeOrTypeClass tc) >> return []+ Nothing -> report (errUndefinedEntity m tc) >> return []+ where+ -- check if given identifier is constructor or label of type tc+ checkElement err cs' c = do+ unless (c `elem` cs') $ report $ err tc c+ return c++expandTypeAll :: SpanInfo -> Ident -> ExpandM Import+expandTypeAll spi tc = do+ m <- getModuleIdent+ tcEnv <- getTyConsEnv+ ImportTypeWith spi tc `liftM` case Map.lookup tc tcEnv of+ Just (Data _ xs) -> return xs+ Just (Class _ xs) -> return xs+ Just (Alias _) -> report (errNonDataTypeOrTypeClass tc) >> return []+ Nothing -> report (errUndefinedEntity m tc) >> return []++-- error messages++errUndefinedElement :: Ident -> Ident -> Message+errUndefinedElement tc c = spanInfoMessage c $ hsep $ map text+ [ idName c, "is not a constructor or label of type ", idName tc ]++errUndefinedMethod :: Ident -> Ident -> Message+errUndefinedMethod cls f = spanInfoMessage f $ hsep $ map text+ [ idName f, "is not a method of class", idName cls ]++errUndefinedEntity :: ModuleIdent -> Ident -> Message+errUndefinedEntity m x = spanInfoMessage x $ hsep $ map text+ [ "Module", moduleName m, "does not export", idName x ]++errNonDataTypeOrTypeClass :: Ident -> Message+errNonDataTypeOrTypeClass tc = spanInfoMessage tc $ hsep $ map text+ [ idName tc, "is not a data type or type class" ]++errImportDataConstr :: ModuleIdent -> Ident -> Message+errImportDataConstr _ c = spanInfoMessage c $ hsep $ map text+ [ "Explicit import for data constructor", idName c ]
+ src/Checks/InstanceCheck.hs view
@@ -0,0 +1,414 @@+{- |+ Module : $Header$+ Description : Checks instances+ Copyright : (c) 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ Before type checking, the compiler checks for every instance declaration+ that all necessary super class instances exist. Furthermore, the compiler+ infers the contexts of the implicit instance declarations introduced by+ deriving clauses in data and newtype declarations. The instances declared+ explicitly and automatically derived by the compiler are added to the+ instance environment . It is also checked that there are no duplicate+ instances and that all types specified in a default declaration are+ instances of the Num class.+-}+module Checks.InstanceCheck (instanceCheck) where++import Control.Monad.Extra (concatMapM, whileM, unless)+import qualified Control.Monad.State as S (State, execState, gets, modify)+import Data.List (nub, partition, sortBy)+import qualified Data.Map as Map+import qualified Data.Set.Extra as Set++import Curry.Base.Ident+import Curry.Base.Pretty+import Curry.Base.SpanInfo+import Curry.Syntax hiding (impls)+import Curry.Syntax.Pretty++import Base.CurryTypes+import Base.Messages (Message, spanInfoMessage, message, internalError)+import Base.SCC (scc)+import Base.TypeExpansion+import Base.Types+import Base.TypeSubst+import Base.Utils (fst3, snd3, findMultiples)++import Env.Class+import Env.Instance+import Env.TypeConstructor++instanceCheck :: ModuleIdent -> TCEnv -> ClassEnv -> InstEnv -> [Decl a]+ -> (InstEnv, [Message])+instanceCheck m tcEnv clsEnv inEnv ds =+ case findMultiples (local ++ imported) of+ [] -> execINCM (checkDecls tcEnv clsEnv ds) state+ iss -> (inEnv, map (errMultipleInstances tcEnv) iss)+ where+ local = map (flip InstSource m) $ concatMap (genInstIdents m tcEnv) ds+ imported = map (uncurry InstSource . fmap fst3) $ Map.toList inEnv+ state = INCState m inEnv []++-- In order to provide better error messages, we use the following data type+-- to keep track of an instance's source, i.e., the module it was defined in.++data InstSource = InstSource InstIdent ModuleIdent++instance Eq InstSource where+ InstSource i1 _ == InstSource i2 _ = i1 == i2++-- |Instance Check Monad+type INCM = S.State INCState++-- |Internal state of the Instance Check+data INCState = INCState+ { moduleIdent :: ModuleIdent+ , instEnv :: InstEnv+ , errors :: [Message]+ }++execINCM :: INCM a -> INCState -> (InstEnv, [Message])+execINCM incm s =+ let s' = S.execState incm s in (instEnv s', reverse $ nub $ errors s')++getModuleIdent :: INCM ModuleIdent+getModuleIdent = S.gets moduleIdent++getInstEnv :: INCM InstEnv+getInstEnv = S.gets instEnv++modifyInstEnv :: (InstEnv -> InstEnv) -> INCM ()+modifyInstEnv f = S.modify $ \s -> s { instEnv = f $ instEnv s }++report :: Message -> INCM ()+report err = S.modify (\s -> s { errors = err : errors s })++ok :: INCM ()+ok = return ()++checkDecls :: TCEnv -> ClassEnv -> [Decl a] -> INCM ()+checkDecls tcEnv clsEnv ds = do+ mapM_ (bindInstance tcEnv clsEnv) ids+ mapM (declDeriveDataInfo tcEnv clsEnv) (filter isDataDecl tds) >>=+ mapM_ (bindDerivedInstances clsEnv) . groupDeriveInfos+ mapM (declDeriveInfo tcEnv clsEnv) (filter hasDerivedInstances tds) >>=+ mapM_ (bindDerivedInstances clsEnv) . groupDeriveInfos+ mapM_ (checkInstance tcEnv clsEnv) ids+ mapM_ (checkDefault tcEnv clsEnv) dds+ where (tds, ods) = partition isTypeDecl ds+ ids = filter isInstanceDecl ods+ dds = filter isDefaultDecl ods+ isDataDecl (DataDecl _ _ _ _ _) = True+ isDataDecl (NewtypeDecl _ _ _ _ _) = True+ isDataDecl _ = False++-- First, the compiler adds all explicit instance declarations to the+-- instance environment.++bindInstance :: TCEnv -> ClassEnv -> Decl a -> INCM ()+bindInstance tcEnv clsEnv (InstanceDecl _ _ cx qcls inst ds) = do+ m <- getModuleIdent+ let PredType ps _ = expandPolyType m tcEnv clsEnv $+ QualTypeExpr NoSpanInfo cx inst+ modifyInstEnv $+ bindInstInfo (genInstIdent m tcEnv qcls inst) (m, ps, impls [] ds)+ where impls is [] = is+ impls is (FunctionDecl _ _ f eqs:ds')+ | f' `elem` map fst is = impls is ds'+ | otherwise = impls ((f', eqnArity $ head eqs) : is) ds'+ where f' = unRenameIdent f+ impls _ _ = internalError "InstanceCheck.bindInstance.impls"+bindInstance _ _ _ = ok++-- Next, the compiler sorts the data and newtype declarations with non-empty+-- deriving clauses into minimal binding groups and infers contexts for their+-- instance declarations. In the case of (mutually) recursive data types,+-- inference of the appropriate contexts may require a fixpoint calculation.++hasDerivedInstances :: Decl a -> Bool+hasDerivedInstances (DataDecl _ _ _ _ clss) = not $ null clss+hasDerivedInstances (NewtypeDecl _ _ _ _ clss) = not $ null clss+hasDerivedInstances _ = False++-- For the purposes of derived instances, a newtype declaration is treated+-- as a data declaration with a single constructor. The compiler also sorts+-- derived classes with respect to the super class hierarchy so that subclass+-- instances are added to the instance environment after their super classes.++data DeriveInfo = DeriveInfo SpanInfo QualIdent PredType [Type] [QualIdent]++declDeriveInfo :: TCEnv -> ClassEnv -> Decl a -> INCM DeriveInfo+declDeriveInfo tcEnv clsEnv (DataDecl p tc tvs cs clss) =+ mkDeriveInfo tcEnv clsEnv p tc tvs (concat tyss) clss+ where tyss = map constrDeclTypes cs+ constrDeclTypes (ConstrDecl _ _ tys) = tys+ constrDeclTypes (ConOpDecl _ ty1 _ ty2) = [ty1, ty2]+ constrDeclTypes (RecordDecl _ _ fs) = tys+ where tys = [ty | FieldDecl _ ls ty <- fs, _ <- ls]+declDeriveInfo tcEnv clsEnv (NewtypeDecl p tc tvs nc clss) =+ mkDeriveInfo tcEnv clsEnv p tc tvs [nconstrType nc] clss+declDeriveInfo _ _ _ =+ internalError "InstanceCheck.declDeriveInfo: no data or newtype declaration"++declDeriveDataInfo :: TCEnv -> ClassEnv -> Decl a -> INCM DeriveInfo+declDeriveDataInfo tcEnv clsEnv (DataDecl p tc tvs cs _) =+ mkDeriveDataInfo tcEnv clsEnv p tc tvs (concat tyss)+ where tyss = map constrDeclTypes cs+ constrDeclTypes (ConstrDecl _ _ tys) = tys+ constrDeclTypes (ConOpDecl _ ty1 _ ty2) = [ty1, ty2]+ constrDeclTypes (RecordDecl _ _ fs) = tys+ where tys = [ty | FieldDecl _ ls ty <- fs, _ <- ls]+declDeriveDataInfo tcEnv clsEnv (NewtypeDecl p tc tvs nc _) =+ mkDeriveDataInfo tcEnv clsEnv p tc tvs [nconstrType nc]+declDeriveDataInfo _ _ _ = internalError+ "InstanceCheck.declDeriveDataInfo: no data or newtype declaration"++mkDeriveInfo :: TCEnv -> ClassEnv -> SpanInfo -> Ident -> [Ident]+ -> [TypeExpr] -> [QualIdent] -> INCM DeriveInfo+mkDeriveInfo tcEnv clsEnv spi tc tvs tys clss = do+ m <- getModuleIdent+ let otc = qualifyWith m tc+ oclss = map (flip (getOrigName m) tcEnv) clss+ PredType ps ty = expandConstrType m tcEnv clsEnv otc tvs tys+ (tys', ty') = arrowUnapply ty+ return $ DeriveInfo spi otc (PredType ps ty') tys' $ sortClasses clsEnv oclss++mkDeriveDataInfo :: TCEnv -> ClassEnv -> SpanInfo -> Ident -> [Ident]+ -> [TypeExpr] -> INCM DeriveInfo+mkDeriveDataInfo tcEnv clsEnv spi tc tvs tys = do+ m <- getModuleIdent+ let otc = qualifyWith m tc+ PredType ps ty = expandConstrType m tcEnv clsEnv otc tvs tys+ (tys', ty') = arrowUnapply ty+ return $ DeriveInfo spi otc (PredType ps ty') tys' [qDataId]++sortClasses :: ClassEnv -> [QualIdent] -> [QualIdent]+sortClasses clsEnv clss = map fst $ sortBy compareDepth $ map adjoinDepth clss+ where (_, d1) `compareDepth` (_, d2) = d1 `compare` d2+ adjoinDepth cls = (cls, length $ allSuperClasses cls clsEnv)++groupDeriveInfos :: [DeriveInfo] -> [[DeriveInfo]]+groupDeriveInfos = scc bound free+ where bound (DeriveInfo _ tc _ _ _) = [tc]+ free (DeriveInfo _ _ _ tys _) = concatMap typeConstrs tys++bindDerivedInstances :: ClassEnv -> [DeriveInfo] -> INCM ()+bindDerivedInstances clsEnv dis = unless (any hasDataFunType dis) $ do+ mapM_ (enterInitialPredSet clsEnv) dis+ whileM $ concatMapM (inferPredSets clsEnv) dis >>= updatePredSets+ where+ hasDataFunType (DeriveInfo _ _ _ tys clss) =+ clss == [qDataId] && any isFunType tys++enterInitialPredSet :: ClassEnv -> DeriveInfo -> INCM ()+enterInitialPredSet clsEnv (DeriveInfo spi tc pty _ clss) =+ mapM_ (bindDerivedInstance clsEnv spi tc pty) clss++-- Note: The methods and arities entered into the instance environment have+-- to match methods and arities of the later generated instance declarations.+-- TODO: Add remark about value environment entry++bindDerivedInstance :: HasSpanInfo s => ClassEnv -> s -> QualIdent -> PredType -> QualIdent+ -> INCM ()+bindDerivedInstance clsEnv p tc pty cls = do+ m <- getModuleIdent+ ((i, ps), _) <- inferPredSet clsEnv p tc pty [] cls+ modifyInstEnv (bindInstInfo i (m, ps, impls))+ where impls | cls == qEqId = [(eqOpId, 2)]+ | cls == qOrdId = [(leqOpId, 2)]+ | cls == qEnumId = [ (succId, 1), (predId, 1), (toEnumId, 1)+ , (fromEnumId, 1), (enumFromId, 1)+ , (enumFromThenId, 2)+ ]+ | cls == qBoundedId = [(maxBoundId, 0), (minBoundId, 0)]+ | cls == qReadId = [(readsPrecId, 2)]+ | cls == qShowId = [(showsPrecId, 2)]+ | cls == qDataId = [(dataEqId, 2), (aValueId, 0)]+ | otherwise =+ internalError "InstanceCheck.bindDerivedInstance.impls"++inferPredSets :: ClassEnv -> DeriveInfo -> INCM [((InstIdent, PredSet), Bool)]+inferPredSets clsEnv (DeriveInfo spi tc pty tys clss) =+ mapM (inferPredSet clsEnv spi tc pty tys) clss++inferPredSet :: HasSpanInfo s => ClassEnv -> s -> QualIdent -> PredType -> [Type]+ -> QualIdent -> INCM ((InstIdent, PredSet), Bool)+inferPredSet clsEnv p tc (PredType ps inst) tys cls = do+ m <- getModuleIdent+ let doc = ppPred m $ Pred cls inst+ sclss = superClasses cls clsEnv+ ps' = Set.fromList [Pred cls ty | ty <- tys]+ ps'' = Set.fromList [Pred scls inst | scls <- sclss]+ ps''' = ps `Set.union` ps' `Set.union` ps''+ (ps4, novarps) <-+ reducePredSet (cls == qDataId) p "derived instance" doc clsEnv ps'''+ let ps5 = filter noPolyPred $ Set.toList ps4+ if any (isDataPred m) (Set.toList novarps ++ ps5) && cls == qDataId+ then return (((cls, tc), ps4), False)+ else mapM_ (reportUndecidable p "derived instance" doc) ps5+ >> return (((cls, tc), ps4), True)+ where+ noPolyPred (Pred _ (TypeVariable _)) = False+ noPolyPred (Pred _ _ ) = True+ isDataPred _ (Pred qid _) = qid == qDataId++updatePredSets :: [((InstIdent, PredSet), Bool)] -> INCM Bool+updatePredSets = fmap or . mapM (uncurry updatePredSet)++updatePredSet :: (InstIdent, PredSet) -> Bool -> INCM Bool+updatePredSet (i, ps) enter = do+ inEnv <- getInstEnv+ case lookupInstInfo i inEnv of+ Just (m, ps', is)+ | not enter -> modifyInstEnv (removeInstInfo i) >> return False+ | ps == ps' -> return False+ | otherwise -> do+ modifyInstEnv $ bindInstInfo i (m, ps, is)+ return True+ Nothing -> internalError "InstanceCheck.updatePredSet"++reportUndecidable :: HasSpanInfo s => s -> String -> Doc -> Pred -> INCM ()+reportUndecidable p what doc predicate@(Pred _ ty) = do+ m <- getModuleIdent+ case ty of+ TypeVariable _ -> return ()+ _ -> report $ errMissingInstance m p what doc predicate++-- Then, the compiler checks the contexts of all explicit instance+-- declarations to detect missing super class instances. For an instance+-- declaration+--+-- instance cx => C (T u_1 ... u_k) where ...+--+-- the compiler ensures that T is an instance of all of C's super classes+-- and also that the contexts of the corresponding instance declarations are+-- satisfied by cx.++checkInstance :: TCEnv -> ClassEnv -> Decl a -> INCM ()+checkInstance tcEnv clsEnv (InstanceDecl _ _ cx cls inst _) = do+ m <- getModuleIdent+ let PredType ps ty = expandPolyType m tcEnv clsEnv $+ QualTypeExpr NoSpanInfo cx inst+ ocls = getOrigName m cls tcEnv+ ps' = Set.fromList [ Pred scls ty | scls <- superClasses ocls clsEnv ]+ doc = ppPred m $ Pred cls ty+ what = "instance declaration"+ (ps'', _) <- reducePredSet False inst what doc clsEnv ps'+ Set.mapM_ (report . errMissingInstance m inst what doc) $+ ps'' `Set.difference` maxPredSet clsEnv ps+checkInstance _ _ _ = ok++-- All types specified in the optional default declaration of a module+-- must be instances of the Num class. Since these types are used to resolve+-- ambiguous type variables, the predicate sets of the respective instances+-- must be empty.++checkDefault :: TCEnv -> ClassEnv -> Decl a -> INCM ()+checkDefault tcEnv clsEnv (DefaultDecl _ tys) =+ mapM_ (checkDefaultType tcEnv clsEnv) tys+checkDefault _ _ _ = ok++checkDefaultType :: TCEnv -> ClassEnv -> TypeExpr -> INCM ()+checkDefaultType tcEnv clsEnv ty = do+ m <- getModuleIdent+ let PredType _ ty' = expandPolyType m tcEnv clsEnv $+ QualTypeExpr NoSpanInfo [] ty+ (ps, _) <- reducePredSet False ty what empty clsEnv+ (Set.singleton $ Pred qNumId ty')+ Set.mapM_ (report . errMissingInstance m ty what empty) ps+ where what = "default declaration"++-- The function 'reducePredSet' simplifies a predicate set of the form+-- (C_1 tau_1,..,C_n tau_n) where the tau_i are arbitrary types into a+-- predicate set where all predicates are of the form C u with u being+-- a type variable. An error is reported if the predicate set cannot+-- be transformed into this form. In addition, we remove all predicates+-- that are implied by others within the same set.+-- When the flag is set, all missing Data preds are ignored++reducePredSet :: HasSpanInfo s => Bool -> s -> String -> Doc -> ClassEnv -> PredSet+ -> INCM (PredSet, PredSet)+reducePredSet b p what doc clsEnv ps = do+ m <- getModuleIdent+ inEnv <- getInstEnv+ let (ps1, ps2) = partitionPredSet $ minPredSet clsEnv $ reducePreds inEnv ps+ ps2' = if b then Set.filter (isNotDataPred m) ps2 else ps2+ Set.mapM_ (reportMissing m) ps2' >> return (ps1, ps2)+ where+ isNotDataPred _ (Pred qid _) = qid /= qDataId+ reportMissing m pr@(Pred _ _) =+ report $ errMissingInstance m p what doc pr+ reducePreds inEnv = Set.concatMap $ reducePred inEnv+ reducePred inEnv predicate = maybe (Set.singleton predicate)+ (reducePreds inEnv)+ (instPredSet inEnv predicate)++instPredSet :: InstEnv -> Pred -> Maybe PredSet+instPredSet inEnv (Pred qcls ty) =+ case unapplyType False ty of+ (TypeConstructor tc, tys) ->+ fmap (expandAliasType tys . snd3) (lookupInstInfo (qcls, tc) inEnv)+ _ -> Nothing++-- ---------------------------------------------------------------------------+-- Auxiliary definitions+-- ---------------------------------------------------------------------------++genInstIdents :: ModuleIdent -> TCEnv -> Decl a -> [InstIdent]+genInstIdents m tcEnv (DataDecl _ tc _ _ qclss) =+ map (flip (genInstIdent m tcEnv) $ ConstructorType NoSpanInfo $ qualify tc)+ qclss+genInstIdents m tcEnv (NewtypeDecl _ tc _ _ qclss) =+ map (flip (genInstIdent m tcEnv) $ ConstructorType NoSpanInfo $ qualify tc)+ qclss+genInstIdents m tcEnv (InstanceDecl _ _ _ qcls ty _) =+ [genInstIdent m tcEnv qcls ty]+genInstIdents _ _ _ = []++genInstIdent :: ModuleIdent -> TCEnv -> QualIdent -> TypeExpr -> InstIdent+genInstIdent m tcEnv qcls = qualInstIdent m tcEnv . (,) qcls . typeConstr++-- When qualifiying an instance identifier, we replace both the class and+-- type constructor with their original names as found in the type constructor+-- environment.++qualInstIdent :: ModuleIdent -> TCEnv -> InstIdent -> InstIdent+qualInstIdent m tcEnv (cls, tc) = (qual cls, qual tc)+ where+ qual = flip (getOrigName m) tcEnv++unqualInstIdent :: TCEnv -> InstIdent -> InstIdent+unqualInstIdent tcEnv (qcls, tc) = (unqual qcls, unqual tc)+ where+ unqual = head . flip reverseLookupByOrigName tcEnv++isFunType :: Type -> Bool+isFunType (TypeArrow _ _) = True+isFunType (TypeApply t1 t2) = isFunType t1 || isFunType t2+isFunType (TypeForall _ ty) = isFunType ty+isFunType (TypeConstrained tys _) = any isFunType tys+isFunType _ = False++-- ---------------------------------------------------------------------------+-- Error messages+-- ---------------------------------------------------------------------------++errMultipleInstances :: TCEnv -> [InstSource] -> Message+errMultipleInstances tcEnv iss = message $+ text "Multiple instances for the same class and type" $+$+ nest 2 (vcat (map ppInstSource iss))+ where+ ppInstSource (InstSource i m) = ppInstIdent (unqualInstIdent tcEnv i) <+>+ parens (text "defined in" <+> ppMIdent m)++errMissingInstance :: HasSpanInfo s => ModuleIdent -> s -> String -> Doc -> Pred+ -> Message+errMissingInstance m p what doc predicate = spanInfoMessage (getSpanInfo p) $ vcat+ [ text "Missing instance for" <+> ppPred m predicate+ , text "in" <+> text what <+> doc+ ]
+ src/Checks/InterfaceCheck.hs view
@@ -0,0 +1,321 @@+{- |+ Module : $Header$+ Description : Checks consistency of interface files+ Copyright : (c) 2000 - 2007 Wolfgang Lux+ 2015 Jan Tikovsky+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ Interface files include declarations of all entities that are exported+ by the module, but defined in another module. Since these declarations+ can become inconsistent if client modules are not recompiled properly,+ the compiler checks that all imported declarations in an interface+ agree with their original definitions.++ One may ask why we include imported declarations at all, if the+ compiler always has to compare those declarations with the original+ definitions. The main reason for this is that it helps to avoid+ unnecessary recompilations of client modules. As an example, consider+ the three modules:++ module A where { data T = C }+ module B(T(..)) where { import A }+ module C where { import B; f = C }++ where module B could be considered as a public interface of module A,+ which restricts access to type A.T and its constructor C.+ The client module C imports this type via the public interface B.+ If now module A is changed by adding a definition of a new global function++ module A where { data T = C; f = C }++ module B must be recompiled because A's interface is changed.+ On the other hand, module C need not be recompiled because the change in+ A does not affect B's interface. By including the declaration of type A.T+ in B's interface, the compiler can trivially check that B's interface+ remains unchanged and therefore the client module C is not recompiled.++ Another reason for including imported declarations in interfaces is+ that the compiler in principle could avoid loading interfaces of+ modules that are imported only indirectly, which would save processing+ time and allow distributing binary packages of a library with a public+ interface module only. However, this has not been implemented yet.+-}++module Checks.InterfaceCheck (interfaceCheck) where++import Control.Monad (unless)+import qualified Control.Monad.State as S+import Data.List (sort)+import Data.Maybe (fromMaybe, isJust, isNothing)++import Curry.Base.Ident+import Curry.Base.SpanInfo+import Curry.Base.Pretty+import Curry.Syntax++import Base.CurryKinds (toKind')+import Base.CurryTypes+import Base.Messages (Message, spanInfoMessage, internalError)+import Base.TopEnv+import Base.Types++import Env.Class+import Env.Instance+import Env.OpPrec+import Env.TypeConstructor+import Env.Value++data ICState = ICState+ { moduleIdent :: ModuleIdent+ , precEnv :: OpPrecEnv+ , tyConsEnv :: TCEnv+ , classEnv :: ClassEnv+ , instEnv :: InstEnv+ , valueEnv :: ValueEnv+ , errors :: [Message]+ }++type IC = S.State ICState++getModuleIdent :: IC ModuleIdent+getModuleIdent = S.gets moduleIdent++getPrecEnv :: IC OpPrecEnv+getPrecEnv = S.gets precEnv++getTyConsEnv :: IC TCEnv+getTyConsEnv = S.gets tyConsEnv++getClassEnv :: IC ClassEnv+getClassEnv = S.gets classEnv++getInstEnv :: IC InstEnv+getInstEnv = S.gets instEnv++getValueEnv :: IC ValueEnv+getValueEnv = S.gets valueEnv++-- |Report a syntax error+report :: Message -> IC ()+report msg = S.modify $ \s -> s { errors = msg : errors s }++ok :: IC ()+ok = return ()++interfaceCheck :: OpPrecEnv -> TCEnv -> ClassEnv -> InstEnv -> ValueEnv+ -> Interface -> [Message]+interfaceCheck pEnv tcEnv clsEnv inEnv tyEnv (Interface m _ ds) =+ reverse (errors s)+ where s = S.execState (mapM_ checkImport ds) initState+ initState = ICState m pEnv tcEnv clsEnv inEnv tyEnv []++checkImport :: IDecl -> IC ()+checkImport (IInfixDecl _ fix pr op) = checkPrecInfo check op op+ where check (PrecInfo op' (OpPrec fix' pr')) =+ op == op' && fix == fix' && pr == pr'+checkImport (HidingDataDecl _ tc k tvs) =+ checkTypeInfo "hidden data type" check tc tc+ where check (DataType tc' k' _)+ | tc == tc' && toKind' k (length tvs) == k' = Just ok+ check (RenamingType tc' k' _)+ | tc == tc' && toKind' k (length tvs) == k' = Just ok+ check _ = Nothing+checkImport (IDataDecl _ tc k tvs cs _) = checkTypeInfo "data type" check tc tc+ where check (DataType tc' k' cs')+ | tc == tc' && toKind' k (length tvs) == k' &&+ (null cs || map constrId cs == map constrIdent cs')+ = Just (mapM_ (checkConstrImport tc tvs) cs)+ check (RenamingType tc' k' _)+ | tc == tc' && toKind' k (length tvs) == k' && null cs+ = Just ok+ check _ = Nothing+checkImport (INewtypeDecl _ tc k tvs nc _) = checkTypeInfo "newtype" check tc tc+ where check (RenamingType tc' k' nc')+ | tc == tc' && toKind' k (length tvs) == k' &&+ nconstrId nc == constrIdent nc'+ = Just (checkNewConstrImport tc tvs nc)+ check _ = Nothing+checkImport (ITypeDecl _ tc k tvs ty) = do+ m <- getModuleIdent+ let check (AliasType tc' k' n' ty')+ | tc == tc' && toKind' k (length tvs) == k' &&+ length tvs == n' && toQualType m tvs ty == ty'+ = Just ok+ check _ = Nothing+ checkTypeInfo "synonym type" check tc tc+checkImport (IFunctionDecl _ f (Just tv) n ty) = do+ m <- getModuleIdent+ let check (Value f' cm' n' (ForAll _ ty')) =+ f == f' && isJust cm' && n' == n &&+ toQualPredType m [tv] ty == ty'+ check _ = False+ checkValueInfo "method" check f f+checkImport (IFunctionDecl _ f Nothing n ty) = do+ m <- getModuleIdent+ let check (Value f' cm' n' (ForAll _ ty')) =+ f == f' && isNothing cm' && n' == n &&+ toQualPredType m [] ty == ty'+ check _ = False+ checkValueInfo "function" check f f+checkImport (HidingClassDecl _ cx cls k _) = do+ clsEnv <- getClassEnv+ let check (TypeClass cls' k' _)+ | cls == cls' && toKind' k 0 == k' &&+ [cls'' | Constraint _ cls'' _ <- cx] == superClasses cls' clsEnv+ = Just ok+ check _ = Nothing+ checkTypeInfo "hidden type class" check cls cls+checkImport (IClassDecl _ cx cls k clsvar ms _) = do+ clsEnv <- getClassEnv+ let check (TypeClass cls' k' fs)+ | cls == cls' && toKind' k 0 == k' &&+ [cls'' | Constraint _ cls'' _ <- cx] == superClasses cls' clsEnv &&+ map (\m -> (imethod m, imethodArity m)) ms ==+ map (\f -> (methodName f, methodArity f)) fs+ = Just $ mapM_ (checkMethodImport cls clsvar) ms+ check _ = Nothing+ checkTypeInfo "type class" check cls cls+checkImport (IInstanceDecl _ cx cls ty is m) =+ checkInstInfo check cls (cls, typeConstr ty) m+ where PredType ps _ = toPredType [] $ QualTypeExpr NoSpanInfo cx ty+ check ps' is' = ps == ps' && sort is == sort is'++checkConstrImport :: QualIdent -> [Ident] -> ConstrDecl -> IC ()+checkConstrImport tc tvs (ConstrDecl _ c tys) = do+ m <- getModuleIdent+ let qc = qualifyLike tc c+ check (DataConstructor c' _ _ (ForAll uqvs pty)) =+ qc == c' && length tvs == uqvs &&+ qualifyPredType m (toConstrType tc tvs tys) == pty+ check _ = False+ checkValueInfo "data constructor" check c qc+checkConstrImport tc tvs (ConOpDecl _ ty1 op ty2) = do+ m <- getModuleIdent+ let qc = qualifyLike tc op+ check (DataConstructor c' _ _ (ForAll uqvs pty)) =+ qc == c' && length tvs == uqvs &&+ qualifyPredType m (toConstrType tc tvs [ty1, ty2]) == pty+ check _ = False+ checkValueInfo "data constructor" check op qc+checkConstrImport tc tvs (RecordDecl _ c fs) = do+ m <- getModuleIdent+ let qc = qualifyLike tc c+ (ls, tys) = unzip [(l, ty) | FieldDecl _ labels ty <- fs, l <- labels]+ check (DataConstructor c' _ ls' (ForAll uqvs pty)) =+ qc == c' && length tvs == uqvs && ls == ls' &&+ qualifyPredType m (toConstrType tc tvs tys) == pty+ check _ = False+ checkValueInfo "data constructor" check c qc++checkNewConstrImport :: QualIdent -> [Ident] -> NewConstrDecl -> IC ()+checkNewConstrImport tc tvs (NewConstrDecl _ c ty) = do+ m <- getModuleIdent+ let qc = qualifyLike tc c+ check (NewtypeConstructor c' _ (ForAll uqvs (PredType _ ty'))) =+ qc == c' && length tvs == uqvs && toQualType m tvs ty == head (arrowArgs ty')+ check _ = False+ checkValueInfo "newtype constructor" check c qc+checkNewConstrImport tc tvs (NewRecordDecl _ c (l, ty)) = do+ m <- getModuleIdent+ let qc = qualifyLike tc c+ check (NewtypeConstructor c' l' (ForAll uqvs (PredType _ ty'))) =+ qc == c' && length tvs == uqvs && l == l' &&+ toQualType m tvs ty == head (arrowArgs ty')+ check _ = False+ checkValueInfo "newtype constructor" check c qc++checkMethodImport :: QualIdent -> Ident -> IMethodDecl -> IC ()+checkMethodImport qcls clsvar (IMethodDecl _ f _ qty) =+ checkValueInfo "method" check f qf+ where qf = qualifyLike qcls f+ check (Value f' cm' _ (ForAll _ pty)) =+ qf == f' && isJust cm' &&+ toMethodType qcls clsvar qty == pty+ check _ = False++checkPrecInfo :: HasSpanInfo s => (PrecInfo -> Bool) -> s -> QualIdent -> IC ()+checkPrecInfo check p op = do+ pEnv <- getPrecEnv+ let checkInfo m op' = case qualLookupTopEnv op pEnv of+ [] -> report $ errNoPrecedence p m op'+ [prec] -> unless (check prec)+ (report $ errImportConflict p "precedence" m op')+ _ -> internalError "checkPrecInfo"+ checkImported checkInfo op++checkTypeInfo :: HasSpanInfo s => String -> (TypeInfo -> Maybe (IC ())) -> s+ -> QualIdent -> IC ()+checkTypeInfo what check p tc = do+ tcEnv <- getTyConsEnv+ let checkInfo m tc' = case qualLookupTopEnv tc tcEnv of+ [] -> report $ errNotExported p what m tc'+ [ti] -> fromMaybe (report $ errImportConflict p what m tc') (check ti)+ _ -> internalError "checkTypeInfo"+ checkImported checkInfo tc++checkInstInfo :: HasSpanInfo s => (PredSet -> [(Ident, Int)] -> Bool) -> s -> InstIdent+ -> Maybe ModuleIdent -> IC ()+checkInstInfo check p i mm = do+ inEnv <- getInstEnv+ let checkInfo m _ = case lookupInstInfo i inEnv of+ Just (m', ps, is)+ | m /= m' -> report $ errNoInstance p m i+ | otherwise ->+ unless (check ps is) $ report $ errInstanceConflict p m i+ Nothing -> report $ errNoInstance p m i+ checkImported checkInfo (maybe qualify qualifyWith mm anonId)++checkValueInfo :: HasSpanInfo a => String -> (ValueInfo -> Bool) -> a+ -> QualIdent -> IC ()+checkValueInfo what check p x = do+ tyEnv <- getValueEnv+ let checkInfo m x' = case qualLookupTopEnv x tyEnv of+ [] -> report $ errNotExported p' what m x'+ [vi] -> unless (check vi)+ (report $ errImportConflict p' what m x')+ _ -> internalError "checkValueInfo"+ checkImported checkInfo x+ where p' = getSpanInfo p++checkImported :: (ModuleIdent -> Ident -> IC ()) -> QualIdent -> IC ()+checkImported _ (QualIdent _ Nothing _) = ok+checkImported f (QualIdent _ (Just m) x) = f m x++-- ---------------------------------------------------------------------------+-- Error messages+-- ---------------------------------------------------------------------------++errNotExported :: HasSpanInfo s => s -> String -> ModuleIdent -> Ident -> Message+errNotExported p what m x = spanInfoMessage p $+ text "Inconsistent module interfaces"+ $+$ text "Module" <+> text (moduleName m)+ <+> text "does not export"<+> text what <+> text (escName x)++errNoPrecedence :: HasSpanInfo s => s -> ModuleIdent -> Ident -> Message+errNoPrecedence p m x = spanInfoMessage p $+ text "Inconsistent module interfaces"+ $+$ text "Module" <+> text (moduleName m)+ <+> text "does not define a precedence for" <+> text (escName x)++errNoInstance :: HasSpanInfo s => s -> ModuleIdent -> InstIdent -> Message+errNoInstance p m i = spanInfoMessage p $+ text "Inconsistent module interfaces"+ $+$ text "Module" <+> text (moduleName m)+ <+> text "does not define an instance for" <+> ppInstIdent i++errImportConflict :: HasSpanInfo s => s -> String -> ModuleIdent -> Ident -> Message+errImportConflict p what m x = spanInfoMessage p $+ text "Inconsistent module interfaces"+ $+$ text "Declaration of" <+> text what <+> text (escName x)+ <+> text "does not match its definition in module" <+> text (moduleName m)++errInstanceConflict :: HasSpanInfo s => s -> ModuleIdent -> InstIdent -> Message+errInstanceConflict p m i = spanInfoMessage p $+ text "Inconsistent module interfaces"+ $+$ text "Declaration of instance" <+> ppInstIdent i+ <+> text "does not match its definition in module" <+> text (moduleName m)
+ src/Checks/InterfaceSyntaxCheck.hs view
@@ -0,0 +1,346 @@+{- |+ Module : $Header$+ Description : Checks interface declarations+ Copyright : (c) 2000 - 2007 Wolfgang Lux+ 2011 - 2015 Björn Peemöller+ 2015 Jan Tikovsky+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ Similar to Curry source files, some post-processing has to be applied+ to parsed interface files. In particular, the compiler must+ disambiguate nullary type constructors and type variables. In+ addition, the compiler also checks that all type constructor+ applications are saturated. Since interface files are closed -- i.e.,+ they include declarations of all entities which are defined in other+ modules -- the compiler can perform this check without reference to+ the global environments.+-}++module Checks.InterfaceSyntaxCheck (intfSyntaxCheck) where++import Control.Monad (liftM, liftM2, unless, when)+import qualified Control.Monad.State as S+import Data.List (nub, partition)+import Data.Maybe (isNothing)++import Base.Expr+import Base.Messages (Message, spanInfoMessage, internalError)+import Base.TopEnv+import Base.Utils (findMultiples, findDouble)++import Env.TypeConstructor+import Env.Type++import Curry.Base.Ident+import Curry.Base.SpanInfo+import Curry.Base.Pretty+import Curry.Syntax++data ISCState = ISCState+ { typeEnv :: TypeEnv+ , errors :: [Message]+ }++type ISC = S.State ISCState++getTypeEnv :: ISC TypeEnv+getTypeEnv = S.gets typeEnv++-- |Report a syntax error+report :: Message -> ISC ()+report msg = S.modify $ \ s -> s { errors = msg : errors s }++intfSyntaxCheck :: Interface -> (Interface, [Message])+intfSyntaxCheck (Interface n is ds) = (Interface n is ds', reverse $ errors s')+ where (ds', s') = S.runState (mapM checkIDecl ds) (ISCState env [])+ env = foldr bindType (fmap toTypeKind initTCEnv) ds++-- The compiler requires information about the arity of each defined type+-- constructor as well as information whether the type constructor+-- denotes an algebraic data type, a renaming type, or a type synonym.+-- The latter must not occur in type expressions in interfaces.++bindType :: IDecl -> TypeEnv -> TypeEnv+bindType (IInfixDecl _ _ _ _) = id+bindType (HidingDataDecl _ tc _ _) = qualBindTopEnv tc (Data tc [])+bindType (IDataDecl _ tc _ _ cs _) =+ qualBindTopEnv tc (Data tc (map constrId cs))+bindType (INewtypeDecl _ tc _ _ nc _) =+ qualBindTopEnv tc (Data tc [nconstrId nc])+bindType (ITypeDecl _ tc _ _ _) = qualBindTopEnv tc (Alias tc)+bindType (IFunctionDecl _ _ _ _ _) = id+bindType (HidingClassDecl _ _ cls _ _) = qualBindTopEnv cls (Class cls [])+bindType (IClassDecl _ _ cls _ _ ms hs) =+ qualBindTopEnv cls (Class cls (filter (`notElem` hs) (map imethod ms)))+bindType (IInstanceDecl _ _ _ _ _ _) = id++-- The checks applied to the interface are similar to those performed+-- during syntax checking of type expressions.++checkIDecl :: IDecl -> ISC IDecl+checkIDecl (IInfixDecl p fix pr op) = return (IInfixDecl p fix pr op)+checkIDecl (HidingDataDecl p tc k tvs) = do+ checkTypeLhs tvs+ return (HidingDataDecl p tc k tvs)+checkIDecl (IDataDecl p tc k tvs cs hs) = do+ checkTypeLhs tvs+ checkHiddenType tc (cons ++ labels) hs+ cs' <- mapM (checkConstrDecl tvs) cs+ return $ IDataDecl p tc k tvs cs' hs+ where cons = map constrId cs+ labels = nub $ concatMap recordLabels cs+checkIDecl (INewtypeDecl p tc k tvs nc hs) = do+ checkTypeLhs tvs+ checkHiddenType tc (con : labels) hs+ nc' <- checkNewConstrDecl tvs nc+ return $ INewtypeDecl p tc k tvs nc' hs+ where con = nconstrId nc+ labels = nrecordLabels nc+checkIDecl (ITypeDecl p tc k tvs ty) = do+ checkTypeLhs tvs+ liftM (ITypeDecl p tc k tvs) (checkClosedType tvs ty)+checkIDecl (IFunctionDecl p f cm n qty) =+ liftM (IFunctionDecl p f cm n) (checkQualType qty)+checkIDecl (HidingClassDecl p cx qcls k clsvar) = do+ checkTypeVars "hiding class declaration" [clsvar]+ cx' <- checkClosedContext [clsvar] cx+ checkSimpleContext cx'+ return $ HidingClassDecl p cx' qcls k clsvar+checkIDecl (IClassDecl p cx qcls k clsvar ms hs) = do+ checkTypeVars "class declaration" [clsvar]+ cx' <- checkClosedContext [clsvar] cx+ checkSimpleContext cx'+ ms' <- mapM (checkIMethodDecl clsvar) ms+ checkHidden (errNoElement "method" "class") qcls (map imethod ms') hs+ return $ IClassDecl p cx' qcls k clsvar ms' hs+checkIDecl (IInstanceDecl p cx qcls inst is m) = do+ checkClass qcls+ QualTypeExpr _ cx' inst' <- checkQualType $ QualTypeExpr NoSpanInfo cx inst+ checkSimpleContext cx'+ checkInstanceType inst'+ mapM_ (report . errMultipleImplementation . head) $ findMultiples $ map fst is+ return $ IInstanceDecl p cx' qcls inst' is m++checkHiddenType :: QualIdent -> [Ident] -> [Ident] -> ISC ()+checkHiddenType = checkHidden $ errNoElement "constructor or label" "type"++checkHidden :: (QualIdent -> Ident -> Message) -> QualIdent -> [Ident]+ -> [Ident] -> ISC ()+checkHidden err tc csls hs =+ mapM_ (report . err tc) $ nub $ filter (`notElem` csls) hs++checkTypeLhs :: [Ident] -> ISC ()+checkTypeLhs = checkTypeVars "left hand side of type declaration"++checkTypeVars :: String -> [Ident] -> ISC ()+checkTypeVars what tvs = do+ tyEnv <- getTypeEnv+ let (tcs, tvs') = partition isTypeConstrOrClass tvs+ isTypeConstrOrClass tv = not (null (lookupTypeKind tv tyEnv))+ mapM_ (report . flip errNoVariable what) (nub tcs)+ mapM_ (report . flip errNonLinear what . head) (findMultiples tvs')++checkConstrDecl :: [Ident] -> ConstrDecl -> ISC ConstrDecl+checkConstrDecl tvs (ConstrDecl p c tys) = do+ liftM (ConstrDecl p c) (mapM (checkClosedType tvs) tys)+checkConstrDecl tvs (ConOpDecl p ty1 op ty2) = do+ liftM2 (\t1 t2 -> ConOpDecl p t1 op t2)+ (checkClosedType tvs ty1)+ (checkClosedType tvs ty2)+checkConstrDecl tvs (RecordDecl p c fs) = do+ liftM (RecordDecl p c) (mapM (checkFieldDecl tvs) fs)++checkFieldDecl :: [Ident] -> FieldDecl -> ISC FieldDecl+checkFieldDecl tvs (FieldDecl p ls ty) =+ liftM (FieldDecl p ls) (checkClosedType tvs ty)++checkNewConstrDecl :: [Ident] -> NewConstrDecl -> ISC NewConstrDecl+checkNewConstrDecl tvs (NewConstrDecl p c ty) =+ liftM (NewConstrDecl p c) (checkClosedType tvs ty)+checkNewConstrDecl tvs (NewRecordDecl p c (l, ty)) = do+ ty' <- checkClosedType tvs ty+ return $ NewRecordDecl p c (l, ty')++checkSimpleContext :: Context -> ISC ()+checkSimpleContext = mapM_ checkSimpleConstraint++checkSimpleConstraint :: Constraint -> ISC ()+checkSimpleConstraint c@(Constraint _ _ ty) =+ unless (isVariableType ty) $ report $ errIllegalSimpleConstraint c++checkIMethodDecl :: Ident -> IMethodDecl -> ISC IMethodDecl+checkIMethodDecl tv (IMethodDecl p f a qty) = do+ qty' <- checkQualType qty+ unless (tv `elem` fv qty') $ report $ errAmbiguousType f tv+ let QualTypeExpr _ cx _ = qty'+ when (tv `elem` fv cx) $ report $ errConstrainedClassVariable f tv+ return $ IMethodDecl p f a qty'++checkInstanceType :: InstanceType -> ISC ()+checkInstanceType inst = do+ tEnv <- getTypeEnv+ unless (isSimpleType inst &&+ not (isTypeSyn (typeConstr inst) tEnv) &&+ null (filter isAnonId $ typeVars inst) &&+ isNothing (findDouble $ fv inst)) $+ report $ errIllegalInstanceType inst inst++checkQualType :: QualTypeExpr -> ISC QualTypeExpr+checkQualType (QualTypeExpr spi cx ty) = do+ ty' <- checkType ty+ cx' <- checkClosedContext (fv ty') cx+ return $ QualTypeExpr spi cx' ty'++checkClosedContext :: [Ident] -> Context -> ISC Context+checkClosedContext tvs cx = do+ cx' <- checkContext cx+ mapM_ (\(Constraint _ _ ty) -> checkClosed tvs ty) cx'+ return cx'++checkContext :: Context -> ISC Context+checkContext = mapM checkConstraint++checkConstraint :: Constraint -> ISC Constraint+checkConstraint (Constraint spi qcls ty) = do+ checkClass qcls+ Constraint spi qcls `liftM` checkType ty++checkClass :: QualIdent -> ISC ()+checkClass qcls = do+ tEnv <- getTypeEnv+ case qualLookupTypeKind qcls tEnv of+ [] -> report $ errUndefinedClass qcls+ [Class _ _] -> return ()+ [_] -> report $ errUndefinedClass qcls+ _ -> internalError $ "Checks.InterfaceSyntaxCheck.checkClass: " +++ "ambiguous identifier " ++ show qcls++checkClosedType :: [Ident] -> TypeExpr -> ISC TypeExpr+checkClosedType tvs ty = do+ ty' <- checkType ty+ checkClosed tvs ty'+ return ty'++checkType :: TypeExpr -> ISC TypeExpr+checkType (ConstructorType spi tc) = checkTypeConstructor spi tc+checkType (ApplyType spi ty1 ty2) =+ liftM2 (ApplyType spi) (checkType ty1) (checkType ty2)+checkType (VariableType spi tv) =+ checkType $ ConstructorType spi (qualify tv)+checkType (TupleType spi tys) = liftM (TupleType spi) (mapM checkType tys)+checkType (ListType spi ty) = liftM (ListType spi) (checkType ty)+checkType (ArrowType spi ty1 ty2) =+ liftM2 (ArrowType spi) (checkType ty1) (checkType ty2)+checkType (ParenType spi ty) = liftM (ParenType spi) (checkType ty)+checkType (ForallType spi vs ty) = liftM (ForallType spi vs) (checkType ty)++checkClosed :: [Ident] -> TypeExpr -> ISC ()+checkClosed _ (ConstructorType _ _) = return ()+checkClosed tvs (ApplyType _ ty1 ty2) = mapM_ (checkClosed tvs) [ty1, ty2]+checkClosed tvs (VariableType _ tv) =+ when (isAnonId tv || tv `notElem` tvs) $ report $ errUnboundVariable tv+checkClosed tvs (TupleType _ tys) = mapM_ (checkClosed tvs) tys+checkClosed tvs (ListType _ ty) = checkClosed tvs ty+checkClosed tvs (ArrowType _ ty1 ty2) = mapM_ (checkClosed tvs) [ty1, ty2]+checkClosed tvs (ParenType _ ty) = checkClosed tvs ty+checkClosed tvs (ForallType _ vs ty) = checkClosed (tvs ++ vs) ty++checkTypeConstructor :: SpanInfo -> QualIdent -> ISC TypeExpr+checkTypeConstructor spi tc = do+ tyEnv <- getTypeEnv+ case qualLookupTypeKind tc tyEnv of+ [] | not (isQualified tc) -> return $ VariableType spi $ unqualify tc+ | otherwise -> do+ report $ errUndefinedType tc+ return $ ConstructorType spi tc+ [Data _ _] -> return $ ConstructorType spi tc+ [Alias _] -> do+ report $ errBadTypeSynonym tc+ return $ ConstructorType spi tc+ _ ->+ internalError "Checks.InterfaceSyntaxCheck.checkTypeConstructor"++-- ---------------------------------------------------------------------------+-- Auxiliary definitions+-- ---------------------------------------------------------------------------++typeVars :: TypeExpr -> [Ident]+typeVars (ConstructorType _ _) = []+typeVars (ApplyType _ ty1 ty2) = typeVars ty1 ++ typeVars ty2+typeVars (VariableType _ tv) = [tv]+typeVars (TupleType _ tys) = concatMap typeVars tys+typeVars (ListType _ ty) = typeVars ty+typeVars (ArrowType _ ty1 ty2) = typeVars ty1 ++ typeVars ty2+typeVars (ParenType _ ty) = typeVars ty+typeVars (ForallType _ vs ty) = vs ++ typeVars ty++isTypeSyn :: QualIdent -> TypeEnv -> Bool+isTypeSyn tc tEnv = case qualLookupTypeKind tc tEnv of+ [Alias _] -> True+ _ -> False++-- ---------------------------------------------------------------------------+-- Error messages+-- ---------------------------------------------------------------------------++errUndefined :: String -> QualIdent -> Message+errUndefined what qident = spanInfoMessage qident $ hsep $ map text+ ["Undefined", what, qualName qident]++errUndefinedClass :: QualIdent -> Message+errUndefinedClass = errUndefined "class"++errUndefinedType :: QualIdent -> Message+errUndefinedType = errUndefined "type"++errMultipleImplementation :: Ident -> Message+errMultipleImplementation f = spanInfoMessage f $ hsep $ map text+ ["Arity information for method", idName f, "occurs more than once"]++errAmbiguousType :: HasSpanInfo s => s -> Ident -> Message+errAmbiguousType p ident = spanInfoMessage p $ hsep $ map text+ [ "Method type does not mention class variable", idName ident ]++errConstrainedClassVariable :: HasSpanInfo s => s -> Ident -> Message+errConstrainedClassVariable p ident = spanInfoMessage p $ hsep $ map text+ [ "Method context must not constrain class variable", idName ident ]++errNonLinear :: Ident -> String -> Message+errNonLinear tv what = spanInfoMessage tv $ hsep $ map text+ [ "Type variable", escName tv, "occurs more than once in", what ]++errNoVariable :: Ident -> String -> Message+errNoVariable tv what = spanInfoMessage tv $ hsep $ map text+ [ "Type constructor or type class identifier", escName tv, "used in", what ]++errUnboundVariable :: Ident -> Message+errUnboundVariable tv = spanInfoMessage tv $+ text "Undefined type variable" <+> text (escName tv)++errBadTypeSynonym :: QualIdent -> Message+errBadTypeSynonym tc = spanInfoMessage tc $ text "Synonym type"+ <+> text (qualName tc) <+> text "in interface"++errNoElement :: String -> String -> QualIdent -> Ident -> Message+errNoElement what for tc x = spanInfoMessage x $ hsep $ map text+ [ "Hidden", what, escName x, "is not defined for", for, qualName tc ]++errIllegalSimpleConstraint :: Constraint -> Message+errIllegalSimpleConstraint c@(Constraint _ qcls _) = spanInfoMessage qcls $ vcat+ [ text "Illegal class constraint" <+> pPrint c+ , text "Constraints in class and instance declarations must be of"+ , text "the form C u, where C is a type class and u is a type variable."+ ]++errIllegalInstanceType :: HasSpanInfo s => s -> InstanceType -> Message+errIllegalInstanceType p inst = spanInfoMessage p $ vcat+ [ text "Illegal instance type" <+> pPrint inst+ , text "The instance type must be of the form (T u_1 ... u_n),"+ , text "where T is not a type synonym and u_1, ..., u_n are"+ , text "mutually distinct, non-anonymous type variables."+ ]
+ src/Checks/KindCheck.hs view
@@ -0,0 +1,762 @@+{- |+ Module : $Header$+ Description : Checks type kinds+ Copyright : (c) 2016 - 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ After the type syntax has been checked und nullary type constructors and+ type variables have been disambiguated, the compiler infers kinds for all+ type constructors and type classes defined in the current module and+ performs kind checking on all type definitions and type signatures.+-}+{-# LANGUAGE CPP #-}+module Checks.KindCheck (kindCheck) where++#if __GLASGOW_HASKELL__ >= 804+import Prelude hiding ((<>))+#endif++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative ((<$>), (<*>))+#endif+import Control.Monad (when, foldM)+import Control.Monad.Fix (mfix)+import qualified Control.Monad.State as S (State, runState, gets, modify)+import Data.List (partition, nub)++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Base.SpanInfo+import Curry.Base.Pretty+import Curry.Syntax+import Curry.Syntax.Pretty++import Base.CurryKinds+import Base.Expr+import Base.Kinds+import Base.KindSubst+import Base.Messages (Message, spanInfoMessage, internalError)+import Base.SCC+import Base.TopEnv+import Base.Types+import Base.TypeExpansion++import Env.Class+import Env.TypeConstructor++-- In order to infer kinds for type constructors and type classes, the+-- compiler sorts the module's type and class declarations into minimal+-- recursive binding groups and then applies kind inference to each+-- declaration group. Besides inferring kinds for the type constructors+-- and type classes of a group, the compiler also checks that there are+-- no mutually recursive type synonym definitions and that the super class+-- hierarchy is acyclic. The former allows entering fully expanded type+-- synonyms into the type constructor environment.++kindCheck :: TCEnv -> ClassEnv -> Module a -> ((TCEnv, ClassEnv), [Message])+kindCheck tcEnv clsEnv (Module _ _ _ m _ _ ds) = runKCM check initState+ where+ check = do+ checkNonRecursiveTypes tds &&> checkAcyclicSuperClasses cds+ errs <- S.gets errors+ if null errs+ then checkDecls+ else return (tcEnv, clsEnv)+ checkDecls = do+ (tcEnv', clsEnv') <- kcDecls tcEnv clsEnv tcds+ mapM_ (kcDecl tcEnv') ods+ return (tcEnv', clsEnv')+ tds = filter isTypeDecl tcds+ cds = filter isClassDecl tcds+ (tcds, ods) = partition isTypeOrClassDecl ds+ initState = KCState m idSubst 0 []++-- Kind Check Monad+type KCM = S.State KCState++-- |Internal state of the Kind Check+data KCState = KCState+ { moduleIdent :: ModuleIdent -- read only+ , kindSubst :: KindSubst+ , nextId :: Int -- automatic counter+ , errors :: [Message]+ }++(&&>) :: KCM () -> KCM () -> KCM ()+pre &&> suf = do+ errs <- pre >> S.gets errors+ when (null errs) suf++runKCM :: KCM a -> KCState -> (a, [Message])+runKCM kcm s = let (a, s') = S.runState kcm s in (a, reverse $ errors s')++getModuleIdent :: KCM ModuleIdent+getModuleIdent = S.gets moduleIdent++getKindSubst :: KCM KindSubst+getKindSubst = S.gets kindSubst++modifyKindSubst :: (KindSubst -> KindSubst) -> KCM ()+modifyKindSubst f = S.modify $ \s -> s { kindSubst = f $ kindSubst s }++getNextId :: KCM Int+getNextId = do+ nid <- S.gets nextId+ S.modify $ \s -> s { nextId = succ nid }+ return nid++report :: Message -> KCM ()+report err = S.modify (\s -> s { errors = err : errors s })++ok :: KCM ()+ok = return ()++-- Minimal recursive declaration groups are computed using the sets of bound+-- and free type constructor and type class identifiers of the declarations.++bt :: Decl a -> [Ident]+bt (DataDecl _ tc _ _ _) = [tc]+bt (ExternalDataDecl _ tc _) = [tc]+bt (NewtypeDecl _ tc _ _ _) = [tc]+bt (TypeDecl _ tc _ _) = [tc]+bt (ClassDecl _ _ _ cls _ _) = [cls]+bt _ = []++ft :: ModuleIdent -> Decl a -> [Ident]+ft m d = fts m d []++class HasType a where+ fts :: ModuleIdent -> a -> [Ident] -> [Ident]++instance HasType a => HasType [a] where+ fts m = flip $ foldr $ fts m++instance HasType a => HasType (Maybe a) where+ fts m = maybe id $ fts m++instance HasType (Decl a) where+ fts _ (InfixDecl _ _ _ _) = id+ fts m (DataDecl _ _ _ cs clss) = fts m cs . fts m clss+ fts _ (ExternalDataDecl _ _ _) = id+ fts m (NewtypeDecl _ _ _ nc clss) = fts m nc . fts m clss+ fts m (TypeDecl _ _ _ ty) = fts m ty+ fts m (TypeSig _ _ ty) = fts m ty+ fts m (FunctionDecl _ _ _ eqs) = fts m eqs+ fts _ (ExternalDecl _ _) = id+ fts m (PatternDecl _ _ rhs) = fts m rhs+ fts _ (FreeDecl _ _) = id+ fts m (DefaultDecl _ tys) = fts m tys+ fts m (ClassDecl _ _ cx _ _ ds) = fts m cx . fts m ds+ fts m (InstanceDecl _ _ cx cls inst ds) =+ fts m cx . fts m cls . fts m inst . fts m ds++instance HasType ConstrDecl where+ fts m (ConstrDecl _ _ tys) = fts m tys+ fts m (ConOpDecl _ ty1 _ ty2) = fts m ty1 . fts m ty2+ fts m (RecordDecl _ _ fs) = fts m fs++instance HasType FieldDecl where+ fts m (FieldDecl _ _ ty) = fts m ty++instance HasType NewConstrDecl where+ fts m (NewConstrDecl _ _ ty) = fts m ty+ fts m (NewRecordDecl _ _ (_, ty)) = fts m ty++instance HasType Constraint where+ fts m (Constraint _ qcls _) = fts m qcls++instance HasType QualTypeExpr where+ fts m (QualTypeExpr _ cx ty) = fts m cx . fts m ty++instance HasType TypeExpr where+ fts m (ConstructorType _ tc) = fts m tc+ fts m (ApplyType _ ty1 ty2) = fts m ty1 . fts m ty2+ fts _ (VariableType _ _) = id+ fts m (TupleType _ tys) = (tupleId (length tys) :) . fts m tys+ fts m (ListType _ ty) = (listId :) . fts m ty+ fts m (ArrowType _ ty1 ty2) = (arrowId :) . fts m ty1 . fts m ty2+ fts m (ParenType _ ty) = fts m ty+ fts m (ForallType _ _ ty) = fts m ty++instance HasType (Equation a) where+ fts m (Equation _ _ rhs) = fts m rhs++instance HasType (Rhs a) where+ fts m (SimpleRhs _ _ e ds) = fts m e . fts m ds+ fts m (GuardedRhs _ _ es ds) = fts m es . fts m ds++instance HasType (CondExpr a) where+ fts m (CondExpr _ g e) = fts m g . fts m e++instance HasType (Expression a) where+ fts _ (Literal _ _ _) = id+ fts _ (Variable _ _ _) = id+ fts _ (Constructor _ _ _) = id+ fts m (Paren _ e) = fts m e+ fts m (Typed _ e ty) = fts m e . fts m ty+ fts m (Record _ _ _ fs) = fts m fs+ fts m (RecordUpdate _ e fs) = fts m e . fts m fs+ fts m (Tuple _ es) = fts m es+ fts m (List _ _ es) = fts m es+ fts m (ListCompr _ e stms) = fts m e . fts m stms+ fts m (EnumFrom _ e) = fts m e+ fts m (EnumFromThen _ e1 e2) = fts m e1 . fts m e2+ fts m (EnumFromTo _ e1 e2) = fts m e1 . fts m e2+ fts m (EnumFromThenTo _ e1 e2 e3) = fts m e1 . fts m e2 . fts m e3+ fts m (UnaryMinus _ e) = fts m e+ fts m (Apply _ e1 e2) = fts m e1 . fts m e2+ fts m (InfixApply _ e1 _ e2) = fts m e1 . fts m e2+ fts m (LeftSection _ e _) = fts m e+ fts m (RightSection _ _ e) = fts m e+ fts m (Lambda _ _ e) = fts m e+ fts m (Let _ _ ds e) = fts m ds . fts m e+ fts m (Do _ _ stms e) = fts m stms . fts m e+ fts m (IfThenElse _ e1 e2 e3) = fts m e1 . fts m e2 . fts m e3+ fts m (Case _ _ _ e as) = fts m e . fts m as++instance HasType (Statement a) where+ fts m (StmtExpr _ e) = fts m e+ fts m (StmtDecl _ _ ds) = fts m ds+ fts m (StmtBind _ _ e) = fts m e++instance HasType (Alt a) where+ fts m (Alt _ _ rhs) = fts m rhs++instance HasType a => HasType (Field a) where+ fts m (Field _ _ x) = fts m x++instance HasType QualIdent where+ fts m qident = maybe id (:) (localIdent m qident)++-- When types are entered into the type constructor environment, all type+-- synonyms occuring in the definitions are fully expanded (except for+-- record types) and all type constructors and type classes are qualified+-- with the name of the module in which they are defined. This is possible+-- because Curry does not allow (mutually) recursive type synonyms or+-- newtypes, which is checked in the function 'checkNonRecursiveTypes' below.++ft' :: ModuleIdent -> Decl a -> [Ident]+ft' _ (DataDecl _ _ _ _ _) = []+ft' _ (ExternalDataDecl _ _ _) = []+ft' m (NewtypeDecl _ _ _ nc _) = fts m nc []+ft' m (TypeDecl _ _ _ ty) = fts m ty []+ft' _ _ = []++checkNonRecursiveTypes :: [Decl a] -> KCM ()+checkNonRecursiveTypes ds = do+ m <- getModuleIdent+ mapM_ checkTypeAndNewtypeDecls $ scc bt (ft' m) ds++checkTypeAndNewtypeDecls :: [Decl a] -> KCM ()+checkTypeAndNewtypeDecls [] =+ internalError "Checks.KindCheck.checkTypeAndNewtypeDecls: empty list"+checkTypeAndNewtypeDecls [DataDecl _ _ _ _ _] = ok+checkTypeAndNewtypeDecls [ExternalDataDecl _ _ _] = ok+checkTypeAndNewtypeDecls [d] | isTypeOrNewtypeDecl d = do+ m <- getModuleIdent+ let tc = typeConstructor d+ when (tc `elem` ft m d) $ report $ errRecursiveTypes [tc]+checkTypeAndNewtypeDecls (d:ds) | isTypeOrNewtypeDecl d =+ report $ errRecursiveTypes $+ typeConstructor d : [typeConstructor d' | d' <- ds, isTypeOrNewtypeDecl d']+checkTypeAndNewtypeDecls _ = internalError+ "Checks.KindCheck.checkTypeAndNewtypeDecls: no type or newtype declarations"++-- The function 'checkAcyclicSuperClasses' checks that the super class+-- hierarchy is acyclic.++fc :: ModuleIdent -> Context -> [Ident]+fc m = foldr fc' []+ where+ fc' (Constraint _ qcls _) = maybe id (:) (localIdent m qcls)++checkAcyclicSuperClasses :: [Decl a] -> KCM ()+checkAcyclicSuperClasses ds = do+ m <- getModuleIdent+ mapM_ checkClassDecl $ scc bt (\(ClassDecl _ _ cx _ _ _) -> fc m cx) ds++checkClassDecl :: [Decl a] -> KCM ()+checkClassDecl [] =+ internalError "Checks.KindCheck.checkClassDecl: empty list"+checkClassDecl [ClassDecl _ _ cx cls _ _] = do+ m <- getModuleIdent+ when (cls `elem` fc m cx) $ report $ errRecursiveClasses [cls]+checkClassDecl (ClassDecl _ _ _ cls _ _ : ds) =+ report $ errRecursiveClasses $ cls : [cls' | ClassDecl _ _ _ cls' _ _ <- ds]+checkClassDecl _ =+ internalError "Checks.KindCheck.checkClassDecl: no class declaration"++-- For each declaration group, the kind checker first enters new+-- assumptions into the type constructor environment. For a type+-- constructor with arity n, we enter kind k_1 -> ... -> k_n -> k,+-- where k_i are fresh kind variables and k is * for data and newtype+-- type constructors and a fresh kind variable for type synonym type+-- constructors. For a type class we enter kind k, where k is a fresh+-- kind variable. We also add a type class to the class environment.+-- Next, the kind checker checks the declarations of the group within+-- the extended environment, and finally the kind checker instantiates+-- all remaining free kind variables to *.++-- As noted above, type synonyms are fully expanded while types are+-- entered into the type constructor environment. Furthermore, we uses+-- original names for classes and super classes in the class environment.+-- Unfortunately, both of this requires either sorting type declarations+-- properly or using the final type constructor environment for the expansion+-- and original names. We have chosen the latter option here, which requires+-- recursive monadic bindings which are supported using the 'mfix' method+-- from the 'MonadFix' type class.++bindKind :: ModuleIdent -> TCEnv -> ClassEnv -> TCEnv -> Decl a -> KCM TCEnv+bindKind m tcEnv' clsEnv tcEnv (DataDecl _ tc tvs cs _) =+ bindTypeConstructor DataType tc tvs (Just KindStar) (map mkData cs) tcEnv+ where+ mkData (ConstrDecl _ c tys) = mkData' c tys+ mkData (ConOpDecl _ ty1 op ty2) = mkData' op [ty1, ty2]+ mkData (RecordDecl _ c fs) =+ let (labels, tys) = unzip [(l, ty) | FieldDecl _ ls ty <- fs, l <- ls]+ in mkRec c labels tys+ mkData' c tys = DataConstr c tys'+ where qtc = qualifyWith m tc+ PredType _ ty = expandConstrType m tcEnv' clsEnv qtc tvs tys+ tys' = arrowArgs ty+ mkRec c ls tys =+ RecordConstr c ls tys'+ where qtc = qualifyWith m tc+ PredType _ ty = expandConstrType m tcEnv' clsEnv qtc tvs tys+ tys' = arrowArgs ty+bindKind _ _ _ tcEnv (ExternalDataDecl _ tc tvs) =+ bindTypeConstructor DataType tc tvs (Just KindStar) [] tcEnv+bindKind m tcEnv' _ tcEnv (NewtypeDecl _ tc tvs nc _) =+ bindTypeConstructor RenamingType tc tvs (Just KindStar) (mkData nc) tcEnv+ where+ mkData (NewConstrDecl _ c ty) = DataConstr c [ty']+ where ty' = expandMonoType m tcEnv' tvs ty+ mkData (NewRecordDecl _ c (l, ty)) = RecordConstr c [l] [ty']+ where ty' = expandMonoType m tcEnv' tvs ty+bindKind m tcEnv' _ tcEnv (TypeDecl _ tc tvs ty) =+ bindTypeConstructor aliasType tc tvs Nothing ty' tcEnv+ where+ aliasType tc' k = AliasType tc' k $ length tvs+ ty' = expandMonoType m tcEnv' tvs ty+bindKind m tcEnv' clsEnv tcEnv (ClassDecl _ _ _ cls tv ds) =+ bindTypeClass cls (concatMap mkMethods ds) tcEnv+ where+ mkMethods (TypeSig _ fs qty) = map (mkMethod qty) fs+ mkMethods _ = []+ mkMethod qty f = ClassMethod f (findArity f ds) $+ expandMethodType m tcEnv' clsEnv (qualify cls) tv qty+ findArity _ [] = Nothing+ findArity f (FunctionDecl _ _ f' eqs:_) | f == f' =+ Just $ eqnArity $ head eqs+ findArity f (_:ds') = findArity f ds'+bindKind _ _ _ tcEnv _ = return tcEnv++bindTypeConstructor :: (QualIdent -> Kind -> a -> TypeInfo) -> Ident+ -> [Ident] -> Maybe Kind -> a -> TCEnv -> KCM TCEnv+bindTypeConstructor f tc tvs k x tcEnv = do+ m <- getModuleIdent+ k' <- maybe freshKindVar return k+ ks <- mapM (const freshKindVar) tvs+ let qtc = qualifyWith m tc+ ti = f qtc (foldr KindArrow k' ks) x+ return $ bindTypeInfo m tc ti tcEnv++bindTypeClass :: Ident -> [ClassMethod] -> TCEnv -> KCM TCEnv+bindTypeClass cls ms tcEnv = do+ m <- getModuleIdent+ k <- freshKindVar+ let qcls = qualifyWith m cls+ ti = TypeClass qcls k ms+ return $ bindTypeInfo m cls ti tcEnv++bindFreshKind :: TCEnv -> Ident -> KCM TCEnv+bindFreshKind tcEnv tv = do+ k <- freshKindVar+ return $ bindTypeVar tv k tcEnv++bindTypeVars :: Ident -> [Ident] -> TCEnv -> KCM (Kind, TCEnv)+bindTypeVars tc tvs tcEnv = do+ m <- getModuleIdent+ return $ foldl (\(KindArrow k1 k2, tcEnv') tv ->+ (k2, bindTypeVar tv k1 tcEnv'))+ (tcKind m (qualifyWith m tc) tcEnv, tcEnv)+ tvs++bindTypeVar :: Ident -> Kind -> TCEnv -> TCEnv+bindTypeVar ident k = bindTopEnv ident (TypeVar k)++bindClass :: ModuleIdent -> TCEnv -> ClassEnv -> Decl a -> ClassEnv+bindClass m tcEnv clsEnv (ClassDecl _ _ cx cls _ ds) =+ bindClassInfo qcls (sclss, ms) clsEnv+ where qcls = qualifyWith m cls+ ms = map (\f -> (f, f `elem` fs)) $ concatMap methods ds+ fs = concatMap impls ds+ sclss = nub $ map (\(Constraint _ cls' _) -> getOrigName m cls' tcEnv) cx+bindClass _ _ clsEnv _ = clsEnv++instantiateWithDefaultKind :: TypeInfo -> TypeInfo+instantiateWithDefaultKind (DataType tc k cs) =+ DataType tc (defaultKind k) cs+instantiateWithDefaultKind (RenamingType tc k nc) =+ RenamingType tc (defaultKind k) nc+instantiateWithDefaultKind (AliasType tc k n ty) =+ AliasType tc (defaultKind k) n ty+instantiateWithDefaultKind (TypeClass cls k ms) =+ TypeClass cls (defaultKind k) ms+instantiateWithDefaultKind (TypeVar _) =+ internalError "Checks.KindCheck.instantiateWithDefaultKind: type variable"++kcDecls :: TCEnv -> ClassEnv -> [Decl a] -> KCM (TCEnv, ClassEnv)+kcDecls tcEnv clsEnv ds = do+ m <- getModuleIdent+ foldM (uncurry kcDeclGroup) (tcEnv, clsEnv) $ scc bt (ft m) ds++kcDeclGroup :: TCEnv -> ClassEnv -> [Decl a] -> KCM (TCEnv, ClassEnv)+kcDeclGroup tcEnv clsEnv ds = do+ m <- getModuleIdent+ (tcEnv', clsEnv') <- mfix (\ ~(tcEnv', clsEnv') ->+ flip (,) (foldl (bindClass m tcEnv') clsEnv ds) <$>+ foldM (bindKind m tcEnv' clsEnv') tcEnv ds)+ mapM_ (kcDecl tcEnv') ds+ theta <- getKindSubst+ return (fmap (instantiateWithDefaultKind . subst theta) tcEnv', clsEnv')++-- After adding new assumptions to the environment, kind inference is+-- applied to all declarations. The type environment may be extended+-- temporarily with bindings for type variables occurring in the left+-- hand side of type declarations and free type variables of type+-- signatures. While the kinds of the former are determined already by+-- the kinds of their type constructors and type classes, respectively,+-- fresh kind variables are added for the latter.++kcDecl :: TCEnv -> Decl a -> KCM ()+kcDecl _ (InfixDecl _ _ _ _) = ok+kcDecl tcEnv (DataDecl _ tc tvs cs _) = do+ (_, tcEnv') <- bindTypeVars tc tvs tcEnv+ mapM_ (kcConstrDecl tcEnv') cs+kcDecl _ (ExternalDataDecl _ _ _) = ok+kcDecl tcEnv (NewtypeDecl _ tc tvs nc _) = do+ (_, tcEnv') <- bindTypeVars tc tvs tcEnv+ kcNewConstrDecl tcEnv' nc+kcDecl tcEnv t@(TypeDecl _ tc tvs ty) = do+ (k, tcEnv') <- bindTypeVars tc tvs tcEnv+ kcType tcEnv' "type declaration" (pPrint t) k ty+kcDecl tcEnv (TypeSig _ _ qty) = kcTypeSig tcEnv qty+kcDecl tcEnv (FunctionDecl _ _ _ eqs) = mapM_ (kcEquation tcEnv) eqs+kcDecl _ (ExternalDecl _ _) = ok+kcDecl tcEnv (PatternDecl _ _ rhs) = kcRhs tcEnv rhs+kcDecl _ (FreeDecl _ _) = ok+kcDecl tcEnv (DefaultDecl _ tys) = do+ tcEnv' <- foldM bindFreshKind tcEnv $ nub $ fv tys+ mapM_ (kcValueType tcEnv' "default declaration" empty) tys+kcDecl tcEnv (ClassDecl _ _ cx cls tv ds) = do+ m <- getModuleIdent+ let tcEnv' = bindTypeVar tv (clsKind m (qualifyWith m cls) tcEnv) tcEnv+ kcContext tcEnv' cx+ mapM_ (kcDecl tcEnv') ds+kcDecl tcEnv (InstanceDecl p _ cx qcls inst ds) = do+ m <- getModuleIdent+ tcEnv' <- foldM bindFreshKind tcEnv $ fv inst+ kcContext tcEnv' cx+ kcType tcEnv' what doc (clsKind m qcls tcEnv) inst+ mapM_ (kcDecl tcEnv') ds+ where+ what = "instance declaration"+ doc = pPrint (InstanceDecl p WhitespaceLayout cx qcls inst [])++kcConstrDecl :: TCEnv -> ConstrDecl -> KCM ()+kcConstrDecl tcEnv d@(ConstrDecl _ _ tys) = do+ mapM_ (kcValueType tcEnv what doc) tys+ where+ what = "data constructor declaration"+ doc = pPrint d+kcConstrDecl tcEnv d@(ConOpDecl _ ty1 _ ty2) = do+ kcValueType tcEnv what doc ty1+ kcValueType tcEnv what doc ty2+ where+ what = "data constructor declaration"+ doc = pPrint d+kcConstrDecl tcEnv (RecordDecl _ _ fs) = do+ mapM_ (kcFieldDecl tcEnv) fs++kcFieldDecl :: TCEnv -> FieldDecl -> KCM ()+kcFieldDecl tcEnv d@(FieldDecl _ _ ty) =+ kcValueType tcEnv "field declaration" (pPrint d) ty++kcNewConstrDecl :: TCEnv -> NewConstrDecl -> KCM ()+kcNewConstrDecl tcEnv d@(NewConstrDecl _ _ ty) =+ kcValueType tcEnv "newtype constructor declaration" (pPrint d) ty+kcNewConstrDecl tcEnv (NewRecordDecl p _ (l, ty)) =+ kcFieldDecl tcEnv (FieldDecl p [l] ty)++kcEquation :: TCEnv -> Equation a -> KCM ()+kcEquation tcEnv (Equation _ _ rhs) = kcRhs tcEnv rhs++kcRhs :: TCEnv -> Rhs a -> KCM ()+kcRhs tcEnv (SimpleRhs _ _ e ds) = do+ kcExpr tcEnv e+ mapM_ (kcDecl tcEnv) ds+kcRhs tcEnv (GuardedRhs _ _ es ds) = do+ mapM_ (kcCondExpr tcEnv) es+ mapM_ (kcDecl tcEnv) ds++kcCondExpr :: TCEnv -> CondExpr a -> KCM ()+kcCondExpr tcEnv (CondExpr _ g e) = kcExpr tcEnv g >> kcExpr tcEnv e++kcExpr :: TCEnv -> Expression a -> KCM ()+kcExpr _ (Literal _ _ _) = ok+kcExpr _ (Variable _ _ _) = ok+kcExpr _ (Constructor _ _ _) = ok+kcExpr tcEnv (Paren _ e) = kcExpr tcEnv e+kcExpr tcEnv (Typed _ e qty) = do+ kcExpr tcEnv e+ kcTypeSig tcEnv qty+kcExpr tcEnv (Record _ _ _ fs) = mapM_ (kcField tcEnv) fs+kcExpr tcEnv (RecordUpdate _ e fs) = do+ kcExpr tcEnv e+ mapM_ (kcField tcEnv) fs+kcExpr tcEnv (Tuple _ es) = mapM_ (kcExpr tcEnv) es+kcExpr tcEnv (List _ _ es) = mapM_ (kcExpr tcEnv) es+kcExpr tcEnv (ListCompr _ e stms) = do+ kcExpr tcEnv e+ mapM_ (kcStmt tcEnv) stms+kcExpr tcEnv (EnumFrom _ e) = kcExpr tcEnv e+kcExpr tcEnv (EnumFromThen _ e1 e2) = do+ kcExpr tcEnv e1+ kcExpr tcEnv e2+kcExpr tcEnv (EnumFromTo _ e1 e2) = do+ kcExpr tcEnv e1+ kcExpr tcEnv e2+kcExpr tcEnv (EnumFromThenTo _ e1 e2 e3) = do+ kcExpr tcEnv e1+ kcExpr tcEnv e2+ kcExpr tcEnv e3+kcExpr tcEnv (UnaryMinus _ e) = kcExpr tcEnv e+kcExpr tcEnv (Apply _ e1 e2) = do+ kcExpr tcEnv e1+ kcExpr tcEnv e2+kcExpr tcEnv (InfixApply _ e1 _ e2) = do+ kcExpr tcEnv e1+ kcExpr tcEnv e2+kcExpr tcEnv (LeftSection _ e _) = kcExpr tcEnv e+kcExpr tcEnv (RightSection _ _ e) = kcExpr tcEnv e+kcExpr tcEnv (Lambda _ _ e) = kcExpr tcEnv e+kcExpr tcEnv (Let _ _ ds e) = do+ mapM_ (kcDecl tcEnv) ds+ kcExpr tcEnv e+kcExpr tcEnv (Do _ _ stms e) = do+ mapM_ (kcStmt tcEnv) stms+ kcExpr tcEnv e+kcExpr tcEnv (IfThenElse _ e1 e2 e3) = do+ kcExpr tcEnv e1+ kcExpr tcEnv e2+ kcExpr tcEnv e3+kcExpr tcEnv (Case _ _ _ e alts) = do+ kcExpr tcEnv e+ mapM_ (kcAlt tcEnv) alts++kcStmt :: TCEnv -> Statement a -> KCM ()+kcStmt tcEnv (StmtExpr _ e) = kcExpr tcEnv e+kcStmt tcEnv (StmtDecl _ _ ds) = mapM_ (kcDecl tcEnv) ds+kcStmt tcEnv (StmtBind _ _ e) = kcExpr tcEnv e++kcAlt :: TCEnv -> Alt a -> KCM ()+kcAlt tcEnv (Alt _ _ rhs) = kcRhs tcEnv rhs++kcField :: TCEnv -> Field (Expression a) -> KCM ()+kcField tcEnv (Field _ _ e) = kcExpr tcEnv e++kcContext :: TCEnv -> Context -> KCM ()+kcContext tcEnv = mapM_ (kcConstraint tcEnv)++kcConstraint :: TCEnv -> Constraint -> KCM ()+kcConstraint tcEnv sc@(Constraint _ qcls ty) = do+ m <- getModuleIdent+ kcType tcEnv "class constraint" doc (clsKind m qcls tcEnv) ty+ where+ doc = pPrint sc++kcTypeSig :: TCEnv -> QualTypeExpr -> KCM ()+kcTypeSig tcEnv (QualTypeExpr _ cx ty) = do+ tcEnv' <- foldM bindFreshKind tcEnv free+ kcContext tcEnv' cx+ kcValueType tcEnv' "type signature" doc ty+ where+ free = filter (null . flip lookupTypeInfo tcEnv) $ nub $ fv ty+ doc = pPrintPrec 0 ty++kcValueType :: TCEnv -> String -> Doc -> TypeExpr -> KCM ()+kcValueType tcEnv what doc = kcType tcEnv what doc KindStar++kcType :: TCEnv -> String -> Doc -> Kind -> TypeExpr -> KCM ()+kcType tcEnv what doc k ty = do+ k' <- kcTypeExpr tcEnv "type expression" doc' 0 ty+ unify ty what (doc $-$ text "Type:" <+> doc') k k'+ where+ doc' = pPrintPrec 0 ty++kcTypeExpr :: TCEnv -> String -> Doc -> Int -> TypeExpr -> KCM Kind+kcTypeExpr tcEnv _ _ n (ConstructorType p tc) = do+ m <- getModuleIdent+ case qualLookupTypeInfo tc tcEnv of+ [AliasType _ _ n' _] -> case n >= n' of+ True -> return $ tcKind m tc tcEnv+ False -> do+ report $ errPartialAlias p tc n' n+ freshKindVar+ _ -> return $ tcKind m tc tcEnv+kcTypeExpr tcEnv what doc n (ApplyType p ty1 ty2) = do+ (alpha, beta) <- kcTypeExpr tcEnv what doc (n + 1) ty1 >>=+ kcArrow p what (doc $-$ text "Type:" <+> pPrintPrec 0 ty1)+ kcTypeExpr tcEnv what doc 0 ty2 >>=+ unify p what (doc $-$ text "Type:" <+> pPrintPrec 0 ty2) alpha+ return beta+kcTypeExpr tcEnv _ _ _ (VariableType _ tv) = return (varKind tv tcEnv)+kcTypeExpr tcEnv what doc _ (TupleType _ tys) = do+ mapM_ (kcValueType tcEnv what doc) tys+ return KindStar+kcTypeExpr tcEnv what doc _ (ListType _ ty) = do+ kcValueType tcEnv what doc ty+ return KindStar+kcTypeExpr tcEnv what doc _ (ArrowType _ ty1 ty2) = do+ kcValueType tcEnv what doc ty1+ kcValueType tcEnv what doc ty2+ return KindStar+kcTypeExpr tcEnv what doc n (ParenType _ ty) = kcTypeExpr tcEnv what doc n ty+kcTypeExpr tcEnv what doc n (ForallType _ vs ty) = do+ tcEnv' <- foldM bindFreshKind tcEnv vs+ kcTypeExpr tcEnv' what doc n ty++kcArrow :: HasSpanInfo p => p -> String -> Doc -> Kind -> KCM (Kind, Kind)+kcArrow p what doc k = do+ theta <- getKindSubst+ case subst theta k of+ KindStar -> do+ report $ errNonArrowKind p what doc KindStar+ (,) <$> freshKindVar <*> freshKindVar+ KindVariable kv -> do+ alpha <- freshKindVar+ beta <- freshKindVar+ modifyKindSubst $ bindVar kv $ KindArrow alpha beta+ return (alpha, beta)+ KindArrow k1 k2 -> return (k1, k2)++-- ---------------------------------------------------------------------------+-- Unification+-- ---------------------------------------------------------------------------++-- The unification uses Robinson's algorithm.+unify :: HasSpanInfo p => p -> String -> Doc -> Kind -> Kind -> KCM ()+unify p what doc k1 k2 = do+ theta <- getKindSubst+ let k1' = subst theta k1+ let k2' = subst theta k2+ case unifyKinds k1' k2' of+ Nothing -> report $ errKindMismatch p what doc k1' k2'+ Just sigma -> modifyKindSubst (compose sigma)++unifyKinds :: Kind -> Kind -> Maybe KindSubst+unifyKinds KindStar KindStar = Just idSubst+unifyKinds (KindVariable kv1) (KindVariable kv2)+ | kv1 == kv2 = Just idSubst+ | otherwise = Just (singleSubst kv1 (KindVariable kv2))+unifyKinds (KindVariable kv) k+ | kv `elem` kindVars k = Nothing+ | otherwise = Just (singleSubst kv k)+unifyKinds k (KindVariable kv)+ | kv `elem` kindVars k = Nothing+ | otherwise = Just (singleSubst kv k)+unifyKinds (KindArrow k11 k12) (KindArrow k21 k22) = do+ theta <- unifyKinds k11 k21+ theta' <- unifyKinds (subst theta k12) (subst theta k22)+ Just (compose theta' theta)+unifyKinds _ _ = Nothing++-- ---------------------------------------------------------------------------+-- Fresh variables+-- ---------------------------------------------------------------------------++fresh :: (Int -> a) -> KCM a+fresh f = f <$> getNextId++freshKindVar :: KCM Kind+freshKindVar = fresh KindVariable++-- ---------------------------------------------------------------------------+-- Auxiliary definitions+-- ---------------------------------------------------------------------------++typeConstructor :: Decl a -> Ident+typeConstructor (DataDecl _ tc _ _ _) = tc+typeConstructor (ExternalDataDecl _ tc _) = tc+typeConstructor (NewtypeDecl _ tc _ _ _) = tc+typeConstructor (TypeDecl _ tc _ _ ) = tc+typeConstructor _ =+ internalError "Checks.KindCheck.typeConstructor: no type declaration"++isTypeOrNewtypeDecl :: Decl a -> Bool+isTypeOrNewtypeDecl (NewtypeDecl _ _ _ _ _) = True+isTypeOrNewtypeDecl (TypeDecl _ _ _ _) = True+isTypeOrNewtypeDecl _ = False++-- ---------------------------------------------------------------------------+-- Error messages+-- ---------------------------------------------------------------------------++errRecursiveTypes :: [Ident] -> Message+errRecursiveTypes [] = internalError+ "KindCheck.errRecursiveTypes: empty list"+errRecursiveTypes [tc] = spanInfoMessage tc $ hsep $ map text+ ["Recursive synonym or renaming type", idName tc]+errRecursiveTypes (tc:tcs) = spanInfoMessage tc $+ text "Mutually recursive synonym and/or renaming types" <+>+ text (idName tc) <> types empty tcs+ where+ types _ [] = empty+ types del [tc'] = del <> space <> text "and" <+> typePos tc'+ types _ (tc':tcs') = comma <+> typePos tc' <> types comma tcs'+ typePos tc' =+ text (idName tc') <+> parens (text $ showLine $ getPosition tc')++errRecursiveClasses :: [Ident] -> Message+errRecursiveClasses [] = internalError+ "KindCheck.errRecursiveClasses: empty list"+errRecursiveClasses [cls] = spanInfoMessage cls $ hsep $ map text+ ["Recursive type class", idName cls]+errRecursiveClasses (cls:clss) = spanInfoMessage cls $+ text "Mutually recursive type classes" <+> text (idName cls) <>+ classes empty clss+ where+ classes _ [] = empty+ classes del [cls'] = del <> space <> text "and" <+> classPos cls'+ classes _ (cls':clss') = comma <+> classPos cls' <> classes comma clss'+ classPos cls' =+ text (idName cls') <+> parens (text $ showLine $ getPosition cls')++errNonArrowKind :: HasSpanInfo p => p -> String -> Doc -> Kind -> Message+errNonArrowKind p what doc k = spanInfoMessage p $ vcat+ [ text "Kind error in" <+> text what, doc+ , text "Kind:" <+> ppKind k+ , text "Cannot be applied"+ ]++errPartialAlias :: HasSpanInfo p => p -> QualIdent -> Int -> Int -> Message+errPartialAlias p tc arity argc = spanInfoMessage p $ hsep+ [ text "Type synonym", ppQIdent tc+ , text "requires at least"+ , int arity, text (plural arity "argument") <> comma+ , text "but is applied to only", int argc+ ]+ where+ plural n x = if n == 1 then x else x ++ "s"++errKindMismatch :: HasSpanInfo p => p -> String -> Doc -> Kind -> Kind -> Message+errKindMismatch p what doc k1 k2 = spanInfoMessage p $ vcat+ [ text "Kind error in" <+> text what, doc+ , text "Inferred kind:" <+> ppKind k2+ , text "Expected kind:" <+> ppKind k1+ ]
+ src/Checks/PrecCheck.hs view
@@ -0,0 +1,515 @@+{- |+ Module : $Header$+ Description : Checks precedences of infix operators+ Copyright : (c) 2001 - 2004 Wolfgang Lux+ Martin Engelke+ Björn Peemöller+ 2015 Jan Tikovsky+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ The parser does not know the relative precedences of infix operators+ and therefore parses them as if they all associate to the right and+ have the same precedence. After performing the definition checks,+ the compiler is going to process the infix applications in the module+ and rearrange infix applications according to the relative precedences+ of the operators involved.+-}+{-# LANGUAGE CPP #-}+module Checks.PrecCheck (precCheck) where++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative ((<$>), (<*>))+#endif+import Control.Monad (unless, when)+import qualified Control.Monad.State as S (State, runState, gets, modify)+import Data.List (partition)++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Base.SpanInfo+import Curry.Base.Span+import Curry.Base.Pretty+import Curry.Syntax++import Base.Expr+import Base.Messages (Message, spanInfoMessage, internalError)+import Base.Utils (findMultiples)++import Env.OpPrec (OpPrecEnv, OpPrec (..), PrecInfo (..), defaultP, bindP+ , mkPrec, qualLookupP)++precCheck :: ModuleIdent -> OpPrecEnv -> [Decl a] -> ([Decl a], OpPrecEnv, [Message])+precCheck m pEnv decls = runPCM (checkDecls decls) initState+ where initState = PCState m pEnv []++data PCState = PCState+ { moduleIdent :: ModuleIdent+ , precEnv :: OpPrecEnv+ , errors :: [Message]+ }++type PCM = S.State PCState -- the Prec Check Monad++runPCM :: PCM a -> PCState -> (a, OpPrecEnv, [Message])+runPCM kcm s = let (a, s') = S.runState kcm s+ in (a, precEnv s', reverse $ errors s')++getModuleIdent :: PCM ModuleIdent+getModuleIdent = S.gets moduleIdent++getPrecEnv :: PCM OpPrecEnv+getPrecEnv = S.gets precEnv++modifyPrecEnv :: (OpPrecEnv -> OpPrecEnv) -> PCM ()+modifyPrecEnv f = S.modify $ \ s -> s { precEnv = f $ precEnv s }++withLocalPrecEnv :: PCM a -> PCM a+withLocalPrecEnv act = do+ oldEnv <- getPrecEnv+ res <- act+ modifyPrecEnv $ const oldEnv+ return res++report :: Message -> PCM ()+report err = S.modify (\ s -> s { errors = err : errors s })++-- For each declaration group, including the module-level, the compiler+-- first checks that its fixity declarations contain no duplicates and+-- that there is a corresponding value or constructor declaration in that+-- group. The fixity declarations are then used for extending the+-- imported precedence environment.++bindPrecs :: [Decl a] -> PCM ()+bindPrecs ds0 = case findMultiples opFixDecls of+ [] -> case filter (`notElem` bvs) opFixDecls of+ [] -> do+ m <- getModuleIdent+ modifyPrecEnv $ \env -> foldr (bindPrec m) env fixDs+ ops -> mapM_ (report . errUndefinedOperator) ops+ opss -> mapM_ (report . errMultiplePrecedence) opss+ where+ (fixDs, nonFixDs) = partition isInfixDecl ds0+ innerDs = [ d | ClassDecl _ _ _ _ _ ds <- ds0, d <- ds ]+ opFixDecls = [ op | InfixDecl _ _ _ ops <- fixDs, op <- ops ]+ -- Unrenaming is necessary for inner class declarations, because operators+ -- within class declarations have been renamed during syntax checking.+ bvs = concatMap boundValues nonFixDs +++ map unRenameIdent (concatMap boundValues innerDs)++bindPrec :: ModuleIdent -> Decl a -> OpPrecEnv -> OpPrecEnv+bindPrec m (InfixDecl _ fix mprec ops) pEnv+ | p == defaultP = pEnv+ | otherwise = foldr (flip (bindP m) p) pEnv ops+ where p = OpPrec fix (mkPrec mprec)+bindPrec _ _ pEnv = pEnv++boundValues :: Decl a -> [Ident]+boundValues (DataDecl _ _ _ cs _) = [ v | c <- cs+ , v <- constrId c : recordLabels c]+boundValues (NewtypeDecl _ _ _ nc _) = nconstrId nc : nrecordLabels nc+boundValues (TypeSig _ fs _) = fs+boundValues (FunctionDecl _ _ f _) = [f]+boundValues (ExternalDecl _ vs) = bv vs+boundValues (PatternDecl _ t _) = bv t+boundValues (FreeDecl _ vs) = bv vs+boundValues _ = []++-- With the help of the precedence environment, the compiler checks all+-- infix applications and sections in the program. This pass will modify+-- the parse tree such that for a nested infix application the operator+-- with the lowest precedence becomes the root and that two adjacent+-- operators with the same precedence will not have conflicting+-- associativities. Note that the top-level precedence environment has to+-- be returned because it is needed for constructing the module's+-- interface.++checkDecls :: [Decl a] -> PCM [Decl a]+checkDecls decls = bindPrecs decls >> mapM checkDecl decls++checkDecl :: Decl a -> PCM (Decl a)+checkDecl (FunctionDecl p a f eqs) =+ FunctionDecl p a f <$> mapM checkEquation eqs+checkDecl (PatternDecl p t rhs) =+ PatternDecl p <$> checkPattern t <*> checkRhs rhs+checkDecl (ClassDecl p li cx cls tv ds) =+ ClassDecl p li cx cls tv <$> mapM checkDecl ds+checkDecl (InstanceDecl p li cx qcls inst ds) =+ InstanceDecl p li cx qcls inst <$> mapM checkDecl ds+checkDecl d = return d++checkEquation :: Equation a -> PCM (Equation a)+checkEquation (Equation p lhs rhs) =+ Equation p <$> checkLhs lhs <*> checkRhs rhs++checkLhs :: Lhs a -> PCM (Lhs a)+checkLhs (FunLhs spi f ts) = FunLhs spi f <$> mapM checkPattern ts+checkLhs (OpLhs spi t1 op t2) =+ flip (OpLhs spi) op <$> (checkPattern t1 >>= checkOpL op)+ <*> (checkPattern t2 >>= checkOpR op)+checkLhs (ApLhs spi lhs ts) =+ ApLhs spi <$> checkLhs lhs <*> mapM checkPattern ts++checkPattern :: Pattern a -> PCM (Pattern a)+checkPattern l@(LiteralPattern _ _ _) = return l+checkPattern n@(NegativePattern _ _ _) = return n+checkPattern v@(VariablePattern _ _ _) = return v+checkPattern (ConstructorPattern spi a c ts) =+ ConstructorPattern spi a c <$> mapM checkPattern ts+checkPattern (InfixPattern _ a t1 op t2) = do+ t1' <- checkPattern t1+ t2' <- checkPattern t2+ fixPrecT mkInfixPattern t1' op t2'+ where mkInfixPattern t1'' op'' t2'' =+ InfixPattern (t1'' @+@ t2'') a t1'' op'' t2''+checkPattern (ParenPattern spi t) =+ ParenPattern spi <$> checkPattern t+checkPattern (TuplePattern spi ts) =+ TuplePattern spi <$> mapM checkPattern ts+checkPattern (ListPattern spi a ts) =+ ListPattern spi a <$> mapM checkPattern ts+checkPattern (AsPattern spi v t) =+ AsPattern spi v <$> checkPattern t+checkPattern (LazyPattern spi t) =+ LazyPattern spi <$> checkPattern t+checkPattern (FunctionPattern spi a f ts) =+ FunctionPattern spi a f <$> mapM checkPattern ts+checkPattern (InfixFuncPattern _ a t1 op t2) = do+ t1' <- checkPattern t1+ t2' <- checkPattern t2+ fixPrecT mkInfixFuncPattern t1' op t2'+ where mkInfixFuncPattern t1'' op'' t2'' =+ InfixFuncPattern (t1'' @+@ t2'') a t1'' op'' t2''+checkPattern (RecordPattern spi a c fs) =+ RecordPattern spi a c <$> mapM (checkField checkPattern) fs++checkRhs :: Rhs a -> PCM (Rhs a)+checkRhs (SimpleRhs spi li e ds) = withLocalPrecEnv $+ flip (SimpleRhs spi li) <$> checkDecls ds <*> checkExpr e+checkRhs (GuardedRhs spi li es ds) = withLocalPrecEnv $+ flip (GuardedRhs spi li) <$> checkDecls ds <*> mapM checkCondExpr es++checkCondExpr :: CondExpr a -> PCM (CondExpr a)+checkCondExpr (CondExpr p g e) = CondExpr p <$> checkExpr g <*> checkExpr e++checkExpr :: Expression a -> PCM (Expression a)+checkExpr l@(Literal _ _ _) = return l+checkExpr v@(Variable _ _ _) = return v+checkExpr c@(Constructor _ _ _) = return c+checkExpr (Paren spi e) = Paren spi <$> checkExpr e+checkExpr (Typed spi e ty) = flip (Typed spi) ty <$> checkExpr e+checkExpr (Record spi a c fs) = Record spi a c <$> mapM (checkField checkExpr) fs+checkExpr (RecordUpdate spi e fs) = RecordUpdate spi <$> checkExpr e+ <*> mapM (checkField checkExpr) fs+checkExpr (Tuple spi es) = Tuple spi <$> mapM checkExpr es+checkExpr (List spi a es) = List spi a <$> mapM checkExpr es+checkExpr (ListCompr spi e qs) = withLocalPrecEnv $+ flip (ListCompr spi) <$> mapM checkStmt qs <*> checkExpr e+checkExpr (EnumFrom spi e) = EnumFrom spi <$> checkExpr e+checkExpr (EnumFromThen spi e1 e2) =+ EnumFromThen spi <$> checkExpr e1 <*> checkExpr e2+checkExpr (EnumFromTo spi e1 e2) =+ EnumFromTo spi <$> checkExpr e1 <*> checkExpr e2+checkExpr (EnumFromThenTo spi e1 e2 e3) =+ EnumFromThenTo spi <$> checkExpr e1 <*> checkExpr e2 <*> checkExpr e3+checkExpr (UnaryMinus spi e) = UnaryMinus spi <$> checkExpr e+checkExpr (Apply spi e1 e2) =+ Apply spi <$> checkExpr e1 <*> checkExpr e2+checkExpr (InfixApply spi e1 op e2) = do+ e1' <- checkExpr e1+ e2' <- checkExpr e2+ fixPrec spi e1' op e2'+checkExpr (LeftSection spi e op) = checkExpr e >>= checkLSection spi op+checkExpr (RightSection spi op e) = checkExpr e >>= checkRSection spi op+checkExpr (Lambda spi ts e) =+ Lambda spi <$> mapM checkPattern ts <*> checkExpr e+checkExpr (Let spi li ds e) = withLocalPrecEnv $+ Let spi li <$> checkDecls ds <*> checkExpr e+checkExpr (Do spi li sts e) = withLocalPrecEnv $+ Do spi li <$> mapM checkStmt sts <*> checkExpr e+checkExpr (IfThenElse spi e1 e2 e3) =+ IfThenElse spi <$> checkExpr e1 <*> checkExpr e2 <*> checkExpr e3+checkExpr (Case spi li ct e alts) =+ Case spi li ct <$> checkExpr e <*> mapM checkAlt alts++checkStmt :: Statement a -> PCM (Statement a)+checkStmt (StmtExpr spi e) =+ StmtExpr spi <$> checkExpr e+checkStmt (StmtDecl spi li ds) =+ StmtDecl spi li <$> checkDecls ds+checkStmt (StmtBind spi t e) =+ StmtBind spi <$> checkPattern t <*> checkExpr e++checkAlt :: Alt a -> PCM (Alt a)+checkAlt (Alt p t rhs) = Alt p <$> checkPattern t <*> checkRhs rhs++checkField :: (a -> PCM a) -> Field a -> PCM (Field a)+checkField check (Field p l x) = Field p l <$> check x++-- The functions 'fixPrec', 'fixUPrec', and 'fixRPrec' check the relative+-- precedences of adjacent infix operators in nested infix applications+-- and unary negations. The expressions will be reordered such that the+-- infix operator with the lowest precedence becomes the root of the+-- expression. The functions rely on the fact that the parser constructs+-- infix applications in a right-associative fashion, i.e., the left argument+-- of an infix application will never be an infix application. In addition,+-- a unary negation will never have an infix application as its argument.++-- The function 'fixPrec' checks whether the left argument of an+-- infix application is a unary negation and eventually reorders the+-- expression if the precedence of the infix operator is higher than that+-- of the negation. This will be done with the help of the function+-- 'fixUPrec'. In any case, the function 'fixRPrec' is used for fixing the+-- precedence of the infix operator and that of its right argument.+-- Note that both arguments already have been checked before 'fixPrec'+-- is called.++fixPrec :: SpanInfo -> Expression a -> InfixOp a -> Expression a -> PCM (Expression a)+fixPrec spi (UnaryMinus spi' e1) op e2 = do+ OpPrec fix pr <- getOpPrec op+ if pr < 6 || pr == 6 && fix == InfixL+ then fixRPrec spi (UnaryMinus spi' e1) op e2+ else if pr > 6+ then fixUPrec spi' e1 op e2+ else do+ report $ errAmbiguousParse "unary" (qualify minusId) (opName op)+ return $ InfixApply spi (UnaryMinus spi' e1) op e2+fixPrec spi e1 op e2 = fixRPrec spi e1 op e2++fixUPrec :: SpanInfo -> Expression a -> InfixOp a -> Expression a+ -> PCM (Expression a)+fixUPrec spi e1 op e2@(UnaryMinus spi' _) = do+ report $ errAmbiguousParse "operator" (opName op) (qualify minusId)+ return $ UnaryMinus spi' (InfixApply spi e1 op e2)+fixUPrec spi e1 op1 e'@(InfixApply spi' e2 op2 e3) = do+ OpPrec fix2 pr2 <- getOpPrec op2+ if pr2 < 6 || pr2 == 6 && fix2 == InfixL+ then do+ left <- fixUPrec spi e1 op1 e2+ return $ InfixApply (left @+@ e3) left op2 e3+ else if pr2 > 6+ then do+ op <- fixRPrec spi e1 op1 $ InfixApply spi' e2 op2 e3+ return $ updateEndPos $ UnaryMinus spi' op+ else do+ report $ errAmbiguousParse "unary" (qualify minusId) (opName op2)+ let left = updateEndPos (UnaryMinus spi' e1)+ return $ InfixApply (left @+@ e') left op1 e'+fixUPrec spi e1 op e2 = return $ updateEndPos $ UnaryMinus spi+ (InfixApply (e1 @+@ e2) e1 op e2)++fixRPrec :: SpanInfo -> Expression a -> InfixOp a -> Expression a+ -> PCM (Expression a)+fixRPrec spi e1 op (UnaryMinus spi' e2) = do+ OpPrec _ pr <- getOpPrec op+ unless (pr < 6) $ report $ errAmbiguousParse "operator" (opName op) (qualify minusId)+ return $ InfixApply spi e1 op $ UnaryMinus spi' e2+fixRPrec spi e1 op1 (InfixApply spi' e2 op2 e3) = do+ OpPrec fix1 pr1 <- getOpPrec op1+ OpPrec fix2 pr2 <- getOpPrec op2+ if pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR+ then return $ InfixApply spi e1 op1 $ InfixApply spi' e2 op2 e3+ else if pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL+ then do+ left <- fixPrec (e1 @+@ e2) e1 op1 e2+ return $ InfixApply (left @+@ e3) left op2 e3+ else do+ report $ errAmbiguousParse "operator" (opName op1) (opName op2)+ return $ InfixApply spi e1 op1 $ InfixApply spi' e2 op2 e3+fixRPrec spi e1 op e2 = return $ InfixApply spi e1 op e2++-- The functions 'checkLSection' and 'checkRSection' are used for handling+-- the precedences inside left and right sections.+-- These functions only need to check that an infix operator occurring in+-- the section has either a higher precedence than the section operator+-- or both operators have the same precedence and are both left+-- associative for a left section and right associative for a right+-- section, respectively.++checkLSection :: SpanInfo -> InfixOp a -> Expression a -> PCM (Expression a)+checkLSection spi op e@(UnaryMinus _ _) = do+ OpPrec fix pr <- getOpPrec op+ unless (pr < 6 || pr == 6 && fix == InfixL) $+ report $ errAmbiguousParse "unary" (qualify minusId) (opName op)+ return $ LeftSection spi e op+checkLSection spi op1 e@(InfixApply _ _ op2 _) = do+ OpPrec fix1 pr1 <- getOpPrec op1+ OpPrec fix2 pr2 <- getOpPrec op2+ unless (pr1 < pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL) $+ report $ errAmbiguousParse "operator" (opName op1) (opName op2)+ return $ LeftSection spi e op1+checkLSection spi op e = return $ LeftSection spi e op++checkRSection :: SpanInfo -> InfixOp a -> Expression a -> PCM (Expression a)+checkRSection spi op e@(UnaryMinus _ _) = do+ OpPrec _ pr <- getOpPrec op+ unless (pr < 6) $ report $ errAmbiguousParse "unary" (qualify minusId) (opName op)+ return $ RightSection spi op e+checkRSection spi op1 e@(InfixApply _ _ op2 _) = do+ OpPrec fix1 pr1 <- getOpPrec op1+ OpPrec fix2 pr2 <- getOpPrec op2+ unless (pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR) $+ report $ errAmbiguousParse "operator" (opName op1) (opName op2)+ return $ RightSection spi op1 e+checkRSection spi op e = return $ RightSection spi op e++-- The functions 'fixPrecT' and 'fixRPrecT' check the relative precedences+-- of adjacent infix operators in patterns. The patterns will be reordered+-- such that the infix operator with the lowest precedence becomes the root+-- of the term. The functions rely on the fact that the parser constructs+-- infix patterns in a right-associative fashion, i.e., the left argument+-- of an infix pattern will never be an infix pattern. The functions also+-- check whether the left and right arguments of an infix pattern are negative+-- literals. In this case, the negation must bind more tightly than the+-- operator for the pattern to be accepted.++fixPrecT :: (Pattern a -> QualIdent -> Pattern a -> Pattern a)+ -> Pattern a -> QualIdent -> Pattern a -> PCM (Pattern a)+fixPrecT infixpatt t1@(NegativePattern _ _ _) op t2 = do+ OpPrec fix pr <- prec op <$> getPrecEnv+ unless (pr < 6 || pr == 6 && fix == InfixL) $+ report $ errInvalidParse "unary operator" minusId op+ fixRPrecT infixpatt t1 op t2+fixPrecT infixpatt t1 op t2 = fixRPrecT infixpatt t1 op t2++fixRPrecT :: (Pattern a -> QualIdent -> Pattern a -> Pattern a)+ -> Pattern a -> QualIdent -> Pattern a -> PCM (Pattern a)+fixRPrecT infixpatt t1 op t2@(NegativePattern _ _ _) = do+ OpPrec _ pr <- prec op <$> getPrecEnv+ unless (pr < 6) $ report $ errInvalidParse "unary operator" minusId op+ return $ infixpatt t1 op t2+fixRPrecT infixpatt t1 op1 (InfixPattern spi a t2 op2 t3) = do+ OpPrec fix1 pr1 <- prec op1 <$> getPrecEnv+ OpPrec fix2 pr2 <- prec op2 <$> getPrecEnv+ if pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR+ then return $ infixpatt t1 op1 (InfixPattern spi a t2 op2 t3)+ else if pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL+ then do+ left <- fixPrecT infixpatt t1 op1 t2+ return $ InfixPattern (left @+@ t3) a left op2 t3+ else do+ report $ errAmbiguousParse "operator" op1 op2+ return $ infixpatt t1 op1 (InfixPattern spi a t2 op2 t3)+fixRPrecT infixpatt t1 op1 (InfixFuncPattern spi a t2 op2 t3) = do+ OpPrec fix1 pr1 <- prec op1 <$> getPrecEnv+ OpPrec fix2 pr2 <- prec op2 <$> getPrecEnv+ if pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR+ then return $ infixpatt t1 op1 (InfixFuncPattern spi a t2 op2 t3)+ else if pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL+ then do+ left <- fixPrecT infixpatt t1 op1 t2+ return $ InfixFuncPattern (left @+@ t3) a left op2 t3+ else do+ report $ errAmbiguousParse "operator" op1 op2+ return $ infixpatt t1 op1 (InfixFuncPattern spi a t2 op2 t3)+fixRPrecT infixpatt t1 op t2 = return $ infixpatt t1 op t2++{-fixPrecT :: Position -> OpPrecEnv -> Pattern -> QualIdent -> Pattern+ -> Pattern+fixPrecT p pEnv t1@(NegativePattern uop l) op t2+ | pr < 6 || pr == 6 && fix == InfixL = fixRPrecT p pEnv t1 op t2+ | otherwise = errorAt p $ errInvalidParse "unary" uop op+ where OpPrec fix pr = prec op pEnv+fixPrecT p pEnv t1 op t2 = fixRPrecT p pEnv t1 op t2-}++{-fixRPrecT :: Position -> OpPrecEnv -> Pattern -> QualIdent -> Pattern+ -> Pattern+fixRPrecT p pEnv t1 op t2@(NegativePattern uop l)+ | pr < 6 = InfixPattern t1 op t2+ | otherwise = errorAt p $ errInvalidParse "unary" uop op+ where OpPrec _ pr = prec op pEnv+fixRPrecT p pEnv t1 op1 (InfixPattern t2 op2 t3)+ | pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR =+ InfixPattern t1 op1 (InfixPattern t2 op2 t3)+ | pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL =+ InfixPattern (fixPrecT p pEnv t1 op1 t2) op2 t3+ | otherwise = errorAt p $ errAmbiguousParse "operator" op1 op2+ where OpPrec fix1 pr1 = prec op1 pEnv+ OpPrec fix2 pr2 = prec op2 pEnv+fixRPrecT _ _ t1 op t2 = InfixPattern t1 op t2-}++-- The functions 'checkOpL' and 'checkOpR' check the left and right arguments+-- of an operator declaration. If they are infix patterns they must bind+-- more tightly than the operator, otherwise the left-hand side of the+-- declaration is invalid.++checkOpL :: Ident -> Pattern a -> PCM (Pattern a)+checkOpL op t@(NegativePattern _ _ _) = do+ OpPrec fix pr <- prec (qualify op) <$> getPrecEnv+ unless (pr < 6 || pr == 6 && fix == InfixL) $+ report $ errInvalidParse "unary operator" minusId (qualify op)+ return t+checkOpL op1 t@(InfixPattern _ _ _ op2 _) = do+ OpPrec fix1 pr1 <- prec (qualify op1) <$> getPrecEnv+ OpPrec fix2 pr2 <- prec op2 <$> getPrecEnv+ unless (pr1 < pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL) $+ report $ errInvalidParse "operator" op1 op2+ return t+checkOpL _ t = return t++checkOpR :: Ident -> Pattern a -> PCM (Pattern a)+checkOpR op t@(NegativePattern _ _ _) = do+ OpPrec _ pr <- prec (qualify op) <$> getPrecEnv+ when (pr >= 6) $ report $ errInvalidParse "unary operator" minusId (qualify op)+ return t+checkOpR op1 t@(InfixPattern _ _ _ op2 _) = do+ OpPrec fix1 pr1 <- prec (qualify op1) <$> getPrecEnv+ OpPrec fix2 pr2 <- prec op2 <$> getPrecEnv+ unless (pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR) $+ report $ errInvalidParse "operator" op1 op2+ return t+checkOpR _ t = return t++-- The functions 'opPrec' and 'prec' return the fixity and operator precedence+-- of an entity. Even though precedence checking is performed after the+-- renaming phase, we have to be prepared to see ambiguoeus identifiers here.+-- This may happen while checking the root of an operator definition that+-- shadows an imported definition.++getOpPrec :: InfixOp a -> PCM OpPrec+getOpPrec op = opPrec op <$> getPrecEnv++opPrec :: InfixOp a -> OpPrecEnv -> OpPrec+opPrec op = prec (opName op)++prec :: QualIdent -> OpPrecEnv -> OpPrec+prec op env = case qualLookupP op env of+ [] -> defaultP+ PrecInfo _ p : _ -> p+++-- Combine two entities with SpanInfo to a new SpanInfo (discarding info points)+(@+@) :: (HasSpanInfo a, HasSpanInfo b) => a -> b -> SpanInfo+a @+@ b = fromSrcSpan (combineSpans (getSrcSpan a) (getSrcSpan b))++-- ---------------------------------------------------------------------------+-- Error messages+-- ---------------------------------------------------------------------------++errUndefinedOperator :: Ident -> Message+errUndefinedOperator op = spanInfoMessage op $ hsep $ map text+ ["No definition for", escName op, "in this scope"]++errMultiplePrecedence :: [Ident] -> Message+errMultiplePrecedence [] = internalError+ "PrecCheck.errMultiplePrecedence: empty list"+errMultiplePrecedence (op:ops) = spanInfoMessage op $+ (hsep $ map text ["More than one fixity declaration for", escName op, "at"])+ $+$ nest 2 (vcat (map (ppPosition . getPosition) (op:ops)))++errInvalidParse :: String -> Ident -> QualIdent -> Message+errInvalidParse what op1 op2 = spanInfoMessage op1 $ hsep $ map text+ [ "Invalid use of", what, escName op1, "with", escQualName op2, "in"+ , showLine $ getPosition op2]++-- FIXME: Messages may have missing positions for minus operators+-- TODO: Is this still true after span update for parser?++errAmbiguousParse :: String -> QualIdent -> QualIdent -> Message+errAmbiguousParse what op1 op2 = spanInfoMessage op1 $ hsep $ map text+ ["Ambiguous use of", what, escQualName op1, "with", escQualName op2, "in"+ , showLine $ getPosition op2]
+ src/Checks/SyntaxCheck.hs view
@@ -0,0 +1,1430 @@+{- |+ Module : $Header$+ Description : Syntax checks+ Copyright : (c) 1999 - 2004 Wolfgang Lux+ Martin Engelke+ Björn Peemöller+ 2015 Jan Tikovsky+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ After the type declarations have been checked, the compiler performs+ a syntax check on the remaining declarations. This check disambiguates+ nullary data constructors and variables which -- in contrast to Haskell --+ is not possible on purely syntactic criteria. In addition, this pass checks+ for undefined as well as ambiguous variables and constructors. In order to+ allow lifting of local definitions in later phases, all local variables are+ renamed by adding a key identifying their scope. Therefore, all variables+ defined in the same scope share the same key so that multiple definitions+ can be recognized. Finally, all (adjacent) equations of a function are+ merged into a single definition.+-}+{-# LANGUAGE CPP #-}+module Checks.SyntaxCheck (syntaxCheck) where++#if __GLASGOW_HASKELL__ >= 804+import Prelude hiding ((<>))+#endif++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative ((<$>), (<*>))+#endif++import Control.Monad (unless, when)+import qualified Control.Monad.State as S (State, gets, modify, runState,+ withState)+import Data.Function (on)+import Data.List (insertBy, intersect, nub, nubBy)+import qualified Data.Map as Map (Map, empty, findWithDefault,+ fromList, insertWith, keys)+import Data.Maybe (isJust, isNothing)+import qualified Data.Set as Set (Set, empty, insert, member,+ singleton, toList, union)++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Base.Pretty+import Curry.Base.Span+import Curry.Base.SpanInfo+import Curry.Syntax++import Base.Expr+import Base.Messages (Message, internalError,+ spanInfoMessage)+import Base.NestEnv+import Base.SCC (scc)+import Base.Utils (findDouble, findMultiples, (++!))++import Env.TypeConstructor (TCEnv, clsMethods, getOrigName)+import Env.Value (ValueEnv, ValueInfo (..),+ qualLookupValueUnique)+++-- The syntax checking proceeds as follows. First, the compiler extracts+-- information about all imported values and data constructors from the+-- imported (type) environments. Next, the data constructors defined in+-- the current module are entered into this environment. After this,+-- all record labels are entered into the environment. If a record+-- identifier is already assigned to a constructor, then an error will be+-- generated. Class methods defined in the current module are entered into+-- the environment, too. Finally, all declarations are checked within the+-- resulting environment. In addition, this process will also rename the+-- local variables.++-- TODO: use SpanInfos for errors and then stop passing down SpanInfo from the decls to the checks++syntaxCheck :: [KnownExtension] -> TCEnv -> ValueEnv -> Module ()+ -> ((Module (), [KnownExtension]), [Message])+syntaxCheck exts tcEnv vEnv mdl@(Module _ _ _ m _ _ ds) =+ case findMultiples cons of+ [] -> case findMultiples (ls ++ fs ++ cons ++ cs) of+ [] -> runSC (checkModule mdl) state+ iss -> ((mdl, exts), map (errMultipleDeclarations m) iss)+ css -> ((mdl, exts), map errMultipleDataConstructor css)+ where+ tds = filter isTypeDecl ds+ vds = filter isValueDecl ds+ cds = filter isClassDecl ds+ cons = concatMap constrs tds+ ls = nub $ concatMap recLabels tds+ fs = nub $ concatMap vars vds+ cs = concatMap (concatMap methods) [ds' | ClassDecl _ _ _ _ _ ds' <- cds]+ rEnv = globalEnv $ fmap renameInfo vEnv+ state = initState exts m tcEnv rEnv vEnv++-- A global state transformer is used for generating fresh integer keys with+-- which the variables are renamed.+-- The state tracks the identifier of the current scope 'scopeId' as well as+-- the next fresh identifier, which is used for introducing new scopes as well+-- as renaming literals and underscore to disambiguate them.++-- |Syntax check monad+type SCM = S.State SCState++-- |Internal state of the syntax check+data SCState = SCState+ { extensions :: [KnownExtension] -- ^ Enabled language extensions+ , moduleIdent :: ModuleIdent -- ^ 'ModuleIdent' of the current module+ , tyConsEnv :: TCEnv+ , renameEnv :: RenameEnv -- ^ Information store+ , valueEnv :: ValueEnv -- ^ To check instance method visibility+ , scopeId :: Integer -- ^ Identifier for the current scope+ , nextId :: Integer -- ^ Next fresh identifier+ , funcDeps :: FuncDeps -- ^ Stores data about functions dependencies+ , typeClassesCheck :: Bool+ , errors :: [Message] -- ^ Syntactic errors in the module+ }++-- |Initial syntax check state+initState :: [KnownExtension] -> ModuleIdent -> TCEnv -> RenameEnv -> ValueEnv+ -> SCState+initState exts m tcEnv rEnv vEnv =+ SCState exts m tcEnv rEnv vEnv globalScopeId 1 noFuncDeps False []++-- |Identifier for global (top-level) declarations+globalScopeId :: Integer+globalScopeId = idUnique (mkIdent "")++-- |Run the syntax check monad+runSC :: SCM a -> SCState -> (a, [Message])+runSC scm s = let (a, s') = S.runState scm s in (a, reverse $ errors s')++-- |Check for an enabled extension+hasExtension :: KnownExtension -> SCM Bool+hasExtension ext = S.gets (elem ext . extensions)++-- |Enable an additional 'Extension' to avoid redundant complaints about+-- missing extensions+enableExtension :: KnownExtension -> SCM ()+enableExtension e = S.modify $ \s -> s { extensions = e : extensions s }++-- |Retrieve all enabled extensions+getExtensions :: SCM [KnownExtension]+getExtensions = S.gets extensions++-- |Retrieve the 'ModuleIdent' of the current module+getModuleIdent :: SCM ModuleIdent+getModuleIdent = S.gets moduleIdent++-- |Retrieve the 'TCEnv'+getTyConsEnv :: SCM TCEnv+getTyConsEnv = S.gets tyConsEnv++-- |Retrieve the 'RenameEnv'+getRenameEnv :: SCM RenameEnv+getRenameEnv = S.gets renameEnv++-- |Retrieve the 'ValueEnv'+getValueEnv :: SCM ValueEnv+getValueEnv = S.gets valueEnv++-- |Modify the 'RenameEnv'+modifyRenameEnv :: (RenameEnv -> RenameEnv) -> SCM ()+modifyRenameEnv f = S.modify $ \s -> s { renameEnv = f $ renameEnv s }++-- |Retrieve the current scope identifier+getScopeId :: SCM Integer+getScopeId = S.gets scopeId++-- |Create a new identifier and return it+newId :: SCM Integer+newId = do+ curId <- S.gets nextId+ S.modify $ \s -> s { nextId = succ curId }+ return curId++-- |Checks whether a type classes check is running+isTypeClassesCheck :: SCM Bool+isTypeClassesCheck = S.gets typeClassesCheck++-- |Performs a type classes check in a nested scope+performTypeClassesCheck :: SCM a -> SCM a+performTypeClassesCheck = inNestedScope .+ S.withState (\s -> s { typeClassesCheck = True })++-- |Increase the nesting of the 'RenameEnv' to introduce a new local scope.+-- This also increases the scope identifier.+incNesting :: SCM ()+incNesting = do+ newScopeId <- newId+ S.modify $ \s -> s { scopeId = newScopeId }+ modifyRenameEnv nestEnv++withLocalEnv :: SCM a -> SCM a+withLocalEnv act = do+ oldEnv <- getRenameEnv+ res <- act+ modifyRenameEnv $ const oldEnv+ return res++-- |Perform an action in a nested scope (by creating a nested 'RenameEnv')+-- and discard the nested 'RenameEnv' afterwards+inNestedScope :: SCM a -> SCM a+inNestedScope act = withLocalEnv (incNesting >> act)++-- |Modify the `FuncDeps'+modifyFuncDeps :: (FuncDeps -> FuncDeps) -> SCM ()+modifyFuncDeps f = S.modify $ \ s -> s { funcDeps = f $ funcDeps s }++-- |Report a syntax error+report :: Message -> SCM ()+report msg = S.modify $ \s -> s { errors = msg : errors s }++-- |Everything is checked+ok :: SCM ()+ok = return ()++-- FuncDeps contains information to deal with dependencies between functions.+-- This is used for checking whether functional patterns are cyclic.+-- curGlobalFunc contains the identifier of the global function that is+-- currently being checked, if any.+-- data X = X+-- f = let g = lookup 42 in g [1,2,3]+-- While `X' is being checked `curGlobalFunc' should be `Nothing',+-- while `lookup' is being checked is should be `f's identifier.+-- globalDeps collects all dependencies (other functions) of global functions+-- funcPats collects all functional patterns and the global function they're+-- used in+data FuncDeps = FuncDeps+ { curGlobalFunc :: Maybe QualIdent+ , globalDeps :: GlobalDeps+ , funcPats :: [(QualIdent, QualIdent)]+ }+type GlobalDeps = Map.Map QualIdent (Set.Set QualIdent)++-- |Initial state for FuncDeps+noFuncDeps :: FuncDeps+noFuncDeps = FuncDeps Nothing Map.empty []++-- |Perform an action inside a function, settìng `curGlobalFunc' to that function+inFunc :: Ident -> SCM a -> SCM a+inFunc i scm = do+ m <- getModuleIdent+ global <- isNothing <$> S.gets (curGlobalFunc . funcDeps)+ when global $ modifyFuncDeps $ \ fd -> fd { curGlobalFunc = Just (qualifyWith m i) }+ res <- scm+ when global $ modifyFuncDeps $ \ fd -> fd { curGlobalFunc = Nothing }+ return res++-- |Add a dependency to `curGlobalFunction'+addGlobalDep :: QualIdent -> SCM ()+addGlobalDep dep = do+ maybeF <- S.gets (curGlobalFunc . funcDeps)+ case maybeF of+ Nothing -> internalError "SyntaxCheck.addFuncPat: no global function set"+ Just f -> modifyFuncDeps $ \ fd -> fd+ { globalDeps = Map.insertWith Set.union f+ (Set.singleton dep) (globalDeps fd) }++-- |Add a functional pattern to `curGlobalFunction'+addFuncPat :: QualIdent -> SCM ()+addFuncPat fp = do+ maybeF <- S.gets (curGlobalFunc . funcDeps)+ case maybeF of+ Nothing -> internalError "SyntaxCheck.addFuncPat: no global function set"+ Just f -> modifyFuncDeps $ \ fd -> fd { funcPats = (fp, f) : funcPats fd }++-- |Return dependencies of global functions+getGlobalDeps :: SCM GlobalDeps+getGlobalDeps = globalDeps <$> S.gets funcDeps++-- |Return used functional patterns+getFuncPats :: SCM [(QualIdent, QualIdent)]+getFuncPats = funcPats <$> S.gets funcDeps+++-- A nested environment is used for recording information about the data+-- constructors and variables in the module. For every data constructor+-- its arity is saved. This is used for checking that all constructor+-- applications in patterns are saturated. For local variables the+-- environment records the new name of the variable after renaming.+-- Global variables are recorded with qualified identifiers in order+-- to distinguish multiply declared entities.++-- Currently, records must explicitly be declared together with their labels.+-- When constructing or updating a record, it is necessary to compute+-- all its labels using just one of them. Thus for each label+-- the record identifier and all its labels are entered into the environment++-- Note: the function 'qualLookupVar' has been extended to allow the usage of+-- the qualified list constructor (prelude.:).++type RenameEnv = NestEnv RenameInfo++data RenameInfo+ -- |Arity of data constructor+ = Constr QualIdent Int+ -- |Constructors of a record label+ | RecordLabel QualIdent [QualIdent]+ -- |Arity of global function+ | GlobalVar QualIdent Int+ -- |Arity of local function+ | LocalVar Ident Int+ deriving (Eq, Show)++ppRenameInfo :: RenameInfo -> Doc+ppRenameInfo (Constr qn _) = text (escQualName qn)+ppRenameInfo (RecordLabel qn _) = text (escQualName qn)+ppRenameInfo (GlobalVar qn _) = text (escQualName qn)+ppRenameInfo (LocalVar n _) = text (escName n)++-- Since record types are currently translated into data types, it is necessary+-- to ensure that all identifiers for records and constructors are different.+-- Furthermore, it is not allowed to declare a label more than once.++renameInfo :: ValueInfo -> RenameInfo+renameInfo (DataConstructor qid a _ _) = Constr qid a+renameInfo (NewtypeConstructor qid _ _) = Constr qid 1+renameInfo (Value qid _ a _) = GlobalVar qid a+renameInfo (Label qid cs _) = RecordLabel qid cs++bindGlobal :: Bool -> ModuleIdent -> Ident -> RenameInfo -> RenameEnv+ -> RenameEnv+bindGlobal tcc m c r+ | not tcc = bindNestEnv c r . qualBindNestEnv (qualifyWith m c) r+ | otherwise = id++bindLocal :: Ident -> RenameInfo -> RenameEnv -> RenameEnv+bindLocal = bindNestEnv++-- ------------------------------------------------------------------------------++-- |Bind type constructor information and record label information+bindTypeDecl :: Decl a -> SCM ()+bindTypeDecl (DataDecl _ _ _ cs _) =+ mapM_ bindConstr cs >> bindRecordLabels cs+bindTypeDecl (NewtypeDecl _ _ _ nc _) = bindNewConstr nc+bindTypeDecl _ = ok++bindConstr :: ConstrDecl -> SCM ()+bindConstr (ConstrDecl _ c tys) = do+ m <- getModuleIdent+ modifyRenameEnv $ bindGlobal False m c (Constr (qualifyWith m c) $ length tys)+bindConstr (ConOpDecl _ _ op _) = do+ m <- getModuleIdent+ modifyRenameEnv $ bindGlobal False m op (Constr (qualifyWith m op) 2)+bindConstr (RecordDecl _ c fs) = do+ m <- getModuleIdent+ modifyRenameEnv $ bindGlobal False m c (Constr (qualifyWith m c) (length labels))+ where labels = [l | FieldDecl _ ls _ <- fs, l <- ls]++bindNewConstr :: NewConstrDecl -> SCM ()+bindNewConstr (NewConstrDecl _ c _) = do+ m <- getModuleIdent+ modifyRenameEnv $ bindGlobal False m c (Constr (qualifyWith m c) 1)+bindNewConstr (NewRecordDecl _ c (l, _)) = do+ m <- getModuleIdent+ bindRecordLabel (l, [c])+ modifyRenameEnv $ bindGlobal False m c (Constr (qualifyWith m c) 1)++bindRecordLabels :: [ConstrDecl] -> SCM ()+bindRecordLabels cs =+ mapM_ bindRecordLabel [(l, constr l) | l <- nub (concatMap recordLabels cs)]+ where constr l = [constrId c | c <- cs, l `elem` recordLabels c]++bindRecordLabel :: (Ident, [Ident]) -> SCM ()+bindRecordLabel (l, cs) = do+ m <- getModuleIdent+ new <- null . lookupVar l <$> getRenameEnv+ unless new $ report $ errDuplicateDefinition l+ modifyRenameEnv $ bindGlobal False m l $+ RecordLabel (qualifyWith m l) (map (qualifyWith m) cs)++-- ------------------------------------------------------------------------------++-- |Bind a global function declaration in the 'RenameEnv'+bindFuncDecl :: Bool -> ModuleIdent -> Decl a -> RenameEnv -> RenameEnv+bindFuncDecl _ _ (FunctionDecl _ _ _ []) _+ = internalError "SyntaxCheck.bindFuncDecl: no equations"+bindFuncDecl tcc m (FunctionDecl _ _ f (eq:_)) env+ = let arty = length $ snd $ getFlatLhs eq+ in bindGlobal tcc m f (GlobalVar (qualifyWith m f) arty) env+bindFuncDecl tcc m (TypeSig _ fs (QualTypeExpr _ _ ty)) env+ = foldr (bindTS . qualifyWith m) env fs+ where+ bindTS qf env'+ | null $ qualLookupVar qf env'+ = bindGlobal tcc m (unqualify qf) (GlobalVar qf (typeArity ty)) env'+ | otherwise = env'+bindFuncDecl _ _ _ env = env++-- ------------------------------------------------------------------------------++-- |Bind type class information, i.e. class methods+bindClassDecl :: Decl a -> SCM ()+bindClassDecl (ClassDecl _ _ _ _ _ ds) = mapM_ bindClassMethod ds+bindClassDecl _ = ok++bindClassMethod :: Decl a -> SCM ()+bindClassMethod ts@(TypeSig _ _ _) = do+ m <- getModuleIdent+ modifyRenameEnv $ bindFuncDecl False m ts+bindClassMethod _ = ok++-- ------------------------------------------------------------------------------++-- |Bind a local declaration (function, variables) in the 'RenameEnv'+bindVarDecl :: Decl a -> RenameEnv -> RenameEnv+bindVarDecl (FunctionDecl _ _ f eqs) env+ | null eqs = internalError "SyntaxCheck.bindVarDecl: no equations"+ | otherwise = let arty = length $ snd $ getFlatLhs $ head eqs+ in bindLocal (unRenameIdent f) (LocalVar f arty) env+bindVarDecl (PatternDecl _ t _) env = foldr bindVar env (bv t)+bindVarDecl (FreeDecl _ vs) env = foldr (bindVar . varIdent) env vs+bindVarDecl _ env = env++bindVar :: Ident -> RenameEnv -> RenameEnv+bindVar v | isAnonId v = id+ | otherwise = bindLocal (unRenameIdent v) (LocalVar v 0)++lookupVar :: Ident -> RenameEnv -> [RenameInfo]+lookupVar v env = lookupNestEnv v env ++! lookupTupleConstr v++qualLookupVar :: QualIdent -> RenameEnv -> [RenameInfo]+qualLookupVar v env = qualLookupNestEnv v env+ ++! qualLookupListCons v env+ ++! lookupTupleConstr (unqualify v)++lookupTupleConstr :: Ident -> [RenameInfo]+lookupTupleConstr v+ | isTupleId v = let a = tupleArity v+ in [Constr (qualifyWith preludeMIdent $ tupleId a) a]+ | otherwise = []++qualLookupListCons :: QualIdent -> RenameEnv -> [RenameInfo]+qualLookupListCons v env+ | v == qualifyWith preludeMIdent consId+ = qualLookupNestEnv (qualify $ qidIdent v) env+ | otherwise+ = []++-- When a module is checked, the global declaration group is checked. The+-- resulting renaming environment can be discarded. The same is true for+-- a goal. Note that all declarations in the goal must be considered as+-- local declarations. Class and instance declarations define their own scope,+-- thus defined functions will be renamed as well. For class and instance+-- declarations several checks have to be disabled (for instance, type+-- signatures without corresponding function declaration are allowed in class+-- declarations), while some have to be performed extra (for instance, no+-- other functions than specified by the type signatures within a class+-- declaration are allowed to be declared).++checkModule :: Module () -> SCM (Module (), [KnownExtension])+checkModule (Module spi li ps m es is ds) = do+ mapM_ bindTypeDecl tds+ mapM_ bindClassDecl cds+ ds' <- checkTopDecls ds+ cds' <- mapM (performTypeClassesCheck . checkClassDecl) cds+ ids' <- mapM (performTypeClassesCheck . checkInstanceDecl) ids+ let ds'' = updateClassAndInstanceDecls cds' ids' ds'+ checkFuncPatDeps+ exts <- getExtensions+ return (Module spi li ps m es is ds'', exts)+ where tds = filter isTypeDecl ds+ cds = filter isClassDecl ds+ ids = filter isInstanceDecl ds++-- |Checks whether a function in a functional pattern contains cycles+-- |(depends on its own global function)+checkFuncPatDeps :: SCM ()+checkFuncPatDeps = do+ fps <- getFuncPats+ deps <- getGlobalDeps+ let levels = scc (:[])+ (\k -> Set.toList (Map.findWithDefault Set.empty k deps))+ (Map.keys deps)+ levelMap = Map.fromList [ (f, l) | (fs, l) <- zip levels [1 ..], f <- fs ]+ level f = Map.findWithDefault (0 :: Int) f levelMap+ mapM_ (checkFuncPatDep level) fps++checkFuncPatDep :: Ord a => (QualIdent -> a) -> (QualIdent, QualIdent) -> SCM ()+checkFuncPatDep level (fp, f) = unless (level fp < level f) $+ report $ errFuncPatCyclic fp f++checkTopDecls :: [Decl ()] -> SCM [Decl ()]+checkTopDecls ds = do+ m <- getModuleIdent+ tcc <- isTypeClassesCheck+ checkDeclGroup (bindFuncDecl tcc m) ds++checkClassDecl :: Decl () -> SCM (Decl ())+checkClassDecl (ClassDecl p li cx cls tv ds) = do+ checkMethods (qualify cls) (concatMap methods ds) ds+ ClassDecl p li cx cls tv <$> checkTopDecls ds+checkClassDecl _ =+ internalError "SyntaxCheck.checkClassDecl: no class declaration"++checkInstanceDecl :: Decl () -> SCM (Decl ())+checkInstanceDecl (InstanceDecl p li cx qcls ty ds) = do+ m <- getModuleIdent+ vEnv <- getValueEnv+ tcEnv <- getTyConsEnv+ let clsMthds = clsMethods m qcls tcEnv+ let orig = getOrigName m qcls tcEnv+ let mthds =+ if isLocalIdent m orig+ then clsMthds+ else filter (isFromCls orig m vEnv) clsMthds+ checkMethods qcls mthds ds+ mapM_ checkAmbiguousMethod ds+ InstanceDecl p li cx qcls ty <$> checkTopDecls ds+ where+ isFromCls orig m vEnv f = case qualLookupValueUnique m (qualify f) vEnv of+ [Value _ (Just cls) _ _]+ | cls == orig -> True+ _ -> False++checkInstanceDecl _ =+ internalError "SyntaxCheck.checkInstanceDecl: no instance declaration"++checkAmbiguousMethod :: Decl a -> SCM ()+checkAmbiguousMethod (FunctionDecl _ _ f _) = do+ m <- getModuleIdent+ rename <- getRenameEnv+ case lookupVar f rename of+ rs1@(_:_:_) -> case qualLookupVar (qualifyWith m f) rename of+ [] -> report $ errAmbiguousIdent rs1 (qualify f)+ rs2@(_:_:_) -> report $ errAmbiguousIdent rs2 (qualify f)+ _ -> return ()+ _ -> return ()+checkAmbiguousMethod _ =+ internalError "SyntaxCheck.checkAmbiguousMethod: no function declaration"++checkMethods :: QualIdent -> [Ident] -> [Decl a] -> SCM ()+checkMethods qcls ms ds =+ mapM_ (report . errUndefinedMethod qcls) $ filter (`notElem` ms) fs+ where fs = [f | FunctionDecl _ _ f _ <- ds]++updateClassAndInstanceDecls :: [Decl a] -> [Decl a] -> [Decl a] -> [Decl a]+updateClassAndInstanceDecls [] [] ds = ds+updateClassAndInstanceDecls (c:cs) is (ClassDecl _ _ _ _ _ _:ds) =+ c : updateClassAndInstanceDecls cs is ds+updateClassAndInstanceDecls cs (i:is) (InstanceDecl _ _ _ _ _ _:ds) =+ i : updateClassAndInstanceDecls cs is ds+updateClassAndInstanceDecls cs is (d:ds) =+ d : updateClassAndInstanceDecls cs is ds+updateClassAndInstanceDecls _ _ _ =+ internalError "SyntaxCheck.updateClassAndInstanceDecls"++-- Each declaration group opens a new scope and uses a distinct key+-- for renaming the variables in this scope. In a declaration group,+-- first the left hand sides of all declarations are checked, next the+-- compiler checks that there is a definition for every type signature+-- and evaluation annotation in this group. Finally, the right hand sides+-- are checked and adjacent equations for the same function are merged+-- into a single definition.++-- The function 'checkDeclLhs' also handles the case where a pattern+-- declaration is recognized as a function declaration by the parser.+-- This happens, e.g., for the declaration+-- where Just x = y+-- because the parser cannot distinguish nullary constructors and functions.+-- Note that pattern declarations are not allowed on the top-level.++checkDeclGroup :: (Decl () -> RenameEnv -> RenameEnv) -> [Decl ()] -> SCM [Decl ()]+checkDeclGroup bindDecl ds = do+ checkedLhs <- mapM checkDeclLhs $ sortFuncDecls ds+ joinEquations checkedLhs >>= checkDecls bindDecl++checkDeclLhs :: Decl () -> SCM (Decl ())+checkDeclLhs (InfixDecl p fix' pr ops) =+ InfixDecl p fix' <$> checkPrecedence p pr <*> mapM renameVar ops+checkDeclLhs (TypeSig p vs ty) =+ (\vs' -> TypeSig p vs' ty) <$> mapM (checkVar "type signature") vs+checkDeclLhs (FunctionDecl p _ f eqs) =+ inFunc f $ checkEquationsLhs p eqs+checkDeclLhs (ExternalDecl p vs) =+ ExternalDecl p <$> mapM (checkVar' "external declaration") vs+checkDeclLhs (PatternDecl p t rhs) =+ (\t' -> PatternDecl p t' rhs) <$> checkPattern p t+checkDeclLhs (FreeDecl p vs) =+ FreeDecl p <$> mapM (checkVar' "free variables declaration") vs+checkDeclLhs d = return d++checkPrecedence :: SpanInfo -> Maybe Precedence -> SCM (Maybe Precedence)+checkPrecedence _ Nothing = return Nothing+checkPrecedence p (Just i) = do+ unless (0 <= i && i <= 9) $ report+ $ errPrecedenceOutOfRange p i+ return $ Just i++checkVar' :: String -> Var a -> SCM (Var a)+checkVar' what (Var a v) = Var a <$> checkVar what v++checkVar :: String -> Ident -> SCM Ident+checkVar _what v = do+ -- isDC <- S.gets (isDataConstr v . renameEnv)+ -- when isDC $ report $ nonVariable what v -- TODO Why is this disabled?+ renameVar v++renameVar :: Ident -> SCM Ident+renameVar v = renameIdent v <$> getScopeId++checkEquationsLhs :: SpanInfo -> [Equation ()] -> SCM (Decl ())+checkEquationsLhs p [Equation p' lhs rhs] = do+ lhs' <- checkEqLhs p' lhs+ case lhs' of+ Left l -> return $ funDecl' l+ Right r -> checkDeclLhs (PatternDecl p' r rhs)+ where funDecl' (f, lhs') = FunctionDecl p () f [Equation p' lhs' rhs]+checkEquationsLhs _ _ = internalError "SyntaxCheck.checkEquationsLhs"++checkEqLhs :: SpanInfo -> Lhs () -> SCM (Either (Ident, Lhs ()) (Pattern ()))+checkEqLhs pspi toplhs = do+ m <- getModuleIdent+ k <- getScopeId+ env <- getRenameEnv+ case toplhs of+ FunLhs spi f ts+ | not $ isDataConstr f env -> return left+ | k /= globalScopeId -> return right+ | null infos -> return left+ | otherwise -> do report $ errToplevelPattern pspi+ return right+ where f' = renameIdent f k+ infos = qualLookupVar (qualifyWith m f) env+ left = Left (f', FunLhs spi f' ts)+ right = Right $ -- use start from the parsed FunLhs and compute end+ updateEndPos $ ConstructorPattern spi () (qualify f) ts+ OpLhs spi t1 op t2+ | not $ isDataConstr op env -> return left+ | k /= globalScopeId -> return right+ | null infos -> return left+ | otherwise -> do report $ errToplevelPattern pspi+ return right+ where op' = renameIdent op k+ infos = qualLookupVar (qualifyWith m op) env+ left = Left (op', OpLhs spi t1 op' t2)+ right = checkOpLhs k env (infixPattern t1 (qualify op)) t2+ infixPattern (InfixPattern _ a' t1' op1 t2') op2 t3 =+ let t2'' = infixPattern t2' op2 t3+ sp = combineSpans (getSrcSpan t1') (getSrcSpan t2'')+ in InfixPattern (fromSrcSpan sp) a' t1' op1 t2''+ infixPattern t1' op1 t2' =+ let sp = combineSpans (getSrcSpan t1') (getSrcSpan t2')+ in InfixPattern (fromSrcSpan sp) () t1' op1 t2'+ ApLhs spi lhs ts -> do+ checked <- checkEqLhs pspi lhs+ case checked of+ Left (f', lhs') -> return $ Left (f', updateEndPos $ ApLhs spi lhs' ts)+ r -> do report $ errNonVariable "curried definition" f+ return $ r+ where (f, _) = flatLhs lhs++checkOpLhs :: Integer -> RenameEnv -> (Pattern a -> Pattern a)+ -> Pattern a -> Either (Ident, Lhs a) (Pattern a)+checkOpLhs k env f (InfixPattern spi a t1 op t2)+ | isJust m || isDataConstr op' env+ = checkOpLhs k env (f . InfixPattern spi a t1 op) t2+ | otherwise+ = Left (op'', OpLhs (getSpanInfo t1') t1' op'' t2)+ where (m,op') = (qidModule op, qidIdent op)+ op'' = renameIdent op' k+ t1' = f t1+checkOpLhs _ _ f t = Right (f t)++-- -- ---------------------------------------------------------------------------++joinEquations :: [Decl a] -> SCM [Decl a]+joinEquations [] = return []+joinEquations (FunctionDecl a p f eqs : FunctionDecl _ _ f' [eq] : ds)+ | f == f' = do+ when (getArity (head eqs) /= getArity eq) $ report $ errDifferentArity [f, f']+ joinEquations (updateEndPos (FunctionDecl a p f (eqs ++ [eq])) : ds)+ where getArity = length . snd . getFlatLhs+joinEquations (d : ds) = (d :) <$> joinEquations ds++checkDecls :: (Decl () -> RenameEnv -> RenameEnv) -> [Decl ()] -> SCM [Decl ()]+checkDecls bindDecl ds = do+ let dblVar = findDouble bvs+ onJust (report . errDuplicateDefinition) dblVar+ let mulTys = findMultiples tys+ mapM_ (report . errDuplicateTypeSig) mulTys+ let missingTys = [v | ExternalDecl _ vs <- ds, Var _ v <- vs, v `notElem` tys]+ mapM_ (report . errNoTypeSig) missingTys+ if isNothing dblVar && null mulTys && null missingTys+ then do+ modifyRenameEnv $ \env -> foldr bindDecl env (tds ++ vds)+ mapM (checkDeclRhs bvs) ds+ else return ds -- skip further checking+ where vds = filter isValueDecl ds+ tds = filter isTypeSig ds+ bvs = concatMap vars vds+ tys = concatMap vars tds+ onJust = maybe ok++-- -- ---------------------------------------------------------------------------++checkDeclRhs :: [Ident] -> Decl () -> SCM (Decl ())+checkDeclRhs _ (DataDecl p tc tvs cs clss) =+ flip (DataDecl p tc tvs) clss <$> mapM checkDeclLabels cs+checkDeclRhs bvs (TypeSig p vs ty) =+ (\vs' -> TypeSig p vs' ty) <$> mapM (checkLocalVar bvs) vs+checkDeclRhs _ (FunctionDecl a p f eqs) =+ FunctionDecl a p f <$> inFunc f (mapM checkEquation eqs)+checkDeclRhs _ (PatternDecl p t rhs) =+ PatternDecl p t <$> checkRhs rhs+checkDeclRhs _ d = return d++checkDeclLabels :: ConstrDecl -> SCM ConstrDecl+checkDeclLabels rd@(RecordDecl _ _ fs) = do+ onJust (report . errDuplicateLabel "declaration")+ (findDouble $ map qualify labels)+ return rd+ where+ onJust = maybe ok+ labels = [l | FieldDecl _ ls _ <- fs, l <- ls]+checkDeclLabels d = return d++checkLocalVar :: [Ident] -> Ident -> SCM Ident+checkLocalVar bvs v = do+ tcc <- isTypeClassesCheck+ when (v `notElem` bvs && not tcc) $ report $ errNoBody v+ return v++checkEquation :: Equation () -> SCM (Equation ())+checkEquation (Equation p lhs rhs) = inNestedScope $ do+ lhs' <- checkLhs p lhs >>= addBoundVariables False+ rhs' <- checkRhs rhs+ return $ Equation p lhs' rhs'++checkLhs :: SpanInfo -> Lhs () -> SCM (Lhs ())+checkLhs p (FunLhs spi f ts) = FunLhs spi f <$> mapM (checkPattern p) ts+checkLhs p (OpLhs spi t1 op t2) = do+ let wrongCalls = concatMap (checkParenPattern (Just $ qualify op)) [t1,t2]+ unless (null wrongCalls) $ report $ errInfixWithoutParens+ spi wrongCalls+ flip (OpLhs spi) op <$> checkPattern p t1 <*> checkPattern p t2+checkLhs p (ApLhs spi lhs ts) =+ ApLhs spi <$> checkLhs p lhs <*> mapM (checkPattern p) ts++-- checkParen+-- @param Aufrufende InfixFunktion+-- @param Pattern+-- @return Liste mit fehlerhaften Funktionsaufrufen++checkParenPattern :: Maybe QualIdent -> Pattern a -> [(QualIdent, QualIdent)]+checkParenPattern _ (LiteralPattern _ _ _) = []+checkParenPattern _ (NegativePattern _ _ _) = []+checkParenPattern _ (VariablePattern _ _ _) = []+checkParenPattern _ (ConstructorPattern _ _ _ cs) =+ concatMap (checkParenPattern Nothing) cs+checkParenPattern o (InfixPattern _ _ t1 op t2) =+ maybe [] (\c -> [(c, op)]) o+ ++ checkParenPattern Nothing t1 ++ checkParenPattern Nothing t2+checkParenPattern _ (ParenPattern _ t) =+ checkParenPattern Nothing t+checkParenPattern _ (RecordPattern _ _ _ fs) =+ concatMap (\(Field _ _ t) -> checkParenPattern Nothing t) fs+checkParenPattern _ (TuplePattern _ ts) =+ concatMap (checkParenPattern Nothing) ts+checkParenPattern _ (ListPattern _ _ ts) =+ concatMap (checkParenPattern Nothing) ts+checkParenPattern o (AsPattern _ _ t) =+ checkParenPattern o t+checkParenPattern o (LazyPattern _ t) =+ checkParenPattern o t+checkParenPattern _ (FunctionPattern _ _ _ ts) =+ concatMap (checkParenPattern Nothing) ts+checkParenPattern o (InfixFuncPattern _ _ t1 op t2) =+ maybe [] (\c -> [(c, op)]) o+ ++ checkParenPattern Nothing t1 ++ checkParenPattern Nothing t2++checkPattern :: SpanInfo -> Pattern () -> SCM (Pattern ())+checkPattern _ (LiteralPattern spi a l) =+ return $ LiteralPattern spi a l+checkPattern _ (NegativePattern spi a l) =+ return $ NegativePattern spi a l+checkPattern p (VariablePattern spi a v)+ | isAnonId v = VariablePattern spi a . renameIdent v <$> newId+ | otherwise = checkConstructorPattern p spi (qualify v) []+checkPattern p (ConstructorPattern spi _ c ts) =+ checkConstructorPattern p spi c ts+checkPattern p (InfixPattern spi _ t1 op t2) =+ checkInfixPattern p spi t1 op t2+checkPattern p (ParenPattern spi t) =+ ParenPattern spi <$> checkPattern p t+checkPattern p (RecordPattern spi _ c fs) =+ checkRecordPattern p spi c fs+checkPattern p (TuplePattern spi ts) =+ TuplePattern spi <$> mapM (checkPattern p) ts+checkPattern p (ListPattern spi a ts) =+ ListPattern spi a <$> mapM (checkPattern p) ts+checkPattern p (AsPattern spi v t) =+ AsPattern spi <$> checkVar "@ pattern" v <*> checkPattern p t+checkPattern p (LazyPattern spi t) = do+ t' <- checkPattern p t+ banFPTerm "lazy pattern" p t'+ return (LazyPattern spi t')+checkPattern _ (FunctionPattern _ _ _ _) = internalError+ "SyntaxCheck.checkPattern: function pattern not defined"+checkPattern _ (InfixFuncPattern _ _ _ _ _) = internalError+ "SyntaxCheck.checkPattern: infix function pattern not defined"++checkConstructorPattern :: SpanInfo -> SpanInfo -> QualIdent -> [Pattern ()]+ -> SCM (Pattern ())+checkConstructorPattern p spi c ts = do+ env <- getRenameEnv+ m <- getModuleIdent+ k <- getScopeId+ case qualLookupVar c env of+ [Constr _ n] -> processCons c n+ [r] -> processVarFun r k+ rs -> case qualLookupVar (qualQualify m c) env of+ [Constr _ n] -> processCons (qualQualify m c) n+ [r] -> processVarFun r k+ []+ | null ts && not (isQualified c) ->+ return $ VariablePattern spi () $ renameIdent (unqualify c) k+ | null rs -> do+ ts' <- mapM (checkPattern p) ts+ report $ errUndefinedData c+ return $ ConstructorPattern spi () c ts'+ _ -> do ts' <- mapM (checkPattern p) ts+ report $ errAmbiguousData rs c+ return $ ConstructorPattern spi () c ts'+ where+ n' = length ts+ processCons qc n = do+ when (n /= n') $ report $ errWrongArity c n n'+ ConstructorPattern spi () qc <$> mapM (checkPattern p) ts+ processVarFun r k+ | null ts && not (isQualified c)+ = return $ VariablePattern spi () $ renameIdent (unqualify c) k -- (varIdent r) k+ | otherwise = do+ checkFuncPatsExtension p+ checkFuncPatCall r c+ ts' <- mapM (checkPattern p) ts+ mapM_ (checkFPTerm p) ts'+ return $ FunctionPattern spi () (qualVarIdent r) ts'++checkInfixPattern :: SpanInfo -> SpanInfo -> Pattern () -> QualIdent -> Pattern ()+ -> SCM (Pattern ())+checkInfixPattern p spi t1 op t2 = do+ m <- getModuleIdent+ env <- getRenameEnv+ case qualLookupVar op env of+ [Constr _ n] -> infixPattern op n+ [r] -> funcPattern r op+ rs -> case qualLookupVar (qualQualify m op) env of+ [Constr _ n] -> infixPattern (qualQualify m op) n+ [r] -> funcPattern r (qualQualify m op)+ rs' -> do if null rs && null rs'+ then report $ errUndefinedData op+ else report $ errAmbiguousData rs op+ flip (InfixPattern spi ()) op <$> checkPattern p t1+ <*> checkPattern p t2+ where+ infixPattern qop n = do+ when (n /= 2) $ report $ errWrongArity op n 2+ flip (InfixPattern spi ()) qop <$> checkPattern p t1 <*> checkPattern p t2+ funcPattern r qop = do+ checkFuncPatsExtension p+ checkFuncPatCall r qop+ ts' <- mapM (checkPattern p) [t1,t2]+ let [t1',t2'] = ts'+ mapM_ (checkFPTerm p) ts'+ return $ InfixFuncPattern spi () t1' qop t2'++checkRecordPattern :: SpanInfo -> SpanInfo -> QualIdent -> [Field (Pattern ())]+ -> SCM (Pattern ())+checkRecordPattern p spi c fs = do+ env <- getRenameEnv+ m <- getModuleIdent+ case qualLookupVar c env of+ [Constr c' _] -> processRecPat (Just c') fs+ rs -> case qualLookupVar (qualQualify m c) env of+ [Constr c' _] -> processRecPat (Just c') fs+ rs' -> if null rs && null rs'+ then do report $ errUndefinedData c+ processRecPat Nothing fs+ else do report $ errAmbiguousData rs c+ processRecPat Nothing fs+ where+ processRecPat mcon fields = do+ fs' <- mapM (checkField (checkPattern p)) fields+ checkFieldLabels "pattern" p mcon fs'+ return $ RecordPattern spi () c fs'++checkFuncPatCall :: RenameInfo -> QualIdent -> SCM ()+checkFuncPatCall r f = case r of+ GlobalVar dep _ -> do+ addGlobalDep dep+ addFuncPat (dep @> f)+ _ -> report $ errFuncPatNotGlobal f++-- Note: process decls first+checkRhs :: Rhs () -> SCM (Rhs ())+checkRhs (SimpleRhs spi li e ds) = inNestedScope $+ flip (SimpleRhs spi li) <$>+ checkDeclGroup bindVarDecl ds <*>+ checkExpr spi e+checkRhs (GuardedRhs spi li es ds) = inNestedScope $+ flip (GuardedRhs spi li) <$>+ checkDeclGroup bindVarDecl ds <*>+ mapM checkCondExpr es++checkCondExpr :: CondExpr () -> SCM (CondExpr ())+checkCondExpr (CondExpr spi g e) = CondExpr spi <$> checkExpr spi g <*> checkExpr spi e++checkExpr :: SpanInfo -> Expression () -> SCM (Expression ())+checkExpr _ (Literal spi a l) = return $ Literal spi a l+checkExpr _ (Variable spi a v) = checkVariable spi a v+checkExpr _ (Constructor spi a c) = checkVariable spi a c+checkExpr p (Paren spi e) = Paren spi <$> checkExpr p e+checkExpr p (Typed spi e ty) = flip (Typed spi) ty <$> checkExpr p e+checkExpr p (Record spi _ c fs) = checkRecordExpr p spi c fs+checkExpr p (RecordUpdate spi e fs) = checkRecordUpdExpr p spi e fs+checkExpr p (Tuple spi es) = Tuple spi <$> mapM (checkExpr p) es+checkExpr p (List spi a es) = List spi a <$> mapM (checkExpr p) es+checkExpr p (ListCompr spi e qs) = withLocalEnv $ flip (ListCompr spi) <$>+ -- Note: must be flipped to insert qs into RenameEnv first+ mapM (checkStatement "list comprehension" p) qs <*> checkExpr p e+checkExpr p (EnumFrom spi e) = EnumFrom spi <$> checkExpr p e+checkExpr p (EnumFromThen spi e1 e2) =+ EnumFromThen spi <$> checkExpr p e1 <*> checkExpr p e2+checkExpr p (EnumFromTo spi e1 e2) =+ EnumFromTo spi <$> checkExpr p e1 <*> checkExpr p e2+checkExpr p (EnumFromThenTo spi e1 e2 e3) =+ EnumFromThenTo spi <$> checkExpr p e1 <*> checkExpr p e2 <*> checkExpr p e3+checkExpr p (UnaryMinus spi e) = UnaryMinus spi <$> checkExpr p e+checkExpr p (Apply spi e1 e2) =+ Apply spi <$> checkExpr p e1 <*> checkExpr p e2+checkExpr p (InfixApply spi e1 op e2) =+ InfixApply spi <$> checkExpr p e1 <*> checkOp op <*> checkExpr p e2+checkExpr p (LeftSection spi e op) =+ LeftSection spi <$> checkExpr p e <*> checkOp op+checkExpr p (RightSection spi op e) =+ RightSection spi <$> checkOp op <*> checkExpr p e+checkExpr p (Lambda spi ts e) = inNestedScope $ checkLambda p spi ts e+checkExpr p (Let spi li ds e) = inNestedScope $+ Let spi li <$> checkDeclGroup bindVarDecl ds <*> checkExpr p e+checkExpr p (Do spi li sts e) = withLocalEnv $+ Do spi li <$> mapM (checkStatement "do sequence" p) sts <*> checkExpr p e+checkExpr p (IfThenElse spi e1 e2 e3) =+ IfThenElse spi <$> checkExpr p e1 <*> checkExpr p e2 <*> checkExpr p e3+checkExpr p (Case spi li ct e alts) =+ Case spi li ct <$> checkExpr p e <*> mapM checkAlt alts++checkLambda :: SpanInfo -> SpanInfo -> [Pattern ()] -> Expression ()+ -> SCM (Expression ())+checkLambda p spi ts e = case findMultiples (bvNoAnon ts) of+ [] -> do+ ts' <- mapM (bindPattern "lambda expression" p) ts+ Lambda spi ts' <$> checkExpr p e+ errVars -> do+ mapM_ (report . errDuplicateVariables) errVars+ let nubTs = nubBy (\t1 t2 -> (not . null) (on intersect bvNoAnon t1 t2)) ts+ mapM_ (bindPattern "lambda expression" p) nubTs+ Lambda spi ts <$> checkExpr p e+ where+ bvNoAnon t = filter (not . isAnonId) $ bv t++checkVariable :: SpanInfo -> a -> QualIdent -> SCM (Expression a)+checkVariable spi a v+ -- anonymous free variable+ | isAnonId (unqualify v) = do+ checkAnonFreeVarsExtension $ getSpanInfo v+ (\n -> Variable spi a $ updQualIdent id (`renameIdent` n) v) <$> newId+ -- return $ Variable v+ -- normal variable+ | otherwise = do+ env <- getRenameEnv+ case qualLookupVar v env of+ [] -> do report $ errUndefinedVariable v+ return $ Variable spi a v+ [Constr _ _] -> return $ Constructor spi a v+ [GlobalVar f _] -> addGlobalDep f >> return (Variable spi a v)+ [LocalVar v' _] -> return $ Variable spi a+ $ qualify+ $ spanInfoLike v' (qidIdent v)+ [RecordLabel _ _] -> return $ Variable spi a v+ rs -> do+ m <- getModuleIdent+ case qualLookupVar (qualQualify m v) env of+ [] -> do report $ errAmbiguousIdent rs v+ return $ Variable spi a v+ [Constr _ _] -> return $ Constructor spi a v+ [GlobalVar f _] -> addGlobalDep f >> return (Variable spi a v)+ [LocalVar v' _] -> return $ Variable spi a+ $ qualify+ $ spanInfoLike v' (qidIdent v)+ [RecordLabel _ _] -> return $ Variable spi a v+ rs' -> do report $ errAmbiguousIdent rs' v+ return $ Variable spi a v++checkRecordExpr :: SpanInfo -> SpanInfo -> QualIdent -> [Field (Expression ())]+ -> SCM (Expression ())+checkRecordExpr _ spi c [] = do+ m <- getModuleIdent+ env <- getRenameEnv+ case qualLookupVar c env of+ [Constr _ _] -> return $ Record spi () c []+ rs -> case qualLookupVar (qualQualify m c) env of+ [Constr _ _] -> return $ Record spi () c []+ rs' -> if null rs && null rs'+ then do report $ errUndefinedData c+ return $ Record spi () c []+ else do report $ errAmbiguousData rs c+ return $ Record spi () c []+checkRecordExpr p spi c fs =+ checkExpr p (RecordUpdate spi (Constructor (getSpanInfo c) () c)+ fs)++checkRecordUpdExpr :: SpanInfo -> SpanInfo -> Expression ()+ -> [Field (Expression ())] -> SCM (Expression ())+checkRecordUpdExpr p spi e fs = do+ e' <- checkExpr p e+ fs' <- mapM (checkField (checkExpr p)) fs+ case e' of+ Constructor _ a c -> do checkFieldLabels "construction" p (Just c) fs'+ return $ Record spi a c fs'+ _ -> do checkFieldLabels "update" p Nothing fs'+ return $ RecordUpdate spi e' fs'++-- * Because patterns or decls eventually introduce new variables, the+-- scope has to be nested one level.+-- * Because statements are processed list-wise, inNestedEnv can not be+-- used as this nesting must be visible to following statements.+checkStatement :: String -> SpanInfo -> Statement () -> SCM (Statement ())+checkStatement _ p (StmtExpr spi e) = StmtExpr spi <$> checkExpr p e+checkStatement s p (StmtBind spi t e) =+ flip (StmtBind spi) <$> checkExpr p e <*> (incNesting >> bindPattern s p t)+checkStatement _ _ (StmtDecl spi li ds) =+ StmtDecl spi li <$> (incNesting >> checkDeclGroup bindVarDecl ds)++bindPattern :: String -> SpanInfo -> Pattern () -> SCM (Pattern ())+bindPattern s p t = do+ t' <- checkPattern p t+ banFPTerm s p t'+ addBoundVariables True t'++banFPTerm :: String -> SpanInfo -> Pattern a -> SCM ()+banFPTerm _ _ (LiteralPattern _ _ _) = ok+banFPTerm _ _ (NegativePattern _ _ _) = ok+banFPTerm _ _ (VariablePattern _ _ _) = ok+banFPTerm s p (ConstructorPattern _ _ _ ts) = mapM_ (banFPTerm s p) ts+banFPTerm s p (InfixPattern _ _ t1 _ t2) = mapM_ (banFPTerm s p) [t1, t2]+banFPTerm s p (ParenPattern _ t) = banFPTerm s p t+banFPTerm s p (RecordPattern _ _ _ fs) = mapM_ banFPTermField fs+ where banFPTermField (Field _ _ x) = banFPTerm s p x+banFPTerm s p (TuplePattern _ ts) = mapM_ (banFPTerm s p) ts+banFPTerm s p (ListPattern _ _ ts) = mapM_ (banFPTerm s p) ts+banFPTerm s p (AsPattern _ _ t) = banFPTerm s p t+banFPTerm s p (LazyPattern _ t) = banFPTerm s p t+banFPTerm s p pat@(FunctionPattern _ _ _ _)+ = report $ errUnsupportedFuncPattern s p pat+banFPTerm s p pat@(InfixFuncPattern _ _ _ _ _)+ = report $ errUnsupportedFuncPattern s p pat++checkOp :: InfixOp a -> SCM (InfixOp a)+checkOp op = do+ env <- getRenameEnv+ case qualLookupVar v env of+ [] -> report (errUndefinedVariable v) >> return op+ [Constr _ _] -> return $ InfixConstr a v+ [GlobalVar f _] -> addGlobalDep f >> return (InfixOp a v)+ [LocalVar v' _] -> return $ InfixOp a $ qualify v'+ rs -> do+ m <- getModuleIdent+ case qualLookupVar (qualQualify m v) env of+ [] -> report (errAmbiguousIdent rs v) >> return op+ [Constr _ _] -> return $ InfixConstr a v+ [GlobalVar f _] -> addGlobalDep f >> return (InfixOp a v)+ [LocalVar v' _] -> return $ InfixOp a $ qualify v'+ rs' -> report (errAmbiguousIdent rs' v) >> return op+ where v = opName op+ a = opAnnotation op++checkAlt :: Alt () -> SCM (Alt ())+checkAlt (Alt spi t rhs) = inNestedScope $+ Alt spi <$> bindPattern "case expression" spi t <*> checkRhs rhs++addBoundVariables :: (QuantExpr t) => Bool -> t -> SCM t+addBoundVariables checkDuplicates ts = do+ when checkDuplicates $ mapM_ (report . errDuplicateVariables)+ (findMultiples bvs)+ modifyRenameEnv $ \ env -> foldr bindVar env (nub bvs)+ return ts+ where bvs = bv ts++-- For record patterns and expressions the compiler checks that all field+-- labels belong to the pattern or expression's constructor. For record+-- update expressions, the compiler checks that there is at least one+-- constructor which has all the specified field labels. In addition, the+-- compiler always checks that no field label occurs twice. Field labels+-- are always looked up in the global environment since they cannot be+-- shadowed by local variables (cf.\ Sect.~3.15.1 of the revised+-- Haskell'98 report~\cite{PeytonJones03:Haskell}).++checkFieldLabels :: String -> SpanInfo -> Maybe QualIdent -> [Field a] -> SCM ()+checkFieldLabels what p c fs = do+ mapM checkFieldLabel ls' >>= checkLabels p c ls'+ onJust (report . errDuplicateLabel what) (findDouble ls)+ where ls = [l | Field _ l _ <- fs]+ ls' = nub ls+ onJust = maybe ok++checkFieldLabel :: QualIdent -> SCM [QualIdent]+checkFieldLabel l = do+ m <- getModuleIdent+ env <- getRenameEnv+ case qualLookupVar l env of+ [RecordLabel _ cs] -> processLabel cs+ rs -> case qualLookupVar (qualQualify m l) env of+ [RecordLabel _ cs] -> processLabel cs+ rs' -> if (null rs && null rs')+ then do report $ errUndefinedLabel l+ return []+ else do report $+ errAmbiguousIdent rs (qualQualify m l)+ return []+ where+ processLabel cs' = do+ when (null cs') $ report $ errUndefinedLabel l+ return cs'++checkLabels :: SpanInfo -> Maybe QualIdent -> [QualIdent] -> [[QualIdent]]+ -> SCM ()+checkLabels _ (Just c) ls css = do+ env <- getRenameEnv+ case qualLookupVar c env of+ [Constr c' _] -> mapM_ (report . errNoLabel c)+ [l | (l, cs) <- zip ls css, c' `notElem` cs]+ _ -> internalError $+ "Checks.SyntaxCheck.checkLabels: " ++ show c+checkLabels p Nothing ls css+ | not (null (foldr1 intersect css)) ||+ any null css = ok+ | otherwise = report $ errNoCommonCons p ls++checkField :: (a -> SCM a) -> Field a -> SCM (Field a)+checkField check (Field p l x) = Field p l <$> check x++-- ---------------------------------------------------------------------------+-- Auxiliary definitions+-- ---------------------------------------------------------------------------++constrs :: Decl a -> [Ident]+constrs (DataDecl _ _ _ cs _) = map constrId cs+constrs (NewtypeDecl _ _ _ nc _) = [nconstrId nc]+constrs _ = []++vars :: Decl a -> [Ident]+vars (TypeSig _ fs _) = fs+vars (FunctionDecl _ _ f _) = [f]+vars (ExternalDecl _ vs) = bv vs+vars (PatternDecl _ t _) = bv t+vars (FreeDecl _ vs) = bv vs+vars _ = []++recLabels :: Decl a -> [Ident]+recLabels (DataDecl _ _ _ cs _) = concatMap recordLabels cs+recLabels (NewtypeDecl _ _ _ nc _) = nrecordLabels nc+recLabels _ = []++-- Since the compiler expects all rules of the same function to be together,+-- it is necessary to sort the list of declarations.++sortFuncDecls :: [Decl a] -> [Decl a]+sortFuncDecls = sortFD Set.empty []+ where+ sortFD _ res [] = reverse res+ sortFD env res (decl : decls') = case decl of+ FunctionDecl _ _ ident _+ | ident `Set.member` env+ -> sortFD env (insertBy cmpFuncDecl decl res) decls'+ | otherwise+ -> sortFD (Set.insert ident env) (decl:res) decls'+ _ -> sortFD env (decl:res) decls'++cmpFuncDecl :: Decl a -> Decl a -> Ordering+cmpFuncDecl (FunctionDecl _ _ id1 _) (FunctionDecl _ _ id2 _)+ | id1 == id2 = EQ+ | otherwise = GT+cmpFuncDecl _ _ = GT++-- Due to the lack of a capitalization convention in Curry, it is+-- possible that an identifier may ambiguously refer to a data+-- constructor and a function provided that both are imported from some+-- other module. When checking whether an identifier denotes a+-- constructor there are two options with regard to ambiguous+-- identifiers:+-- * Handle the identifier as a data constructor if at least one of+-- the imported names is a data constructor.+-- * Handle the identifier as a data constructor only if all imported+-- entities are data constructors.+-- We choose the first possibility here because in the second case a+-- redefinition of a constructor can magically become possible if a+-- function with the same name is imported. It seems better to warn+-- the user about the fact that the identifier is ambiguous.++isDataConstr :: Ident -> RenameEnv -> Bool+isDataConstr v = any isConstr . lookupVar v . globalEnv . toplevelEnv++isConstr :: RenameInfo -> Bool+isConstr (Constr _ _) = True+isConstr (GlobalVar _ _) = False+isConstr (LocalVar _ _) = False+isConstr (RecordLabel _ _) = False++isLabel :: RenameInfo -> Bool+isLabel (Constr _ _) = False+isLabel (GlobalVar _ _) = False+isLabel (LocalVar _ _) = False+isLabel (RecordLabel _ _) = True++-- varIdent :: RenameInfo -> Ident+-- varIdent (GlobalVar _ v) = unqualify v+-- varIdent (LocalVar _ v) = v+-- varIdent _ = internalError "SyntaxCheck.varIdent: no variable"++qualVarIdent :: RenameInfo -> QualIdent+qualVarIdent (GlobalVar v _) = v+qualVarIdent (LocalVar v _) = qualify v+qualVarIdent _ = internalError "SyntaxCheck.qualVarIdent: no variable"++checkFPTerm :: SpanInfo -> Pattern a -> SCM ()+checkFPTerm _ (LiteralPattern _ _ _) = ok+checkFPTerm _ (NegativePattern _ _ _) = ok+checkFPTerm _ (VariablePattern _ _ _) = ok+checkFPTerm p (ConstructorPattern _ _ _ ts) = mapM_ (checkFPTerm p) ts+checkFPTerm p (InfixPattern _ _ t1 _ t2) = mapM_ (checkFPTerm p) [t1, t2]+checkFPTerm p (ParenPattern _ t) = checkFPTerm p t+checkFPTerm p (TuplePattern _ ts) = mapM_ (checkFPTerm p) ts+checkFPTerm p (ListPattern _ _ ts) = mapM_ (checkFPTerm p) ts+checkFPTerm p (AsPattern _ _ t) = checkFPTerm p t+checkFPTerm p t@(LazyPattern _ _) =+ report $ errUnsupportedFPTerm "Lazy" p t+checkFPTerm p (RecordPattern _ _ _ fs) = mapM_ (checkFPTerm p)+ [ t | Field _ _ t <- fs ]+checkFPTerm _ (FunctionPattern _ _ _ _) = ok -- do not check again+checkFPTerm _ (InfixFuncPattern _ _ _ _ _) = ok -- do not check again++-- ---------------------------------------------------------------------------+-- Miscellaneous functions+-- ---------------------------------------------------------------------------++checkFuncPatsExtension :: SpanInfo -> SCM ()+checkFuncPatsExtension spi = checkUsedExtension spi+ "Functional Patterns" FunctionalPatterns++checkAnonFreeVarsExtension :: SpanInfo -> SCM ()+checkAnonFreeVarsExtension spi = checkUsedExtension spi+ "Anonymous free variables" AnonFreeVars++checkUsedExtension :: SpanInfo -> String -> KnownExtension -> SCM ()+checkUsedExtension spi msg ext = do+ enabled <- hasExtension ext+ unless enabled $ do+ report $ errMissingLanguageExtension spi msg ext+ enableExtension ext -- to avoid multiple warnings++typeArity :: TypeExpr -> Int+typeArity (ArrowType _ _ t2) = 1 + typeArity t2+typeArity _ = 0++getFlatLhs :: Equation a -> (Ident, [Pattern a])+getFlatLhs (Equation _ lhs _) = flatLhs lhs++opAnnotation :: InfixOp a -> a+opAnnotation (InfixOp a _) = a+opAnnotation (InfixConstr a _) = a++-- ---------------------------------------------------------------------------+-- Error messages+-- ---------------------------------------------------------------------------++errUnsupportedFPTerm :: String -> SpanInfo -> Pattern a -> Message+errUnsupportedFPTerm s spi pat = spanInfoMessage spi $ text s+ <+> text "patterns are not supported inside a functional pattern."+ $+$ pPrintPrec 0 pat++errUnsupportedFuncPattern :: String -> SpanInfo -> Pattern a -> Message+errUnsupportedFuncPattern s spi pat = spanInfoMessage spi $+ text "Functional patterns are not supported inside a" <+> text s <> dot+ $+$ pPrintPrec 0 pat++errFuncPatNotGlobal :: QualIdent -> Message+errFuncPatNotGlobal f = spanInfoMessage f $ hsep $ map text+ ["Function", escQualName f, "in functional pattern is not global"]++errFuncPatCyclic :: QualIdent -> QualIdent -> Message+errFuncPatCyclic fp f = spanInfoMessage fp $ hsep $ map text+ [ "Function", escName $ unqualify fp, "used in functional pattern depends on"+ , escName $ unqualify f, " causing a cyclic dependency"]++errPrecedenceOutOfRange :: SpanInfo -> Integer -> Message+errPrecedenceOutOfRange spi i = spanInfoMessage spi $ hsep $ map text+ ["Precedence out of range:", show i]++errUndefinedVariable :: QualIdent -> Message+errUndefinedVariable v = spanInfoMessage v $ hsep $ map text+ [escQualName v, "is undefined"]++errUndefinedData :: QualIdent -> Message+errUndefinedData c = spanInfoMessage c $ hsep $ map text+ ["Undefined data constructor", escQualName c]++errUndefinedLabel :: QualIdent -> Message+errUndefinedLabel l = spanInfoMessage l $ hsep $ map text+ ["Undefined record label", escQualName l]++errUndefinedMethod :: QualIdent -> Ident -> Message+errUndefinedMethod qcls f = spanInfoMessage f $ hsep $ map text+ [escName f, "is not a (visible) method of class", escQualName qcls]++errAmbiguousIdent :: [RenameInfo] -> QualIdent -> Message+errAmbiguousIdent rs qn | any isConstr rs = errAmbiguousData rs qn+ | any isLabel rs = errAmbiguousLabel rs qn+ | otherwise = errAmbiguous "variable" rs qn++errAmbiguousData :: [RenameInfo] -> QualIdent -> Message+errAmbiguousData = errAmbiguous "data constructor"++errAmbiguousLabel :: [RenameInfo] -> QualIdent -> Message+errAmbiguousLabel = errAmbiguous "field label"++errAmbiguous :: String -> [RenameInfo] -> QualIdent -> Message+errAmbiguous what rs qn = spanInfoMessage qn+ $ text "Ambiguous" <+> text what <+> text (escQualName qn)+ $+$ text "It could refer to:"+ $+$ nest 2 (vcat (map ppRenameInfo rs))++errDuplicateDefinition :: Ident -> Message+errDuplicateDefinition v = spanInfoMessage v $ hsep $ map text+ ["More than one definition for", escName v]++errDuplicateVariables :: [Ident] -> Message+errDuplicateVariables [] = internalError+ "SyntaxCheck.errDuplicateVariables: empty list"+errDuplicateVariables (v:vs) = spanInfoMessage v $+ text (escName v) <+> text "occurs more than one in pattern at:" $+$+ nest 2 (vcat (map (ppPosition . getPosition) (v:vs)))++errMultipleDataConstructor :: [Ident] -> Message+errMultipleDataConstructor [] = internalError+ "SyntaxCheck.errMultipleDataDeclaration: empty list"+errMultipleDataConstructor (i:is) = spanInfoMessage i $+ text "Multiple definitions for data/record constructor" <+> text (escName i)+ <+> text "at:" $+$+ nest 2 (vcat (map (ppPosition . getPosition) (i:is)))++errMultipleDeclarations :: ModuleIdent -> [Ident] -> Message+errMultipleDeclarations _ [] = internalError+ "SyntaxCheck.errMultipleDeclarations: empty list"+errMultipleDeclarations m (i:is) = spanInfoMessage i $+ text "Multiple declarations of" <+> text (escQualName (qualifyWith m i))+ $+$ text "Declared at:" $+$+ nest 2 (vcat (map (ppPosition . getPosition) (i:is)))++errDuplicateTypeSig :: [Ident] -> Message+errDuplicateTypeSig [] = internalError+ "SyntaxCheck.errDuplicateTypeSig: empty list"+errDuplicateTypeSig (v:vs) = spanInfoMessage v $+ text "More than one type signature for" <+> text (escName v)+ <+> text "at:" $+$+ nest 2 (vcat (map (ppPosition . getPosition) (v:vs)))++errDuplicateLabel :: String -> QualIdent -> Message+errDuplicateLabel what l = spanInfoMessage l $ hsep $ map text+ ["Field label", escQualName l, "occurs more than once in record", what]++errNonVariable :: String -> Ident -> Message+errNonVariable what c = spanInfoMessage c $ hsep $ map text+ ["Data constructor", escName c, "in left hand side of", what]++errNoBody :: Ident -> Message+errNoBody v = spanInfoMessage v $ hsep $ map text ["No body for", escName v]++errNoCommonCons :: SpanInfo -> [QualIdent] -> Message+errNoCommonCons spi ls = spanInfoMessage spi $+ text "No constructor has all of these fields:"+ $+$ nest 2 (vcat (map (text . escQualName) ls))++errNoLabel :: QualIdent -> QualIdent -> Message+errNoLabel c l = spanInfoMessage l $ hsep $ map text+ [escQualName l, "is not a field label of constructor", escQualName c]++errNoTypeSig :: Ident -> Message+errNoTypeSig f = spanInfoMessage f $ hsep $ map text+ ["No type signature for external function", escName f]++errToplevelPattern :: SpanInfo -> Message+errToplevelPattern spi = spanInfoMessage spi $ text+ "Pattern declaration not allowed at top-level"++errDifferentArity :: [Ident] -> Message+errDifferentArity [] = internalError+ "SyntaxCheck.errDifferentArity: empty list"+errDifferentArity (i:is) = spanInfoMessage i $+ text "Equations for" <+> text (escName i) <+> text "have different arities"+ <+> text "at:" $+$+ nest 2 (vcat (map (ppPosition . getPosition) (i:is)))++errWrongArity :: QualIdent -> Int -> Int -> Message+errWrongArity c arity' argc = spanInfoMessage c $ hsep (map text+ ["Data constructor", escQualName c, "expects", arguments arity'])+ <> comma <+> text "but is applied to" <+> text (show argc)+ where arguments 0 = "no arguments"+ arguments 1 = "1 argument"+ arguments n = show n ++ " arguments"++errMissingLanguageExtension :: SpanInfo -> String -> KnownExtension -> Message+errMissingLanguageExtension spi what ext = spanInfoMessage spi $+ text what <+> text "are not supported in standard Curry." $+$+ nest 2 (text "Use flag or -X" <+> text (show ext)+ <+> text "to enable this extension.")++errInfixWithoutParens :: SpanInfo -> [(QualIdent, QualIdent)] -> Message+errInfixWithoutParens spi calls = spanInfoMessage spi $+ text "Missing parens in infix patterns:" $+$+ vcat (map showCall calls)+ where+ showCall (q1, q2) = showWithPos q1 <+> text "calls" <+> showWithPos q2+ showWithPos q = text (qualName q)+ <+> parens (text $ showLine $ getPosition q)
+ src/Checks/TypeCheck.hs view
@@ -0,0 +1,1874 @@+{- |+ Module : $Header$+ Description : Type checking Curry programs+ Copyright : (c) 1999 - 2004 Wolfgang Lux+ Martin Engelke+ 2011 - 2015 Björn Peemöller+ 2014 - 2015 Jan Tikovsky+ 2016 - 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module implements the type checker of the Curry compiler. The+ type checker is invoked after the syntactic correctness of the program+ has been verified and kind checking has been applied to all type+ expressions. Local variables have been renamed already. Thus the+ compiler can maintain a flat type environment. The type checker now+ checks the correct typing of all expressions and also verifies that+ the type signatures given by the user match the inferred types. The+ type checker uses the algorithm by Damas and Milner (1982) for inferring+ the types of unannotated declarations, but allows for polymorphic+ recursion when a type annotation is present.++ The result of type checking is a (flat) top-level environment+ containing the types of all constructors, variables, and functions+ defined at the top level of a module. In addition, a type annotated+ source module is returned. Note that type annotations on the+ left hand side of a declaration hold the function or variable's+ generalized type with the type scheme's universal quantifier left+ implicit. Type annotations on the right hand side of a declaration+ hold the particular instance at which a polymorphic function or+ variable is used.+-}+{-# LANGUAGE CPP #-}+module Checks.TypeCheck (typeCheck) where++#if __GLASGOW_HASKELL__ >= 804+import Prelude hiding ((<>))+#endif++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative ((<$>), (<*>))+#endif+import Control.Monad.Trans (lift)+import Control.Monad.Extra (allM, filterM, foldM, liftM, (&&^),+ notM, replicateM, when, unless, unlessM)+import qualified Control.Monad.State as S+ (State, StateT, get, gets, put, modify,+ runState, evalStateT)+import Data.Function (on)+import Data.List (nub, nubBy, partition, sortBy, (\\))+import qualified Data.Map as Map (Map, empty, insert, lookup)+import Data.Maybe (fromJust, fromMaybe, isJust)+import qualified Data.Set.Extra as Set ( Set, concatMap, deleteMin, empty+ , fromList, insert, member+ , notMember, partition, singleton+ , toList, union, unions )++import Curry.Base.Ident+import Curry.Base.Pretty+import Curry.Base.SpanInfo+import Curry.Syntax+import Curry.Syntax.Pretty++import Base.CurryTypes+import Base.Expr+import Base.Kinds+import Base.Messages (Message, spanInfoMessage, internalError)+import Base.SCC+import Base.TopEnv+import Base.TypeExpansion+import Base.Types+import Base.TypeSubst+import Base.Utils (foldr2, fst3, snd3, thd3, uncurry3, mapAccumM)++import Env.Class+import Env.Instance+import Env.TypeConstructor+import Env.Value++-- Type checking proceeds as follows. First, the types of all data+-- constructors, field labels and class methods are entered into the+-- value environment and then a type inference for all function and+-- value definitions is performed.++typeCheck :: ModuleIdent -> TCEnv -> ValueEnv -> ClassEnv -> InstEnv -> [Decl a]+ -> ([Decl PredType], ValueEnv, [Message])+typeCheck m tcEnv vEnv clsEnv inEnv ds = runTCM (checkDecls ds) initState+ where initState = TcState m tcEnv vEnv clsEnv (inEnv, Map.empty)+ [intType, floatType] idSubst emptySigEnv 1 []++checkDecls :: [Decl a] -> TCM [Decl PredType]+checkDecls ds = do+ bindConstrs+ mapM_ checkFieldLabel (filter isTypeDecl ds) &&> bindLabels+ bindClassMethods+ mapM_ setDefaults $ filter isDefaultDecl ds+ (_, bpds') <- tcPDecls bpds+ tpds' <- mapM tcTopPDecl tpds+ theta <- getTypeSubst+ return $ map (fmap $ subst theta) $ fromPDecls $ tpds' ++ bpds'+ where (bpds, tpds) = partition (isBlockDecl . snd) $ toPDecls ds++-- The type checker makes use of a state monad in order to maintain the value+-- environment, the current substitution, and a counter which is used for+-- generating fresh type variables.++-- Additionally, an extended instance environment is used in order to handle+-- the introduction of local instances when matching a data constructor with a+-- non-empty context. This extended instance environment is composed of the+-- static top-level environment and a dynamic environment that maps each class+-- on the instances which are in scope for it. The rationale behind using this+-- representation is that it makes it easy to apply the current substitution to+-- the dynamic part of the environment.++type TCM = S.State TcState++type InstEnv' = (InstEnv, Map.Map QualIdent [Type])++data TcState = TcState+ { moduleIdent :: ModuleIdent -- read only+ , tyConsEnv :: TCEnv+ , valueEnv :: ValueEnv+ , classEnv :: ClassEnv+ , instEnv :: InstEnv' -- instances (static and dynamic)+ , defaultTypes :: [Type]+ , typeSubst :: TypeSubst+ , sigEnv :: SigEnv+ , nextId :: Int -- automatic counter+ , errors :: [Message]+ }++(&&>) :: TCM () -> TCM () -> TCM ()+pre &&> suf = do+ errs <- pre >> S.gets errors+ when (null errs) suf++(>>-) :: Monad m => m (a, b, c) -> (a -> b -> m a) -> m (a, c)+m >>- f = do+ (u, v, w) <- m+ u' <- f u v+ return (u', w)++(>>=-) :: TCM (a, b, d) -> (b -> TCM c) -> TCM (a, c, d)+m >>=- f = do+ (u, v, x) <- m+ w <- f v+ return (u, w, x)++runTCM :: TCM a -> TcState -> (a, ValueEnv, [Message])+runTCM tcm ts = let (a, s') = S.runState tcm ts+ in (a, typeSubst s' `subst` valueEnv s', reverse $ errors s')++getModuleIdent :: TCM ModuleIdent+getModuleIdent = S.gets moduleIdent++getTyConsEnv :: TCM TCEnv+getTyConsEnv = S.gets tyConsEnv++getValueEnv :: TCM ValueEnv+getValueEnv = S.gets valueEnv++modifyValueEnv :: (ValueEnv -> ValueEnv) -> TCM ()+modifyValueEnv f = S.modify $ \s -> s { valueEnv = f $ valueEnv s }++withLocalValueEnv :: TCM a -> TCM a+withLocalValueEnv act = do+ oldEnv <- getValueEnv+ res <- act+ modifyValueEnv $ const oldEnv+ return res++getClassEnv :: TCM ClassEnv+getClassEnv = S.gets classEnv++getInstEnv :: TCM InstEnv'+getInstEnv = S.gets instEnv++modifyInstEnv :: (InstEnv' -> InstEnv') -> TCM ()+modifyInstEnv f = S.modify $ \s -> s { instEnv = f $ instEnv s }++getDefaultTypes :: TCM [Type]+getDefaultTypes = S.gets defaultTypes++setDefaultTypes :: [Type] -> TCM ()+setDefaultTypes tys = S.modify $ \s -> s { defaultTypes = tys }++getTypeSubst :: TCM TypeSubst+getTypeSubst = S.gets typeSubst++modifyTypeSubst :: (TypeSubst -> TypeSubst) -> TCM ()+modifyTypeSubst f = S.modify $ \s -> s { typeSubst = f $ typeSubst s }++getSigEnv :: TCM SigEnv+getSigEnv = S.gets sigEnv++setSigEnv :: SigEnv -> TCM ()+setSigEnv sigs = S.modify $ \s -> s { sigEnv = sigs }++withLocalSigEnv :: TCM a -> TCM a+withLocalSigEnv act = do+ oldSigs <- getSigEnv+ res <- act+ setSigEnv oldSigs+ return res++getNextId :: TCM Int+getNextId = do+ nid <- S.gets nextId+ S.modify $ \s -> s { nextId = succ nid }+ return nid++report :: Message -> TCM ()+report err = S.modify $ \s -> s { errors = err : errors s }++ok :: TCM ()+ok = return ()++-- Because the type check may mess up the order of the declarations, we+-- associate each declaration with a number. At the end of the type check,+-- we can use these numbers to restore the original declaration order.++type PDecl a = (Int, Decl a)++toPDecls :: [Decl a] -> [PDecl a]+toPDecls = zip [0 ..]++fromPDecls :: [PDecl a] -> [Decl a]+fromPDecls = map snd . sortBy (compare `on` fst)++-- During the type check we also have to convert the type of declarations+-- without annotations which is done by the function 'untyped' below.++untyped :: PDecl a -> PDecl b+untyped = fmap $ fmap $ internalError "TypeCheck.untyped"++-- Defining Data Constructors:+-- In the next step, the types of all data constructors are entered into+-- the value environment using the information entered into the type constructor+-- environment before.++bindConstrs :: TCM ()+bindConstrs = do+ m <- getModuleIdent+ tcEnv <- getTyConsEnv+ modifyValueEnv $ bindConstrs' m tcEnv++bindConstrs' :: ModuleIdent -> TCEnv -> ValueEnv -> ValueEnv+bindConstrs' m tcEnv vEnv = foldr (bindData . snd) vEnv $ localBindings tcEnv+ where+ bindData (DataType tc k cs) vEnv' =+ let n = kindArity k in foldr (bindConstr m n (constrType' tc n)) vEnv' cs+ bindData (RenamingType tc k c) vEnv' =+ let n = kindArity k in bindNewConstr m n (constrType' tc n) c vEnv'+ bindData _ vEnv' = vEnv'++bindConstr :: ModuleIdent -> Int -> Type -> DataConstr -> ValueEnv -> ValueEnv+bindConstr m n ty (DataConstr c tys) =+ bindGlobalInfo (\qc tyScheme -> DataConstructor qc arity ls tyScheme) m c+ (ForAll n (PredType emptyPredSet (foldr TypeArrow ty tys)))+ where arity = length tys+ ls = replicate arity anonId+bindConstr m n ty (RecordConstr c ls tys) =+ bindGlobalInfo (\qc tyScheme -> DataConstructor qc arity ls tyScheme) m c+ (ForAll n (PredType emptyPredSet (foldr TypeArrow ty tys)))+ where arity = length tys++bindNewConstr :: ModuleIdent -> Int -> Type -> DataConstr -> ValueEnv+ -> ValueEnv+bindNewConstr m n cty (DataConstr c [lty]) =+ bindGlobalInfo (\qc tyScheme -> NewtypeConstructor qc anonId tyScheme) m c+ (ForAll n (predType (TypeArrow lty cty)))+bindNewConstr m n cty (RecordConstr c [l] [lty]) =+ bindGlobalInfo (\qc tyScheme -> NewtypeConstructor qc l tyScheme) m c+ (ForAll n (predType (TypeArrow lty cty)))+bindNewConstr _ _ _ _ = internalError+ "TypeCheck.bindConstrs'.bindNewConstr: newtype with illegal constructors"++constrType' :: QualIdent -> Int -> Type+constrType' tc n =+ applyType (TypeConstructor tc) $ map TypeVariable [0 .. n - 1]++-- When a field label occurs in more than one constructor declaration of+-- a data type, the compiler ensures that the label is defined+-- consistently, i.e. both occurrences have the same type. In addition,+-- the compiler ensures that no existentially quantified type variable occurs+-- in the type of a field label because such type variables necessarily escape+-- their scope with the type of the record selection function associated with+-- the field label.++checkFieldLabel :: Decl a -> TCM ()+checkFieldLabel (DataDecl _ _ tvs cs _) = do+ ls' <- mapM (tcFieldLabel tvs) labels+ mapM_ tcFieldLabels (groupLabels ls')+ where labels = [(l, p, ty) | RecordDecl _ _ fs <- cs,+ FieldDecl p ls ty <- fs, l <- ls]+checkFieldLabel (NewtypeDecl _ _ tvs (NewRecordDecl p _ (l, ty)) _) = do+ _ <- tcFieldLabel tvs (l, p, ty)+ ok+checkFieldLabel _ = ok++tcFieldLabel :: HasSpanInfo p => [Ident] -> (Ident, p, TypeExpr)+ -> TCM (Ident, p, Type)+tcFieldLabel tvs (l, p, ty) = do+ m <- getModuleIdent+ tcEnv <- getTyConsEnv+ let ForAll n (PredType _ ty') = polyType $ expandMonoType m tcEnv tvs ty+ unless (n <= length tvs) $ report $ errSkolemFieldLabel p l+ return (l, p, ty')++groupLabels :: Eq a => [(a, b, c)] -> [(a, b, [c])]+groupLabels [] = []+groupLabels ((x, y, z):xyzs) =+ (x, y, z : map thd3 xyzs') : groupLabels xyzs''+ where (xyzs', xyzs'') = partition ((x ==) . fst3) xyzs++tcFieldLabels :: HasSpanInfo p => (Ident, p, [Type]) -> TCM ()+tcFieldLabels (_, _, []) = return ()+tcFieldLabels (l, p, ty:tys) = unless (not (any (ty /=) tys)) $ do+ m <- getModuleIdent+ report $ errIncompatibleLabelTypes p m l ty (head tys)++-- Defining Field Labels:+-- Next the types of all field labels are added to the value environment.++bindLabels :: TCM ()+bindLabels = do+ m <- getModuleIdent+ tcEnv <- getTyConsEnv+ modifyValueEnv $ bindLabels' m tcEnv++bindLabels' :: ModuleIdent -> TCEnv -> ValueEnv -> ValueEnv+bindLabels' m tcEnv vEnv = foldr (bindData . snd) vEnv $ localBindings tcEnv+ where+ bindData (DataType tc k cs) vEnv' =+ foldr (bindLabel m n (constrType' tc n)) vEnv' $ nubBy sameLabel clabels+ where+ n = kindArity k+ labels = zip (concatMap recLabels cs) (concatMap recLabelTypes cs)+ clabels = [(l, constr l, ty) | (l, ty) <- labels]+ constr l = [qualifyLike tc (constrIdent c)+ | c <- cs, l `elem` recLabels c]+ sameLabel (l1, _, _) (l2, _, _) = l1 == l2+ bindData (RenamingType tc k (RecordConstr c [l] [lty])) vEnv'+ = bindLabel m n (constrType' tc n) (l, [qc], lty) vEnv'+ where+ n = kindArity k+ qc = qualifyLike tc c+ bindData (RenamingType _ _ (RecordConstr _ _ _)) _ =+ internalError $ "Checks.TypeCheck.bindLabels'.bindData: " +++ "RenamingType with more than one record label"+ bindData _ vEnv' = vEnv'++bindLabel :: ModuleIdent -> Int -> Type -> (Ident, [QualIdent], Type)+ -> ValueEnv -> ValueEnv+bindLabel m n ty (l, lcs, lty) =+ bindGlobalInfo (\qc tyScheme -> Label qc lcs tyScheme) m l+ (ForAll n (predType (TypeArrow ty lty)))++-- Defining class methods:+-- Last, the types of all class methods are added to the value environment.++bindClassMethods :: TCM ()+bindClassMethods = do+ m <- getModuleIdent+ tcEnv <- getTyConsEnv+ modifyValueEnv $ bindClassMethods' m tcEnv++bindClassMethods' :: ModuleIdent -> TCEnv -> ValueEnv -> ValueEnv+bindClassMethods' m tcEnv vEnv =+ foldr (bindMethods . snd) vEnv $ localBindings tcEnv+ where+ bindMethods (TypeClass cls _ ms) vEnv' =+ foldr (bindClassMethod m cls) vEnv' ms+ bindMethods _ vEnv' =+ vEnv'++-- Since the implementations of class methods can differ in their arity,+-- we assume an arity of 0 when we enter one into the value environment.++bindClassMethod :: ModuleIdent -> QualIdent -> ClassMethod -> ValueEnv+ -> ValueEnv+bindClassMethod m cls (ClassMethod f _ ty) =+ bindGlobalInfo (\qc tySc -> Value qc (Just cls) 0 tySc) m f (typeScheme ty)++-- -----------------------------------------------------------------------------+-- Default Types+-- -----------------------------------------------------------------------------++-- Default Types:+-- The list of default types is given either by a default declaration in+-- the source code or defaults to the predefined list of numeric data types.++setDefaults :: Decl a -> TCM ()+setDefaults (DefaultDecl _ tys) = mapM toDefaultType tys >>= setDefaultTypes+ where+ toDefaultType =+ liftM snd . (inst =<<) . liftM typeScheme+ . expandPoly . QualTypeExpr NoSpanInfo []+setDefaults _ = ok++-- Type Signatures:+-- The type checker collects type signatures in a flat environment.+-- The types are not expanded so that the signature is available for+-- use in the error message that is printed when the inferred type is+-- less general than the signature.++type SigEnv = Map.Map Ident QualTypeExpr++emptySigEnv :: SigEnv+emptySigEnv = Map.empty++bindTypeSig :: Ident -> QualTypeExpr -> SigEnv -> SigEnv+bindTypeSig = Map.insert++bindTypeSigs :: Decl a -> SigEnv -> SigEnv+bindTypeSigs (TypeSig _ vs ty) env = foldr (`bindTypeSig` ty) env vs+bindTypeSigs _ env = env++lookupTypeSig :: Ident -> SigEnv -> Maybe QualTypeExpr+lookupTypeSig = Map.lookup++-- Declaration groups:+-- Before type checking a group of declarations, a dependency analysis is+-- performed and the declaration group is eventually transformed into nested+-- declaration groups which are checked separately. Within each declaration+-- group, first the value environment is extended with new bindings for all+-- variables and functions defined in the group. Next, types are inferred for+-- all declarations without an explicit type signature and the inferred types+-- are then generalized. Finally, the types of all explicitly typed declarations+-- are checked.++-- Within a group of mutually recursive declarations, all type variables that+-- appear in the types of the variables defined in the group and whose type+-- cannot be generalized must not be generalized in the other declarations of+-- that group as well.++tcDecls :: [Decl a] -> TCM (PredSet, [Decl PredType])+tcDecls = fmap (fmap fromPDecls) . tcPDecls . toPDecls++tcPDecls :: [PDecl a] -> TCM (PredSet, [PDecl PredType])+tcPDecls pds = withLocalSigEnv $ do+ let (vpds, opds) = partition (isValueDecl . snd) pds+ setSigEnv $ foldr (bindTypeSigs . snd) emptySigEnv $ opds+ m <- getModuleIdent+ (ps, vpdss') <-+ mapAccumM tcPDeclGroup emptyPredSet $ scc (bv . snd) (qfv m . snd) vpds+ return (ps, map untyped opds ++ concat (vpdss' :: [[PDecl PredType]]))++tcPDeclGroup :: PredSet -> [PDecl a] -> TCM (PredSet, [PDecl PredType])+tcPDeclGroup ps [(i, ExternalDecl p fs)] = do+ tys <- mapM (tcExternal . varIdent) fs+ return (ps, [(i, ExternalDecl p (zipWith (fmap . const . predType) tys fs))])+tcPDeclGroup ps [(i, FreeDecl p fvs)] = do+ vs <- mapM (tcDeclVar False) (bv fvs)+ m <- getModuleIdent+ (vs', ps') <- unzip <$> mapM addDataPred vs+ modifyValueEnv $ flip (bindVars m) vs'+ let d = FreeDecl p (map (\(v, _, ForAll _ ty) -> Var ty v) vs')+ return (ps `Set.union` Set.unions ps', [(i, d)])+ where+ addDataPred (idt, n, ForAll ids ty1) = do+ (ps2, ty2) <- freshDataType+ ps' <- unify idt "free variable" (ppIdent idt) emptyPredSet (unpredType ty1) ps2 ty2+ return ((idt, n, ForAll ids ty1), ps')+tcPDeclGroup ps pds = do+ vEnv <- getValueEnv+ vss <- mapM (tcDeclVars . snd) pds+ m <- getModuleIdent+ modifyValueEnv $ flip (bindVars m) $ concat vss+ sigs <- getSigEnv+ let (impPds, expPds) = partitionPDecls sigs pds+ (ps', impPds') <- mapAccumM tcPDecl ps impPds+ theta <- getTypeSubst+ tvs <- concatMap (typeVars . subst theta . fst) <$>+ filterM (notM . isNonExpansive . snd . snd) impPds'+ let fvs = foldr Set.insert (fvEnv (subst theta vEnv)) tvs+ (gps, lps) = splitPredSet fvs ps'+ lps' <- foldM (uncurry . defaultPDecl fvs) lps impPds'+ theta' <- getTypeSubst+ let impPds'' = map (uncurry (fixType . gen fvs lps' . subst theta')) impPds'+ modifyValueEnv $ flip (rebindVars m) (concatMap (declVars . snd) impPds'')+ (ps'', expPds') <- mapAccumM (uncurry . tcCheckPDecl) gps expPds+ return (ps'', impPds'' ++ expPds')++partitionPDecls :: SigEnv -> [PDecl a] -> ([PDecl a], [(QualTypeExpr, PDecl a)])+partitionPDecls sigs =+ foldr (\pd -> maybe (implicit pd) (explicit pd) (typeSig $ snd pd)) ([], [])+ where implicit pd ~(impPds, expPds) = (pd : impPds, expPds)+ explicit pd qty ~(impPds, expPds) = (impPds, (qty, pd) : expPds)+ typeSig (FunctionDecl _ _ f _) = lookupTypeSig f sigs+ typeSig (PatternDecl _ (VariablePattern _ _ v) _) = lookupTypeSig v sigs+ typeSig _ = Nothing++bindVars :: ModuleIdent -> ValueEnv -> [(Ident, Int, TypeScheme)] -> ValueEnv+bindVars m = foldr $ uncurry3 $ flip (bindFun m) Nothing++rebindVars :: ModuleIdent -> ValueEnv -> [(Ident, Int, TypeScheme)] -> ValueEnv+rebindVars m = foldr $ uncurry3 $ flip (rebindFun m) Nothing++tcDeclVars :: Decl a -> TCM [(Ident, Int, TypeScheme)]+tcDeclVars (FunctionDecl _ _ f eqs) = do+ sigs <- getSigEnv+ let n = eqnArity $ head eqs+ case lookupTypeSig f sigs of+ Just qty -> do+ pty <- expandPoly qty+ return [(f, n, typeScheme pty)]+ Nothing -> do+ tys <- replicateM (n + 1) freshTypeVar+ return [(f, n, monoType $ foldr1 TypeArrow tys)]+tcDeclVars (PatternDecl _ t _) = case t of+ VariablePattern _ _ v -> return <$> tcDeclVar True v+ _ -> mapM (tcDeclVar False) (bv t)+tcDeclVars _ = internalError "TypeCheck.tcDeclVars"++tcDeclVar :: Bool -> Ident -> TCM (Ident, Int, TypeScheme)+tcDeclVar poly v = do+ sigs <- getSigEnv+ case lookupTypeSig v sigs of+ Just qty+ | poly || null (fv qty) -> do+ pty <- expandPoly qty+ return (v, 0, typeScheme pty)+ | otherwise -> do+ report $ errPolymorphicVar v+ lambdaVar v+ Nothing -> lambdaVar v++tcPDecl :: PredSet -> PDecl a -> TCM (PredSet, (Type, PDecl PredType))+tcPDecl ps (i, FunctionDecl p _ f eqs) = do+ vEnv <- getValueEnv+ tcFunctionPDecl i ps (varType f vEnv) p f eqs+tcPDecl ps (i, d@(PatternDecl p t rhs)) = do+ (ps', ty', t') <- tcPattern p t+ (ps'', rhs') <- tcRhs rhs >>-+ unifyDecl p "pattern declaration" (pPrint d) (ps `Set.union` ps') ty'+ return (ps'', (ty', (i, PatternDecl p t' rhs')))+tcPDecl _ _ = internalError "TypeCheck.tcPDecl"++-- The function 'tcFunctionPDecl' ignores the context of a function's type+-- signature. This prevents missing instance errors when the inferred type+-- of a function is less general than the declared type.++tcFunctionPDecl :: Int -> PredSet -> TypeScheme -> SpanInfo -> Ident+ -> [Equation a] -> TCM (PredSet, (Type, PDecl PredType))+tcFunctionPDecl i ps tySc@(ForAll _ pty) p f eqs = do+ (_, ty) <- inst tySc+ (ps', eqs') <- mapAccumM (tcEquation ty) ps eqs+ return (ps', (ty, (i, FunctionDecl p pty f eqs')))++tcEquation :: Type -> PredSet -> Equation a+ -> TCM (PredSet, Equation PredType)+tcEquation ty ps eqn@(Equation p lhs rhs) =+ tcEqn p lhs rhs >>- unifyDecl p "equation" (pPrint eqn) ps ty++tcEqn :: SpanInfo -> Lhs a -> Rhs a+ -> TCM (PredSet, Type, Equation PredType)+tcEqn p lhs rhs = do+ (ps, tys, lhs', ps', ty, rhs') <- withLocalValueEnv $ do+ bindLambdaVars lhs+ (ps, tys, lhs') <- S.evalStateT (tcLhs p lhs) Set.empty+ (ps', ty, rhs') <- tcRhs rhs+ return (ps, tys, lhs', ps', ty, rhs')+ ps'' <- reducePredSet p "equation" (pPrint (Equation p lhs' rhs'))+ (ps `Set.union` ps')+ return (ps'', foldr TypeArrow ty tys, Equation p lhs' rhs')++bindLambdaVars :: QuantExpr t => t -> TCM ()+bindLambdaVars t = do+ m <- getModuleIdent+ vs <- mapM lambdaVar (nub $ bv t)+ modifyValueEnv $ flip (bindVars m) vs++lambdaVar :: Ident -> TCM (Ident, Int, TypeScheme)+lambdaVar v = do+ ty <- freshTypeVar+ return (v, 0, monoType ty)++unifyDecl :: HasSpanInfo p => p -> String -> Doc -> PredSet -> Type -> PredSet+ -> Type+ -> TCM PredSet+unifyDecl p what doc psLhs tyLhs psRhs tyRhs = do+ ps <- unify p what doc psLhs tyLhs psRhs tyRhs+ fvs <- computeFvEnv+ applyDefaultsDecl p what doc fvs ps tyLhs++-- After inferring types for a group of mutually recursive declarations+-- and computing the set of its constrained type variables, the compiler+-- has to be prepared for some of the constrained type variables to not+-- appear in some of the inferred types, i.e., there may be ambiguous+-- types that have not been reported by 'unifyDecl' above at the level+-- of individual function equations and pattern declarations.++defaultPDecl :: Set.Set Int -> PredSet -> Type -> PDecl a -> TCM PredSet+defaultPDecl fvs ps ty (_, FunctionDecl p _ f _) =+ applyDefaultsDecl p ("function " ++ escName f) empty fvs ps ty+defaultPDecl fvs ps ty (_, PatternDecl p t _) = case t of+ VariablePattern _ _ v ->+ applyDefaultsDecl p ("variable " ++ escName v) empty fvs ps ty+ _ -> return ps+defaultPDecl _ _ _ _ = internalError "TypeCheck.defaultPDecl"++applyDefaultsDecl :: HasSpanInfo p => p -> String -> Doc -> Set.Set Int+ -> PredSet -> Type -> TCM PredSet+applyDefaultsDecl p what doc fvs ps ty = do+ theta <- getTypeSubst+ let ty' = subst theta ty+ fvs' = foldr Set.insert fvs $ typeVars ty'+ applyDefaults p what doc fvs' ps ty'++-- After 'tcDeclGroup' has generalized the types of the implicitly+-- typed declarations of a declaration group it must update their left+-- hand side type annotations and the type environment accordingly.+-- Recall that the compiler generalizes only the types of variable and+-- function declarations.++fixType :: TypeScheme -> PDecl PredType -> PDecl PredType+fixType ~(ForAll _ pty) (i, FunctionDecl p _ f eqs) =+ (i, FunctionDecl p pty f eqs)+fixType ~(ForAll _ pty) pd@(i, PatternDecl p t rhs) = case t of+ VariablePattern spi _ v+ -> (i, PatternDecl p (VariablePattern spi pty v) rhs)+ _ -> pd+fixType _ _ = internalError "TypeCheck.fixType"++declVars :: Decl PredType -> [(Ident, Int, TypeScheme)]+declVars (FunctionDecl _ pty f eqs) = [(f, eqnArity $ head eqs, typeScheme pty)]+declVars (PatternDecl _ t _) = case t of+ VariablePattern _ pty v -> [(v, 0, typeScheme pty)]+ _ -> []+declVars _ = internalError "TypeCheck.declVars"++-- The function 'tcCheckPDecl' checks the type of an explicitly typed function+-- or variable declaration. After inferring a type for the declaration, the+-- inferred type is compared with the type signature. Since the inferred type+-- of an explicitly typed function or variable declaration is automatically an+-- instance of its type signature, the type signature is correct only if the+-- inferred type matches the type signature exactly except for the inferred+-- predicate set, which may contain only a subset of the declared context+-- because the context of a function's type signature is ignored in the+-- function 'tcFunctionPDecl' above.++tcCheckPDecl :: PredSet -> QualTypeExpr -> PDecl a+ -> TCM (PredSet, PDecl PredType)+tcCheckPDecl ps qty pd = do+ (ps', (ty, pd')) <- tcPDecl ps pd+ fvs <- computeFvEnv+ theta <- getTypeSubst+ poly <- isNonExpansive $ snd pd+ let (gps, lps) = splitPredSet fvs ps'+ ty' = subst theta ty+ tySc = if poly then gen fvs lps ty' else monoType ty'+ checkPDeclType qty gps tySc pd'++checkPDeclType :: QualTypeExpr -> PredSet -> TypeScheme -> PDecl PredType+ -> TCM (PredSet, PDecl PredType)+checkPDeclType qty ps tySc (i, FunctionDecl p _ f eqs) = do+ pty <- expandPoly qty+ unlessM (checkTypeSig pty tySc) $ do+ m <- getModuleIdent+ report $ errTypeSigTooGeneral m (text "Function:" <+> ppIdent f) qty tySc+ return (ps, (i, FunctionDecl p pty f eqs))+checkPDeclType qty ps tySc (i, PatternDecl p (VariablePattern spi _ v) rhs) = do+ pty <- expandPoly qty+ unlessM (checkTypeSig pty tySc) $ do+ m <- getModuleIdent+ report $ errTypeSigTooGeneral m (text "Variable:" <+> ppIdent v) qty tySc+ return (ps, (i, PatternDecl p (VariablePattern spi pty v) rhs))+checkPDeclType _ _ _ _ = internalError "TypeCheck.checkPDeclType"++checkTypeSig :: PredType -> TypeScheme -> TCM Bool+checkTypeSig (PredType sigPs sigTy) (ForAll _ (PredType ps ty)) = do+ clsEnv <- getClassEnv+ return $+ ty `eqTypes` sigTy &&+ all (`Set.member` maxPredSet clsEnv sigPs) (Set.toList ps)++-- The function 'equTypes' computes whether two types are equal modulo+-- renaming of type variables.+-- WARNING: This operation is not reflexive and expects the second type to be+-- the type signature provided by the programmer.+eqTypes :: Type -> Type -> Bool+eqTypes t1 t2 = fst (eq [] t1 t2)+ where+ -- @is@ is an AssocList of type variable indices+ eq is (TypeConstructor qid1) (TypeConstructor qid2) = (qid1 == qid2, is)+ eq is (TypeVariable i1) (TypeVariable i2)+ | i1 < 0 = (False, is)+ | otherwise = eqVar is i1 i2+ eq is (TypeConstrained ts1 i1) (TypeConstrained ts2 i2)+ = let (res1, is1) = eqs is ts1 ts2+ (res2, is2) = eqVar is1 i1 i2+ in (res1 && res2, is2)+ eq is (TypeApply ta1 tb1) (TypeApply ta2 tb2)+ = let (res1, is1) = eq is ta1 ta2+ (res2, is2) = eq is1 tb1 tb2+ in (res1 && res2, is2)+ eq is (TypeArrow tf1 tt1) (TypeArrow tf2 tt2)+ = let (res1, is1) = eq is tf1 tf2+ (res2, is2) = eq is1 tt1 tt2+ in (res1 && res2, is2)+ eq is (TypeForall is1 t1') (TypeForall is2 t2')+ = let (res1, is') = eqs [] (map TypeVariable is1) (map TypeVariable is2)+ (res2, _ ) = eq is' t1' t2'+ in (res1 && res2, is)+ eq is _ _ = (False, is)++ eqVar is i1 i2 = case lookup i1 is of+ Nothing -> (True, (i1, i2) : is)+ Just i2' -> (i2 == i2', is)++ eqs is [] [] = (True , is)+ eqs is (t1':ts1) (t2':ts2)+ = let (res1, is1) = eq is t1' t2'+ (res2, is2) = eqs is1 ts1 ts2+ in (res1 && res2, is2)+ eqs is _ _ = (False, is)++-- In Curry, a non-expansive expression is either+--+-- * a literal,+-- * a variable,+-- * an application of a constructor with arity n to at most n+-- non-expansive expressions,+-- * an application of a function with arity n to at most n-1+-- non-expansive expressions, or+-- * a let expression whose body is a non-expansive expression and+-- whose local declarations are either function declarations or+-- variable declarations of the form x=e where e is a non-expansive+-- expression, or+-- * an expression whose desugared form is one of the above.+--+-- At first it may seem strange that variables are included in the list+-- above because a variable may be bound to a logical variable. However,+-- this is no problem because type variables that are present among the+-- typing assumptions of the environment enclosing a let expression+-- cannot be generalized.++class Binding a where+ isNonExpansive :: a -> TCM Bool++instance Binding a => Binding [a] where+ isNonExpansive = allM isNonExpansive++instance Binding (Decl a) where+ isNonExpansive (InfixDecl _ _ _ _) = return True+ isNonExpansive (TypeSig _ _ _) = return True+ isNonExpansive (FunctionDecl _ _ _ _) = return True+ isNonExpansive (ExternalDecl _ _) = return True+ isNonExpansive (PatternDecl _ _ _) = return False+ -- TODO: Uncomment when polymorphic let declarations are fully supported+ {-isNonExpansive (PatternDecl _ t rhs) = case t of+ VariablePattern _ _ -> isNonExpansive rhs+ _ -> return False-}+ isNonExpansive (FreeDecl _ _) = return False+ isNonExpansive _ =+ internalError "TypeCheck.isNonExpansive: declaration"++instance Binding (Rhs a) where+ isNonExpansive (GuardedRhs _ _ _ _) = return False+ isNonExpansive (SimpleRhs _ _ e ds) = withLocalValueEnv $ do+ m <- getModuleIdent+ tcEnv <- getTyConsEnv+ clsEnv <- getClassEnv+ sigs <- getSigEnv+ modifyValueEnv $ flip (foldr (bindDeclArity m tcEnv clsEnv sigs)) ds+ isNonExpansive e &&^ isNonExpansive ds++-- A record construction is non-expansive only if all field labels are present.++instance Binding (Expression a) where+ isNonExpansive = isNonExpansive' 0++isNonExpansive' :: Int -> Expression a -> TCM Bool+isNonExpansive' _ (Literal _ _ _) = return True+isNonExpansive' n (Variable _ _ v)+ | v' == anonId = return False+ | isRenamed v' = do+ vEnv <- getValueEnv+ return $ n == 0 || n < varArity v vEnv+ | otherwise = do+ vEnv <- getValueEnv+ return $ n < varArity v vEnv+ where v' = unqualify v+isNonExpansive' _ (Constructor _ _ _) = return True+isNonExpansive' n (Paren _ e) = isNonExpansive' n e+isNonExpansive' n (Typed _ e _) = isNonExpansive' n e+isNonExpansive' _ (Record _ _ c fs) = do+ m <- getModuleIdent+ vEnv <- getValueEnv+ fmap ((length (constrLabels m c vEnv) == length fs) &&) (isNonExpansive fs)+isNonExpansive' _ (Tuple _ es) = isNonExpansive es+isNonExpansive' _ (List _ _ es) = isNonExpansive es+isNonExpansive' n (Apply _ f e) = isNonExpansive' (n + 1) f+ &&^ isNonExpansive e+isNonExpansive' n (InfixApply _ e1 op e2)+ = isNonExpansive' (n + 2) (infixOp op) &&^ isNonExpansive e1+ &&^ isNonExpansive e2+isNonExpansive' n (LeftSection _ e op) = isNonExpansive' (n + 1) (infixOp op)+ &&^ isNonExpansive e+isNonExpansive' n (Lambda _ ts e) = withLocalValueEnv $ do+ modifyValueEnv $ flip (foldr bindVarArity) (bv ts)+ fmap (((n < length ts) ||) . (all isVariablePattern ts &&))+ (isNonExpansive' (n - length ts) e)+isNonExpansive' n (Let _ _ ds e) = withLocalValueEnv $ do+ m <- getModuleIdent+ tcEnv <- getTyConsEnv+ clsEnv <- getClassEnv+ sigs <- getSigEnv+ modifyValueEnv $ flip (foldr (bindDeclArity m tcEnv clsEnv sigs)) ds+ isNonExpansive ds &&^ isNonExpansive' n e+isNonExpansive' _ _ = return False++instance Binding a => Binding (Field a) where+ isNonExpansive (Field _ _ e) = isNonExpansive e++bindDeclArity :: ModuleIdent -> TCEnv -> ClassEnv -> SigEnv -> Decl a+ -> ValueEnv -> ValueEnv+bindDeclArity _ _ _ _ (InfixDecl _ _ _ _) = id+bindDeclArity _ _ _ _ (TypeSig _ _ _) = id+bindDeclArity _ _ _ _ (FunctionDecl _ _ f eqs) =+ bindArity f (eqnArity $ head eqs)+bindDeclArity m tcEnv clsEnv sigs (ExternalDecl _ fs) =+ flip (foldr $ \(Var _ f) -> bindArity f $ arrowArity $ ty f) fs+ where ty = unpredType . expandPolyType m tcEnv clsEnv . fromJust .+ flip lookupTypeSig sigs+bindDeclArity _ _ _ _ (PatternDecl _ t _) =+ flip (foldr bindVarArity) (bv t)+bindDeclArity _ _ _ _ (FreeDecl _ vs) =+ flip (foldr bindVarArity) (bv vs)+bindDeclArity _ _ _ _ _ =+ internalError "TypeCheck.bindDeclArity"++bindVarArity :: Ident -> ValueEnv -> ValueEnv+bindVarArity v = bindArity v 0++bindArity :: Ident -> Int -> ValueEnv -> ValueEnv+bindArity v n = bindTopEnv v (Value (qualify v) Nothing n undefined)++-- Class and instance declarations:+-- When checking method implementations in class and instance+-- declarations, the compiler must check that the inferred type matches+-- the method's declared type. This is straight forward in class+-- declarations (the only difference with respect to an overloaded+-- function with an explicit type signature is that a class method's type+-- signature is composed of its declared type signature and the context+-- from the class declaration), but a little bit more complicated for+-- instance declarations because the instance type must be substituted+-- for the type variable used in the type class declaration.+--+-- When checking inferred method types against their expected types, we have to+-- be careful because the class' type variable is always assigned index 0 in+-- the method types recorded in the value environment. However, in the inferred+-- type scheme returned from 'tcMethodDecl', type variables are assigned+-- indices in the order of their occurrence. In order to avoid incorrectly+-- reporting errors when the type class variable is not the first variable that+-- appears in a method's type, 'tcInstanceMethodPDecl' normalizes the expected+-- method type before applying 'checkInstMethodType' to it. Unfortunately, this+-- means that the compiler has to add the class constraint explicitly to the+-- type signature.++tcTopPDecl :: PDecl a -> TCM (PDecl PredType)+tcTopPDecl (i, DataDecl p tc tvs cs clss)+ = return (i, DataDecl p tc tvs cs clss)+tcTopPDecl (i, ExternalDataDecl p tc tvs)+ = return (i, ExternalDataDecl p tc tvs)+tcTopPDecl (i, NewtypeDecl p tc tvs nc clss)+ = return (i, NewtypeDecl p tc tvs nc clss)+tcTopPDecl (i, TypeDecl p tc tvs ty)+ = return (i, TypeDecl p tc tvs ty)+tcTopPDecl (i, DefaultDecl p tys)+ = return (i, DefaultDecl p tys)+tcTopPDecl (i, ClassDecl p li cx cls tv ds) = withLocalSigEnv $ do+ let (vpds, opds) = partition (isValueDecl . snd) $ toPDecls ds+ setSigEnv $ foldr (bindTypeSigs . snd) emptySigEnv opds+ vpds' <- mapM (tcClassMethodPDecl (qualify cls) tv) vpds+ return (i, ClassDecl p li cx cls tv $ fromPDecls $ map untyped opds ++ vpds')+tcTopPDecl (i, InstanceDecl p li cx qcls ty ds) = do+ tcEnv <- getTyConsEnv+ pty <- expandPoly $ QualTypeExpr NoSpanInfo cx ty+ mid <- getModuleIdent+ let origCls = getOrigName mid qcls tcEnv+ clsQual = head $ filter isQualified $ reverseLookupByOrigName origCls tcEnv+ qQualCls = qualQualify (fromJust $ qidModule clsQual) qcls+ vpds' <- mapM (tcInstanceMethodPDecl qQualCls pty) vpds+ return (i,InstanceDecl p li cx qcls ty $ fromPDecls $ map untyped opds++vpds')+ where (vpds, opds) = partition (isValueDecl . snd) $ toPDecls ds+tcTopPDecl _ = internalError "TypeCheck.tcTopDecl"++tcClassMethodPDecl :: QualIdent -> Ident -> PDecl a -> TCM (PDecl PredType)+tcClassMethodPDecl qcls tv pd@(_, FunctionDecl _ _ f _) = do+ methTy <- classMethodType qualify f+ (tySc, pd') <- tcMethodPDecl qcls methTy pd+ sigs <- getSigEnv+ let QualTypeExpr spi cx ty = fromJust $ lookupTypeSig f sigs+ qty = QualTypeExpr spi+ (Constraint NoSpanInfo qcls (VariableType NoSpanInfo tv) : cx) ty+ checkClassMethodType qty tySc pd'+tcClassMethodPDecl _ _ _ = internalError "TypeCheck.tcClassMethodPDecl"++tcInstanceMethodPDecl :: QualIdent -> PredType -> PDecl a+ -> TCM (PDecl PredType)+tcInstanceMethodPDecl qcls pty pd@(_, FunctionDecl _ _ f _) = do+ methTy <- instMethodType (qualifyLike qcls) pty f+ (tySc, pd') <- tcMethodPDecl qcls (typeScheme methTy) pd+ checkInstMethodType (normalize 0 methTy) tySc pd'+tcInstanceMethodPDecl _ _ _ = internalError "TypeCheck.tcInstanceMethodPDecl"++tcMethodPDecl :: QualIdent -> TypeScheme -> PDecl a -> TCM (TypeScheme, PDecl PredType)+tcMethodPDecl qcls tySc (i, FunctionDecl p _ f eqs) = withLocalValueEnv $ do+ m <- getModuleIdent+ modifyValueEnv $ bindFun m f (Just qcls) (eqnArity $ head eqs) tySc+ (ps, (ty, pd)) <- tcFunctionPDecl i emptyPredSet tySc p f eqs+ theta <- getTypeSubst+ return (gen Set.empty ps $ subst theta ty, pd)+tcMethodPDecl _ _ _ = internalError "TypeCheck.tcMethodPDecl"++checkClassMethodType :: QualTypeExpr -> TypeScheme -> PDecl PredType+ -> TCM (PDecl PredType)+checkClassMethodType qty tySc pd@(_, FunctionDecl _ _ f _) = do+ pty <- expandPoly qty+ unlessM (checkTypeSig pty tySc) $ do+ m <- getModuleIdent+ report $ errTypeSigTooGeneral m (text "Method:" <+> ppIdent f) qty tySc+ return pd+checkClassMethodType _ _ _ = internalError "TypeCheck.checkClassMethodType"++checkInstMethodType :: PredType -> TypeScheme -> PDecl PredType+ -> TCM (PDecl PredType)+checkInstMethodType pty tySc pd@(_, FunctionDecl _ _ f _) = do+ unlessM (checkTypeSig pty tySc) $ do+ m <- getModuleIdent+ report $+ errMethodTypeTooSpecific f m (text "Method:" <+> ppIdent f) pty tySc+ return pd+checkInstMethodType _ _ _ = internalError "TypeCheck.checkInstMethodType"++classMethodType :: (Ident -> QualIdent) -> Ident -> TCM TypeScheme+classMethodType qual f = do+ m <- getModuleIdent+ vEnv <- getValueEnv+ return $ funType m (qual $ unRenameIdent f) vEnv++-- Due to the sorting of the predicate set, we can simply remove the minimum+-- element as this is guaranteed to be the class constraint (see module 'Types'+-- for more information).++instMethodType :: (Ident -> QualIdent) -> PredType -> Ident -> TCM PredType+instMethodType qual (PredType ps ty) f = do+ ForAll _ (PredType ps' ty') <- classMethodType qual f+ let PredType ps'' ty'' = instanceType ty (PredType (Set.deleteMin ps') ty')+ return $ PredType (ps `Set.union` ps'') ty''++-- External functions:++tcExternal :: Ident -> TCM Type+tcExternal f = do+ sigs <- getSigEnv+ case lookupTypeSig f sigs of+ Nothing -> internalError "TypeCheck.tcExternal: type signature not found"+ Just (QualTypeExpr _ _ ty) -> do+ m <- getModuleIdent+ PredType _ ty' <- expandPoly $ QualTypeExpr NoSpanInfo [] ty+ modifyValueEnv $ bindFun m f Nothing (arrowArity ty') (polyType ty')+ return ty'++-- Patterns and Expressions:+-- Note that the type attribute associated with a constructor or infix+-- pattern is the type of the whole pattern and not the type of the+-- constructor itself. Overloaded (numeric) literals are not supported in+-- patterns.++tcLiteral :: Bool -> Literal -> TCM (PredSet, Type)+tcLiteral _ (Char _) = return (emptyPredSet, charType)+tcLiteral poly (Int _)+ | poly = freshNumType+ | otherwise = fmap ((,) emptyPredSet) (freshConstrained numTypes)+tcLiteral poly (Float _)+ | poly = freshFractionalType+ | otherwise = fmap ((,) emptyPredSet) (freshConstrained fractionalTypes)+tcLiteral _ (String _) = return (emptyPredSet, stringType)++tcLhs :: HasSpanInfo p => p -> Lhs a -> PTCM (PredSet, [Type], Lhs PredType)+tcLhs p (FunLhs spi f ts) = do+ (pss, tys, ts') <- unzip3 <$> mapM (tcPatternHelper p) ts+ return (Set.unions pss, tys, FunLhs spi f ts')+tcLhs p (OpLhs spi t1 op t2) = do+ (ps1, ty1, t1') <- tcPatternHelper p t1+ (ps2, ty2, t2') <- tcPatternHelper p t2+ return (ps1 `Set.union` ps2, [ty1, ty2], OpLhs spi t1' op t2')+tcLhs p (ApLhs spi lhs ts) = do+ (ps, tys1, lhs') <- tcLhs p lhs+ (pss, tys2, ts') <- unzip3 <$> mapM (tcPatternHelper p) ts+ return (Set.unions (ps:pss), tys1 ++ tys2, ApLhs spi lhs' ts')++-- When computing the type of a variable in a pattern, we ignore the+-- predicate set of the variable's type (which can only be due to a type+-- signature in the same declaration group) for just the same reason as+-- in 'tcFunctionPDecl'. Infix and infix functional patterns are currently+-- checked as constructor and functional patterns, respectively, resulting+-- in slighty misleading error messages if the type check fails.++-- We also keep track of already used variables,+-- in order to add a Data constraint for non-linear patterns++tcPattern :: HasSpanInfo p => p -> Pattern a+ -> TCM (PredSet, Type, Pattern PredType)+tcPattern = tcPatternWith Set.empty++tcPatternWith :: HasSpanInfo p => Set.Set Ident -> p -> Pattern a+ -> TCM (PredSet, Type, Pattern PredType)+tcPatternWith s p pt = S.evalStateT (tcPatternHelper p pt) s++type PTCM a = S.StateT (Set.Set Ident) TCM a++tcPatternHelper :: HasSpanInfo p => p -> Pattern a+ -> PTCM (PredSet, Type, Pattern PredType)+tcPatternHelper _ (LiteralPattern spi _ l) = do+ (ps, ty) <- lift $ tcLiteral False l+ return (ps, ty, LiteralPattern spi (predType ty) l)+tcPatternHelper _ (NegativePattern spi _ l) = do+ (ps, ty) <- lift $ tcLiteral False l+ return (ps, ty, NegativePattern spi (predType ty) l)+tcPatternHelper _ (VariablePattern spi _ v) = do+ vEnv <- lift getValueEnv+ (_, ty) <- lift $ inst (varType v vEnv)+ used <- S.get+ ps <- if Set.member v used+ then return (Set.singleton (Pred qDataId ty))+ else S.put (Set.insert v used) >> return Set.empty+ return (ps, ty, VariablePattern spi (predType ty) v)+tcPatternHelper p t@(ConstructorPattern spi _ c ts) = do+ m <- lift getModuleIdent+ vEnv <- lift getValueEnv+ (ps, (tys, ty')) <- fmap arrowUnapply <$> lift (skol (constrType m c vEnv))+ (ps', ts') <- mapAccumM (uncurry . ptcPatternArg p "pattern" (pPrintPrec 0 t))+ ps (zip tys ts)+ return (ps', ty', ConstructorPattern spi (predType ty') c ts')+tcPatternHelper p (InfixPattern spi a t1 op t2) = do+ (ps, ty, t') <- tcPatternHelper p (ConstructorPattern NoSpanInfo a op [t1,t2])+ let ConstructorPattern _ a' op' [t1', t2'] = t'+ return (ps, ty, InfixPattern spi a' t1' op' t2')+tcPatternHelper p (ParenPattern spi t) = do+ (ps, ty, t') <- tcPatternHelper p t+ return (ps, ty, ParenPattern spi t')+tcPatternHelper _ t@(RecordPattern spi _ c fs) = do+ m <- lift getModuleIdent+ vEnv <- lift getValueEnv+ (ps, ty) <- fmap arrowBase <$> lift (skol (constrType m c vEnv))+ -- tcField does not support passing "used" variables, thus we do it by hand+ used <- S.get+ (ps', fs') <- lift $ mapAccumM (tcField (tcPatternWith used) "pattern"+ (\t' -> pPrintPrec 0 t $-$ text "Term:" <+> pPrintPrec 0 t') ty) ps fs+ S.put $ foldr Set.insert used $ concatMap bv fs+ return (ps', ty, RecordPattern spi (predType ty) c fs')+tcPatternHelper p (TuplePattern spi ts) = do+ (pss, tys, ts') <- unzip3 <$> mapM (tcPatternHelper p) ts+ return (Set.unions pss, tupleType tys, TuplePattern spi ts')+tcPatternHelper p t@(ListPattern spi _ ts) = do+ ty <- lift freshTypeVar+ (ps, ts') <- mapAccumM (flip (ptcPatternArg p "pattern" (pPrintPrec 0 t)) ty)+ emptyPredSet ts+ return (ps, listType ty, ListPattern spi (predType $ listType ty) ts')+tcPatternHelper p t@(AsPattern spi v t') = do+ vEnv <- lift getValueEnv+ (_, ty) <- lift $ inst (varType v vEnv)+ used <- S.get+ ps <- if Set.member v used+ then return (Set.singleton (Pred qDataId ty))+ else S.put (Set.insert v used) >> return Set.empty+ (ps'', t'') <- tcPatternHelper p t' >>-+ (\ps' ty' -> lift $ unify p "pattern" (pPrintPrec 0 t) ps ty ps' ty')+ return (ps'', ty, AsPattern spi v t'')+tcPatternHelper p (LazyPattern spi t) = do+ (ps, ty, t') <- tcPatternHelper p t+ return (ps, ty, LazyPattern spi t')+tcPatternHelper p t@(FunctionPattern spi _ f ts) = do+ m <- lift getModuleIdent+ vEnv <- lift getValueEnv+ (ps, ty) <- lift $ inst (funType m f vEnv)+ -- insert all+ S.modify (flip (foldr Set.insert) (bv t))+ tcFuncPattern p spi (pPrintPrec 0 t) f id ps ty ts+tcPatternHelper p (InfixFuncPattern spi a t1 op t2) = do+ (ps, ty, t') <- tcPatternHelper p (FunctionPattern spi a op [t1, t2])+ let FunctionPattern _ a' op' [t1', t2'] = t'+ return (ps, ty, InfixFuncPattern spi a' t1' op' t2')++tcFuncPattern :: HasSpanInfo p => p -> SpanInfo -> Doc -> QualIdent+ -> ([Pattern PredType] -> [Pattern PredType])+ -> PredSet -> Type -> [Pattern a]+ -> PTCM (PredSet, Type, Pattern PredType)+tcFuncPattern _ spi _ f ts ps ty [] =+ return (Set.insert (Pred qDataId ty) ps, ty, FunctionPattern spi (predType ty) f (ts []))+tcFuncPattern p spi doc f ts ps ty (t':ts') = do+ (alpha, beta) <- lift $+ tcArrow p "functional pattern" (doc $-$ text "Term:" <+> pPrintPrec 0 t) ty+ (ps', t'') <- ptcPatternArg p "functional pattern" doc ps alpha t'+ tcFuncPattern p spi doc f (ts . (t'' :)) ps' beta ts'+ where t = FunctionPattern spi (predType ty) f (ts [])++ptcPatternArg :: HasSpanInfo p => p -> String -> Doc -> PredSet -> Type+ -> Pattern a -> PTCM (PredSet, Pattern PredType)+ptcPatternArg p what doc ps ty t =+ tcPatternHelper p t >>-+ (\ps' ty' -> lift $+ unify p what (doc $-$ text "Term:" <+> pPrintPrec 0 t) ps ty ps' ty')++tcPatternArg :: HasSpanInfo p => p -> String -> Doc -> PredSet -> Type+ -> Pattern a -> TCM (PredSet, Pattern PredType)+tcPatternArg p what doc ps ty t =+ tcPattern p t >>-+ unify p what (doc $-$ text "Term:" <+> pPrintPrec 0 t) ps ty++tcRhs :: Rhs a -> TCM (PredSet, Type, Rhs PredType)+tcRhs (SimpleRhs p li e ds) = do+ (ps, ds', ps', ty, e') <- withLocalValueEnv $ do+ (ps, ds') <- tcDecls ds+ (ps', ty, e') <- tcExpr e+ return (ps, ds', ps', ty, e')+ ps'' <- reducePredSet p "expression" (pPrintPrec 0 e') (ps `Set.union` ps')+ return (ps'', ty, SimpleRhs p li e' ds')+tcRhs (GuardedRhs spi li es ds) = withLocalValueEnv $ do+ (ps, ds') <- tcDecls ds+ ty <- freshTypeVar+ (ps', es') <- mapAccumM (tcCondExpr ty) ps es+ return (ps', ty, GuardedRhs spi li es' ds')++tcCondExpr :: Type -> PredSet -> CondExpr a -> TCM (PredSet, CondExpr PredType)+tcCondExpr ty ps (CondExpr p g e) = do+ (ps', g') <- tcExpr g >>- unify p "guard" (pPrintPrec 0 g) ps boolType+ (ps'', e') <- tcExpr e >>- unify p "guarded expression" (pPrintPrec 0 e) ps' ty+ return (ps'', CondExpr p g' e')++tcExpr :: Expression a -> TCM (PredSet, Type, Expression PredType)+tcExpr (Literal spi _ l) = do+ (ps, ty) <- tcLiteral True l+ return (ps, ty, Literal spi (predType ty) l)+tcExpr (Variable spi _ v) = do+ m <- getModuleIdent+ vEnv <- getValueEnv+ (ps, ty) <- if isAnonId (unqualify v) then freshPredType [qDataId]+ else inst (funType m v vEnv)+ return (ps, ty, Variable spi (predType ty) v)+tcExpr (Constructor spi _ c) = do+ m <- getModuleIdent+ vEnv <- getValueEnv+ (ps, ty) <- inst (constrType m c vEnv)+ return (ps, ty, Constructor spi (predType ty) c)+tcExpr (Paren spi e) = do+ (ps, ty, e') <- tcExpr e+ return (ps, ty, Paren spi e')+tcExpr (Typed spi e qty) = do+ pty <- expandPoly qty+ (ps, ty) <- inst (typeScheme pty)+ (ps', e') <- tcExpr e >>-+ unifyDecl spi "explicitly typed expression" (pPrintPrec 0 e) emptyPredSet ty+ fvs <- computeFvEnv+ theta <- getTypeSubst+ let (gps, lps) = splitPredSet fvs ps'+ tySc = gen fvs lps (subst theta ty)+ unlessM (checkTypeSig pty tySc) $ do+ m <- getModuleIdent+ report $+ errTypeSigTooGeneral m (text "Expression:" <+> pPrintPrec 0 e) qty tySc+ return (ps `Set.union` gps, ty, Typed spi e' qty)+tcExpr e@(Record spi _ c fs) = do+ m <- getModuleIdent+ vEnv <- getValueEnv+ (ps, ty) <- fmap arrowBase <$> inst (constrType m c vEnv)+ (ps', fs') <- mapAccumM (tcField (const tcExpr) "construction"+ (\e' -> pPrintPrec 0 e $-$ text "Term:" <+> pPrintPrec 0 e') ty) ps fs+ let missing = map (qualifyLike c) (constrLabels m c vEnv)+ \\ map (\(Field _ qid _) -> qid) fs'+ pss <- mapM (tcMissingField spi ty) missing+ return (Set.unions (ps':pss), ty, Record spi (predType ty) c fs')+tcExpr e@(RecordUpdate spi e1 fs) = do+ (ps, ty, e1') <- tcExpr e1+ (ps', fs') <- mapAccumM (tcField (const tcExpr) "update"+ (\e' -> pPrintPrec 0 e $-$ text "Term:" <+> pPrintPrec 0 e') ty) ps fs+ return (ps', ty, RecordUpdate spi e1' fs')+tcExpr (Tuple spi es) = do+ (pss, tys, es') <- liftM unzip3 $ mapM (tcExpr) es+ return (Set.unions pss, tupleType tys, Tuple spi es')+tcExpr e@(List spi _ es) = do+ ty <- freshTypeVar+ (ps, es') <-+ mapAccumM (flip (tcArg spi "expression" (pPrintPrec 0 e)) ty) emptyPredSet es+ return (ps, listType ty, List spi (predType $ listType ty) es')+tcExpr (ListCompr spi e qs) = do+ (ps, qs', ps', ty, e') <- withLocalValueEnv $ do+ (ps, qs') <- mapAccumM (tcQual spi) emptyPredSet qs+ (ps', ty, e') <- tcExpr e+ return (ps, qs', ps', ty, e')+ ps'' <- reducePredSet spi "expression" (pPrintPrec 0 e') (ps `Set.union` ps')+ return (ps'', listType ty, ListCompr spi e' qs')+tcExpr e@(EnumFrom spi e1) = do+ (ps, ty) <- freshEnumType+ (ps', e1') <- tcArg spi "arithmetic sequence" (pPrintPrec 0 e) ps ty e1+ return (ps', listType ty, EnumFrom spi e1')+tcExpr e@(EnumFromThen spi e1 e2) = do+ (ps, ty) <- freshEnumType+ (ps', e1') <- tcArg spi "arithmetic sequence" (pPrintPrec 0 e) ps ty e1+ (ps'', e2') <- tcArg spi "arithmetic sequence" (pPrintPrec 0 e) ps' ty e2+ return (ps'', listType ty, EnumFromThen spi e1' e2')+tcExpr e@(EnumFromTo spi e1 e2) = do+ (ps, ty) <- freshEnumType+ (ps', e1') <- tcArg spi "arithmetic sequence" (pPrintPrec 0 e) ps ty e1+ (ps'', e2') <- tcArg spi "arithmetic sequence" (pPrintPrec 0 e) ps' ty e2+ return (ps'', listType ty, EnumFromTo spi e1' e2')+tcExpr e@(EnumFromThenTo spi e1 e2 e3) = do+ (ps, ty) <- freshEnumType+ (ps', e1') <- tcArg spi "arithmetic sequence" (pPrintPrec 0 e) ps ty e1+ (ps'', e2') <- tcArg spi "arithmetic sequence" (pPrintPrec 0 e) ps' ty e2+ (ps''', e3') <- tcArg spi "arithmetic sequence" (pPrintPrec 0 e) ps'' ty e3+ return (ps''', listType ty, EnumFromThenTo spi e1' e2' e3')+tcExpr e@(UnaryMinus spi e1) = do+ (ps, ty) <- freshNumType+ (ps', e1') <- tcArg spi "unary negation" (pPrintPrec 0 e) ps ty e1+ return (ps', ty, UnaryMinus spi e1')+tcExpr e@(Apply spi e1 e2) = do+ (ps, (alpha, beta), e1') <- tcExpr e1 >>=-+ tcArrow spi "application" (pPrintPrec 0 e $-$ text "Term:" <+> pPrintPrec 0 e1)+ (ps', e2') <- tcArg spi "application" (pPrintPrec 0 e) ps alpha e2+ return (ps', beta, Apply spi e1' e2')+tcExpr e@(InfixApply spi e1 op e2) = do+ (ps, (alpha, beta, gamma), op') <- tcInfixOp op >>=-+ tcBinary spi "infix application" (pPrintPrec 0 e $-$ text "Operator:" <+> pPrint op)+ (ps', e1') <- tcArg spi "infix application" (pPrintPrec 0 e) ps alpha e1+ (ps'', e2') <- tcArg spi "infix application" (pPrintPrec 0 e) ps' beta e2+ return (ps'', gamma, InfixApply spi e1' op' e2')+tcExpr e@(LeftSection spi e1 op) = do+ (ps, (alpha, beta), op') <- tcInfixOp op >>=-+ tcArrow spi "left section" (pPrintPrec 0 e $-$ text "Operator:" <+> pPrint op)+ (ps', e1') <- tcArg spi "left section" (pPrintPrec 0 e) ps alpha e1+ return (ps', beta, LeftSection spi e1' op')+tcExpr e@(RightSection spi op e1) = do+ (ps, (alpha, beta, gamma), op') <- tcInfixOp op >>=-+ tcBinary spi "right section" (pPrintPrec 0 e $-$ text "Operator:" <+> pPrint op)+ (ps', e1') <- tcArg spi "right section" (pPrintPrec 0 e) ps beta e1+ return (ps', TypeArrow alpha gamma, RightSection spi op' e1')+tcExpr (Lambda spi ts e) = do+ (pss, tys, ts', ps, ty, e')<- withLocalValueEnv $ do+ bindLambdaVars ts+ (pss, tys, ts') <- liftM unzip3 $ mapM (tcPattern spi) ts+ (ps, ty, e') <- tcExpr e+ return (pss, tys, ts', ps, ty, e')+ ps' <- reducePredSet spi "expression" (pPrintPrec 0 e') (Set.unions $ ps : pss)+ return (ps', foldr TypeArrow ty tys, Lambda spi ts' e')+tcExpr (Let spi li ds e) = do+ (ps, ds', ps', ty, e') <- withLocalValueEnv $ do+ (ps, ds') <- tcDecls ds+ (ps', ty, e') <- tcExpr e+ return (ps, ds', ps', ty, e')+ ps'' <- reducePredSet spi "expression" (pPrintPrec 0 e') (ps `Set.union` ps')+ return (ps'', ty, Let spi li ds' e')+tcExpr (Do spi li sts e) = do+ (sts', ty, ps', e') <- withLocalValueEnv $ do+ ((ps, mTy), sts') <-+ mapAccumM (uncurry (tcStmt spi)) (emptyPredSet, Nothing) sts+ ty <- liftM (maybe id TypeApply mTy) freshTypeVar+ (ps', e') <- tcExpr e >>- unify spi "statement" (pPrintPrec 0 e) ps ty+ return (sts', ty, ps', e')+ return (ps', ty, Do spi li sts' e')+tcExpr e@(IfThenElse spi e1 e2 e3) = do+ (ps, e1') <- tcArg spi "expression" (pPrintPrec 0 e) emptyPredSet boolType e1+ (ps', ty, e2') <- tcExpr e2+ (ps'', e3') <- tcArg spi "expression" (pPrintPrec 0 e) (ps `Set.union` ps') ty e3+ return (ps'', ty, IfThenElse spi e1' e2' e3')+tcExpr (Case spi li ct e as) = do+ (ps, tyLhs, e') <- tcExpr e+ tyRhs <- freshTypeVar+ (ps', as') <- mapAccumM (tcAlt tyLhs tyRhs) ps as+ return (ps', tyRhs, Case spi li ct e' as')++tcArg :: HasSpanInfo p => p -> String -> Doc -> PredSet -> Type -> Expression a+ -> TCM (PredSet, Expression PredType)+tcArg p what doc ps ty e =+ tcExpr e >>- unify p what (doc $-$ text "Term:" <+> pPrintPrec 0 e) ps ty++tcAlt :: Type -> Type -> PredSet -> Alt a+ -> TCM (PredSet, Alt PredType)+tcAlt tyLhs tyRhs ps a@(Alt p t rhs) =+ tcAltern tyLhs p t rhs >>-+ unify p "case alternative" (pPrint a) ps tyRhs++tcAltern :: Type -> SpanInfo -> Pattern a+ -> Rhs a -> TCM (PredSet, Type, Alt PredType)+tcAltern tyLhs p t rhs = do+ (ps, t', ps', ty', rhs') <- withLocalValueEnv $ do+ bindLambdaVars t+ (ps, t') <-+ tcPatternArg p "case pattern" (pPrint (Alt p t rhs)) emptyPredSet tyLhs t+ (ps', ty', rhs') <- tcRhs rhs+ return (ps, t', ps', ty', rhs')+ ps'' <- reducePredSet p "alternative" (pPrint (Alt p t' rhs'))+ (ps `Set.union` ps')+ return (ps'', ty', Alt p t' rhs')++tcQual :: HasSpanInfo p => p -> PredSet -> Statement a+ -> TCM (PredSet, Statement PredType)+tcQual p ps (StmtExpr spi e) = do+ (ps', e') <- tcExpr e >>- unify p "guard" (pPrintPrec 0 e) ps boolType+ return (ps', StmtExpr spi e')+tcQual _ ps (StmtDecl spi li ds) = do+ (ps', ds') <- tcDecls ds+ return (ps `Set.union` ps', StmtDecl spi li ds')+tcQual p ps q@(StmtBind spi t e) = do+ alpha <- freshTypeVar+ (ps', e') <- tcArg p "generator" (pPrint q) ps (listType alpha) e+ bindLambdaVars t+ (ps'', t') <- tcPatternArg p "generator" (pPrint q) ps' alpha t+ return (ps'', StmtBind spi t' e')++tcStmt :: HasSpanInfo p => p -> PredSet -> Maybe Type -> Statement a+ -> TCM ((PredSet, Maybe Type), Statement PredType)+tcStmt p ps mTy (StmtExpr spi e) = do+ (ps', ty) <- maybe freshMonadType (return . (,) emptyPredSet) mTy+ alpha <- freshTypeVar+ (ps'', e') <- tcExpr e >>-+ unify p "statement" (pPrintPrec 0 e) (ps `Set.union` ps') (applyType ty [alpha])+ return ((ps'', Just ty), StmtExpr spi e')+tcStmt _ ps mTy (StmtDecl spi li ds) = do+ (ps', ds') <- tcDecls ds+ return ((ps `Set.union` ps', mTy), StmtDecl spi li ds')+tcStmt p ps mTy st@(StmtBind spi t e) = do+ failable <- checkFailableBind t+ let freshMType = if failable then freshMonadFailType else freshMonadType+ (ps', ty) <- maybe freshMType (return . (,) emptyPredSet) mTy+ alpha <- freshTypeVar+ (ps'', e') <-+ tcArg p "statement" (pPrint st) (ps `Set.union` ps') (applyType ty [alpha]) e+ bindLambdaVars t+ (ps''', t') <- tcPatternArg p "statement" (pPrint st) ps'' alpha t+ return ((ps''', Just ty), StmtBind spi t' e')++checkFailableBind :: Pattern a -> TCM Bool+checkFailableBind (ConstructorPattern _ _ idt ps ) = do+ tcEnv <- getTyConsEnv+ case qualLookupTypeInfo idt tcEnv of+ [RenamingType _ _ _ ] -> or <$> mapM checkFailableBind ps -- or [] == False+ [DataType _ _ cs]+ | length cs == 1 -> or <$> mapM checkFailableBind ps+ | otherwise -> return True+ _ -> return True+checkFailableBind (InfixPattern _ _ p1 idt p2) = do+ tcEnv <- getTyConsEnv+ case qualLookupTypeInfo idt tcEnv of+ [RenamingType _ _ _ ] -> (||) <$> checkFailableBind p1+ <*> checkFailableBind p2+ [DataType _ _ cs]+ | length cs == 1 -> (||) <$> checkFailableBind p1+ <*> checkFailableBind p2+ | otherwise -> return True+ _ -> return True+checkFailableBind (RecordPattern _ _ idt fs ) = do+ tcEnv <- getTyConsEnv+ case qualLookupTypeInfo idt tcEnv of+ [RenamingType _ _ _ ] -> or <$> mapM (checkFailableBind . fieldContent) fs+ [DataType _ _ cs]+ | length cs == 1 -> or <$> mapM (checkFailableBind . fieldContent) fs+ | otherwise -> return True+ _ -> return True+ where fieldContent (Field _ _ c) = c+checkFailableBind (TuplePattern _ ps ) =+ or <$> mapM checkFailableBind ps+checkFailableBind (AsPattern _ _ p ) = checkFailableBind p+checkFailableBind (ParenPattern _ p ) = checkFailableBind p+checkFailableBind (LazyPattern _ _ ) = return False+checkFailableBind (VariablePattern _ _ _ ) = return False+checkFailableBind _ = return True++tcInfixOp :: InfixOp a -> TCM (PredSet, Type, InfixOp PredType)+tcInfixOp (InfixOp _ op) = do+ m <- getModuleIdent+ vEnv <- getValueEnv+ (ps, ty) <- inst (funType m op vEnv)+ return (ps, ty, InfixOp (predType ty) op)+tcInfixOp (InfixConstr _ op) = do+ m <- getModuleIdent+ vEnv <- getValueEnv+ (ps, ty) <- inst (constrType m op vEnv)+ return (ps, ty, InfixConstr (predType ty) op)++-- The first unification in 'tcField' cannot fail; it serves only for+-- instantiating the type variables in the field label's type.++tcField :: (SpanInfo -> a b -> TCM (PredSet, Type, a PredType))+ -> String -> (a b -> Doc) -> Type -> PredSet -> Field (a b)+ -> TCM (PredSet, Field (a PredType))+tcField check what doc ty ps (Field p l x) = do+ m <- getModuleIdent+ vEnv <- getValueEnv+ (ps', ty') <- inst (labelType m l vEnv)+ let TypeArrow ty1 ty2 = ty'+ _ <- unify p "field label" empty emptyPredSet ty emptyPredSet ty1+ (ps'', x') <- check p x >>-+ unify p ("record " ++ what) (doc x) (ps `Set.union` ps') ty2+ return (ps'', Field p l x')++tcMissingField :: HasSpanInfo p => p -> Type -> QualIdent -> TCM PredSet+tcMissingField p ty l = do+ m <- getModuleIdent+ vEnv <- getValueEnv+ (ps, ty') <- inst (labelType m l vEnv)+ let TypeArrow _ ty2 = ty'+ let ps' = Set.singleton (Pred qDataId ty2)+ unify p "field label" empty ps ty' ps' (TypeArrow ty ty2)++-- | Checks that it's argument can be used as an arrow type @a -> b@ and returns+-- the pair @(a, b)@.+tcArrow :: HasSpanInfo p => p -> String -> Doc -> Type -> TCM (Type, Type)+tcArrow p what doc ty = do+ theta <- getTypeSubst+ unaryArrow (subst theta ty)+ where+ unaryArrow (TypeArrow ty1 ty2) = return (ty1, ty2)+ unaryArrow (TypeVariable tv) = do+ alpha <- freshTypeVar+ beta <- freshTypeVar+ modifyTypeSubst $ bindVar tv $ TypeArrow alpha beta+ return (alpha, beta)+ unaryArrow ty' = do+ m <- getModuleIdent+ report $ errNonFunctionType p what doc m ty'+ (,) <$> freshTypeVar <*> freshTypeVar++-- The function 'tcBinary' checks that its argument can be used as an arrow type+-- a -> b -> c and returns the triple (a,b,c).++tcBinary :: HasSpanInfo p => p -> String -> Doc -> Type+ -> TCM (Type, Type, Type)+tcBinary p what doc ty = tcArrow p what doc ty >>= uncurry binaryArrow+ where+ binaryArrow ty1 (TypeArrow ty2 ty3) = return (ty1, ty2, ty3)+ binaryArrow ty1 (TypeVariable tv) = do+ beta <- freshTypeVar+ gamma <- freshTypeVar+ modifyTypeSubst $ bindVar tv $ TypeArrow beta gamma+ return (ty1, beta, gamma)+ binaryArrow ty1 ty2 = do+ m <- getModuleIdent+ report $ errNonBinaryOp p what doc m (TypeArrow ty1 ty2)+ (,,) <$> return ty1 <*> freshTypeVar <*> freshTypeVar++-- Unification: The unification uses Robinson's algorithm.++unify :: HasSpanInfo p => p -> String -> Doc -> PredSet -> Type -> PredSet+ -> Type -> TCM PredSet+unify p what doc ps1 ty1 ps2 ty2 = do+ theta <- getTypeSubst+ let ty1' = subst theta ty1+ ty2' = subst theta ty2+ m <- getModuleIdent+ case unifyTypes m ty1' ty2' of+ Left reason -> report $ errTypeMismatch p what doc m ty1' ty2' reason+ Right sigma -> modifyTypeSubst (compose sigma)+ reducePredSet p what doc $ ps1 `Set.union` ps2++unifyTypes :: ModuleIdent -> Type -> Type -> Either Doc TypeSubst+unifyTypes _ (TypeVariable tv1) (TypeVariable tv2)+ | tv1 == tv2 = Right idSubst+ | otherwise = Right (singleSubst tv1 (TypeVariable tv2))+unifyTypes m (TypeVariable tv) ty+ | tv `elem` typeVars ty = Left (errRecursiveType m tv ty)+ | otherwise = Right (singleSubst tv ty)+unifyTypes m ty (TypeVariable tv)+ | tv `elem` typeVars ty = Left (errRecursiveType m tv ty)+ | otherwise = Right (singleSubst tv ty)+unifyTypes _ (TypeConstrained tys1 tv1) (TypeConstrained tys2 tv2)+ | tv1 == tv2 = Right idSubst+ | tys1 == tys2 = Right (singleSubst tv1 (TypeConstrained tys2 tv2))+unifyTypes m (TypeConstrained tys tv) ty =+ foldr (choose . unifyTypes m ty) (Left (errIncompatibleTypes m ty (head tys)))+ tys+ where choose (Left _) theta' = theta'+ choose (Right theta) _ = Right (bindSubst tv ty theta)+unifyTypes m ty (TypeConstrained tys tv) =+ foldr (choose . unifyTypes m ty) (Left (errIncompatibleTypes m ty (head tys)))+ tys+ where choose (Left _) theta' = theta'+ choose (Right theta) _ = Right (bindSubst tv ty theta)+unifyTypes _ (TypeConstructor tc1) (TypeConstructor tc2)+ | tc1 == tc2 = Right idSubst+unifyTypes m (TypeApply ty11 ty12) (TypeApply ty21 ty22) =+ unifyTypeLists m [ty11, ty12] [ty21, ty22]+unifyTypes m ty1@(TypeApply _ _) (TypeArrow ty21 ty22) =+ unifyTypes m ty1 (TypeApply (TypeApply (TypeConstructor qArrowId) ty21) ty22)+unifyTypes m (TypeArrow ty11 ty12) ty2@(TypeApply _ _) =+ unifyTypes m (TypeApply (TypeApply (TypeConstructor qArrowId) ty11) ty12) ty2+unifyTypes m (TypeArrow ty11 ty12) (TypeArrow ty21 ty22) =+ unifyTypeLists m [ty11, ty12] [ty21, ty22]+unifyTypes m ty1 ty2 = Left (errIncompatibleTypes m ty1 ty2)++unifyTypeLists :: ModuleIdent -> [Type] -> [Type] -> Either Doc TypeSubst+unifyTypeLists _ [] _ = Right idSubst+unifyTypeLists _ _ [] = Right idSubst+unifyTypeLists m (ty1 : tys1) (ty2 : tys2) =+ either Left unifyTypesTheta (unifyTypeLists m tys1 tys2)+ where+ unifyTypesTheta theta =+ either Left (Right . flip compose theta)+ (unifyTypes m (subst theta ty1) (subst theta ty2))++-- After performing a unification, the resulting substitution is applied+-- to the current predicate set and the resulting predicate set is subject+-- to a reduction. This predicate set reduction retains all predicates whose+-- types are simple variables and which are not implied but other+-- predicates in the predicate set. For all other predicates, the compiler+-- checks whether an instance exists and replaces them by applying the+-- instances' predicate set to the respective types. A minor complication+-- arises due to constrained types, which at present are used to+-- implement overloading of guard expressions and of numeric literals in+-- patterns. The set of admissible types of a constrained type may be+-- restricted by the current predicate set after the reduction and thus+-- may cause a further extension of the current type substitution.++reducePredSet :: HasSpanInfo p => p -> String -> Doc -> PredSet -> TCM PredSet+reducePredSet p what doc ps = do+ m <- getModuleIdent+ clsEnv <- getClassEnv+ theta <- getTypeSubst+ inEnv <- fmap (fmap (subst theta)) <$> getInstEnv+ let ps' = subst theta ps+ (ps1, ps2) = partitionPredSet $ minPredSet clsEnv $ reducePreds inEnv ps'+ theta' <-+ foldM (reportMissingInstance m p what doc inEnv) idSubst $ Set.toList ps2+ modifyTypeSubst $ compose theta'+ return ps1+ where+ reducePreds inEnv = Set.concatMap $ reducePred inEnv+ reducePred inEnv pr@(Pred qcls ty) =+ maybe (Set.singleton pr) (reducePreds inEnv) (instPredSet inEnv qcls ty)++instPredSet :: InstEnv' -> QualIdent -> Type -> Maybe PredSet+instPredSet inEnv qcls ty = case Map.lookup qcls $ snd inEnv of+ Just tys | ty `elem` tys -> Just emptyPredSet+ _ -> case unapplyType False ty of+ (TypeConstructor tc, tys) ->+ fmap (expandAliasType tys . snd3) (lookupInstInfo (qcls, tc) $ fst inEnv)+ _ -> Nothing++reportMissingInstance :: HasSpanInfo p => ModuleIdent -> p -> String -> Doc+ -> InstEnv' -> TypeSubst -> Pred -> TCM TypeSubst+reportMissingInstance m p what doc inEnv theta (Pred qcls ty) =+ case subst theta ty of+ ty'@(TypeConstrained tys tv) ->+ case filter (hasInstance inEnv qcls) tys of+ [] -> do+ report $ errMissingInstance m p what doc (Pred qcls ty')+ return theta+ [ty''] -> return (bindSubst tv ty'' theta)+ tys'+ | length tys == length tys' -> return theta+ | otherwise ->+ liftM (flip (bindSubst tv) theta) (freshConstrained tys')+ ty'+ | hasInstance inEnv qcls ty' -> return theta+ | otherwise -> do+ report $ errMissingInstance m p what doc (Pred qcls ty')+ return theta++hasInstance :: InstEnv' -> QualIdent -> Type -> Bool+hasInstance inEnv qcls = isJust . instPredSet inEnv qcls++-- When a constrained type variable that is not free in the type environment+-- disappears from the current type, the type becomes ambiguous. For instance,+-- the type of the expression+--+-- let x = read "" in show x+--+-- is ambiguous assuming that 'read' and 'show' have types+--+-- read :: Read a => String -> a+-- show :: Show a => a -> String+--+-- because the compiler cannot determine which 'Read' and 'Show' instances to+-- use.+--+-- In the case of expressions with an ambiguous numeric type, i.e., a type that+-- must be an instance of 'Num' or one of its subclasses, the compiler tries to+-- resolve the ambiguity by choosing the first type from the list of default+-- types that satisfies all constraints for the ambiguous type variable. An+-- error is reported if no such type exists.++applyDefaults :: HasSpanInfo p => p -> String -> Doc -> Set.Set Int -> PredSet+ -> Type -> TCM PredSet+applyDefaults p what doc fvs ps ty = do+ m <- getModuleIdent+ clsEnv <- getClassEnv+ inEnv <- getInstEnv+ defs <- getDefaultTypes+ let theta = foldr (bindDefault defs inEnv ps) idSubst $ nub+ [ tv | Pred qcls (TypeVariable tv) <- Set.toList ps+ , tv `Set.notMember` fvs, isNumClass clsEnv qcls ]+ ps' = fst (partitionPredSet (subst theta ps))+ ty' = subst theta ty+ tvs' = nub $ filter (`Set.notMember` fvs) (typeVars ps')+ mapM_ (report . errAmbiguousTypeVariable m p what doc ps' ty') tvs'+ modifyTypeSubst $ compose theta+ return ps'++bindDefault :: [Type] -> InstEnv' -> PredSet -> Int -> TypeSubst -> TypeSubst+bindDefault defs inEnv ps tv =+ case foldr (defaultType inEnv tv) defs (Set.toList ps) of+ [] -> id+ ty:_ -> bindSubst tv ty++defaultType :: InstEnv' -> Int -> Pred -> [Type] -> [Type]+defaultType inEnv tv (Pred qcls (TypeVariable tv'))+ | tv == tv' = filter (hasInstance inEnv qcls)+ | otherwise = id+defaultType _ _ _ = id++isNumClass :: ClassEnv -> QualIdent -> Bool+isNumClass = (elem qNumId .) . flip allSuperClasses++-- Instantiation and Generalization:+-- We use negative offsets for fresh type variables.++fresh :: (Int -> a) -> TCM a+fresh f = f <$> getNextId++freshVar :: (Int -> a) -> TCM a+freshVar f = fresh $ \n -> f (- n)++freshTypeVar :: TCM Type+freshTypeVar = freshVar TypeVariable++freshPredType :: [QualIdent] -> TCM (PredSet, Type)+freshPredType qclss = do+ ty <- freshTypeVar+ return (foldr (\qcls -> Set.insert $ Pred qcls ty) emptyPredSet qclss, ty)++freshEnumType :: TCM (PredSet, Type)+freshEnumType = freshPredType [qEnumId]++freshNumType :: TCM (PredSet, Type)+freshNumType = freshPredType [qNumId]++freshFractionalType :: TCM (PredSet, Type)+freshFractionalType = freshPredType [qFractionalId]++freshMonadType :: TCM (PredSet, Type)+freshMonadType = freshPredType [qMonadId]++freshMonadFailType :: TCM (PredSet, Type)+freshMonadFailType = freshPredType [qMonadFailId]++freshDataType :: TCM (PredSet, Type)+freshDataType = freshPredType [qDataId]++freshConstrained :: [Type] -> TCM Type+freshConstrained = freshVar . TypeConstrained++inst :: TypeScheme -> TCM (PredSet, Type)+inst (ForAll n (PredType ps ty)) = do+ tys <- replicateM n freshTypeVar+ return (expandAliasType tys ps, expandAliasType tys ty)++-- The function 'skol' instantiates the type of data and newtype+-- constructors in patterns. All universally quantified type variables+-- are instantiated with fresh type variables and all existentially+-- quantified type variables are instantiated with fresh skolem types.+-- All constraints that appear on the right hand side of the+-- constructor's declaration are added to the dynamic instance+-- environment.++skol :: TypeScheme -> TCM (PredSet, Type)+skol (ForAll n (PredType ps ty)) = do+ tys <- replicateM n freshTypeVar+ clsEnv <- getClassEnv+ modifyInstEnv $+ fmap $ bindSkolemInsts $ expandAliasType tys $ maxPredSet clsEnv ps+ return (emptyPredSet, expandAliasType tys ty)+ where bindSkolemInsts = flip (foldr bindSkolemInst) . Set.toList+ bindSkolemInst (Pred qcls ty') dInEnv =+ Map.insert qcls (ty' : fromMaybe [] (Map.lookup qcls dInEnv)) dInEnv++-- The function 'gen' generalizes a predicate set ps and a type tau into+-- a type scheme forall alpha . ps -> tau by universally quantifying all+-- type variables that are free in tau and not fixed by the environment.+-- The set of the latter is given by gvs.++gen :: Set.Set Int -> PredSet -> Type -> TypeScheme+gen gvs ps ty = ForAll (length tvs) (subst theta (PredType ps ty))+ where tvs = [tv | tv <- nub (typeVars ty), tv `Set.notMember` gvs]+ tvs' = map TypeVariable [0 ..]+ theta = foldr2 bindSubst idSubst tvs tvs'++-- Auxiliary Functions:+-- The functions 'constrType', 'varType', 'funType' and 'labelType' are used+-- to retrieve the type of constructors, pattern variables, variables and+-- labels in expressions, respectively, from the value environment. Because+-- the syntactical correctness has already been verified by the syntax checker,+-- none of these functions should fail.++-- Note that 'varType' can handle ambiguous identifiers and returns the first+-- available type. This function is used for looking up the type of an+-- identifier on the left hand side of a rule where it unambiguously refers+-- to the local definition.++-- The function 'constrLabels' returns a list of all labels belonging to a+-- data constructor. The function 'varArity' works like 'varType' but returns+-- a variable's arity instead of its type.++constrType :: ModuleIdent -> QualIdent -> ValueEnv -> TypeScheme+constrType m c vEnv = case qualLookupValue c vEnv of+ [DataConstructor _ _ _ tySc] -> tySc+ [NewtypeConstructor _ _ tySc] -> tySc+ _ -> case qualLookupValue (qualQualify m c) vEnv of+ [DataConstructor _ _ _ tySc] -> tySc+ [NewtypeConstructor _ _ tySc] -> tySc+ _ -> internalError $ "TypeCheck.constrType: " ++ show c++constrLabels :: ModuleIdent -> QualIdent -> ValueEnv -> [Ident]+constrLabels m c vEnv = case qualLookupValue c vEnv of+ [DataConstructor _ _ ls _] -> ls+ [NewtypeConstructor _ l _] -> [l]+ _ -> case qualLookupValue (qualQualify m c) vEnv of+ [DataConstructor _ _ ls _] -> ls+ [NewtypeConstructor _ l _] -> [l]+ _ -> internalError $ "TypeCheck.constrLabels: " ++ show c++varType :: Ident -> ValueEnv -> TypeScheme+varType v vEnv = case lookupValue v vEnv of+ Value _ _ _ tySc : _ -> tySc+ _ -> internalError $ "TypeCheck.varType: " ++ show v++varArity :: QualIdent -> ValueEnv -> Int+varArity v vEnv = case qualLookupValue v vEnv of+ Value _ _ n _ : _ -> n+ Label _ _ _ : _ -> 1+ _ -> internalError $ "TypeCheck.varArity: " ++ show v++funType :: ModuleIdent -> QualIdent -> ValueEnv -> TypeScheme+funType m f vEnv = case qualLookupValue f vEnv of+ [Value _ _ _ tySc] -> tySc+ [Label _ _ tySc] -> tySc+ _ -> case qualLookupValue (qualQualify m f) vEnv of+ [Value _ _ _ tySc] -> tySc+ [Label _ _ tySc] -> tySc+ _ -> internalError $ "TypeCheck.funType: " ++ show f++labelType :: ModuleIdent -> QualIdent -> ValueEnv -> TypeScheme+labelType m l vEnv = case qualLookupValue l vEnv of+ [Label _ _ tySc] -> tySc+ _ -> case qualLookupValue (qualQualify m l) vEnv of+ [Label _ _ tySc] -> tySc+ _ -> internalError $ "TypeCheck.labelType: " ++ show l++-- The function 'expandPoly' handles the expansion of type aliases.++expandPoly :: QualTypeExpr -> TCM PredType+expandPoly qty = do+ m <- getModuleIdent+ tcEnv <- getTyConsEnv+ clsEnv <- getClassEnv+ return $ expandPolyType m tcEnv clsEnv qty++-- The function 'splitPredSet' splits a predicate set into a pair of predicate+-- set such that all type variables that appear in the types of the predicates+-- in the first predicate set are elements of a given set of type variables.++splitPredSet :: Set.Set Int -> PredSet -> (PredSet, PredSet)+splitPredSet fvs = Set.partition (all (`Set.member` fvs) . typeVars)++-- The functions 'fvEnv' and 'fsEnv' compute the set of free type variables+-- and free skolems of a type environment, respectively. We ignore the types+-- of data constructors here because we know that they are closed.++fvEnv :: ValueEnv -> Set.Set Int+fvEnv vEnv =+ Set.fromList [tv | tySc <- localTypes vEnv, tv <- typeVars tySc, tv < 0]++computeFvEnv :: TCM (Set.Set Int)+computeFvEnv = do+ theta <- getTypeSubst+ vEnv <- getValueEnv+ return $ fvEnv (subst theta vEnv)++localTypes :: ValueEnv -> [TypeScheme]+localTypes vEnv = [tySc | (_, Value _ _ _ tySc) <- localBindings vEnv]++-- ---------------------------------------------------------------------------+-- Error functions+-- ---------------------------------------------------------------------------++errPolymorphicVar :: Ident -> Message+errPolymorphicVar v = spanInfoMessage v $ hsep $ map text+ ["Variable", idName v, "has a polymorphic type"]++errTypeSigTooGeneral :: ModuleIdent -> Doc -> QualTypeExpr+ -> TypeScheme -> Message+errTypeSigTooGeneral m what qty tySc = spanInfoMessage qty $ vcat+ [ text "Type signature too general", what+ , text "Inferred type:" <+> ppTypeScheme m tySc+ , text "Type signature:" <+> pPrint qty+ ]++errMethodTypeTooSpecific :: HasSpanInfo a => a -> ModuleIdent -> Doc -> PredType+ -> TypeScheme -> Message+errMethodTypeTooSpecific p m what pty tySc = spanInfoMessage p $ vcat+ [ text "Method type too specific", what+ , text "Inferred type:" <+> ppTypeScheme m tySc+ , text "Expected type:" <+> ppPredType m pty+ ]++errNonFunctionType :: HasSpanInfo a => a -> String -> Doc -> ModuleIdent -> Type+ -> Message+errNonFunctionType p what doc m ty = spanInfoMessage p $ vcat+ [ text "Type error in" <+> text what, doc+ , text "Type:" <+> ppType m ty+ , text "Cannot be applied"+ ]++errNonBinaryOp :: HasSpanInfo a => a -> String -> Doc -> ModuleIdent -> Type+ -> Message+errNonBinaryOp p what doc m ty = spanInfoMessage p $ vcat+ [ text "Type error in" <+> text what, doc+ , text "Type:" <+> ppType m ty+ , text "Cannot be used as binary operator"+ ]++errTypeMismatch :: HasSpanInfo a => a -> String -> Doc -> ModuleIdent -> Type+ -> Type -> Doc -> Message+errTypeMismatch p what doc m ty1 ty2 reason = spanInfoMessage p $ vcat+ [ text "Type error in" <+> text what, doc+ , text "Inferred type:" <+> ppType m ty2+ , text "Expected type:" <+> ppType m ty1+ , reason+ ]++errSkolemFieldLabel :: HasSpanInfo a => a -> Ident -> Message+errSkolemFieldLabel p l = spanInfoMessage p $ hsep $ map text+ ["Existential type escapes with type of record selector", escName l]++errRecursiveType :: ModuleIdent -> Int -> Type -> Doc+errRecursiveType m tv ty = errIncompatibleTypes m (TypeVariable tv) ty++errIncompatibleTypes :: ModuleIdent -> Type -> Type -> Doc+errIncompatibleTypes m ty1 ty2 = sep+ [ text "Types" <+> ppType m ty1+ , nest 2 $ text "and" <+> ppType m ty2+ , text "are incompatible"+ ]++errIncompatibleLabelTypes :: HasSpanInfo a => a -> ModuleIdent -> Ident -> Type+ -> Type -> Message+errIncompatibleLabelTypes p m l ty1 ty2 = spanInfoMessage p $ sep+ [ text "Labeled types" <+> ppIdent l <+> text "::" <+> ppType m ty1+ , nest 10 $ text "and" <+> ppIdent l <+> text "::" <+> ppType m ty2+ , text "are incompatible"+ ]++errMissingInstance :: HasSpanInfo a => ModuleIdent -> a -> String -> Doc -> Pred+ -> Message+errMissingInstance m p what doc pr = spanInfoMessage p $ vcat+ [ text "Missing instance for" <+> ppPred m pr+ , text "in" <+> text what+ , doc+ ]++errAmbiguousTypeVariable :: HasSpanInfo a => ModuleIdent -> a -> String -> Doc+ -> PredSet -> Type -> Int -> Message+errAmbiguousTypeVariable m p what doc ps ty tv = spanInfoMessage p $ vcat+ [ text "Ambiguous type variable" <+> ppType m (TypeVariable tv)+ , text "in type" <+> ppPredType m (PredType ps ty)+ , text "inferred for" <+> text what+ , doc+ ]
+ src/Checks/TypeSyntaxCheck.hs view
@@ -0,0 +1,498 @@+{- |+ Module : $Header$+ Description : Checks type syntax+ Copyright : (c) 2016 - 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ After the source file has been parsed and all modules have been+ imported, the compiler first checks all type definitions and+ signatures. In particular, this module disambiguates nullary type+ constructors and type variables, which -- in contrast to Haskell -- is+ not possible on purely syntactic criteria. In addition it is checked+ that all type constructors and type variables occurring on the right+ hand side of a type declaration are actually defined and no identifier+ is defined more than once.+-}+{-# LANGUAGE CPP #-}+module Checks.TypeSyntaxCheck (typeSyntaxCheck) where++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative ((<$>), (<*>), pure)+#endif+import Control.Monad (unless, when)+import qualified Control.Monad.State as S (State, runState, gets, modify)+import Data.List (nub)+import Data.Maybe (isNothing)++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Base.SpanInfo+import Curry.Base.Pretty+import Curry.Syntax+import Curry.Syntax.Pretty++import Base.Expr (Expr (fv))+import Base.Messages (Message, spanInfoMessage, internalError)+import Base.TopEnv+import Base.Utils (findMultiples, findDouble)++import Env.TypeConstructor (TCEnv)+import Env.Type++-- TODO Use span info for err messages++-- In order to check type constructor applications, the compiler+-- maintains an environment containing all known type constructors and+-- type classes. The function 'typeSyntaxCheck' expects a type constructor+-- environment that is already initialized with the imported type constructors+-- and type classes. The type constructor environment is converted to a type+-- identifier environment, before all locally defined type constructors and+-- type classes are added to this environment and the declarations are checked+-- within this environment.++typeSyntaxCheck :: TCEnv -> Module a -> (Module a, [Message])+typeSyntaxCheck tcEnv mdl@(Module _ _ _ m _ _ ds) =+ case findMultiples $ map getIdent tcds of+ [] -> if length dfds <= 1+ then runTSCM (checkModule mdl) state+ else (mdl, [errMultipleDefaultDeclarations dfps])+ tss -> (mdl, map errMultipleDeclarations tss)+ where+ tcds = filter isTypeOrClassDecl ds+ dfds = filter isDefaultDecl ds+ dfps = map (\(DefaultDecl p _) -> p) dfds+ tEnv = foldr (bindType m) (fmap toTypeKind tcEnv) tcds+ state = TSCState m tEnv 1 []++-- Type Syntax Check Monad+type TSCM = S.State TSCState++-- |Internal state of the Type Syntax Check+data TSCState = TSCState+ { moduleIdent :: ModuleIdent+ , typeEnv :: TypeEnv+ , nextId :: Integer+ , errors :: [Message]+ }++runTSCM :: TSCM a -> TSCState -> (a, [Message])+runTSCM tscm s = let (a, s') = S.runState tscm s in (a, reverse $ errors s')++getModuleIdent :: TSCM ModuleIdent+getModuleIdent = S.gets moduleIdent++getTypeEnv :: TSCM TypeEnv+getTypeEnv = S.gets typeEnv++newId :: TSCM Integer+newId = do+ curId <- S.gets nextId+ S.modify $ \s -> s { nextId = succ curId }+ return curId++report :: Message -> TSCM ()+report err = S.modify (\s -> s { errors = err : errors s })++ok :: TSCM ()+ok = return ()++bindType :: ModuleIdent -> Decl a -> TypeEnv -> TypeEnv+bindType m (DataDecl _ tc _ cs _) = bindTypeKind m tc (Data qtc ids)+ where+ qtc = qualifyWith m tc+ ids = map constrId cs ++ nub (concatMap recordLabels cs)+bindType m (ExternalDataDecl _ tc _) = bindTypeKind m tc (Data qtc [])+ where+ qtc = qualifyWith m tc+bindType m (NewtypeDecl _ tc _ nc _) = bindTypeKind m tc (Data qtc ids)+ where+ qtc = qualifyWith m tc+ ids = nconstrId nc : nrecordLabels nc+bindType m (TypeDecl _ tc _ _) = bindTypeKind m tc (Alias qtc)+ where+ qtc = qualifyWith m tc+bindType m (ClassDecl _ _ _ cls _ ds) = bindTypeKind m cls (Class qcls ms)+ where+ qcls = qualifyWith m cls+ ms = concatMap methods ds+bindType _ _ = id++-- When type declarations are checked, the compiler will allow anonymous+-- type variables on the left hand side of the declaration, but not on+-- the right hand side. Function and pattern declarations must be+-- traversed because they can contain local type signatures.++checkModule :: Module a -> TSCM (Module a)+checkModule (Module spi li ps m es is ds) = do+ ds' <- mapM checkDecl ds+ return $ Module spi li ps m es is ds'++checkDecl :: Decl a -> TSCM (Decl a)+checkDecl (DataDecl p tc tvs cs clss) = do+ checkTypeLhs tvs+ cs' <- mapM (checkConstrDecl tvs) cs+ mapM_ (checkClass False) clss+ return $ DataDecl p tc tvs cs' clss+checkDecl (NewtypeDecl p tc tvs nc clss) = do+ checkTypeLhs tvs+ nc' <- checkNewConstrDecl tvs nc+ mapM_ (checkClass False) clss+ return $ NewtypeDecl p tc tvs nc' clss+checkDecl (TypeDecl p tc tvs ty) = do+ checkTypeLhs tvs+ ty' <- checkClosedType tvs ty+ return $ TypeDecl p tc tvs ty'+checkDecl (TypeSig p vs qty) =+ TypeSig p vs <$> checkQualType qty+checkDecl (FunctionDecl a p f eqs) = FunctionDecl a p f <$>+ mapM checkEquation eqs+checkDecl (PatternDecl p t rhs) = PatternDecl p t <$> checkRhs rhs+checkDecl (DefaultDecl p tys) = DefaultDecl p <$>+ mapM (checkClosedType []) tys+checkDecl (ClassDecl p li cx cls clsvar ds) = do+ checkTypeVars "class declaration" [clsvar]+ cx' <- checkClosedContext [clsvar] cx+ checkSimpleContext cx'+ ds' <- mapM checkDecl ds+ mapM_ (checkClassMethod clsvar) ds'+ return $ ClassDecl p li cx' cls clsvar ds'+checkDecl (InstanceDecl p li cx qcls inst ds) = do+ checkClass True qcls+ QualTypeExpr _ cx' inst' <- checkQualType $ QualTypeExpr NoSpanInfo cx inst+ checkSimpleContext cx'+ checkInstanceType p inst'+ InstanceDecl p li cx' qcls inst' <$> mapM checkDecl ds+checkDecl d = return d++checkConstrDecl :: [Ident] -> ConstrDecl -> TSCM ConstrDecl+checkConstrDecl tvs (ConstrDecl p c tys) = do+ tys' <- mapM (checkClosedType tvs) tys+ return $ ConstrDecl p c tys'+checkConstrDecl tvs (ConOpDecl p ty1 op ty2) = do+ tys' <- mapM (checkClosedType tvs) [ty1, ty2]+ let [ty1', ty2'] = tys'+ return $ ConOpDecl p ty1' op ty2'+checkConstrDecl tvs (RecordDecl p c fs) = do+ fs' <- mapM (checkFieldDecl tvs) fs+ return $ RecordDecl p c fs'++checkFieldDecl :: [Ident] -> FieldDecl -> TSCM FieldDecl+checkFieldDecl tvs (FieldDecl p ls ty) =+ FieldDecl p ls <$> checkClosedType tvs ty++checkNewConstrDecl :: [Ident] -> NewConstrDecl -> TSCM NewConstrDecl+checkNewConstrDecl tvs (NewConstrDecl p c ty) = do+ ty' <- checkClosedType tvs ty+ return $ NewConstrDecl p c ty'+checkNewConstrDecl tvs (NewRecordDecl p c (l, ty)) = do+ ty' <- checkClosedType tvs ty+ return $ NewRecordDecl p c (l, ty')++checkSimpleContext :: Context -> TSCM ()+checkSimpleContext = mapM_ checkSimpleConstraint++checkSimpleConstraint :: Constraint -> TSCM ()+checkSimpleConstraint c@(Constraint _ _ ty) =+ unless (isVariableType ty) $ report $ errIllegalSimpleConstraint c++-- Class method's type signatures have to obey a few additional restrictions.+-- The class variable must appear in the method's type and the method's+-- context must not contain any additional constraints for that class variable.++checkClassMethod :: Ident -> Decl a -> TSCM ()+checkClassMethod tv (TypeSig spi _ qty) = do+ unless (tv `elem` fv qty) $ report $ errAmbiguousType spi tv+ let QualTypeExpr _ cx _ = qty+ when (tv `elem` fv cx) $ report $ errConstrainedClassVariable spi tv+checkClassMethod _ _ = ok++checkInstanceType :: SpanInfo -> InstanceType -> TSCM ()+checkInstanceType p inst = do+ tEnv <- getTypeEnv+ unless (isSimpleType inst &&+ not (isTypeSyn (typeConstr inst) tEnv) &&+ not (any isAnonId $ typeVariables inst) &&+ isNothing (findDouble $ fv inst)) $+ report $ errIllegalInstanceType p inst++checkTypeLhs :: [Ident] -> TSCM ()+checkTypeLhs = checkTypeVars "left hand side of type declaration"++-- |Checks a list of type variables for+-- * Anonymous type variables are allowed+-- * only type variables (no type constructors)+-- * linearity+checkTypeVars :: String -> [Ident] -> TSCM ()+checkTypeVars _ [] = ok+checkTypeVars what (tv : tvs) = do+ unless (isAnonId tv) $ do+ isTypeConstrOrClass <- not . null . lookupTypeKind tv <$> getTypeEnv+ when isTypeConstrOrClass $ report $ errNoVariable tv what+ when (tv `elem` tvs) $ report $ errNonLinear tv what+ checkTypeVars what tvs++-- Checking expressions is rather straight forward. The compiler must+-- only traverse the structure of expressions in order to find local+-- declaration groups.++checkEquation :: Equation a -> TSCM (Equation a)+checkEquation (Equation p lhs rhs) = Equation p lhs <$> checkRhs rhs++checkRhs :: Rhs a -> TSCM (Rhs a)+checkRhs (SimpleRhs spi li e ds) =+ SimpleRhs spi li <$> checkExpr e <*> mapM checkDecl ds+checkRhs (GuardedRhs spi li es ds) =+ GuardedRhs spi li <$> mapM checkCondExpr es <*> mapM checkDecl ds++checkCondExpr :: CondExpr a -> TSCM (CondExpr a)+checkCondExpr (CondExpr spi g e) = CondExpr spi <$> checkExpr g <*> checkExpr e++checkExpr :: Expression a -> TSCM (Expression a)+checkExpr l@(Literal _ _ _) = return l+checkExpr v@(Variable _ _ _) = return v+checkExpr c@(Constructor _ _ _) = return c+checkExpr (Paren spi e) = Paren spi <$> checkExpr e+checkExpr (Typed spi e qty) = Typed spi <$> checkExpr e+ <*> checkQualType qty+checkExpr (Record spi a c fs) =+ Record spi a c <$> mapM checkFieldExpr fs+checkExpr (RecordUpdate spi e fs) =+ RecordUpdate spi <$> checkExpr e <*> mapM checkFieldExpr fs+checkExpr (Tuple spi es) = Tuple spi <$> mapM checkExpr es+checkExpr (List spi a es) = List spi a <$> mapM checkExpr es+checkExpr (ListCompr spi e qs) = ListCompr spi <$> checkExpr e+ <*> mapM checkStmt qs+checkExpr (EnumFrom spi e) = EnumFrom spi <$> checkExpr e+checkExpr (EnumFromThen spi e1 e2) = EnumFromThen spi <$> checkExpr e1+ <*> checkExpr e2+checkExpr (EnumFromTo spi e1 e2) = EnumFromTo spi <$> checkExpr e1+ <*> checkExpr e2+checkExpr (EnumFromThenTo spi e1 e2 e3) = EnumFromThenTo spi <$> checkExpr e1+ <*> checkExpr e2+ <*> checkExpr e3+checkExpr (UnaryMinus spi e) = UnaryMinus spi <$> checkExpr e+checkExpr (Apply spi e1 e2) = Apply spi <$> checkExpr e1+ <*> checkExpr e2+checkExpr (InfixApply spi e1 op e2) = InfixApply spi <$> checkExpr e1+ <*> return op+ <*> checkExpr e2+checkExpr (LeftSection spi e op) = flip (LeftSection spi) op <$>+ checkExpr e+checkExpr (RightSection spi op e) = RightSection spi op <$> checkExpr e+checkExpr (Lambda spi ts e) = Lambda spi ts <$> checkExpr e+checkExpr (Let spi li ds e) = Let spi li <$> mapM checkDecl ds+ <*> checkExpr e+checkExpr (Do spi li sts e) = Do spi li <$> mapM checkStmt sts+ <*> checkExpr e+checkExpr (IfThenElse spi e1 e2 e3) = IfThenElse spi <$> checkExpr e1+ <*> checkExpr e2+ <*> checkExpr e3+checkExpr (Case spi li ct e alts) = Case spi li ct <$> checkExpr e+ <*> mapM checkAlt alts++checkStmt :: Statement a -> TSCM (Statement a)+checkStmt (StmtExpr spi e) = StmtExpr spi <$> checkExpr e+checkStmt (StmtBind spi t e) = StmtBind spi t <$> checkExpr e+checkStmt (StmtDecl spi li ds) = StmtDecl spi li <$> mapM checkDecl ds++checkAlt :: Alt a -> TSCM (Alt a)+checkAlt (Alt spi t rhs) = Alt spi t <$> checkRhs rhs++checkFieldExpr :: Field (Expression a) -> TSCM (Field (Expression a))+checkFieldExpr (Field spi l e) = Field spi l <$> checkExpr e++-- The parser cannot distinguish unqualified nullary type constructors+-- and type variables. Therefore, if the compiler finds an unbound+-- identifier in a position where a type variable is admissible, it will+-- interpret the identifier as such.++checkQualType :: QualTypeExpr -> TSCM QualTypeExpr+checkQualType (QualTypeExpr spi cx ty) = do+ ty' <- checkType ty+ cx' <- checkClosedContext (fv ty') cx+ return $ QualTypeExpr spi cx' ty'++checkClosedContext :: [Ident] -> Context -> TSCM Context+checkClosedContext tvs cx = do+ cx' <- checkContext cx+ mapM_ (\(Constraint _ _ ty) -> checkClosed tvs ty) cx'+ return cx'++checkContext :: Context -> TSCM Context+checkContext = mapM checkConstraint++checkConstraint :: Constraint -> TSCM Constraint+checkConstraint c@(Constraint spi qcls ty) = do+ checkClass False qcls+ ty' <- checkType ty+ unless (isVariableType $ rootType ty') $ report $ errIllegalConstraint c+ return $ Constraint spi qcls ty'+ where+ rootType (ApplyType _ ty' _) = ty'+ rootType ty' = ty'++checkClass :: Bool -> QualIdent -> TSCM ()+checkClass isInstDecl qcls = do+ m <- getModuleIdent+ tEnv <- getTypeEnv+ case qualLookupTypeKind qcls tEnv of+ [] -> report $ errUndefinedClass qcls+ [Class c _]+ | c == qDataId -> when (isInstDecl && m /= preludeMIdent) $ report $+ errIllegalDataInstance qcls+ | otherwise -> ok+ [_] -> report $ errUndefinedClass qcls+ tks -> case qualLookupTypeKind (qualQualify m qcls) tEnv of+ [Class c _]+ | c == qDataId -> when (isInstDecl && m /= preludeMIdent) $ report $+ errIllegalDataInstance qcls+ | otherwise -> ok+ [_] -> report $ errUndefinedClass qcls+ _ -> report $ errAmbiguousIdent qcls $ map origName tks++checkClosedType :: [Ident] -> TypeExpr -> TSCM TypeExpr+checkClosedType tvs ty = do+ ty' <- checkType ty+ checkClosed tvs ty'+ return ty'++checkType :: TypeExpr -> TSCM TypeExpr+checkType c@(ConstructorType spi tc) = do+ m <- getModuleIdent+ tEnv <- getTypeEnv+ case qualLookupTypeKind tc tEnv of+ []+ | isQTupleId tc -> return c+ | not (isQualified tc) -> return $ VariableType spi $ unqualify tc+ | otherwise -> report (errUndefinedType tc) >> return c+ [Class _ _] -> report (errUndefinedType tc) >> return c+ [_] -> return c+ tks -> case qualLookupTypeKind (qualQualify m tc) tEnv of+ [Class _ _] -> report (errUndefinedType tc) >> return c+ [_] -> return c+ _ -> report (errAmbiguousIdent tc $ map origName tks) >> return c+checkType (ApplyType spi ty1 ty2) = ApplyType spi <$> checkType ty1+ <*> checkType ty2+checkType (VariableType spi tv)+ | isAnonId tv = (VariableType spi . renameIdent tv) <$> newId+ | otherwise = checkType $ ConstructorType spi (qualify tv)+checkType (TupleType spi tys) = TupleType spi <$> mapM checkType tys+checkType (ListType spi ty) = ListType spi <$> checkType ty+checkType (ArrowType spi ty1 ty2) = ArrowType spi <$> checkType ty1+ <*> checkType ty2+checkType (ParenType spi ty) = ParenType spi <$> checkType ty+checkType (ForallType spi vs ty) = ForallType spi vs <$> checkType ty++checkClosed :: [Ident] -> TypeExpr -> TSCM ()+checkClosed _ (ConstructorType _ _) = ok+checkClosed tvs (ApplyType _ ty1 ty2) = mapM_ (checkClosed tvs) [ty1, ty2]+checkClosed tvs (VariableType _ tv) =+ when (isAnonId tv || tv `notElem` tvs) $ report $ errUnboundVariable tv+checkClosed tvs (TupleType _ tys) = mapM_ (checkClosed tvs) tys+checkClosed tvs (ListType _ ty) = checkClosed tvs ty+checkClosed tvs (ArrowType _ ty1 ty2) = mapM_ (checkClosed tvs) [ty1, ty2]+checkClosed tvs (ParenType _ ty) = checkClosed tvs ty+checkClosed tvs (ForallType _ vs ty) = checkClosed (tvs ++ vs) ty++-- ---------------------------------------------------------------------------+-- Auxiliary definitions+-- ---------------------------------------------------------------------------++getIdent :: Decl a -> Ident+getIdent (DataDecl _ tc _ _ _) = tc+getIdent (ExternalDataDecl _ tc _) = tc+getIdent (NewtypeDecl _ tc _ _ _) = tc+getIdent (TypeDecl _ tc _ _) = tc+getIdent (ClassDecl _ _ _ cls _ _) = cls+getIdent _ = internalError+ "Checks.TypeSyntaxCheck.getIdent: no type or class declaration"++isTypeSyn :: QualIdent -> TypeEnv -> Bool+isTypeSyn tc tEnv = case qualLookupTypeKind tc tEnv of+ [Alias _] -> True+ _ -> False++-- ---------------------------------------------------------------------------+-- Error messages+-- ---------------------------------------------------------------------------++errMultipleDefaultDeclarations :: [SpanInfo] -> Message+errMultipleDefaultDeclarations spis = spanInfoMessage (head spis) $+ text "More than one default declaration:" $+$+ nest 2 (vcat $ map showPos spis)+ where showPos = text . showLine . getPosition++errMultipleDeclarations :: [Ident] -> Message+errMultipleDeclarations is = spanInfoMessage i $+ text "Multiple declarations of" <+> text (escName i) <+> text "at:" $+$+ nest 2 (vcat $ map showPos is)+ where i = head is+ showPos = text . showLine . getPosition++errUndefined :: String -> QualIdent -> Message+errUndefined what qident = spanInfoMessage qident $ hsep $ map text+ ["Undefined", what, qualName qident]++errUndefinedClass :: QualIdent -> Message+errUndefinedClass = errUndefined "class"++errUndefinedType :: QualIdent -> Message+errUndefinedType = errUndefined "type"++errAmbiguousIdent :: QualIdent -> [QualIdent] -> Message+errAmbiguousIdent qident qidents = spanInfoMessage qident $+ text "Ambiguous identifier" <+> text (escQualName qident) $+$+ text "It could refer to:" $+$ nest 2 (vcat (map (text . qualName) qidents))++errAmbiguousType :: SpanInfo -> Ident -> Message+errAmbiguousType spi ident = spanInfoMessage spi $ hsep $ map text+ [ "Method type does not mention class variable", idName ident ]++errConstrainedClassVariable :: SpanInfo -> Ident -> Message+errConstrainedClassVariable spi ident = spanInfoMessage spi $ hsep $ map text+ [ "Method context must not constrain class variable", idName ident ]++errNonLinear :: Ident -> String -> Message+errNonLinear tv what = spanInfoMessage tv $ hsep $ map text+ [ "Type variable", idName tv, "occurs more than once in", what ]++errNoVariable :: Ident -> String -> Message+errNoVariable tv what = spanInfoMessage tv $ hsep $ map text+ ["Type constructor or type class identifier", idName tv, "used in", what]++errUnboundVariable :: Ident -> Message+errUnboundVariable tv = spanInfoMessage tv $ hsep $ map text+ [ "Unbound type variable", idName tv ]++errIllegalConstraint :: Constraint -> Message+errIllegalConstraint c@(Constraint _ qcls _) = spanInfoMessage qcls $ vcat+ [ text "Illegal class constraint" <+> pPrint c+ , text "Constraints must be of the form C u or C (u t1 ... tn),"+ , text "where C is a type class, u is a type variable and t1, ..., tn are types."+ ]++errIllegalSimpleConstraint :: Constraint -> Message+errIllegalSimpleConstraint c@(Constraint _ qcls _) = spanInfoMessage qcls $ vcat+ [ text "Illegal class constraint" <+> pPrint c+ , text "Constraints in class and instance declarations must be of"+ , text "the form C u, where C is a type class and u is a type variable."+ ]++errIllegalInstanceType :: SpanInfo -> InstanceType -> Message+errIllegalInstanceType spi inst = spanInfoMessage spi $ vcat+ [ text "Illegal instance type" <+> ppInstanceType inst+ , text "The instance type must be of the form (T u_1 ... u_n),"+ , text "where T is not a type synonym and u_1, ..., u_n are"+ , text "mutually distinct, non-anonymous type variables."+ ]++errIllegalDataInstance :: QualIdent -> Message+errIllegalDataInstance qcls = spanInfoMessage qcls $ vcat+ [ text "Illegal instance of" <+> ppQIdent qcls+ , text "Instances of this class cannot be defined."+ , text "Instead, they are automatically derived if possible."+ ]
+ src/Checks/WarnCheck.hs view
@@ -0,0 +1,1641 @@+{- |+ Module : $Header$+ Description : Checks for irregular code+ Copyright : (c) 2006 Martin Engelke+ 2011 - 2014 Björn Peemöller+ 2014 - 2015 Jan Tikovsky+ 2016 - 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module searches for potentially irregular code and generates+ warning messages.+-}+{-# LANGUAGE CPP #-}+module Checks.WarnCheck (warnCheck) where++#if __GLASGOW_HASKELL__ >= 804+import Prelude hiding ((<>))+#endif++import Control.Applicative+ ((<|>))+import Control.Monad+ (filterM, foldM_, guard, liftM, liftM2, when, unless, void)+import Control.Monad.State.Strict (State, execState, gets, modify)+import qualified Data.IntSet as IntSet+ (IntSet, empty, insert, notMember, singleton, union, unions)+import qualified Data.Map as Map (empty, insert, lookup, (!))+import Data.Maybe+ (catMaybes, fromMaybe, listToMaybe)+import Data.List+ ((\\), intersect, intersectBy, nub, sort, unionBy)+import Data.Char+ (isLower, isUpper, toLower, toUpper, isAlpha)+import qualified Data.Set.Extra as Set+import Data.Tuple.Extra+ (snd3)++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Base.Pretty+import Curry.Base.SpanInfo+import Curry.Syntax+import Curry.Syntax.Utils (typeVariables)+import Curry.Syntax.Pretty (pPrint)++import Base.CurryTypes (ppTypeScheme, fromPred, toPredSet)+import Base.Messages (Message, spanInfoMessage, internalError)+import Base.NestEnv ( NestEnv, emptyEnv, localNestEnv, nestEnv, unnestEnv+ , qualBindNestEnv, qualInLocalNestEnv, qualLookupNestEnv+ , qualModifyNestEnv)++import Base.Types+import Base.Utils (findMultiples)+import Env.ModuleAlias+import Env.Class (ClassEnv, classMethods, hasDefaultImpl)+import Env.TypeConstructor ( TCEnv, TypeInfo (..), lookupTypeInfo+ , qualLookupTypeInfo, getOrigName )+import Env.Value (ValueEnv, ValueInfo (..), qualLookupValue)++import CompilerOpts++-- Find potentially incorrect code in a Curry program and generate warnings+-- for the following issues:+-- - multiply imported modules, multiply imported/hidden values+-- - unreferenced variables+-- - shadowing variables+-- - idle case alternatives+-- - overlapping case alternatives+-- - non-adjacent function rules+-- - wrong case mode+-- - redundant context+warnCheck :: WarnOpts -> CaseMode -> AliasEnv -> ValueEnv -> TCEnv -> ClassEnv+ -> Module a -> [Message]+warnCheck wOpts cOpts aEnv valEnv tcEnv clsEnv mdl+ = runOn (initWcState mid aEnv valEnv tcEnv clsEnv (wnWarnFlags wOpts) cOpts) $ do+ checkImports is+ checkDeclGroup ds+ checkExports es+ checkMissingTypeSignatures ds+ checkModuleAlias is+ checkCaseMode ds+ checkRedContext ds+ where Module _ _ _ mid es is ds = fmap (const ()) mdl++type ScopeEnv = NestEnv IdInfo++-- Current state of generating warnings+data WcState = WcState+ { moduleId :: ModuleIdent+ , scope :: ScopeEnv+ , aliasEnv :: AliasEnv+ , valueEnv :: ValueEnv+ , tyConsEnv :: TCEnv+ , classEnv :: ClassEnv+ , warnFlags :: [WarnFlag]+ , caseMode :: CaseMode+ , warnings :: [Message]+ }++-- The monadic representation of the state allows the usage of monadic+-- syntax (do expression) for dealing easier and safer with its+-- contents.+type WCM = State WcState++initWcState :: ModuleIdent -> AliasEnv -> ValueEnv -> TCEnv -> ClassEnv+ -> [WarnFlag] -> CaseMode -> WcState+initWcState mid ae ve te ce wf cm = WcState mid emptyEnv ae ve te ce wf cm []++getModuleIdent :: WCM ModuleIdent+getModuleIdent = gets moduleId++modifyScope :: (ScopeEnv -> ScopeEnv) -> WCM ()+modifyScope f = modify $ \s -> s { scope = f $ scope s }++warnFor :: WarnFlag -> WCM () -> WCM ()+warnFor f act = do+ warn <- gets $ \s -> f `elem` warnFlags s+ when warn act++report :: Message -> WCM ()+report w = modify $ \ s -> s { warnings = w : warnings s }++unAlias :: QualIdent -> WCM QualIdent+unAlias q = do+ aEnv <- gets aliasEnv+ case qidModule q of+ Nothing -> return q+ Just m -> case Map.lookup m aEnv of+ Nothing -> return q+ Just m' -> return $ qualifyWith m' (unqualify q)++ok :: WCM ()+ok = return ()++-- |Run a 'WCM' action and return the list of messages+runOn :: WcState -> WCM a -> [Message]+runOn s f = sort $ warnings $ execState f s++-- ---------------------------------------------------------------------------+-- checkExports+-- ---------------------------------------------------------------------------++checkExports :: Maybe ExportSpec -> WCM () -- TODO checks+checkExports Nothing = ok+checkExports (Just (Exporting _ exports)) = do+ mapM_ visitExport exports+ reportUnusedGlobalVars+ where+ visitExport (Export _ qid) = visitQId qid+ visitExport _ = ok++-- ---------------------------------------------------------------------------+-- checkImports+-- ---------------------------------------------------------------------------++-- Check import declarations for multiply imported modules and multiply+-- imported/hidden values.+-- The function uses a map of the already imported or hidden entities to+-- collect the entities throughout multiple import statements.+checkImports :: [ImportDecl] -> WCM ()+checkImports = warnFor WarnMultipleImports . foldM_ checkImport Map.empty+ where+ checkImport env (ImportDecl pos mid _ _ spec) = case Map.lookup mid env of+ Nothing -> setImportSpec env mid $ fromImpSpec spec+ Just ishs -> checkImportSpec env pos mid ishs spec++ checkImportSpec env _ mid (_, _) Nothing = do+ report $ warnMultiplyImportedModule mid+ return env++ checkImportSpec env _ mid (is, hs) (Just (Importing _ is'))+ | null is && any (`notElem` hs) is' = do+ report $ warnMultiplyImportedModule mid+ setImportSpec env mid (is', hs)+ | null iis = setImportSpec env mid (is' ++ is, hs)+ | otherwise = do+ mapM_ (report . (warnMultiplyImportedSymbol mid) . impName) iis+ setImportSpec env mid (unionBy cmpImport is' is, hs)+ where iis = intersectBy cmpImport is' is++ checkImportSpec env _ mid (is, hs) (Just (Hiding _ hs'))+ | null ihs = setImportSpec env mid (is, hs' ++ hs)+ | otherwise = do+ mapM_ (report . (warnMultiplyHiddenSymbol mid) . impName) ihs+ setImportSpec env mid (is, unionBy cmpImport hs' hs)+ where ihs = intersectBy cmpImport hs' hs++ fromImpSpec Nothing = ([], [])+ fromImpSpec (Just (Importing _ is)) = (is, [])+ fromImpSpec (Just (Hiding _ hs)) = ([], hs)++ setImportSpec env mid ishs = return $ Map.insert mid ishs env++ cmpImport (ImportTypeWith _ id1 cs1) (ImportTypeWith _ id2 cs2)+ = id1 == id2 && null (intersect cs1 cs2)+ cmpImport i1 i2 = (impName i1) == (impName i2)++ impName (Import _ v) = v+ impName (ImportTypeAll _ t) = t+ impName (ImportTypeWith _ t _) = t++warnMultiplyImportedModule :: ModuleIdent -> Message+warnMultiplyImportedModule mid = spanInfoMessage mid $ hsep $ map text+ ["Module", moduleName mid, "is imported more than once"]++warnMultiplyImportedSymbol :: ModuleIdent -> Ident -> Message+warnMultiplyImportedSymbol mid ident = spanInfoMessage ident $ hsep $ map text+ [ "Symbol", escName ident, "from module", moduleName mid+ , "is imported more than once" ]++warnMultiplyHiddenSymbol :: ModuleIdent -> Ident -> Message+warnMultiplyHiddenSymbol mid ident = spanInfoMessage ident $ hsep $ map text+ [ "Symbol", escName ident, "from module", moduleName mid+ , "is hidden more than once" ]++-- ---------------------------------------------------------------------------+-- checkDeclGroup+-- ---------------------------------------------------------------------------++checkDeclGroup :: [Decl ()] -> WCM ()+checkDeclGroup ds = do+ mapM_ insertDecl ds+ mapM_ checkDecl ds+ checkRuleAdjacency ds++checkLocalDeclGroup :: [Decl ()] -> WCM ()+checkLocalDeclGroup ds = do+ mapM_ checkLocalDecl ds+ checkDeclGroup ds++-- ---------------------------------------------------------------------------+-- Find function rules which are disjoined+-- ---------------------------------------------------------------------------++checkRuleAdjacency :: [Decl a] -> WCM ()+checkRuleAdjacency decls = warnFor WarnDisjoinedRules+ $ foldM_ check (mkIdent "", Map.empty) decls+ where+ check (prevId, env) (FunctionDecl p _ f _) = do+ cons <- isConsId f+ if cons || prevId == f+ then return (f, env)+ else case Map.lookup f env of+ Nothing -> return (f, Map.insert f p env)+ Just p' -> do+ report $ warnDisjoinedFunctionRules f (spanInfo2Pos p')+ return (f, env)+ check (_ , env) _ = return (mkIdent "", env)++warnDisjoinedFunctionRules :: Ident -> Position -> Message+warnDisjoinedFunctionRules ident pos = spanInfoMessage ident $ hsep (map text+ [ "Rules for function", escName ident, "are disjoined" ])+ <+> parens (text "first occurrence at" <+> text (showLine pos))++checkDecl :: Decl () -> WCM ()+checkDecl (DataDecl _ _ vs cs _) = inNestedScope $ do+ mapM_ insertTypeVar vs+ mapM_ checkConstrDecl cs+ reportUnusedTypeVars vs+checkDecl (NewtypeDecl _ _ vs nc _) = inNestedScope $ do+ mapM_ insertTypeVar vs+ checkNewConstrDecl nc+ reportUnusedTypeVars vs+checkDecl (TypeDecl _ _ vs ty) = inNestedScope $ do+ mapM_ insertTypeVar vs+ checkTypeExpr ty+ reportUnusedTypeVars vs+checkDecl (FunctionDecl p _ f eqs) = checkFunctionDecl p f eqs+checkDecl (PatternDecl _ p rhs) = checkPattern p >> checkRhs rhs+checkDecl (DefaultDecl _ tys) = mapM_ checkTypeExpr tys+checkDecl (ClassDecl _ _ _ _ _ ds) = mapM_ checkDecl ds+checkDecl (InstanceDecl p _ cx cls ty ds) = do+ checkOrphanInstance p cx cls ty+ checkMissingMethodImplementations p cls ds+ mapM_ checkDecl ds+checkDecl _ = ok++--TODO: shadowing und context etc.+checkConstrDecl :: ConstrDecl -> WCM ()+checkConstrDecl (ConstrDecl _ c tys) = inNestedScope $ do+ visitId c+ mapM_ checkTypeExpr tys+checkConstrDecl (ConOpDecl _ ty1 op ty2) = inNestedScope $ do+ visitId op+ mapM_ checkTypeExpr [ty1, ty2]+checkConstrDecl (RecordDecl _ c fs) = inNestedScope $ do+ visitId c+ mapM_ checkTypeExpr tys+ where+ tys = [ty | FieldDecl _ _ ty <- fs]++checkNewConstrDecl :: NewConstrDecl -> WCM ()+checkNewConstrDecl (NewConstrDecl _ c ty) = do+ visitId c+ checkTypeExpr ty+checkNewConstrDecl (NewRecordDecl _ c (_, ty)) = do+ visitId c+ checkTypeExpr ty++checkTypeExpr :: TypeExpr -> WCM ()+checkTypeExpr (ConstructorType _ qid) = visitQTypeId qid+checkTypeExpr (ApplyType _ ty1 ty2) = mapM_ checkTypeExpr [ty1, ty2]+checkTypeExpr (VariableType _ v) = visitTypeId v+checkTypeExpr (TupleType _ tys) = mapM_ checkTypeExpr tys+checkTypeExpr (ListType _ ty) = checkTypeExpr ty+checkTypeExpr (ArrowType _ ty1 ty2) = mapM_ checkTypeExpr [ty1, ty2]+checkTypeExpr (ParenType _ ty) = checkTypeExpr ty+checkTypeExpr (ForallType _ vs ty) = do+ mapM_ insertTypeVar vs+ checkTypeExpr ty++-- Checks locally declared identifiers (i.e. functions and logic variables)+-- for shadowing+checkLocalDecl :: Decl a -> WCM ()+checkLocalDecl (FunctionDecl _ _ f _) = checkShadowing f+checkLocalDecl (FreeDecl _ vs) = mapM_ (checkShadowing . varIdent) vs+checkLocalDecl (PatternDecl _ p _) = checkPattern p+checkLocalDecl _ = ok++checkFunctionDecl :: SpanInfo -> Ident -> [Equation ()] -> WCM ()+checkFunctionDecl _ _ [] = ok+checkFunctionDecl p f eqs = inNestedScope $ do+ mapM_ checkEquation eqs+ checkFunctionPatternMatch p f eqs++checkFunctionPatternMatch :: SpanInfo -> Ident -> [Equation ()] -> WCM ()+checkFunctionPatternMatch spi f eqs = do+ let pats = map (\(Equation _ lhs _) -> snd (flatLhs lhs)) eqs+ let guards = map eq2Guards eqs+ (nonExhaustive, overlapped, nondet) <- checkPatternMatching pats guards+ unless (null nonExhaustive) $ warnFor WarnIncompletePatterns $ report $+ warnMissingPattern spi ("an equation for " ++ escName f) nonExhaustive+ when (nondet || not (null overlapped)) $ warnFor WarnOverlapping $ report $+ warnNondetOverlapping spi ("Function " ++ escName f)+ where eq2Guards :: Equation () -> [CondExpr ()]+ eq2Guards (Equation _ _ (GuardedRhs _ _ conds _)) = conds+ eq2Guards _ = []++-- Check an equation for warnings.+-- This is done in a seperate scope as the left-hand-side may introduce+-- new variables.+checkEquation :: Equation () -> WCM ()+checkEquation (Equation _ lhs rhs) = inNestedScope $ do+ checkLhs lhs+ checkRhs rhs+ reportUnusedVars++checkLhs :: Lhs a -> WCM ()+checkLhs (FunLhs _ _ ts) = do+ mapM_ checkPattern ts+ mapM_ (insertPattern False) ts+checkLhs (OpLhs spi t1 op t2) = checkLhs (FunLhs spi op [t1, t2])+checkLhs (ApLhs _ lhs ts) = do+ checkLhs lhs+ mapM_ checkPattern ts+ mapM_ (insertPattern False) ts++checkPattern :: Pattern a -> WCM ()+checkPattern (VariablePattern _ _ v) = checkShadowing v+checkPattern (ConstructorPattern _ _ _ ps) = mapM_ checkPattern ps+checkPattern (InfixPattern spi a p1 f p2) =+ checkPattern (ConstructorPattern spi a f [p1, p2])+checkPattern (ParenPattern _ p) = checkPattern p+checkPattern (RecordPattern _ _ _ fs) = mapM_ (checkField checkPattern) fs+checkPattern (TuplePattern _ ps) = mapM_ checkPattern ps+checkPattern (ListPattern _ _ ps) = mapM_ checkPattern ps+checkPattern (AsPattern _ v p) = checkShadowing v >> checkPattern p+checkPattern (LazyPattern _ p) = checkPattern p+checkPattern (FunctionPattern _ _ _ ps) = mapM_ checkPattern ps+checkPattern (InfixFuncPattern spi a p1 f p2) =+ checkPattern (FunctionPattern spi a f [p1, p2])+checkPattern _ = ok++-- Check the right-hand-side of an equation.+-- Because local declarations may introduce new variables, we need+-- another scope nesting.+checkRhs :: Rhs () -> WCM ()+checkRhs (SimpleRhs _ _ e ds) = inNestedScope $ do+ checkLocalDeclGroup ds+ checkExpr e+ reportUnusedVars+checkRhs (GuardedRhs _ _ ce ds) = inNestedScope $ do+ checkLocalDeclGroup ds+ mapM_ checkCondExpr ce+ reportUnusedVars++checkCondExpr :: CondExpr () -> WCM ()+checkCondExpr (CondExpr _ c e) = checkExpr c >> checkExpr e++checkExpr :: Expression () -> WCM ()+checkExpr (Variable _ _ v) = visitQId v+checkExpr (Paren _ e) = checkExpr e+checkExpr (Typed _ e _) = checkExpr e+checkExpr (Record _ _ _ fs) = mapM_ (checkField checkExpr) fs+checkExpr (RecordUpdate _ e fs) = do+ checkExpr e+ mapM_ (checkField checkExpr) fs+checkExpr (Tuple _ es) = mapM_ checkExpr es+checkExpr (List _ _ es) = mapM_ checkExpr es+checkExpr (ListCompr _ e sts) = checkStatements sts e+checkExpr (EnumFrom _ e) = checkExpr e+checkExpr (EnumFromThen _ e1 e2) = mapM_ checkExpr [e1, e2]+checkExpr (EnumFromTo _ e1 e2) = mapM_ checkExpr [e1, e2]+checkExpr (EnumFromThenTo _ e1 e2 e3) = mapM_ checkExpr [e1, e2, e3]+checkExpr (UnaryMinus _ e) = checkExpr e+checkExpr (Apply _ e1 e2) = mapM_ checkExpr [e1, e2]+checkExpr (InfixApply _ e1 op e2) = do+ visitQId (opName op)+ mapM_ checkExpr [e1, e2]+checkExpr (LeftSection _ e _) = checkExpr e+checkExpr (RightSection _ _ e) = checkExpr e+checkExpr (Lambda _ ps e) = inNestedScope $ do+ mapM_ checkPattern ps+ mapM_ (insertPattern False) ps+ checkExpr e+ reportUnusedVars+checkExpr (Let _ _ ds e) = inNestedScope $ do+ checkLocalDeclGroup ds+ checkExpr e+ reportUnusedVars+checkExpr (Do _ _ sts e) = checkStatements sts e+checkExpr (IfThenElse _ e1 e2 e3) = mapM_ checkExpr [e1, e2, e3]+checkExpr (Case spi _ ct e alts) = do+ checkExpr e+ mapM_ checkAlt alts+ checkCaseAlts spi ct alts+checkExpr _ = ok++checkStatements :: [Statement ()] -> Expression () -> WCM ()+checkStatements [] e = checkExpr e+checkStatements (s:ss) e = inNestedScope $ do+ checkStatement s >> checkStatements ss e+ reportUnusedVars++checkStatement :: Statement () -> WCM ()+checkStatement (StmtExpr _ e) = checkExpr e+checkStatement (StmtDecl _ _ ds) = checkLocalDeclGroup ds+checkStatement (StmtBind _ p e) = do+ checkPattern p >> insertPattern False p+ checkExpr e++checkAlt :: Alt () -> WCM ()+checkAlt (Alt _ p rhs) = inNestedScope $ do+ checkPattern p >> insertPattern False p+ checkRhs rhs+ reportUnusedVars++checkField :: (a -> WCM ()) -> Field a -> WCM ()+checkField check (Field _ _ x) = check x++-- -----------------------------------------------------------------------------+-- Check for orphan instances+-- -----------------------------------------------------------------------------++checkOrphanInstance :: SpanInfo -> Context -> QualIdent -> TypeExpr -> WCM ()+checkOrphanInstance p cx cls ty = warnFor WarnOrphanInstances $ do+ m <- getModuleIdent+ tcEnv <- gets tyConsEnv+ let ocls = getOrigName m cls tcEnv+ otc = getOrigName m tc tcEnv+ unless (isLocalIdent m ocls || isLocalIdent m otc) $ report $+ warnOrphanInstance p $ pPrint $+ InstanceDecl p WhitespaceLayout cx cls ty []+ where tc = typeConstr ty++warnOrphanInstance :: SpanInfo -> Doc -> Message+warnOrphanInstance spi doc = spanInfoMessage spi $ text "Orphan instance:" <+> doc++-- -----------------------------------------------------------------------------+-- Check for missing method implementations+-- -----------------------------------------------------------------------------++checkMissingMethodImplementations :: SpanInfo -> QualIdent -> [Decl a] -> WCM ()+checkMissingMethodImplementations p cls ds = warnFor WarnMissingMethods $ do+ m <- getModuleIdent+ tcEnv <- gets tyConsEnv+ clsEnv <- gets classEnv+ let ocls = getOrigName m cls tcEnv+ ms = classMethods ocls clsEnv+ mapM_ (report . warnMissingMethodImplementation p) $+ filter ((null fs ||) . not . flip (hasDefaultImpl ocls) clsEnv) $ ms \\ fs+ where fs = map unRenameIdent $ concatMap impls ds++warnMissingMethodImplementation :: SpanInfo -> Ident -> Message+warnMissingMethodImplementation spi f = spanInfoMessage spi $ hsep $ map text+ ["No explicit implementation for method", escName f]++-- -----------------------------------------------------------------------------+-- Check for missing type signatures+-- -----------------------------------------------------------------------------++-- |Check if every top-level function has an accompanying type signature.+-- For external function declarations, this check is already performed+-- during syntax checking.+checkMissingTypeSignatures :: [Decl a] -> WCM ()+checkMissingTypeSignatures ds = warnFor WarnMissingSignatures $ do+ let typedFs = [f | TypeSig _ fs _ <- ds, f <- fs]+ untypedFs = [f | FunctionDecl _ _ f _ <- ds, f `notElem` typedFs]+ unless (null untypedFs) $ do+ mid <- getModuleIdent+ tyScs <- mapM getTyScheme untypedFs+ mapM_ report $ zipWith (warnMissingTypeSignature mid) untypedFs tyScs++getTyScheme :: Ident -> WCM TypeScheme+getTyScheme q = do+ m <- getModuleIdent+ tyEnv <- gets valueEnv+ return $ case qualLookupValue (qualifyWith m q) tyEnv of+ [Value _ _ _ tys] -> tys+ _ -> internalError $ "Checks.WarnCheck.getTyScheme: " ++ show q++warnMissingTypeSignature :: ModuleIdent -> Ident -> TypeScheme -> Message+warnMissingTypeSignature mid i tys = spanInfoMessage i $ fsep+ [ text "Top-level binding with no type signature:"+ , nest 2 $ text (showIdent i) <+> text "::" <+> ppTypeScheme mid tys+ ]++-- -----------------------------------------------------------------------------+-- Check for overlapping module alias names+-- -----------------------------------------------------------------------------++-- check if module aliases in import declarations overlap with the module name+-- or another module alias++checkModuleAlias :: [ImportDecl] -> WCM ()+checkModuleAlias is = do+ mid <- getModuleIdent+ let alias = catMaybes [a | ImportDecl _ _ _ a _ <- is]+ modClash = [a | a <- alias, a == mid]+ aliasClash = findMultiples alias+ unless (null modClash) $ mapM_ (report . warnModuleNameClash) modClash+ unless (null aliasClash) $ mapM_ (report . warnAliasNameClash ) aliasClash++warnModuleNameClash :: ModuleIdent -> Message+warnModuleNameClash mid = spanInfoMessage mid $ hsep $ map text+ ["The module alias", escModuleName mid+ , "overlaps with the current module name"]++warnAliasNameClash :: [ModuleIdent] -> Message+warnAliasNameClash [] = internalError+ "WarnCheck.warnAliasNameClash: empty list"+warnAliasNameClash mids = spanInfoMessage (head mids) $ text+ "Overlapping module aliases" $+$ nest 2 (vcat (map myppAlias mids))+ where myppAlias mid =+ ppLine (getPosition mid) <> text ":" <+> text (escModuleName mid)++-- -----------------------------------------------------------------------------+-- Check for overlapping/unreachable and non-exhaustive case alternatives+-- -----------------------------------------------------------------------------++checkCaseAlts :: SpanInfo -> CaseType -> [Alt ()] -> WCM ()+checkCaseAlts _ _ [] = ok+checkCaseAlts spi ct alts = do+ let spis = map (\(Alt s _ _) -> s) alts+ let pats = map (\(Alt _ pat _) -> [pat]) alts+ let guards = map alt2Guards alts+ (nonExhaustive, overlapped, nondet) <- checkPatternMatching pats guards+ case ct of+ Flex -> do+ unless (null nonExhaustive) $ warnFor WarnIncompletePatterns $ report $+ warnMissingPattern spi "an fcase alternative" nonExhaustive+ when (nondet || not (null overlapped)) $ warnFor WarnOverlapping $ report+ $ warnNondetOverlapping spi "An fcase expression"+ Rigid -> do+ unless (null nonExhaustive) $ warnFor WarnIncompletePatterns $ report $+ warnMissingPattern spi "a case alternative" nonExhaustive+ unless (null overlapped) $ void $ mapM (warnFor WarnOverlapping . report) $+ map (\(i, pat) -> warnUnreachablePattern (spis !! i) pat) overlapped+ where alt2Guards :: Alt () -> [CondExpr ()]+ alt2Guards (Alt _ _ (GuardedRhs _ _ conds _)) = conds+ alt2Guards _ = []++-- -----------------------------------------------------------------------------+-- Check for non-exhaustive and overlapping patterns.+-- For an example, consider the following function definition:+-- @+-- f [True] = 0+-- f (False:_) = 1+-- @+-- In this declaration, the following patterns are not matched:+-- @+-- [] _+-- (True:_:_)+-- @+-- This is identified and reported by the following code,, both for pattern+-- matching in function declarations and (f)case expressions.+-- -----------------------------------------------------------------------------++checkPatternMatching :: [[Pattern ()]] -> [[CondExpr ()]]+ -> WCM ([ExhaustivePats], [OverlappingPats], Bool)+checkPatternMatching pats guards = do+ -- 1. We simplify the patterns by removing syntactic sugar temporarily+ -- for a simpler implementation.+ simplePats <- mapM (mapM simplifyPat) pats+ -- 2. We compute missing and used pattern matching alternatives+ (missing, used, nondet) <- processEqs (zip3 [0..] simplePats guards)+ -- 3. If any, we report the missing patterns, whereby we re-add the syntactic+ -- sugar removed in step (1) for a more precise output.+ nonExhaustive <- mapM tidyExhaustivePats missing+ let overlap = [(i, eqn) | (i, eqn) <- zip [0..] pats, i `IntSet.notMember` used]+ return (nonExhaustive, overlap, nondet)++-- |Simplify a 'Pattern' until it only consists of+-- * Variables+-- * Integer, Float or Char literals+-- * Constructors+-- All other patterns like as-patterns, list patterns and alike are desugared.+simplifyPat :: Pattern () -> WCM (Pattern ())+simplifyPat p@(LiteralPattern _ _ l) = return $ case l of+ String s -> simplifyListPattern $ map (LiteralPattern NoSpanInfo () . Char) s+ _ -> p+simplifyPat (NegativePattern spi a l) =+ return $ LiteralPattern spi a (negateLit l)+ where+ negateLit (Int n) = Int (-n)+ negateLit (Float d) = Float (-d)+ negateLit x = x+simplifyPat v@(VariablePattern _ _ _) = return v+simplifyPat (ConstructorPattern spi a c ps) =+ ConstructorPattern spi a c `liftM` mapM simplifyPat ps+simplifyPat (InfixPattern spi a p1 c p2) =+ ConstructorPattern spi a c `liftM` mapM simplifyPat [p1, p2]+simplifyPat (ParenPattern _ p) = simplifyPat p+simplifyPat (RecordPattern _ _ c fs) = do+ (_, ls) <- getAllLabels c+ let ps = map (getPattern (map field2Tuple fs)) ls+ simplifyPat (ConstructorPattern NoSpanInfo () c ps)+ where+ getPattern fs' l' =+ fromMaybe wildPat (lookup l' [(unqualify l, p) | (l, p) <- fs'])+simplifyPat (TuplePattern _ ps) =+ ConstructorPattern NoSpanInfo () (qTupleId (length ps))+ `liftM` mapM simplifyPat ps+simplifyPat (ListPattern _ _ ps) =+ simplifyListPattern `liftM` mapM simplifyPat ps+simplifyPat (AsPattern _ _ p) = simplifyPat p+simplifyPat (LazyPattern _ _) = return wildPat+simplifyPat (FunctionPattern _ _ _ _) = return wildPat+simplifyPat (InfixFuncPattern _ _ _ _ _) = return wildPat++getAllLabels :: QualIdent -> WCM (QualIdent, [Ident])+getAllLabels c = do+ tyEnv <- gets valueEnv+ case qualLookupValue c tyEnv of+ [DataConstructor qc _ ls _] -> return (qc, ls)+ _ -> internalError $+ "Checks.WarnCheck.getAllLabels: " ++ show c++-- |Create a simplified list pattern by applying @:@ and @[]@.+simplifyListPattern :: [Pattern ()] -> Pattern ()+simplifyListPattern =+ foldr (\p1 p2 -> ConstructorPattern NoSpanInfo () qConsId [p1, p2])+ (ConstructorPattern NoSpanInfo () qNilId [])++-- |'ExhaustivePats' describes those pattern missing for an exhaustive+-- pattern matching, where a value can be thought of as a missing equation.+-- The first component contains the unmatched patterns, while the second+-- pattern contains an identifier and the literals matched for this identifier.+--+-- This is necessary when checking literal patterns because of the sheer+-- number of possible patterns. Missing literals are therefore converted+-- into the form @ ... x ... with x `notElem` [l1, ..., ln]@.+type EqnPats = [Pattern ()]+type EqnGuards = [CondExpr ()]+type EqnNo = Int+type EqnInfo = (EqnNo, EqnPats, EqnGuards)++type ExhaustivePats = (EqnPats, [(Ident, [Literal])])+type OverlappingPats = (EqnNo, EqnPats)+type EqnSet = IntSet.IntSet++-- |Compute the missing pattern by inspecting the first patterns and+-- categorize them as literal, constructor or variable patterns.+processEqs :: [EqnInfo] -> WCM ([ExhaustivePats], EqnSet, Bool)+processEqs [] = return ([], IntSet.empty, False)+processEqs eqs@((n, ps, gs):eqs')+ | null ps = if guardsExhaustive then return ([], IntSet.singleton n, length eqs > 1)+ else do -- Current expression is guarded, thus potentially+ -- non-exhaustive. Therefore process remaining expressions.+ (missing', used', _) <- processEqs eqs'+ return (missing', IntSet.insert n used', length eqs > 1)+ | any isLitPat firstPats = processLits eqs+ | any isConPat firstPats = processCons eqs+ | all isVarPat firstPats = processVars eqs+ | otherwise = internalError "Checks.WarnCheck.processEqs"+ where firstPats = map firstPat eqs+ guardsExhaustive = null gs || any guardAlwaysTrue gs+ guardAlwaysTrue :: CondExpr () -> Bool+ guardAlwaysTrue (CondExpr _ e _) = case e of+ Constructor _ _ q -> qidAlwaysTrue q+ Variable _ _ q -> qidAlwaysTrue q+ _ -> False+ qidAlwaysTrue :: QualIdent -> Bool+ qidAlwaysTrue q = elem (idName $ qidIdent q) ["True", "success", "otherwise"]+ ++-- |Literal patterns are checked by extracting the matched literals+-- and constructing a pattern for any missing case.+processLits :: [EqnInfo] -> WCM ([ExhaustivePats], EqnSet, Bool)+processLits [] = error "WarnCheck.processLits"+processLits qs@(q:_) = do+ -- Check any patterns starting with the literals used+ (missing1, used1, nd1) <- processUsedLits usedLits qs+ if null defaults+ then return $ (defaultPat : missing1, used1, nd1)+ else do+ -- Missing patterns for the default alternatives+ (missing2, used2, nd2) <- processEqs defaults+ return ( [ (wildPat : ps, cs) | (ps, cs) <- missing2 ] ++ missing1+ , IntSet.union used1 used2, nd1 || nd2 )+ where+ -- The literals occurring in the patterns+ usedLits = nub $ concatMap (getLit . firstPat) qs+ -- default alternatives (variable pattern)+ defaults = [ shiftPat q' | q' <- qs, isVarPat (firstPat q') ]+ -- Pattern for all non-matched literals+ defaultPat = ( VariablePattern NoSpanInfo () newVar :+ replicate (length (snd3 q) - 1) wildPat+ , [(newVar, usedLits)]+ )+ newVar = mkIdent "x"++-- |Construct exhaustive patterns starting with the used literals+processUsedLits :: [Literal] -> [EqnInfo]+ -> WCM ([ExhaustivePats], EqnSet, Bool)+processUsedLits lits qs = do+ (eps, idxs, nds) <- unzip3 `liftM` mapM process lits+ return (concat eps, IntSet.unions idxs, or nds)+ where+ process lit = do+ let qs' = [shiftPat q | q <- qs, isVarLit lit (firstPat q)]+ ovlp = length qs' > 1+ (missing, used, nd) <- processEqs qs'+ return ( map (\(xs, ys) -> (LiteralPattern NoSpanInfo () lit : xs, ys))+ missing+ , used+ , nd && ovlp+ )++-- |Constructor patterns are checked by extracting the matched constructors+-- and constructing a pattern for any missing case.+processCons :: [EqnInfo] -> WCM ([ExhaustivePats], EqnSet, Bool)+processCons [] = error "WarnCheck.processCons"+processCons qs@(q:_) = do+ -- Compute any missing patterns starting with the used constructors+ (missing1, used1, nd) <- processUsedCons used_cons qs+ -- Determine unused constructors+ unused <- getUnusedCons (map fst used_cons)+ if null unused+ then return (missing1, used1, nd)+ else if null defaults+ then return $ (map defaultPat unused ++ missing1, used1, nd)+ else do+ -- Missing patterns for the default alternatives+ (missing2, used2, nd2) <- processEqs defaults+ return ( [ (mkPattern c : ps, cs) | c <- unused, (ps, cs) <- missing2 ]+ ++ missing1+ , IntSet.union used1 used2, nd || nd2)+ where+ -- used constructors (occurring in a pattern)+ used_cons = nub $ concatMap (getCon . firstPat) qs+ -- default alternatives (variable pattern)+ defaults = [ shiftPat q' | q' <- qs, isVarPat (firstPat q') ]+ -- Pattern for a non-matched constructors+ defaultPat c = (mkPattern c : replicate (length (snd3 q) - 1) wildPat, [])+ mkPattern c = ConstructorPattern NoSpanInfo ()+ (qualifyLike (fst $ head used_cons) (constrIdent c))+ (replicate (length $ constrTypes c) wildPat)++-- |Construct exhaustive patterns starting with the used constructors+processUsedCons :: [(QualIdent, Int)] -> [EqnInfo]+ -> WCM ([ExhaustivePats], EqnSet, Bool)+processUsedCons cons qs = do+ (eps, idxs, nds) <- unzip3 `liftM` mapM process cons+ return (concat eps, IntSet.unions idxs, or nds)+ where+ process (c, a) = do+ let qs' = [ removeFirstCon c a q | q <- qs , isVarCon c (firstPat q)]+ ovlp = length qs' > 1+ (missing, used, nd) <- processEqs qs'+ return (map (\(xs, ys) -> (makeCon c a xs, ys)) missing, used, nd && ovlp)++ makeCon c a ps = let (args, rest) = splitAt a ps+ in ConstructorPattern NoSpanInfo () c args : rest+ + removeFirstCon c a (n, p:ps, gs)+ | isVarPat p = (n, replicate a wildPat ++ ps, gs)+ | isCon c p = (n, patArgs p ++ ps, gs)+ removeFirstCon _ _ _ = internalError "Checks.WarnCheck.removeFirstCon"++-- |Variable patterns are exhaustive, so they are checked by simply+-- checking the following patterns.+processVars :: [EqnInfo] -> WCM ([ExhaustivePats], EqnSet, Bool)+processVars [] = error "WarnCheck.processVars"+processVars eqs@((n, _, _) : _) = do+ let ovlp = length eqs > 1+ (missing, used, nd) <- processEqs (map shiftPat eqs)+ return ( map (\(xs, ys) -> (wildPat : xs, ys)) missing+ , IntSet.insert n used, nd && ovlp)++-- |Return the constructors of a type not contained in the list of constructors.+getUnusedCons :: [QualIdent] -> WCM [DataConstr]+getUnusedCons [] = internalError "Checks.WarnCheck.getUnusedCons"+getUnusedCons qs@(q:_) = do+ allCons <- getConTy q >>= getTyCons . rootOfType . arrowBase+ return [c | c <- allCons, (constrIdent c) `notElem` map unqualify qs]++-- |Retrieve the type of a given constructor.+getConTy :: QualIdent -> WCM Type+getConTy q = do+ tyEnv <- gets valueEnv+ tcEnv <- gets tyConsEnv+ case qualLookupValue q tyEnv of+ [DataConstructor _ _ _ (ForAll _ (PredType _ ty))] -> return ty+ [NewtypeConstructor _ _ (ForAll _ (PredType _ ty))] -> return ty+ _ -> case qualLookupTypeInfo q tcEnv of+ [AliasType _ _ _ ty] -> return ty+ _ -> internalError $ "Checks.WarnCheck.getConTy: " ++ show q++-- |Retrieve all constructors of a given type.+getTyCons :: QualIdent -> WCM [DataConstr]+getTyCons tc = do+ tc' <- unAlias tc+ tcEnv <- gets tyConsEnv+ let getTyCons' :: [TypeInfo] -> Either String [DataConstr]+ getTyCons' ti = case ti of+ [DataType _ _ cs] -> Right cs+ [RenamingType _ _ nc] -> Right $ [nc]+ _ -> Left $ "Checks.WarnCheck.getTyCons: " ++ show tc ++ ' ' : show ti ++ '\n' : show tcEnv+ csResult = getTyCons' (qualLookupTypeInfo tc tcEnv)+ <|> getTyCons' (qualLookupTypeInfo tc' tcEnv)+ <|> getTyCons' (lookupTypeInfo (unqualify tc) tcEnv) -- Fall back on unqualified lookup if qualified doesn't work+ case csResult of+ Right cs -> return cs+ Left err -> internalError err++-- |Resugar the exhaustive patterns previously desugared at 'simplifyPat'.+tidyExhaustivePats :: ExhaustivePats -> WCM ExhaustivePats+tidyExhaustivePats (xs, ys) = mapM tidyPat xs >>= \xs' -> return (xs', ys)++-- |Resugar a pattern previously desugared at 'simplifyPat', i.e.+-- * Convert a tuple constructor pattern into a tuple pattern+-- * Convert a list constructor pattern representing a finite list+-- into a list pattern+tidyPat :: Pattern () -> WCM (Pattern ())+tidyPat p@(LiteralPattern _ _ _) = return p+tidyPat p@(VariablePattern _ _ _) = return p+tidyPat p@(ConstructorPattern _ _ c ps)+ | isQTupleId c =+ TuplePattern NoSpanInfo `liftM` mapM tidyPat ps+ | c == qConsId && isFiniteList p =+ ListPattern NoSpanInfo () `liftM` mapM tidyPat (unwrapFinite p)+ | c == qConsId = unwrapInfinite p+ | otherwise =+ ConstructorPattern NoSpanInfo () c `liftM` mapM tidyPat ps+ where+ isFiniteList (ConstructorPattern _ _ d [] ) = d == qNilId+ isFiniteList (ConstructorPattern _ _ d [_, e2])+ | d == qConsId = isFiniteList e2+ isFiniteList _ = False++ unwrapFinite (ConstructorPattern _ _ _ [] ) = []+ unwrapFinite (ConstructorPattern _ _ _ [p1,p2]) = p1 : unwrapFinite p2+ unwrapFinite pat+ = internalError $ "WarnCheck.tidyPat.unwrapFinite: " ++ show pat++ unwrapInfinite (ConstructorPattern _ a d [p1,p2]) =+ liftM2 (flip (InfixPattern NoSpanInfo a) d) (tidyPat p1) (unwrapInfinite p2)+ unwrapInfinite p0 = return p0++tidyPat p = internalError $ "Checks.WarnCheck.tidyPat: " ++ show p++-- |Get the first pattern of a list.+firstPat :: EqnInfo -> Pattern ()+firstPat (_, [], _) = internalError "Checks.WarnCheck.firstPat: empty list"+firstPat (_, (p:_), _) = p++-- |Drop the first pattern of a list.+shiftPat :: EqnInfo -> EqnInfo+shiftPat (_, [], _ ) = internalError "Checks.WarnCheck.shiftPat: empty list"+shiftPat (n, (_:ps), gs) = (n, ps, gs)++-- |Wildcard pattern.+wildPat :: Pattern ()+wildPat = VariablePattern NoSpanInfo () anonId++-- |Retrieve any literal out of a pattern.+getLit :: Pattern a -> [Literal]+getLit (LiteralPattern _ _ l) = [l]+getLit _ = []++-- |Retrieve the constructor name and its arity for a pattern.+getCon :: Pattern a -> [(QualIdent, Int)]+getCon (ConstructorPattern _ _ c ps) = [(c, length ps)]+getCon _ = []++-- |Is a pattern a variable or literal pattern?+isVarLit :: Literal -> Pattern a -> Bool+isVarLit l p = isVarPat p || isLit l p++-- |Is a pattern a variable or a constructor pattern with the given constructor?+isVarCon :: QualIdent -> Pattern a -> Bool+isVarCon c p = isVarPat p || isCon c p++-- |Is a pattern a pattern matching for the given constructor?+isCon :: QualIdent -> Pattern a -> Bool+isCon c (ConstructorPattern _ _ d _) = c == d+isCon _ _ = False++-- |Is a pattern a pattern matching for the given literal?+isLit :: Literal -> Pattern a -> Bool+isLit l (LiteralPattern _ _ m) = l == m+isLit _ _ = False++-- |Is a pattern a literal pattern?+isLitPat :: Pattern a -> Bool+isLitPat (LiteralPattern _ _ _) = True+isLitPat _ = False++-- |Is a pattern a variable pattern?+isVarPat :: Pattern a -> Bool+isVarPat (VariablePattern _ _ _) = True+isVarPat _ = False++-- |Is a pattern a constructor pattern?+isConPat :: Pattern a -> Bool+isConPat (ConstructorPattern _ _ _ _) = True+isConPat _ = False++-- |Retrieve the arguments of a pattern.+patArgs :: Pattern a -> [Pattern a]+patArgs (ConstructorPattern _ _ _ ps) = ps+patArgs _ = []++-- |Warning message for non-exhaustive patterns.+-- To shorten the output only the first 'maxPattern' are printed,+-- additional pattern are abbreviated by dots.+warnMissingPattern :: SpanInfo -> String -> [ExhaustivePats] -> Message+warnMissingPattern spi loc pats = spanInfoMessage spi+ $ text "Pattern matches are non-exhaustive"+ $+$ text "In" <+> text loc <> char ':'+ $+$ nest 2 (text "Patterns not matched:" $+$ nest 2 (vcat (ppExPats pats)))+ where+ ppExPats ps+ | length ps > maxPattern = ppPats ++ [text "..."]+ | otherwise = ppPats+ where ppPats = map ppExPat (take maxPattern ps)+ ppExPat (ps, cs)+ | null cs = ppPats+ | otherwise = ppPats <+> text "with" <+> hsep (map ppCons cs)+ where ppPats = hsep (map (pPrintPrec 2) ps)+ ppCons (i, lits) = pPrint i <+> text "`notElem`"+ <+> pPrintPrec 0 (List NoSpanInfo () (map (Literal NoSpanInfo ()) lits))++-- |Warning message for unreachable patterns.+-- To shorten the output only the first 'maxPattern' are printed,+-- additional pattern are abbreviated by dots.+warnUnreachablePattern :: SpanInfo -> [Pattern a] -> Message+warnUnreachablePattern spi pats = spanInfoMessage spi+ $ text "Pattern matches are potentially unreachable"+ $+$ text "In a case alternative:"+ $+$ nest 2 (ppPat pats <+> text "->" <+> text "...")+ where+ ppPat ps = hsep (map (pPrintPrec 2) ps)++-- |Maximum number of missing patterns to be shown.+maxPattern :: Int+maxPattern = 4++warnNondetOverlapping :: SpanInfo -> String -> Message+warnNondetOverlapping spi loc = spanInfoMessage spi $+ text loc <+> text "is potentially non-deterministic due to overlapping rules"++-- -----------------------------------------------------------------------------++checkShadowing :: Ident -> WCM ()+checkShadowing x = warnFor WarnNameShadowing $+ shadowsVar x >>= maybe ok (report . warnShadowing x)++reportUnusedVars :: WCM ()+reportUnusedVars = reportAllUnusedVars WarnUnusedBindings++reportUnusedGlobalVars :: WCM ()+reportUnusedGlobalVars = reportAllUnusedVars WarnUnusedGlobalBindings++reportAllUnusedVars :: WarnFlag -> WCM ()+reportAllUnusedVars wFlag = warnFor wFlag $ do+ unused <- returnUnrefVars+ unless (null unused) $ mapM_ report $ map warnUnrefVar unused++reportUnusedTypeVars :: [Ident] -> WCM ()+reportUnusedTypeVars vs = warnFor WarnUnusedBindings $ do+ unused <- filterM isUnrefTypeVar vs+ unless (null unused) $ mapM_ report $ map warnUnrefTypeVar unused++-- ---------------------------------------------------------------------------+-- For detecting unreferenced variables, the following functions update the+-- current check state by adding identifiers occuring in declaration left hand+-- sides.++insertDecl :: Decl a -> WCM ()+insertDecl (DataDecl _ d _ cs _) = do+ insertTypeConsId d+ mapM_ insertConstrDecl cs+insertDecl (ExternalDataDecl _ d _) = insertTypeConsId d+insertDecl (NewtypeDecl _ d _ nc _) = do+ insertTypeConsId d+ insertNewConstrDecl nc+insertDecl (TypeDecl _ t _ ty) = do+ insertTypeConsId t+ insertTypeExpr ty+insertDecl (FunctionDecl _ _ f _) = do+ cons <- isConsId f+ unless cons $ insertVar f+insertDecl (ExternalDecl _ vs) = mapM_ (insertVar . varIdent) vs+insertDecl (PatternDecl _ p _) = insertPattern False p+insertDecl (FreeDecl _ vs) = mapM_ (insertVar . varIdent) vs+insertDecl (ClassDecl _ _ _ cls _ ds) = do+ insertTypeConsId cls+ mapM_ insertVar $ concatMap methods ds+insertDecl _ = ok++insertTypeExpr :: TypeExpr -> WCM ()+insertTypeExpr (VariableType _ _) = ok+insertTypeExpr (ConstructorType _ _) = ok+insertTypeExpr (ApplyType _ ty1 ty2) = mapM_ insertTypeExpr [ty1,ty2]+insertTypeExpr (TupleType _ tys) = mapM_ insertTypeExpr tys+insertTypeExpr (ListType _ ty) = insertTypeExpr ty+insertTypeExpr (ArrowType _ ty1 ty2) = mapM_ insertTypeExpr [ty1,ty2]+insertTypeExpr (ParenType _ ty) = insertTypeExpr ty+insertTypeExpr (ForallType _ _ ty) = insertTypeExpr ty++insertConstrDecl :: ConstrDecl -> WCM ()+insertConstrDecl (ConstrDecl _ c _) = insertConsId c+insertConstrDecl (ConOpDecl _ _ op _) = insertConsId op+insertConstrDecl (RecordDecl _ c _) = insertConsId c++insertNewConstrDecl :: NewConstrDecl -> WCM ()+insertNewConstrDecl (NewConstrDecl _ c _) = insertConsId c+insertNewConstrDecl (NewRecordDecl _ c _) = insertConsId c++-- 'fp' indicates whether 'checkPattern' deals with the arguments+-- of a function pattern or not.+-- Since function patterns are not recognized before syntax check, it is+-- necessary to determine whether a constructor pattern represents a+-- constructor or a function.+insertPattern :: Bool -> Pattern a -> WCM ()+insertPattern fp (VariablePattern _ _ v) = do+ cons <- isConsId v+ unless cons $ do+ var <- isVarId v+ if and [fp, var, not (isAnonId v)] then visitId v else insertVar v+insertPattern fp (ConstructorPattern _ _ c ps) = do+ cons <- isQualConsId c+ mapM_ (insertPattern (not cons || fp)) ps+insertPattern fp (InfixPattern spi a p1 c p2)+ = insertPattern fp (ConstructorPattern spi a c [p1, p2])+insertPattern fp (ParenPattern _ p) = insertPattern fp p+insertPattern fp (RecordPattern _ _ _ fs) = mapM_ (insertFieldPattern fp) fs+insertPattern fp (TuplePattern _ ps) = mapM_ (insertPattern fp) ps+insertPattern fp (ListPattern _ _ ps) = mapM_ (insertPattern fp) ps+insertPattern fp (AsPattern _ v p) = insertVar v >> insertPattern fp p+insertPattern fp (LazyPattern _ p) = insertPattern fp p+insertPattern _ (FunctionPattern _ _ f ps) = do+ visitQId f+ mapM_ (insertPattern True) ps+insertPattern _ (InfixFuncPattern spi a p1 f p2)+ = insertPattern True (FunctionPattern spi a f [p1, p2])+insertPattern _ _ = ok++insertFieldPattern :: Bool -> Field (Pattern a) -> WCM ()+insertFieldPattern fp (Field _ _ p) = insertPattern fp p++-- ---------------------------------------------------------------------------++-- Data type for distinguishing identifiers as either (type) constructors or+-- (type) variables (including functions).+data IdInfo+ = ConsInfo -- ^ Constructor+ | VarInfo Ident Bool -- ^ Variable with original definition (for position)+ -- and used flag+ deriving Show++isVariable :: IdInfo -> Bool+isVariable (VarInfo _ _) = True+isVariable _ = False++getVariable :: IdInfo -> Maybe Ident+getVariable (VarInfo v _) = Just v+getVariable _ = Nothing++isConstructor :: IdInfo -> Bool+isConstructor ConsInfo = True+isConstructor _ = False++variableVisited :: IdInfo -> Bool+variableVisited (VarInfo _ v) = v+variableVisited _ = True++visitVariable :: IdInfo -> IdInfo+visitVariable (VarInfo v _) = VarInfo v True+visitVariable info = info++insertScope :: QualIdent -> IdInfo -> WCM ()+insertScope qid info = modifyScope $ qualBindNestEnv qid info++insertVar :: Ident -> WCM ()+insertVar v = unless (isAnonId v) $ do+ known <- isKnownVar v+ if known then visitId v else insertScope (commonId v) (VarInfo v False)++insertTypeVar :: Ident -> WCM ()+insertTypeVar v = unless (isAnonId v)+ $ insertScope (typeId v) (VarInfo v False)++insertConsId :: Ident -> WCM ()+insertConsId c = insertScope (commonId c) ConsInfo++insertTypeConsId :: Ident -> WCM ()+insertTypeConsId c = insertScope (typeId c) ConsInfo++isVarId :: Ident -> WCM Bool+isVarId v = gets (isVar $ commonId v)++isConsId :: Ident -> WCM Bool+isConsId c = gets (isCons $ qualify c)++isQualConsId :: QualIdent -> WCM Bool+isQualConsId qid = gets (isCons qid)++shadows :: QualIdent -> WcState -> Maybe Ident+shadows qid s = do+ guard $ not (qualInLocalNestEnv qid sc)+ info <- listToMaybe $ qualLookupNestEnv qid sc+ getVariable info+ where sc = scope s++shadowsVar :: Ident -> WCM (Maybe Ident)+shadowsVar v = gets (shadows $ commonId v)++visitId :: Ident -> WCM ()+visitId v = modifyScope (qualModifyNestEnv visitVariable (commonId v))++visitQId :: QualIdent -> WCM ()+visitQId v = do+ mid <- getModuleIdent+ maybe ok visitId (localIdent mid v)++visitTypeId :: Ident -> WCM ()+visitTypeId v = modifyScope (qualModifyNestEnv visitVariable (typeId v))++visitQTypeId :: QualIdent -> WCM ()+visitQTypeId v = do+ mid <- getModuleIdent+ maybe ok visitTypeId (localIdent mid v)++isKnownVar :: Ident -> WCM Bool+isKnownVar v = gets $ \s -> isKnown s (commonId v)++isUnrefTypeVar :: Ident -> WCM Bool+isUnrefTypeVar v = gets (\s -> isUnref s (typeId v))++returnUnrefVars :: WCM [Ident]+returnUnrefVars = gets (\s ->+ let ids = map fst (localNestEnv (scope s))+ unrefs = filter (isUnref s . qualify) ids+ in unrefs )++inNestedScope :: WCM a -> WCM ()+inNestedScope m = beginScope >> m >> endScope++beginScope :: WCM ()+beginScope = modifyScope nestEnv++endScope :: WCM ()+endScope = modifyScope unnestEnv++------------------------------------------------------------------------------++isKnown :: WcState -> QualIdent -> Bool+isKnown s qid = qualInLocalNestEnv qid (scope s)++isUnref :: WcState -> QualIdent -> Bool+isUnref s qid = let sc = scope s+ in any (not . variableVisited) (qualLookupNestEnv qid sc)+ && qualInLocalNestEnv qid sc++isVar :: QualIdent -> WcState -> Bool+isVar qid s = maybe (isAnonId (unqualify qid))+ isVariable+ (listToMaybe (qualLookupNestEnv qid (scope s)))++isCons :: QualIdent -> WcState -> Bool+isCons qid s = maybe (isImportedCons s qid)+ isConstructor+ (listToMaybe (qualLookupNestEnv qid (scope s)))+ where isImportedCons s' qid' = case qualLookupValue qid' (valueEnv s') of+ (DataConstructor _ _ _ _) : _ -> True+ (NewtypeConstructor _ _ _) : _ -> True+ _ -> False++-- Since type identifiers and normal identifiers (e.g. functions, variables+-- or constructors) don't share the same namespace, it is necessary+-- to distinguish them in the scope environment of the check state.+-- For this reason type identifiers are annotated with 1 and normal+-- identifiers are annotated with 0.+commonId :: Ident -> QualIdent+commonId = qualify . unRenameIdent++typeId :: Ident -> QualIdent+typeId = qualify . flip renameIdent 1+++-- --------------------------------------------------------------------------+-- Check Case Mode+-- --------------------------------------------------------------------------+++-- The following functions traverse the AST and search for (defining)+-- identifiers and check if their names have the appropriate case mode.+checkCaseMode :: [Decl a] -> WCM ()+checkCaseMode = warnFor WarnIrregularCaseMode . mapM_ checkCaseModeDecl++checkCaseModeDecl :: Decl a -> WCM ()+checkCaseModeDecl (DataDecl _ tc vs cs _) = do+ checkCaseModeID isDataDeclName tc+ mapM_ (checkCaseModeID isVarName) vs+ mapM_ checkCaseModeConstr cs+checkCaseModeDecl (NewtypeDecl _ tc vs nc _) = do+ checkCaseModeID isDataDeclName tc+ mapM_ (checkCaseModeID isVarName) vs+ checkCaseModeNewConstr nc+checkCaseModeDecl (TypeDecl _ tc vs ty) = do+ checkCaseModeID isDataDeclName tc+ mapM_ (checkCaseModeID isVarName) vs+ checkCaseModeTypeExpr ty+checkCaseModeDecl (TypeSig _ fs qty) = do+ mapM_ (checkCaseModeID isFuncName) fs+ checkCaseModeQualTypeExpr qty+checkCaseModeDecl (FunctionDecl _ _ f eqs) = do+ checkCaseModeID isFuncName f+ mapM_ checkCaseModeEquation eqs+checkCaseModeDecl (ExternalDecl _ vs) =+ mapM_ (checkCaseModeID isFuncName . varIdent) vs+checkCaseModeDecl (PatternDecl _ t rhs) = do+ checkCaseModePattern t+ checkCaseModeRhs rhs+checkCaseModeDecl (FreeDecl _ vs) =+ mapM_ (checkCaseModeID isVarName . varIdent) vs+checkCaseModeDecl (DefaultDecl _ tys) = mapM_ checkTypeExpr tys+checkCaseModeDecl (ClassDecl _ _ cx cls tv ds) = do+ checkCaseModeContext cx+ checkCaseModeID isClassDeclName cls+ checkCaseModeID isVarName tv+ mapM_ checkCaseModeDecl ds+checkCaseModeDecl (InstanceDecl _ _ cx _ inst ds) = do+ checkCaseModeContext cx+ checkCaseModeTypeExpr inst+ mapM_ checkCaseModeDecl ds+checkCaseModeDecl _ = ok++checkCaseModeConstr :: ConstrDecl -> WCM ()+checkCaseModeConstr (ConstrDecl _ c tys) = do+ checkCaseModeID isConstrName c+ mapM_ checkCaseModeTypeExpr tys+checkCaseModeConstr (ConOpDecl _ ty1 c ty2) = do+ checkCaseModeTypeExpr ty1+ checkCaseModeID isConstrName c+ checkCaseModeTypeExpr ty2+checkCaseModeConstr (RecordDecl _ c fs) = do+ checkCaseModeID isConstrName c+ mapM_ checkCaseModeFieldDecl fs++checkCaseModeFieldDecl :: FieldDecl -> WCM ()+checkCaseModeFieldDecl (FieldDecl _ fs ty) = do+ mapM_ (checkCaseModeID isFuncName) fs+ checkCaseModeTypeExpr ty++checkCaseModeNewConstr :: NewConstrDecl -> WCM ()+checkCaseModeNewConstr (NewConstrDecl _ nc ty) = do+ checkCaseModeID isConstrName nc+ checkCaseModeTypeExpr ty+checkCaseModeNewConstr (NewRecordDecl _ nc (f, ty)) = do+ checkCaseModeID isConstrName nc+ checkCaseModeID isFuncName f+ checkCaseModeTypeExpr ty++checkCaseModeContext :: Context -> WCM ()+checkCaseModeContext = mapM_ checkCaseModeConstraint++checkCaseModeConstraint :: Constraint -> WCM ()+checkCaseModeConstraint (Constraint _ _ ty) = checkCaseModeTypeExpr ty++checkCaseModeTypeExpr :: TypeExpr -> WCM ()+checkCaseModeTypeExpr (ApplyType _ ty1 ty2) = do+ checkCaseModeTypeExpr ty1+ checkCaseModeTypeExpr ty2+checkCaseModeTypeExpr (VariableType _ tv) = checkCaseModeID isVarName tv+checkCaseModeTypeExpr (TupleType _ tys) = mapM_ checkCaseModeTypeExpr tys+checkCaseModeTypeExpr (ListType _ ty) = checkCaseModeTypeExpr ty+checkCaseModeTypeExpr (ArrowType _ ty1 ty2) = do+ checkCaseModeTypeExpr ty1+ checkCaseModeTypeExpr ty2+checkCaseModeTypeExpr (ParenType _ ty) = checkCaseModeTypeExpr ty+checkCaseModeTypeExpr (ForallType _ tvs ty) = do+ mapM_ (checkCaseModeID isVarName) tvs+ checkCaseModeTypeExpr ty+checkCaseModeTypeExpr _ = ok++checkCaseModeQualTypeExpr :: QualTypeExpr -> WCM ()+checkCaseModeQualTypeExpr (QualTypeExpr _ cx ty) = do+ checkCaseModeContext cx+ checkCaseModeTypeExpr ty++checkCaseModeEquation :: Equation a -> WCM ()+checkCaseModeEquation (Equation _ lhs rhs) = do+ checkCaseModeLhs lhs+ checkCaseModeRhs rhs++checkCaseModeLhs :: Lhs a -> WCM ()+checkCaseModeLhs (FunLhs _ f ts) = do+ checkCaseModeID isFuncName f+ mapM_ checkCaseModePattern ts+checkCaseModeLhs (OpLhs _ t1 f t2) = do+ checkCaseModePattern t1+ checkCaseModeID isFuncName f+ checkCaseModePattern t2+checkCaseModeLhs (ApLhs _ lhs ts) = do+ checkCaseModeLhs lhs+ mapM_ checkCaseModePattern ts++checkCaseModeRhs :: Rhs a -> WCM ()+checkCaseModeRhs (SimpleRhs _ _ e ds) = do+ checkCaseModeExpr e+ mapM_ checkCaseModeDecl ds+checkCaseModeRhs (GuardedRhs _ _ es ds) = do+ mapM_ checkCaseModeCondExpr es+ mapM_ checkCaseModeDecl ds++checkCaseModeCondExpr :: CondExpr a -> WCM ()+checkCaseModeCondExpr (CondExpr _ g e) = do+ checkCaseModeExpr g+ checkCaseModeExpr e++checkCaseModePattern :: Pattern a -> WCM ()+checkCaseModePattern (VariablePattern _ _ v) = checkCaseModeID isVarName v+checkCaseModePattern (ConstructorPattern _ _ _ ts) =+ mapM_ checkCaseModePattern ts+checkCaseModePattern (InfixPattern _ _ t1 _ t2) = do+ checkCaseModePattern t1+ checkCaseModePattern t2+checkCaseModePattern (ParenPattern _ t) = checkCaseModePattern t+checkCaseModePattern (RecordPattern _ _ _ fs) =+ mapM_ checkCaseModeFieldPattern fs+checkCaseModePattern (TuplePattern _ ts) = mapM_ checkCaseModePattern ts+checkCaseModePattern (ListPattern _ _ ts) = mapM_ checkCaseModePattern ts+checkCaseModePattern (AsPattern _ v t) = do+ checkCaseModeID isVarName v+ checkCaseModePattern t+checkCaseModePattern (LazyPattern _ t) = checkCaseModePattern t+checkCaseModePattern (FunctionPattern _ _ _ ts) = mapM_ checkCaseModePattern ts+checkCaseModePattern (InfixFuncPattern _ _ t1 _ t2) = do+ checkCaseModePattern t1+ checkCaseModePattern t2+checkCaseModePattern _ = ok++checkCaseModeExpr :: Expression a -> WCM ()+checkCaseModeExpr (Paren _ e) = checkCaseModeExpr e+checkCaseModeExpr (Typed _ e qty) = do+ checkCaseModeExpr e+ checkCaseModeQualTypeExpr qty+checkCaseModeExpr (Record _ _ _ fs) = mapM_ checkCaseModeFieldExpr fs+checkCaseModeExpr (RecordUpdate _ e fs) = do+ checkCaseModeExpr e+ mapM_ checkCaseModeFieldExpr fs+checkCaseModeExpr (Tuple _ es) = mapM_ checkCaseModeExpr es+checkCaseModeExpr (List _ _ es) = mapM_ checkCaseModeExpr es+checkCaseModeExpr (ListCompr _ e stms) = do+ checkCaseModeExpr e+ mapM_ checkCaseModeStatement stms+checkCaseModeExpr (EnumFrom _ e) = checkCaseModeExpr e+checkCaseModeExpr (EnumFromThen _ e1 e2) = do+ checkCaseModeExpr e1+ checkCaseModeExpr e2+checkCaseModeExpr (EnumFromTo _ e1 e2) = do+ checkCaseModeExpr e1+ checkCaseModeExpr e2+checkCaseModeExpr (EnumFromThenTo _ e1 e2 e3) = do+ checkCaseModeExpr e1+ checkCaseModeExpr e2+ checkCaseModeExpr e3+checkCaseModeExpr (UnaryMinus _ e) = checkCaseModeExpr e+checkCaseModeExpr (Apply _ e1 e2) = do+ checkCaseModeExpr e1+ checkCaseModeExpr e2+checkCaseModeExpr (InfixApply _ e1 _ e2) = do+ checkCaseModeExpr e1+ checkCaseModeExpr e2+checkCaseModeExpr (LeftSection _ e _) = checkCaseModeExpr e+checkCaseModeExpr (RightSection _ _ e) = checkCaseModeExpr e+checkCaseModeExpr (Lambda _ ts e) = do+ mapM_ checkCaseModePattern ts+ checkCaseModeExpr e+checkCaseModeExpr (Let _ _ ds e) = do+ mapM_ checkCaseModeDecl ds+ checkCaseModeExpr e+checkCaseModeExpr (Do _ _ stms e) = do+ mapM_ checkCaseModeStatement stms+ checkCaseModeExpr e+checkCaseModeExpr (IfThenElse _ e1 e2 e3) = do+ checkCaseModeExpr e1+ checkCaseModeExpr e2+ checkCaseModeExpr e3+checkCaseModeExpr (Case _ _ _ e as) = do+ mapM_ checkCaseModeAlt as+ checkCaseModeExpr e+checkCaseModeExpr _ = ok++checkCaseModeStatement :: Statement a -> WCM ()+checkCaseModeStatement (StmtExpr _ e) = checkCaseModeExpr e+checkCaseModeStatement (StmtDecl _ _ ds) = mapM_ checkCaseModeDecl ds+checkCaseModeStatement (StmtBind _ t e) = do+ checkCaseModePattern t+ checkCaseModeExpr e++checkCaseModeAlt :: Alt a -> WCM ()+checkCaseModeAlt (Alt _ t rhs) = checkCaseModePattern t >> checkCaseModeRhs rhs++checkCaseModeFieldPattern :: Field (Pattern a) -> WCM ()+checkCaseModeFieldPattern (Field _ _ t) = checkCaseModePattern t++checkCaseModeFieldExpr :: Field (Expression a) -> WCM ()+checkCaseModeFieldExpr (Field _ _ e) = checkCaseModeExpr e++checkCaseModeID :: (CaseMode -> String -> Bool) -> Ident -> WCM ()+checkCaseModeID f i@(Ident _ name _) = do+ c <- gets caseMode+ unless (f c name) (report $ warnCaseMode i c)++isVarName :: CaseMode -> String -> Bool+isVarName CaseModeProlog (x:_) | isAlpha x = isUpper x+isVarName CaseModeGoedel (x:_) | isAlpha x = isLower x+isVarName CaseModeHaskell (x:_) | isAlpha x = isLower x+isVarName _ _ = True++isFuncName :: CaseMode -> String -> Bool+isFuncName CaseModeHaskell (x:_) | isAlpha x = isLower x+isFuncName CaseModeGoedel (x:_) | isAlpha x = isUpper x+isFuncName CaseModeProlog (x:_) | isAlpha x = isLower x+isFuncName _ _ = True++isConstrName :: CaseMode -> String -> Bool+isConstrName = isDataDeclName++isClassDeclName :: CaseMode -> String -> Bool+isClassDeclName = isDataDeclName++isDataDeclName :: CaseMode -> String -> Bool+isDataDeclName CaseModeProlog (x:_) | isAlpha x = isLower x+isDataDeclName CaseModeGoedel (x:_) | isAlpha x = isUpper x+isDataDeclName CaseModeHaskell (x:_) | isAlpha x = isUpper x+isDataDeclName _ _ = True++-- ---------------------------------------------------------------------------+-- Warn for redundant context+-- ---------------------------------------------------------------------------++--traverse the AST for QualTypeExpr/Context and check for redundancy+checkRedContext :: [Decl a] -> WCM ()+checkRedContext = warnFor WarnRedundantContext . mapM_ checkRedContextDecl++getRedPredSet :: ModuleIdent -> ClassEnv -> TCEnv -> PredSet -> PredSet+getRedPredSet m cenv tcEnv ps =+ Set.map (pm Map.!) $ Set.difference qps $ minPredSet cenv qps --or fromJust $ Map.lookup+ where (qps, pm) = Set.foldr qualifyAndAddPred (Set.empty, Map.empty) ps+ qualifyAndAddPred p@(Pred qid ty) (ps', pm') =+ let qp = Pred (getOrigName m qid tcEnv) ty+ in (Set.insert qp ps', Map.insert qp p pm')++getPredFromContext :: Context -> ([Ident], PredSet)+getPredFromContext cx =+ let vs = concatMap (\(Constraint _ _ ty) -> typeVariables ty) cx+ in (vs, toPredSet vs cx)++checkRedContext' :: (Pred -> Message) -> PredSet -> WCM ()+checkRedContext' f ps = do+ m <- gets moduleId+ cenv <- gets classEnv+ tcEnv <- gets tyConsEnv+ mapM_ (report . f) (getRedPredSet m cenv tcEnv ps)++checkRedContextDecl :: Decl a -> WCM ()+checkRedContextDecl (TypeSig _ ids (QualTypeExpr _ cx _)) =+ checkRedContext' (warnRedContext (warnRedFuncString ids) vs) ps+ where (vs, ps) = getPredFromContext cx+checkRedContextDecl (FunctionDecl _ _ _ eqs) = mapM_ checkRedContextEq eqs+checkRedContextDecl (PatternDecl _ _ rhs) = checkRedContextRhs rhs+checkRedContextDecl (ClassDecl _ _ cx i _ ds) = do+ checkRedContext'+ (warnRedContext (text ("class declaration " ++ escName i)) vs)+ ps+ mapM_ checkRedContextDecl ds+ where (vs, ps) = getPredFromContext cx+checkRedContextDecl (InstanceDecl _ _ cx qid _ ds) = do+ checkRedContext'+ (warnRedContext (text ("instance declaration " ++ escQualName qid)) vs)+ ps+ mapM_ checkRedContextDecl ds+ where (vs, ps) = getPredFromContext cx+checkRedContextDecl _ = return ()++checkRedContextEq :: Equation a -> WCM ()+checkRedContextEq (Equation _ _ rhs) = checkRedContextRhs rhs++checkRedContextRhs :: Rhs a -> WCM ()+checkRedContextRhs (SimpleRhs _ _ e ds) = do+ checkRedContextExpr e+ mapM_ checkRedContextDecl ds+checkRedContextRhs (GuardedRhs _ _ cs ds) = do+ mapM_ checkRedContextCond cs+ mapM_ checkRedContextDecl ds++checkRedContextCond :: CondExpr a -> WCM ()+checkRedContextCond (CondExpr _ e1 e2) = do+ checkRedContextExpr e1+ checkRedContextExpr e2++checkRedContextExpr :: Expression a -> WCM ()+checkRedContextExpr (Paren _ e) = checkRedContextExpr e+checkRedContextExpr (Typed _ e (QualTypeExpr _ cx _)) = do+ checkRedContextExpr e+ checkRedContext' (warnRedContext (text "type signature") vs) ps+ where (vs, ps) = getPredFromContext cx+checkRedContextExpr (Record _ _ _ fs) = mapM_ checkRedContextFieldExpr fs+checkRedContextExpr (RecordUpdate _ e fs) = do+ checkRedContextExpr e+ mapM_ checkRedContextFieldExpr fs+checkRedContextExpr (Tuple _ es) = mapM_ checkRedContextExpr es+checkRedContextExpr (List _ _ es) = mapM_ checkRedContextExpr es+checkRedContextExpr (ListCompr _ e sts) = do+ checkRedContextExpr e+ mapM_ checkRedContextStmt sts+checkRedContextExpr (EnumFrom _ e) = checkRedContextExpr e+checkRedContextExpr (EnumFromThen _ e1 e2) = do+ checkRedContextExpr e1+ checkRedContextExpr e2+checkRedContextExpr (EnumFromTo _ e1 e2) = do+ checkRedContextExpr e1+ checkRedContextExpr e2+checkRedContextExpr (EnumFromThenTo _ e1 e2 e3) = do+ checkRedContextExpr e1+ checkRedContextExpr e2+ checkRedContextExpr e3+checkRedContextExpr (UnaryMinus _ e) = checkRedContextExpr e+checkRedContextExpr (Apply _ e1 e2) = do+ checkRedContextExpr e1+ checkRedContextExpr e2+checkRedContextExpr (InfixApply _ e1 _ e2) = do+ checkRedContextExpr e1+ checkRedContextExpr e2+checkRedContextExpr (LeftSection _ e _) = checkRedContextExpr e+checkRedContextExpr (RightSection _ _ e) = checkRedContextExpr e+checkRedContextExpr (Lambda _ _ e) = checkRedContextExpr e+checkRedContextExpr (Let _ _ ds e) = do+ mapM_ checkRedContextDecl ds+ checkRedContextExpr e+checkRedContextExpr (IfThenElse _ e1 e2 e3) = do+ checkRedContextExpr e1+ checkRedContextExpr e2+ checkRedContextExpr e3+checkRedContextExpr (Case _ _ _ e as) = do+ checkRedContextExpr e+ mapM_ checkRedContextAlt as+checkRedContextExpr _ = return ()++checkRedContextStmt :: Statement a -> WCM ()+checkRedContextStmt (StmtExpr _ e) = checkRedContextExpr e+checkRedContextStmt (StmtDecl _ _ ds) = mapM_ checkRedContextDecl ds+checkRedContextStmt (StmtBind _ _ e) = checkRedContextExpr e++checkRedContextAlt :: Alt a -> WCM ()+checkRedContextAlt (Alt _ _ rhs) = checkRedContextRhs rhs++checkRedContextFieldExpr :: Field (Expression a) -> WCM ()+checkRedContextFieldExpr (Field _ _ e) = checkRedContextExpr e++-- ---------------------------------------------------------------------------+-- Warnings messages+-- ---------------------------------------------------------------------------++warnRedFuncString :: [Ident] -> Doc+warnRedFuncString is = text "type signature for function" <>+ text (if length is == 1 then [] else "s") <+>+ csep (map (text . escName) is)++-- Doc description -> TypeVars -> Pred -> Warning+warnRedContext :: Doc -> [Ident] -> Pred -> Message+warnRedContext d vs p@(Pred qid _) = spanInfoMessage qid $+ text "Redundant context in" <+> d <> colon <+>+ quotes (pPrint $ fromPred vs p) -- idents use ` ' as quotes not ' '++-- seperate a list by ', '+csep :: [Doc] -> Doc+csep [] = empty+csep [x] = x+csep (x:xs) = x <> comma <+> csep xs++warnCaseMode :: Ident -> CaseMode -> Message+warnCaseMode i@(Ident _ name _ ) c = spanInfoMessage i $+ text "Wrong case mode in symbol" <+> text (escName i) <+>+ text "due to selected case mode" <+> text (escapeCaseMode c) <> comma <+>+ text "try renaming to" <+> text (caseSuggestion name) <+> text "instead"++caseSuggestion :: String -> String+caseSuggestion (x:xs) | isLower x = toUpper x : xs+ | isUpper x = toLower x : xs+caseSuggestion _ = internalError+ "Checks.WarnCheck.caseSuggestion: Identifier starts with illegal Symbol"++escapeCaseMode :: CaseMode -> String+escapeCaseMode CaseModeFree = "`free`"+escapeCaseMode CaseModeHaskell = "`haskell`"+escapeCaseMode CaseModeProlog = "`prolog`"+escapeCaseMode CaseModeGoedel = "`goedel`"++warnUnrefTypeVar :: Ident -> Message+warnUnrefTypeVar v = spanInfoMessage v $ hsep $ map text+ [ "Unreferenced type variable", escName v ]++warnUnrefVar :: Ident -> Message+warnUnrefVar v = spanInfoMessage v $ hsep $ map text+ [ "Unused declaration of variable", escName v ]++warnShadowing :: Ident -> Ident -> Message+warnShadowing x v = spanInfoMessage x $+ text "Shadowing symbol" <+> text (escName x)+ <> comma <+> text "bound at:" <+> ppPosition (getPosition v)
+ src/CompilerEnv.hs view
@@ -0,0 +1,117 @@+{- |+ Module : $Header$+ Description : Environment containing the module's information+ Copyright : (c) 2011 - 2015 Björn Peemöller+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module defines the compilation environment for a single module,+ containing the information needed throughout the compilation process.+-}+module CompilerEnv where++import qualified Data.Map as Map (Map, keys, toList)++import Curry.Base.Ident (ModuleIdent, moduleName)+import Curry.Base.Pretty+import Curry.Base.Span (Span)+import Curry.Syntax++import Base.TopEnv (allBindings, allLocalBindings)++import Env.Class+import Env.Instance+import Env.Interface+import Env.ModuleAlias (AliasEnv, initAliasEnv)+import Env.OpPrec+import Env.TypeConstructor+import Env.Value++type CompEnv a = (CompilerEnv, a)++-- |A compiler environment contains information about the module currently+-- compiled. The information is updated during the different stages of+-- compilation.+data CompilerEnv = CompilerEnv+ { moduleIdent :: ModuleIdent -- ^ identifier of the module+ , filePath :: FilePath -- ^ 'FilePath' of compilation target+ , extensions :: [KnownExtension] -- ^ enabled language extensions+ , tokens :: [(Span, Token)] -- ^ token list of module+ , interfaceEnv :: InterfaceEnv -- ^ declarations of imported interfaces+ , aliasEnv :: AliasEnv -- ^ aliases for imported modules+ , tyConsEnv :: TCEnv -- ^ type constructors and type classes+ , classEnv :: ClassEnv -- ^ all type classes with their super classes+ , instEnv :: InstEnv -- ^ instances+ , valueEnv :: ValueEnv -- ^ functions and data constructors+ , opPrecEnv :: OpPrecEnv -- ^ operator precedences+ }++-- |Initial 'CompilerEnv'+initCompilerEnv :: ModuleIdent -> CompilerEnv+initCompilerEnv mid = CompilerEnv+ { moduleIdent = mid+ , filePath = []+ , extensions = []+ , tokens = []+ , interfaceEnv = initInterfaceEnv+ , aliasEnv = initAliasEnv+ , tyConsEnv = initTCEnv+ , classEnv = initClassEnv+ , instEnv = initInstEnv+ , valueEnv = initDCEnv+ , opPrecEnv = initOpPrecEnv+ }++-- |Show the 'CompilerEnv'+showCompilerEnv :: CompilerEnv -> Bool -> Bool -> String+showCompilerEnv env allBinds simpleEnv = show $ vcat+ [ header "Module Identifier " $ text $ moduleName $ moduleIdent env+ , header "FilePath" $ text $ filePath env+ , header "Language Extensions" $ text $ show $ extensions env+ , header "Interfaces " $ hcat $ punctuate comma+ $ map (text . moduleName)+ $ Map.keys $ interfaceEnv env+ , header "Module Aliases " $ ppMap simpleEnv $ aliasEnv env+ , header "Precedences " $ ppAL simpleEnv $ bindings $ opPrecEnv env+ , header "Type Constructors " $ ppAL simpleEnv $ bindings $ tyConsEnv env+ , header "Classes " $ ppMap simpleEnv $ classEnv env+ , header "Instances " $ ppMap simpleEnv $ instEnv env+ , header "Values " $ ppAL simpleEnv $ bindings $ valueEnv env+ ]+ where+ header hdr content = hang (text hdr <+> colon) 4 content+ bindings = if allBinds then allBindings else allLocalBindings++-- |Pretty print a 'Map'+ppMap :: (Show a, Pretty a, Show b, Pretty b) => Bool-> Map.Map a b -> Doc+ppMap True = ppMapPretty+ppMap False = ppMapShow++ppMapShow :: (Show a, Show b) => Map.Map a b -> Doc+ppMapShow = ppALShow . Map.toList++ppMapPretty :: (Pretty a, Pretty b) => Map.Map a b -> Doc+ppMapPretty = ppALPretty . Map.toList++-- |Pretty print an association list+ppAL :: (Show a, Pretty a, Show b, Pretty b) => Bool -> [(a, b)] -> Doc+ppAL True = ppALPretty+ppAL False = ppALShow++ppALShow :: (Show a, Show b) => [(a, b)] -> Doc+ppALShow xs = vcat+ $ map (\(a,b) -> text (pad a keyWidth) <+> equals <+> text b) showXs+ where showXs = map (\(a,b) -> (show a, show b)) xs+ keyWidth = maximum (0 : map (length .fst) showXs)+ pad s n = take n (s ++ repeat ' ')++ppALPretty :: (Pretty a, Pretty b) => [(a, b)] -> Doc+ppALPretty xs = vcat+ $ map (\(a,b) -> text (pad a keyWidth) <+> equals <+> text b) showXs+ where showXs = map (\(a,b) -> (render (pPrint a), render (pPrint b))) xs+ keyWidth = maximum (0 : map (length .fst) showXs)+ pad s n = take n (s ++ repeat ' ')+
+ src/CompilerOpts.hs view
@@ -0,0 +1,644 @@+{- |+ Module : $Header$+ Description : Compiler options+ Copyright : (c) 2005 Martin Engelke+ 2007 Sebastian Fischer+ 2011 - 2016 Björn Peemöller+ 2016 - 2017 Finn Teegen+ 2018 Kai-Oliver Prott+ License : BSD-3-clause++ Maintainer : fte@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module defines data structures holding options for the+ compilation of Curry programs, and utility functions for printing+ help information as well as parsing the command line arguments.+-}+module CompilerOpts+ ( Options (..), CppOpts (..), PrepOpts (..), WarnOpts (..), DebugOpts (..)+ , OptimizationOpts(..), CaseMode (..), CymakeMode (..), Verbosity (..)+ , TargetType (..), WarnFlag (..), KnownExtension (..), DumpLevel (..)+ , dumpLevel+ , defaultOptions, defaultPrepOpts, defaultWarnOpts, defaultDebugOpts+ , getCompilerOpts, updateOpts, usage+ ) where++import Data.List (intercalate, nub)+import Data.Maybe (isJust)+import Data.Char (isDigit)+import qualified Data.Map as Map (Map, empty, insert)+import System.Console.GetOpt+import System.Environment (getArgs, getProgName)+import System.FilePath ( addTrailingPathSeparator, normalise+ , splitSearchPath )++import Curry.Files.Filenames (defaultOutDir)+import Curry.Syntax.Extension++-- -----------------------------------------------------------------------------+-- Option data structures+-- -----------------------------------------------------------------------------++-- |Compiler options+data Options = Options+ -- general+ { optMode :: CymakeMode -- ^ modus operandi+ , optVerbosity :: Verbosity -- ^ verbosity level+ -- compilation+ , optForce :: Bool -- ^ force (re-)compilation of target+ , optLibraryPaths :: [FilePath] -- ^ directories to search in+ -- for libraries+ , optImportPaths :: [FilePath] -- ^ directories to search in+ -- for imports+ , optOutDir :: FilePath -- ^ output directory for FlatCurry, ...+ , optHtmlDir :: Maybe FilePath -- ^ output directory for HTML+ , optUseOutDir :: Bool -- ^ use subdir for output?+ , optInterface :: Bool -- ^ create a FlatCurry interface file?+ , optPrepOpts :: PrepOpts -- ^ preprocessor options+ , optWarnOpts :: WarnOpts -- ^ warning options+ , optTargetTypes :: [TargetType] -- ^ what to generate+ , optExtensions :: [KnownExtension] -- ^ enabled language extensions+ , optDebugOpts :: DebugOpts -- ^ debug options+ , optCaseMode :: CaseMode -- ^ case mode+ , optCppOpts :: CppOpts -- ^ C preprocessor options+ , optOptimizations :: OptimizationOpts -- ^ Optimization options+ } deriving Show++-- |C preprocessor options+data CppOpts = CppOpts+ { cppRun :: Bool -- ^ run C preprocessor+ , cppDefinitions :: Map.Map String Int -- ^ defintions for the C preprocessor+ } deriving Show++-- |Preprocessor options+data PrepOpts = PrepOpts+ { ppPreprocess :: Bool -- ^ apply custom preprocessor+ , ppCmd :: String -- ^ preprocessor command+ , ppOpts :: [String] -- ^ preprocessor options+ } deriving Show++data CaseMode+ = CaseModeFree+ | CaseModeHaskell+ | CaseModeProlog+ | CaseModeGoedel+ deriving (Eq, Show)++-- |Warning options+data WarnOpts = WarnOpts+ { wnWarn :: Bool -- ^ show warnings? (legacy option)+ , wnWarnFlags :: [WarnFlag] -- ^ Warnings flags (see below)+ , wnWarnAsError :: Bool -- ^ Should warnings be treated as errors?+ } deriving Show++-- |Debug options+data DebugOpts = DebugOpts+ { dbDumpLevels :: [DumpLevel] -- ^ dump levels+ , dbDumpEnv :: Bool -- ^ dump compilation environment+ , dbDumpRaw :: Bool -- ^ dump data structure+ , dbDumpAllBindings :: Bool -- ^ dump all bindings instead of just the+ -- local bindings+ , dbDumpSimple :: Bool -- ^ print more readable environments+ } deriving Show++data OptimizationOpts = OptimizationOpts+ { optDesugarNewtypes :: Bool -- ^ Desugar newtypes+ , optInlineDictionaries :: Bool -- ^ Inline type class dictionaries+ , optRemoveUnusedImports :: Bool -- ^ Remove unused imports in IL+ } deriving Show++-- | Default compiler options+defaultOptions :: Options+defaultOptions = Options+ { optMode = ModeMake+ , optVerbosity = VerbStatus+ , optForce = False+ , optLibraryPaths = []+ , optImportPaths = []+ , optOutDir = defaultOutDir+ , optHtmlDir = Nothing+ , optUseOutDir = True+ , optInterface = True+ , optPrepOpts = defaultPrepOpts+ , optWarnOpts = defaultWarnOpts+ , optTargetTypes = []+ , optExtensions = []+ , optDebugOpts = defaultDebugOpts+ , optCaseMode = CaseModeFree+ , optCppOpts = defaultCppOpts+ , optOptimizations = defaultOptimizationOpts+ }++-- | Default C preprocessor options+defaultCppOpts :: CppOpts+defaultCppOpts = CppOpts+ { cppRun = False+ , cppDefinitions = Map.empty+ }++-- | Default preprocessor options+defaultPrepOpts :: PrepOpts+defaultPrepOpts = PrepOpts+ { ppPreprocess = False+ , ppCmd = ""+ , ppOpts = []+ }++-- | Default warning options+defaultWarnOpts :: WarnOpts+defaultWarnOpts = WarnOpts+ { wnWarn = True+ , wnWarnFlags = stdWarnFlags+ , wnWarnAsError = False+ }++-- | Default dump options+defaultDebugOpts :: DebugOpts+defaultDebugOpts = DebugOpts+ { dbDumpLevels = []+ , dbDumpEnv = False+ , dbDumpRaw = False+ , dbDumpAllBindings = False+ , dbDumpSimple = False+ }++defaultOptimizationOpts :: OptimizationOpts+defaultOptimizationOpts = OptimizationOpts+ { optDesugarNewtypes = False+ , optInlineDictionaries = True+ , optRemoveUnusedImports = True+ }++-- |Modus operandi of the program+data CymakeMode+ = ModeHelp -- ^ Show help information and exit+ | ModeVersion -- ^ Show version and exit+ | ModeNumericVersion -- ^ Show numeric version, suitable for later processing+ | ModeMake -- ^ Compile with dependencies+ deriving (Eq, Show)++-- |Verbosity level+data Verbosity+ = VerbQuiet -- ^ be quiet+ | VerbStatus -- ^ show status of compilation+ deriving (Eq, Ord, Show)++-- |Description and flag of verbosities+verbosities :: [(Verbosity, String, String)]+verbosities = [ ( VerbQuiet , "0", "quiet" )+ , ( VerbStatus, "1", "status")+ ]++-- |Type of the target file+data TargetType+ = Tokens -- ^ Source code tokens+ | Comments -- ^ Source code comments+ | Parsed -- ^ Parsed source code+ | FlatCurry -- ^ FlatCurry+ | AnnotatedFlatCurry -- ^ Annotated FlatCurry+ | TypedFlatCurry -- ^ Typed FlatCurry+ | AbstractCurry -- ^ AbstractCurry+ | UntypedAbstractCurry -- ^ Untyped AbstractCurry+ | Html -- ^ HTML documentation+ | AST -- ^ Abstract-Syntax-Tree after checks+ | ShortAST -- ^ Abstract-Syntax-Tree with shortened decls+ deriving (Eq, Show)++-- |Warnings flags+data WarnFlag+ = WarnMultipleImports -- ^ Warn for multiple imports+ | WarnDisjoinedRules -- ^ Warn for disjoined function rules+ | WarnUnusedGlobalBindings -- ^ Warn for unused global bindings+ | WarnUnusedBindings -- ^ Warn for unused local bindings+ | WarnNameShadowing -- ^ Warn for name shadowing+ | WarnOverlapping -- ^ Warn for overlapping rules/alternatives+ | WarnIncompletePatterns -- ^ Warn for incomplete pattern matching+ | WarnMissingSignatures -- ^ Warn for missing type signatures+ | WarnMissingMethods -- ^ Warn for missing method implementations+ | WarnOrphanInstances -- ^ Warn for orphan instances+ | WarnIrregularCaseMode -- ^ Warn for irregular case mode+ | WarnRedundantContext -- ^ Warn for redundant context in type signatures+ deriving (Eq, Bounded, Enum, Show)++-- |Warning flags enabled by default+stdWarnFlags :: [WarnFlag]+stdWarnFlags =+ [ WarnMultipleImports , WarnDisjoinedRules --, WarnUnusedGlobalBindings+ , WarnUnusedBindings , WarnNameShadowing , WarnOverlapping+ , WarnIncompletePatterns, WarnMissingSignatures, WarnMissingMethods+ , WarnIrregularCaseMode , WarnRedundantContext+ ]++-- |Description and flag of warnings flags+warnFlags :: [(WarnFlag, String, String)]+warnFlags =+ [ ( WarnMultipleImports , "multiple-imports"+ , "multiple imports" )+ , ( WarnDisjoinedRules , "disjoined-rules"+ , "disjoined function rules" )+ , ( WarnUnusedGlobalBindings, "unused-global-bindings"+ , "unused bindings" )+ , ( WarnUnusedBindings , "unused-bindings"+ , "unused bindings" )+ , ( WarnNameShadowing , "name-shadowing"+ , "name shadowing" )+ , ( WarnOverlapping , "overlapping"+ , "overlapping function rules" )+ , ( WarnIncompletePatterns , "incomplete-patterns"+ , "incomplete pattern matching" )+ , ( WarnMissingSignatures , "missing-signatures"+ , "missing type signatures" )+ , ( WarnMissingMethods , "missing-methods"+ , "missing method implementations" )+ , ( WarnOrphanInstances , "orphan-instances"+ , "orphan instances" )+ , ( WarnIrregularCaseMode , "irregular-case-mode"+ , "irregular case mode")+ , ( WarnRedundantContext , "redundant-context"+ , "redundant context")+ ]++-- |Dump level+data DumpLevel+ = DumpCondCompiled -- ^ dump source code after conditional compiling+ | DumpParsed -- ^ dump source code after parsing+ | DumpExtensionChecked -- ^ dump source code after extension checking+ | DumpTypeSyntaxChecked -- ^ dump source code after type syntax checking+ | DumpKindChecked -- ^ dump source code after kind checking+ | DumpSyntaxChecked -- ^ dump source code after syntax checking+ | DumpPrecChecked -- ^ dump source code after precedence checking+ | DumpDeriveChecked -- ^ dump source code after derive checking+ | DumpInstanceChecked -- ^ dump source code after instance checking+ | DumpTypeChecked -- ^ dump source code after type checking+ | DumpExportChecked -- ^ dump source code after export checking+ | DumpQualified -- ^ dump source code after qualification+ | DumpDerived -- ^ dump source code after deriving+ | DumpDesugared -- ^ dump source code after desugaring+ | DumpDictionaries -- ^ dump source code after dictionary transformation+ | DumpNewtypes -- ^ dump source code after removing newtype constructors+ | DumpSimplified -- ^ dump source code after simplification+ | DumpLifted -- ^ dump source code after lambda-lifting+ | DumpTranslated -- ^ dump IL code after translation+ | DumpCaseCompleted -- ^ dump IL code after case completion+ | DumpTypedFlatCurry -- ^ dump typed FlatCurry code+ | DumpFlatCurry -- ^ dump FlatCurry code+ deriving (Eq, Bounded, Enum, Show)++-- |Description and flag of dump levels+dumpLevel :: [(DumpLevel, String, String)]+dumpLevel = [ (DumpCondCompiled , "dump-cond" , "conditional compiling" )+ , (DumpParsed , "dump-parse", "parsing" )+ , (DumpExtensionChecked , "dump-exc" , "extension checking" )+ , (DumpTypeSyntaxChecked, "dump-tsc" , "type syntax checking" )+ , (DumpKindChecked , "dump-kc" , "kind checking" )+ , (DumpSyntaxChecked , "dump-sc" , "syntax checking" )+ , (DumpPrecChecked , "dump-pc" , "precedence checking" )+ , (DumpDeriveChecked , "dump-dc" , "derive checking" )+ , (DumpInstanceChecked , "dump-inc" , "instance checking" )+ , (DumpTypeChecked , "dump-tc" , "type checking" )+ , (DumpExportChecked , "dump-ec" , "export checking" )+ , (DumpQualified , "dump-qual" , "qualification" )+ , (DumpDerived , "dump-deriv", "deriving" )+ , (DumpDesugared , "dump-ds" , "desugaring" )+ , (DumpDictionaries , "dump-dict" , "dictionary insertion" )+ , (DumpNewtypes , "dump-new" , "removing newtype constructors" )+ , (DumpLifted , "dump-lift" , "lifting" )+ , (DumpSimplified , "dump-simpl", "simplification" )+ , (DumpTranslated , "dump-trans", "pattern matching compilation" )+ , (DumpCaseCompleted , "dump-cc" , "case completion" )+ , (DumpTypedFlatCurry , "dump-tflat", "translation into typed FlatCurry")+ , (DumpFlatCurry , "dump-flat" , "translation into FlatCurry" )+ ]++-- |Description and flag of language extensions+extensions :: [(KnownExtension, String, String)]+extensions =+ [ ( AnonFreeVars , "AnonFreeVars"+ , "enable anonymous free variables" )+ , ( CPP , "CPP"+ , "run C preprocessor" )+ , ( FunctionalPatterns , "FunctionalPatterns"+ , "enable functional patterns" )+ , ( NegativeLiterals , "NegativeLiterals"+ , "desugar negated literals as negative literal" )+ , ( NoImplicitPrelude , "NoImplicitPrelude"+ , "do not implicitly import the Prelude" )+ ]++-- -----------------------------------------------------------------------------+-- Parsing of the command line options.+--+-- Because some flags require additional arguments, the structure is slightly+-- more complicated to enable malformed arguments to be reported.+-- -----------------------------------------------------------------------------++-- |Instead of just returning the resulting 'Options' structure, we also+-- collect errors from arguments passed to specific options.+type OptErr = (Options, [String])++-- |An 'OptErrTable' consists of a list of entries of the following form:+-- * a flag to be recognized on the command line+-- * an explanation text for the usage information+-- * a modification funtion adjusting the options structure+-- The type is parametric about the option's type to adjust.+type OptErrTable opt = [(String, String, opt -> opt)]++onOpts :: (Options -> Options) -> OptErr -> OptErr+onOpts f (opts, errs) = (f opts, errs)++onCppOpts :: (CppOpts -> CppOpts) -> OptErr -> OptErr+onCppOpts f (opts, errs) = (opts { optCppOpts = f (optCppOpts opts) }, errs)++onPrepOpts :: (PrepOpts -> PrepOpts) -> OptErr -> OptErr+onPrepOpts f (opts, errs) = (opts { optPrepOpts = f (optPrepOpts opts) }, errs)++onWarnOpts :: (WarnOpts -> WarnOpts) -> OptErr -> OptErr+onWarnOpts f (opts, errs) = (opts { optWarnOpts = f (optWarnOpts opts) }, errs)++onDebugOpts :: (DebugOpts -> DebugOpts) -> OptErr -> OptErr+onDebugOpts f (opts, errs)+ = (opts { optDebugOpts = f (optDebugOpts opts) }, errs)++onOptimOpts :: (OptimizationOpts -> OptimizationOpts) -> OptErr -> OptErr+onOptimOpts f (opts, errs)+ = (opts { optOptimizations = f (optOptimizations opts) }, errs)++withArg :: ((a -> b) -> OptErr -> OptErr)+ -> (String -> a -> b) -> String -> OptErr -> OptErr+withArg lift f arg = lift (f arg)++addErr :: String -> OptErr -> OptErr+addErr err (opts, errs) = (opts, errs ++ [err])++mkOptDescr :: ((opt -> opt) -> OptErr -> OptErr)+ -> String -> [String] -> String -> String -> OptErrTable opt+ -> OptDescr (OptErr -> OptErr)+mkOptDescr lift flags longFlags arg what tbl = Option flags longFlags+ (ReqArg (parseOptErr lift what tbl) arg)+ ("set " ++ what ++ " `" ++ arg ++ "', where `" ++ arg ++ "' is one of\n"+ ++ renderOptErrTable tbl)++parseOptErr :: ((opt -> opt) -> OptErr -> OptErr)+ -> String -> OptErrTable opt -> String -> OptErr -> OptErr+parseOptErr lift what table opt = case lookup3 opt table of+ Just f -> lift f+ Nothing -> addErr $ "unrecognized " ++ what ++ '`' : opt ++ "'\n"+ where+ lookup3 _ [] = Nothing+ lookup3 k ((k', _, v2) : kvs)+ | k == k' = Just v2+ | otherwise = lookup3 k kvs++renderOptErrTable :: OptErrTable opt -> String+renderOptErrTable ds+ = intercalate "\n" $ map (\(k, d, _) -> " " ++ rpad maxLen k ++ ": " ++ d) ds+ where+ maxLen = maximum $ map (\(k, _, _) -> length k) ds+ rpad n x = x ++ replicate (n - length x) ' '++-- | All available compiler options+options :: [OptDescr (OptErr -> OptErr)]+options =+ -- modus operandi+ [ Option "h?" ["help"]+ (NoArg (onOpts $ \ opts -> opts { optMode = ModeHelp }))+ "display this help and exit"+ , Option "V" ["version"]+ (NoArg (onOpts $ \ opts -> opts { optMode = ModeVersion }))+ "show the version number and exit"+ , Option "" ["numeric-version"]+ (NoArg (onOpts $ \ opts -> opts { optMode = ModeNumericVersion }))+ "show the numeric version number and exit"+ -- verbosity+ , mkOptDescr onOpts "v" ["verbosity"] "n" "verbosity level" verbDescriptions+ , Option "q" ["no-verb"]+ (NoArg (onOpts $ \ opts -> opts { optVerbosity = VerbQuiet } ))+ "set verbosity level to quiet"+ -- compilation+ , Option "f" ["force"]+ (NoArg (onOpts $ \ opts -> opts { optForce = True }))+ "force compilation of target file"+ , Option "P" ["lib-dir"]+ (ReqArg (withArg onOpts $ \ arg opts -> opts { optLibraryPaths =+ nub $ optLibraryPaths opts ++ splitSearchPath arg}) "dir[:dir]")+ "search for libraries in dir[:dir]"+ , Option "i" ["import-dir"]+ (ReqArg (withArg onOpts $ \ arg opts -> opts { optImportPaths =+ nub $ optImportPaths opts +++ map (normalise . addTrailingPathSeparator) (splitSearchPath arg)+ }) "dir[:dir]")+ "search for imports in dir[:dir]"+ , Option "o" ["outdir"]+ (ReqArg (withArg onOpts $ \ arg opts -> opts { optOutDir = arg }) "dir")+ "write compilation artifacts (FlatCurry, ...) into directory `dir'"+ , Option [] ["htmldir"]+ (ReqArg (withArg onOpts $ \ arg opts -> opts { optHtmlDir =+ Just arg }) "dir")+ "write HTML documentation into directory `dir'"+ , Option "" ["no-outdir", "no-subdir"]+ (NoArg (onOpts $ \ opts -> opts { optUseOutDir = False }))+ ("disable writing to `" ++ defaultOutDir ++ "' subdirectory")+ , Option "" ["no-intf"]+ (NoArg (onOpts $ \ opts -> opts { optInterface = False }))+ "do not create an interface file"+ -- legacy warning flags+ , Option "" ["no-warn"]+ (NoArg (onWarnOpts $ \ opts -> opts { wnWarn = False }))+ "do not print warnings"+ , Option "" ["no-overlap-warn"]+ (NoArg (onWarnOpts $ \ opts -> opts {wnWarnFlags =+ addFlag WarnOverlapping (wnWarnFlags opts) }))+ "do not print warnings for overlapping rules"+ -- target types+ , targetOption Tokens "tokens"+ "generate token stream"+ , targetOption Comments "comments"+ "generate comments stream"+ , targetOption Parsed "parse-only"+ "generate source representation"+ , targetOption FlatCurry "flat"+ "generate FlatCurry code"+ , targetOption TypedFlatCurry "typed-flat"+ "generate typed FlatCurry code"+ , targetOption AnnotatedFlatCurry "type-annotated-flat"+ "generate type-annotated FlatCurry code"+ , targetOption AbstractCurry "acy"+ "generate typed AbstractCurry"+ , targetOption UntypedAbstractCurry "uacy"+ "generate untyped AbstractCurry"+ , targetOption Html "html"+ "generate html documentation"+ , targetOption AST "ast"+ "generate abstract syntax tree"+ , targetOption ShortAST "short-ast"+ "generate shortened abstract syntax tree for documentation"+ , Option "F" []+ (NoArg (onPrepOpts $ \ opts -> opts { ppPreprocess = True }))+ "use custom preprocessor"+ , Option "" ["pgmF"]+ (ReqArg (withArg onPrepOpts $ \ arg opts -> opts { ppCmd = arg})+ "cmd")+ "execute preprocessor command <cmd>"+ , Option "" ["optF"]+ (ReqArg (withArg onPrepOpts $ \ arg opts ->+ opts { ppOpts = ppOpts opts ++ [arg]}) "option")+ "execute preprocessor with option <option>"+ -- extensions+ , Option "e" ["extended"]+ (NoArg (onOpts $ \ opts -> opts { optExtensions =+ nub $ kielExtensions ++ optExtensions opts }))+ "enable extended Curry functionalities"+ , mkOptDescr onOpts "c" ["case-mode"] "mode" "case mode" caseModeDescriptions+ , mkOptDescr onOpts "X" [] "ext" "language extension" extDescriptions+ , mkOptDescr onWarnOpts "W" [] "opt" "warning option" warnDescriptions+ , mkOptDescr onDebugOpts "d" [] "opt" "debug option" debugDescriptions+ , mkOptDescr onOptimOpts "O" [] "opt" "optimization option" optimizeDescriptions+ , Option "" ["cpp"]+ (NoArg (onCppOpts $ \ opts -> opts { cppRun = True }))+ "run C preprocessor"+ , Option "D" []+ (ReqArg (withArg ($) parseCppDefinition) "s=v")+ "define symbol `s` with value `v` for the C preprocessor"+ ]++parseCppDefinition :: String -> OptErr -> OptErr+parseCppDefinition arg optErr+ | not (null s) && not (null v) && all isDigit v+ = onCppOpts (addCppDefinition s v) optErr+ | otherwise+ = addErr (cppDefinitionErr arg) optErr+ where (s, v) = drop 1 <$> break ('=' ==) arg++addCppDefinition :: String -> String -> CppOpts -> CppOpts+addCppDefinition s v opts =+ opts { cppDefinitions = Map.insert s (read v) (cppDefinitions opts) }++cppDefinitionErr :: String -> String+cppDefinitionErr = (++) "Invalid format for option '-D': "++targetOption :: TargetType -> String -> String -> OptDescr (OptErr -> OptErr)+targetOption ty flag+ = Option "" [flag] (NoArg (onOpts $ \ opts -> opts { optTargetTypes =+ nub $ ty : optTargetTypes opts }))++verbDescriptions :: OptErrTable Options+verbDescriptions = map toDescr verbosities+ where+ toDescr (flag, name, desc)+ = (name, desc, \ opts -> opts { optVerbosity = flag })++extDescriptions :: OptErrTable Options+extDescriptions = map toDescr extensions+ where+ toDescr (flag, name, desc)+ = (name, desc,+ \opts -> let cppOpts = optCppOpts opts+ in opts { optCppOpts =+ cppOpts { cppRun = cppRun cppOpts || flag == CPP }+ , optExtensions = addFlag flag (optExtensions opts)+ })+++caseModeDescriptions :: OptErrTable Options+caseModeDescriptions+ = [ ( "free" , "use free case mode"+ , \ opts -> opts { optCaseMode = CaseModeFree } )+ , ( "haskell", "use haskell style case mode"+ , \ opts -> opts { optCaseMode = CaseModeHaskell } )+ , ( "prolog" , "use prolog style case mode"+ , \ opts -> opts { optCaseMode = CaseModeProlog } )+ , ( "goedel" , "use goedel case mode"+ , \ opts -> opts { optCaseMode = CaseModeGoedel } )+ ]++warnDescriptions :: OptErrTable WarnOpts+warnDescriptions+ = [ ( "all" , "turn on all warnings"+ , \ opts -> opts { wnWarnFlags = [minBound .. maxBound] } )+ , ("none" , "turn off all warnings"+ , \ opts -> opts { wnWarnFlags = [] } )+ , ("error", "treat warnings as errors"+ , \ opts -> opts { wnWarnAsError = True } )+ ] ++ map turnOn warnFlags ++ map turnOff warnFlags+ where+ turnOn (flag, name, desc)+ = (name, "warn for " ++ desc+ , \ opts -> opts { wnWarnFlags = addFlag flag (wnWarnFlags opts)})+ turnOff (flag, name, desc)+ = ("no-" ++ name, "do not warn for " ++ desc+ , \ opts -> opts { wnWarnFlags = removeFlag flag (wnWarnFlags opts)})++debugDescriptions :: OptErrTable DebugOpts+debugDescriptions =+ [ ( "dump-all" , "dump everything"+ , \ opts -> opts { dbDumpLevels = [minBound .. maxBound] })+ , ( "dump-none" , "dump nothing"+ , \ opts -> opts { dbDumpLevels = [] })+ , ( "dump-env" , "additionally dump compiler environment"+ , \ opts -> opts { dbDumpEnv = True })+ , ( "dump-raw" , "dump as raw AST (instead of pretty printing)"+ , \ opts -> opts { dbDumpRaw = True })+ , ( "dump-all-bindings" , "when dumping bindings, dump all instead of just local ones"+ , \ opts -> opts { dbDumpAllBindings = True })+ , ( "dump-simple" , "print a simplified, more readable environment"+ , \ opts -> opts { dbDumpSimple = True })++ ] ++ map toDescr dumpLevel+ where+ toDescr (flag, name, desc)+ = (name , "dump code after " ++ desc+ , \ opts -> opts { dbDumpLevels = addFlag flag (dbDumpLevels opts)})++optimizeDescriptions :: OptErrTable OptimizationOpts+optimizeDescriptions =+ [ ( "desugar-newtypes" , "desugars newtypes in FlatCurry"+ , \ opts -> opts { optDesugarNewtypes = True })+ , ( "inline-dictionaries" , "inlines type class dictionaries"+ , \ opts -> opts { optInlineDictionaries = True })+ , ( "remove-unused-imports" , "removes unused imports"+ , \ opts -> opts { optRemoveUnusedImports = True })+ , ( "no-desugar-newtypes" , "prevents desugaring of newtypes in FlatCurry"+ , \ opts -> opts { optDesugarNewtypes = False })+ , ( "no-inline-dictionaries" , "prevents inlining of type class dictionaries"+ , \ opts -> opts { optInlineDictionaries = False })+ , ( "no-remove-unused-imports", "prevents removing of unused imports"+ , \ opts -> opts { optRemoveUnusedImports = False })+ ]++addFlag :: Eq a => a -> [a] -> [a]+addFlag o opts = nub $ o : opts++removeFlag :: Eq a => a -> [a] -> [a]+removeFlag o = filter (/= o)++-- |Update the 'Options' record by the parsed and processed arguments+updateOpts :: Options -> [String] -> (Options, [String], [String])+updateOpts opts args = (opts', files, errs ++ errs2 ++ checkOpts opts files)+ where+ (opts', errs2) = foldl (flip ($)) (opts, []) optErrs+ (optErrs, files, errs) = getOpt Permute options args++-- |Parse the command line arguments+parseOpts :: [String] -> (Options, [String], [String])+parseOpts = updateOpts defaultOptions++-- |Check options and files and return a list of error messages+checkOpts :: Options -> [String] -> [String]+checkOpts opts _+ = [ "The option '--htmldir' is only valid for HTML generation mode"+ | isJust (optHtmlDir opts) && Html `notElem` optTargetTypes opts ]++-- |Print the usage information of the command line tool.+usage :: String -> String+usage prog = usageInfo header options+ where header = "usage: " ++ prog ++ " [OPTION] ... MODULES ..."++-- |Retrieve the compiler 'Options'+getCompilerOpts :: IO (String, Options, [String], [String])+getCompilerOpts = do+ args <- getArgs+ prog <- getProgName+ let (opts, files, errs) = parseOpts args+ return (prog, opts, files, errs)
+ src/CondCompile.hs view
@@ -0,0 +1,26 @@+{- |+ Module : $Header$+ Description : Conditional compilation+ Copyright : (c) 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : fte@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ TODO+-}++module CondCompile (condCompile) where++import Curry.Base.Monad+import Curry.CondCompile.Transform (condTransform)++import CompilerOpts (CppOpts (..))++condCompile :: CppOpts -> FilePath -> String -> CYIO String+condCompile opts fn p+ | not (cppRun opts) = return p+ | otherwise = either (failMessages . (: []))+ ok+ (condTransform (cppDefinitions opts) fn p)
+ src/Curry/AbstractCurry.hs view
@@ -0,0 +1,30 @@+{- |+ Module : $Header$+ Description : Library to support meta-programming in Curry+ Copyright : Michael Hanus , 2004+ Martin Engelke , 2005+ Björn Peemöller, 2013+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This library contains a definition for representing Curry programs+ in Haskell by the type 'CurryProg' and I/O actions to read Curry programs+ and transform them into this abstract representation as well as+ write them to a file.++ Note that this defines a slightly new format for AbstractCurry+ in comparison to the first proposal of 2003.++ /Assumption:/ An AbstractCurry program @Prog@ is stored in a file with+ the file extension @acy@, i.e. in a file @Prog.acy@.+-}+module Curry.AbstractCurry+ ( module Curry.AbstractCurry.Type+ , module Curry.AbstractCurry.Files+ ) where++import Curry.AbstractCurry.Type+import Curry.AbstractCurry.Files
+ src/Curry/AbstractCurry/Files.hs view
@@ -0,0 +1,61 @@+{- |+ Module : $Header$+ Description : Library to support meta-programming in Curry+ Copyright : (c) Michael Hanus , 2004+ Martin Engelke , 2005+ Björn Peemöller, 2014+ Finn Teegen , 2016+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This library contains I/O actions to read Curry programs+ and transform them into this abstract representation as well as+ write them to a file.+-}+module Curry.AbstractCurry.Files+ ( readCurry, writeCurry, showCurry+ ) where++import qualified Control.Exception as C (catch)+import Data.List (intercalate)++import Curry.Files.PathUtils ( writeModule, readModule+ , addVersion, checkVersion)++import Curry.AbstractCurry.Type++-- ---------------------------------------------------------------------------+-- Reading and writing AbstractCurry terms+-- ---------------------------------------------------------------------------++-- |Read an AbstractCurry file and return the corresponding AbstractCurry+-- program term of type 'CurryProg'+readCurry :: FilePath -> IO (Maybe CurryProg)+readCurry fn = do+ mbSrc <- readModule fn+ return $ case mbSrc of+ Nothing -> Nothing+ Just src -> case checkVersion version src of+ Left _ -> Nothing+ Right ac -> Just (read ac)++-- |Write an AbstractCurry program term into a file.+writeCurry :: FilePath -> CurryProg -> IO ()+writeCurry fn p = C.catch (writeModule fn $ addVersion version $ showCurry p)+ ioError++-- |Show an AbstractCurry program in a nicer way+showCurry :: CurryProg -> String+showCurry (CurryProg mname imps dflt clss insts types funcs ops)+ = "CurryProg " ++ show mname ++ "\n"+ ++ show imps ++ "\n"+ ++ showsPrec 11 dflt "\n"+ ++ wrapList clss+ ++ wrapList insts+ ++ wrapList types+ ++ wrapList funcs+ ++ wrapList ops+ where wrapList xs = " [" ++ intercalate ",\n " (map show xs) ++ "]\n"
+ src/Curry/AbstractCurry/Type.hs view
@@ -0,0 +1,329 @@+{- |+ Module : $Header$+ Description : Library to support meta-programming in Curry+ Copyright : Michael Hanus , 2004+ Martin Engelke , 2005+ Björn Peemöller, 2015+ Finn Teegen , 2016+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This library contains a definition for representing Curry programs+ in Haskell by the type 'CurryProg' and I/O actions to read Curry programs+ and transform them into this abstract representation as well as+ write them to a file.++ Note that this defines a slightly new format for AbstractCurry+ in comparison to the first proposal of 2003.+-}+module Curry.AbstractCurry.Type+ ( CurryProg (..), MName, QName, CVisibility (..), CTVarIName+ , CDefaultDecl (..), CClassDecl (..), CInstanceDecl (..)+ , CTypeDecl (..), CConsDecl (..), CFieldDecl (..)+ , CConstraint, CContext (..), CTypeExpr (..), CQualTypeExpr (..)+ , COpDecl (..), CFixity (..), Arity, CFuncDecl (..), CRhs (..), CRule (..)+ , CLocalDecl (..), CVarIName, CExpr (..), CCaseType (..), CStatement (..)+ , CPattern (..), CLiteral (..), CField, version+ ) where++-- ---------------------------------------------------------------------------+-- Abstract syntax+-- ---------------------------------------------------------------------------++-- |Current version of AbstractCurry+version :: String+version = "AbstractCurry 3.0"++-- |A module name.+type MName = String++-- |A qualified name.+-- In AbstractCurry all names are qualified to avoid name clashes.+-- The first component is the module name and the second component the+-- unqualified name as it occurs in the source program.+type QName = (MName, String)++-- |Data type to specify the visibility of various entities.+data CVisibility+ = Public -- ^ exported entity+ | Private -- ^ private entity+ deriving (Eq, Read, Show)++-- |A Curry module in the intermediate form. A value of this type has the form+-- @+-- CurryProg modname imports dfltdecl clsdecls instdecls typedecls funcdecls opdecls+-- @+-- where+-- [@modname@] Name of this module+-- [@imports@] List of modules names that are imported+-- [@dfltdecl@] Optional default declaration+-- [@clsdecls@] Class declarations+-- [@instdecls@] Instance declarations+-- [@typedecls@] Type declarations+-- [@funcdecls@] Function declarations+-- [@opdecls@] Operator precedence declarations+data CurryProg = CurryProg MName [MName] (Maybe CDefaultDecl) [CClassDecl]+ [CInstanceDecl] [CTypeDecl] [CFuncDecl] [COpDecl]+ deriving (Eq, Read, Show)++-- |Default declaration.+data CDefaultDecl = CDefaultDecl [CTypeExpr]+ deriving (Eq, Read, Show)++-- |Definitions of type classes.+-- A type class definition of the form+-- @+-- class cx => c a where { ...;f :: t;... }+-- @+-- is represented by the Curry term+-- @+-- (CClass c v cx tv [...(CFunc f ar v t [...,CRule r,...])...])+-- @+-- where @tv@ is the index of the type variable @a@ and @v@ is the+-- visibility of the type class resp. method.+-- /Note:/ The type variable indices are unique inside each class+-- declaration and are usually numbered from 0.+-- The methods' types share the type class' type variable index+-- as the class variable has to occur in a method's type signature.+-- The list of rules for a method's declaration may be empty if+-- no default implementation is provided. The arity @ar@ is+-- determined by a given default implementation or 0.+-- Regardless of whether typed or untyped abstract curry is generated,+-- the methods' declarations are always typed.+data CClassDecl = CClass QName CVisibility CContext CTVarIName [CFuncDecl]+ deriving (Eq, Read, Show)++-- |Definitions of instances.+-- An instance definition of the form+-- @+-- instance cx => c ty where { ...;fundecl;... }+-- @+-- is represented by the Curry term+-- @+-- (CInstance c cx ty [...fundecl...])+-- @+-- /Note:/ The type variable indices are unique inside each instance+-- declaration and are usually numbered from 0.+-- The methods' types use the instance's type variable indices+-- (if typed abstract curry is generated).+data CInstanceDecl = CInstance QName CContext CTypeExpr [CFuncDecl]+ deriving (Eq, Read, Show)++-- |Definitions of algebraic data types and type synonyms.+-- A data type definition of the form+-- @+-- data t x1...xn = ...| forall y1...ym . cx => c t1....tkc |...+-- deriving (d1,...,dp)+-- @+-- is represented by the Curry term+-- @+-- (CType t v [i1,...,in] [...(CCons [l1,...,lm] cx c kc v [t1,...,tkc])...]+-- [d1,...,dp])+-- @+-- where each @ij@ is the index of the type variable @xj@, each @lj@ is the+-- index of the existentially quantified type variable @yj@ and @v@ is the+-- visibility of the type resp. constructor.+-- /Note:/ The type variable indices are unique inside each type declaration+-- and are usually numbered from 0.+-- Thus, a data type declaration consists of the name of the data type,+-- a list of type parameters and a list of constructor declarations.+data CTypeDecl+ -- |algebraic data type+ = CType QName CVisibility [CTVarIName] [CConsDecl] [QName]+ -- |type synonym+ | CTypeSyn QName CVisibility [CTVarIName] CTypeExpr+ -- |renaming type, may have only exactly one type expression+ -- in the constructor declaration and no existentially type variables and+ -- no context+ | CNewType QName CVisibility [CTVarIName] CConsDecl [QName]+ deriving (Eq, Read, Show)++-- |The type for representing type variables.+-- They are represented by @(i,n)@ where @i@ is a type variable index+-- which is unique inside a function and @n@ is a name (if possible,+-- the name written in the source program).+type CTVarIName = (Int, String)++-- |A constructor declaration consists of the name of the constructor+-- and a list of the argument types of the constructor.+-- The arity equals the number of types.+data CConsDecl+ = CCons QName CVisibility [CTypeExpr]+ | CRecord QName CVisibility [CFieldDecl]+ deriving (Eq, Read, Show)++-- |A record field declaration consists of the name of the+-- the label, the visibility and its corresponding type.+data CFieldDecl = CField QName CVisibility CTypeExpr+ deriving (Eq, Read, Show)++-- |The type for representing a class constraint.+type CConstraint = (QName, CTypeExpr)++-- |The type for representing a context.+data CContext = CContext [CConstraint]+ deriving (Eq, Read, Show)++-- |Type expression.+-- A type expression is either a type variable, a function type,+-- a type constructor or a type application.+data CTypeExpr+ -- |Type variable+ = CTVar CTVarIName+ -- |Function type @t1 -> t2@+ | CFuncType CTypeExpr CTypeExpr+ -- |Type constructor+ | CTCons QName+ -- |Type application+ | CTApply CTypeExpr CTypeExpr+ deriving (Eq, Read, Show)++-- |Qualified type expression.+data CQualTypeExpr = CQualType CContext CTypeExpr+ deriving (Eq, Read, Show)++-- |Labeled record fields+type CField a = (QName, a)++-- |Operator precedence declaration.+-- An operator precedence declaration @fix p n@ in Curry corresponds to the+-- AbstractCurry term @(COp n fix p)@.+data COpDecl = COp QName CFixity Int+ deriving (Eq, Read, Show)++-- |Fixity declarations of infix operators+data CFixity+ = CInfixOp -- ^ non-associative infix operator+ | CInfixlOp -- ^ left-associative infix operator+ | CInfixrOp -- ^ right-associative infix operator+ deriving (Eq, Read, Show)++-- |Function arity+type Arity = Int++-- |Data type for representing function declarations.+-- A function declaration in FlatCurry is a term of the form+-- @+-- (CFunc name arity visibility type (CRules eval [CRule rule1,...,rulek]))+-- @+-- and represents the function @name@ with definition+-- @+-- name :: type+-- rule1+-- ...+-- rulek+-- @+-- /Note:/ The variable indices are unique inside each rule.+-- External functions are represented as+-- @+-- (CFunc name arity type (CExternal s))+-- @+-- where s is the external name associated to this function.+-- Thus, a function declaration consists of the name, arity, type, and+-- a list of rules.+-- If the list of rules is empty, the function is considered+-- to be externally defined.+data CFuncDecl = CFunc QName Arity CVisibility CQualTypeExpr [CRule]+ deriving (Eq, Read, Show)++-- |The general form of a function rule. It consists of a list of patterns+-- (left-hand side), a list of guards (@success@ if not present in the+-- source text) with their corresponding right-hand sides, and+-- a list of local declarations.+data CRule = CRule [CPattern] CRhs+ deriving (Eq, Read, Show)++-- |Right-hand-side of a 'CRule' or an @case@ expression+data CRhs+ = CSimpleRhs CExpr [CLocalDecl] -- @expr where decls@+ | CGuardedRhs [(CExpr, CExpr)] [CLocalDecl] -- @| cond = expr where decls@+ deriving (Eq, Read, Show)++-- | Local (let/where) declarations+data CLocalDecl+ = CLocalFunc CFuncDecl -- ^ local function declaration+ | CLocalPat CPattern CRhs -- ^ local pattern declaration+ | CLocalVars [CVarIName] -- ^ local free variable declarations+ deriving (Eq, Read, Show)++-- |Variable names.+-- Object variables occurring in expressions are represented by @(Var i)@+-- where @i@ is a variable index.+type CVarIName = (Int, String)++-- |Pattern expressions.+data CPattern+ -- |pattern variable (unique index / name)+ = CPVar CVarIName+ -- |literal (Integer/Float/Char constant)+ | CPLit CLiteral+ -- |application @(m.c e1 ... en)@ of n-ary constructor @m.c@+ -- (@CPComb (m,c) [e1,...,en]@)+ | CPComb QName [CPattern]+ -- |as-pattern (extended Curry)+ | CPAs CVarIName CPattern+ -- |functional pattern (extended Curry)+ | CPFuncComb QName [CPattern]+ -- |lazy pattern (extended Curry)+ | CPLazy CPattern+ -- |record pattern (extended curry)+ | CPRecord QName [CField CPattern]+ deriving (Eq, Read, Show)++-- | Curry expressions.+data CExpr+ -- |variable (unique index / name)+ = CVar CVarIName+ -- |literal (Integer/Float/Char/String constant)+ | CLit CLiteral+ -- |a defined symbol with module and name, i.e., a function or a constructor+ | CSymbol QName+ -- |application (e1 e2)+ | CApply CExpr CExpr+ -- |lambda abstraction+ | CLambda [CPattern] CExpr+ -- |local let declarations+ | CLetDecl [CLocalDecl] CExpr+ -- |do block+ | CDoExpr [CStatement]+ -- |list comprehension+ | CListComp CExpr [CStatement]+ -- |case expression+ | CCase CCaseType CExpr [(CPattern, CRhs)]+ -- |typed expression+ | CTyped CExpr CQualTypeExpr+ -- |record construction (extended Curry)+ | CRecConstr QName [CField CExpr]+ -- |record update (extended Curry)+ | CRecUpdate CExpr [CField CExpr]+ deriving (Eq, Read, Show)++-- |Literals occurring in an expression or a pattern,+-- either an integer, a float, a character, or a string constant.+-- /Note:/ The constructor definition of 'CIntc' differs from the original+-- PAKCS definition. It uses Haskell type 'Integer' instead of 'Int'+-- to provide an unlimited range of integer numbers. Furthermore,+-- float values are represented with Haskell type 'Double' instead of+-- 'Float' to gain double precision.+data CLiteral+ = CIntc Integer -- ^ Int literal+ | CFloatc Double -- ^ Float literal+ | CCharc Char -- ^ Char literal+ | CStringc String -- ^ String literal+ deriving (Eq, Read, Show)++-- |Statements in do expressions and list comprehensions.+data CStatement+ = CSExpr CExpr -- ^ an expression (I/O action or boolean)+ | CSPat CPattern CExpr -- ^ a pattern definition+ | CSLet [CLocalDecl] -- ^ a local let declaration+ deriving (Eq, Read, Show)++-- |Type of case expressions+data CCaseType+ = CRigid -- ^ rigid case expression+ | CFlex -- ^ flexible case expression+ deriving (Eq, Read, Show)
+ src/Curry/Base/Ident.hs view
@@ -0,0 +1,1036 @@+{- |+ Module : $Header$+ Description : Identifiers+ Copyright : (c) 1999 - 2004, Wolfgang Lux+ 2011 - 2013, Björn Peemöller+ 2016 , Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module provides the implementation of identifiers and some+ utility functions for identifiers.++ Identifiers comprise the name of the denoted entity and an /id/,+ which can be used for renaming identifiers, e.g., in order to resolve+ name conflicts between identifiers from different scopes. An+ identifier with an /id/ @0@ is considered as not being renamed+ and, hence, its /id/ will not be shown.++ Qualified identifiers may optionally be prefixed by a module name.+-}+{-# LANGUAGE CPP #-}+module Curry.Base.Ident+ ( -- * Module identifiers+ ModuleIdent (..), mkMIdent, moduleName, escModuleName+ , fromModuleName, isValidModuleName, addPositionModuleIdent, mIdentLength++ -- * Local identifiers+ , Ident (..), mkIdent, showIdent, escName, identSupply+ , globalScope, hasGlobalScope, isRenamed, renameIdent, unRenameIdent+ , updIdentName, addPositionIdent, isInfixOp, identLength++ -- * Qualified identifiers+ , QualIdent (..), qualName, escQualName, isQInfixOp, qualify+ , qualifyWith, qualQualify, qualifyLike, isQualified, unqualify, qualUnqualify+ , localIdent, isLocalIdent, updQualIdent, qIdentLength++ -- * Predefined simple identifiers+ -- ** Identifiers for modules+ , emptyMIdent, mainMIdent, preludeMIdent+ -- ** Identifiers for types+ , arrowId, unitId, boolId, charId, intId, floatId, listId, ioId, successId+ -- ** Identifiers for type classes+ , eqId, ordId, enumId, boundedId, readId, showId+ , numId, fractionalId+ , monadId, monadFailId+ , dataId+ -- ** Identifiers for constructors+ , trueId, falseId, nilId, consId, tupleId, isTupleId, tupleArity+ -- ** Identifiers for values+ , mainId, minusId, fminusId, applyId, errorId, failedId, idId+ , succId, predId, toEnumId, fromEnumId, enumFromId, enumFromThenId+ , enumFromToId, enumFromThenToId+ , maxBoundId, minBoundId+ , lexId, readsPrecId, readParenId+ , showsPrecId, showParenId, showStringId+ , andOpId, eqOpId, leqOpId, ltOpId, orOpId, appendOpId, dotOpId+ , aValueId, dataEqId+ , anonId, isAnonId++ -- * Predefined qualified identifiers+ -- ** Identifiers for types+ , qArrowId, qUnitId, qBoolId, qCharId, qIntId, qFloatId, qListId, qIOId+ , qSuccessId, isPrimTypeId+ -- ** Identifiers for type classes+ , qEqId, qOrdId, qEnumId, qBoundedId, qReadId, qShowId+ , qNumId, qFractionalId+ , qMonadId, qMonadFailId+ , qDataId+ -- ** Identifiers for constructors+ , qTrueId, qFalseId, qNilId, qConsId, qTupleId, isQTupleId, qTupleArity+ -- ** Identifiers for values+ , qApplyId, qErrorId, qFailedId, qIdId+ , qFromEnumId, qEnumFromId, qEnumFromThenId, qEnumFromToId, qEnumFromThenToId+ , qMaxBoundId, qMinBoundId+ , qLexId, qReadsPrecId, qReadParenId+ , qShowsPrecId, qShowParenId, qShowStringId+ , qAndOpId, qEqOpId, qLeqOpId, qLtOpId, qOrOpId, qAppendOpId, qDotOpId+ , qAValueId, qDataEqId++ -- * Extended functionality+ -- ** Functional patterns+ , fpSelectorId, isFpSelectorId, isQualFpSelectorId+ -- ** Records+ , recSelectorId, qualRecSelectorId, recUpdateId, qualRecUpdateId+ , recordExt, recordExtId, isRecordExtId, fromRecordExtId+ , labelExt, labelExtId, isLabelExtId, fromLabelExtId+ , renameLabel, mkLabelIdent+ ) where++import Prelude hiding ((<>))+import Data.Char (isAlpha, isAlphaNum)+import Data.Function (on)+import Data.List (intercalate, isInfixOf, isPrefixOf)+import Data.Maybe (isJust, fromMaybe)+import Data.Binary+import Control.Monad++import Curry.Base.Position+import Curry.Base.Span hiding (file)+import Curry.Base.SpanInfo+import Curry.Base.Pretty++-- ---------------------------------------------------------------------------+-- Module identifier+-- ---------------------------------------------------------------------------++-- | Module identifier+data ModuleIdent = ModuleIdent+ { midSpanInfo :: SpanInfo -- ^ source code 'SpanInfo'+ , midQualifiers :: [String] -- ^ hierarchical idenfiers+ } deriving (Read, Show)++instance Eq ModuleIdent where+ (==) = (==) `on` midQualifiers++instance Ord ModuleIdent where+ compare = compare `on` midQualifiers++instance HasSpanInfo ModuleIdent where+ getSpanInfo = midSpanInfo+ setSpanInfo spi a = a { midSpanInfo = spi }+ updateEndPos i =+ setEndPosition (incr (getPosition i) (mIdentLength i - 1)) i++instance HasPosition ModuleIdent where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance Pretty ModuleIdent where+ pPrint = hcat . punctuate dot . map text . midQualifiers++instance Binary ModuleIdent where+ put (ModuleIdent sp qs) = put sp >> put qs+ get = liftM2 ModuleIdent get get++mIdentLength :: ModuleIdent -> Int+mIdentLength a = length (concat (midQualifiers a))+ + length (midQualifiers a)++-- |Construct a 'ModuleIdent' from a list of 'String's forming the+-- the hierarchical module name.+mkMIdent :: [String] -> ModuleIdent+mkMIdent = ModuleIdent NoSpanInfo++-- |Retrieve the hierarchical name of a module+moduleName :: ModuleIdent -> String+moduleName = intercalate "." . midQualifiers++-- |Show the name of an 'ModuleIdent' escaped by ticks+escModuleName :: ModuleIdent -> String+escModuleName m = '`' : moduleName m ++ "'"++-- |Add a source code 'Position' to a 'ModuleIdent'+addPositionModuleIdent :: Position -> ModuleIdent -> ModuleIdent+addPositionModuleIdent = setPosition++-- |Check whether a 'String' is a valid module name.+--+-- Valid module names must satisfy the following conditions:+--+-- * The name must not be empty+-- * The name must consist of one or more single identifiers,+-- seperated by dots+-- * Each single identifier must be non-empty, start with a letter and+-- consist of letter, digits, single quotes or underscores only+isValidModuleName :: String -> Bool+isValidModuleName [] = False -- Module names may not be empty+isValidModuleName qs = all isModuleIdentifier $ splitIdentifiers qs+ where+ -- components of a module identifier may not be null+ isModuleIdentifier [] = False+ -- components of a module identifier must start with a letter and consist+ -- of letter, digits, underscores or single quotes+ isModuleIdentifier (c:cs) = isAlpha c && all isIdent cs+ isIdent c = isAlphaNum c || c `elem` "'_"++-- |Resemble the hierarchical module name from a 'String' by splitting+-- the 'String' at inner dots.+--+-- /Note:/ This function does not check the 'String' to be a valid module+-- identifier, use isValidModuleName for this purpose.+fromModuleName :: String -> ModuleIdent+fromModuleName = mkMIdent . splitIdentifiers++-- Auxiliary function to split a hierarchical module identifier at the dots+splitIdentifiers :: String -> [String]+splitIdentifiers s = let (pref, rest) = break (== '.') s in+ pref : case rest of+ [] -> []+ (_:s') -> splitIdentifiers s'++-- ---------------------------------------------------------------------------+-- Simple identifier+-- ---------------------------------------------------------------------------++-- |Simple identifier+data Ident = Ident+ { idSpanInfo :: SpanInfo -- ^ Source code 'SpanInfo'+ , idName :: String -- ^ Name of the identifier+ , idUnique :: Integer -- ^ Unique number of the identifier+ } deriving (Read, Show)++instance Eq Ident where+ Ident _ m i == Ident _ n j = (m, i) == (n, j)++instance Ord Ident where+ Ident _ m i `compare` Ident _ n j = (m, i) `compare` (n, j)++instance HasSpanInfo Ident where+ getSpanInfo = idSpanInfo+ setSpanInfo spi a = a { idSpanInfo = spi }+ updateEndPos i@(Ident (SpanInfo _ [_,ss]) _ _) =+ setEndPosition (end ss) i+ updateEndPos i =+ setEndPosition (incr (getPosition i) (identLength i - 1)) i++instance HasPosition Ident where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance Pretty Ident where+ pPrint (Ident _ x n) | n == globalScope = text x+ | otherwise = text x <> dot <> integer n++instance Binary Ident where+ put (Ident sp qs i) = put sp >> put qs >> put i+ get = liftM3 Ident get get get++identLength :: Ident -> Int+identLength a = length (idName a)++-- |Global scope for renaming+globalScope :: Integer+globalScope = 0++-- |Construct an 'Ident' from a 'String'+mkIdent :: String -> Ident+mkIdent x = Ident NoSpanInfo x globalScope++-- |Infinite list of different 'Ident's+identSupply :: [Ident]+identSupply = [ mkNewIdent c i | i <- [0 ..] :: [Integer], c <- ['a'..'z'] ]+ where mkNewIdent c 0 = mkIdent [c]+ mkNewIdent c n = mkIdent $ c : show n++-- |Show function for an 'Ident'+showIdent :: Ident -> String+showIdent (Ident _ x n) | n == globalScope = x+ | otherwise = x ++ '.' : show n++-- |Show the name of an 'Ident' escaped by ticks+escName :: Ident -> String+escName i = '`' : idName i ++ "'"++-- |Has the identifier global scope?+hasGlobalScope :: Ident -> Bool+hasGlobalScope = (== globalScope) . idUnique++-- |Is the 'Ident' renamed?+isRenamed :: Ident -> Bool+isRenamed = (/= globalScope) . idUnique++-- |Rename an 'Ident' by changing its unique number+renameIdent :: Ident -> Integer -> Ident+renameIdent ident n = ident { idUnique = n }++-- |Revert the renaming of an 'Ident' by resetting its unique number+unRenameIdent :: Ident -> Ident+unRenameIdent ident = renameIdent ident globalScope++-- |Change the name of an 'Ident' using a renaming function+updIdentName :: (String -> String) -> Ident -> Ident+updIdentName f (Ident p n i) = Ident p (f n) i++-- |Add a 'Position' to an 'Ident'+addPositionIdent :: Position -> Ident -> Ident+addPositionIdent = setPosition++-- |Check whether an 'Ident' identifies an infix operation+isInfixOp :: Ident -> Bool+isInfixOp (Ident _ ('<' : c : cs) _) =+ last (c : cs) /= '>' || not (isAlphaNum c) && c `notElem` "_(["+isInfixOp (Ident _ (c : _) _) = not (isAlphaNum c) && c `notElem` "_(["+isInfixOp Ident{} = False -- error "Zero-length identifier"++-- ---------------------------------------------------------------------------+-- Qualified identifier+-- ---------------------------------------------------------------------------++-- |Qualified identifier+data QualIdent = QualIdent+ { qidSpanInfo :: SpanInfo -- ^ Source code 'SpanInfo'+ , qidModule :: Maybe ModuleIdent -- ^ optional module identifier+ , qidIdent :: Ident -- ^ identifier itself+ } deriving (Read, Show)++instance Eq QualIdent where+ QualIdent _ m i == QualIdent _ n j = (m, i) == (n, j)++instance Ord QualIdent where+ QualIdent _ m i `compare` QualIdent _ n j = (m, i) `compare` (n, j)++instance HasSpanInfo QualIdent where+ getSpanInfo = qidSpanInfo+ setSpanInfo spi a = a { qidSpanInfo = spi }+ updateEndPos i@(QualIdent (SpanInfo _ [_,ss]) _ _) =+ setEndPosition (end ss) i+ updateEndPos i =+ setEndPosition (incr (getPosition i) (qIdentLength i - 1)) i++instance HasPosition QualIdent where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance Pretty QualIdent where+ pPrint = text . qualName++instance Binary QualIdent where+ put (QualIdent sp mid idt) = put sp >> put mid >> put idt+ get = liftM3 QualIdent get get get++qIdentLength :: QualIdent -> Int+qIdentLength (QualIdent _ (Just m) i) = identLength i + mIdentLength m+qIdentLength (QualIdent _ Nothing i) = identLength i++-- |show function for qualified identifiers)=+qualName :: QualIdent -> String+qualName (QualIdent _ Nothing x) = idName x+qualName (QualIdent _ (Just m) x) = moduleName m ++ "." ++ idName x++-- |Show the name of an 'QualIdent' escaped by ticks+escQualName :: QualIdent -> String+escQualName qn = '`' : qualName qn ++ "'"++-- |Check whether an 'QualIdent' identifies an infix operation+isQInfixOp :: QualIdent -> Bool+isQInfixOp = isInfixOp . qidIdent++-- ---------------------------------------------------------------------------+-- The functions \texttt{qualify} and \texttt{qualifyWith} convert an+-- unqualified identifier into a qualified identifier (without and with a+-- given module prefix, respectively).+-- ---------------------------------------------------------------------------++-- | Convert an 'Ident' to a 'QualIdent'+qualify :: Ident -> QualIdent+qualify i = QualIdent (fromSrcSpan (getSrcSpan i)) Nothing i++-- | Convert an 'Ident' to a 'QualIdent' with a given 'ModuleIdent'+qualifyWith :: ModuleIdent -> Ident -> QualIdent+qualifyWith mid i = updateEndPos $+ QualIdent (fromSrcSpan (getSrcSpan mid)) (Just mid) i++-- | Convert an 'QualIdent' to a new 'QualIdent' with a given 'ModuleIdent'.+-- If the original 'QualIdent' already contains an 'ModuleIdent' it+-- remains unchanged.+qualQualify :: ModuleIdent -> QualIdent -> QualIdent+qualQualify m (QualIdent _ Nothing x) = qualifyWith m x+qualQualify _ x = x++-- |Qualify an 'Ident' with the 'ModuleIdent' of the given 'QualIdent',+-- if present.+qualifyLike :: QualIdent -> Ident -> QualIdent+qualifyLike (QualIdent _ Nothing _) x = qualify x+qualifyLike (QualIdent _ (Just m) _) x = qualifyWith m x++-- | Check whether a 'QualIdent' contains a 'ModuleIdent'+isQualified :: QualIdent -> Bool+isQualified = isJust . qidModule++-- | Remove the qualification of an 'QualIdent'+unqualify :: QualIdent -> Ident+unqualify = qidIdent++-- | Remove the qualification with a specific 'ModuleIdent'. If the+-- original 'QualIdent' has no 'ModuleIdent' or a different one, it+-- remains unchanged.+qualUnqualify :: ModuleIdent -> QualIdent -> QualIdent+qualUnqualify _ qid@(QualIdent _ Nothing _) = qid+qualUnqualify m (QualIdent spi (Just m') x) = QualIdent spi m'' x+ where m'' | m == m' = Nothing+ | otherwise = Just m'++-- | Extract the 'Ident' of an 'QualIdent' if it is local to the+-- 'ModuleIdent', i.e. if the 'Ident' is either unqualified or qualified+-- with the given 'ModuleIdent'.+localIdent :: ModuleIdent -> QualIdent -> Maybe Ident+localIdent _ (QualIdent _ Nothing x) = Just x+localIdent m (QualIdent _ (Just m') x)+ | m == m' = Just x+ | otherwise = Nothing++-- |Check whether the given 'QualIdent' is local to the given 'ModuleIdent'.+isLocalIdent :: ModuleIdent -> QualIdent -> Bool+isLocalIdent mid qid = isJust (localIdent mid qid)++-- | Update a 'QualIdent' by applying functions to its components+updQualIdent :: (ModuleIdent -> ModuleIdent) -> (Ident -> Ident)+ -> QualIdent -> QualIdent+updQualIdent f g (QualIdent spi m x) = QualIdent spi (fmap f m) (g x)++-- ---------------------------------------------------------------------------+-- A few identifiers are predefined here.+-- ---------------------------------------------------------------------------+-- | 'ModuleIdent' for the empty module+emptyMIdent :: ModuleIdent+emptyMIdent = ModuleIdent NoSpanInfo []++-- | 'ModuleIdent' for the main module+mainMIdent :: ModuleIdent+mainMIdent = ModuleIdent NoSpanInfo ["main"]++-- | 'ModuleIdent' for the Prelude+preludeMIdent :: ModuleIdent+preludeMIdent = ModuleIdent NoSpanInfo ["Prelude"]++-- ---------------------------------------------------------------------------+-- Identifiers for types+-- ---------------------------------------------------------------------------++-- | 'Ident' for the type '(->)'+arrowId :: Ident+arrowId = mkIdent "(->)"++-- | 'Ident' for the type/value unit ('()')+unitId :: Ident+unitId = mkIdent "()"++-- | 'Ident' for the type 'Bool'+boolId :: Ident+boolId = mkIdent "Bool"++-- | 'Ident' for the type 'Char'+charId :: Ident+charId = mkIdent "Char"++-- | 'Ident' for the type 'Int'+intId :: Ident+intId = mkIdent "Int"++-- | 'Ident' for the type 'Float'+floatId :: Ident+floatId = mkIdent "Float"++-- | 'Ident' for the type '[]'+listId :: Ident+listId = mkIdent "[]"++-- | 'Ident' for the type 'IO'+ioId :: Ident+ioId = mkIdent "IO"++-- | 'Ident' for the type 'Success'+successId :: Ident+successId = mkIdent "Success"++-- | Construct an 'Ident' for an n-ary tuple where n > 1+tupleId :: Int -> Ident+tupleId n+ | n > 1 = mkIdent $ '(' : replicate (n - 1) ',' ++ ")"+ | otherwise = error $ "Curry.Base.Ident.tupleId: wrong arity " ++ show n++-- | Check whether an 'Ident' is an identifier for an tuple type+isTupleId :: Ident -> Bool+isTupleId (Ident _ x _) = n > 1 && x == idName (tupleId n)+ where n = length x - 1++-- | Compute the arity of a tuple identifier+tupleArity :: Ident -> Int+tupleArity i@(Ident _ x _)+ | n > 1 && x == idName (tupleId n) = n+ | otherwise = error $+ "Curry.Base.Ident.tupleArity: no tuple identifier: " ++ showIdent i+ where n = length x - 1++-- ---------------------------------------------------------------------------+-- Identifiers for type classes+-- ---------------------------------------------------------------------------++-- | 'Ident' for the 'Eq' class+eqId :: Ident+eqId = mkIdent "Eq"++-- | 'Ident' for the 'Ord' class+ordId :: Ident+ordId = mkIdent "Ord"++-- | 'Ident' for the 'Enum' class+enumId :: Ident+enumId = mkIdent "Enum"++-- | 'Ident' for the 'Bounded' class+boundedId :: Ident+boundedId = mkIdent "Bounded"++-- | 'Ident' for the 'Read' class+readId :: Ident+readId = mkIdent "Read"++-- | 'Ident' for the 'Show' class+showId :: Ident+showId = mkIdent "Show"++-- | 'Ident' for the 'Num' class+numId :: Ident+numId = mkIdent "Num"++-- | 'Ident' for the 'Fractional' class+fractionalId :: Ident+fractionalId = mkIdent "Fractional"++-- | 'Ident' for the 'Monad' class+monadId :: Ident+monadId = mkIdent "Monad"++-- | 'Ident' for the 'MonadFail' class+monadFailId :: Ident+monadFailId = mkIdent "MonadFail"++-- | 'Ident' for the 'Data' class+dataId :: Ident+dataId = mkIdent "Data"++-- ---------------------------------------------------------------------------+-- Identifiers for constructors+-- ---------------------------------------------------------------------------++-- | 'Ident' for the value 'True'+trueId :: Ident+trueId = mkIdent "True"++-- | 'Ident' for the value 'False'+falseId :: Ident+falseId = mkIdent "False"++-- | 'Ident' for the value '[]'+nilId :: Ident+nilId = mkIdent "[]"++-- | 'Ident' for the function ':'+consId :: Ident+consId = mkIdent ":"++-- ---------------------------------------------------------------------------+-- Identifiers for values+-- ---------------------------------------------------------------------------++-- | 'Ident' for the main function+mainId :: Ident+mainId = mkIdent "main"++-- | 'Ident' for the minus function+minusId :: Ident+minusId = mkIdent "-"++-- | 'Ident' for the minus function for Floats+fminusId :: Ident+fminusId = mkIdent "-."++-- | 'Ident' for the apply function+applyId :: Ident+applyId = mkIdent "apply"++-- | 'Ident' for the error function+errorId :: Ident+errorId = mkIdent "error"++-- | 'Ident' for the failed function+failedId :: Ident+failedId = mkIdent "failed"++-- | 'Ident' for the id function+idId :: Ident+idId = mkIdent "id"++-- | 'Ident' for the maxBound function+maxBoundId :: Ident+maxBoundId = mkIdent "maxBound"++-- | 'Ident' for the minBound function+minBoundId :: Ident+minBoundId = mkIdent "minBound"++-- | 'Ident' for the pred function+predId :: Ident+predId = mkIdent "pred"++-- | 'Ident' for the succ function+succId :: Ident+succId = mkIdent "succ"++-- | 'Ident' for the toEnum function+toEnumId :: Ident+toEnumId = mkIdent "toEnum"++-- | 'Ident' for the fromEnum function+fromEnumId :: Ident+fromEnumId = mkIdent "fromEnum"++-- | 'Ident' for the enumFrom function+enumFromId :: Ident+enumFromId = mkIdent "enumFrom"++-- | 'Ident' for the enumFromThen function+enumFromThenId :: Ident+enumFromThenId = mkIdent "enumFromThen"++-- | 'Ident' for the enumFromTo function+enumFromToId :: Ident+enumFromToId = mkIdent "enumFromTo"++-- | 'Ident' for the enumFromThenTo function+enumFromThenToId :: Ident+enumFromThenToId = mkIdent "enumFromThenTo"++-- | 'Ident' for the lex function+lexId :: Ident+lexId = mkIdent "lex"++-- | 'Ident' for the readsPrec function+readsPrecId :: Ident+readsPrecId = mkIdent "readsPrec"++-- | 'Ident' for the readParen function+readParenId :: Ident+readParenId = mkIdent "readParen"++-- | 'Ident' for the showsPrec function+showsPrecId :: Ident+showsPrecId = mkIdent "showsPrec"++-- | 'Ident' for the showParen function+showParenId :: Ident+showParenId = mkIdent "showParen"++-- | 'Ident' for the showString function+showStringId :: Ident+showStringId = mkIdent "showString"++-- | 'Ident' for the '&&' operator+andOpId :: Ident+andOpId = mkIdent "&&"++-- | 'Ident' for the '==' operator+eqOpId :: Ident+eqOpId = mkIdent "=="++-- | 'Ident' for the '<=' operator+leqOpId :: Ident+leqOpId = mkIdent "<="++-- | 'Ident' for the '<' operator+ltOpId :: Ident+ltOpId = mkIdent "<"++-- | 'Ident' for the '||' operator+orOpId :: Ident+orOpId = mkIdent "||"++-- | 'Ident' for the '++' operator+appendOpId :: Ident+appendOpId = mkIdent "++"++-- | 'Ident' for the '.' operator+dotOpId :: Ident+dotOpId = mkIdent "."++aValueId :: Ident+aValueId = mkIdent "aValue"++dataEqId :: Ident+dataEqId = mkIdent "==="++-- | 'Ident' for anonymous variable+anonId :: Ident+anonId = mkIdent "_"++-- |Check whether an 'Ident' represents an anonymous identifier ('anonId')+isAnonId :: Ident -> Bool+isAnonId = (== anonId) . unRenameIdent++-- ---------------------------------------------------------------------------+-- Qualified Identifiers for types+-- ---------------------------------------------------------------------------++-- | Construct a 'QualIdent' for an 'Ident' using the module prelude+qPreludeIdent :: Ident -> QualIdent+qPreludeIdent = qualifyWith preludeMIdent++-- | 'QualIdent' for the type '(->)'+qArrowId :: QualIdent+qArrowId = qualify arrowId++-- | 'QualIdent' for the type/value unit ('()')+qUnitId :: QualIdent+qUnitId = qualify unitId++-- | 'QualIdent' for the type '[]'+qListId :: QualIdent+qListId = qualify listId++-- | 'QualIdent' for the type 'Bool'+qBoolId :: QualIdent+qBoolId = qPreludeIdent boolId++-- | 'QualIdent' for the type 'Char'+qCharId :: QualIdent+qCharId = qPreludeIdent charId++-- | 'QualIdent' for the type 'Int'+qIntId :: QualIdent+qIntId = qPreludeIdent intId++-- | 'QualIdent' for the type 'Float'+qFloatId :: QualIdent+qFloatId = qPreludeIdent floatId++-- | 'QualIdent' for the type 'IO'+qIOId :: QualIdent+qIOId = qPreludeIdent ioId++-- | 'QualIdent' for the type 'Success'+qSuccessId :: QualIdent+qSuccessId = qPreludeIdent successId++-- | Check whether an 'QualIdent' is an primary type constructor+isPrimTypeId :: QualIdent -> Bool+isPrimTypeId tc = tc `elem` [qArrowId, qUnitId, qListId] || isQTupleId tc++-- ---------------------------------------------------------------------------+-- Qualified Identifiers for type classes+-- ---------------------------------------------------------------------------++-- | 'QualIdent' for the 'Eq' class+qEqId :: QualIdent+qEqId = qPreludeIdent eqId++-- | 'QualIdent' for the 'Ord' class+qOrdId :: QualIdent+qOrdId = qPreludeIdent ordId++-- | 'QualIdent' for the 'Enum' class+qEnumId :: QualIdent+qEnumId = qPreludeIdent enumId++-- | 'QualIdent' for the 'Bounded' class+qBoundedId :: QualIdent+qBoundedId = qPreludeIdent boundedId++-- | 'QualIdent' for the 'Read' class+qReadId :: QualIdent+qReadId = qPreludeIdent readId++-- | 'QualIdent' for the 'Show' class+qShowId :: QualIdent+qShowId = qPreludeIdent showId++-- | 'QualIdent' for the 'Num' class+qNumId :: QualIdent+qNumId = qPreludeIdent numId++-- | 'QualIdent' for the 'Fractional' class+qFractionalId :: QualIdent+qFractionalId = qPreludeIdent fractionalId++-- | 'QualIdent' for the 'Monad' class+qMonadId :: QualIdent+qMonadId = qPreludeIdent monadId++-- | 'QualIdent' for the 'MonadFail' class+qMonadFailId :: QualIdent+qMonadFailId = qPreludeIdent monadFailId++-- | 'QualIdent' for the 'Data' class+qDataId :: QualIdent+qDataId = qPreludeIdent dataId++-- ---------------------------------------------------------------------------+-- Qualified Identifiers for constructors+-- ---------------------------------------------------------------------------++-- | 'QualIdent' for the constructor 'True'+qTrueId :: QualIdent+qTrueId = qPreludeIdent trueId++-- | 'QualIdent' for the constructor 'False'+qFalseId :: QualIdent+qFalseId = qPreludeIdent falseId++-- | 'QualIdent' for the constructor '[]'+qNilId :: QualIdent+qNilId = qualify nilId++-- | 'QualIdent' for the constructor ':'+qConsId :: QualIdent+qConsId = qualify consId++-- | 'QualIdent' for the type of n-ary tuples+qTupleId :: Int -> QualIdent+qTupleId = qualify . tupleId++-- | Check whether an 'QualIdent' is an identifier for an tuple type+isQTupleId :: QualIdent -> Bool+isQTupleId = isTupleId . unqualify++-- | Compute the arity of an qualified tuple identifier+qTupleArity :: QualIdent -> Int+qTupleArity = tupleArity . unqualify++-- ---------------------------------------------------------------------------+-- Qualified Identifiers for values+-- ---------------------------------------------------------------------------++-- | 'QualIdent' for the apply function+qApplyId :: QualIdent+qApplyId = qPreludeIdent applyId++-- | 'QualIdent' for the error function+qErrorId :: QualIdent+qErrorId = qPreludeIdent errorId++-- | 'QualIdent' for the failed function+qFailedId :: QualIdent+qFailedId = qPreludeIdent failedId++-- | 'QualIdent' for the id function+qIdId :: QualIdent+qIdId = qPreludeIdent idId++-- | 'QualIdent' for the maxBound function+qMaxBoundId :: QualIdent+qMaxBoundId = qPreludeIdent maxBoundId++-- | 'QualIdent' for the minBound function+qMinBoundId :: QualIdent+qMinBoundId = qPreludeIdent minBoundId++-- | 'QualIdent' for the fromEnum function+qFromEnumId :: QualIdent+qFromEnumId = qPreludeIdent fromEnumId++-- | 'QualIdent' for the enumFrom function+qEnumFromId :: QualIdent+qEnumFromId = qPreludeIdent enumFromId++-- | 'QualIdent' for the enumFromThen function+qEnumFromThenId :: QualIdent+qEnumFromThenId = qPreludeIdent enumFromThenId++-- | 'QualIdent' for the enumFromTo function+qEnumFromToId :: QualIdent+qEnumFromToId = qPreludeIdent enumFromToId++-- | 'QualIdent' for the enumFromThenTo function+qEnumFromThenToId :: QualIdent+qEnumFromThenToId = qPreludeIdent enumFromThenToId++-- | 'QualIdent' for the lex function+qLexId :: QualIdent+qLexId = qPreludeIdent lexId++-- | 'QualIdent' for the readsPrec function+qReadsPrecId :: QualIdent+qReadsPrecId = qPreludeIdent readsPrecId++-- | 'QualIdent' for the readParen function+qReadParenId :: QualIdent+qReadParenId = qPreludeIdent readParenId++-- | 'QualIdent' for the showsPrec function+qShowsPrecId :: QualIdent+qShowsPrecId = qPreludeIdent showsPrecId++-- | 'QualIdent' for the showParen function+qShowParenId :: QualIdent+qShowParenId = qPreludeIdent showParenId++-- | 'QualIdent' for the showString function+qShowStringId :: QualIdent+qShowStringId = qPreludeIdent showStringId++-- | 'QualIdent' for the '&&' operator+qAndOpId :: QualIdent+qAndOpId = qPreludeIdent andOpId++-- | 'QualIdent' for the '==' operator+qEqOpId :: QualIdent+qEqOpId = qPreludeIdent eqOpId++-- | 'QualIdent' for the '<=' operator+qLeqOpId :: QualIdent+qLeqOpId = qPreludeIdent leqOpId++-- | 'QualIdent' for the '<' operator+qLtOpId :: QualIdent+qLtOpId = qPreludeIdent ltOpId++-- | 'QualIdent' for the '||' operator+qOrOpId :: QualIdent+qOrOpId = qPreludeIdent orOpId++-- | 'QualIdent' for the '.' operator+qDotOpId :: QualIdent+qDotOpId = qPreludeIdent dotOpId++qAValueId :: QualIdent+qAValueId = qPreludeIdent aValueId++qDataEqId :: QualIdent+qDataEqId = qPreludeIdent dataEqId++-- | 'QualIdent' for the '++' operator+qAppendOpId :: QualIdent+qAppendOpId = qPreludeIdent appendOpId++-- ---------------------------------------------------------------------------+-- Micellaneous functions for generating and testing extended identifiers+-- ---------------------------------------------------------------------------++-- Functional patterns++-- | Annotation for function pattern identifiers+fpSelExt :: String+fpSelExt = "_#selFP"++-- | Construct an 'Ident' for a functional pattern+fpSelectorId :: Int -> Ident+fpSelectorId n = mkIdent $ fpSelExt ++ show n++-- | Check whether an 'Ident' is an identifier for a functional pattern+isFpSelectorId :: Ident -> Bool+isFpSelectorId = (fpSelExt `isInfixOf`) . idName++-- | Check whether an 'QualIdent' is an identifier for a function pattern+isQualFpSelectorId :: QualIdent -> Bool+isQualFpSelectorId = isFpSelectorId . unqualify++-- Record selection++-- | Annotation for record selection identifiers+recSelExt :: String+recSelExt = "_#selR@"++-- | Construct an 'Ident' for a record selection pattern+recSelectorId :: QualIdent -- ^ identifier of the record+ -> Ident -- ^ identifier of the label+ -> Ident+recSelectorId = mkRecordId recSelExt++-- | Construct a 'QualIdent' for a record selection pattern+qualRecSelectorId :: ModuleIdent -- ^ default module+ -> QualIdent -- ^ record identifier+ -> Ident -- ^ label identifier+ -> QualIdent+qualRecSelectorId m r l = qualRecordId m r $ recSelectorId r l++-- Record update++-- | Annotation for record update identifiers+recUpdExt :: String+recUpdExt = "_#updR@"++-- | Construct an 'Ident' for a record update pattern+recUpdateId :: QualIdent -- ^ record identifier+ -> Ident -- ^ label identifier+ -> Ident+recUpdateId = mkRecordId recUpdExt++-- | Construct a 'QualIdent' for a record update pattern+qualRecUpdateId :: ModuleIdent -- ^ default module+ -> QualIdent -- ^ record identifier+ -> Ident -- ^ label identifier+ -> QualIdent+qualRecUpdateId m r l = qualRecordId m r $ recUpdateId r l++-- Auxiliary function to construct a selector/update identifier+mkRecordId :: String -> QualIdent -> Ident -> Ident+mkRecordId ann r l = mkIdent $ concat+ [ann, idName (unqualify r), ".", idName l]++-- Auxiliary function to qualify a selector/update identifier+qualRecordId :: ModuleIdent -> QualIdent -> Ident -> QualIdent+qualRecordId m r = qualifyWith (fromMaybe m $ qidModule r)++-- Record tyes++-- | Annotation for record identifiers+recordExt :: String+recordExt = "_#Rec:"++-- | Construct an 'Ident' for a record+recordExtId :: Ident -> Ident+recordExtId r = mkIdent $ recordExt ++ idName r++-- | Check whether an 'Ident' is an identifier for a record+isRecordExtId :: Ident -> Bool+isRecordExtId = (recordExt `isPrefixOf`) . idName++-- | Retrieve the 'Ident' from a record identifier+fromRecordExtId :: Ident -> Ident+fromRecordExtId r+ | p == recordExt = mkIdent r'+ | otherwise = r+ where (p, r') = splitAt (length recordExt) (idName r)++-- Record labels++-- | Annotation for record label identifiers+labelExt :: String+labelExt = "_#Lab:"++-- | Construct an 'Ident' for a record label+labelExtId :: Ident -> Ident+labelExtId l = mkIdent $ labelExt ++ idName l++-- | Check whether an 'Ident' is an identifier for a record label+isLabelExtId :: Ident -> Bool+isLabelExtId = (labelExt `isPrefixOf`) . idName++-- | Retrieve the 'Ident' from a record label identifier+fromLabelExtId :: Ident -> Ident+fromLabelExtId l+ | p == labelExt = mkIdent l'+ | otherwise = l+ where (p, l') = splitAt (length labelExt) (idName l)++-- | Construct an 'Ident' for a record label+mkLabelIdent :: String -> Ident+mkLabelIdent c = renameIdent (mkIdent c) (-1)++-- | Rename an 'Ident' for a record label+renameLabel :: Ident -> Ident+renameLabel l = renameIdent l (-1)
+ src/Curry/Base/LLParseComb.hs view
@@ -0,0 +1,380 @@+{- |+ Module : $Header$+ Description : Parser combinators+ Copyright : (c) 1999-2004, Wolfgang Lux+ 2016 , Jan Tikovsky+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ The parsing combinators implemented in this module are based on the+ LL(1) parsing combinators developed by Swierstra and Duponcheel.+ They have been adapted to using continuation passing style in order to+ work with the lexing combinators described in the previous section.+ In addition, the facilities for error correction are omitted+ in this implementation.++ The two functions 'applyParser' and 'prefixParser' use the specified+ parser for parsing a string. When 'applyParser' is used, an error is+ reported if the parser does not consume the whole string,+ whereas 'prefixParser' discards the rest of the input string in this case.+-}+{-# LANGUAGE CPP #-}++module Curry.Base.LLParseComb+ ( -- * Data types+ Parser++ -- * Parser application+ , fullParser, prefixParser++ -- * Basic parsers+ , position, spanPosition, succeed, failure, symbol++ -- * parser combinators+ , (<?>), (<|>), (<|?>), (<*>), (<\>), (<\\>)+ , (<$>), (<$->), (<*->), (<-*>), (<**>), (<??>), (<.>)+ , opt, choice, flag, optional, option, many, many1, sepBy, sepBy1+ , sepBySp, sepBy1Sp+ , chainr, chainr1, chainl, chainl1, between, ops++ -- * Layout combinators+ , layoutOn, layoutOff, layoutEnd+ ) where++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative (Applicative, (<*>), (<$>), pure)+#endif+import Control.Monad+import qualified Data.Map as Map+import Data.Maybe+import qualified Data.Set as Set++import Curry.Base.LexComb+import Curry.Base.Position+import Curry.Base.Span (span2Pos, Span, startCol, setDistance)++infixl 5 <\>, <\\>+infixl 4 <$->, <*->, <-*>, <**>, <??>, <.>+infixl 3 <|>, <|?>+infixl 2 <?>, `opt`++-- ---------------------------------------------------------------------------+-- Parser types+-- ---------------------------------------------------------------------------++-- |Parsing function+type ParseFun a s b = (b -> SuccessP s a) -> FailP a -> SuccessP s a++-- |CPS-Parser type+data Parser a s b = Parser+ -- Parsing function for empty word+ (Maybe (ParseFun a s b))+ -- Lookup table (continuations for 'Symbol's recognized by the parser)+ (Map.Map s (Lexer s a -> ParseFun a s b))++instance Symbol s => Functor (Parser a s) where+ fmap f p = succeed f <*> p++instance Symbol s => Applicative (Parser a s) where+ pure = succeed++ -- |Apply the result function of the first parser to the result of the+ -- second parser.+ Parser Nothing ps1 <*> p2 = Parser Nothing+ (fmap (`seqPP` p2) ps1)+ Parser (Just p1) ps1 <*> ~p2@(Parser e2 ps2) = Parser (fmap (seqEE p1) e2)+ (Map.union (fmap (`seqPP` p2) ps1) (fmap (seqEP p1) ps2))++instance Show s => Show (Parser a s b) where+ showsPrec p (Parser e ps) = showParen (p >= 10) $+ showString "Parser " . shows (isJust e) .+ showChar ' ' . shows (Map.keysSet ps)++-- ---------------------------------------------------------------------------+-- Parser application+-- ---------------------------------------------------------------------------++-- |Apply a parser and lexer to a 'String', whereas the 'FilePath' is used+-- to identify the origin of the 'String' in case of parsing errors.+fullParser :: Symbol s => Parser a s a -> Lexer s a -> FilePath -> String+ -> CYM a+fullParser p lexer = parse (lexer (choose p lexer successP failP) failP)+ where successP x pos s+ | isEOF s = returnP x+ | otherwise = failP pos (unexpected s)++-- |Apply a parser and lexer to parse the beginning of a 'String'.+-- The 'FilePath' is used to identify the origin of the 'String' in case of+-- parsing errors.+prefixParser :: Symbol s => Parser a s a -> Lexer s a -> FilePath -> String+ -> CYM a+prefixParser p lexer = parse (lexer (choose p lexer discardP failP) failP)+ where discardP x _ _ = returnP x++-- |Choose the appropriate parsing function w.r.t. to the next 'Symbol'.+choose :: Symbol s => Parser a s b -> Lexer s a -> ParseFun a s b+choose (Parser e ps) lexer success failp pos s = case Map.lookup s ps of+ Just p -> p lexer success failp pos s+ Nothing -> case e of+ Just p -> p success failp pos s+ Nothing -> failp pos (unexpected s)++-- |Fail on an unexpected 'Symbol'+unexpected :: Symbol s => s -> String+unexpected s+ | isEOF s = "Unexpected end-of-file"+ | otherwise = "Unexpected token " ++ show s++-- ---------------------------------------------------------------------------+-- Basic parsers+-- ---------------------------------------------------------------------------++-- |Return the current position without consuming the input+position :: Parser a s Position+position = Parser (Just p) Map.empty+ where p success _ sp = success (span2Pos sp) sp++spanPosition :: Symbol s => Parser a s Span+spanPosition = Parser (Just p) Map.empty+ where p success _ sp s = success (setDistance sp (dist (startCol sp) s)) sp s++-- |Always succeeding parser+succeed :: b -> Parser a s b+succeed x = Parser (Just p) Map.empty+ where p success _ = success x++-- |Always failing parser with a given message+failure :: String -> Parser a s b+failure msg = Parser (Just p) Map.empty+ where p _ failp pos _ = failp pos msg++-- |Create a parser accepting the given 'Symbol'+symbol :: s -> Parser a s s+symbol s = Parser Nothing (Map.singleton s p)+ where p lexer success failp _ s' = lexer (success s') failp++-- ---------------------------------------------------------------------------+-- Parser combinators+-- ---------------------------------------------------------------------------++-- |Behave like the given parser, but use the given 'String' as the error+-- message if the parser fails+(<?>) :: Symbol s => Parser a s b -> String -> Parser a s b+p <?> msg = p <|> failure msg++-- |Deterministic choice between two parsers.+-- The appropriate parser is chosen based on the next 'Symbol'+(<|>) :: Symbol s => Parser a s b -> Parser a s b -> Parser a s b+Parser e1 ps1 <|> Parser e2 ps2+ | isJust e1 && isJust e2 = failure "Ambiguous parser for empty word"+ | not (Set.null common) = failure $ "Ambiguous parser for " ++ show common+ | otherwise = Parser (e1 `mplus` e2) (Map.union ps1 ps2)+ where common = Map.keysSet ps1 `Set.intersection` Map.keysSet ps2++-- |Non-deterministic choice between two parsers.+--+-- The other parsing combinators require that the grammar being parsed+-- is LL(1). In some cases it may be difficult or even+-- impossible to transform a grammar into LL(1) form. As a remedy, we+-- include a non-deterministic version of the choice combinator in+-- addition to the deterministic combinator adapted from the paper. For+-- every symbol from the intersection of the parser's first sets, the+-- combinator '(<|?>)' applies both parsing functions to the input+-- stream and uses that one which processes the longer prefix of the+-- input stream irrespective of whether it succeeds or fails. If both+-- functions recognize the same prefix, we choose the one that succeeds+-- and report an ambiguous parse error if both succeed.+(<|?>) :: Symbol s => Parser a s b -> Parser a s b -> Parser a s b+Parser e1 ps1 <|?> Parser e2 ps2+ | isJust e1 && isJust e2 = failure "Ambiguous parser for empty word"+ | otherwise = Parser (e1 `mplus` e2) (Map.union ps1' ps2)+ where+ ps1' = Map.fromList [ (s, maybe p (try p) (Map.lookup s ps2))+ | (s, p) <- Map.toList ps1+ ]+ try p1 p2 lexer success failp pos s =+ closeP1 p2s `thenP` \p2s' ->+ closeP1 p2f `thenP` \p2f' ->+ parse' p1 (retry p2s') (retry p2f')+ where p2s r1 = parse' p2 (select True r1) (select False r1)+ p2f r1 = parse' p2 (flip (select False) r1) (select False r1)+ parse' p psucc pfail =+ p lexer (successK psucc) (failK pfail) pos s+ successK k x pos' s' = k (pos', success x pos' s')+ failK k pos' msg = k (pos', failp pos' msg)+ retry k (pos',p) = closeP0 p `thenP` curry k pos'+ select suc (pos1, p1) (pos2, p2) = case pos1 `compare` pos2 of+ GT -> p1+ EQ | suc -> failP pos1 $ "Ambiguous parse before " ++ showPosition (span2Pos pos1)+ | otherwise -> p1+ LT -> p2++seqEE :: ParseFun a s (b -> c) -> ParseFun a s b -> ParseFun a s c+seqEE p1 p2 success failp = p1 (\f -> p2 (success . f) failp) failp++seqEP :: ParseFun a s (b -> c) -> (Lexer s a -> ParseFun a s b)+ -> Lexer s a -> ParseFun a s c+seqEP p1 p2 lexer success failp = p1 (\f -> p2 lexer (success . f) failp) failp++seqPP :: Symbol s => (Lexer s a -> ParseFun a s (b -> c)) -> Parser a s b+ -> Lexer s a -> ParseFun a s c+seqPP p1 p2 lexer success failp =+ p1 lexer (\f -> choose p2 lexer (success . f) failp) failp++-- ---------------------------------------------------------------------------+-- The combinators \verb|<\\>| and \verb|<\>| can be used to restrict+-- the first set of a parser. This is useful for combining two parsers+-- with an overlapping first set with the deterministic combinator <|>.+-- ---------------------------------------------------------------------------++-- |Restrict the first parser by the first 'Symbol's of the second+(<\>) :: Symbol s => Parser a s b -> Parser a s c -> Parser a s b+p <\> Parser _ ps = p <\\> Map.keys ps++-- |Restrict a parser by a list of first 'Symbol's+(<\\>) :: Symbol s => Parser a s b -> [s] -> Parser a s b+Parser e ps <\\> xs = Parser e (foldr Map.delete ps xs)++-- ---------------------------------------------------------------------------+-- Other combinators+-- Note that some of these combinators have not been published in the+-- paper, but were taken from the implementation found on the web.+-- ---------------------------------------------------------------------------++-- |Replace the result of the parser with the first argument+(<$->) :: Symbol s => a -> Parser b s c -> Parser b s a+f <$-> p = f <$ p++-- |Apply two parsers in sequence, but return only the result of the first+-- parser+(<*->) :: Symbol s => Parser a s b -> Parser a s c -> Parser a s b+p <*-> q = const <$> p <*> q++-- |Apply two parsers in sequence, but return only the result of the second+-- parser+(<-*>) :: Symbol s => Parser a s b -> Parser a s c -> Parser a s c+p <-*> q = id <$ p <*> q++-- |Apply the parsers in sequence and apply the result function of the second+-- parse to the result of the first+(<**>) :: Symbol s => Parser a s b -> Parser a s (b -> c) -> Parser a s c+p <**> q = flip ($) <$> p <*> q++-- |Same as (<**>), but only applies the function if the second parser+-- succeeded.+(<??>) :: Symbol s => Parser a s b -> Parser a s (b -> b) -> Parser a s b+p <??> q = p <**> (q `opt` id)++-- |Flipped function composition on parsers+(<.>) :: Symbol s => Parser a s (b -> c) -> Parser a s (c -> d)+ -> Parser a s (b -> d)+p1 <.> p2 = p1 <**> ((.) <$> p2)++-- |Try the first parser, but return the second argument if it didn't succeed+opt :: Symbol s => Parser a s b -> b -> Parser a s b+p `opt` x = p <|> succeed x++-- |Choose the first succeeding parser from a non-empty list of parsers+choice :: Symbol s => [Parser a s b] -> Parser a s b+choice = foldr1 (<|>)++-- |Try to apply a given parser and return a boolean value if the parser+-- succeeded.+flag :: Symbol s => Parser a s b -> Parser a s Bool+flag p = True <$-> p `opt` False++-- |Try to apply a parser but forget if it succeeded+optional :: Symbol s => Parser a s b -> Parser a s ()+optional p = void p `opt` ()++-- |Try to apply a parser and return its result in a 'Maybe' type+option :: Symbol s => Parser a s b -> Parser a s (Maybe b)+option p = Just <$> p `opt` Nothing++-- |Repeatedly apply a parser for 0 or more occurences+many :: Symbol s => Parser a s b -> Parser a s [b]+many p = many1 p `opt` []++-- |Repeatedly apply a parser for 1 or more occurences+many1 :: Symbol s => Parser a s b -> Parser a s [b]+many1 p = (:) <$> p <*> many p++-- |Parse a list with is separated by a seperator+sepBy :: Symbol s => Parser a s b -> Parser a s c -> Parser a s [b]+p `sepBy` q = p `sepBy1` q `opt` []++-- |Parse a non-empty list with is separated by a seperator+sepBy1 :: Symbol s => Parser a s b -> Parser a s c -> Parser a s [b]+p `sepBy1` q = (:) <$> p <*> many (q <-*> p)++-- |Parse a list with is separated by a seperator+sepBySp :: Symbol s => Parser a s b -> Parser a s c -> Parser a s ([b], [Span])+p `sepBySp` q = p `sepBy1Sp` q `opt` ([], [])++sepBy1Sp :: Symbol s => Parser a s b -> Parser a s c -> Parser a s ([b], [Span])+p `sepBy1Sp` q = comb <$> p <*> many ((,) <$> spanPosition <*-> q <*> p)+ where comb x xs = let (ss, ys) = unzip xs+ in (x:ys,ss)++-- |@chainr p op x@ parses zero or more occurrences of @p@, separated by @op@.+-- Returns a value produced by a *right* associative application of all+-- functions returned by op. If there are no occurrences of @p@, @x@ is+-- returned.+chainr :: Symbol s+ => Parser a s b -> Parser a s (b -> b -> b) -> b -> Parser a s b+chainr p op x = chainr1 p op `opt` x++-- |Like 'chainr', but parses one or more occurrences of p.+chainr1 :: Symbol s => Parser a s b -> Parser a s (b -> b -> b) -> Parser a s b+chainr1 p op = r where r = p <**> (flip <$> op <*> r `opt` id)++-- |@chainr p op x@ parses zero or more occurrences of @p@, separated by @op@.+-- Returns a value produced by a *left* associative application of all+-- functions returned by op. If there are no occurrences of @p@, @x@ is+-- returned.+chainl :: Symbol s+ => Parser a s b -> Parser a s (b -> b -> b) -> b -> Parser a s b+chainl p op x = chainl1 p op `opt` x++-- |Like 'chainl', but parses one or more occurrences of p.+chainl1 :: Symbol s => Parser a s b -> Parser a s (b -> b -> b) -> Parser a s b+chainl1 p op = foldF <$> p <*> many (flip <$> op <*> p)+ where foldF x [] = x+ foldF x (f:fs) = foldF (f x) fs++-- |Parse an expression between an opening and a closing part.+between :: Symbol s => Parser a s b -> Parser a s c -> Parser a s b+ -> Parser a s c+between open p close = open <-*> p <*-> close++-- |Parse one of the given operators+ops :: Symbol s => [(s, b)] -> Parser a s b+ops [] = failure "Curry.Base.LLParseComb.ops: empty list"+ops [(s, x)] = x <$-> symbol s+ops ((s, x) : rest) = x <$-> symbol s <|> ops rest++-- ---------------------------------------------------------------------------+-- Layout combinators+-- Note that the layout functions grab the next token (and its position).+-- After modifying the layout context, the continuation is called with+-- the same token and an undefined result.+-- ---------------------------------------------------------------------------++-- |Disable layout-awareness for the following+layoutOff :: Symbol s => Parser a s b+layoutOff = Parser (Just off) Map.empty+ where off success _ pos = pushContext (-1) . success undefined pos++-- |Add a new scope for layout+layoutOn :: Symbol s => Parser a s b+layoutOn = Parser (Just on) Map.empty+ where on success _ pos = pushContext (column (span2Pos pos)) . success undefined pos++-- |End the current layout scope (or re-enable layout-awareness if it is+-- currently disabled+layoutEnd :: Symbol s => Parser a s b+layoutEnd = Parser (Just end) Map.empty+ where end success _ pos = popContext . success undefined pos
+ src/Curry/Base/LexComb.hs view
@@ -0,0 +1,179 @@+{- |+ Module : $Header$+ Description : Lexer combinators+ Copyright : (c) 1999 - 2004, Wolfgang Lux+ 2012 - 2013, Björn Peemöller+ 2016 , Jan Tikovsky+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module provides the basic types and combinators to implement the+ lexers. The combinators use continuation passing code in a monadic style.++ The first argument of the continuation function is the current span,+ and the second is the string to be parsed. The third argument is a flag+ which signals the lexer that it is lexing the beginning of a line and+ therefore has to check for layout tokens. The fourth argument is a stack+ of indentations that is used to handle nested layout groups.+-}+module Curry.Base.LexComb+ ( -- * Types+ Symbol (..), Indent, Context, P, CYM, SuccessP, FailP, Lexer++ -- * Monadic functions+ , parse, applyLexer, returnP, thenP, thenP_, failP, warnP+ , liftP, closeP0, closeP1++ -- * Combinators for layout handling+ , pushContext, popContext++ -- * Conversion of numbers+ , convertSignedIntegral, convertSignedFloating+ , convertIntegral, convertFloating+ ) where++import Data.Char (digitToInt)++import Curry.Base.Monad (CYM, failMessageAt, warnMessageAt)+import Curry.Base.Span ( Distance, Span (..), startCol, fstSpan+ , setDistance)+++infixl 1 `thenP`, `thenP_`++-- |Type class for symbols+class (Ord s, Show s) => Symbol s where+ -- |Does the 'Symbol' represent the end of the input?+ isEOF :: s -> Bool+ -- |Compute the distance of a 'Symbol'+ dist :: Int -> s -> Distance++-- |Type for indentations, necessary for the layout rule+type Indent = Int++-- |Type of context for representing layout grouping+type Context = [Indent]++-- |Basic lexer function+type P a = Span -- ^ Current source code span+ -> String -- ^ 'String' to be parsed+ -> Bool -- ^ Flag whether the beginning of a line should be+ -- parsed, which requires layout checking+ -> Context -- ^ context as a stack of 'Indent's+ -> CYM a++-- |Apply a lexer on a 'String' to lex the content. The second parameter+-- requires a 'FilePath' to use in the 'Span'+parse :: P a -> FilePath -> String -> CYM a+parse p fn s = p (fstSpan fn) s True []++-- ---------------------------------------------------------------------------+-- CPS lexer+-- ---------------------------------------------------------------------------++-- |success continuation+type SuccessP s a = Span -> s -> P a++-- |failure continuation+type FailP a = Span -> String -> P a++-- |A CPS lexer+type Lexer s a = SuccessP s a -> FailP a -> P a++-- |Apply a lexer+applyLexer :: Symbol s => Lexer s [(Span, s)] -> P [(Span, s)]+applyLexer lexer = lexer successP failP+ where successP sp t | isEOF t = returnP [(sp', t)]+ | otherwise = ((sp', t) :) `liftP` lexer successP failP+ where sp' = setDistance sp (dist (startCol sp) t)++-- ---------------------------------------------------------------------------+-- Monadic functions for the lexer.+-- ---------------------------------------------------------------------------++-- |Lift a value into the lexer type+returnP :: a -> P a+returnP x _ _ _ _ = return x++-- |Apply the first lexer and then apply the second one, based on the result+-- of the first lexer.+thenP :: P a -> (a -> P b) -> P b+thenP lexer k sp s bol ctxt+ = lexer sp s bol ctxt >>= \x -> k x sp s bol ctxt++-- |Apply the first lexer and then apply the second one, ignoring the first+-- result.+thenP_ :: P a -> P b -> P b+p1 `thenP_` p2 = p1 `thenP` const p2++-- |Fail to lex on a 'Span', given an error message+failP :: Span -> String -> P a+failP sp msg _ _ _ _ = failMessageAt sp msg++-- |Warn on a 'Span', given a warning message+warnP :: Span -> String -> P a -> P a+warnP warnSpan msg lexer sp s bol ctxt+ = warnMessageAt warnSpan msg >> lexer sp s bol ctxt++-- |Apply a pure function to the lexers result+liftP :: (a -> b) -> P a -> P b+liftP f p = p `thenP` returnP . f++-- |Lift a lexer into the 'P' monad, returning the lexer when evaluated.+closeP0 :: P a -> P (P a)+closeP0 lexer sp s bol ctxt = return (\_ _ _ _ -> lexer sp s bol ctxt)++-- |Lift a lexer-generating function into the 'P' monad, returning the+-- function when evaluated.+closeP1 :: (a -> P b) -> P (a -> P b)+closeP1 f sp s bol ctxt = return (\x _ _ _ _ -> f x sp s bol ctxt)++-- ---------------------------------------------------------------------------+-- Combinators for handling layout.+-- ---------------------------------------------------------------------------++-- |Push an 'Indent' to the context, increasing the levels of indentation+pushContext :: Indent -> P a -> P a+pushContext col cont sp s bol ctxt = cont sp s bol (col : ctxt)++-- |Pop an 'Indent' from the context, decreasing the levels of indentation+popContext :: P a -> P a+popContext cont sp s bol (_ : ctxt) = cont sp s bol ctxt+popContext _ sp _ _ [] = failMessageAt sp $+ "Parse error: popping layout from empty context stack. " +++ "Perhaps you have inserted too many '}'?"++-- ---------------------------------------------------------------------------+-- Conversions from 'String's into numbers.+-- ---------------------------------------------------------------------------++-- |Convert a String into a signed intergral using a given base+convertSignedIntegral :: Num a => a -> String -> a+convertSignedIntegral b ('+':s) = convertIntegral b s+convertSignedIntegral b ('-':s) = - convertIntegral b s+convertSignedIntegral b s = convertIntegral b s++-- |Convert a String into an unsigned intergral using a given base+convertIntegral :: Num a => a -> String -> a+convertIntegral b = foldl op 0+ where m `op` n = b * m + fromIntegral (digitToInt n)++-- |Convert a mantissa, a fraction part and an exponent into a signed+-- floating value+convertSignedFloating :: Fractional a => String -> String -> Int -> a+convertSignedFloating ('+':m) f e = convertFloating m f e+convertSignedFloating ('-':m) f e = - convertFloating m f e+convertSignedFloating m f e = convertFloating m f e++-- |Convert a mantissa, a fraction part and an exponent into an unsigned+-- floating value+convertFloating :: Fractional a => String -> String -> Int -> a+convertFloating m f e+ | e' == 0 = m'+ | e' > 0 = m' * 10 ^ e'+ | otherwise = m' / 10 ^ (- e')+ where m' = convertIntegral 10 (m ++ f)+ e' = e - length f
+ src/Curry/Base/Message.hs view
@@ -0,0 +1,114 @@+{- |+ Module : $Header$+ Description : Monads for message handling+ Copyright : 2009 Holger Siegel+ 2012 - 2015 Björn Peemöller+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ The type message represents a compiler message with an optional source+ code position.+-}+{-# LANGUAGE CPP #-}+module Curry.Base.Message+ ( Message (..), message, posMessage, spanMessage, spanInfoMessage+ , showWarning, showError+ , ppMessage, ppWarning, ppError, ppMessages, ppMessagesWithPreviews+ ) where++#if __GLASGOW_HASKELL__ >= 804+import Prelude hiding ((<>))+#endif++import Curry.Base.Position+import Curry.Base.Pretty+import Curry.Base.Span+import Curry.Base.SpanInfo++-- ---------------------------------------------------------------------------+-- Message+-- ---------------------------------------------------------------------------++-- |Compiler message+data Message = Message+ { msgSpanInfo :: SpanInfo -- ^ span in the source code+ , msgTxt :: Doc -- ^ the message itself+ }++instance Eq Message where+ Message s1 t1 == Message s2 t2 = (s1, show t1) == (s2, show t2)++instance Ord Message where+ Message s1 t1 `compare` Message s2 t2 = compare (s1, show t1) (s2, show t2)++instance Show Message where+ showsPrec _ = shows . ppMessage++instance HasPosition Message where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasSpanInfo Message where+ getSpanInfo = msgSpanInfo+ setSpanInfo spi m = m { msgSpanInfo = spi }++instance Pretty Message where+ pPrint = ppMessage++-- |Construct a 'Message' without a 'SpanInfo'+message :: Doc -> Message+message = Message NoSpanInfo++-- |Construct a message from a position.+posMessage :: HasPosition p => p -> Doc -> Message+posMessage p = spanMessage $ pos2Span $ getPosition p++-- |Construct a message from a span and a text+spanMessage :: Span -> Doc -> Message+spanMessage s = spanInfoMessage $ fromSrcSpan s++-- |Construct a message from an entity with a 'SpanInfo' and a text+spanInfoMessage :: HasSpanInfo s => s -> Doc -> Message+spanInfoMessage s msg = Message (getSpanInfo s) msg++-- |Show a 'Message' as a warning+showWarning :: Message -> String+showWarning = show . ppWarning++-- |Show a 'Message' as an error+showError :: Message -> String+showError = show . ppError++-- |Pretty print a 'Message'+ppMessage :: Message -> Doc+ppMessage = ppAs ""++-- |Pretty print a 'Message' as a warning+ppWarning :: Message -> Doc+ppWarning = ppAs "Warning"++-- |Pretty print a 'Message' as an error+ppError :: Message -> Doc+ppError = ppAs "Error"++-- |Pretty print a 'Message' with a given key+ppAs :: String -> Message -> Doc+ppAs key (Message mbSpanInfo txt) = (hsep $ filter (not . isEmpty) [spanPP, keyPP]) $$ nest 4 txt+ where+ spanPP = ppCompactSpan $ getSrcSpan $ mbSpanInfo+ keyPP = if null key then empty else text key <> colon++-- |Pretty print a list of 'Message's by vertical concatenation+ppMessages :: (Message -> Doc) -> [Message] -> Doc+ppMessages ppFun = foldr (\m ms -> text "" $+$ m $+$ ms) empty . map ppFun++-- |Pretty print a list of 'Message's with previews by vertical concatenation+ppMessagesWithPreviews :: (Message -> Doc) -> [Message] -> IO Doc+ppMessagesWithPreviews ppFun = (fmap $ foldr (\m ms -> text "" $+$ m $+$ ms) empty) . mapM ppFunWithPreview+ where ppFunWithPreview m = do preview <- case m of+ Message (SpanInfo sp _) _ -> ppSpanPreview sp+ _ -> return empty+ return $ ppFun m $+$ preview
+ src/Curry/Base/Monad.hs view
@@ -0,0 +1,95 @@+{- |+ Module : $Header$+ Description : Monads for message handling+ Copyright : 2014 - 2016 Björn Peemöller+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental++ The monads defined in this module provide a common way to stop execution+ when some errors occur. They are used to integrate different compiler passes+ smoothly.+-}++module Curry.Base.Monad+ ( CYIO, CYM, CYT, failMessages, failMessageAt, warnMessages, warnMessageAt+ , ok, runCYIO, runCYM, runCYIOIgnWarn, runCYMIgnWarn, liftCYM, silent+ ) where++import Control.Monad.Identity+import Control.Monad.Trans.Except (ExceptT, mapExceptT, runExceptT, throwE)+import Control.Monad.Writer++import Curry.Base.Message (Message, spanMessage)+import Curry.Base.Span (Span)+import Curry.Base.Pretty (text)++-- |Curry compiler monad transformer+type CYT m a = WriterT [Message] (ExceptT [Message] m) a++-- |Curry compiler monad based on the `IO` monad+type CYIO a = CYT IO a++-- |Pure Curry compiler monad+type CYM a = CYT Identity a++-- |Run an `IO`-based Curry compiler action in the `IO` monad,+-- yielding either a list of errors or a result in case of success+-- consisting of the actual result and a (possibly empty) list of warnings+runCYIO :: CYIO a -> IO (Either [Message] (a, [Message]))+runCYIO = runExceptT . runWriterT++-- |Run an pure Curry compiler action,+-- yielding either a list of errors or a result in case of success+-- consisting of the actual result and a (possibly empty) list of warnings+runCYM :: CYM a -> Either [Message] (a, [Message])+runCYM = runIdentity . runExceptT . runWriterT++-- |Run an `IO`-based Curry compiler action in the `IO` monad,+-- yielding either a list of errors or a result in case of success.+runCYIOIgnWarn :: CYIO a -> IO (Either [Message] a)+runCYIOIgnWarn = runExceptT . (liftM fst) . runWriterT++-- |Run an pure Curry compiler action,+-- yielding either a list of errors or a result in case of success.+runCYMIgnWarn :: CYM a -> Either [Message] a+runCYMIgnWarn = runIdentity . runExceptT . (liftM fst) . runWriterT++-- |Failing action with a message describing the cause of failure.+failMessage :: Monad m => Message -> CYT m a+failMessage msg = failMessages [msg]++-- |Failing action with a list of messages describing the cause(s) of failure.+failMessages :: Monad m => [Message] -> CYT m a+failMessages = lift . throwE++-- |Failing action with a source code span and a `String` indicating+-- the cause of failure.+failMessageAt :: Monad m => Span -> String -> CYT m a+failMessageAt sp s = failMessage $ spanMessage sp $ text s++-- |Warning with a message describing the cause of the warning.+warnMessage :: Monad m => Message -> CYT m ()+warnMessage msg = warnMessages [msg]++-- |Warning with a list of messages describing the cause(s) of the warnings.+warnMessages :: Monad m => [Message] -> CYT m ()+warnMessages msgs = tell msgs++-- |Execute a monadic action, but ignore any warnings it issues+silent :: Monad m => CYT m a -> CYT m a+silent act = censor (const []) act++-- |Warning with a source code position and a `String` indicating+-- the cause of the warning.+warnMessageAt :: Monad m => Span -> String -> CYT m ()+warnMessageAt sp s = warnMessage $ spanMessage sp $ text s++-- |Lift a value into the `CYT m` monad, same as `return`.+ok :: Monad m => a -> CYT m a+ok = return++-- |Lift a pure action into an action based on another monad.+liftCYM :: Monad m => CYM a -> CYT m a+liftCYM = mapWriterT (mapExceptT (return . runIdentity))
+ src/Curry/Base/Position.hs view
@@ -0,0 +1,128 @@+{- |+ Module : $Header$+ Description : Positions in a source file+ Copyright : (c) Wolfgang Lux+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module implements a data type for positions in a source file and+ respective functions to operate on them. A source file position consists+ of a filename, a line number, and a column number. A tab stop is assumed+ at every eighth column.+-}+module Curry.Base.Position+ ( -- * Source code position+ HasPosition (..), Position (..), (@>)+ , showPosition, ppPosition, ppCompactLine, ppLine, showLine+ , first, next, incr, tab, tabWidth, nl+ ) where++import Prelude hiding ((<>))+import Data.Binary+import Control.Monad+import System.FilePath++import Curry.Base.Pretty++-- |Type class for entities which have a source code 'Position'+class HasPosition a where+ -- |Get the 'Position'+ getPosition :: a -> Position+ getPosition _ = NoPos++ -- |Set the 'Position'+ setPosition :: Position -> a -> a+ setPosition _ = id++-- | @x \@> y@ returns @x@ with the position obtained from @y@+(@>) :: (HasPosition a, HasPosition b) => a -> b -> a+x @> y = setPosition (getPosition y) x++-- |Source code positions+data Position+ -- |Normal source code position+ = Position+ { file :: FilePath -- ^ 'FilePath' of the source file+ , line :: Int -- ^ line number, beginning at 1+ , column :: Int -- ^ column number, beginning at 1+ }+ -- |no position+ | NoPos+ deriving (Eq, Ord, Read, Show)++instance HasPosition Position where+ getPosition = id+ setPosition = const++instance Pretty Position where+ pPrint = ppPosition++instance Binary Position where+ put (Position _ l c) = putWord8 0 >> put l >> put c+ put NoPos = putWord8 1++ get = do+ x <- getWord8+ case x of+ 0 -> liftM2 (Position "") get get+ 1 -> return NoPos+ _ -> fail "Not a valid encoding for a Position"++-- |Show a 'Position' as a 'String'+showPosition :: Position -> String+showPosition = show . ppPosition++-- |Pretty print a 'Position'+ppPosition :: Position -> Doc+ppPosition p@(Position f _ _)+ | null f = lineCol+ | otherwise = text (normalise f) <> comma <+> lineCol+ where lineCol = ppLine p+ppPosition _ = empty++-- |Pretty print a compact representation of a 'Position''s line/column+ppCompactLine :: Position -> Doc+ppCompactLine (Position _ l c) = text (show l)+ <> if c == 0 then empty else (colon <> text (show c))+ppCompactLine _ = empty++-- |Pretty print the line and column of a 'Position'+ppLine :: Position -> Doc+ppLine (Position _ l c) = text "line" <+> text (show l)+ <> if c == 0 then empty else text ('.' : show c)+ppLine _ = empty++-- |Show the line and column of a 'Position'+showLine :: Position -> String+showLine = show . ppLine++-- | Absolute first position of a file+first :: FilePath -> Position+first fn = Position fn 1 1++-- |Next position to the right+next :: Position -> Position+next = flip incr 1++-- |Increment a position by a number of columns+incr :: Position -> Int -> Position+incr p@Position { column = c } n = p { column = c + n }+incr p _ = p++-- |Number of spaces for a tabulator+tabWidth :: Int+tabWidth = 8++-- |First position after the next tabulator+tab :: Position -> Position+tab p@Position { column = c }+ = p { column = c + tabWidth - (c - 1) `mod` tabWidth }+tab p = p++-- |First position of the next line+nl :: Position -> Position+nl p@Position { line = l } = p { line = l + 1, column = 1 }+nl p = p
+ src/Curry/Base/Pretty.hs view
@@ -0,0 +1,209 @@+{- |+ Module : $Header$+ Description : Pretty printing+ Copyright : (c) 2013 - 2014 Björn Peemöller+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : stable+ Portability : portable++ This module re-exports the well known pretty printing combinators+ from Hughes and Peyton-Jones. In addition, it re-exports the type class+ 'Pretty' for pretty printing arbitrary types.+-}+{-# LANGUAGE CPP #-}+module Curry.Base.Pretty+ ( module Curry.Base.Pretty+ , module Text.PrettyPrint+ ) where++import Prelude hiding ((<>))++import Text.PrettyPrint++-- | Pretty printing class.+-- The precedence level is used in a similar way as in the 'Show' class.+-- Minimal complete definition is either 'pPrintPrec' or 'pPrint'.+class Pretty a where+ -- | Pretty-print something in isolation.+ pPrint :: a -> Doc+ pPrint = pPrintPrec 0++ -- | Pretty-print something in a precedence context.+ pPrintPrec :: Int -> a -> Doc+ pPrintPrec _ = pPrint++ -- |Pretty-print a list.+ pPrintList :: [a] -> Doc+ pPrintList = brackets . fsep . punctuate comma . map (pPrintPrec 0)++#if __GLASGOW_HASKELL__ >= 707+ {-# MINIMAL pPrintPrec | pPrint #-}+#endif++-- | Pretty print a value to a 'String'.+prettyShow :: Pretty a => a -> String+prettyShow = render . pPrint++-- | Parenthesize an value if the boolean is true.+parenIf :: Bool -> Doc -> Doc+parenIf False = id+parenIf True = parens++-- | Pretty print a value if the boolean is true+ppIf :: Bool -> Doc -> Doc+ppIf True = id+ppIf False = const empty++-- | Pretty print a 'Maybe' value for the 'Just' constructor only+maybePP :: (a -> Doc) -> Maybe a -> Doc+maybePP = maybe empty++-- | A blank line.+blankLine :: Doc+blankLine = text ""++-- |Above with a blank line in between. If one of the documents is empty,+-- then the other document is returned.+($++$) :: Doc -> Doc -> Doc+d1 $++$ d2 | isEmpty d1 = d2+ | isEmpty d2 = d1+ | otherwise = d1 $+$ blankLine $+$ d2++-- |Above with overlapping, but with a space in between. If one of the+-- documents is empty, then the other document is returned.+($-$) :: Doc -> Doc -> Doc+d1 $-$ d2 | isEmpty d1 = d2+ | isEmpty d2 = d1+ | otherwise = d1 $$ space $$ d2++-- | Seperate a list of 'Doc's by a 'blankLine'.+sepByBlankLine :: [Doc] -> Doc+sepByBlankLine = foldr ($++$) empty++-- |A '.' character.+dot :: Doc+dot = char '.'++-- |Precedence of function application+appPrec :: Int+appPrec = 10++-- |A left arrow @<-@.+larrow :: Doc+larrow = text "<-"++-- |A right arrow @->@.+rarrow :: Doc+rarrow = text "->"++-- |A double arrow @=>@.+darrow :: Doc+darrow = text "=>"++-- |A back quote @`@.+backQuote :: Doc+backQuote = char '`'++-- |A backslash @\@.+backsl :: Doc+backsl = char '\\'++-- |A vertical bar @|@.+vbar :: Doc+vbar = char '|'++-- |Set a document in backquotes.+bquotes :: Doc -> Doc+bquotes doc = backQuote <> doc <> backQuote++-- |Set a document in backquotes if the condition is @True@.+bquotesIf :: Bool -> Doc -> Doc+bquotesIf b doc = if b then bquotes doc else doc++-- |Seperate a list of documents by commas+list :: [Doc] -> Doc+list = fsep . punctuate comma . filter (not . isEmpty)++-- | Instance for 'Int'+instance Pretty Int where pPrint = int++-- | Instance for 'Integer'+instance Pretty Integer where pPrint = integer++-- | Instance for 'Float'+instance Pretty Float where pPrint = float++-- | Instance for 'Double'+instance Pretty Double where pPrint = double++-- | Instance for '()'+instance Pretty () where pPrint _ = text "()"++-- | Instance for 'Bool'+instance Pretty Bool where pPrint = text . show++-- | Instance for 'Ordering'+instance Pretty Ordering where pPrint = text . show++-- | Instance for 'Char'+instance Pretty Char where+ pPrint = char+ pPrintList = text . show++-- | Instance for 'Maybe'+instance (Pretty a) => Pretty (Maybe a) where+ pPrintPrec _ Nothing = text "Nothing"+ pPrintPrec p (Just x) = parenIf (p > appPrec)+ $ text "Just" <+> pPrintPrec (appPrec + 1) x++-- | Instance for 'Either'+instance (Pretty a, Pretty b) => Pretty (Either a b) where+ pPrintPrec p (Left x) = parenIf (p > appPrec)+ $ text "Left" <+> pPrintPrec (appPrec + 1) x+ pPrintPrec p (Right x) = parenIf (p > appPrec)+ $ text "Right" <+> pPrintPrec (appPrec + 1) x++-- | Instance for '[]'+instance (Pretty a) => Pretty [a] where+ pPrintPrec _ = pPrintList++-- | Instance for '(,)'+instance (Pretty a, Pretty b) => Pretty (a, b) where+ pPrintPrec _ (a, b) = parens $ fsep $ punctuate comma [pPrint a, pPrint b]++-- | Instance for '(,,)'+instance (Pretty a, Pretty b, Pretty c) => Pretty (a, b, c) where+ pPrintPrec _ (a, b, c) = parens $ fsep $ punctuate comma+ [pPrint a, pPrint b, pPrint c]++-- | Instance for '(,,,)'+instance (Pretty a, Pretty b, Pretty c, Pretty d) => Pretty (a, b, c, d) where+ pPrintPrec _ (a, b, c, d) = parens $ fsep $ punctuate comma+ [pPrint a, pPrint b, pPrint c, pPrint d]++-- | Instance for '(,,,,)'+instance (Pretty a, Pretty b, Pretty c, Pretty d, Pretty e)+ => Pretty (a, b, c, d, e) where+ pPrintPrec _ (a, b, c, d, e) = parens $ fsep $ punctuate comma+ [pPrint a, pPrint b, pPrint c, pPrint d, pPrint e]++-- | Instance for '(,,,,,)'+instance (Pretty a, Pretty b, Pretty c, Pretty d, Pretty e, Pretty f)+ => Pretty (a, b, c, d, e, f) where+ pPrintPrec _ (a, b, c, d, e, f) = parens $ fsep $ punctuate comma+ [pPrint a, pPrint b, pPrint c, pPrint d, pPrint e, pPrint f]++-- | Instance for '(,,,,,,)'+instance (Pretty a, Pretty b, Pretty c, Pretty d, Pretty e, Pretty f, Pretty g)+ => Pretty (a, b, c, d, e, f, g) where+ pPrintPrec _ (a, b, c, d, e, f, g) = parens $ fsep $ punctuate comma+ [pPrint a, pPrint b, pPrint c, pPrint d, pPrint e, pPrint f, pPrint g]++-- | Instance for '(,,,,,,,)'+instance (Pretty a, Pretty b, Pretty c, Pretty d, Pretty e, Pretty f, Pretty g, Pretty h)+ => Pretty (a, b, c, d, e, f, g, h) where+ pPrintPrec _ (a, b, c, d, e, f, g, h) = parens $ fsep $ punctuate comma+ [pPrint a, pPrint b, pPrint c, pPrint d, pPrint e, pPrint f, pPrint g, pPrint h]
+ src/Curry/Base/Span.hs view
@@ -0,0 +1,180 @@+{- |+ Module : $Header$+ Description : Spans in a source file+ Copyright : (c) 2016 Jan Tikovsky+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : jrt@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module implements a data type for span information in a source file and+ respective functions to operate on them. A source file span consists+ of a filename, a start position and an end position.++ In addition, the type 'SrcRef' identifies the path to an expression in+ the abstract syntax tree by argument positions, which is used for+ debugging purposes.+-}+module Curry.Base.Span where++import Prelude hiding ((<>))++import Data.Binary+import Data.List (transpose)+import Control.Monad+import System.FilePath++import Curry.Base.Position hiding (file)+import Curry.Base.Pretty++data Span+ -- |Normal source code span+ = Span+ { file :: FilePath -- ^ 'FilePath' of the source file+ , start :: Position -- ^ start position+ , end :: Position -- ^ end position+ }+ -- |no span+ | NoSpan+ deriving (Eq, Ord, Read, Show)++instance Pretty Span where+ pPrint = ppSpan++instance HasPosition Span where+ setPosition p NoSpan = Span "" p NoPos+ setPosition p (Span f _ e) = Span f p e++ getPosition NoSpan = NoPos+ getPosition (Span _ p _) = p++instance Binary Span where+ put (Span _ s e) = putWord8 0 >> put s >> put e+ put NoSpan = putWord8 1++ get = do+ x <- getWord8+ case x of+ 0 -> liftM2 (Span "") get get+ 1 -> return NoSpan+ _ -> fail "Not a valid encoding for a Span"++-- |Show a 'Span' as a 'String'+showSpan :: Span -> String+showSpan = show . ppSpan++-- |Pretty print a 'Span'+ppSpan :: Span -> Doc+ppSpan s@(Span f _ _)+ | null f = startEnd+ | otherwise = text (normalise f) <> comma <+> startEnd+ where startEnd = ppPositions s+ppSpan _ = empty++-- |Pretty print a span with it's file path and position compactly.+ppCompactSpan :: Span -> Doc+ppCompactSpan s@(Span f _ _)+ | null f = ppCompactPositions s+ | otherwise = text (normalise f) <> colon <> ppCompactPositions s+ppCompactSpan _ = empty++-- |Pretty print a source preview of a span+ppSpanPreview :: Span -> IO Doc+ppSpanPreview (Span f (Position _ sl sc) (Position _ el ec))+ | null f = return empty+ | otherwise = do+ fileContents <- readFile f++ let lns = lines fileContents+ lnContent | sl <= 0 || sl > length lns = ""+ | otherwise = lns !! (sl - 1)+ lnNum = text <$> lPadStr lnNumWidth <$> (vPad ++ [show sl] ++ vPad)+ ec' = if isMultiline then length lnContent else ec+ gutter = text <$> replicate (1 + 2 * vPadCount) "|"+ highlight = replicate (sc - 1) ' ' ++ replicate (1 + ec' - sc) '^' ++ if isMultiline then "..." else ""+ previews = text <$> (vPad ++ [lnContent, highlight] ++ replicate (vPadCount - 1) "")+ + return $ vcat $ map hsep $ transpose [lnNum, gutter, previews]+ where vPadCount = 1 -- Number of padding lines at the top and bottom+ isMultiline = el - sl > 0+ numWidth = length . show+ lnNumWidth = 1 + numWidth el+ vPad = replicate vPadCount ""+ lPadStr n s = replicate (n - length s) ' ' ++ s+ppSpanPreview _ = return empty++-- |Pretty print the positions compactly.+ppCompactPositions :: Span -> Doc+ppCompactPositions (Span _ s e) | s == e = ppCompactLine s+ | otherwise = ppCompactLine s <> text "-" <> ppCompactLine e+ppCompactPositions _ = empty++-- |Pretty print the start and end position of a 'Span'+ppPositions :: Span -> Doc+ppPositions (Span _ s e) = text "startPos:" <+> ppLine s <> comma+ <+> text "endPos:" <+> ppLine e+ppPositions _ = empty++fstSpan :: FilePath -> Span+fstSpan fn = Span fn (first fn) (first fn)++-- |Compute the column of the start position of a 'Span'+startCol :: Span -> Int+startCol (Span _ p _) = column p+startCol _ = 0++nextSpan :: Span -> Span+nextSpan sp = incrSpan sp 1++incrSpan :: Span -> Int -> Span+incrSpan (Span fn s e) n = Span fn (incr s n) (incr e n)+incrSpan sp _ = sp++-- TODO: Rename to tab and nl as soon as positions are completely replaced by spans++-- |Convert a position to a single character span.+pos2Span :: Position -> Span+pos2Span p@(Position f _ _) = Span f p p+pos2Span _ = NoSpan++-- |Convert a span to a (start) position+-- TODO: This function should be removed as soon as positions are completely replaced by spans+-- in the frontend+span2Pos :: Span -> Position+span2Pos (Span _ p _) = p+span2Pos NoSpan = NoPos++combineSpans :: Span -> Span -> Span+combineSpans sp1 sp2 = Span f s e+ where s = start sp1+ e = end sp2+ f = file sp1++-- |First position after the next tabulator+tabSpan :: Span -> Span+tabSpan (Span fn s e) = Span fn (tab s) (tab e)+tabSpan sp = sp++-- |First position of the next line+nlSpan :: Span -> Span+nlSpan (Span fn s e) = Span fn (nl s) (nl e)+nlSpan sp = sp++addSpan :: Span -> (a, [Span]) -> (a, [Span])+addSpan sp (a, ss) = (a, sp:ss)++-- |Distance of a span, i.e. the line and column distance between start+-- and end position+type Distance = (Int, Int)++-- |Set the distance of a span, i.e. update its end position+setDistance :: Span -> Distance -> Span+setDistance (Span fn p _) d = Span fn p (p `moveBy` d)+setDistance s _ = s++-- |Move position by given distance+moveBy :: Position -> Distance -> Position+moveBy (Position fn l c) (ld, cd) = Position fn (l + ld) (c + cd)+moveBy p _ = p
+ src/Curry/Base/SpanInfo.hs view
@@ -0,0 +1,139 @@+{- |+ Module : $Header$+ Description : SpansInfo for entities+ Copyright : (c) 2017 Kai-Oliver Prott+ License : BSD-3-clause++ Maintainer : fte@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module implements a data type for span information for entities from a+ source file and function to operate on them. A span info consists of the+ span of the entity and a list of sub-spans whith additional information+ about location of keywords, e.g.+-}+module Curry.Base.SpanInfo+ ( SpanInfo(..), spanInfo, LayoutInfo(..), HasSpanInfo(..)+ , fromSrcSpan, fromSrcSpanBoth, getSrcSpan, setSrcSpan, spanInfoLike+ , fromSrcInfoPoints, getSrcInfoPoints, setSrcInfoPoints+ , getStartPosition, getSrcSpanEnd, setStartPosition, setEndPosition+ , spanInfo2Pos+ ) where++import Data.Binary+import Control.Monad++import Curry.Base.Position+import Curry.Base.Span++data SpanInfo = SpanInfo+ { srcSpan :: Span+ , srcInfoPoints :: [Span]+ }+ | NoSpanInfo+ deriving (Eq, Ord, Read, Show)++spanInfo :: Span -> [Span] -> SpanInfo+spanInfo sp sps = SpanInfo sp sps++data LayoutInfo = ExplicitLayout [Span]+ | WhitespaceLayout+ deriving (Eq, Read, Show)++class HasPosition a => HasSpanInfo a where++ getSpanInfo :: a -> SpanInfo++ setSpanInfo :: SpanInfo -> a -> a++ updateEndPos :: a -> a+ updateEndPos = id++ getLayoutInfo :: a -> LayoutInfo+ getLayoutInfo = const WhitespaceLayout++instance HasSpanInfo SpanInfo where+ getSpanInfo = id+ setSpanInfo = const++instance HasPosition SpanInfo where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance Binary SpanInfo where+ put (SpanInfo sp ss) = putWord8 0 >> put sp >> put ss+ put NoSpanInfo = putWord8 1++ get = do+ x <- getWord8+ case x of+ 0 -> liftM2 SpanInfo get get+ 1 -> return NoSpanInfo+ _ -> fail "Not a valid encoding for a SpanInfo"++instance Binary LayoutInfo where+ put (ExplicitLayout ss) = putWord8 0 >> put ss+ put WhitespaceLayout = putWord8 1++ get = do+ x <- getWord8+ case x of+ 0 -> fmap ExplicitLayout get+ 1 -> return WhitespaceLayout+ _ -> fail "Not a valid encoding for a LayoutInfo"++fromSrcSpan :: Span -> SpanInfo+fromSrcSpan sp = SpanInfo sp []++fromSrcSpanBoth :: Span -> SpanInfo+fromSrcSpanBoth sp = SpanInfo sp [sp]++getSrcSpan :: HasSpanInfo a => a -> Span+getSrcSpan a = case getSpanInfo a of+ NoSpanInfo -> NoSpan+ SpanInfo s _ -> s++setSrcSpan :: HasSpanInfo a => Span -> a -> a+setSrcSpan s a = case getSpanInfo a of+ NoSpanInfo -> setSpanInfo (SpanInfo s [] ) a+ SpanInfo _ inf -> setSpanInfo (SpanInfo s inf) a++fromSrcInfoPoints :: [Span] -> SpanInfo+fromSrcInfoPoints = SpanInfo NoSpan++getSrcInfoPoints :: HasSpanInfo a => a -> [Span]+getSrcInfoPoints a = case getSpanInfo a of+ NoSpanInfo -> []+ SpanInfo _ xs -> xs++setSrcInfoPoints :: HasSpanInfo a => [Span] -> a -> a+setSrcInfoPoints inf a = case getSpanInfo a of+ NoSpanInfo -> setSpanInfo (SpanInfo NoSpan inf) a+ SpanInfo s _ -> setSpanInfo (SpanInfo s inf) a++getStartPosition :: HasSpanInfo a => a -> Position+getStartPosition a = case getSrcSpan a of+ NoSpan -> NoPos+ Span _ s _ -> s++getSrcSpanEnd :: HasSpanInfo a => a -> Position+getSrcSpanEnd a = case getSpanInfo a of+ NoSpanInfo -> NoPos+ SpanInfo s _ -> end s++setStartPosition :: HasSpanInfo a => Position -> a -> a+setStartPosition p a = case getSrcSpan a of+ NoSpan -> setSrcSpan (Span "" p NoPos) a+ Span f _ e -> setSrcSpan (Span f p e) a++setEndPosition :: HasSpanInfo a => Position -> a -> a+setEndPosition e a = case getSrcSpan a of+ NoSpan -> setSrcSpan (Span "" NoPos e) a+ Span f p _ -> setSrcSpan (Span f p e) a++spanInfo2Pos :: HasSpanInfo a => a -> Position+spanInfo2Pos = getStartPosition++spanInfoLike :: (HasSpanInfo a, HasSpanInfo b) => a -> b -> a+spanInfoLike a b = setSpanInfo (getSpanInfo b) a
+ src/Curry/CondCompile/Parser.hs view
@@ -0,0 +1,90 @@+{- |+ Module : $Header$+ Description : Parser for conditional compiling+ Copyright : (c) 2017 Kai-Oliver Prott+ 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : fte@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ TODO+-}+{-# LANGUAGE CPP #-}+module Curry.CondCompile.Parser where++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative ((<$>), (<*>), (*>), (<*))+#endif++import Text.Parsec++import Curry.CondCompile.Type++type Parser a = Parsec String () a++program :: Parser Program+program = statement `sepBy` eol <* eof++statement :: Parser Stmt+statement = ifElse "if" condition If+ <|> ifElse "ifdef" identifier IfDef+ <|> ifElse "ifndef" identifier IfNDef+ <|> define+ <|> undef+ <|> line++ifElse :: String -> Parser a -> (a -> [Stmt] -> [Elif] -> Else -> Stmt)+ -> Parser Stmt+ifElse k p c = c <$> (try (many sp *> keyword k *> many1 sp) *> p <* many sp <* eol)+ <*> many (statement <* eol)+ <*> many (Elif <$> ((,) <$> (try (many sp *> keyword "elif" *> many1 sp) *> condition <* many sp <* eol)+ <*> many (statement <* eol)))+ <*> (Else <$> optionMaybe+ (try (many sp *> keyword "else" *> many sp) *> eol *> many (statement <* eol)))+ <* try (many sp <* keyword "endif" <* many sp)++define :: Parser Stmt+define = Define <$> (try (many sp *> keyword "define" *> many1 sp) *> identifier <* many1 sp)+ <*> value <* many sp++undef :: Parser Stmt+undef = Undef <$> (try (many sp *> keyword "undef" *> many1 sp) *> identifier <* many sp)++line :: Parser Stmt+line = do+ sps <- many sp+ try $ ((char '#' <?> "") *> fail "unknown directive")+ <|> ((Line . (sps ++)) <$> manyTill anyChar (try (lookAhead (eol <|> eof))))++keyword :: String -> Parser String+keyword = string . ('#' :)++condition :: Parser Cond+condition = (Defined <$> (try (string "defined(") *> many sp *> identifier <* many sp <* char ')'))+ <|> (NDefined <$> (try (string "!defined(") *> many sp *> identifier <* many sp <* char ')'))+ <|> (Comp <$> (identifier <* many sp) <*> operator <*> (many sp *> value) <?> "condition")++identifier :: Parser String+identifier = (:) <$> firstChar <*> many (firstChar <|> digit) <?> "identifier"+ where firstChar = letter <|> char '_'++operator :: Parser Op+operator = choice [ Leq <$ try (string "<=")+ , Lt <$ try (string "<")+ , Geq <$ try (string ">=")+ , Gt <$ try (string ">")+ , Neq <$ try (string "!=")+ , Eq <$ string "=="+ ] <?> "operator"++value :: Parser Int+value = fmap read (many1 digit)++eol :: Parser ()+eol = endOfLine *> return ()++sp :: Parser Char+sp = try $ lookAhead (eol *> unexpected "end of line" <?> "")+ <|> space
+ src/Curry/CondCompile/Transform.hs view
@@ -0,0 +1,116 @@+{- |+ Module : $Header$+ Description : Conditional compiling transformation+ Copyright : (c) 2017 Kai-Oliver Prott+ 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : fte@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ TODO+-}+module Curry.CondCompile.Transform (condTransform) where++import Control.Monad.State+import Control.Monad.Extra (concatMapM)+import qualified Data.Map as Map+import Data.Maybe (fromMaybe)+import Text.Parsec hiding (State)+import Text.Parsec.Error ()++import Curry.Base.Message+import Curry.Base.Position+import Curry.Base.Pretty++import Curry.CondCompile.Parser+import Curry.CondCompile.Type++type CCState = Map.Map String Int++type CCM = State CCState++condTransform :: CCState -> FilePath -> String -> Either Message String+condTransform s fn p = either (Left . convertError)+ (Right . transformWith s)+ (parse program fn p)++transformWith :: CCState -> Program -> String+transformWith s p = show $ pPrint $ evalState (transform p) s++convertError :: ParseError -> Message+convertError err = posMessage pos $+ foldr ($+$) empty $ map text $ tail $ lines $ show err+ where pos = Position (sourceName src) (sourceLine src) (sourceColumn src)+ src = errorPos err++class CCTransform a where+ transform :: a -> CCM [Stmt]++instance CCTransform Stmt where+ transform (Line s) = return [Line s]+ transform (If c stmts is e) = do+ s <- get+ if checkCond c s+ then do stmts' <- transform stmts+ return (blank : stmts' ++ fill is ++ fill e ++ [blank])+ else case is of+ [] -> do+ stmts' <- transform e+ return (blank : fill stmts ++ stmts' ++ [blank])+ (Elif (c', stmts') : is') -> do+ stmts'' <- transform (If c' stmts' is' e)+ return (blank : fill stmts ++ stmts'')+ transform (IfDef v stmts is e) = transform (If (Defined v) stmts is e)+ transform (IfNDef v stmts is e) = transform (If (NDefined v) stmts is e)+ transform (Define v i) = modify (Map.insert v i) >> return [blank]+ transform (Undef v ) = modify (Map.delete v) >> return [blank]++instance CCTransform a => CCTransform [a] where+ transform = concatMapM transform++instance CCTransform Else where+ transform (Else (Just p)) = (blank :) <$> transform p+ transform (Else Nothing ) = return []++checkCond :: Cond -> CCState -> Bool+checkCond (Comp v op i) = flip (compareOp op) i . fromMaybe 0 . Map.lookup v+checkCond (Defined v) = Map.member v+checkCond (NDefined v) = Map.notMember v++compareOp :: Ord a => Op -> a -> a -> Bool+compareOp Eq = (==)+compareOp Neq = (/=)+compareOp Lt = (<)+compareOp Leq = (<=)+compareOp Gt = (>)+compareOp Geq = (>=)++class FillLength a where+ fillLength :: a -> Int++instance FillLength Stmt where+ fillLength (Line _ ) = 1+ fillLength (Define _ _ ) = 1+ fillLength (Undef _ ) = 1+ fillLength (If _ stmts is e) =+ 3 + fillLength stmts + fillLength e + fillLength is+ fillLength (IfDef v stmts is e) = fillLength (If (Defined v) stmts is e)+ fillLength (IfNDef v stmts is e) = fillLength (If (NDefined v) stmts is e)++instance FillLength a => FillLength [a] where+ fillLength = foldr ((+) . fillLength) 0++instance FillLength Else where+ fillLength (Else (Just stmts)) = 1 + fillLength stmts+ fillLength (Else Nothing ) = 0++instance FillLength Elif where+ fillLength (Elif (_, stmts)) = 1 + fillLength stmts++fill :: FillLength a => a -> [Stmt]+fill p = replicate (fillLength p) blank++blank :: Stmt+blank = Line ""
+ src/Curry/CondCompile/Type.hs view
@@ -0,0 +1,88 @@+{- |+ Module : $Header$+ Description : Abstract syntax for conditional compiling+ Copyright : (c) 2017 Kai-Oliver Prott+ 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : fte@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ TODO+-}+{-# LANGUAGE CPP #-}+module Curry.CondCompile.Type+ ( Program, Stmt (..), Else (..), Elif (..), Cond (..), Op (..)+ ) where++#if __GLASGOW_HASKELL__ >= 804+import Prelude hiding ((<>))+#endif++import Curry.Base.Pretty++type Program = [Stmt]++data Stmt = If Cond [Stmt] [Elif] Else+ | IfDef String [Stmt] [Elif] Else+ | IfNDef String [Stmt] [Elif] Else+ | Define String Int+ | Undef String+ | Line String+ deriving Show++newtype Else = Else (Maybe [Stmt])+ deriving Show++newtype Elif = Elif (Cond, [Stmt])+ deriving Show++data Cond = Comp String Op Int+ | Defined String+ | NDefined String+ deriving Show++data Op = Eq+ | Neq+ | Lt+ | Leq+ | Gt+ | Geq+ deriving Show++instance Pretty Stmt where+ pPrint (If c stmts is e) = prettyIf "#if" (pPrint c) stmts is e+ pPrint (IfDef v stmts is e) = prettyIf "#ifdef" (text v) stmts is e+ pPrint (IfNDef v stmts is e) = prettyIf "#ifndef" (text v) stmts is e+ pPrint (Define v i ) = text "#define" <+> text v <+> int i+ pPrint (Undef v ) = text "#undef" <+> text v+ pPrint (Line s ) = text s++ pPrintList = foldr (($+$) . pPrint) empty++instance Pretty Elif where+ pPrint (Elif (c, stmts)) = text "#elif" <+> pPrint c $+$ pPrint stmts++ pPrintList = foldr (($+$) . pPrint) empty++instance Pretty Else where+ pPrint (Else (Just stmts)) = text "#else" $+$ pPrint stmts+ pPrint (Else Nothing) = empty++prettyIf :: String -> Doc -> [Stmt] -> [Elif] -> Else -> Doc+prettyIf k doc stmts is e = foldr ($+$) empty+ [text k <+> doc, pPrint stmts, pPrint is, pPrint e, text "#endif"]++instance Pretty Cond where+ pPrint (Comp v op i) = text v <+> pPrint op <+> int i+ pPrint (Defined v ) = text "defined(" <> text v <> char ')'+ pPrint (NDefined v ) = text "!defined(" <> text v <> char ')'++instance Pretty Op where+ pPrint Eq = text "=="+ pPrint Neq = text "/="+ pPrint Lt = text "<"+ pPrint Leq = text "<="+ pPrint Gt = text ">"+ pPrint Geq = text ">="
− src/Curry/Files/CymakePath.hs
@@ -1,15 +0,0 @@-module Curry.Files.CymakePath (getCymake,cymakeVersion) where--import Data.Version-import System.FilePath-import Paths_curry_frontend---- | Retrieve the version number of cymake-cymakeVersion :: String-cymakeVersion = showVersion version---- | Retrieve the location of the cymake executable-getCymake :: IO String-getCymake = do- cymakeDir <- getBinDir- return (cymakeDir </> "cymake")
+ src/Curry/Files/Filenames.hs view
@@ -0,0 +1,256 @@+{- |+ Module : $Header$+ Description : File names for several intermediate file formats.+ Copyright : (c) 2009 Holger Siegel+ 2013 - 2014 Björn Peemöller+ 2018 Kai-Oliver Prott+ License : BSD-3-clause++ Maintainer : fte@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ The functions in this module were collected from several compiler modules+ in order to provide a unique accessing point for this functionality.+-}+module Curry.Files.Filenames+ ( -- * Re-exports from 'System.FilePath'+ FilePath, takeBaseName, dropExtension, takeExtension, takeFileName++ -- * Conversion between 'ModuleIdent' and 'FilePath'+ , moduleNameToFile, fileNameToModule, splitModuleFileName, isCurryFilePath++ -- * Curry sub-directory+ , defaultOutDir, hasOutDir, addOutDir, addOutDirModule+ , ensureOutDir++ -- * File name extensions+ -- ** Curry files+ , curryExt, lcurryExt, icurryExt++ -- ** FlatCurry files+ , annotatedFlatExt, typedFlatExt, flatExt, flatIntExt++ -- ** AbstractCurry files+ , acyExt, uacyExt++ -- ** Source and object files+ , sourceRepExt, sourceExts, moduleExts++ -- * Functions for computing file names+ , interfName, typedFlatName, annotatedFlatName, flatName, flatIntName+ , acyName, uacyName, sourceRepName, tokensName, commentsName+ , astName, shortASTName, htmlName+ ) where++import System.FilePath++import Curry.Base.Ident++-- -----------------------------------------------------------------------------+-- Conversion between ModuleIdent and FilePath+-- -----------------------------------------------------------------------------++-- |Create a 'FilePath' from a 'ModuleIdent' using the hierarchical module+-- system+moduleNameToFile :: ModuleIdent -> FilePath+moduleNameToFile = foldr1 (</>) . midQualifiers++-- |Extract the 'ModuleIdent' from a 'FilePath'+fileNameToModule :: FilePath -> ModuleIdent+fileNameToModule = mkMIdent . splitDirectories . dropExtension . dropDrive++-- |Split a 'FilePath' into a prefix directory part and those part that+-- corresponds to the 'ModuleIdent'. This is especially useful for+-- hierarchically module names.+splitModuleFileName :: ModuleIdent -> FilePath -> (FilePath, FilePath)+splitModuleFileName m fn = case midQualifiers m of+ [_] -> splitFileName fn+ ms -> let (base, ext) = splitExtension fn+ dirs = splitDirectories base+ (pre, suf) = splitAt (length dirs - length ms) dirs+ path = if null pre then ""+ else addTrailingPathSeparator (joinPath pre)+ in (path, joinPath suf <.> ext)++-- |Checks whether a 'String' represents a 'FilePath' to a Curry module+isCurryFilePath :: String -> Bool+isCurryFilePath str = isValid str+ && takeExtension str `elem` ("" : moduleExts)++-- -----------------------------------------------------------------------------+-- Curry sub-directory+-- -----------------------------------------------------------------------------++-- |The standard hidden subdirectory for curry files+defaultOutDir :: String+defaultOutDir = ".curry"++-- |Does the given 'FilePath' contain the 'outDir'+-- as its last directory component?+hasOutDir :: String -> FilePath -> Bool+hasOutDir outDir f = not (null dirs) && last dirs == outDir+ where dirs = splitDirectories $ takeDirectory f++-- |Add the 'outDir' to the given 'FilePath' if the flag is 'True' and+-- the path does not already contain it, otherwise leave the path untouched.+addOutDir :: Bool -> String -> FilePath -> FilePath+addOutDir b outDir fn = if b then ensureOutDir outDir fn else fn++-- |Add the 'outDir' to the given 'FilePath' if the flag is 'True' and+-- the path does not already contain it, otherwise leave the path untouched.+addOutDirModule :: Bool -> String -> ModuleIdent -> FilePath -> FilePath+addOutDirModule b outDir m fn+ | b = let (pre, file) = splitModuleFileName m fn+ in ensureOutDir outDir pre </> file+ | otherwise = fn++-- | Ensure that the 'outDir' is the last component of the+-- directory structure of the given 'FilePath'. If the 'FilePath' already+-- contains the sub-directory, it remains unchanged.+ensureOutDir :: String -- ^ the 'outDir'+ -> FilePath -- ^ original 'FilePath'+ -> FilePath -- ^ new 'FilePath'+ensureOutDir outDir fn = normalise $ addSub (splitDirectories d) </> f+ where+ (d, f) = splitFileName fn+ addSub dirs | null dirs = outDir+ | last dirs == outDir = joinPath dirs+ | otherwise = joinPath dirs </> outDir++-- -----------------------------------------------------------------------------+-- File name extensions+-- -----------------------------------------------------------------------------++-- |Filename extension for non-literate curry files+curryExt :: String+curryExt = ".curry"++-- |Filename extension for literate curry files+lcurryExt :: String+lcurryExt = ".lcurry"++-- |Filename extension for curry interface files+icurryExt :: String+icurryExt = ".icurry"++-- |Filename extension for curry source files.+--+-- /Note:/ The order of the extensions defines the order in which source files+-- should be searched for, i.e. given a module name @M@, the search order+-- should be the following:+--+-- 1. @M.curry@+-- 2. @M.lcurry@+--+sourceExts :: [String]+sourceExts = [curryExt, lcurryExt]++-- |Filename extension for curry module files+-- TODO: Is the order correct?+moduleExts :: [String]+moduleExts = sourceExts ++ [icurryExt]++-- |Filename extension for typed flat-curry files+typedFlatExt :: String+typedFlatExt = ".tfcy"++-- |Filename extension for type-annotated flat-curry files+annotatedFlatExt :: String+annotatedFlatExt = ".tafcy"++-- |Filename extension for flat-curry files+flatExt :: String+flatExt = ".fcy"++-- |Filename extension for extended-flat-curry interface files+flatIntExt :: String+flatIntExt = ".fint"++-- |Filename extension for abstract-curry files+acyExt :: String+acyExt = ".acy"++-- |Filename extension for untyped-abstract-curry files+uacyExt :: String+uacyExt = ".uacy"++-- |Filename extension for curry source representation files+sourceRepExt :: String+sourceRepExt = ".cy"++-- |Filename extension for token files+tokensExt :: String+tokensExt = ".tokens"++-- |Filename extension for comment token files+commentsExt :: String+commentsExt = ".cycom"++-- |Filename extension for AST files+astExt :: String+astExt = ".ast"++-- |Filename extension for shortened AST files+shortASTExt :: String+shortASTExt = ".sast"++-- ---------------------------------------------------------------------------+-- Computation of file names for a given source file+-- ---------------------------------------------------------------------------++-- |Compute the filename of the interface file for a source file+interfName :: FilePath -> FilePath+interfName = replaceExtensionWith icurryExt++-- |Compute the filename of the typed flat curry file for a source file+typedFlatName :: FilePath -> FilePath+typedFlatName = replaceExtensionWith typedFlatExt++-- |Compute the filename of the typed flat curry file for a source file+annotatedFlatName :: FilePath -> FilePath+annotatedFlatName = replaceExtensionWith annotatedFlatExt++-- |Compute the filename of the flat curry file for a source file+flatName :: FilePath -> FilePath+flatName = replaceExtensionWith flatExt++-- |Compute the filename of the flat curry interface file for a source file+flatIntName :: FilePath -> FilePath+flatIntName = replaceExtensionWith flatIntExt++-- |Compute the filename of the abstract curry file for a source file+acyName :: FilePath -> FilePath+acyName = replaceExtensionWith acyExt++-- |Compute the filename of the untyped abstract curry file for a source file+uacyName :: FilePath -> FilePath+uacyName = replaceExtensionWith uacyExt++-- |Compute the filename of the source representation file for a source file+sourceRepName :: FilePath -> FilePath+sourceRepName = replaceExtensionWith sourceRepExt++-- |Compute the filename of the tokens file for a source file+tokensName :: FilePath -> FilePath+tokensName = replaceExtensionWith tokensExt++-- |Compute the filename of the comment tokens file for a source file+commentsName :: FilePath -> FilePath+commentsName = replaceExtensionWith commentsExt++-- |Compute the filename of the ast file for a source file+astName :: FilePath -> FilePath+astName = replaceExtensionWith astExt++-- |Compute the filename of the ast file for a source file+shortASTName :: FilePath -> FilePath+shortASTName = replaceExtensionWith shortASTExt++-- |Compute the filename of the HTML file for a source file+htmlName :: ModuleIdent -> String+htmlName m = moduleName m ++ "_curry.html"++-- |Replace a filename extension with a new extension+replaceExtensionWith :: String -> FilePath -> FilePath+replaceExtensionWith = flip replaceExtension
+ src/Curry/Files/PathUtils.hs view
@@ -0,0 +1,206 @@+{- |+ Module : $Header$+ Description : Utility functions for reading and writing files+ Copyright : (c) 1999 - 2003, Wolfgang Lux+ 2011 - 2014, Björn Peemöller (bjp@informatik.uni-kiel.de)+ 2017 , Finn Teegen (fte@informatik.uni-kiel.de)+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable+-}++{-# LANGUAGE CPP #-}++module Curry.Files.PathUtils+ ( -- * Retrieving curry files+ lookupCurryFile+ , lookupCurryModule+ , lookupCurryInterface+ , lookupFile++ -- * Reading and writing modules from files+ , getModuleModTime+ , writeModule+ , readModule+ , writeBinaryModule+ , addVersion+ , checkVersion+ ) where++import qualified Control.Exception as C (IOException, handle)+import Control.Monad (liftM)+import Data.List (isPrefixOf, isSuffixOf)+import qualified Data.ByteString.Lazy as B (ByteString, writeFile)+import System.FilePath+import System.Directory+import System.IO++#if MIN_VERSION_directory(1,2,0)+import Data.Time (UTCTime)+#else+import System.Time (ClockTime)+#endif++import Curry.Base.Ident+import Curry.Files.Filenames++-- ---------------------------------------------------------------------------+-- Searching for files+-- ---------------------------------------------------------------------------++-- |Search in the given list of paths for the given 'FilePath' and eventually+-- return the file name of the found file.+--+-- - If the file name already contains a directory, then the paths to search+-- in are ignored.+-- - If the file name has no extension, then a source file extension is+-- assumed.+lookupCurryFile :: [FilePath] -> FilePath -> IO (Maybe FilePath)+lookupCurryFile paths fn = lookupFile paths exts fn+ where+ exts | null fnExt = sourceExts+ | otherwise = [fnExt]+ fnExt = takeExtension fn++-- |Search for a given curry module in the given source file and+-- library paths. Note that the current directory is always searched first.+-- Returns the path of the found file.+lookupCurryModule :: [FilePath] -- ^ list of paths to source files+ -> [FilePath] -- ^ list of paths to library files+ -> ModuleIdent -- ^ module identifier+ -> IO (Maybe FilePath)+lookupCurryModule paths libPaths m =+ lookupFile (paths ++ libPaths) moduleExts (moduleNameToFile m)++-- |Search for an interface file in the import search path using the+-- interface extension 'icurryExt'. Note that the current directory is+-- always searched first.+lookupCurryInterface :: [FilePath] -- ^ list of paths to search in+ -> ModuleIdent -- ^ module identifier+ -> IO (Maybe FilePath) -- ^ the file path if found+lookupCurryInterface paths m = lookupFile paths [icurryExt] (moduleNameToFile m)++-- |Search in the given directories for the file with the specified file+-- extensions and eventually return the 'FilePath' of the file.+lookupFile :: [FilePath] -- ^ Directories to search in+ -> [String] -- ^ Accepted file extensions+ -> FilePath -- ^ Initial file name+ -> IO (Maybe FilePath) -- ^ 'FilePath' of the file if found+lookupFile paths exts file = lookup' files+ where+ files = [ normalise (p </> f) | p <- paths, f <- baseNames ]+ baseNames = map (replaceExtension file) exts++ lookup' [] = return Nothing+ lookup' (f : fs) = do+ exists <- doesFileExist f+ if exists then return (Just f) else lookup' fs++-- ---------------------------------------------------------------------------+-- Reading and writing files+-- ---------------------------------------------------------------------------++-- | Write the content to a file in the given directory.+writeModule :: FilePath -- ^ original path+ -> String -- ^ file content+ -> IO ()+writeModule fn contents = do+ createDirectoryIfMissing True $ takeDirectory fn+ tryWriteFile fn contents++-- | Write the content in binary to a file in the given directory.+writeBinaryModule :: FilePath -- ^ original path+ -> B.ByteString -- ^ file content+ -> IO ()+writeBinaryModule fn contents = do+ createDirectoryIfMissing True $ takeDirectory fn+ tryWriteBinaryFile (fn ++ "-bin") contents++-- | Read the specified module and returns either 'Just String' if+-- reading was successful or 'Nothing' otherwise.+readModule :: FilePath -> IO (Maybe String)+readModule = tryOnExistingFile readFileUTF8+ where+ readFileUTF8 :: FilePath -> IO String+ readFileUTF8 fn = do+ hdl <- openFile fn ReadMode+ hSetEncoding hdl utf8+ hGetContents hdl++-- | Get the modification time of a file, if existent+#if MIN_VERSION_directory(1,2,0)+getModuleModTime :: FilePath -> IO (Maybe UTCTime)+#else+getModuleModTime :: FilePath -> IO (Maybe ClockTime)+#endif+getModuleModTime = tryOnExistingFile getModificationTime++-- |Add the given version string to the file content+addVersion :: String -> String -> String+addVersion v content = "{- " ++ v ++ " -}\n" ++ content++-- |Check a source file for the given version string+checkVersion :: String -> String -> Either String String+checkVersion expected src = case lines src of+ [] -> Left "empty file"+ (l:ls) -> case getVersion l of+ Just v | v == expected -> Right (unlines ls)+ | otherwise -> Left $ "Expected version `" ++ expected+ ++ "', but found version `" ++ v ++ "'"+ _ -> Left $ "No version found"++ where+ getVersion s | "{- " `isPrefixOf` s && " -}" `isSuffixOf` s+ = Just (reverse $ drop 3 $ reverse $ drop 3 s)+ | otherwise+ = Nothing++-- ---------------------------------------------------------------------------+-- Helper functions+-- ---------------------------------------------------------------------------++tryOnExistingFile :: (FilePath -> IO a) -> FilePath -> IO (Maybe a)+tryOnExistingFile action fn = C.handle ignoreIOException $ do+ exists <- doesFileExist fn+ if exists then Just `liftM` action fn+ else return Nothing++ignoreIOException :: C.IOException -> IO (Maybe a)+ignoreIOException _ = return Nothing++-- | Try to write a file. If it already exists and is not writable,+-- a warning is issued. This solves some file dependency problems+-- in global installations.+tryWriteFile :: FilePath -- ^ original path+ -> String -- ^ file content+ -> IO ()+tryWriteFile fn contents = do+ exists <- doesFileExist fn+ if exists then C.handle issueWarning (writeFileUTF8 fn contents)+ else writeFileUTF8 fn contents+ where+ issueWarning :: C.IOException -> IO ()+ issueWarning _ = do+ putStrLn $ "*** Warning: cannot update file `" ++ fn ++ "' (update ignored)"+ return ()+ writeFileUTF8 :: FilePath -> String -> IO ()+ writeFileUTF8 fn' str =+ withFile fn' WriteMode (\hdl -> hSetEncoding hdl utf8 >> hPutStr hdl str)++-- | Try to write a file. If it already exists and is not writable,+-- a warning is issued. This solves some file dependency problems+-- in global installations.+tryWriteBinaryFile :: FilePath -- ^ original path+ -> B.ByteString -- ^ file content+ -> IO ()+tryWriteBinaryFile fn contents = do+ exists <- doesFileExist fn+ if exists then C.handle issueWarning (B.writeFile fn contents)+ else B.writeFile fn contents+ where+ issueWarning :: C.IOException -> IO ()+ issueWarning _ = do+ putStrLn $ "*** Warning: cannot update file `" ++ fn ++ "' (update ignored)"+ return ()
+ src/Curry/Files/Unlit.hs view
@@ -0,0 +1,124 @@+{-# LANGUAGE ViewPatterns #-}+{- |+ Module : $Header$+ Description : Handling of literate Curry files+ Copyright : (c) 2009 Holger Siegel+ 2012 - 2014 Björn Peemöller+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ Since version 0.7 of the language report, Curry accepts literate+ source programs. In a literate source, all program lines must begin+ with a greater sign in the first column. All other lines are assumed+ to be documentation. In order to avoid some common errors with+ literate programs, Curry requires at least one program line to be+ present in the file. In addition, every block of program code must be+ preceded by a blank line and followed by a blank line.++ It is also possible to use "\begin{code}" and "\end{code}"+ to mark code segments. Both styles can be used in mixed fashion.+-}++module Curry.Files.Unlit (isLiterate, unlit) where++import Control.Monad (when, unless, zipWithM)+import Data.Char (isSpace)+import Data.List (stripPrefix)++import Curry.Base.Monad (CYM, failMessageAt)+import Curry.Base.Span (pos2Span)+import Curry.Base.Position (Position (..), first)+import Curry.Files.Filenames (lcurryExt, takeExtension)++-- |Check whether a 'FilePath' represents a literate Curry module+isLiterate :: FilePath -> Bool+isLiterate = (== lcurryExt) . takeExtension++-- |Data type representing different kind of lines in a literate source+data Line+ = ProgramStart !Int -- ^ \begin{code}+ | ProgramEnd !Int -- ^ \end{code}+ | Program !Int String -- ^ program line with a line number and content+ | Comment !Int String -- ^ comment line+ | Blank !Int -- ^ blank line++-- |Process a curry program into error messages (if any) and the+-- corresponding non-literate program.+unlit :: FilePath -> String -> CYM String+unlit fn cy+ | isLiterate fn = do+ let cyl = lines cy+ ls <- progLines fn =<<+ normalize fn (length cyl) False (zipWith classify [1 .. ] cyl)+ when (all null ls) $ failMessageAt (pos2Span $ first fn) "No code in literate script"+ return (unlines ls)+ | otherwise = return cy++-- |Classification of a single program line+classify :: Int -> String -> Line+classify l s@('>' : _) = Program l s+classify l s@(stripPrefix "\\begin{code}" -> Just cs)+ | all isSpace cs = ProgramStart l+ | otherwise = Comment l s+classify l s@(stripPrefix "\\end{code}" -> Just cs)+ | all isSpace cs = ProgramEnd l+ | otherwise = Comment l s+classify l s+ | all isSpace s = Blank l+ | otherwise = Comment l s++-- |Check that ProgramStart and ProgramEnd match and desugar them.+normalize :: FilePath -> Int -> Bool -> [Line] -> CYM [Line]+normalize _ _ False [] = return []+normalize fn n True [] = reportMissingEnd fn n+normalize fn n b (ProgramStart l : rest) = do+ when b $ reportSpurious fn l "\\begin{code}"+ norm <- normalize fn n True rest+ return (Blank l : norm)+normalize fn n b (ProgramEnd l : rest) = do+ unless b $ reportSpurious fn l "\\end{code}"+ norm <- normalize fn n False rest+ return (Blank l : norm)+normalize fn n b (Comment l s : rest) = do+ let cons = if b then Program l s else Comment l s+ norm <- normalize fn n b rest+ return (cons : norm)+normalize fn n b (Program l s : rest) = do+ let cons = if b then Program l s else Program l (drop 1 s)+ norm <- normalize fn n b rest+ return (cons : norm)+normalize fn n b (Blank l : rest) = do+ let cons = if b then Program l "" else Blank l+ norm <- normalize fn n b rest+ return (cons : norm)++-- |Check that each program line is not adjacent to a comment line.+progLines :: FilePath -> [Line] -> CYM [String]+progLines fn cs = zipWithM checkAdjacency (Blank 0 : cs) cs where+ checkAdjacency (Program p _) (Comment _ _) = reportBlank fn p "followed"+ checkAdjacency (Comment _ _) (Program p _) = reportBlank fn p "preceded"+ checkAdjacency _ (Program _ s) = return s+ checkAdjacency _ _ = return ""++-- |Compute an appropiate error message+reportBlank :: FilePath -> Int -> String -> CYM a+reportBlank f l cause = failMessageAt (pos2Span $ Position f l 1) msg+ where msg = concat [ "When reading literate source: "+ , "Program line is " ++ cause ++ " by comment line."+ ]++reportMissingEnd :: FilePath -> Int -> CYM a+reportMissingEnd f l = failMessageAt (pos2Span $ Position f (l+1) 1) msg+ where msg = concat [ "When reading literate source: "+ , "Missing '\\end{code}' at the end of file."+ ]+++reportSpurious :: FilePath -> Int -> String -> CYM a+reportSpurious f l cause = failMessageAt (pos2Span $ Position f l 1) msg+ where msg = concat [ "When reading literate source: "+ , "Spurious '" ++ cause ++ "'."+ ]
+ src/Curry/FlatCurry.hs view
@@ -0,0 +1,19 @@+{- |+ Module : $Header$+ Description : Interface for reading and manipulating FlatCurry source code+ Copyright : (c) 2014 Björn Peemöller+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable+-}+module Curry.FlatCurry+ ( module Curry.FlatCurry.Type+ , module Curry.FlatCurry.Pretty+ , module Curry.FlatCurry.Files+ ) where++import Curry.FlatCurry.Files+import Curry.FlatCurry.Pretty+import Curry.FlatCurry.Type
+ src/Curry/FlatCurry/Annotated/Goodies.hs view
@@ -0,0 +1,685 @@+{- |+ Module : $Header$+ Description : Utility functions for working with annotated FlatCurry.+ Copyright : (c) 2016 - 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : fte@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This library provides selector functions, test and update operations+ as well as some useful auxiliary functions for AnnotatedFlatCurry data terms.+ Most of the provided functions are based on general transformation+ functions that replace constructors with user-defined+ functions. For recursive datatypes the transformations are defined+ inductively over the term structure. This is quite usual for+ transformations on AnnotatedFlatCurry terms,+ so the provided functions can be used to implement specific transformations+ without having to explicitly state the recursion. Essentially, the tedious+ part of such transformations - descend in fairly complex term structures -+ is abstracted away, which hopefully makes the code more clear and brief.+-}++module Curry.FlatCurry.Annotated.Goodies+ ( module Curry.FlatCurry.Annotated.Goodies+ , module Curry.FlatCurry.Goodies+ ) where++import Curry.FlatCurry.Goodies ( Update+ , trType, typeName, typeVisibility, typeParams+ , typeConsDecls, typeSyn, isTypeSyn+ , isDataTypeDecl, isExternalType, isPublicType+ , updType, updTypeName, updTypeVisibility+ , updTypeParams, updTypeConsDecls, updTypeSynonym+ , updQNamesInType+ , trCons, consName, consArity, consVisibility+ , isPublicCons, consArgs, updCons, updConsName+ , updConsArity, updConsVisibility, updConsArgs+ , updQNamesInConsDecl+ , trNewCons, newConsName, newConsVisibility+ , isPublicNewCons, newConsArg+ , updNewCons, updNewConsName+ , updNewConsVisibility, updNewConsArg+ , updQNamesInNewConsDecl+ , tVarIndex, domain, range, tConsName, tConsArgs+ , trTypeExpr, isTVar, isTCons, isFuncType+ , updTVars, updTCons, updFuncTypes, argTypes+ , typeArity, resultType, allVarsInTypeExpr+ , allTypeCons, rnmAllVarsInTypeExpr+ , updQNamesInTypeExpr+ , trOp, opName, opFixity, opPrecedence, updOp+ , updOpName, updOpFixity, updOpPrecedence+ , trCombType, isCombTypeFuncCall+ , isCombTypeFuncPartCall, isCombTypeConsCall+ , isCombTypeConsPartCall+ , isPublic+ )++import Curry.FlatCurry.Annotated.Type++-- AProg ----------------------------------------------------------------------++-- |transform program+trAProg :: (String -> [String] -> [TypeDecl] -> [AFuncDecl a] -> [OpDecl] -> b)+ -> AProg a -> b+trAProg prog (AProg name imps types funcs ops) = prog name imps types funcs ops++-- Selectors++-- |get name from program+aProgName :: AProg a -> String+aProgName = trAProg (\name _ _ _ _ -> name)++-- |get imports from program+aProgImports :: AProg a -> [String]+aProgImports = trAProg (\_ imps _ _ _ -> imps)++-- |get type declarations from program+aProgTypes :: AProg a -> [TypeDecl]+aProgTypes = trAProg (\_ _ types _ _ -> types)++-- |get functions from program+aProgAFuncs :: AProg a -> [AFuncDecl a]+aProgAFuncs = trAProg (\_ _ _ funcs _ -> funcs)++-- |get infix operators from program+aProgOps :: AProg a -> [OpDecl]+aProgOps = trAProg (\_ _ _ _ ops -> ops)++-- Update Operations++-- |update program+updAProg :: (String -> String) ->+ ([String] -> [String]) ->+ ([TypeDecl] -> [TypeDecl]) ->+ ([AFuncDecl a] -> [AFuncDecl a]) ->+ ([OpDecl] -> [OpDecl]) -> AProg a -> AProg a+updAProg fn fi ft ff fo = trAProg prog+ where+ prog name imps types funcs ops+ = AProg (fn name) (fi imps) (ft types) (ff funcs) (fo ops)++-- |update name of program+updAProgName :: Update (AProg a) String+updAProgName f = updAProg f id id id id++-- |update imports of program+updAProgImports :: Update (AProg a) [String]+updAProgImports f = updAProg id f id id id++-- |update type declarations of program+updAProgTypes :: Update (AProg a) [TypeDecl]+updAProgTypes f = updAProg id id f id id++-- |update functions of program+updAProgAFuncs :: Update (AProg a) [AFuncDecl a]+updAProgAFuncs f = updAProg id id id f id++-- |update infix operators of program+updAProgOps :: Update (AProg a) [OpDecl]+updAProgOps = updAProg id id id id++-- Auxiliary Functions++-- |get all program variables (also from patterns)+allVarsInAProg :: AProg a -> [(VarIndex, a)]+allVarsInAProg = concatMap allVarsInAFunc . aProgAFuncs++-- |lift transformation on expressions to program+updAProgAExps :: Update (AProg a) (AExpr a)+updAProgAExps = updAProgAFuncs . map . updAFuncBody++-- |rename programs variables+rnmAllVarsInAProg :: Update (AProg a) VarIndex+rnmAllVarsInAProg = updAProgAFuncs . map . rnmAllVarsInAFunc++-- |update all qualified names in program+updQNamesInAProg :: Update (AProg a) QName+updQNamesInAProg f = updAProg id id+ (map (updQNamesInType f)) (map (updQNamesInAFunc f)) (map (updOpName f))++-- |rename program (update name of and all qualified names in program)+rnmAProg :: String -> AProg a -> AProg a+rnmAProg name p = updAProgName (const name) (updQNamesInAProg rnm p)+ where+ rnm (m, n) | m == aProgName p = (name, n)+ | otherwise = (m, n)++-- AFuncDecl ------------------------------------------------------------------++-- |transform function+trAFunc :: (QName -> Int -> Visibility -> TypeExpr -> ARule a -> b) -> AFuncDecl a -> b+trAFunc func (AFunc name arity vis t rule) = func name arity vis t rule++-- Selectors++-- |get name of function+aFuncName :: AFuncDecl a -> QName+aFuncName = trAFunc (\name _ _ _ _ -> name)++-- |get arity of function+aFuncArity :: AFuncDecl a -> Int+aFuncArity = trAFunc (\_ arity _ _ _ -> arity)++-- |get visibility of function+aFuncVisibility :: AFuncDecl a -> Visibility+aFuncVisibility = trAFunc (\_ _ vis _ _ -> vis)++-- |get type of function+aFuncType :: AFuncDecl a -> TypeExpr+aFuncType = trAFunc (\_ _ _ t _ -> t)++-- |get rule of function+aFuncARule :: AFuncDecl a -> ARule a+aFuncARule = trAFunc (\_ _ _ _ rule -> rule)++-- Update Operations++-- |update function+updAFunc :: (QName -> QName) ->+ (Int -> Int) ->+ (Visibility -> Visibility) ->+ (TypeExpr -> TypeExpr) ->+ (ARule a -> ARule a) -> AFuncDecl a -> AFuncDecl a+updAFunc fn fa fv ft fr = trAFunc func+ where+ func name arity vis t rule+ = AFunc (fn name) (fa arity) (fv vis) (ft t) (fr rule)++-- |update name of function+updAFuncName :: Update (AFuncDecl a) QName+updAFuncName f = updAFunc f id id id id++-- |update arity of function+updAFuncArity :: Update (AFuncDecl a) Int+updAFuncArity f = updAFunc id f id id id++-- |update visibility of function+updAFuncVisibility :: Update (AFuncDecl a) Visibility+updAFuncVisibility f = updAFunc id id f id id++-- |update type of function+updFuncType :: Update (AFuncDecl a) TypeExpr+updFuncType f = updAFunc id id id f id++-- |update rule of function+updAFuncARule :: Update (AFuncDecl a) (ARule a)+updAFuncARule = updAFunc id id id id++-- Auxiliary Functions++-- |is function public?+isPublicAFunc :: AFuncDecl a -> Bool+isPublicAFunc = isPublic . aFuncVisibility++-- |is function externally defined?+isExternal :: AFuncDecl a -> Bool+isExternal = isARuleExternal . aFuncARule++-- |get variable names in a function declaration+allVarsInAFunc :: AFuncDecl a -> [(VarIndex, a)]+allVarsInAFunc = allVarsInARule . aFuncARule++-- |get arguments of function, if not externally defined+aFuncArgs :: AFuncDecl a -> [(VarIndex, a)]+aFuncArgs = aRuleArgs . aFuncARule++-- |get body of function, if not externally defined+aFuncBody :: AFuncDecl a -> AExpr a+aFuncBody = aRuleBody . aFuncARule++-- |get the right-hand-sides of a 'FuncDecl'+aFuncRHS :: AFuncDecl a -> [AExpr a]+aFuncRHS f | not (isExternal f) = orCase (aFuncBody f)+ | otherwise = []+ where+ orCase e+ | isAOr e = concatMap orCase (orExps e)+ | isACase e = concatMap orCase (map aBranchAExpr (caseBranches e))+ | otherwise = [e]++-- |rename all variables in function+rnmAllVarsInAFunc :: Update (AFuncDecl a) VarIndex+rnmAllVarsInAFunc = updAFunc id id id id . rnmAllVarsInARule++-- |update all qualified names in function+updQNamesInAFunc :: Update (AFuncDecl a) QName+updQNamesInAFunc f = updAFunc f id id (updQNamesInTypeExpr f) (updQNamesInARule f)++-- |update arguments of function, if not externally defined+updAFuncArgs :: Update (AFuncDecl a) [(VarIndex, a)]+updAFuncArgs = updAFuncARule . updARuleArgs++-- |update body of function, if not externally defined+updAFuncBody :: Update (AFuncDecl a) (AExpr a)+updAFuncBody = updAFuncARule . updARuleBody++-- ARule ----------------------------------------------------------------------++-- |transform rule+trARule :: (a -> [(VarIndex, a)] -> AExpr a -> b) -> (a -> String -> b) -> ARule a -> b+trARule rule _ (ARule a args e) = rule a args e+trARule _ ext (AExternal a s) = ext a s++-- Selectors++-- |get rules annotation+aRuleAnnot :: ARule a -> a+aRuleAnnot = trARule (\a _ _ -> a) (\a _ -> a)++-- |get rules arguments if it's not external+aRuleArgs :: ARule a -> [(VarIndex, a)]+aRuleArgs = trARule (\_ args _ -> args) undefined++-- |get rules body if it's not external+aRuleBody :: ARule a -> AExpr a+aRuleBody = trARule (\_ _ e -> e) undefined++-- |get rules external declaration+aRuleExtDecl :: ARule a -> String+aRuleExtDecl = trARule undefined (\_ s -> s)++-- Test Operations++-- |is rule external?+isARuleExternal :: ARule a -> Bool+isARuleExternal = trARule (\_ _ _ -> False) (\_ _ -> True)++-- Update Operations++-- |update rule+updARule :: (a -> b) ->+ ([(VarIndex, a)] -> [(VarIndex, b)]) ->+ (AExpr a -> AExpr b) ->+ (String -> String) -> ARule a -> ARule b+updARule fannot fa fe fs = trARule rule ext+ where+ rule a args e = ARule (fannot a) (fa args) (fe e)+ ext a s = AExternal (fannot a) (fs s)++-- |update rules annotation+updARuleAnnot :: Update (ARule a) a+updARuleAnnot f = updARule f id id id++-- |update rules arguments+updARuleArgs :: Update (ARule a) [(VarIndex, a)]+updARuleArgs f = updARule id f id id++-- |update rules body+updARuleBody :: Update (ARule a) (AExpr a)+updARuleBody f = updARule id id f id++-- |update rules external declaration+updARuleExtDecl :: Update (ARule a) String+updARuleExtDecl f = updARule id id id f++-- Auxiliary Functions++-- |get variable names in a functions rule+allVarsInARule :: ARule a -> [(VarIndex, a)]+allVarsInARule = trARule (\_ args body -> args ++ allVars body) (\_ _ -> [])++-- |rename all variables in rule+rnmAllVarsInARule :: Update (ARule a) VarIndex+rnmAllVarsInARule f = updARule id (map (\(a, b) -> (f a, b))) (rnmAllVars f) id++-- |update all qualified names in rule+updQNamesInARule :: Update (ARule a) QName+updQNamesInARule = updARuleBody . updQNames++-- AExpr ----------------------------------------------------------------------++-- Selectors++-- |get annoation of an expression+annot :: AExpr a -> a+annot (AVar a _ ) = a+annot (ALit a _ ) = a+annot (AComb a _ _ _) = a+annot (ALet a _ _ ) = a+annot (AFree a _ _ ) = a+annot (AOr a _ _ ) = a+annot (ACase a _ _ _) = a+annot (ATyped a _ _ ) = a++-- |get internal number of variable+varNr :: AExpr a -> VarIndex+varNr (AVar _ n) = n+varNr _ = error "Curry.FlatCurry.Annotated.Goodies.varNr: no variable"++-- |get literal if expression is literal expression+literal :: AExpr a -> Literal+literal (ALit _ l) = l+literal _ = error "Curry.FlatCurry.Annotated.Goodies.literal: no literal"++-- |get combination type of a combined expression+combType :: AExpr a -> CombType+combType (AComb _ ct _ _) = ct+combType _ = error $ "Curry.FlatCurry.Annotated.Goodies.combType: " +++ "no combined expression"++-- |get name of a combined expression+combName :: AExpr a -> (QName, a)+combName (AComb _ _ name _) = name+combName _ = error $ "Curry.FlatCurry.Annotated.Goodies.combName: " +++ "no combined expression"++-- |get arguments of a combined expression+combArgs :: AExpr a -> [AExpr a]+combArgs (AComb _ _ _ args) = args+combArgs _ = error $ "Curry.FlatCurry.Annotated.Goodies.combArgs: " +++ "no combined expression"++-- |get number of missing arguments if expression is combined+missingCombArgs :: AExpr a -> Int+missingCombArgs = missingArgs . combType+ where+ missingArgs :: CombType -> Int+ missingArgs = trCombType 0 id 0 id++-- |get indices of varoables in let declaration+letBinds :: AExpr a -> [((VarIndex, a), AExpr a)]+letBinds (ALet _ vs _) = vs+letBinds _ = error $ "Curry.FlatCurry.Annotated.Goodies.letBinds: " +++ "no let expression"++-- |get body of let declaration+letBody :: AExpr a -> AExpr a+letBody (ALet _ _ e) = e+letBody _ = error $ "Curry.FlatCurry.Annotated.Goodies.letBody: " +++ "no let expression"++-- |get variable indices from declaration of free variables+freeVars :: AExpr a -> [(VarIndex, a)]+freeVars (AFree _ vs _) = vs+freeVars _ = error $ "Curry.FlatCurry.Annotated.Goodies.freeVars: " +++ "no declaration of free variables"++-- |get expression from declaration of free variables+freeExpr :: AExpr a -> AExpr a+freeExpr (AFree _ _ e) = e+freeExpr _ = error $ "Curry.FlatCurry.Annotated.Goodies.freeExpr: " +++ "no declaration of free variables"++-- |get expressions from or-expression+orExps :: AExpr a -> [AExpr a]+orExps (AOr _ e1 e2) = [e1, e2]+orExps _ = error $ "Curry.FlatCurry.Annotated.Goodies.orExps: " +++ "no or expression"++-- |get case-type of case expression+caseType :: AExpr a -> CaseType+caseType (ACase _ ct _ _) = ct+caseType _ = error $ "Curry.FlatCurry.Annotated.Goodies.caseType: " +++ "no case expression"++-- |get scrutinee of case expression+caseExpr :: AExpr a -> AExpr a+caseExpr (ACase _ _ e _) = e+caseExpr _ = error $ "Curry.FlatCurry.Annotated.Goodies.caseExpr: " +++ "no case expression"+++-- |get branch expressions from case expression+caseBranches :: AExpr a -> [ABranchExpr a]+caseBranches (ACase _ _ _ bs) = bs+caseBranches _ = error+ "Curry.FlatCurry.Annotated.Goodies.caseBranches: no case expression"++-- Test Operations++-- |is expression a variable?+isAVar :: AExpr a -> Bool+isAVar e = case e of+ AVar _ _ -> True+ _ -> False++-- |is expression a literal expression?+isALit :: AExpr a -> Bool+isALit e = case e of+ ALit _ _ -> True+ _ -> False++-- |is expression combined?+isAComb :: AExpr a -> Bool+isAComb e = case e of+ AComb _ _ _ _ -> True+ _ -> False++-- |is expression a let expression?+isALet :: AExpr a -> Bool+isALet e = case e of+ ALet _ _ _ -> True+ _ -> False++-- |is expression a declaration of free variables?+isAFree :: AExpr a -> Bool+isAFree e = case e of+ AFree _ _ _ -> True+ _ -> False++-- |is expression an or-expression?+isAOr :: AExpr a -> Bool+isAOr e = case e of+ AOr _ _ _ -> True+ _ -> False++-- |is expression a case expression?+isACase :: AExpr a -> Bool+isACase e = case e of+ ACase _ _ _ _ -> True+ _ -> False++-- |transform expression+trAExpr :: (a -> VarIndex -> b)+ -> (a -> Literal -> b)+ -> (a -> CombType -> (QName, a) -> [b] -> b)+ -> (a -> [((VarIndex, a), b)] -> b -> b)+ -> (a -> [(VarIndex, a)] -> b -> b)+ -> (a -> b -> b -> b)+ -> (a -> CaseType -> b -> [c] -> b)+ -> (APattern a -> b -> c)+ -> (a -> b -> TypeExpr -> b)+ -> AExpr a+ -> b+trAExpr var lit comb lt fr oR cas branch typed expr = case expr of+ AVar a n -> var a n+ ALit a l -> lit a l+ AComb a ct name args -> comb a ct name (map f args)+ ALet a bs e -> lt a (map (\(v, x) -> (v, f x)) bs) (f e)+ AFree a vs e -> fr a vs (f e)+ AOr a e1 e2 -> oR a (f e1) (f e2)+ ACase a ct e bs -> cas a ct (f e) (map (\ (ABranch p e') -> branch p (f e')) bs)+ ATyped a e ty -> typed a (f e) ty+ where+ f = trAExpr var lit comb lt fr oR cas branch typed++-- |update all variables in given expression+updVars :: (a -> VarIndex -> AExpr a) -> AExpr a -> AExpr a+updVars var = trAExpr var ALit AComb ALet AFree AOr ACase ABranch ATyped++-- |update all literals in given expression+updLiterals :: (a -> Literal -> AExpr a) -> AExpr a -> AExpr a+updLiterals lit = trAExpr AVar lit AComb ALet AFree AOr ACase ABranch ATyped++-- |update all combined expressions in given expression+updCombs :: (a -> CombType -> (QName, a) -> [AExpr a] -> AExpr a) -> AExpr a -> AExpr a+updCombs comb = trAExpr AVar ALit comb ALet AFree AOr ACase ABranch ATyped++-- |update all let expressions in given expression+updLets :: (a -> [((VarIndex, a), AExpr a)] -> AExpr a -> AExpr a) -> AExpr a -> AExpr a+updLets lt = trAExpr AVar ALit AComb lt AFree AOr ACase ABranch ATyped++-- |update all free declarations in given expression+updFrees :: (a -> [(VarIndex, a)] -> AExpr a -> AExpr a) -> AExpr a -> AExpr a+updFrees fr = trAExpr AVar ALit AComb ALet fr AOr ACase ABranch ATyped++-- |update all or expressions in given expression+updOrs :: (a -> AExpr a -> AExpr a -> AExpr a) -> AExpr a -> AExpr a+updOrs oR = trAExpr AVar ALit AComb ALet AFree oR ACase ABranch ATyped++-- |update all case expressions in given expression+updCases :: (a -> CaseType -> AExpr a -> [ABranchExpr a] -> AExpr a) -> AExpr a -> AExpr a+updCases cas = trAExpr AVar ALit AComb ALet AFree AOr cas ABranch ATyped++-- |update all case branches in given expression+updBranches :: (APattern a -> AExpr a -> ABranchExpr a) -> AExpr a -> AExpr a+updBranches branch = trAExpr AVar ALit AComb ALet AFree AOr ACase branch ATyped++-- |update all typed expressions in given expression+updTypeds :: (a -> AExpr a -> TypeExpr -> AExpr a) -> AExpr a -> AExpr a+updTypeds = trAExpr AVar ALit AComb ALet AFree AOr ACase ABranch++-- Auxiliary Functions++-- |is expression a call of a function where all arguments are provided?+isFuncCall :: AExpr a -> Bool+isFuncCall e = isAComb e && isCombTypeFuncCall (combType e)++-- |is expression a partial function call?+isFuncPartCall :: AExpr a -> Bool+isFuncPartCall e = isAComb e && isCombTypeFuncPartCall (combType e)++-- |is expression a call of a constructor?+isConsCall :: AExpr a -> Bool+isConsCall e = isAComb e && isCombTypeConsCall (combType e)++-- |is expression a partial constructor call?+isConsPartCall :: AExpr a -> Bool+isConsPartCall e = isAComb e && isCombTypeConsPartCall (combType e)++-- |is expression fully evaluated?+isGround :: AExpr a -> Bool+isGround e+ = case e of+ AComb _ ConsCall _ args -> all isGround args+ _ -> isALit e++-- |get all variables (also pattern variables) in expression+allVars :: AExpr a -> [(VarIndex, a)]+allVars e = trAExpr var lit comb lt fr (const (.)) cas branch typ e []+ where+ var a v = (:) (v, a)+ lit = const (const id)+ comb _ _ _ = foldr (.) id+ lt _ bs e' = e' . foldr (.) id (map (\(n,ns) -> (n:) . ns) bs)+ fr _ vs e' = (vs++) . e'+ cas _ _ e' bs = e' . foldr (.) id bs+ branch pat e' = ((args pat)++) . e'+ typ _ = const+ args pat | isConsPattern pat = aPatArgs pat+ | otherwise = []++-- |rename all variables (also in patterns) in expression+rnmAllVars :: Update (AExpr a) VarIndex+rnmAllVars f = trAExpr var ALit AComb lt fr AOr ACase branch ATyped+ where+ var a = AVar a . f+ lt a = ALet a . map (\((n, b), e) -> ((f n, b), e))+ fr a = AFree a . map (\(b, c) -> (f b, c))+ branch = ABranch . updAPatArgs (map (\(a, b) -> (f a, b)))++-- |update all qualified names in expression+updQNames :: Update (AExpr a) QName+updQNames f = trAExpr AVar ALit comb ALet AFree AOr ACase branch ATyped+ where+ comb a ct (name, a') args = AComb a ct (f name, a') args+ branch = ABranch . updAPatCons (\(q, a) -> (f q, a))++-- ABranchExpr ----------------------------------------------------------------++-- |transform branch expression+trABranch :: (APattern a -> AExpr a -> b) -> ABranchExpr a -> b+trABranch branch (ABranch pat e) = branch pat e++-- Selectors++-- |get pattern from branch expression+aBranchAPattern :: ABranchExpr a -> APattern a+aBranchAPattern = trABranch (\pat _ -> pat)++-- |get expression from branch expression+aBranchAExpr :: ABranchExpr a -> AExpr a+aBranchAExpr = trABranch (\_ e -> e)++-- Update Operations++-- |update branch expression+updABranch :: (APattern a -> APattern a) -> (AExpr a -> AExpr a) -> ABranchExpr a -> ABranchExpr a+updABranch fp fe = trABranch branch+ where+ branch pat e = ABranch (fp pat) (fe e)++-- |update pattern of branch expression+updABranchAPattern :: Update (ABranchExpr a) (APattern a)+updABranchAPattern f = updABranch f id++-- |update expression of branch expression+updABranchAExpr :: Update (ABranchExpr a) (AExpr a)+updABranchAExpr = updABranch id++-- APattern -------------------------------------------------------------------++-- |transform pattern+trAPattern :: (a -> (QName, a) -> [(VarIndex, a)] -> b) -> (a -> Literal -> b) -> APattern a -> b+trAPattern pat _ (APattern a name args) = pat a name args+trAPattern _ lpat (ALPattern a l) = lpat a l++-- Selectors++-- |get annotation from pattern+aPatAnnot :: APattern a -> a+aPatAnnot = trAPattern (\a _ _ -> a) (\a _ -> a)++-- |get name from constructor pattern+aPatCons :: APattern a -> (QName, a)+aPatCons = trAPattern (\_ name _ -> name) undefined++-- |get arguments from constructor pattern+aPatArgs :: APattern a -> [(VarIndex, a)]+aPatArgs = trAPattern (\_ _ args -> args) undefined++-- |get literal from literal pattern+aPatLiteral :: APattern a -> Literal+aPatLiteral = trAPattern undefined (const id)++-- Test Operations++-- |is pattern a constructor pattern?+isConsPattern :: APattern a -> Bool+isConsPattern = trAPattern (\_ _ _ -> True) (\_ _ -> False)++-- Update Operations++-- |update pattern+updAPattern :: (a -> a) ->+ ((QName, a) -> (QName, a)) ->+ ([(VarIndex, a)] -> [(VarIndex, a)]) ->+ (Literal -> Literal) -> APattern a -> APattern a+updAPattern fannot fn fa fl = trAPattern pat lpat+ where+ pat a name args = APattern (fannot a) (fn name) (fa args)+ lpat a l = ALPattern (fannot a) (fl l)++-- |update annotation of pattern+updAPatAnnot :: (a -> a) -> APattern a -> APattern a+updAPatAnnot f = updAPattern f id id id++-- |update constructors name of pattern+updAPatCons :: ((QName, a) -> (QName, a)) -> APattern a -> APattern a+updAPatCons f = updAPattern id f id id++-- |update arguments of constructor pattern+updAPatArgs :: ([(VarIndex, a)] -> [(VarIndex, a)]) -> APattern a -> APattern a+updAPatArgs f = updAPattern id id f id++-- |update literal of pattern+updAPatLiteral :: (Literal -> Literal) -> APattern a -> APattern a+updAPatLiteral f = updAPattern id id id f++-- Auxiliary Functions++-- |build expression from pattern+aPatExpr :: APattern a -> AExpr a+aPatExpr = trAPattern (\a name -> AComb a ConsCall name . map (uncurry (flip AVar))) ALit
+ src/Curry/FlatCurry/Annotated/Type.hs view
@@ -0,0 +1,132 @@+{- |+ Module : $Header$+ Description : Representation of annotated FlatCurry.+ Copyright : (c) 2016 - 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : fte@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ TODO+-}++module Curry.FlatCurry.Annotated.Type+ ( module Curry.FlatCurry.Annotated.Type+ , module Curry.FlatCurry.Typeable+ , module Curry.FlatCurry.Type+ ) where++import Data.Binary+import Control.Monad++import Curry.FlatCurry.Typeable+import Curry.FlatCurry.Type ( QName, VarIndex, Visibility (..), TVarIndex+ , TypeDecl (..), Kind (..), OpDecl (..), Fixity (..)+ , TypeExpr (..), ConsDecl (..), NewConsDecl (..)+ , Literal (..), CombType (..), CaseType (..)+ )++data AProg a = AProg String [String] [TypeDecl] [AFuncDecl a] [OpDecl]+ deriving (Eq, Read, Show)++data AFuncDecl a = AFunc QName Int Visibility TypeExpr (ARule a)+ deriving (Eq, Read, Show)++data ARule a+ = ARule a [(VarIndex, a)] (AExpr a)+ | AExternal a String+ deriving (Eq, Read, Show)++data AExpr a+ = AVar a VarIndex+ | ALit a Literal+ | AComb a CombType (QName, a) [AExpr a]+ | ALet a [((VarIndex, a), AExpr a)] (AExpr a)+ | AFree a [(VarIndex, a)] (AExpr a)+ | AOr a (AExpr a) (AExpr a)+ | ACase a CaseType (AExpr a) [ABranchExpr a]+ | ATyped a (AExpr a) TypeExpr+ deriving (Eq, Read, Show)++data ABranchExpr a = ABranch (APattern a) (AExpr a)+ deriving (Eq, Read, Show)++data APattern a+ = APattern a (QName, a) [(VarIndex, a)]+ | ALPattern a Literal+ deriving (Eq, Read, Show)++instance Typeable a => Typeable (AExpr a) where+ typeOf (AVar a _) = typeOf a+ typeOf (ALit a _) = typeOf a+ typeOf (AComb a _ _ _) = typeOf a+ typeOf (ALet a _ _) = typeOf a+ typeOf (AFree a _ _) = typeOf a+ typeOf (AOr a _ _) = typeOf a+ typeOf (ACase a _ _ _) = typeOf a+ typeOf (ATyped a _ _) = typeOf a++instance Typeable a => Typeable (APattern a) where+ typeOf (APattern a _ _) = typeOf a+ typeOf (ALPattern a _) = typeOf a++instance Binary a => Binary (AProg a) where+ put (AProg mid im tys fus ops) =+ put mid >> put im >> put tys >> put fus >> put ops+ get = AProg <$> get <*> get <*> get <*> get <*> get++instance Binary a => Binary (AFuncDecl a) where+ put (AFunc qid arity vis ty r) =+ put qid >> put arity >> put vis >> put ty >> put r+ get = AFunc <$> get <*> get <*> get <*> get <*> get++instance Binary a => Binary (ARule a) where+ put (ARule a alts e) = putWord8 0 >> put a >> put alts >> put e+ put (AExternal ty n ) = putWord8 1 >> put ty >> put n++ get = do+ x <- getWord8+ case x of+ 0 -> liftM3 ARule get get get+ 1 -> liftM2 AExternal get get+ _ -> fail "Invalid encoding for TRule"++instance Binary a => Binary (AExpr a) where+ put (AVar a v) = putWord8 0 >> put a >> put v+ put (ALit a l) = putWord8 1 >> put a >> put l+ put (AComb a cty qid es) =+ putWord8 2 >> put a >> put cty >> put qid >> put es+ put (ALet a bs e ) = putWord8 3 >> put a >> put bs >> put e+ put (AFree a vs e ) = putWord8 4 >> put a >> put vs >> put e+ put (AOr a e1 e2) = putWord8 5 >> put a >> put e1 >> put e2+ put (ACase a cty ty as) = putWord8 6 >> put a >> put cty >> put ty >> put as+ put (ATyped a e ty) = putWord8 7 >> put a >> put e >> put ty++ get = do+ x <- getWord8+ case x of+ 0 -> liftM2 AVar get get+ 1 -> liftM2 ALit get get+ 2 -> liftM4 AComb get get get get+ 3 -> liftM3 ALet get get get+ 4 -> liftM3 AFree get get get+ 5 -> liftM3 AOr get get get+ 6 -> liftM4 ACase get get get get+ 7 -> liftM3 ATyped get get get+ _ -> fail "Invalid encoding for TExpr"++instance Binary a => Binary (ABranchExpr a) where+ put (ABranch p e) = put p >> put e+ get = liftM2 ABranch get get++instance Binary a => Binary (APattern a) where+ put (APattern a qid vs) = putWord8 0 >> put a >> put qid >> put vs+ put (ALPattern a l ) = putWord8 1 >> put a >> put l++ get = do+ x <- getWord8+ case x of+ 0 -> liftM3 APattern get get get+ 1 -> liftM2 ALPattern get get+ _ -> fail "Invalid encoding for TPattern"
+ src/Curry/FlatCurry/Files.hs view
@@ -0,0 +1,68 @@+{- |+ Module : $Header$+ Description : Functions for reading and writing FlatCurry files+ Copyright : (c) 2014 Björn Peemöller+ 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module contains functions for reading and writing FlatCurry files.+-}++module Curry.FlatCurry.Files+ ( readTypedFlatCurry, readFlatCurry, readFlatInterface+ , writeFlatCurry, writeBinaryFlatCurry+ ) where++import Data.Binary (Binary, encode)+import Data.Char (isSpace)++import Curry.Files.Filenames (typedFlatName, flatName, flatIntName)+import Curry.Files.PathUtils (writeModule, writeBinaryModule, readModule)++import Curry.FlatCurry.Type (Prog)+import Curry.FlatCurry.Annotated.Type (AProg, TypeExpr)+++-- ---------------------------------------------------------------------------+-- Functions for reading and writing FlatCurry terms+-- ---------------------------------------------------------------------------++-- |Reads an typed FlatCurry file (extension ".tfcy") and eventually+-- returns the corresponding FlatCurry program term (type 'AProg').+readTypedFlatCurry :: FilePath -> IO (Maybe (AProg TypeExpr))+readTypedFlatCurry = readFlat . typedFlatName++-- |Reads a FlatCurry file (extension ".fcy") and eventually returns the+-- corresponding FlatCurry program term (type 'Prog').+readFlatCurry :: FilePath -> IO (Maybe Prog)+readFlatCurry = readFlat . flatName++-- |Reads a FlatInterface file (extension @.fint@) and returns the+-- corresponding term (type 'Prog') as a value of type 'Maybe'.+readFlatInterface :: FilePath -> IO (Maybe Prog)+readFlatInterface = readFlat . flatIntName++-- |Reads a Flat file and returns the corresponding term (type 'Prog' or+-- 'AProg') as a value of type 'Maybe'.+-- Due to compatibility with PAKCS it is allowed to have a commentary+-- at the beginning of the file enclosed in {- ... -}.+readFlat :: Read a => FilePath -> IO (Maybe a)+readFlat = fmap (fmap (read . skipComment)) . readModule where+ skipComment s = case dropWhile isSpace s of+ '{' : '-' : s' -> dropComment s'+ s' -> s'+ dropComment ('-' : '}' : xs) = xs+ dropComment (_ : xs) = dropComment xs+ dropComment [] = []++-- |Writes a FlatCurry program term into a file.+writeFlatCurry :: Show a => FilePath -> a -> IO ()+writeFlatCurry fn = writeModule fn . show++-- |Writes a FlatCurry program term into a normal and a binary file.+writeBinaryFlatCurry :: Binary a => FilePath -> a -> IO ()+writeBinaryFlatCurry fn = writeBinaryModule fn . encode
+ src/Curry/FlatCurry/Goodies.hs view
@@ -0,0 +1,1037 @@+{- |+ Module : $Header$+ Description : Utility functions for working with FlatCurry.+ Copyright : (c) Sebastian Fischer 2006+ Björn Peemöller 2011+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This library provides selector functions, test and update operations+ as well as some useful auxiliary functions for FlatCurry data terms.+ Most of the provided functions are based on general transformation+ functions that replace constructors with user-defined functions. For+ recursive datatypes the transformations are defined inductively over the+ term structure. This is quite usual for transformations on FlatCurry+ terms, so the provided functions can be used to implement specific+ transformations without having to explicitly state the recursion.+ Essentially, the tedious part of such transformations - descend in fairly+ complex term structures - is abstracted away, which hopefully makes the+ code more clear and brief.+-}++module Curry.FlatCurry.Goodies where++import Curry.FlatCurry.Type++-- |Update of a type's component+type Update a b = (b -> b) -> a -> a++-- Prog ----------------------------------------------------------------------++-- |transform program+trProg :: (String -> [String] -> [TypeDecl] -> [FuncDecl] -> [OpDecl] -> a)+ -> Prog -> a+trProg prog (Prog name imps types funcs ops) = prog name imps types funcs ops++-- Selectors++-- |get name from program+progName :: Prog -> String+progName = trProg (\name _ _ _ _ -> name)++-- |get imports from program+progImports :: Prog -> [String]+progImports = trProg (\_ imps _ _ _ -> imps)++-- |get type declarations from program+progTypes :: Prog -> [TypeDecl]+progTypes = trProg (\_ _ types _ _ -> types)++-- |get functions from program+progFuncs :: Prog -> [FuncDecl]+progFuncs = trProg (\_ _ _ funcs _ -> funcs)++-- |get infix operators from program+progOps :: Prog -> [OpDecl]+progOps = trProg (\_ _ _ _ ops -> ops)++-- Update Operations++-- |update program+updProg :: (String -> String) ->+ ([String] -> [String]) ->+ ([TypeDecl] -> [TypeDecl]) ->+ ([FuncDecl] -> [FuncDecl]) ->+ ([OpDecl] -> [OpDecl]) -> Prog -> Prog+updProg fn fi ft ff fo = trProg prog+ where+ prog name imps types funcs ops+ = Prog (fn name) (fi imps) (ft types) (ff funcs) (fo ops)++-- |update name of program+updProgName :: Update Prog String+updProgName f = updProg f id id id id++-- |update imports of program+updProgImports :: Update Prog [String]+updProgImports f = updProg id f id id id++-- |update type declarations of program+updProgTypes :: Update Prog [TypeDecl]+updProgTypes f = updProg id id f id id++-- |update functions of program+updProgFuncs :: Update Prog [FuncDecl]+updProgFuncs f = updProg id id id f id++-- |update infix operators of program+updProgOps :: Update Prog [OpDecl]+updProgOps = updProg id id id id++-- Auxiliary Functions++-- |get all program variables (also from patterns)+allVarsInProg :: Prog -> [VarIndex]+allVarsInProg = concatMap allVarsInFunc . progFuncs++-- |lift transformation on expressions to program+updProgExps :: Update Prog Expr+updProgExps = updProgFuncs . map . updFuncBody++-- |rename programs variables+rnmAllVarsInProg :: Update Prog VarIndex+rnmAllVarsInProg = updProgFuncs . map . rnmAllVarsInFunc++-- |update all qualified names in program+updQNamesInProg :: Update Prog QName+updQNamesInProg f = updProg id id+ (map (updQNamesInType f)) (map (updQNamesInFunc f)) (map (updOpName f))++-- |rename program (update name of and all qualified names in program)+rnmProg :: String -> Prog -> Prog+rnmProg name p = updProgName (const name) (updQNamesInProg rnm p)+ where+ rnm (m,n) | m==progName p = (name,n)+ | otherwise = (m,n)++-- TypeDecl ------------------------------------------------------------------++-- Selectors++-- |transform type declaration+trType :: (QName -> Visibility -> [TVarWithKind] -> [ConsDecl] -> a) ->+ (QName -> Visibility -> [TVarWithKind] -> TypeExpr -> a) ->+ (QName -> Visibility -> [TVarWithKind] -> NewConsDecl -> a) -> TypeDecl -> a+trType typ _ _ (Type name vis params cs) = typ name vis params cs+trType _ typesyn _ (TypeSyn name vis params syn) = typesyn name vis params syn+trType _ _ newtyp (TypeNew name vis params nc) = newtyp name vis params nc++-- |get name of type declaration+typeName :: TypeDecl -> QName+typeName = trType (\name _ _ _ -> name) (\name _ _ _ -> name) (\name _ _ _ -> name)++-- |get visibility of type declaration+typeVisibility :: TypeDecl -> Visibility+typeVisibility = trType (\_ vis _ _ -> vis) (\_ vis _ _ -> vis) (\_ vis _ _ -> vis)++-- |get type parameters of type declaration+typeParams :: TypeDecl -> [TVarWithKind]+typeParams = trType (\_ _ params _ -> params) (\_ _ params _ -> params) (\_ _ params _ -> params)++-- |get constructor declarations from type declaration+typeConsDecls :: TypeDecl -> [ConsDecl]+typeConsDecls = trType (\_ _ _ cs -> cs)+ (error "Curry.FlatCurry.Goodies: type synonym")+ (error "Curry.FlatCurry.Goodies: newtype")++-- |get synonym of type declaration+typeSyn :: TypeDecl -> TypeExpr+typeSyn = trType undefined (\_ _ _ syn -> syn) undefined++-- |is type declaration a type synonym?+isTypeSyn :: TypeDecl -> Bool+isTypeSyn = trType (\_ _ _ _ -> False) (\_ _ _ _ -> True) (\_ _ _ _ -> False)++-- | is type declaration declaring a regular type?+isDataTypeDecl :: TypeDecl -> Bool+isDataTypeDecl = trType (\_ _ _ cs -> not (null cs)) (\_ _ _ _ -> False) (\_ _ _ _ -> False)++-- | is type declaration declaring an external type?+isExternalType :: TypeDecl -> Bool+isExternalType = trType (\_ _ _ cs -> null cs) (\_ _ _ _ -> False) (\_ _ _ _ -> False)++-- |is type declaration a newtype?+isNewtype :: TypeDecl -> Bool+isNewtype = trType (\_ _ _ _ -> False) (\_ _ _ _ -> False) (\_ _ _ _ -> False)++-- |Is the 'TypeDecl' public?+isPublicType :: TypeDecl -> Bool+isPublicType = (== Public) . typeVisibility++-- Update Operations++-- |update type declaration+updType :: (QName -> QName) ->+ (Visibility -> Visibility) ->+ ([TVarWithKind] -> [TVarWithKind]) ->+ ([ConsDecl] -> [ConsDecl]) ->+ (NewConsDecl -> NewConsDecl) ->+ (TypeExpr -> TypeExpr) -> TypeDecl -> TypeDecl+updType fn fv fp fc fnc fs = trType typ typesyn newtyp+ where+ typ name vis params cs = Type (fn name) (fv vis) (fp params) (fc cs)+ newtyp name vis params nc = TypeNew (fn name) (fv vis) (fp params) (fnc nc)+ typesyn name vis params syn = TypeSyn (fn name) (fv vis) (fp params) (fs syn)++-- |update name of type declaration+updTypeName :: Update TypeDecl QName+updTypeName f = updType f id id id id id++-- |update visibility of type declaration+updTypeVisibility :: Update TypeDecl Visibility+updTypeVisibility f = updType id f id id id id++-- |update type parameters of type declaration+updTypeParams :: Update TypeDecl [TVarWithKind]+updTypeParams f = updType id id f id id id++-- |update constructor declarations of type declaration+updTypeConsDecls :: Update TypeDecl [ConsDecl]+updTypeConsDecls f = updType id id id f id id++-- |update constructor declarations of newtype declaration+updTypeNewConsDecls :: Update TypeDecl NewConsDecl+updTypeNewConsDecls f = updType id id id id f id++-- |update synonym of type declaration+updTypeSynonym :: Update TypeDecl TypeExpr+updTypeSynonym = updType id id id id id++-- Auxiliary Functions++-- |update all qualified names in type declaration+updQNamesInType :: Update TypeDecl QName+updQNamesInType f+ = updType f id id (map (updQNamesInConsDecl f)) (updQNamesInNewConsDecl f)+ (updQNamesInTypeExpr f)++-- ConsDecl ------------------------------------------------------------------++-- Selectors++-- |transform constructor declaration+trCons :: (QName -> Int -> Visibility -> [TypeExpr] -> a) -> ConsDecl -> a+trCons cons (Cons name arity vis args) = cons name arity vis args++-- |get name of constructor declaration+consName :: ConsDecl -> QName+consName = trCons (\name _ _ _ -> name)++-- |get arity of constructor declaration+consArity :: ConsDecl -> Int+consArity = trCons (\_ arity _ _ -> arity)++-- |get visibility of constructor declaration+consVisibility :: ConsDecl -> Visibility+consVisibility = trCons (\_ _ vis _ -> vis)++-- |Is the constructor declaration public?+isPublicCons :: ConsDecl -> Bool+isPublicCons = isPublic . consVisibility++-- |get arguments of constructor declaration+consArgs :: ConsDecl -> [TypeExpr]+consArgs = trCons (\_ _ _ args -> args)++-- Update Operations++-- |update constructor declaration+updCons :: (QName -> QName) ->+ (Int -> Int) ->+ (Visibility -> Visibility) ->+ ([TypeExpr] -> [TypeExpr]) -> ConsDecl -> ConsDecl+updCons fn fa fv fas = trCons cons+ where+ cons name arity vis args = Cons (fn name) (fa arity) (fv vis) (fas args)++-- |update name of constructor declaration+updConsName :: Update ConsDecl QName+updConsName f = updCons f id id id++-- |update arity of constructor declaration+updConsArity :: Update ConsDecl Int+updConsArity f = updCons id f id id++-- |update visibility of constructor declaration+updConsVisibility :: Update ConsDecl Visibility+updConsVisibility f = updCons id id f id++-- |update arguments of constructor declaration+updConsArgs :: Update ConsDecl [TypeExpr]+updConsArgs = updCons id id id++-- Auxiliary Functions++-- |update all qualified names in constructor declaration+updQNamesInConsDecl :: Update ConsDecl QName+updQNamesInConsDecl f = updCons f id id (map (updQNamesInTypeExpr f))+++-- NewConsDecl ------------------------------------------------------------------++-- Selectors++-- |transform newtype constructor declaration+trNewCons :: (QName -> Visibility -> TypeExpr -> a) -> NewConsDecl -> a+trNewCons cons (NewCons name vis arg) = cons name vis arg++-- |get name of new constructor declaration+newConsName :: NewConsDecl -> QName+newConsName = trNewCons (\name _ _ -> name)++-- |get visibility of new constructor declaration+newConsVisibility :: NewConsDecl -> Visibility+newConsVisibility = trNewCons (\_ vis _ -> vis)++-- |Is the new constructor declaration public?+isPublicNewCons :: ConsDecl -> Bool+isPublicNewCons = isPublic . consVisibility++-- |get argument of new constructor declaration+newConsArg :: NewConsDecl -> TypeExpr+newConsArg = trNewCons (\_ _ arg -> arg)++-- Update Operations++-- |update new constructor declaration+updNewCons :: (QName -> QName) ->+ (Visibility -> Visibility) ->+ (TypeExpr -> TypeExpr) -> NewConsDecl -> NewConsDecl+updNewCons fn fv fas = trNewCons cons+ where+ cons name vis args = NewCons (fn name) (fv vis) (fas args)++-- |update name of new constructor declaration+updNewConsName :: Update NewConsDecl QName+updNewConsName f = updNewCons f id id++-- |update visibility of new constructor declaration+updNewConsVisibility :: Update NewConsDecl Visibility+updNewConsVisibility f = updNewCons id f id++-- |update argument of new constructor declaration+updNewConsArg :: Update NewConsDecl TypeExpr+updNewConsArg = updNewCons id id++-- Auxiliary Functions++-- |update all qualified names in new constructor declaration+updQNamesInNewConsDecl :: Update NewConsDecl QName+updQNamesInNewConsDecl f = updNewCons f id (updQNamesInTypeExpr f)++-- TypeExpr ------------------------------------------------------------------++-- Selectors++-- |get index from type variable+tVarIndex :: TypeExpr -> TVarIndex+tVarIndex (TVar n) = n+tVarIndex _ = error $ "Curry.FlatCurry.Goodies.tvarIndex: " +++ "no type variable"++-- |get domain from functional type+domain :: TypeExpr -> TypeExpr+domain (FuncType dom _) = dom+domain _ = error $ "Curry.FlatCurry.Goodies.domain: " +++ "no function type"++-- |get range from functional type+range :: TypeExpr -> TypeExpr+range (FuncType _ ran) = ran+range _ = error $ "Curry.FlatCurry.Goodies.range: " +++ "no function type"++-- |get name from constructed type+tConsName :: TypeExpr -> QName+tConsName (TCons name _) = name+tConsName _ = error $ "Curry.FlatCurry.Goodies.tConsName: " +++ "no constructor type"++-- |get arguments from constructed type+tConsArgs :: TypeExpr -> [TypeExpr]+tConsArgs (TCons _ args) = args+tConsArgs _ = error $ "Curry.FlatCurry.Goodies.tConsArgs: " +++ "no constructor type"++-- |transform type expression+trTypeExpr :: (TVarIndex -> a) ->+ (QName -> [a] -> a) ->+ (a -> a -> a) ->+ ([TVarWithKind] -> a -> a) -> TypeExpr -> a+trTypeExpr tvar _ _ _ (TVar t) = tvar t+trTypeExpr tvar tcons functype foralltype (TCons name args)+ = tcons name (map (trTypeExpr tvar tcons functype foralltype) args)+trTypeExpr tvar tcons functype foralltype (FuncType from to)+ = functype (f from) (f to)+ where+ f = trTypeExpr tvar tcons functype foralltype+trTypeExpr tvar tcons functype foralltype (ForallType ns t)+ = foralltype ns (trTypeExpr tvar tcons functype foralltype t)++-- Test Operations++-- |is type expression a type variable?+isTVar :: TypeExpr -> Bool+isTVar = trTypeExpr (\_ -> True) (\_ _ -> False) (\_ _ -> False) (\_ _ -> False)++-- |is type declaration a constructed type?+isTCons :: TypeExpr -> Bool+isTCons+ = trTypeExpr (\_ -> False) (\_ _ -> True) (\_ _ -> False) (\_ _ -> False)++-- |is type declaration a functional type?+isFuncType :: TypeExpr -> Bool+isFuncType+ = trTypeExpr (\_ -> False) (\_ _ -> False) (\_ _ -> True) (\_ _ -> False)++-- |is type declaration a forall type?+isForallType :: TypeExpr -> Bool+isForallType+ = trTypeExpr (\_ -> False) (\_ _ -> False) (\_ _ -> False) (\_ _ -> True)++-- Update Operations++-- |update all type variables+updTVars :: (TVarIndex -> TypeExpr) -> TypeExpr -> TypeExpr+updTVars tvar = trTypeExpr tvar TCons FuncType ForallType++-- |update all type constructors+updTCons :: (QName -> [TypeExpr] -> TypeExpr) -> TypeExpr -> TypeExpr+updTCons tcons = trTypeExpr TVar tcons FuncType ForallType++-- |update all functional types+updFuncTypes :: (TypeExpr -> TypeExpr -> TypeExpr) -> TypeExpr -> TypeExpr+updFuncTypes functype = trTypeExpr TVar TCons functype ForallType++-- |update all forall types+updForallTypes :: ([TVarWithKind] -> TypeExpr -> TypeExpr) -> TypeExpr -> TypeExpr+updForallTypes = trTypeExpr TVar TCons FuncType++-- Auxiliary Functions++-- |get argument types from functional type+argTypes :: TypeExpr -> [TypeExpr]+argTypes (TVar _) = []+argTypes (TCons _ _) = []+argTypes (FuncType dom ran) = dom : argTypes ran+argTypes (ForallType _ _) = []++-- |Compute the arity of a 'TypeExpr'+typeArity :: TypeExpr -> Int+typeArity = length . argTypes++-- |get result type from (nested) functional type+resultType :: TypeExpr -> TypeExpr+resultType (TVar n) = TVar n+resultType (TCons name args) = TCons name args+resultType (FuncType _ ran) = resultType ran+resultType (ForallType ns t) = ForallType ns t++-- |get indexes of all type variables+allVarsInTypeExpr :: TypeExpr -> [TVarIndex]+allVarsInTypeExpr = trTypeExpr pure (const concat) (++) ((++) . map fst)++-- |yield the list of all contained type constructors+allTypeCons :: TypeExpr -> [QName]+allTypeCons (TVar _) = []+allTypeCons (TCons name args) = name : concatMap allTypeCons args+allTypeCons (FuncType t1 t2) = allTypeCons t1 ++ allTypeCons t2+allTypeCons (ForallType _ t) = allTypeCons t++-- |rename variables in type expression+rnmAllVarsInTypeExpr :: (TVarIndex -> TVarIndex) -> TypeExpr -> TypeExpr+rnmAllVarsInTypeExpr f = updTVars (TVar . f)++-- |update all qualified names in type expression+updQNamesInTypeExpr :: (QName -> QName) -> TypeExpr -> TypeExpr+updQNamesInTypeExpr f = updTCons (\name args -> TCons (f name) args)++-- OpDecl --------------------------------------------------------------------++-- |transform operator declaration+trOp :: (QName -> Fixity -> Integer -> a) -> OpDecl -> a+trOp op (Op name fix prec) = op name fix prec++-- Selectors++-- |get name from operator declaration+opName :: OpDecl -> QName+opName = trOp (\name _ _ -> name)++-- |get fixity of operator declaration+opFixity :: OpDecl -> Fixity+opFixity = trOp (\_ fix _ -> fix)++-- |get precedence of operator declaration+opPrecedence :: OpDecl -> Integer+opPrecedence = trOp (\_ _ prec -> prec)++-- Update Operations++-- |update operator declaration+updOp :: (QName -> QName) ->+ (Fixity -> Fixity) ->+ (Integer -> Integer) -> OpDecl -> OpDecl+updOp fn ff fp = trOp op+ where op name fix prec = Op (fn name) (ff fix) (fp prec)++-- |update name of operator declaration+updOpName :: Update OpDecl QName+updOpName f = updOp f id id++-- |update fixity of operator declaration+updOpFixity :: Update OpDecl Fixity+updOpFixity f = updOp id f id++-- |update precedence of operator declaration+updOpPrecedence :: Update OpDecl Integer+updOpPrecedence = updOp id id++-- FuncDecl ------------------------------------------------------------------++-- |transform function+trFunc :: (QName -> Int -> Visibility -> TypeExpr -> Rule -> a) -> FuncDecl -> a+trFunc func (Func name arity vis t rule) = func name arity vis t rule++-- Selectors++-- |get name of function+funcName :: FuncDecl -> QName+funcName = trFunc (\name _ _ _ _ -> name)++-- |get arity of function+funcArity :: FuncDecl -> Int+funcArity = trFunc (\_ arity _ _ _ -> arity)++-- |get visibility of function+funcVisibility :: FuncDecl -> Visibility+funcVisibility = trFunc (\_ _ vis _ _ -> vis)++-- |get type of function+funcType :: FuncDecl -> TypeExpr+funcType = trFunc (\_ _ _ t _ -> t)++-- |get rule of function+funcRule :: FuncDecl -> Rule+funcRule = trFunc (\_ _ _ _ rule -> rule)++-- Update Operations++-- |update function+updFunc :: (QName -> QName) ->+ (Int -> Int) ->+ (Visibility -> Visibility) ->+ (TypeExpr -> TypeExpr) ->+ (Rule -> Rule) -> FuncDecl -> FuncDecl+updFunc fn fa fv ft fr = trFunc func+ where+ func name arity vis t rule+ = Func (fn name) (fa arity) (fv vis) (ft t) (fr rule)++-- |update name of function+updFuncName :: Update FuncDecl QName+updFuncName f = updFunc f id id id id++-- |update arity of function+updFuncArity :: Update FuncDecl Int+updFuncArity f = updFunc id f id id id++-- |update visibility of function+updFuncVisibility :: Update FuncDecl Visibility+updFuncVisibility f = updFunc id id f id id++-- |update type of function+updFuncType :: Update FuncDecl TypeExpr+updFuncType f = updFunc id id id f id++-- |update rule of function+updFuncRule :: Update FuncDecl Rule+updFuncRule = updFunc id id id id++-- Auxiliary Functions++-- |is function public?+isPublicFunc :: FuncDecl -> Bool+isPublicFunc = isPublic . funcVisibility++-- |is function externally defined?+isExternal :: FuncDecl -> Bool+isExternal = isRuleExternal . funcRule++-- |get variable names in a function declaration+allVarsInFunc :: FuncDecl -> [VarIndex]+allVarsInFunc = allVarsInRule . funcRule++-- |get arguments of function, if not externally defined+funcArgs :: FuncDecl -> [VarIndex]+funcArgs = ruleArgs . funcRule++-- |get body of function, if not externally defined+funcBody :: FuncDecl -> Expr+funcBody = ruleBody . funcRule++-- |get the right-hand-sides of a 'FuncDecl'+funcRHS :: FuncDecl -> [Expr]+funcRHS f | not (isExternal f) = orCase (funcBody f)+ | otherwise = []+ where+ orCase e+ | isOr e = concatMap orCase (orExps e)+ | isCase e = concatMap orCase (map branchExpr (caseBranches e))+ | otherwise = [e]++-- |rename all variables in function+rnmAllVarsInFunc :: Update FuncDecl VarIndex+rnmAllVarsInFunc = updFunc id id id id . rnmAllVarsInRule++-- |update all qualified names in function+updQNamesInFunc :: Update FuncDecl QName+updQNamesInFunc f = updFunc f id id (updQNamesInTypeExpr f) (updQNamesInRule f)++-- |update arguments of function, if not externally defined+updFuncArgs :: Update FuncDecl [VarIndex]+updFuncArgs = updFuncRule . updRuleArgs++-- |update body of function, if not externally defined+updFuncBody :: Update FuncDecl Expr+updFuncBody = updFuncRule . updRuleBody++-- Rule ----------------------------------------------------------------------++-- |transform rule+trRule :: ([VarIndex] -> Expr -> a) -> (String -> a) -> Rule -> a+trRule rule _ (Rule args e) = rule args e+trRule _ ext (External s) = ext s++-- Selectors++-- |get rules arguments if it's not external+ruleArgs :: Rule -> [VarIndex]+ruleArgs = trRule (\args _ -> args) undefined++-- |get rules body if it's not external+ruleBody :: Rule -> Expr+ruleBody = trRule (\_ e -> e) undefined++-- |get rules external declaration+ruleExtDecl :: Rule -> String+ruleExtDecl = trRule undefined id++-- Test Operations++-- |is rule external?+isRuleExternal :: Rule -> Bool+isRuleExternal = trRule (\_ _ -> False) (\_ -> True)++-- Update Operations++-- |update rule+updRule :: ([VarIndex] -> [VarIndex]) ->+ (Expr -> Expr) ->+ (String -> String) -> Rule -> Rule+updRule fa fe fs = trRule rule ext+ where+ rule args e = Rule (fa args) (fe e)+ ext s = External (fs s)++-- |update rules arguments+updRuleArgs :: Update Rule [VarIndex]+updRuleArgs f = updRule f id id++-- |update rules body+updRuleBody :: Update Rule Expr+updRuleBody f = updRule id f id++-- |update rules external declaration+updRuleExtDecl :: Update Rule String+updRuleExtDecl f = updRule id id f++-- Auxiliary Functions++-- |get variable names in a functions rule+allVarsInRule :: Rule -> [VarIndex]+allVarsInRule = trRule (\args body -> args ++ allVars body) (\_ -> [])++-- |rename all variables in rule+rnmAllVarsInRule :: Update Rule VarIndex+rnmAllVarsInRule f = updRule (map f) (rnmAllVars f) id++-- |update all qualified names in rule+updQNamesInRule :: Update Rule QName+updQNamesInRule = updRuleBody . updQNames++-- CombType ------------------------------------------------------------------++-- |transform combination type+trCombType :: a -> (Int -> a) -> a -> (Int -> a) -> CombType -> a+trCombType fc _ _ _ FuncCall = fc+trCombType _ fpc _ _ (FuncPartCall n) = fpc n+trCombType _ _ cc _ ConsCall = cc+trCombType _ _ _ cpc (ConsPartCall n) = cpc n++-- Test Operations++-- |is type of combination FuncCall?+isCombTypeFuncCall :: CombType -> Bool+isCombTypeFuncCall = trCombType True (\_ -> False) False (\_ -> False)++-- |is type of combination FuncPartCall?+isCombTypeFuncPartCall :: CombType -> Bool+isCombTypeFuncPartCall = trCombType False (\_ -> True) False (\_ -> False)++-- |is type of combination ConsCall?+isCombTypeConsCall :: CombType -> Bool+isCombTypeConsCall = trCombType False (\_ -> False) True (\_ -> False)++-- |is type of combination ConsPartCall?+isCombTypeConsPartCall :: CombType -> Bool+isCombTypeConsPartCall = trCombType False (\_ -> False) False (\_ -> True)++-- Expr ----------------------------------------------------------------------++-- Selectors++-- |get internal number of variable+varNr :: Expr -> VarIndex+varNr (Var n) = n+varNr _ = error "Curry.FlatCurry.Goodies.varNr: no variable"++-- |get literal if expression is literal expression+literal :: Expr -> Literal+literal (Lit l) = l+literal _ = error "Curry.FlatCurry.Goodies.literal: no literal"++-- |get combination type of a combined expression+combType :: Expr -> CombType+combType (Comb ct _ _) = ct+combType _ = error $ "Curry.FlatCurry.Goodies.combType: " +++ "no combined expression"++-- |get name of a combined expression+combName :: Expr -> QName+combName (Comb _ name _) = name+combName _ = error $ "Curry.FlatCurry.Goodies.combName: " +++ "no combined expression"++-- |get arguments of a combined expression+combArgs :: Expr -> [Expr]+combArgs (Comb _ _ args) = args+combArgs _ = error $ "Curry.FlatCurry.Goodies.combArgs: " +++ "no combined expression"++-- |get number of missing arguments if expression is combined+missingCombArgs :: Expr -> Int+missingCombArgs = missingArgs . combType+ where+ missingArgs :: CombType -> Int+ missingArgs = trCombType 0 id 0 id++-- |get indices of varoables in let declaration+letBinds :: Expr -> [(VarIndex,Expr)]+letBinds (Let vs _) = vs+letBinds _ = error $ "Curry.FlatCurry.Goodies.letBinds: " +++ "no let expression"++-- |get body of let declaration+letBody :: Expr -> Expr+letBody (Let _ e) = e+letBody _ = error $ "Curry.FlatCurry.Goodies.letBody: " +++ "no let expression"++-- |get variable indices from declaration of free variables+freeVars :: Expr -> [VarIndex]+freeVars (Free vs _) = vs+freeVars _ = error $ "Curry.FlatCurry.Goodies.freeVars: " +++ "no declaration of free variables"++-- |get expression from declaration of free variables+freeExpr :: Expr -> Expr+freeExpr (Free _ e) = e+freeExpr _ = error $ "Curry.FlatCurry.Goodies.freeExpr: " +++ "no declaration of free variables"++-- |get expressions from or-expression+orExps :: Expr -> [Expr]+orExps (Or e1 e2) = [e1,e2]+orExps _ = error $ "Curry.FlatCurry.Goodies.orExps: " +++ "no or expression"++-- |get case-type of case expression+caseType :: Expr -> CaseType+caseType (Case ct _ _) = ct+caseType _ = error $ "Curry.FlatCurry.Goodies.caseType: " +++ "no case expression"++-- |get scrutinee of case expression+caseExpr :: Expr -> Expr+caseExpr (Case _ e _) = e+caseExpr _ = error $ "Curry.FlatCurry.Goodies.caseExpr: " +++ "no case expression"+++-- |get branch expressions from case expression+caseBranches :: Expr -> [BranchExpr]+caseBranches (Case _ _ bs) = bs+caseBranches _ = error+ "Curry.FlatCurry.Goodies.caseBranches: no case expression"++-- Test Operations++-- |is expression a variable?+isVar :: Expr -> Bool+isVar e = case e of+ Var _ -> True+ _ -> False++-- |is expression a literal expression?+isLit :: Expr -> Bool+isLit e = case e of+ Lit _ -> True+ _ -> False++-- |is expression combined?+isComb :: Expr -> Bool+isComb e = case e of+ Comb _ _ _ -> True+ _ -> False++-- |is expression a let expression?+isLet :: Expr -> Bool+isLet e = case e of+ Let _ _ -> True+ _ -> False++-- |is expression a declaration of free variables?+isFree :: Expr -> Bool+isFree e = case e of+ Free _ _ -> True+ _ -> False++-- |is expression an or-expression?+isOr :: Expr -> Bool+isOr e = case e of+ Or _ _ -> True+ _ -> False++-- |is expression a case expression?+isCase :: Expr -> Bool+isCase e = case e of+ Case _ _ _ -> True+ _ -> False++-- |transform expression+trExpr :: (VarIndex -> a)+ -> (Literal -> a)+ -> (CombType -> QName -> [a] -> a)+ -> ([(VarIndex, a)] -> a -> a)+ -> ([VarIndex] -> a -> a)+ -> (a -> a -> a)+ -> (CaseType -> a -> [b] -> a)+ -> (Pattern -> a -> b)+ -> (a -> TypeExpr -> a)+ -> Expr+ -> a+trExpr var lit comb lt fr oR cas branch typed expr = case expr of+ Var n -> var n+ Lit l -> lit l+ Comb ct name args -> comb ct name (map f args)+ Let bs e -> lt (map (\(v, x) -> (v, f x)) bs) (f e)+ Free vs e -> fr vs (f e)+ Or e1 e2 -> oR (f e1) (f e2)+ Case ct e bs -> cas ct (f e) (map (\ (Branch p e') -> branch p (f e')) bs)+ Typed e ty -> typed (f e) ty+ where+ f = trExpr var lit comb lt fr oR cas branch typed++-- Update Operations++-- |update all variables in given expression+updVars :: (VarIndex -> Expr) -> Expr -> Expr+updVars var = trExpr var Lit Comb Let Free Or Case Branch Typed++-- |update all literals in given expression+updLiterals :: (Literal -> Expr) -> Expr -> Expr+updLiterals lit = trExpr Var lit Comb Let Free Or Case Branch Typed++-- |update all combined expressions in given expression+updCombs :: (CombType -> QName -> [Expr] -> Expr) -> Expr -> Expr+updCombs comb = trExpr Var Lit comb Let Free Or Case Branch Typed++-- |update all let expressions in given expression+updLets :: ([(VarIndex,Expr)] -> Expr -> Expr) -> Expr -> Expr+updLets lt = trExpr Var Lit Comb lt Free Or Case Branch Typed++-- |update all free declarations in given expression+updFrees :: ([VarIndex] -> Expr -> Expr) -> Expr -> Expr+updFrees fr = trExpr Var Lit Comb Let fr Or Case Branch Typed++-- |update all or expressions in given expression+updOrs :: (Expr -> Expr -> Expr) -> Expr -> Expr+updOrs oR = trExpr Var Lit Comb Let Free oR Case Branch Typed++-- |update all case expressions in given expression+updCases :: (CaseType -> Expr -> [BranchExpr] -> Expr) -> Expr -> Expr+updCases cas = trExpr Var Lit Comb Let Free Or cas Branch Typed++-- |update all case branches in given expression+updBranches :: (Pattern -> Expr -> BranchExpr) -> Expr -> Expr+updBranches branch = trExpr Var Lit Comb Let Free Or Case branch Typed++-- |update all typed expressions in given expression+updTypeds :: (Expr -> TypeExpr -> Expr) -> Expr -> Expr+updTypeds = trExpr Var Lit Comb Let Free Or Case Branch++-- Auxiliary Functions++-- |is expression a call of a function where all arguments are provided?+isFuncCall :: Expr -> Bool+isFuncCall e = isComb e && isCombTypeFuncCall (combType e)++-- |is expression a partial function call?+isFuncPartCall :: Expr -> Bool+isFuncPartCall e = isComb e && isCombTypeFuncPartCall (combType e)++-- |is expression a call of a constructor?+isConsCall :: Expr -> Bool+isConsCall e = isComb e && isCombTypeConsCall (combType e)++-- |is expression a partial constructor call?+isConsPartCall :: Expr -> Bool+isConsPartCall e = isComb e && isCombTypeConsPartCall (combType e)++-- |is expression fully evaluated?+isGround :: Expr -> Bool+isGround e+ = case e of+ Comb ConsCall _ args -> all isGround args+ _ -> isLit e++-- |get all variables (also pattern variables) in expression+allVars :: Expr -> [VarIndex]+allVars e = trExpr (:) (const id) comb lt fr (.) cas branch const e []+ where+ comb _ _ = foldr (.) id+ lt bs e' = e' . foldr (.) id (map (\ (n,ns) -> (n:) . ns) bs)+ fr vs e' = (vs++) . e'+ cas _ e' bs = e' . foldr (.) id bs+ branch pat e' = ((args pat)++) . e'+ args pat | isConsPattern pat = patArgs pat+ | otherwise = []++-- |rename all variables (also in patterns) in expression+rnmAllVars :: Update Expr VarIndex+rnmAllVars f = trExpr (Var . f) Lit Comb lt (Free . map f) Or Case branch Typed+ where+ lt = Let . map (\ (n,e) -> (f n,e))+ branch = Branch . updPatArgs (map f)++-- |update all qualified names in expression+updQNames :: Update Expr QName+updQNames f = trExpr Var Lit comb Let Free Or Case (Branch . updPatCons f) Typed+ where+ comb ct name args = Comb ct (f name) args++-- BranchExpr ----------------------------------------------------------------++-- |transform branch expression+trBranch :: (Pattern -> Expr -> a) -> BranchExpr -> a+trBranch branch (Branch pat e) = branch pat e++-- Selectors++-- |get pattern from branch expression+branchPattern :: BranchExpr -> Pattern+branchPattern = trBranch (\pat _ -> pat)++-- |get expression from branch expression+branchExpr :: BranchExpr -> Expr+branchExpr = trBranch (\_ e -> e)++-- Update Operations++-- |update branch expression+updBranch :: (Pattern -> Pattern) -> (Expr -> Expr) -> BranchExpr -> BranchExpr+updBranch fp fe = trBranch branch+ where+ branch pat e = Branch (fp pat) (fe e)++-- |update pattern of branch expression+updBranchPattern :: Update BranchExpr Pattern+updBranchPattern f = updBranch f id++-- |update expression of branch expression+updBranchExpr :: Update BranchExpr Expr+updBranchExpr = updBranch id++-- Pattern -------------------------------------------------------------------++-- |transform pattern+trPattern :: (QName -> [VarIndex] -> a) -> (Literal -> a) -> Pattern -> a+trPattern pattern _ (Pattern name args) = pattern name args+trPattern _ lpattern (LPattern l) = lpattern l++-- Selectors++-- |get name from constructor pattern+patCons :: Pattern -> QName+patCons = trPattern (\name _ -> name) undefined++-- |get arguments from constructor pattern+patArgs :: Pattern -> [VarIndex]+patArgs = trPattern (\_ args -> args) undefined++-- |get literal from literal pattern+patLiteral :: Pattern -> Literal+patLiteral = trPattern undefined id++-- Test Operations++-- |is pattern a constructor pattern?+isConsPattern :: Pattern -> Bool+isConsPattern = trPattern (\_ _ -> True) (\_ -> False)++-- Update Operations++-- |update pattern+updPattern :: (QName -> QName) ->+ ([VarIndex] -> [VarIndex]) ->+ (Literal -> Literal) -> Pattern -> Pattern+updPattern fn fa fl = trPattern pattern lpattern+ where+ pattern name args = Pattern (fn name) (fa args)+ lpattern l = LPattern (fl l)++-- |update constructors name of pattern+updPatCons :: (QName -> QName) -> Pattern -> Pattern+updPatCons f = updPattern f id id++-- |update arguments of constructor pattern+updPatArgs :: ([VarIndex] -> [VarIndex]) -> Pattern -> Pattern+updPatArgs f = updPattern id f id++-- |update literal of pattern+updPatLiteral :: (Literal -> Literal) -> Pattern -> Pattern+updPatLiteral f = updPattern id id f++-- Auxiliary Functions++-- |build expression from pattern+patExpr :: Pattern -> Expr+patExpr = trPattern (\ name -> Comb ConsCall name . map Var) Lit++-- |Is this a public 'Visibility'?+isPublic :: Visibility -> Bool+isPublic = (== Public)
+ src/Curry/FlatCurry/InterfaceEquivalence.hs view
@@ -0,0 +1,58 @@+{- |+ Module : $Header$+ Description : Check the equality of two FlatCurry interfaces+ Copyright : (c) 2006 , Martin Engelke+ 2011 - 2014, Björn Peemöller+ 2014 , Jan Tikovsky+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable+-}++module Curry.FlatCurry.InterfaceEquivalence (eqInterface) where++import Data.List (deleteFirstsBy)++import Curry.FlatCurry.Type++infix 4 =~=, `eqvSet`++-- |Check whether the interfaces of two FlatCurry programs are equivalent.+eqInterface :: Prog -> Prog -> Bool+eqInterface = (=~=)++-- |Type class to express the equivalence of two values+class Equiv a where+ (=~=) :: a -> a -> Bool++instance Equiv a => Equiv [a] where+ [] =~= [] = True+ (x:xs) =~= (y:ys) = x =~= y && xs =~= ys+ _ =~= _ = False++instance Equiv Char where (=~=) = (==)++-- |Equivalence of lists independent of the order.+eqvSet :: Equiv a => [a] -> [a] -> Bool+xs `eqvSet` ys = null (deleteFirstsBy (=~=) xs ys ++ deleteFirstsBy (=~=) ys xs)++instance Equiv Prog where+ Prog m1 is1 ts1 fs1 os1 =~= Prog m2 is2 ts2 fs2 os2+ = m1 == m2 && is1 `eqvSet` is2 && ts1 `eqvSet` ts2+ && fs1 `eqvSet` fs2 && os1 `eqvSet` os2++instance Equiv TypeDecl where (=~=) = (==)++instance Equiv FuncDecl where+ Func qn1 ar1 vis1 ty1 r1 =~= Func qn2 ar2 vis2 ty2 r2+ = qn1 == qn2 && ar1 == ar2 && vis1 == vis2 && ty1 == ty2 && r1 =~= r2++-- TODO: Check why arguments of rules are not checked for equivalence+instance Equiv Rule where+ Rule _ _ =~= Rule _ _ = True+ External _ =~= External _ = True+ _ =~= _ = False++instance Equiv OpDecl where (=~=) = (==)
+ src/Curry/FlatCurry/Pretty.hs view
@@ -0,0 +1,217 @@+{- |+ Module : $Header$+ Description : A pretty printer for FlatCurry+ Copyright : (c) 2015 Björn Peemöller+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module implements a pretty printer for FlatCurry modules.+-}+{-# OPTIONS_GHC -Wno-orphans #-}+module Curry.FlatCurry.Pretty (pPrint, pPrintPrec) where++import Prelude hiding ((<>))+import Data.Char (ord)++import Curry.Base.Pretty+import Curry.FlatCurry.Type++instance Pretty Prog where+ pPrint (Prog m is ts fs os) = sepByBlankLine+ [ ppHeader m ts fs+ , vcat (map ppImport is)+ , vcat (map pPrint os)+ , sepByBlankLine (map pPrint ts)+ , sepByBlankLine (map pPrint fs)+ ]++ppHeader :: String -> [TypeDecl] -> [FuncDecl] -> Doc+ppHeader m ts fs = sep+ [text "module" <+> text m, ppExports ts fs, text "where"]++-- |pretty-print the export list+ppExports :: [TypeDecl] -> [FuncDecl] -> Doc+ppExports ts fs = parens $ list (map ppTypeExport ts ++ ppFuncExports fs)++ppTypeExport :: TypeDecl -> Doc+ppTypeExport (Type qn vis _ cs)+ | vis == Private = empty+ | all isPublicCons cs = ppPrefixOp qn <+> text "(..)"+ | otherwise = ppPrefixOp qn <+> parens (list (ppConsExports cs))+ where isPublicCons (Cons _ _ v _) = v == Public+ppTypeExport (TypeNew qn vis _ nc)+ | vis == Private = empty+ | isPublicCons nc = ppPrefixOp qn <+> text "(..)"+ | otherwise = ppPrefixOp qn <+> parens empty+ where isPublicCons (NewCons _ v _) = v == Public+ppTypeExport (TypeSyn qn vis _ _ )+ | vis == Private = empty+ | otherwise = ppPrefixOp qn++-- |pretty-print the export list of constructors+ppConsExports :: [ConsDecl] -> [Doc]+ppConsExports cs = [ ppPrefixOp qn | Cons qn _ Public _ <- cs]++-- |pretty-print the export list of functions+ppFuncExports :: [FuncDecl] -> [Doc]+ppFuncExports fs = [ ppPrefixOp qn | Func qn _ Public _ _ <- fs]++-- |pretty-print an import statement+ppImport :: String -> Doc+ppImport m = text "import" <+> text m++instance Pretty OpDecl where+ pPrint(Op qn fix n) = pPrint fix <+> integer n <+> ppInfixOp qn++instance Pretty Fixity where+ pPrint InfixOp = text "infix"+ pPrint InfixlOp = text "infixl"+ pPrint InfixrOp = text "infixr"++instance Pretty TypeDecl where+ pPrint (Type qn _ vs cs) = text "data" <+> ppQName qn+ <+> hsep (ppTVarIndex <$> fst <$> vs) $+$ ppConsDecls cs+ pPrint (TypeSyn qn _ vs ty) = text "type" <+> ppQName qn+ <+> hsep (ppTVarIndex <$> fst <$> vs) <+> equals <+> pPrintPrec 0 ty+ pPrint (TypeNew qn _ vs nc) = text "newtype" <+> ppQName qn+ <+> hsep (ppTVarIndex <$> fst <$> vs) <+> equals <+> pPrint nc++-- |pretty-print the constructor declarations+ppConsDecls :: [ConsDecl] -> Doc+ppConsDecls cs = indent $ vcat $+ zipWith (<+>) (equals : repeat (char '|')) (map pPrint cs)++instance Pretty ConsDecl where+ pPrint (Cons qn _ _ tys) = fsep $ ppPrefixOp qn : map (pPrintPrec 2) tys++instance Pretty NewConsDecl where+ pPrint (NewCons qn _ ty) = fsep [pPrint qn, pPrintPrec 2 ty]++instance Pretty TypeExpr where+ pPrintPrec _ (TVar i) = ppTVarIndex i+ pPrintPrec p (FuncType ty1 ty2) = parenIf (p > 0) $ fsep+ [pPrintPrec 1 ty1, rarrow, pPrintPrec 0 ty2]+ pPrintPrec p (TCons qn tys) = parenIf (p > 1 && not (null tys)) $ fsep+ (ppPrefixOp qn : map (pPrintPrec 2) tys)+ pPrintPrec p (ForallType vs ty)+ | null vs = pPrintPrec p ty+ | otherwise = parenIf (p > 0) $ ppQuantifiedVars vs <+> pPrintPrec 0 ty++-- |pretty-print explicitly quantified type variables (without kinds)+ppQuantifiedVars :: [(TVarIndex, Kind)] -> Doc+ppQuantifiedVars vs+ | null vs = empty+ | otherwise = text "forall" <+> hsep (map ppTVar vs) <> char '.'++ppTVar :: (TVarIndex, Kind) -> Doc+ppTVar (i, _) = ppTVarIndex i++-- |pretty-print a type variable+ppTVarIndex :: TVarIndex -> Doc+ppTVarIndex i = text $ vars !! i+ where vars = [ if n == 0 then [c] else c : show n+ | n <- [0 :: Int ..], c <- ['a' .. 'z']+ ]++instance Pretty FuncDecl where+ pPrint (Func qn _ _ ty r)+ = hsep [ppPrefixOp qn, text "::", pPrintPrec 0 ty]+ $+$ ppPrefixOp qn <+> pPrint r++instance Pretty Rule where+ pPrint (Rule vs e) =+ fsep (map ppVarIndex vs) <+> equals <+> indent (pPrintPrec 0 e)+ pPrint (External _) = text "external"++instance Pretty Expr where+ pPrintPrec _ (Var v) = ppVarIndex v+ pPrintPrec _ (Lit l) = pPrint l+ pPrintPrec p (Comb _ qn es) = ppComb p qn es+ pPrintPrec p (Free vs e)+ | null vs = pPrintPrec p e+ | otherwise = parenIf (p > 0) $ sep+ [ text "let" <+> list (map ppVarIndex vs)+ <+> text "free"+ , text "in" <+> pPrintPrec 0 e+ ]+ pPrintPrec p (Let ds e) = parenIf (p > 0) $+ sep [text "let" <+> ppDecls ds, text "in" <+> pPrintPrec 0 e]+ pPrintPrec p (Or e1 e2) = parenIf (p > 0) $+ pPrintPrec 1 e1 <+> text "?" <+> pPrintPrec 1 e2+ pPrintPrec p (Case ct e bs) = parenIf (p > 0) $+ pPrint ct <+> pPrintPrec 0 e <+> text "of" $$ indent (vcat (map pPrint bs))+ pPrintPrec p (Typed e ty) = parenIf (p > 0) $+ pPrintPrec 0 e <+> text "::" <+> pPrintPrec 0 ty++-- |pretty-print a variable+ppVarIndex :: VarIndex -> Doc+ppVarIndex i = text $ 'v' : show i++instance Pretty Literal where+ pPrint (Intc i) = integer i+ pPrint (Floatc f) = double f+ pPrint (Charc c) = text (showEscape c)++-- |Escape character literal+showEscape :: Char -> String+showEscape c+ | o < 10 = "'\\00" ++ show o ++ "'"+ | o < 32 = "'\\0" ++ show o ++ "'"+ | o == 127 = "'\\127'"+ | otherwise = show c+ where o = ord c++-- |Pretty print a constructor or function call+ppComb :: Int -> QName -> [Expr] -> Doc+ppComb _ qn [] = ppPrefixOp qn+ppComb p qn [e1,e2]+ | isInfixOp qn = parenIf (p > 0)+ $ hsep [pPrintPrec 1 e1, pPrint qn, pPrintPrec 1 e2]+ppComb p qn es = parenIf (p > 0)+ $ hsep (ppPrefixOp qn : map (pPrintPrec 1) es)++-- |pretty-print a list of declarations+ppDecls :: [(VarIndex, Expr)] -> Doc+ppDecls = vcat . map ppDecl++-- |pretty-print a single declaration+ppDecl :: (VarIndex, Expr) -> Doc+ppDecl (v, e) = ppVarIndex v <+> equals <+> pPrintPrec 0 e++instance Pretty CaseType where+ pPrint Rigid = text "case"+ pPrint Flex = text "fcase"++instance Pretty BranchExpr where+ pPrint (Branch p e) = pPrint p <+> rarrow <+> pPrintPrec 0 e++instance Pretty Pattern where+ pPrint (Pattern c [v1,v2])+ | isInfixOp c = ppVarIndex v1 <+> ppInfixOp c <+> ppVarIndex v2+ pPrint (Pattern c vs) = fsep (ppPrefixOp c : map ppVarIndex vs)+ pPrint (LPattern l) = pPrint l++-- Names++-- |pretty-print a prefix operator+ppPrefixOp :: QName -> Doc+ppPrefixOp qn = parenIf (isInfixOp qn) (ppQName qn)++-- |pretty-print a name in infix manner+ppInfixOp :: QName -> Doc+ppInfixOp qn = if isInfixOp qn then ppQName qn else bquotes (ppQName qn)++-- |pretty-print a qualified name+ppQName :: QName -> Doc+ppQName (m, i) = text $ m ++ '.' : i++-- |Check whether an operator is an infix operator+isInfixOp :: QName -> Bool+isInfixOp = all (`elem` "~!@#$%^&*+-=<>:?./|\\") . snd++-- Indentation+indent :: Doc -> Doc+indent = nest 2
+ src/Curry/FlatCurry/Type.hs view
@@ -0,0 +1,521 @@+{- |+ Module : $Header$+ Description : Representation of FlatCurry.+ Copyright : (c) Michael Hanus 2003+ Martin Engelke 2004+ Bernd Brassel 2005+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module contains a definition for representing FlatCurry programs+ in Haskell in type 'Prog'.+-}++module Curry.FlatCurry.Type+ ( -- * Representation of qualified names and (type) variables+ QName, VarIndex, TVarIndex, TVarWithKind+ -- * Data types for FlatCurry+ , Visibility (..), Prog (..), TypeDecl (..), TypeExpr (..), Kind (..)+ , ConsDecl (..), NewConsDecl(..), OpDecl (..), Fixity (..)+ , FuncDecl (..), Rule (..), Expr (..), Literal (..)+ , CombType (..), CaseType (..), BranchExpr (..), Pattern (..)+ ) where++import Data.Binary+import Control.Monad++-- ---------------------------------------------------------------------------+-- Qualified names+-- ---------------------------------------------------------------------------++-- |Qualified names.+--+-- In FlatCurry all names are qualified to avoid name clashes.+-- The first component is the module name and the second component the+-- unqualified name as it occurs in the source program.+type QName = (String, String)++-- ---------------------------------------------------------------------------+-- Variable representation+-- ---------------------------------------------------------------------------++-- |Representation of variables.+type VarIndex = Int++-- ---------------------------------------------------------------------------+-- FlatCurry representation+-- ---------------------------------------------------------------------------++-- |Visibility of various entities.+data Visibility+ = Public -- ^ public (exported) entity+ | Private -- ^ private entity+ deriving (Eq, Read, Show)++-- |A FlatCurry module.+--+-- A value of this data type has the form+--+-- @Prog modname imports typedecls functions opdecls@+--+-- where+--+-- [@modname@] Name of this module+-- [@imports@] List of modules names that are imported+-- [@typedecls@] Type declarations+-- [@funcdecls@] Function declarations+-- [@ opdecls@] Operator declarations+data Prog = Prog String [String] [TypeDecl] [FuncDecl] [OpDecl]+ deriving (Eq, Read, Show)++-- |Declaration of algebraic data type or type synonym.+--+-- A data type declaration of the form+--+-- @data t x1...xn = ...| c t1....tkc |...@+--+-- is represented by the FlatCurry term+--+-- @Type t [i1,...,in] [...(Cons c kc [t1,...,tkc])...]@+--+-- where each @ij@ is the index of the type variable @xj@+--+-- /Note:/ The type variable indices are unique inside each type declaration+-- and are usually numbered from 0.+--+-- Thus, a data type declaration consists of the name of the data type,+-- a list of type parameters and a list of constructor declarations.+data TypeDecl+ = Type QName Visibility [TVarWithKind] [ConsDecl]+ | TypeSyn QName Visibility [TVarWithKind] TypeExpr+ | TypeNew QName Visibility [TVarWithKind] NewConsDecl+ deriving (Eq, Read, Show)++-- |Type variables are represented by @(TVar i)@ where @i@ is a+-- type variable index.+type TVarIndex = Int++-- |Kinded type variables are represented by a tuple of type variable+-- index and kind.+type TVarWithKind = (TVarIndex, Kind)++-- |A constructor declaration consists of the name and arity of the+-- constructor and a list of the argument types of the constructor.+data ConsDecl = Cons QName Int Visibility [TypeExpr]+ deriving (Eq, Read, Show)++-- |A constructor declaration for a newtype consists+-- of the name of the constructor+-- and the argument type of the constructor.+data NewConsDecl = NewCons QName Visibility TypeExpr+ deriving (Eq, Read, Show)++-- |Type expressions.+--+-- A type expression is either a type variable, a function type,+-- or a type constructor application.+--+-- /Note:/ the names of the predefined type constructors are+-- @Int@, @Float@, @Bool@, @Char@, @IO@, @Success@,+-- @()@ (unit type), @(,...,)@ (tuple types), @[]@ (list type)+data TypeExpr+ = TVar TVarIndex -- ^ type variable+ | FuncType TypeExpr TypeExpr -- ^ function type @t1 -> t2@+ | TCons QName [TypeExpr] -- ^ type constructor application+ | ForallType [TVarWithKind] TypeExpr -- ^ forall type+ deriving (Eq, Read, Show)++-- |Kinds.+--+-- A kind is either * or k_1 -> k_2 where k_1 and k_2 are kinds.+data Kind+ = KStar -- ^ star kind+ | KArrow Kind Kind -- ^ arrow kind+ deriving (Eq, Ord, Read, Show)+ +-- |Operator declarations.+--+-- An operator declaration @fix p n@ in Curry corresponds to the+-- FlatCurry term @(Op n fix p)@.+--+-- /Note:/ the constructor definition of 'Op' differs from the original+-- PAKCS definition using Haskell type 'Integer' instead of 'Int'+-- for representing the precedence.+data OpDecl = Op QName Fixity Integer+ deriving (Eq, Read, Show)++-- |Fixity of an operator.+data Fixity+ = InfixOp -- ^ non-associative infix operator+ | InfixlOp -- ^ left-associative infix operator+ | InfixrOp -- ^ right-associative infix operator+ deriving (Eq, Read, Show)++-- |Data type for representing function declarations.+--+-- A function declaration in FlatCurry is a term of the form+--+-- @(Func name arity type (Rule [i_1,...,i_arity] e))@+--+-- and represents the function "name" with definition+--+-- @+-- name :: type+-- name x_1...x_arity = e+-- @+--+-- where each @i_j@ is the index of the variable @x_j@+--+-- /Note:/ The variable indices are unique inside each function declaration+-- and are usually numbered from 0.+--+-- External functions are represented as+--+-- @Func name arity type (External s)@+--+-- where s is the external name associated to this function.+--+-- Thus, a function declaration consists of the name, arity, type, and rule.+data FuncDecl = Func QName Int Visibility TypeExpr Rule+ deriving (Eq, Read, Show)++-- |A rule is either a list of formal parameters together with an expression+-- or an 'External' tag.+data Rule+ = Rule [VarIndex] Expr+ | External String+ deriving (Eq, Read, Show)++-- |Data type for representing expressions.+--+-- Remarks:+--+-- 1.if-then-else expressions are represented as function calls:+--+-- @(if e1 then e2 else e3)@+--+-- is represented as+--+-- @(Comb FuncCall ("Prelude","ifThenElse") [e1,e2,e3])@+--+-- 2.Higher order applications are represented as calls to the (external)+-- function @apply@. For instance, the rule+--+-- @app f x = f x@+--+-- is represented as+--+-- @(Rule [0,1] (Comb FuncCall ("Prelude","apply") [Var 0, Var 1]))@+--+-- 3.A conditional rule is represented as a call to an external function+-- @cond@ where the first argument is the condition (a constraint).+--+-- For instance, the rule+--+-- @equal2 x | x=:=2 = success@+--+-- is represented as+--+-- @+-- (Rule [0]+-- (Comb FuncCall ("Prelude","cond")+-- [Comb FuncCall ("Prelude","=:=") [Var 0, Lit (Intc 2)],+-- Comb FuncCall ("Prelude","success") []]))+-- @+--+-- 4.Functions with evaluation annotation @choice@ are represented+-- by a rule whose right-hand side is enclosed in a call to the+-- external function @Prelude.commit@.+-- Furthermore, all rules of the original definition must be+-- represented by conditional expressions (i.e., (cond [c,e]))+-- after pattern matching.+--+-- Example:+--+-- @+-- m eval choice+-- m [] y = y+-- m x [] = x+-- @+--+-- is translated into (note that the conditional branches can be also+-- wrapped with Free declarations in general):+--+-- @+-- Rule [0,1]+-- (Comb FuncCall ("Prelude","commit")+-- [Or (Case Rigid (Var 0)+-- [(Pattern ("Prelude","[]") []+-- (Comb FuncCall ("Prelude","cond")+-- [Comb FuncCall ("Prelude","success") [],+-- Var 1]))] )+-- (Case Rigid (Var 1)+-- [(Pattern ("Prelude","[]") []+-- (Comb FuncCall ("Prelude","cond")+-- [Comb FuncCall ("Prelude","success") [],+-- Var 0]))] )])+-- @+--+-- Operational meaning of @(Prelude.commit e)@:+-- evaluate @e@ with local search spaces and commit to the first+-- @(Comb FuncCall ("Prelude","cond") [c,ge])@ in @e@ whose constraint @c@+-- is satisfied+data Expr+ -- |Variable, represented by unique index+ = Var VarIndex+ -- |Literal (Integer/Float/Char constant)+ | Lit Literal+ -- |Application @(f e1 ... en)@ of function/constructor @f@+ -- with @n <= arity f@+ | Comb CombType QName [Expr]+ -- |Introduction of free local variables for an expression+ | Free [VarIndex] Expr+ -- |Local let-declarations+ | Let [(VarIndex, Expr)] Expr+ -- |Disjunction of two expressions+ -- (resulting from overlapping left-hand sides)+ | Or Expr Expr+ -- |case expression+ | Case CaseType Expr [BranchExpr]+ -- |typed expression+ | Typed Expr TypeExpr+ deriving (Eq, Read, Show)++-- |Data type for representing literals.+--+-- A literal is either an integer, a float, or a character constant.+--+-- /Note:/ The constructor definition of 'Intc' differs from the original+-- PAKCS definition. It uses Haskell type 'Integer' instead of 'Int'+-- to provide an unlimited range of integer numbers. Furthermore,+-- float values are represented with Haskell type 'Double' instead of+-- 'Float'.+data Literal+ = Intc Integer+ | Floatc Double+ | Charc Char+ deriving (Eq, Read, Show)++-- |Data type for classifying combinations+-- (i.e., a function/constructor applied to some arguments).+data CombType+ -- |a call to a function where all arguments are provided+ = FuncCall+ -- |a call with a constructor at the top, all arguments are provided+ | ConsCall+ -- |a partial call to a function (i.e., not all arguments are provided)+ -- where the parameter is the number of missing arguments+ | FuncPartCall Int+ -- |a partial call to a constructor along with number of missing arguments+ | ConsPartCall Int+ deriving (Eq, Read, Show)++-- |Classification of case expressions, either flexible or rigid.+data CaseType+ = Rigid+ | Flex+ deriving (Eq, Read, Show)++-- |Branches in a case expression.+--+-- Branches @(m.c x1...xn) -> e@ in case expressions are represented as+--+-- @(Branch (Pattern (m,c) [i1,...,in]) e)@+--+-- where each @ij@ is the index of the pattern variable @xj@, or as+--+-- @(Branch (LPattern (Intc i)) e)@+--+-- for integers as branch patterns (similarly for other literals+-- like float or character constants).+data BranchExpr = Branch Pattern Expr+ deriving (Eq, Read, Show)++-- |Patterns in case expressions.+data Pattern+ = Pattern QName [VarIndex]+ | LPattern Literal+ deriving (Eq, Read, Show)++instance Binary Visibility where+ put Public = putWord8 0+ put Private = putWord8 1++ get = do+ x <- getWord8+ case x of+ 0 -> return Public+ 1 -> return Private+ _ -> fail "Invalid encoding for Visibility"++instance Binary Prog where+ put (Prog mid im tys fus ops) =+ put mid >> put im >> put tys >> put fus >> put ops+ get = Prog <$> get <*> get <*> get <*> get <*> get++instance Binary TypeDecl where+ put (Type qid vis vs cs) =+ putWord8 0 >> put qid >> put vis >> put vs >> put cs+ put (TypeSyn qid vis vs ty) =+ putWord8 1 >> put qid >> put vis >> put vs >> put ty+ put (TypeNew qid vis vs c ) =+ putWord8 2 >> put qid >> put vis >> put vs >> put c++ get = do+ x <- getWord8+ case x of+ 0 -> liftM4 Type get get get get+ 1 -> liftM4 TypeSyn get get get get+ 2 -> liftM4 TypeNew get get get get+ _ -> fail "Invalid encoding for TypeDecl"++instance Binary ConsDecl where+ put (Cons qid arity vis tys) = put qid >> put arity >> put vis >> put tys+ get = Cons <$> get <*> get <*> get <*> get++instance Binary NewConsDecl where+ put (NewCons qid vis ty) = put qid >> put vis >> put ty+ get = NewCons <$> get <*> get <*> get++instance Binary TypeExpr where+ put (TVar tv) =+ putWord8 0 >> put tv+ put (FuncType ty1 ty2) =+ putWord8 1 >> put ty1 >> put ty2+ put (TCons qid tys) =+ putWord8 2 >> put qid >> put tys+ put (ForallType vs ty) =+ putWord8 3 >> put vs >> put ty++ get = do+ x <- getWord8+ case x of+ 0 -> fmap TVar get+ 1 -> liftM2 FuncType get get+ 2 -> liftM2 TCons get get+ 3 -> liftM2 ForallType get get+ _ -> fail "Invalid encoding for TypeExpr"++instance Binary Kind where+ put KStar = putWord8 0+ put (KArrow k1 k2) = putWord8 1 >> put k1 >> put k2+ get = do+ x <- getWord8+ case x of+ 0 -> return KStar+ 1 -> liftM2 KArrow get get+ _ -> fail "Invalid encoding for Kind"++instance Binary OpDecl where+ put (Op qid fix pr) = put qid >> put fix >> put pr+ get = liftM3 Op get get get++instance Binary Fixity where+ put InfixOp = putWord8 0+ put InfixlOp = putWord8 1+ put InfixrOp = putWord8 2++ get = do+ x <- getWord8+ case x of+ 0 -> return InfixOp+ 1 -> return InfixlOp+ 2 -> return InfixrOp+ _ -> fail "Invalid encoding for Fixity"++instance Binary FuncDecl where+ put (Func qid arity vis ty r) =+ put qid >> put arity >> put vis >> put ty >> put r+ get = Func <$> get <*> get <*> get <*> get <*> get++instance Binary Rule where+ put (Rule alts e) = putWord8 0 >> put alts >> put e+ put (External n ) = putWord8 1 >> put n++ get = do+ x <- getWord8+ case x of+ 0 -> liftM2 Rule get get+ 1 -> fmap External get+ _ -> fail "Invalid encoding for TRule"++instance Binary Expr where+ put (Var v) = putWord8 0 >> put v+ put (Lit l) = putWord8 1 >> put l+ put (Comb cty qid es) =+ putWord8 2 >> put cty >> put qid >> put es+ put (Let bs e) = putWord8 3 >> put bs >> put e+ put (Free vs e) = putWord8 4 >> put vs >> put e+ put (Or e1 e2) = putWord8 5 >> put e1 >> put e2+ put (Case cty ty as) = putWord8 6 >> put cty >> put ty >> put as+ put (Typed e ty) = putWord8 7 >> put e >> put ty++ get = do+ x <- getWord8+ case x of+ 0 -> fmap Var get+ 1 -> fmap Lit get+ 2 -> liftM3 Comb get get get+ 3 -> liftM2 Let get get+ 4 -> liftM2 Free get get+ 5 -> liftM2 Or get get+ 6 -> liftM3 Case get get get+ 7 -> liftM2 Typed get get+ _ -> fail "Invalid encoding for TExpr"++instance Binary BranchExpr where+ put (Branch p e) = put p >> put e+ get = liftM2 Branch get get++instance Binary Pattern where+ put (Pattern qid vs) = putWord8 0 >> put qid >> put vs+ put (LPattern l ) = putWord8 1 >> put l++ get = do+ x <- getWord8+ case x of+ 0 -> liftM2 Pattern get get+ 1 -> fmap LPattern get+ _ -> fail "Invalid encoding for TPattern"++instance Binary Literal where+ put (Intc i) = putWord8 0 >> put i+ put (Floatc f) = putWord8 1 >> put f+ put (Charc c) = putWord8 2 >> put c++ get = do+ x <- getWord8+ case x of+ 0 -> fmap Intc get+ 1 -> fmap Floatc get+ 2 -> fmap Charc get+ _ -> fail "Invalid encoding for Literal"++instance Binary CombType where+ put FuncCall = putWord8 0+ put ConsCall = putWord8 1+ put (FuncPartCall i) = putWord8 2 >> put i+ put (ConsPartCall i) = putWord8 3 >> put i++ get = do+ x <- getWord8+ case x of+ 0 -> return FuncCall+ 1 -> return ConsCall+ 2 -> fmap FuncPartCall get+ 3 -> fmap ConsPartCall get+ _ -> fail "Invalid encoding for CombType"++instance Binary CaseType where+ put Rigid = putWord8 0+ put Flex = putWord8 1++ get = do+ x <- getWord8+ case x of+ 0 -> return Rigid+ 1 -> return Flex+ _ -> fail "Invalid encoding for CaseType"
+ src/Curry/FlatCurry/Typeable.hs view
@@ -0,0 +1,22 @@+{- |+ Module : $Header$+ Description : Typeclass of Typeable entities+ Copyright : (c) 2018 Kai-Oliver Prott+ License : BSD-3-clause++ Maintainer : fte@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module defines a Typeclass for easy access to the type of entites+-}++module Curry.FlatCurry.Typeable (Typeable(..)) where++import Curry.FlatCurry.Type (TypeExpr)++class Typeable a where+ typeOf :: a -> TypeExpr++instance Typeable TypeExpr where+ typeOf = id
+ src/Curry/FlatCurry/Typed/Goodies.hs view
@@ -0,0 +1,666 @@+{- |+ Module : $Header$+ Description : Utility functions for working with TypedFlatCurry.+ Copyright : (c) 2016 - 2017 Finn Teegen+ 2018 Kai-Oliver Prott+ License : BSD-3-clause++ Maintainer : fte@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This library provides selector functions, test and update operations+ as well as some useful auxiliary functions for TypedFlatCurry data terms.+ Most of the provided functions are based on general transformation+ functions that replace constructors with user-defined+ functions. For recursive datatypes the transformations are defined+ inductively over the term structure. This is quite usual for+ transformations on TypedFlatCurry terms,+ so the provided functions can be used to implement specific transformations+ without having to explicitly state the recursion. Essentially, the tedious+ part of such transformations - descend in fairly complex term structures -+ is abstracted away, which hopefully makes the code more clear and brief.+-}++module Curry.FlatCurry.Typed.Goodies+ ( module Curry.FlatCurry.Typed.Goodies+ , module Curry.FlatCurry.Goodies+ ) where++import Curry.FlatCurry.Goodies ( Update+ , trType, typeName, typeVisibility, typeParams+ , typeConsDecls, typeSyn, isTypeSyn+ , isDataTypeDecl, isExternalType, isPublicType+ , updType, updTypeName, updTypeVisibility+ , updTypeParams, updTypeConsDecls, updTypeSynonym+ , updQNamesInType+ , trCons, consName, consArity, consVisibility+ , isPublicCons, consArgs, updCons, updConsName+ , updConsArity, updConsVisibility, updConsArgs+ , updQNamesInConsDecl+ , trNewCons, newConsName, newConsVisibility+ , isPublicNewCons, newConsArg+ , updNewCons, updNewConsName+ , updNewConsVisibility, updNewConsArg+ , updQNamesInNewConsDecl+ , tVarIndex, domain, range, tConsName, tConsArgs+ , trTypeExpr, isTVar, isTCons, isFuncType+ , updTVars, updTCons, updFuncTypes, argTypes+ , typeArity, resultType, allVarsInTypeExpr+ , allTypeCons, rnmAllVarsInTypeExpr+ , updQNamesInTypeExpr+ , trOp, opName, opFixity, opPrecedence, updOp+ , updOpName, updOpFixity, updOpPrecedence+ , trCombType, isCombTypeFuncCall+ , isCombTypeFuncPartCall, isCombTypeConsCall+ , isCombTypeConsPartCall+ , isPublic+ )++import Curry.FlatCurry.Typed.Type++-- TProg ----------------------------------------------------------------------++-- |transform program+trTProg :: (String -> [String] -> [TypeDecl] -> [TFuncDecl] -> [OpDecl] -> b)+ -> TProg -> b+trTProg prog (TProg name imps types funcs ops) = prog name imps types funcs ops++-- Selectors++-- |get name from program+tProgName :: TProg -> String+tProgName = trTProg (\name _ _ _ _ -> name)++-- |get imports from program+tProgImports :: TProg -> [String]+tProgImports = trTProg (\_ imps _ _ _ -> imps)++-- |get type declarations from program+tProgTypes :: TProg -> [TypeDecl]+tProgTypes = trTProg (\_ _ types _ _ -> types)++-- |get functions from program+tProgTFuncs :: TProg -> [TFuncDecl]+tProgTFuncs = trTProg (\_ _ _ funcs _ -> funcs)++-- |get infix operators from program+tProgOps :: TProg -> [OpDecl]+tProgOps = trTProg (\_ _ _ _ ops -> ops)++-- Update Operations++-- |update program+updTProg :: (String -> String) ->+ ([String] -> [String]) ->+ ([TypeDecl] -> [TypeDecl]) ->+ ([TFuncDecl] -> [TFuncDecl]) ->+ ([OpDecl] -> [OpDecl]) -> TProg -> TProg+updTProg fn fi ft ff fo = trTProg prog+ where+ prog name imps types funcs ops+ = TProg (fn name) (fi imps) (ft types) (ff funcs) (fo ops)++-- |update name of program+updTProgName :: Update TProg String+updTProgName f = updTProg f id id id id++-- |update imports of program+updTProgImports :: Update TProg [String]+updTProgImports f = updTProg id f id id id++-- |update type declarations of program+updTProgTypes :: Update TProg [TypeDecl]+updTProgTypes f = updTProg id id f id id++-- |update functions of program+updTProgTFuncs :: Update TProg [TFuncDecl]+updTProgTFuncs f = updTProg id id id f id++-- |update infix operators of program+updTProgOps :: Update TProg [OpDecl]+updTProgOps = updTProg id id id id++-- Auxiliary Functions++-- |get all program variables (also from patterns)+allVarsInTProg :: TProg -> [(VarIndex, TypeExpr)]+allVarsInTProg = concatMap allVarsInTFunc . tProgTFuncs++-- |lift transformation on expressions to program+updTProgTExps :: Update TProg TExpr+updTProgTExps = updTProgTFuncs . map . updTFuncBody++-- |rename programs variables+rnmAllVarsInTProg :: Update TProg VarIndex+rnmAllVarsInTProg = updTProgTFuncs . map . rnmAllVarsInTFunc++-- |update all qualified names in program+updQNamesInTProg :: Update TProg QName+updQNamesInTProg f = updTProg id id+ (map (updQNamesInType f)) (map (updQNamesInTFunc f)) (map (updOpName f))++-- |rename program (update name of and all qualified names in program)+rnmTProg :: String -> TProg -> TProg+rnmTProg name p = updTProgName (const name) (updQNamesInTProg rnm p)+ where+ rnm (m, n) | m == tProgName p = (name, n)+ | otherwise = (m, n)++-- TFuncDecl ------------------------------------------------------------------++-- |transform function+trTFunc :: (QName -> Int -> Visibility -> TypeExpr -> TRule -> b) -> TFuncDecl -> b+trTFunc func (TFunc name arity vis t rule) = func name arity vis t rule++-- Selectors++-- |get name of function+tFuncName :: TFuncDecl -> QName+tFuncName = trTFunc (\name _ _ _ _ -> name)++-- |get arity of function+tFuncArity :: TFuncDecl -> Int+tFuncArity = trTFunc (\_ arity _ _ _ -> arity)++-- |get visibility of function+tFuncVisibility :: TFuncDecl -> Visibility+tFuncVisibility = trTFunc (\_ _ vis _ _ -> vis)++-- |get type of function+tFuncType :: TFuncDecl -> TypeExpr+tFuncType = trTFunc (\_ _ _ t _ -> t)++-- |get rule of function+tFuncTRule :: TFuncDecl -> TRule+tFuncTRule = trTFunc (\_ _ _ _ rule -> rule)++-- Update Operations++-- |update function+updTFunc :: (QName -> QName) ->+ (Int -> Int) ->+ (Visibility -> Visibility) ->+ (TypeExpr -> TypeExpr) ->+ (TRule -> TRule) -> TFuncDecl -> TFuncDecl+updTFunc fn fa fv ft fr = trTFunc func+ where+ func name arity vis t rule+ = TFunc (fn name) (fa arity) (fv vis) (ft t) (fr rule)++-- |update name of function+updTFuncName :: Update TFuncDecl QName+updTFuncName f = updTFunc f id id id id++-- |update arity of function+updTFuncArity :: Update TFuncDecl Int+updTFuncArity f = updTFunc id f id id id++-- |update visibility of function+updTFuncVisibility :: Update TFuncDecl Visibility+updTFuncVisibility f = updTFunc id id f id id++-- |update type of function+updFuncType :: Update TFuncDecl TypeExpr+updFuncType f = updTFunc id id id f id++-- |update rule of function+updTFuncTRule :: Update TFuncDecl TRule+updTFuncTRule = updTFunc id id id id++-- Auxiliary Functions++-- |is function public?+isPublicTFunc :: TFuncDecl -> Bool+isPublicTFunc = isPublic . tFuncVisibility++-- |is function externally defined?+isExternal :: TFuncDecl -> Bool+isExternal = isTRuleExternal . tFuncTRule++-- |get variable names in a function declaration+allVarsInTFunc :: TFuncDecl -> [(VarIndex, TypeExpr)]+allVarsInTFunc = allVarsInTRule . tFuncTRule++-- |get arguments of function, if not externally defined+tFuncArgs :: TFuncDecl -> [(VarIndex, TypeExpr)]+tFuncArgs = tRuleArgs . tFuncTRule++-- |get body of function, if not externally defined+tFuncBody :: TFuncDecl -> TExpr+tFuncBody = tRuleBody . tFuncTRule++-- |get the right-hand-sides of a 'FuncDecl'+tFuncRHS :: TFuncDecl -> [TExpr]+tFuncRHS f | not (isExternal f) = orCase (tFuncBody f)+ | otherwise = []+ where+ orCase e+ | isTOr e = concatMap orCase (orExps e)+ | isTCase e = concatMap (orCase . tBranchTExpr) (caseBranches e)+ | otherwise = [e]++-- |rename all variables in function+rnmAllVarsInTFunc :: Update TFuncDecl VarIndex+rnmAllVarsInTFunc = updTFunc id id id id . rnmAllVarsInTRule++-- |update all qualified names in function+updQNamesInTFunc :: Update TFuncDecl QName+updQNamesInTFunc f = updTFunc f id id (updQNamesInTypeExpr f) (updQNamesInTRule f)++-- |update arguments of function, if not externally defined+updTFuncArgs :: Update TFuncDecl [(VarIndex, TypeExpr)]+updTFuncArgs = updTFuncTRule . updTRuleArgs++-- |update body of function, if not externally defined+updTFuncBody :: Update TFuncDecl TExpr+updTFuncBody = updTFuncTRule . updTRuleBody++-- TRule ----------------------------------------------------------------------++-- |transform rule+trTRule :: ([(VarIndex, TypeExpr)] -> TExpr -> b) -> (TypeExpr -> String -> b) -> TRule -> b+trTRule rule _ (TRule args e) = rule args e+trTRule _ ext (TExternal ty s) = ext ty s++-- Selectors++-- |get rules arguments if it's not external+tRuleArgs :: TRule -> [(VarIndex, TypeExpr)]+tRuleArgs = trTRule const undefined++-- |get rules body if it's not external+tRuleBody :: TRule -> TExpr+tRuleBody = trTRule (\_ e -> e) undefined++-- |get rules external declaration+tRuleExtDecl :: TRule -> String+tRuleExtDecl = trTRule undefined (\_ s -> s)++-- Test Operations++-- |is rule external?+isTRuleExternal :: TRule -> Bool+isTRuleExternal = trTRule (\_ _ -> False) (\_ _ -> True)++-- Update Operations++-- |update rule+updTRule :: (TypeExpr -> TypeExpr) ->+ ([(VarIndex, TypeExpr)] -> [(VarIndex, TypeExpr)]) ->+ (TExpr -> TExpr) ->+ (String -> String) -> TRule -> TRule+updTRule fannot fa fe fs = trTRule rule ext+ where+ rule args e = TRule (fa args) (fe e)+ ext ty s = TExternal (fannot ty) (fs s)++-- |update rules TypeExpr+updTRuleType :: Update TRule TypeExpr+updTRuleType f = updTRule f id id id++-- |update rules arguments+updTRuleArgs :: Update TRule [(VarIndex, TypeExpr)]+updTRuleArgs f = updTRule id f id id++-- |update rules body+updTRuleBody :: Update TRule TExpr+updTRuleBody f = updTRule id id f id++-- |update rules external declaration+updTRuleExtDecl :: Update TRule String+updTRuleExtDecl = updTRule id id id++-- Auxiliary Functions++-- |get variable names in a functions rule+allVarsInTRule :: TRule -> [(VarIndex, TypeExpr)]+allVarsInTRule = trTRule (\args body -> args ++ allVars body) (\_ _ -> [])++-- |rename all variables in rule+rnmAllVarsInTRule :: Update TRule VarIndex+rnmAllVarsInTRule f = updTRule id (map (\(a, b) -> (f a, b))) (rnmAllVars f) id++-- |update all qualified names in rule+updQNamesInTRule :: Update TRule QName+updQNamesInTRule = updTRuleBody . updQNames++-- TExpr ----------------------------------------------------------------------++-- Selectors++-- |get internal number of variable+varNr :: TExpr -> VarIndex+varNr (TVarE _ n) = n+varNr _ = error "Curry.FlatCurry.Typed.Goodies.varNr: no variable"++-- |get literal if expression is literal expression+literal :: TExpr -> Literal+literal (TLit _ l) = l+literal _ = error "Curry.FlatCurry.Typed.Goodies.literal: no literal"++-- |get combination type of a combined expression+combType :: TExpr -> CombType+combType (TComb _ ct _ _) = ct+combType _ = error $ "Curry.FlatCurry.Typed.Goodies.combType: " +++ "no combined expression"++-- |get name of a combined expression+combName :: TExpr -> QName+combName (TComb _ _ name _) = name+combName _ = error $ "Curry.FlatCurry.Typed.Goodies.combName: " +++ "no combined expression"++-- |get arguments of a combined expression+combArgs :: TExpr -> [TExpr]+combArgs (TComb _ _ _ args) = args+combArgs _ = error $ "Curry.FlatCurry.Typed.Goodies.combArgs: " +++ "no combined expression"++-- |get number of missing arguments if expression is combined+missingCombArgs :: TExpr -> Int+missingCombArgs = missingArgs . combType+ where+ missingArgs :: CombType -> Int+ missingArgs = trCombType 0 id 0 id++-- |get indices of variables in let declaration+letBinds :: TExpr -> [((VarIndex, TypeExpr), TExpr)]+letBinds (TLet vs _) = vs+letBinds _ = error $ "Curry.FlatCurry.Typed.Goodies.letBinds: " +++ "no let expression"++-- |get body of let declaration+letBody :: TExpr -> TExpr+letBody (TLet _ e) = e+letBody _ = error $ "Curry.FlatCurry.Typed.Goodies.letBody: " +++ "no let expression"++-- |get variable indices from declaration of free variables+freeVars :: TExpr -> [(VarIndex, TypeExpr)]+freeVars (TFree vs _) = vs+freeVars _ = error $ "Curry.FlatCurry.Typed.Goodies.freeVars: " +++ "no declaration of free variables"++-- |get expression from declaration of free variables+freeExpr :: TExpr -> TExpr+freeExpr (TFree _ e) = e+freeExpr _ = error $ "Curry.FlatCurry.Typed.Goodies.freeExpr: " +++ "no declaration of free variables"++-- |get expressions from or-expression+orExps :: TExpr -> [TExpr]+orExps (TOr e1 e2) = [e1, e2]+orExps _ = error $ "Curry.FlatCurry.Typed.Goodies.orExps: " +++ "no or expression"++-- |get case-type of case expression+caseType :: TExpr -> CaseType+caseType (TCase ct _ _) = ct+caseType _ = error $ "Curry.FlatCurry.Typed.Goodies.caseType: " +++ "no case expression"++-- |get scrutinee of case expression+caseExpr :: TExpr -> TExpr+caseExpr (TCase _ e _) = e+caseExpr _ = error $ "Curry.FlatCurry.Typed.Goodies.caseExpr: " +++ "no case expression"+++-- |get branch expressions from case expression+caseBranches :: TExpr -> [TBranchExpr]+caseBranches (TCase _ _ bs) = bs+caseBranches _ = error "Curry.FlatCurry.Typed.Goodies.caseBranches: no case expression"++-- Test Operations++-- |is expression a variable?+isTVarE :: TExpr -> Bool+isTVarE e = case e of+ TVarE _ _ -> True+ _ -> False++-- |is expression a literal expression?+isTLit :: TExpr -> Bool+isTLit e = case e of+ TLit _ _ -> True+ _ -> False++-- |is expression combined?+isTComb :: TExpr -> Bool+isTComb e = case e of+ TComb _ _ _ _ -> True+ _ -> False++-- |is expression a let expression?+isTLet :: TExpr -> Bool+isTLet e = case e of+ TLet _ _ -> True+ _ -> False++-- |is expression a declaration of free variables?+isTFree :: TExpr -> Bool+isTFree e = case e of+ TFree _ _ -> True+ _ -> False++-- |is expression an or-expression?+isTOr :: TExpr -> Bool+isTOr e = case e of+ TOr _ _ -> True+ _ -> False++-- |is expression a case expression?+isTCase :: TExpr -> Bool+isTCase e = case e of+ TCase _ _ _ -> True+ _ -> False++-- |transform expression+trTExpr :: (TypeExpr -> VarIndex -> b)+ -> (TypeExpr -> Literal -> b)+ -> (TypeExpr -> CombType -> QName -> [b] -> b)+ -> ([((VarIndex, TypeExpr), b)] -> b -> b)+ -> ([(VarIndex, TypeExpr)] -> b -> b)+ -> (b -> b -> b)+ -> (CaseType -> b -> [c] -> b)+ -> (TPattern -> b -> c)+ -> (b -> TypeExpr -> b)+ -> TExpr+ -> b+trTExpr var lit comb lt fr oR cas branch typed expr = case expr of+ TVarE ty n -> var ty n+ TLit ty l -> lit ty l+ TComb ty ct name args -> comb ty ct name (map f args)+ TLet bs e -> lt (map (\(v, x) -> (v, f x)) bs) (f e)+ TFree vs e -> fr vs (f e)+ TOr e1 e2 -> oR (f e1) (f e2)+ TCase ct e bs -> cas ct (f e) (map (\ (TBranch p e') -> branch p (f e')) bs)+ TTyped e ty -> typed (f e) ty+ where+ f = trTExpr var lit comb lt fr oR cas branch typed++-- |update all variables in given expression+updVars :: (TypeExpr -> VarIndex -> TExpr) -> TExpr -> TExpr+updVars var = trTExpr var TLit TComb TLet TFree TOr TCase TBranch TTyped++-- |update all literals in given expression+updLiterals :: (TypeExpr -> Literal -> TExpr) -> TExpr -> TExpr+updLiterals lit = trTExpr TVarE lit TComb TLet TFree TOr TCase TBranch TTyped++-- |update all combined expressions in given expression+updCombs :: (TypeExpr -> CombType -> QName -> [TExpr] -> TExpr) -> TExpr -> TExpr+updCombs comb = trTExpr TVarE TLit comb TLet TFree TOr TCase TBranch TTyped++-- |update all let expressions in given expression+updLets :: ([((VarIndex, TypeExpr), TExpr)] -> TExpr -> TExpr) -> TExpr -> TExpr+updLets lt = trTExpr TVarE TLit TComb lt TFree TOr TCase TBranch TTyped++-- |update all free declarations in given expression+updFrees :: ([(VarIndex, TypeExpr)] -> TExpr -> TExpr) -> TExpr -> TExpr+updFrees fr = trTExpr TVarE TLit TComb TLet fr TOr TCase TBranch TTyped++-- |update all or expressions in given expression+updOrs :: (TExpr -> TExpr -> TExpr) -> TExpr -> TExpr+updOrs oR = trTExpr TVarE TLit TComb TLet TFree oR TCase TBranch TTyped++-- |update all case expressions in given expression+updCases :: (CaseType -> TExpr -> [TBranchExpr] -> TExpr) -> TExpr -> TExpr+updCases cas = trTExpr TVarE TLit TComb TLet TFree TOr cas TBranch TTyped++-- |update all case branches in given expression+updBranches :: (TPattern -> TExpr -> TBranchExpr) -> TExpr -> TExpr+updBranches branch = trTExpr TVarE TLit TComb TLet TFree TOr TCase branch TTyped++-- |update all typed expressions in given expression+updTypeds :: (TExpr -> TypeExpr -> TExpr) -> TExpr -> TExpr+updTypeds = trTExpr TVarE TLit TComb TLet TFree TOr TCase TBranch++-- Auxiliary Functions++-- |is expression a call of a function where all arguments are provided?+isFuncCall :: TExpr -> Bool+isFuncCall e = isTComb e && isCombTypeFuncCall (combType e)++-- |is expression a partial function call?+isFuncPartCall :: TExpr -> Bool+isFuncPartCall e = isTComb e && isCombTypeFuncPartCall (combType e)++-- |is expression a call of a constructor?+isConsCall :: TExpr -> Bool+isConsCall e = isTComb e && isCombTypeConsCall (combType e)++-- |is expression a partial constructor call?+isConsPartCall :: TExpr -> Bool+isConsPartCall e = isTComb e && isCombTypeConsPartCall (combType e)++-- |is expression fully evaluated?+isGround :: TExpr -> Bool+isGround e+ = case e of+ TComb _ ConsCall _ args -> all isGround args+ _ -> isTLit e++-- |get all variables (also pattern variables) in expression+allVars :: TExpr -> [(VarIndex, TypeExpr)]+allVars e = trTExpr var lit comb lt fr (.) cas branch typ e []+ where+ var a v = (:) (v, a)+ lit = const (const id)+ comb _ _ _ = foldr (.) id+ lt bs e' = e' . foldr (.) id (map (\(n,ns) -> (n:) . ns) bs)+ fr vs e' = (vs++) . e'+ cas _ e' bs = e' . foldr (.) id bs+ branch pat e' = (args pat ++) . e'+ typ = const+ args pat | isConsPattern pat = tPatArgs pat+ | otherwise = []++-- |rename all variables (also in patterns) in expression+rnmAllVars :: Update TExpr VarIndex+rnmAllVars f = trTExpr var TLit TComb lt fr TOr TCase branch TTyped+ where+ var a = TVarE a . f+ lt = TLet . map (\((n, b), e) -> ((f n, b), e))+ fr = TFree . map (\(b, c) -> (f b, c))+ branch = TBranch . updTPatArgs (map (\(a, b) -> (f a, b)))++-- |update all qualified names in expression+updQNames :: Update TExpr QName+updQNames f = trTExpr TVarE TLit comb TLet TFree TOr TCase branch TTyped+ where+ comb ty ct name args = TComb ty ct (f name) args+ branch = TBranch . updTPatCons f++-- TBranchExpr ----------------------------------------------------------------++-- |transform branch expression+trTBranch :: (TPattern -> TExpr -> b) -> TBranchExpr -> b+trTBranch branch (TBranch pat e) = branch pat e++-- Selectors++-- |get pattern from branch expression+tBranchTPattern :: TBranchExpr -> TPattern+tBranchTPattern = trTBranch const++-- |get expression from branch expression+tBranchTExpr :: TBranchExpr -> TExpr+tBranchTExpr = trTBranch (\_ e -> e)++-- Update Operations++-- |update branch expression+updTBranch :: (TPattern -> TPattern) -> (TExpr -> TExpr) -> TBranchExpr -> TBranchExpr+updTBranch fp fe = trTBranch branch+ where+ branch pat e = TBranch (fp pat) (fe e)++-- |update pattern of branch expression+updTBranchTPattern :: Update TBranchExpr TPattern+updTBranchTPattern f = updTBranch f id++-- |update expression of branch expression+updTBranchTExpr :: Update TBranchExpr TExpr+updTBranchTExpr = updTBranch id++-- TPattern -------------------------------------------------------------------++-- |transform pattern+trTPattern :: (TypeExpr -> QName -> [(VarIndex, TypeExpr)] -> b) -> (TypeExpr -> Literal -> b) -> TPattern -> b+trTPattern pat _ (TPattern ty name args) = pat ty name args+trTPattern _ lpat (TLPattern a l) = lpat a l++-- Selectors++-- |get name from constructor pattern+tPatCons :: TPattern -> QName+tPatCons = trTPattern (\_ name _ -> name) undefined++-- |get arguments from constructor pattern+tPatArgs :: TPattern -> [(VarIndex, TypeExpr)]+tPatArgs = trTPattern (\_ _ args -> args) undefined++-- |get literal from literal pattern+tPatLiteral :: TPattern -> Literal+tPatLiteral = trTPattern undefined (const id)++-- Test Operations++-- |is pattern a constructor pattern?+isConsPattern :: TPattern -> Bool+isConsPattern = trTPattern (\_ _ _ -> True) (\_ _ -> False)++-- Update Operations++-- |update pattern+updTPattern :: (TypeExpr -> TypeExpr) ->+ (QName -> QName) ->+ ([(VarIndex, TypeExpr)] -> [(VarIndex, TypeExpr)]) ->+ (Literal -> Literal) -> TPattern -> TPattern+updTPattern fannot fn fa fl = trTPattern pattern lpattern+ where+ pattern ty name args = TPattern (fannot ty) (fn name) (fa args)+ lpattern ty l = TLPattern (fannot ty) (fl l)++-- |update TypeExpr of pattern+updTPatType :: (TypeExpr -> TypeExpr) -> TPattern -> TPattern+updTPatType f = updTPattern f id id id++-- |update constructors name of pattern+updTPatCons :: (QName -> QName) -> TPattern -> TPattern+updTPatCons f = updTPattern id f id id++-- |update arguments of constructor pattern+updTPatArgs :: ([(VarIndex, TypeExpr)] -> [(VarIndex, TypeExpr)]) -> TPattern -> TPattern+updTPatArgs f = updTPattern id id f id++-- |update literal of pattern+updTPatLiteral :: (Literal -> Literal) -> TPattern -> TPattern+updTPatLiteral = updTPattern id id id++-- Auxiliary Functions++-- |build expression from pattern+tPatExpr :: TPattern -> TExpr+tPatExpr = trTPattern (\ty name -> TComb ty ConsCall name . map (uncurry (flip TVarE))) TLit
+ src/Curry/FlatCurry/Typed/Type.hs view
@@ -0,0 +1,146 @@+{- |+ Module : $Header$+ Description : Representation of annotated FlatCurry.+ Copyright : (c) 2016 - 2017 Finn Teegen+ 2018 Kai-Oliver Prott+ License : BSD-3-clause++ Maintainer : fte@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This library contains a version of FlatCurry's abstract syntax tree+ modified with type information++ For more information about the abstract syntax tree of `FlatCurry`,+ see the documentation of the respective module.+-}++module Curry.FlatCurry.Typed.Type+ ( module Curry.FlatCurry.Typed.Type+ , module Curry.FlatCurry.Typeable+ , module Curry.FlatCurry.Type+ ) where++import Data.Binary+import Control.Monad++import Curry.FlatCurry.Typeable+import Curry.FlatCurry.Type ( QName, VarIndex, Visibility (..), TVarIndex+ , TypeDecl (..), Kind (..), OpDecl (..), Fixity (..)+ , TypeExpr (..), ConsDecl (..), NewConsDecl (..)+ , Literal (..), CombType (..), CaseType (..)+ )++data TProg = TProg String [String] [TypeDecl] [TFuncDecl] [OpDecl]+ deriving (Eq, Read, Show)++data TFuncDecl = TFunc QName Int Visibility TypeExpr TRule+ deriving (Eq, Read, Show)++data TRule+ = TRule [(VarIndex, TypeExpr)] TExpr+ | TExternal TypeExpr String+ deriving (Eq, Read, Show)++data TExpr+ = TVarE TypeExpr VarIndex -- otherwise name clash with TypeExpr's TVar+ | TLit TypeExpr Literal+ | TComb TypeExpr CombType QName [TExpr]+ | TLet [((VarIndex, TypeExpr), TExpr)] TExpr+ | TFree [(VarIndex, TypeExpr)] TExpr+ | TOr TExpr TExpr+ | TCase CaseType TExpr [TBranchExpr]+ | TTyped TExpr TypeExpr+ deriving (Eq, Read, Show)++data TBranchExpr = TBranch TPattern TExpr+ deriving (Eq, Read, Show)++data TPattern+ = TPattern TypeExpr QName [(VarIndex, TypeExpr)]+ | TLPattern TypeExpr Literal+ deriving (Eq, Read, Show)++instance Typeable TRule where+ typeOf (TRule args e) = foldr (FuncType . snd) (typeOf e) args+ typeOf (TExternal ty _) = ty++instance Typeable TExpr where+ typeOf (TVarE ty _) = ty+ typeOf (TLit ty _) = ty+ typeOf (TComb ty _ _ _) = ty+ typeOf (TLet _ e) = typeOf e+ typeOf (TFree _ e) = typeOf e+ typeOf (TOr e _) = typeOf e+ typeOf (TCase _ _ (e:_)) = typeOf e+ typeOf (TTyped _ ty) = ty+ typeOf (TCase _ _ []) = error $ "Curry.FlatCurry.Typed.Type.typeOf: " +++ "empty list in case expression"++instance Typeable TPattern where+ typeOf (TPattern ty _ _) = ty+ typeOf (TLPattern ty _) = ty++instance Typeable TBranchExpr where+ typeOf (TBranch _ e) = typeOf e++instance Binary TProg where+ put (TProg mid im tys fus ops) =+ put mid >> put im >> put tys >> put fus >> put ops+ get = TProg <$> get <*> get <*> get <*> get <*> get++instance Binary TFuncDecl where+ put (TFunc qid arity vis ty r) =+ put qid >> put arity >> put vis >> put ty >> put r+ get = TFunc <$> get <*> get <*> get <*> get <*> get++instance Binary TRule where+ put (TRule alts e) = putWord8 0 >> put alts >> put e+ put (TExternal ty n ) = putWord8 1 >> put ty >> put n++ get = do+ x <- getWord8+ case x of+ 0 -> liftM2 TRule get get+ 1 -> liftM2 TExternal get get+ _ -> fail "Invalid encoding for TRule"++instance Binary TExpr where+ put (TVarE ty v) = putWord8 0 >> put ty >> put v+ put (TLit ty l) = putWord8 1 >> put ty >> put l+ put (TComb ty cty qid es) =+ putWord8 2 >> put ty >> put cty >> put qid >> put es+ put (TLet bs e) = putWord8 3 >> put bs >> put e+ put (TFree vs e) = putWord8 4 >> put vs >> put e+ put (TOr e1 e2) = putWord8 5 >> put e1 >> put e2+ put (TCase cty ty as) = putWord8 6 >> put cty >> put ty >> put as+ put (TTyped e ty) = putWord8 7 >> put e >> put ty++ get = do+ x <- getWord8+ case x of+ 0 -> liftM2 TVarE get get+ 1 -> liftM2 TLit get get+ 2 -> liftM4 TComb get get get get+ 3 -> liftM2 TLet get get+ 4 -> liftM2 TFree get get+ 5 -> liftM2 TOr get get+ 6 -> liftM3 TCase get get get+ 7 -> liftM2 TTyped get get+ _ -> fail "Invalid encoding for TExpr"++instance Binary TBranchExpr where+ put (TBranch p e) = put p >> put e+ get = liftM2 TBranch get get++instance Binary TPattern where+ put (TPattern ty qid vs) = putWord8 0 >> put ty >> put qid >> put vs+ put (TLPattern ty l ) = putWord8 1 >> put ty >> put l++ get = do+ x <- getWord8+ case x of+ 0 -> liftM3 TPattern get get get+ 1 -> liftM2 TLPattern get get+ _ -> fail "Invalid encoding for TPattern"
src/Curry/Syntax.hs view
@@ -1,43 +1,81 @@-{-- A simple interface for reading and manipulating Curry- source code.+{- |+ Module : $Header$+ Description : Interface for reading and manipulating Curry source code+ Copyright : (c) 2009 Holger Siegel+ 2011 - 2013 Björn Peemöller+ 2016 Finn Teegen+ 2016 Jan Tikovsky+ License : BSD-3-clause - (c) 2009, Holger Siegel.+ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable -}- module Curry.Syntax ( module Curry.Syntax.Type- , parseModule- , parseHeader+ , module Curry.Syntax.Utils+ , L.Token (..), L.Category (..), L.Attributes (..)+ , unlit, unlitLexSource, unlitParseHeader, unlitParsePragmas, unlitParseModule+ , lexSource, parseInterface, parseHeader, parsePragmas, parseModule, parseGoal+ , pPrint, pPrintPrec+ , showModule ) where -import Control.Monad-import Data.List+import Curry.Base.Monad (CYM)+import Curry.Base.Span (Span)+import Curry.Base.Pretty (pPrint, pPrintPrec)+import qualified Curry.Files.Unlit as U (unlit) -import Curry.Base.MessageMonad-import Curry.Syntax.Type-import qualified Curry.Syntax.Parser as CSP-import Curry.Syntax.Unlit+import qualified Curry.Syntax.Lexer as L+import qualified Curry.Syntax.Parser as P+import Curry.Syntax.Pretty ()+import Curry.Syntax.ShowModule (showModule)+import Curry.Syntax.Type+import Curry.Syntax.Utils --- | Parses a curry module.-parseModule :: Bool -> FilePath -> String -> MsgMonad Module-parseModule likeFlat fn =- unlitLiterate fn >=> CSP.parseSource likeFlat fn+-- |Unliterate a LiterateCurry file, identity on normal Curry file.+unlit :: FilePath -> String -> CYM String+unlit = U.unlit --- | Pares a curry header-parseHeader :: FilePath -> String -> MsgMonad Module-parseHeader fn =- unlitLiterate fn >=> CSP.parseHeader fn+-- |Unliterate and return the result of a lexical analysis of the source+-- program @src@.+-- The result is a list of tuples consisting of a 'Span' and a 'Token'.+unlitLexSource :: FilePath -> String -> CYM [(Span, L.Token)]+unlitLexSource fn src = U.unlit fn src >>= L.lexSource fn --- Literate source files use the extension ".lcurry"-unlitLiterate :: FilePath -> String -> MsgMonad String-unlitLiterate fn s- | isLiterateSource fn = unlit fn s- | otherwise = return s+-- |Unliterate and parse only pragmas of a Curry 'Module'+unlitParsePragmas :: FilePath -> String -> CYM (Module ())+unlitParsePragmas fn src = U.unlit fn src >>= P.parsePragmas fn --- | Compute if a file contains literate curry by its extension-isLiterateSource :: FilePath -> Bool-isLiterateSource fn = litExt `isSuffixOf` fn+-- |Unliterate and parse a Curry 'Module' header+unlitParseHeader :: FilePath -> String -> CYM (Module ())+unlitParseHeader fn src = U.unlit fn src >>= P.parseHeader fn -litExt = ".lcurry"+-- |Unliterate and parse a Curry 'Module'+unlitParseModule :: FilePath -> String -> CYM (Module ())+unlitParseModule fn src = U.unlit fn src >>= P.parseSource fn +-- |Return the result of a lexical analysis of the source program @src@.+-- The result is a list of tuples consisting of a 'Span' and a 'Token'.+lexSource :: FilePath -> String -> CYM [(Span, L.Token)]+lexSource = L.lexSource++-- |Parse a Curry 'Interface'+parseInterface :: FilePath -> String -> CYM Interface+parseInterface = P.parseInterface++-- |Parse only pragmas of a Curry 'Module'+parsePragmas :: FilePath -> String -> CYM (Module ())+parsePragmas = P.parsePragmas++-- |Parse a Curry 'Module' header+parseHeader :: FilePath -> String -> CYM (Module ())+parseHeader = P.parseHeader++-- |Parse a Curry 'Module'+parseModule :: FilePath -> String -> CYM (Module ())+parseModule = P.parseSource++-- |Parse a 'Goal', i.e. an expression with (optional) local declarations+parseGoal :: String -> CYM (Goal ())+parseGoal = P.parseGoal
+ src/Curry/Syntax/Extension.hs view
@@ -0,0 +1,120 @@+{- |+ Module : $Header$+ Description : Curry language extensions+ Copyright : (c) 2013 - 2014 Björn Peemöller+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module provides the data structures for Curry language extensions.+-}++module Curry.Syntax.Extension+ ( -- * Extensions+ Extension (..), KnownExtension (..), classifyExtension, kielExtensions+ -- * Tools+ , Tool (..), classifyTool+ ) where++import Data.Binary+import Data.Char (toUpper)+import Control.Monad++import Curry.Base.Ident (Ident (..))+import Curry.Base.Position+import Curry.Base.SpanInfo++-- |Specified language extensions, either known or unknown.+data Extension+ = KnownExtension SpanInfo KnownExtension -- ^ a known extension+ | UnknownExtension SpanInfo String -- ^ an unknown extension+ deriving (Eq, Read, Show)++instance HasSpanInfo Extension where+ getSpanInfo (KnownExtension spi _) = spi+ getSpanInfo (UnknownExtension spi _) = spi+ + setSpanInfo spi (KnownExtension _ ke) = KnownExtension spi ke+ setSpanInfo spi (UnknownExtension _ s) = UnknownExtension spi s++instance HasPosition Extension where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance Binary Extension where+ put (KnownExtension p e) = putWord8 0 >> put p >> put e+ put (UnknownExtension p e) = putWord8 1 >> put p >> put e++ get = do+ x <- getWord8+ case x of+ 0 -> liftM2 KnownExtension get get+ 1 -> liftM2 UnknownExtension get get+ _ -> fail "Invalid encoding for Extension"++instance Binary KnownExtension where+ put AnonFreeVars = putWord8 0+ put CPP = putWord8 1+ put FunctionalPatterns = putWord8 2+ put NegativeLiterals = putWord8 3+ put NoImplicitPrelude = putWord8 4++ get = do+ x <- getWord8+ case x of+ 0 -> return AnonFreeVars+ 1 -> return CPP+ 2 -> return FunctionalPatterns+ 3 -> return NegativeLiterals+ 4 -> return NoImplicitPrelude+ _ -> fail "Invalid encoding for KnownExtension"++-- |Known language extensions of Curry.+data KnownExtension+ = AnonFreeVars -- ^ anonymous free variables+ | CPP -- ^ C preprocessor+ | FunctionalPatterns -- ^ functional patterns+ | NegativeLiterals -- ^ negative literals+ | NoImplicitPrelude -- ^ no implicit import of the prelude+ deriving (Eq, Read, Show, Enum, Bounded)++-- |Classifies a 'String' as an 'Extension'+classifyExtension :: Ident -> Extension+classifyExtension i = case reads extName of+ [(e, "")] -> KnownExtension (getSpanInfo i) e+ _ -> UnknownExtension (getSpanInfo i) extName+ where extName = idName i++-- |'Extension's available by Kiel's Curry compilers.+kielExtensions :: [KnownExtension]+kielExtensions = [AnonFreeVars, FunctionalPatterns]++-- |Different Curry tools which may accept compiler options.+data Tool = KICS2 | PAKCS | CYMAKE | FRONTEND | UnknownTool String+ deriving (Eq, Read, Show)++instance Binary Tool where+ put KICS2 = putWord8 0+ put PAKCS = putWord8 1+ put CYMAKE = putWord8 2+ put FRONTEND = putWord8 3+ put (UnknownTool s) = putWord8 4 >> put s++ get = do+ x <- getWord8+ case x of+ 0 -> return KICS2+ 1 -> return PAKCS+ 2 -> return CYMAKE+ 3 -> return FRONTEND+ 4 -> fmap UnknownTool get+ _ -> fail "Invalid encoding for Tool"++-- |Classifies a 'String' as a 'Tool'+classifyTool :: String -> Tool+classifyTool str = case reads (map toUpper str) of+ [(t, "")] -> t+ _ -> UnknownTool str
− src/Curry/Syntax/Frontend.hs
@@ -1,202 +0,0 @@---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Frontend - Provides an API for dealing with several kinds of Curry--- program representations------ December 2005,--- Martin Engelke (men@informatik.uni-kiel.de)----module Curry.Syntax.Frontend (lex, parse, fullParse, typingParse)where--import Data.Maybe-import qualified Data.Map as Map-import Control.Monad.Writer-import Control.Monad.Error-import Prelude hiding (lex)---import Curry.Base.MessageMonad-import Curry.Base.Ident-import Curry.Base.Position--import Curry.Files.Filenames-import Curry.Files.PathUtils--import qualified Curry.Syntax as CS-import Curry.Syntax.Lexer--import Modules-import CurryBuilder-import CurryCompilerOpts--import CurryDeps--import Base(ModuleEnv)--------------------------------------------------------------------------------------------------------------------------------------------------------------------- Returns the result of a lexical analysis of the source program 'src'.--- The result is a list of tuples consisting of a position and a token--- (see Modules "Position" and "CurryLexer")-lex :: FilePath -> String -> MsgMonad [(Position,Token)]-lex fn src = lexFile (first fn) src False []----- Returns the result of a syntactical analysis of the source program 'src'.--- The result is the syntax tree of the program (type 'Module'; see Module--- "CurrySyntax").-parse :: FilePath -> String -> MsgMonad CS.Module-parse fn src = CS.parseModule True fn src >>= genCurrySyntax fn----- Returns the syntax tree of the source program 'src' (type 'Module'; see--- Module "CurrySyntax") after resolving the category (i.e. function,--- constructor or variable) of an identifier. 'fullParse' always--- searches for standard Curry libraries in the path defined in the--- environment variable "PAKCSLIBPATH". Additional search paths can--- be defined using the argument 'paths'.-fullParse :: [FilePath] -> FilePath -> String -> IO (MsgMonad CS.Module)-fullParse paths fn src = -- liftM msgmonad2result $- genFullCurrySyntax simpleCheckModule paths fn (parse fn src)---- Behaves like 'fullParse', but Returns the syntax tree of the source --- program 'src' (type 'Module'; see Module "CurrySyntax") after inferring --- the types of identifiers.-typingParse :: [FilePath] -> FilePath -> String -> IO (MsgMonad CS.Module)-typingParse paths fn src = genFullCurrySyntax checkModule paths fn (parse fn src)--{---- Compiles the source programm 'src' to an AbstractCurry program.--- 'fullParse' always searches for standard Curry libraries in the path --- defined in the environment variable "PAKCSLIBPATH". Additional search --- paths can be defined using the argument 'paths'.--- Notes: Due to the lack of error handling in the current version of the--- front end, this function may fail when an error occurs-abstractIO :: [FilePath] -> FilePath -> String -> IO (MsgMonad ACY.CurryProg)-abstractIO paths fn src = genAbstractIO paths fn (parse fn src)---- Compiles the source program 'src' to a FlatCurry program.--- 'fullParse' always searches for standard Curry libraries in the path --- defined in the environment variable "PAKCSLIBPATH". Additional search --- paths can be defined using the argument 'paths'.--- Note: Due to the lack of error handling in the current version of the--- front end, this function may fail when an error occurs-flatIO :: [FilePath] -> FilePath -> String -> IO (MsgMonad FCY.Prog)-flatIO paths fn src = genFlatIO paths fn (parse fn src)--}-------------------------------------------------------------------------------------------------------------------------------------------------------------------- Privates...---opts paths = defaultOpts{ - importPaths = paths,- noVerb = True,- noWarn = True,- abstract = True- }------genCurrySyntax :: FilePath -> CS.Module -> MsgMonad (CS.Module)-genCurrySyntax fn mod- = let mod'@(CS.Module mid _ _) = patchModuleId fn (importPrelude fn mod)- in if isValidModuleId fn mid- then return mod'- else failWith $ err_invalidModuleName mid------genFullCurrySyntax :: (Options -> Base.ModuleEnv -> CS.Module -> IO (t1, t2, t3, CS.Module, t4, [WarnMsg]))- -> [FilePath] -> t -> MsgMonad CS.Module -> IO (MsgMonad CS.Module)-genFullCurrySyntax check paths fn m- = runMsgIO m $ \mod -> do errs <- makeInterfaces paths mod- if null errs- then do mEnv <- loadInterfaces paths mod- (_, _, _, mod', _, msgs') <- check (opts paths) mEnv mod- return (tell msgs' >> return mod')- else return (failWith (head errs))---{--genAbstractIO :: [FilePath] -> FilePath -> MsgMonad CS.Module- -> IO (MsgMonad ACY.CurryProg)-genAbstractIO paths fn m- = runMsgIO m $ \mod ->- do errs <- makeInterfaces paths mod- if null errs- then do mEnv <- loadInterfaces paths mod- (tyEnv, tcEnv, _, mod', _, msgs')- <- simpleCheckModule (opts paths) mEnv mod- return (tell msgs' >> return (genTypedAbstract tyEnv tcEnv mod'))- else return (failWith $ head errs)------genFlatIO :: [FilePath] -> FilePath -> MsgMonad CS.Module -> IO (MsgMonad FCY.Prog)-genFlatIO paths fn m- = runMsgIO m $ \ mod -> - do errs <- makeInterfaces paths mod- if null errs then- (do mEnv <- loadInterfaces paths mod- (tyEnv, tcEnv, aEnv, mod', intf, msgs') <- - checkModule (opts paths) mEnv mod- let (il, aEnv', _) - = transModule True True False mEnv tyEnv tcEnv aEnv mod'- il' = completeCase mEnv il- cEnv = curryEnv mEnv tcEnv intf mod'- (prog,msgs'') = genFlatCurry (opts paths) cEnv mEnv - tyEnv tcEnv aEnv' il'- return (tell msgs'' >> tell msgs' >> return prog)- )- else return (failWith $ head errs)--}-------------------------------------------------------------------------------------- Generates interface files for importes modules, if they don't exist or--- if they are not up-to-date.-makeInterfaces :: [FilePath] -> CS.Module -> IO [String]-makeInterfaces paths (CS.Module mid _ decls)- = do let imports = [preludeMIdent | mid /= preludeMIdent] - ++ [imp | CS.ImportDecl _ imp _ _ _ <- decls]- (deps, errs) <- fmap flattenDeps (foldM (moduleDeps paths []) Map.empty imports)- when (null errs) (mapM_ (compile deps . snd) deps)- return errs- where- compile deps (Source file' mods)- = do smake [flatName file', flatIntName file']- (file':mapMaybe (flatInterface deps) mods)- (compileModule (opts paths) file')- (return Nothing)- return ()- compile _ _ = return ()-- flatInterface deps mod - = case (lookup mod deps) of- Just (Source file _) -> Just (flatIntName (dropExtension file))- Just (Interface file) -> Just (flatIntName (dropExtension file))- _ -> Nothing----- Returns 'True', if file name and module name are equal.-isValidModuleId :: FilePath -> ModuleIdent -> Bool-isValidModuleId fn mid- = last (moduleQualifiers mid) == takeBaseName fn------------------------------------------------------------------------------------- Messages--err_invalidModuleName :: ModuleIdent -> String-err_invalidModuleName mid - = "module \"" ++ moduleName mid - ++ "\" must be in a file \"" ++ moduleName mid ++ ".curry\""------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ src/Curry/Syntax/InterfaceEquivalence.hs view
@@ -0,0 +1,209 @@+{- |+ Module : $Header$+ Description : Comparison of Curry Interfaces+ Copyright : (c) 2000 - 2007 Wolfgang Lux+ 2014 - 2015 Björn Peemöller+ 2014 Jan Tikovsky+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ If a module is recompiled, the compiler has to check whether the+ interface file must be updated. This must be done if any exported+ entity has been changed, or an export was removed or added. The+ function 'intfEquiv' checks whether two interfaces are+ equivalent, i.e., whether they define the same entities.+-}+module Curry.Syntax.InterfaceEquivalence (fixInterface, intfEquiv) where++import Data.List (deleteFirstsBy, sort)+import qualified Data.Set as Set++import Curry.Base.Ident+import Curry.Syntax++infix 4 =~=, `eqvSet`++-- |Are two given interfaces equivalent?+intfEquiv :: Interface -> Interface -> Bool+intfEquiv = (=~=)++-- |Type class to express the equivalence of two values+class Equiv a where+ (=~=) :: a -> a -> Bool++instance Equiv a => Equiv (Maybe a) where+ Nothing =~= Nothing = True+ Nothing =~= Just _ = False+ Just _ =~= Nothing = False+ Just x =~= Just y = x =~= y++instance Equiv a => Equiv [a] where+ [] =~= [] = True+ (x:xs) =~= (y:ys) = x =~= y && xs =~= ys+ _ =~= _ = False++eqvList, eqvSet :: Equiv a => [a] -> [a] -> Bool+xs `eqvList` ys = length xs == length ys && and (zipWith (=~=) xs ys)+xs `eqvSet` ys = null (deleteFirstsBy (=~=) xs ys ++ deleteFirstsBy (=~=) ys xs)++instance Equiv Interface where+ Interface m1 is1 ds1 =~= Interface m2 is2 ds2+ = m1 == m2 && is1 `eqvSet` is2 && ds1 `eqvSet` ds2++instance Equiv IImportDecl where+ IImportDecl _ m1 =~= IImportDecl _ m2 = m1 == m2++-- Since the kind of type constructors or type classes can be omitted+-- in the interface when the kind is simple, i.e., it is either * or of+-- the form * -> ... -> *, a non given kind has to be considered equivalent+-- to a given one if the latter is simple.++eqvKindExpr :: Maybe KindExpr -> Maybe KindExpr -> Bool+Nothing `eqvKindExpr` (Just k) = isSimpleKindExpr k+(Just k) `eqvKindExpr` Nothing = isSimpleKindExpr k+k1 `eqvKindExpr` k2 = k1 == k2++isSimpleKindExpr :: KindExpr -> Bool+isSimpleKindExpr Star = True+isSimpleKindExpr (ArrowKind Star k) = isSimpleKindExpr k+isSimpleKindExpr _ = False+++instance Equiv IDecl where+ IInfixDecl _ fix1 p1 op1 =~= IInfixDecl _ fix2 p2 op2+ = fix1 == fix2 && p1 == p2 && op1 == op2+ HidingDataDecl _ tc1 k1 tvs1 =~= HidingDataDecl _ tc2 k2 tvs2+ = tc1 == tc2 && k1 `eqvKindExpr` k2 && tvs1 == tvs2+ IDataDecl _ tc1 k1 tvs1 cs1 hs1 =~= IDataDecl _ tc2 k2 tvs2 cs2 hs2+ = tc1 == tc2 && k1 `eqvKindExpr` k2 && tvs1 == tvs2 && cs1 =~= cs2 &&+ hs1 `eqvSet` hs2+ INewtypeDecl _ tc1 k1 tvs1 nc1 hs1 =~= INewtypeDecl _ tc2 k2 tvs2 nc2 hs2+ = tc1 == tc2 && k1 `eqvKindExpr` k2 && tvs1 == tvs2 && nc1 =~= nc2 &&+ hs1 `eqvSet` hs2+ ITypeDecl _ tc1 k1 tvs1 ty1 =~= ITypeDecl _ tc2 k2 tvs2 ty2+ = tc1 == tc2 && k1 `eqvKindExpr` k2 && tvs1 == tvs2 && ty1 == ty2+ IFunctionDecl _ f1 cm1 n1 qty1 =~= IFunctionDecl _ f2 cm2 n2 qty2+ = f1 == f2 && cm1 == cm2 && n1 == n2 && qty1 == qty2+ HidingClassDecl _ cx1 cls1 k1 _ =~= HidingClassDecl _ cx2 cls2 k2 _+ = cx1 == cx2 && cls1 == cls2 && k1 `eqvKindExpr` k2+ IClassDecl _ cx1 cls1 k1 _ ms1 hs1 =~= IClassDecl _ cx2 cls2 k2 _ ms2 hs2+ = cx1 == cx2 && cls1 == cls2 && k1 `eqvKindExpr` k2 &&+ ms1 `eqvList` ms2 && hs1 `eqvSet` hs2+ IInstanceDecl _ cx1 cls1 ty1 is1 m1 =~= IInstanceDecl _ cx2 cls2 ty2 is2 m2+ = cx1 == cx2 && cls1 == cls2 && ty1 == ty2 && sort is1 == sort is2 &&+ m1 == m2+ _ =~= _ = False++instance Equiv ConstrDecl where+ ConstrDecl _ c1 tys1 =~= ConstrDecl _ c2 tys2+ = c1 == c2 && tys1 == tys2+ ConOpDecl _ ty11 op1 ty12 =~= ConOpDecl _ ty21 op2 ty22+ = op1 == op2 && ty11 == ty21 && ty12 == ty22+ RecordDecl _ c1 fs1 =~= RecordDecl _ c2 fs2+ = c1 == c2 && fs1 `eqvList` fs2+ _ =~= _ = False++instance Equiv FieldDecl where+ FieldDecl _ ls1 ty1 =~= FieldDecl _ ls2 ty2 = ls1 == ls2 && ty1 == ty2++instance Equiv NewConstrDecl where+ NewConstrDecl _ c1 ty1 =~= NewConstrDecl _ c2 ty2 = c1 == c2 && ty1 == ty2+ NewRecordDecl _ c1 fld1 =~= NewRecordDecl _ c2 fld2 = c1 == c2 && fld1 == fld2+ _ =~= _ = False++instance Equiv IMethodDecl where+ IMethodDecl _ f1 a1 qty1 =~= IMethodDecl _ f2 a2 qty2+ = f1 == f2 && a1 == a2 && qty1 == qty2++instance Equiv Ident where+ (=~=) = (==)++-- If we check for a change in the interface, we do not need to check the+-- interface declarations, but still must disambiguate (nullary) type+-- constructors and type variables in type expressions. This is handled+-- by function 'fixInterface' and the associated type class 'FixInterface'.++-- |Disambiguate nullary type constructors and type variables.+fixInterface :: Interface -> Interface+fixInterface (Interface m is ds) = Interface m is $+ fix (Set.fromList (typeConstructors ds)) ds++class FixInterface a where+ fix :: Set.Set Ident -> a -> a++instance FixInterface a => FixInterface (Maybe a) where+ fix tcs = fmap (fix tcs)++instance FixInterface a => FixInterface [a] where+ fix tcs = map (fix tcs)++instance FixInterface IDecl where+ fix tcs (IDataDecl p tc k vs cs hs) =+ IDataDecl p tc k vs (fix tcs cs) hs+ fix tcs (INewtypeDecl p tc k vs nc hs) =+ INewtypeDecl p tc k vs (fix tcs nc) hs+ fix tcs (ITypeDecl p tc k vs ty) =+ ITypeDecl p tc k vs (fix tcs ty)+ fix tcs (IFunctionDecl p f cm n qty) =+ IFunctionDecl p f cm n (fix tcs qty)+ fix tcs (HidingClassDecl p cx cls k tv) =+ HidingClassDecl p (fix tcs cx) cls k tv+ fix tcs (IClassDecl p cx cls k tv ms hs) =+ IClassDecl p (fix tcs cx) cls k tv (fix tcs ms) hs+ fix tcs (IInstanceDecl p cx cls inst is m) =+ IInstanceDecl p (fix tcs cx) cls (fix tcs inst) is m+ fix _ d = d++instance FixInterface ConstrDecl where+ fix tcs (ConstrDecl p c tys) = ConstrDecl p c (fix tcs tys)+ fix tcs (ConOpDecl p ty1 op ty2) = ConOpDecl p (fix tcs ty1)+ op (fix tcs ty2)+ fix tcs (RecordDecl p c fs) = RecordDecl p c (fix tcs fs)++instance FixInterface FieldDecl where+ fix tcs (FieldDecl p ls ty) = FieldDecl p ls (fix tcs ty)++instance FixInterface NewConstrDecl where+ fix tcs (NewConstrDecl p c ty ) = NewConstrDecl p c (fix tcs ty)+ fix tcs (NewRecordDecl p c (i,ty)) = NewRecordDecl p c (i, fix tcs ty)++instance FixInterface IMethodDecl where+ fix tcs (IMethodDecl p f a qty) = IMethodDecl p f a (fix tcs qty)++instance FixInterface QualTypeExpr where+ fix tcs (QualTypeExpr spi cx ty) = QualTypeExpr spi (fix tcs cx) (fix tcs ty)++instance FixInterface Constraint where+ fix tcs (Constraint spi qcls ty) = Constraint spi qcls (fix tcs ty)++instance FixInterface TypeExpr where+ fix tcs (ConstructorType spi tc)+ | not (isQualified tc) && not (isPrimTypeId tc) && tc' `Set.notMember` tcs+ = VariableType spi tc'+ | otherwise = ConstructorType spi tc+ where tc' = unqualify tc+ fix tcs (ApplyType spi ty1 ty2) = ApplyType spi (fix tcs ty1) (fix tcs ty2)+ fix tcs (VariableType spi tv)+ | tv `Set.member` tcs = ConstructorType spi (qualify tv)+ | otherwise = VariableType spi tv+ fix tcs (TupleType spi tys) = TupleType spi (fix tcs tys)+ fix tcs (ListType spi ty) = ListType spi (fix tcs ty)+ fix tcs (ArrowType spi ty1 ty2) = ArrowType spi (fix tcs ty1) (fix tcs ty2)+ fix tcs (ParenType spi ty) = ParenType spi (fix tcs ty)+ fix tcs (ForallType spi vs ty) = ForallType spi vs (fix tcs ty)++typeConstructors :: [IDecl] -> [Ident]+typeConstructors ds = [tc | (QualIdent _ Nothing tc) <- foldr tyCons [] ds]+ where tyCons (IInfixDecl _ _ _ _) tcs = tcs+ tyCons (HidingDataDecl _ tc _ _) tcs = tc : tcs+ tyCons (IDataDecl _ tc _ _ _ _) tcs = tc : tcs+ tyCons (INewtypeDecl _ tc _ _ _ _) tcs = tc : tcs+ tyCons (ITypeDecl _ tc _ _ _) tcs = tc : tcs+ tyCons (IFunctionDecl _ _ _ _ _) tcs = tcs+ tyCons (HidingClassDecl _ _ _ _ _) tcs = tcs+ tyCons (IClassDecl _ _ _ _ _ _ _) tcs = tcs+ tyCons (IInstanceDecl _ _ _ _ _ _) tcs = tcs
− src/Curry/Syntax/LLParseComb.lhs
@@ -1,288 +0,0 @@-% $Id: LLParseComb.lhs,v 1.26 2004/02/15 23:11:30 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{LLParseComb.lhs}-\section{Parsing Combinators}\label{sec:ll-parsecomb}-The parsing combinators implemented in the module \texttt{LLParseComb}-are based on the LL(1) parsing combinators developed by Swierstra and-Duponcheel~\cite{SwierstraDuponcheel96:Parsers}. They have been-adapted to using continuation passing style in order to work with the-lexing combinators described in the previous section. In addition, the-facilities for error correction are omitted in this implementation.--The two functions \texttt{applyParser} and \texttt{prefixParser} use-the specified parser for parsing a string. When \texttt{applyParser}-is used, an error is reported if the parser does not consume the whole-string, whereas \texttt{prefixParser} discards the rest of the input-string in this case.-\begin{verbatim}--> module Curry.Syntax.LLParseComb(Symbol(..),Parser,-> applyParser,prefixParser, position,succeed,symbol,-> (<?>),(<|>),(<|?>),(<*>),(<\>),(<\\>),-> opt,(<$>),(<$->),(<*->),(<-*>),(<**>),(<??>),(<.>),-> many,many1, sepBy,sepBy1, chainr,chainr1,chainl,chainl1,-> bracket,ops, layoutOn,layoutOff,layoutEnd) where--> import Control.Monad-> import Data.Maybe-> import qualified Data.Set as Set-> import qualified Data.Map as Map--> import Curry.Syntax.LexComb-> import Curry.Base.MessageMonad-> import Curry.Base.Position---> infixl 5 <\>, <\\>-> infixl 4 <*>, <$>, <$->, <*->, <-*>, <**>, <??>, <.>-> infixl 3 <|>, <|?>-> infixl 2 <?>, `opt`--\end{verbatim}-\paragraph{Parser types}-\begin{verbatim}--> class (Ord s,Show s) => Symbol s where-> isEOF :: s -> Bool--> type SuccessCont s a = Position -> s -> P a-> type FailureCont a = Position -> String -> P a-> type Lexer s a = SuccessCont s a -> FailureCont a -> P a-> type ParseFun s a b = (a -> SuccessCont s b) -> FailureCont b-> -> SuccessCont s b--> data Parser s a b = Parser (Maybe (ParseFun s a b))-> (Map.Map s (Lexer s b -> ParseFun s a b))--> instance Symbol s => Show (Parser s a b) where-> showsPrec p (Parser e ps) = showParen (p >= 10) $-> showString "Parser " . shows (isJust e) .-> showChar ' ' . shows (Map.keysSet ps)--> applyParser :: Symbol s => Parser s a a -> Lexer s a -> FilePath -> String-> -> MsgMonad a-> applyParser p lexer = parse (lexer (choose p lexer done failP) failP)-> where done x pos s-> | isEOF s = returnP x-> | otherwise = failP pos (unexpected s)--> prefixParser :: Symbol s => Parser s a a -> Lexer s a -> FilePath -> String-> -> MsgMonad a-> prefixParser p lexer = parse (lexer (choose p lexer discard failP) failP)-> where discard x _ _ = returnP x--> choose :: Symbol s => Parser s a b -> Lexer s b -> ParseFun s a b-> choose (Parser e ps) lexer success fail pos s =-> case Map.lookup s ps of-> Just p -> p lexer success fail pos s-> Nothing ->-> case e of-> Just p -> p success fail pos s-> Nothing -> fail pos (unexpected s)--> unexpected :: Symbol s => s -> String-> unexpected s-> | isEOF s = "Unexpected end-of-file"-> | otherwise = "Unexpected token " ++ show s--\end{verbatim}-\paragraph{Basic combinators}-\begin{verbatim}--> position :: Symbol s => Parser s Position b-> position = Parser (Just p) Map.empty-> where p success _ pos = success pos pos--> succeed :: Symbol s => a -> Parser s a b-> succeed x = Parser (Just p) Map.empty-> where p success _ = success x--> symbol :: Symbol s => s -> Parser s s a-> symbol s = Parser Nothing (Map.singleton s p)-> where p lexer success fail pos s = lexer (success s) fail--> (<?>) :: Symbol s => Parser s a b -> String -> Parser s a b-> p <?> msg = p <|> Parser (Just pfail) Map.empty-> where pfail _ fail pos _ = fail pos msg--> (<|>) :: Symbol s => Parser s a b -> Parser s a b -> Parser s a b-> Parser e1 ps1 <|> Parser e2 ps2-> | isJust e1 && isJust e2 = error "Ambiguous parser for empty word"-> | not (Set.null common) = error ("Ambiguous parser for " ++ show common)-> | otherwise = Parser (e1 `mplus` e2) (Map.union ps1 ps2)-> where common = Map.keysSet ps1 `Set.intersection` Map.keysSet ps2--\end{verbatim}-The parsing combinators presented so far require that the grammar-being parsed is LL(1). In some cases it may be difficult or even-impossible to transform a grammar into LL(1) form. As a remedy, we-include a non-deterministic version of the choice combinator in-addition to the deterministic combinator adapted from the paper. For-every symbol from the intersection of the parser's first sets, the-combinator \texttt{(<|?>)} applies both parsing functions to the input-stream and uses that one which processes the longer prefix of the-input stream irrespective of whether it succeeds or fails. If both-functions recognize the same prefix, we choose the one that succeeds-and report an ambiguous parse error if both succeed.-\begin{verbatim}--> (<|?>) :: Symbol s => Parser s a b -> Parser s a b -> Parser s a b-> Parser e1 ps1 <|?> Parser e2 ps2-> | isJust e1 && isJust e2 = error "Ambiguous parser for empty word"-> | otherwise = Parser (e1 `mplus` e2) (Map.union ps1' ps2)-> where ps1' = Map.fromList [(s,maybe p (try p) (Map.lookup s ps2))-> | (s,p) <- Map.toList ps1]-> try p1 p2 lexer success fail pos s =-> closeP1 p2s `thenP` \p2s' ->-> closeP1 p2f `thenP` \p2f' ->-> parse p1 (retry p2s') (retry p2f')-> where p2s r1 = parse p2 (select True r1) (select False r1)-> p2f r1 = parse p2 (flip (select False) r1) (select False r1)-> parse p psucc pfail =-> p lexer (successK psucc) (failK pfail) pos s-> successK k x pos s = k (pos,success x pos s)-> failK k pos msg = k (pos,fail pos msg)-> retry k (pos,p) = closeP0 p `thenP` curry k pos-> select suc (pos1,p1) (pos2,p2) =-> case pos1 `compare` pos2 of-> GT -> p1-> EQ-> | suc -> error ("Ambiguous parse before " ++ show pos1)-> | otherwise -> p1-> LT -> p2--> (<*>) :: Symbol s => Parser s (a -> b) c -> Parser s a c -> Parser s b c-> Parser (Just p1) ps1 <*> ~p2@(Parser e2 ps2) =-> Parser (fmap (seqEE p1) e2)-> (Map.union (fmap (flip seqPP p2) ps1) (fmap (seqEP p1) ps2))-> Parser Nothing ps1 <*> p2 = Parser Nothing (fmap (flip seqPP p2) ps1)--> seqEE :: Symbol s => ParseFun s (a -> b) c -> ParseFun s a c-> -> ParseFun s b c-> seqEE p1 p2 success fail = p1 (\f -> p2 (success . f) fail) fail--> seqEP :: Symbol s => ParseFun s (a -> b) c -> (Lexer s c -> ParseFun s a c)-> -> Lexer s c -> ParseFun s b c-> seqEP p1 p2 lexer success fail = p1 (\f -> p2 lexer (success . f) fail) fail--> seqPP :: Symbol s => (Lexer s c -> ParseFun s (a -> b) c) -> Parser s a c-> -> Lexer s c -> ParseFun s b c-> seqPP p1 p2 lexer success fail =-> p1 lexer (\f -> choose p2 lexer (success . f) fail) fail--\end{verbatim}-The combinators \verb|<\\>| and \verb|<\>| can be used to restrict-the first set of a parser. This is useful for combining two parsers-with an overlapping first set with the deterministic combinator <|>.-\begin{verbatim}--> (<\>) :: Symbol s => Parser s a c -> Parser s b c -> Parser s a c-> p <\> Parser _ ps = p <\\> Map.keys ps--> (<\\>) :: Symbol s => Parser s a b -> [s] -> Parser s a b-> Parser e ps <\\> xs = Parser e (foldr Map.delete ps xs)--\end{verbatim}-\paragraph{Other combinators.}-Note that some of these combinators have not been published in the-paper, but were taken from the implementation found on the web.-\begin{verbatim}--> opt :: Symbol s => Parser s a b -> a -> Parser s a b-> p `opt` x = p <|> succeed x--> (<$>) :: Symbol s => (a -> b) -> Parser s a c -> Parser s b c-> f <$> p = succeed f <*> p--> (<$->) :: Symbol s => a -> Parser s b c -> Parser s a c-> f <$-> p = const f <$> p--> (<*->) :: Symbol s => Parser s a c -> Parser s b c -> Parser s a c-> p <*-> q = const <$> p <*> q--> (<-*>) :: Symbol s => Parser s a c -> Parser s b c -> Parser s b c-> p <-*> q = const id <$> p <*> q--> (<**>) :: Symbol s => Parser s a c -> Parser s (a -> b) c -> Parser s b c-> p <**> q = flip ($) <$> p <*> q--> (<??>) :: Symbol s => Parser s a b -> Parser s (a -> a) b -> Parser s a b-> p <??> q = p <**> (q `opt` id)--> (<.>) :: Symbol s => Parser s (a -> b) d -> Parser s (b -> c) d-> -> Parser s (a -> c) d-> p1 <.> p2 = p1 <**> ((.) <$> p2)--> many :: Symbol s => Parser s a b -> Parser s [a] b-> many p = many1 p `opt` []--> many1 :: Symbol s => Parser s a b -> Parser s [a] b-> -- many1 p = (:) <$> p <*> many p-> many1 p = (:) <$> p <*> (many1 p `opt` [])--\end{verbatim}-The first definition of \texttt{many1} is commented out because it-does not compile under nhc. This is due to a -- known -- bug in the-type checker of nhc which expects a default declaration when compiling-mutually recursive functions with class constraints. However, no such-default can be given in the above case because neither of the types-involved is a numeric type.-\begin{verbatim}--> sepBy :: Symbol s => Parser s a c -> Parser s b c -> Parser s [a] c-> p `sepBy` q = p `sepBy1` q `opt` []--> sepBy1 :: Symbol s => Parser s a c -> Parser s b c -> Parser s [a] c-> p `sepBy1` q = (:) <$> p <*> many (q <-*> p)--> chainr :: Symbol s => Parser s a b -> Parser s (a -> a -> a) b -> a-> -> Parser s a b-> chainr p op x = chainr1 p op `opt` x--> chainr1 :: Symbol s => Parser s a b -> Parser s (a -> a -> a) b-> -> Parser s a b-> chainr1 p op = r-> where r = p <**> (flip <$> op <*> r `opt` id)--> chainl :: Symbol s => Parser s a b -> Parser s (a -> a -> a) b -> a-> -> Parser s a b-> chainl p op x = chainl1 p op `opt` x--> chainl1 :: Symbol s => Parser s a b -> Parser s (a -> a -> a) b-> -> Parser s a b-> chainl1 p op = foldF <$> p <*> many (flip <$> op <*> p)-> where foldF x [] = x-> foldF x (f:fs) = foldF (f x) fs--> bracket :: Symbol s => Parser s a c -> Parser s b c -> Parser s a c-> -> Parser s b c-> bracket open p close = open <-*> p <*-> close--> ops :: Symbol s => [(s,a)] -> Parser s a b-> ops [] = error "internal error: ops"-> ops [(s,x)] = x <$-> symbol s-> ops ((s,x):rest) = x <$-> symbol s <|> ops rest--\end{verbatim}-\paragraph{Layout combinators}-Note that the layout functions grab the next token (and its position).-After modifying the layout context, the continuation is called with-the same token and an undefined result.-\begin{verbatim}--> layoutOn :: Symbol s => Parser s a b-> layoutOn = Parser (Just on) Map.empty-> where on success _ pos = pushContext (column pos) . success undefined pos--> layoutOff :: Symbol s => Parser s a b-> layoutOff = Parser (Just off) Map.empty-> where off success _ pos = pushContext (-1) . success undefined pos--> layoutEnd :: Symbol s => Parser s a b-> layoutEnd = Parser (Just end) Map.empty-> where end success _ pos = popContext . success undefined pos--\end{verbatim}
− src/Curry/Syntax/LexComb.lhs
@@ -1,104 +0,0 @@-% -*- LaTeX -*--% $Id: LexComb.lhs,v 1.16 2004/01/20 16:44:14 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{LexComb.lhs}-\section{Lexing combinators}-The module \texttt{LexComb} provides the basic types and combinators-to implement the lexers. The combinators use continuation passing code-in a monadic style. The first argument of the continuation function is-the current position, and the second is the string to be parsed. The third-argument is a flag which signals the lexer that it is lexing the-beginning of a line and therefore has to check for layout tokens. The-fourth argument is a stack of indentations that is used to handle-nested layout groups.-\begin{verbatim}--> module Curry.Syntax.LexComb where--> import Data.Char--> import Curry.Base.MessageMonad-> import Curry.Base.Position--> infixl 1 `thenP`, `thenP_`--> type Indent = Int-> type Context = [Indent]-> type P a = Position -> String -> Bool -> Context -> MsgMonad a--> parse :: P a -> FilePath -> String -> MsgMonad a-> parse p fn s = p (first fn) s False []--\end{verbatim}-Monad functions for the lexer.-\begin{verbatim}--> returnP :: a -> P a-> returnP x _ _ _ _ = return x--> thenP :: P a -> (a -> P b) -> P b-> thenP lex k pos s bol ctxt = lex pos s bol ctxt >>= \x -> k x pos s bol ctxt--> thenP_ :: P a -> P b -> P b-> p1 `thenP_` p2 = p1 `thenP` \_ -> p2--> failP :: Position -> String -> P a-> failP pos msg _ _ _ _ = failWith (parseError pos msg)--> closeP0 :: P a -> P (P a)-> closeP0 lex pos s bol ctxt = return (\_ _ _ _ -> lex pos s bol ctxt)--> closeP1 :: (a -> P b) -> P (a -> P b)-> closeP1 f pos s bol ctxt = return (\x _ _ _ _ -> f x pos s bol ctxt)--> parseError :: Position -> String -> String-> parseError p what = "\n" ++ show p ++ ": " ++ what--\end{verbatim}-Combinators that handle layout.-\begin{verbatim}--> pushContext :: Int -> P a -> P a-> pushContext col cont pos s bol ctxt = cont pos s bol (col:ctxt)--> popContext :: P a -> P a-> popContext cont pos s bol (_:ctxt) = cont pos s bol ctxt-> popContext cont pos s bol [] =-> error "parse error: popping layout from empty context stack. \-> \Perhaps you have inserted too many '}'?"--\end{verbatim}-Conversions from strings into numbers.-\begin{verbatim}--> convertSignedIntegral :: Num a => a -> String -> a-> convertSignedIntegral b ('+':s) = convertIntegral b s-> convertSignedIntegral b ('-':s) = - convertIntegral b s-> convertSignedIntegral b s = convertIntegral b s--> convertIntegral :: Num a => a -> String -> a-> convertIntegral b = foldl op 0-> where m `op` n | isDigit n = b * m + fromIntegral (ord n - ord0)-> | isUpper n = b * m + fromIntegral (ord n - ordA)-> | otherwise = b * m + fromIntegral (ord n - orda)-> ord0 = ord '0'-> ordA = ord 'A' - 10-> orda = ord 'a' - 10--> convertSignedFloating :: Fractional a => String -> String -> Int -> a-> convertSignedFloating ('+':m) f e = convertFloating m f e-> convertSignedFloating ('-':m) f e = - convertFloating m f e-> convertSignedFloating m f e = convertFloating m f e--> convertFloating :: Fractional a => String -> String -> Int -> a-> convertFloating m f e-> | e' == 0 = m'-> | e' > 0 = m' * 10^e'-> | otherwise = m' / 10^(-e')-> where m' = convertIntegral 10 (m ++ f)-> e' = e - length f--\end{verbatim}
+ src/Curry/Syntax/Lexer.hs view
@@ -0,0 +1,889 @@+{- |+ Module : $Header$+ Description : A lexer for Curry+ Copyright : (c) 1999 - 2004 Wolfgang Lux+ 2005 Martin Engelke+ 2011 - 2013 Björn Peemöller+ 2016 Finn Teegen+ 2016 Jan Tikovsky+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable+-}+module Curry.Syntax.Lexer+ ( -- * Data types for tokens+ Token (..), Category (..), Attributes (..)++ -- * lexing functions+ , lexSource, lexer, fullLexer+ ) where++import Prelude hiding (fail)+import Data.Char+ ( chr, ord, isAlpha, isAlphaNum, isDigit, isHexDigit, isOctDigit+ , isSpace, isUpper, toLower+ )+import Data.List (intercalate)+import qualified Data.Map as Map+ (Map, union, lookup, findWithDefault, fromList)++import Curry.Base.LexComb+import Curry.Base.Position+import Curry.Base.Span++-- ---------------------------------------------------------------------------+-- Tokens. Note that the equality and ordering instances of Token disregard+-- the attributes, as so that the parser decides about accepting a token+-- just by its category.+-- ---------------------------------------------------------------------------++-- |Data type for curry lexer tokens+data Token = Token Category Attributes++instance Eq Token where+ Token c1 _ == Token c2 _ = c1 == c2++instance Ord Token where+ Token c1 _ `compare` Token c2 _ = c1 `compare` c2++instance Symbol Token where+ isEOF (Token c _) = c == EOF++ dist _ (Token VSemicolon _) = (0, 0)+ dist _ (Token VRightBrace _) = (0, 0)+ dist _ (Token EOF _) = (0, 0)+ dist _ (Token DotDot _) = (0, 1)+ dist _ (Token DoubleColon _) = (0, 1)+ dist _ (Token LeftArrow _) = (0, 1)+ dist _ (Token RightArrow _) = (0, 1)+ dist _ (Token DoubleArrow _) = (0, 1)+ dist _ (Token KW_do _) = (0, 1)+ dist _ (Token KW_if _) = (0, 1)+ dist _ (Token KW_in _) = (0, 1)+ dist _ (Token KW_of _) = (0, 1)+ dist _ (Token Id_as _) = (0, 1)+ dist _ (Token KW_let _) = (0, 2)+ dist _ (Token PragmaEnd _) = (0, 2)+ dist _ (Token KW_case _) = (0, 3)+ dist _ (Token KW_class _) = (0, 4)+ dist _ (Token KW_data _) = (0, 3)+ dist _ (Token KW_default _) = (0, 6)+ dist _ (Token KW_deriving _) = (0, 7)+ dist _ (Token KW_else _) = (0, 3)+ dist _ (Token KW_free _) = (0, 3)+ dist _ (Token KW_then _) = (0, 3)+ dist _ (Token KW_type _) = (0, 3)+ dist _ (Token KW_fcase _) = (0, 4)+ dist _ (Token KW_infix _) = (0, 4)+ dist _ (Token KW_instance _) = (0, 7)+ dist _ (Token KW_where _) = (0, 4)+ dist _ (Token Id_ccall _) = (0, 4)+ dist _ (Token KW_import _) = (0, 5)+ dist _ (Token KW_infixl _) = (0, 5)+ dist _ (Token KW_infixr _) = (0, 5)+ dist _ (Token KW_module _) = (0, 5)+ dist _ (Token Id_forall _) = (0, 5)+ dist _ (Token Id_hiding _) = (0, 5)+ dist _ (Token KW_newtype _) = (0, 6)+ dist _ (Token KW_external _) = (0, 7)+ dist _ (Token Id_interface _) = (0, 8)+ dist _ (Token Id_primitive _) = (0, 8)+ dist _ (Token Id_qualified _) = (0, 8)+ dist _ (Token PragmaHiding _) = (0, 9)+ dist _ (Token PragmaLanguage _) = (0, 11)+ dist _ (Token Id a) = distAttr False a+ dist _ (Token QId a) = distAttr False a+ dist _ (Token Sym a) = distAttr False a+ dist _ (Token QSym a) = distAttr False a+ dist _ (Token IntTok a) = distAttr False a+ dist _ (Token FloatTok a) = distAttr False a+ dist _ (Token CharTok a) = distAttr False a+ dist c (Token StringTok a) = updColDist c (distAttr False a)+ dist _ (Token LineComment a) = distAttr True a+ dist c (Token NestedComment a) = updColDist c (distAttr True a)+ dist _ (Token PragmaOptions a) = let (ld, cd) = distAttr False a+ in (ld, cd + 11)+ dist _ _ = (0, 0)++-- TODO: Comment+updColDist :: Int -> Distance -> Distance+updColDist c (ld, cd) = (ld, if ld == 0 then cd else cd - c + 1)++distAttr :: Bool -> Attributes -> Distance+distAttr isComment attr = case attr of+ NoAttributes -> (0, 0)+ CharAttributes _ orig -> (0, length orig + 1)+ IntAttributes _ orig -> (0, length orig - 1)+ FloatAttributes _ orig -> (0, length orig - 1)+ StringAttributes _ orig+ -- comment without surrounding quotes+ | isComment -> (ld, cd)+ -- string with one ending double quote or two surrounding double quotes+ -- (column distance + 1 / + 2)+ | '\n' `elem` orig -> (ld, cd + 1)+ | otherwise -> (ld, cd + 2)+ where ld = length (filter (== '\n') orig)+ cd = length (takeWhile (/= '\n') (reverse orig)) - 1+ IdentAttributes mid i -> (0, length (intercalate "." (mid ++ [i])) - 1)+ OptionsAttributes mt args -> case mt of+ Nothing -> (0, distArgs + 1)+ Just t -> (0, length t + distArgs + 2)+ where distArgs = length args++-- |Category of curry tokens+data Category+ -- literals+ = CharTok+ | IntTok+ | FloatTok+ | StringTok++ -- identifiers+ | Id -- identifier+ | QId -- qualified identifier+ | Sym -- symbol+ | QSym -- qualified symbol++ -- punctuation symbols+ | LeftParen -- (+ | RightParen -- )+ | Semicolon -- ;+ | LeftBrace -- {+ | RightBrace -- }+ | LeftBracket -- [+ | RightBracket -- ]+ | Comma -- ,+ | Underscore -- _+ | Backquote -- `++ -- layout+ | VSemicolon -- virtual ;+ | VRightBrace -- virtual }++ -- reserved keywords+ | KW_case+ | KW_class+ | KW_data+ | KW_default+ | KW_deriving+ | KW_do+ | KW_else+ | KW_external+ | KW_fcase+ | KW_free+ | KW_if+ | KW_import+ | KW_in+ | KW_infix+ | KW_infixl+ | KW_infixr+ | KW_instance+ | KW_let+ | KW_module+ | KW_newtype+ | KW_of+ | KW_then+ | KW_type+ | KW_where++ -- reserved operators+ | At -- @+ | Colon -- :+ | DotDot -- ..+ | DoubleColon -- ::+ | Equals -- =+ | Backslash -- \+ | Bar -- |+ | LeftArrow -- <-+ | RightArrow -- ->+ | Tilde -- ~+ | DoubleArrow -- =>++ -- special identifiers+ | Id_as+ | Id_ccall+ | Id_forall+ | Id_hiding+ | Id_interface+ | Id_primitive+ | Id_qualified++ -- special operators+ | SymDot -- .+ | SymMinus -- -++ -- special symbols+ | SymStar -- kind star (*)++ -- pragmas+ | PragmaLanguage -- {-# LANGUAGE+ | PragmaOptions -- {-# OPTIONS+ | PragmaHiding -- {-# HIDING+ | PragmaMethod -- {-# METHOD+ | PragmaModule -- {-# MODULE+ | PragmaEnd -- #-}+++ -- comments (only for full lexer) inserted by men & bbr+ | LineComment+ | NestedComment++ -- end-of-file token+ | EOF+ deriving (Eq, Ord)++-- There are different kinds of attributes associated with the tokens.+-- Most attributes simply save the string corresponding to the token.+-- However, for qualified identifiers, we also record the list of module+-- qualifiers. The values corresponding to a literal token are properly+-- converted already. To simplify the creation and extraction of+-- attribute values, we make use of records.++-- |Attributes associated to a token+data Attributes+ = NoAttributes+ | CharAttributes { cval :: Char , original :: String }+ | IntAttributes { ival :: Integer , original :: String }+ | FloatAttributes { fval :: Double , original :: String }+ | StringAttributes { sval :: String , original :: String }+ | IdentAttributes { modulVal :: [String] , sval :: String }+ | OptionsAttributes { toolVal :: Maybe String, toolArgs :: String }++instance Show Attributes where+ showsPrec _ NoAttributes = showChar '_'+ showsPrec _ (CharAttributes cv _) = shows cv+ showsPrec _ (IntAttributes iv _) = shows iv+ showsPrec _ (FloatAttributes fv _) = shows fv+ showsPrec _ (StringAttributes sv _) = shows sv+ showsPrec _ (IdentAttributes mid i) = showsEscaped+ $ intercalate "." $ mid ++ [i]+ showsPrec _ (OptionsAttributes mt s) = showsTool mt+ . showChar ' ' . showString s+ where showsTool = maybe id (\t -> showChar '_' . showString t)+++-- ---------------------------------------------------------------------------+-- The 'Show' instance of 'Token' is designed to display all tokens in their+-- source representation.+-- ---------------------------------------------------------------------------++showsEscaped :: String -> ShowS+showsEscaped s = showChar '`' . showString s . showChar '\''++showsIdent :: Attributes -> ShowS+showsIdent a = showString "identifier " . shows a++showsSpecialIdent :: String -> ShowS+showsSpecialIdent s = showString "identifier " . showsEscaped s++showsOperator :: Attributes -> ShowS+showsOperator a = showString "operator " . shows a++showsSpecialOperator :: String -> ShowS+showsSpecialOperator s = showString "operator " . showsEscaped s++instance Show Token where+ showsPrec _ (Token Id a) = showsIdent a+ showsPrec _ (Token QId a) = showString "qualified "+ . showsIdent a+ showsPrec _ (Token Sym a) = showsOperator a+ showsPrec _ (Token QSym a) = showString "qualified "+ . showsOperator a+ showsPrec _ (Token IntTok a) = showString "integer " . shows a+ showsPrec _ (Token FloatTok a) = showString "float " . shows a+ showsPrec _ (Token CharTok a) = showString "character " . shows a+ showsPrec _ (Token StringTok a) = showString "string " . shows a+ showsPrec _ (Token LeftParen _) = showsEscaped "("+ showsPrec _ (Token RightParen _) = showsEscaped ")"+ showsPrec _ (Token Semicolon _) = showsEscaped ";"+ showsPrec _ (Token LeftBrace _) = showsEscaped "{"+ showsPrec _ (Token RightBrace _) = showsEscaped "}"+ showsPrec _ (Token LeftBracket _) = showsEscaped "["+ showsPrec _ (Token RightBracket _) = showsEscaped "]"+ showsPrec _ (Token Comma _) = showsEscaped ","+ showsPrec _ (Token Underscore _) = showsEscaped "_"+ showsPrec _ (Token Backquote _) = showsEscaped "`"+ showsPrec _ (Token VSemicolon _)+ = showsEscaped ";" . showString " (inserted due to layout)"+ showsPrec _ (Token VRightBrace _)+ = showsEscaped "}" . showString " (inserted due to layout)"+ showsPrec _ (Token At _) = showsEscaped "@"+ showsPrec _ (Token Colon _) = showsEscaped ":"+ showsPrec _ (Token DotDot _) = showsEscaped ".."+ showsPrec _ (Token DoubleArrow _) = showsEscaped "=>"+ showsPrec _ (Token DoubleColon _) = showsEscaped "::"+ showsPrec _ (Token Equals _) = showsEscaped "="+ showsPrec _ (Token Backslash _) = showsEscaped "\\"+ showsPrec _ (Token Bar _) = showsEscaped "|"+ showsPrec _ (Token LeftArrow _) = showsEscaped "<-"+ showsPrec _ (Token RightArrow _) = showsEscaped "->"+ showsPrec _ (Token Tilde _) = showsEscaped "~"+ showsPrec _ (Token SymDot _) = showsSpecialOperator "."+ showsPrec _ (Token SymMinus _) = showsSpecialOperator "-"+ showsPrec _ (Token SymStar _) = showsEscaped "*"+ showsPrec _ (Token KW_case _) = showsEscaped "case"+ showsPrec _ (Token KW_class _) = showsEscaped "class"+ showsPrec _ (Token KW_data _) = showsEscaped "data"+ showsPrec _ (Token KW_default _) = showsEscaped "default"+ showsPrec _ (Token KW_deriving _) = showsEscaped "deriving"+ showsPrec _ (Token KW_do _) = showsEscaped "do"+ showsPrec _ (Token KW_else _) = showsEscaped "else"+ showsPrec _ (Token KW_external _) = showsEscaped "external"+ showsPrec _ (Token KW_fcase _) = showsEscaped "fcase"+ showsPrec _ (Token KW_free _) = showsEscaped "free"+ showsPrec _ (Token KW_if _) = showsEscaped "if"+ showsPrec _ (Token KW_import _) = showsEscaped "import"+ showsPrec _ (Token KW_in _) = showsEscaped "in"+ showsPrec _ (Token KW_infix _) = showsEscaped "infix"+ showsPrec _ (Token KW_infixl _) = showsEscaped "infixl"+ showsPrec _ (Token KW_infixr _) = showsEscaped "infixr"+ showsPrec _ (Token KW_instance _) = showsEscaped "instance"+ showsPrec _ (Token KW_let _) = showsEscaped "let"+ showsPrec _ (Token KW_module _) = showsEscaped "module"+ showsPrec _ (Token KW_newtype _) = showsEscaped "newtype"+ showsPrec _ (Token KW_of _) = showsEscaped "of"+ showsPrec _ (Token KW_then _) = showsEscaped "then"+ showsPrec _ (Token KW_type _) = showsEscaped "type"+ showsPrec _ (Token KW_where _) = showsEscaped "where"+ showsPrec _ (Token Id_as _) = showsSpecialIdent "as"+ showsPrec _ (Token Id_ccall _) = showsSpecialIdent "ccall"+ showsPrec _ (Token Id_forall _) = showsSpecialIdent "forall"+ showsPrec _ (Token Id_hiding _) = showsSpecialIdent "hiding"+ showsPrec _ (Token Id_interface _) = showsSpecialIdent "interface"+ showsPrec _ (Token Id_primitive _) = showsSpecialIdent "primitive"+ showsPrec _ (Token Id_qualified _) = showsSpecialIdent "qualified"+ showsPrec _ (Token PragmaLanguage _) = showString "{-# LANGUAGE"+ showsPrec _ (Token PragmaOptions a) = showString "{-# OPTIONS"+ . shows a+ showsPrec _ (Token PragmaHiding _) = showString "{-# HIDING"+ showsPrec _ (Token PragmaMethod _) = showString "{-# METHOD"+ showsPrec _ (Token PragmaModule _) = showString "{-# MODULE"+ showsPrec _ (Token PragmaEnd _) = showString "#-}"+ showsPrec _ (Token LineComment a) = shows a+ showsPrec _ (Token NestedComment a) = shows a+ showsPrec _ (Token EOF _) = showString "<end-of-file>"++-- ---------------------------------------------------------------------------+-- The following functions can be used to construct tokens with+-- specific attributes.+-- ---------------------------------------------------------------------------++-- |Construct a simple 'Token' without 'Attributes'+tok :: Category -> Token+tok t = Token t NoAttributes++-- |Construct a 'Token' for a single 'Char'+charTok :: Char -> String -> Token+charTok c o = Token CharTok CharAttributes { cval = c, original = o }++-- |Construct a 'Token' for an int value+intTok :: Integer -> String -> Token+intTok base digits = Token IntTok IntAttributes+ { ival = convertIntegral base digits, original = digits }++-- |Construct a 'Token' for a float value+floatTok :: String -> String -> Int -> String -> Token+floatTok mant frac expo rest = Token FloatTok FloatAttributes+ { fval = convertFloating mant frac expo+ , original = mant ++ "." ++ frac ++ rest }++-- |Construct a 'Token' for a string value+stringTok :: String -> String -> Token+stringTok cs s = Token StringTok StringAttributes { sval = cs, original = s }++-- |Construct a 'Token' for identifiers+idTok :: Category -> [String] -> String -> Token+idTok t mIdent ident = Token t+ IdentAttributes { modulVal = mIdent, sval = ident }++-- TODO+pragmaOptionsTok :: Maybe String -> String -> Token+pragmaOptionsTok mbTool s = Token PragmaOptions+ OptionsAttributes { toolVal = mbTool, toolArgs = s }++-- |Construct a 'Token' for a line comment+lineCommentTok :: String -> Token+lineCommentTok s = Token LineComment+ StringAttributes { sval = s, original = s }++-- |Construct a 'Token' for a nested comment+nestedCommentTok :: String -> Token+nestedCommentTok s = Token NestedComment+ StringAttributes { sval = s, original = s }++-- ---------------------------------------------------------------------------+-- Tables for reserved operators and identifiers+-- ---------------------------------------------------------------------------++-- |Map of reserved operators+reservedOps:: Map.Map String Category+reservedOps = Map.fromList+ [ ("@" , At )+ , (":" , Colon )+ , ("=>", DoubleArrow)+ , ("::", DoubleColon)+ , ("..", DotDot )+ , ("=" , Equals )+ , ("\\", Backslash )+ , ("|" , Bar )+ , ("<-", LeftArrow )+ , ("->", RightArrow )+ , ("~" , Tilde )+ ]++-- |Map of reserved and special operators+reservedSpecialOps :: Map.Map String Category+reservedSpecialOps = Map.union reservedOps $ Map.fromList+ [ ("." , SymDot )+ , ("-" , SymMinus )+ , ("*" , SymStar )+ ]++-- |Map of keywords+keywords :: Map.Map String Category+keywords = Map.fromList+ [ ("case" , KW_case )+ , ("class" , KW_class )+ , ("data" , KW_data )+ , ("default" , KW_default )+ , ("deriving", KW_deriving)+ , ("do" , KW_do )+ , ("else" , KW_else )+ , ("external", KW_external)+ , ("fcase" , KW_fcase )+ , ("free" , KW_free )+ , ("if" , KW_if )+ , ("import" , KW_import )+ , ("in" , KW_in )+ , ("infix" , KW_infix )+ , ("infixl" , KW_infixl )+ , ("infixr" , KW_infixr )+ , ("instance", KW_instance)+ , ("let" , KW_let )+ , ("module" , KW_module )+ , ("newtype" , KW_newtype )+ , ("of" , KW_of )+ , ("then" , KW_then )+ , ("type" , KW_type )+ , ("where" , KW_where )+ ]++-- |Map of keywords and special identifiers+keywordsSpecialIds :: Map.Map String Category+keywordsSpecialIds = Map.union keywords $ Map.fromList+ [ ("as" , Id_as )+ , ("ccall" , Id_ccall )+ , ("forall" , Id_forall )+ , ("hiding" , Id_hiding )+ , ("interface", Id_interface)+ , ("primitive", Id_primitive)+ , ("qualified", Id_qualified)+ ]++pragmas :: Map.Map String Category+pragmas = Map.fromList+ [ ("language", PragmaLanguage)+ , ("options" , PragmaOptions )+ , ("hiding" , PragmaHiding )+ , ("method" , PragmaMethod )+ , ("module" , PragmaModule )+ ]+++-- ---------------------------------------------------------------------------+-- Character classes+-- ---------------------------------------------------------------------------++-- |Check whether a 'Char' is allowed for identifiers+isIdentChar :: Char -> Bool+isIdentChar c = isAlphaNum c || c `elem` "'_"++-- |Check whether a 'Char' is allowed for symbols+isSymbolChar :: Char -> Bool+isSymbolChar c = c `elem` "~!@#$%^&*+-=<>:?./|\\"++-- ---------------------------------------------------------------------------+-- Lexing functions+-- ---------------------------------------------------------------------------++-- |Lex source code+lexSource :: FilePath -> String -> CYM [(Span, Token)]+lexSource = parse (applyLexer fullLexer)++-- |CPS-Lexer for Curry+lexer :: Lexer Token a+lexer = skipWhiteSpace True -- skip comments++-- |CPS-Lexer for Curry which also lexes comments.+-- This lexer is useful for documentation tools.+fullLexer :: Lexer Token a+fullLexer = skipWhiteSpace False -- lex comments++-- |Lex the source code and skip whitespaces+skipWhiteSpace :: Bool -> Lexer Token a+skipWhiteSpace skipComments suc fail = skip+ where+ skip sp [] bol = suc sp (tok EOF) sp [] bol+ skip sp c@('-':'-':_) _ = lexLineComment sucComment fail sp c True+ skip sp c@('{':'-':'#':_) bol = lexPragma noPragma suc fail sp c bol+ skip sp c@('{':'-':_) bol = lexNestedComment sucComment fail sp c bol+ skip sp cs@(c:s) bol+ | c == '\t' = warnP sp "Tab character" skip (tabSpan sp) s bol+ | c == '\n' = skip (nlSpan sp) s True+ | isSpace c = skip (nextSpan sp) s bol+ | bol = lexBOL suc fail sp cs bol+ | otherwise = lexToken suc fail sp cs bol+ sucComment = if skipComments then (\ _suc _fail -> skip) else suc+ noPragma = lexNestedComment sucComment fail++-- Lex a line comment+lexLineComment :: Lexer Token a+lexLineComment suc _ sp str = case break (== '\n') str of+ (c, s ) -> suc sp (lineCommentTok c) (incrSpan sp $ length c) s++lexPragma :: P a -> Lexer Token a+lexPragma noPragma suc fail sp0 str = pragma (incrSpan sp0 3) (drop 3 str)+ where+ skip = noPragma sp0 str+ pragma sp [] = fail sp0 "Unterminated pragma" sp []+ pragma sp cs@(c : s)+ | c == '\t' = pragma (tabSpan sp) s+ | c == '\n' = pragma (nlSpan sp) s+ | isSpace c = pragma (nextSpan sp) s+ | isAlpha c = case Map.lookup (map toLower prag) pragmas of+ Nothing -> skip+ Just PragmaOptions -> lexOptionsPragma sp0 suc fail sp1 rest+ Just t -> suc sp0 (tok t) sp1 rest+ | otherwise = skip+ where+ (prag, rest) = span isAlphaNum cs+ sp1 = incrSpan sp (length prag)++lexOptionsPragma :: Span -> Lexer Token a+lexOptionsPragma sp0 _ fail sp [] = fail sp0 "Unterminated Options pragma" sp []+lexOptionsPragma sp0 suc fail sp (c : s)+ | c == '\t' = lexArgs Nothing (tabSpan sp) s+ | c == '\n' = lexArgs Nothing (nlSpan sp) s+ | isSpace c = lexArgs Nothing (nextSpan sp) s+ | c == '_' = let (tool, s1) = span isIdentChar s+ in lexArgs (Just tool) (incrSpan sp (length tool + 1)) s1+ | otherwise = fail sp0 "Malformed Options pragma" sp s+ where+ lexArgs mbTool = lexRaw ""+ where+ lexRaw s0 sp1 r = case hash of+ [] -> fail sp0 "End-of-file inside pragma" (incrSpan sp1 len) []+ '#':'-':'}':_ -> token (trim $ s0 ++ opts) (incrSpan sp1 len) hash+ _ -> lexRaw (s0 ++ opts ++ "#") (incrSpan sp1 (len + 1)) (drop 1 hash)+ where+ (opts, hash) = span (/= '#') r+ len = length opts+ token = suc sp0 . pragmaOptionsTok mbTool+ trim = reverse . dropWhile isSpace . reverse . dropWhile isSpace++-- Lex a nested comment+lexNestedComment :: Lexer Token a+lexNestedComment suc fail sp0 = lnc (0 :: Integer) id sp0+ where+ -- d : nesting depth+ -- comm: comment already lexed as functional list+ lnc d comm sp str = case (d, str) of+ (_, []) -> fail sp0 "Unterminated nested comment" sp []+ (1, '-':'}':s) -> suc sp0 (nestedCommentTok (comm "-}")) (incrSpan sp 2) s+ (_, '{':'-':s) -> cont (d+1) ("{-" ++) (incrSpan sp 2) s+ (_, '-':'}':s) -> cont (d-1) ("-}" ++) (incrSpan sp 2) s+ (_, c@'\t' :s) -> cont d (c:) (tabSpan sp) s+ (_, c@'\n' :s) -> cont d (c:) (nlSpan sp) s+ (_, c :s) -> cont d (c:) (nextSpan sp) s+ where cont d' comm' = lnc d' (comm . comm')++-- Lex tokens at the beginning of a line, managing layout.+lexBOL :: Lexer Token a+lexBOL suc fail sp s _ [] = lexToken suc fail sp s False []+lexBOL suc fail sp s _ ctxt@(n:rest)+ | col < n = suc sp (tok VRightBrace) sp s True rest+ | col == n = lexSemiOrWhere suc fail sp s False ctxt+ | otherwise = lexToken suc fail sp s False ctxt+ where col = column (span2Pos sp)++lexSemiOrWhere :: Lexer Token a+lexSemiOrWhere suc _ sp ('w':'h':'e':'r':'e':s@(c:_))+ | not (isIdentChar c) = suc sp (tok KW_where) sp s+lexSemiOrWhere suc _ sp s = suc sp (tok VSemicolon) sp s++-- Lex a single 'Token'+lexToken :: Lexer Token a+lexToken suc _ sp [] = suc sp (tok EOF) sp []+lexToken suc fail sp cs@(c:s)+ | take 3 cs == "#-}" = suc sp (tok PragmaEnd) (incrSpan sp 3) (drop 3 cs)+ | c == '(' = token LeftParen+ | c == ')' = token RightParen+ | c == ',' = token Comma+ | c == ';' = token Semicolon+ | c == '[' = token LeftBracket+ | c == ']' = token RightBracket+ | c == '_' = token Underscore+ | c == '`' = token Backquote+ | c == '{' = token LeftBrace+ | c == '}' = lexRightBrace (suc sp) (nextSpan sp) s+ | c == '\'' = lexChar sp suc fail (nextSpan sp) s+ | c == '\"' = lexString sp suc fail (nextSpan sp) s+ | isAlpha c = lexIdent (suc sp) sp cs+ | isSymbolChar c = lexSymbol (suc sp) sp cs+ | isDigit c = lexNumber (suc sp) sp cs+ | otherwise = fail sp ("Illegal character " ++ show c) sp s+ where token t = suc sp (tok t) (nextSpan sp) s++-- Lex a right brace and pop from the context stack+lexRightBrace :: (Token -> P a) -> P a+lexRightBrace cont sp s bol ctxt = cont (tok RightBrace) sp s bol (drop 1 ctxt)++-- Lex an identifier+lexIdent :: (Token -> P a) -> P a+lexIdent cont sp s = maybe (lexOptQual cont (token Id) [ident]) (cont . token)+ (Map.lookup ident keywordsSpecialIds)+ (incrSpan sp $ length ident) rest+ where (ident, rest) = span isIdentChar s+ token t = idTok t [] ident++-- Lex a symbol+lexSymbol :: (Token -> P a) -> P a+lexSymbol cont sp s = cont+ (idTok (Map.findWithDefault Sym sym reservedSpecialOps) [] sym)+ (incrSpan sp $ length sym) rest+ where (sym, rest) = span isSymbolChar s++-- Lex an optionally qualified entity (identifier or symbol).+lexOptQual :: (Token -> P a) -> Token -> [String] -> P a+lexOptQual cont token mIdent sp cs@('.':c:s)+ | isAlpha c = lexQualIdent cont identCont mIdent+ (nextSpan sp) (c:s)+ | isSymbolChar c && c /= '.' = lexQualSymbol cont identCont mIdent+ (nextSpan sp) (c:s)+-- | c `elem` ":[(" = lexQualPrimitive cont token mIdent (nextSpan sp) (c:s)+ where identCont _ _ = cont token sp cs+lexOptQual cont token mIdent sp cs@('.':'.':c:s)+ | isSymbolChar c = lexQualSymbol cont identCont mIdent+ (nextSpan sp) ('.':c:s)+ | not $ isIdentChar c = lexQualSymbol cont identCont mIdent+ (nextSpan sp) ('.':c:s)+ where identCont _ _ = cont token sp cs+lexOptQual cont token _ sp cs = cont token sp cs++-- Lex a qualified identifier.+lexQualIdent :: (Token -> P a) -> P a -> [String] -> P a+lexQualIdent cont identCont mIdent sp s =+ maybe (lexOptQual cont (idTok QId mIdent ident) (mIdent ++ [ident]))+ (const identCont)+ (Map.lookup ident keywords)+ (incrSpan sp (length ident)) rest+ where (ident, rest) = span isIdentChar s++-- Lex a qualified symbol.+lexQualSymbol :: (Token -> P a) -> P a -> [String] -> P a+lexQualSymbol cont identCont mIdent sp s =+ maybe (cont (idTok QSym mIdent sym)) (const identCont)+ (Map.lookup sym reservedOps)+ (incrSpan sp (length sym)) rest+ where (sym, rest) = span isSymbolChar s++-- ---------------------------------------------------------------------------+-- /Note:/ since Curry allows an unlimited range of integer numbers,+-- read numbers must be converted to Haskell type 'Integer'.+-- ---------------------------------------------------------------------------++-- Lex a numeric literal.+lexNumber :: (Token -> P a) -> P a+lexNumber cont sp ('0':c:s)+ | c `elem` "bB" = lexBinary cont nullCont (incrSpan sp 2) s+ | c `elem` "oO" = lexOctal cont nullCont (incrSpan sp 2) s+ | c `elem` "xX" = lexHexadecimal cont nullCont (incrSpan sp 2) s+ where nullCont _ _ = cont (intTok 10 "0") (nextSpan sp) (c:s)+lexNumber cont sp s = lexOptFraction cont (intTok 10 digits) digits+ (incrSpan sp $ length digits) rest+ where (digits, rest) = span isDigit s++-- Lex a binary literal.+lexBinary :: (Token -> P a) -> P a -> P a+lexBinary cont nullCont sp s+ | null digits = nullCont undefined undefined+ | otherwise = cont (intTok 2 digits) (incrSpan sp $ length digits) rest+ where (digits, rest) = span isBinDigit s+ isBinDigit c = c >= '0' && c <= '1'++-- Lex an octal literal.+lexOctal :: (Token -> P a) -> P a -> P a+lexOctal cont nullCont sp s+ | null digits = nullCont undefined undefined+ | otherwise = cont (intTok 8 digits) (incrSpan sp $ length digits) rest+ where (digits, rest) = span isOctDigit s++-- Lex a hexadecimal literal.+lexHexadecimal :: (Token -> P a) -> P a -> P a+lexHexadecimal cont nullCont sp s+ | null digits = nullCont undefined undefined+ | otherwise = cont (intTok 16 digits) (incrSpan sp $ length digits) rest+ where (digits, rest) = span isHexDigit s++-- Lex an optional fractional part (float literal).+lexOptFraction :: (Token -> P a) -> Token -> String -> P a+lexOptFraction cont _ mant sp ('.':c:s)+ | isDigit c = lexOptExponent cont (floatTok mant frac 0 "") mant frac+ (incrSpan sp (length frac+1)) rest+ where (frac,rest) = span isDigit (c:s)+lexOptFraction cont token mant sp (c:s)+ | c `elem` "eE" = lexSignedExponent cont intCont mant "" [c] (nextSpan sp) s+ where intCont _ _ = cont token sp (c:s)+lexOptFraction cont token _ sp s = cont token sp s++-- Lex an optional exponent (float literal).+lexOptExponent :: (Token -> P a) -> Token -> String -> String -> P a+lexOptExponent cont token mant frac sp (c:s)+ | c `elem` "eE" = lexSignedExponent cont floatCont mant frac [c] (nextSpan sp) s+ where floatCont _ _ = cont token sp (c:s)+lexOptExponent cont token _ _ sp s = cont token sp s++-- Lex an exponent with sign (float literal).+lexSignedExponent :: (Token -> P a) -> P a -> String -> String -> String+ -> P a+lexSignedExponent cont floatCont mant frac e sp str = case str of+ ('+':c:s) | isDigit c -> lexExpo (e ++ "+") id (nextSpan sp) (c:s)+ ('-':c:s) | isDigit c -> lexExpo (e ++ "-") negate (nextSpan sp) (c:s)+ (c:_) | isDigit c -> lexExpo e id sp str+ _ -> floatCont sp str+ where lexExpo = lexExponent cont mant frac++-- Lex an exponent without sign (float literal).+lexExponent :: (Token -> P a) -> String -> String -> String -> (Int -> Int)+ -> P a+lexExponent cont mant frac e expSign sp s =+ cont (floatTok mant frac expo (e ++ digits)) (incrSpan sp $ length digits) rest+ where (digits, rest) = span isDigit s+ expo = expSign (convertIntegral 10 digits)++-- Lex a character literal.+lexChar :: Span -> Lexer Token a+lexChar sp0 _ fail sp [] = fail sp0 "Illegal character constant" sp []+lexChar sp0 success fail sp (c:s)+ | c == '\\' = lexEscape sp (\d o -> lexCharEnd d o sp0 success fail)+ fail (nextSpan sp) s+ | c == '\n' = fail sp0 "Illegal character constant" sp (c:s)+ | c == '\t' = lexCharEnd c "\t" sp0 success fail (tabSpan sp) s+ | otherwise = lexCharEnd c [c] sp0 success fail (nextSpan sp) s++-- Lex the end of a character literal.+lexCharEnd :: Char -> String -> Span -> Lexer Token a+lexCharEnd c o sp0 suc _ sp ('\'':s) = suc sp0 (charTok c o) (nextSpan sp) s+lexCharEnd _ _ sp0 _ fail sp s =+ fail sp0 "Improperly terminated character constant" sp s++-- Lex a String literal.+lexString :: Span -> Lexer Token a+lexString sp0 suc fail = lexStringRest "" id+ where+ lexStringRest _ _ sp [] = improperTermination sp+ lexStringRest s0 so sp (c:s)+ | c == '\n' = improperTermination sp+ | c == '\"' = suc sp0 (stringTok (reverse s0) (so "")) (nextSpan sp) s+ | c == '\\' = lexStringEscape sp s0 so lexStringRest fail (nextSpan sp) s+ | c == '\t' = lexStringRest (c:s0) (so . (c:)) (tabSpan sp) s+ | otherwise = lexStringRest (c:s0) (so . (c:)) (nextSpan sp) s+ improperTermination sp = fail sp0 "Improperly terminated string constant" sp []++-- Lex an escaped character inside a string.+lexStringEscape :: Span -> String -> (String -> String)+ -> (String -> (String -> String) -> P a)+ -> FailP a -> P a+lexStringEscape sp0 _ _ _ fail sp [] = lexEscape sp0 undefined fail sp []+lexStringEscape sp0 s0 so suc fail sp cs@(c:s)+ -- The escape sequence represents an empty character of length zero+ | c == '&' = suc s0 (so . ("\\&" ++)) (nextSpan sp) s+ | isSpace c = lexStringGap so (suc s0) fail sp cs+ | otherwise = lexEscape sp0 (\ c' s' -> suc (c': s0) (so . (s' ++))) fail sp cs++-- Lex a string gap.+lexStringGap :: (String -> String) -> ((String -> String) -> P a)+ -> FailP a -> P a+lexStringGap _ _ fail sp [] = fail sp "End-of-file in string gap" sp []+lexStringGap so suc fail sp (c:s)+ | c == '\\' = suc (so . (c:)) (nextSpan sp) s+ | c == '\t' = lexStringGap (so . (c:)) suc fail (tabSpan sp) s+ | c == '\n' = lexStringGap (so . (c:)) suc fail (nlSpan sp) s+ | isSpace c = lexStringGap (so . (c:)) suc fail (nextSpan sp) s+ | otherwise = fail sp ("Illegal character in string gap: " ++ show c) sp s++-- Lex an escaped character.+lexEscape :: Span -> (Char -> String -> P a) -> FailP a -> P a+lexEscape sp0 suc fail sp str = case str of+ -- character escape+ ('a' :s) -> suc '\a' "\\a" (nextSpan sp) s+ ('b' :s) -> suc '\b' "\\b" (nextSpan sp) s+ ('f' :s) -> suc '\f' "\\f" (nextSpan sp) s+ ('n' :s) -> suc '\n' "\\n" (nextSpan sp) s+ ('r' :s) -> suc '\r' "\\r" (nextSpan sp) s+ ('t' :s) -> suc '\t' "\\t" (nextSpan sp) s+ ('v' :s) -> suc '\v' "\\v" (nextSpan sp) s+ ('\\':s) -> suc '\\' "\\\\" (nextSpan sp) s+ ('"' :s) -> suc '\"' "\\\"" (nextSpan sp) s+ ('\'':s) -> suc '\'' "\\\'" (nextSpan sp) s+ -- control characters+ ('^':c:s) | isControlEsc c -> controlEsc c (incrSpan sp 2) s+ -- numeric escape+ ('o':c:s) | isOctDigit c -> numEsc 8 isOctDigit ("\\o" ++) (nextSpan sp) (c:s)+ ('x':c:s) | isHexDigit c -> numEsc 16 isHexDigit ("\\x" ++) (nextSpan sp) (c:s)+ (c:s) | isDigit c -> numEsc 10 isDigit ("\\" ++) sp (c:s)+ -- ascii escape+ _ -> asciiEscape sp0 suc fail sp str+ where numEsc = numEscape sp0 suc fail+ controlEsc c = suc (chr (ord c `mod` 32)) ("\\^" ++ [c])+ isControlEsc c = isUpper c || c `elem` "@[\\]^_"++numEscape :: Span -> (Char -> String -> P a) -> FailP a -> Int+ -> (Char -> Bool) -> (String -> String) -> P a+numEscape sp0 suc fail b isDigit' so sp s+ | n >= ord minBound && n <= ord maxBound+ = suc (chr n) (so digits) (incrSpan sp $ length digits) rest+ | otherwise+ = fail sp0 "Numeric escape out-of-range" sp s+ where (digits, rest) = span isDigit' s+ n = convertIntegral b digits++asciiEscape :: Span -> (Char -> String -> P a) -> FailP a -> P a+asciiEscape sp0 suc fail sp str = case str of+ ('N':'U':'L':s) -> suc '\NUL' "\\NUL" (incrSpan sp 3) s+ ('S':'O':'H':s) -> suc '\SOH' "\\SOH" (incrSpan sp 3) s+ ('S':'T':'X':s) -> suc '\STX' "\\STX" (incrSpan sp 3) s+ ('E':'T':'X':s) -> suc '\ETX' "\\ETX" (incrSpan sp 3) s+ ('E':'O':'T':s) -> suc '\EOT' "\\EOT" (incrSpan sp 3) s+ ('E':'N':'Q':s) -> suc '\ENQ' "\\ENQ" (incrSpan sp 3) s+ ('A':'C':'K':s) -> suc '\ACK' "\\ACK" (incrSpan sp 3) s+ ('B':'E':'L':s) -> suc '\BEL' "\\BEL" (incrSpan sp 3) s+ ('B':'S' :s) -> suc '\BS' "\\BS" (incrSpan sp 2) s+ ('H':'T' :s) -> suc '\HT' "\\HT" (incrSpan sp 2) s+ ('L':'F' :s) -> suc '\LF' "\\LF" (incrSpan sp 2) s+ ('V':'T' :s) -> suc '\VT' "\\VT" (incrSpan sp 2) s+ ('F':'F' :s) -> suc '\FF' "\\FF" (incrSpan sp 2) s+ ('C':'R' :s) -> suc '\CR' "\\CR" (incrSpan sp 2) s+ ('S':'O' :s) -> suc '\SO' "\\SO" (incrSpan sp 2) s+ ('S':'I' :s) -> suc '\SI' "\\SI" (incrSpan sp 2) s+ ('D':'L':'E':s) -> suc '\DLE' "\\DLE" (incrSpan sp 3) s+ ('D':'C':'1':s) -> suc '\DC1' "\\DC1" (incrSpan sp 3) s+ ('D':'C':'2':s) -> suc '\DC2' "\\DC2" (incrSpan sp 3) s+ ('D':'C':'3':s) -> suc '\DC3' "\\DC3" (incrSpan sp 3) s+ ('D':'C':'4':s) -> suc '\DC4' "\\DC4" (incrSpan sp 3) s+ ('N':'A':'K':s) -> suc '\NAK' "\\NAK" (incrSpan sp 3) s+ ('S':'Y':'N':s) -> suc '\SYN' "\\SYN" (incrSpan sp 3) s+ ('E':'T':'B':s) -> suc '\ETB' "\\ETB" (incrSpan sp 3) s+ ('C':'A':'N':s) -> suc '\CAN' "\\CAN" (incrSpan sp 3) s+ ('E':'M' :s) -> suc '\EM' "\\EM" (incrSpan sp 2) s+ ('S':'U':'B':s) -> suc '\SUB' "\\SUB" (incrSpan sp 3) s+ ('E':'S':'C':s) -> suc '\ESC' "\\ESC" (incrSpan sp 3) s+ ('F':'S' :s) -> suc '\FS' "\\FS" (incrSpan sp 2) s+ ('G':'S' :s) -> suc '\GS' "\\GS" (incrSpan sp 2) s+ ('R':'S' :s) -> suc '\RS' "\\RS" (incrSpan sp 2) s+ ('U':'S' :s) -> suc '\US' "\\US" (incrSpan sp 2) s+ ('S':'P' :s) -> suc '\SP' "\\SP" (incrSpan sp 2) s+ ('D':'E':'L':s) -> suc '\DEL' "\\DEL" (incrSpan sp 3) s+ s -> fail sp0 "Illegal escape sequence" sp s
− src/Curry/Syntax/Lexer.lhs
@@ -1,630 +0,0 @@--% $Id: CurryLexer.lhs,v 1.40 2004/03/04 22:39:12 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{CurryLexer.lhs}-\section{A Lexer for Curry}-In this section a lexer for Curry is implemented.-\begin{verbatim}- -> module Curry.Syntax.Lexer (lexFile,lexer, Token (..), Category(..), Attributes(..)) where--> import Data.Char -> import Data.List-> import qualified Data.Map as Map--> import Curry.Syntax.LexComb-> import Curry.Base.Position----\end{verbatim}-\paragraph{Tokens} Note that the equality and ordering instances of-\texttt{Token} disregard the attributes.-\begin{verbatim}--> data Token = Token Category Attributes--> instance Eq Token where-> Token t1 _ == Token t2 _ = t1 == t2-> instance Ord Token where-> Token t1 _ `compare` Token t2 _ = t1 `compare` t2--> data Category =-> -- literals-> CharTok | IntTok | FloatTok | IntegerTok | StringTok-> -- identifiers-> | Id | QId | Sym | QSym-> -- punctuation symbols-> | LeftParen | RightParen | Semicolon | LeftBrace | RightBrace-> | LeftBracket | RightBracket | Comma | Underscore | Backquote-> -- turn off layout (inserted by bbr)-> | LeftBraceSemicolon-> -- virtual punctation (inserted by layout)-> | VSemicolon | VRightBrace-> -- reserved identifiers-> | KW_case | KW_choice | KW_data | KW_do | KW_else | KW_eval | KW_external-> | KW_free | KW_if | KW_import | KW_in | KW_infix | KW_infixl | KW_infixr-> | KW_let | KW_module | KW_newtype | KW_of | KW_rigid | KW_then | KW_type-> | KW_where-> -- reserved operators-> | At | Colon | DotDot | DoubleColon | Equals | Backslash | Bar-> | LeftArrow | RightArrow | Tilde | Binds-> -- special identifiers-> | Id_as | Id_ccall | Id_forall | Id_hiding | Id_interface | Id_primitive-> | Id_qualified-> -- special operators-> | Sym_Dot | Sym_Minus | Sym_MinusDot-> -- end-of-file token-> | EOF-> -- comments (only for full lexer) inserted by men & bbr-> | LineComment | NestedComment -> deriving (Eq,Ord)--\end{verbatim}-There are different kinds of attributes associated with the tokens.-Most attributes simply save the string corresponding to the token.-However, for qualified identifiers, we also record the list of module-qualifiers. The values corresponding to a literal token are properly-converted already. To simplify the creation and extraction of-attribute values we make use of records.-\begin{verbatim}--> data Attributes =-> NoAttributes-> | CharAttributes{ cval :: Char, original :: String}-> | IntAttributes{ ival :: Int , original :: String}-> | FloatAttributes{ fval :: Double, original :: String}-> | IntegerAttributes{ intval :: Integer, original :: String}-> | StringAttributes{ sval :: String, original :: String}-> | IdentAttributes{ modul :: [String], sval :: String}--> instance Show Attributes where-> showsPrec _ NoAttributes = showChar '_'-> showsPrec _ (CharAttributes cval _) = shows cval-> showsPrec _ (IntAttributes ival _) = shows ival-> showsPrec _ (FloatAttributes fval _) = shows fval-> showsPrec _ (IntegerAttributes intval _) = shows intval-> showsPrec _ (StringAttributes sval _) = shows sval-> showsPrec _ (IdentAttributes mIdent ident) =-> showString ("`" ++ concat (intersperse "." (mIdent ++ [ident])) ++ "'")--\end{verbatim}-The following functions can be used to construct tokens with-specific attributes.-\begin{verbatim}--> tok :: Category -> Token-> tok t = Token t NoAttributes--> idTok :: Category -> [String] -> String -> Token-> idTok t mIdent ident = Token t IdentAttributes{ modul = mIdent, sval = ident }--> charTok :: Char -> String -> Token-> charTok c o = Token CharTok CharAttributes{ cval = c, original = o }--> intTok :: Int -> String -> Token-> intTok base digits =-> Token IntTok IntAttributes{ ival = convertIntegral base digits,-> original = digits}--> floatTok :: String -> String -> Int -> String -> Token-> floatTok mant frac exp rest =-> Token FloatTok FloatAttributes{ fval = convertFloating mant frac exp, -> original = mant++"."++frac++rest}- -> integerTok :: Integer -> String -> Token-> integerTok base digits =-> Token IntegerTok-> IntegerAttributes{intval = (convertIntegral base digits) :: Integer,-> original = digits}--> stringTok :: String -> String -> Token-> stringTok cs o = Token StringTok StringAttributes{ sval = cs, original = o }--> lineCommentTok :: String -> Token-> lineCommentTok s = Token LineComment StringAttributes{ sval = s, original = s}--> nestedCommentTok :: String -> Token-> nestedCommentTok s = Token NestedComment StringAttributes{ sval = s, original = s }--\end{verbatim}-The \texttt{Show} instance of \texttt{Token} is designed to display-all tokens in their source representation.-\begin{verbatim}--> instance Show Token where-> showsPrec _ (Token Id a) = showString "identifier " . shows a-> showsPrec _ (Token QId a) = showString "qualified identifier " . shows a-> showsPrec _ (Token Sym a) = showString "operator " . shows a-> showsPrec _ (Token QSym a) = showString "qualified operator " . shows a-> showsPrec _ (Token IntTok a) = showString "integer " . shows a-> showsPrec _ (Token FloatTok a) = showString "float " . shows a-> showsPrec _ (Token CharTok a) = showString "character " . shows a-> showsPrec _ (Token IntegerTok a) = showString "integer " . shows a-> showsPrec _ (Token StringTok a) = showString "string " . shows a-> showsPrec _ (Token LeftParen _) = showString "`('"-> showsPrec _ (Token RightParen _) = showString "`)'"-> showsPrec _ (Token Semicolon _) = showString "`;'"-> showsPrec _ (Token LeftBrace _) = showString "`{'"-> showsPrec _ (Token RightBrace _) = showString "`}'"-> showsPrec _ (Token LeftBracket _) = showString "`['"-> showsPrec _ (Token RightBracket _) = showString "`]'"-> showsPrec _ (Token Comma _) = showString "`,'"-> showsPrec _ (Token Underscore _) = showString "`_'"-> showsPrec _ (Token Backquote _) = showString "``'"-> showsPrec _ (Token VSemicolon _) =-> showString "`;' (inserted due to layout)"-> showsPrec _ (Token VRightBrace _) =-> showString "`}' (inserted due to layout)"-> showsPrec _ (Token At _) = showString "`@'"-> showsPrec _ (Token Colon _) = showString "`:'"-> showsPrec _ (Token DotDot _) = showString "`..'"-> showsPrec _ (Token DoubleColon _) = showString "`::'"-> showsPrec _ (Token Equals _) = showString "`='"-> showsPrec _ (Token Backslash _) = showString "`\\'"-> showsPrec _ (Token Bar _) = showString "`|'"-> showsPrec _ (Token LeftArrow _) = showString "`<-'"-> showsPrec _ (Token RightArrow _) = showString "`->'"-> showsPrec _ (Token Tilde _) = showString "`~'"-> showsPrec _ (Token Binds _) = showString "`:='"-> showsPrec _ (Token Sym_Dot _) = showString "operator `.'"-> showsPrec _ (Token Sym_Minus _) = showString "operator `-'"-> showsPrec _ (Token Sym_MinusDot _) = showString "operator `-.'"-> showsPrec _ (Token KW_case _) = showString "`case'"-> showsPrec _ (Token KW_choice _) = showString "`choice'"-> showsPrec _ (Token KW_data _) = showString "`data'"-> showsPrec _ (Token KW_do _) = showString "`do'"-> showsPrec _ (Token KW_else _) = showString "`else'"-> showsPrec _ (Token KW_eval _) = showString "`eval'"-> showsPrec _ (Token KW_external _) = showString "`external'"-> showsPrec _ (Token KW_free _) = showString "`free'"-> showsPrec _ (Token KW_if _) = showString "`if'"-> showsPrec _ (Token KW_import _) = showString "`import'"-> showsPrec _ (Token KW_in _) = showString "`in'"-> showsPrec _ (Token KW_infix _) = showString "`infix'"-> showsPrec _ (Token KW_infixl _) = showString "`infixl'"-> showsPrec _ (Token KW_infixr _) = showString "`infixr'"-> showsPrec _ (Token KW_let _) = showString "`let'"-> showsPrec _ (Token KW_module _) = showString "`module'"-> showsPrec _ (Token KW_newtype _) = showString "`newtype'"-> showsPrec _ (Token KW_of _) = showString "`of'"-> showsPrec _ (Token KW_rigid _) = showString "`rigid'"-> showsPrec _ (Token KW_then _) = showString "`then'"-> showsPrec _ (Token KW_type _) = showString "`type'"-> showsPrec _ (Token KW_where _) = showString "`where'"-> showsPrec _ (Token Id_as _) = showString "identifier `as'"-> showsPrec _ (Token Id_ccall _) = showString "identifier `ccall'"-> showsPrec _ (Token Id_forall _) = showString "identifier `forall'"-> showsPrec _ (Token Id_hiding _) = showString "identifier `hiding'"-> showsPrec _ (Token Id_interface _) = showString "identifier `interface'"-> showsPrec _ (Token Id_primitive _) = showString "identifier `primitive'"-> showsPrec _ (Token Id_qualified _) = showString "identifier `qualified'"-> showsPrec _ (Token EOF _) = showString "<end-of-file>"-> showsPrec _ (Token LineComment a) = shows a-> showsPrec _ (Token NestedComment a) = shows a--\end{verbatim}-Tables for reserved operators and identifiers-\begin{verbatim}--> reserved_ops, reserved_and_special_ops :: Map.Map String Category-> reserved_ops = Map.fromList [-> ("@", At),-> ("::", DoubleColon),-> ("..", DotDot),-> ("=", Equals),-> ("\\", Backslash),-> ("|", Bar),-> ("<-", LeftArrow),-> ("->", RightArrow),-> ("~", Tilde),-> (":=", Binds)-> ]-> reserved_and_special_ops = foldr (uncurry Map.insert) reserved_ops [-> (":", Colon),-> (".", Sym_Dot),-> ("-", Sym_Minus),-> ("-.", Sym_MinusDot)-> ]--> reserved_ids, reserved_and_special_ids :: Map.Map String Category-> reserved_ids = Map.fromList [-> ("case", KW_case),-> ("choice", KW_choice),-> ("data", KW_data),-> ("do", KW_do),-> ("else", KW_else),-> ("eval", KW_eval),-> ("external", KW_external),-> ("free", KW_free),-> ("if", KW_if),-> ("import", KW_import),-> ("in", KW_in),-> ("infix", KW_infix),-> ("infixl", KW_infixl),-> ("infixr", KW_infixr),-> ("let", KW_let),-> ("module", KW_module),-> ("newtype", KW_newtype),-> ("of", KW_of),-> ("rigid", KW_rigid),-> ("then", KW_then),-> ("type", KW_type),-> ("where", KW_where)-> ]-> reserved_and_special_ids = foldr (uncurry Map.insert) reserved_ids [-> ("as", Id_as),-> ("ccall", Id_ccall),-> ("forall", Id_forall),-> ("hiding", Id_hiding),-> ("interface", Id_interface),-> ("primitive", Id_primitive),-> ("qualified", Id_qualified)-> ]--\end{verbatim}-Character classes-\begin{verbatim}--> isIdent, isSym, isOctit, isHexit :: Char -> Bool-> isIdent c = isAlphaNum c || c `elem` "'_"-> isSym c = c `elem` "~!@#$%^&*+-=<>:?./|\\"-> isOctit c = c >= '0' && c <= '7'-> isHexit c = isDigit c || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f'--inserted for full lexing (men&bbr)--> isLineComment, isNestedComment :: String -> Bool-> isLineComment ('-':'-':_) = True-> isLineComment _ = False-> isNestedComment ('{':'-':s) = True-> isNestedComment _ = False---\end{verbatim}-Lexing functions-\begin{verbatim}--> type SuccessP a = Position -> Token -> P a-> type FailP a = Position -> String -> P a--> lexFile :: P [(Position,Token)]-> lexFile = fullLexer tokens failP-> where tokens p t@(Token c _)-> | c == EOF = returnP [(p,t)]-> | otherwise = lexFile `thenP` returnP . ((p,t):)--> lexer :: SuccessP a -> FailP a -> P a-> lexer success fail = skipBlanks-> where -- skipBlanks moves past whitespace and comments-> skipBlanks p [] bol = success p (tok EOF) p [] bol-> skipBlanks p ('\t':s) bol = skipBlanks (tab p) s bol-> skipBlanks p ('\n':s) bol = skipBlanks (nl p) s True-> skipBlanks p ('-':'-':s) bol =-> skipBlanks (nl p) (tail' (dropWhile (/= '\n') s)) True-> skipBlanks p ('{':'-':s) bol =-> nestedComment p skipBlanks fail (incr p 2) s bol-> skipBlanks p (c:s) bol-> | isSpace c = skipBlanks (next p) s bol-> | otherwise =-> (if bol then lexBOL else lexToken) success fail p (c:s) bol-> tail' [] = []-> tail' (_:tl) = tl--> fullLexer :: SuccessP a -> FailP a -> P a-> fullLexer success fail = skipBlanks-> where -- skipBlanks moves past whitespace -> skipBlanks p [] bol = success p (tok EOF) p [] bol-> skipBlanks p ('\t':s) bol = skipBlanks (tab p) s bol-> skipBlanks p ('\n':s) bol = skipBlanks (nl p) s True-> skipBlanks p s@('-':'-':_) bol = lexLineComment success p s bol-> skipBlanks p s@('{':'-':_) bol =-> lexNestedComment 0 id p success fail p s bol-> skipBlanks p (c:s) bol-> | isSpace c = skipBlanks (next p) s bol-> | otherwise =-> (if bol then lexBOL else lexToken) success fail p (c:s) bol-> tail' [] = []-> tail' (_:tl) = tl--> lexLineComment :: SuccessP a -> P a-> lexLineComment success p s = case break (=='\n') s of-> (comment,rest) -> success p (lineCommentTok comment) (incr p (length comment)) rest- -> lexNestedComment :: Int -> (String -> String) -> -> Position -> SuccessP a -> FailP a -> P a-> lexNestedComment 1 comment p0 success fail p ('-':'}':s) = -> success p0 (nestedCommentTok (comment "-}") ) (incr p 2) s -> lexNestedComment n comment p0 success fail p ('{':'-':s) = -> lexNestedComment (n+1) (comment . ("{-"++)) p0 success fail (incr p 2) s-> lexNestedComment n comment p0 success fail p ('-':'}':s) = -> lexNestedComment (n-1) (comment . ("-}"++)) p0 success fail (incr p 2) s-> lexNestedComment n comment p0 success fail p (c@'\t':s) = -> lexNestedComment n (comment . (c:)) p0 success fail (tab p) s-> lexNestedComment n comment p0 success fail p (c@'\n':s) = -> lexNestedComment n (comment . (c:)) p0 success fail (nl p) s-> lexNestedComment n comment p0 success fail p (c:s) = -> lexNestedComment n (comment . (c:)) p0 success fail (next p) s-> lexNestedComment n comment p0 success fail p "" = -> fail p0 "Unterminated nested comment" p []--> nestedComment :: Position -> P a -> FailP a -> P a-> nestedComment p0 success fail p ('-':'}':s) = success (incr p 2) s-> nestedComment p0 success fail p ('{':'-':s) =-> nestedComment p (nestedComment p0 success fail) fail (incr p 2) s-> nestedComment p0 success fail p ('\t':s) =-> nestedComment p0 success fail (tab p) s-> nestedComment p0 success fail p ('\n':s) =-> nestedComment p0 success fail (nl p) s-> nestedComment p0 success fail p (_:s) =-> nestedComment p0 success fail (next p) s-> nestedComment p0 success fail p [] =-> fail p0 "Unterminated nested comment at end-of-file" p []---> lexBOL :: SuccessP a -> FailP a -> P a-> lexBOL success fail p s _ [] = lexToken success fail p s False []-> lexBOL success fail p s _ ctxt@(n:rest)-> | col < n = success p (tok VRightBrace) p s True rest-> | col == n = success p (tok VSemicolon) p s False ctxt-> | otherwise = lexToken success fail p s False ctxt-> where col = column p--> lexToken :: SuccessP a -> FailP a -> P a-> lexToken success fail p [] = success p (tok EOF) p []-> lexToken success fail p (c:s)-> | c == '(' = token LeftParen-> | c == ')' = token RightParen-> | c == ',' = token Comma-> | c == ';' = token Semicolon-> | c == '[' = token LeftBracket-> | c == ']' = token RightBracket-> | c == '_' = token Underscore-> | c == '`' = token Backquote-> | c == '{' = lexLeftBrace (token LeftBrace) (next p) (success p) s -> | c == '}' = \bol -> token RightBrace bol . drop 1-> | c == '\'' = lexChar p success fail (next p) s-> | c == '\"' = lexString p success fail (next p) s-> | isAlpha c = lexIdent (success p) p (c:s)-> | isSym c = lexSym (success p) p (c:s)-> | isDigit c = lexNumber (success p) p (c:s)-> | otherwise = fail p ("Illegal character " ++ show c) p s-> where token t = success p (tok t) (next p) s--> lexIdent :: (Token -> P a) -> P a-> lexIdent cont p s =-> maybe (lexOptQual cont (token Id) [ident]) (cont . token)-> (Map.lookup ident reserved_and_special_ids)-> (incr p (length ident)) rest-> where (ident,rest) = span isIdent s-> token t = idTok t [] ident--> lexSym :: (Token -> P a) -> P a-> lexSym cont p s =-> cont (idTok (maybe Sym id (Map.lookup sym reserved_and_special_ops)) [] sym)-> (incr p (length sym)) rest-> where (sym,rest) = span isSym s--> lexLeftBrace leftBrace _ _ [] = leftBrace-> lexLeftBrace leftBrace p cont (c:s) -> | c==';' = cont (tok LeftBraceSemicolon) (next p) s-> | otherwise = leftBrace--\end{verbatim}-{\em Note:} the function \texttt{lexOptQual} has been extended to provide-the qualified use of the Prelude list operators and tuples.-\begin{verbatim}--> lexOptQual :: (Token -> P a) -> Token -> [String] -> P a-> lexOptQual cont token mIdent p ('.':c:s)-> | isAlpha c = lexQualIdent cont identCont mIdent (next p) (c:s)-> | isSym c = lexQualSym cont identCont mIdent (next p) (c:s)-> | c=='(' || c=='[' -> = lexQualPreludeSym cont token identCont mIdent (next p) (c:s)-> where identCont _ _ = cont token p ('.':c:s)-> lexOptQual cont token mIdent p s = cont token p s--> lexQualIdent :: (Token -> P a) -> P a -> [String] -> P a-> lexQualIdent cont identCont mIdent p s =-> maybe (lexOptQual cont (idTok QId mIdent ident) (mIdent ++ [ident]))-> (const identCont)-> (Map.lookup ident reserved_ids)-> (incr p (length ident)) rest-> where (ident,rest) = span isIdent s--> lexQualSym :: (Token -> P a) -> P a -> [String] -> P a-> lexQualSym cont identCont mIdent p s =-> maybe (cont (idTok QSym mIdent sym)) (const identCont)-> (Map.lookup sym reserved_ops)-> (incr p (length sym)) rest-> where (sym,rest) = span isSym s---> lexQualPreludeSym :: (Token -> P a) -> Token -> P a -> [String] -> P a-> lexQualPreludeSym cont _ identCont mIdent p ('[':']':rest) =-> cont (idTok QId mIdent "[]") (incr p 2) rest-> lexQualPreludeSym cont _ identCont mIdent p ('(':rest)-> | not (null rest') && head rest'==')' -> = cont (idTok QId mIdent ('(':tup++")")) (incr p (length tup+2)) (tail rest')-> where (tup,rest') = span (==',') rest-> lexQualPreludeSym cont token _ _ p s = cont token p s---\end{verbatim}-{\em Note:} since Curry allows an unlimited range of integer numbers,-read numbers must be converted to Haskell type \texttt{Integer}.-\begin{verbatim}--> lexNumber :: (Token -> P a) -> P a-> lexNumber cont p ('0':c:s)-> | c `elem` "oO" = lexOctal cont nullCont (incr p 2) s-> | c `elem` "xX" = lexHexadecimal cont nullCont (incr p 2) s-> where nullCont _ _ = cont (intTok 10 "0") (next p) (c:s)-> lexNumber cont p s-> = lexOptFraction cont (integerTok 10 digits) digits-> (incr p (length digits)) rest-> where (digits,rest) = span isDigit s-> num = (read digits) :: Integer--> lexOctal :: (Token -> P a) -> P a -> P a-> lexOctal cont nullCont p s-> | null digits = nullCont undefined undefined-> | otherwise = cont (integerTok 8 digits) (incr p (length digits)) rest-> where (digits,rest) = span isOctit s--> lexHexadecimal :: (Token -> P a) -> P a -> P a-> lexHexadecimal cont nullCont p s-> | null digits = nullCont undefined undefined-> | otherwise = cont (integerTok 16 digits) (incr p (length digits)) rest-> where (digits,rest) = span isHexit s--> lexOptFraction :: (Token -> P a) -> Token -> String -> P a-> lexOptFraction cont _ mant p ('.':c:s)-> | isDigit c = lexOptExponent cont (floatTok mant frac 0 "") mant frac-> (incr p (length frac+1)) rest-> where (frac,rest) = span isDigit (c:s)-> lexOptFraction cont token mant p (c:s)-> | c `elem` "eE" = lexSignedExponent cont intCont mant "" [c] (next p) s-> where intCont _ _ = cont token p (c:s)-> lexOptFraction cont token _ p s = cont token p s--> lexOptExponent :: (Token -> P a) -> Token -> String -> String -> P a-> lexOptExponent cont token mant frac p (c:s)-> | c `elem` "eE" = lexSignedExponent cont floatCont mant frac [c] (next p) s-> where floatCont _ _ = cont token p (c:s)-> lexOptExponent cont token mant frac p s = cont token p s--> lexSignedExponent :: (Token -> P a) -> P a -> String -> String -> String -> P a-> lexSignedExponent cont floatCont mant frac e p ('+':c:s)-> | isDigit c = lexExponent cont mant frac (e++"+") id (next p) (c:s)-> lexSignedExponent cont floatCont mant frac e p ('-':c:s)-> | isDigit c = lexExponent cont mant frac (e++"-") negate (next p) (c:s)-> lexSignedExponent cont floatCont mant frac e p (c:s)-> | isDigit c = lexExponent cont mant frac e id p (c:s)-> lexSignedExponent cont floatCont mant frac e p s = floatCont p s--> lexExponent :: (Token -> P a) -> String -> String -> String -> (Int -> Int) -> P a-> lexExponent cont mant frac e expSign p s =-> cont (floatTok mant frac exp (e++digits)) (incr p (length digits)) rest-> where (digits,rest) = span isDigit s-> exp = expSign (convertIntegral 10 digits)--> lexChar :: Position -> SuccessP a -> FailP a -> P a-> lexChar p0 success fail p [] = fail p0 "Illegal character constant" p []-> lexChar p0 success fail p (c:s)-> | c == '\\' = lexEscape p (lexCharEnd p0 success fail) fail (next p) s-> | c == '\n' = fail p0 "Illegal character constant" p (c:s)-> | c == '\t' = lexCharEnd p0 success fail c "\t" (tab p) s-> | otherwise = lexCharEnd p0 success fail c [c] (next p) s--> lexCharEnd :: Position -> SuccessP a -> FailP a -> Char -> String -> P a-> lexCharEnd p0 success fail c o p ('\'':s) = success p0 (charTok c o) (next p) s-> lexCharEnd p0 success fail c o p s =-> fail p0 "Improperly terminated character constant" p s--> lexString :: Position -> SuccessP a -> FailP a -> P a-> lexString p0 success fail = lexStringRest p0 success fail "" id--> lexStringRest :: Position -> SuccessP a -> FailP a -> String -> (String -> String) -> P a-> lexStringRest p0 success fail s0 so p [] = -> fail p0 "Improperly terminated string constant" p []-> lexStringRest p0 success fail s0 so p (c:s)-> | c == '\\' =-> lexStringEscape p (lexStringRest p0 success fail) fail s0 so (next p) s-> | c == '\"' = success p0 (stringTok (reverse s0) (so "")) (next p) s-> | c == '\n' = fail p0 "Improperly terminated string constant" p []-> | c == '\t' = lexStringRest p0 success fail (c:s0) (so . (c:)) (tab p) s-> | otherwise = lexStringRest p0 success fail (c:s0) (so . (c:)) (next p) s--> lexStringEscape :: Position -> (String -> (String -> String) -> P a) -> FailP a -> -> String -> (String -> String) -> P a-> lexStringEscape p0 success fail s0 so p [] = lexEscape p0 undefined fail p []-> lexStringEscape p0 success fail s0 so p (c:s)-> | c == '&' = success s0 (so . ("\\&"++)) (next p) s-> | isSpace c = lexStringGap (success s0) fail so p (c:s)-> | otherwise = lexEscape p0 (\ c' s' -> success (c':s0) (so . (s'++))) fail p (c:s)--> lexStringGap :: ((String -> String) -> P a) -> FailP a -> (String -> String) -> P a-> lexStringGap success fail so p [] = fail p "End of file in string gap" p []-> lexStringGap success fail so p (c:s)-> | c == '\\' = success (so . (c:)) (next p) s-> | c == '\t' = lexStringGap success fail (so . (c:)) (tab p) s-> | c == '\n' = lexStringGap success fail (so . (c:)) (nl p) s-> | isSpace c = lexStringGap success fail (so . (c:)) (next p) s-> | otherwise = fail p ("Illegal character in string gap " ++ show c) p s--> lexEscape :: Position -> (Char -> String -> P a) -> FailP a -> P a-> lexEscape p0 success fail p ('a':s) = success '\a' "\\a" (next p) s-> lexEscape p0 success fail p ('b':s) = success '\b' "\\b" (next p) s-> lexEscape p0 success fail p ('f':s) = success '\f' "\\f" (next p) s-> lexEscape p0 success fail p ('n':s) = success '\n' "\\n" (next p) s-> lexEscape p0 success fail p ('r':s) = success '\r' "\\r" (next p) s-> lexEscape p0 success fail p ('t':s) = success '\t' "\\t" (next p) s-> lexEscape p0 success fail p ('v':s) = success '\v' "\\v" (next p) s-> lexEscape p0 success fail p ('\\':s) = success '\\' "\\\\" (next p) s-> lexEscape p0 success fail p ('"':s) = success '\"' "\\\"" (next p) s-> lexEscape p0 success fail p ('\'':s) = success '\'' "\\\'" (next p) s-> lexEscape p0 success fail p ('^':c:s)-> | isUpper c || c `elem` "@[\\]^_" =-> success (chr (ord c `mod` 32)) ("\\^"++[c]) (incr p 2) s-> lexEscape p0 success fail p ('o':c:s)-> | isOctit c = numEscape p0 success fail 8 isOctit ("\\o"++) (next p) (c:s)-> lexEscape p0 success fail p ('x':c:s)-> | isHexit c = numEscape p0 success fail 16 isHexit ("\\x"++) (next p) (c:s)-> lexEscape p0 success fail p (c:s)-> | isDigit c = numEscape p0 success fail 10 isDigit ("\\"++) p (c:s)-> lexEscape p0 success fail p s = asciiEscape p0 success fail p s--> asciiEscape :: Position -> (Char -> String -> P a) -> FailP a -> P a-> asciiEscape p0 success fail p ('N':'U':'L':s) = success '\NUL' "\\NUL" (incr p 3) s-> asciiEscape p0 success fail p ('S':'O':'H':s) = success '\SOH' "\\SOH" (incr p 3) s-> asciiEscape p0 success fail p ('S':'T':'X':s) = success '\STX' "\\STX" (incr p 3) s-> asciiEscape p0 success fail p ('E':'T':'X':s) = success '\ETX' "\\ETX" (incr p 3) s-> asciiEscape p0 success fail p ('E':'O':'T':s) = success '\EOT' "\\EOT" (incr p 3) s-> asciiEscape p0 success fail p ('E':'N':'Q':s) = success '\ENQ' "\\ENQ" (incr p 3) s-> asciiEscape p0 success fail p ('A':'C':'K':s) = success '\ACK' "\\ACK" (incr p 3) s -> asciiEscape p0 success fail p ('B':'E':'L':s) = success '\BEL' "\\BEL" (incr p 3) s-> asciiEscape p0 success fail p ('B':'S':s) = success '\BS' "\\BS" (incr p 2) s-> asciiEscape p0 success fail p ('H':'T':s) = success '\HT' "\\HT" (incr p 2) s-> asciiEscape p0 success fail p ('L':'F':s) = success '\LF' "\\LF" (incr p 2) s-> asciiEscape p0 success fail p ('V':'T':s) = success '\VT' "\\VT" (incr p 2) s-> asciiEscape p0 success fail p ('F':'F':s) = success '\FF' "\\FF" (incr p 2) s-> asciiEscape p0 success fail p ('C':'R':s) = success '\CR' "\\CR" (incr p 2) s-> asciiEscape p0 success fail p ('S':'O':s) = success '\SO' "\\SO" (incr p 2) s-> asciiEscape p0 success fail p ('S':'I':s) = success '\SI' "\\SI" (incr p 2) s-> asciiEscape p0 success fail p ('D':'L':'E':s) = success '\DLE' "\\DLE" (incr p 3) s -> asciiEscape p0 success fail p ('D':'C':'1':s) = success '\DC1' "\\DC1" (incr p 3) s-> asciiEscape p0 success fail p ('D':'C':'2':s) = success '\DC2' "\\DC2" (incr p 3) s-> asciiEscape p0 success fail p ('D':'C':'3':s) = success '\DC3' "\\DC3" (incr p 3) s-> asciiEscape p0 success fail p ('D':'C':'4':s) = success '\DC4' "\\DC4" (incr p 3) s-> asciiEscape p0 success fail p ('N':'A':'K':s) = success '\NAK' "\\NAK" (incr p 3) s-> asciiEscape p0 success fail p ('S':'Y':'N':s) = success '\SYN' "\\SYN" (incr p 3) s-> asciiEscape p0 success fail p ('E':'T':'B':s) = success '\ETB' "\\ETB" (incr p 3) s-> asciiEscape p0 success fail p ('C':'A':'N':s) = success '\CAN' "\\CAN" (incr p 3) s -> asciiEscape p0 success fail p ('E':'M':s) = success '\EM' "\\EM" (incr p 2) s-> asciiEscape p0 success fail p ('S':'U':'B':s) = success '\SUB' "\\SUB" (incr p 3) s-> asciiEscape p0 success fail p ('E':'S':'C':s) = success '\ESC' "\\ESC" (incr p 3) s-> asciiEscape p0 success fail p ('F':'S':s) = success '\FS' "\\FS" (incr p 2) s-> asciiEscape p0 success fail p ('G':'S':s) = success '\GS' "\\GS" (incr p 2) s-> asciiEscape p0 success fail p ('R':'S':s) = success '\RS' "\\RS" (incr p 2) s-> asciiEscape p0 success fail p ('U':'S':s) = success '\US' "\\US" (incr p 2) s-> asciiEscape p0 success fail p ('S':'P':s) = success '\SP' "\\SP" (incr p 2) s-> asciiEscape p0 success fail p ('D':'E':'L':s) = success '\DEL' "\\DEL" (incr p 3) s-> asciiEscape p0 success fail p s = fail p0 "Illegal escape sequence" p s--> numEscape :: Position -> (Char -> String -> P a) -> FailP a -> Int-> -> (Char -> Bool) -> (String -> String) -> P a-> numEscape p0 success fail b isDigit so p s-> | n >= min && n <= max = success (chr n) (so digits) (incr p (length digits)) rest-> | otherwise = fail p0 "Numeric escape out-of-range" p s-> where (digits,rest) = span isDigit s-> n = convertIntegral b digits-> min = ord minBound-> max = ord maxBound--\end{verbatim}
+ src/Curry/Syntax/Parser.hs view
@@ -0,0 +1,1428 @@+{- |+ Module : $Header$+ Description : A Parser for Curry+ Copyright : (c) 1999 - 2004 Wolfgang Lux+ 2005 Martin Engelke+ 2011 - 2015 Björn Peemöller+ 2016 - 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ The Curry parser is implemented using the (mostly) LL(1) parsing+ combinators implemented in 'Curry.Base.LLParseComb'.+-}+module Curry.Syntax.Parser+ ( parseSource, parseHeader, parsePragmas, parseInterface, parseGoal+ ) where++import Curry.Base.Ident+import Curry.Base.Monad (CYM)+import Curry.Base.Position (Position(..), getPosition, setPosition, incr)+import Curry.Base.LLParseComb+import Curry.Base.Span hiding (file) -- clash with Position.file+import Curry.Base.SpanInfo++import Curry.Syntax.Extension+import Curry.Syntax.Lexer (Token (..), Category (..), Attributes (..), lexer)+import Curry.Syntax.Type++-- |Parse a 'Module'+parseSource :: FilePath -> String -> CYM (Module ())+parseSource = fullParser (mkMod <$> moduleHeader <*> layout moduleDecls) lexer+ where mkMod f ((im, ds), lay) = f lay im ds++-- |Parse only pragmas of a 'Module'+parsePragmas :: FilePath -> String -> CYM (Module ())+parsePragmas+ = prefixParser ((\ps sp -> setEndPosition NoPos+ (Module (spanInfo sp []) WhitespaceLayout+ ps mainMIdent Nothing [] []))+ <$> modulePragmas <*> spanPosition)+ lexer++-- |Parse a 'Module' header+parseHeader :: FilePath -> String -> CYM (Module ())+parseHeader = prefixParser+ (mkMod <$> moduleHeader <*> startLayout importDecls) lexer+ where+ importDecls = mkImport <$> many ((,) <$> importDecl+ <*> many (spanPosition <*-> semicolon))+ mkImport xs = let (im, spss) = unzip xs in (im, concat spss)+ mkMod f (im, lay) = f lay im []++-- |Parse an 'Interface'+parseInterface :: FilePath -> String -> CYM Interface+parseInterface = fullParser interface lexer++-- |Parse a 'Goal'+parseGoal :: String -> CYM (Goal ())+parseGoal = fullParser goal lexer ""++-- ---------------------------------------------------------------------------+-- Module header+-- ---------------------------------------------------------------------------++-- |Parser for a module header+moduleHeader :: Parser a Token+ (LayoutInfo -> [ImportDecl] -> [Decl b] -> Module b)+moduleHeader =+ (\sp ps (m, es, inf) lay is ds -> updateEndPos $+ Module (spanInfo sp inf) lay ps m es is ds)+ <$> spanPosition+ <*> modulePragmas+ <*> header+ where header = (\sp1 m es sp2 -> (m, es, [sp1,sp2]))+ <$> tokenSpan KW_module+ <*> modIdent+ <*> option exportSpec+ <*> spanPosition+ <*-> expectWhere+ `opt` (mainMIdent, Nothing, [])++modulePragmas :: Parser a Token [ModulePragma]+modulePragmas = many (languagePragma <|> optionsPragma)++languagePragma :: Parser a Token ModulePragma+languagePragma = languagePragma'+ <$> tokenSpan PragmaLanguage+ <*> (languageExtension `sepBy1Sp` comma)+ <*> tokenSpan PragmaEnd+ where languageExtension = classifyExtension <$> ident+ languagePragma' sp1 (ex, ss) sp2 = updateEndPos $+ LanguagePragma (spanInfo sp1 (sp1 : ss ++ [sp2])) ex++-- TODO The span info is not 100% complete due to the lexer+-- combining OPTIONS, toolVal and toolArgs+optionsPragma :: Parser a Token ModulePragma+optionsPragma = optionsPragma'+ <$> spanPosition+ <*> token PragmaOptions+ <*> tokenSpan PragmaEnd+ where optionsPragma' sp1 a sp2 = updateEndPos $+ OptionsPragma (spanInfo sp1 [sp1, sp2])+ (classifyTool <$> toolVal a)+ (toolArgs a)++-- |Parser for an export specification+exportSpec :: Parser a Token ExportSpec+exportSpec = exportSpec' <$> spanPosition <*> parensSp (export `sepBySp` comma)+ where exportSpec' sp1 ((ex, ss),sp2,sp3) = updateEndPos $+ Exporting (spanInfo sp1 (sp2:(ss ++ [sp3]))) ex++-- |Parser for an export item+export :: Parser a Token Export+export = qtycon <**> (tcExportWith <$> parensSp spec `opt` tcExport)+ <|> tcExport <$> qfun <\> qtycon+ <|> exportModule' <$> tokenSpan KW_module <*> modIdent+ where spec = (\sp -> (ExportTypeAll , [sp])) <$> tokenSpan DotDot+ <|> (\(c, ss) -> (exportTypeWith' c, ss )) <$> con `sepBySp` comma+ tcExport qtc = updateEndPos $ Export (fromSrcSpan (getSrcSpan qtc)) qtc+ tcExportWith ((spc, ss), sp1, sp2) qtc =+ updateEndPos $ setSrcInfoPoints (sp1 : (ss ++ [sp2])) $+ spc (fromSrcSpan (getSrcSpan qtc)) qtc+ exportTypeWith' c spi qtc = ExportTypeWith spi qtc c+ exportModule' sp = updateEndPos . ExportModule (spanInfo sp [sp])++moduleDecls :: Parser a Token (([ImportDecl], [Decl ()]), [Span])+moduleDecls = mkImpDecl <$> importDecl+ <*> (moduleDecls' `opt` ([], [], []))+ <|> mkTopDecl <$> topDecls+ where+ mkImpDecl i (is, ds, sps) = ((i:is, ds), sps)+ mkTopDecl (ds, sps) = (([], ds), sps)++ moduleDecls' = mkDecls <$> spanPosition <*-> semicolon <*> moduleDecls+ mkDecls sp ((im, ds), sps) = (im, ds, sp:sps)++-- |Parser for a single import declaration+importDecl :: Parser a Token ImportDecl+importDecl = importDecl'+ <$> tokenSpan KW_import+ <*> option (tokenSpan Id_qualified)+ <*> modIdent+ <*> option ((,) <$> tokenSpan Id_as <*> modIdent)+ <*> option importSpec+ where+ importDecl' sp1 (Just sp2) mid (Just (sp3, alias)) = updateEndPos .+ ImportDecl (spanInfo sp1 [sp1, sp2, sp3]) mid True (Just alias)+ importDecl' sp1 Nothing mid (Just (sp3, alias)) = updateEndPos .+ ImportDecl (spanInfo sp1 [sp1, sp3]) mid False (Just alias)+ importDecl' sp1 (Just sp2) mid Nothing = updateEndPos .+ ImportDecl (spanInfo sp1 [sp1, sp2]) mid True Nothing+ importDecl' sp1 Nothing mid Nothing = updateEndPos .+ ImportDecl (spanInfo sp1 [sp1]) mid False Nothing++-- |Parser for an import specification+importSpec :: Parser a Token ImportSpec+importSpec = spanPosition+ <**> (hiding' <$-> token Id_hiding `opt` importing')+ <*> parensSp (importSp `sepBySp` comma)+ where+ hiding' sp1 ((specs, ss), sp2, sp3) = updateEndPos $+ Hiding (spanInfo sp1 (sp1 : sp2 : (ss ++ [sp3]))) specs+ importing' sp1 ((specs, ss), sp2, sp3) = updateEndPos $+ Importing (spanInfo sp1 ( sp2 : (ss ++ [sp3]))) specs++importSp :: Parser a Token Import+importSp = tycon <**> (tcImportWith <$> parensSp spec `opt` tcImport)+ <|> tcImport <$> fun <\> tycon+ where spec = (\sp -> (ImportTypeAll , [sp])) <$> tokenSpan DotDot+ <|> (\(c, ss) -> (importTypeWith' c, ss )) <$> con `sepBySp` comma+ tcImport tc = updateEndPos $ Import (fromSrcSpan (getSrcSpan tc)) tc+ tcImportWith ((spc, ss), sp1, sp2) tc =+ updateEndPos $ setSrcInfoPoints (sp1 : (ss ++ [sp2])) $+ spc (fromSrcSpan (getSrcSpan tc)) tc+ importTypeWith' c spi tc = ImportTypeWith spi tc c+-- ---------------------------------------------------------------------------+-- Interfaces+-- ---------------------------------------------------------------------------++-- |Parser for an interface+interface :: Parser a Token Interface+interface = uncurry <$> intfHeader <*> braces intfDecls++intfHeader :: Parser a Token ([IImportDecl] -> [IDecl] -> Interface)+intfHeader = Interface <$-> token Id_interface <*> modIdent <*-> expectWhere++intfDecls :: Parser a Token ([IImportDecl], [IDecl])+intfDecls = impDecl <$> iImportDecl+ <*> (semicolon <-*> intfDecls `opt` ([], []))+ <|> (,) [] <$> intfDecl `sepBy` semicolon+ where impDecl i (is, ds) = (i:is, ds)++-- |Parser for a single interface import declaration+iImportDecl :: Parser a Token IImportDecl+iImportDecl = IImportDecl <$> tokenPos KW_import <*> modIdent++-- |Parser for a single interface declaration+intfDecl :: Parser a Token IDecl+intfDecl = choice [ iInfixDecl, iHidingDecl, iDataDecl, iNewtypeDecl+ , iTypeDecl , iFunctionDecl <\> token Id_hiding+ , iClassDecl, iInstanceDecl ]++-- |Parser for an interface infix declaration+iInfixDecl :: Parser a Token IDecl+iInfixDecl = infixDeclLhs iInfixDecl' <*> integer <*> qfunop+ where iInfixDecl' sp = IInfixDecl (span2Pos sp)++-- |Parser for an interface hiding declaration+iHidingDecl :: Parser a Token IDecl+iHidingDecl = tokenPos Id_hiding <**> (hDataDecl <|> hClassDecl)+ where+ hDataDecl = hiddenData <$-> token KW_data <*> withKind qtycon <*> many tyvar+ hClassDecl = hiddenClass <$> classInstHead KW_class (withKind qtycls) clsvar+ hiddenData (tc, k) tvs p = HidingDataDecl p tc k tvs+ hiddenClass (_, _, cx, (qcls, k), tv) p = HidingClassDecl p cx qcls k tv++-- |Parser for an interface data declaration+iDataDecl :: Parser a Token IDecl+iDataDecl = iTypeDeclLhs IDataDecl KW_data <*> constrs <*> iHiddenPragma+ where constrs = equals <-*> constrDecl `sepBy1` bar `opt` []++-- |Parser for an interface newtype declaration+iNewtypeDecl :: Parser a Token IDecl+iNewtypeDecl = iTypeDeclLhs INewtypeDecl KW_newtype+ <*-> equals <*> newConstrDecl <*> iHiddenPragma++-- |Parser for an interface type synonym declaration+iTypeDecl :: Parser a Token IDecl+iTypeDecl = iTypeDeclLhs ITypeDecl KW_type+ <*-> equals <*> type0++-- |Parser for an interface hiding pragma+iHiddenPragma :: Parser a Token [Ident]+iHiddenPragma = token PragmaHiding+ <-*> (con `sepBy` comma)+ <*-> token PragmaEnd+ `opt` []++-- |Parser for an interface function declaration+iFunctionDecl :: Parser a Token IDecl+iFunctionDecl = IFunctionDecl <$> position <*> qfun <*> option iMethodPragma+ <*> arity <*-> token DoubleColon <*> qualType++-- |Parser for an interface method pragma+iMethodPragma :: Parser a Token Ident+iMethodPragma = token PragmaMethod <-*> clsvar <*-> token PragmaEnd++-- |Parser for function's arity+arity :: Parser a Token Int+arity = int `opt` 0++iTypeDeclLhs :: (Position -> QualIdent -> Maybe KindExpr -> [Ident] -> a)+ -> Category -> Parser b Token a+iTypeDeclLhs f kw = f' <$> tokenPos kw <*> withKind qtycon <*> many tyvar+ where f' p (tc, k) = f p tc k++-- |Parser for an interface class declaration+iClassDecl :: Parser a Token IDecl+iClassDecl = (\(sp, _, cx, (qcls, k), tv) ->+ IClassDecl (span2Pos sp) cx qcls k tv)+ <$> classInstHead KW_class (withKind qtycls) clsvar+ <*> braces (iMethod `sepBy` semicolon)+ <*> iClassHidden++-- |Parser for an interface method declaration+iMethod :: Parser a Token IMethodDecl+iMethod = IMethodDecl <$> position+ <*> fun <*> option int <*-> token DoubleColon <*> qualType++-- |Parser for an interface hiding pragma+iClassHidden :: Parser a Token [Ident]+iClassHidden = token PragmaHiding+ <-*> (fun `sepBy` comma)+ <*-> token PragmaEnd+ `opt` []++-- |Parser for an interface instance declaration+iInstanceDecl :: Parser a Token IDecl+iInstanceDecl = (\(sp, _, cx, qcls, inst) ->+ IInstanceDecl (span2Pos sp) cx qcls inst)+ <$> classInstHead KW_instance qtycls type2+ <*> braces (iImpl `sepBy` semicolon)+ <*> option iModulePragma++-- |Parser for an interface method implementation+iImpl :: Parser a Token IMethodImpl+iImpl = (,) <$> fun <*> arity++iModulePragma :: Parser a Token ModuleIdent+iModulePragma = token PragmaModule <-*> modIdent <*-> token PragmaEnd++-- ---------------------------------------------------------------------------+-- Top-Level Declarations+-- ---------------------------------------------------------------------------++topDecls :: Parser a Token ([Decl ()], [Span])+topDecls = topDecl `sepBySp` semicolon++topDecl :: Parser a Token (Decl ())+topDecl = choice [ dataDecl, externalDataDecl, newtypeDecl, typeDecl+ , classDecl, instanceDecl, defaultDecl+ , infixDecl, functionDecl ]++dataDecl :: Parser a Token (Decl ())+dataDecl = combineWithSpans+ <$> typeDeclLhs dataDecl' KW_data+ <*> ((addSpan <$> tokenSpan Equals <*> constrs) `opt` ([],[]))+ <*> deriv+ where constrs = constrDecl `sepBy1Sp` bar+ dataDecl' sp = DataDecl (spanInfo sp [sp])++externalDataDecl :: Parser a Token (Decl ())+externalDataDecl = decl <$> tokenSpan KW_external <*> typeDeclLhs (,,) KW_data+ where decl sp1 (sp2, tc, tvs) = updateEndPos $+ ExternalDataDecl (spanInfo sp1 [sp1, sp2]) tc tvs++newtypeDecl :: Parser a Token (Decl ())+newtypeDecl = combineWithSpans+ <$> typeDeclLhs newtypeDecl' KW_newtype+ <*> ((\sp c -> (c, [sp])) <$> tokenSpan Equals <*> newConstrDecl)+ <*> deriv+ where newtypeDecl' sp = NewtypeDecl (spanInfo sp [sp])++combineWithSpans :: HasSpanInfo a =>+ (t1 -> t2 -> a) -> (t1, [Span]) -> (t2, [Span]) -> a+combineWithSpans df (cs, sps1) (cls, sps2)+ = updateEndPos $ setSrcInfoPoints (getSrcInfoPoints res ++ sps1 ++ sps2) res+ where res = df cs cls++typeDecl :: Parser a Token (Decl ())+typeDecl = typeDeclLhs typeDecl' KW_type <*> tokenSpan Equals <*> type0+ where typeDecl' sp1 tyc tyv sp2 txp = updateEndPos $+ TypeDecl (spanInfo sp1 [sp1, sp2]) tyc tyv txp++typeDeclLhs :: (Span -> Ident -> [Ident] -> a) -> Category+ -> Parser b Token a+typeDeclLhs f kw = f <$> tokenSpan kw <*> tycon <*> many anonOrTyvar++constrDecl :: Parser a Token ConstrDecl+constrDecl = spanPosition <**> constr+ where+ constr = conId <**> identDecl+ <|> tokenSpan LeftParen <**> parenDecl+ <|> type1 <\> conId <\> leftParen <**> opDecl+ identDecl = many type2 <**> (conType <$> opDecl `opt` conDecl)+ <|> recDecl <$> recFields+ parenDecl = conOpDeclPrefix+ <$> conSym <*> tokenSpan RightParen <*> type2 <*> type2+ <|> tupleType <**> (tokenSpan RightParen <**> opDeclParen)+ opDecl = conOpDecl <$> conop <*> type1+ opDeclParen = conOpDeclParen <$> conop <*> type1+ recFields = layoutOff <-*> bracesSp (fieldDecl `sepBySp` comma)+ conType f tys c = f $ foldl mkApply (mkConstructorType $ qualify c) tys+ mkApply t1 t2 = updateEndPos $ ApplyType (fromSrcSpan (getSrcSpan t1)) t1 t2+ mkConstructorType qid = ConstructorType (fromSrcSpan (getSrcSpan qid)) qid+ conDecl tys c sp = updateEndPos $+ ConstrDecl (SpanInfo sp []) c tys+ conOpDecl op ty2 ty1 sp = updateEndPos $+ ConOpDecl (SpanInfo sp []) ty1 op ty2+ conOpDeclParen op ty2 sp1 ty1 sp2 sp5 = updateEndPos $+ ConOpDecl (SpanInfo sp5 [sp2, sp1]) ty1 op ty2+ conOpDeclPrefix op sp1 ty1 ty2 sp2 sp3 = updateEndPos $+ ConOpDecl (SpanInfo sp3 [sp2, sp1]) ty1 op ty2+ recDecl ((fs, ss), sp1, sp2) c sp3 = updateEndPos $+ RecordDecl (SpanInfo sp3 (sp1 : ss ++ [sp2])) c fs++fieldDecl :: Parser a Token FieldDecl+fieldDecl = mkFieldDecl <$> spanPosition <*> labels+ <*> tokenSpan DoubleColon <*> type0+ where labels = fun `sepBy1Sp` comma+ mkFieldDecl sp1 (idt,ss) sp2 ty = updateEndPos $+ FieldDecl (spanInfo sp1 (ss ++ [sp2])) idt ty++newConstrDecl :: Parser a Token NewConstrDecl+newConstrDecl = spanPosition <**> (con <**> newConstr)+ where newConstr = newConDecl <$> type2+ <|> newRecDecl <$> newFieldDecl+ newConDecl ty c sp = updateEndPos $ NewConstrDecl (spanInfo sp []) c ty+ newRecDecl ((idt, sp2, ty), sp3, sp4) c sp1 = updateEndPos $+ NewRecordDecl (spanInfo sp1 [sp3,sp2,sp4]) c (idt, ty)++newFieldDecl :: Parser a Token ((Ident, Span, TypeExpr), Span, Span)+newFieldDecl = layoutOff <-*> bracesSp labelDecl+ where labelDecl = (,,) <$> fun <*> tokenSpan DoubleColon <*> type0++deriv :: Parser a Token ([QualIdent], [Span])+deriv = (addSpan <$> tokenSpan KW_deriving <*> classes) `opt` ([], [])+ where classes = ((\q -> ([q], [])) <$> qtycls)+ <|> ((\sp1 (qs, ss) sp2 -> (qs, sp1 : (ss ++ [sp2])))+ <$> tokenSpan LeftParen+ <*> (qtycls `sepBySp` comma)+ <*> tokenSpan RightParen)++functionDecl :: Parser a Token (Decl ())+functionDecl = spanPosition <**> decl+ where decl = fun `sepBy1Sp` comma <**> funListDecl <|?> funRule++funRule :: Parser a Token (Span -> Decl ())+funRule = mkFunDecl <$> lhs <*> declRhs+ where lhs = (\f ->+ (f, updateEndPos $ FunLhs (fromSrcSpan (getSrcSpan f)) f []))+ <$> fun <|?> funLhs++funListDecl :: Parser a Token (([Ident],[Span]) -> Span -> Decl ())+funListDecl = typeSig <|> mkExtFun <$> tokenSpan KW_external+ where mkExtFun sp1 (vs,ss) sp2 = updateEndPos $+ ExternalDecl (spanInfo sp2 (ss++[sp1])) (map (Var ()) vs)+++typeSig :: Parser a Token (([Ident],[Span]) -> Span -> Decl ())+typeSig = sig <$> tokenSpan DoubleColon <*> qualType+ where sig sp1 qty (vs,ss) sp2 = updateEndPos $+ TypeSig (spanInfo sp2 (ss++[sp1])) vs qty++mkFunDecl :: (Ident, Lhs ()) -> Rhs () -> Span -> Decl ()+mkFunDecl (f, lhs) rhs' p = updateEndPos $+ FunctionDecl (spanInfo p []) () f [updateEndPos $+ Equation (spanInfo p []) lhs rhs']++funLhs :: Parser a Token (Ident, Lhs ())+funLhs = mkFunLhs <$> fun <*> many1 pattern2+ <|?> flip ($ updateEndPos) <$> pattern1 <*> opLhs+ <|?> curriedLhs+ where+ opLhs = opLHS funSym (gConSym <\> funSym)+ <|> tokenSpan Backquote <**>+ opLHSSp ((,) <$> funId <*> spanPosition+ <*-> expectBackquote)+ ((,) <$> qConId <\> funId <*> spanPosition+ <*-> expectBackquote)+ opLHS funP consP = mkOpLhs <$> funP <*> pattern0+ <|> mkInfixPat <$> consP <*> pattern1 <*> opLhs+ opLHSSp funP consP = mkOpLhsSp <$> funP <*> pattern0+ <|> mkInfixPatSp <$> consP <*> pattern1 <*> opLhs+ mkFunLhs f ts = (f , updateEndPos $ FunLhs (fromSrcSpan (getSrcSpan f)) f ts)+ mkOpLhs op t2 f t1 =+ let t1' = f t1+ in (op, updateEndPos $ OpLhs (fromSrcSpan (getSrcSpan t1')) t1' op t2)+ mkInfixPat op t2 f g t1 =+ f (g . InfixPattern (fromSrcSpan (getSrcSpan t1)) () t1 op) t2+ mkOpLhsSp (op, sp1) t2 sp2 f t1 =+ let t1' = f t1+ in (op, updateEndPos $+ OpLhs (spanInfo (getSrcSpan t1') [sp2, sp1]) t1' op t2)++ mkInfixPatSp (op, sp1) t2 g sp2 f t1 =+ g (f . InfixPattern (spanInfo (getSrcSpan t1) [sp2, sp1]) () t1 op) t2+++curriedLhs :: Parser a Token (Ident, Lhs ())+curriedLhs = apLhs <$> parensSp funLhs <*> many1 pattern2+ where apLhs ((f, lhs), sp1, sp2) ts =+ let spi = fromSrcSpan sp1+ in (f, updateEndPos $ setSrcInfoPoints [sp1, sp2] $ ApLhs spi lhs ts)++declRhs :: Parser a Token (Rhs ())+declRhs = rhs equals++rhs :: Parser a Token b -> Parser a Token (Rhs ())+rhs eq = rhsExpr <*> localDecls+ where rhsExpr = mkSimpleRhs <$> spanPosition <*-> eq <*> expr+ <|> mkGuardedRhs <$> spanPosition <*> many1 (condExpr eq)+ mkSimpleRhs sp1 e (Just sp2, ds, li) = updateEndPos $+ SimpleRhs (SpanInfo sp1 [sp1, sp2]) li e ds+ mkSimpleRhs sp1 e (Nothing, ds, li) = updateEndPos $+ SimpleRhs (SpanInfo sp1 [sp1]) li e ds+ mkGuardedRhs sp1 ce (Just sp2, ds, li) = updateEndPos $+ GuardedRhs (SpanInfo sp1 [sp1, sp2]) li ce ds+ mkGuardedRhs sp1 ce (Nothing, ds, li) = updateEndPos $+ GuardedRhs (SpanInfo sp1 [sp1]) li ce ds++whereClause :: Parser a Token b -> Parser a Token (Maybe Span, [b], LayoutInfo)+whereClause decl = (\sp (ds, li) -> (Just sp, ds, li))+ <$> tokenSpan KW_where+ <*> layoutWhere decl `opt` (Nothing, [], WhitespaceLayout)++localDecls :: Parser a Token (Maybe Span, [Decl ()], LayoutInfo)+localDecls = whereClause valueOrInfixDecl++valueDecls :: Parser a Token ([Decl ()], [Span])+valueDecls = valueOrInfixDecl `sepBySp` semicolon++valueOrInfixDecl :: Parser a Token (Decl ())+valueOrInfixDecl = choice [infixDecl, valueDecl]++infixDecl :: Parser a Token (Decl ())+infixDecl = infixDeclLhs infixDecl'+ <*> option ((,) <$> spanPosition <*> integer)+ <*> funop `sepBy1Sp` comma+ where infixDecl' sp1 inf (Just (sp2, pr)) (ids, ss) =+ updateEndPos $ InfixDecl (spanInfo sp1 (sp1:sp2:ss)) inf (Just pr) ids+ infixDecl' sp1 inf Nothing (ids, ss) =+ updateEndPos $ InfixDecl (spanInfo sp1 (sp1 :ss)) inf Nothing ids++infixDeclLhs :: (Span -> Infix -> a) -> Parser b Token a+infixDeclLhs f = f <$> spanPosition <*> tokenOps infixKW+ where infixKW = [(KW_infix, Infix), (KW_infixl, InfixL), (KW_infixr, InfixR)]++valueDecl :: Parser a Token (Decl ())+valueDecl = spanPosition <**> decl+ where+ decl = var `sepBy1Sp` comma <**> valListDecl+ <|?> patOrFunDecl <$> pattern0 <*> declRhs+ <|?> mkFunDecl <$> curriedLhs <*> declRhs++ valListDecl = funListDecl+ <|> mkFree <$> tokenSpan KW_free+ where mkFree sp1 (vs, ss) sp2 = updateEndPos $+ FreeDecl (spanInfo sp2 (ss ++ [sp1])) (map (Var ()) vs)++ patOrFunDecl (ConstructorPattern spi _ c ts)+ | not (isConstrId c) = mkFunDecl (f, FunLhs spi f ts)+ where f = unqualify c+ patOrFunDecl t = patOrOpDecl updateEndPos t++ patOrOpDecl f (InfixPattern spi a t1 op t2)+ | isConstrId op = patOrOpDecl (f . InfixPattern spi a t1 op) t2+ | otherwise = mkFunDecl (op', updateEndPos $ OpLhs spi (f t1) op' t2)+ where op' = unqualify op+ patOrOpDecl f t = mkPatDecl (f t)++ mkPatDecl t rhs' sp = updateEndPos $ PatternDecl (fromSrcSpan sp) t rhs'++ isConstrId c = c == qConsId || isQualified c || isQTupleId c++defaultDecl :: Parser a Token (Decl ())+defaultDecl = mkDefaultDecl <$> tokenSpan KW_default+ <*> parensSp (type0 `sepBySp` comma)+ where mkDefaultDecl sp1 ((ty, ss), sp2, sp3) = updateEndPos $+ DefaultDecl (spanInfo sp1 (sp1 : sp2 : (ss ++ [sp3]))) ty++classInstHead :: Category -> Parser a Token b -> Parser a Token c+ -> Parser a Token (Span, [Span], Context, b, c)+classInstHead kw cls ty = f <$> tokenSpan kw+ <*> optContext (,,) ((,) <$> cls <*> ty)+ where f sp (cx, ss, (cls', ty')) = (sp, ss, cx, cls', ty')++classDecl :: Parser a Token (Decl ())+classDecl = mkClass+ <$> classInstHead KW_class tycls clsvar+ <*> whereClause innerDecl+ where+ --TODO: Refactor by left-factorization+ --TODO: Support infixDecl+ innerDecl = foldr1 (<|?>)+ [ spanPosition <**> (fun `sepBy1Sp` comma <**> typeSig)+ , spanPosition <**> funRule+ {-, infixDecl-} ]+ mkClass (sp1, ss, cx, cls, tv) (Just sp2, ds, li) = updateEndPos $+ ClassDecl (SpanInfo sp1 (sp1 : (ss ++ [sp2]))) li cx cls tv ds+ mkClass (sp1, ss, cx, cls, tv) (Nothing, ds, li) = updateEndPos $+ ClassDecl (SpanInfo sp1 (sp1 : ss)) li cx cls tv ds++instanceDecl :: Parser a Token (Decl ())+instanceDecl = mkInstance+ <$> classInstHead KW_instance qtycls type2+ <*> whereClause innerDecl+ where+ innerDecl = spanPosition <**> funRule+ mkInstance (sp1, ss, cx, qcls, inst) (Just sp2, ds, li) = updateEndPos $+ InstanceDecl (SpanInfo sp1 (sp1 : (ss ++ [sp2]))) li cx qcls inst ds+ mkInstance (sp1, ss, cx, qcls, inst) (Nothing, ds, li) = updateEndPos $+ InstanceDecl (SpanInfo sp1 (sp1 : ss)) li cx qcls inst ds+-- ---------------------------------------------------------------------------+-- Type classes+-- ---------------------------------------------------------------------------++optContext :: (Context -> [Span] -> a -> b)+ -> Parser c Token a+ -> Parser c Token b+optContext f p = combine <$> context <*> tokenSpan DoubleArrow <*> p+ <|?> f [] [] <$> p+ where combine (ctx, ss) sp = f ctx (ss ++ [sp])++context :: Parser a Token (Context, [Span])+context = (\c -> ([c], [])) <$> constraint+ <|> combine <$> parensSp (constraint `sepBySp` comma)+ where combine ((ctx, ss), sp1, sp2) = (ctx, sp1 : (ss ++ [sp2]))++constraint :: Parser a Token Constraint+constraint = mkConstraint <$> spanPosition <*> qtycls <*> conType+ where varType = mkVariableType <$> spanPosition <*> clsvar+ conType = fmap ((,) []) varType+ <|> mk <$> parensSp+ (foldl mkApplyType <$> varType <*> many1 type2)+ mkConstraint sp qtc (ss, ty) = updateEndPos $+ Constraint (spanInfo sp ss) qtc ty+ mkVariableType sp = VariableType (fromSrcSpan sp)+ mkApplyType t1 t2 =+ ApplyType (fromSrcSpan (combineSpans (getSrcSpan t1)+ (getSrcSpan t2)))+ t1 t2+ mk (a, sp1, sp2) = ([sp1, sp2], a)++-- ---------------------------------------------------------------------------+-- Kinds+-- ---------------------------------------------------------------------------++withKind :: Parser a Token b -> Parser a Token (b, Maybe KindExpr)+withKind p = implicitKind <$> p+ <|?> parens (explicitKind <$> p <*-> token DoubleColon <*> kind0)+ where implicitKind x = (x, Nothing)+ explicitKind x k = (x, Just k)++-- kind0 ::= kind1 ['->' kind0]+kind0 :: Parser a Token KindExpr+kind0 = kind1 `chainr1` (ArrowKind <$-> token RightArrow)++-- kind1 ::= * | '(' kind0 ')'+kind1 :: Parser a Token KindExpr+kind1 = Star <$-> token SymStar+ <|> parens kind0++-- ---------------------------------------------------------------------------+-- Types+-- ---------------------------------------------------------------------------++-- qualType ::= [context '=>'] type0+qualType :: Parser a Token QualTypeExpr+qualType = mkQualTypeExpr <$> spanPosition <*> optContext (,,) type0+ where mkQualTypeExpr sp (cx, ss, ty) = updateEndPos $+ QualTypeExpr (spanInfo sp ss) cx ty++-- type0 ::= type1 ['->' type0]+type0 :: Parser a Token TypeExpr+type0 = type1 `chainr1` (mkArrowType <$> tokenSpan RightArrow)+ where mkArrowType sp ty1 ty2 = updateEndPos $+ ArrowType (spanInfo (getSrcSpan ty1) [sp]) ty1 ty2++-- type1 ::= [type1] type2+type1 :: Parser a Token TypeExpr+type1 = foldl1 mkApplyType <$> many1 type2+ where mkApplyType ty1 ty2 = updateEndPos $+ ApplyType (fromSrcSpan (getSrcSpan ty1)) ty1 ty2++-- type2 ::= anonType | identType | parenType | bracketType+type2 :: Parser a Token TypeExpr+type2 = anonType <|> identType <|> parenType <|> bracketType++-- anonType ::= '_'+anonType :: Parser a Token TypeExpr+anonType = mkVariableType <$> spanPosition <*> anonIdent+ where mkVariableType sp = VariableType (fromSrcSpan sp)++-- identType ::= <identifier>+identType :: Parser a Token TypeExpr+identType = mkVariableType <$> spanPosition <*> tyvar+ <|> mkConstructorType <$> spanPosition <*> qtycon <\> tyvar+ where mkVariableType sp = VariableType (fromSrcSpan sp)+ mkConstructorType sp = ConstructorType (fromSrcSpan sp)++-- parenType ::= '(' tupleType ')'+parenType :: Parser a Token TypeExpr+parenType = fmap updateSpanWithBrackets (parensSp tupleType)++-- tupleType ::= type0 (parenthesized type)+-- | type0 ',' type0 { ',' type0 } (tuple type)+-- | '->' (function type constructor)+-- | ',' { ',' } (tuple type constructor)+-- | (unit type)+tupleType :: Parser a Token TypeExpr+tupleType = type0 <**> (mkTuple <$> many1 ((,) <$> tokenSpan Comma <*> type0)+ `opt` ParenType NoSpanInfo)+ <|> tokenSpan RightArrow <**> succeed (mkConstructorType qArrowId)+ <|> mkConstructorTupleType <$> many1 (tokenSpan Comma)+ <|> succeed (ConstructorType NoSpanInfo qUnitId)+ where mkTuple stys ty = let (ss, tys) = unzip stys+ in TupleType (fromSrcInfoPoints ss) (ty : tys)+ mkConstructorType qid sp = ConstructorType (fromSrcInfoPoints [sp]) qid+ mkConstructorTupleType ss = ConstructorType (fromSrcInfoPoints ss)+ (qTupleId (length ss + 1))++-- bracketType ::= '[' listType ']'+bracketType :: Parser a Token TypeExpr+bracketType = fmap updateSpanWithBrackets (bracketsSp listType)++-- listType ::= type0 (list type)+-- | (list type constructor)+listType :: Parser a Token TypeExpr+listType = ListType NoSpanInfo <$> type0+ `opt` ConstructorType NoSpanInfo qListId++-- ---------------------------------------------------------------------------+-- Literals+-- ---------------------------------------------------------------------------++-- literal ::= '\'' <escaped character> '\''+-- | <integer>+-- | <float>+-- | '"' <escaped string> '"'+literal :: Parser a Token Literal+literal = Char <$> char+ <|> Int <$> integer+ <|> Float <$> float+ <|> String <$> string++-- ---------------------------------------------------------------------------+-- Patterns+-- ---------------------------------------------------------------------------++-- pattern0 ::= pattern1 [ gconop pattern0 ]+pattern0 :: Parser a Token (Pattern ())+pattern0 = pattern1 `chainr1` (mkInfixPattern <$> gconop)+ where mkInfixPattern qid p1 p2 =+ InfixPattern (fromSrcSpan (combineSpans (getSrcSpan p1)+ (getSrcSpan p2)))+ () p1 qid p2++-- pattern1 ::= varId+-- | QConId { pattern2 }+-- | '-' Integer+-- | '-.' Float+-- | '(' parenPattern'+-- | pattern2+pattern1 :: Parser a Token (Pattern ())+pattern1 = varId <**> identPattern' -- unqualified+ <|> qConId <\> varId <**> constrPattern -- qualified+ <|> mkNegNum <$> minus <*> negNum+ <|> tokenSpan LeftParen <**> parenPattern'+ <|> pattern2 <\> qConId <\> leftParen+ where+ identPattern' = optAsRecPattern+ <|> mkConsPattern qualify <$> many1 pattern2++ constrPattern = mkConsPattern id <$> many1 pattern2+ <|> optRecPattern+++ parenPattern' = minus <**> minusPattern+ <|> mkGconPattern <$> gconId <*> tokenSpan RightParen <*> many pattern2+ <|> mkFunIdentP <$> funSym <\> minus <*> tokenSpan RightParen+ <*> identPattern'+ <|> mkParenTuple <$> parenTuplePattern <\> minus <*> tokenSpan RightParen+ minusPattern = flip mkParenMinus <$> tokenSpan RightParen <*> identPattern'+ <|> mkParenMinus <$> parenMinusPattern <*> tokenSpan RightParen++ mkNegNum idt = setEndPosition (end (getSrcSpan idt))+ mkParenTuple p sp1 sp2 =+ setSpanInfo (spanInfo (combineSpans sp2 sp1) [sp2, sp1]) p+ mkFunIdentP idt sp1 f sp2 = setSrcSpan (combineSpans sp2 sp1) (f idt)+ mkParenMinus f sp1 idt sp2 = setSrcSpan (combineSpans sp2 sp1) (f idt)+ mkConsPattern f ts c = updateEndPos $+ ConstructorPattern (fromSrcSpan (getSrcSpan (f c))) () (f c) ts+ mkGconPattern qid sp1 ps sp2 = updateEndPos $+ ConstructorPattern (spanInfo (getSrcSpan qid) [sp2,sp1]) () qid ps++pattern2 :: Parser a Token (Pattern ())+pattern2 = literalPattern <|> anonPattern <|> identPattern+ <|> parenPattern <|> listPattern <|> lazyPattern++-- literalPattern ::= <integer> | <char> | <float> | <string>+literalPattern :: Parser a Token (Pattern ())+literalPattern = flip LiteralPattern () <$> fmap fromSrcSpan spanPosition+ <*> literal++-- anonPattern ::= '_'+anonPattern :: Parser a Token (Pattern ())+anonPattern = flip VariablePattern () <$> fmap fromSrcSpan spanPosition+ <*> anonIdent++-- identPattern ::= Variable [ '@' pattern2 | '{' fields '}'+-- | qConId [ '{' fields '}' ]+identPattern :: Parser a Token (Pattern ())+identPattern = varId <**> optAsRecPattern -- unqualified+ <|> qConId <\> varId <**> optRecPattern -- qualified++-- TODO: document me!+parenPattern :: Parser a Token (Pattern ())+parenPattern = tokenSpan LeftParen <**> parenPattern'+ where+ parenPattern' = minus <**> minusPattern+ <|> mkConstructorPattern <$> gconId <*> tokenSpan RightParen+ <|> mkFunAsRec <$> funSym <\> minus <*> tokenSpan RightParen+ <*> optAsRecPattern+ <|> mkParenTuple <$> parenTuplePattern <\> minus <*> tokenSpan RightParen+ minusPattern = mkOptAsRec <$> tokenSpan RightParen <*> optAsRecPattern+ <|> mkParen <$> parenMinusPattern <*> tokenSpan RightParen++ mkConstructorPattern qid sp1 sp2 =+ ConstructorPattern (fromSrcSpan (combineSpans sp2 sp1)) () qid []+ mkFunAsRec = flip (flip . mkOptAsRec)+ mkParenTuple p sp1 sp2 =+ let ss = getSrcInfoPoints p+ spi = spanInfo (combineSpans sp2 sp1) (sp2 : (ss ++ [sp1]))+ in setSpanInfo spi p+ mkOptAsRec sp1 f idt sp2 =+ let p = f idt+ ss = getSrcInfoPoints p+ spi = spanInfo (combineSpans sp2 sp1) ([sp2, sp1] ++ ss)+ in setSpanInfo spi p+ mkParen f sp1 idt sp2 =+ let p = f idt+ ss = getSrcInfoPoints p+ spi = spanInfo (combineSpans sp2 sp1) (sp2 : (ss ++ [sp1]))+ in setSpanInfo spi p++-- listPattern ::= '[' pattern0s ']'+-- pattern0s ::= {- empty -}+-- | pattern0 ',' pattern0s+listPattern :: Parser a Token (Pattern ())+listPattern = mkListPattern <$> bracketsSp (pattern0 `sepBySp` comma)+ where mkListPattern ((ps, ss), sp1, sp2) = updateEndPos $+ ListPattern (spanInfo sp1 (sp1 : (ss ++ [sp2]))) () ps++-- lazyPattern ::= '~' pattern2+lazyPattern :: Parser a Token (Pattern ())+lazyPattern = mkLazyPattern <$> tokenSpan Tilde <*> pattern2+ where mkLazyPattern sp p = updateEndPos $ LazyPattern (spanInfo sp [sp]) p++-- optRecPattern ::= [ '{' fields '}' ]+optRecPattern :: Parser a Token (QualIdent -> Pattern ())+optRecPattern = mkRecordPattern <$> fieldsSp pattern0 `opt` mkConPattern+ where+ mkRecordPattern ((fs, ss), sp1, sp2) c = updateEndPos $+ RecordPattern (spanInfo (getSrcSpan c) (sp1 : (ss ++ [sp2]))) () c fs+ mkConPattern c = ConstructorPattern (fromSrcSpan (getSrcSpan c)) () c []++-- ---------------------------------------------------------------------------+-- Partial patterns used in the combinators above, but also for parsing+-- the left-hand side of a declaration.+-- ---------------------------------------------------------------------------++gconId :: Parser a Token QualIdent+gconId = colon <|> tupleCommas++negNum :: Parser a Token (Pattern ())+negNum = mkNegativePattern <$> spanPosition <*>+ (Int <$> integer <|> Float <$> float)+ where mkNegativePattern sp = NegativePattern (fromSrcSpan sp) ()++optAsRecPattern :: Parser a Token (Ident -> Pattern ())+optAsRecPattern = mkAsPattern <$> tokenSpan At <*> pattern2+ <|> mkRecordPattern <$> fieldsSp pattern0+ `opt` mkVariablePattern+ where mkRecordPattern ((fs,ss),sp1,sp2) v =+ let s = getPosition v+ e = end sp2+ f = file s+ spi = spanInfo (Span f s e) (sp1 : (ss ++ [sp2]))+ in updateEndPos $ RecordPattern spi () (qualify v) fs+ mkAsPattern sp p idt =+ AsPattern (spanInfo (getSrcSpan idt) [sp]) idt p+ mkVariablePattern idt =+ VariablePattern (fromSrcSpan (getSrcSpan idt)) () idt++optInfixPattern :: Parser a Token (Pattern () -> Pattern ())+optInfixPattern = mkInfixPat <$> gconop <*> pattern0+ `opt` id+ where mkInfixPat op t2 t1 =+ let s = getPosition t1+ e = getSrcSpanEnd t2+ f = file s+ in InfixPattern (fromSrcSpan (Span f s e)) () t1 op t2++optTuplePattern :: Parser a Token (Pattern () -> Pattern ())+optTuplePattern = mkTuple <$> many1 ((,) <$> tokenSpan Comma <*> pattern0)+ `opt` ParenPattern NoSpanInfo+ where mkTuple ts t = let (ss, ps) = unzip ts+ in TuplePattern (fromSrcInfoPoints ss) (t:ps)++parenMinusPattern :: Parser a Token (Ident -> Pattern ())+parenMinusPattern = mkNeg <$> negNum <.> optInfixPattern <.> optTuplePattern+ where mkNeg neg idt = setEndPosition (end (getSrcSpan idt)) neg++parenTuplePattern :: Parser a Token (Pattern ())+parenTuplePattern = pattern0 <**> optTuplePattern+ `opt` ConstructorPattern NoSpanInfo () qUnitId []++-- ---------------------------------------------------------------------------+-- Expressions+-- ---------------------------------------------------------------------------++-- condExpr ::= '|' expr0 eq expr+--+-- Note: The guard is an `expr0` instead of `expr` since conditional expressions+-- may also occur in case expressions, and an expression like+-- @+-- case a of { _ -> True :: Bool -> a }+-- @+-- can not be parsed with a limited parser lookahead.+condExpr :: Parser a Token b -> Parser a Token (CondExpr ())+condExpr eq = mkCondExpr <$> spanPosition <*-> bar <*> expr0+ <*> spanPosition <*-> eq <*> expr+ where mkCondExpr sp1 e1 sp2 e2 = updateEndPos $+ CondExpr (spanInfo sp1 [sp1, sp2]) e1 e2++-- expr ::= expr0 [ '::' type0 ]+expr :: Parser a Token (Expression ())+expr = expr0 <??> (mkTyped <$> tokenSpan DoubleColon <*> qualType)+ where mkTyped sp qty e = updateEndPos $ setSrcSpan (getSrcSpan e) $+ Typed (fromSrcInfoPoints [sp]) e qty++-- expr0 ::= expr1 { infixOp expr1 }+expr0 :: Parser a Token (Expression ())+expr0 = expr1 `chainr1` (mkInfixApply <$> infixOp)+ where mkInfixApply op e1 e2 = InfixApply+ (fromSrcSpan (combineSpans (getSrcSpan e1) (getSrcSpan e2))) e1 op e2++-- expr1 ::= - expr2 | -. expr2 | expr2+expr1 :: Parser a Token (Expression ())+expr1 = mkUnaryMinus <$> minus <*> expr2+ <|> expr2+ where mkUnaryMinus idt ex =+ let p = getPosition idt+ e = getSrcSpanEnd ex+ f = file p+ in UnaryMinus (spanInfo (Span f p e) [Span f p (incr p 1)]) ex++-- expr2 ::= lambdaExpr | letExpr | doExpr | ifExpr | caseExpr | expr3+expr2 :: Parser a Token (Expression ())+expr2 = choice [ lambdaExpr, letExpr, doExpr, ifExpr, caseExpr+ , foldl1 mkApply <$> many1 expr3+ ]+ where mkApply e1 e2 = updateEndPos $ Apply (fromSrcSpan (getSrcSpan e1)) e1 e2++expr3 :: Parser a Token (Expression ())+expr3 = foldl mkRecordUpdate <$> expr4 <*> many recUpdate+ where recUpdate = layoutOff <-*> bracesSp (field expr0 `sepBy1Sp` comma)+ mkRecordUpdate e ((fs,ss), sp1, sp2) = updateEndPos $+ setSrcInfoPoints (sp1 : (ss ++ [sp2])) $+ RecordUpdate (fromSrcSpan (getSrcSpan e)) e fs++expr4 :: Parser a Token (Expression ())+expr4 = choice+ [constant, anonFreeVariable, variable, parenExpr, listExpr]++constant :: Parser a Token (Expression ())+constant = mkLiteral <$> spanPosition <*> literal+ where mkLiteral sp = Literal (fromSrcSpan sp) ()++anonFreeVariable :: Parser a Token (Expression ())+anonFreeVariable = (\ p v -> mkVariable $ qualify $ addPositionIdent p v)+ <$> position <*> anonIdent+ where mkVariable qid = Variable (fromSrcSpan (getSrcSpan qid)) () qid++variable :: Parser a Token (Expression ())+variable = qFunId <**> optRecord+ where optRecord = mkRecord <$> fieldsSp expr0 `opt` mkVariable+ mkRecord ((fs,ss), sp1, sp2) qid =+ let spi = spanInfo (getSrcSpan qid) (sp1 : (ss ++ [sp2]))+ in updateEndPos $ Record spi () qid fs+ mkVariable qid = Variable (fromSrcSpan (getSrcSpan qid)) () qid++parenExpr :: Parser a Token (Expression ())+parenExpr = fmap updateSpanWithBrackets (parensSp pExpr)+ where+ pExpr = minus <**> minusOrTuple+ <|> mkConstructor () <$> tupleCommas+ <|> leftSectionOrTuple <\> minus+ <|> opOrRightSection <\> minus+ `opt` Constructor (fromSrcInfoPoints []) () qUnitId+ minusOrTuple = mkUnaryMinus <$> expr1 <.> infixOrTuple+ `opt` mkVariable . qualify+ leftSectionOrTuple = expr1 <**> infixOrTuple+ infixOrTuple = ($ updateEndPos) <$> infixOrTuple'+ infixOrTuple' = infixOp <**> leftSectionOrExp+ <|> (.) <$> (optType <.> tupleExpr)+ leftSectionOrExp = expr1 <**> (infixApp <$> infixOrTuple')+ `opt` leftSection+ optType = mkTyped <$> tokenSpan DoubleColon <*> qualType `opt` id+ tupleExpr = mkTuple <$> many1 ((,) <$> tokenSpan Comma <*> expr)+ `opt` Paren NoSpanInfo+ opOrRightSection = qFunSym <**> optRightSection+ <|> colon <**> optCRightSection+ <|> infixOp <\> colon <\> qFunSym <**> rightSection+ optRightSection = (. InfixOp () ) <$> rightSection+ `opt` Variable NoSpanInfo ()+ optCRightSection = (. InfixConstr ()) <$> rightSection+ `opt` Constructor NoSpanInfo ()+ rightSection = mkRightSection <$> expr0+ infixApp f e2 op g e1 = f (g . mkInfixApply e1 op) e2+ leftSection op f e = mkLeftSection (f e) op+ mkTuple ses e = let (ss,es) = unzip ses+ in Tuple (fromSrcInfoPoints ss) (e:es)+ mkConstructor = Constructor NoSpanInfo+ mkTyped sp ty e = Typed (fromSrcInfoPoints [sp]) e ty+ mkRightSection = flip (RightSection NoSpanInfo)+ mkLeftSection = LeftSection NoSpanInfo+ mkInfixApply e1 op e2 = InfixApply (fromSrcSpan+ (combineSpans (getSrcSpan e1) (getSrcSpan e2))) e1 op e2+ mkVariable = Variable NoSpanInfo ()+ mkUnaryMinus ex idt =+ let p = getPosition idt+ e = getSrcSpanEnd ex+ f = file p+ in UnaryMinus (spanInfo (Span f p e) [Span f p (incr p 1)]) ex++infixOp :: Parser a Token (InfixOp ())+infixOp = InfixOp () <$> qfunop <|> InfixConstr () <$> colon++listExpr :: Parser a Token (Expression ())+listExpr = updateSpanWithBrackets <$>+ bracketsSp (elements `opt` List (fromSrcInfoPoints []) () [])+ where+ elements = expr <**> rest+ rest = comprehension+ <|> enumeration mkEnumFromTo mkEnumFrom+ <|> (tokenSpan Comma <**> (expr <**>(+ enumeration mkEnumFromThenTo mkEnumFromThen+ <|> list <$> many ((,) <$> tokenSpan Comma <*> expr)))+ `opt` (\ e -> List (fromSrcInfoPoints []) () [e]))+ comprehension = mkListCompr <$> tokenSpan Bar <*> quals+ enumeration enumTo enum =+ tokenSpan DotDot <**> (enumTo <$> expr `opt` enum)++ mkEnumFrom sp =+ EnumFrom (fromSrcInfoPoints [sp])+ mkEnumFromTo e1 sp e2 =+ EnumFromTo (fromSrcInfoPoints [sp]) e2 e1+ mkEnumFromThen sp1 e1 sp2 e2 =+ EnumFromThen (fromSrcInfoPoints [sp2,sp1]) e2 e1+ mkEnumFromThenTo e1 sp1 e2 sp2 e3 =+ EnumFromThenTo (fromSrcInfoPoints [sp2,sp1]) e3 e2 e1+ mkListCompr sp qu e = ListCompr (fromSrcInfoPoints [sp]) e qu++ list xs e2 sp e1 = let (ss, es) = unzip xs+ in List (fromSrcInfoPoints (sp:ss)) () (e1:e2:es)++updateSpanWithBrackets :: HasSpanInfo a => (a, Span, Span) -> a+updateSpanWithBrackets (ex, sp1, sp2) =+ let ss = getSrcInfoPoints ex+ s = getPosition sp1+ e = end sp2+ f = file s+ spi = spanInfo (Span f s e) (sp1 : (ss ++ [sp2]))+ in setSpanInfo spi ex++lambdaExpr :: Parser a Token (Expression ())+lambdaExpr = mkLambda <$> tokenSpan Backslash <*> many1 pattern2+ <*> spanPosition <*-> expectRightArrow+ <*> expr+ where mkLambda sp1 ps sp2 e = updateEndPos $ Lambda (spanInfo sp1 [sp1, sp2]) ps e++letExpr :: Parser a Token (Expression ())+letExpr = mkLet <$> tokenSpan KW_let <*> layout valueDecls+ <*> (tokenSpan KW_in <?> "in expected") <*> expr+ where+ mkLet sp1 (ds, lay) sp2 e = updateEndPos $+ Let (spanInfo sp1 [sp1, sp2])lay ds e++doExpr :: Parser a Token (Expression ())+doExpr = mkDo <$> tokenSpan KW_do <*> layout stmts+ where+ mkDo sp ((stms, ex), lay) = updateEndPos $+ Do (spanInfo sp [sp]) lay stms ex++ifExpr :: Parser a Token (Expression ())+ifExpr = mkIfThenElse+ <$> tokenSpan KW_if <*> expr+ <*> (tokenSpan KW_then <?> "then expected") <*> expr+ <*> (tokenSpan KW_else <?> "else expected") <*> expr+ where mkIfThenElse sp1 e1 sp2 e2 sp3 e3 = updateEndPos $+ IfThenElse (spanInfo sp1 [sp1, sp2, sp3]) e1 e2 e3++caseExpr :: Parser a Token (Expression ())+caseExpr = (mkCase Flex <$> tokenSpan KW_fcase+ <|> mkCase Rigid <$> tokenSpan KW_case)+ <*> expr+ <*> (tokenSpan KW_of <?> "of expected")+ <*> layout (alt `sepBy1Sp` semicolon)+ where+ mkCase ct sp1 e sp2 (alts, lay) = updateEndPos $+ Case (spanInfo sp1 [sp1, sp2]) lay ct e alts++alt :: Parser a Token (Alt ())+alt = mkAlt <$> spanPosition <*> pattern0+ <*> spanPosition <*> rhs expectRightArrow+ where mkAlt sp1 p sp2 = updateEndPos . Alt (spanInfo sp1 [sp2]) p++fieldsSp :: Parser a Token b -> Parser a Token (([Field b], [Span]), Span, Span)+fieldsSp p = layoutOff <-*> bracesSp (field p `sepBySp` comma)++field :: Parser a Token b -> Parser a Token (Field b)+field p = mkField <$> spanPosition <*> qfun+ <*> spanPosition <*-> expectEquals+ <*> p+ where mkField sp1 q sp2 = updateEndPos . Field (spanInfo sp1 [sp2]) q++-- ---------------------------------------------------------------------------+-- \paragraph{Statements in list comprehensions and \texttt{do} expressions}+-- Parsing statements is a bit difficult because the syntax of patterns+-- and expressions largely overlaps. The parser will first try to+-- recognize the prefix \emph{Pattern}~\texttt{<-} of a binding statement+-- and if this fails fall back into parsing an expression statement. In+-- addition, we have to be prepared that the sequence+-- \texttt{let}~\emph{LocalDefs} can be either a let-statement or the+-- prefix of a let expression.+-- ---------------------------------------------------------------------------++stmts :: Parser a Token (([Statement ()], Expression ()), [Span])+stmts = stmt reqStmts optStmts++reqStmts :: Parser a Token (Statement ()+ -> (([Statement ()], Expression ()), [Span]))+reqStmts = mkStmts <$> spanPosition <*-> semicolon <*> stmts+ where mkStmts sp ((sts, e), sps) st = ((st : sts, e), sp:sps)++optStmts :: Parser a Token (Expression ()+ -> (([Statement ()], Expression ()), [Span]))+optStmts = succeed mkStmtExpr <.> reqStmts `opt` (\e -> (([], e), []))+ where mkStmtExpr e = StmtExpr (fromSrcSpan (getSrcSpan e)) e++quals :: Parser a Token [Statement ()]+quals = stmt (succeed id) (succeed mkStmtExpr) `sepBy1` comma+ where mkStmtExpr e = StmtExpr (fromSrcSpan (getSrcSpan e)) e++stmt :: Parser a Token (Statement () -> b)+ -> Parser a Token (Expression () -> b) -> Parser a Token b+stmt stmtCont exprCont = letStmt stmtCont exprCont+ <|> exprOrBindStmt stmtCont exprCont++letStmt :: Parser a Token (Statement () -> b)+ -> Parser a Token (Expression () -> b) -> Parser a Token b+letStmt stmtCont exprCont = ((,) <$> tokenSpan KW_let <*> layout valueDecls)+ <**> optExpr+ where optExpr = let' <$> tokenSpan KW_in <*> expr <.> exprCont+ <|> succeed stmtDecl' <.> stmtCont+ where+ let' sp1 e (sp2, (ds, lay)) = updateEndPos $+ Let (spanInfo sp2 [sp2, sp1]) lay ds e+ stmtDecl' (sp2, (ds, lay)) = updateEndPos $+ StmtDecl (spanInfo sp2 [sp2]) lay ds++exprOrBindStmt :: Parser a Token (Statement () -> b)+ -> Parser a Token (Expression () -> b)+ -> Parser a Token b+exprOrBindStmt stmtCont exprCont =+ stmtBind' <$> spanPosition <*> pattern0 <*> tokenSpan LeftArrow <*> expr+ <**> stmtCont+ <|?> expr <\> token KW_let <**> exprCont+ where+ stmtBind' sp1 p sp2 e = updateEndPos $+ StmtBind (spanInfo sp1 [sp2]) p e++-- ---------------------------------------------------------------------------+-- Goals+-- ---------------------------------------------------------------------------++goal :: Parser a Token (Goal ())+goal = mkGoal <$> spanPosition <*> expr <*> localDecls+ where+ mkGoal sp1 ex (Just sp2, ds, li) = updateEndPos $+ Goal (SpanInfo sp1 [sp2]) li ex ds+ mkGoal sp1 ex (Nothing, ds, li) = updateEndPos $+ Goal (SpanInfo sp1 []) li ex ds++-- ---------------------------------------------------------------------------+-- Literals, identifiers, and (infix) operators+-- ---------------------------------------------------------------------------++char :: Parser a Token Char+char = cval <$> token CharTok++float :: Parser a Token Double+float = fval <$> token FloatTok++int :: Parser a Token Int+int = fromInteger <$> integer++integer :: Parser a Token Integer+integer = ival <$> token IntTok++string :: Parser a Token String+string = sval <$> token StringTok++tycon :: Parser a Token Ident+tycon = conId++anonOrTyvar :: Parser a Token Ident+anonOrTyvar = anonIdent <|> tyvar++tyvar :: Parser a Token Ident+tyvar = varId++clsvar :: Parser a Token Ident+clsvar = tyvar++tycls :: Parser a Token Ident+tycls = conId++qtycls :: Parser a Token QualIdent+qtycls = qConId++qtycon :: Parser a Token QualIdent+qtycon = qConId++varId :: Parser a Token Ident+varId = ident++funId :: Parser a Token Ident+funId = ident++conId :: Parser a Token Ident+conId = ident++funSym :: Parser a Token Ident+funSym = sym++conSym :: Parser a Token Ident+conSym = sym++modIdent :: Parser a Token ModuleIdent+modIdent = mIdent <?> "module name expected"++var :: Parser a Token Ident+var = varId <|> updateSpanWithBrackets+ <$> parensSp (funSym <?> "operator symbol expected")++fun :: Parser a Token Ident+fun = funId <|> updateSpanWithBrackets+ <$> parensSp (funSym <?> "operator symbol expected")++con :: Parser a Token Ident+con = conId <|> updateSpanWithBrackets+ <$> parensSp (conSym <?> "operator symbol expected")++funop :: Parser a Token Ident+funop = funSym <|> updateSpanWithBrackets+ <$> backquotesSp (funId <?> "operator name expected")++conop :: Parser a Token Ident+conop = conSym <|> updateSpanWithBrackets+ <$> backquotesSp (conId <?> "operator name expected")++qFunId :: Parser a Token QualIdent+qFunId = qIdent++qConId :: Parser a Token QualIdent+qConId = qIdent++qFunSym :: Parser a Token QualIdent+qFunSym = qSym++qConSym :: Parser a Token QualIdent+qConSym = qSym++gConSym :: Parser a Token QualIdent+gConSym = qConSym <|> colon++qfun :: Parser a Token QualIdent+qfun = qFunId <|> updateSpanWithBrackets+ <$> parensSp (qFunSym <?> "operator symbol expected")++qfunop :: Parser a Token QualIdent+qfunop = qFunSym <|> updateSpanWithBrackets+ <$> backquotesSp (qFunId <?> "operator name expected")++gconop :: Parser a Token QualIdent+gconop = gConSym <|> updateSpanWithBrackets+ <$> backquotesSp (qConId <?> "operator name expected")++anonIdent :: Parser a Token Ident+anonIdent = (`setSpanInfo` anonId) . fromSrcSpanBoth <$> tokenSpan Underscore++mIdent :: Parser a Token ModuleIdent+mIdent = mIdent' <$> spanPosition <*>+ tokens [Id,QId,Id_as,Id_ccall,Id_forall,Id_hiding,+ Id_interface,Id_primitive,Id_qualified]+ where mIdent' sp a = ModuleIdent (fromSrcSpanBoth sp) (modulVal a ++ [sval a])++ident :: Parser a Token Ident+ident = (\ sp t -> setSpanInfo (fromSrcSpanBoth sp) (mkIdent (sval t)))+ <$> spanPosition <*> tokens [Id,Id_as,Id_ccall,Id_forall,Id_hiding,+ Id_interface,Id_primitive,Id_qualified]++qIdent :: Parser a Token QualIdent+qIdent = qualify <$> ident <|> qIdentWith QId++sym :: Parser a Token Ident+sym = (\ sp t -> setSpanInfo (fromSrcSpanBoth sp) (mkIdent (sval t)))+ <$> spanPosition <*> tokens [Sym, SymDot, SymMinus, SymStar]++qSym :: Parser a Token QualIdent+qSym = qualify <$> sym <|> qIdentWith QSym++qIdentWith :: Category -> Parser a Token QualIdent+qIdentWith c = mkQIdent <$> spanPosition <*> token c+ where mkQIdent :: Span -> Attributes -> QualIdent+ mkQIdent sp a =+ let mid = ModuleIdent (fromSrcSpan sp) (modulVal a)+ p = incr (getPosition sp) (mIdentLength mid - 1)+ mid' = setEndPosition p mid+ idt = setSrcSpan sp $ mkIdent (sval a)+ idt' = setPosition (incr p 1) idt+ in QualIdent (fromSrcSpanBoth sp) (Just mid') idt'++colon :: Parser a Token QualIdent+colon = qualify . (`setSpanInfo` consId) . fromSrcSpanBoth <$> tokenSpan Colon++minus :: Parser a Token Ident+minus = (`setSpanInfo` minusId) . fromSrcSpanBoth <$> tokenSpan SymMinus++tupleCommas :: Parser a Token QualIdent+tupleCommas = (\ sp ss -> qualify $ updateEndPos $ setSpanInfo (spanInfo sp ss)+ $ tupleId $ succ $ length ss)+ <$> spanPosition <*> many1 (tokenSpan Comma)++-- ---------------------------------------------------------------------------+-- Layout+-- ---------------------------------------------------------------------------++-- |This function starts a new layout block but does not wait for its end.+-- This is only used for parsing the module header.+startLayout :: Parser a Token (b, [Span]) -> Parser a Token (b, LayoutInfo)+startLayout p = layoutOff <-*>+ (createExpli1Layout <$> tokenSpan LeftBrace <*> p)+ <|> layoutOn <-*>+ (createWhiteLayout <$> p)++layout :: Parser a Token (b, [Span]) -> Parser a Token (b, LayoutInfo)+layout p = (createExpliLayout+ <$> (layoutOff <-*> bracesSp p))+ <|> (createWhiteLayout+ <$> (layoutOn <-*> p <*-> (token VRightBrace <|> layoutEnd)))++createExpli1Layout :: Span -> (b, [Span]) -> (b, LayoutInfo)+createExpli1Layout sp1 (b, ss) = (b, ExplicitLayout (sp1:ss))++createExpliLayout :: ((b, [Span]), Span, Span) -> (b, LayoutInfo)+createExpliLayout ((b, ss), sp1, spe) = (b, ExplicitLayout (sp1:ss ++ [spe]))++createWhiteLayout :: (b, [Span]) -> (b, LayoutInfo)+createWhiteLayout (b, _) = (b, WhitespaceLayout)++-- We have to remove an additional context on an empty where-clause+layoutWhere :: Parser a Token b -> Parser a Token ([b], LayoutInfo)+layoutWhere p = (createExpliLayout+ <$> (layoutOff <-*> bracesSp (p `sepBySp` semicolon)))+ <|> (createWhiteLayout+ <$> (layoutOn <-*> (p `sepBy1Sp` semicolon)+ <*-> (token VRightBrace <|> layoutEnd)))+ <|> succeed ([], WhitespaceLayout)++-- ---------------------------------------------------------------------------+-- Bracket combinators+-- ---------------------------------------------------------------------------++braces :: Parser a Token b -> Parser a Token b+braces p = between leftBrace p rightBrace++bracesSp :: Parser a Token b -> Parser a Token (b, Span, Span)+bracesSp p = (\sp1 b sp2 -> (b, sp1, sp2))+ <$> tokenSpan LeftBrace+ <*> p+ <*> tokenSpan RightBrace++bracketsSp :: Parser a Token b -> Parser a Token (b, Span, Span)+bracketsSp p = (\sp1 b sp2 -> (b, sp1, sp2))+ <$> tokenSpan LeftBracket+ <*> p+ <*> tokenSpan RightBracket++parens :: Parser a Token b -> Parser a Token b+parens p = between leftParen p rightParen++parensSp :: Parser a Token b -> Parser a Token (b, Span, Span)+parensSp p = (\sp1 b sp2 -> (b, sp1, sp2))+ <$> tokenSpan LeftParen+ <*> p+ <*> tokenSpan RightParen++backquotesSp :: Parser a Token b -> Parser a Token (b, Span, Span)+backquotesSp p = (\sp1 b sp2 -> (b, sp1, sp2))+ <$> tokenSpan Backquote+ <*> p+ <*> spanPosition <*-> expectBackquote++-- ---------------------------------------------------------------------------+-- Simple token parsers+-- ---------------------------------------------------------------------------++token :: Category -> Parser a Token Attributes+token c = attr <$> symbol (Token c NoAttributes)+ where attr (Token _ a) = a++tokens :: [Category] -> Parser a Token Attributes+tokens = foldr1 (<|>) . map token++tokenPos :: Category -> Parser a Token Position+tokenPos c = position <*-> token c++tokenSpan :: Category -> Parser a Token Span+tokenSpan c = spanPosition <*-> token c++tokenOps :: [(Category, b)] -> Parser a Token b+tokenOps cs = ops [(Token c NoAttributes, x) | (c, x) <- cs]++comma :: Parser a Token Attributes+comma = token Comma++semicolon :: Parser a Token Attributes+semicolon = token Semicolon <|> token VSemicolon++bar :: Parser a Token Attributes+bar = token Bar++equals :: Parser a Token Attributes+equals = token Equals++expectEquals :: Parser a Token Attributes+expectEquals = equals <?> "= expected"++expectWhere :: Parser a Token Attributes+expectWhere = token KW_where <?> "where expected"++expectRightArrow :: Parser a Token Attributes+expectRightArrow = token RightArrow <?> "-> expected"++backquote :: Parser a Token Attributes+backquote = token Backquote++expectBackquote :: Parser a Token Attributes+expectBackquote = backquote <?> "backquote (`) expected"++leftParen :: Parser a Token Attributes+leftParen = token LeftParen++rightParen :: Parser a Token Attributes+rightParen = token RightParen++leftBrace :: Parser a Token Attributes+leftBrace = token LeftBrace++rightBrace :: Parser a Token Attributes+rightBrace = token RightBrace
− src/Curry/Syntax/Parser.lhs
@@ -1,806 +0,0 @@--% $Id: CurryParser.lhs,v 1.75 2004/02/15 23:11:28 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{CurryParser.lhs}-\section{A Parser for Curry}-The Curry parser is implemented using the (mostly) LL(1) parsing-combinators described in appendix~\ref{sec:ll-parsecomb}.-\begin{verbatim}--> module Curry.Syntax.Parser where--> import Curry.Base.Ident-> import Curry.Base.Position-> import Curry.Base.MessageMonad-> import Curry.Syntax.LLParseComb-> import Curry.Syntax.Type-> import Curry.Syntax.Lexer--> instance Symbol Token where-> isEOF (Token c _) = c == EOF--\end{verbatim}-\paragraph{Modules}-\begin{verbatim}--> parseSource :: Bool -> FilePath -> String -> MsgMonad Module-> parseSource flat path = -> fmap addSrcRefs . applyParser ( moduleHeader <*> decls flat) lexer path--> parseHeader :: FilePath -> String -> MsgMonad Module-> parseHeader = prefixParser (moduleHeader <*->-> (leftBrace `opt` undefined) <*>-> many (importDecl <*-> many semicolon))-> lexer--> moduleHeader :: Parser Token ([Decl] -> Module) a-> moduleHeader = Module <$-> token KW_module-> <*> (mIdent <?> "module name expected")-> <*> ((Just <$> exportSpec) `opt` Nothing)-> <*-> (token KW_where <?> "where expected")-> `opt` Module mainMIdent Nothing--> exportSpec :: Parser Token ExportSpec a-> exportSpec = Exporting <$> position <*> parens (export `sepBy` comma)--> export :: Parser Token Export a-> export = qtycon <**> (parens spec `opt` Export)-> <|> Export <$> qfun <\> qtycon-> <|> ExportModule <$-> token KW_module <*> mIdent-> where spec = ExportTypeAll <$-> token DotDot-> <|> flip ExportTypeWith <$> con `sepBy` comma--\end{verbatim}-\paragraph{Interfaces}-Since this modified version of MCC uses FlatCurry interfaces instead of-".icurry" files, a separate parser is not required any longer.-\begin{verbatim}--> --parseInterface :: FilePath -> String -> Error Interface-> --parseInterface fn s = applyParser parseIface lexer fn s--> --parseIface :: Parser Token Interface a-> --parseIface = Interface <$-> token Id_interface-> -- <*> (mIdent <?> "module name expected")-> -- <*-> (token KW_where <?> "where expected")-> -- <*> braces intfDecls--\end{verbatim}----\paragraph{Declarations}-\begin{verbatim}--> decls :: Bool -> Parser Token [Decl] a-> decls = layout . globalDecls--> globalDecls :: Bool -> Parser Token [Decl] a-> globalDecls flat =-> (:) <$> importDecl <*> (semicolon <-*> globalDecls flat `opt` [])-> <|> topDecl flat `sepBy` semicolon--> topDecl :: Bool -> Parser Token Decl a-> topDecl flat-> | flat = infixDecl <|> dataDecl flat <|> typeDecl <|> functionDecl flat-> | otherwise = infixDecl-> <|> dataDecl flat <|> newtypeDecl <|> typeDecl-> <|> functionDecl flat <|> externalDecl--> localDefs :: Bool -> Parser Token [Decl] a-> localDefs flat = token KW_where <-*> layout (valueDecls flat)-> `opt` []--> valueDecls :: Bool -> Parser Token [Decl] a-> valueDecls flat = localDecl flat `sepBy` semicolon-> where localDecl flat-> | flat = infixDecl <|> valueDecl flat-> | otherwise = infixDecl <|> valueDecl flat <|> externalDecl--> importDecl :: Parser Token Decl a-> importDecl =-> flip . ImportDecl <$> position <*-> token KW_import -> <*> (True <$-> token Id_qualified `opt` False)-> <*> mIdent-> <*> (Just <$-> token Id_as <*> mIdent `opt` Nothing)-> <*> (Just <$> importSpec `opt` Nothing)--> importSpec :: Parser Token ImportSpec a-> importSpec = position <**> (Hiding <$-> token Id_hiding `opt` Importing)-> <*> parens (spec `sepBy` comma)-> where spec = tycon <**> (parens constrs `opt` Import)-> <|> Import <$> fun <\> tycon-> constrs = ImportTypeAll <$-> token DotDot-> <|> flip ImportTypeWith <$> con `sepBy` comma--> infixDecl :: Parser Token Decl a-> infixDecl = infixDeclLhs InfixDecl <*> funop `sepBy1` comma--> infixDeclLhs :: (Position -> Infix -> Integer -> a) -> Parser Token a b-> infixDeclLhs f = f <$> position <*> tokenOps infixKW <*> integer-> where infixKW = [(KW_infix,Infix),(KW_infixl,InfixL),(KW_infixr,InfixR)]--> dataDecl :: Bool -> Parser Token Decl a-> dataDecl flat = typeDeclLhs DataDecl KW_data <*> constrs-> where constrs = equals <-*> constrDecl flat `sepBy1` bar-> `opt` []--> newtypeDecl :: Parser Token Decl a-> newtypeDecl =-> typeDeclLhs NewtypeDecl KW_newtype <*-> equals <*> newConstrDecl--> typeDecl :: Parser Token Decl a-> typeDecl = typeDeclLhs TypeDecl KW_type <*-> equals <*> typeDeclRhs --type0--> typeDeclLhs :: (Position -> Ident -> [Ident] -> a) -> Category-> -> Parser Token a b-> typeDeclLhs f kw = f <$> position <*-> token kw <*> tycon <*> many typeVar-> where typeVar = tyvar <|> anonId <$-> token Underscore--> typeDeclRhs :: Parser Token TypeExpr a-> typeDeclRhs = type0-> <|> flip RecordType Nothing-> <$> (layoutOff <-*> braces (labelDecls `sepBy` comma))--> labelDecls = (,) <$> labId `sepBy1` comma <*-> token DoubleColon <*> type0--> constrDecl :: Bool -> Parser Token ConstrDecl a-> constrDecl flat = position <**> (existVars <**> constr)-> where constr = conId <**> identDecl-> <|> leftParen <-*> parenDecl-> <|> type1 <\> conId <\> leftParen <**> opDecl-> identDecl = many type2 <**> (conType <$> opDecl `opt` conDecl)-> parenDecl = conOpDeclPrefix -> <$> conSym <*-> rightParen <*> type2 <*> type2-> <|> tupleType <*-> rightParen <**> opDecl-> opDecl = conOpDecl <$> conop <*> type1-> conType f tys c = f (ConstructorType (qualify c) tys)-> conDecl tys c tvs p = ConstrDecl p tvs c tys-> conOpDecl op ty2 ty1 tvs p = ConOpDecl p tvs ty1 op ty2-> conOpDeclPrefix op ty1 ty2 tvs p = ConOpDecl p tvs ty1 op ty2--> newConstrDecl :: Parser Token NewConstrDecl a-> newConstrDecl =-> NewConstrDecl <$> position <*> existVars <*> con <*> type2--> existVars :: Parser Token [Ident] a-> {--> existVars flat-> | flat = succeed []-> | otherwise = token Id_forall <-*> many1 tyvar <*-> dot `opt` []-> -}-> existVars = succeed []--> functionDecl :: Bool -> Parser Token Decl a-> functionDecl flat = position <**> decl-> where decl = fun `sepBy1` comma <**> funListDecl flat-> <|?> funDecl <$> lhs <*> declRhs flat-> lhs = (\f -> (f,FunLhs f [])) <$> fun-> <|?> funLhs--> valueDecl :: Bool -> Parser Token Decl a-> valueDecl flat = position <**> decl-> where decl = var `sepBy1` comma <**> valListDecl flat-> <|?> valDecl <$> constrTerm0 <*> declRhs flat-> <|?> funDecl <$> curriedLhs <*> declRhs flat-> valDecl t@(ConstructorPattern c ts)-> | not (isConstrId c) = funDecl (f,FunLhs f ts)-> where f = unqualify c-> valDecl t = opDecl id t-> opDecl f (InfixPattern t1 op t2)-> | isConstrId op = opDecl (f . InfixPattern t1 op) t2-> | otherwise = funDecl (op',OpLhs (f t1) op' t2)-> where op' = unqualify op-> opDecl f t = patDecl (f t)-> isConstrId c = c == qConsId || isQualified c || isQTupleId c--> funDecl :: (Ident,Lhs) -> Rhs -> Position -> Decl-> funDecl (f,lhs) rhs p = FunctionDecl p f [Equation p lhs rhs]--> patDecl :: ConstrTerm -> Rhs -> Position -> Decl-> patDecl t rhs p = PatternDecl p t rhs--> funListDecl :: Bool -> Parser Token ([Ident] -> Position -> Decl) a-> funListDecl flat-> | flat = typeSig <$-> token DoubleColon <*> type0-> <|> evalAnnot <$-> token KW_eval <*> tokenOps evalKW-> <|> externalDecl <$-> token KW_external-> | otherwise = typeSig <$-> token DoubleColon <*> type0-> <|> evalAnnot <$-> token KW_eval <*> tokenOps evalKW-> where typeSig ty vs p = TypeSig p vs ty-> evalAnnot ev vs p = EvalAnnot p vs ev-> evalKW = [(KW_rigid,EvalRigid),(KW_choice,EvalChoice)]-> externalDecl vs p = FlatExternalDecl p vs--> valListDecl :: Bool -> Parser Token ([Ident] -> Position -> Decl) a-> valListDecl flat = funListDecl flat <|> extraVars <$-> token KW_free-> where extraVars vs p = ExtraVariables p vs--> funLhs :: Parser Token (Ident,Lhs) a-> funLhs = funLhs <$> fun <*> many1 constrTerm2-> <|?> flip ($ id) <$> constrTerm1 <*> opLhs'-> <|?> curriedLhs-> where opLhs' = opLhs <$> funSym <*> constrTerm0-> <|> infixPat <$> gConSym <\> funSym <*> constrTerm1 <*> opLhs'-> <|> backquote <-*> opIdLhs-> opIdLhs = opLhs <$> funId <*-> checkBackquote <*> constrTerm0-> <|> infixPat <$> qConId <\> funId <*-> backquote <*> constrTerm1-> <*> opLhs'-> funLhs f ts = (f,FunLhs f ts)-> opLhs op t2 f t1 = (op,OpLhs (f t1) op t2)-> infixPat op t2 f g t1 = f (g . InfixPattern t1 op) t2--> curriedLhs :: Parser Token (Ident,Lhs) a-> curriedLhs = apLhs <$> parens funLhs <*> many1 constrTerm2-> where apLhs (f,lhs) ts = (f,ApLhs lhs ts)--> declRhs :: Bool -> Parser Token Rhs a-> declRhs flat = rhs flat equals--> rhs :: Bool -> Parser Token a b -> Parser Token Rhs b-> rhs flat eq = rhsExpr <*> localDefs flat-> where rhsExpr = SimpleRhs <$-> eq <*> position <*> expr flat-> <|> GuardedRhs <$> many1 (condExpr flat eq)--> externalDecl :: Parser Token Decl a-> externalDecl =-> ExternalDecl <$> position <*-> token KW_external-> <*> callConv <*> (Just <$> string `opt` Nothing)-> <*> fun <*-> token DoubleColon <*> type0-> where callConv = CallConvPrimitive <$-> token Id_primitive-> <|> CallConvCCall <$-> token Id_ccall-> <?> "Unsupported calling convention"--\end{verbatim}-\paragraph{Interface declarations}-\begin{verbatim}--> --intfDecls :: Parser Token [IDecl] a-> --intfDecls = (:) <$> iImportDecl <*> (semicolon <-*> intfDecls `opt` [])-> -- <|> intfDecl `sepBy` semicolon--> --intfDecl :: Parser Token IDecl a-> --intfDecl = iInfixDecl-> -- <|> iHidingDecl <|> iDataDecl <|> iNewtypeDecl <|> iTypeDecl-> -- <|> iFunctionDecl <\> token Id_hiding--> --iImportDecl :: Parser Token IDecl a-> --iImportDecl = IImportDecl <$> position <*-> token KW_import <*> mIdent--> --iInfixDecl :: Parser Token IDecl a-> --iInfixDecl = infixDeclLhs IInfixDecl <*> qfunop--> --iHidingDecl :: Parser Token IDecl a-> --iHidingDecl = position <*-> token Id_hiding <**> (dataDecl <|> funcDecl)-> -- where dataDecl = hiddenData <$-> token KW_data <*> tycon <*> many tyvar-> -- funcDecl = hidingFunc <$-> token DoubleColon <*> type0-> -- hiddenData tc tvs p = HidingDataDecl p tc tvs-> -- hidingFunc ty p = IFunctionDecl p hidingId ty-> -- hidingId = qualify (mkIdent "hiding")--> --iDataDecl :: Parser Token IDecl a-> --iDataDecl = iTypeDeclLhs IDataDecl KW_data <*> constrs-> -- where constrs = equals <-*> iConstrDecl `sepBy1` bar-> -- `opt` []-> -- iConstrDecl = Just <$> constrDecl False <\> token Underscore-> -- <|> Nothing <$-> token Underscore--> --iNewtypeDecl :: Parser Token IDecl a-> --iNewtypeDecl =-> -- iTypeDeclLhs INewtypeDecl KW_newtype <*-> equals <*> newConstrDecl--> --iTypeDecl :: Parser Token IDecl a-> --iTypeDecl = iTypeDeclLhs ITypeDecl KW_type <*-> equals <*> type0--> --iTypeDeclLhs :: (Position -> QualIdent -> [Ident] -> a) -> Category-> -- -> Parser Token a b-> --iTypeDeclLhs f kw = f <$> position <*-> token kw <*> qtycon <*> many tyvar--> --iFunctionDecl :: Parser Token IDecl a-> --iFunctionDecl = IFunctionDecl <$> position <*> qfun <*-> token DoubleColon-> -- <*> type0--\end{verbatim}-\paragraph{Types}-\begin{verbatim}--> type0 :: Parser Token TypeExpr a-> type0 = type1 `chainr1` (ArrowType <$-> token RightArrow)--> type1 :: Parser Token TypeExpr a-> type1 = ConstructorType <$> qtycon <*> many type2-> <|> type2 <\> qtycon--> type2 :: Parser Token TypeExpr a-> type2 = anonType <|> identType <|> parenType <|> listType--> anonType :: Parser Token TypeExpr a-> anonType = VariableType anonId <$-> token Underscore--> identType :: Parser Token TypeExpr a-> identType = VariableType <$> tyvar-> <|> flip ConstructorType [] <$> qtycon <\> tyvar--> parenType :: Parser Token TypeExpr a-> parenType = parens tupleType--> tupleType :: Parser Token TypeExpr a-> tupleType = type0 <??> (tuple <$> many1 (comma <-*> type0))-> `opt` TupleType []-> where tuple tys ty = TupleType (ty:tys)--> listType :: Parser Token TypeExpr a-> listType = ListType <$> brackets type0--\end{verbatim}-\paragraph{Literals}-\begin{verbatim}--> literal :: Parser Token Literal a-> literal = mk Char <$> char-> <|> mkInt <$> integer-> <|> mk Float <$> float-> <|> mk String <$> string--\end{verbatim}-\paragraph{Patterns}-\begin{verbatim}--> constrTerm0 :: Parser Token ConstrTerm a-> constrTerm0 = constrTerm1 `chainr1` (flip InfixPattern <$> gconop)--> constrTerm1 :: Parser Token ConstrTerm a-> constrTerm1 = varId <**> identPattern-> <|> ConstructorPattern <$> qConId <\> varId <*> many constrTerm2-> <|> minus <**> negNum-> <|> fminus <**> negFloat-> <|> leftParen <-*> parenPattern-> <|> constrTerm2 <\> qConId <\> leftParen-> where identPattern = optAsPattern-> <|> conPattern <$> many1 constrTerm2-> parenPattern = minus <**> minusPattern negNum-> <|> fminus <**> minusPattern negFloat-> <|> gconPattern-> <|> funSym <\> minus <\> fminus <*-> rightParen-> <**> identPattern-> <|> parenTuplePattern <\> minus <\> fminus <*-> rightParen-> minusPattern p = rightParen <-*> identPattern-> <|> parenMinusPattern p <*-> rightParen-> gconPattern = ConstructorPattern <$> gconId <*-> rightParen-> <*> many constrTerm2-> conPattern ts = flip ConstructorPattern ts . qualify--> constrTerm2 :: Parser Token ConstrTerm a-> constrTerm2 = literalPattern <|> anonPattern <|> identPattern-> <|> parenPattern <|> listPattern <|> lazyPattern-> <|> recordPattern--> literalPattern :: Parser Token ConstrTerm a-> literalPattern = LiteralPattern <$> literal--> anonPattern :: Parser Token ConstrTerm a-> anonPattern = VariablePattern anonId <$-> token Underscore--> identPattern :: Parser Token ConstrTerm a-> identPattern = varId <**> optAsPattern-> <|> flip ConstructorPattern [] <$> qConId <\> varId--> parenPattern :: Parser Token ConstrTerm a-> parenPattern = leftParen <-*> parenPattern-> where parenPattern = minus <**> minusPattern negNum-> <|> fminus <**> minusPattern negFloat-> <|> flip ConstructorPattern [] <$> gconId <*-> rightParen-> <|> funSym <\> minus <\> fminus <*-> rightParen-> <**> optAsPattern-> <|> parenTuplePattern <\> minus <\> fminus <*-> rightParen-> minusPattern p = rightParen <-*> optAsPattern-> <|> parenMinusPattern p <*-> rightParen--> listPattern :: Parser Token ConstrTerm a-> listPattern = mk' ListPattern <$> brackets (constrTerm0 `sepBy` comma)--> lazyPattern :: Parser Token ConstrTerm a-> lazyPattern = mk LazyPattern <$-> token Tilde <*> constrTerm2--> recordPattern :: Parser Token ConstrTerm a-> recordPattern = layoutOff <-*> braces content-> where-> content = RecordPattern <$> fields <*> record-> fields = fieldPatt `sepBy` comma-> fieldPatt = Field <$> position <*> labId <*-> checkEquals <*> constrTerm0-> record = Just <$-> checkBar <*> constrTerm2 `opt` Nothing--\end{verbatim}-Partial patterns used in the combinators above, but also for parsing-the left-hand side of a declaration.-\begin{verbatim}--> gconId :: Parser Token QualIdent a-> gconId = colon <|> tupleCommas--> negNum,negFloat :: Parser Token (Ident -> ConstrTerm) a-> negNum = flip NegativePattern -> <$> (mkInt <$> integer <|> mk Float <$> float)-> negFloat = flip NegativePattern . mk Float -> <$> (fromIntegral <$> integer <|> float)--> optAsPattern :: Parser Token (Ident -> ConstrTerm) a-> optAsPattern = flip AsPattern <$-> token At <*> constrTerm2-> `opt` VariablePattern--> optInfixPattern :: Parser Token (ConstrTerm -> ConstrTerm) a-> optInfixPattern = infixPat <$> gconop <*> constrTerm0-> `opt` id-> where infixPat op t2 t1 = InfixPattern t1 op t2--> optTuplePattern :: Parser Token (ConstrTerm -> ConstrTerm) a-> optTuplePattern = tuple <$> many1 (comma <-*> constrTerm0)-> `opt` ParenPattern-> where tuple ts t = mk TuplePattern (t:ts)--> parenMinusPattern :: Parser Token (Ident -> ConstrTerm) a-> -> Parser Token (Ident -> ConstrTerm) a-> parenMinusPattern p = p <.> optInfixPattern <.> optTuplePattern--> parenTuplePattern :: Parser Token ConstrTerm a-> parenTuplePattern = constrTerm0 <**> optTuplePattern-> `opt` mk TuplePattern []--\end{verbatim}-\paragraph{Expressions}-\begin{verbatim}--> condExpr :: Bool -> Parser Token a b -> Parser Token CondExpr b-> condExpr flat eq =-> CondExpr <$> position <*-> bar <*> expr0 flat <*-> eq <*> expr flat--> expr :: Bool -> Parser Token Expression a-> expr flat = expr0 flat <??> (flip Typed <$-> token DoubleColon <*> type0)--> expr0 :: Bool -> Parser Token Expression a-> expr0 flat = expr1 flat `chainr1` (flip InfixApply <$> infixOp)--> expr1 :: Bool -> Parser Token Expression a-> expr1 flat = UnaryMinus <$> (minus <|> fminus) <*> expr2 flat-> <|> expr2 flat--> expr2 :: Bool -> Parser Token Expression a-> expr2 flat = lambdaExpr flat <|> letExpr flat <|> doExpr flat-> <|> ifExpr flat <|> caseExpr flat-> <|> expr3 flat <**> applicOrSelect-> where-> applicOrSelect = flip RecordSelection -> <$-> (token RightArrow <?> "-> expected")-> <*> labId-> <|?> (\es e -> foldl1 Apply (e:es))-> <$> many (expr3 flat) --> expr3 :: Bool -> Parser Token Expression a-> expr3 flat = expr3' -> where-> expr3' = constant <|> variable <|> parenExpr flat-> <|> listExpr flat <|> recordExpr flat--> constant :: Parser Token Expression a-> constant = Literal <$> literal--> variable :: Parser Token Expression a-> variable = Variable <$> qFunId--> parenExpr :: Bool -> Parser Token Expression a-> parenExpr flat = parens pExpr-> where pExpr = (minus <|> fminus) <**> minusOrTuple-> <|> Constructor <$> tupleCommas-> <|> leftSectionOrTuple <\> minus <\> fminus-> <|> opOrRightSection <\> minus <\> fminus-> `opt` mk Tuple []-> minusOrTuple = flip UnaryMinus <$> expr1 flat <.> infixOrTuple-> `opt` Variable . qualify-> leftSectionOrTuple = expr1 flat <**> infixOrTuple-> infixOrTuple = ($ id) <$> infixOrTuple'-> infixOrTuple' = infixOp <**> leftSectionOrExp-> <|> (.) <$> (optType <.> tupleExpr)-> leftSectionOrExp = expr1 flat <**> (infixApp <$> infixOrTuple')-> `opt` leftSection-> optType = flip Typed <$-> token DoubleColon <*> type0-> `opt` id-> tupleExpr = tuple <$> many1 (comma <-*> expr flat)-> `opt` Paren-> opOrRightSection = qFunSym <**> optRightSection-> <|> colon <**> optCRightSection-> <|> infixOp <\> colon <\> qFunSym <**> rightSection-> optRightSection = (. InfixOp) <$> rightSection `opt` Variable-> optCRightSection = (. InfixConstr) <$> rightSection `opt` Constructor-> rightSection = flip RightSection <$> expr0 flat-> infixApp f e2 op g e1 = f (g . InfixApply e1 op) e2-> leftSection op f e = LeftSection (f e) op-> tuple es e = mk Tuple (e:es)--> infixOp :: Parser Token InfixOp a-> infixOp = InfixOp <$> qfunop-> <|> InfixConstr <$> colon--> listExpr :: Bool -> Parser Token Expression a-> listExpr flat = brackets (elements `opt` mk' List [])-> where elements = expr flat <**> rest-> rest = comprehension-> <|> enumeration (flip EnumFromTo) EnumFrom-> <|> comma <-*> expr flat <**>-> (enumeration (flip3 EnumFromThenTo) (flip EnumFromThen)-> <|> list <$> many (comma <-*> expr flat))-> `opt` (\e -> mk' List [e])-> comprehension = flip (mk ListCompr) <$-> bar <*> quals flat-> enumeration enumTo enum =-> token DotDot <-*> (enumTo <$> expr flat `opt` enum)-> list es e2 e1 = mk' List (e1:e2:es)-> flip3 f x y z = f z y x--> recordExpr :: Bool -> Parser Token Expression a-> recordExpr flat = layoutOff <-*> braces content-> where content = RecordConstr <$> fieldConstr `sepBy` comma-> <|?> RecordUpdate <$> fieldUpdate `sepBy` comma-> <*-> checkBar <*> expr flat-> fieldConstr = Field <$> position <*> labId -> <*-> checkEquals <*> expr flat-> fieldUpdate = Field <$> position <*> labId -> <*-> checkBinds <*> expr flat--> lambdaExpr :: Bool -> Parser Token Expression a-> lambdaExpr flat =-> mk Lambda <$-> token Backslash <*> many1 constrTerm2-> <*-> (token RightArrow <?> "-> expected") <*> expr flat--> letExpr :: Bool -> Parser Token Expression a-> letExpr flat = Let <$-> token KW_let <*> layout (valueDecls flat)-> <*-> (token KW_in <?> "in expected") <*> expr flat--> doExpr :: Bool -> Parser Token Expression a-> doExpr flat = uncurry Do <$-> token KW_do <*> layout (stmts flat)--> ifExpr :: Bool -> Parser Token Expression a-> ifExpr flat =-> mk IfThenElse <$-> token KW_if <*> expr flat-> <*-> (token KW_then <?> "then expected") <*> expr flat-> <*-> (token KW_else <?> "else expected") <*> expr flat--> caseExpr :: Bool -> Parser Token Expression a-> caseExpr flat = mk Case <$-> token KW_case <*> expr flat-> <*-> (token KW_of <?> "of expected") <*> layout (alts flat)--> alts :: Bool -> Parser Token [Alt] a-> alts flat = alt flat `sepBy1` semicolon--> alt :: Bool -> Parser Token Alt a-> alt flat = Alt <$> position <*> constrTerm0-> <*> rhs flat (token RightArrow <?> "-> expected")--\end{verbatim}-\paragraph{Statements in list comprehensions and \texttt{do} expressions}-Parsing statements is a bit difficult because the syntax of patterns-and expressions largely overlaps. The parser will first try to-recognize the prefix \emph{Pattern}~\texttt{<-} of a binding statement-and if this fails fall back into parsing an expression statement. In-addition, we have to be prepared that the sequence-\texttt{let}~\emph{LocalDefs} can be either a let-statement or the-prefix of a let expression.-\begin{verbatim}--> stmts :: Bool -> Parser Token ([Statement],Expression) a-> stmts flat = stmt flat (reqStmts flat) (optStmts flat)--> reqStmts :: Bool -> Parser Token (Statement -> ([Statement],Expression)) a-> reqStmts flat = (\(sts,e) st -> (st : sts,e)) <$-> semicolon <*> stmts flat--> optStmts :: Bool -> Parser Token (Expression -> ([Statement],Expression)) a-> optStmts flat = succeed (mk StmtExpr) <.> reqStmts flat-> `opt` (,) []--> quals :: Bool -> Parser Token [Statement] a-> quals flat = stmt flat (succeed id) (succeed $ mk StmtExpr) `sepBy1` comma--> stmt :: Bool -> Parser Token (Statement -> a) b-> -> Parser Token (Expression -> a) b -> Parser Token a b-> stmt flat stmtCont exprCont = letStmt flat stmtCont exprCont-> <|> exprOrBindStmt flat stmtCont exprCont--> letStmt :: Bool -> Parser Token (Statement -> a) b-> -> Parser Token (Expression -> a) b -> Parser Token a b-> letStmt flat stmtCont exprCont =-> token KW_let <-*> layout (valueDecls flat) <**> optExpr-> where optExpr = flip Let <$-> token KW_in <*> expr flat <.> exprCont-> <|> succeed StmtDecl <.> stmtCont--> exprOrBindStmt :: Bool -> Parser Token (Statement -> a) b-> -> Parser Token (Expression -> a) b-> -> Parser Token a b-> exprOrBindStmt flat stmtCont exprCont =-> mk StmtBind <$> constrTerm0 <*-> leftArrow <*> expr flat <**> stmtCont-> <|?> expr flat <\> token KW_let <**> exprCont--\end{verbatim}-\paragraph{Literals, identifiers, and (infix) operators}-\begin{verbatim}--> char :: Parser Token Char a-> char = cval <$> token CharTok--> int, checkInt :: Parser Token Int a-> int = ival <$> token IntTok-> checkInt = int <?> "integer number expected"--> float, checkFloat :: Parser Token Double a-> float = fval <$> token FloatTok-> checkFloat = float <?> "floating point number expected"--> integer, checkInteger :: Parser Token Integer a-> integer = intval <$> token IntegerTok-> checkInteger = integer <?> "integer number expected"--> string :: Parser Token String a-> string = sval <$> token StringTok--> tycon, tyvar :: Parser Token Ident a-> tycon = conId-> tyvar = varId--> qtycon :: Parser Token QualIdent a-> qtycon = qConId--> varId, funId, conId, labId :: Parser Token Ident a-> varId = ident-> funId = ident-> conId = ident-> labId = renameLabel <$> ident--> funSym, conSym :: Parser Token Ident a-> funSym = sym-> conSym = sym--> var, fun, con :: Parser Token Ident a-> var = varId <|> parens (funSym <?> "operator symbol expected")-> fun = funId <|> parens (funSym <?> "operator symbol expected")-> con = conId <|> parens (conSym <?> "operator symbol expected")--> funop, conop :: Parser Token Ident a-> funop = funSym <|> backquotes (funId <?> "operator name expected")-> conop = conSym <|> backquotes (conId <?> "operator name expected")--> qFunId, qConId, qLabId :: Parser Token QualIdent a-> qFunId = qIdent-> qConId = qIdent-> qLabId = qIdent--> qFunSym, qConSym :: Parser Token QualIdent a-> qFunSym = qSym-> qConSym = qSym-> gConSym = qConSym <|> colon--> qfun, qcon :: Parser Token QualIdent a-> qfun = qFunId <|> parens (qFunSym <?> "operator symbol expected")-> qcon = qConId <|> parens (qConSym <?> "operator symbol expected")--> qfunop, qconop, gconop :: Parser Token QualIdent a-> qfunop = qFunSym <|> backquotes (qFunId <?> "operator name expected")-> qconop = qConSym <|> backquotes (qConId <?> "operator name expected")-> gconop = gConSym <|> backquotes (qConId <?> "operator name expected")--> ident :: Parser Token Ident a-> ident = (\ pos -> mkIdentPosition pos . sval) <$> position <*> -> tokens [Id,Id_as,Id_ccall,Id_forall,Id_hiding,-> Id_interface,Id_primitive,Id_qualified]--> qIdent :: Parser Token QualIdent a-> qIdent = qualify <$> ident <|> mkQIdent <$> position <*> token QId-> where mkQIdent p a = qualifyWith (mkMIdent (modul a)) -> (mkIdentPosition p (sval a))--> mIdent :: Parser Token ModuleIdent a-> mIdent = mIdent <$> position <*> -> tokens [Id,QId,Id_as,Id_ccall,Id_forall,Id_hiding,-> Id_interface,Id_primitive,Id_qualified]-> where mIdent p a = addPositionModuleIdent p $ -> mkMIdent (modul a ++ [sval a])--> sym :: Parser Token Ident a-> sym = (\ pos -> mkIdentPosition pos . sval) <$> position <*> -> tokens [Sym,Sym_Dot,Sym_Minus,Sym_MinusDot]--> qSym :: Parser Token QualIdent a-> qSym = qualify <$> sym <|> mkQIdent <$> position <*> token QSym-> where mkQIdent p a = qualifyWith (mkMIdent (modul a)) -> (mkIdentPosition p (sval a))--> colon :: Parser Token QualIdent a-> colon = (\ p _ -> qualify $ addPositionIdent p consId) <$> -> position <*> token Colon--> minus :: Parser Token Ident a-> minus = (\ p _ -> addPositionIdent p minusId) <$> -> position <*> token Sym_Minus--> fminus :: Parser Token Ident a-> fminus = (\ p _ -> addPositionIdent p fminusId) <$> -> position <*> token Sym_MinusDot--> tupleCommas :: Parser Token QualIdent a-> tupleCommas = (\ p -> qualify . addPositionIdent p . tupleId . succ . length )-> <$> position <*> many1 comma--\end{verbatim}-\paragraph{Layout}-\begin{verbatim}--> layout :: Parser Token a b -> Parser Token a b-> layout p = layoutOff <-*> bracket leftBraceSemicolon p rightBrace-> <|> layoutOn <-*> p <*-> (token VRightBrace <|> layoutEnd)--\end{verbatim}-\paragraph{More combinators}-\begin{verbatim}--> braces, brackets, parens, backquotes :: Parser Token a b -> Parser Token a b-> braces p = bracket leftBrace p rightBrace-> brackets p = bracket leftBracket p rightBracket-> parens p = bracket leftParen p rightParen-> backquotes p = bracket backquote p checkBackquote--\end{verbatim}-\paragraph{Simple token parsers}-\begin{verbatim}--> token :: Category -> Parser Token Attributes a-> token c = attr <$> symbol (Token c NoAttributes)-> where attr (Token _ a) = a--> tokens :: [Category] -> Parser Token Attributes a-> tokens = foldr1 (<|>) . map token--> tokenOps :: [(Category,a)] -> Parser Token a b-> tokenOps cs = ops [(Token c NoAttributes,x) | (c,x) <- cs]--> dot, comma, semicolon, bar, equals, binds :: Parser Token Attributes a-> dot = token Sym_Dot-> comma = token Comma-> semicolon = token Semicolon <|> token VSemicolon-> bar = token Bar-> equals = token Equals-> binds = token Binds--> checkBar, checkEquals, checkBinds :: Parser Token Attributes a-> checkBar = bar <?> "| expected"-> checkEquals = equals <?> "= expected"-> checkBinds = binds <?> ":= expected"--> backquote, checkBackquote :: Parser Token Attributes a-> backquote = token Backquote-> checkBackquote = backquote <?> "backquote (`) expected"--> leftParen, rightParen :: Parser Token Attributes a-> leftParen = token LeftParen-> rightParen = token RightParen--> leftBracket, rightBracket :: Parser Token Attributes a-> leftBracket = token LeftBracket-> rightBracket = token RightBracket--> leftBrace, leftBraceSemicolon, rightBrace :: Parser Token Attributes a-> leftBrace = token LeftBrace-> leftBraceSemicolon = token LeftBraceSemicolon-> rightBrace = token RightBrace--> leftArrow :: Parser Token Attributes a-> leftArrow = token LeftArrow--\end{verbatim}-\paragraph{Ident}-\begin{verbatim}--> mkIdentPosition :: Position -> String -> Ident-> mkIdentPosition pos = addPositionIdent pos . mkIdent--\end{verbatim}
+ src/Curry/Syntax/Pretty.hs view
@@ -0,0 +1,463 @@+{- |+ Module : $Header$+ Description : A pretty printer for Curry+ Copyright : (c) 1999 - 2004 Wolfgang Lux+ 2005 Martin Engelke+ 2011 - 2015 Björn Peemöller+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module implements a pretty printer for Curry expressions. It was+ derived from the Haskell pretty printer provided in Simon Marlow's+ Haskell parser.+-}+{-# OPTIONS_GHC -Wno-orphans #-}+module Curry.Syntax.Pretty+ ( pPrint, pPrintPrec, ppContext, ppInstanceType, ppIMethodImpl+ , ppIdent, ppQIdent, ppInfixOp, ppQInfixOp, ppMIdent+ ) where++import Prelude hiding ((<>))++import Curry.Base.Ident+import Curry.Base.Pretty++import Curry.Syntax.Type+import Curry.Syntax.Utils (opName)++instance Pretty (Module a) where+ pPrint (Module _ _ ps m es is ds) = ppModuleHeader ps m es is $$ ppSepBlock ds++ppModuleHeader :: [ModulePragma] -> ModuleIdent -> Maybe ExportSpec+ -> [ImportDecl] -> Doc+ppModuleHeader ps m es is+ | null is = header+ | otherwise = header $+$ text "" $+$ vcat (map pPrint is)+ where header = vcat (map pPrint ps)+ $+$ text "module" <+> ppMIdent m+ <+> maybePP pPrint es <+> text "where"++instance Pretty ModulePragma where+ pPrint (LanguagePragma _ exts) =+ ppPragma "LANGUAGE" $ list $ map pPrint exts+ pPrint (OptionsPragma _ tool args) =+ ppPragma "OPTIONS" $ maybe empty ((text "_" <>) . pPrint) tool <+> text args++ppPragma :: String -> Doc -> Doc+ppPragma kw doc = text "{-#" <+> text kw <+> doc <+> text "#-}"++instance Pretty Extension where+ pPrint (KnownExtension _ e) = text (show e)+ pPrint (UnknownExtension _ e) = text e++instance Pretty Tool where+ pPrint (UnknownTool t) = text t+ pPrint t = text (show t)++instance Pretty ExportSpec where+ pPrint (Exporting _ es) = parenList (map pPrint es)++instance Pretty Export where+ pPrint (Export _ x) = ppQIdent x+ pPrint (ExportTypeWith _ tc cs) = ppQIdent tc <> parenList (map ppIdent cs)+ pPrint (ExportTypeAll _ tc) = ppQIdent tc <> text "(..)"+ pPrint (ExportModule _ m) = text "module" <+> ppMIdent m++instance Pretty ImportDecl where+ pPrint (ImportDecl _ m q asM is) =+ text "import" <+> ppQualified q <+> ppMIdent m <+> maybePP ppAs asM+ <+> maybePP pPrint is+ where+ ppQualified q' = if q' then text "qualified" else empty+ ppAs m' = text "as" <+> ppMIdent m'++instance Pretty ImportSpec where+ pPrint (Importing _ is) = parenList (map pPrint is)+ pPrint (Hiding _ is) = text "hiding" <+> parenList (map pPrint is)++instance Pretty Import where+ pPrint (Import _ x) = ppIdent x+ pPrint (ImportTypeWith _ tc cs) = ppIdent tc <> parenList (map ppIdent cs)+ pPrint (ImportTypeAll _ tc) = ppIdent tc <> text "(..)"++ppBlock :: Pretty a => [a] -> Doc+ppBlock = vcat . map pPrint++ppSepBlock :: Pretty a => [a] -> Doc+ppSepBlock = vcat . map (\d -> text "" $+$ pPrint d)++instance Pretty (Decl a) where+ pPrint (InfixDecl _ fix p ops) = ppPrec fix p <+> list (map ppInfixOp ops)+ pPrint (DataDecl _ tc tvs cs clss) =+ sep (ppTypeDeclLhs "data" tc tvs :+ map indent (zipWith (<+>) (equals : repeat vbar) (map pPrint cs) +++ [ppDeriving clss]))+ pPrint (ExternalDataDecl _ tc tvs) = ppTypeDeclLhs "external data" tc tvs+ pPrint (NewtypeDecl _ tc tvs nc clss) =+ sep (ppTypeDeclLhs "newtype" tc tvs <+> equals :+ map indent [pPrint nc, ppDeriving clss])+ pPrint (TypeDecl _ tc tvs ty) =+ sep [ppTypeDeclLhs "type" tc tvs <+> equals,indent (pPrintPrec 0 ty)]+ pPrint (TypeSig _ fs ty) =+ list (map ppIdent fs) <+> text "::" <+> pPrintPrec 0 ty+ pPrint (FunctionDecl _ _ _ eqs) = vcat (map pPrint eqs)+ pPrint (ExternalDecl _ vs) = list (map pPrint vs) <+> text "external"+ pPrint (PatternDecl _ t rhs) = ppRule (pPrintPrec 0 t) equals rhs+ pPrint (FreeDecl _ vs) = list (map pPrint vs) <+> text "free"+ pPrint (DefaultDecl _ tys) =+ text "default" <+> parenList (map (pPrintPrec 0) tys)+ pPrint (ClassDecl _ _ cx cls clsvar ds) =+ ppClassInstHead "class" cx (ppIdent cls) (ppIdent clsvar) <+>+ ppIf (not $ null ds) (text "where") $$+ ppIf (not $ null ds) (indent $ ppBlock ds)+ pPrint (InstanceDecl _ _ cx qcls inst ds) =+ ppClassInstHead "instance" cx (ppQIdent qcls) (ppInstanceType inst) <+>+ ppIf (not $ null ds) (text "where") $$+ ppIf (not $ null ds) (indent $ ppBlock ds)++ppClassInstHead :: String -> Context -> Doc -> Doc -> Doc+ppClassInstHead kw cx cls ty = text kw <+> ppContext cx <+> cls <+> ty++ppContext :: Context -> Doc+ppContext [] = empty+ppContext [c] = pPrint c <+> darrow+ppContext cs = parenList (map pPrint cs) <+> darrow++instance Pretty Constraint where+ pPrint (Constraint _ qcls ty) = ppQIdent qcls <+> pPrintPrec 2 ty++ppInstanceType :: InstanceType -> Doc+ppInstanceType = pPrintPrec 2++ppDeriving :: [QualIdent] -> Doc+ppDeriving [] = empty+ppDeriving [qcls] = text "deriving" <+> ppQIdent qcls+ppDeriving qclss = text "deriving" <+> parenList (map ppQIdent qclss)++ppPrec :: Infix -> Maybe Precedence -> Doc+ppPrec fix p = pPrint fix <+> ppPrio p+ where+ ppPrio Nothing = empty+ ppPrio (Just p') = integer p'++ppTypeDeclLhs :: String -> Ident -> [Ident] -> Doc+ppTypeDeclLhs kw tc tvs = text kw <+> ppIdent tc <+> hsep (map ppIdent tvs)++instance Pretty ConstrDecl where+ pPrint (ConstrDecl _ c tys) =+ sep [ ppIdent c <+> fsep (map (pPrintPrec 2) tys) ]+ pPrint (ConOpDecl _ ty1 op ty2) =+ sep [ pPrintPrec 1 ty1, ppInfixOp op <+> pPrintPrec 1 ty2 ]+ pPrint (RecordDecl _ c fs) =+ sep [ ppIdent c <+> record (list (map pPrint fs)) ]++instance Pretty FieldDecl where+ pPrint (FieldDecl _ ls ty) = list (map ppIdent ls)+ <+> text "::" <+> pPrintPrec 0 ty++instance Pretty NewConstrDecl where+ pPrint (NewConstrDecl _ c ty) = sep [ppIdent c <+> pPrintPrec 2 ty]+ pPrint (NewRecordDecl _ c (i,ty)) =+ sep [ppIdent c <+> record (ppIdent i <+> text "::" <+> pPrintPrec 0 ty)]++ppQuantifiedVars :: [Ident] -> Doc+ppQuantifiedVars tvs+ | null tvs = empty+ | otherwise = text "forall" <+> hsep (map ppIdent tvs) <+> char '.'++instance Pretty (Equation a) where+ pPrint (Equation _ lhs rhs) = ppRule (pPrint lhs) equals rhs++instance Pretty (Lhs a) where+ pPrint (FunLhs _ f ts) =+ ppIdent f <+> fsep (map (pPrintPrec 2) ts)+ pPrint (OpLhs _ t1 f t2) =+ pPrintPrec 1 t1 <+> ppInfixOp f <+> pPrintPrec 1 t2+ pPrint (ApLhs _ lhs ts) =+ parens (pPrint lhs) <+> fsep (map (pPrintPrec 2) ts)++ppRule :: Doc -> Doc -> Rhs a -> Doc+ppRule lhs eq (SimpleRhs _ _ e ds) =+ sep [lhs <+> eq, indent (pPrintPrec 0 e)] $$ ppLocalDefs ds+ppRule lhs eq (GuardedRhs _ _ es ds) =+ sep [lhs, indent (vcat (map (ppCondExpr eq) es))] $$ ppLocalDefs ds++ppLocalDefs :: [Decl a] -> Doc+ppLocalDefs ds+ | null ds = empty+ | otherwise = indent (text "where" <+> ppBlock ds)++-- ---------------------------------------------------------------------------+-- Interfaces+-- ---------------------------------------------------------------------------++instance Pretty Interface where+ pPrint (Interface m is ds) =+ text "interface" <+> ppMIdent m <+> text "where" <+> lbrace+ $$ vcat (punctuate semi $ map pPrint is ++ map pPrint ds)+ $$ rbrace++instance Pretty IImportDecl where+ pPrint (IImportDecl _ m) = text "import" <+> ppMIdent m++instance Pretty IDecl where+ pPrint (IInfixDecl _ fix p op) = ppPrec fix (Just p) <+> ppQInfixOp op+ pPrint (HidingDataDecl _ tc k tvs) =+ text "hiding" <+> ppITypeDeclLhs "data" tc k tvs+ pPrint (IDataDecl _ tc k tvs cs hs) =+ sep (ppITypeDeclLhs "data" tc k tvs :+ map indent (zipWith (<+>) (equals : repeat vbar) (map pPrint cs)) +++ [indent (ppHiding hs)])+ pPrint (INewtypeDecl _ tc k tvs nc hs) =+ sep [ ppITypeDeclLhs "newtype" tc k tvs <+> equals+ , indent (pPrint nc)+ , indent (ppHiding hs)+ ]+ pPrint (ITypeDecl _ tc k tvs ty) =+ sep [ppITypeDeclLhs "type" tc k tvs <+> equals,indent (pPrintPrec 0 ty)]+ pPrint (IFunctionDecl _ f cm a ty) =+ sep [ ppQIdent f, maybePP (ppPragma "METHOD" . ppIdent) cm+ , int a, text "::", pPrintPrec 0 ty ]+ pPrint (HidingClassDecl _ cx qcls k clsvar) = text "hiding" <+>+ ppClassInstHead "class" cx (ppQIdentWithKind qcls k) (ppIdent clsvar)+ pPrint (IClassDecl _ cx qcls k clsvar ms hs) =+ ppClassInstHead "class" cx (ppQIdentWithKind qcls k) (ppIdent clsvar) <+>+ lbrace $$+ vcat (punctuate semi $ map (indent . pPrint) ms) $$+ rbrace <+> ppHiding hs+ pPrint (IInstanceDecl _ cx qcls inst impls m) =+ ppClassInstHead "instance" cx (ppQIdent qcls) (ppInstanceType inst) <+>+ lbrace $$+ vcat (punctuate semi $ map (indent . ppIMethodImpl) impls) $$+ rbrace <+> maybePP (ppPragma "MODULE" . ppMIdent) m++ppITypeDeclLhs :: String -> QualIdent -> Maybe KindExpr -> [Ident] -> Doc+ppITypeDeclLhs kw tc k tvs =+ text kw <+> ppQIdentWithKind tc k <+> hsep (map ppIdent tvs)++instance Pretty IMethodDecl where+ pPrint (IMethodDecl _ f a qty) =+ ppIdent f <+> maybePP int a <+> text "::" <+> pPrintPrec 0 qty++ppIMethodImpl :: IMethodImpl -> Doc+ppIMethodImpl (f, a) = ppIdent f <+> int a++ppQIdentWithKind :: QualIdent -> Maybe KindExpr -> Doc+ppQIdentWithKind tc (Just k) =+ parens $ ppQIdent tc <+> text "::" <+> pPrintPrec 0 k+ppQIdentWithKind tc Nothing = ppQIdent tc++ppHiding :: [Ident] -> Doc+ppHiding hs+ | null hs = empty+ | otherwise = ppPragma "HIDING" $ list $ map ppIdent hs++-- ---------------------------------------------------------------------------+-- Kinds+-- ---------------------------------------------------------------------------++instance Pretty KindExpr where+ pPrintPrec _ Star = char '*'+ pPrintPrec p (ArrowKind k1 k2) =+ parenIf (p > 0) (fsep (ppArrowKind (ArrowKind k1 k2)))+ where+ ppArrowKind (ArrowKind k1' k2') =+ pPrintPrec 1 k1' <+> rarrow : ppArrowKind k2'+ ppArrowKind k =+ [pPrintPrec 0 k]++-- ---------------------------------------------------------------------------+-- Types+-- ---------------------------------------------------------------------------++instance Pretty QualTypeExpr where+ pPrint (QualTypeExpr _ cx ty) = ppContext cx <+> pPrintPrec 0 ty++instance Pretty TypeExpr where+ pPrintPrec _ (ConstructorType _ tc) = ppQIdent tc+ pPrintPrec p (ApplyType _ ty1 ty2) = parenIf (p > 1) (ppApplyType ty1 [ty2])+ where+ ppApplyType (ApplyType _ ty1' ty2') tys =+ ppApplyType ty1' (ty2' : tys)+ ppApplyType ty tys =+ pPrintPrec 1 ty <+> fsep (map (pPrintPrec 2) tys)+ pPrintPrec _ (VariableType _ tv) = ppIdent tv+ pPrintPrec _ (TupleType _ tys) = parenList (map (pPrintPrec 0) tys)+ pPrintPrec _ (ListType _ ty) = brackets (pPrintPrec 0 ty)+ pPrintPrec p (ArrowType spi ty1 ty2) = parenIf (p > 0)+ (fsep (ppArrowType (ArrowType spi ty1 ty2)))+ where+ ppArrowType (ArrowType _ ty1' ty2') =+ pPrintPrec 1 ty1' <+> rarrow : ppArrowType ty2'+ ppArrowType ty =+ [pPrintPrec 0 ty]+ pPrintPrec _ (ParenType _ ty) = parens (pPrintPrec 0 ty)+ pPrintPrec p (ForallType _ vs ty)+ | null vs = pPrintPrec p ty+ | otherwise = parenIf (p > 0) $ ppQuantifiedVars vs <+> pPrintPrec 0 ty++-- ---------------------------------------------------------------------------+-- Literals+-- ---------------------------------------------------------------------------++instance Pretty Literal where+ pPrint (Char c) = text (show c)+ pPrint (Int i) = integer i+ pPrint (Float f) = double f+ pPrint (String s) = text (show s)++-- ---------------------------------------------------------------------------+-- Patterns+-- ---------------------------------------------------------------------------++instance Pretty (Pattern a) where+ pPrintPrec p (LiteralPattern _ _ l) =+ parenIf (p > 1 && isNegative l) (pPrint l)+ where+ isNegative (Char _) = False+ isNegative (Int i) = i < 0+ isNegative (Float f) = f < 0.0+ isNegative (String _) = False+ pPrintPrec p (NegativePattern _ _ l) = parenIf (p > 1)+ (ppInfixOp minusId <> pPrint l)+ pPrintPrec _ (VariablePattern _ _ v) = ppIdent v+ pPrintPrec p (ConstructorPattern _ _ c ts) = parenIf (p > 1 && not (null ts))+ (ppQIdent c <+> fsep (map (pPrintPrec 2) ts))+ pPrintPrec p (InfixPattern _ _ t1 c t2) = parenIf (p > 0)+ (sep [pPrintPrec 1 t1 <+> ppQInfixOp c, indent (pPrintPrec 0 t2)])+ pPrintPrec _ (ParenPattern _ t) = parens (pPrintPrec 0 t)+ pPrintPrec _ (TuplePattern _ ts) =+ parenList (map (pPrintPrec 0) ts)+ pPrintPrec _ (ListPattern _ _ ts) =+ bracketList (map (pPrintPrec 0) ts)+ pPrintPrec _ (AsPattern _ v t) =+ ppIdent v <> char '@' <> pPrintPrec 2 t+ pPrintPrec _ (LazyPattern _ t) = char '~' <> pPrintPrec 2 t+ pPrintPrec p (FunctionPattern _ _ f ts) = parenIf (p > 1 && not (null ts))+ (ppQIdent f <+> fsep (map (pPrintPrec 2) ts))+ pPrintPrec p (InfixFuncPattern _ _ t1 f t2) = parenIf (p > 0)+ (sep [pPrintPrec 1 t1 <+> ppQInfixOp f, indent (pPrintPrec 0 t2)])+ pPrintPrec p (RecordPattern _ _ c fs) = parenIf (p > 1)+ (ppQIdent c <+> record (list (map pPrint fs)))++instance Pretty a => Pretty (Field a) where+ pPrint (Field _ l t) = ppQIdent l <+> equals <+> pPrintPrec 0 t++-- ---------------------------------------------------------------------------+-- Expressions+-- ---------------------------------------------------------------------------++ppCondExpr :: Doc -> CondExpr a -> Doc+ppCondExpr eq (CondExpr _ g e) =+ vbar <+> sep [pPrintPrec 0 g <+> eq, indent (pPrintPrec 0 e)]++instance Pretty (Expression a) where+ pPrintPrec _ (Literal _ _ l) = pPrint l+ pPrintPrec _ (Variable _ _ v) = ppQIdent v+ pPrintPrec _ (Constructor _ _ c) = ppQIdent c+ pPrintPrec _ (Paren _ e) = parens (pPrintPrec 0 e)+ pPrintPrec p (Typed _ e ty) =+ parenIf (p > 0) (pPrintPrec 0 e <+> text "::" <+> pPrintPrec 0 ty)+ pPrintPrec _ (Tuple _ es) = parenList (map (pPrintPrec 0) es)+ pPrintPrec _ (List _ _ es) = bracketList (map (pPrintPrec 0) es)+ pPrintPrec _ (ListCompr _ e qs) =+ brackets (pPrintPrec 0 e <+> vbar <+> list (map pPrint qs))+ pPrintPrec _ (EnumFrom _ e) =+ brackets (pPrintPrec 0 e <+> text "..")+ pPrintPrec _ (EnumFromThen _ e1 e2) =+ brackets (pPrintPrec 0 e1 <> comma <+> pPrintPrec 0 e2 <+> text "..")+ pPrintPrec _ (EnumFromTo _ e1 e2) =+ brackets (pPrintPrec 0 e1 <+> text ".." <+> pPrintPrec 0 e2)+ pPrintPrec _ (EnumFromThenTo _ e1 e2 e3) =+ brackets (pPrintPrec 0 e1 <> comma <+> pPrintPrec 0 e2+ <+> text ".." <+> pPrintPrec 0 e3)+ pPrintPrec p (UnaryMinus _ e) =+ parenIf (p > 1) (ppInfixOp minusId <> pPrintPrec 1 e)+ pPrintPrec p (Apply _ e1 e2) =+ parenIf (p > 1) (sep [pPrintPrec 1 e1, indent (pPrintPrec 2 e2)])+ pPrintPrec p (InfixApply _ e1 op e2) = parenIf (p > 0)+ (sep [pPrintPrec 1 e1 <+> ppQInfixOp (opName op), indent (pPrintPrec 1 e2)])+ pPrintPrec _ (LeftSection _ e op) =+ parens (pPrintPrec 1 e <+> ppQInfixOp (opName op))+ pPrintPrec _ (RightSection _ op e) =+ parens (ppQInfixOp (opName op) <+> pPrintPrec 1 e)+ pPrintPrec p (Lambda _ t e) = parenIf (p > 0) $+ sep [backsl <> fsep (map (pPrintPrec 2) t) <+> rarrow,+ indent (pPrintPrec 0 e)]+ pPrintPrec p (Let _ _ ds e) = parenIf (p > 0)+ (sep [text "let" <+> ppBlock ds, text "in" <+> pPrintPrec 0 e])+ pPrintPrec p (Do _ _ sts e) = parenIf (p > 0)+ (text "do" <+> (vcat (map pPrint sts) $$ pPrintPrec 0 e))+ pPrintPrec p (IfThenElse _ e1 e2 e3) = parenIf (p > 0)+ (text "if" <+>+ sep [pPrintPrec 0 e1,+ text "then" <+> pPrintPrec 0 e2,+ text "else" <+> pPrintPrec 0 e3])+ pPrintPrec p (Case _ _ ct e alts) = parenIf (p > 0)+ (pPrint ct <+> pPrintPrec 0 e <+> text "of" $$+ indent (vcat (map pPrint alts)))+ pPrintPrec p (Record _ _ c fs) = parenIf (p > 0)+ (ppQIdent c <+> record (list (map pPrint fs)))+ pPrintPrec _ (RecordUpdate _ e fs) =+ pPrintPrec 0 e <+> record (list (map pPrint fs))++instance Pretty (Statement a) where+ pPrint (StmtExpr _ e) = pPrintPrec 0 e+ pPrint (StmtBind _ t e) =+ sep [pPrintPrec 0 t <+> larrow, indent (pPrintPrec 0 e)]+ pPrint (StmtDecl _ _ ds) = text "let" <+> ppBlock ds++instance Pretty CaseType where+ pPrint Rigid = text "case"+ pPrint Flex = text "fcase"++instance Pretty (Alt a) where+ pPrint (Alt _ t rhs) = ppRule (pPrintPrec 0 t) rarrow rhs++instance Pretty (Var a) where+ pPrint (Var _ ident) = ppIdent ident++instance Pretty (InfixOp a) where+ pPrint (InfixOp _ op) = ppQInfixOp op+ pPrint (InfixConstr _ op) = ppQInfixOp op++-- ---------------------------------------------------------------------------+-- Names+-- ---------------------------------------------------------------------------++-- |Pretty print an identifier+ppIdent :: Ident -> Doc+ppIdent x = parenIf (isInfixOp x) (text (idName x))++ppQIdent :: QualIdent -> Doc+ppQIdent x = parenIf (isQInfixOp x) (text (qualName x))++ppInfixOp :: Ident -> Doc+ppInfixOp x = bquotesIf (not (isInfixOp x)) (text (idName x))++ppQInfixOp :: QualIdent -> Doc+ppQInfixOp x = bquotesIf (not (isQInfixOp x)) (text (qualName x))++ppMIdent :: ModuleIdent -> Doc+ppMIdent m = text (moduleName m)++-- ---------------------------------------------------------------------------+-- Print printing utilities+-- ---------------------------------------------------------------------------++indent :: Doc -> Doc+indent = nest 2++parenList :: [Doc] -> Doc+parenList = parens . list++record :: Doc -> Doc+record doc | isEmpty doc = braces empty+ | otherwise = braces $ space <> doc <> space++bracketList :: [Doc] -> Doc+bracketList = brackets . list
− src/Curry/Syntax/Pretty.lhs
@@ -1,368 +0,0 @@--% $Id: CurryPP.lhs,v 1.50 2004/02/15 22:10:27 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{CurryPP.lhs}-\section{A Pretty Printer for Curry}\label{sec:CurryPP}-This module implements a pretty printer for Curry expressions. It was-derived from the Haskell pretty printer provided in Simon Marlow's-Haskell parser.-\begin{verbatim}--> module Curry.Syntax.Pretty where--> import Text.PrettyPrint.HughesPJ--> import Curry.Base.Ident-> import Curry.Syntax.Type---\end{verbatim}-Pretty print a module-\begin{verbatim}--> ppModule :: Module -> Doc-> ppModule (Module m es ds) = ppModuleHeader m es $$ ppBlock ds--\end{verbatim}-Module header-\begin{verbatim}--> ppModuleHeader :: ModuleIdent -> Maybe ExportSpec -> Doc-> ppModuleHeader m es =-> text "module" <+> ppMIdent m <+> maybePP ppExportSpec es <+> text "where"--> ppExportSpec :: ExportSpec -> Doc-> ppExportSpec (Exporting _ es) = parenList (map ppExport es)--> ppExport :: Export -> Doc-> ppExport (Export x) = ppQIdent x-> ppExport (ExportTypeWith tc cs) = ppQIdent tc <> parenList (map ppIdent cs)-> ppExport (ExportTypeAll tc) = ppQIdent tc <> text "(..)"-> ppExport (ExportModule m) = text "module" <+> ppMIdent m--\end{verbatim}-Declarations-\begin{verbatim}--> ppBlock :: [Decl] -> Doc-> ppBlock = vcat . map ppDecl--> ppDecl :: Decl -> Doc-> ppDecl (ImportDecl _ m q asM is) =-> text "import" <+> ppQualified q <+> ppMIdent m <+> maybePP ppAs asM-> <+> maybePP ppImportSpec is-> where ppQualified q = if q then text "qualified" else empty-> ppAs m = text "as" <+> ppMIdent m-> ppDecl (InfixDecl _ fix p ops) = ppPrec fix p <+> list (map ppInfixOp ops)-> ppDecl (DataDecl _ tc tvs cs) =-> sep (ppTypeDeclLhs "data" tc tvs :-> map indent (zipWith (<+>) (equals : repeat vbar) (map ppConstr cs)))-> ppDecl (NewtypeDecl _ tc tvs nc) =-> sep [ppTypeDeclLhs "newtype" tc tvs <+> equals,indent (ppNewConstr nc)]-> ppDecl (TypeDecl _ tc tvs ty) =-> sep [ppTypeDeclLhs "type" tc tvs <+> equals,indent (ppTypeExpr 0 ty)]-> ppDecl (TypeSig _ fs ty) =-> list (map ppIdent fs) <+> text "::" <+> ppTypeExpr 0 ty-> ppDecl (EvalAnnot _ fs ev) =-> list (map ppIdent fs) <+> text "eval" <+> ppEval ev-> where ppEval EvalRigid = text "rigid"-> ppEval EvalChoice = text "choice"-> ppDecl (FunctionDecl _ _ eqs) = vcat (map ppEquation eqs)-> ppDecl (ExternalDecl p cc impent f ty) =-> sep [text "external" <+> ppCallConv cc <+> maybePP (text . show) impent,-> indent (ppDecl (TypeSig p [f] ty))]-> where ppCallConv CallConvPrimitive = text "primitive"-> ppCallConv CallConvCCall = text "ccall"-> ppDecl (FlatExternalDecl _ fs) = list (map ppIdent fs) <+> text "external"-> ppDecl (PatternDecl _ t rhs) = ppRule (ppConstrTerm 0 t) equals rhs-> ppDecl (ExtraVariables _ vs) = list (map ppIdent vs) <+> text "free"--> ppImportSpec :: ImportSpec -> Doc-> ppImportSpec (Importing _ is) = parenList (map ppImport is)-> ppImportSpec (Hiding _ is) = text "hiding" <+> parenList (map ppImport is)--> ppImport :: Import -> Doc-> ppImport (Import x) = ppIdent x-> ppImport (ImportTypeWith tc cs) = ppIdent tc <> parenList (map ppIdent cs)-> ppImport (ImportTypeAll tc) = ppIdent tc <> text "(..)"--> ppPrec :: Infix -> Integer -> Doc-> ppPrec fix p = ppAssoc fix <+> ppPrio p-> where ppAssoc InfixL = text "infixl"-> ppAssoc InfixR = text "infixr"-> ppAssoc Infix = text "infix"-> ppPrio p = if p < 0 then empty else integer p--> ppTypeDeclLhs :: String -> Ident -> [Ident] -> Doc-> ppTypeDeclLhs kw tc tvs = text kw <+> ppIdent tc <+> hsep (map ppIdent tvs)--> ppConstr :: ConstrDecl -> Doc-> ppConstr (ConstrDecl _ tvs c tys) =-> sep [ppExistVars tvs,ppIdent c <+> fsep (map (ppTypeExpr 2) tys)]-> ppConstr (ConOpDecl _ tvs ty1 op ty2) =-> sep [ppExistVars tvs,ppTypeExpr 1 ty1,ppInfixOp op <+> ppTypeExpr 1 ty2]--> ppNewConstr :: NewConstrDecl -> Doc-> ppNewConstr (NewConstrDecl _ tvs c ty) =-> sep [ppExistVars tvs,ppIdent c <+> ppTypeExpr 2 ty]--> ppExistVars :: [Ident] -> Doc-> ppExistVars tvs-> | null tvs = empty-> | otherwise = text "forall" <+> hsep (map ppIdent tvs) <+> char '.'--> ppEquation :: Equation -> Doc-> ppEquation (Equation _ lhs rhs) = ppRule (ppLhs lhs) equals rhs--> ppLhs :: Lhs -> Doc-> ppLhs (FunLhs f ts) = ppIdent f <+> fsep (map (ppConstrTerm 2) ts)-> ppLhs (OpLhs t1 f t2) =-> ppConstrTerm 1 t1 <+> ppInfixOp f <+> ppConstrTerm 1 t2-> ppLhs (ApLhs lhs ts) = parens (ppLhs lhs) <+> fsep (map (ppConstrTerm 2) ts)--> ppRule :: Doc -> Doc -> Rhs -> Doc-> ppRule lhs eq (SimpleRhs _ e ds) =-> sep [lhs <+> eq,indent (ppExpr 0 e)] $$ ppLocalDefs ds-> ppRule lhs eq (GuardedRhs es ds) =-> sep [lhs,indent (vcat (map (ppCondExpr eq) es))] $$ ppLocalDefs ds--> ppLocalDefs :: [Decl] -> Doc-> ppLocalDefs ds-> | null ds = empty-> | otherwise = indent (text "where" <+> ppBlock ds)--\end{verbatim}-Interfaces-\begin{verbatim}--> ppInterface :: Interface -> Doc-> ppInterface (Interface m ds) =-> text "interface" <+> ppMIdent m <+> text "where" <+> lbrace-> $$ vcat (punctuate semi (map ppIDecl ds)) $$ rbrace--> ppIDecl :: IDecl -> Doc-> ppIDecl (IImportDecl _ m) = text "import" <+> ppMIdent m-> ppIDecl (IInfixDecl _ fix p op) = ppPrec fix p <+> ppQInfixOp op-> ppIDecl (HidingDataDecl _ tc tvs) =-> text "hiding" <+> ppITypeDeclLhs "data" (qualify tc) tvs-> ppIDecl (IDataDecl _ tc tvs cs) =-> sep (ppITypeDeclLhs "data" tc tvs :-> map indent (zipWith (<+>) (equals : repeat vbar) (map ppIConstr cs)))-> where ppIConstr = maybe (char '_') ppConstr-> ppIDecl (INewtypeDecl _ tc tvs nc) =-> sep [ppITypeDeclLhs "newtype" tc tvs <+> equals,indent (ppNewConstr nc)]-> ppIDecl (ITypeDecl _ tc tvs ty) =-> sep [ppITypeDeclLhs "type" tc tvs <+> equals,indent (ppTypeExpr 0 ty)]-> ppIDecl (IFunctionDecl _ f _ ty) = ppQIdent f <+> text "::" <+> ppTypeExpr 0 ty--> ppITypeDeclLhs :: String -> QualIdent -> [Ident] -> Doc-> ppITypeDeclLhs kw tc tvs = text kw <+> ppQIdent tc <+> hsep (map ppIdent tvs)--\end{verbatim}-Types-\begin{verbatim}--> ppTypeExpr :: Int -> TypeExpr -> Doc-> ppTypeExpr p (ConstructorType tc tys) =-> parenExp (p > 1 && not (null tys))-> (ppQIdent tc <+> fsep (map (ppTypeExpr 2) tys))-> ppTypeExpr _ (VariableType tv) = ppIdent tv-> ppTypeExpr _ (TupleType tys) = parenList (map (ppTypeExpr 0) tys)-> ppTypeExpr _ (ListType ty) = brackets (ppTypeExpr 0 ty)-> ppTypeExpr p (ArrowType ty1 ty2) =-> parenExp (p > 0) (fsep (ppArrowType (ArrowType ty1 ty2)))-> where ppArrowType (ArrowType ty1 ty2) =-> ppTypeExpr 1 ty1 <+> rarrow : ppArrowType ty2-> ppArrowType ty = [ppTypeExpr 0 ty]-> ppTypeExpr p (RecordType fs rty) = -> braces (list (map ppTypedField fs) -> <> maybe empty (\ty -> space <> char '|' <+> ppTypeExpr 0 ty) rty)-> where-> ppTypedField (ls,ty) = -> list (map ppIdent ls) <> text "::" <> ppTypeExpr 0 ty----\end{verbatim}-Literals-\begin{verbatim}--> ppLiteral :: Literal -> Doc-> ppLiteral (Char _ c) = text (show c)-> ppLiteral (Int _ i) = integer i-> ppLiteral (Float _ f) = double f-> ppLiteral (String _ s) = text (show s)--\end{verbatim}-Patterns-\begin{verbatim}--> ppConstrTerm :: Int -> ConstrTerm -> Doc-> ppConstrTerm p (LiteralPattern l) =-> parenExp (p > 1 && isNegative l) (ppLiteral l)-> where isNegative (Char _ _) = False-> isNegative (Int _ i) = i < 0-> isNegative (Float _ f) = f < 0.0-> isNegative (String _ _) = False-> ppConstrTerm p (NegativePattern op l) =-> parenExp (p > 1) (ppInfixOp op <> ppLiteral l)-> ppConstrTerm _ (VariablePattern v) = ppIdent v-> ppConstrTerm p (ConstructorPattern c ts) =-> parenExp (p > 1 && not (null ts))-> (ppQIdent c <+> fsep (map (ppConstrTerm 2) ts))-> ppConstrTerm p (InfixPattern t1 c t2) =-> parenExp (p > 0)-> (sep [ppConstrTerm 1 t1 <+> ppQInfixOp c,-> indent (ppConstrTerm 0 t2)])-> ppConstrTerm _ (ParenPattern t) = parens (ppConstrTerm 0 t)-> ppConstrTerm _ (TuplePattern _ ts) = parenList (map (ppConstrTerm 0) ts)-> ppConstrTerm _ (ListPattern _ ts) = bracketList (map (ppConstrTerm 0) ts)-> ppConstrTerm _ (AsPattern v t) = ppIdent v <> char '@' <> ppConstrTerm 2 t-> ppConstrTerm _ (LazyPattern _ t) = char '~' <> ppConstrTerm 2 t-> ppConstrTerm p (FunctionPattern f ts) =-> parenExp (p > 1 && not (null ts))-> (ppQIdent f <+> fsep (map (ppConstrTerm 2) ts))-> ppConstrTerm p (InfixFuncPattern t1 f t2) =-> parenExp (p > 0)-> (sep [ppConstrTerm 1 t1 <+> ppQInfixOp f,-> indent (ppConstrTerm 0 t2)])-> ppConstrTerm p (RecordPattern fs rt) =-> braces (list (map ppFieldPatt fs)-> <> (maybe empty (\t -> space <> char '|' <+> ppConstrTerm 0 t) rt))--> ppFieldPatt :: Field ConstrTerm -> Doc-> ppFieldPatt (Field _ l t) = ppIdent l <> equals <> ppConstrTerm 0 t--\end{verbatim}-Expressions-\begin{verbatim}--> ppCondExpr :: Doc -> CondExpr -> Doc-> ppCondExpr eq (CondExpr _ g e) =-> vbar <+> sep [ppExpr 0 g <+> eq,indent (ppExpr 0 e)]--> ppExpr :: Int -> Expression -> Doc-> ppExpr _ (Literal l) = ppLiteral l-> ppExpr _ (Variable v) = ppQIdent v-> ppExpr _ (Constructor c) = ppQIdent c-> ppExpr _ (Paren e) = parens (ppExpr 0 e)-> ppExpr p (Typed e ty) =-> parenExp (p > 0) (ppExpr 0 e <+> text "::" <+> ppTypeExpr 0 ty)-> ppExpr _ (Tuple _ es) = parenList (map (ppExpr 0) es)-> ppExpr _ (List _ es) = bracketList (map (ppExpr 0) es)-> ppExpr _ (ListCompr _ e qs) =-> brackets (ppExpr 0 e <+> vbar <+> list (map ppStmt qs))-> ppExpr _ (EnumFrom e) = brackets (ppExpr 0 e <+> text "..")-> ppExpr _ (EnumFromThen e1 e2) =-> brackets (ppExpr 0 e1 <> comma <+> ppExpr 0 e2 <+> text "..")-> ppExpr _ (EnumFromTo e1 e2) =-> brackets (ppExpr 0 e1 <+> text ".." <+> ppExpr 0 e2)-> ppExpr _ (EnumFromThenTo e1 e2 e3) =-> brackets (ppExpr 0 e1 <> comma <+> ppExpr 0 e2-> <+> text ".." <+> ppExpr 0 e3)-> ppExpr p (UnaryMinus op e) = parenExp (p > 1) (ppInfixOp op <> ppExpr 1 e)-> ppExpr p (Apply e1 e2) =-> parenExp (p > 1) (sep [ppExpr 1 e1,indent (ppExpr 2 e2)])-> ppExpr p (InfixApply e1 op e2) =-> parenExp (p > 0) (sep [ppExpr 1 e1 <+> ppQInfixOp (opName op),-> indent (ppExpr 1 e2)])-> ppExpr _ (LeftSection e op) = parens (ppExpr 1 e <+> ppQInfixOp (opName op))-> ppExpr _ (RightSection op e) = parens (ppQInfixOp (opName op) <+> ppExpr 1 e)-> ppExpr p (Lambda _ t e) =-> parenExp (p > 0)-> (sep [backsl <> fsep (map (ppConstrTerm 2) t) <+> rarrow,-> indent (ppExpr 0 e)])-> ppExpr p (Let ds e) =-> parenExp (p > 0)-> (sep [text "let" <+> ppBlock ds <+> text "in",ppExpr 0 e])-> ppExpr p (Do sts e) =-> parenExp (p > 0) (text "do" <+> (vcat (map ppStmt sts) $$ ppExpr 0 e))-> ppExpr p (IfThenElse _ e1 e2 e3) =-> parenExp (p > 0)-> (text "if" <+>-> sep [ppExpr 0 e1,-> text "then" <+> ppExpr 0 e2,-> text "else" <+> ppExpr 0 e3])-> ppExpr p (Case _ e alts) =-> parenExp (p > 0)-> (text "case" <+> ppExpr 0 e <+> text "of" $$-> indent (vcat (map ppAlt alts)))-> ppExpr p (RecordConstr fs) =-> braces (list (map (ppFieldExpr equals) fs))-> ppExpr p (RecordSelection e l) =-> parenExp (p > 0)-> (ppExpr 1 e <+> text "->" <+> ppIdent l)-> ppExpr p (RecordUpdate fs e) =-> braces (list (map (ppFieldExpr (text ":=")) fs)-> <+> char '|' <+> ppExpr 0 e)--> ppStmt :: Statement -> Doc-> ppStmt (StmtExpr _ e) = ppExpr 0 e-> ppStmt (StmtBind _ t e) = sep [ppConstrTerm 0 t <+> larrow,indent (ppExpr 0 e)]-> ppStmt (StmtDecl ds) = text "let" <+> ppBlock ds--> ppAlt :: Alt -> Doc-> ppAlt (Alt _ t rhs) = ppRule (ppConstrTerm 0 t) rarrow rhs--> ppFieldExpr :: Doc -> Field Expression -> Doc-> ppFieldExpr comb (Field _ l e) = ppIdent l <> comb <> ppExpr 0 e--> ppOp :: InfixOp -> Doc-> ppOp (InfixOp op) = ppQInfixOp op-> ppOp (InfixConstr op) = ppQInfixOp op--\end{verbatim}--Names-\begin{verbatim}--> ppIdent :: Ident -> Doc-> ppIdent x = parenExp (isInfixOp x) (text (name x))--> ppQIdent :: QualIdent -> Doc-> ppQIdent x = parenExp (isQInfixOp x) (text (qualName x))--> ppInfixOp :: Ident -> Doc-> ppInfixOp x = backQuoteExp (not (isInfixOp x)) (text (name x))--> ppQInfixOp :: QualIdent -> Doc-> ppQInfixOp x = backQuoteExp (not (isQInfixOp x)) (text (qualName x))--> ppMIdent :: ModuleIdent -> Doc-> ppMIdent m = text (moduleName m)--\end{verbatim}-Print printing utilities-\begin{verbatim}--> indent :: Doc -> Doc-> indent = nest 2--> maybePP :: (a -> Doc) -> Maybe a -> Doc-> maybePP pp = maybe empty pp--> parenExp :: Bool -> Doc -> Doc-> parenExp b doc = if b then parens doc else doc--> backQuoteExp :: Bool -> Doc -> Doc-> backQuoteExp b doc = if b then backQuote <> doc <> backQuote else doc--> list, parenList, bracketList, braceList :: [Doc] -> Doc-> list = fsep . punctuate comma-> parenList = parens . list-> bracketList = brackets . list-> braceList = braces . list--> backQuote,backsl,vbar,rarrow,larrow :: Doc-> backQuote = char '`'-> backsl = char '\\'-> vbar = char '|'-> rarrow = text "->"-> larrow = text "<-"--\end{verbatim}
src/Curry/Syntax/ShowModule.hs view
@@ -1,462 +1,732 @@---- Transform a CurrySyntax module into a string representation without any---- pretty printing.---- Behaves like a derived Show instance even on parts with a specific one.---- ---- @author Sebastian Fischer (sebf@informatik.uni-kiel.de)---- @version December 2008---- bug fixed by bbr+{- |+ Module : $Header$+ Copyright : (c) 2008 Sebastian Fischer+ 2011 - 2015 Björn Peemöller+ 2016 Finn Teegen+ License : BSD-3-clause + Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable -module Curry.Syntax.ShowModule ( showModule ) where+ Transform a CurrySyntax module into a string representation without any+ pretty printing. + Behaves like a derived Show instance even on parts with a specific one.+-}+module Curry.Syntax.ShowModule (showModule) where+ import Curry.Base.Ident import Curry.Base.Position+import Curry.Base.Span+import Curry.Base.SpanInfo+ import Curry.Syntax.Type -showModule :: Module -> String+-- |Show a Curry module like by an devired 'Show' instance+showModule :: Show a => Module a -> String showModule m = showsModule m "\n" -showsModule :: Module -> ShowS-showsModule (Module mident espec decls)+showsModule :: Show a => Module a -> ShowS+showsModule (Module spi li ps mident espec imps decls) = showsString "Module "+ . showsLayoutInfo li . space+ . showsSpanInfo spi . space+ . showsList (\p -> showsPragma p . newline) ps . space . showsModuleIdent mident . newline . showsMaybe showsExportSpec espec . newline+ . showsList (\i -> showsImportDecl i . newline) imps . showsList (\d -> showsDecl d . newline) decls -showsPosition :: Position -> ShowS-showsPosition Position{line=row,column=col} = showsPair shows shows (row,col)--- showsPosition (Position file row col)--- = showsString "(Position "--- . shows file . space--- . shows row . space--- . shows col--- . showsString ")"+showsPragma :: ModulePragma -> ShowS+showsPragma (LanguagePragma pos exts)+ = showsString "(LanguagePragma "+ . showsSpanInfo pos . space+ . showsList showsExtension exts+ . showsString ")"+showsPragma (OptionsPragma pos mbTool args)+ = showsString "(OptionsPragma "+ . showsSpanInfo pos . space+ . showsMaybe shows mbTool+ . shows args+ . showsString ")" +showsExtension :: Extension -> ShowS+showsExtension (KnownExtension p e)+ = showsString "(KnownExtension "+ . showsSpanInfo p . space+ . shows e+ . showString ")"+showsExtension (UnknownExtension p s)+ = showsString "(UnknownExtension "+ . showsSpanInfo p . space+ . shows s+ . showString ")"+ showsExportSpec :: ExportSpec -> ShowS showsExportSpec (Exporting pos exports) = showsString "(Exporting "- . showsPosition pos . space+ . showsSpanInfo pos . space . showsList showsExport exports . showsString ")" showsExport :: Export -> ShowS-showsExport (Export qident)- = showsString "(Export " . showsQualIdent qident . showsString ")"-showsExport (ExportTypeWith qident ids)+showsExport (Export spi qident)+ = showsString "(Export "+ . showsSpanInfo spi . space+ . showsQualIdent qident+ . showsString ")"+showsExport (ExportTypeWith spi qident ids) = showsString "(ExportTypeWith "+ . showsSpanInfo spi . space . showsQualIdent qident . space . showsList showsIdent ids . showsString ")"-showsExport (ExportTypeAll qident)- = showsString "(ExportTypeAll " . showsQualIdent qident . showsString ")"-showsExport (ExportModule m) - = showsString "(ExportModule " . showsModuleIdent m . showChar ')'+showsExport (ExportTypeAll spi qident)+ = showsString "(ExportTypeAll "+ . showsSpanInfo spi . space+ . showsQualIdent qident+ . showsString ")"+showsExport (ExportModule spi m)+ = showsString "(ExportModule "+ . showsSpanInfo spi . space+ . showsModuleIdent m+ . showsString ")" +showsImportDecl :: ImportDecl -> ShowS+showsImportDecl (ImportDecl spi mident quali mmident mimpspec)+ = showsString "(ImportDecl "+ . showsSpanInfo spi . space+ . showsModuleIdent mident . space+ . shows quali . space+ . showsMaybe showsModuleIdent mmident . space+ . showsMaybe showsImportSpec mimpspec+ . showsString ")"+ showsImportSpec :: ImportSpec -> ShowS-showsImportSpec (Importing pos imports)+showsImportSpec (Importing spi imports) = showsString "(Importing "- . showsPosition pos . space+ . showsSpanInfo spi . space . showsList showsImport imports . showsString ")"-showsImportSpec (Hiding pos imports)+showsImportSpec (Hiding spi imports) = showsString "(Hiding "- . showsPosition pos . space+ . showsSpanInfo spi . space . showsList showsImport imports . showsString ")" showsImport :: Import -> ShowS-showsImport (Import ident)- = showsString "(Import " . showsIdent ident . showsString ")"-showsImport (ImportTypeWith ident idents)+showsImport (Import spi ident)+ = showsString "(Import "+ . showsSpanInfo spi . space+ . showsIdent ident+ . showsString ")"+showsImport (ImportTypeWith spi ident idents) = showsString "(ImportTypeWith "+ . showsSpanInfo spi . space . showsIdent ident . space . showsList showsIdent idents . showsString ")"-showsImport (ImportTypeAll ident)- = showsString "(ImportTypeAll " . showsIdent ident . showsString ")"--showsDecl :: Decl -> ShowS-showsDecl (ImportDecl pos mident quali mmident mimpspec)- = showsString "(ImportDecl "- . showsPosition pos . space- . showsModuleIdent mident . space- . shows quali . space- . showsMaybe showsModuleIdent mmident . space- . showsMaybe showsImportSpec mimpspec+showsImport (ImportTypeAll spi ident)+ = showsString "(ImportTypeAll "+ . showsSpanInfo spi . space+ . showsIdent ident . showsString ")"-showsDecl (InfixDecl pos infx prec idents)++showsDecl :: Show a => Decl a -> ShowS+showsDecl (InfixDecl spi infx prec idents) = showsString "(InfixDecl "- . showsPosition pos . space+ . showsSpanInfo spi . space . shows infx . space- . shows prec . space+ . showsMaybe shows prec . space . showsList showsIdent idents . showsString ")"-showsDecl (DataDecl pos ident idents consdecls)+showsDecl (DataDecl spi ident idents consdecls classes) = showsString "(DataDecl "- . showsPosition pos . space+ . showsSpanInfo spi . space . showsIdent ident . space . showsList showsIdent idents . space- . showsList showsConsDecl consdecls+ . showsList showsConsDecl consdecls . space+ . showsList showsQualIdent classes . showsString ")"-showsDecl (NewtypeDecl pos ident idents newconsdecl)+showsDecl (ExternalDataDecl spi ident idents)+ = showsString "(ExternalDataDecl "+ . showsSpanInfo spi . space+ . showsIdent ident . space+ . showsList showsIdent idents+ . showsString ")"+showsDecl (NewtypeDecl spi ident idents newconsdecl classes) = showsString "(NewtypeDecl "- . showsPosition pos . space+ . showsSpanInfo spi . space . showsIdent ident . space . showsList showsIdent idents . space- . showsNewConsDecl newconsdecl+ . showsNewConsDecl newconsdecl . space+ . showsList showsQualIdent classes . showsString ")"-showsDecl (TypeDecl pos ident idents typ)+showsDecl (TypeDecl spi ident idents typ) = showsString "(TypeDecl "- . showsPosition pos . space+ . showsSpanInfo spi . space . showsIdent ident . space . showsList showsIdent idents . space . showsTypeExpr typ . showsString ")"-showsDecl (TypeSig pos idents typ)+showsDecl (TypeSig spi idents qtype) = showsString "(TypeSig "- . showsPosition pos . space- . showsList showsIdent idents . space- . showsTypeExpr typ- . showsString ")"-showsDecl (EvalAnnot pos idents annot)- = showsString "(EvalAnnot "- . showsPosition pos . space+ . showsSpanInfo spi . space . showsList showsIdent idents . space- . shows annot+ . showsQualTypeExpr qtype . showsString ")"-showsDecl (FunctionDecl pos ident eqs)+showsDecl (FunctionDecl spi a ident eqs) = showsString "(FunctionDecl "- . showsPosition pos . space+ . showsSpanInfo spi . space+ . showsPrec 11 a . space . showsIdent ident . space . showsList showsEquation eqs . showsString ")"-showsDecl (ExternalDecl pos cconv mstr ident typ)+showsDecl (ExternalDecl spi vars) = showsString "(ExternalDecl "- . showsPosition pos . space- . shows cconv . space- . shows mstr . space- . showsIdent ident . space- . showsTypeExpr typ- . showsString ")"-showsDecl (FlatExternalDecl pos idents)- = showsString "(FlatExternalDecl "- . showsPosition pos . space- . showsList showsIdent idents+ . showsSpanInfo spi . space+ . showsList showsVar vars . showsString ")"-showsDecl (PatternDecl pos cons rhs)+showsDecl (PatternDecl spi cons rhs) = showsString "(PatternDecl "- . showsPosition pos . space+ . showsSpanInfo spi . space . showsConsTerm cons . space . showsRhs rhs . showsString ")"-showsDecl (ExtraVariables pos idents)- = showsString "(ExtraVariables "- . showsPosition pos . space- . showsList showsIdent idents+showsDecl (FreeDecl spi vars)+ = showsString "(FreeDecl "+ . showsSpanInfo spi . space+ . showsList showsVar vars . showsString ")"+showsDecl (DefaultDecl spi types)+ = showsString "(DefaultDecl "+ . showsSpanInfo spi . space+ . showsList showsTypeExpr types+ . showsString ")"+showsDecl (ClassDecl spi li context cls clsvar decls)+ = showsString "(ClassDecl "+ . showsSpanInfo spi . space+ . showsLayoutInfo li . space+ . showsContext context . space+ . showsIdent cls . space+ . showsIdent clsvar . space+ . showsList showsDecl decls+ . showsString ")"+showsDecl (InstanceDecl spi li context qcls inst decls)+ = showsString "(InstanceDecl "+ . showsSpanInfo spi . space+ . showsLayoutInfo li . space+ . showsContext context . space+ . showsQualIdent qcls . space+ . showsInstanceType inst . space+ . showsList showsDecl decls+ . showsString ")" +showsContext :: Context -> ShowS+showsContext = showsList showsConstraint++showsConstraint :: Constraint -> ShowS+showsConstraint (Constraint spi qcls ty)+ = showsString "(Constraint "+ . showsSpanInfo spi . space+ . showsQualIdent qcls . space+ . showsTypeExpr ty+ . showsString ")"++showsInstanceType :: InstanceType -> ShowS+showsInstanceType = showsTypeExpr+ showsConsDecl :: ConstrDecl -> ShowS-showsConsDecl (ConstrDecl pos idents ident types)+showsConsDecl (ConstrDecl spi ident types) = showsString "(ConstrDecl "- . showsPosition pos . space- . showsList showsIdent idents . space+ . showsSpanInfo spi . space . showsIdent ident . space . showsList showsTypeExpr types . showsString ")"+showsConsDecl (ConOpDecl spi ty1 ident ty2)+ = showsString "(ConOpDecl "+ . showsSpanInfo spi . space+ . showsTypeExpr ty1 . space+ . showsIdent ident . space+ . showsTypeExpr ty2+ . showsString ")"+showsConsDecl (RecordDecl spi ident fs)+ = showsString "(RecordDecl "+ . showsSpanInfo spi . space+ . showsIdent ident . space+ . showsList showsFieldDecl fs+ . showsString ")" +showsFieldDecl :: FieldDecl -> ShowS+showsFieldDecl (FieldDecl spi labels ty)+ = showsString "(FieldDecl "+ . showsSpanInfo spi . space+ . showsList showsIdent labels . space+ . showsTypeExpr ty+ . showsString ")"+ showsNewConsDecl :: NewConstrDecl -> ShowS-showsNewConsDecl (NewConstrDecl pos idents ident typ)+showsNewConsDecl (NewConstrDecl spi ident typ) = showsString "(NewConstrDecl "- . showsPosition pos . space- . showsList showsIdent idents . space+ . showsSpanInfo spi . space . showsIdent ident . space . showsTypeExpr typ . showsString ")"+showsNewConsDecl (NewRecordDecl spi ident fld)+ = showsString "(NewRecordDecl "+ . showsSpanInfo spi . space+ . showsIdent ident . space+ . showsPair showsIdent showsTypeExpr fld+ . showsString ")" +showsQualTypeExpr :: QualTypeExpr -> ShowS+showsQualTypeExpr (QualTypeExpr spi context typ)+ = showsString "(QualTypeExpr "+ . showsSpanInfo spi . space+ . showsContext context . space+ . showsTypeExpr typ+ . showsString ")"+ showsTypeExpr :: TypeExpr -> ShowS-showsTypeExpr (ConstructorType qident types)+showsTypeExpr (ConstructorType spi qident) = showsString "(ConstructorType "+ . showsSpanInfo spi . space . showsQualIdent qident . space+ . showsString ")"+showsTypeExpr (ApplyType spi type1 type2)+ = showsString "(ApplyType "+ . showsSpanInfo spi . space+ . showsTypeExpr type1 . space+ . showsTypeExpr type2 . space+ . showsString ")"+showsTypeExpr (VariableType spi ident)+ = showsString "(VariableType "+ . showsSpanInfo spi . space+ . showsIdent ident+ . showsString ")"+showsTypeExpr (TupleType spi types)+ = showsString "(TupleType "+ . showsSpanInfo spi . space . showsList showsTypeExpr types . showsString ")"-showsTypeExpr (VariableType ident)- = showsString "(VariableType " . showsIdent ident . showsString ")"-showsTypeExpr (TupleType types)- = showsString "(TupleType " . showsList showsTypeExpr types . showsString ")"-showsTypeExpr (ListType typ)- = showsString "(ListType " . showsTypeExpr typ . showsString ")"-showsTypeExpr (ArrowType dom ran)+showsTypeExpr (ListType spi typ)+ = showsString "(ListType "+ . showsSpanInfo spi . space+ . showsTypeExpr typ+ . showsString ")"+showsTypeExpr (ArrowType spi dom ran) = showsString "(ArrowType "+ . showsSpanInfo spi . space . showsTypeExpr dom . space . showsTypeExpr ran . showsString ")"-showsTypeExpr (RecordType fieldts mtyp)- = showsString "(RecordType "- . showsList (showsPair (showsList showsIdent) showsTypeExpr) fieldts . space- . showsMaybe showsTypeExpr mtyp+showsTypeExpr (ParenType spi ty)+ = showsString "(ParenType "+ . showsSpanInfo spi . space+ . showsTypeExpr ty . showsString ")"+showsTypeExpr (ForallType spi vars ty)+ = showsString "(ForallType "+ . showsSpanInfo spi . space+ . showsList showsIdent vars+ . showsTypeExpr ty+ . showsString ")" -showsEquation :: Equation -> ShowS-showsEquation (Equation pos lhs rhs)+showsEquation :: Show a => Equation a -> ShowS+showsEquation (Equation spi lhs rhs) = showsString "(Equation "- . showsPosition pos . space+ . showsSpanInfo spi . space . showsLhs lhs . space . showsRhs rhs . showsString ")" -showsLhs :: Lhs -> ShowS-showsLhs (FunLhs ident conss)+showsLhs :: Show a => Lhs a -> ShowS+showsLhs (FunLhs spi ident conss) = showsString "(FunLhs "+ . showsSpanInfo spi . space . showsIdent ident . space . showsList showsConsTerm conss . showsString ")"-showsLhs (OpLhs cons1 ident cons2)+showsLhs (OpLhs spi cons1 ident cons2) = showsString "(OpLhs "+ . showsSpanInfo spi . space . showsConsTerm cons1 . space . showsIdent ident . space . showsConsTerm cons2 . showsString ")"-showsLhs (ApLhs lhs conss)+showsLhs (ApLhs spi lhs conss) = showsString "(ApLhs "+ . showsSpanInfo spi . space . showsLhs lhs . space . showsList showsConsTerm conss . showsString ")" -showsRhs :: Rhs -> ShowS-showsRhs (SimpleRhs pos exp decls)+showsRhs :: Show a => Rhs a -> ShowS+showsRhs (SimpleRhs spi li expr decls) = showsString "(SimpleRhs "- . showsPosition pos . space- . showsExpression exp . space+ . showsSpanInfo spi . space+ . showsLayoutInfo li . space+ . showsExpression expr . space . showsList showsDecl decls . showsString ")"-showsRhs (GuardedRhs cexps decls)+showsRhs (GuardedRhs spi li cexps decls) = showsString "(GuardedRhs "+ . showsSpanInfo spi . space+ . showsLayoutInfo li . space . showsList showsCondExpr cexps . space . showsList showsDecl decls . showsString ")" -showsCondExpr :: CondExpr -> ShowS-showsCondExpr (CondExpr pos exp1 exp2)+showsCondExpr :: Show a => CondExpr a -> ShowS+showsCondExpr (CondExpr spi exp1 exp2) = showsString "(CondExpr "- . showsPosition pos . space+ . showsSpanInfo spi . space . showsExpression exp1 . space . showsExpression exp2 . showsString ")" showsLiteral :: Literal -> ShowS-showsLiteral (Char _ c) = showsString "(Char " . shows c . showsString ")"-showsLiteral (Int ident n)+showsLiteral (Char c)+ = showsString "(Char "+ . shows c+ . showsString ")"+showsLiteral (Int n) = showsString "(Int "- . showsIdent ident . space . shows n . showsString ")"-showsLiteral (Float _ x) = showsString "(Float " . shows x . showsString ")"-showsLiteral (String _ s) = showsString "(String " . shows s . showsString ")"+showsLiteral (Float x)+ = showsString "(Float "+ . shows x+ . showsString ")"+showsLiteral (String s)+ = showsString "(String "+ . shows s+ . showsString ")" -showsConsTerm :: ConstrTerm -> ShowS-showsConsTerm (LiteralPattern lit)+showsConsTerm :: Show a => Pattern a -> ShowS+showsConsTerm (LiteralPattern spi a lit) = showsString "(LiteralPattern "+ . showsSpanInfo spi . space+ . showsPrec 11 a . space . showsLiteral lit . showsString ")"-showsConsTerm (NegativePattern ident lit)+showsConsTerm (NegativePattern spi a lit) = showsString "(NegativePattern "- . showsIdent ident . space+ . showsSpanInfo spi . space+ . showsPrec 11 a . space . showsLiteral lit . showsString ")"-showsConsTerm (VariablePattern ident)+showsConsTerm (VariablePattern spi a ident) = showsString "(VariablePattern "- . showsIdent ident + . showsSpanInfo spi . space+ . showsPrec 11 a . space+ . showsIdent ident . showsString ")"-showsConsTerm (ConstructorPattern qident conss)+showsConsTerm (ConstructorPattern spi a qident conss) = showsString "(ConstructorPattern "+ . showsSpanInfo spi . space+ . showsPrec 11 a . space . showsQualIdent qident . space . showsList showsConsTerm conss . showsString ")"-showsConsTerm (InfixPattern cons1 qident cons2)+showsConsTerm (InfixPattern spi a cons1 qident cons2) = showsString "(InfixPattern "+ . showsSpanInfo spi . space+ . showsPrec 11 a . space . showsConsTerm cons1 . space . showsQualIdent qident . space . showsConsTerm cons2 . showsString ")"-showsConsTerm (ParenPattern cons)+showsConsTerm (ParenPattern spi cons) = showsString "(ParenPattern "+ . showsSpanInfo spi . space . showsConsTerm cons . showsString ")"-showsConsTerm (TuplePattern _ conss)+showsConsTerm (TuplePattern spi conss) = showsString "(TuplePattern "+ . showsSpanInfo spi . space . showsList showsConsTerm conss . showsString ")"-showsConsTerm (ListPattern _ conss)+showsConsTerm (ListPattern spi a conss) = showsString "(ListPattern "+ . showsSpanInfo spi . space+ . showsPrec 11 a . space . showsList showsConsTerm conss . showsString ")"-showsConsTerm (AsPattern ident cons)+showsConsTerm (AsPattern spi ident cons) = showsString "(AsPattern "+ . showsSpanInfo spi . space . showsIdent ident . space . showsConsTerm cons . showsString ")"-showsConsTerm (LazyPattern _ cons)+showsConsTerm (LazyPattern spi cons) = showsString "(LazyPattern "+ . showsSpanInfo spi . space . showsConsTerm cons . showsString ")"-showsConsTerm (FunctionPattern qident conss)+showsConsTerm (FunctionPattern spi a qident conss) = showsString "(FunctionPattern "+ . showsSpanInfo spi . space+ . showsPrec 11 a . space . showsQualIdent qident . space . showsList showsConsTerm conss . showsString ")"-showsConsTerm (InfixFuncPattern cons1 qident cons2)+showsConsTerm (InfixFuncPattern spi a cons1 qident cons2) = showsString "(InfixFuncPattern "+ . showsSpanInfo spi . space+ . showsPrec 11 a . space . showsConsTerm cons1 . space . showsQualIdent qident . space . showsConsTerm cons2 . showsString ")"-showsConsTerm (RecordPattern cfields mcons)- = shows "(RecordPattern "+showsConsTerm (RecordPattern spi a qident cfields)+ = showsString "(RecordPattern "+ . showsSpanInfo spi . space+ . showsPrec 11 a . space+ . showsQualIdent qident . space . showsList (showsField showsConsTerm) cfields . space- . showsMaybe showsConsTerm mcons . showsString ")" -showsExpression :: Expression -> ShowS-showsExpression (Literal lit)- = showsString "(Literal " . showsLiteral lit . showsString ")"-showsExpression (Variable qident)- = showsString "(Variable " . showsQualIdent qident . showsString ")"-showsExpression (Constructor qident)- = showsString "(Constructor " . showsQualIdent qident . showsString ")"-showsExpression (Paren exp)- = showsString "(Paren " . showsExpression exp . showsString ")"-showsExpression (Typed exp typ)+showsExpression :: Show a => Expression a -> ShowS+showsExpression (Literal spi a lit)+ = showsString "(Literal "+ . showsSpanInfo spi . space+ . showsPrec 11 a . space+ . showsLiteral lit+ . showsString ")"+showsExpression (Variable spi a qident)+ = showsString "(Variable "+ . showsSpanInfo spi . space+ . showsPrec 11 a . space+ . showsQualIdent qident+ . showsString ")"+showsExpression (Constructor spi a qident)+ = showsString "(Constructor "+ . showsSpanInfo spi . space+ . showsPrec 11 a . space+ . showsQualIdent qident+ . showsString ")"+showsExpression (Paren spi expr)+ = showsString "(Paren "+ . showsSpanInfo spi . space+ . showsExpression expr+ . showsString ")"+showsExpression (Typed spi expr qtype) = showsString "(Typed "- . showsExpression exp . space- . showsTypeExpr typ+ . showsSpanInfo spi . space+ . showsExpression expr . space+ . showsQualTypeExpr qtype . showsString ")"-showsExpression (Tuple _ exps)- = showsString "(Tuple " . showsList showsExpression exps . showsString ")"-showsExpression (List _ exps)- = showsString "(List " . showsList showsExpression exps . showsString ")"-showsExpression (ListCompr _ exp stmts)+showsExpression (Tuple spi exps)+ = showsString "(Tuple "+ . showsSpanInfo spi . space+ . showsList showsExpression exps+ . showsString ")"+showsExpression (List spi a exps)+ = showsString "(List "+ . showsSpanInfo spi . space+ . showsPrec 11 a . space+ . showsList showsExpression exps+ . showsString ")"+showsExpression (ListCompr spi expr stmts) = showsString "(ListCompr "- . showsExpression exp . space+ . showsSpanInfo spi . space+ . showsExpression expr . space . showsList showsStatement stmts . showsString ")"-showsExpression (EnumFrom exp)- = showsString "(EnumFrom " . showsExpression exp . showsString ")"-showsExpression (EnumFromThen exp1 exp2)+showsExpression (EnumFrom spi expr)+ = showsString "(EnumFrom "+ . showsSpanInfo spi . space+ . showsExpression expr+ . showsString ")"+showsExpression (EnumFromThen spi exp1 exp2) = showsString "(EnumFromThen "+ . showsSpanInfo spi . space . showsExpression exp1 . space . showsExpression exp2 . showsString ")"-showsExpression (EnumFromTo exp1 exp2)+showsExpression (EnumFromTo spi exp1 exp2) = showsString "(EnumFromTo "+ . showsSpanInfo spi . space . showsExpression exp1 . space . showsExpression exp2 . showsString ")"-showsExpression (EnumFromThenTo exp1 exp2 exp3)+showsExpression (EnumFromThenTo spi exp1 exp2 exp3) = showsString "(EnumFromThenTo "+ . showsSpanInfo spi . space . showsExpression exp1 . space . showsExpression exp2 . space . showsExpression exp3 . showsString ")"-showsExpression (UnaryMinus ident exp)+showsExpression (UnaryMinus spi expr) = showsString "(UnaryMinus "- . showsIdent ident . space- . showsExpression exp+ . showsSpanInfo spi . space+ . showsExpression expr . showsString ")"-showsExpression (Apply exp1 exp2)+showsExpression (Apply spi exp1 exp2) = showsString "(Apply "+ . showsSpanInfo spi . space . showsExpression exp1 . space . showsExpression exp2 . showsString ")"-showsExpression (InfixApply exp1 op exp2)+showsExpression (InfixApply spi exp1 op exp2) = showsString "(InfixApply "+ . showsSpanInfo spi . space . showsExpression exp1 . space . showsInfixOp op . space . showsExpression exp2 . showsString ")"-showsExpression (LeftSection exp op)+showsExpression (LeftSection spi expr op) = showsString "(LeftSection "- . showsExpression exp . space+ . showsSpanInfo spi . space+ . showsExpression expr . space . showsInfixOp op . showsString ")"-showsExpression (RightSection op exp)+showsExpression (RightSection spi op expr) = showsString "(RightSection "+ . showsSpanInfo spi . space . showsInfixOp op . space- . showsExpression exp+ . showsExpression expr . showsString ")"-showsExpression (Lambda _ conss exp)+showsExpression (Lambda spi conss expr) = showsString "(Lambda "+ . showsSpanInfo spi . space . showsList showsConsTerm conss . space- . showsExpression exp + . showsExpression expr . showsString ")"-showsExpression (Let decls exp)+showsExpression (Let spi li decls expr) = showsString "(Let "+ . showsSpanInfo spi . space+ . showsLayoutInfo li . space . showsList showsDecl decls . space- . showsExpression exp + . showsExpression expr . showsString ")"-showsExpression (Do stmts exp)+showsExpression (Do spi li stmts expr) = showsString "(Do "+ . showsSpanInfo spi . space+ . showsLayoutInfo li . space . showsList showsStatement stmts . space- . showsExpression exp+ . showsExpression expr . showsString ")"-showsExpression (IfThenElse _ exp1 exp2 exp3)+showsExpression (IfThenElse spi exp1 exp2 exp3) = showsString "(IfThenElse "+ . showsSpanInfo spi . space . showsExpression exp1 . space . showsExpression exp2 . space . showsExpression exp3 . showsString ")"-showsExpression (Case _ exp alts)+showsExpression (Case spi li ct expr alts) = showsString "(Case "- . showsExpression exp . space+ . showsSpanInfo spi . space+ . showsLayoutInfo li . space+ . showsCaseType ct . space+ . showsExpression expr . space . showsList showsAlt alts . showsString ")"-showsExpression (RecordConstr efields)- = showsString "(RecordConstr "+showsExpression (RecordUpdate spi expr efields)+ = showsString "(RecordUpdate "+ . showsSpanInfo spi . space+ . showsExpression expr . space . showsList (showsField showsExpression) efields . showsString ")"-showsExpression (RecordSelection exp ident)- = showsString "(RecordSelection "- . showsExpression exp . space- . showsIdent ident- . showsString ")"-showsExpression (RecordUpdate efields exp)- = showsString "(RecordUpdate "- . showsList (showsField showsExpression) efields . space- . showsExpression exp+showsExpression (Record spi a qident efields)+ = showsString "(Record "+ . showsSpanInfo spi . space+ . showsPrec 11 a . space+ . showsQualIdent qident . space+ . showsList (showsField showsExpression) efields . showsString ")" -showsInfixOp :: InfixOp -> ShowS-showsInfixOp (InfixOp qident)- = showsString "(InfixOp " . showsQualIdent qident . showsString ")"-showsInfixOp (InfixConstr qident)- = showsString "(InfixConstr " . showsQualIdent qident . showsString ")"+showsInfixOp :: Show a => InfixOp a -> ShowS+showsInfixOp (InfixOp a qident)+ = showsString "(InfixOp "+ . showsPrec 11 a . space+ . showsQualIdent qident+ . showsString ")"+showsInfixOp (InfixConstr a qident)+ = showsString "(InfixConstr "+ . showsPrec 11 a . space+ . showsQualIdent qident+ . showsString ")" -showsStatement :: Statement -> ShowS-showsStatement (StmtExpr _ exp)- = showsString "(StmtExpr " . showsExpression exp . showsString ")"-showsStatement (StmtDecl decls)- = showsString "(StmtDecl " . showsList showsDecl decls . showsString ")"-showsStatement (StmtBind _ cons exp)+showsStatement :: Show a => Statement a -> ShowS+showsStatement (StmtExpr spi expr)+ = showsString "(StmtExpr "+ . showsSpanInfo spi . space+ . showsExpression expr+ . showsString ")"+showsStatement (StmtDecl spi li decls)+ = showsString "(StmtDecl "+ . showsSpanInfo spi . space+ . showsLayoutInfo li . space+ . showsList showsDecl decls+ . showsString ")"+showsStatement (StmtBind spi cons expr) = showsString "(StmtBind "+ . showsSpanInfo spi . space . showsConsTerm cons . space- . showsExpression exp+ . showsExpression expr . showsString ")" -showsAlt :: Alt -> ShowS-showsAlt (Alt pos cons rhs)+showsCaseType :: CaseType -> ShowS+showsCaseType Rigid = showsString "Rigid"+showsCaseType Flex = showsString "Flex"++showsAlt :: Show a => Alt a -> ShowS+showsAlt (Alt spi cons rhs) = showsString "(Alt "- . showsPosition pos . space+ . showsSpanInfo spi . space . showsConsTerm cons . space . showsRhs rhs . showsString ")" showsField :: (a -> ShowS) -> Field a -> ShowS-showsField sa (Field pos ident a)+showsField sa (Field spi ident a) = showsString "(Field "- . showsPosition pos . space- . showsIdent ident . space+ . showsSpanInfo spi . space+ . showsQualIdent ident . space . sa a . showsString ")" +showsVar :: Show a => Var a -> ShowS+showsVar (Var a ident)+ = showsString "(Var "+ . showsPrec 11 a . space+ . showsIdent ident+ . showsString ")"++showsPosition :: Position -> ShowS+showsPosition NoPos = showsString "NoPos"+showsPosition Position { line = l, column = c }+ = showsString "(Position "+ . shows l . space+ . shows c+ . showsString ")"++showsSpanInfo :: SpanInfo -> ShowS+showsSpanInfo NoSpanInfo = showsString "NoSpanInfo"+showsSpanInfo SpanInfo { srcSpan = sp, srcInfoPoints = ss }+ = showsString "(SpanInfo "+ . showsSpan sp . space+ . showsList showsSpan ss+ . showsString ")"++showsLayoutInfo :: LayoutInfo -> ShowS+showsLayoutInfo WhitespaceLayout = showsString "WhitespaceLayout"+showsLayoutInfo (ExplicitLayout ss)+ = showsString "(ExplicitLayout "+ . showsList showsSpan ss+ . showsString ")"++showsSpan :: Span -> ShowS+showsSpan NoSpan = showsString "NoSpan"+showsSpan Span { start = s, end = e }+ = showsString "(Span "+ . showsPosition s . space+ . showsPosition e+ . showsString ")"+ showsString :: String -> ShowS showsString = (++) @@ -467,12 +737,11 @@ newline = showsString "\n" showsMaybe :: (a -> ShowS) -> Maybe a -> ShowS-showsMaybe shs- = maybe (showsString "Nothing")- (\x -> showsString "(Just " . shs x . showsString ")")+showsMaybe shs = maybe (showsString "Nothing")+ (\x -> showsString "(Just " . shs x . showsString ")") showsList :: (a -> ShowS) -> [a] -> ShowS-showsList _ [] = showsString "[]"+showsList _ [] = showsString "[]" showsList shs (x:xs) = showsString "[" . foldl (\sys y -> sys . showsString "," . shs y) (shs x) xs@@ -482,18 +751,27 @@ showsPair sa sb (a,b) = showsString "(" . sa a . showsString "," . sb b . showsString ")" - showsIdent :: Ident -> ShowS-showsIdent (Ident _ name n)- = showsString "(Ident " . shows name . space . shows n . showsString ")"+showsIdent (Ident spi x n)+ = showsString "(Ident " . showsSpanInfo spi . space+ . shows x . space . shows n . showsString ")" showsQualIdent :: QualIdent -> ShowS-showsQualIdent (QualIdent mident ident)- = showsString "(QualIdent "- . showsMaybe showsModuleIdent mident - . space- . showsIdent ident- . showsString ")"+showsQualIdent (QualIdent spi mident ident)+ = showsString "(QualIdent "+ . showsSpanInfo spi . space+ . showsMaybe showsModuleIdent mident+ . space+ . showsIdent ident+ . showsString ")" showsModuleIdent :: ModuleIdent -> ShowS-showsModuleIdent = shows . moduleName+showsModuleIdent (ModuleIdent spi ss)+ = showsString "(ModuleIdent "+ . showsSpanInfo spi . space+ . showsList (showsQuotes showsString) ss+ . showsString ")"++showsQuotes :: (a -> ShowS) -> a -> ShowS+showsQuotes sa a+ = showsString "\"" . sa a . showsString "\""
+ src/Curry/Syntax/Type.hs view
@@ -0,0 +1,1540 @@+{- |+ Module : $Header$+ Description : Abstract syntax for Curry+ Copyright : (c) 1999 - 2004 Wolfgang Lux+ 2005 Martin Engelke+ 2011 - 2015 Björn Peemöller+ 2014 Jan Rasmus Tikovsky+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module provides the necessary data structures to maintain the+ parsed representation of a Curry program.+-}++module Curry.Syntax.Type+ ( -- * Module header+ Module (..)+ -- ** Module pragmas+ , ModulePragma (..), Extension (..), KnownExtension (..), Tool (..)+ -- ** Export specification+ , ExportSpec (..), Export (..)+ -- ** Import declarations+ , ImportDecl (..), ImportSpec (..), Import (..), Qualified+ -- * Interface+ , Interface (..), IImportDecl (..), Arity, IDecl (..), KindExpr (..)+ , IMethodDecl (..), IMethodImpl+ -- * Declarations+ , Decl (..), Precedence, Infix (..), ConstrDecl (..), NewConstrDecl (..)+ , FieldDecl (..)+ , TypeExpr (..), QualTypeExpr (..)+ , Equation (..), Lhs (..), Rhs (..), CondExpr (..)+ , Literal (..), Pattern (..), Expression (..), InfixOp (..)+ , Statement (..), CaseType (..), Alt (..), Field (..), Var (..)+ -- * Type classes+ , Context, Constraint (..), InstanceType+ -- * Goals+ , Goal (..)+ ) where++import Data.Binary+import Control.Monad++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Base.SpanInfo+import Curry.Base.Span+import Curry.Base.Pretty (Pretty(..))++import Curry.Syntax.Extension++import Text.PrettyPrint++-- ---------------------------------------------------------------------------+-- Modules+-- ---------------------------------------------------------------------------++-- |Curry module+data Module a = Module SpanInfo LayoutInfo [ModulePragma] ModuleIdent+ (Maybe ExportSpec) [ImportDecl] [Decl a]+ deriving (Eq, Read, Show)++-- |Module pragma+data ModulePragma+ = LanguagePragma SpanInfo [Extension] -- ^ language pragma+ | OptionsPragma SpanInfo (Maybe Tool) String -- ^ options pragma+ deriving (Eq, Read, Show)++-- |Export specification+data ExportSpec = Exporting SpanInfo [Export]+ deriving (Eq, Read, Show)++-- |Single exported entity+data Export+ = Export SpanInfo QualIdent -- f/T+ | ExportTypeWith SpanInfo QualIdent [Ident] -- T (C1,...,Cn)+ | ExportTypeAll SpanInfo QualIdent -- T (..)+ | ExportModule SpanInfo ModuleIdent -- module M+ deriving (Eq, Read, Show)++-- |Import declaration+data ImportDecl = ImportDecl SpanInfo ModuleIdent Qualified+ (Maybe ModuleIdent) (Maybe ImportSpec)+ deriving (Eq, Read, Show)++-- |Flag to signal qualified import+type Qualified = Bool++-- |Import specification+data ImportSpec+ = Importing SpanInfo [Import]+ | Hiding SpanInfo [Import]+ deriving (Eq, Read, Show)++-- |Single imported entity+data Import+ = Import SpanInfo Ident -- f/T+ | ImportTypeWith SpanInfo Ident [Ident] -- T (C1,...,Cn)+ | ImportTypeAll SpanInfo Ident -- T (..)+ deriving (Eq, Read, Show)++-- ---------------------------------------------------------------------------+-- Module interfaces+-- ---------------------------------------------------------------------------++-- | Module interface+--+-- Interface declarations are restricted to type declarations and signatures.+-- Note that an interface function declaration additionaly contains the+-- function arity (= number of parameters) in order to generate+-- correct FlatCurry function applications.+data Interface = Interface ModuleIdent [IImportDecl] [IDecl]+ deriving (Eq, Read, Show)++-- |Interface import declaration+data IImportDecl = IImportDecl Position ModuleIdent+ deriving (Eq, Read, Show)++-- |Arity of a function+type Arity = Int++-- |Interface declaration+data IDecl+ = IInfixDecl Position Infix Precedence QualIdent+ | HidingDataDecl Position QualIdent (Maybe KindExpr) [Ident]+ | IDataDecl Position QualIdent (Maybe KindExpr) [Ident] [ConstrDecl] [Ident]+ | INewtypeDecl Position QualIdent (Maybe KindExpr) [Ident] NewConstrDecl [Ident]+ | ITypeDecl Position QualIdent (Maybe KindExpr) [Ident] TypeExpr+ | IFunctionDecl Position QualIdent (Maybe Ident) Arity QualTypeExpr+ | HidingClassDecl Position Context QualIdent (Maybe KindExpr) Ident+ | IClassDecl Position Context QualIdent (Maybe KindExpr) Ident [IMethodDecl] [Ident]+ | IInstanceDecl Position Context QualIdent InstanceType [IMethodImpl] (Maybe ModuleIdent)+ deriving (Eq, Read, Show)++-- |Class methods+data IMethodDecl = IMethodDecl Position Ident (Maybe Arity) QualTypeExpr+ deriving (Eq, Read, Show)++-- |Class method implementations+type IMethodImpl = (Ident, Arity)++-- |Kind expressions+data KindExpr+ = Star+ | ArrowKind KindExpr KindExpr+ deriving (Eq, Read, Show)++-- ---------------------------------------------------------------------------+-- Declarations (local or top-level)+-- ---------------------------------------------------------------------------++-- |Declaration in a module+data Decl a+ = InfixDecl SpanInfo Infix (Maybe Precedence) [Ident] -- infixl 5 (op), `fun`+ | DataDecl SpanInfo Ident [Ident] [ConstrDecl] [QualIdent] -- data C a b = C1 a | C2 b deriving (D, ...)+ | ExternalDataDecl SpanInfo Ident [Ident] -- external data C a b+ | NewtypeDecl SpanInfo Ident [Ident] NewConstrDecl [QualIdent] -- newtype C a b = C a b deriving (D, ...)+ | TypeDecl SpanInfo Ident [Ident] TypeExpr -- type C a b = D a b+ | TypeSig SpanInfo [Ident] QualTypeExpr -- f, g :: Bool+ | FunctionDecl SpanInfo a Ident [Equation a] -- f True = 1 ; f False = 0+ | ExternalDecl SpanInfo [Var a] -- f, g external+ | PatternDecl SpanInfo (Pattern a) (Rhs a) -- Just x = ...+ | FreeDecl SpanInfo [Var a] -- x, y free+ | DefaultDecl SpanInfo [TypeExpr] -- default (Int, Float)+ | ClassDecl SpanInfo LayoutInfo Context Ident Ident [Decl a] -- class C a => D a where {TypeSig|InfixDecl|FunctionDecl}+ | InstanceDecl SpanInfo LayoutInfo Context QualIdent InstanceType [Decl a] -- instance C a => M.D (N.T a b c) where {FunctionDecl}+ deriving (Eq, Read, Show)++-- ---------------------------------------------------------------------------+-- Infix declaration+-- ---------------------------------------------------------------------------++-- |Operator precedence+type Precedence = Integer++-- |Fixity of operators+data Infix+ = InfixL -- ^ left-associative+ | InfixR -- ^ right-associative+ | Infix -- ^ no associativity+ deriving (Eq, Read, Show)++-- |Constructor declaration for algebraic data types+data ConstrDecl+ = ConstrDecl SpanInfo Ident [TypeExpr]+ | ConOpDecl SpanInfo TypeExpr Ident TypeExpr+ | RecordDecl SpanInfo Ident [FieldDecl]+ deriving (Eq, Read, Show)++-- |Constructor declaration for renaming types (newtypes)+data NewConstrDecl+ = NewConstrDecl SpanInfo Ident TypeExpr+ | NewRecordDecl SpanInfo Ident (Ident, TypeExpr)+ deriving (Eq, Read, Show)++-- |Declaration for labelled fields+data FieldDecl = FieldDecl SpanInfo [Ident] TypeExpr+ deriving (Eq, Read, Show)++-- |Type expressions+data TypeExpr+ = ConstructorType SpanInfo QualIdent+ | ApplyType SpanInfo TypeExpr TypeExpr+ | VariableType SpanInfo Ident+ | TupleType SpanInfo [TypeExpr]+ | ListType SpanInfo TypeExpr+ | ArrowType SpanInfo TypeExpr TypeExpr+ | ParenType SpanInfo TypeExpr+ | ForallType SpanInfo [Ident] TypeExpr+ deriving (Eq, Read, Show)++-- |Qualified type expressions+data QualTypeExpr = QualTypeExpr SpanInfo Context TypeExpr+ deriving (Eq, Read, Show)++-- ---------------------------------------------------------------------------+-- Type classes+-- ---------------------------------------------------------------------------++type Context = [Constraint]++data Constraint = Constraint SpanInfo QualIdent TypeExpr+ deriving (Eq, Read, Show)++type InstanceType = TypeExpr++-- ---------------------------------------------------------------------------+-- Functions+-- ---------------------------------------------------------------------------++-- |Function defining equation+data Equation a = Equation SpanInfo (Lhs a) (Rhs a)+ deriving (Eq, Read, Show)++-- |Left-hand-side of an 'Equation' (function identifier and patterns)+data Lhs a+ = FunLhs SpanInfo Ident [Pattern a] -- f x y+ | OpLhs SpanInfo (Pattern a) Ident (Pattern a) -- x $ y+ | ApLhs SpanInfo (Lhs a) [Pattern a] -- ($) x y+ deriving (Eq, Read, Show)++-- |Right-hand-side of an 'Equation'+data Rhs a+ = SimpleRhs SpanInfo LayoutInfo (Expression a) [Decl a] -- @expr where decls@+ | GuardedRhs SpanInfo LayoutInfo [CondExpr a] [Decl a] -- @| cond = expr where decls@+ deriving (Eq, Read, Show)++-- |Conditional expression (expression conditioned by a guard)+data CondExpr a = CondExpr SpanInfo (Expression a) (Expression a)+ deriving (Eq, Read, Show)++-- |Literal+data Literal+ = Char Char+ | Int Integer+ | Float Double+ | String String+ deriving (Eq, Read, Show)++-- |Constructor term (used for patterns)+data Pattern a+ = LiteralPattern SpanInfo a Literal+ | NegativePattern SpanInfo a Literal+ | VariablePattern SpanInfo a Ident+ | ConstructorPattern SpanInfo a QualIdent [Pattern a]+ | InfixPattern SpanInfo a (Pattern a) QualIdent (Pattern a)+ | ParenPattern SpanInfo (Pattern a)+ | RecordPattern SpanInfo a QualIdent [Field (Pattern a)] -- C { l1 = p1, ..., ln = pn }+ | TuplePattern SpanInfo [Pattern a]+ | ListPattern SpanInfo a [Pattern a]+ | AsPattern SpanInfo Ident (Pattern a)+ | LazyPattern SpanInfo (Pattern a)+ | FunctionPattern SpanInfo a QualIdent [Pattern a]+ | InfixFuncPattern SpanInfo a (Pattern a) QualIdent (Pattern a)+ deriving (Eq, Read, Show)++-- |Expression+data Expression a+ = Literal SpanInfo a Literal+ | Variable SpanInfo a QualIdent+ | Constructor SpanInfo a QualIdent+ | Paren SpanInfo (Expression a)+ | Typed SpanInfo (Expression a) QualTypeExpr+ | Record SpanInfo a QualIdent [Field (Expression a)] -- C {l1 = e1,..., ln = en}+ | RecordUpdate SpanInfo (Expression a) [Field (Expression a)] -- e {l1 = e1,..., ln = en}+ | Tuple SpanInfo [Expression a]+ | List SpanInfo a [Expression a]+ | ListCompr SpanInfo (Expression a) [Statement a] -- the ref corresponds to the main list+ | EnumFrom SpanInfo (Expression a)+ | EnumFromThen SpanInfo (Expression a) (Expression a)+ | EnumFromTo SpanInfo (Expression a) (Expression a)+ | EnumFromThenTo SpanInfo (Expression a) (Expression a) (Expression a)+ | UnaryMinus SpanInfo (Expression a)+ | Apply SpanInfo (Expression a) (Expression a)+ | InfixApply SpanInfo (Expression a) (InfixOp a) (Expression a)+ | LeftSection SpanInfo (Expression a) (InfixOp a)+ | RightSection SpanInfo (InfixOp a) (Expression a)+ | Lambda SpanInfo [Pattern a] (Expression a)+ | Let SpanInfo LayoutInfo [Decl a] (Expression a)+ | Do SpanInfo LayoutInfo [Statement a] (Expression a)+ | IfThenElse SpanInfo (Expression a) (Expression a) (Expression a)+ | Case SpanInfo LayoutInfo CaseType (Expression a) [Alt a]+ deriving (Eq, Read, Show)++-- |Infix operation+data InfixOp a+ = InfixOp a QualIdent+ | InfixConstr a QualIdent+ deriving (Eq, Read, Show)++-- |Statement (used for do-sequence and list comprehensions)+data Statement a+ = StmtExpr SpanInfo (Expression a)+ | StmtDecl SpanInfo LayoutInfo [Decl a]+ | StmtBind SpanInfo (Pattern a) (Expression a)+ deriving (Eq, Read, Show)++-- |Type of case expressions+data CaseType+ = Rigid+ | Flex+ deriving (Eq, Read, Show)++-- |Single case alternative+data Alt a = Alt SpanInfo (Pattern a) (Rhs a)+ deriving (Eq, Read, Show)++-- |Record field+data Field a = Field SpanInfo QualIdent a+ deriving (Eq, Read, Show)++-- |Annotated identifier+data Var a = Var a Ident+ deriving (Eq, Read, Show)++-- ---------------------------------------------------------------------------+-- Goals+-- ---------------------------------------------------------------------------++-- |Goal in REPL (expression to evaluate)+data Goal a = Goal SpanInfo LayoutInfo (Expression a) [Decl a]+ deriving (Eq, Read, Show)++-- ---------------------------------------------------------------------------+-- instances+-- ---------------------------------------------------------------------------++instance Functor Module where+ fmap f (Module sp li ps m es is ds) = Module sp li ps m es is (map (fmap f) ds)++instance Functor Decl where+ fmap _ (InfixDecl sp fix prec ops) = InfixDecl sp fix prec ops+ fmap _ (DataDecl sp tc tvs cs clss) = DataDecl sp tc tvs cs clss+ fmap _ (ExternalDataDecl sp tc tvs) = ExternalDataDecl sp tc tvs+ fmap _ (NewtypeDecl sp tc tvs nc clss) = NewtypeDecl sp tc tvs nc clss+ fmap _ (TypeDecl sp tc tvs ty) = TypeDecl sp tc tvs ty+ fmap _ (TypeSig sp fs qty) = TypeSig sp fs qty+ fmap f (FunctionDecl sp a f' eqs) = FunctionDecl sp (f a) f' (map (fmap f) eqs)+ fmap f (ExternalDecl sp vs) = ExternalDecl sp (map (fmap f) vs)+ fmap f (PatternDecl sp t rhs) = PatternDecl sp (fmap f t) (fmap f rhs)+ fmap f (FreeDecl sp vs) = FreeDecl sp (map (fmap f) vs)+ fmap _ (DefaultDecl sp tys) = DefaultDecl sp tys+ fmap f (ClassDecl sp li cx cls clsvar ds) =+ ClassDecl sp li cx cls clsvar (map (fmap f) ds)+ fmap f (InstanceDecl sp li cx qcls inst ds) =+ InstanceDecl sp li cx qcls inst (map (fmap f) ds)++instance Functor Equation where+ fmap f (Equation p lhs rhs) = Equation p (fmap f lhs) (fmap f rhs)++instance Functor Lhs where+ fmap f (FunLhs p f' ts) = FunLhs p f' (map (fmap f) ts)+ fmap f (OpLhs p t1 op t2) = OpLhs p (fmap f t1) op (fmap f t2)+ fmap f (ApLhs p lhs ts) = ApLhs p (fmap f lhs) (map (fmap f) ts)++instance Functor Rhs where+ fmap f (SimpleRhs p li e ds) = SimpleRhs p li (fmap f e) (map (fmap f) ds)+ fmap f (GuardedRhs p li cs ds) = GuardedRhs p li (map (fmap f) cs) (map (fmap f) ds)++instance Functor CondExpr where+ fmap f (CondExpr p g e) = CondExpr p (fmap f g) (fmap f e)++instance Functor Pattern where+ fmap f (LiteralPattern p a l) = LiteralPattern p (f a) l+ fmap f (NegativePattern p a l) = NegativePattern p (f a) l+ fmap f (VariablePattern p a v) = VariablePattern p (f a) v+ fmap f (ConstructorPattern p a c ts) =+ ConstructorPattern p (f a) c (map (fmap f) ts)+ fmap f (InfixPattern p a t1 op t2) =+ InfixPattern p (f a) (fmap f t1) op (fmap f t2)+ fmap f (ParenPattern p t) = ParenPattern p (fmap f t)+ fmap f (RecordPattern p a c fs) =+ RecordPattern p (f a) c (map (fmap (fmap f)) fs)+ fmap f (TuplePattern p ts) = TuplePattern p (map (fmap f) ts)+ fmap f (ListPattern p a ts) = ListPattern p (f a) (map (fmap f) ts)+ fmap f (AsPattern p v t) = AsPattern p v (fmap f t)+ fmap f (LazyPattern p t) = LazyPattern p (fmap f t)+ fmap f (FunctionPattern p a f' ts) =+ FunctionPattern p (f a) f' (map (fmap f) ts)+ fmap f (InfixFuncPattern p a t1 op t2) =+ InfixFuncPattern p (f a) (fmap f t1) op (fmap f t2)++instance Functor Expression where+ fmap f (Literal p a l) = Literal p (f a) l+ fmap f (Variable p a v) = Variable p (f a) v+ fmap f (Constructor p a c) = Constructor p (f a) c+ fmap f (Paren p e) = Paren p (fmap f e)+ fmap f (Typed p e qty) = Typed p (fmap f e) qty+ fmap f (Record p a c fs) = Record p (f a) c (map (fmap (fmap f)) fs)+ fmap f (RecordUpdate p e fs) = RecordUpdate p (fmap f e) (map (fmap (fmap f)) fs)+ fmap f (Tuple p es) = Tuple p (map (fmap f) es)+ fmap f (List p a es) = List p (f a) (map (fmap f) es)+ fmap f (ListCompr p e stms) = ListCompr p (fmap f e) (map (fmap f) stms)+ fmap f (EnumFrom p e) = EnumFrom p (fmap f e)+ fmap f (EnumFromThen p e1 e2) = EnumFromThen p (fmap f e1) (fmap f e2)+ fmap f (EnumFromTo p e1 e2) = EnumFromTo p (fmap f e1) (fmap f e2)+ fmap f (EnumFromThenTo p e1 e2 e3) =+ EnumFromThenTo p (fmap f e1) (fmap f e2) (fmap f e3)+ fmap f (UnaryMinus p e) = UnaryMinus p (fmap f e)+ fmap f (Apply p e1 e2) = Apply p (fmap f e1) (fmap f e2)+ fmap f (InfixApply p e1 op e2) =+ InfixApply p (fmap f e1) (fmap f op) (fmap f e2)+ fmap f (LeftSection p e op) = LeftSection p (fmap f e) (fmap f op)+ fmap f (RightSection p op e) = RightSection p (fmap f op) (fmap f e)+ fmap f (Lambda p ts e) = Lambda p (map (fmap f) ts) (fmap f e)+ fmap f (Let p li ds e) = Let p li (map (fmap f) ds) (fmap f e)+ fmap f (Do p li stms e) = Do p li (map (fmap f) stms) (fmap f e)+ fmap f (IfThenElse p e1 e2 e3) =+ IfThenElse p (fmap f e1) (fmap f e2) (fmap f e3)+ fmap f (Case p li ct e as) = Case p li ct (fmap f e) (map (fmap f) as)++instance Functor InfixOp where+ fmap f (InfixOp a op) = InfixOp (f a) op+ fmap f (InfixConstr a op) = InfixConstr (f a) op++instance Functor Statement where+ fmap f (StmtExpr p e) = StmtExpr p (fmap f e)+ fmap f (StmtDecl p li ds) = StmtDecl p li (map (fmap f) ds)+ fmap f (StmtBind p t e) = StmtBind p (fmap f t) (fmap f e)++instance Functor Alt where+ fmap f (Alt p t rhs) = Alt p (fmap f t) (fmap f rhs)++instance Functor Field where+ fmap f (Field p l x) = Field p l (f x)++instance Functor Var where+ fmap f (Var a v) = Var (f a) v++instance Functor Goal where+ fmap f (Goal p li e ds) = Goal p li (fmap f e) (map (fmap f) ds)++instance Pretty Infix where+ pPrint InfixL = text "infixl"+ pPrint InfixR = text "infixr"+ pPrint Infix = text "infix"++instance HasSpanInfo (Module a) where+ getSpanInfo (Module sp _ _ _ _ _ _) = sp++ setSpanInfo sp (Module _ li ps m es is ds) = Module sp li ps m es is ds++ updateEndPos m@(Module _ _ _ _ _ _ (d:ds)) =+ setEndPosition (getSrcSpanEnd (last (d:ds))) m+ updateEndPos m@(Module _ _ _ _ _ (i:is) _) =+ setEndPosition (getSrcSpanEnd (last (i:is))) m+ updateEndPos m@(Module (SpanInfo _ (s:ss)) _ _ _ _ _ _) =+ setEndPosition (end (last (s:ss))) m+ updateEndPos m@(Module _ _ (p:ps) _ _ _ _) =+ setEndPosition (getSrcSpanEnd (last (p:ps))) m+ updateEndPos m = m++ getLayoutInfo (Module _ li _ _ _ _ _) = li++instance HasSpanInfo (Decl a) where+ getSpanInfo (InfixDecl sp _ _ _) = sp+ getSpanInfo (DataDecl sp _ _ _ _) = sp+ getSpanInfo (ExternalDataDecl sp _ _) = sp+ getSpanInfo (NewtypeDecl sp _ _ _ _) = sp+ getSpanInfo (TypeDecl sp _ _ _) = sp+ getSpanInfo (TypeSig sp _ _) = sp+ getSpanInfo (FunctionDecl sp _ _ _) = sp+ getSpanInfo (ExternalDecl sp _) = sp+ getSpanInfo (PatternDecl sp _ _) = sp+ getSpanInfo (FreeDecl sp _) = sp+ getSpanInfo (DefaultDecl sp _) = sp+ getSpanInfo (ClassDecl sp _ _ _ _ _) = sp+ getSpanInfo (InstanceDecl sp _ _ _ _ _) = sp++ setSpanInfo sp (InfixDecl _ fix prec ops) = InfixDecl sp fix prec ops+ setSpanInfo sp (DataDecl _ tc tvs cs clss) = DataDecl sp tc tvs cs clss+ setSpanInfo sp (ExternalDataDecl _ tc tvs) = ExternalDataDecl sp tc tvs+ setSpanInfo sp (NewtypeDecl _ tc tvs nc clss) = NewtypeDecl sp tc tvs nc clss+ setSpanInfo sp (TypeDecl _ tc tvs ty) = TypeDecl sp tc tvs ty+ setSpanInfo sp (TypeSig _ fs qty) = TypeSig sp fs qty+ setSpanInfo sp (FunctionDecl _ a f' eqs) = FunctionDecl sp a f' eqs+ setSpanInfo sp (ExternalDecl _ vs) = ExternalDecl sp vs+ setSpanInfo sp (PatternDecl _ t rhs) = PatternDecl sp t rhs+ setSpanInfo sp (FreeDecl _ vs) = FreeDecl sp vs+ setSpanInfo sp (DefaultDecl _ tys) = DefaultDecl sp tys+ setSpanInfo sp (ClassDecl _ li cx cls clsvar ds) = ClassDecl sp li cx cls clsvar ds+ setSpanInfo sp (InstanceDecl _ li cx qcls inst ds) = InstanceDecl sp li cx qcls inst ds++ updateEndPos d@(InfixDecl _ _ _ ops) =+ let i' = last ops+ in setEndPosition (incr (getPosition i') (identLength i' - 1)) d+ updateEndPos d@(DataDecl _ _ _ _ (c:cs)) =+ let i' = last (c:cs)+ in setEndPosition (incr (getPosition i') (qIdentLength i' - 1)) d+ updateEndPos d@(DataDecl _ _ _ (c:cs) _) =+ setEndPosition (getSrcSpanEnd (last (c:cs))) d+ updateEndPos d@(DataDecl _ _ (i:is) _ _) =+ let i' = last (i:is)+ in setEndPosition (incr (getPosition i') (identLength i' - 1)) d+ updateEndPos d@(DataDecl _ i _ _ _) =+ setEndPosition (incr (getPosition i) (identLength i - 1)) d+ updateEndPos d@(ExternalDataDecl _ _ (i:is)) =+ let i' = last (i:is)+ in setEndPosition (incr (getPosition i') (identLength i' - 1)) d+ updateEndPos d@(ExternalDataDecl _ i _) =+ setEndPosition (incr (getPosition i) (identLength i - 1)) d+ updateEndPos d@(NewtypeDecl _ _ _ _ (c:cs)) =+ let i' = last (c:cs)+ in setEndPosition (incr (getPosition i') (qIdentLength i' - 1)) d+ updateEndPos d@(NewtypeDecl _ _ _ c _) =+ setEndPosition (getSrcSpanEnd c) d+ updateEndPos d@(TypeDecl _ _ _ ty) =+ setEndPosition (getSrcSpanEnd ty) d+ updateEndPos d@(TypeSig _ _ qty) =+ setEndPosition (getSrcSpanEnd qty) d+ updateEndPos d@(FunctionDecl _ _ _ eqs) =+ setEndPosition (getSrcSpanEnd (last eqs)) d+ updateEndPos d@(ExternalDecl (SpanInfo _ ss) _) =+ setEndPosition (end (last ss)) d+ updateEndPos d@(ExternalDecl _ _) = d+ updateEndPos d@(PatternDecl _ _ rhs) =+ setEndPosition (getSrcSpanEnd rhs) d+ updateEndPos d@(FreeDecl (SpanInfo _ ss) _) =+ setEndPosition (end (last ss)) d+ updateEndPos d@(FreeDecl _ _) = d+ updateEndPos d@(DefaultDecl (SpanInfo _ ss) _) =+ setEndPosition (end (last ss)) d+ updateEndPos d@(DefaultDecl _ _) = d+ updateEndPos d@(ClassDecl _ _ _ _ _ (d':ds)) =+ setEndPosition (getSrcSpanEnd (last (d':ds))) d+ updateEndPos d@(ClassDecl (SpanInfo _ ss) _ _ _ _ _) =+ setEndPosition (end (last ss)) d+ updateEndPos d@(ClassDecl _ _ _ _ _ _) = d+ updateEndPos d@(InstanceDecl _ _ _ _ _ (d':ds)) =+ setEndPosition (getSrcSpanEnd (last (d':ds))) d+ updateEndPos d@(InstanceDecl (SpanInfo _ ss) _ _ _ _ _) =+ setEndPosition (end (last ss)) d+ updateEndPos d@(InstanceDecl _ _ _ _ _ _) = d++ getLayoutInfo (ClassDecl _ li _ _ _ _) = li+ getLayoutInfo (InstanceDecl _ li _ _ _ _) = li+ getLayoutInfo _ = WhitespaceLayout++instance HasSpanInfo (Equation a) where+ getSpanInfo (Equation spi _ _) = spi+ setSpanInfo spi (Equation _ lhs rhs) = Equation spi lhs rhs+ updateEndPos e@(Equation _ _ rhs) =+ setEndPosition (getSrcSpanEnd rhs) e++instance HasSpanInfo ModulePragma where+ getSpanInfo (LanguagePragma sp _ ) = sp+ getSpanInfo (OptionsPragma sp _ _) = sp++ setSpanInfo sp (LanguagePragma _ ex ) = LanguagePragma sp ex+ setSpanInfo sp (OptionsPragma _ t a) = OptionsPragma sp t a++ updateEndPos p@(LanguagePragma (SpanInfo _ ss) _) =+ setEndPosition (end (last ss)) p+ updateEndPos p@(LanguagePragma _ _) = p+ updateEndPos p@(OptionsPragma (SpanInfo _ ss) _ _) =+ setEndPosition (end (last ss)) p+ updateEndPos p@(OptionsPragma _ _ _) = p++instance HasSpanInfo ExportSpec where+ getSpanInfo (Exporting sp _) = sp+ setSpanInfo sp (Exporting _ ex) = Exporting sp ex++ updateEndPos e@(Exporting (SpanInfo _ ss) _) =+ setEndPosition (end (last ss)) e+ updateEndPos e@(Exporting _ _) = e++instance HasSpanInfo Export where+ getSpanInfo (Export sp _) = sp+ getSpanInfo (ExportTypeWith sp _ _) = sp+ getSpanInfo (ExportTypeAll sp _) = sp+ getSpanInfo (ExportModule sp _) = sp++ setSpanInfo sp (Export _ qid) = Export sp qid+ setSpanInfo sp (ExportTypeWith _ qid cs) = ExportTypeWith sp qid cs+ setSpanInfo sp (ExportTypeAll _ qid) = ExportTypeAll sp qid+ setSpanInfo sp (ExportModule _ mid) = ExportModule sp mid++ updateEndPos e@(Export _ idt) =+ setEndPosition (incr (getPosition idt) (qIdentLength idt - 1)) e+ updateEndPos e@(ExportTypeWith (SpanInfo _ ss) _ _) =+ setEndPosition (end (last ss)) e+ updateEndPos e@(ExportTypeWith _ _ _) = e+ updateEndPos e@(ExportTypeAll (SpanInfo _ ss) _) =+ setEndPosition (end (last ss)) e+ updateEndPos e@(ExportTypeAll _ _) = e+ updateEndPos e@(ExportModule _ mid) =+ setEndPosition (incr (getPosition mid) (mIdentLength mid - 1)) e++instance HasSpanInfo ImportDecl where+ getSpanInfo (ImportDecl sp _ _ _ _) = sp+ setSpanInfo sp (ImportDecl _ mid q as spec) = ImportDecl sp mid q as spec++ updateEndPos i@(ImportDecl _ _ _ _ (Just spec)) =+ setEndPosition (getSrcSpanEnd spec) i+ updateEndPos i@(ImportDecl _ _ _ (Just mid) _) =+ setEndPosition (incr (getPosition mid) (mIdentLength mid - 1)) i+ updateEndPos i@(ImportDecl _ mid _ _ _) =+ setEndPosition (incr (getPosition mid) (mIdentLength mid - 1)) i++instance HasSpanInfo ImportSpec where+ getSpanInfo (Importing sp _) = sp+ getSpanInfo (Hiding sp _) = sp++ setSpanInfo sp (Importing _ im) = Importing sp im+ setSpanInfo sp (Hiding _ im) = Hiding sp im++ updateEndPos i@(Importing (SpanInfo _ ss) _) =+ setEndPosition (end (last ss)) i+ updateEndPos i@(Importing _ _) = i+ updateEndPos i@(Hiding (SpanInfo _ ss) _) =+ setEndPosition (end (last ss)) i+ updateEndPos i@(Hiding _ _) = i++instance HasSpanInfo Import where+ getSpanInfo (Import sp _) = sp+ getSpanInfo (ImportTypeWith sp _ _) = sp+ getSpanInfo (ImportTypeAll sp _) = sp++ setSpanInfo sp (Import _ qid) = Import sp qid+ setSpanInfo sp (ImportTypeWith _ qid cs) = ImportTypeWith sp qid cs+ setSpanInfo sp (ImportTypeAll _ qid) = ImportTypeAll sp qid++ updateEndPos i@(Import _ idt) =+ setEndPosition (incr (getPosition idt) (identLength idt - 1)) i+ updateEndPos i@(ImportTypeWith (SpanInfo _ ss) _ _) =+ setEndPosition (end (last ss)) i+ updateEndPos i@(ImportTypeWith _ _ _) = i+ updateEndPos i@(ImportTypeAll (SpanInfo _ ss) _) =+ setEndPosition (end (last ss)) i+ updateEndPos i@(ImportTypeAll _ _) = i++instance HasSpanInfo ConstrDecl where+ getSpanInfo (ConstrDecl sp _ _) = sp+ getSpanInfo (ConOpDecl sp _ _ _) = sp+ getSpanInfo (RecordDecl sp _ _) = sp++ setSpanInfo sp (ConstrDecl _ idt ty) = ConstrDecl sp idt ty+ setSpanInfo sp (ConOpDecl _ ty1 idt ty2) = ConOpDecl sp ty1 idt ty2+ setSpanInfo sp (RecordDecl _ idt fd) = RecordDecl sp idt fd++ updateEndPos c@(ConstrDecl _ _ (t:ts)) =+ setEndPosition (getSrcSpanEnd (last (t:ts))) c+ updateEndPos c@(ConstrDecl _ idt _) =+ setEndPosition (incr (getPosition idt) (identLength idt - 1)) c+ updateEndPos c@(ConOpDecl _ _ _ ty) =+ setEndPosition (getSrcSpanEnd ty) c+ updateEndPos c@(RecordDecl (SpanInfo _ ss) _ _) =+ setEndPosition (end (last ss)) c+ updateEndPos c@(RecordDecl _ _ _) = c++instance HasSpanInfo NewConstrDecl where+ getSpanInfo (NewConstrDecl sp _ _) = sp+ getSpanInfo (NewRecordDecl sp _ _) = sp++ setSpanInfo sp (NewConstrDecl _ idt ty) = NewConstrDecl sp idt ty+ setSpanInfo sp (NewRecordDecl _ idt fty) = NewRecordDecl sp idt fty++ updateEndPos c@(NewConstrDecl _ _ ty) =+ setEndPosition (getSrcSpanEnd ty) c+ updateEndPos c@(NewRecordDecl (SpanInfo _ ss) _ _) =+ setEndPosition (end (last ss)) c+ updateEndPos c@(NewRecordDecl _ _ _) = c++instance HasSpanInfo FieldDecl where+ getSpanInfo (FieldDecl sp _ _) = sp+ setSpanInfo sp (FieldDecl _ idt ty) = FieldDecl sp idt ty+ updateEndPos d@(FieldDecl _ _ ty) =+ setEndPosition (getSrcSpanEnd ty) d++instance HasSpanInfo TypeExpr where+ getSpanInfo (ConstructorType sp _) = sp+ getSpanInfo (ApplyType sp _ _) = sp+ getSpanInfo (VariableType sp _) = sp+ getSpanInfo (TupleType sp _) = sp+ getSpanInfo (ListType sp _) = sp+ getSpanInfo (ArrowType sp _ _) = sp+ getSpanInfo (ParenType sp _) = sp+ getSpanInfo (ForallType sp _ _) = sp++ setSpanInfo sp (ConstructorType _ qid) = ConstructorType sp qid+ setSpanInfo sp (ApplyType _ ty1 ty2) = ApplyType sp ty1 ty2+ setSpanInfo sp (VariableType _ idt) = VariableType sp idt+ setSpanInfo sp (TupleType _ tys) = TupleType sp tys+ setSpanInfo sp (ListType _ ty) = ListType sp ty+ setSpanInfo sp (ArrowType _ ty1 ty2) = ArrowType sp ty1 ty2+ setSpanInfo sp (ParenType _ ty) = ParenType sp ty+ setSpanInfo sp (ForallType _ idt ty) = ForallType sp idt ty++ updateEndPos t@(ConstructorType _ qid) =+ setEndPosition (incr (getPosition qid) (qIdentLength qid - 1)) t+ updateEndPos t@(ApplyType _ _ t2) =+ setEndPosition (getSrcSpanEnd t2) t+ updateEndPos t@(VariableType _ idt) =+ setEndPosition (incr (getPosition idt) (identLength idt - 1)) t+ updateEndPos t@(ListType (SpanInfo _ (s:ss)) _) =+ setEndPosition (end (last (s:ss))) t+ updateEndPos t@(ListType _ _) = t+ updateEndPos t@(TupleType _ tys) =+ setEndPosition (getSrcSpanEnd (last tys)) t+ updateEndPos t@(ArrowType _ _ t2) =+ setEndPosition (getSrcSpanEnd t2) t+ updateEndPos t@(ParenType (SpanInfo _ (s:ss)) _) =+ setEndPosition (end (last (s:ss))) t+ updateEndPos t@(ParenType _ _) = t+ updateEndPos t@(ForallType _ _ _) = t -- not a parseable type++instance HasSpanInfo QualTypeExpr where+ getSpanInfo (QualTypeExpr sp _ _) = sp+ setSpanInfo sp (QualTypeExpr _ cx ty) = QualTypeExpr sp cx ty+ updateEndPos t@(QualTypeExpr _ _ ty) =+ setEndPosition (getSrcSpanEnd ty) t++instance HasSpanInfo Constraint where+ getSpanInfo (Constraint sp _ _) = sp+ setSpanInfo sp (Constraint _ qid ty) = Constraint sp qid ty+ updateEndPos c@(Constraint (SpanInfo _ (s:ss)) _ _) =+ setEndPosition (end (last (s:ss))) c+ updateEndPos c@(Constraint _ _ ty) =+ setEndPosition (getSrcSpanEnd ty) c++instance HasSpanInfo (Lhs a) where+ getSpanInfo (FunLhs sp _ _) = sp+ getSpanInfo (OpLhs sp _ _ _) = sp+ getSpanInfo (ApLhs sp _ _) = sp++ setSpanInfo sp (FunLhs _ idt ps) = FunLhs sp idt ps+ setSpanInfo sp (OpLhs _ p1 idt p2) = OpLhs sp p1 idt p2+ setSpanInfo sp (ApLhs _ lhs ps) = ApLhs sp lhs ps++ updateEndPos l@(FunLhs _ _ (p:ps)) =+ setEndPosition (getSrcSpanEnd (last (p:ps))) l+ updateEndPos l@(FunLhs _ idt _) =+ setEndPosition (incr (getPosition idt) (identLength idt - 1)) l+ updateEndPos l@(OpLhs _ _ _ p) =+ setEndPosition (getSrcSpanEnd p) l+ updateEndPos l@(ApLhs _ _ (p:ps)) =+ setEndPosition (getSrcSpanEnd (last (p:ps))) l+ updateEndPos l@(ApLhs (SpanInfo _ [_,s]) _ _) =+ setEndPosition (end s) l+ updateEndPos l@(ApLhs _ _ _) = l+++instance HasSpanInfo (Rhs a) where+ getSpanInfo (SimpleRhs sp _ _ _) = sp+ getSpanInfo (GuardedRhs sp _ _ _) = sp++ setSpanInfo sp (SimpleRhs _ li ex ds) = SimpleRhs sp li ex ds+ setSpanInfo sp (GuardedRhs _ li cs ds) = GuardedRhs sp li cs ds++ updateEndPos r@(SimpleRhs (SpanInfo _ [_,_]) _ _ (d:ds)) =+ setEndPosition (getSrcSpanEnd (last (d:ds))) r+ updateEndPos r@(SimpleRhs (SpanInfo _ [_,s]) _ _ _) =+ setEndPosition (end s) r+ updateEndPos r@(SimpleRhs _ _ e _) =+ setEndPosition (getSrcSpanEnd e) r+ updateEndPos r@(GuardedRhs (SpanInfo _ [_,_]) _ _ (d:ds)) =+ setEndPosition (getSrcSpanEnd (last (d:ds))) r+ updateEndPos r@(GuardedRhs (SpanInfo _ [_,s]) _ _ _) =+ setEndPosition (end s) r+ updateEndPos r@(GuardedRhs _ _ cs _) =+ setEndPosition (getSrcSpanEnd (last cs)) r++ getLayoutInfo (SimpleRhs _ li _ _) = li+ getLayoutInfo (GuardedRhs _ li _ _) = li++instance HasSpanInfo (CondExpr a) where+ getSpanInfo (CondExpr sp _ _) = sp+ setSpanInfo sp (CondExpr _ e1 e2) = CondExpr sp e1 e2+ updateEndPos ce@(CondExpr _ _ e) =+ setEndPosition (getSrcSpanEnd e) ce++instance HasSpanInfo (Pattern a) where+ getSpanInfo (LiteralPattern sp _ _) = sp+ getSpanInfo (NegativePattern sp _ _) = sp+ getSpanInfo (VariablePattern sp _ _) = sp+ getSpanInfo (ConstructorPattern sp _ _ _) = sp+ getSpanInfo (InfixPattern sp _ _ _ _) = sp+ getSpanInfo (ParenPattern sp _) = sp+ getSpanInfo (RecordPattern sp _ _ _) = sp+ getSpanInfo (TuplePattern sp _) = sp+ getSpanInfo (ListPattern sp _ _) = sp+ getSpanInfo (AsPattern sp _ _) = sp+ getSpanInfo (LazyPattern sp _) = sp+ getSpanInfo (FunctionPattern sp _ _ _) = sp+ getSpanInfo (InfixFuncPattern sp _ _ _ _) = sp++ setSpanInfo sp (LiteralPattern _ a l) = LiteralPattern sp a l+ setSpanInfo sp (NegativePattern _ a l) = NegativePattern sp a l+ setSpanInfo sp (VariablePattern _ a v) = VariablePattern sp a v+ setSpanInfo sp (ConstructorPattern _ a c ts) = ConstructorPattern sp a c ts+ setSpanInfo sp (InfixPattern _ a t1 op t2) = InfixPattern sp a t1 op t2+ setSpanInfo sp (ParenPattern _ t) = ParenPattern sp t+ setSpanInfo sp (RecordPattern _ a c fs) = RecordPattern sp a c fs+ setSpanInfo sp (TuplePattern _ ts) = TuplePattern sp ts+ setSpanInfo sp (ListPattern _ a ts) = ListPattern sp a ts+ setSpanInfo sp (AsPattern _ v t) = AsPattern sp v t+ setSpanInfo sp (LazyPattern _ t) = LazyPattern sp t+ setSpanInfo sp (FunctionPattern _ a f' ts) = FunctionPattern sp a f' ts+ setSpanInfo sp (InfixFuncPattern _ a t1 op t2) = InfixFuncPattern sp a t1 op t2++ updateEndPos p@(LiteralPattern _ _ _) = p+ updateEndPos p@(NegativePattern _ _ _) = p+ updateEndPos p@(VariablePattern _ _ v) =+ setEndPosition (incr (getPosition v) (identLength v - 1)) p+ updateEndPos p@(ConstructorPattern _ _ _ (t:ts)) =+ setEndPosition (getSrcSpanEnd (last (t:ts))) p+ updateEndPos p@(ConstructorPattern _ _ c _) =+ setEndPosition (incr (getPosition c) (qIdentLength c - 1)) p+ updateEndPos p@(InfixPattern _ _ _ _ t2) =+ setEndPosition (getSrcSpanEnd t2) p+ updateEndPos p@(ParenPattern (SpanInfo _ (s:ss)) _) =+ setEndPosition (end (last (s:ss))) p+ updateEndPos p@(ParenPattern _ _) = p+ updateEndPos p@(RecordPattern (SpanInfo _ (s:ss)) _ _ _) =+ setEndPosition (end (last (s:ss))) p+ updateEndPos p@(RecordPattern _ _ _ _) = p+ updateEndPos p@(TuplePattern (SpanInfo _ (s:ss)) _) =+ setEndPosition (end (last (s:ss))) p+ updateEndPos p@(TuplePattern _ _) = p+ updateEndPos p@(ListPattern (SpanInfo _ (s:ss)) _ _) =+ setEndPosition (end (last (s:ss))) p+ updateEndPos p@(ListPattern _ _ _) = p+ updateEndPos p@(AsPattern _ _ t) =+ setEndPosition (getSrcSpanEnd t) p+ updateEndPos p@(LazyPattern _ t) =+ setEndPosition (getSrcSpanEnd t) p+ updateEndPos p@(FunctionPattern _ _ _ _) = p+ updateEndPos p@(InfixFuncPattern _ _ _ _ _) = p++instance HasSpanInfo (Expression a) where+ getSpanInfo (Literal sp _ _) = sp+ getSpanInfo (Variable sp _ _) = sp+ getSpanInfo (Constructor sp _ _) = sp+ getSpanInfo (Paren sp _) = sp+ getSpanInfo (Typed sp _ _) = sp+ getSpanInfo (Record sp _ _ _) = sp+ getSpanInfo (RecordUpdate sp _ _) = sp+ getSpanInfo (Tuple sp _) = sp+ getSpanInfo (List sp _ _) = sp+ getSpanInfo (ListCompr sp _ _) = sp+ getSpanInfo (EnumFrom sp _) = sp+ getSpanInfo (EnumFromThen sp _ _) = sp+ getSpanInfo (EnumFromTo sp _ _) = sp+ getSpanInfo (EnumFromThenTo sp _ _ _) = sp+ getSpanInfo (UnaryMinus sp _) = sp+ getSpanInfo (Apply sp _ _) = sp+ getSpanInfo (InfixApply sp _ _ _) = sp+ getSpanInfo (LeftSection sp _ _) = sp+ getSpanInfo (RightSection sp _ _) = sp+ getSpanInfo (Lambda sp _ _) = sp+ getSpanInfo (Let sp _ _ _) = sp+ getSpanInfo (Do sp _ _ _) = sp+ getSpanInfo (IfThenElse sp _ _ _) = sp+ getSpanInfo (Case sp _ _ _ _) = sp++ setSpanInfo sp (Literal _ a l) = Literal sp a l+ setSpanInfo sp (Variable _ a v) = Variable sp a v+ setSpanInfo sp (Constructor _ a c) = Constructor sp a c+ setSpanInfo sp (Paren _ e) = Paren sp e+ setSpanInfo sp (Typed _ e qty) = Typed sp e qty+ setSpanInfo sp (Record _ a c fs) = Record sp a c fs+ setSpanInfo sp (RecordUpdate _ e fs) = RecordUpdate sp e fs+ setSpanInfo sp (Tuple _ es) = Tuple sp es+ setSpanInfo sp (List _ a es) = List sp a es+ setSpanInfo sp (ListCompr _ e stms) = ListCompr sp e stms+ setSpanInfo sp (EnumFrom _ e) = EnumFrom sp e+ setSpanInfo sp (EnumFromThen _ e1 e2) = EnumFromThen sp e1 e2+ setSpanInfo sp (EnumFromTo _ e1 e2) = EnumFromTo sp e1 e2+ setSpanInfo sp (EnumFromThenTo _ e1 e2 e3) = EnumFromThenTo sp e1 e2 e3+ setSpanInfo sp (UnaryMinus _ e) = UnaryMinus sp e+ setSpanInfo sp (Apply _ e1 e2) = Apply sp e1 e2+ setSpanInfo sp (InfixApply _ e1 op e2) = InfixApply sp e1 op e2+ setSpanInfo sp (LeftSection _ e op) = LeftSection sp e op+ setSpanInfo sp (RightSection _ op e) = RightSection sp op e+ setSpanInfo sp (Lambda _ ts e) = Lambda sp ts e+ setSpanInfo sp (Let _ li ds e) = Let sp li ds e+ setSpanInfo sp (Do _ li stms e) = Do sp li stms e+ setSpanInfo sp (IfThenElse _ e1 e2 e3) = IfThenElse sp e1 e2 e3+ setSpanInfo sp (Case _ li ct e as) = Case sp li ct e as++ updateEndPos e@(Literal _ _ _) = e+ updateEndPos e@(Variable _ _ v) =+ setEndPosition (incr (getPosition v) (qIdentLength v - 1)) e+ updateEndPos e@(Constructor _ _ c) =+ setEndPosition (incr (getPosition c) (qIdentLength c - 1)) e+ updateEndPos e@(Paren (SpanInfo _ [_,s]) _) =+ setEndPosition (end s) e+ updateEndPos e@(Paren _ _) = e+ updateEndPos e@(Typed _ _ qty) =+ setEndPosition (getSrcSpanEnd qty) e+ updateEndPos e@(Record (SpanInfo _ (s:ss)) _ _ _) =+ setEndPosition (end (last (s:ss))) e+ updateEndPos e@(Record _ _ _ _) = e+ updateEndPos e@(RecordUpdate (SpanInfo _ (s:ss)) _ _) =+ setEndPosition (end (last (s:ss))) e+ updateEndPos e@(RecordUpdate _ _ _) = e+ updateEndPos e@(Tuple (SpanInfo _ [_,s]) _) =+ setEndPosition (end s) e+ updateEndPos e@(Tuple _ _) = e+ updateEndPos e@(List (SpanInfo _ (s:ss)) _ _) =+ setEndPosition (end (last (s:ss))) e+ updateEndPos e@(List _ _ _) = e+ updateEndPos e@(ListCompr (SpanInfo _ (s:ss)) _ _) =+ setEndPosition (end (last (s:ss))) e+ updateEndPos e@(ListCompr _ _ _) = e+ updateEndPos e@(EnumFrom (SpanInfo _ [_,_,s]) _) =+ setEndPosition (end s) e+ updateEndPos e@(EnumFrom _ _) = e+ updateEndPos e@(EnumFromTo (SpanInfo _ [_,_,s]) _ _) =+ setEndPosition (end s) e+ updateEndPos e@(EnumFromTo _ _ _) = e+ updateEndPos e@(EnumFromThen (SpanInfo _ [_,_,_,s]) _ _) =+ setEndPosition (end s) e+ updateEndPos e@(EnumFromThen _ _ _) = e+ updateEndPos e@(EnumFromThenTo (SpanInfo _ [_,_,_,s]) _ _ _) =+ setEndPosition (end s) e+ updateEndPos e@(EnumFromThenTo _ _ _ _) = e+ updateEndPos e@(UnaryMinus _ e') =+ setEndPosition (getSrcSpanEnd e') e+ updateEndPos e@(Apply _ _ e') =+ setEndPosition (getSrcSpanEnd e') e+ updateEndPos e@(InfixApply _ _ _ e') =+ setEndPosition (getSrcSpanEnd e') e+ updateEndPos e@(LeftSection (SpanInfo _ [_,s]) _ _) =+ setEndPosition (end s) e+ updateEndPos e@(LeftSection _ _ _) = e+ updateEndPos e@(RightSection (SpanInfo _ [_,s]) _ _) =+ setEndPosition (end s) e+ updateEndPos e@(RightSection _ _ _) = e+ updateEndPos e@(Lambda _ _ e') =+ setEndPosition (getSrcSpanEnd e') e+ updateEndPos e@(Let _ _ _ e') =+ setEndPosition (getSrcSpanEnd e') e+ updateEndPos e@(Do _ _ _ e') =+ setEndPosition (getSrcSpanEnd e') e+ updateEndPos e@(IfThenElse _ _ _ e') =+ setEndPosition (getSrcSpanEnd e') e+ updateEndPos e@(Case _ _ _ _ (a:as)) =+ setEndPosition (getSrcSpanEnd (last (a:as))) e+ updateEndPos e@(Case (SpanInfo _ (s:ss)) _ _ _ _) =+ setEndPosition (end (last (s:ss))) e+ updateEndPos e@(Case _ _ _ _ _) = e++ getLayoutInfo (Let _ li _ _) = li+ getLayoutInfo (Do _ li _ _) = li+ getLayoutInfo (Case _ li _ _ _) = li+ getLayoutInfo _ = WhitespaceLayout++instance HasSpanInfo (Statement a) where+ getSpanInfo (StmtExpr sp _) = sp+ getSpanInfo (StmtDecl sp _ _) = sp+ getSpanInfo (StmtBind sp _ _) = sp++ setSpanInfo sp (StmtExpr _ ex) = StmtExpr sp ex+ setSpanInfo sp (StmtDecl _ li ds) = StmtDecl sp li ds+ setSpanInfo sp (StmtBind _ p ex) = StmtBind sp p ex++ updateEndPos s@(StmtExpr _ e) =+ setEndPosition (getSrcSpanEnd e) s+ updateEndPos s@(StmtBind _ _ e) =+ setEndPosition (getSrcSpanEnd e) s+ updateEndPos s@(StmtDecl _ _ (d:ds)) =+ setEndPosition (getSrcSpanEnd (last (d:ds))) s+ updateEndPos s@(StmtDecl (SpanInfo _ [s']) _ _) = -- empty let+ setEndPosition (end s') s+ updateEndPos s@(StmtDecl _ _ _) = s++ getLayoutInfo (StmtDecl _ li _) = li+ getLayoutInfo _ = WhitespaceLayout++instance HasSpanInfo (Alt a) where+ getSpanInfo (Alt sp _ _) = sp+ setSpanInfo sp (Alt _ p rhs) = Alt sp p rhs+ updateEndPos a@(Alt _ _ rhs) =+ setEndPosition (getSrcSpanEnd rhs) a++instance HasSpanInfo (Field a) where+ getSpanInfo (Field sp _ _) = sp+ setSpanInfo sp (Field _ qid a) = Field sp qid a+ updateEndPos f@(Field (SpanInfo _ ss) _ _) =+ setEndPosition (end (last ss)) f+ updateEndPos f@ (Field _ _ _) = f++instance HasSpanInfo (Goal a) where+ getSpanInfo (Goal sp _ _ _) = sp+ setSpanInfo sp (Goal _ li e ds) = Goal sp li e ds++ updateEndPos g@(Goal (SpanInfo _ [_]) _ _ (d:ds)) =+ setEndPosition (getSrcSpanEnd (last (d:ds))) g+ updateEndPos g@(Goal (SpanInfo _ [s]) _ _ _) =+ setEndPosition (end s) g+ updateEndPos g@(Goal _ _ _ _) = g++ getLayoutInfo (Goal _ li _ _) = li++instance HasPosition (Module a) where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition (Decl a) where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition (Equation a) where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition ModulePragma where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition ExportSpec where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition ImportDecl where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition ImportSpec where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition Export where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition Import where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition ConstrDecl where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition TypeExpr where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition QualTypeExpr where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition NewConstrDecl where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition Constraint where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition FieldDecl where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition (Lhs a) where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition (Rhs a) where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition (CondExpr a) where+ getPosition = getStartPosition++instance HasPosition (Pattern a) where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition (Expression a) where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition (Alt a) where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition (Goal a) where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition (Field a) where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition (Statement a) where+ getPosition = getStartPosition+ setPosition = setStartPosition++instance HasPosition (InfixOp a) where+ getPosition (InfixOp _ q) = getPosition q+ getPosition (InfixConstr _ q) = getPosition q++ setPosition p (InfixOp a q) = InfixOp a (setPosition p q)+ setPosition p (InfixConstr a q) = InfixConstr a (setPosition p q)++instance Binary a => Binary (Module a) where+ put (Module spi li ps mid ex im ds) = put spi >> put li >> put ps >>+ put mid >> put ex >> put im >> put ds+ get = Module <$> get <*> get <*> get <*> get <*> get <*> get <*> get++instance Binary ModulePragma where+ put (LanguagePragma spi ex ) = putWord8 0 >> put spi >> put ex+ put (OptionsPragma spi t s) = putWord8 1 >> put spi >> put t >> put s++ get = do+ x <- getWord8+ case x of+ 0 -> liftM2 LanguagePragma get get+ 1 -> liftM3 OptionsPragma get get get+ _ -> fail "Invalid encoding for ModulePragma"++instance Binary ExportSpec where+ put (Exporting spi es) = put spi >> put es+ get = liftM2 Exporting get get++instance Binary Export where+ put (Export spi qid ) = putWord8 0 >> put spi >> put qid+ put (ExportTypeWith spi qid is) = putWord8 1 >> put spi >> put qid >> put is+ put (ExportTypeAll spi qid ) = putWord8 2 >> put spi >> put qid+ put (ExportModule spi mid ) = putWord8 3 >> put spi >> put mid++ get = do+ x <- getWord8+ case x of+ 0 -> liftM2 Export get get+ 1 -> liftM3 ExportTypeWith get get get+ 2 -> liftM2 ExportTypeAll get get+ 3 -> liftM2 ExportModule get get+ _ -> fail "Invalid encoding for Export"++instance Binary ImportDecl where+ put (ImportDecl spi mid q al im) = put spi >> put mid >> put q >>+ put al >> put im+ get = ImportDecl <$> get <*> get <*> get <*> get <*> get++instance Binary ImportSpec where+ put (Importing spi im) = putWord8 0 >> put spi >> put im+ put (Hiding spi im) = putWord8 1 >> put spi >> put im++ get = do+ x <- getWord8+ case x of+ 0 -> liftM2 Importing get get+ 1 -> liftM2 Hiding get get+ _ -> fail "Invalid encoding for ImportSpec"++instance Binary Import where+ put (Import spi idt ) = putWord8 0 >> put spi >> put idt+ put (ImportTypeWith spi idt is) = putWord8 1 >> put spi >> put idt >> put is+ put (ImportTypeAll spi idt ) = putWord8 2 >> put spi >> put idt++ get = do+ x <- getWord8+ case x of+ 0 -> liftM2 Import get get+ 1 -> liftM3 ImportTypeWith get get get+ 2 -> liftM2 ImportTypeAll get get+ _ -> fail "Invalid encoding for Import"++instance Binary a => Binary (Decl a) where+ put (InfixDecl spi i pr is) =+ putWord8 0 >> put spi >> put i >> put pr >> put is+ put (DataDecl spi idt vs cns cls) =+ putWord8 1 >> put spi >> put idt >> put vs >> put cns >> put cls+ put (ExternalDataDecl spi idt vs) =+ putWord8 2 >> put spi >> put idt >> put vs+ put (NewtypeDecl spi idt vs cn cls) =+ putWord8 3 >> put spi >> put idt >> put vs >> put cn >> put cls >> put cls+ put (TypeDecl spi idt vs ty) =+ putWord8 4 >> put spi >> put idt >> put vs >> put ty+ put (TypeSig spi fs ty) =+ putWord8 5 >> put spi >> put fs >> put ty+ put (FunctionDecl spi a f eqs) =+ putWord8 6 >> put spi >> put a >> put f >> put eqs+ put (ExternalDecl spi vs) =+ putWord8 7 >> put spi >> put vs+ put (PatternDecl spi p rhs) =+ putWord8 8 >> put spi >> put p >> put rhs+ put (FreeDecl spi vs) =+ putWord8 9 >> put spi >> put vs+ put (DefaultDecl spi tys) =+ putWord8 10 >> put spi >> put tys+ put (ClassDecl spi li cx cls v ds) =+ putWord8 11 >> put spi >> put li >> put cx >> put cls >> put v >> put ds+ put (InstanceDecl spi li cx cls ty ds) =+ putWord8 12 >> put spi >> put li >> put cx >> put cls >> put ty >> put ds++ get = do+ x <- getWord8+ case x of+ 0 -> InfixDecl <$> get <*> get <*> get <*> get+ 1 -> DataDecl <$> get <*> get <*> get <*> get <*> get+ 2 -> ExternalDataDecl <$> get <*> get <*> get+ 3 -> NewtypeDecl <$> get <*> get <*> get <*> get <*> get+ 4 -> TypeDecl <$> get <*> get <*> get <*> get+ 5 -> TypeSig <$> get <*> get <*> get+ 6 -> FunctionDecl <$> get <*> get <*> get <*> get+ 7 -> ExternalDecl <$> get <*> get+ 8 -> PatternDecl <$> get <*> get <*> get+ 9 -> FreeDecl <$> get <*> get+ 10 -> DefaultDecl <$> get <*> get+ 11 -> ClassDecl <$> get <*> get <*> get <*> get <*> get <*> get+ 12 -> InstanceDecl <$> get <*> get <*> get <*> get <*> get <*> get+ _ -> fail "Invalid encoding for Decl"++instance Binary Infix where+ put InfixL = putWord8 0+ put InfixR = putWord8 1+ put Infix = putWord8 2++ get = do+ x <- getWord8+ case x of+ 0 -> return InfixL+ 1 -> return InfixR+ 2 -> return Infix+ _ -> fail "Invalid encoding for Infix"++instance Binary ConstrDecl where+ put (ConstrDecl spi idt tys) =+ putWord8 0 >> put spi >> put idt >> put tys+ put (ConOpDecl spi ty1 idt ty2) =+ putWord8 1 >> put spi >> put ty1 >> put idt >> put ty2+ put (RecordDecl spi idt fs) =+ putWord8 2 >> put spi >> put idt >> put fs++ get = do+ x <- getWord8+ case x of+ 0 -> liftM3 ConstrDecl get get get+ 1 -> ConOpDecl <$> get <*> get <*> get <*> get+ 2 -> liftM3 RecordDecl get get get+ _ -> fail "Invalid encoding for ConstrDecl"++instance Binary NewConstrDecl where+ put (NewConstrDecl spi c ty) =+ putWord8 0 >> put spi >> put c >> put ty+ put (NewRecordDecl spi c fs) =+ putWord8 1 >> put spi >> put c >> put fs++ get = do+ x <- getWord8+ case x of+ 0 -> liftM3 NewConstrDecl get get get+ 1 -> liftM3 NewRecordDecl get get get+ _ -> fail "Invalid encoding for NewConstrDecl"++instance Binary FieldDecl where+ put (FieldDecl spi is ty) = put spi >> put is >> put ty+ get = liftM3 FieldDecl get get get++instance Binary QualTypeExpr where+ put (QualTypeExpr spi ctx te) = put spi >> put ctx >> put te+ get = liftM3 QualTypeExpr get get get++instance Binary TypeExpr where+ put (ConstructorType spi qid) =+ putWord8 0 >> put spi >> put qid+ put (ApplyType spi ty1 ty2) =+ putWord8 1 >> put spi >> put ty1 >> put ty2+ put (VariableType spi idt) =+ putWord8 2 >> put spi >> put idt+ put (TupleType spi tys) =+ putWord8 3 >> put spi >> put tys+ put (ListType spi ty) =+ putWord8 4 >> put spi >> put ty+ put (ArrowType spi ty1 ty2) =+ putWord8 5 >> put spi >> put ty1 >> put ty2+ put (ParenType spi ty) =+ putWord8 6 >> put spi >> put ty+ put (ForallType spi is ty) =+ putWord8 7 >> put spi >> put is >> put ty++ get = do+ x <- getWord8+ case x of+ 0 -> liftM2 ConstructorType get get+ 1 -> liftM3 ApplyType get get get+ 2 -> liftM2 VariableType get get+ 3 -> liftM2 TupleType get get+ 4 -> liftM2 ListType get get+ 5 -> liftM3 ArrowType get get get+ 6 -> liftM2 ParenType get get+ 7 -> liftM3 ForallType get get get+ _ -> fail "Invalid encoding for TypeExpr"++instance Binary Constraint where+ put (Constraint spi cls ty) = put spi >> put cls >> put ty+ get = liftM3 Constraint get get get++instance Binary a => Binary (Equation a) where+ put (Equation spi lhs rhs) = put spi >> put lhs >> put rhs+ get = liftM3 Equation get get get++instance Binary a => Binary (Lhs a) where+ put (FunLhs spi f ps) =+ putWord8 0 >> put spi >> put f >> put ps+ put (OpLhs spi p1 op p2) =+ putWord8 1 >> put spi >> put p1 >> put op >> put p2+ put (ApLhs spi lhs ps) =+ putWord8 2 >> put spi >> put lhs >> put ps++ get = do+ x <- getWord8+ case x of+ 0 -> liftM3 FunLhs get get get+ 1 -> OpLhs <$> get <*> get <*> get <*> get+ 2 -> liftM3 ApLhs get get get+ _ -> fail "Invalid encoding for Lhs"++instance Binary a => Binary (Rhs a) where+ put (SimpleRhs spi li e ds) =+ putWord8 0 >> put spi >> put li >> put e >> put ds+ put (GuardedRhs spi li gs ds) =+ putWord8 1 >> put spi >> put li >> put gs >> put ds++ get = do+ x <- getWord8+ case x of+ 0 -> SimpleRhs <$> get <*> get <*> get <*> get+ 1 -> GuardedRhs <$> get <*> get <*> get <*> get+ _ -> fail "Invalid encoding for Rhs"++instance Binary a => Binary (CondExpr a) where+ put (CondExpr spi g e) = put spi >> put g >> put e+ get = liftM3 CondExpr get get get++instance Binary Literal where+ put (Char c) = putWord8 0 >> put c+ put (Int i) = putWord8 1 >> put i+ put (Float f) = putWord8 2 >> put (show f)+ put (String s) = putWord8 3 >> put s++ get = do+ x <- getWord8+ case x of+ 0 -> fmap Char get+ 1 -> fmap Int get+ 2 -> fmap (Float . read) get+ 3 -> fmap String get+ _ -> fail "Invalid encoding for Literal"++instance Binary a => Binary (Pattern a) where+ put (LiteralPattern spi a l) =+ putWord8 0 >> put spi >> put a >> put l+ put (NegativePattern spi a l) =+ putWord8 1 >> put spi >> put a >> put l+ put (VariablePattern spi a idt) =+ putWord8 2 >> put spi >> put a >> put idt+ put (ConstructorPattern spi a qid ps) =+ putWord8 3 >> put spi >> put a >> put qid >> put ps+ put (InfixPattern spi a p1 qid p2) =+ putWord8 4 >> put spi >> put a >> put p1 >> put qid >> put p2+ put (ParenPattern spi p) =+ putWord8 5 >> put spi >> put p+ put (RecordPattern spi a qid fs) =+ putWord8 6 >> put spi >> put a >> put qid >> put fs+ put (TuplePattern spi ps) =+ putWord8 7 >> put spi >> put ps+ put (ListPattern spi a ps) =+ putWord8 8 >> put spi >> put a >> put ps+ put (AsPattern spi idt p) =+ putWord8 9 >> put spi >> put idt >> put p+ put (LazyPattern spi p) =+ putWord8 10 >> put spi >> put p+ put (FunctionPattern spi a qid ps) =+ putWord8 11 >> put spi >> put a >> put qid >> put ps+ put (InfixFuncPattern spi a p1 qid p2) =+ putWord8 12 >> put spi >> put a >> put p1 >> put qid >> put p2++ get = do+ x <- getWord8+ case x of+ 0 -> liftM3 LiteralPattern get get get+ 1 -> liftM3 NegativePattern get get get+ 2 -> liftM3 VariablePattern get get get+ 3 -> ConstructorPattern <$> get <*> get <*> get <*> get+ 4 -> InfixPattern <$> get <*> get <*> get <*> get <*> get+ 5 -> liftM2 ParenPattern get get+ 6 -> RecordPattern <$> get <*> get <*> get <*> get+ 7 -> liftM2 TuplePattern get get+ 8 -> liftM3 ListPattern get get get+ 9 -> liftM3 AsPattern get get get+ 10 -> liftM2 LazyPattern get get+ 11 -> FunctionPattern <$> get <*> get <*> get <*> get+ 12 -> InfixFuncPattern <$> get <*> get <*> get <*> get <*> get+ _ -> fail "Invalid encoding for Pattern"++instance Binary a => Binary (Expression a) where+ put (Literal spi a l) =+ putWord8 0 >> put spi >> put a >> put l+ put (Variable spi a qid) =+ putWord8 1 >> put spi >> put a >> put qid+ put (Constructor spi a qid) =+ putWord8 2 >> put spi >> put a >> put qid+ put (Paren spi e) =+ putWord8 3 >> put spi >> put e+ put (Typed spi e ty) =+ putWord8 4 >> put spi >> put e >> put ty+ put (Record spi a qid fs) =+ putWord8 5 >> put spi >> put a >> put qid >> put fs+ put (RecordUpdate spi e fs) =+ putWord8 6 >> put spi >> put e >> put fs+ put (Tuple spi es) =+ putWord8 7 >> put spi >> put es+ put (List spi a es) =+ putWord8 8 >> put spi >> put a >> put es+ put (ListCompr spi e stms) =+ putWord8 9 >> put spi >> put e >> put stms+ put (EnumFrom spi e1) =+ putWord8 10 >> put spi >> put e1+ put (EnumFromThen spi e1 e2) =+ putWord8 11 >> put spi >> put e1 >> put e2+ put (EnumFromTo spi e1 e2) =+ putWord8 12 >> put spi >> put e1 >> put e2+ put (EnumFromThenTo spi e1 e2 e3) =+ putWord8 13 >> put spi >> put e1 >> put e2 >> put e3+ put (UnaryMinus spi e) =+ putWord8 14 >> put spi >> put e+ put (Apply spi e1 e2) =+ putWord8 15 >> put spi >> put e1 >> put e2+ put (InfixApply spi e1 op e2) =+ putWord8 16 >> put spi >> put e1 >> put op >> put e2+ put (LeftSection spi e op) =+ putWord8 17 >> put spi >> put e >> put op+ put (RightSection spi op e) =+ putWord8 18 >> put spi >> put op >> put e+ put (Lambda spi ps e) =+ putWord8 19 >> put spi >> put ps >> put e+ put (Let spi li ds e) =+ putWord8 20 >> put spi >> put li >> put ds >> put e+ put (Do spi li stms e) =+ putWord8 21 >> put spi >> put li >> put stms >> put e+ put (IfThenElse spi e1 e2 e3) =+ putWord8 22 >> put spi >> put e1 >> put e2 >> put e3+ put (Case spi li cty e as) =+ putWord8 23 >> put spi >> put li >> put cty >> put e >> put as++ get = do+ x <- getWord8+ case x of+ 0 -> liftM3 Literal get get get+ 1 -> liftM3 Variable get get get+ 2 -> liftM3 Constructor get get get+ 3 -> liftM2 Paren get get+ 4 -> liftM3 Typed get get get+ 5 -> Record <$> get <*> get <*> get <*> get+ 6 -> RecordUpdate <$> get <*> get <*> get+ 7 -> liftM2 Tuple get get+ 8 -> liftM3 List get get get+ 9 -> liftM3 ListCompr get get get+ 10 -> liftM2 EnumFrom get get+ 11 -> liftM3 EnumFromThen get get get+ 12 -> liftM3 EnumFromTo get get get+ 13 -> EnumFromThenTo <$> get <*> get <*> get <*> get+ 14 -> liftM2 UnaryMinus get get+ 15 -> liftM3 Apply get get get+ 16 -> InfixApply <$> get <*> get <*> get <*> get+ 17 -> liftM3 LeftSection get get get+ 18 -> liftM3 RightSection get get get+ 19 -> liftM3 Lambda get get get+ 20 -> Let <$> get <*> get <*> get <*> get+ 21 -> Do <$> get <*> get <*> get <*> get+ 22 -> IfThenElse <$> get <*> get <*> get <*> get+ 23 -> Case <$> get <*> get <*> get <*> get <*> get+ _ -> fail "Invalid encoding for Expression"++instance Binary a => Binary (InfixOp a) where+ put (InfixOp a qid) = putWord8 0 >> put a >> put qid+ put (InfixConstr a qid) = putWord8 1 >> put a >> put qid++ get = do+ x <- getWord8+ case x of+ 0 -> liftM2 InfixOp get get+ 1 -> liftM2 InfixConstr get get+ _ -> fail "Invalid encoding for InfixOp"++instance Binary a => Binary (Statement a) where+ put (StmtExpr spi e) = putWord8 0 >> put spi >> put e+ put (StmtDecl spi li ds) = putWord8 1 >> put spi >> put li >> put ds+ put (StmtBind spi p e) = putWord8 2 >> put spi >> put p >> put e++ get = do+ x <- getWord8+ case x of+ 0 -> liftM2 StmtExpr get get+ 1 -> liftM3 StmtDecl get get get+ 2 -> liftM3 StmtBind get get get+ _ -> fail "Invalid encoding for Statement"++instance Binary CaseType where+ put Rigid = putWord8 0+ put Flex = putWord8 1++ get = do+ x <- getWord8+ case x of+ 0 -> return Rigid+ 1 -> return Flex+ _ -> fail "Invalid encoding for CaseType"++instance Binary a => Binary (Alt a) where+ put (Alt spi p rhs) = put spi >> put p >> put rhs+ get = liftM3 Alt get get get++instance Binary a => Binary (Field a) where+ put (Field spi qid a) = put spi >> put qid >> put a+ get = liftM3 Field get get get++instance Binary a => Binary (Var a) where+ put (Var a idt) = put a >> put idt+ get = liftM2 Var get get++{- HLINT ignore "Use record patterns"-}
− src/Curry/Syntax/Type.lhs
@@ -1,315 +0,0 @@-> {-# LANGUAGE DeriveDataTypeable #-}--% $Id: CurrySyntax.lhs,v 1.43 2004/02/15 22:10:31 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{CurrySyntax.lhs}-\section{The Parse Tree}-This module provides the necessary data structures to maintain the-parsed representation of a Curry program.--\em{Note:} this modified version uses haskell type \texttt{Integer}-instead of \texttt{Int} for representing integer values. This allows-an unlimited range of integer constants in Curry programs.-\begin{verbatim}--> module Curry.Syntax.Type where--> import Curry.Base.Ident-> import Curry.Base.Position-> import Data.Generics-> import Control.Monad.State--\end{verbatim}-\paragraph{Modules}-\begin{verbatim}--> data Module = Module ModuleIdent (Maybe ExportSpec) [Decl] -> deriving (Eq,Show,Read,Typeable,Data)--> data ExportSpec = Exporting Position [Export] deriving (Eq,Show,Read,Typeable,Data)-> data Export =-> Export QualIdent -- f/T-> | ExportTypeWith QualIdent [Ident] -- T(C1,...,Cn)-> | ExportTypeAll QualIdent -- T(..)-> | ExportModule ModuleIdent-> deriving (Eq,Show,Read,Typeable,Data)--\end{verbatim}-\paragraph{Module declarations}-\begin{verbatim}--> data ImportSpec =-> Importing Position [Import]-> | Hiding Position [Import]-> deriving (Eq,Show,Read,Typeable,Data)-> data Import =-> Import Ident -- f/T-> | ImportTypeWith Ident [Ident] -- T(C1,...,Cn)-> | ImportTypeAll Ident -- T(..)-> deriving (Eq,Show,Read,Typeable,Data)--> data Decl =-> ImportDecl Position ModuleIdent Qualified (Maybe ModuleIdent)-> (Maybe ImportSpec)-> | InfixDecl Position Infix Integer [Ident]-> | DataDecl Position Ident [Ident] [ConstrDecl]-> | NewtypeDecl Position Ident [Ident] NewConstrDecl-> | TypeDecl Position Ident [Ident] TypeExpr-> | TypeSig Position [Ident] TypeExpr-> | EvalAnnot Position [Ident] EvalAnnotation-> | FunctionDecl Position Ident [Equation]-> | ExternalDecl Position CallConv (Maybe String) Ident TypeExpr-> | FlatExternalDecl Position [Ident]-> | PatternDecl Position ConstrTerm Rhs-> | ExtraVariables Position [Ident]-> deriving (Eq,Show,Read,Typeable,Data)--> data ConstrDecl =-> ConstrDecl Position [Ident] Ident [TypeExpr]-> | ConOpDecl Position [Ident] TypeExpr Ident TypeExpr-> deriving (Eq,Show,Read,Typeable,Data)-> data NewConstrDecl =-> NewConstrDecl Position [Ident] Ident TypeExpr-> deriving (Eq,Show,Read,Typeable,Data)--> type Qualified = Bool-> data Infix = InfixL | InfixR | Infix deriving (Eq,Show,Read,Typeable,Data)-> data EvalAnnotation = EvalRigid | EvalChoice deriving (Eq,Show,Read,Typeable,Data)-> data CallConv = CallConvPrimitive | CallConvCCall deriving (Eq,Show,Read,Typeable,Data)--\end{verbatim}-\paragraph{Module interfaces}-Interface declarations are restricted to type declarations and signatures. -Note that an interface function declaration additionaly contains the -function arity (= number of parameters) in order to generate-correct FlatCurry function applications.-\begin{verbatim}--> data Interface = Interface ModuleIdent [IDecl] deriving (Eq,Show,Read,Typeable,Data)--> data IDecl =-> IImportDecl Position ModuleIdent-> | IInfixDecl Position Infix Integer QualIdent-> | HidingDataDecl Position Ident [Ident] -> | IDataDecl Position QualIdent [Ident] [Maybe ConstrDecl]-> | INewtypeDecl Position QualIdent [Ident] NewConstrDecl-> | ITypeDecl Position QualIdent [Ident] TypeExpr-> | IFunctionDecl Position QualIdent Int TypeExpr-> deriving (Eq,Show,Read,Typeable,Data)--\end{verbatim}-\paragraph{Types}-\begin{verbatim}--> data TypeExpr =-> ConstructorType QualIdent [TypeExpr]-> | VariableType Ident-> | TupleType [TypeExpr]-> | ListType TypeExpr-> | ArrowType TypeExpr TypeExpr-> | RecordType [([Ident],TypeExpr)] (Maybe TypeExpr) -> -- {l1 :: t1,...,ln :: tn | r}-> deriving (Eq,Show,Read,Typeable,Data)--\end{verbatim}-\paragraph{Functions}-\begin{verbatim}--> data Equation = Equation Position Lhs Rhs deriving (Eq,Show,Read,Typeable,Data)-> data Lhs =-> FunLhs Ident [ConstrTerm]-> | OpLhs ConstrTerm Ident ConstrTerm-> | ApLhs Lhs [ConstrTerm]-> deriving (Eq,Show,Read,Typeable,Data)-> data Rhs =-> SimpleRhs Position Expression [Decl]-> | GuardedRhs [CondExpr] [Decl]-> deriving (Eq,Show,Read,Typeable,Data)-> data CondExpr = CondExpr Position Expression Expression deriving (Eq,Show,Read,Typeable,Data)--> flatLhs :: Lhs -> (Ident,[ConstrTerm])-> flatLhs lhs = flat lhs []-> where flat (FunLhs f ts) ts' = (f,ts ++ ts')-> flat (OpLhs t1 op t2) ts = (op,t1:t2:ts)-> flat (ApLhs lhs ts) ts' = flat lhs (ts ++ ts')--\end{verbatim}-\paragraph{Literals} The \texttt{Ident} argument of an \texttt{Int}-literal is used for supporting ad-hoc polymorphism on integer-numbers. An integer literal can be used either as an integer number or-as a floating-point number depending on its context. The compiler uses-the identifier of the \texttt{Int} literal for maintaining its type.-\begin{verbatim}--> data Literal =-> Char SrcRef Char -- should be Int to handle Unicode-> | Int Ident Integer-> | Float SrcRef Double-> | String SrcRef String -- should be [Int] to handle Unicode-> deriving (Eq,Show,Read,Typeable,Data)--> mk' :: ([SrcRef] -> a) -> a-> mk' = ($[])--> mk :: (SrcRef -> a) -> a-> mk = ($noRef)--> mkInt :: Integer -> Literal-> mkInt i = mk (\r -> Int (addPositionIdent (AST r) anonId) i) --\end{verbatim}-\paragraph{Patterns}-\begin{verbatim}--> data ConstrTerm =-> LiteralPattern Literal-> | NegativePattern Ident Literal-> | VariablePattern Ident-> | ConstructorPattern QualIdent [ConstrTerm]-> | InfixPattern ConstrTerm QualIdent ConstrTerm-> | ParenPattern ConstrTerm-> | TuplePattern SrcRef [ConstrTerm]-> | ListPattern [SrcRef] [ConstrTerm]-> | AsPattern Ident ConstrTerm-> | LazyPattern SrcRef ConstrTerm-> | FunctionPattern QualIdent [ConstrTerm]-> | InfixFuncPattern ConstrTerm QualIdent ConstrTerm-> | RecordPattern [Field ConstrTerm] (Maybe ConstrTerm) -> -- {l1 = p1, ..., ln = pn} oder {l1 = p1, ..., ln = pn | p}-> deriving (Eq,Show,Read,Typeable,Data)--\end{verbatim}-\paragraph{Expressions}-\begin{verbatim}--> data Expression =-> Literal Literal-> | Variable QualIdent-> | Constructor QualIdent-> | Paren Expression-> | Typed Expression TypeExpr-> | Tuple SrcRef [Expression]-> | List [SrcRef] [Expression]-> | ListCompr SrcRef Expression [Statement] -- the ref corresponds to the main list -> | EnumFrom Expression-> | EnumFromThen Expression Expression-> | EnumFromTo Expression Expression-> | EnumFromThenTo Expression Expression Expression-> | UnaryMinus Ident Expression-> | Apply Expression Expression-> | InfixApply Expression InfixOp Expression-> | LeftSection Expression InfixOp-> | RightSection InfixOp Expression-> | Lambda SrcRef [ConstrTerm] Expression-> | Let [Decl] Expression-> | Do [Statement] Expression-> | IfThenElse SrcRef Expression Expression Expression-> | Case SrcRef Expression [Alt]-> | RecordConstr [Field Expression] -- {l1 = e1,...,ln = en}-> | RecordSelection Expression Ident -- e -> l-> | RecordUpdate [Field Expression] Expression -- {l1 := e1,...,ln := en | e}-> deriving (Eq,Show,Read,Typeable,Data)--> data InfixOp = InfixOp QualIdent | InfixConstr QualIdent deriving (Eq,Show,Read,Typeable,Data)--> data Statement =-> StmtExpr SrcRef Expression-> | StmtDecl [Decl]-> | StmtBind SrcRef ConstrTerm Expression-> deriving (Eq,Show,Read,Typeable,Data)--> data Alt = Alt Position ConstrTerm Rhs deriving (Eq,Show,Read,Typeable,Data)--> data Field a = Field Position Ident a deriving (Eq, Show,Read,Typeable,Data)--> fieldLabel :: Field a -> Ident-> fieldLabel (Field _ l _) = l--> fieldTerm :: Field a -> a-> fieldTerm (Field _ _ t) = t--> field2Tuple :: Field a -> (Ident,a)-> field2Tuple (Field _ l t) = (l,t)--> opName :: InfixOp -> QualIdent-> opName (InfixOp op) = op-> opName (InfixConstr c) = c--\end{verbatim}--> instance SrcRefOf ConstrTerm where-> srcRefOf (LiteralPattern l) = srcRefOf l-> srcRefOf (NegativePattern i _) = srcRefOf i-> srcRefOf (VariablePattern i) = srcRefOf i-> srcRefOf (ConstructorPattern i _) = srcRefOf i-> srcRefOf (InfixPattern _ i _) = srcRefOf i-> srcRefOf (ParenPattern c) = srcRefOf c-> srcRefOf (TuplePattern s _) = s-> srcRefOf (ListPattern s _) = error "list pattern has several source refs"-> srcRefOf (AsPattern i _) = srcRefOf i-> srcRefOf (LazyPattern s _) = s-> srcRefOf (FunctionPattern i _) = srcRefOf i-> srcRefOf (InfixFuncPattern _ i _) = srcRefOf i--> instance SrcRefOf Literal where-> srcRefOf (Char s _) = s-> srcRefOf (Int i _) = srcRefOf i-> srcRefOf (Float s _) = s-> srcRefOf (String s _) = s-------------------------------- add source references------------------------------> type M a = a -> State Int a-> -> addSrcRefs :: Module -> Module-> addSrcRefs x = evalState (addRef x) 0-> where -> addRef :: Data a' => M a' -> addRef = down `extM` addRefPos -> `extM` addRefSrc -> `extM` addRefIdent-> `extM` addRefListPat-> `extM` addRefListExp-> where-> down :: Data a' => M a'-> down = gmapM addRef-> -> addRefPos :: M [SrcRef]-> addRefPos _ = liftM (:[]) next-> -> addRefSrc :: M SrcRef-> addRefSrc _ = next-> -> addRefIdent :: M Ident-> addRefIdent ident = liftM (flip addRefId ident) next->-> addRefListPat :: M ConstrTerm-> addRefListPat (ListPattern _ ts) = do-> liftM (uncurry ListPattern) (addRefList ts)-> addRefListPat ct = gmapM addRef ct-> -> addRefListExp :: M Expression-> addRefListExp (List _ ts) = do-> liftM (uncurry List) (addRefList ts)-> addRefListExp ct = gmapM addRef ct-> -> addRefList :: Data a' => [a'] -> State Int ([SrcRef],[a'])-> addRefList ts = do-> i <- next-> let add t = do t' <- addRef t;j <- next; return (j,t')-> ists <- sequence (map add ts)-> let (is,ts') = unzip ists-> return (i:is,ts')-> -> next :: State Int SrcRef-> next = do-> i <- get-> put $! i+1-> return (SrcRef [i])
− src/Curry/Syntax/Unlit.hs
@@ -1,61 +0,0 @@-{-- Since version 0.7 of the language report, Curry accepts literate- source programs. In a literate source all program lines must begin- with a greater sign in the first column. All other lines are assumed- to be documentation. In order to avoid some common errors with- literate programs, Curry requires at least one program line to be- present in the file. In addition, every block of program code must be- preceded by a blank line and followed by a blank line.-- This module has been rewritten by Holger Siegel in 2009.-- (c) Holger Siegel, 2009.--}---module Curry.Syntax.Unlit(unlit) where--import Control.Monad(when, zipWithM)-import Data.Char--import Curry.Base.Position-import Curry.Base.MessageMonad---data Line = Program !Int String- | Blank | Comment--classify :: Int -> String -> Line-classify l ('>':cs) = Program l cs-classify _ cs- | all isSpace cs = Blank- | otherwise = Comment--{-- Process a literate program into error messages (if any) and the- corresponding non-literate program.--}--unlit :: FilePath -> String -> MsgMonad String-unlit fn lcy = do ls <- progLines fn (zipWith classify [1..] $ lines lcy)- when (all null ls) $- failWith (fn ++ ": no code in literate script")- return (unlines ls)--{-- Check that each program line is not adjacent to a comment line and- there is at least one program line.--}-progLines :: FilePath -> [Line] -> MsgMonad [String]-progLines fn cs - = zipWithM adjacent (Blank : cs) cs- where- adjacent :: Line -> Line -> MsgMonad String- adjacent (Program p _) Comment = message fn p "followed"- adjacent Comment (Program p _) = message fn p "preceded"- adjacent _ (Program _ s) = return s- adjacent _ _ = return ""--message :: String -> Int -> String -> MsgMonad a-message file p w = failWithAt (Position file p 1 noRef) msg- where msg = "When reading literate source: Program line is " ++ w ++ " by comment line."
src/Curry/Syntax/Utils.hs view
@@ -1,257 +1,325 @@-module Curry.Syntax.Utils(Expr, fv, qfv,- QuantExpr, bv,+{- |+ Module : $Header$+ Description : Utility functions for Curry's abstract syntax+ Copyright : (c) 1999 - 2004 Wolfgang Lux+ 2005 Martin Engelke+ 2011 - 2014 Björn Peemöller+ 2015 Jan Tikovsky+ 2016 Finn Teegen+ License : BSD-3-clause - isEvalAnnot, isTypeSig,- infixOp,- isTypeDecl, isValueDecl,- isInfixDecl,- isRecordDecl, isImportDecl) where+ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable -import qualified Data.Set as Set+ This module provides some utility functions for working with the+ abstract syntax tree of Curry.+-} +module Curry.Syntax.Utils+ ( hasLanguageExtension, knownExtensions+ , isTopDecl, isBlockDecl+ , isTypeSig, infixOp, isTypeDecl, isValueDecl, isInfixDecl+ , isDefaultDecl, isClassDecl, isTypeOrClassDecl, isInstanceDecl+ , isFunctionDecl, isExternalDecl, patchModuleId+ , isVariablePattern+ , isVariableType, isSimpleType+ , typeConstr, typeVariables, varIdent+ , flatLhs, eqnArity, fieldLabel, fieldTerm, field2Tuple, opName+ , funDecl, mkEquation, simpleRhs, patDecl, varDecl, constrPattern, caseAlt+ , mkLet, mkVar, mkCase, mkLambda+ , apply, unapply+ , constrId, nconstrId+ , nconstrType+ , recordLabels, nrecordLabels+ , methods, impls, imethod, imethodArity+ , shortenModuleAST+ ) where -import Curry.Base.Ident +import Control.Monad.State++import Curry.Base.Ident+import Curry.Base.SpanInfo+import Curry.Files.Filenames (takeBaseName)+import Curry.Syntax.Extension import Curry.Syntax.Type -{-- Free and bound variables- - The compiler needs to compute the sets of free and bound variables for- various different entities. We will devote three type classes to that- purpose. The \texttt{QualExpr} class is expected to take into account- that it is possible to use a qualified name to refer to a function- defined in the current module and therefore \emph{M.x} and $x$, where- $M$ is the current module name, should be considered the same name.- However note that this is correct only after renaming all local- definitions as \emph{M.x} always denotes an entity defined at the- top-level.- - The \texttt{Decl} instance of \texttt{QualExpr} returns all free- variables on the right hand side, regardless of whether they are bound- on the left hand side. This is more convenient as declarations are- usually processed in a declaration group where the set of free- variables cannot be computed independently for each declaration. Also- note that the operator in a unary minus expression is not a free- variable. This operator always refers to a global function from the- prelude.--}+-- |Check whether a 'Module' has a specific 'KnownExtension' enabled by a pragma+hasLanguageExtension :: Module a -> KnownExtension -> Bool+hasLanguageExtension mdl ext = ext `elem` knownExtensions mdl -class Expr e where- fv :: e -> [Ident]-class QualExpr e where- qfv :: ModuleIdent -> e -> [Ident]-class QuantExpr e where- bv :: e -> [Ident]+-- |Extract all known extensions from a 'Module'+knownExtensions :: Module a -> [KnownExtension]+knownExtensions (Module _ _ ps _ _ _ _) =+ [ e | LanguagePragma _ exts <- ps, KnownExtension _ e <- exts] -instance Expr e => Expr [e] where- fv = concat . map fv-instance QualExpr e => QualExpr [e] where- qfv m = concat . map (qfv m)-instance QuantExpr e => QuantExpr [e] where- bv = concat . map bv+-- |Replace the generic module name @main@ with the module name derived+-- from the 'FilePath' of the module.+patchModuleId :: FilePath -> Module a -> Module a+patchModuleId fn m@(Module spi li ps mid es is ds)+ | mid == mainMIdent = Module spi li ps (mkMIdent [takeBaseName fn]) es is ds+ | otherwise = m -instance QualExpr Decl where- qfv m (FunctionDecl _ _ eqs) = qfv m eqs- qfv m (PatternDecl _ _ rhs) = qfv m rhs- qfv _ _ = []+-- |Is the declaration a top declaration?+isTopDecl :: Decl a -> Bool+isTopDecl = not . isBlockDecl -instance QuantExpr Decl where- bv (TypeSig _ vs _) = vs- bv (EvalAnnot _ fs _) = fs- bv (FunctionDecl _ f _) = [f]- bv (ExternalDecl _ _ _ f _) = [f]- bv (FlatExternalDecl _ fs) = fs- bv (PatternDecl _ t _) = bv t- bv (ExtraVariables _ vs) = vs- bv _ = []+-- |Is the declaration a block declaration?+isBlockDecl :: Decl a -> Bool+isBlockDecl = liftM3 ((.) (||) . (||)) isInfixDecl isTypeSig isValueDecl -instance QualExpr Equation where- qfv m (Equation _ lhs rhs) = filterBv lhs (qfv m lhs ++ qfv m rhs)+-- |Is the declaration an infix declaration?+isInfixDecl :: Decl a -> Bool+isInfixDecl (InfixDecl _ _ _ _) = True+isInfixDecl _ = False -instance QuantExpr Lhs where- bv = bv . snd . flatLhs+-- |Is the declaration a type declaration?+isTypeDecl :: Decl a -> Bool+isTypeDecl (DataDecl _ _ _ _ _) = True+isTypeDecl (ExternalDataDecl _ _ _) = True+isTypeDecl (NewtypeDecl _ _ _ _ _) = True+isTypeDecl (TypeDecl _ _ _ _) = True+isTypeDecl _ = False -instance QualExpr Lhs where- qfv m lhs = qfv m (snd (flatLhs lhs))+-- |Is the declaration a default declaration?+isDefaultDecl :: Decl a -> Bool+isDefaultDecl (DefaultDecl _ _) = True+isDefaultDecl _ = False -instance QualExpr Rhs where- qfv m (SimpleRhs _ e ds) = filterBv ds (qfv m e ++ qfv m ds)- qfv m (GuardedRhs es ds) = filterBv ds (qfv m es ++ qfv m ds)+-- |Is the declaration a class declaration?+isClassDecl :: Decl a -> Bool+isClassDecl (ClassDecl _ _ _ _ _ _) = True+isClassDecl _ = False -instance QualExpr CondExpr where- qfv m (CondExpr _ g e) = qfv m g ++ qfv m e+-- |Is the declaration a type or a class declaration?+isTypeOrClassDecl :: Decl a -> Bool+isTypeOrClassDecl = liftM2 (||) isTypeDecl isClassDecl -instance QualExpr Expression where- qfv _ (Literal _) = []- qfv m (Variable v) = maybe [] return (localIdent m v)- qfv _ (Constructor _) = []- qfv m (Paren e) = qfv m e- qfv m (Typed e _) = qfv m e- qfv m (Tuple _ es) = qfv m es- qfv m (List _ es) = qfv m es- qfv m (ListCompr _ e qs) = foldr (qfvStmt m) (qfv m e) qs- qfv m (EnumFrom e) = qfv m e- qfv m (EnumFromThen e1 e2) = qfv m e1 ++ qfv m e2- qfv m (EnumFromTo e1 e2) = qfv m e1 ++ qfv m e2- qfv m (EnumFromThenTo e1 e2 e3) = qfv m e1 ++ qfv m e2 ++ qfv m e3- qfv m (UnaryMinus _ e) = qfv m e- qfv m (Apply e1 e2) = qfv m e1 ++ qfv m e2- qfv m (InfixApply e1 op e2) = qfv m op ++ qfv m e1 ++ qfv m e2- qfv m (LeftSection e op) = qfv m op ++ qfv m e- qfv m (RightSection op e) = qfv m op ++ qfv m e- qfv m (Lambda _ ts e) = filterBv ts (qfv m e)- qfv m (Let ds e) = filterBv ds (qfv m ds ++ qfv m e)- qfv m (Do sts e) = foldr (qfvStmt m) (qfv m e) sts- qfv m (IfThenElse _ e1 e2 e3) = qfv m e1 ++ qfv m e2 ++ qfv m e3- qfv m (Case _ e alts) = qfv m e ++ qfv m alts- qfv m (RecordConstr fs) = qfv m fs- qfv m (RecordSelection e _) = qfv m e- qfv m (RecordUpdate fs e) = qfv m e ++ qfv m fs+-- |Is the declaration an instance declaration?+isInstanceDecl :: Decl a -> Bool+isInstanceDecl (InstanceDecl _ _ _ _ _ _) = True+isInstanceDecl _ = False -qfvStmt :: ModuleIdent -> Statement -> [Ident] -> [Ident]-qfvStmt m st fvs = qfv m st ++ filterBv st fvs+-- |Is the declaration a type signature?+isTypeSig :: Decl a -> Bool+isTypeSig (TypeSig _ _ _) = True+isTypeSig _ = False -instance QualExpr Statement where- qfv m (StmtExpr _ e) = qfv m e- qfv m (StmtDecl ds) = filterBv ds (qfv m ds)- qfv m (StmtBind _ t e) = qfv m e+-- |Is the declaration a value declaration?+isValueDecl :: Decl a -> Bool+isValueDecl (FunctionDecl _ _ _ _) = True+isValueDecl (ExternalDecl _ _) = True+isValueDecl (PatternDecl _ _ _) = True+isValueDecl (FreeDecl _ _) = True+isValueDecl _ = False -instance QualExpr Alt where- qfv m (Alt _ t rhs) = filterBv t (qfv m rhs)+-- |Is the declaration a function declaration?+isFunctionDecl :: Decl a -> Bool+isFunctionDecl (FunctionDecl _ _ _ _) = True+isFunctionDecl _ = False -instance QuantExpr a => QuantExpr (Field a) where- bv (Field _ _ t) = bv t+-- |Is the declaration an external declaration?+isExternalDecl :: Decl a -> Bool+isExternalDecl (ExternalDecl _ _) = True+isExternalDecl _ = False -instance QualExpr a => QualExpr (Field a) where- qfv m (Field _ _ t) = qfv m t+-- |Is the pattern semantically equivalent to a variable pattern?+isVariablePattern :: Pattern a -> Bool+isVariablePattern (VariablePattern _ _ _) = True+isVariablePattern (ParenPattern _ t) = isVariablePattern t+isVariablePattern (AsPattern _ _ t) = isVariablePattern t+isVariablePattern (LazyPattern _ _) = True+isVariablePattern _ = False -instance QuantExpr Statement where- bv (StmtExpr _ e) = []- bv (StmtBind _ t e) = bv t- bv (StmtDecl ds) = bv ds+-- |Is a type expression a type variable?+isVariableType :: TypeExpr -> Bool+isVariableType (VariableType _ _) = True+isVariableType _ = False -instance QualExpr InfixOp where- qfv m (InfixOp op) = qfv m (Variable op)- qfv _ (InfixConstr _) = []+-- |Is a type expression simple, i.e., is it of the form T u_1 ... u_n,+-- where T is a type constructor and u_1 ... u_n are type variables?+isSimpleType :: TypeExpr -> Bool+isSimpleType (ConstructorType _ _) = True+isSimpleType (ApplyType _ ty1 ty2) = isSimpleType ty1 && isVariableType ty2+isSimpleType (VariableType _ _) = False+isSimpleType (TupleType _ tys) = all isVariableType tys+isSimpleType (ListType _ ty) = isVariableType ty+isSimpleType (ArrowType _ ty1 ty2) = isVariableType ty1 && isVariableType ty2+isSimpleType (ParenType _ ty) = isSimpleType ty+isSimpleType (ForallType _ _ _) = False -instance QuantExpr ConstrTerm where- bv (LiteralPattern _) = []- bv (NegativePattern _ _) = []- bv (VariablePattern v) = [v]- bv (ConstructorPattern c ts) = bv ts- bv (InfixPattern t1 op t2) = bv t1 ++ bv t2- bv (ParenPattern t) = bv t- bv (TuplePattern _ ts) = bv ts- bv (ListPattern _ ts) = bv ts- bv (AsPattern v t) = v : bv t- bv (LazyPattern _ t) = bv t- bv (FunctionPattern f ts) = bvFuncPatt (FunctionPattern f ts)- bv (InfixFuncPattern t1 op t2) = bvFuncPatt (InfixFuncPattern t1 op t2)- bv (RecordPattern fs r) = (maybe [] bv r) ++ bv fs+-- |Return the qualified type constructor of a type expression.+typeConstr :: TypeExpr -> QualIdent+typeConstr (ConstructorType _ tc) = tc+typeConstr (ApplyType _ ty _) = typeConstr ty+typeConstr (TupleType _ tys) = qTupleId (length tys)+typeConstr (ListType _ _) = qListId+typeConstr (ArrowType _ _ _) = qArrowId+typeConstr (ParenType _ ty) = typeConstr ty+typeConstr (VariableType _ _) =+ error "Curry.Syntax.Utils.typeConstr: variable type"+typeConstr (ForallType _ _ _) =+ error "Curry.Syntax.Utils.typeConstr: forall type" -instance QualExpr ConstrTerm where- qfv _ (LiteralPattern _) = []- qfv _ (NegativePattern _ _) = []- qfv _ (VariablePattern _) = []- qfv m (ConstructorPattern _ ts) = qfv m ts- qfv m (InfixPattern t1 _ t2) = qfv m [t1,t2]- qfv m (ParenPattern t) = qfv m t- qfv m (TuplePattern _ ts) = qfv m ts- qfv m (ListPattern _ ts) = qfv m ts- qfv m (AsPattern _ ts) = qfv m ts- qfv m (LazyPattern _ t) = qfv m t- qfv m (FunctionPattern f ts) - = (maybe [] return (localIdent m f)) ++ qfv m ts- qfv m (InfixFuncPattern t1 op t2) - = (maybe [] return (localIdent m op)) ++ qfv m [t1,t2]- qfv m (RecordPattern fs r) = (maybe [] (qfv m) r) ++ qfv m fs+-- |Return the list of variables occuring in a type expression.+typeVariables :: TypeExpr -> [Ident]+typeVariables (ConstructorType _ _) = []+typeVariables (ApplyType _ ty1 ty2) = typeVariables ty1 ++ typeVariables ty2+typeVariables (VariableType _ tv) = [tv]+typeVariables (TupleType _ tys) = concatMap typeVariables tys+typeVariables (ListType _ ty) = typeVariables ty+typeVariables (ArrowType _ ty1 ty2) = typeVariables ty1 ++ typeVariables ty2+typeVariables (ParenType _ ty) = typeVariables ty+typeVariables (ForallType _ vs ty) = vs ++ typeVariables ty -instance Expr TypeExpr where- fv (ConstructorType _ tys) = fv tys- fv (VariableType tv)- | tv == anonId = []- | otherwise = [tv]- fv (TupleType tys) = fv tys- fv (ListType ty) = fv ty- fv (ArrowType ty1 ty2) = fv ty1 ++ fv ty2- fv (RecordType fs rty) = (maybe [] fv rty) ++ fv (map snd fs)+-- |Return the identifier of a variable.+varIdent :: Var a -> Ident+varIdent (Var _ v) = v -filterBv :: QuantExpr e => e -> [Ident] -> [Ident]-filterBv e = filter (`Set.notMember` Set.fromList (bv e))+-- |Convert an infix operator into an expression+infixOp :: InfixOp a -> Expression a+infixOp (InfixOp a op) = Variable NoSpanInfo a op+infixOp (InfixConstr a op) = Constructor NoSpanInfo a op -{-- Since multiple variable occurrences are allowed in function patterns,- it is necessary to compute the list of bound variables in a different way:- Each variable occuring in the function pattern will be unique in the result- list.- -}+-- |flatten the left-hand-side to the identifier and all constructor terms+flatLhs :: Lhs a -> (Ident, [Pattern a])+flatLhs lhs = flat lhs []+ where flat (FunLhs _ f ts) ts' = (f, ts ++ ts')+ flat (OpLhs _ t1 op t2) ts' = (op, t1 : t2 : ts')+ flat (ApLhs _ lhs' ts) ts' = flat lhs' (ts ++ ts') -bvFuncPatt :: ConstrTerm -> [Ident]-bvFuncPatt = bvfp []- where- bvfp bvs (LiteralPattern _) = bvs- bvfp bvs (NegativePattern _ _) = bvs- bvfp bvs (VariablePattern v)- | elem v bvs = bvs- | otherwise = v:bvs- bvfp bvs (ConstructorPattern c ts) = foldl bvfp bvs ts- bvfp bvs (InfixPattern t1 op t2) = foldl bvfp bvs [t1,t2]- bvfp bvs (ParenPattern t) = bvfp bvs t- bvfp bvs (TuplePattern _ ts) = foldl bvfp bvs ts- bvfp bvs (ListPattern _ ts) = foldl bvfp bvs ts- bvfp bvs (AsPattern v t)- | elem v bvs = bvfp bvs t- | otherwise = bvfp (v:bvs) t- bvfp bvs (LazyPattern _ t) = bvfp bvs t- bvfp bvs (FunctionPattern f ts) = foldl bvfp bvs ts- bvfp bvs (InfixFuncPattern t1 op t2) = foldl bvfp bvs [t1, t2]- bvfp bvs (RecordPattern fs r)- = foldl bvfp (maybe bvs (bvfp bvs) r) (map fieldTerm fs)+-- |Return the arity of an equation.+eqnArity :: Equation a -> Int+eqnArity (Equation _ lhs _) = length $ snd $ flatLhs lhs +-- |Select the label of a field+fieldLabel :: Field a -> QualIdent+fieldLabel (Field _ l _) = l +-- |Select the term of a field+fieldTerm :: Field a -> a+fieldTerm (Field _ _ t) = t -{-- Here is a list of predicates identifying various kinds of- declarations.--}+-- |Select the label and term of a field+field2Tuple :: Field a -> (QualIdent, a)+field2Tuple (Field _ l t) = (l, t) -isImportDecl, isInfixDecl, isTypeDecl :: Decl -> Bool-isTypeSig, isEvalAnnot, isValueDecl :: Decl -> Bool+-- |Get the operator name of an infix operator+opName :: InfixOp a -> QualIdent+opName (InfixOp _ op) = op+opName (InfixConstr _ c ) = c -isImportDecl (ImportDecl _ _ _ _ _) = True-isImportDecl _ = False+-- | Get the identifier of a constructor declaration+constrId :: ConstrDecl -> Ident+constrId (ConstrDecl _ c _) = c+constrId (ConOpDecl _ _ op _) = op+constrId (RecordDecl _ c _) = c -isInfixDecl (InfixDecl _ _ _ _) = True-isInfixDecl _ = False+-- | Get the identifier of a newtype constructor declaration+nconstrId :: NewConstrDecl -> Ident+nconstrId (NewConstrDecl _ c _) = c+nconstrId (NewRecordDecl _ c _) = c -isTypeDecl (DataDecl _ _ _ _) = True-isTypeDecl (NewtypeDecl _ _ _ _) = True-isTypeDecl (TypeDecl _ _ _ _) = True-isTypeDecl _ = False+-- | Get the type of a newtype constructor declaration+nconstrType :: NewConstrDecl -> TypeExpr+nconstrType (NewConstrDecl _ _ ty) = ty+nconstrType (NewRecordDecl _ _ (_, ty)) = ty -isTypeSig (TypeSig _ _ _) = True-isTypeSig (ExternalDecl _ _ _ _ _) = True-isTypeSig _ = False+-- | Get record label identifiers of a constructor declaration+recordLabels :: ConstrDecl -> [Ident]+recordLabels (ConstrDecl _ _ _) = []+recordLabels (ConOpDecl _ _ _ _) = []+recordLabels (RecordDecl _ _ fs) = [l | FieldDecl _ ls _ <- fs, l <- ls] -isEvalAnnot (EvalAnnot _ _ _) = True-isEvalAnnot _ = False+-- | Get record label identifier of a newtype constructor declaration+nrecordLabels :: NewConstrDecl -> [Ident]+nrecordLabels (NewConstrDecl _ _ _ ) = []+nrecordLabels (NewRecordDecl _ _ (l, _)) = [l] -isValueDecl (FunctionDecl _ _ _) = True-isValueDecl (ExternalDecl _ _ _ _ _) = True-isValueDecl (FlatExternalDecl _ _) = True-isValueDecl (PatternDecl _ _ _) = True-isValueDecl (ExtraVariables _ _) = True-isValueDecl _ = False+-- | Get the declared method identifiers of a type class method declaration+methods :: Decl a -> [Ident]+methods (TypeSig _ fs _) = fs+methods _ = [] -isRecordDecl (TypeDecl _ _ _ (RecordType _ _)) = True-isRecordDecl _ = False+-- | Get the method identifiers of a type class method implementations+impls :: Decl a -> [Ident]+impls (FunctionDecl _ _ f _) = [f]+impls _ = [] +-- | Get the declared method identifier of an interface method declaration+imethod :: IMethodDecl -> Ident+imethod (IMethodDecl _ f _ _) = f -{-- The function \texttt{infixOp} converts an infix operator into an- expression.--}+-- | Get the arity of an interface method declaration+imethodArity :: IMethodDecl -> Maybe Int+imethodArity (IMethodDecl _ _ a _) = a -infixOp :: InfixOp -> Expression-infixOp (InfixOp op) = Variable op-infixOp (InfixConstr op) = Constructor op+--------------------------------------------------------+-- constructing elements of the abstract syntax tree+--------------------------------------------------------++funDecl :: SpanInfo -> a -> Ident -> [Pattern a] -> Expression a -> Decl a+funDecl spi a f ts e = FunctionDecl spi a f [mkEquation spi f ts e]++mkEquation :: SpanInfo -> Ident -> [Pattern a] -> Expression a -> Equation a+mkEquation spi f ts e = Equation spi (FunLhs NoSpanInfo f ts) (simpleRhs NoSpanInfo e)++simpleRhs :: SpanInfo -> Expression a -> Rhs a+simpleRhs spi e = SimpleRhs spi WhitespaceLayout e []++patDecl :: SpanInfo -> Pattern a -> Expression a -> Decl a+patDecl spi t e = PatternDecl spi t (SimpleRhs spi WhitespaceLayout e [])++varDecl :: SpanInfo -> a -> Ident -> Expression a -> Decl a+varDecl p ty = patDecl p . VariablePattern NoSpanInfo ty++constrPattern :: a -> QualIdent -> [(a, Ident)] -> Pattern a+constrPattern ty c = ConstructorPattern NoSpanInfo ty c+ . map (uncurry (VariablePattern NoSpanInfo))++caseAlt :: SpanInfo -> Pattern a -> Expression a -> Alt a+caseAlt spi t e = Alt spi t (SimpleRhs spi WhitespaceLayout e [])++mkLet :: [Decl a] -> Expression a -> Expression a+mkLet ds e = if null ds then e else Let NoSpanInfo WhitespaceLayout ds e++mkVar :: a -> Ident -> Expression a+mkVar ty = Variable NoSpanInfo ty . qualify++mkCase :: CaseType -> Expression a -> [Alt a] -> Expression a+mkCase = Case NoSpanInfo WhitespaceLayout++mkLambda :: [Pattern a] -> Expression a -> Expression a+mkLambda = Lambda NoSpanInfo++apply :: Expression a -> [Expression a] -> Expression a+apply = foldl (Apply NoSpanInfo)++unapply :: Expression a -> [Expression a] -> (Expression a, [Expression a])+unapply (Apply _ e1 e2) es = unapply e1 (e2 : es)+unapply e es = (e, es)+++--------------------------------------------------------+-- Shorten Module+-- Module Pragmas and Equations will be removed+--------------------------------------------------------++shortenModuleAST :: Module () -> Module ()+shortenModuleAST = shortenAST++class ShortenAST a where+ shortenAST :: a -> a++instance ShortenAST (Module a) where+ shortenAST (Module spi li _ mid ex im ds) =+ Module spi li [] mid ex im (map shortenAST ds)++instance ShortenAST (Decl a) where+ shortenAST (FunctionDecl spi a idt _) =+ FunctionDecl spi a idt []+ shortenAST (ClassDecl spi li cx cls tyv ds) =+ ClassDecl spi li cx cls tyv (map shortenAST ds)+ shortenAST (InstanceDecl spi li cx cls tyv ds) =+ InstanceDecl spi li cx cls tyv (map shortenAST ds)+ shortenAST d = d
src/CurryBuilder.hs view
@@ -1,202 +1,240 @@---------------------------------------------------------------------------------------------------------------------------------------------------------------------- CurryBuilder - Generates Curry representations for a Curry source file--- including all imported modules.------ September 2005,--- Martin Engelke (men@informatik.uni-kiel.de)--- March 2007, extensions by Sebastian Fischer (sebf@informatik.uni-kiel.de)----module CurryBuilder (buildCurry, smake) where+{- |+ Module : $Header$+ Description : Build tool for compiling multiple Curry modules+ Copyright : (c) 2005 Martin Engelke+ 2007 Sebastian Fischer+ 2011 - 2015 Björn Peemöller+ 2018 Kai-Oliver Prott+ License : BSD-3-clause -import System.Exit-import System.Time-import Control.Monad-import qualified Data.Map as Map-import Data.Maybe-import Data.List -import System.IO+ Maintainer : fte@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable -import Curry.Base.Ident+ This module contains functions to generate Curry representations for a+ Curry source file including all imported modules.+-}+module CurryBuilder (buildCurry, findCurry) where -import Modules (compileModule)-import CurryCompilerOpts -import CurryDeps+import Control.Monad (foldM, liftM)+import Data.Char (isSpace)+import Data.Maybe (catMaybes, fromMaybe, mapMaybe)+import System.FilePath ((</>), normalise)++import Curry.Base.Ident+import Curry.Base.Monad+import Curry.Base.SpanInfo (SpanInfo)+import Curry.Base.Pretty import Curry.Files.Filenames import Curry.Files.PathUtils+import Curry.Syntax ( ModulePragma (..), Extension (KnownExtension)+ , KnownExtension (CPP), Tool (CYMAKE, FRONTEND) ) +import Base.Messages -flatName' :: Options -> FilePath -> FilePath-flatName' o- | extendedFlat o = extFlatName- | otherwise = flatName+import CompilerOpts ( Options (..), CppOpts (..), DebugOpts (..)+ , TargetType (..), defaultDebugOpts, updateOpts )+import CurryDeps (Source (..), flatDeps)+import Modules (compileModule) --------------------------------------------------------------------------------+-- |Compile the Curry module in the given source file including all imported+-- modules w.r.t. the given 'Options'.+buildCurry :: Options -> String -> CYIO ()+buildCurry opts s = do+ fn <- findCurry opts s+ deps <- flatDeps opts fn+ makeCurry opts' deps+ where+ opts' | null $ optTargetTypes opts = opts { optTargetTypes = [FlatCurry] }+ | otherwise = opts --- Compiles the Curry program 'file' including all imported modules, depending--- on the options 'options'. The compilation was successful, if the returned--- list is empty, otherwise it contains error messages.-buildCurry :: Options -> FilePath -> IO ()-buildCurry options file- = do let paths = importPaths options- file' <- getCurryPath paths file- (cfile, errs1) <- return (maybe ("", [missingModule file])- (\f -> (f,[]))- file')- unless (null errs1) (abortWith errs1)- (deps, errs2) <- genDeps paths cfile- unless (null errs2) (abortWith errs2)- makeCurry options deps cfile+-- |Search for a compilation target identified by the given 'String'.+findCurry :: Options -> String -> CYIO FilePath+findCurry opts s = do+ mbTarget <- findFile `orIfNotFound` findModule+ case mbTarget of+ Nothing -> failMessages [complaint]+ Just fn -> ok fn+ where+ canBeFile = isCurryFilePath s+ canBeModule = isValidModuleName s+ moduleFile = moduleNameToFile $ fromModuleName s+ paths = "." : optImportPaths opts+ findFile = if canBeFile+ then liftIO $ lookupCurryFile paths s+ else return Nothing+ findModule = if canBeModule+ then liftIO $ lookupCurryFile paths moduleFile+ else return Nothing+ complaint+ | canBeFile && canBeModule = errMissing "target" s+ | canBeFile = errMissing "file" s+ | canBeModule = errMissing "module" s+ | otherwise = errUnrecognized s+ first `orIfNotFound` second = do+ mbFile <- first+ case mbFile of+ Nothing -> second+ justFn -> return justFn +-- |Compiles the given source modules, which must be in topological order.+makeCurry :: Options -> [(ModuleIdent, Source)] -> CYIO ()+makeCurry opts srcs = mapM_ process' (zip [1 ..] srcs)+ where+ total = length srcs+ tgtDir m = addOutDirModule (optUseOutDir opts) (optOutDir opts) m --------------------------------------------------------------------------------+ process' :: (Int, (ModuleIdent, Source)) -> CYIO ()+ process' (n, (m, Source fn ps is)) = do+ opts' <- processPragmas opts ps+ process (adjustOptions (n == total) opts') (n, total) m fn deps+ where+ deps = fn : mapMaybe curryInterface is -makeCurry :: Options -> [(ModuleIdent,Source)] -> FilePath -> IO ()-makeCurry options deps file- = mapM compile (map snd deps) >> return ()- where- compile (Source file' mods)- | dropExtension file == dropExtension file'- = do - flatIntfExists <- doesModuleExist (flatIntName file')- if flatIntfExists && not (force options) && null (dump options)- then smake (targetNames file')- (file':(catMaybes (map flatInterface mods)))- (generateFile file')- (skipFile file')- else generateFile file'- | otherwise- = do - flatIntfExists <- doesModuleExist (flatIntName file')- if flatIntfExists- then smake [flatName' options file'] --[flatName file', flatIntName file']- (file':(catMaybes (map flatInterface mods)))- (compileFile file')- (skipFile file')- else compileFile file'- compile _ = return ()+ curryInterface i = case lookup i srcs of+ Just (Source fn' _ _) -> Just $ tgtDir i $ interfName fn'+ Just (Interface fn' ) -> Just $ tgtDir i $ interfName fn'+ _ -> Nothing - compileFile file- = do unless (noVerb options) (putStrLn ("compiling " ++ file ++ " ..."))- compileModule (compOpts True) file- return ()+ process' _ = return () - skipFile file- = do unless (noVerb options)- (putStrLn ("skipping " ++ file ++ " ..."))+adjustOptions :: Bool -> Options -> Options+adjustOptions final opts+ | final = opts { optForce = optForce opts || isDump }+ | otherwise = opts { optForce = False+ , optDebugOpts = defaultDebugOpts+ }+ where+ isDump = not $ null $ dbDumpLevels $ optDebugOpts opts - generateFile file- = do unless (noVerb options) - (putStrLn ("generating " - ++ (head (targetNames file)) - ++ " ..."))- compileModule (compOpts False) file- return () - targetNames fn - | flat options = [flatName' options fn] -- , flatIntName fn]- | flatXml options = [xmlName fn]- | abstract options = [acyName fn]- | untypedAbstract options = [uacyName fn]- | parseOnly options = [maybe (sourceRepName fn) id (output options)]- | otherwise = [flatName' options fn] -- , flatIntName fn]-- flatInterface mod - = case (lookup mod deps) of- Just (Source file _) -> Just (flatIntName (dropExtension file))- Just (Interface file) -> Just (flatIntName (dropExtension file))- _ -> Nothing-- compOpts isImport- | isImport - = options - { flat = True,- flatXml = False,- abstract = False,- untypedAbstract = False,- parseOnly = False,- dump = []- }- | otherwise = options------------------------------------------------------------------------------------- Computes a dependency list for the Curry file 'file' (such a list--- usualy starts with the prelude and ends with 'file'). The result --- is a tuple containing an association list (type [(ModuleIdent,Source)]; --- see module "CurryDeps") and a list of error messages.-genDeps :: [FilePath] -> FilePath- -> IO ([(ModuleIdent,Source)], [String])-genDeps paths file- = fmap flattenDeps (deps paths [] Map.empty file)+processPragmas :: Options -> [ModulePragma] -> CYIO Options+processPragmas opts0 ps = do+ let opts1 = foldl processLanguagePragma opts0+ [ e | LanguagePragma _ es <- ps, KnownExtension _ e <- es ]+ foldM processOptionPragma opts1 $+ [ (p, s) | OptionsPragma p (Just FRONTEND) s <- ps ] +++ [ (p, s) | OptionsPragma p (Just CYMAKE) s <- ps ]+ where+ processLanguagePragma opts CPP+ = opts { optCppOpts = (optCppOpts opts) { cppRun = True } }+ processLanguagePragma opts _+ = opts+ processOptionPragma opts (p, s)+ | not (null unknownFlags)+ = failMessages [errUnknownOptions p unknownFlags]+ | optMode opts /= optMode opts'+ = failMessages [errIllegalOption p "Cannot change mode"]+ | optLibraryPaths opts /= optLibraryPaths opts'+ = failMessages [errIllegalOption p "Cannot change library path"]+ | optImportPaths opts /= optImportPaths opts'+ = failMessages [errIllegalOption p "Cannot change import path"]+ | optTargetTypes opts /= optTargetTypes opts'+ = failMessages [errIllegalOption p "Cannot change target type"]+ | otherwise+ = return opts'+ where+ (opts', files, errs) = updateOpts opts (quotedWords s)+ unknownFlags = files ++ errs +quotedWords :: String -> [String]+quotedWords str = case dropWhile isSpace str of+ [] -> []+ s@('\'' : cs) -> case break (== '\'') cs of+ (_ , [] ) -> def s+ (quoted, (_:rest)) -> quoted : quotedWords rest+ s@('"' : cs) -> case break (== '"') cs of+ (_ , [] ) -> def s+ (quoted, (_:rest)) -> quoted : quotedWords rest+ s -> def s+ where+ def s = let (w, rest) = break isSpace s in w : quotedWords rest ----------------------------------------------------------------------------------- A simple make function+-- |Compile a single source module.+process :: Options -> (Int, Int)+ -> ModuleIdent -> FilePath -> [FilePath] -> CYIO ()+process opts idx m fn deps+ | optForce opts = compile+ | otherwise = smake (tgtDir (interfName fn) : destFiles) deps compile skip+ where+ skip = status opts $ compMessage idx "Skipping" m (fn, head destFiles)+ compile = do+ status opts $ compMessage idx "Compiling" m (fn, head destFiles)+ compileModule opts m fn --- smake <destination files>--- <dependencies> --- <io action, if dependencies are newer than destination files>--- <io action, if destination files are newer than dependencies>-smake :: [FilePath] -> [FilePath] -> IO a -> IO a -> IO a-smake dests deps cmd alt- = do destTimes <- getDestTimes dests- depTimes <- getDepTimes deps- make destTimes depTimes- where- make destTimes depTimes- | (length destTimes) < (length dests) - = catch cmd (\err -> abortWith [show err]) - | null depTimes - = abortWith ["unknown dependencies"]- | outOfDate destTimes depTimes- = catch cmd (\err -> abortWith [show err])- | otherwise- = alt+ tgtDir = addOutDirModule (optUseOutDir opts) (optOutDir opts) m ----getDestTimes :: [FilePath] -> IO [ClockTime]-getDestTimes [] = return []-getDestTimes (file:files)- = catch (do time <- getModuleModTime file- times <- getDestTimes files- return (time:times))- (const (getDestTimes files))+ destFiles = [ gen fn | (t, gen) <- nameGens, t `elem` optTargetTypes opts]+ nameGens =+ [ (Tokens , tgtDir . tokensName )+ , (Comments , tgtDir . commentsName)+ , (Parsed , tgtDir . sourceRepName )+ , (FlatCurry , tgtDir . flatName )+ , (TypedFlatCurry , tgtDir . typedFlatName )+ , (AnnotatedFlatCurry , tgtDir . annotatedFlatName)+ , (AbstractCurry , tgtDir . acyName )+ , (UntypedAbstractCurry, tgtDir . uacyName )+ , (AST , tgtDir . astName )+ , (ShortAST , tgtDir . shortASTName )+ , (Html , const (fromMaybe "." (optHtmlDir opts) </> htmlName m))+ ] ----getDepTimes :: [String] -> IO [ClockTime]-getDepTimes [] = return []-getDepTimes (file:files)- = catch (do time <- getModuleModTime file- times <- getDepTimes files- return (time:times))- (\err -> abortWith [show err])+-- |Create a status message like+-- @[m of n] Compiling Module ( M.curry, .curry/M.fcy )@+compMessage :: (Int, Int) -> String -> ModuleIdent+ -> (FilePath, FilePath) -> String+compMessage (curNum, maxNum) what m (src, dst)+ = '[' : lpad (length sMaxNum) (show curNum) ++ " of " ++ sMaxNum ++ "]"+ ++ ' ' : rpad 9 what ++ ' ' : rpad 16 (moduleName m)+ ++ " ( " ++ normalise src ++ ", " ++ normalise dst ++ " )"+ where+ sMaxNum = show maxNum+ lpad n s = replicate (n - length s) ' ' ++ s+ rpad n s = s ++ replicate (n - length s) ' ' ----outOfDate :: [ClockTime] -> [ClockTime] -> Bool-outOfDate tgtimes dptimes = or (map (\t -> or (map ((<) t) dptimes)) tgtimes)+-- |A simple make function+smake :: [FilePath] -- ^ destination files+ -> [FilePath] -- ^ dependency files+ -> CYIO a -- ^ action to perform if depedency files are newer+ -> CYIO a -- ^ action to perform if destination files are newer+ -> CYIO a+smake dests deps actOutdated actUpToDate = do+ destTimes <- catMaybes `liftM` mapM (liftIO . getModuleModTime) dests+ depTimes <- mapM (cancelMissing getModuleModTime) deps+ make destTimes depTimes+ where+ make destTimes depTimes+ | length destTimes < length dests = actOutdated+ | outOfDate destTimes depTimes = actOutdated+ | otherwise = actUpToDate ----------------------------------------------------------------------------------- Error handling+ outOfDate tgtimes dptimes = or [ tg < dp | tg <- tgtimes, dp <- dptimes] --- Prints an error message on 'stderr'-putErrLn :: String -> IO ()-putErrLn = hPutStrLn stderr+cancelMissing :: (FilePath -> IO (Maybe a)) -> FilePath -> CYIO a+cancelMissing act f = liftIO (act f) >>= \res -> case res of+ Nothing -> failMessages [errModificationTime f]+ Just val -> ok val --- Prints a list of error messages on 'stderr'-putErrsLn :: [String] -> IO ()-putErrsLn = mapM_ putErrLn+errUnknownOptions :: SpanInfo -> [String] -> Message+errUnknownOptions spi errs = spanInfoMessage spi $+ text "Unknown flag(s) in {-# OPTIONS_FRONTEND #-} pragma:"+ <+> sep (punctuate comma $ map text errs) --- Prints a list of error messages on 'stderr' and aborts the program-abortWith :: [String] -> IO a-abortWith errs = putErrsLn errs >> exitWith (ExitFailure 1)+errIllegalOption :: SpanInfo -> String -> Message+errIllegalOption spi err = spanInfoMessage spi $+ text "Illegal option in {-# OPTIONS_FRONTEND #-} pragma:" <+> text err +errMissing :: String -> String -> Message+errMissing what which = message $ sep $ map text+ [ "Missing", what, quote which ] --- Error messages+errUnrecognized :: String -> Message+errUnrecognized f = message $ sep $ map text+ [ "Unrecognized input", quote f ] -missingModule :: FilePath -> String-missingModule file = "Error: missing module \"" ++ file ++ "\""+errModificationTime :: FilePath -> Message+errModificationTime f = message $ sep $ map text+ [ "Could not inspect modification time of file", quote f ] ----------------------------------------------------------------------------------------------------------------------------------------------------------------+quote :: String -> String+quote s = "\"" ++ s ++ "\""
− src/CurryCompilerOpts.hs
@@ -1,166 +0,0 @@--- -------------------------------------------------------------------------------- |--- CurryCompilerOpts - Defines data structures containing options for--- compiling Curry programs (see module "CurryCompiler")------ September 2005,--- Martin Engelke (men@informatik.uni-kiel.de)--- March 2007, extensions by Sebastian Fischer (sebf@informatik.uni-kiel.de)------ -------------------------------------------------------------------------------module CurryCompilerOpts where--import System.Console.GetOpt----- | Data type for recording compiler options-data Options- = Options- { force :: Bool -- ^ force compilation- , html :: Bool -- ^ generate Html code- , importPaths :: [FilePath] -- ^ directories for searching imports- , output :: Maybe FilePath -- ^ name of output file- , noInterface :: Bool -- ^ do not create an interface file- , noVerb :: Bool -- ^ verbosity on/off- , noWarn :: Bool -- ^ warnings on/off- , noOverlapWarn :: Bool -- ^ "overlap" warnings on/off- , flat :: Bool -- ^ generate FlatCurry code- , extendedFlat :: Bool -- ^ generate FlatCurry code with extensions- , flatXml :: Bool -- ^ generate flat XML code- , abstract :: Bool -- ^ generate typed AbstracCurry code- , untypedAbstract :: Bool -- ^ generate untyped AbstractCurry code- , parseOnly :: Bool -- ^ generate source representation- , withExtensions :: Bool -- ^ enable extended functionalities- , dump :: [Dump] -- ^ dumps- , writeToSubdir :: Bool -- ^ should the output be written to the subdir?- } deriving Show----- | Default compiler options-defaultOpts = Options- { force = False- , html = False- , importPaths = []- , output = Nothing- , noInterface = False- , noVerb = False- , noWarn = False- , noOverlapWarn = False- , extendedFlat = False- , flat = False- , flatXml = False- , abstract = False- , untypedAbstract = False- , parseOnly = False- , withExtensions = False- , dump = []- , writeToSubdir = True- }----- | Data type for representing all available options (needed to read and parse--- the options from the command line; see module 'GetOpt')-data Option- = Help | Force | Html- | ImportPath FilePath | Output FilePath- | NoInterface | NoVerb | NoWarn | NoOverlapWarn- | FlatXML | Flat | ExtFlat | Abstract | UntypedAbstract | ParseOnly- | WithExtensions- | Dump [Dump]- | WriteToSubdir- deriving Eq----- | All available compiler options-options =- [ Option "f" ["force"] (NoArg Force)- "force compilation of dependent files"- , Option "" ["html"] (NoArg Html)- "generate html code"- , Option "i" ["import-dir"] (ReqArg ImportPath "DIR")- "search for imports in DIR"- , Option "o" ["output"] (ReqArg Output "FILE")- "write code to FILE"- , Option "" ["no-intf"] (NoArg NoInterface)- "do not create an interface file"- , Option "" ["no-verb"] (NoArg NoVerb)- "do not print compiler messages"- , Option "" ["no-warn"] (NoArg NoWarn)- "do not print warnings"- , Option "" ["no-overlap-warn"] (NoArg NoOverlapWarn)- "do not print warnings for overlapping rules"- , Option "" ["flat"] (NoArg Flat)- "generate FlatCurry code"- , Option "" ["extended-flat"] (NoArg ExtFlat)- "generate FlatCurry code with source references"- , Option "" ["xml"] (NoArg FlatXML)- "generate flat xml code"- , Option "" ["acy"] (NoArg Abstract)- "generate (type infered) AbstractCurry code"- , Option "" ["uacy"] (NoArg UntypedAbstract)- "generate untyped AbstractCurry code"- , Option "" ["parse-only"] (NoArg ParseOnly)- "generate source representation"- , Option "e" ["extended"] (NoArg WithExtensions)- "enable extended Curry functionalities"- , Option "" ["dump-all"] (NoArg (Dump [minBound..maxBound]))- "dump everything"- , Option "" ["dump-renamed"] (NoArg (Dump [DumpRenamed]))- "dump source code after renaming"- , Option "" ["dump-types"] (NoArg (Dump [DumpTypes]))- "dump types after type-checking"- , Option "" ["dump-desugared"] (NoArg (Dump [DumpDesugared]))- "dump source code after desugaring"- , Option "" ["dump-simplified"] (NoArg (Dump [DumpSimplified]))- "dump source code after simplification"- , Option "" ["dump-lifted"] (NoArg (Dump [DumpLifted]))- "dump source code after lambda-lifting"- , Option "" ["dump-il"] (NoArg (Dump [DumpIL]))- "dump intermediate language before lifting"- , Option "" ["dump-case"] (NoArg (Dump [DumpCase]))- "dump intermediate language after case simplification"- , Option "?h" ["help"] (NoArg Help)- "display this help and exit"- , Option "" ["no-hidden-subdir"] (NoArg WriteToSubdir)- "write all output to hidden .curry subdirectory"- ]----- | Marks an 'Option' as selected in the 'Options' record-selectOption :: Option -> Options -> Options-selectOption Force opts = opts { force = True }-selectOption (ImportPath dir) opts- = opts { importPaths = dir:(importPaths opts) }-selectOption (Output file) opts = opts { output = Just file }-selectOption NoInterface opts = opts { noInterface = True }-selectOption NoVerb opts = opts { noVerb = True }-selectOption NoWarn opts = opts { noWarn = True }-selectOption NoOverlapWarn opts = opts { noOverlapWarn = True }-selectOption Flat opts = opts { flat = True }-selectOption ExtFlat opts = opts { extendedFlat = True }-selectOption Html opts = opts { html = True }-selectOption FlatXML opts = opts { flatXml = True }-selectOption Abstract opts = opts { abstract = True }-selectOption UntypedAbstract opts = opts { untypedAbstract = True }-selectOption ParseOnly opts = opts { parseOnly = True }-selectOption WithExtensions opts = opts { withExtensions = True }-selectOption (Dump ds) opts = opts { dump = ds ++ dump opts }-selectOption WriteToSubdir opts = opts { writeToSubdir = False }----- | Data type for representing code dumps--- TODO: dump FlatCurry code, dump AbstractCurry code, dump after 'case'--- expansion-data Dump- = DumpRenamed -- ^ dump source after renaming- | DumpTypes -- ^ dump types after typechecking- | DumpDesugared -- ^ dump source after desugaring- | DumpSimplified -- ^ dump source after simplification- | DumpLifted -- ^ dump source after lambda-lifting- | DumpIL -- ^ dump IL code after translation- | DumpCase -- ^ dump IL code after case elimination- deriving (Eq,Bounded,Enum,Show)-----------------------------------------------------------------------------------------------------------------------------------------------------------------
+ src/CurryDeps.hs view
@@ -0,0 +1,191 @@+{- |+ Module : $Header$+ Description : Computation of module dependencies+ Copyright : (c) 2002 - 2004 Wolfgang Lux+ 2005 Martin Engelke+ 2007 Sebastian Fischer+ 2011 - 2013 Björn Peemöller+ 2016 - 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module implements the functions to compute the dependency+ information between Curry modules. This is used to create Makefile+ dependencies and to update programs composed of multiple modules.+-}+{-# LANGUAGE CPP #-}+module CurryDeps+ ( Source (..), flatDeps, deps, flattenDeps, sourceDeps, moduleDeps ) where++#if __GLASGOW_HASKELL__ >= 804+import Prelude hiding ((<>))+#endif++import Control.Monad (foldM)+import Data.List (isSuffixOf, nub)+import qualified Data.Map as Map (Map, empty, insert, lookup, toList)++import Curry.Base.Ident+import Curry.Base.Monad+import Curry.Base.Pretty+import Curry.Files.Filenames+import Curry.Files.PathUtils+import Curry.Syntax+ ( Module (..), ModulePragma (..), ImportDecl (..), parseHeader, parsePragmas+ , patchModuleId, hasLanguageExtension)++import Base.Messages+import Base.SCC (scc)+import CompilerOpts (Options (..), CppOpts (..), KnownExtension (..))+import CondCompile (condCompile)++-- |Different types of source files+data Source+ -- | A source file with pragmas and module imports+ = Source FilePath [ModulePragma] [ModuleIdent]+ -- | An interface file+ | Interface FilePath+ -- | An unknown file+ | Unknown+ deriving (Eq, Show)++type SourceEnv = Map.Map ModuleIdent Source++-- |Retrieve the dependencies of a source file in topological order+-- and possible errors during flattering+flatDeps :: Options -> FilePath -> CYIO [(ModuleIdent, Source)]+flatDeps opts fn = do+ sEnv <- deps opts Map.empty fn+ case flattenDeps sEnv of+ (env, [] ) -> ok env+ (_ , errs) -> failMessages errs++-- |Retrieve the dependencies of a source file as a 'SourceEnv'+deps :: Options -> SourceEnv -> FilePath -> CYIO SourceEnv+deps opts sEnv fn+ | ext == icurryExt = return sEnv+ | ext `elem` sourceExts = sourceDeps opts sEnv fn+ | otherwise = targetDeps opts sEnv fn+ where ext = takeExtension fn++-- The following functions are used to lookup files related to a given+-- module. Source files for targets are looked up in the current+-- directory only. Two different search paths are used to look up+-- imported modules, the first is used to find source modules, whereas+-- the library path is used only for finding matching interface files. As+-- the compiler does not distinguish these paths, we actually check for+-- interface files in the source paths as well.++-- In order to compute the dependency graph, source files for each module+-- need to be looked up. When a source module is found, its header is+-- parsed in order to determine the modules that it imports, and+-- dependencies for these modules are computed recursively. The prelude+-- is added implicitly to the list of imported modules except for the+-- prelude itself.++-- |Retrieve the dependencies of a given target file+targetDeps :: Options -> SourceEnv -> FilePath -> CYIO SourceEnv+targetDeps opts sEnv fn = do+ mFile <- liftIO $ lookupFile [""] sourceExts fn+ case mFile of+ Nothing -> return $ Map.insert (mkMIdent [fn]) Unknown sEnv+ Just file -> sourceDeps opts sEnv file++-- |Retrieve the dependencies of a given source file+sourceDeps :: Options -> SourceEnv -> FilePath -> CYIO SourceEnv+sourceDeps opts sEnv fn = readHeader opts fn >>= moduleDeps opts sEnv fn++-- |Retrieve the dependencies of a given module+moduleDeps :: Options -> SourceEnv -> FilePath -> Module a -> CYIO SourceEnv+moduleDeps opts sEnv fn mdl@(Module _ _ ps m _ _ _) = case Map.lookup m sEnv of+ Just _ -> return sEnv+ Nothing -> do+ let imps = imports opts mdl+ sEnv' = Map.insert m (Source fn ps imps) sEnv+ foldM (moduleIdentDeps opts) sEnv' imps++-- |Retrieve the imported modules and add the import of the Prelude+-- according to the compiler options.+imports :: Options -> Module a -> [ModuleIdent]+imports opts mdl@(Module _ _ _ m _ is _) = nub $+ [preludeMIdent | m /= preludeMIdent && not noImplicitPrelude]+ ++ [m' | ImportDecl _ m' _ _ _ <- is]+ where noImplicitPrelude = NoImplicitPrelude `elem` optExtensions opts+ || mdl `hasLanguageExtension` NoImplicitPrelude++-- |Retrieve the dependencies for a given 'ModuleIdent'+moduleIdentDeps :: Options -> SourceEnv -> ModuleIdent -> CYIO SourceEnv+moduleIdentDeps opts sEnv m = case Map.lookup m sEnv of+ Just _ -> return sEnv+ Nothing -> do+ mFile <- liftIO $ lookupCurryModule ("." : optImportPaths opts)+ (optLibraryPaths opts) m+ case mFile of+ Nothing -> return $ Map.insert m Unknown sEnv+ Just fn+ | icurryExt `isSuffixOf` fn ->+ return $ Map.insert m (Interface fn) sEnv+ | otherwise -> do+ hdr@(Module _ _ _ m' _ _ _) <- readHeader opts fn+ if m == m' then moduleDeps opts sEnv fn hdr+ else failMessages [errWrongModule m m']++readHeader :: Options -> FilePath -> CYIO (Module ())+readHeader opts fn = do+ mbFile <- liftIO $ readModule fn+ case mbFile of+ Nothing -> failMessages [errMissingFile fn]+ Just src -> do+ prgs <- liftCYM $ parsePragmas fn src+ let cppOpts = optCppOpts opts+ cppOpts' =+ cppOpts { cppRun = cppRun cppOpts || hasLanguageExtension prgs CPP }+ condC <- condCompile cppOpts' fn src+ hdr <- liftCYM $ parseHeader fn condC+ return $ patchModuleId fn hdr++-- If we want to compile the program instead of generating Makefile+-- dependencies, the environment has to be sorted topologically. Note+-- that the dependency graph should not contain any cycles.+flattenDeps :: SourceEnv -> ([(ModuleIdent, Source)], [Message])+flattenDeps = fdeps . sortDeps+ where+ sortDeps :: SourceEnv -> [[(ModuleIdent, Source)]]+ sortDeps = scc idents imported . Map.toList++ idents (m, _) = [m]++ imported (_, Source _ _ ms) = ms+ imported (_, _) = []++ fdeps :: [[(ModuleIdent, Source)]] -> ([(ModuleIdent, Source)], [Message])+ fdeps = foldr checkdep ([], [])++ checkdep [] (srcs, errs) = (srcs , errs )+ checkdep [src] (srcs, errs) = (src : srcs, errs )+ checkdep dep (srcs, errs) = (srcs , err : errs)+ where err = errCyclicImport $ map fst dep++errMissingFile :: FilePath -> Message+errMissingFile fn = message $ sep $ map text [ "Missing file:", fn ]++errWrongModule :: ModuleIdent -> ModuleIdent -> Message+errWrongModule m m' = message $ sep $+ [ text "Expected module for", text (moduleName m) <> comma+ , text "but found", text (moduleName m') ]++errCyclicImport :: [ModuleIdent] -> Message+errCyclicImport [] = internalError "CurryDeps.errCyclicImport: empty list"+errCyclicImport [m] = message $ sep $ map text+ [ "Recursive import for module", moduleName m ]+errCyclicImport ms = message $ sep $+ text "Cyclic import dependency between modules" : punctuate comma inits+ ++ [text "and", lastm]+ where+ (inits, lastm) = splitLast $ map (text . moduleName) ms+ splitLast [] = internalError "CurryDeps.splitLast: empty list"+ splitLast (x : []) = ([] , x)+ splitLast (x : xs) = (x : ys, y) where (ys, y) = splitLast xs
− src/CurryDeps.lhs
@@ -1,144 +0,0 @@--% $Id: CurryDeps.lhs,v 1.14 2004/02/09 17:10:05 wlux Exp $-%-% Copyright (c) 2002-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-% Extended by Sebastian Fischer (sebf@informatik.uni-kiel.de)-\nwfilename{CurryDeps.lhs}-\section{Building Programs}-This module implements the functions to compute the dependency-information between Curry modules. This is used to create Makefile-dependencies and to update programs composed of multiple modules.-\begin{verbatim}--> module CurryDeps(Source(..),-> deps, flattenDeps, sourceDeps, moduleDeps-> ) where--> import Data.List-> import qualified Data.Map as Map-> import Data.Maybe-> import Control.Monad--> import Curry.Base.Ident-> import Curry.Base.MessageMonad--> import Curry.Files.Filenames-> import Curry.Files.PathUtils--> import Curry.Syntax hiding(Interface(..))--> import SCC---> data Source = Source FilePath [ModuleIdent]-> | Interface FilePath-> | Unknown-> deriving (Eq,Ord,Show)-> type SourceEnv = Map.Map ModuleIdent Source--> deps :: [FilePath] -> [FilePath] -> SourceEnv -> FilePath -> IO SourceEnv-> deps paths libraryPaths mEnv fn-> | e `elem` sourceExts = sourceDeps paths libraryPaths (mkMIdent [r]) mEnv fn-> | e == icurryExt = return Map.empty-> | e `elem` objectExts = targetDeps paths libraryPaths mEnv r-> | otherwise = targetDeps paths libraryPaths mEnv fn-> where r = dropExtension fn-> e = takeExtension fn--> targetDeps :: [FilePath] -> [FilePath] -> SourceEnv -> FilePath-> -> IO SourceEnv-> targetDeps paths libraryPaths mEnv fn =-> lookupFile [""] sourceExts fn >>=-> maybe (return (Map.insert m Unknown mEnv)) (sourceDeps paths libraryPaths m mEnv)-> where m = mkMIdent [fn]--\end{verbatim}-The following functions are used to lookup files related to a given-module. Source files for targets are looked up in the current-directory only. Two different search paths are used to look up-imported modules, the first is used to find source modules, whereas-the library path is used only for finding matching interface files. As-the compiler does not distinguish these paths, we actually check for-interface files in the source paths as well.--Note that the functions \texttt{buildScript} and \texttt{makeDepend}-already remove all directories that are included in the both search-paths from the library paths in order to avoid scanning such-directories more than twice.-\begin{verbatim}--\end{verbatim}-In order to compute the dependency graph, source files for each module-need to be looked up. When a source module is found, its header is-parsed in order to determine the modules that it imports, and-dependencies for these modules are computed recursively. The prelude-is added implicitly to the list of imported modules except for the-prelude itself. Any errors reported by the parser are ignored.-\begin{verbatim}--> moduleDeps :: [FilePath] -> [FilePath] -> SourceEnv -> ModuleIdent-> -> IO SourceEnv-> moduleDeps paths libraryPaths mEnv m =-> case Map.lookup m mEnv of-> Just _ -> return mEnv-> Nothing ->-> do-> mbFn <- lookupModule paths libraryPaths m-> case mbFn of-> Just fn-> | icurryExt `isSuffixOf` fn ->-> return (Map.insert m (Interface fn) mEnv)-> | otherwise -> sourceDeps paths libraryPaths m mEnv fn-> Nothing -> return (Map.insert m Unknown mEnv)--> sourceDeps :: [FilePath] -> [FilePath] -> ModuleIdent -> SourceEnv-> -> FilePath -> IO SourceEnv-> sourceDeps paths libraryPaths m mEnv fn =-> do-> s <- readModule fn-> case fst $ runMsg $ parseHeader fn s of-> Right (Module m' _ ds) ->-> let ms = imports m' ds in-> foldM (moduleDeps paths libraryPaths) (Map.insert m (Source fn ms) mEnv) ms-> Left _ -> return (Map.insert m (Source fn []) mEnv)--> imports :: ModuleIdent -> [Decl] -> [ModuleIdent]-> imports m ds = nub $-> [preludeMIdent | m /= preludeMIdent] ++ [m | ImportDecl _ m _ _ _ <- ds]----If we want to compile the program instead of generating Makefile-dependencies the environment has to be sorted topologically. Note-that the dependency graph should not contain any cycles.--> flattenDeps :: SourceEnv -> ([(ModuleIdent,Source)],[String])-> flattenDeps = fdeps . sortDeps-> where-> sortDeps :: SourceEnv -> [[(ModuleIdent,Source)]]-> sortDeps = scc modules imports . Map.toList->-> modules (m, _) = [m]->-> imports (_,Source _ ms) = ms-> imports (_,Interface _) = []-> imports (_,Unknown) = []->-> fdeps :: [[(ModuleIdent,Source)]] -> ([(ModuleIdent,Source)],[String])-> fdeps = foldr checkdep ([], [])-> -> checkdep [] (ms', es') = (ms',es')-> checkdep [m] (ms', es') = (m:ms',es')-> checkdep dep (ms', es') = (ms',cyclicError (map fst dep) : es')->-> cyclicError :: [ModuleIdent] -> String-> cyclicError (m:ms) =-> "Cylic import dependency between modules " ++ show m ++ rest ms->-> rest [m] = " and " ++ show m-> rest ms = rest' ms-> rest' [m] = ", and " ++ show m-> rest' (m:ms) = ", " ++ show m ++ rest' ms
− src/CurryEnv.hs
@@ -1,181 +0,0 @@---------------------------------------------------------------------------------------------------------------------------------------------------------------------- CurryEnv - Generates a record containing extracted and prepared data--- from a CurrySyntax module------ November 2005,--- Martin Engelke (men@informatik.uni-kiel.de)----module CurryEnv (CurryEnv(..), curryEnv) where--import Data.Maybe--import Curry.Base.Position-import Curry.Base.Ident--import Curry.Syntax--import Types-import Base------------------------------------------------------------------------------------- A record containing the following data for a module 'm':------ moduleId - the name of 'm'--- exports - the export list extracted from 'm'--- interface - all exported declarations in 'm' (including exported --- imports)--- infixDecls - interfaces of all infix declarations in 'm'--- typeSynonym - interfaces of all type synonyms in 'm'----data CurryEnv = CurryEnv{ moduleId :: ModuleIdent,- exports :: [Export],- imports :: [IDecl],- interface :: [IDecl],- infixDecls :: [IDecl],- typeSynonyms :: [IDecl]- } deriving Show- ------------------------------------------------------------------------------------- Returns a Curry environment for the module 'mod' and its corresponding--- environments 'mEnv' (imported modules), 'tcEnv' (table of type--- constructors) and 'intf' (the interface of 'mod')-curryEnv :: ModuleEnv -> TCEnv -> Interface -> Module -> CurryEnv-curryEnv mEnv tcEnv (Interface iid idecls) mod@(Module mid mExp decls)- | iid == mid- = CurryEnv{ moduleId = mid,- exports = maybe [] (\ (Exporting _ exps) -> exps) mExp,- imports = genImportIntf decls,- interface = idecls,- infixDecls = genInfixDecls mod,- typeSynonyms = genTypeSyns tcEnv mod- }- | otherwise- = internalError ("CurryEnv: interface \"" ++ show iid - ++ "\" does not match module \"" ++ show mid ++ "\"")---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Generate interfaces for import declarations-genImportIntf :: [Decl] -> [IDecl]-genImportIntf decls = reverse (map snd (foldl genImpIntf [] decls))-----genImpIntf imps (ImportDecl pos mid _ _ _)- = maybe ((mid, IImportDecl pos mid):imps) (const imps) (lookup mid imps)-genImpIntf imps _ = imps-------------------------------------------------------------------------------------- Generate interface declaration for all infix declarations in the module-genInfixDecls :: Module -> [IDecl]-genInfixDecls (Module mident _ decls) = collectIInfixDecls mident decls-----collectIInfixDecls :: ModuleIdent -> [Decl] -> [IDecl]-collectIInfixDecls mident [] = []-collectIInfixDecls mident ((InfixDecl pos infixspec prec idents):decls)- = (map (\ident - -> IInfixDecl pos infixspec prec (qualifyWith mident ident)) - idents)- ++ (collectIInfixDecls mident decls)-collectIInfixDecls mident (_:decls) = collectIInfixDecls mident decls-------------------------------------------------------------------------------------- Generate interface declarations for all type synonyms in the module.-genTypeSyns :: TCEnv -> Module -> [IDecl]-genTypeSyns tcEnv (Module mident _ decls)- = concatMap (genTypeSynDecl mident tcEnv) (filter isTypeSyn decls)-----genTypeSynDecl :: ModuleIdent -> TCEnv -> Decl -> [IDecl]-genTypeSynDecl mid tcEnv (TypeDecl pos ident params texpr)- = [genTypeDecl pos mid ident params tcEnv texpr]-genTypeSynDecl _ _ _ - = []-----genTypeDecl :: Position -> ModuleIdent -> Ident -> [Ident] -> TCEnv- -> TypeExpr -> IDecl-genTypeDecl pos mid ident params tcEnv texpr- = ITypeDecl pos (qualifyWith mid ident) params- (modifyTypeExpr tcEnv texpr)------modifyTypeExpr :: TCEnv -> TypeExpr -> TypeExpr-modifyTypeExpr tcEnv (ConstructorType qident typeexprs)- = case (qualLookupTC qident tcEnv) of- [AliasType _ arity rhstype]- -> modifyTypeExpr tcEnv - (genTypeSynDeref (zip [0 .. (arity-1)] typeexprs)- rhstype)- _ -> ConstructorType (fromMaybe qident (lookupTCId qident tcEnv))- (map (modifyTypeExpr tcEnv) typeexprs)-modifyTypeExpr _ (VariableType ident)- = VariableType ident-modifyTypeExpr tcEnv (ArrowType type1 type2)- = ArrowType (modifyTypeExpr tcEnv type1) (modifyTypeExpr tcEnv type2)-modifyTypeExpr tcEnv (TupleType typeexprs)- | null typeexprs - = ConstructorType qUnitId []- | otherwise- = ConstructorType (qTupleId (length typeexprs)) - (map (modifyTypeExpr tcEnv) typeexprs)-modifyTypeExpr tcEnv (ListType typeexpr)- = ConstructorType (qualify listId) [(modifyTypeExpr tcEnv typeexpr)]-modifyTypeExpr tcEnv (RecordType fields rtype)- = RecordType (map (\ (labs, texpr) -> (labs, (modifyTypeExpr tcEnv texpr)))- fields)- (maybe Nothing (Just . modifyTypeExpr tcEnv) rtype)-----genTypeSynDeref :: [(Int,TypeExpr)] -> Type -> TypeExpr-genTypeSynDeref its (TypeConstructor qident typeexprs)- = ConstructorType qident (map (genTypeSynDeref its) typeexprs)-genTypeSynDeref its (TypeVariable i)- = fromMaybe (internalError ("@CurryInfo.genTypeSynDeref: " ++- "unkown type var index"))- (lookup i its)-genTypeSynDeref its (TypeConstrained typeexprs i)- = internalError ("@CurryInfo.genTypeSynDeref: " ++- "illegal constrained type occured")-genTypeSynDeref its (TypeArrow type1 type2)- = ArrowType (genTypeSynDeref its type1) (genTypeSynDeref its type2)-genTypeSynDeref its (TypeSkolem i)- = internalError ("@CurryInfo.genTypeSynDeref: " ++- "illegal skolem type occured")-genTypeSynDeref its (TypeRecord fields ri)- = RecordType (map (\ (lab, texpr) -> ([lab], genTypeSynDeref its texpr))- fields)- (maybe Nothing - (\i -> Just (genTypeSynDeref its (TypeVariable i)))- ri)-----lookupTCId :: QualIdent -> TCEnv -> Maybe QualIdent-lookupTCId qident tcEnv- = case (qualLookupTC qident tcEnv) of- [DataType qident' _ _] -> Just qident'- [RenamingType qident' _ _] -> Just qident'- [AliasType qident' _ _] -> Just qident'- _ -> Nothing----isTypeSyn :: Decl -> Bool-isTypeSyn (TypeDecl _ _ _ texpr)- = case texpr of- RecordType _ _ -> False- _ -> True-isTypeSyn _ = False
− src/CurryHtml.hs
@@ -1,190 +0,0 @@-module CurryHtml(source2html) where--import Data.Char hiding(Space)-import Control.Exception--import Curry.Base.Ident-import Curry.Base.MessageMonad--import Curry.Files.PathUtils (readModule, writeModule, getCurryPath)--import SyntaxColoring-import Curry.Syntax.Frontend as Frontend------- translate source file into HTML file with syntaxcoloring---- @param outputfilename---- @param sourcefilename-source2html :: [String] -> String -> String -> IO ()-source2html imports outputfilename sourcefilename = do- let sourceprogname = removeExtension sourcefilename- output = if null outputfilename - then sourceprogname ++ "_curry.html"- else outputfilename - modulname = fileName sourceprogname- fullfname <- getCurryPath imports sourcefilename- program <- filename2program imports (maybe sourcefilename id fullfname)- (if null outputfilename then writeModule True output - else writeFile output)- (program2html modulname program)- ---- @param importpaths---- @param filename ---- @return program-filename2program :: [String] -> String -> IO Program-filename2program paths filename- = do cont <- readModule filename- typingParseResult <- (catchError (typingParse paths filename cont))- fullParseResult <- (catchError (fullParse paths filename cont))- parseResult <- (catchError (return (parse filename cont)))- lexResult <- (catchError (return (Frontend.lex filename cont)))- return (genProgram cont (typingParseResult : fullParseResult : [parseResult]) lexResult)------ this function intercepts errors and converts it to Messages ---- @param a show-function for (Result a) ---- @param a function that generates a (Result a)---- @return (Result a) without runtimeerrors ---- FIXME This is ugly. Avoid exceptions and report failure via MsgMonad instead! (hsi)-catchError :: Show a =>IO (MsgMonad a) -> IO (MsgMonad a)-catchError toDo = Control.Exception.catch (toDo >>= returnNF) handler - where - -- This refers to base3- handler (ErrorCall str) = return (failWith str)- handler e = return (failWith (show e)) - - returnNF a = normalform a `seq` return a- normalform = length . show . runMsg- - ----- generates htmlcode with syntax highlighting ---- @param modulname---- @param a program---- @return HTMLcode-program2html :: String ->Program -> String-program2html modulname codes =- "<html>\n<head>\n<title>Module "++ - modulname++- "</title>\n" ++- "<link rel=\"stylesheet\" type=\"text/css\" href=\"currydoc.css\">"++- "</link>\n</head>\n<body style=\"font-family:'Courier New', Arial;\">\n<pre>\n" ++- concat (map (code2html True . (\(_,_,c) -> c)) codes) ++- "<pre>\n</body>\n</html>" - - ---- which code has which color ---- @param code---- @return color of the code -code2class :: Code -> String -code2class (Keyword _) = "keyword"-code2class (Space _)= ""-code2class NewLine = ""-code2class (ConstructorName ConstrPattern _) = "constructorname_constrpattern"-code2class (ConstructorName ConstrCall _) = "constructorname_constrcall"-code2class (ConstructorName ConstrDecla _) = "constructorname_constrdecla"-code2class (ConstructorName OtherConstrKind _) = "constructorname_otherconstrkind"-code2class (Function InfixFunction _) = "function_infixfunction"-code2class (Function TypSig _) = "function_typsig"-code2class (Function FunDecl _) = "function_fundecl"-code2class (Function FunctionCall _) = "function_functioncall"-code2class (Function OtherFunctionKind _) = "function_otherfunctionkind"-code2class (ModuleName _) = "modulename"-code2class (Commentary _) = "commentary"-code2class (NumberCode _) = "numbercode"-code2class (StringCode _) = "stringcode"-code2class (CharCode _) = "charcode"-code2class (Symbol _) = "symbol"-code2class (Identifier IdDecl _) = "identifier_iddecl"-code2class (Identifier IdOccur _) = "identifier_idoccur"-code2class (Identifier UnknownId _) = "identifier_unknownid"-code2class (TypeConstructor TypeDecla _) = "typeconstructor_typedecla"-code2class (TypeConstructor TypeUse _) = "typeconstructor_typeuse"-code2class (TypeConstructor TypeExport _) = "typeconstructor_typeexport"-code2class (CodeWarning _ _) = "codewarning"-code2class (NotParsed _) = "notparsed"---code2html :: Bool -> Code -> String -code2html ownClass code@(CodeWarning _ c) =- (if ownClass then spanTag (code2class code) else id)- (code2html False c) -code2html ownClass code@(Commentary _) =- (if ownClass then spanTag (code2class code) else id)- (replace '<' "<span><</span>" (code2string code)) -code2html ownClass c- | isCall c && ownClass = maybe tag (addHtmlLink tag) (getQualIdent c) - | isDecl c && ownClass= maybe tag (addHtmlAnchor tag) (getQualIdent c)- | otherwise = tag- where tag = (if ownClass then spanTag (code2class c) else id)- (htmlQuote (code2string c)) - -spanTag :: String -> String -> String-spanTag [] str = str-spanTag cl str = "<span class=\""++ cl ++ "\">" ++ str ++ "</span>"--replace :: Char -> String -> String -> String-replace old new = foldr (\ x -> if x == old then (new ++) else ([x]++)) ""--addHtmlAnchor :: String -> QualIdent -> String-addHtmlAnchor html qualIdent = "<a name=\""++ string2urlencoded (show (unqualify qualIdent)) ++"\"></a>" ++ html--addHtmlLink :: String -> QualIdent -> String-addHtmlLink html qualIdent =- let (maybeModuleIdent,ident) = (qualidMod qualIdent, qualidId qualIdent) in- "<a href=\"" ++ - (maybe "" (\x -> show x ++ "_curry.html") maybeModuleIdent) ++ - "#"++ - string2urlencoded (show ident) ++- "\">"++ - html ++- "</a>"--isCall :: Code -> Bool-isCall (TypeConstructor TypeExport _) = True-isCall (TypeConstructor _ _) = False-isCall (Identifier _ _) = False-isCall code = not (isDecl code) &&- maybe False (const True) (getQualIdent code)-- -isDecl :: Code -> Bool-isDecl (ConstructorName ConstrDecla _) = True-isDecl (Function FunDecl _) = True-isDecl (TypeConstructor TypeDecla _) = True-isDecl _ = False ---fileName = reverse . takeWhile (/='/') . reverse --removeExtension = reverse . drop 1 . dropWhile (/='.') . reverse ------ Translates arbitrary strings into equivalent urlencoded string.-string2urlencoded :: String -> String-string2urlencoded = id-{--string2urlencoded [] = []-string2urlencoded (c:cs)- | isAlphaNum c = c : string2urlencoded cs- | c == ' ' = '+' : string2urlencoded cs- | otherwise = show (ord c) ++ (if null cs then "" else ".") ++ string2urlencoded cs--}--htmlQuote :: String -> String-htmlQuote [] = []-htmlQuote (c:cs) | c=='<' = "<" ++ htmlQuote cs- | c=='>' = ">" ++ htmlQuote cs- | c=='&' = "&" ++ htmlQuote cs- | c=='"' = """ ++ htmlQuote cs- | c=='\228' = "ä" ++ htmlQuote cs- | c=='\246' = "ö" ++ htmlQuote cs- | c=='\252' = "ü" ++ htmlQuote cs- | c=='\196' = "Ä" ++ htmlQuote cs- | c=='\214' = "Ö" ++ htmlQuote cs- | c=='\220' = "Ü" ++ htmlQuote cs- | c=='\223' = "ß"++ htmlQuote cs- | otherwise = c : htmlQuote cs-
− src/Desugar.lhs
@@ -1,843 +0,0 @@-% $Id: Desugar.lhs,v 1.42 2004/02/15 22:10:32 wlux Exp $-%-% Copyright (c) 2001-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{Desugar.lhs}-\section{Desugaring Curry Expressions}-The desugaring pass removes all syntactic sugar from the module. In-particular, the output of the desugarer will have the following-properties.-\begin{itemize}-\item All function definitions are $\eta$-expanded.\\- {\em Note:} Since this version is used as a frontend for PAKCS, the - $\eta$-expansion had been disabled.-\item No guarded right hand sides occur in equations, pattern- declarations, and case alternatives. In addition, the declaration- lists of the right hand sides are empty; local declarations are- transformed into let expressions.-\item Patterns in equations and case alternatives are composed only of- \begin{itemize}- \item literals,- \item variables,- \item constructor applications, and- \item as patterns.- \end{itemize}-\item Expressions are composed only of- \begin{itemize}- \item literals,- \item variables,- \item constructors,- \item (binary) applications,- \item let expressions, and- \item case expressions.- \end{itemize}-\item Applications $N\:x$ in patterns and expressions, where $N$ is a- newtype constructor, are replaced by a $x$. Note that neither the- newtype declaration itself nor partial applications of newtype- constructors are changed.\footnote{It were possible to replace- partial applications of newtype constructor by \texttt{prelude.id}.- However, our solution yields a more accurate output when the result- of a computation includes partial applications.}-\item Function patterns are replaced by variables and are integrated- in a guarded right hand side using the \texttt{=:<=} operator-\item Records, which currently must be declared using the keyword- \texttt{type}, are transformed into data types with one constructor.- Record construction and pattern matching are represented using the- record constructor. Selection and update are represented using selector- and update functions which are generated for each record declaration.- The record constructor must be entered into the type environment as well- as the selector functions and the update functions. -\end{itemize}--\ToDo{Use a different representation for the restricted code instead-of using the syntax tree from \texttt{CurrySyntax}.}--\textbf{As we are going to insert references to real prelude entities,-all names must be properly qualified before calling this module.}-\begin{verbatim}--> module Desugar(desugar) where--> import Data.Maybe-> import Control.Arrow(second)-> import Control.Monad.State as S-> import Data.List--> import Curry.Base.Position-> import Curry.Base.Ident-> import Curry.Syntax.Utils-> import Curry.Syntax--> import Types-> import Base-> import Typing-> import Utils----posE = undefined--\end{verbatim}-New identifiers may be introduced while desugaring pattern-declarations, case and $\lambda$-expressions, and list comprehensions.-As usual, we use a state monad transformer for generating unique-names. In addition, the state is also used for passing through the-type environment, which must be augmented with the types of these new-variables.-\begin{verbatim}--> type DesugarState a = S.StateT ValueEnv (S.State Int) a--> run :: DesugarState a -> ValueEnv -> a-> run m tyEnv = S.evalState (S.evalStateT m tyEnv) 1--\end{verbatim}-The desugaring phase keeps only the type, function, and value-declarations of the module. In the current version record declarations-are transformed into data types. The remaining type declarations are-not desugared and cannot occur in local declaration groups.-They are filtered out separately.--In order to use records within other modules, the export specification-of the module has to be extended with the selector and update functions of-all exported labels.--Actually, the transformation is slightly more general than necessary-as it allows value declarations at the top-level of a module.-\begin{verbatim}--> desugar :: ValueEnv -> TCEnv -> Module -> (Module,ValueEnv)-> desugar tyEnv tcEnv (Module m es ds) = (Module m es ds',tyEnv')-> where (ds',tyEnv') = run (desugarModule m tcEnv ds) tyEnv--> desugarModule :: ModuleIdent -> TCEnv -> [Decl] -> -> DesugarState ([Decl],ValueEnv)-> desugarModule m tcEnv ds = -> do-> dss <- mapM (desugarRecordDecl m tcEnv) ds-> let ds' = concat dss-> ds'' <- desugarDeclGroup m tcEnv ds'-> tyEnv' <- S.get-> return (filter isTypeDecl ds' ++ ds'', tyEnv')--\end{verbatim}---Within a declaration group, all type signatures and evaluation-annotations are discarded. First, the patterns occurring in the left-hand sides are desugared. Due to lazy patterns this may add further-declarations to the group that must be desugared as well.-\begin{verbatim}--> desugarDeclGroup :: ModuleIdent -> TCEnv -> [Decl] -> DesugarState [Decl]-> desugarDeclGroup m tcEnv ds =-> do-> dss' <- mapM (desugarDeclLhs m tcEnv) (filter isValueDecl ds)-> mapM (desugarDeclRhs m tcEnv) (concat dss')--> desugarDeclLhs :: ModuleIdent -> TCEnv -> Decl -> DesugarState [Decl]-> desugarDeclLhs m tcEnv (PatternDecl p t rhs) =-> do-> (ds',t') <- desugarTerm m tcEnv p [] t-> dss' <- mapM (desugarDeclLhs m tcEnv) ds'-> return (PatternDecl p t' rhs : concat dss')-> desugarDeclLhs m tcEnv (FlatExternalDecl p fs) =-> do-> tyEnv <- S.get-> return (map (externalDecl tyEnv p) fs)-> where externalDecl tyEnv p f =-> ExternalDecl p CallConvPrimitive (Just (name f)) f-> (fromType (typeOf tyEnv (Variable (qual f))))-> qual f-> | unRenameIdent f == f = qualifyWith m f-> | otherwise = qualify f-> desugarDeclLhs _ _ d = return [d]--\end{verbatim}-After desugaring its right hand side, each equation is $\eta$-expanded-by adding as many variables as necessary to the argument list and-applying the right hand side to those variables ({\em Note:} $\eta$-expansion-is disabled in the version for PAKCS).-Furthermore every occurrence of a record type within the type of a function-is simplified to the corresponding type constructor from the record-declaration. This is possible because currently records must not be empty-and a record label belongs to only one record declaration.-\begin{verbatim}--> desugarDeclRhs :: ModuleIdent -> TCEnv -> Decl -> DesugarState Decl-> desugarDeclRhs m tcEnv (FunctionDecl p f eqs) =-> do-> tyEnv <- S.get-> let ty = (flip typeOf (Variable (qual f))) tyEnv-> liftM (FunctionDecl p f) -> (mapM (desugarEquation m tcEnv (arrowArgs ty)) eqs)-> where qual f-> | unRenameIdent f == f = qualifyWith m f-> | otherwise = qualify f-> desugarDeclRhs _ tcEnv (ExternalDecl p cc ie f ty) =-> return (ExternalDecl p cc (ie `mplus` Just (name f)) f ty)-> desugarDeclRhs m tcEnv (PatternDecl p t rhs) =-> liftM (PatternDecl p t) (desugarRhs m tcEnv p rhs)-> desugarDeclRhs _ tcEnv (ExtraVariables p vs) = return (ExtraVariables p vs)--> desugarEquation :: ModuleIdent -> TCEnv -> [Type] -> Equation -> -> DesugarState Equation-> desugarEquation m tcEnv tys (Equation p lhs rhs) =-> do-> (ds',ts') <- mapAccumM (desugarTerm m tcEnv p) [] ts-> rhs' <- desugarRhs m tcEnv p (addDecls ds' rhs)-> (ts'', rhs'') <- desugarFunctionPatterns m p ts' rhs'-> return (Equation p (FunLhs f ts'') rhs'')-> where (f,ts) = flatLhs lhs---\end{verbatim}-The transformation of patterns is straight forward except for lazy-patterns. A lazy pattern \texttt{\~}$t$ is replaced by a fresh-variable $v$ and a new local declaration $t$~\texttt{=}~$v$ in the-scope of the pattern. In addition, as-patterns $v$\texttt{@}$t$ where-$t$ is a variable or an as-pattern are replaced by $t$ in combination-with a local declaration for $v$.-\begin{verbatim}--> desugarLiteral :: Literal -> DesugarState (Either Literal ([SrcRef],[Literal]))-> desugarLiteral (Char p c) = return (Left (Char p c))-> desugarLiteral (Int v i) = liftM (Left . fixType) S.get-> where -> fixType tyEnv-> | typeOf tyEnv v == floatType -> = Float (srcRefOf $ positionOfIdent v) (fromIntegral i)-> | otherwise = Int v i-> desugarLiteral (Float p f) = return (Left (Float p f))-> desugarLiteral (String (SrcRef [i]) cs) -> = return (Right (consRefs i cs,zipWith (Char . SrcRef . (:[])) [i,i+2..] cs))-> where consRefs r [] = [SrcRef [r]]-> consRefs r (_:xs) = let r'=r+2 in r' `seq` (SrcRef [r']:consRefs r' xs)-> desugarLiteral (String is _) = error $ "internal error desugarLiteral; "++-> "wrong source ref for string: " ++ show is--> desugarList :: [SrcRef] -> (SrcRef -> b -> b -> b) -> (SrcRef -> b) -> [b] -> b-> desugarList pos cons nil xs = snd (foldr cons' nil' xs)-> where rNil:rCs = reverse pos -> nil' = (rCs,nil rNil)-> cons' t (rC:rCs,ts) = (rCs,cons rC t ts)--> desugarTerm :: ModuleIdent -> TCEnv -> Position -> [Decl] -> ConstrTerm-> -> DesugarState ([Decl],ConstrTerm)-> desugarTerm m tcEnv p ds (LiteralPattern l) =-> desugarLiteral l >>=-> either (return . (,) ds . LiteralPattern)-> (\ (pos,ls) -> desugarTerm m tcEnv p ds $ ListPattern pos $ map LiteralPattern ls)-> desugarTerm m tcEnv p ds (NegativePattern _ l) =-> desugarTerm m tcEnv p ds (LiteralPattern (negateLiteral l))-> where negateLiteral (Int v i) = Int v (-i)-> negateLiteral (Float p f) = Float p (-f)-> negateLiteral _ = internalError "negateLiteral"-> desugarTerm _ _ _ ds (VariablePattern v) = return (ds,VariablePattern v)-> desugarTerm m tcEnv p ds (ConstructorPattern c [t]) =-> do-> tyEnv <- S.get-> liftM (if isNewtypeConstr tyEnv c then id else second (constrPat c))-> (desugarTerm m tcEnv p ds t)-> where constrPat c t = ConstructorPattern c [t]-> desugarTerm m tcEnv p ds (ConstructorPattern c ts) =-> liftM (second (ConstructorPattern c)) (mapAccumM (desugarTerm m tcEnv p) ds ts)-> desugarTerm m tcEnv p ds (InfixPattern t1 op t2) =-> desugarTerm m tcEnv p ds (ConstructorPattern op [t1,t2])-> desugarTerm m tcEnv p ds (ParenPattern t) = desugarTerm m tcEnv p ds t-> desugarTerm m tcEnv p ds (TuplePattern pos ts) =-> desugarTerm m tcEnv p ds (ConstructorPattern (tupleConstr ts) ts)-> where tupleConstr ts = addRef pos $ -> if null ts then qUnitId else qTupleId (length ts)-> desugarTerm m tcEnv p ds (ListPattern pos ts) =-> liftM (second (desugarList pos cons nil)) (mapAccumM (desugarTerm m tcEnv p) ds ts)-> where nil p' = ConstructorPattern (addRef p' qNilId) []-> cons p' t ts = ConstructorPattern (addRef p' qConsId) [t,ts]--> desugarTerm m tcEnv p ds (AsPattern v t) =-> liftM (desugarAs p v) (desugarTerm m tcEnv p ds t)-> desugarTerm m tcEnv p ds (LazyPattern pos t) = desugarLazy pos m p ds t-> desugarTerm m tcEnv p ds (FunctionPattern f ts) =-> liftM (second (FunctionPattern f)) (mapAccumM (desugarTerm m tcEnv p) ds ts)-> desugarTerm m tcEnv p ds (InfixFuncPattern t1 f t2) =-> desugarTerm m tcEnv p ds (FunctionPattern f [t1,t2])-> desugarTerm m tcEnv p ds (RecordPattern fs _)-> | null fs = internalError "desugarTerm: empty record"-> | otherwise =-> do tyEnv <- S.get -> case (lookupValue (fieldLabel (head fs)) tyEnv) of-> [Label _ r _] -> -> desugarRecordPattern m tcEnv p ds (map field2Tuple fs) r-> _ -> internalError "desugarTerm: no label"--> desugarAs :: Position -> Ident -> ([Decl],ConstrTerm) -> ([Decl],ConstrTerm)-> desugarAs p v (ds,t) =-> case t of-> VariablePattern v' -> (varDecl p v (mkVar v') : ds,t)-> AsPattern v' _ -> (varDecl p v (mkVar v') : ds,t)-> _ -> (ds,AsPattern v t)--> desugarLazy :: SrcRef -> ModuleIdent -> Position -> [Decl] -> ConstrTerm-> -> DesugarState ([Decl],ConstrTerm)-> desugarLazy pos m p ds t =-> case t of-> VariablePattern _ -> return (ds,t)-> ParenPattern t' -> desugarLazy pos m p ds t'-> AsPattern v t' -> liftM (desugarAs p v) (desugarLazy pos m p ds t')-> LazyPattern pos t' -> desugarLazy pos m p ds t'-> _ ->-> do-> v0 <- S.get >>= freshIdent m "_#lazy" . monoType . flip typeOf t-> let v' = addPositionIdent (AST pos) v0-> return (patDecl p{astRef=pos} t (mkVar v') : ds,VariablePattern v')---\end{verbatim}-A list of boolean guards is expanded into a nested if-then-else-expression, whereas a constraint guard is replaced by a case-expression. Note that if the guard type is \texttt{Success} only a-single guard is allowed for each equation.\footnote{This change was-introduced in version 0.8 of the Curry report.} We check for the-type \texttt{Bool} of the guard because the guard's type defaults to-\texttt{Success} if it is not restricted by the guard expression.-\begin{verbatim}--> desugarRhs :: ModuleIdent -> TCEnv -> Position -> Rhs -> DesugarState Rhs-> desugarRhs m tcEnv p rhs =-> do-> tyEnv <- S.get-> e' <- desugarExpr m tcEnv p (expandRhs tyEnv prelFailed rhs)-> return (SimpleRhs p e' [])--> expandRhs :: ValueEnv -> Expression -> Rhs -> Expression-> expandRhs tyEnv _ (SimpleRhs _ e ds) = Let ds e-> expandRhs tyEnv e0 (GuardedRhs es ds) = Let ds (expandGuards tyEnv e0 es)--> expandGuards :: ValueEnv -> Expression -> [CondExpr] -> Expression-> expandGuards tyEnv e0 es-> | booleanGuards tyEnv es = foldr mkIfThenElse e0 es-> | otherwise = mkCond es-> where mkIfThenElse (CondExpr p g e) = IfThenElse (srcRefOf p) g e-> mkCond [CondExpr p g e] = Apply (Apply prelCond g) e--> booleanGuards :: ValueEnv -> [CondExpr] -> Bool-> booleanGuards _ [] = False-> booleanGuards tyEnv (CondExpr _ g _ : es) =-> not (null es) || typeOf tyEnv g == boolType--> desugarExpr :: ModuleIdent -> TCEnv -> Position -> Expression-> -> DesugarState Expression-> desugarExpr m tcEnv p (Literal l) =-> desugarLiteral l >>=-> either (return . Literal) (\ (pos,ls) -> desugarExpr m tcEnv p $ List pos $ map Literal ls)-> desugarExpr _ _ _ (Variable v) = return (Variable v)-> desugarExpr _ _ _ (Constructor c) = return (Constructor c)-> desugarExpr m tcEnv p (Paren e) = desugarExpr m tcEnv p e-> desugarExpr m tcEnv p (Typed e _) = desugarExpr m tcEnv p e-> desugarExpr m tcEnv p (Tuple pos es) =-> liftM (apply (Constructor (tupleConstr es))) -> (mapM (desugarExpr m tcEnv p) es)-> where tupleConstr es = addRef pos $ if null es then qUnitId else qTupleId (length es)-> desugarExpr m tcEnv p (List pos es) =-> liftM (desugarList pos cons nil) (mapM (desugarExpr m tcEnv p) es)-> where nil p' = Constructor (addRef p' qNilId)-> cons p' = Apply . Apply (Constructor $ addRef p' qConsId)-> desugarExpr m tcEnv p (ListCompr pos e []) = desugarExpr m tcEnv p (List [pos,pos] [e])-> desugarExpr m tcEnv p (ListCompr r e (q:qs)) = -> desugarQual m tcEnv p q (ListCompr r e qs)-> desugarExpr m tcEnv p (EnumFrom e) = -> liftM (Apply prelEnumFrom) (desugarExpr m tcEnv p e)-> desugarExpr m tcEnv p (EnumFromThen e1 e2) =-> liftM (apply prelEnumFromThen) (mapM (desugarExpr m tcEnv p) [e1,e2])-> desugarExpr m tcEnv p (EnumFromTo e1 e2) =-> liftM (apply prelEnumFromTo) (mapM (desugarExpr m tcEnv p) [e1,e2])-> desugarExpr m tcEnv p (EnumFromThenTo e1 e2 e3) =-> liftM (apply prelEnumFromThenTo) (mapM (desugarExpr m tcEnv p) [e1,e2,e3])-> desugarExpr m tcEnv p (UnaryMinus op e) =-> do-> tyEnv <- S.get-> liftM (Apply (unaryMinus op (typeOf tyEnv e))) (desugarExpr m tcEnv p e)-> where unaryMinus op ty-> | op == minusId =-> if ty == floatType then prelNegateFloat else prelNegate-> | op == fminusId = prelNegateFloat-> | otherwise = internalError "unaryMinus"-> desugarExpr m tcEnv p (Apply (Constructor c) e) =-> do-> tyEnv <- S.get-> liftM (if isNewtypeConstr tyEnv c then id else (Apply (Constructor c)))-> (desugarExpr m tcEnv p e)-> desugarExpr m tcEnv p (Apply e1 e2) =-> do-> e1' <- desugarExpr m tcEnv p e1-> e2' <- desugarExpr m tcEnv p e2-> return (Apply e1' e2')-> desugarExpr m tcEnv p (InfixApply e1 op e2) =-> do-> op' <- desugarExpr m tcEnv p (infixOp op)-> e1' <- desugarExpr m tcEnv p e1-> e2' <- desugarExpr m tcEnv p e2-> return (Apply (Apply op' e1') e2')-> desugarExpr m tcEnv p (LeftSection e op) =-> do-> op' <- desugarExpr m tcEnv p (infixOp op)-> e' <- desugarExpr m tcEnv p e-> return (Apply op' e')-> desugarExpr m tcEnv p (RightSection op e) =-> do-> op' <- desugarExpr m tcEnv p (infixOp op)-> e' <- desugarExpr m tcEnv p e-> return (Apply (Apply prelFlip op') e')-> desugarExpr m tcEnv p exp@(Lambda r ts e) =-> do-> f <- S.get >>=-> freshIdent m "_#lambda" . polyType . flip typeOf exp-> desugarExpr m tcEnv p (Let [funDecl (AST r) f ts e] (mkVar f))-> desugarExpr m tcEnv p (Let ds e) =-> do-> ds' <- desugarDeclGroup m tcEnv ds-> e' <- desugarExpr m tcEnv p e-> return (if null ds' then e' else Let ds' e')-> desugarExpr m tcEnv p (Do sts e) = -> desugarExpr m tcEnv p (foldr desugarStmt e sts)-> where desugarStmt (StmtExpr r e) e' = apply (prelBind_ r) [e,e']-> desugarStmt (StmtBind r t e) e' = apply (prelBind r) [e,Lambda r [t] e']-> desugarStmt (StmtDecl ds) e' = Let ds e'-> desugarExpr m tcEnv p (IfThenElse r e1 e2 e3) =-> do-> e1' <- desugarExpr m tcEnv p e1-> e2' <- desugarExpr m tcEnv p e2-> e3' <- desugarExpr m tcEnv p e3-> return (Case r e1' [caseAlt p truePattern e2',caseAlt p falsePattern e3'])-> desugarExpr m tcEnv p (Case r e alts)-> | null alts = return prelFailed-> | otherwise =-> do-> e' <- desugarExpr m tcEnv p e-> v <- S.get >>= freshIdent m "_#case" . monoType . flip typeOf e-> alts' <- mapM (desugarAltLhs m tcEnv) alts-> tyEnv <- S.get-> alts'' <- mapM (desugarAltRhs m tcEnv)-> (map (expandAlt tyEnv v) (init (tails alts')))-> return (mkCase m v e' alts'')-> where mkCase m v e alts-> | v `elem` qfv m alts = Let [varDecl p v e] (Case r (mkVar v) alts)-> | otherwise = Case r e alts-> desugarExpr m tcEnv p (RecordConstr fs)-> | null fs = internalError "desugarExpr: empty record construction"-> | otherwise =-> do let l = fieldLabel (head fs)-> fs' = map field2Tuple fs-> tyEnv <- S.get-> case (lookupValue l tyEnv) of-> [Label l' r _] -> desugarRecordConstr m tcEnv p r fs'-> _ -> internalError "desugarExpr: illegal record construction"-> desugarExpr m tcEnv p (RecordSelection e l) =-> do tyEnv <- S.get-> case (lookupValue l tyEnv) of-> [Label _ r _] -> desugarRecordSelection m tcEnv p r l e-> _ -> internalError "desugarExpr: illegal record selection"-> desugarExpr m tcEnv p (RecordUpdate fs rexpr)-> | null fs = internalError "desugarExpr: empty record update"-> | otherwise =-> do let l = fieldLabel (head fs)-> fs' = map field2Tuple fs-> tyEnv <- S.get-> case (lookupValue l tyEnv) of-> [Label _ r _] -> desugarRecordUpdate m tcEnv p r rexpr fs'-> _ -> internalError "desugarExpr: illegal record update"--desugarExpr _ _ _ x = internalError $ "desugarExpr: unexpected expression " ++ show x--\end{verbatim}-If an alternative in a case expression has boolean guards and all of-these guards return \texttt{False}, the enclosing case expression does-not fail but continues to match the remaining alternatives against the-selector expression. In order to implement this semantics, which is-compatible with Haskell, we expand an alternative with boolean guards-such that it evaluates a case expression with the remaining cases that-are compatible with the matched pattern when the guards fail.-\begin{verbatim}--> desugarAltLhs :: ModuleIdent -> TCEnv -> Alt -> DesugarState Alt-> desugarAltLhs m tcEnv (Alt p t rhs) =-> do-> (ds',t') <- desugarTerm m tcEnv p [] t-> return (Alt p t' (addDecls ds' rhs))--> desugarAltRhs :: ModuleIdent -> TCEnv -> Alt -> DesugarState Alt-> desugarAltRhs m tcEnv (Alt p t rhs) = -> liftM (Alt p t) (desugarRhs m tcEnv p rhs)--> expandAlt :: ValueEnv -> Ident -> [Alt] -> Alt-> expandAlt tyEnv v (Alt p t rhs : alts) = caseAlt p t (expandRhs tyEnv e0 rhs)-> where e0 = Case (srcRefOf p) (mkVar v) -> (filter (isCompatible t . altPattern) alts)-> altPattern (Alt _ t _) = t--> isCompatible :: ConstrTerm -> ConstrTerm -> Bool-> isCompatible (VariablePattern _) _ = True-> isCompatible _ (VariablePattern _) = True-> isCompatible (AsPattern _ t1) t2 = isCompatible t1 t2-> isCompatible t1 (AsPattern _ t2) = isCompatible t1 t2-> isCompatible (ConstructorPattern c1 ts1) (ConstructorPattern c2 ts2) =-> and ((c1 == c2) : zipWith isCompatible ts1 ts2)-> isCompatible (LiteralPattern l1) (LiteralPattern l2) = canon l1 == canon l2-> where canon (Int _ i) = Int anonId i-> canon l = l--\end{verbatim}-The frontend provides several extensions of the Curry functionality, which-have to be desugared as well. This part transforms the following extensions:-\begin{itemize}-\item runction patterns-\item records-\end{itemize}-\begin{verbatim}--> desugarFunctionPatterns :: ModuleIdent -> Position -> [ConstrTerm] -> Rhs-> -> DesugarState ([ConstrTerm], Rhs)-> desugarFunctionPatterns m p ts rhs = -> do (ts', its) <- elimFunctionPattern m p ts-> rhs' <- genFunctionPatternExpr m p its rhs-> return (ts', rhs')--> desugarRecordDecl :: ModuleIdent -> TCEnv -> Decl -> DesugarState [Decl]-> desugarRecordDecl m tcEnv (TypeDecl p r vs (RecordType fss _)) =-> case (qualLookupTC r' tcEnv) of-> [AliasType _ n (TypeRecord fs' _)] ->-> do tyEnv <- S.get-> let tys = concatMap (\ (ls,ty) -> replicate (length ls) ty) fss-> --tys' = map (elimRecordTypes tyEnv) tys-> rdecl = DataDecl p r vs [ConstrDecl p [] r tys]-> rty' = TypeConstructor r' (map TypeVariable [0 .. n-1])-> rcts' = ForAllExist 0 n (foldr TypeArrow rty' (map snd fs'))-> rfuncs <- mapM (genRecordFuncs m tcEnv p r' rty' (map fst fs')) fs'-> S.modify (bindGlobalInfo DataConstructor m r rcts')-> return (rdecl:(concat rfuncs))-> _ -> internalError "desugarRecordDecl: no record"-> where r' = qualifyWith m r-> desugarRecordDecl _ _ decl = return [decl]--> desugarRecordPattern :: ModuleIdent -> TCEnv -> Position -> [Decl]-> -> [(Ident,ConstrTerm)] -> QualIdent-> -> DesugarState ([Decl],ConstrTerm)-> desugarRecordPattern m tcEnv p ds fs r =-> case (qualLookupTC r tcEnv) of-> [AliasType _ _ (TypeRecord fs' _)] ->-> do let ts = map (\ (l,_) -> -> fromMaybe (VariablePattern anonId)-> (lookup l fs))-> fs'-> desugarTerm m tcEnv p ds (ConstructorPattern r ts)--> desugarRecordConstr :: ModuleIdent -> TCEnv -> Position -> QualIdent -> -> [(Ident,Expression)] -> DesugarState Expression-> desugarRecordConstr m tcEnv p r fs =-> case (qualLookupTC r tcEnv) of-> [AliasType _ _ (TypeRecord fs' _)] ->-> do let cts = map (\ (l,_) -> -> fromMaybe (internalError "desugarRecordConstr")-> (lookup l fs)) fs'-> desugarExpr m tcEnv p (foldl Apply (Constructor r) cts)-> _ -> internalError "desugarRecordConstr: wrong type"--> desugarRecordSelection :: ModuleIdent -> TCEnv -> Position -> QualIdent -> -> Ident -> Expression -> DesugarState Expression-> desugarRecordSelection m tcEnv p r l e =-> desugarExpr m tcEnv p (Apply (Variable (qualRecSelectorId m r l)) e)--> desugarRecordUpdate :: ModuleIdent -> TCEnv -> Position -> QualIdent-> -> Expression -> [(Ident,Expression)] -> -> DesugarState Expression-> desugarRecordUpdate m tcEnv p r rexpr fs =-> desugarExpr m tcEnv p (foldl (genRecordUpdate m r) rexpr fs)-> where-> genRecordUpdate m r rexpr (l,e) =-> Apply (Apply (Variable (qualRecUpdateId m r l)) rexpr) e--> elimFunctionPattern :: ModuleIdent -> Position -> [ConstrTerm]-> -> DesugarState ([ConstrTerm], [(Ident,ConstrTerm)])-> elimFunctionPattern m p [] = return ([],[])-> elimFunctionPattern m p (t:ts)-> | containsFunctionPattern t-> = do tyEnv <- S.get-> ident <- freshIdent m "_#funpatt" (monoType (typeOf tyEnv t))-> (ts',its') <- elimFunctionPattern m p ts-> return ((VariablePattern ident):ts', (ident,t):its')-> | otherwise-> = do (ts', its') <- elimFunctionPattern m p ts-> return (t:ts', its')--> containsFunctionPattern :: ConstrTerm -> Bool-> containsFunctionPattern (ConstructorPattern _ ts)-> = any containsFunctionPattern ts-> containsFunctionPattern (InfixPattern t1 _ t2)-> = any containsFunctionPattern [t1,t2]-> containsFunctionPattern (ParenPattern t)-> = containsFunctionPattern t-> containsFunctionPattern (TuplePattern _ ts)-> = any containsFunctionPattern ts-> containsFunctionPattern (ListPattern _ ts)-> = any containsFunctionPattern ts-> containsFunctionPattern (AsPattern _ t)-> = containsFunctionPattern t-> containsFunctionPattern (LazyPattern _ t)-> = containsFunctionPattern t-> containsFunctionPattern (FunctionPattern _ _) = True-> containsFunctionPattern (InfixFuncPattern _ _ _) = True-> containsFunctionPattern _ = False--> genFunctionPatternExpr :: ModuleIdent -> Position -> [(Ident, ConstrTerm)]-> -> Rhs -> DesugarState Rhs-> genFunctionPatternExpr m _ its rhs@(SimpleRhs p expr decls)-> | null its = return rhs-> | otherwise-> = let ies = map (\ (i,t) -> (i, constrTerm2Expr t)) its-> fpexprs = map (\ (ident, expr) -> -> Apply (Apply prelFuncPattEqu expr) -> (Variable (qualify ident)))-> ies-> fpexpr = foldl (\e1 e2 -> Apply (Apply prelConstrConj e1) e2)-> (head fpexprs) -> (tail fpexprs)-> freevars = foldl getConstrTermVars [] (map snd its)-> rhsexpr = Let [ExtraVariables p freevars]-> (Apply (Apply prelCond fpexpr) expr)-> in return (SimpleRhs p rhsexpr decls) -> genFunctionPatternExpr _ _ _ rhs-> = internalError "genFunctionPatternExpr: unexpected right-hand-side"--> constrTerm2Expr :: ConstrTerm -> Expression-> constrTerm2Expr (LiteralPattern lit)-> = Literal lit-> constrTerm2Expr (VariablePattern ident)-> = Variable (qualify ident)-> constrTerm2Expr (ConstructorPattern qident cts)-> = foldl (\e1 e2 -> Apply e1 e2) -> (Constructor qident) -> (map constrTerm2Expr cts)-> constrTerm2Expr (FunctionPattern qident cts)-> = foldl (\e1 e2 -> Apply e1 e2) -> (Variable qident) -> (map constrTerm2Expr cts)-> constrTerm2Expr _-> = internalError "constrTerm2Expr: unexpected constructor term"--> getConstrTermVars :: [Ident] -> ConstrTerm -> [Ident]-> getConstrTermVars ids (VariablePattern ident)-> | elem ident ids = ids-> | otherwise = ident:ids-> getConstrTermVars ids (ConstructorPattern _ cts)-> = foldl getConstrTermVars ids cts-> getConstrTermVars ids (InfixPattern c1 qid c2)-> = getConstrTermVars ids (ConstructorPattern qid [c1,c2])-> getConstrTermVars ids (ParenPattern c)-> = getConstrTermVars ids c-> getConstrTermVars ids (TuplePattern _ cts)-> = foldl getConstrTermVars ids cts-> getConstrTermVars ids (ListPattern _ cts)-> = foldl getConstrTermVars ids cts-> getConstrTermVars ids (AsPattern _ c)-> = getConstrTermVars ids c-> getConstrTermVars ids (LazyPattern _ c)-> = getConstrTermVars ids c-> getConstrTermVars ids (FunctionPattern _ cts)-> = foldl getConstrTermVars ids cts-> getConstrTermVars ids (InfixFuncPattern c1 qid c2)-> = getConstrTermVars ids (FunctionPattern qid [c1,c2])-> getConstrTermVars ids _-> = ids--> genRecordFuncs :: ModuleIdent -> TCEnv -> Position -> QualIdent -> Type -> -> [Ident] -> (Ident, Type) -> DesugarState [Decl]-> genRecordFuncs m tcEnv p r rty ls (l,ty) =-> case (qualLookupTC r tcEnv) of-> [AliasType _ n (TypeRecord fs _)] ->-> do let (selId, selFunc) = genSelectorFunc m p r ls l-> (updId, updFunc) = genUpdateFunc m p r ls l-> selType = polyType (TypeArrow rty ty)-> updType = polyType (TypeArrow rty (TypeArrow ty rty))-> S.modify (bindFun m selId selType . bindFun m updId updType)-> return [selFunc,updFunc]-> _ -> internalError "genRecordFuncs: wrong type"--> genSelectorFunc :: ModuleIdent -> Position -> QualIdent -> [Ident] -> Ident-> -> (Ident, Decl)-> genSelectorFunc m p r ls l =-> let selId = recSelectorId r l-> cpatt = ConstructorPattern r (map VariablePattern ls)-> selLhs = FunLhs selId [cpatt]-> selRhs = SimpleRhs p (Variable (qualify l)) []-> in (selId, FunctionDecl p selId [Equation p selLhs selRhs])--> genUpdateFunc :: ModuleIdent -> Position -> QualIdent -> [Ident] -> Ident-> -> (Ident, Decl)-> genUpdateFunc m p r ls l =-> let updId = recUpdateId r l-> ls' = replaceIdent l anonId ls-> cpatt1 = ConstructorPattern r (map VariablePattern ls')-> cpatt2 = VariablePattern l-> cexpr = foldl Apply -> (Constructor r)-> (map (Variable . qualify) ls) -> updLhs = FunLhs updId [cpatt1, cpatt2]-> updRhs = SimpleRhs p cexpr []-> in (updId, FunctionDecl p updId [Equation p updLhs updRhs])--> replaceIdent :: Ident -> Ident -> [Ident] -> [Ident]-> replaceIdent _ _ [] = []-> replaceIdent what with (id:ids)-> | what == id = with:ids-> | otherwise = id:(replaceIdent what with ids)--\end{verbatim}-In general, a list comprehension of the form-\texttt{[}$e$~\texttt{|}~$t$~\texttt{<-}~$l$\texttt{,}~\emph{qs}\texttt{]}-is transformed into an expression \texttt{foldr}~$f$~\texttt{[]}~$l$ where $f$-is a new function defined as-\begin{quote}- \begin{tabbing}- $f$ $x$ \emph{xs} \texttt{=} \\- \quad \= \texttt{case} $x$ \texttt{of} \\- \> \quad \= $t$ \texttt{->} \texttt{[}$e$ \texttt{|} \emph{qs}\texttt{]} \texttt{++} \emph{xs} \\- \> \> \texttt{\_} \texttt{->} \emph{xs}- \end{tabbing}-\end{quote}-Note that this translation evaluates the elements of $l$ rigidly,-whereas the translation given in the Curry report is flexible.-However, it does not seem very useful to have the comprehension-generate instances of $t$ which do not contribute to the list.--Actually, we generate slightly better code in a few special cases.-When $t$ is a plain variable, the \texttt{case} expression degenerates-into a let-binding and the auxiliary function thus becomes an alias-for \texttt{(++)}. Instead of \texttt{foldr~(++)} we use the-equivalent prelude function \texttt{concatMap}. In addition, if the-remaining list comprehension in the body of the auxiliary function has-no qualifiers -- i.e., if it is equivalent to \texttt{[$e$]} -- we-avoid the construction of the singleton list by calling \texttt{(:)}-instead of \texttt{(++)} and \texttt{map} in place of-\texttt{concatMap}, respectively. -}-\begin{verbatim}--> desugarQual :: ModuleIdent -> TCEnv -> Position -> Statement -> Expression-> -> DesugarState Expression-> desugarQual m tcEnv p (StmtExpr pos b) e = -> desugarExpr m tcEnv p (IfThenElse pos b e (List [pos] []))-> desugarQual m tcEnv p (StmtBind refBind t l) e-> | isVarPattern t = desugarExpr m tcEnv p (qualExpr t e l)-> | otherwise =-> do-> tyEnv <- S.get-> v0 <- freshIdent m "_#var" (monoType (typeOf tyEnv t))-> l0 <- freshIdent m "_#var" (monoType (typeOf tyEnv e))-> let v = addRefId refBind v0-> l' = addRefId refBind l0-> desugarExpr m tcEnv p (apply (prelFoldr refBind) -> [foldFunct v l' e,List [refBind] [],l])-> where -> qualExpr v (ListCompr _ e []) l -> = apply (prelMap refBind) [Lambda refBind [v] e,l]-> qualExpr v e l = apply (prelConcatMap refBind) [Lambda refBind [v] e,l]--> foldFunct v l e =-> Lambda refBind (map VariablePattern [v,l])-> (Case refBind (mkVar v)-> [caseAlt {-refBind-} p t (append e (mkVar l)),-> caseAlt {-refBind-} p (VariablePattern v) (mkVar l)])->-> append (ListCompr _ e []) l = apply (Constructor $ addRef refBind $ qConsId) [e,l]-> append e l = apply (prelAppend refBind) [e,l]->-> desugarQual m tcEnv p (StmtDecl ds) e = desugarExpr m tcEnv p (Let ds e)--\end{verbatim}-Generation of fresh names-\begin{verbatim}--> freshIdent :: ModuleIdent -> String -> TypeScheme -> DesugarState Ident-> freshIdent m prefix ty =-> do-> x <- liftM (mkName prefix) (S.lift (S.modify succ >> S.get))-> S.modify (bindFun m x ty)-> return x-> where mkName pre n = mkIdent (pre ++ show n)--\end{verbatim}-Prelude entities-\begin{verbatim}--> prelBind = prel ">>="-> prelBind_ = prel ">>"-> prelFlip = Variable $ preludeIdent "flip"-> prelEnumFrom = Variable $ preludeIdent "enumFrom"-> prelEnumFromTo = Variable $ preludeIdent "enumFromTo"-> prelEnumFromThen = Variable $ preludeIdent "enumFromThen"-> prelEnumFromThenTo = Variable $ preludeIdent "enumFromThenTo"-> prelFailed = Variable $ preludeIdent "failed"-> prelMap r = Variable $ addRef r $ preludeIdent "map"-> prelFoldr = prel "foldr"-> prelAppend = prel "++"-> prelConcatMap = prel "concatMap"-> prelNegate = Variable $ preludeIdent "negate"-> prelNegateFloat = Variable $ preludeIdent "negateFloat"-> prelCond = Variable $ preludeIdent "cond"-> prelFuncPattEqu = Variable $ preludeIdent "=:<="-> prelConstrConj = Variable $ preludeIdent "&"--> prel s r = Variable (addRef r (preludeIdent s))--> truePattern = ConstructorPattern qTrueId []-> falsePattern = ConstructorPattern qFalseId []---> preludeIdent :: String -> QualIdent-> preludeIdent = qualifyWith preludeMIdent . mkIdent--\end{verbatim}-Auxiliary definitions-\begin{verbatim}--> isNewtypeConstr :: ValueEnv -> QualIdent -> Bool-> isNewtypeConstr tyEnv c =-> case qualLookupValue c tyEnv of-> [DataConstructor _ _] -> False-> [NewtypeConstructor _ _] -> True-> _ -> internalError ("isNewtypeConstr " ++ show c) --internalError "isNewtypeConstr"--> isVarPattern :: ConstrTerm -> Bool-> isVarPattern (VariablePattern _) = True-> isVarPattern (ParenPattern t) = isVarPattern t-> isVarPattern (AsPattern _ t) = isVarPattern t-> isVarPattern (LazyPattern _ _) = True-> isVarPattern _ = False--> funDecl :: Position -> Ident -> [ConstrTerm] -> Expression -> Decl-> funDecl p f ts e =-> FunctionDecl p f [Equation p (FunLhs f ts) (SimpleRhs p e [])]--> patDecl :: Position -> ConstrTerm -> Expression -> Decl-> patDecl p t e = PatternDecl p t (SimpleRhs p e [])--> varDecl :: Position -> Ident -> Expression -> Decl-> varDecl p = patDecl p . VariablePattern--> addDecls :: [Decl] -> Rhs -> Rhs-> addDecls ds (SimpleRhs p e ds') = SimpleRhs p e (ds ++ ds')-> addDecls ds (GuardedRhs es ds') = GuardedRhs es (ds ++ ds')--> caseAlt :: Position -> ConstrTerm -> Expression -> Alt-> caseAlt p t e = Alt p t (SimpleRhs p e [])--> apply :: Expression -> [Expression] -> Expression-> apply = foldl Apply--> mkVar :: Ident -> Expression-> mkVar = Variable . qualify---\end{verbatim}
+ src/Env/Class.hs view
@@ -0,0 +1,75 @@+{- |+ Module : $Header$+ Description : Environment of classes+ Copyright : (c) 2016 - 2020 Finn Teegen+ License : BSD-3-clause++ Maintainer : fte@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ The compiler maintains information about all type classes in an+ environment that maps type classes to a sorted list of their direct+ superclasses and all their associated class methods with an additional+ flag stating whether an default implementation has been provided or not.+ For both the type class identifier and the list of super classes original+ names are used. Thus, the use of a flat environment is sufficient.+-}++module Env.Class+ ( ClassEnv, initClassEnv+ , ClassInfo, bindClassInfo, mergeClassInfo, lookupClassInfo+ , superClasses, allSuperClasses, classMethods, hasDefaultImpl+ ) where++import Data.List (nub, sort)+import qualified Data.Map as Map (Map, empty, insertWith, lookup)++import Curry.Base.Ident++import Base.Messages (internalError)++type ClassInfo = ([QualIdent], [(Ident, Bool)])++type ClassEnv = Map.Map QualIdent ClassInfo++initClassEnv :: ClassEnv+initClassEnv = Map.empty++bindClassInfo :: QualIdent -> ClassInfo -> ClassEnv -> ClassEnv+bindClassInfo cls (sclss, ms) =+ Map.insertWith mergeClassInfo cls (sort sclss, ms)++-- We have to be careful when merging two class infos into one as hidden class+-- declarations in interfaces provide no information about class methods. If+-- one of the method lists is empty, we simply take the other one. This way,+-- we do overwrite the list of class methods that may have been entered into+-- the class environment before with an empty list.++mergeClassInfo :: ClassInfo -> ClassInfo -> ClassInfo+mergeClassInfo (sclss1, ms1) (_, ms2) = (sclss1, if null ms1 then ms2 else ms1)++lookupClassInfo :: QualIdent -> ClassEnv -> Maybe ClassInfo+lookupClassInfo = Map.lookup++superClasses :: QualIdent -> ClassEnv -> [QualIdent]+superClasses cls clsEnv = case lookupClassInfo cls clsEnv of+ Just (sclss, _) -> sclss+ _ -> internalError $ "Env.Classes.superClasses: " ++ show cls++allSuperClasses :: QualIdent -> ClassEnv -> [QualIdent]+allSuperClasses cls clsEnv = nub $ classes cls+ where+ classes cls' = cls' : concatMap classes (superClasses cls' clsEnv)++classMethods :: QualIdent -> ClassEnv -> [Ident]+classMethods cls clsEnv = case lookupClassInfo cls clsEnv of+ Just (_, ms) -> map fst ms+ _ -> internalError $ "Env.Classes.classMethods: " ++ show cls++hasDefaultImpl :: QualIdent -> Ident -> ClassEnv -> Bool+hasDefaultImpl cls f clsEnv = case lookupClassInfo cls clsEnv of+ Just (_, ms) -> case lookup f ms of+ Just dflt -> dflt+ Nothing -> internalError $ "Env.Classes.hasDefaultImpl: " ++ show f+ _ -> internalError $ "Env.Classes.hasDefaultImpl: " ++ show cls
+ src/Env/Instance.hs view
@@ -0,0 +1,54 @@+{- |+ Module : $Header$+ Description : Environment of instances+ Copyright : (c) 2016 - 2020 Finn Teegen+ License : BSD-3-clause++ Maintainer : fte@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ The compiler maintains information about defined instances in an+ environment that maps pairs of type classes and type constructors+ to the name of the module where the instance is declared, the context+ as given in the instance declaration, and a list of the class methods+ implemented in the specific instance along with their arity. A flat+ environment is sufficient because instances are visible globally and+ cannot be hidden. Instances are recorded only with the original names+ of the type class and type constructor involved. The context also uses+ original names and is already minimized.+-}++module Env.Instance+ ( InstIdent, ppInstIdent, InstInfo+ , InstEnv, initInstEnv, bindInstInfo, removeInstInfo, lookupInstInfo+ ) where++import qualified Data.Map as Map (Map, empty, insert, delete, lookup)++import Curry.Base.Ident+import Curry.Base.Pretty+import Curry.Syntax.Pretty++import Base.Types++type InstIdent = (QualIdent, QualIdent)++ppInstIdent :: InstIdent -> Doc+ppInstIdent (qcls, qtc) = ppQIdent qcls <+> ppQIdent qtc++type InstInfo = (ModuleIdent, PredSet, [(Ident, Int)])++type InstEnv = Map.Map InstIdent InstInfo++initInstEnv :: InstEnv+initInstEnv = Map.empty++bindInstInfo :: InstIdent -> InstInfo -> InstEnv -> InstEnv+bindInstInfo = Map.insert++removeInstInfo :: InstIdent -> InstEnv -> InstEnv+removeInstInfo = Map.delete++lookupInstInfo :: InstIdent -> InstEnv -> Maybe InstInfo+lookupInstInfo = Map.lookup
+ src/Env/Interface.hs view
@@ -0,0 +1,31 @@+{- |+ Module : $Header$+ Description : Environment of imported interfaces+ Copyright : (c) 2002 - 2004 Wolfgang Lux+ 2011 - 2013 Björn Peemöller+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module provides an environment for imported interfaces.+-}+module Env.Interface where++import qualified Data.Map as Map (Map, empty, lookup)++import Curry.Base.Ident (ModuleIdent)+import Curry.Syntax (Interface)++-- |Environment which maps the 'ModuleIdent' of an imported module+-- to the corresponding 'Interface'.+type InterfaceEnv = Map.Map ModuleIdent Interface++-- |Initial 'InterfaceEnv'.+initInterfaceEnv :: InterfaceEnv+initInterfaceEnv = Map.empty++-- |Lookup the 'Interface' for an imported module.+lookupInterface :: ModuleIdent -> InterfaceEnv -> Maybe Interface+lookupInterface = Map.lookup
+ src/Env/ModuleAlias.hs view
@@ -0,0 +1,41 @@+{- |+ Module : $Header$+ Description : Environment of module aliases+ Copyright : (c) 2002 - 2004, Wolfgang Lux+ 2011 - 2013, Björn Peemöller+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module provides an environment for resolving module aliases.++ For example, if module @FiniteMap@ is imported via++ @import FiniteMap as FM@++ then @FM@ is an alias for @FiniteMap@, and @FiniteMap@ is aliased by @FM@.+-}+module Env.ModuleAlias ( AliasEnv, initAliasEnv, importAliases ) where++import qualified Data.Map as Map (Map, empty, insert)+import Data.Maybe (fromMaybe)++import Curry.Base.Ident (ModuleIdent)+import Curry.Syntax (ImportDecl (..))++-- |Mapping from the original name of an imported module to its alias.+type AliasEnv = Map.Map ModuleIdent ModuleIdent++-- |Initial alias environment+initAliasEnv :: AliasEnv+initAliasEnv = Map.empty++-- |Create an alias environment from a list of import declarations+importAliases :: [ImportDecl] -> AliasEnv+importAliases = foldr bindAlias initAliasEnv++-- |Bind an alias for a module from a single import declaration+bindAlias :: ImportDecl -> AliasEnv -> AliasEnv+bindAlias (ImportDecl _ mid _ alias _) = Map.insert mid $ fromMaybe mid alias
+ src/Env/OpPrec.hs view
@@ -0,0 +1,111 @@+{- |+ Module : $Header$+ Description : Environment of operator precedences+ Copyright : (c) 2002 - 2004, Wolfgang Lux+ 2011 - 2013, Björn Peemöller+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ In order to parse infix expressions correctly, the compiler must know+ the precedence and fixity of each operator. Operator precedences are+ associated with entities and will be checked after renaming was+ applied. Nevertheless, we need to save precedences for ambiguous names+ in order to handle them correctly while computing the exported+ interface of a module.++ If no fixity is assigned to an operator, it will be given the default+ precedence 9 and assumed to be a left-associative operator.++ /Note:/ this modified version uses Haskell type 'Integer'+ for representing the precedence. This change had to be done due to the+ introduction of unlimited integer constants in the parser / lexer.+-}+module Env.OpPrec+ ( OpPrec (..), defaultP, defaultAssoc, defaultPrecedence, mkPrec+ , OpPrecEnv, PrecInfo (..), bindP, lookupP, qualLookupP, initOpPrecEnv+ ) where++import Curry.Base.Ident+import Curry.Base.Pretty (Pretty(..))+import Curry.Syntax (Infix (..))++import Base.TopEnv++import Data.Maybe (fromMaybe)++import Text.PrettyPrint++-- |Operator precedence.+data OpPrec = OpPrec Infix Precedence deriving Eq++type Precedence = Integer++-- TODO: Change to real show instance and provide Pretty instance+-- if used anywhere.+instance Show OpPrec where+ showsPrec _ (OpPrec fix p) = showString (assoc fix) . shows p+ where+ assoc InfixL = "left "+ assoc InfixR = "right "+ assoc Infix = "non-assoc "++instance Pretty OpPrec where+ pPrint (OpPrec fix p) = pPrint fix <+> integer p++-- |Default operator declaration (associativity and precedence).+defaultP :: OpPrec+defaultP = OpPrec defaultAssoc defaultPrecedence++-- |Default operator associativity.+defaultAssoc :: Infix+defaultAssoc = InfixL++-- |Default operator precedence.+defaultPrecedence :: Precedence+defaultPrecedence = 9++mkPrec :: Maybe Precedence -> Precedence+mkPrec mprec = fromMaybe defaultPrecedence mprec++-- |Precedence information for an identifier.+data PrecInfo = PrecInfo QualIdent OpPrec deriving (Eq, Show)++instance Entity PrecInfo where+ origName (PrecInfo op _) = op++instance Pretty PrecInfo where+ pPrint (PrecInfo qid prec) = pPrint qid <+> pPrint prec++-- |Environment mapping identifiers to their operator precedence.+type OpPrecEnv = TopEnv PrecInfo++-- |Initial 'OpPrecEnv'.+initOpPrecEnv :: OpPrecEnv+initOpPrecEnv = predefTopEnv qConsId consPrec emptyTopEnv++-- |Precedence of list constructor.+consPrec :: PrecInfo+consPrec = PrecInfo qConsId (OpPrec InfixR 5)++-- |Bind an operator precedence.+bindP :: ModuleIdent -> Ident -> OpPrec -> OpPrecEnv -> OpPrecEnv+bindP m op p+ | hasGlobalScope op = bindTopEnv op info . qualBindTopEnv qop info+ | otherwise = bindTopEnv op info+ where qop = qualifyWith m op+ info = PrecInfo qop p++-- The lookup functions for the environment which maintains the operator+-- precedences are simpler than for the type and value environments+-- because they do not need to handle tuple constructors.++-- |Lookup the operator precedence for an 'Ident'.+lookupP :: Ident -> OpPrecEnv -> [PrecInfo]+lookupP = lookupTopEnv++-- |Lookup the operator precedence for an 'QualIdent'.+qualLookupP :: QualIdent -> OpPrecEnv -> [PrecInfo]+qualLookupP = qualLookupTopEnv
+ src/Env/Type.hs view
@@ -0,0 +1,70 @@+{- |+ Module : $Header$+ Description : Environment of type identifiers+ Copyright : (c) 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ At the type level, we distinguish data and renaming types, synonym+ types, and type classes. Type variables are not recorded. Type+ synonyms use a kind of their own so that the compiler can verify that+ no type synonyms are used in type expressions in interface files.+-}++module Env.Type+ ( TypeKind (..), toTypeKind,+ TypeEnv, bindTypeKind, lookupTypeKind, qualLookupTypeKind+ ) where++import Curry.Base.Ident++import Base.Messages (internalError)+import Base.TopEnv+import Base.Types (constrIdent, methodName)++import Env.TypeConstructor (TypeInfo (..))++import Data.List (union)++data TypeKind+ = Data QualIdent [Ident]+ | Alias QualIdent+ | Class QualIdent [Ident]+ deriving (Eq, Show)++instance Entity TypeKind where+ origName (Data tc _) = tc+ origName (Alias tc ) = tc+ origName (Class cls _) = cls++ merge (Data tc cs) (Data tc' cs')+ | tc == tc' = Just $ Data tc $ cs `union` cs'+ merge (Alias tc) (Alias tc')+ | tc == tc' = Just $ Alias tc+ merge (Class cls ms) (Class cls' ms')+ | cls == cls' = Just $Class cls $ ms `union` ms'+ merge _ _ = Nothing++toTypeKind :: TypeInfo -> TypeKind+toTypeKind (DataType tc _ cs) = Data tc (map constrIdent cs)+toTypeKind (RenamingType tc _ nc) = Data tc [constrIdent nc]+toTypeKind (AliasType tc _ _ _) = Alias tc+toTypeKind (TypeClass cls _ ms) = Class cls (map methodName ms)+toTypeKind (TypeVar _) =+ internalError "Env.Type.toTypeKind: type variable"++type TypeEnv = TopEnv TypeKind++bindTypeKind :: ModuleIdent -> Ident -> TypeKind -> TypeEnv -> TypeEnv+bindTypeKind m ident tk = bindTopEnv ident tk . qualBindTopEnv qident tk+ where+ qident = qualifyWith m ident++lookupTypeKind :: Ident -> TypeEnv -> [TypeKind]+lookupTypeKind = lookupTopEnv++qualLookupTypeKind :: QualIdent -> TypeEnv -> [TypeKind]+qualLookupTypeKind = qualLookupTopEnv
+ src/Env/TypeConstructor.hs view
@@ -0,0 +1,221 @@+{- |+ Module : $Header$+ Description : Environment of type constructors+ Copyright : (c) 2002 - 2004 Wolfgang Lux+ 2011 Björn Peemöller+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ For all defined types the compiler must maintain kind information.+ For algebraic data types and renaming types the compiler also records+ all data constructors belonging to that type, for alias types the+ type expression to be expanded is saved. Futhermore, recording the+ arity is necessary for alias types because the right hand side, i.e.,+ the type expression, can have arbitrary kind and therefore the type+ alias' arity cannot be determined from its own kind. For instance,+ the type alias type List = [] has the kind * -> *, but its arity is 0.+ In order to manage the import and export of types, the names of the+ original definitions are also recorded. On import two types are+ considered equal if their original names match.++ The information for a data constructor comprises the number of+ existentially quantified type variables, the context and the list+ of the argument types. Note that renaming type constructors have only+ one type argument.++ For type classes the all their methods are saved. Type classes are+ recorded in the type constructor environment because type constructors+ and type classes share a common name space.++ For type variables only their kind is recorded in the environment.++ Importing and exporting algebraic data types and renaming types is+ complicated by the fact that the constructors of the type may be+ (partially) hidden in the interface. This facilitates the definition+ of abstract data types. An abstract type is always represented as a+ data type without constructors in the interface regardless of whether+ it is defined as a data type or as a renaming type. When only some+ constructors of a data type are hidden, those constructors are+ replaced by underscores in the interface. Furthermore, if the+ right-most constructors of a data type are hidden, they are not+ exported at all in order to make the interface more stable against+ changes which are private to the module.+-}+{-# LANGUAGE CPP #-}+module Env.TypeConstructor+ ( TypeInfo (..), tcKind, clsKind, varKind, clsMethods+ , TCEnv, initTCEnv, bindTypeInfo, rebindTypeInfo+ , lookupTypeInfo, qualLookupTypeInfo, qualLookupTypeInfoUnique+ , getOrigName, reverseLookupByOrigName+ ) where++#if __GLASGOW_HASKELL__ >= 804+import Prelude hiding ((<>))+#endif++import Curry.Base.Ident+import Curry.Base.Pretty (Pretty(..), blankLine)++import Base.Kinds+import Base.Messages (internalError)+import Base.PrettyKinds ()+import Base.PrettyTypes ()+import Base.TopEnv+import Base.Types+import Base.Utils ((++!))++import Text.PrettyPrint++data TypeInfo+ = DataType QualIdent Kind [DataConstr]+ | RenamingType QualIdent Kind DataConstr+ | AliasType QualIdent Kind Int Type+ | TypeClass QualIdent Kind [ClassMethod]+ | TypeVar Kind+ deriving Show++instance Entity TypeInfo where+ origName (DataType tc _ _) = tc+ origName (RenamingType tc _ _) = tc+ origName (AliasType tc _ _ _) = tc+ origName (TypeClass cls _ _) = cls+ origName (TypeVar _) =+ internalError "Env.TypeConstructor.origName: type variable"++ merge (DataType tc k cs) (DataType tc' k' cs')+ | tc == tc' && k == k' && (null cs || null cs' || cs == cs') =+ Just $ DataType tc k $ if null cs then cs' else cs+ merge (DataType tc k _) (RenamingType tc' k' nc)+ | tc == tc' && k == k' = Just (RenamingType tc k nc)+ merge l@(RenamingType tc k _) (DataType tc' k' _)+ | tc == tc' && k == k' = Just l+ merge l@(RenamingType tc k _) (RenamingType tc' k' _)+ | tc == tc' && k == k' = Just l+ merge l@(AliasType tc k _ _) (AliasType tc' k' _ _)+ | tc == tc' && k == k' = Just l+ merge (TypeClass cls k ms) (TypeClass cls' k' ms')+ | cls == cls' && k == k' && (null ms || null ms' || ms == ms') =+ Just $ TypeClass cls k $ if null ms then ms' else ms+ merge _ _ = Nothing++instance Pretty TypeInfo where+ pPrint (DataType qid k cs) = text "data" <+> pPrint qid+ <> text "/" <> pPrint k+ <+> equals+ <+> hsep (punctuate (text "|") (map pPrint cs))+ pPrint (RenamingType qid k c) = text "newtype" <+> pPrint qid+ <> text "/" <> pPrint k+ <+> equals <+> pPrint c+ pPrint (AliasType qid k ar ty)= text "type" <+> pPrint qid+ <> text "/" <> pPrint k <> text "/" <> int ar+ <+> equals <+> pPrint ty+ pPrint (TypeClass qid k ms) = text "class" <+> pPrint qid+ <> text "/" <> pPrint k+ <+> equals+ <+> vcat (blankLine : map pPrint ms)+ pPrint (TypeVar _) =+ internalError $ "Env.TypeConstructor.Pretty.TypeInfo.pPrint: type variable"++tcKind :: ModuleIdent -> QualIdent -> TCEnv -> Kind+tcKind m tc tcEnv = case qualLookupTypeInfo tc tcEnv of+ [DataType _ k _] -> k+ [RenamingType _ k _] -> k+ [AliasType _ k _ _] -> k+ _ -> case qualLookupTypeInfo (qualQualify m tc) tcEnv of+ [DataType _ k _] -> k+ [RenamingType _ k _] -> k+ [AliasType _ k _ _] -> k+ _ -> internalError $+ "Env.TypeConstructor.tcKind: no type constructor: " ++ show tc++clsKind :: ModuleIdent -> QualIdent -> TCEnv -> Kind+clsKind m cls tcEnv = case qualLookupTypeInfo cls tcEnv of+ [TypeClass _ k _] -> k+ _ -> case qualLookupTypeInfo (qualQualify m cls) tcEnv of+ [TypeClass _ k _] -> k+ _ -> internalError $+ "Env.TypeConstructor.clsKind: no type class: " ++ show cls++varKind :: Ident -> TCEnv -> Kind+varKind tv tcEnv+ | isAnonId tv = KindStar+ | otherwise = case lookupTypeInfo tv tcEnv of+ [TypeVar k] -> k+ _ -> internalError "Env.TypeConstructor.varKind: no type variable"++clsMethods :: ModuleIdent -> QualIdent -> TCEnv -> [Ident]+clsMethods m cls tcEnv = case qualLookupTypeInfo cls tcEnv of+ [TypeClass _ _ ms] -> map methodName ms+ _ -> case qualLookupTypeInfo (qualQualify m cls) tcEnv of+ [TypeClass _ _ ms] -> map methodName ms+ _ -> internalError $ "Env.TypeConstructor.clsMethods: " ++ show cls++-- Types can only be defined on the top-level; no nested environments are+-- needed for them. Tuple types must be handled as a special case because+-- there is an infinite number of potential tuple types making it+-- impossible to insert them into the environment in advance.++type TCEnv = TopEnv TypeInfo++initTCEnv :: TCEnv+initTCEnv = foldr (uncurry $ predefTC . unapplyType False) emptyTopEnv predefTypes+ where+ predefTC (TypeConstructor tc, tys) =+ predefTopEnv tc . DataType tc (simpleKind $ length tys)+ predefTC _ =+ internalError "Env.TypeConstructor.initTCEnv.predefTC: no type constructor"++bindTypeInfo :: ModuleIdent -> Ident -> TypeInfo -> TCEnv -> TCEnv+bindTypeInfo m ident ti = bindTopEnv ident ti . qualBindTopEnv qident ti+ where+ qident = qualifyWith m ident++rebindTypeInfo :: ModuleIdent -> Ident -> TypeInfo -> TCEnv -> TCEnv+rebindTypeInfo m ident ti = rebindTopEnv ident ti . qualRebindTopEnv qident ti+ where+ qident = qualifyWith m ident++lookupTypeInfo :: Ident -> TCEnv -> [TypeInfo]+lookupTypeInfo ident tcEnv = lookupTopEnv ident tcEnv ++! lookupTupleTC ident++qualLookupTypeInfo :: QualIdent -> TCEnv -> [TypeInfo]+qualLookupTypeInfo ident tcEnv =+ qualLookupTopEnv ident tcEnv ++! lookupTupleTC (unqualify ident)++qualLookupTypeInfoUnique :: ModuleIdent -> QualIdent -> TCEnv -> [TypeInfo]+qualLookupTypeInfoUnique m qident tcEnv =+ case qualLookupTypeInfo qident tcEnv of+ [] -> []+ [ti] -> [ti]+ tis -> case qualLookupTypeInfo (qualQualify m qident) tcEnv of+ [] -> tis+ [ti] -> [ti]+ tis' -> tis'++getOrigName :: ModuleIdent -> QualIdent -> TCEnv -> QualIdent+getOrigName m tc tcEnv = case qualLookupTypeInfo tc tcEnv of+ [y] -> origName y+ _ -> case qualLookupTypeInfo (qualQualify m tc) tcEnv of+ [y] -> origName y+ _ -> internalError $ "Env.TypeConstructor.getOrigName: " ++ show tc++reverseLookupByOrigName :: QualIdent -> TCEnv -> [QualIdent]+reverseLookupByOrigName on+ | isQTupleId on = const [on]+ | otherwise = map fst . filter ((== on) . origName . snd) . allBindings++lookupTupleTC :: Ident -> [TypeInfo]+lookupTupleTC tc | isTupleId tc = [tupleTCs !! (tupleArity tc - 2)]+ | otherwise = []++tupleTCs :: [TypeInfo]+tupleTCs = map typeInfo tupleData+ where+ typeInfo dc@(DataConstr _ tys) =+ let n = length tys in DataType (qTupleId n) (simpleKind n) [dc]+ typeInfo (RecordConstr _ _ _) =+ internalError "Env.TypeConstructor.tupleTCs: record constructor"
+ src/Env/Value.hs view
@@ -0,0 +1,207 @@+{- |+ Module : $Header$+ Description : Environment for functions, constructors and labels+ Copyright : (c) 2001 - 2004 Wolfgang Lux+ 2011 Björn Peemöller+ 2015 Jan Tikovsky+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ In order to test the type correctness of a module, the compiler needs+ to determine the type of every data constructor, function and+ variable in the module.+ For the purpose of type checking there is no+ need for distinguishing between variables and functions. For all objects+ their original names and their types are saved. In addition, the compiler+ also saves the (optional) list of field labels for data and newtype+ constructors. Data constructors and functions also contain arity+ information. On import two values are considered equal if their original+ names match.+-}+{-# LANGUAGE CPP #-}+module Env.Value+ ( ValueEnv, ValueInfo (..)+ , bindGlobalInfo, bindFun, qualBindFun, rebindFun, unbindFun+ , lookupValue, qualLookupValue, qualLookupValueUnique+ , initDCEnv+ , ValueType (..), bindLocalVars, bindLocalVar+ ) where++#if __GLASGOW_HASKELL__ >= 804+import Prelude hiding ((<>))+#endif++import Curry.Base.Ident+import Curry.Base.Pretty (Pretty(..))++import Base.Messages (internalError)+import Base.PrettyTypes ()+import Base.TopEnv+import Base.Types+import Base.Utils ((++!))++import Text.PrettyPrint++data ValueInfo+ -- |Data constructor with original name, arity, list of record labels and type+ = DataConstructor QualIdent Int [Ident] TypeScheme+ -- |Newtype constructor with original name, record label and type+ -- (arity is always 1)+ | NewtypeConstructor QualIdent Ident TypeScheme+ -- |Value with original name, class method name, arity and type+ | Value QualIdent (Maybe QualIdent) Int TypeScheme+ -- |Record label with original name, list of constructors for which label+ -- is a valid field and type (arity is always 1)+ | Label QualIdent [QualIdent] TypeScheme+ deriving Show++instance Entity ValueInfo where+ origName (DataConstructor orgName _ _ _) = orgName+ origName (NewtypeConstructor orgName _ _) = orgName+ origName (Value orgName _ _ _) = orgName+ origName (Label orgName _ _) = orgName++ merge (DataConstructor c1 ar1 ls1 ty1) (DataConstructor c2 ar2 ls2 ty2)+ | c1 == c2 && ar1 == ar2 && ty1 == ty2 = do+ ls' <- sequence (zipWith mergeLabel ls1 ls2)+ Just (DataConstructor c1 ar1 ls' ty1)+ merge (NewtypeConstructor c1 l1 ty1) (NewtypeConstructor c2 l2 ty2)+ | c1 == c2 && ty1 == ty2 = do+ l' <- mergeLabel l1 l2+ Just (NewtypeConstructor c1 l' ty1)+ merge (Value x1 ar1 cm1 ty1) (Value x2 ar2 cm2 ty2)+ | x1 == x2 && ar1 == ar2 && cm1 == cm2 && ty1 == ty2 =+ Just (Value x1 ar1 cm1 ty1)+ merge (Label l1 cs1 ty1) (Label l2 cs2 ty2)+ | l1 == l2 && cs1 == cs2 && ty1 == ty2 = Just (Label l1 cs1 ty1)+ merge _ _ = Nothing++instance Pretty ValueInfo where+ pPrint (DataConstructor qid ar _ tySc) = text "data" <+> pPrint qid+ <> text "/" <> int ar+ <+> equals <+> pPrint tySc+ pPrint (NewtypeConstructor qid _ tySc) = text "newtype" <+> pPrint qid+ <+> equals <+> pPrint tySc+ pPrint (Value qid _ ar tySc) = pPrint qid+ <> text "/" <> int ar+ <+> equals <+> pPrint tySc+ pPrint (Label qid _ tySc) = text "label" <+> pPrint qid+ <+> equals <+> pPrint tySc++mergeLabel :: Ident -> Ident -> Maybe Ident+mergeLabel l1 l2+ | l1 == anonId = Just l2+ | l2 == anonId = Just l1+ | l1 == l2 = Just l1+ | otherwise = Nothing++-- Even though value declarations may be nested, the compiler uses only+-- flat environments for saving type information. This is possible+-- because all identifiers are renamed by the compiler. Here we need+-- special cases for handling tuple constructors.+--+-- Note: the function 'qualLookupValue' has been extended to+-- allow the usage of the qualified list constructor (Prelude.:).++type ValueEnv = TopEnv ValueInfo++bindGlobalInfo :: (QualIdent -> a -> ValueInfo) -> ModuleIdent -> Ident -> a+ -> ValueEnv -> ValueEnv+bindGlobalInfo f m c ty = bindTopEnv c v . qualBindTopEnv qc v+ where qc = qualifyWith m c+ v = f qc ty++bindFun :: ModuleIdent -> Ident -> Maybe QualIdent -> Int -> TypeScheme+ -> ValueEnv -> ValueEnv+bindFun m f cm a ty+ | hasGlobalScope f = bindTopEnv f v . qualBindTopEnv qf v+ | otherwise = bindTopEnv f v+ where qf = qualifyWith m f+ v = Value qf cm a ty++qualBindFun :: ModuleIdent -> Ident -> Maybe QualIdent -> Int -> TypeScheme+ -> ValueEnv -> ValueEnv+qualBindFun m f cm a ty = qualBindTopEnv qf $ Value qf cm a ty+ where qf = qualifyWith m f++rebindFun :: ModuleIdent -> Ident -> Maybe QualIdent -> Int -> TypeScheme+ -> ValueEnv -> ValueEnv+rebindFun m f cm a ty+ | hasGlobalScope f = rebindTopEnv f v . qualRebindTopEnv qf v+ | otherwise = rebindTopEnv f v+ where qf = qualifyWith m f+ v = Value qf cm a ty++unbindFun :: Ident -> ValueEnv -> ValueEnv+unbindFun = unbindTopEnv++lookupValue :: Ident -> ValueEnv -> [ValueInfo]+lookupValue x tyEnv = lookupTopEnv x tyEnv ++! lookupTuple x++qualLookupValue :: QualIdent -> ValueEnv -> [ValueInfo]+qualLookupValue x tyEnv = qualLookupTopEnv x tyEnv+ ++! lookupTuple (unqualify x)++qualLookupValueUnique :: ModuleIdent -> QualIdent -> ValueEnv -> [ValueInfo]+qualLookupValueUnique m x tyEnv = case qualLookupValue x tyEnv of+ [] -> []+ [v] -> [v]+ vs -> case qualLookupValue (qualQualify m x) tyEnv of+ [] -> vs+ [v] -> [v]+ qvs -> qvs++lookupTuple :: Ident -> [ValueInfo]+lookupTuple c | isTupleId c = [tupleDCs !! (tupleArity c - 2)]+ | otherwise = []++tupleDCs :: [ValueInfo]+tupleDCs = map dataInfo tupleData+ where dataInfo (DataConstr _ tys) =+ let n = length tys+ in DataConstructor (qTupleId n) n (replicate n anonId) $+ ForAll n $ predType $ foldr TypeArrow (tupleType tys) tys+ dataInfo (RecordConstr _ _ _) =+ internalError $ "Env.Value.tupleDCs: " ++ show tupleDCs++-- Since all predefined types are free of existentially quantified type+-- variables and have an empty predicate set, we can ignore both of them+-- when entering the types into the value environment.++initDCEnv :: ValueEnv+initDCEnv = foldr predefDC emptyTopEnv+ [ (c, length tys, constrType (polyType ty) tys)+ | (ty, cs) <- predefTypes, DataConstr c tys <- cs ]+ where predefDC (c, a, ty) = predefTopEnv c' (DataConstructor c' a ls ty)+ where ls = replicate a anonId+ c' = qualify c+ constrType (ForAll n (PredType ps ty)) =+ ForAll n . PredType ps . foldr TypeArrow ty++-- The functions 'bindLocalVar' and 'bindLocalVars' add the type of one or+-- many local variables or functions to the value environment. In contrast+-- to global functions, we do not care about the name of the module containing+-- the variable or function's definition.++class ValueType t where+ toValueType :: Type -> t+ fromValueType :: t -> PredType++instance ValueType Type where+ toValueType = id+ fromValueType = predType++instance ValueType PredType where+ toValueType = predType+ fromValueType = id++bindLocalVars :: ValueType t => [(Ident, Int, t)] -> ValueEnv -> ValueEnv+bindLocalVars = flip $ foldr bindLocalVar++bindLocalVar :: ValueType t => (Ident, Int, t) -> ValueEnv -> ValueEnv+bindLocalVar (v, a, ty) =+ bindTopEnv v $ Value (qualify v) Nothing a $ typeScheme $ fromValueType ty
− src/Eval.lhs
@@ -1,96 +0,0 @@--% $Id: Eval.lhs,v 1.12 2004/02/08 15:35:12 wlux Exp $-%-% Copyright (c) 2001-2004, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{Eval.lhs}-\section{Collecting Evaluation Annotations}-The module \texttt{Eval} computes the evaluation annotation-environment. There is no need to check the annotations because this-happens already while checking the definitions of the module.-\begin{verbatim}--> module Eval(evalEnv) where--> import qualified Data.Map as Map--> import Curry.Syntax-> import Base---\end{verbatim}-The function \texttt{evalEnv} collects all evaluation annotations of-the module by traversing the syntax tree.-\begin{verbatim}--> evalEnv :: [Decl] -> EvalEnv-> evalEnv = foldr collectAnnotsDecl Map.empty--> collectAnnotsDecl :: Decl -> EvalEnv -> EvalEnv-> collectAnnotsDecl (EvalAnnot _ fs ev) env = foldr (flip Map.insert ev) env fs-> collectAnnotsDecl (FunctionDecl _ _ eqs) env = foldr collectAnnotsEqn env eqs-> collectAnnotsDecl (PatternDecl _ _ rhs) env = collectAnnotsRhs rhs env-> collectAnnotsDecl _ env = env--> collectAnnotsEqn :: Equation -> EvalEnv -> EvalEnv-> collectAnnotsEqn (Equation _ _ rhs) env = collectAnnotsRhs rhs env--> collectAnnotsRhs :: Rhs -> EvalEnv -> EvalEnv-> collectAnnotsRhs (SimpleRhs _ e ds) env =-> collectAnnotsExpr e (foldr collectAnnotsDecl env ds)-> collectAnnotsRhs (GuardedRhs es ds) env =-> foldr collectAnnotsCondExpr (foldr collectAnnotsDecl env ds) es--> collectAnnotsCondExpr :: CondExpr -> EvalEnv -> EvalEnv-> collectAnnotsCondExpr (CondExpr _ g e) env =-> collectAnnotsExpr g (collectAnnotsExpr e env)--> collectAnnotsExpr :: Expression -> EvalEnv -> EvalEnv-> collectAnnotsExpr (Literal _) env = env-> collectAnnotsExpr (Variable _) env = env-> collectAnnotsExpr (Constructor _) env = env-> collectAnnotsExpr (Paren e) env = collectAnnotsExpr e env-> collectAnnotsExpr (Typed e _) env = collectAnnotsExpr e env-> collectAnnotsExpr (Tuple _ es) env = foldr collectAnnotsExpr env es-> collectAnnotsExpr (List _ es) env = foldr collectAnnotsExpr env es-> collectAnnotsExpr (ListCompr _ e qs) env =-> collectAnnotsExpr e (foldr collectAnnotsStmt env qs)-> collectAnnotsExpr (EnumFrom e) env = collectAnnotsExpr e env-> collectAnnotsExpr (EnumFromThen e1 e2) env =-> collectAnnotsExpr e1 (collectAnnotsExpr e2 env)-> collectAnnotsExpr (EnumFromTo e1 e2) env =-> collectAnnotsExpr e1 (collectAnnotsExpr e2 env)-> collectAnnotsExpr (EnumFromThenTo e1 e2 e3) env =-> collectAnnotsExpr e1 (collectAnnotsExpr e2 (collectAnnotsExpr e3 env))-> collectAnnotsExpr (UnaryMinus _ e) env = collectAnnotsExpr e env-> collectAnnotsExpr (Apply e1 e2) env =-> collectAnnotsExpr e1 (collectAnnotsExpr e2 env)-> collectAnnotsExpr (InfixApply e1 _ e2) env =-> collectAnnotsExpr e1 (collectAnnotsExpr e2 env)-> collectAnnotsExpr (LeftSection e _) env = collectAnnotsExpr e env-> collectAnnotsExpr (RightSection _ e) env = collectAnnotsExpr e env-> collectAnnotsExpr (Lambda _ _ e) env = collectAnnotsExpr e env-> collectAnnotsExpr (Let ds e) env =-> foldr collectAnnotsDecl (collectAnnotsExpr e env) ds-> collectAnnotsExpr (Do sts e) env =-> foldr collectAnnotsStmt (collectAnnotsExpr e env) sts-> collectAnnotsExpr (IfThenElse _ e1 e2 e3) env =-> collectAnnotsExpr e1 (collectAnnotsExpr e2 (collectAnnotsExpr e3 env))-> collectAnnotsExpr (Case _ e alts) env =-> collectAnnotsExpr e (foldr collectAnnotsAlt env alts)-> collectAnnotsExpr (RecordConstr fs) env =-> foldr collectAnnotsExpr env (map fieldTerm fs)-> collectAnnotsExpr (RecordSelection e _) env = collectAnnotsExpr e env-> collectAnnotsExpr (RecordUpdate fs e) env =-> foldr collectAnnotsExpr (collectAnnotsExpr e env) (map fieldTerm fs)--> collectAnnotsStmt :: Statement -> EvalEnv -> EvalEnv-> collectAnnotsStmt (StmtExpr _ e) env = collectAnnotsExpr e env-> collectAnnotsStmt (StmtDecl ds) env = foldr collectAnnotsDecl env ds-> collectAnnotsStmt (StmtBind _ _ e) env = collectAnnotsExpr e env--> collectAnnotsAlt :: Alt -> EvalEnv -> EvalEnv-> collectAnnotsAlt (Alt _ _ rhs) env = collectAnnotsRhs rhs env--\end{verbatim}
+ src/Exports.hs view
@@ -0,0 +1,425 @@+{- |+ Module : $Header$+ Description : Computation of export interface+ Copyright : (c) 2000 - 2004 Wolfgang Lux+ 2005 Martin Engelke+ 2011 - 2016 Björn Peemöller+ 2015 Jan Tikovsky+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module provides the computation of the exported interface of a+ compiled module. The function 'exportInterface' uses the expanded export+ specifications and the corresponding environments in order to compute+ the interface of the module.+-}+module Exports (exportInterface) where++import Data.List (nub)+import qualified Data.Map as Map (foldrWithKey, toList)+import Data.Maybe (mapMaybe)+import qualified Data.Set as Set ( Set, empty, insert, deleteMin, fromList+ , member, toList )++import Curry.Base.Position+import Curry.Base.SpanInfo+import Curry.Base.Ident+import Curry.Syntax++import Base.CurryKinds (fromKind')+import Base.CurryTypes (fromQualType, fromQualPredType)+import Base.Messages+import Base.Types++import Env.Class+import Env.OpPrec (OpPrecEnv, PrecInfo (..), OpPrec (..), qualLookupP)+import Env.Instance+import Env.TypeConstructor ( TCEnv, TypeInfo (..), tcKind, clsKind+ , qualLookupTypeInfo )+import Env.Value (ValueEnv, ValueInfo (..), qualLookupValue)++import CompilerEnv++import Base.Kinds++-- ---------------------------------------------------------------------------+-- Computation of the interface+-- ---------------------------------------------------------------------------++-- After checking that the interface is not ambiguous, the compiler+-- generates the interface's declarations from the list of exported+-- functions and values. In order to make the interface more stable+-- against private changes in the module, we remove the hidden data+-- constructors of a data type in the interface when they occur+-- right-most in the declaration. In addition, newtypes whose constructor+-- is not exported are transformed into (abstract) data types.+--+-- If a type is imported from another module, its name is qualified with+-- the name of the module where it is defined. The same applies to an+-- exported function.++exportInterface :: CompilerEnv -> Module a -> Interface+exportInterface env (Module _ _ _ m (Just (Exporting _ es)) _ _) =+ exportInterface' m es (opPrecEnv env) (tyConsEnv env) (valueEnv env)+ (classEnv env) (instEnv env)+exportInterface _ (Module _ _ _ _ Nothing _ _) =+ internalError "Exports.exportInterface: no export specification"++exportInterface' :: ModuleIdent -> [Export] -> OpPrecEnv -> TCEnv -> ValueEnv+ -> ClassEnv -> InstEnv -> Interface+exportInterface' m es pEnv tcEnv vEnv clsEnv inEnv = Interface m imports decls'+ where+ tvs = filter (`notElem` tcs) identSupply+ tcs = mapMaybe (localIdent m) $ definedTypes decls'+ imports = map (IImportDecl NoPos) $ usedModules decls'+ precs = foldr (infixDecl m pEnv) [] es+ types = foldr (typeDecl m tcEnv clsEnv tvs) [] es+ values = foldr (valueDecl m vEnv tvs) [] es+ insts = Map.foldrWithKey (instDecl m tcEnv tvs) [] inEnv+ decls = precs ++ types ++ values ++ insts+ decls' = closeInterface m tcEnv clsEnv inEnv tvs Set.empty decls++infixDecl :: ModuleIdent -> OpPrecEnv -> Export -> [IDecl] -> [IDecl]+infixDecl m pEnv (Export _ f) ds = iInfixDecl m pEnv f ds+infixDecl m pEnv (ExportTypeWith _ tc cs) ds =+ foldr (iInfixDecl m pEnv . qualifyLike tc) ds cs+infixDecl _ _ _ _ = internalError "Exports.infixDecl: no pattern match"++iInfixDecl :: ModuleIdent -> OpPrecEnv -> QualIdent -> [IDecl] -> [IDecl]+iInfixDecl m pEnv op ds = case qualLookupP op pEnv of+ [] -> ds+ [PrecInfo _ (OpPrec f p)] -> IInfixDecl NoPos f p (qualUnqualify m op) : ds+ _ -> internalError "Exports.infixDecl"++-- Data types and renaming types whose constructors and field labels are+-- not exported are exported as abstract types, i.e., their constructors+-- do not appear in the interface. If only some constructors or field+-- labels of a type are not exported all constructors appear in the+-- interface, but a pragma marks the constructors and field labels which+-- are not exported as hidden to prevent their use in user code.++typeDecl :: ModuleIdent -> TCEnv -> ClassEnv -> [Ident] -> Export -> [IDecl]+ -> [IDecl]+typeDecl _ _ _ _ (Export _ _) ds = ds+typeDecl m tcEnv clsEnv tvs (ExportTypeWith _ tc xs) ds =+ case qualLookupTypeInfo tc tcEnv of+ [DataType tc' k cs]+ | null xs -> iTypeDecl IDataDecl m tvs tc' k [] [] : ds+ | otherwise -> iTypeDecl IDataDecl m tvs tc' k cs' hs : ds+ where hs = filter (`notElem` xs) (csIds ++ ls)+ cs' = map (constrDecl m n tvs) cs+ ls = nub (concatMap recordLabels cs')+ csIds = map constrIdent cs+ n = kindArity k+ [RenamingType tc' k c]+ | null xs -> iTypeDecl IDataDecl m tvs tc' k [] [] : ds+ | otherwise -> iTypeDecl INewtypeDecl m tvs tc' k nc hs : ds+ where hs = filter (`notElem` xs) (cId : ls)+ nc = newConstrDecl m tvs c+ ls = nrecordLabels nc+ cId = constrIdent c+ [AliasType tc' k n ty] -> ITypeDecl NoPos tc'' k' tvs' ty' : ds+ where tc'' = qualUnqualify m tc'+ k' = fromKind' k n+ tvs' = take n tvs+ ty' = fromQualType m tvs' ty+ [TypeClass qcls k ms] -> IClassDecl NoPos cx qcls' k' tv ms' hs : ds+ where qcls' = qualUnqualify m qcls+ cx = [ Constraint NoSpanInfo (qualUnqualify m scls)+ (VariableType NoSpanInfo tv)+ | scls <- superClasses qcls clsEnv ]+ k' = fromKind' k 0+ tv = head tvs+ ms' = map (methodDecl m tvs) ms+ hs = filter (`notElem` xs) (map methodName ms)+ _ -> internalError "Exports.typeDecl"+typeDecl _ _ _ _ _ _ = internalError "Exports.typeDecl: no pattern match"++iTypeDecl+ :: (Position -> QualIdent -> Maybe KindExpr -> [Ident] -> a -> [Ident] -> IDecl)+ -> ModuleIdent -> [Ident] -> QualIdent -> Kind -> a -> [Ident] -> IDecl+iTypeDecl f m tvs tc k x hs = f NoPos (qualUnqualify m tc) k' (take n tvs) x hs+ where n = kindArity k+ k' = fromKind' k n++constrDecl :: ModuleIdent -> Int -> [Ident] -> DataConstr -> ConstrDecl+constrDecl m _ tvs (DataConstr c [ty1, ty2])+ | isInfixOp c = ConOpDecl NoSpanInfo ty1' c ty2'+ where [ty1', ty2'] = map (fromQualType m tvs) [ty1, ty2]+constrDecl m _ tvs (DataConstr c tys) =+ ConstrDecl NoSpanInfo c tys'+ where tys' = map (fromQualType m tvs) tys+constrDecl m _ tvs (RecordConstr c ls tys) =+ RecordDecl NoSpanInfo c fs+ where+ tys' = map (fromQualType m tvs) tys+ fs = zipWith (FieldDecl NoSpanInfo . return) ls tys'++newConstrDecl :: ModuleIdent -> [Ident] -> DataConstr -> NewConstrDecl+newConstrDecl m tvs (DataConstr c tys)+ = NewConstrDecl NoSpanInfo c (fromQualType m tvs (head tys))+newConstrDecl m tvs (RecordConstr c ls tys)+ = NewRecordDecl NoSpanInfo c (head ls, fromQualType m tvs (head tys))++-- When exporting a class method, we have to remove the implicit class context.+-- Due to the sorting of the predicate set, this is fortunatly very easy. The+-- implicit class context is always the minimum element as the class variable+-- is assigned the index 0 and no other constraints on it are allowed.++methodDecl :: ModuleIdent -> [Ident] -> ClassMethod -> IMethodDecl+methodDecl m tvs (ClassMethod f a (PredType ps ty)) = IMethodDecl NoPos f a $+ fromQualPredType m tvs $ PredType (Set.deleteMin ps) ty++valueDecl :: ModuleIdent -> ValueEnv -> [Ident] -> Export -> [IDecl] -> [IDecl]+valueDecl m vEnv tvs (Export _ f) ds = case qualLookupValue f vEnv of+ [Value _ cm a (ForAll _ pty)] ->+ IFunctionDecl NoPos (qualUnqualify m f)+ (fmap (const (head tvs)) cm) a (fromQualPredType m tvs pty) : ds+ [Label _ _ _ ] -> ds -- Record labels are collected somewhere else.+ _ -> internalError $ "Exports.valueDecl: " ++ show f+valueDecl _ _ _ (ExportTypeWith _ _ _) ds = ds+valueDecl _ _ _ _ _ = internalError "Exports.valueDecl: no pattern match"++instDecl :: ModuleIdent -> TCEnv -> [Ident] -> InstIdent -> InstInfo -> [IDecl]+ -> [IDecl]+instDecl m tcEnv tvs ident@(cls, tc) info@(m', _, _) ds+ | qidModule cls /= Just m' && qidModule tc /= Just m' =+ iInstDecl m tcEnv tvs ident info : ds+ | otherwise = ds++iInstDecl :: ModuleIdent -> TCEnv -> [Ident] -> InstIdent -> InstInfo -> IDecl+iInstDecl m tcEnv tvs (cls, tc) (m', ps, is) =+ IInstanceDecl NoPos cx (qualUnqualify m cls) ty is mm+ where pty = PredType ps $ applyType (TypeConstructor tc) $+ map TypeVariable [0 .. n-1]+ QualTypeExpr _ cx ty = fromQualPredType m tvs pty+ n = kindArity (tcKind m tc tcEnv) - kindArity (clsKind m cls tcEnv)+ mm = if m == m' then Nothing else Just m'++-- The compiler determines the list of imported modules from the set of+-- module qualifiers that are used in the interface. Careful readers+-- probably will have noticed that the functions above carefully strip+-- the module prefix from all entities that are defined in the current+-- module. Note that the list of modules returned from+-- 'usedModules' is not necessarily a subset of the modules that+-- were imported into the current module. This will happen when an+-- imported module re-exports entities from another module. E.g., given+-- the three modules+--+-- @+-- module A where { data A = A; }+-- module B(A(..)) where { import A; }+-- module C where { import B; x = A; }+-- @+--+-- the interface for module @C@ will import module @A@ but not module @B@.++usedModules :: [IDecl] -> [ModuleIdent]+usedModules ds = nub' (modules ds [])+ where nub' = Set.toList . Set.fromList++class HasModule a where+ modules :: a -> [ModuleIdent] -> [ModuleIdent]++instance HasModule a => HasModule (Maybe a) where+ modules = maybe id modules++instance HasModule a => HasModule [a] where+ modules xs ms = foldr modules ms xs++instance HasModule IDecl where+ modules (IInfixDecl _ _ _ op) = modules op+ modules (HidingDataDecl _ tc _ _) = modules tc+ modules (IDataDecl _ tc _ _ cs _) = modules tc . modules cs+ modules (INewtypeDecl _ tc _ _ nc _) = modules tc . modules nc+ modules (ITypeDecl _ tc _ _ ty) = modules tc . modules ty+ modules (IFunctionDecl _ f _ _ qty) = modules f . modules qty+ modules (HidingClassDecl _ cx cls _ _) = modules cx . modules cls+ modules (IClassDecl _ cx cls _ _ ms _) =+ modules cx . modules cls . modules ms+ modules (IInstanceDecl _ cx cls ty _ mm) =+ modules cx . modules cls . modules ty . modules mm++instance HasModule ConstrDecl where+ modules (ConstrDecl _ _ tys) = modules tys+ modules (ConOpDecl _ ty1 _ ty2) = modules ty1 . modules ty2+ modules (RecordDecl _ _ fs) = modules fs++instance HasModule FieldDecl where+ modules (FieldDecl _ _ ty) = modules ty++instance HasModule NewConstrDecl where+ modules (NewConstrDecl _ _ ty) = modules ty+ modules (NewRecordDecl _ _ (_, ty)) = modules ty++instance HasModule IMethodDecl where+ modules (IMethodDecl _ _ _ qty) = modules qty++instance HasModule Constraint where+ modules (Constraint _ cls ty) = modules cls . modules ty++instance HasModule TypeExpr where+ modules (ConstructorType _ tc) = modules tc+ modules (ApplyType _ ty1 ty2) = modules ty1 . modules ty2+ modules (VariableType _ _) = id+ modules (TupleType _ tys) = modules tys+ modules (ListType _ ty) = modules ty+ modules (ArrowType _ ty1 ty2) = modules ty1 . modules ty2+ modules (ParenType _ ty) = modules ty+ modules (ForallType _ _ ty) = modules ty++instance HasModule QualTypeExpr where+ modules (QualTypeExpr _ cx ty) = modules cx . modules ty++instance HasModule QualIdent where+ modules = modules . qidModule++instance HasModule ModuleIdent where+ modules = (:)++-- After the interface declarations have been computed, the compiler+-- eventually must add hidden (data) type and class declarations to the+-- interface for all those types and classs which were used in the interface+-- but not exported from the current module, so that these type constructors+-- can always be distinguished from type variables. Besides hidden type and+-- class declarations, the compiler also adds instance declarations to the+-- interface. Since class and instance declarations added to an interface can+-- require the inclusion of further classes by their respective contexts,+-- closing an interface is implemented as a fix-point computation which+-- starts from the initial interface.++data IInfo = IOther | IType QualIdent | IClass QualIdent | IInst InstIdent+ deriving (Eq, Ord)++iInfo :: IDecl -> IInfo+iInfo (IInfixDecl _ _ _ _) = IOther+iInfo (HidingDataDecl _ tc _ _) = IType tc+iInfo (IDataDecl _ tc _ _ _ _) = IType tc+iInfo (INewtypeDecl _ tc _ _ _ _) = IType tc+iInfo (ITypeDecl _ _ _ _ _) = IOther+iInfo (HidingClassDecl _ _ cls _ _) = IClass cls+iInfo (IClassDecl _ _ cls _ _ _ _) = IClass cls+iInfo (IInstanceDecl _ _ cls ty _ _) = IInst (cls, typeConstr ty)+iInfo (IFunctionDecl _ _ _ _ _) = IOther++closeInterface :: ModuleIdent -> TCEnv -> ClassEnv -> InstEnv -> [Ident]+ -> Set.Set IInfo -> [IDecl] -> [IDecl]+closeInterface _ _ _ _ _ _ [] = []+closeInterface m tcEnv clsEnv inEnv tvs is (d:ds)+ | i == IOther =+ d : closeInterface m tcEnv clsEnv inEnv tvs is (ds ++ ds')+ | i `Set.member` is = closeInterface m tcEnv clsEnv inEnv tvs is ds+ | otherwise =+ d : closeInterface m tcEnv clsEnv inEnv tvs (Set.insert i is) (ds ++ ds')+ where i = iInfo d+ ds' = hiddenTypes m tcEnv clsEnv tvs d +++ instances m tcEnv inEnv tvs is i++hiddenTypes :: ModuleIdent -> TCEnv -> ClassEnv -> [Ident] -> IDecl -> [IDecl]+hiddenTypes m tcEnv clsEnv tvs d =+ map hiddenTypeDecl $ filter (not . isPrimTypeId) (usedTypes d [])+ where hiddenTypeDecl tc = case qualLookupTypeInfo (qualQualify m tc) tcEnv of+ [DataType _ k _] -> hidingDataDecl k+ [RenamingType _ k _] -> hidingDataDecl k+ [TypeClass cls k _] -> hidingClassDecl k $ superClasses cls clsEnv+ _ ->+ internalError $ "Exports.hiddenTypeDecl: " ++ show tc+ where hidingDataDecl k =+ let n = kindArity k+ k' = fromKind' k n+ in HidingDataDecl NoPos tc k' $ take n tvs+ hidingClassDecl k sclss =+ let cx = [ Constraint NoSpanInfo (qualUnqualify m scls)+ (VariableType NoSpanInfo tv)+ | scls <- sclss ]+ tv = head tvs+ k' = fromKind' k 0+ in HidingClassDecl NoPos cx tc k' tv++instances :: ModuleIdent -> TCEnv -> InstEnv -> [Ident] -> Set.Set IInfo+ -> IInfo -> [IDecl]+instances _ _ _ _ _ IOther = []+instances m tcEnv inEnv tvs is (IType tc) =+ [ iInstDecl m tcEnv tvs ident info+ | (ident@(cls, tc'), info@(m', _, _)) <- Map.toList inEnv,+ qualQualify m tc == tc',+ if qidModule cls == Just m' then Set.member (IClass (qualUnqualify m cls)) is+ else qidModule tc' == Just m' ]+instances m tcEnv inEnv tvs is (IClass cls) =+ [ iInstDecl m tcEnv tvs ident info+ | (ident@(cls', tc), info@(m', _, _)) <- Map.toList inEnv,+ qualQualify m cls == cls',+ qidModule cls' == Just m',+ m /= m' || isPrimTypeId tc+ || qidModule tc /= Just m+ || Set.member (IType (qualUnqualify m tc)) is ]+instances _ _ _ _ _ (IInst _) = []++definedTypes :: [IDecl] -> [QualIdent]+definedTypes ds = foldr definedType [] ds+ where+ definedType :: IDecl -> [QualIdent] -> [QualIdent]+ definedType (HidingDataDecl _ tc _ _) tcs = tc : tcs+ definedType (IDataDecl _ tc _ _ _ _) tcs = tc : tcs+ definedType (INewtypeDecl _ tc _ _ _ _) tcs = tc : tcs+ definedType (ITypeDecl _ tc _ _ _ ) tcs = tc : tcs+ definedType (HidingClassDecl _ _ cls _ _) tcs = cls : tcs+ definedType (IClassDecl _ _ cls _ _ _ _) tcs = cls : tcs+ definedType _ tcs = tcs++class HasType a where+ usedTypes :: a -> [QualIdent] -> [QualIdent]++instance HasType a => HasType (Maybe a) where+ usedTypes = maybe id usedTypes++instance HasType a => HasType [a] where+ usedTypes xs tcs = foldr usedTypes tcs xs++instance HasType IDecl where+ usedTypes (IInfixDecl _ _ _ _) = id+ usedTypes (HidingDataDecl _ _ _ _) = id+ usedTypes (IDataDecl _ _ _ _ cs _) = usedTypes cs+ usedTypes (INewtypeDecl _ _ _ _ nc _) = usedTypes nc+ usedTypes (ITypeDecl _ _ _ _ ty) = usedTypes ty+ usedTypes (IFunctionDecl _ _ _ _ qty) = usedTypes qty+ usedTypes (HidingClassDecl _ cx _ _ _) = usedTypes cx+ usedTypes (IClassDecl _ cx _ _ _ ms _) = usedTypes cx . usedTypes ms+ usedTypes (IInstanceDecl _ cx cls ty _ _) =+ usedTypes cx . (cls :) . usedTypes ty++instance HasType ConstrDecl where+ usedTypes (ConstrDecl _ _ tys) = usedTypes tys+ usedTypes (ConOpDecl _ ty1 _ ty2) =+ usedTypes ty1 . usedTypes ty2+ usedTypes (RecordDecl _ _ fs) = usedTypes fs++instance HasType FieldDecl where+ usedTypes (FieldDecl _ _ ty) = usedTypes ty++instance HasType NewConstrDecl where+ usedTypes (NewConstrDecl _ _ ty) = usedTypes ty+ usedTypes (NewRecordDecl _ _ (_, ty)) = usedTypes ty++instance HasType IMethodDecl where+ usedTypes (IMethodDecl _ _ _ qty) = usedTypes qty++instance HasType Constraint where+ usedTypes (Constraint _ cls ty) = (cls :) . usedTypes ty++instance HasType TypeExpr where+ usedTypes (ConstructorType _ tc) = (tc :)+ usedTypes (ApplyType _ ty1 ty2) = usedTypes ty1 . usedTypes ty2+ usedTypes (VariableType _ _) = id+ usedTypes (TupleType _ tys) = usedTypes tys+ usedTypes (ListType _ ty) = usedTypes ty+ usedTypes (ArrowType _ ty1 ty2) = usedTypes ty1 . usedTypes ty2+ usedTypes (ParenType _ ty) = usedTypes ty+ usedTypes (ForallType _ _ ty) = usedTypes ty++instance HasType QualTypeExpr where+ usedTypes (QualTypeExpr _ cx ty) = usedTypes cx . usedTypes ty
− src/Exports.lhs
@@ -1,463 +0,0 @@--% $Id: Exports.lhs,v 1.32 2004/02/13 19:23:57 wlux Exp $-%-% Copyright (c) 2000-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{Exports.lhs}-\section{Creating Interfaces}-This section describes how the exported interface of a compiled module-is computed.-\begin{verbatim}--> module Exports(expandInterface,exportInterface) where--> import Data.List-> import Data.Maybe-> import qualified Data.Set as Set-> import qualified Data.Map as Map--> import Curry.Syntax-> import Types-> import Curry.Base.Position-> import Curry.Base.Ident-> import Base-> import TopEnv--\end{verbatim}-The interface of a module is computed in two steps. The function-\texttt{expandInterface} checks the export specifications of the-module and expands them into a list containing all exported types and-functions, combining multiple exports for the same entity. The-expanded export specifications refer to the original names of all-entities. The function \texttt{exportInterface} uses the expanded-specifications and the corresponding environments in order to compute-to the interface of the module.-\begin{verbatim}--> expandInterface :: Module -> TCEnv -> ValueEnv -> Module-> expandInterface (Module m es ds) tcEnv tyEnv =-> --error (show es')-> case findDouble [unqualify tc | ExportTypeWith tc _ <- es'] of-> Nothing ->-> case findDouble ([c | ExportTypeWith _ cs <- es', c <- cs] ++-> [unqualify f | Export f <- es']) of-> Nothing -> Module m (Just (Exporting NoPos es')) ds-> Just v -> errorAt' (ambiguousExportValue v)-> Just tc -> errorAt' (ambiguousExportType tc) -> where ms = Set.fromList [fromMaybe m asM | ImportDecl _ m _ asM _ <- ds]-> es' = joinExports $-> maybe (expandLocalModule tcEnv tyEnv)-> (expandSpecs ms m tcEnv tyEnv)-> es--\end{verbatim}-While checking all export specifications, the compiler expands-specifications of the form \verb|T(..)| into-\texttt{T($C_1,\dots,C_n$)}, where $C_1,\dots,C_n$ are the data-constructors or the record labels of type \texttt{T}, and replaces -an export specification-\verb|module M| by specifications for all entities which are defined-in module \texttt{M} and imported into the current module with their-unqualified name. In order to distinguish exported type constructors-from exported functions, the former are translated into the equivalent-form \verb|T()|. Note that the export specification \texttt{x} may-export a type constructor \texttt{x} \emph{and} a global function-\texttt{x} at the same time.--\em{Note:} This frontend allows redeclaration and export of imported-identifiers.-\begin{verbatim}--> expandSpecs :: Set.Set ModuleIdent -> ModuleIdent -> TCEnv -> ValueEnv-> -> ExportSpec -> [Export]-> expandSpecs ms m tcEnv tyEnv (Exporting _ es) =-> concat (map (expandExport ms m tcEnv tyEnv) es)--> expandExport :: Set.Set ModuleIdent -> ModuleIdent -> TCEnv-> -> ValueEnv -> Export -> [Export]-> expandExport _ m tcEnv tyEnv (Export x) = expandThing m tcEnv tyEnv x-> expandExport _ m tcEnv _ (ExportTypeWith tc cs) =-> expandTypeWith m tcEnv tc cs-> expandExport _ m tcEnv tyEnv (ExportTypeAll tc) = -> expandTypeAll m tyEnv tcEnv tc-> expandExport ms m tcEnv tyEnv (ExportModule m')-> | m == m' = (if m `Set.member` ms then expandModule tcEnv tyEnv m else [])-> ++ expandLocalModule tcEnv tyEnv-> | m' `Set.member` ms = expandModule tcEnv tyEnv m'-> | otherwise = errorAt' (moduleNotImported m')--> expandThing :: ModuleIdent -> TCEnv -> ValueEnv -> QualIdent-> -> [Export]-> expandThing m tcEnv tyEnv tc =-> case qualLookupTC tc tcEnv of-> [] -> expandThing' m tyEnv tc Nothing-> [t] -> expandThing' m tyEnv tc (Just [ExportTypeWith (origName t) []])-> _ -> errorAt' (ambiguousType tc)--> expandThing' :: ModuleIdent -> ValueEnv -> QualIdent-> -> Maybe [Export] -> [Export]-> expandThing' m tyEnv f tcExport =-> case (qualLookupValue f tyEnv) of-> [] -> fromMaybe (errorAt' (undefinedEntity f)) tcExport-> [Value f' _] -> Export f' : fromMaybe [] tcExport-> [_] -> fromMaybe (errorAt' (exportDataConstr f)) tcExport-> vs -> case (qualLookupValue (qualQualify m f) tyEnv) of-> [] -> fromMaybe (errorAt' (undefinedEntity f)) tcExport-> [Value f'' _] -> Export f'' : fromMaybe [] tcExport-> [_] -> fromMaybe (errorAt' (exportDataConstr f)) tcExport-> _ -> errorAt' (ambiguousName f)--> expandTypeWith :: ModuleIdent -> TCEnv -> QualIdent -> [Ident] -> -> [Export]-> expandTypeWith m tcEnv tc cs =-> case qualLookupTC tc tcEnv of-> [] -> errorAt' (undefinedType tc)-> [t]-> | isDataType t -> [ExportTypeWith (origName t)-> (map (checkConstr (constrs t)) (nub cs))]-> | isRecordType t -> [ExportTypeWith (origName t)-> (map (checkLabel (labels t)) (nub cs))]-> | otherwise -> errorAt' (nonDataType tc)-> _ -> errorAt' (ambiguousType tc)-> where checkConstr cs c-> | c `elem` cs = c-> | otherwise = errorAt' (undefinedDataConstr tc c)-> checkLabel ls l-> | l' `elem` ls = l'-> | otherwise = errorAt' (undefinedLabel tc l)-> where l' = renameLabel l--> expandTypeAll :: ModuleIdent -> ValueEnv -> TCEnv -> QualIdent -> -> [Export]-> expandTypeAll m tyEnv tcEnv tc =-> case qualLookupTC tc tcEnv of-> [] -> errorAt' (undefinedType tc)-> [t]-> | isDataType t -> [exportType tyEnv t]-> | isRecordType t -> exportRecord m t-> | otherwise -> errorAt' (nonDataType tc)-> _ -> errorAt' (ambiguousType tc)--> expandLocalModule :: TCEnv -> ValueEnv -> [Export]-> expandLocalModule tcEnv tyEnv =-> [exportType tyEnv t | (_,t) <- localBindings tcEnv] ++-> [Export f' | (f,Value f' _) <- localBindings tyEnv, f == unRenameIdent f]--> expandModule :: TCEnv -> ValueEnv -> ModuleIdent -> [Export]-> expandModule tcEnv tyEnv m =-> [exportType tyEnv t | (_,t) <- moduleImports m tcEnv] ++-> [Export f | (_,Value f _) <- moduleImports m tyEnv]--> exportType :: ValueEnv -> TypeInfo -> Export-> exportType tyEnv t -> | isRecordType t -- = ExportTypeWith (origName t) (labels t)-> = let ls = labels t-> r = origName t-> in case (lookupValue (head ls) tyEnv) of-> [Label _ r' _] -> if r == r' then ExportTypeWith r ls-> else ExportTypeWith r []-> _ -> internalError "exportType"-> | otherwise = ExportTypeWith (origName t) (constrs t)--> exportRecord :: ModuleIdent -> TypeInfo -> [Export]-> exportRecord m t = [ExportTypeWith (origName t) (labels t)]--\end{verbatim}-The expanded list of exported entities may contain duplicates. These-are removed by the function \texttt{joinExports}.-\begin{verbatim}--> joinExports :: [Export] -> [Export]-> joinExports es =-> [ExportTypeWith tc cs | (tc,cs) <- Map.toList (foldr joinType Map.empty es)] ++-> [Export f | f <- Set.toList (foldr joinFun Set.empty es)]--> joinType :: Export -> Map.Map QualIdent [Ident] -> Map.Map QualIdent [Ident]-> joinType (Export _) tcs = tcs-> joinType (ExportTypeWith tc cs) tcs =-> Map.insertWith union tc cs tcs--> joinFun :: Export -> Set.Set QualIdent -> Set.Set QualIdent-> joinFun (Export f) fs = f `Set.insert` fs-> joinFun (ExportTypeWith _ _) fs = fs--\end{verbatim}-After checking that the interface is not ambiguous, the compiler-generates the interface's declarations from the list of exported-functions and values. In order to make the interface more stable-against private changes in the module, we remove the hidden data-constructors of a data type in the interface when they occur-right-most in the declaration. In addition, newtypes whose constructor-is not exported are transformed into (abstract) data types.--If a type is imported from another module, its name is qualified with-the name of the module where it is defined. The same applies to an-exported function.-\begin{verbatim}--> exportInterface :: Module -> PEnv -> TCEnv -> ValueEnv -> Interface-> exportInterface (Module m (Just (Exporting _ es)) _) pEnv tcEnv tyEnv =-> Interface m (imports ++ precs ++ hidden ++ ds)-> where imports = map (IImportDecl NoPos) (usedModules ds)-> precs = foldr (infixDecl m pEnv) [] es-> hidden = map (hiddenTypeDecl m tcEnv) (hiddenTypes ds)-> ds = foldr (typeDecl m tcEnv) (foldr (funDecl m tyEnv) [] es) es-> exportInterface (Module _ Nothing _) _ _ _ = internalError "exportInterface"--> infixDecl :: ModuleIdent -> PEnv -> Export -> [IDecl] -> [IDecl]-> infixDecl m pEnv (Export f) ds = iInfixDecl m pEnv f ds-> infixDecl m pEnv (ExportTypeWith tc cs) ds =-> foldr (iInfixDecl m pEnv . qualifyLike (qualidMod tc)) ds cs-> where qualifyLike = maybe qualify qualifyWith--> iInfixDecl :: ModuleIdent -> PEnv -> QualIdent -> [IDecl] -> [IDecl]-> iInfixDecl m pEnv op ds =-> case qualLookupP op pEnv of-> [] -> ds-> [PrecInfo _ (OpPrec fix pr)] ->-> IInfixDecl NoPos fix pr (qualUnqualify m op) : ds-> _ -> internalError "infixDecl"--> typeDecl :: ModuleIdent -> TCEnv -> Export -> [IDecl] -> [IDecl]-> typeDecl _ _ (Export _) ds = ds-> typeDecl m tcEnv (ExportTypeWith tc cs) ds =-> case qualLookupTC tc tcEnv of-> [DataType tc n cs'] ->-> iTypeDecl IDataDecl m tc n-> (constrDecls m (drop n nameSupply) cs cs') : ds-> [RenamingType tc n (Data c n' ty)]-> | c `elem` cs ->-> iTypeDecl INewtypeDecl m tc n (NewConstrDecl NoPos tvs c ty') : ds-> | otherwise -> iTypeDecl IDataDecl m tc n [] : ds-> where tvs = take n' (drop n nameSupply)-> ty' = fromQualType m ty-> [AliasType tc n ty] ->-> case ty of -> TypeRecord fs _ ->-> let ty' = TypeRecord (filter (\ (l,_) -> elem l cs) fs) Nothing-> in iTypeDecl ITypeDecl m tc n (fromQualType m ty') : ds-> _ -> iTypeDecl ITypeDecl m tc n (fromQualType m ty) : ds-> _ -> internalError "typeDecl"--> iTypeDecl :: (Position -> QualIdent -> [Ident] -> a -> IDecl)-> -> ModuleIdent -> QualIdent -> Int -> a -> IDecl-> iTypeDecl f m tc n = f NoPos (qualUnqualify m tc) (take n nameSupply)--> constrDecls :: ModuleIdent -> [Ident] -> [Ident] -> [Maybe (Data [Type])]-> -> [Maybe ConstrDecl]-> constrDecls m tvs cs = clean . map (>>= constrDecl m tvs)-> where clean = reverse . dropWhile isNothing . reverse-> constrDecl m tvs (Data c n tys)-> | c `elem` cs =-> Just (iConstrDecl (take n tvs) c (map (fromQualType m) tys))-> | otherwise = Nothing--> iConstrDecl :: [Ident] -> Ident -> [TypeExpr] -> ConstrDecl-> iConstrDecl tvs op [ty1,ty2]-> | isInfixOp op = ConOpDecl NoPos tvs ty1 op ty2-> iConstrDecl tvs c tys = ConstrDecl NoPos tvs c tys--> funDecl :: ModuleIdent -> ValueEnv -> Export -> [IDecl] -> [IDecl]-> funDecl m tyEnv (Export f) ds =-> case qualLookupValue f tyEnv of-> [Value _ (ForAll _ ty)] ->-> IFunctionDecl NoPos (qualUnqualify m f) (arrowArity ty) -> (fromQualType m ty) : ds-> _ -> internalError ("funDecl: " ++ show f)-> funDecl _ _ (ExportTypeWith _ _) ds = ds---\end{verbatim}-The compiler determines the list of imported modules from the set of-module qualifiers that are used in the interface. Careful readers-probably will have noticed that the functions above carefully strip-the module prefix from all entities that are defined in the current-module. Note that the list of modules returned from-\texttt{usedModules} is not necessarily a subset of the modules that-were imported into the current module. This will happen when an-imported module re-exports entities from another module. E.g., given-the three modules-\begin{verbatim}-module A where { data A = A; }-module B(A(..)) where { import A; }-module C where { import B; x = A; }-\end{verbatim}-the interface for module \texttt{C} will import module \texttt{A} but-not module \texttt{B}.-\begin{verbatim}--> usedModules :: [IDecl] -> [ModuleIdent]-> usedModules ds = nub (catMaybes (map qualidMod (foldr identsDecl [] ds)))-> where nub = Set.toList . Set.fromList--> identsDecl :: IDecl -> [QualIdent] -> [QualIdent]-> identsDecl (IDataDecl _ tc _ cs) xs =-> tc : foldr identsConstrDecl xs (catMaybes cs)-> identsDecl (INewtypeDecl _ tc _ nc) xs = tc : identsNewConstrDecl nc xs-> identsDecl (ITypeDecl _ tc _ ty) xs = tc : identsType ty xs-> identsDecl (IFunctionDecl _ f _ ty) xs = f : identsType ty xs--> identsConstrDecl :: ConstrDecl -> [QualIdent] -> [QualIdent]-> identsConstrDecl (ConstrDecl _ _ _ tys) xs = foldr identsType xs tys-> identsConstrDecl (ConOpDecl _ _ ty1 _ ty2) xs =-> identsType ty1 (identsType ty2 xs)--> identsNewConstrDecl :: NewConstrDecl -> [QualIdent] -> [QualIdent]-> identsNewConstrDecl (NewConstrDecl _ _ _ ty) xs = identsType ty xs--> identsType :: TypeExpr -> [QualIdent] -> [QualIdent]-> identsType (ConstructorType tc tys) xs = tc : foldr identsType xs tys-> identsType (VariableType _) xs = xs-> identsType (TupleType tys) xs = foldr identsType xs tys-> identsType (ListType ty) xs = identsType ty xs-> identsType (ArrowType ty1 ty2) xs = identsType ty1 (identsType ty2 xs)-> identsType (RecordType fs rty) xs =-> foldr identsType (maybe xs (\ty -> identsType ty xs) rty) (map snd fs)--\end{verbatim}-After the interface declarations have been computed, the compiler-eventually must add hidden (data) type declarations to the interface-for all those types which were used in the interface but not exported-from the current module, so that these type constructors can always be-distinguished from type variables.-\begin{verbatim}--> hiddenTypeDecl :: ModuleIdent -> TCEnv -> QualIdent -> IDecl-> hiddenTypeDecl m tcEnv tc =-> case qualLookupTC (qualQualify m tc) tcEnv of-> [DataType _ n _] -> hidingDataDecl tc n-> [RenamingType _ n _] -> hidingDataDecl tc n-> _ -> internalError "hiddenTypeDecl"-> where hidingDataDecl tc n =-> HidingDataDecl NoPos (unqualify tc) (take n nameSupply)--> hiddenTypes :: [IDecl] -> [QualIdent]-> hiddenTypes ds = [tc | tc <- Set.toList tcs, not (isQualified tc)]-> where tcs = foldr Set.delete (Set.fromList (usedTypes ds))-> (definedTypes ds)--> usedTypes :: [IDecl] -> [QualIdent]-> usedTypes ds = foldr usedTypesDecl [] ds--> usedTypesDecl :: IDecl -> [QualIdent] -> [QualIdent]-> usedTypesDecl (IDataDecl _ _ _ cs) tcs =-> foldr usedTypesConstrDecl tcs (catMaybes cs)-> usedTypesDecl (INewtypeDecl _ _ _ nc) tcs = usedTypesNewConstrDecl nc tcs-> usedTypesDecl (ITypeDecl _ _ _ ty) tcs = usedTypesType ty tcs-> usedTypesDecl (IFunctionDecl _ _ _ ty) tcs = usedTypesType ty tcs--> usedTypesConstrDecl :: ConstrDecl -> [QualIdent] -> [QualIdent]-> usedTypesConstrDecl (ConstrDecl _ _ _ tys) tcs = foldr usedTypesType tcs tys-> usedTypesConstrDecl (ConOpDecl _ _ ty1 _ ty2) tcs =-> usedTypesType ty1 (usedTypesType ty2 tcs)--> usedTypesNewConstrDecl :: NewConstrDecl -> [QualIdent] -> [QualIdent]-> usedTypesNewConstrDecl (NewConstrDecl _ _ _ ty) tcs = usedTypesType ty tcs--> usedTypesType :: TypeExpr -> [QualIdent] -> [QualIdent]-> usedTypesType (ConstructorType tc tys) tcs = tc : foldr usedTypesType tcs tys-> usedTypesType (VariableType _) tcs = tcs-> usedTypesType (TupleType tys) tcs = foldr usedTypesType tcs tys-> usedTypesType (ListType ty) tcs = usedTypesType ty tcs-> usedTypesType (ArrowType ty1 ty2) tcs =-> usedTypesType ty1 (usedTypesType ty2 tcs)-> usedTypesType (RecordType fs rty) tcs =-> foldr usedTypesType -> (maybe tcs (\ty -> usedTypesType ty tcs) rty) -> (map snd fs)--> definedTypes :: [IDecl] -> [QualIdent]-> definedTypes ds = foldr definedType [] ds--> definedType :: IDecl -> [QualIdent] -> [QualIdent]-> definedType (IDataDecl _ tc _ _) tcs = tc : tcs-> definedType (INewtypeDecl _ tc _ _) tcs = tc : tcs-> definedType (ITypeDecl _ tc _ _) tcs = tc : tcs-> definedType (IFunctionDecl _ _ _ _) tcs = tcs--\end{verbatim}-Auxiliary definitions-\begin{verbatim}---> isDataType :: TypeInfo -> Bool-> isDataType (DataType _ _ _) = True-> isDataType (RenamingType _ _ _) = True-> isDataType (AliasType _ _ _) = False--> isRecordType :: TypeInfo -> Bool-> isRecordType (AliasType _ _ (TypeRecord _ _)) = True-> isRecordType _ = False--> constrs :: TypeInfo -> [Ident]-> constrs (DataType _ _ cs) = [c | Just (Data c _ _) <- cs]-> constrs (RenamingType _ _ (Data c _ _)) = [c]-> constrs (AliasType _ _ _) = []--> labels :: TypeInfo -> [Ident]-> labels (AliasType _ _ (TypeRecord fs _)) = map fst fs-> labels _ = []--\end{verbatim}-Error messages-\begin{verbatim}--> undefinedEntity :: QualIdent -> (Position,String)-> undefinedEntity x =-> (positionOfQualIdent x,-> "Entity " ++ qualName x ++ " in export list is not defined")--> undefinedType :: QualIdent -> (Position,String)-> undefinedType tc = -> (positionOfQualIdent tc,-> "Type " ++ qualName tc ++ " in export list is not defined")--> moduleNotImported :: ModuleIdent -> (Position,String)-> moduleNotImported m = -> (positionOfModuleIdent m,-> "Module " ++ moduleName m ++ " not imported")--> ambiguousExportType :: Ident -> (Position,String)-> ambiguousExportType x = -> (positionOfIdent x,-> "Ambiguous export of type " ++ name x)--> ambiguousExportValue :: Ident -> (Position,String)-> ambiguousExportValue x = -> (positionOfIdent x,-> "Ambiguous export of " ++ name x)--> ambiguousType :: QualIdent -> (Position,String)-> ambiguousType tc = -> (positionOfQualIdent tc,-> "Ambiguous type " ++ qualName tc)--> ambiguousName :: QualIdent -> (Position,String)-> ambiguousName x = -> (positionOfQualIdent x,-> "Ambiguous name " ++ qualName x)--> exportDataConstr :: QualIdent -> (Position,String)-> exportDataConstr c = -> (positionOfQualIdent c,-> "Data constructor " ++ qualName c ++ " in export list")--> nonDataType :: QualIdent -> (Position,String)-> nonDataType tc = -> (positionOfQualIdent tc,-> qualName tc ++ " is not a data type")--> undefinedDataConstr :: QualIdent -> Ident -> (Position,String)-> undefinedDataConstr tc c =-> (positionOfIdent c, -> name c ++ " is not a data constructor of type " ++ qualName tc)--> undefinedLabel :: QualIdent -> Ident -> (Position,String)-> undefinedLabel r l =-> (positionOfIdent l, -> name l ++ " is not a label of the record " ++ qualName r)--\end{verbatim}
+ src/Files/CymakePath.hs view
@@ -0,0 +1,32 @@+{- |+ Module : $Header$+ Description : File pathes+ Copyright : (c) 2011, Björn Peemöller (bjp@informatik.uni-kiel.de)+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module contains functions to obtain the version number and path+ of the front end binary.+-}+module Files.CymakePath (getCymake, cymakeGreeting, cymakeVersion) where++import Data.Version (showVersion)+import System.FilePath ((</>))+import Paths_curry_frontend++-- | Show a greeting of the current front end+cymakeGreeting :: String+cymakeGreeting = "This is the Curry front end, version " ++ cymakeVersion++-- | Retrieve the version number of cymake+cymakeVersion :: String+cymakeVersion = showVersion version++-- | Retrieve the location of the front end executable+getCymake :: IO String+getCymake = do+ cymakeDir <- getBinDir+ return $ cymakeDir </> "curry-frontend"
− src/GenAbstractCurry.hs
@@ -1,1041 +0,0 @@---------------------------------------------------------------------------------------------------------------------------------------------------------------------- GenAbstractCurry - Generates an AbstractCurry program term--- (type 'CurryProg')------ July 2005,--- Martin Engelke (men@informatik.uni-kiel.de)----module GenAbstractCurry (genTypedAbstract, - genUntypedAbstract) where--import qualified Data.Map as Map-import qualified Data.Set as Set-import Data.Maybe-import Data.List-import Data.Char--import Curry.Syntax-import Curry.Syntax.Utils-import Curry.AbstractCurry--import Base-import Types-import Curry.Base.Ident-import Curry.Base.Position-import TopEnv-------------------------------------------------------------------------------------- Generates standard (type infered) AbstractCurry code from a CurrySyntax--- module. The function needs the type environment 'tyEnv' to determin the--- infered function types.-genTypedAbstract :: ValueEnv -> TCEnv -> Module -> CurryProg-genTypedAbstract tyEnv tcEnv mod- = genAbstract (genAbstractEnv TypedAcy tyEnv tcEnv mod) mod----- Generates untyped AbstractCurry code from a CurrySyntax module. The type--- signature takes place in every function type annotation, if it exists, --- otherwise the dummy type "Prelude.untyped" is used.-genUntypedAbstract :: ValueEnv -> TCEnv -> Module -> CurryProg-genUntypedAbstract tyEnv tcEnv mod- = genAbstract (genAbstractEnv UntypedAcy tyEnv tcEnv mod) mod--------------------------------------------------------------------------------------------------------------------------------------------------------------------- Private...---- Generates an AbstractCurry program term from the syntax tree-genAbstract :: AbstractEnv -> Module -> CurryProg-genAbstract env (Module mid exp decls)- = let partitions = foldl partitionDecl emptyPartitions decls- modname = moduleName mid - (imps, _) - = mapfoldl genImportDecl env (reverse (importDecls partitions))- (types, _) - = mapfoldl genTypeDecl env (reverse (typeDecls partitions))- (_, funcs) - = Map.mapAccumWithKey (genFuncDecl False) - env - (funcDecls partitions)- (ops, _) - = mapfoldl genOpDecl env (reverse (opDecls partitions))- in CurryProg modname imps types (Map.elems funcs) ops--------------------------------------------------------------------------------------------------------------------------------------------------------------------- The following types and functions can be used to spread a list of--- CurrySyntax declarations into four parts: a list of imports, a list of--- type declarations (data types and type synonyms), a table of function--- declarations and a list of fixity declarations.----- Inserts a CurrySyntax top level declaration into a partition.--- Note: declarations are collected in reverse order.-partitionDecl :: Partitions -> Decl -> Partitions-partitionDecl partitions (TypeSig pos ids typeexpr)- = partitionFuncDecls (\id -> TypeSig pos [id] typeexpr) partitions ids-partitionDecl partitions (EvalAnnot pos ids annot)- = partitionFuncDecls (\id -> EvalAnnot pos [id] annot) partitions ids-partitionDecl partitions (FunctionDecl pos id equs)- = partitionFuncDecls (const (FunctionDecl pos id equs)) partitions [id]-partitionDecl partitions (ExternalDecl pos conv name id typeexpr)- = partitionFuncDecls (const (ExternalDecl pos conv name id typeexpr))- partitions- [id]-partitionDecl partitions (FlatExternalDecl pos ids)- = partitionFuncDecls (\id -> FlatExternalDecl pos [id]) partitions ids-partitionDecl partitions (InfixDecl pos fix prec idents)- = partitions {opDecls = map (\id -> (InfixDecl pos fix prec [id])) idents- ++ opDecls partitions }-partitionDecl partitions decl- = case decl of- ImportDecl _ _ _ _ _ - -> partitions {importDecls = decl: importDecls partitions }- DataDecl _ _ _ _ - -> partitions {typeDecls = decl : typeDecls partitions }- TypeDecl _ _ _ _ - -> partitions {typeDecls = decl : typeDecls partitions }- _ -> partitions------partitionFuncDecls :: (Ident -> Decl) -> Partitions -> [Ident] -> Partitions-partitionFuncDecls genDecl partitions ids- = partitions {funcDecls = foldl partitionFuncDecl (funcDecls partitions) ids}- where- partitionFuncDecl funcs' id- = Map.insert id (genDecl id : fromMaybe [] (Map.lookup id funcs')) funcs'----- Data type for representing partitions of CurrySyntax declarations--- (according to the definition of the AbstractCurry program--- representation; type 'CurryProg').--- Since a complete function declaration usually consist of more than one--- declaration (e.g. rules, type signature etc.), it is necessary --- to collect them within an association list-data Partitions = Partitions {importDecls :: [Decl],- typeDecls :: [Decl],- funcDecls :: Map.Map Ident [Decl],- opDecls :: [Decl]- } deriving Show---- Generates initial partitions.-emptyPartitions = Partitions {importDecls = [],- typeDecls = [],- funcDecls = Map.empty,- opDecls = []- } ------------------------------------------------------------------------------------- The following functions convert CurrySyntax terms to AbstractCurry--- terms.-----genImportDecl :: AbstractEnv -> Decl -> (String, AbstractEnv)-genImportDecl env (ImportDecl _ mid _ _ _) = (moduleName mid, env)------genTypeDecl :: AbstractEnv -> Decl -> (CTypeDecl, AbstractEnv)-genTypeDecl env (DataDecl _ ident params cdecls)- = let (idxs, env1) = mapfoldl genTVarIndex env params- (cdecls', env2) = mapfoldl genConsDecl env1 cdecls- in (CType (genQName True env2 (qualifyWith (moduleId env) ident))- (genVisibility env2 ident)- (zip idxs (map name params))- cdecls',- resetScope env2)-genTypeDecl env (TypeDecl _ ident params typeexpr)- = let (idxs, env1) = mapfoldl genTVarIndex env params- (typeexpr', env2) = genTypeExpr env1 typeexpr- in (CTypeSyn (genQName True env2 (qualifyWith (moduleId env) ident))- (genVisibility env2 ident)- (zip idxs (map name params))- typeexpr',- resetScope env2)-genTypeDecl env (NewtypeDecl pos ident _ _)- = errorAt pos "'newtype' declarations are not supported in AbstractCurry"-genTypeDecl env _- = internalError "unexpected declaration"------genConsDecl :: AbstractEnv -> ConstrDecl -> (CConsDecl, AbstractEnv)-genConsDecl env (ConstrDecl _ _ ident params)- = let (params', env') = mapfoldl genTypeExpr env params- in (CCons (genQName False env' (qualifyWith (moduleId env) ident))- (length params)- (genVisibility env' ident)- params',- env')-genConsDecl env (ConOpDecl pos ids ltype ident rtype)- = genConsDecl env (ConstrDecl pos ids ident [ltype, rtype])------genTypeExpr :: AbstractEnv -> TypeExpr -> (CTypeExpr, AbstractEnv)-genTypeExpr env (ConstructorType qident targs)- = let (targs', env') = mapfoldl genTypeExpr env targs- in (CTCons (genQName True env' qident) targs', env')-genTypeExpr env (VariableType ident)- | isJust midx = (CTVar (fromJust midx, name ident), env)- | otherwise = (CTVar (idx, name ident), env')- where- midx = getTVarIndex env ident- (idx, env') = genTVarIndex env ident-genTypeExpr env (TupleType targs)- | len > 1 = genTypeExpr env (ConstructorType (qTupleId len) targs)- | len == 0 = genTypeExpr env (ConstructorType qUnitId targs)- | len == 1 = genTypeExpr env (head targs)- where len = length targs-genTypeExpr env (ListType typeexpr)- = genTypeExpr env (ConstructorType qListId [typeexpr])-genTypeExpr env (ArrowType texpr1 texpr2)- = let (texpr1', env1) = genTypeExpr env texpr1- (texpr2', env2) = genTypeExpr env1 texpr2- in (CFuncType texpr1' texpr2', env2)-genTypeExpr env (RecordType fss mr)- = let fs = concatMap (\ (ls,typeexpr) -> map (\l -> (l,typeexpr)) ls) fss- (ls,ts) = unzip fs- (ts',env1) = mapfoldl genTypeExpr env ts- ls' = map name ls- in case mr of- Nothing- -> (CRecordType (zip ls' ts') Nothing, env1)- Just tvar@(VariableType _)- -> let (CTVar iname, env2) = genTypeExpr env1 tvar- in (CRecordType (zip ls' ts') (Just iname), env2)- (Just r@(RecordType _ _))- -> let (CRecordType fields rbase, env2) = genTypeExpr env1 r- fields' = foldr (uncurry insertEntry) - fields- (zip ls' ts')- in (CRecordType fields' rbase, env2)- _ -> internalError "illegal record base"----- NOTE: every infix declaration must declare exactly one operator.-genOpDecl :: AbstractEnv -> Decl -> (COpDecl, AbstractEnv)-genOpDecl env (InfixDecl _ fix prec [ident])- = (COp (genQName False env (qualifyWith (moduleId env) ident))- (genFixity fix)- (fromInteger prec),- env)------genFixity :: Infix -> CFixity-genFixity InfixL = CInfixlOp-genFixity InfixR = CInfixrOp-genFixity Infix = CInfixOp----- Generate an AbstractCurry function declaration from a list of CurrySyntax--- function declarations.--- NOTES: --- - every declaration in 'decls' must declare exactly one function.--- - since infered types are internally represented in flat style,--- all type variables are renamed with generated symbols when--- generating typed AbstractCurry.-genFuncDecl :: Bool -> AbstractEnv -> Ident -> [Decl] -> (AbstractEnv, CFuncDecl)-genFuncDecl isLocal env ident decls- | not (null decls)- = let name = genQName False env (qualify ident)- visibility = genVisibility env ident- evalannot = maybe CFlex - (\ (EvalAnnot _ _ ea) -> genEvalAnnot ea)- (find isEvalAnnot decls)- (mtype, env1) = maybe (Nothing, env) - (\ (t, env') -> (Just t, env'))- (genFuncType env decls)- (rules, env2) = maybe ([], env1)- (\ (FunctionDecl _ _ equs)- -> mapfoldl genRule env1 equs)- (find isFunctionDecl decls)- mexternal = fmap genExternal (find isExternal decls)- arity = compArity mtype rules- typeexpr = fromMaybe (CTCons ("Prelude","untyped") []) mtype- rule = compRule evalannot rules mexternal- env3 = if isLocal then env1 else resetScope env2- in (env3, CFunc name arity visibility typeexpr rule)- | otherwise- = internalError ("missing declaration for function \""- ++ show ident ++ "\"")- where- genFuncType env decls- | acytype == UntypedAcy- = fmap (genTypeSig env) (find isTypeSig decls)- | acytype == TypedAcy- = fmap (genTypeExpr env) mftype- | otherwise - = Nothing- where - acytype = acyType env- mftype | isLocal - = lookupType ident (typeEnv env)- | otherwise - = qualLookupType (qualifyWith (moduleId env) ident)- (typeEnv env)-- genTypeSig env (TypeSig _ _ ts) = genTypeExpr env ts- genTypeSig env (ExternalDecl _ _ _ _ ts) = genTypeExpr env ts-- genExternal (ExternalDecl _ _ mname ident _)- = CExternal (fromMaybe (name ident) mname)- genExternal (FlatExternalDecl _ [ident])- = CExternal (name ident)- genExternal _- = internalError "illegal external declaration occured"-- compArity mtypeexpr rules- | not (null rules)- = let (CRule patts _ _) = head rules in length patts- | otherwise- = maybe (internalError ("unable to compute arity for function \""- ++ show ident ++ "\""))- compArityFromType- mtypeexpr-- compArityFromType (CTVar _) = 0- compArityFromType (CFuncType _ t2) = 1 + compArityFromType t2- compArityFromType (CTCons _ _) = 0-- compRule evalannot rules mexternal- | not (null rules) = CRules evalannot rules- | otherwise- = fromMaybe (internalError ("missing rule for function \""- ++ show ident ++ "\""))- mexternal------genRule :: AbstractEnv -> Equation -> (CRule, AbstractEnv)-genRule env (Equation pos lhs rhs)- = let (patts, env1) = mapfoldl (genPattern pos)- (beginScope env) - (simplifyLhs lhs)- (locals, env2) = genLocalDecls env1 (simplifyRhsLocals rhs)- (crhss, env3) = mapfoldl (genCrhs pos) env2 (simplifyRhsExpr rhs)- in (CRule patts crhss locals, endScope env3)------genCrhs :: Position -> AbstractEnv -> (Expression, Expression) - -> ((CExpr, CExpr), AbstractEnv)-genCrhs pos env (cond, expr)- = let (cond', env1) = genExpr pos env cond- (expr', env2) = genExpr pos env1 expr- in ((cond', expr'), env2)----- NOTE: guarded expressions and 'where' declarations in local pattern--- declarations are not supported in PAKCS-genLocalDecls :: AbstractEnv -> [Decl] -> ([CLocalDecl], AbstractEnv)-genLocalDecls env decls- = genLocals (foldl genLocalIndex env decls)- (funcDecls (foldl partitionDecl emptyPartitions decls))- decls- where- genLocalIndex env (PatternDecl _ constr _)- = genLocalPatternIndex env constr- genLocalIndex env (ExtraVariables _ idents)- = let (_, env') = mapfoldl genVarIndex env idents- in env'- genLocalIndex env _- = env-- genLocalPatternIndex env (VariablePattern ident)- = snd (genVarIndex env ident)- genLocalPatternIndex env (ConstructorPattern _ args)- = foldl genLocalPatternIndex env args- genLocalPatternIndex env (InfixPattern c1 _ c2)- = foldl genLocalPatternIndex env [c1,c2]- genLocalPatternIndex env (ParenPattern c)- = genLocalPatternIndex env c- genLocalPatternIndex env (TuplePattern _ args)- = foldl genLocalPatternIndex env args- genLocalPatternIndex env (ListPattern _ args)- = foldl genLocalPatternIndex env args- genLocalPatternIndex env (AsPattern ident c)- = genLocalPatternIndex (snd (genVarIndex env ident)) c- genLocalPatternIndex env (LazyPattern _ c)- = genLocalPatternIndex env c- genLocalPatternIndex env (RecordPattern fields mc)- = let env' = foldl genLocalPatternIndex env (map fieldTerm fields)- in maybe env' (genLocalPatternIndex env') mc- genLocalPatternIndex env _- = env-- -- The association list 'fdecls' is necessary because function- -- rules may not be together in the declaration list- genLocals :: AbstractEnv -> Map.Map Ident [Decl] -> [Decl] - -> ([CLocalDecl], AbstractEnv)- genLocals env _ [] = ([], env)- genLocals env fdecls ((FunctionDecl _ ident _):decls)- = let (funcdecl, env1) = genLocalFuncDecl (beginScope env) fdecls ident- (locals, env2) = genLocals (endScope env1) fdecls decls- in (funcdecl:locals, env2)- genLocals env fdecls ((ExternalDecl _ _ _ ident _):decls)- = let (funcdecl, env1) = genLocalFuncDecl (beginScope env) fdecls ident- (locals, env2) = genLocals (endScope env1) fdecls decls- in (funcdecl:locals, env2)- genLocals env fdecls ((FlatExternalDecl pos idents):decls)- | null idents = genLocals env fdecls decls- | otherwise - = let (funcdecl, env1) - = genLocalFuncDecl (beginScope env) fdecls (head idents)- (locals, env2) - = genLocals (endScope env1)- fdecls - (FlatExternalDecl pos (tail idents):decls)- in (funcdecl:locals, env2)- genLocals env fdecls (PatternDecl pos constr rhs : decls)- = let (patt, env1) = genLocalPattern pos env constr- (plocals, env2) = genLocalDecls (beginScope env1) - (simplifyRhsLocals rhs)- (expr, env3) = genLocalPattRhs pos env2 (simplifyRhsExpr rhs)- (locals, env4) = genLocals (endScope env3) fdecls decls- in (CLocalPat patt expr plocals:locals, env4)- genLocals env fdecls ((ExtraVariables pos idents):decls)- | null idents = genLocals env fdecls decls- | otherwise- = let ident = head idents- idx = fromMaybe - (internalError ("cannot find index"- ++ " for free variable \""- ++ show ident ++ "\""))- (getVarIndex env ident)- decls' = ExtraVariables pos (tail idents) : decls- (locals, env') = genLocals env fdecls decls'- in (CLocalVar (idx, name ident) : locals, env')- genLocals env fdecls ((TypeSig _ _ _):decls)- = genLocals env fdecls decls- genLocals _ _ decl = internalError ("unexpected local declaration: \n"- ++ show (head decl))-- genLocalFuncDecl :: AbstractEnv -> Map.Map Ident [Decl] -> Ident - -> (CLocalDecl, AbstractEnv)- genLocalFuncDecl env fdecls ident- = let fdecl = fromMaybe - (internalError ("missing declaration" - ++ " for local function \""- ++ show ident ++ "\""))- (Map.lookup ident fdecls)- (_, funcdecl) = genFuncDecl True env ident fdecl- in (CLocalFunc funcdecl, env)-- genLocalPattern pos env (LiteralPattern lit)- = case lit of- String _ cs - -> genLocalPattern pos env - (ListPattern [] (map (LiteralPattern . Char noRef) cs))- _ -> (CPLit (genLiteral lit), env)- genLocalPattern pos env (VariablePattern ident)- = let idx = fromMaybe - (internalError ("cannot find index"- ++ " for pattern variable \""- ++ show ident ++ "\""))- (getVarIndex env ident) - in (CPVar (idx, name ident), env)- genLocalPattern pos env (ConstructorPattern qident args)- = let (args', env') = mapfoldl (genLocalPattern pos) env args- in (CPComb (genQName False env qident) args', env')- genLocalPattern pos env (InfixPattern larg qident rarg)- = genLocalPattern pos env (ConstructorPattern qident [larg, rarg])- genLocalPattern pos env (ParenPattern patt)- = genLocalPattern pos env patt- genLocalPattern pos env (TuplePattern _ args)- | len > 1 - = genLocalPattern pos env (ConstructorPattern (qTupleId len) args)- | len == 1- = genLocalPattern pos env (head args)- | len == 0- = genLocalPattern pos env (ConstructorPattern qUnitId [])- where len = length args- genLocalPattern pos env (ListPattern _ args)- = genLocalPattern pos env - (foldr (\p1 p2 -> ConstructorPattern qConsId [p1,p2])- (ConstructorPattern qNilId [])- args)- genLocalPattern pos _ (NegativePattern _ _)- = errorAt pos "negative patterns are not supported in AbstractCurry"- genLocalPattern pos env (AsPattern ident cterm)- = let (patt, env1) = genLocalPattern pos env cterm- idx = fromMaybe - (internalError ("cannot find index"- ++ " for alias variable \""- ++ show ident ++ "\""))- (getVarIndex env1 ident)- in (CPAs (idx, name ident) patt, env1)- genLocalPattern pos env (LazyPattern _ cterm)- = let (patt, env') = genLocalPattern pos env cterm- in (CPLazy patt, env')- genLocalPattern pos env (RecordPattern fields mr)- = let (fields', env1) = mapfoldl (genField genLocalPattern) env fields- (mr', env2)- = maybe (Nothing, env1)- (applyFst Just . genLocalPattern pos env1)- mr- in (CPRecord fields' mr', env2)-- genLocalPattRhs pos env [(Variable qSuccessFunId, expr)]- = genExpr pos env expr- genLocalPattRhs pos _ _- = errorAt pos ("guarded expressions in pattern declarations"- ++ " are not supported in AbstractCurry")------genExpr :: Position -> AbstractEnv -> Expression -> (CExpr, AbstractEnv)-genExpr pos env (Literal lit)- = case lit of- String _ cs -> genExpr pos env (List [] (map (Literal . Char noRef) cs))- _ -> (CLit (genLiteral lit), env)-genExpr _ env (Variable qident)- | isJust midx = (CVar (fromJust midx, name ident), env)- | qident == qSuccessId = (CSymbol (genQName False env qSuccessFunId), env)- | otherwise = (CSymbol (genQName False env qident), env)- where- ident = unqualify qident- midx = getVarIndex env ident-genExpr _ env (Constructor qident)- = (CSymbol (genQName False env qident), env)-genExpr pos env (Paren expr)- = genExpr pos env expr-genExpr pos env (Typed expr _)- = genExpr pos env expr-genExpr pos env (Tuple _ args)- | len > 1- = genExpr pos env (foldl Apply (Variable (qTupleId (length args))) args)- | len == 1- = genExpr pos env (head args)- | len == 0- = genExpr pos env (Variable qUnitId)- where len = length args-genExpr pos env (List _ args)- = let cons = Constructor qConsId- nil = Constructor qNilId- in genExpr pos env (foldr (Apply . Apply cons) nil args)-genExpr pos env (ListCompr _ expr stmts)- = let (stmts', env1) = mapfoldl (genStatement pos) (beginScope env) stmts- (expr', env2) = genExpr pos env1 expr- in (CListComp expr' stmts', endScope env2)-genExpr pos env (EnumFrom expr)- = genExpr pos env (Apply (Variable qEnumFromId) expr)-genExpr pos env (EnumFromThen expr1 expr2)- = genExpr pos env (Apply (Apply (Variable qEnumFromThenId) expr1) expr2)-genExpr pos env (EnumFromTo expr1 expr2)- = genExpr pos env (Apply (Apply (Variable qEnumFromToId) expr1) expr2)-genExpr pos env (EnumFromThenTo expr1 expr2 expr3)- = genExpr pos env (Apply (Apply (Apply (Variable qEnumFromThenToId) - expr1) expr2) expr3)-genExpr pos env (UnaryMinus _ expr)- = genExpr pos env (Apply (Variable qNegateId) expr)-genExpr pos env (Apply expr1 expr2)- = let (expr1', env1) = genExpr pos env expr1- (expr2', env2) = genExpr pos env1 expr2- in (CApply expr1' expr2', env2)-genExpr pos env (InfixApply expr1 op expr2)- = genExpr pos env (Apply (Apply (opToExpr op) expr1) expr2)-genExpr pos env (LeftSection expr op)- = let ident = freshVar env "x"- patt = VariablePattern ident- var = Variable (qualify ident)- applic = Apply (Apply (opToExpr op) expr) var - in genExpr pos env (Lambda noRef [patt] applic)-genExpr pos env (RightSection op expr)- = let ident = freshVar env "x"- patt = VariablePattern ident- var = Variable (qualify ident)- applic = Apply (Apply (opToExpr op) var) expr - in genExpr pos env (Lambda noRef [patt] applic)-genExpr pos env (Lambda _ params expr)- = let (params', env1) = mapfoldl (genPattern pos) (beginScope env) params- (expr', env2) = genExpr pos env1 expr- in (CLambda params' expr', endScope env2)-genExpr pos env (Let decls expr)- = let (decls', env1) = genLocalDecls (beginScope env) decls- (expr', env2) = genExpr pos env1 expr- in (CLetDecl decls' expr', endScope env2)-genExpr pos env (Do stmts expr)- = let (stmts', env1) = mapfoldl (genStatement pos) (beginScope env) stmts- (expr', env2) = genExpr pos env1 expr- in (CDoExpr (stmts' ++ [CSExpr expr']), endScope env2)-genExpr pos env (IfThenElse _ expr1 expr2 expr3)- = genExpr pos env (Apply (Apply (Apply (Variable qIfThenElseId)- expr1) expr2) expr3)-genExpr pos env (Case _ expr alts)- = let (expr', env1) = genExpr pos env expr- (alts', env2) = mapfoldl genBranchExpr env1 alts- in (CCase expr' alts', env2)-genExpr pos env (RecordConstr fields)- = let (fields', env1) = mapfoldl (genField genExpr) env fields- in (CRecConstr fields', env1)-genExpr pos env (RecordSelection expr label)- = let (expr', env1) = genExpr pos env expr- in (CRecSelect expr' (name label), env1)-genExpr pos env (RecordUpdate fields expr)- = let (fields', env1) = mapfoldl (genField genExpr) env fields- (expr', env2) = genExpr pos env1 expr- in (CRecUpdate fields' expr', env2)------genStatement :: Position -> AbstractEnv -> Statement - -> (CStatement, AbstractEnv)-genStatement pos env (StmtExpr _ expr)- = let (expr', env') = genExpr pos env expr- in (CSExpr expr', env')-genStatement _ env (StmtDecl decls)- = let (decls', env') = genLocalDecls env decls- in (CSLet decls', env')-genStatement pos env (StmtBind _ patt expr)- = let (expr', env1) = genExpr pos env expr- (patt', env2) = genPattern pos env1 patt- in (CSPat patt' expr', env2)----- NOTE: guarded expressions and local declarations in case branches--- are not supported in PAKCS-genBranchExpr :: AbstractEnv -> Alt -> (CBranchExpr, AbstractEnv)-genBranchExpr env (Alt pos patt rhs)- = let (patt', env1) = genPattern pos (beginScope env) patt- (expr', env2) = genBranchRhs pos env1 (simplifyRhsExpr rhs)- in (CBranch patt' expr', endScope env2)- where- genBranchRhs pos env [(Variable qSuccessFunId, expr)]- = genExpr pos env expr- genBranchRhs pos _ _- = errorAt pos ("guarded expressions in case alternatives"- ++ " are not supported in AbstractCurry")------genPattern :: Position -> AbstractEnv -> ConstrTerm -> (CPattern, AbstractEnv)-genPattern pos env (LiteralPattern lit)- = case lit of- String _ cs - -> genPattern pos env (ListPattern [] (map (LiteralPattern . Char noRef) cs))- _ -> (CPLit (genLiteral lit), env)-genPattern _ env (VariablePattern ident)- = let (idx, env') = genVarIndex env ident- in (CPVar (idx, name ident), env')-genPattern pos env (ConstructorPattern qident args)- = let (args', env') = mapfoldl (genPattern pos) env args- in (CPComb (genQName False env qident) args', env')-genPattern pos env (InfixPattern larg qident rarg)- = genPattern pos env (ConstructorPattern qident [larg, rarg])-genPattern pos env (ParenPattern patt)- = genPattern pos env patt-genPattern pos env (TuplePattern _ args)- | len > 1- = genPattern pos env (ConstructorPattern (qTupleId len) args)- | len == 1- = genPattern pos env (head args)- | len == 0- = genPattern pos env (ConstructorPattern qUnitId [])- where len = length args-genPattern pos env (ListPattern _ args)- = genPattern pos env (foldr (\x1 x2 -> ConstructorPattern qConsId [x1, x2]) - (ConstructorPattern qNilId []) - args)-genPattern pos _ (NegativePattern _ _)- = errorAt pos "negative patterns are not supported in AbstractCurry"-genPattern pos env (AsPattern ident cterm)- = let (patt, env1) = genPattern pos env cterm- (idx, env2) = genVarIndex env1 ident- in (CPAs (idx, name ident) patt, env2)-genPattern pos env (LazyPattern _ cterm)- = let (patt, env') = genPattern pos env cterm- in (CPLazy patt, env')-genPattern pos env (FunctionPattern qident cterms)- = let (patts, env') = mapfoldl (genPattern pos) env cterms- in (CPFuncComb (genQName False env qident) patts, env')-genPattern pos env (InfixFuncPattern cterm1 qident cterm2)- = genPattern pos env (FunctionPattern qident [cterm1, cterm2])-genPattern pos env (RecordPattern fields mr)- = let (fields', env1) = mapfoldl (genField genPattern) env fields- (mr', env2) = maybe (Nothing, env1)- (applyFst Just . genPattern pos env1)- mr- in (CPRecord fields' mr', env2)------genField :: (Position -> AbstractEnv -> a -> (b, AbstractEnv))- -> AbstractEnv -> Field a -> (CField b, AbstractEnv)-genField genTerm env (Field pos label term)- = let (term',env1) = genTerm pos env term- in ((name label, term'), env1)-----genLiteral :: Literal -> CLiteral-genLiteral (Char _ c) = CCharc c-genLiteral (Int _ i) = CIntc i-genLiteral (Float _ f) = CFloatc f-genLiteral _ = internalError "unsupported literal"----- Notes: --- - Some prelude identifiers are not quialified. The first check ensures--- that they get a correct qualifier.--- - The test for unqualified identifiers is necessary to qualify--- them correctly in the untyped AbstractCurry representation.-genQName :: Bool -> AbstractEnv -> QualIdent -> QName-genQName isTypeCons env qident- | isPreludeSymbol qident- = genQualName (qualQualify preludeMIdent qident)- | not (isQualified qident)- = genQualName (getQualIdent (unqualify qident))- | otherwise- = genQualName qident- where- genQualName qid- = let (mmid, id) = (qualidMod qid, qualidId qid)- mid = maybe (moduleId env)- (\mid' -> fromMaybe mid' (Map.lookup mid' (imports env)))- mmid- in (moduleName mid, name id)-- getQualIdent id- | isTypeCons = case (lookupTC id (tconsEnv env)) of- --[DataType qid _ _] -> qid- --[RenamingType qid _ _] -> qid- --[AliasType qid _ _] -> qid- [info] -> origName info- _ -> qualifyWith (moduleId env) id- | otherwise = case (lookupValue id (typeEnv env)) of- --[DataConstructor qid _] -> qid- --[NewtypeConstructor qid _] -> qid- --[Value qid _] -> qid- [info] -> origName info- _ -> qualifyWith (moduleId env) id- ------genVisibility :: AbstractEnv -> Ident -> CVisibility-genVisibility env ident- | isExported env ident = Public- | otherwise = Private------genEvalAnnot :: EvalAnnotation -> CEvalAnnot-genEvalAnnot EvalRigid = CRigid-genEvalAnnot EvalChoice = CChoice------------------------------------------------------------------------------------- This part defines an environment containing all necessary information--- for generating the AbstractCurry representation of a CurrySyntax term.---- Data type for representing an AbstractCurry generator environment.------ moduleName - name of the module--- typeEnv - table of all known types--- exports - table of all exported symbols from the module--- imports - table of import aliases--- varIndex - index counter for generating variable indices--- tvarIndex - index counter for generating type variable indices--- varScope - stack of variable tables--- tvarScope - stack of type variable tables--- acyType - type of AbstractCurry code to be generated-data AbstractEnv = AbstractEnv {moduleId :: ModuleIdent,- typeEnv :: ValueEnv,- tconsEnv :: TCEnv,- exports :: Set.Set Ident,- imports :: Map.Map ModuleIdent ModuleIdent,- varIndex :: Int,- tvarIndex :: Int,- varScope :: [Map.Map Ident Int],- tvarScope :: [Map.Map Ident Int],- acyType :: AbstractType- } deriving Show---- Data type representing the type of AbstractCurry code to be generated--- (typed infered or untyped (i.e. type signated))-data AbstractType = TypedAcy | UntypedAcy deriving (Eq, Show)----- Initializes the AbstractCurry generator environment.-genAbstractEnv :: AbstractType -> ValueEnv -> TCEnv -> Module -> AbstractEnv-genAbstractEnv absType tyEnv tcEnv (Module mid exps decls)- = AbstractEnv - {moduleId = mid,- typeEnv = tyEnv,- tconsEnv = tcEnv,- exports = foldl (buildExportTable mid decls) Set.empty exps',- imports = foldl buildImportTable Map.empty decls,- varIndex = 0,- tvarIndex = 0,- varScope = [Map.empty],- tvarScope = [Map.empty],- acyType = absType- }- where- exps' = maybe (buildExports mid decls) (\ (Exporting _ es) -> es) exps----- Generates a list of exports for all specified top level declarations-buildExports :: ModuleIdent -> [Decl] -> [Export]-buildExports _ [] = []-buildExports mid (DataDecl _ ident _ _:ds) - = ExportTypeAll (qualifyWith mid ident) : buildExports mid ds-buildExports mid ((NewtypeDecl _ ident _ _):ds)- = ExportTypeAll (qualifyWith mid ident) : buildExports mid ds-buildExports mid ((TypeDecl _ ident _ _):ds)- = Export (qualifyWith mid ident) : buildExports mid ds-buildExports mid ((FunctionDecl _ ident _):ds)- = Export (qualifyWith mid ident) : buildExports mid ds-buildExports mid (ExternalDecl _ _ _ ident _ : ds)- = Export (qualifyWith mid ident) : buildExports mid ds-buildExports mid (FlatExternalDecl _ idents : ds)- = map (Export . qualifyWith mid) idents ++ buildExports mid ds-buildExports mid (_:ds) = buildExports mid ds----- Builds a table containing all exported (i.e. public) identifiers--- from a module.-buildExportTable :: ModuleIdent -> [Decl] -> Set.Set Ident -> Export - -> Set.Set Ident-buildExportTable mid _ exptab (Export qident)- | isJust (localIdent mid qident)- = insertExportedIdent exptab (unqualify qident)- | otherwise = exptab-buildExportTable mid _ exptab (ExportTypeWith qident ids)- | isJust (localIdent mid qident)- = foldl insertExportedIdent - (insertExportedIdent exptab (unqualify qident))- ids- | otherwise = exptab-buildExportTable mid decls exptab (ExportTypeAll qident)- | isJust ident'- = foldl insertExportedIdent- (insertExportedIdent exptab ident)- (maybe [] getConstrIdents (find (isDataDeclOf ident) decls))- | otherwise = exptab- where - ident' = localIdent mid qident- ident = fromJust ident'-buildExportTable _ _ exptab (ExportModule _) = exptab-----insertExportedIdent :: Set.Set Ident -> Ident -> Set.Set Ident-insertExportedIdent env ident = Set.insert ident env-----getConstrIdents :: Decl -> [Ident]-getConstrIdents (DataDecl _ _ _ constrs)- = map getConstrIdent constrs- where- getConstrIdent (ConstrDecl _ _ ident _) = ident- getConstrIdent (ConOpDecl _ _ _ ident _) = ident----- Builds a table for dereferencing import aliases-buildImportTable :: Map.Map ModuleIdent ModuleIdent -> Decl- -> Map.Map ModuleIdent ModuleIdent-buildImportTable env (ImportDecl _ mid _ malias _)- = Map.insert (fromMaybe mid malias) mid env-buildImportTable env _ = env----- Checks whether an identifier is exported or not.-isExported :: AbstractEnv -> Ident -> Bool-isExported env ident = Set.member ident (exports env)----- Generates an unique index for the variable 'ident' and inserts it--- into the variable table of the current scope.-genVarIndex :: AbstractEnv -> Ident -> (Int, AbstractEnv)-genVarIndex env ident - = let idx = varIndex env- vtabs = varScope env- vtab = head vtabs --if null vtabs then Map.empty else head vtabs- in (idx, env {varIndex = idx + 1,- varScope = Map.insert ident idx vtab : sureTail vtabs})---- Generates an unique index for the type variable 'ident' and inserts it--- into the type variable table of the current scope.-genTVarIndex :: AbstractEnv -> Ident -> (Int, AbstractEnv)-genTVarIndex env ident- = let idx = tvarIndex env- vtabs = tvarScope env- vtab = head vtabs --if null vtabs then Map.empty else head vtabs- in (idx, env {tvarIndex = idx + 1,- tvarScope = Map.insert ident idx vtab : sureTail vtabs })----- Looks up the unique index for the variable 'ident' in the--- variable table of the current scope.-getVarIndex :: AbstractEnv -> Ident -> Maybe Int-getVarIndex env ident = Map.lookup ident (head (varScope env))---- Looks up the unique index for the type variable 'ident' in the type--- variable table of the current scope.-getTVarIndex :: AbstractEnv -> Ident -> Maybe Int-getTVarIndex env ident = Map.lookup ident (head (tvarScope env))----- Generates an indentifier which doesn't occur in the variable table--- of the current scope.-freshVar :: AbstractEnv -> String -> Ident-freshVar env name = genFreshVar env name 0- where- genFreshVar env name idx- | isJust (getVarIndex env ident)- = genFreshVar env name (idx + 1)- | otherwise - = ident- where ident = mkIdent (name ++ show idx)---- Sets the index counter back to zero and deletes all stack entries.-resetScope :: AbstractEnv -> AbstractEnv-resetScope env = env {varIndex = 0,- tvarIndex = 0,- varScope = [Map.empty],- tvarScope = [Map.empty]}---- Starts a new scope, i.e. copies and pushes the variable table of the current --- scope onto the top of the stack-beginScope :: AbstractEnv -> AbstractEnv-beginScope env = env {varScope = head vs :vs,- tvarScope = head tvs :tvs }- where- vs = varScope env- tvs = tvarScope env---- End the current scope, i.e. pops and deletes the variable table of the--- current scope from the top of the stack.-endScope :: AbstractEnv -> AbstractEnv-endScope env = env {varScope = if oneElement vs then vs else tail vs,- tvarScope = if oneElement tvs then tvs else tail tvs}- where- vs = varScope env- tvs = tvarScope env------------------------------------------------------------------------------------- Miscellaneous...---- Some identifiers...-qEnumFromId = qualifyWith preludeMIdent (mkIdent "enumFrom")-qEnumFromThenId = qualifyWith preludeMIdent (mkIdent "enumFromThen")-qEnumFromToId = qualifyWith preludeMIdent (mkIdent "enumFromTo")-qEnumFromThenToId = qualifyWith preludeMIdent (mkIdent "enumFromThenTo")-qNegateId = qualifyWith preludeMIdent (mkIdent "negate")-qIfThenElseId = qualifyWith preludeMIdent (mkIdent "if_then_else")-qSuccessFunId = qualifyWith preludeMIdent (mkIdent "success")----- The following functions check whether a declaration is of a certain kind-isFunctionDecl :: Decl -> Bool-isFunctionDecl (FunctionDecl _ _ _) = True-isFunctionDecl _ = False--isExternal :: Decl -> Bool-isExternal (ExternalDecl _ _ _ _ _) = True-isExternal (FlatExternalDecl _ _) = True-isExternal _ = False----- Checks, whether a declaration is the data declaration of 'ident'.-isDataDeclOf :: Ident -> Decl -> Bool-isDataDeclOf ident (DataDecl _ ident' _ _) - = ident == ident'-isDataDeclOf _ _ - = False----- Checks, whether a symbol is defined in the Prelude.-isPreludeSymbol :: QualIdent -> Bool-isPreludeSymbol qident- = let (mmid, ident) = (qualidMod qident, qualidId qident)- in (isJust mmid && preludeMIdent == fromJust mmid)- || elem ident [unitId, listId, nilId, consId]- || isTupleId ident----- Converts an infix operator to an expression-opToExpr :: InfixOp -> Expression-opToExpr (InfixOp qident) = Variable qident-opToExpr (InfixConstr qident) = Constructor qident----- Looks up the type of a qualified symbol in the type environment and--- converts it to a CurrySyntax type term.-qualLookupType :: QualIdent -> ValueEnv -> Maybe TypeExpr-qualLookupType qident tyEnv- = case (qualLookupValue qident tyEnv) of- [Value _ ts] -> (\ (ForAll _ ty) -> Just (fromType ty)) ts- _ -> Nothing---- Looks up the type of a symbol in the type environment and--- converts it to a CurrySyntax type term.-lookupType :: Ident -> ValueEnv -> Maybe TypeExpr-lookupType ident tyEnv- = case (lookupValue ident tyEnv) of- [Value _ ts] -> (\ (ForAll _ ty) -> Just (fromType ty)) ts- _ -> Nothing----- The following functions transform left-hand-side and right-hand-side terms--- for a better handling-simplifyLhs :: Lhs -> [ConstrTerm]-simplifyLhs = snd . flatLhs--simplifyRhsExpr :: Rhs -> [(Expression, Expression)]-simplifyRhsExpr (SimpleRhs _ expr _) - = [(Variable qSuccessId, expr)]-simplifyRhsExpr (GuardedRhs crhs _) - = map (\ (CondExpr _ cond expr) -> (cond, expr)) crhs--simplifyRhsLocals :: Rhs -> [Decl]-simplifyRhsLocals (SimpleRhs _ _ locals) = locals-simplifyRhsLocals (GuardedRhs _ locals) = locals----- FIXME This mapfold is a twisted mapAccumL--- A combination of 'map' and 'foldl'. It maps a function to a list--- from left to right while updating the argument 'e' continously.-mapfoldl :: (a -> b -> (c,a)) -> a -> [b] -> ([c], a)-mapfoldl _ e [] = ([], e)-mapfoldl f e (x:xs) = let (x', e') = f e x- (xs', e'') = mapfoldl f e' xs- in (x':xs', e'')---- Inserts an element under a key into an association list-insertEntry :: Eq a => a -> b -> [(a,b)] -> [(a,b)]-insertEntry k e [] = [(k,e)]-insertEntry k e ((x,y):xys)- | k == x = (k,e):xys- | otherwise = (x,y) : insertEntry k e xys----- Returns the list without the first element. If the list is empty, an--- empty list will be returned.-sureTail :: [a] -> [a]-sureTail [] = []-sureTail (_:xs) = xs----- Returns 'True', if a list contains exactly one element-oneElement :: [a] -> Bool-oneElement [_] = True-oneElement _ = False----- Applies 'f' on the first value in a tuple-applyFst :: (a -> c) -> (a,b) -> (c,b)-applyFst f (x,y) = (f x, y)-----------------------------------------------------------------------------------------------------------------------------------------------------------------
− src/GenFlatCurry.hs
@@ -1,1153 +0,0 @@---------------------------------------------------------------------------------------------------------------------------------------------------------------------- GenFlatCurry - Generates FlatCurry program terms and FlatCurry interfaces--- (type 'FlatCurry.Prog')------ November 2005,--- Martin Engelke (men@informatik.uni-kiel.de)----module GenFlatCurry (genFlatCurry,- genFlatInterface) where---import Control.Monad.State-import Control.Monad-import Data.Maybe-import Data.List-import qualified Data.Map as Map---import Curry.Base.MessageMonad-import Curry.Base.Ident as Id--import qualified Curry.Syntax as CS--import Curry.ExtendedFlat.Type-import Curry.ExtendedFlat.TypeInference--import Curry.ExtendedFlat.EraseTypes--import Base--import qualified IL.Type as IL-import qualified IL.CurryToIL as IL--import TopEnv(topEnvMap)-import CurryEnv (CurryEnv)-import qualified CurryEnv-import ScopeEnv (ScopeEnv)-import qualified ScopeEnv-import Types-import CurryCompilerOpts-import PatchPrelude---import Debug.Trace-trace' _ x = x------------------------------------------------------------------------------------- transforms intermediate language code (IL) to FlatCurry code-genFlatCurry :: Options -> CurryEnv -> ModuleEnv -> ValueEnv -> TCEnv - -> ArityEnv -> IL.Module -> (Prog, [WarnMsg])-genFlatCurry opts cEnv mEnv tyEnv tcEnv aEnv mod- = (prog', messages)- where (prog, messages) - = run opts cEnv mEnv tyEnv tcEnv aEnv False (visitModule mod)- prog' = -- eraseTypes $ - adjustTypeInfo $ adjustTypeInfo $ patchPreludeFCY prog----- transforms intermediate language code (IL) to FlatCurry interfaces-genFlatInterface :: Options -> CurryEnv -> ModuleEnv -> ValueEnv -> TCEnv- -> ArityEnv -> IL.Module -> (Prog, [WarnMsg])-genFlatInterface opts cEnv mEnv tyEnv tcEnv aEnv mod- = (patchPreludeFCY intf, messages)- where (intf, messages) - = run opts cEnv mEnv tyEnv tcEnv aEnv True (visitModule mod)----------------------------------------------------------------------------------------------------------------------------------------------------------------------- The environment 'FlatEnv' is embedded in the monadic representation--- 'FlatState' which allows the usage of 'do' expressions.--type FlatState a = State FlatEnv a---- Data type for representing an environment which contains information needed--- for generating FlatCurry code.-data FlatEnv = FlatEnv{ moduleIdE :: ModuleIdent,- functionIdE :: (QualIdent, [(Ident, IL.Type)]),- compilerOptsE :: Options,- moduleEnvE :: ModuleEnv,- arityEnvE :: ArityEnv,- typeEnvE :: ValueEnv, -- types of defined values- tConsEnvE :: TCEnv,- publicEnvE :: Map.Map Ident IdentExport,- fixitiesE :: [CS.IDecl],- typeSynonymsE :: [CS.IDecl],- importsE :: [CS.IDecl],- exportsE :: [CS.Export],- interfaceE :: [CS.IDecl],- varIndexE :: Int,- varIdsE :: ScopeEnv Ident VarIndex,- tvarIndexE :: Int,- messagesE :: [WarnMsg],- genInterfaceE :: Bool,- localTypes :: Map.Map QualIdent IL.Type,- constrTypes :: Map.Map QualIdent IL.Type- }--data IdentExport = NotConstr -- function, type-constructor- | OnlyConstr -- constructor- | NotOnlyConstr -- constructor, function, type-constructor------- Runs a 'FlatState' action and returns the result-run :: Options -> CurryEnv -> ModuleEnv -> ValueEnv -> TCEnv -> ArityEnv - -> Bool -> FlatState a -> (a, [WarnMsg])-run opts cEnv mEnv tyEnv tcEnv aEnv genIntf f- = (result, messagesE env)- where- (result, env) = runState f env0- env0 = FlatEnv{ moduleIdE = CurryEnv.moduleId cEnv,- functionIdE = (qualify (mkIdent ""), []),- compilerOptsE = opts,- moduleEnvE = mEnv,- arityEnvE = aEnv,- typeEnvE = tyEnv,- tConsEnvE = tcEnv,- publicEnvE = genPubEnv (CurryEnv.moduleId cEnv)- (CurryEnv.interface cEnv),- fixitiesE = CurryEnv.infixDecls cEnv,- typeSynonymsE = CurryEnv.typeSynonyms cEnv,- importsE = CurryEnv.imports cEnv,- exportsE = CurryEnv.exports cEnv,- interfaceE = CurryEnv.interface cEnv,- varIndexE = 0,- varIdsE = ScopeEnv.new,- tvarIndexE =0,- messagesE = [],- genInterfaceE = genIntf,- localTypes = Map.empty,- constrTypes = Map.fromList (getConstrTypes tcEnv)- }--getConstrTypes :: TCEnv -> [(QualIdent, IL.Type)]-getConstrTypes tcEnv = trace' (show tinfos) tinfos- where tcList = Map.toList $ topEnvMap tcEnv- tinfos = [ foo tqid conid argtypes targnum- | (_, (_, DataType tqid targnum dts):_) <- tcList- , Just (Data conid _ argtypes) <- dts]- foo tqid conid argtypes targnum- = let conname = QualIdent (qualidMod tqid) conid- resulttype = IL.TypeConstructor tqid (map IL.TypeVariable [0..targnum-1])- contype = foldr IL.TypeArrow resulttype (map ttrans argtypes)- in (conname, contype)- -----visitModule :: IL.Module -> FlatState Prog-visitModule (IL.Module mid imps decls) = do- -- insert local decls into localDecls- let ts = [ (qn, t) | IL.FunctionDecl qn _ t _ <- decls ]- modify (\ s -> s {localTypes = Map.fromList ts})- whenFlatCurry- (do ops <- genOpDecls- datas <- mapM visitDataDecl (filter isDataDecl decls)- types <- genTypeSynonyms- records <- genRecordTypes- funcs <- mapM visitFuncDecl (filter isFuncDecl decls)- mod <- visitModuleIdent mid- imps' <- imports- is <- mapM visitModuleIdent - (nub (imps ++ (map (\ (CS.IImportDecl _ mid) - -> mid) imps')))- return (Prog mod is (records ++ types ++ datas) funcs ops))- (do ops <- genOpDecls- ds <- filterM isPublicDataDecl decls- datas <- mapM visitDataDecl ds- types <- genTypeSynonyms- records <- genRecordTypes- fs <- filterM isPublicFuncDecl decls- funcs <- mapM visitFuncDecl fs- expimps <- getExportedImports- itypes <- mapM visitTypeIDecl (filter isTypeIDecl expimps)- ifuncs <- mapM visitFuncIDecl (filter isFuncIDecl expimps)- iops <- mapM visitOpIDecl (filter isOpIDecl expimps)- mod <- visitModuleIdent mid- imps' <- imports- is <- mapM visitModuleIdent - (nub (imps ++ (map (\ (CS.IImportDecl _ mid) - -> mid) imps')))- return (Prog mod - is - (itypes ++ records ++ types ++ datas)- (ifuncs ++ funcs)- (iops ++ ops)))-----visitDataDecl :: IL.Decl -> FlatState TypeDecl-visitDataDecl (IL.DataDecl qident arity constrs)- = do cdecls <- mapM visitConstrDecl constrs- qname <- visitQualTypeIdent qident- vis <- getVisibility False qident- return (Type qname vis [0 .. (arity - 1)] (concat cdecls))-visitDataDecl _ = internalError "GenFlatCurry: no data declaration"-----visitConstrDecl :: IL.ConstrDecl [IL.Type] -> FlatState [ConsDecl]-visitConstrDecl (IL.ConstrDecl qident types)- = do texprs <- mapM visitType types- qname <- visitQualIdent qident- vis <- getVisibility True qident- genFint <- genInterface- if genFint && vis == Private - then return []- else return [Cons qname (length types) vis texprs]-----visitType :: IL.Type -> FlatState TypeExpr-visitType (IL.TypeConstructor qident types)- = do texprs <- mapM visitType types- qname <- visitQualTypeIdent qident- if (qualName qident) == "Identity"- then return (head texprs)- else return (TCons qname texprs)-visitType (IL.TypeVariable index)- = return (TVar (abs index))-visitType (IL.TypeArrow type1 type2)- = do texpr1 <- visitType type1- texpr2 <- visitType type2- return (FuncType texpr1 texpr2)-----visitFuncDecl :: IL.Decl -> FlatState FuncDecl-visitFuncDecl (IL.FunctionDecl qident params typeexpr expression)- = let argtypes = splitoffArgTypes typeexpr params - in do setFunctionId (qident, argtypes)- qname <- visitQualIdent qident- whenFlatCurry (do is <- mapM newVarIndex params- texpr <- visitType typeexpr- expr <- visitExpression expression- vis <- getVisibility False qident- clearVarIndices- return (Func qname (length params) vis texpr (Rule is expr)))- (do texpr <- visitType typeexpr- clearVarIndices- return (Func qname (length params) Public texpr (Rule [] (Var $ mkIdx 0))))-visitFuncDecl (IL.ExternalDecl qident _ name typeexpr)- = do setFunctionId (qident, [])- texpr <- visitType typeexpr- qname <- visitQualIdent qident- vis <- getVisibility False qident- xname <- visitExternalName name- return (Func qname (typeArity typeexpr) vis texpr (External xname))-visitFuncDecl (IL.NewtypeDecl _ _ _)- = do mid <- moduleId - error ("\"" ++ Id.moduleName mid - ++ "\": newtype declarations are not supported")-visitFuncDecl _ = internalError "GenFlatCurry: no function declaration"-----visitExpression :: IL.Expression -> FlatState Expr-visitExpression (IL.Literal literal)- = liftM Lit (visitLiteral literal)-visitExpression (IL.Variable ident)- = liftM Var (lookupVarIndex ident)-visitExpression (IL.Function qident _)- = do arity_ <- lookupIdArity qident- qname <- visitQualIdent qident- maybe (internalError (funcArity qname))- (\arity -> genFuncCall qname arity [])- arity_-visitExpression (IL.Constructor qident arity)- = do arity_ <- lookupIdArity qident- qname <- visitQualIdent qident- maybe (internalError (consArity qident))- (\arity -> genConsCall qname arity [])- arity_-visitExpression (IL.Apply e1 e2)- = genFlatApplication e1 e2-visitExpression (IL.Case r evalannot expression alts)- = do ea <- visitEval evalannot- expr <- visitExpression expression- branches <- mapM visitAlt alts- return (Case r ea expr branches)-visitExpression (IL.Or expression1 expression2)- = do expr1 <- visitExpression expression1- expr2 <- visitExpression expression2- checkOverlapping expr1 expr2- return (Or expr1 expr2)-visitExpression (IL.Exist ident expression)- = do index <- newVarIndex ident- expr <- visitExpression expression- case expr of- Free is expr' -> return (Free (index:is) expr')- _ -> return (Free [index] expr)-visitExpression (IL.Let binding expression)- = do beginScope- newVarIndex (bindingIdent binding)- bind <- visitBinding binding- expr <- visitExpression expression- -- is it correct that there is no endScope? (hsi)- return (Let [bind] expr)-visitExpression (IL.Letrec bindings expression)- = do beginScope- mapM_ (newVarIndex . bindingIdent) bindings- binds <- mapM visitBinding bindings- expr <- visitExpression expression- endScope- return (Let binds expr)------visitLiteral :: IL.Literal -> FlatState Literal-visitLiteral (IL.Char rs c) = return (Charc rs c)-visitLiteral (IL.Int rs i) = return (Intc rs i)-visitLiteral (IL.Float rs f) = return (Floatc rs f)-----visitAlt :: IL.Alt -> FlatState BranchExpr-visitAlt (IL.Alt cterm expression)- = do patt <- visitConstrTerm cterm- expr <- visitExpression expression- return (Branch patt expr)-----visitConstrTerm :: IL.ConstrTerm -> FlatState Pattern-visitConstrTerm (IL.LiteralPattern literal)- = do lit <- visitLiteral literal- return (LPattern lit)-visitConstrTerm (IL.ConstructorPattern qident args)- = do is <- mapM newVarIndex args- qname <- visitQualIdent qident- return (Pattern qname is)-visitConstrTerm (IL.VariablePattern ident)- = do mid <- moduleId- error ("\"" ++ Id.moduleName mid - ++ "\": variable patterns are not supported")-----visitEval :: IL.Eval -> FlatState CaseType-visitEval IL.Rigid = return Rigid-visitEval IL.Flex = return Flex-----visitBinding :: IL.Binding -> FlatState (VarIndex, Expr)-visitBinding (IL.Binding ident expression)- = do index <- lookupVarIndex ident- expr <- visitExpression expression- return (index, expr)---------------------------------------------------------------------------------------visitFuncIDecl :: CS.IDecl -> FlatState FuncDecl-visitFuncIDecl (CS.IFunctionDecl _ qident arity typeexpr)- = do texpr <- visitType (fst (cs2ilType [] typeexpr))- qname <- visitQualIdent qident- return (Func qname arity Public texpr (Rule [] (Var $ mkIdx 0)))-visitFuncIDecl _ = internalError "GenFlatCurry: no function interface"-----visitTypeIDecl :: CS.IDecl -> FlatState TypeDecl-visitTypeIDecl (CS.IDataDecl _ qident params constrs_)- = do let mid = fromMaybe (internalError "GenFlatCurry: no module name")- (qualidMod qident)- is = [0 .. length params - 1]- cdecls <- mapM (visitConstrIDecl mid (zip params is)) - (catMaybes constrs_)- qname <- visitQualTypeIdent qident- return (Type qname Public is cdecls)-visitTypeIDecl (CS.ITypeDecl _ qident params typeexpr)- = do let is = [0 .. (length params) - 1]- texpr <- visitType (fst (cs2ilType (zip params is) typeexpr))- qname <- visitQualTypeIdent qident- return (TypeSyn qname Public is texpr)-visitTypeIDecl _ = internalError "GenFlatCurry: no type interface"-----visitConstrIDecl :: ModuleIdent -> [(Ident, Int)] -> CS.ConstrDecl - -> FlatState ConsDecl-visitConstrIDecl mid tis (CS.ConstrDecl _ _ ident typeexprs)- = do texprs <- mapM (visitType . (fst . cs2ilType tis)) typeexprs- qname <- visitQualIdent (qualifyWith mid ident)- return (Cons qname (length typeexprs) Public texprs)-visitConstrIDecl mid tis (CS.ConOpDecl pos ids type1 ident type2)- = visitConstrIDecl mid tis (CS.ConstrDecl pos ids ident [type1,type2])-----visitOpIDecl :: CS.IDecl -> FlatState OpDecl-visitOpIDecl (CS.IInfixDecl _ fixity prec qident)- = do let fix = case fixity of- CS.InfixL -> InfixlOp- CS.InfixR -> InfixrOp- _ -> InfixOp- qname <- visitQualIdent qident- return (Op qname fix prec)---------------------------------------------------------------------------------------visitModuleIdent :: ModuleIdent -> FlatState String-visitModuleIdent = return . Id.moduleName-----visitQualIdent :: QualIdent -> FlatState QName-visitQualIdent qident- = do mid <- moduleId- let (mmod, ident) = (qualidMod qident, qualidId qident)- mod | elem ident [listId, consId, nilId, unitId] || isTupleId ident- = Id.moduleName preludeMIdent- | otherwise- = maybe (Id.moduleName mid) Id.moduleName mmod- ftype <- lookupIdType qident- return (QName Nothing ftype mod $ name ident)---- This variant of visitQualIdent does not look up the type of the identifier,--- which is wise when the identifier is bound to a type, because looking up--- the type of a type via lookupIdType will get stuck in an endless loop. (hsi)-visitQualTypeIdent :: QualIdent -> FlatState QName-visitQualTypeIdent qident- = do mid <- moduleId- let (mmod, ident) = (qualidMod qident, qualidId qident)- mod | elem ident [listId, consId, nilId, unitId] || isTupleId ident- = Id.moduleName preludeMIdent- | otherwise- = maybe (Id.moduleName mid) Id.moduleName mmod- return (QName Nothing Nothing mod $ name ident)-----visitExternalName :: String -> FlatState String-visitExternalName name - = moduleId >>= \mid -> return (Id.moduleName mid ++ "." ++ name)-----------------------------------------------------------------------------------------------------------------------------------------------------------------------getVisibility :: Bool -> QualIdent -> FlatState Visibility-getVisibility isConstr qident- = do public <- isPublic isConstr qident- if public then return Public else return Private------getExportedImports :: FlatState [CS.IDecl]-getExportedImports- = do mid <- moduleId- exps <- exports- genExportedIDecls (Map.toList (getExpImports mid Map.empty exps))-----getExpImports :: ModuleIdent -> Map.Map ModuleIdent [CS.Export] -> [CS.Export]- -> Map.Map ModuleIdent [CS.Export]-getExpImports mident expenv [] = expenv-getExpImports mident expenv ((CS.Export qident):exps)- = getExpImports mident - (bindExpImport mident qident (CS.Export qident) expenv) - exps-getExpImports mident expenv ((CS.ExportTypeWith qident idents):exps)- = getExpImports mident - (bindExpImport mident - qident - (CS.ExportTypeWith qident idents) - expenv)- exps-getExpImports mident expenv ((CS.ExportTypeAll qident):exps)- = getExpImports mident - (bindExpImport mident qident (CS.ExportTypeAll qident) expenv) - exps-getExpImports mident expenv ((CS.ExportModule mident'):exps)- = getExpImports mident (Map.insert mident' [] expenv) exps-----bindExpImport :: ModuleIdent -> QualIdent -> CS.Export - -> Map.Map ModuleIdent [CS.Export] -> Map.Map ModuleIdent [CS.Export]-bindExpImport mident qident export expenv- | isJust (localIdent mident qident)- = expenv- | otherwise- = let (Just mod) = qualidMod qident- in maybe (Map.insert mod [export] expenv)- (\es -> Map.insert mod (export:es) expenv) - (Map.lookup mod expenv)-----genExportedIDecls :: [(ModuleIdent,[CS.Export])] -> FlatState [CS.IDecl]-genExportedIDecls mes = genExpIDecls [] mes-----genExpIDecls :: [CS.IDecl] -> [(ModuleIdent,[CS.Export])] -> FlatState [CS.IDecl]-genExpIDecls idecls [] = return idecls-genExpIDecls idecls ((mid,exps):mes)- = do intf_ <- lookupModuleIntf mid- let idecls' = maybe idecls (p_genExpIDecls mid idecls exps) intf_- genExpIDecls idecls' mes- where- p_genExpIDecls mid idecls exps intf- | null exps = (map (qualifyIDecl mid) intf) ++ idecls- | otherwise = (filter (isExportedIDecl exps) - (map (qualifyIDecl mid) intf))- ++ idecls---- -isExportedIDecl :: [CS.Export] -> CS.IDecl -> Bool-isExportedIDecl exports (CS.IInfixDecl _ _ _ qident)- = isExportedQualIdent qident exports-isExportedIDecl exports (CS.IDataDecl _ qident _ _)- = isExportedQualIdent qident exports-isExportedIDecl exports (CS.ITypeDecl _ qident _ _)- = isExportedQualIdent qident exports-isExportedIDecl exports (CS.IFunctionDecl _ qident _ _)- = isExportedQualIdent qident exports-isExportedIDecl exports _- = False-----isExportedQualIdent :: QualIdent -> [CS.Export] -> Bool-isExportedQualIdent qident [] = False-isExportedQualIdent qident ((CS.Export qident'):exps)- = qident == qident' || isExportedQualIdent qident exps-isExportedQualIdent qident ((CS.ExportTypeWith qident' idents):exps)- = qident == qident' || isExportedQualIdent qident exps-isExportedQualIdent qident ((CS.ExportTypeAll qident'):exps)- = qident == qident' || isExportedQualIdent qident exps-isExportedQualIdent qident ((CS.ExportModule _):exps)- = isExportedQualIdent qident exps-----qualifyIDecl :: ModuleIdent -> CS.IDecl -> CS.IDecl-qualifyIDecl mident (CS.IInfixDecl pos fix prec qident)- = (CS.IInfixDecl pos fix prec (qualQualify mident qident))-qualifyIDecl mident (CS.IDataDecl pos qident idents cdecls)- = (CS.IDataDecl pos (qualQualify mident qident) idents cdecls)-qualifyIDecl mident (CS.INewtypeDecl pos qident idents ncdecl)- = (CS.INewtypeDecl pos (qualQualify mident qident) idents ncdecl)-qualifyIDecl mident (CS.ITypeDecl pos qident idents texpr)- = (CS.ITypeDecl pos (qualQualify mident qident) idents texpr)-qualifyIDecl mident (CS.IFunctionDecl pos qident arity texpr)- = (CS.IFunctionDecl pos (qualQualify mident qident) arity texpr)-qualifyIDecl _ idecl = idecl------typeArity :: IL.Type -> Int-typeArity (IL.TypeArrow _ t) = 1 + (typeArity t)-typeArity (IL.TypeConstructor _ _) = 0-typeArity (IL.TypeVariable _) = 0---------------------------------------------------------------------------------------genFlatApplication :: IL.Expression -> IL.Expression -> FlatState Expr-genFlatApplication e1 e2- = genFlatApplic [e2] e1- where- genFlatApplic args expression - = case expression of- (IL.Apply expr1 expr2) - -> genFlatApplic (expr2:args) expr1- (IL.Function qident _)- -> do arity_ <- lookupIdArity qident- qname <- visitQualIdent qident- maybe (internalError (funcArity qident))- (\arity -> genFuncCall qname arity args)- arity_- (IL.Constructor qident _)- -> do arity_ <- lookupIdArity qident- qname <- visitQualIdent qident- maybe (internalError (consArity qident))- (\arity -> genConsCall qname arity args)- arity_- _ -> do expr <- visitExpression expression- genApplicComb expr args-----genFuncCall :: QName -> Int -> [IL.Expression] -> FlatState Expr-genFuncCall qname arity args- | arity > cnt - = genComb qname args (FuncPartCall (arity - cnt))- | arity < cnt - = do let (funcargs, applicargs) = splitAt arity args- funccall <- genComb qname funcargs FuncCall- genApplicComb funccall applicargs- | otherwise - = genComb qname args FuncCall- where cnt = length args-----genConsCall :: QName -> Int -> [IL.Expression] -> FlatState Expr-genConsCall qname arity args- | arity > cnt - = genComb qname args (ConsPartCall (arity - cnt))- | arity < cnt- = do let (funcargs, applicargs) = splitAt arity args- conscall <- genComb qname funcargs ConsCall- genApplicComb conscall applicargs- | otherwise - = genComb qname args ConsCall - where cnt = length args-----genComb :: QName -> [IL.Expression] -> CombType -> FlatState Expr-genComb qname args combtype- = do exprs <- mapM visitExpression args- return (Comb combtype qname exprs)- ----genApplicComb :: Expr -> [IL.Expression] -> FlatState Expr-genApplicComb expr [] = return expr-genApplicComb expr (e1:es)- = do expr1 <- visitExpression e1- qname <- visitQualIdent qidApply- genApplicComb (Comb FuncCall qname [expr, expr1]) es- where- qidApply = qualifyWith preludeMIdent (mkIdent "apply")------genOpDecls :: FlatState [OpDecl]-genOpDecls = fixities >>= mapM genOpDecl-----genOpDecl :: CS.IDecl -> FlatState OpDecl-genOpDecl (CS.IInfixDecl _ fixity prec qident)- = do qname <- visitQualIdent qident- return (Op qname (p_genOpFixity fixity) prec)- where- p_genOpFixity CS.InfixL = InfixlOp- p_genOpFixity CS.InfixR = InfixrOp- p_genOpFixity CS.Infix = InfixOp-genOpDecl _ = internalError "GenFlatCurry: no infix interface"----- The intermediate language (IL) does not represent type synonyms--- (and also no record declarations). For this reason an interface--- representation of all type synonyms is generated (see "CurryEnv")--- from the abstract syntax representation of the Curry program.--- The function 'typeSynonyms' returns this list of type synonyms.-genTypeSynonyms :: FlatState [TypeDecl]-genTypeSynonyms = typeSynonyms >>= mapM genTypeSynonym-----genTypeSynonym :: CS.IDecl -> FlatState TypeDecl-genTypeSynonym (CS.ITypeDecl _ qident params typeexpr)- = do let is = [0 .. (length params) - 1]- tyEnv <- gets typeEnvE- tcEnv <- gets tConsEnvE- let typeexpr' = elimRecordTypes tyEnv tcEnv typeexpr- texpr <- visitType (fst (cs2ilType (zip params is) typeexpr'))- qname <- visitQualTypeIdent qident- vis <- getVisibility False qident- return (TypeSyn qname vis is texpr)-genTypeSynonym _ = internalError "GenFlatCurry: no type synonym interface"----- In order to provide an interface for record declarations, 'genRecordTypes'--- generates dummy data declarations representing records together--- with their typed labels. For the record declaration------ type Rec = {l_1 :: t_1,..., l_n :: t_n}------ the following data declaration will be generated:------ data Rec' = l_1' t_1 | ... | l_n' :: t_n------ Rec' and l_i' are unique idenfifiers which encode the original names--- Rec and l_i.--- When reading an interface file containing such declarations, it is--- now possible to reconstruct the original record declaration. Since--- usual FlatCurry code is used, these declaration should not have any--- effects on the behaviour of the Curry program. But to ensure correctness,--- these dummies should be generated for the interface file as well as for--- the corresponding FlatCurry file.-genRecordTypes :: FlatState [TypeDecl]-genRecordTypes = records >>= mapM genRecordType-----genRecordType :: CS.IDecl -> FlatState TypeDecl-genRecordType (CS.ITypeDecl _ qident params (CS.RecordType fields _))- = do let is = [0 .. (length params) - 1]- (mod,ident) = (qualidMod qident, qualidId qident)- qname <- visitQualIdent ((maybe qualify qualifyWith mod) - (recordExtId ident))- labels <- mapM (genRecordLabel mod (zip params is)) fields- return (Type qname Public is labels)-----genRecordLabel :: Maybe ModuleIdent -> [(Ident,Int)] -> ([Ident],CS.TypeExpr) - -> FlatState ConsDecl-genRecordLabel mod vis ([ident],typeexpr)- = do tyEnv <- gets typeEnvE- tcEnv <- gets tConsEnvE- let typeexpr' = elimRecordTypes tyEnv tcEnv typeexpr- texpr <- visitType (fst (cs2ilType vis typeexpr'))- qname <- visitQualIdent ((maybe qualify qualifyWith mod) - (labelExtId ident))- return (Cons qname 1 Public [texpr])-------------------------------------------------------------------------------------- FlatCurry provides no possibility of representing record types like--- {l_1::t_1, l_2::t_2, ..., l_n::t_n}. So they have to be transformed to--- to the corresponding type constructors which are defined in the record --- declarations. --- Unlike data declarations or function type annotations, type synonyms and--- record declarations are not generated from the intermediate language.--- So the transformation has only to be performed in these cases.-elimRecordTypes :: ValueEnv -> TCEnv -> CS.TypeExpr -> CS.TypeExpr-elimRecordTypes tyEnv tcEnv (CS.ConstructorType qid typeexprs)- = CS.ConstructorType qid (map (elimRecordTypes tyEnv tcEnv) typeexprs)-elimRecordTypes tyEnv tcEnv (CS.VariableType id)- = CS.VariableType id-elimRecordTypes tyEnv tcEnv (CS.TupleType typeexprs)- = CS.TupleType (map (elimRecordTypes tyEnv tcEnv) typeexprs)-elimRecordTypes tyEnv tcEnv (CS.ListType typeexpr)- = CS.ListType (elimRecordTypes tyEnv tcEnv typeexpr)-elimRecordTypes tyEnv tcEnv (CS.ArrowType typeexpr1 typeexpr2)- = CS.ArrowType (elimRecordTypes tyEnv tcEnv typeexpr1)- (elimRecordTypes tyEnv tcEnv typeexpr2)-elimRecordTypes tyEnv tcEnv (CS.RecordType fss _)- = let fs = flattenRecordTypeFields fss- in case (lookupValue (fst (head fs)) tyEnv) of- [Label _ record _] ->- case (qualLookupTC record tcEnv) of- [AliasType _ n (TypeRecord fs' _)] ->- let ms = foldl (matchTypeVars fs) Map.empty fs'- types = map (\i -> maybe - (CS.VariableType - (mkIdent ("#tvar" ++ show i)))- (elimRecordTypes tyEnv tcEnv)- (Map.lookup i ms))- [0 .. n-1]- in CS.ConstructorType record types- _ -> internalError ("GenFlatCurry.elimRecordTypes: "- ++ "no record type")- _ -> internalError ("GenFlatCurry.elimRecordTypes: "- ++ "no label")--matchTypeVars :: [(Ident,CS.TypeExpr)] -> Map.Map Int CS.TypeExpr- -> (Ident, Type) -> Map.Map Int CS.TypeExpr-matchTypeVars fs ms (l,ty)- = maybe ms (match ms ty) (lookup l fs)- where- match ms (TypeVariable i) typeexpr = Map.insert i typeexpr ms- match ms (TypeConstructor _ tys) (CS.ConstructorType _ typeexprs)- = matchList ms tys typeexprs- match ms (TypeConstructor _ tys) (CS.ListType typeexpr)- = matchList ms tys [typeexpr]- match ms (TypeConstructor _ tys) (CS.TupleType typeexprs)- = matchList ms tys typeexprs- match ms (TypeArrow ty1 ty2) (CS.ArrowType typeexpr1 typeexpr2)- = matchList ms [ty1,ty2] [typeexpr1,typeexpr2]- match ms (TypeRecord fs' _) (CS.RecordType fss _)- = foldl (matchTypeVars (flattenRecordTypeFields fss)) ms fs'- match ms ty typeexpr- = internalError ("GenFlatCurry.matchTypeVars: "- ++ show ty ++ "\n" ++ show typeexpr)-- matchList ms tys- = foldl (\ms' (ty,typeexpr) -> match ms' ty typeexpr) ms . zip tys---flattenRecordTypeFields :: [([Ident],CS.TypeExpr)] -> [(Ident,CS.TypeExpr)]-flattenRecordTypeFields- = concatMap (\ (labels, typeexpr)- -> map (\label -> (label,typeexpr)) labels)--------------------------------------------------------------------------------------checkOverlapping :: Expr -> Expr -> FlatState ()-checkOverlapping expr1 expr2- = do opts <- compilerOpts- unless (noOverlapWarn opts)- (checkOverlap expr1 expr2)- where- checkOverlap (Case _ _ _ _) _ - = do qid <- functionId- genWarning (overlappingRules qid)- checkOverlap _ (Case _ _ _ _)- = do qid <- functionId- genWarning (overlappingRules qid)- checkOverlap _ _ = return ()-------------------------------------------------------------------------------------- -cs2ilType :: [(Ident,Int)] -> CS.TypeExpr -> (IL.Type, [(Ident,Int)])-cs2ilType ids (CS.ConstructorType qident typeexprs)- = let (ilTypeexprs, ids') = emap cs2ilType ids typeexprs- in (IL.TypeConstructor qident ilTypeexprs, ids')-cs2ilType ids (CS.VariableType ident)- = let mid = lookup ident ids- nid | null ids = 0- | otherwise = 1 + snd (head ids)- (id, ids') | isJust mid = (fromJust mid, ids)- | otherwise = (nid, (ident, nid):ids)- in (IL.TypeVariable id, ids')-cs2ilType ids (CS.ArrowType type1 type2)- = let (ilType1, ids') = cs2ilType ids type1- (ilType2, ids'') = cs2ilType ids' type2- in (IL.TypeArrow ilType1 ilType2, ids'')-cs2ilType ids (CS.ListType typeexpr)- = let (ilTypeexpr, ids') = cs2ilType ids typeexpr- in (IL.TypeConstructor (qualify listId) [ilTypeexpr], ids')-cs2ilType ids (CS.TupleType typeexprs)- = case typeexprs of- [] -> (IL.TypeConstructor qUnitId [], ids)- [t] -> cs2ilType ids t- _ -> let (ilTypeexprs, ids') = emap cs2ilType ids typeexprs- tuplen = length ilTypeexprs- in (IL.TypeConstructor (qTupleId tuplen) ilTypeexprs,- ids')-cs2ilType _ typeexpr = internalError ("cs2ilType: " ++ show typeexpr)------------------------------------------------------------------------------------- Messages for internal errors and warnings--funcArity qid = "GenFlatCurry: missing arity for function \"" - ++ show qid ++ "\""--consArity qid = "GenFlatCurry: missing arity for constructor \""- ++ show qid ++ "\""--missingVarIndex id = "GenFlatCurry: missing index for \"" ++ show id ++ "\""---overlappingRules qid = "function \""- ++ qualName qid - ++ "\" is non-deterministic due to non-trivial "- ++ "overlapping rules"-----------------------------------------------------------------------------------------------------------------------------------------------------------------------isDataDecl :: IL.Decl -> Bool-isDataDecl (IL.DataDecl _ _ _) = True-isDataDecl _ = False-----isFuncDecl :: IL.Decl -> Bool-isFuncDecl (IL.FunctionDecl _ _ _ _) = True-isFuncDecl (IL.ExternalDecl _ _ _ _) = True-isFuncDecl _ = False-----isPublicDataDecl :: IL.Decl -> FlatState Bool-isPublicDataDecl (IL.DataDecl qident _ _ ) = isPublic False qident-isPublicDataDecl _ = return False-----isPublicFuncDecl :: IL.Decl -> FlatState Bool-isPublicFuncDecl (IL.FunctionDecl qident _ _ _) = isPublic False qident-isPublicFuncDecl (IL.ExternalDecl qident _ _ _) = isPublic False qident-isPublicFuncDecl _ = return False-----isTypeIDecl :: CS.IDecl -> Bool-isTypeIDecl (CS.IDataDecl _ _ _ _) = True-isTypeIDecl (CS.ITypeDecl _ _ _ _) = True-isTypeIDecl _ = False-----isRecordIDecl :: CS.IDecl -> Bool-isRecordIDecl (CS.ITypeDecl _ _ _ (CS.RecordType (_:_) _)) = True-isRecordIDecl _ = False-----isFuncIDecl :: CS.IDecl -> Bool-isFuncIDecl (CS.IFunctionDecl _ _ _ _) = True-isFuncIDecl _ = False-----isOpIDecl :: CS.IDecl -> Bool-isOpIDecl (CS.IInfixDecl _ _ _ _) = True-isOpIDecl _ = False ------bindingIdent :: IL.Binding -> Ident-bindingIdent (IL.Binding ident _) = ident-------------------------------------------------------------------------------------------------------------------------------------------------------------------emap :: (e -> a -> (b,e)) -> e -> [a] -> ([b], e)-emap _ env [] = ([], env)-emap f env (x:xs) = let (x',env') = f env x- (xs', env'') = emap f env' xs- in ((x':xs'), env'')----------------------------------------------------------------------------------------------------------------------------------------------------------------------moduleId :: FlatState ModuleIdent-moduleId = gets moduleIdE-----functionId :: FlatState QualIdent-functionId = gets (fst . functionIdE)-----setFunctionId :: (QualIdent, [(Ident, IL.Type)]) -> FlatState ()-setFunctionId qid = modify (\env -> env{ functionIdE = qid })-----compilerOpts :: FlatState Options-compilerOpts = gets compilerOptsE-----exports :: FlatState [CS.Export]-exports = gets exportsE-----imports :: FlatState [CS.IDecl]-imports = gets importsE-----records :: FlatState [CS.IDecl]-records = gets (filter isRecordIDecl . interfaceE)-----fixities :: FlatState [CS.IDecl]-fixities = gets fixitiesE-----typeSynonyms :: FlatState [CS.IDecl]-typeSynonyms = gets typeSynonymsE-----isPublic :: Bool -> QualIdent -> FlatState Bool-isPublic isConstr qid = gets (\env -> maybe False isP- (Map.lookup (unqualify qid) - (publicEnvE env)))- where- isP NotConstr = not isConstr- isP OnlyConstr = isConstr- isP NotOnlyConstr = True-----lookupModuleIntf :: ModuleIdent -> FlatState (Maybe [CS.IDecl])-lookupModuleIntf mid- = gets (Map.lookup mid . moduleEnvE)-----lookupIdArity :: QualIdent -> FlatState (Maybe Int)-lookupIdArity qid- = gets (lookupA qid . arityEnvE)- where- lookupA qid aEnv = case (qualLookupArity qid aEnv) of- [ArityInfo _ a]- -> Just a- [] -> case (lookupArity (unqualify qid) aEnv) of- [ArityInfo _ a] -> Just a- _ -> Nothing- _ -> Nothing----getTypeOf :: Ident -> FlatState (Maybe TypeExpr)-getTypeOf ident = do- valEnv <- gets typeEnvE - case lookupValue ident valEnv of - Value _ (ForAll _ t) : _ - -> do t <- visitType (ttrans t)- trace' ("getTypeOf(" ++ show ident ++ ") = " ++ show t)$- return (Just t)- DataConstructor _ (ForAllExist _ _ t):_ - -> do t <- visitType (ttrans t)- trace' ("getTypeOfDataCon(" ++ show ident ++ ") = " ++ show t)$- return (Just t)- _ -> do (_,ats) <- gets functionIdE- case lookup ident ats of- Just t -> liftM Just (visitType t)- Nothing -> trace' ("lookupValue did not return a value for index " ++ show ident)- (return Nothing)-ttrans :: Type -> IL.Type -ttrans (TypeConstructor i ts)- = IL.TypeConstructor i (map ttrans ts)-ttrans (TypeVariable v)- = IL.TypeVariable v-ttrans (TypeConstrained [] v)- = IL.TypeVariable v-ttrans (TypeConstrained (v:_) i)- = ttrans v-ttrans (TypeArrow f x) = IL.TypeArrow (ttrans f) (ttrans x)-ttrans s@(TypeSkolem _) = error $ "in ttrans: " ++ show s-ttrans s@(TypeRecord _ _) = error $ "in ttrans: " ++ show s------ Constructor (:) receives special treatment throughout the--- whole implementation. We won't depart from that for mere--- aesthetic reasons. (hsi)-lookupIdType :: QualIdent -> FlatState (Maybe TypeExpr)-lookupIdType (QualIdent Nothing (Ident _ "[]" _))- = return (Just l0)- where l0 = TCons (mkQName ("Prelude", "[]")) [TVar 0]-lookupIdType (QualIdent Nothing (Ident _ ":" _))- = return (Just (FuncType (TVar 0) (FuncType (l0) (l0))))- where l0 = TCons (mkQName ("Prelude", "[]")) [TVar 0]-lookupIdType (QualIdent Nothing (Ident _ "()" _))- = return (Just l0)- where l0 = TCons (mkQName ("Prelude", "()")) []-lookupIdType (QualIdent Nothing (Ident _ t@('(':',':r) _))- = return (Just funtype)- where tupleArity = length r + 1- argTypes = map TVar [1..tupleArity]- contype = TCons (mkQName ("Prelude", t)) argTypes- funtype = foldr FuncType contype argTypes-lookupIdType qid- = do aEnv <- gets typeEnvE- lt <- gets localTypes- ct <- gets constrTypes- case Map.lookup qid lt `mplus` Map.lookup qid ct of- Just t -> trace' ("lookupIdType local " ++ show (qid, t)) $ liftM Just (visitType t) -- local name or constructor- Nothing -> case [ t | Value _ (ForAll _ t) <- qualLookupValue qid aEnv ] of - t : _ -> liftM Just (visitType (IL.translType t)) -- imported name- [] -> case qualidMod qid of- Nothing -> trace' ("no type for " ++ show qid) $ return Nothing -- no known type- Just _ -> lookupIdType qid {qualidMod = Nothing}--- ---- Generates a new index for a variable-newVarIndex :: Ident -> FlatState VarIndex-newVarIndex ident- = do idx0 <- gets varIndexE- ty <- getTypeOf ident- let idx = idx0 + 1- vid = VarIndex ty idx- vids <- gets varIdsE- modify (\env -> env{ varIndexE = idx,- varIdsE = ScopeEnv.insert ident vid vids- })- return vid-----lookupVarIndex :: Ident -> FlatState VarIndex-lookupVarIndex id- = do index_ <- gets (ScopeEnv.lookup id . varIdsE)- maybe (internalError (missingVarIndex id)) return index_-----clearVarIndices :: FlatState ()-clearVarIndices = modify (\env -> env { varIndexE = 0,- varIdsE = ScopeEnv.new - })-----genWarning :: String -> FlatState ()-genWarning msg- = modify (\env -> env{ messagesE = warnMsg:(messagesE env) })- where warnMsg = WarnMsg Nothing msg-----genInterface :: FlatState Bool-genInterface = gets genInterfaceE-----beginScope :: FlatState ()-beginScope = modify- (\env -> env { varIdsE = ScopeEnv.beginScope (varIdsE env)- })-----endScope :: FlatState ()-endScope = modify- (\env -> env { varIdsE = ScopeEnv.endScope (varIdsE env)- })-----whenFlatCurry :: FlatState a -> FlatState a -> FlatState a-whenFlatCurry genFlat genIntf - = genInterface >>= (\intf -> if intf then genIntf else genFlat)-------------------------------------------------------------------------------------- Generates an evironment containing all public identifiers from the module--- Note: Currently the record functions (selection and update) for all public --- record labels are inserted into the environment, though they are not--- explicitly declared in the export specifications.-genPubEnv :: ModuleIdent -> [CS.IDecl] -> Map.Map Ident IdentExport-genPubEnv mid idecls = foldl (bindEnvIDecl mid) Map.empty idecls--bindIdentExport :: Ident -> Bool -> Map.Map Ident IdentExport -> Map.Map Ident IdentExport-bindIdentExport id isConstr env =- maybe (Map.insert id (if isConstr then OnlyConstr else NotConstr) env)- (\ ie -> Map.insert id (updateIdentExport ie isConstr) env)- (Map.lookup id env)- where- updateIdentExport OnlyConstr True = OnlyConstr- updateIdentExport OnlyConstr False = NotOnlyConstr- updateIdentExport NotConstr True = NotOnlyConstr- updateIdentExport NotConstr False = NotConstr- updateIdentExport NotOnlyConstr _ = NotOnlyConstr------bindEnvIDecl :: ModuleIdent -> Map.Map Ident IdentExport -> CS.IDecl -> Map.Map Ident IdentExport-bindEnvIDecl mid env (CS.IDataDecl _ qid _ mcdecls)- = maybe env - (\id -> foldl bindEnvConstrDecl- (bindIdentExport id False env)- (catMaybes mcdecls))- (localIdent mid qid)-bindEnvIDecl mid env (CS.INewtypeDecl _ qid _ ncdecl)- = maybe env - (\id -> bindEnvNewConstrDecl (bindIdentExport id False env) ncdecl)- (localIdent mid qid)-bindEnvIDecl mid env (CS.ITypeDecl _ qid _ texpr)- = maybe env (\id -> bindEnvITypeDecl env id texpr) (localIdent mid qid)-bindEnvIDecl mid env (CS.IFunctionDecl _ qid _ _)- = maybe env (\id -> bindIdentExport id False env) (localIdent mid qid)-bindEnvIDecl _ env _ = env-----bindEnvITypeDecl :: Map.Map Ident IdentExport -> Ident -> CS.TypeExpr- -> Map.Map Ident IdentExport-bindEnvITypeDecl env id (CS.RecordType fs _)- = bindIdentExport id False (foldl (bindEnvRecordLabel id) env fs)-bindEnvITypeDecl env id texpr- = bindIdentExport id False env-----bindEnvConstrDecl :: Map.Map Ident IdentExport -> CS.ConstrDecl -> Map.Map Ident IdentExport-bindEnvConstrDecl env (CS.ConstrDecl _ _ id _) = bindIdentExport id True env-bindEnvConstrDecl env (CS.ConOpDecl _ _ _ id _) = bindIdentExport id True env-----bindEnvNewConstrDecl :: Map.Map Ident IdentExport -> CS.NewConstrDecl -> Map.Map Ident IdentExport-bindEnvNewConstrDecl env (CS.NewConstrDecl _ _ id _) = bindIdentExport id False env-----bindEnvRecordLabel :: Ident -> Map.Map Ident IdentExport -> ([Ident],CS.TypeExpr) -> Map.Map Ident IdentExport-bindEnvRecordLabel r env ([lab], _) = bindIdentExport (recSelectorId (qualify r) lab) False expo- where - expo = (bindIdentExport (recUpdateId (qualify r) lab) False env)---splitoffArgTypes :: IL.Type -> [Ident] -> [(Ident, IL.Type)]-splitoffArgTypes (IL.TypeArrow l r) (i:is) = (i, l):splitoffArgTypes r is-splitoffArgTypes _ [] = []-splitoffArgTypes _ _ = error "internal error in splitoffArgTypes"--
+ src/Generators.hs view
@@ -0,0 +1,59 @@+{- |+ Module : $Header$+ Description : Code generators+ Copyright : (c) 2011 Björn Peemöller+ 2017 Finn Teegen+ 2018 Kai-Oliver Prott+ License : BSD-3-clause++ Maintainer : fte@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module subsumes the different code generators.+-}+module Generators where++import qualified Curry.AbstractCurry as AC (CurryProg)+import qualified Curry.FlatCurry.Type as FC (Prog, TypeExpr)+import qualified Curry.FlatCurry.Annotated.Type as AFC (AProg)+import qualified Curry.FlatCurry.Typed.Type as TFC (TProg)+import qualified Curry.Syntax as CS (Module)++import qualified Generators.GenAbstractCurry as GAC (genAbstractCurry)+import qualified Generators.GenFlatCurry as GFC ( genFlatCurry+ , genFlatInterface+ )+import qualified Generators.GenAnnotatedFlatCurry+ as GAFC (genAnnotatedFlatCurry)+import qualified Generators.GenTypedFlatCurry as GTFC (genTypedFlatCurry)++import Base.Types (Type, PredType)++import CompilerEnv (CompilerEnv (..))+import qualified IL (Module)++-- |Generate typed AbstractCurry+genTypedAbstractCurry :: CompilerEnv -> CS.Module PredType -> AC.CurryProg+genTypedAbstractCurry = GAC.genAbstractCurry False++-- |Generate untyped AbstractCurry+genUntypedAbstractCurry :: CompilerEnv -> CS.Module PredType -> AC.CurryProg+genUntypedAbstractCurry = GAC.genAbstractCurry True++-- |Generate typed FlatCurry+genTypedFlatCurry :: AFC.AProg FC.TypeExpr -> TFC.TProg+genTypedFlatCurry = GTFC.genTypedFlatCurry++-- |Generate type-annotated FlatCurry+genAnnotatedFlatCurry :: CompilerEnv -> CS.Module Type -> IL.Module+ -> AFC.AProg FC.TypeExpr+genAnnotatedFlatCurry = GAFC.genAnnotatedFlatCurry++-- |Generate FlatCurry+genFlatCurry :: AFC.AProg FC.TypeExpr -> FC.Prog+genFlatCurry = GFC.genFlatCurry++-- |Generate a FlatCurry interface+genFlatInterface :: FC.Prog -> FC.Prog+genFlatInterface = GFC.genFlatInterface
+ src/Generators/GenAbstractCurry.hs view
@@ -0,0 +1,541 @@+{- |+ Module : $Header$+ Description : Generation of AbstractCurry program terms+ Copyright : (c) 2005 Martin Engelke+ 2011 - 2015 Björn Peemöller+ 2015 Jan Tikovsky+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module contains the generation of an 'AbstractCurry' program term+ for a given 'Curry' module.+-}+{-# LANGUAGE CPP #-}+module Generators.GenAbstractCurry (genAbstractCurry) where++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative ((<$>), (<*>), pure)+#endif+import Control.Monad.Extra+import qualified Control.Monad.State as S (State, evalState, get, gets+ , modify, put, when)+import qualified Data.Map as Map (Map, empty, fromList, lookup+ , union)+import qualified Data.Maybe as Maybe (fromJust, fromMaybe, listToMaybe)+import qualified Data.Set as Set (Set, empty, insert, member)+import qualified Data.Traversable as T (forM)++import Curry.AbstractCurry+import Curry.Base.Ident+import Curry.Base.SpanInfo+import Curry.Syntax++import Base.CurryTypes (fromPredType, toType, toPredType)+import Base.Expr (bv)+import Base.Messages (internalError)+import Base.NestEnv+import Base.Types (arrowArity, PredType, unpredType, TypeScheme (..))+import Base.TypeSubst++import Env.Value (ValueEnv, ValueInfo (..), qualLookupValue)+import Env.OpPrec (mkPrec)++import CompilerEnv++type GAC a = S.State AbstractEnv a++-- ---------------------------------------------------------------------------+-- Interface+-- ---------------------------------------------------------------------------++-- |Generate an AbstractCurry program term from the syntax tree+-- when uacy flag is set untype AbstractCurry is generated+genAbstractCurry :: Bool -> CompilerEnv -> Module PredType -> CurryProg+genAbstractCurry uacy env mdl+ = S.evalState (trModule mdl) (abstractEnv uacy env mdl)++-- ---------------------------------------------------------------------------+-- Conversion from Curry to AbstractCurry+-- ---------------------------------------------------------------------------++trModule :: Module PredType -> GAC CurryProg+trModule (Module _ _ _ mid _ is ds) =+ CurryProg mid' is' <$> dflt' <*> cds' <*> ids' <*> ts' <*> fs' <*> os'+ where+ mid' = moduleName mid+ is' = map cvImportDecl is+ dflt' = Maybe.listToMaybe <$> concatMapM (withLocalEnv . trDefaultDecl) ds+ cds' = concatMapM (withLocalEnv . trClassDecl) ds+ ids' = concatMapM (withLocalEnv . trInstanceDecl) ds+ ts' = concatMapM (withLocalEnv . trTypeDecl) ds+ fs' = concatMapM (withLocalEnv . trFuncDecl True) ds+ os' = concatMapM (withLocalEnv . trInfixDecl) ds++cvImportDecl :: ImportDecl -> String+cvImportDecl (ImportDecl _ mid _ _ _) = moduleName mid++trDefaultDecl :: Decl a -> GAC [CDefaultDecl]+trDefaultDecl (DefaultDecl _ tys) = (\tys' -> [CDefaultDecl tys'])+ <$> mapM trTypeExpr tys+trDefaultDecl _ = return []++trClassDecl :: Decl PredType -> GAC [CClassDecl]+trClassDecl (ClassDecl _ _ cx cls tv ds) =+ (\cls' v' cx' tv' ds' -> [CClass cls' v' cx' tv' ds'])+ <$> trGlobalIdent cls <*> getTypeVisibility cls <*> trContext cx+ <*> getTVarIndex tv <*> concatMapM (trClassMethodDecl sigs fs) ds+ where fs = [f | FunctionDecl _ _ f _ <- ds]+ sigs = signatures ds+trClassDecl _ = return []++-- We ignore type signatures for class methods with a given default+-- implementation as declarations for those are generated anyway.+-- For function declarations we use the equation's arity instead of+-- the one from the value environment or 0.+trClassMethodDecl :: [(Ident, QualTypeExpr)] -> [Ident] -> Decl PredType+ -> GAC [CFuncDecl]+trClassMethodDecl sigs fs (TypeSig p [f] _) | f `notElem` fs =+ trClassMethodDecl sigs fs $ FunctionDecl p undefined f []+trClassMethodDecl sigs fs (TypeSig p (f:f':fs') qty) =+ liftM2 (++) (trClassMethodDecl sigs fs $ TypeSig p [f] qty)+ (trClassMethodDecl sigs fs $ TypeSig p (f':fs') qty)+trClassMethodDecl sigs _ (FunctionDecl _ _ f eqs) =+ (\f' a v ty rs -> [CFunc f' a v ty rs]) <$> trGlobalIdent f+ <*> pure (maybe 0 eqnArity $ Maybe.listToMaybe eqs)+ <*> getVisibility (unRenameIdent f)+ <*> trQualTypeExpr (Maybe.fromJust $ lookup f sigs) <*> mapM trEquation eqs+trClassMethodDecl _ _ _ = return []++trInstanceDecl :: Decl PredType -> GAC [CInstanceDecl]+trInstanceDecl (InstanceDecl _ _ cx qcls ty ds) =+ (\qcls' cx' ty' ds' -> [CInstance qcls' cx' ty' ds']) <$> trQual qcls+ <*> trContext cx <*> trTypeExpr ty <*> mapM (trInstanceMethodDecl qcls ty) ds+trInstanceDecl _ = return []++-- Again, we use the equation's arity for function declarations instead of+-- the one from the value.+trInstanceMethodDecl :: QualIdent -> TypeExpr -> Decl PredType -> GAC CFuncDecl+trInstanceMethodDecl qcls ty (FunctionDecl _ _ f eqs) = do+ uacy <- S.gets untypedAcy+ qty <- if uacy+ then return $ QualTypeExpr NoSpanInfo [] $+ ConstructorType NoSpanInfo prelUntyped+ else getQualType' (qualifyLike qcls $ unRenameIdent f)+ CFunc <$> trLocalIdent f <*> pure (eqnArity $ head eqs) <*> pure Public+ <*> trInstanceMethodType ty qty <*> mapM trEquation eqs+trInstanceMethodDecl _ _ _ = internalError "GenAbstractCurry.trInstanceMethodDecl"++-- Transforms a class method type into an instance method's type by replacing+-- the class variable with the given instance type. The implicit class context+-- is dropped in doing so.+trInstanceMethodType :: TypeExpr -> QualTypeExpr -> GAC CQualTypeExpr+trInstanceMethodType ity (QualTypeExpr _ cx ty) =+ trQualTypeExpr $ fromPredType identSupply $+ subst (bindSubst 0 (toType [] ity) idSubst) $+ toPredType (take 1 identSupply) $ QualTypeExpr NoSpanInfo (drop 1 cx) ty++trTypeDecl :: Decl a -> GAC [CTypeDecl]+trTypeDecl (DataDecl _ t vs cs clss) =+ (\t' v vs' cs' clss' -> [CType t' v vs' cs' clss'])+ <$> trGlobalIdent t <*> getTypeVisibility t+ <*> mapM genTVarIndex vs <*> mapM trConsDecl cs+ <*> mapM trQual clss+trTypeDecl (TypeDecl _ t vs ty) = (\t' v vs' ty' -> [CTypeSyn t' v vs' ty'])+ <$> trGlobalIdent t <*> getTypeVisibility t+ <*> mapM genTVarIndex vs <*> trTypeExpr ty+trTypeDecl (NewtypeDecl _ t vs nc clss) =+ (\t' v vs' nc' clss' -> [CNewType t' v vs' nc' clss'])+ <$> trGlobalIdent t <*> getTypeVisibility t+ <*> mapM genTVarIndex vs <*> trNewConsDecl nc+ <*> mapM trQual clss+trTypeDecl (ExternalDataDecl _ t vs) =+ (\t' v vs' -> [CType t' v vs' [] []])+ <$> trGlobalIdent t <*> getTypeVisibility t <*> mapM genTVarIndex vs+trTypeDecl _ = return []++trConsDecl :: ConstrDecl -> GAC CConsDecl+trConsDecl (ConstrDecl _ c tys) = inNestedTScope $ CCons+ <$> trGlobalIdent c <*> getVisibility c <*> mapM trTypeExpr tys+trConsDecl (ConOpDecl p ty1 op ty2) = inNestedTScope $ trConsDecl $+ ConstrDecl p op [ty1, ty2]+trConsDecl (RecordDecl _ c fs) = inNestedTScope $ CRecord+ <$> trGlobalIdent c <*> getVisibility c <*> concatMapM trFieldDecl fs++trFieldDecl :: FieldDecl -> GAC [CFieldDecl]+trFieldDecl (FieldDecl _ ls ty) = T.forM ls $ \l ->+ CField <$> trGlobalIdent l <*> getVisibility l <*> trTypeExpr ty++trNewConsDecl :: NewConstrDecl -> GAC CConsDecl+trNewConsDecl (NewConstrDecl _ nc ty) = CCons+ <$> trGlobalIdent nc <*> getVisibility nc <*> ((:[]) <$> trTypeExpr ty)+trNewConsDecl (NewRecordDecl p nc (l, ty)) = CRecord+ <$> trGlobalIdent nc <*> getVisibility nc <*> trFieldDecl (FieldDecl p [l] ty)++trTypeExpr :: TypeExpr -> GAC CTypeExpr+trTypeExpr (ConstructorType _ q) = CTCons <$> trQual q+trTypeExpr (ApplyType _ ty1 ty2) = CTApply <$> trTypeExpr ty1 <*> trTypeExpr ty2+trTypeExpr (VariableType _ v) = CTVar <$> getTVarIndex v+trTypeExpr (TupleType _ tys) =+ trTypeExpr $ foldl (ApplyType NoSpanInfo)+ (ConstructorType NoSpanInfo $ qTupleId $ length tys) tys+trTypeExpr (ListType _ ty) =+ trTypeExpr $ ApplyType NoSpanInfo (ConstructorType NoSpanInfo qListId) ty+trTypeExpr (ArrowType _ ty1 ty2) = CFuncType <$> trTypeExpr ty1 <*> trTypeExpr ty2+trTypeExpr (ParenType _ ty) = trTypeExpr ty+trTypeExpr (ForallType _ _ _) = internalError "GenAbstractCurry.trTypeExpr"++trConstraint :: Constraint -> GAC CConstraint+trConstraint (Constraint _ q ty) = (,) <$> trQual q <*> trTypeExpr ty++trContext :: Context -> GAC CContext+trContext cx = CContext <$> mapM trConstraint cx++trQualTypeExpr :: QualTypeExpr -> GAC CQualTypeExpr+trQualTypeExpr (QualTypeExpr _ cx ty) =+ CQualType <$> trContext cx <*> trTypeExpr ty++trInfixDecl :: Decl a -> GAC [COpDecl]+trInfixDecl (InfixDecl _ fix mprec ops) = mapM trInfix (reverse ops)+ where+ trInfix op = COp <$> trGlobalIdent op <*> return (cvFixity fix)+ <*> return (fromInteger (mkPrec mprec))+ cvFixity InfixL = CInfixlOp+ cvFixity InfixR = CInfixrOp+ cvFixity Infix = CInfixOp+trInfixDecl _ = return []++trFuncDecl :: Bool -> Decl PredType -> GAC [CFuncDecl]+trFuncDecl global (FunctionDecl _ pty f eqs)+ = (\f' a v ty rs -> [CFunc f' a v ty rs])+ <$> trFuncName global f <*> pure (eqnArity $ head eqs) <*> getVisibility f+ <*> getQualType f pty <*> mapM trEquation eqs+trFuncDecl global (ExternalDecl _ vs)+ = T.forM vs $ \(Var pty f) -> CFunc+ <$> trFuncName global f <*> pure (arrowArity $ unpredType pty)+ <*> getVisibility f <*> getQualType f pty <*> return []+trFuncDecl _ _ = return []++trFuncName :: Bool -> Ident -> GAC QName+trFuncName global = if global then trGlobalIdent else trLocalIdent++trEquation :: Equation PredType -> GAC CRule+trEquation (Equation _ lhs rhs) = inNestedScope+ $ CRule <$> trLhs lhs <*> trRhs rhs++trLhs :: Lhs a -> GAC [CPattern]+trLhs = mapM trPat . snd . flatLhs++trRhs :: Rhs PredType -> GAC CRhs+trRhs (SimpleRhs _ _ e ds) = inNestedScope $ do+ mapM_ insertDeclLhs ds+ CSimpleRhs <$> trExpr e <*> concatMapM trLocalDecl ds+trRhs (GuardedRhs _ _ gs ds) = inNestedScope $ do+ mapM_ insertDeclLhs ds+ CGuardedRhs <$> mapM trCondExpr gs <*> concatMapM trLocalDecl ds++trCondExpr :: CondExpr PredType -> GAC (CExpr, CExpr)+trCondExpr (CondExpr _ g e) = (,) <$> trExpr g <*> trExpr e++trLocalDecls :: [Decl PredType] -> GAC [CLocalDecl]+trLocalDecls ds = do+ mapM_ insertDeclLhs ds+ concatMapM trLocalDecl ds++-- Insert all variables declared in local declarations+insertDeclLhs :: Decl a -> GAC ()+insertDeclLhs (PatternDecl _ p _) = mapM_ genVarIndex (bv p)+insertDeclLhs (FreeDecl _ vs) = mapM_ genVarIndex (map varIdent vs)+insertDeclLhs s@(TypeSig _ _ _) = do+ uacy <- S.gets untypedAcy+ S.when uacy (insertSig s)+insertDeclLhs _ = return ()++trLocalDecl :: Decl PredType -> GAC [CLocalDecl]+trLocalDecl f@(FunctionDecl _ _ _ _) = map CLocalFunc <$> trFuncDecl False f+trLocalDecl f@(ExternalDecl _ _) = map CLocalFunc <$> trFuncDecl False f+trLocalDecl (PatternDecl _ p rhs) = (\p' rhs' -> [CLocalPat p' rhs'])+ <$> trPat p <*> trRhs rhs+trLocalDecl (FreeDecl _ vs) = (\vs' -> [CLocalVars vs'])+ <$> mapM getVarIndex (map varIdent vs)+trLocalDecl _ = return [] -- can not occur (types etc.)++insertSig :: Decl a -> GAC ()+insertSig (TypeSig _ fs qty) = do+ sigs <- S.gets typeSigs+ let lsigs = Map.fromList [(f, qty) | f <- fs]+ S.modify $ \env -> env { typeSigs = sigs `Map.union` lsigs }+insertSig _ = return ()++trExpr :: Expression PredType -> GAC CExpr+trExpr (Literal _ _ l) = return (CLit $ cvLiteral l)+trExpr (Variable _ _ v)+ | isQualified v = CSymbol <$> trQual v+ | otherwise = lookupVarIndex (unqualify v) >>= \mvi -> case mvi of+ Just vi -> return (CVar vi)+ _ -> CSymbol <$> trQual v+trExpr (Constructor _ _ c) = CSymbol <$> trQual c+trExpr (Paren _ e) = trExpr e+trExpr (Typed _ e qty) = CTyped <$> trExpr e <*> trQualTypeExpr qty+trExpr (Record _ _ c fs) = CRecConstr <$> trQual c+ <*> mapM (trField trExpr) fs+trExpr (RecordUpdate _ e fs) = CRecUpdate <$> trExpr e+ <*> mapM (trField trExpr) fs+trExpr (Tuple _ es) =+ trExpr $ apply (Variable NoSpanInfo undefined $ qTupleId $ length es) es+trExpr (List _ _ es) =+ trExpr $ foldr (Apply NoSpanInfo . Apply NoSpanInfo+ (Constructor NoSpanInfo undefined qConsId))+ (Constructor NoSpanInfo undefined qNilId)+ es+trExpr (ListCompr _ e ds) = inNestedScope $ flip CListComp+ <$> mapM trStatement ds <*> trExpr e+trExpr (EnumFrom _ e) =+ trExpr $ apply (Variable NoSpanInfo undefined qEnumFromId) [e]+trExpr (EnumFromThen _ e1 e2) =+ trExpr $ apply (Variable NoSpanInfo undefined qEnumFromThenId) [e1, e2]+trExpr (EnumFromTo _ e1 e2) =+ trExpr $ apply (Variable NoSpanInfo undefined qEnumFromToId) [e1, e2]+trExpr (EnumFromThenTo _ e1 e2 e3) =+ trExpr $ apply (Variable NoSpanInfo undefined qEnumFromThenToId) [e1, e2, e3]+trExpr (UnaryMinus _ e) =+ trExpr $ apply (Variable NoSpanInfo undefined qNegateId) [e]+trExpr (Apply _ e1 e2) = CApply <$> trExpr e1 <*> trExpr e2+trExpr (InfixApply _ e1 op e2) = trExpr $ apply (infixOp op) [e1, e2]+trExpr (LeftSection _ e op) = trExpr $ apply (infixOp op) [e]+trExpr (RightSection _ op e) =+ trExpr $ apply (Variable NoSpanInfo undefined qFlip) [infixOp op, e]+trExpr (Lambda _ ps e) = inNestedScope $+ CLambda <$> mapM trPat ps <*> trExpr e+trExpr (Let _ _ ds e) = inNestedScope $+ CLetDecl <$> trLocalDecls ds <*> trExpr e+trExpr (Do _ _ ss e) = inNestedScope $+ (\ss' e' -> CDoExpr (ss' ++ [CSExpr e']))+ <$> mapM trStatement ss <*> trExpr e+trExpr (IfThenElse _ e1 e2 e3) =+ trExpr $ apply (Variable NoSpanInfo undefined qIfThenElseId) [e1, e2, e3]+trExpr (Case _ _ ct e bs) = CCase (cvCaseType ct)+ <$> trExpr e <*> mapM trAlt bs++cvCaseType :: CaseType -> CCaseType+cvCaseType Flex = CFlex+cvCaseType Rigid = CRigid++trStatement :: Statement PredType -> GAC CStatement+trStatement (StmtExpr _ e) = CSExpr <$> trExpr e+trStatement (StmtDecl _ _ ds) = CSLet <$> trLocalDecls ds+trStatement (StmtBind _ p e) = flip CSPat <$> trExpr e <*> trPat p++trAlt :: Alt PredType -> GAC (CPattern, CRhs)+trAlt (Alt _ p rhs) = inNestedScope $ (,) <$> trPat p <*> trRhs rhs++trPat :: Pattern a -> GAC CPattern+trPat (LiteralPattern _ _ l) = return (CPLit $ cvLiteral l)+trPat (VariablePattern _ _ v) = CPVar <$> getVarIndex v+trPat (ConstructorPattern _ _ c ps) = CPComb <$> trQual c <*> mapM trPat ps+trPat (InfixPattern _ a p1 op p2) =+ trPat $ ConstructorPattern NoSpanInfo a op [p1, p2]+trPat (ParenPattern _ p) = trPat p+trPat (RecordPattern _ _ c fs) = CPRecord <$> trQual c+ <*> mapM (trField trPat) fs+trPat (TuplePattern _ ps) =+ trPat $ ConstructorPattern NoSpanInfo undefined (qTupleId $ length ps) ps+trPat (ListPattern _ _ ps) = trPat $+ foldr (\x1 x2 -> ConstructorPattern NoSpanInfo undefined qConsId [x1, x2])+ (ConstructorPattern NoSpanInfo undefined qNilId [])+ ps+trPat (NegativePattern _ a l) =+ trPat $ LiteralPattern NoSpanInfo a $ negateLiteral l+trPat (AsPattern _ v p) = CPAs <$> getVarIndex v<*> trPat p+trPat (LazyPattern _ p) = CPLazy <$> trPat p+trPat (FunctionPattern _ _ f ps) = CPFuncComb <$> trQual f <*> mapM trPat ps+trPat (InfixFuncPattern _ a p1 f p2) =+ trPat (FunctionPattern NoSpanInfo a f [p1, p2])++trField :: (a -> GAC b) -> Field a -> GAC (CField b)+trField act (Field _ l x) = (,) <$> trQual l <*> act x++negateLiteral :: Literal -> Literal+negateLiteral (Int i) = Int (-i)+negateLiteral (Float f) = Float (-f)+negateLiteral _ = internalError "GenAbstractCurry.negateLiteral"++cvLiteral :: Literal -> CLiteral+cvLiteral (Char c) = CCharc c+cvLiteral (Int i) = CIntc i+cvLiteral (Float f) = CFloatc f+cvLiteral (String s) = CStringc s++trQual :: QualIdent -> GAC QName+trQual qid+ | n `elem` [unitId, listId, nilId, consId] = return ("Prelude", idName n)+ | isTupleId n = return ("Prelude", idName n)+ | otherwise+ = return (maybe "" moduleName (qidModule qid), idName n)+ where n = qidIdent qid++trGlobalIdent :: Ident -> GAC QName+trGlobalIdent i = S.gets moduleId >>= \m -> return (moduleName m, idName i)++trLocalIdent :: Ident -> GAC QName+trLocalIdent i = return ("", idName i)++qFlip :: QualIdent+qFlip = qualifyWith preludeMIdent (mkIdent "flip")++qNegateId :: QualIdent+qNegateId = qualifyWith preludeMIdent (mkIdent "negate")++qIfThenElseId :: QualIdent+qIfThenElseId = qualifyWith preludeMIdent (mkIdent "ifThenElse")++prelUntyped :: QualIdent+prelUntyped = qualifyWith preludeMIdent $ mkIdent "untyped"++-------------------------------------------------------------------------------+-- This part defines an environment containing all necessary information+-- for generating the AbstractCurry representation of a CurrySyntax term.++-- |Data type for representing an AbstractCurry generator environment+data AbstractEnv = AbstractEnv+ { moduleId :: ModuleIdent -- ^name of the module+ , typeEnv :: ValueEnv -- ^known values+ , tyExports :: Set.Set Ident -- ^exported type symbols+ , valExports :: Set.Set Ident -- ^exported value symbols+ , varIndex :: Int -- ^counter for variable indices+ , tvarIndex :: Int -- ^counter for type variable indices+ , varEnv :: NestEnv Int -- ^stack of variable tables+ , tvarEnv :: NestEnv Int -- ^stack of type variable tables+ , untypedAcy :: Bool -- ^flag to indicate whether untyped+ -- AbstractCurry is generated+ , typeSigs :: Map.Map Ident QualTypeExpr -- ^map of user defined type signatures+ } deriving Show++-- |Initialize the AbstractCurry generator environment+abstractEnv :: Bool -> CompilerEnv -> Module a -> AbstractEnv+abstractEnv uacy env (Module _ _ _ mid es _ ds) = AbstractEnv+ { moduleId = mid+ , typeEnv = valueEnv env+ , tyExports = foldr (buildTypeExports mid) Set.empty es'+ , valExports = foldr (buildValueExports mid) Set.empty es'+ , varIndex = 0+ , tvarIndex = 0+ , varEnv = globalEnv emptyTopEnv+ , tvarEnv = globalEnv emptyTopEnv+ , untypedAcy = uacy+ , typeSigs = if uacy+ then Map.fromList $ signatures ds+ else Map.empty+ }+ where es' = case es of+ Just (Exporting _ e) -> e+ _ -> internalError "GenAbstractCurry.abstractEnv"++-- Builds a table containing all exported identifiers from a module.+buildTypeExports :: ModuleIdent -> Export -> Set.Set Ident -> Set.Set Ident+buildTypeExports mid (ExportTypeWith _ tc _)+ | isLocalIdent mid tc = Set.insert (unqualify tc)+buildTypeExports _ _ = id++-- Builds a table containing all exported identifiers from a module.+buildValueExports :: ModuleIdent -> Export -> Set.Set Ident -> Set.Set Ident+buildValueExports mid (Export _ q)+ | isLocalIdent mid q = Set.insert (unqualify q)+buildValueExports mid (ExportTypeWith _ tc cs)+ | isLocalIdent mid tc = flip (foldr Set.insert) cs+buildValueExports _ _ = id++-- Looks up the unique index for the variable 'ident' in the+-- variable table of the current scope.+lookupVarIndex :: Ident -> GAC (Maybe CVarIName)+lookupVarIndex i = S.gets $ \env -> case lookupNestEnv i $ varEnv env of+ [v] -> Just (v, idName i)+ _ -> Nothing++getVarIndex :: Ident -> GAC CVarIName+getVarIndex i = S.get >>= \env -> case lookupNestEnv i $ varEnv env of+ [v] -> return (v, idName i)+ _ -> genVarIndex i++-- Generates an unique index for the variable 'ident' and inserts it+-- into the variable table of the current scope.+genVarIndex :: Ident -> GAC CVarIName+genVarIndex i = do+ env <- S.get+ let idx = varIndex env+ S.put $ env { varIndex = idx + 1, varEnv = bindNestEnv i idx (varEnv env) }+ return (idx, idName i)++-- Looks up the unique index for the type variable 'ident' in the type+-- variable table of the current scope.+getTVarIndex :: Ident -> GAC CTVarIName+getTVarIndex i = S.get >>= \env -> case lookupNestEnv i $ tvarEnv env of+ [v] -> return (v, idName i)+ _ -> genTVarIndex i++-- Generates an unique index for the type variable 'ident' and inserts it+-- into the type variable table of the current scope.+genTVarIndex :: Ident -> GAC CTVarIName+genTVarIndex i = do+ env <- S.get+ let idx = tvarIndex env+ S.put $ env { tvarIndex = idx + 1, tvarEnv = bindNestEnv i idx (tvarEnv env) }+ return (idx, idName i)++withLocalEnv :: GAC a -> GAC a+withLocalEnv act = do+ old <- S.get+ res <- act+ S.put old+ return res++inNestedScope :: GAC a -> GAC a+inNestedScope act = do+ (vo, to) <- S.gets $ \e -> (varEnv e, tvarEnv e)+ S.modify $ \e -> e { varEnv = nestEnv $ vo, tvarEnv = globalEnv emptyTopEnv }+ res <- act+ S.modify $ \e -> e { varEnv = vo, tvarEnv = to }+ return res++inNestedTScope :: GAC a -> GAC a+inNestedTScope act = do+ (vo, to) <- S.gets $ \e -> (varEnv e, tvarEnv e)+ S.modify $ \e -> e { varEnv = globalEnv emptyTopEnv, tvarEnv = nestEnv $ to }+ res <- act+ S.modify $ \e -> e { varEnv = vo, tvarEnv = to }+ return res++getQualType :: Ident -> PredType -> GAC CQualTypeExpr+getQualType f pty = do+ uacy <- S.gets untypedAcy+ sigs <- S.gets typeSigs+ trQualTypeExpr $ case uacy of+ True -> Maybe.fromMaybe (QualTypeExpr NoSpanInfo [] $+ ConstructorType NoSpanInfo prelUntyped)+ (Map.lookup f sigs)+ False -> fromPredType identSupply pty++getQualType' :: QualIdent -> GAC QualTypeExpr+getQualType' f = do+ m <- S.gets moduleId+ tyEnv <- S.gets typeEnv+ return $ case qualLookupValue f tyEnv of+ [Value _ _ _ (ForAll _ pty)] -> fromPredType identSupply pty+ _ -> case qualLookupValue (qualQualify m f) tyEnv of+ [Value _ _ _ (ForAll _ pty)] -> fromPredType identSupply pty+ _ ->+ internalError $ "GenAbstractCurry.getQualType': " ++ show f++getTypeVisibility :: Ident -> GAC CVisibility+getTypeVisibility i = S.gets $ \env ->+ if Set.member i (tyExports env) then Public else Private++getVisibility :: Ident -> GAC CVisibility+getVisibility i = S.gets $ \env ->+ if Set.member i (valExports env) then Public else Private++signatures :: [Decl a] -> [(Ident, QualTypeExpr)]+signatures ds = [(f, qty) | TypeSig _ fs qty <- ds, f <- fs]
+ src/Generators/GenAnnotatedFlatCurry.hs view
@@ -0,0 +1,488 @@+{- |+ Module : $Header$+ Description : Generation of typed FlatCurry program terms+ Copyright : (c) 2017 Finn Teegen+ 2018 Kai-Oliver Prott+ License : BSD-3-clause++ Maintainer : fte@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module contains the generation of a type-annotated 'FlatCurry'+ program term for a given module in the intermediate language.+-}+{-# LANGUAGE CPP #-}+module Generators.GenAnnotatedFlatCurry (genAnnotatedFlatCurry) where++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative ((<$>), (<*>))+#endif+import Control.Monad ((<=<))+import Control.Monad.Extra (concatMapM)+import qualified Control.Monad.State as S ( State, evalState, get, gets+ , modify, put )+import Data.Function (on)+import Data.List (nub, sortBy)+import Data.Maybe (fromMaybe)+import qualified Data.Map as Map (Map, empty, insert, lookup)+import qualified Data.Set as Set (Set, empty, insert, member)++import Curry.Base.Ident+import Curry.FlatCurry.Annotated.Goodies (typeName)+import Curry.FlatCurry.Annotated.Type+import qualified Curry.Syntax as CS++import Base.Messages (internalError)+import Base.NestEnv ( NestEnv, emptyEnv, bindNestEnv, lookupNestEnv+ , nestEnv, unnestEnv )+import Base.Types++import CompilerEnv+import Env.TypeConstructor (TCEnv)++import qualified IL++-- transforms intermediate language code (IL) to type-annotated FlatCurry code+genAnnotatedFlatCurry :: CompilerEnv -> CS.Module Type -> IL.Module+ -> AProg TypeExpr+genAnnotatedFlatCurry env mdl il = patchPrelude $ run env mdl (trModule il)++-- -----------------------------------------------------------------------------+-- Addition of primitive types for lists and tuples to the Prelude+-- -----------------------------------------------------------------------------++patchPrelude :: AProg a -> AProg a+patchPrelude p@(AProg n _ ts fs os)+ | n == prelude = AProg n [] ts' fs os+ | otherwise = p+ where ts' = sortBy (compare `on` typeName) pts+ pts = primTypes ++ ts++primTypes :: [TypeDecl]+primTypes =+ [ Type arrow Public [(0, KStar), (1, KStar)] []+ , Type unit Public [] [(Cons unit 0 Public [])]+ , Type nil Public [(0, KStar)] [ Cons nil 0 Public []+ , Cons cons 2 Public [TVar 0, TCons nil [TVar 0]]+ ]+ ] ++ map mkTupleType [2 .. maxTupleArity]+ where arrow = mkPreludeQName "(->)"+ unit = mkPreludeQName "()"+ nil = mkPreludeQName "[]"+ cons = mkPreludeQName ":"++mkTupleType :: Int -> TypeDecl+mkTupleType arity = Type tuple Public [(i, KStar) | i <- [0 .. arity - 1]]+ [Cons tuple arity Public $ map TVar [0 .. arity - 1]]+ where tuple = mkPreludeQName $ '(' : replicate (arity - 1) ',' ++ ")"++mkPreludeQName :: String -> QName+mkPreludeQName n = (prelude, n)++prelude :: String+prelude = "Prelude"++-- |Maximal arity of tuples+maxTupleArity :: Int+maxTupleArity = 15++-- -----------------------------------------------------------------------------++-- The environment 'FlatEnv' is embedded in the monadic representation+-- 'FlatState' which allows the usage of 'do' expressions.+type FlatState a = S.State FlatEnv a++-- Data type for representing an environment which contains information needed+-- for generating FlatCurry code.+data FlatEnv = FlatEnv+ { modIdent :: ModuleIdent -- current module+ -- for visibility calculation+ , tyExports :: Set.Set Ident -- exported types+ , valExports :: Set.Set Ident -- exported values (functions + constructors)+ , tcEnv :: TCEnv -- type constructor environment+ , typeSynonyms :: [CS.Decl Type] -- type synonyms+ , imports :: [ModuleIdent] -- module imports+ -- state for mapping identifiers to indexes+ , nextVar :: Int -- fresh variable index counter+ , varMap :: NestEnv VarIndex -- map of identifier to variable index+ }++-- Runs a 'FlatState' action and returns the result+run :: CompilerEnv -> CS.Module Type -> FlatState a -> a+run env (CS.Module _ _ _ mid es is ds) act = S.evalState act env0+ where+ es' = case es of Just (CS.Exporting _ e) -> e+ _ -> []+ env0 = FlatEnv+ { modIdent = mid+ -- for visibility calculation+ , tyExports = foldr (buildTypeExports mid) Set.empty es'+ , valExports = foldr (buildValueExports mid) Set.empty es'+ -- This includes *all* imports, even unused ones+ , imports = nub [ m | CS.ImportDecl _ m _ _ _ <- is ]+ -- Environment to retrieve the type of identifiers+ , tcEnv = tyConsEnv env+ -- Type synonyms in the module+ , typeSynonyms = [ d | d@CS.TypeDecl{} <- ds ]+ , nextVar = 0+ , varMap = emptyEnv+ }++-- Builds a table containing all exported identifiers from a module.+buildTypeExports :: ModuleIdent -> CS.Export -> Set.Set Ident -> Set.Set Ident+buildTypeExports mid (CS.ExportTypeWith _ tc _)+ | isLocalIdent mid tc = Set.insert (unqualify tc)+buildTypeExports _ _ = id++-- Builds a table containing all exported identifiers from a module.+buildValueExports :: ModuleIdent -> CS.Export -> Set.Set Ident -> Set.Set Ident+buildValueExports mid (CS.Export _ q)+ | isLocalIdent mid q = Set.insert (unqualify q)+buildValueExports mid (CS.ExportTypeWith _ tc cs)+ | isLocalIdent mid tc = flip (foldr Set.insert) cs+buildValueExports _ _ = id++getModuleIdent :: FlatState ModuleIdent+getModuleIdent = S.gets modIdent++-- Retrieve imports+getImports :: [ModuleIdent] -> FlatState [String]+getImports imps = (nub . map moduleName . (imps ++)) <$> S.gets imports++-- -----------------------------------------------------------------------------+-- Stateful part, used for translation of rules and expressions+-- -----------------------------------------------------------------------------++-- resets var index and environment+withFreshEnv :: FlatState a -> FlatState a+withFreshEnv act = S.modify (\ s -> s { nextVar = 0, varMap = emptyEnv }) >> act++-- Execute an action in a nested variable mapping+inNestedEnv :: FlatState a -> FlatState a+inNestedEnv act = do+ S.modify $ \ s -> s { varMap = nestEnv $ varMap s }+ res <- act+ S.modify $ \ s -> s { varMap = unnestEnv $ varMap s }+ return res++-- Generates a new variable index for an identifier+newVar :: IL.Type -> Ident -> FlatState (VarIndex, TypeExpr)+newVar ty i = do+ idx <- (+1) <$> S.gets nextVar+ S.modify $ \ s -> s { nextVar = idx, varMap = bindNestEnv i idx (varMap s) }+ ty' <- trType ty+ return (idx, ty')++-- Retrieve the variable index assigned to an identifier+getVarIndex :: Ident -> FlatState VarIndex+getVarIndex i = S.gets varMap >>= \ varEnv -> case lookupNestEnv i varEnv of+ [v] -> return v+ _ -> internalError $ "GenTypeAnnotatedFlatCurry.getVarIndex: " ++ escName i++-- -----------------------------------------------------------------------------+-- Translation of a module+-- -----------------------------------------------------------------------------++trModule :: IL.Module -> FlatState (AProg TypeExpr)+trModule (IL.Module mid is ds) = do+ is' <- getImports is+ tds <- concatMapM trTypeDecl ds+ fds <- concatMapM (return . map runNormalization <=< trAFuncDecl) ds+ return $ AProg (moduleName mid) is' tds fds []++-- Translate a data declaration+-- For empty data declarations, an additional constructor is generated. This+-- is due to the fact that external data declarations are translated into data+-- declarations with zero constructors and without the additional constructor+-- empty data declarations could not be distinguished from external ones.+trTypeDecl :: IL.Decl -> FlatState [TypeDecl]+trTypeDecl (IL.DataDecl qid ks []) = do+ q' <- trQualIdent qid+ vis <- getTypeVisibility qid+ c <- trQualIdent $ qualify (mkIdent $ "_Constr#" ++ idName (unqualify qid))+ let ks' = trKind <$> ks+ tvs = zip [0..] ks'+ return [Type q' vis tvs [Cons c 1 Private [TCons q' $ TVar <$> fst <$> tvs]]]+trTypeDecl (IL.DataDecl qid ks cs) = do+ q' <- trQualIdent qid+ vis <- getTypeVisibility qid+ cs' <- mapM trConstrDecl cs+ let ks' = trKind <$> ks+ tvs = zip [0..] ks'+ return [Type q' vis tvs cs']+trTypeDecl (IL.NewtypeDecl qid ks nc) = do+ q' <- trQualIdent qid+ vis <- getTypeVisibility qid+ nc' <- trNewConstrDecl nc+ let ks' = trKind <$> ks+ tvs = zip [0..] ks'+ return [TypeNew q' vis tvs nc']+trTypeDecl (IL.ExternalDataDecl qid ks) = do+ q' <- trQualIdent qid+ vis <- getTypeVisibility qid+ let ks' = trKind <$> ks+ tvs = zip [0..] ks'+ return [Type q' vis tvs []]+trTypeDecl _ = return []++-- Translate a constructor declaration+trConstrDecl :: IL.ConstrDecl -> FlatState ConsDecl+trConstrDecl (IL.ConstrDecl qid tys) = flip Cons (length tys)+ <$> trQualIdent qid+ <*> getVisibility qid+ <*> mapM trType tys++-- Translate a constructor declaration for newtypes+trNewConstrDecl :: IL.NewConstrDecl -> FlatState NewConsDecl+trNewConstrDecl (IL.NewConstrDecl qid ty) = NewCons+ <$> trQualIdent qid+ <*> getVisibility qid+ <*> trType ty++-- Translate a type expression+trType :: IL.Type -> FlatState TypeExpr+trType (IL.TypeConstructor t tys) = TCons <$> trQualIdent t <*> mapM trType tys+trType (IL.TypeVariable idx) = return $ TVar $ abs idx+trType (IL.TypeArrow ty1 ty2) = FuncType <$> trType ty1 <*> trType ty2+trType (IL.TypeForall idxs ty) = ForallType (map trTVarWithKind idxs) <$> trType ty++-- Translates a type variable with kind.+trTVarWithKind :: (Int, IL.Kind) -> (Int, Kind)+trTVarWithKind (i, k) = (abs i, trKind k)++-- Translate a kind+trKind :: IL.Kind -> Kind+trKind IL.KindStar = KStar+trKind (IL.KindVariable _) = KStar+trKind (IL.KindArrow k1 k2) = KArrow (trKind k1) (trKind k2)++-- -----------------------------------------------------------------------------+-- Function declarations+-- -----------------------------------------------------------------------------++-- Translate a function declaration+trAFuncDecl :: IL.Decl -> FlatState [AFuncDecl TypeExpr]+trAFuncDecl (IL.FunctionDecl f vs ty e) = do+ f' <- trQualIdent f+ vis <- getVisibility f+ ty' <- trType ty+ r' <- trARule ty vs e+ return [AFunc f' (length vs) vis ty' r']+trAFuncDecl (IL.ExternalDecl f a ty) = do+ f' <- trQualIdent f+ vis <- getVisibility f+ ty' <- trType ty+ r' <- trAExternal ty f --TODO: get arity from type?+ return [AFunc f' a vis ty' r']+trAFuncDecl _ = return []++-- Translate a function rule.+-- Resets variable index so that for every rule variables start with index 1+trARule :: IL.Type -> [(IL.Type, Ident)] -> IL.Expression+ -> FlatState (ARule TypeExpr)+trARule ty vs e = withFreshEnv $ ARule <$> trType ty+ <*> mapM (uncurry newVar) vs+ <*> trAExpr e++trAExternal :: IL.Type -> QualIdent -> FlatState (ARule TypeExpr)+trAExternal ty f = flip AExternal (qualName f) <$> trType ty++-- Translate an expression+trAExpr :: IL.Expression -> FlatState (AExpr TypeExpr)+trAExpr (IL.Literal ty l) = ALit <$> trType ty <*> trLiteral l+trAExpr (IL.Variable ty v) = AVar <$> trType ty <*> getVarIndex v+trAExpr (IL.Function ty f a) = genCall Fun ty f a []+trAExpr (IL.Constructor ty c a) = genCall Con ty c a []+trAExpr (IL.Apply e1 e2) = trApply e1 e2+trAExpr c@(IL.Case t e bs) = flip ACase (cvEval t) <$> trType (IL.typeOf c) <*> trAExpr e+ <*> mapM (inNestedEnv . trAlt) bs+trAExpr (IL.Or e1 e2) = AOr <$> trType (IL.typeOf e1) <*> trAExpr e1 <*> trAExpr e2+trAExpr (IL.Exist v ty e) = inNestedEnv $ do+ v' <- newVar ty v+ e' <- trAExpr e+ ty' <- trType (IL.typeOf e)+ return $ case e' of AFree ty'' vs e'' -> AFree ty'' (v' : vs) e''+ _ -> AFree ty' (v' : []) e'+trAExpr (IL.Let (IL.Binding v b) e) = inNestedEnv $ do+ v' <- newVar (IL.typeOf b) v+ b' <- trAExpr b+ e' <- trAExpr e+ ty' <- trType $ IL.typeOf e+ return $ case e' of ALet ty'' bs e'' -> ALet ty'' ((v', b'):bs) e''+ _ -> ALet ty' ((v', b'):[]) e'+trAExpr (IL.Letrec bs e) = inNestedEnv $ do+ let (vs, es) = unzip [ ((IL.typeOf b, v), b) | IL.Binding v b <- bs]+ ALet <$> trType (IL.typeOf e)+ <*> (zip <$> mapM (uncurry newVar) vs <*> mapM trAExpr es)+ <*> trAExpr e+trAExpr (IL.Typed e ty) = ATyped <$> ty' <*> trAExpr e <*> ty'+ where ty' = trType $ ty++-- Translate a literal+trLiteral :: IL.Literal -> FlatState Literal+trLiteral (IL.Char c) = return $ Charc c+trLiteral (IL.Int i) = return $ Intc i+trLiteral (IL.Float f) = return $ Floatc f++-- Translate a higher-order application+trApply :: IL.Expression -> IL.Expression -> FlatState (AExpr TypeExpr)+trApply e1 e2 = genFlatApplic e1 [e2]+ where+ genFlatApplic e es = case e of+ IL.Apply ea eb -> genFlatApplic ea (eb:es)+ IL.Function ty f a -> genCall Fun ty f a es+ IL.Constructor ty c a -> genCall Con ty c a es+ _ -> do+ expr <- trAExpr e+ genApply expr es++-- Translate an alternative+trAlt :: IL.Alt -> FlatState (ABranchExpr TypeExpr)+trAlt (IL.Alt p e) = ABranch <$> trPat p <*> trAExpr e++-- Translate a pattern+trPat :: IL.ConstrTerm -> FlatState (APattern TypeExpr)+trPat (IL.LiteralPattern ty l) = ALPattern <$> trType ty <*> trLiteral l+trPat (IL.ConstructorPattern ty c vs) = do+ qty <- trType $ foldr IL.TypeArrow ty $ map fst vs+ APattern <$> trType ty <*> ((\q -> (q, qty)) <$> trQualIdent c) <*> mapM (uncurry newVar) vs+trPat (IL.VariablePattern _ _) = internalError "GenTypeAnnotatedFlatCurry.trPat"++-- Convert a case type+cvEval :: IL.Eval -> CaseType+cvEval IL.Rigid = Rigid+cvEval IL.Flex = Flex++data Call = Fun | Con++-- Generate a function or constructor call+genCall :: Call -> IL.Type -> QualIdent -> Int -> [IL.Expression]+ -> FlatState (AExpr TypeExpr)+genCall call ty f arity es = do+ f' <- trQualIdent f+ case compare supplied arity of+ LT -> genAComb ty f' es (part call (arity - supplied))+ EQ -> genAComb ty f' es (full call)+ GT -> do+ let (es1, es2) = splitAt arity es+ funccall <- genAComb ty f' es1 (full call)+ genApply funccall es2+ where+ supplied = length es+ full Fun = FuncCall+ full Con = ConsCall+ part Fun = FuncPartCall+ part Con = ConsPartCall++genAComb :: IL.Type -> QName -> [IL.Expression] -> CombType -> FlatState (AExpr TypeExpr)+genAComb ty qid es ct = do+ ty' <- trType ty+ let ty'' = defunc ty' (length es)+ AComb ty'' ct (qid, ty') <$> mapM trAExpr es+ where+ defunc t 0 = t+ defunc (FuncType _ t2) n = defunc t2 (n - 1)+ defunc _ _ = internalError "GenTypeAnnotatedFlatCurry.genAComb.defunc"++genApply :: AExpr TypeExpr -> [IL.Expression] -> FlatState (AExpr TypeExpr)+genApply e es = do+ ap <- trQualIdent $ qApplyId+ es' <- mapM trAExpr es+ return $ foldl (\e1 e2 -> let FuncType ty1 ty2 = typeOf e1 in AComb ty2 FuncCall (ap, FuncType (FuncType ty1 ty2) (FuncType ty1 ty2)) [e1, e2]) e es'++-- -----------------------------------------------------------------------------+-- Normalization+-- -----------------------------------------------------------------------------++runNormalization :: Normalize a => a -> a+runNormalization x = S.evalState (normalize x) (0, Map.empty)++type NormState a = S.State (Int, Map.Map Int Int) a++class Normalize a where+ normalize :: a -> NormState a++instance Normalize a => Normalize [a] where+ normalize = mapM normalize++instance Normalize Int where+ normalize i = do+ (n, m) <- S.get+ case Map.lookup i m of+ Nothing -> do+ S.put (n + 1, Map.insert i n m)+ return n+ Just n' -> return n'++instance Normalize TypeExpr where+ normalize (TVar i) = TVar <$> normalize i+ normalize (TCons q tys) = TCons q <$> normalize tys+ normalize (FuncType ty1 ty2) = FuncType <$> normalize ty1 <*> normalize ty2+ normalize (ForallType is ty) = ForallType <$> mapM normalizeTypeVar is+ <*> normalize ty+ where normalizeTypeVar (tv, k) = (,) <$> normalize tv <*> pure k++instance Normalize a => Normalize (AFuncDecl a) where+ normalize (AFunc f a v ty r) = AFunc f a v <$> normalize ty <*> normalize r++instance Normalize a => Normalize (ARule a) where+ normalize (ARule ty vs e) = ARule <$> normalize ty+ <*> mapM normalizeTuple vs+ <*> normalize e+ normalize (AExternal ty s) = flip AExternal s <$> normalize ty++normalizeTuple :: Normalize b => (a, b) -> NormState (a, b)+normalizeTuple (a, b) = (,) <$> pure a <*> normalize b ++instance Normalize a => Normalize (AExpr a) where+ normalize (AVar ty v) = flip AVar v <$> normalize ty+ normalize (ALit ty l) = flip ALit l <$> normalize ty+ normalize (AComb ty ct f es) = flip AComb ct <$> normalize ty+ <*> normalizeTuple f+ <*> normalize es+ normalize (ALet ty ds e) = ALet <$> normalize ty+ <*> mapM normalizeBinding ds+ <*> normalize e+ where normalizeBinding (v, b) = (,) <$> normalizeTuple v <*> normalize b+ normalize (AOr ty a b) = AOr <$> normalize ty <*> normalize a+ <*> normalize b+ normalize (ACase ty ct e bs) = flip ACase ct <$> normalize ty <*> normalize e+ <*> normalize bs+ normalize (AFree ty vs e) = AFree <$> normalize ty+ <*> mapM normalizeTuple vs+ <*> normalize e+ normalize (ATyped ty e ty') = ATyped <$> normalize ty <*> normalize e+ <*> normalize ty'++instance Normalize a => Normalize (ABranchExpr a) where+ normalize (ABranch p e) = ABranch <$> normalize p <*> normalize e++instance Normalize a => Normalize (APattern a) where+ normalize (APattern ty c vs) = APattern <$> normalize ty+ <*> normalizeTuple c+ <*> mapM normalizeTuple vs+ normalize (ALPattern ty l) = flip ALPattern l <$> normalize ty++-- -----------------------------------------------------------------------------+-- Helper functions+-- -----------------------------------------------------------------------------++trQualIdent :: QualIdent -> FlatState QName+trQualIdent qid = do+ mid <- getModuleIdent+ return $ (moduleName $ fromMaybe mid mid', idName i)+ where+ mid' | i `elem` [listId, consId, nilId, unitId] || isTupleId i+ = Just preludeMIdent+ | otherwise+ = qidModule qid+ i = qidIdent qid++getTypeVisibility :: QualIdent -> FlatState Visibility+getTypeVisibility i = S.gets $ \s ->+ if Set.member (unqualify i) (tyExports s) then Public else Private++getVisibility :: QualIdent -> FlatState Visibility+getVisibility i = S.gets $ \s ->+ if Set.member (unqualify i) (valExports s) then Public else Private
+ src/Generators/GenFlatCurry.hs view
@@ -0,0 +1,56 @@+{- |+ Module : $Header$+ Description : Generation of FlatCurry program and interface terms+ Copyright : (c) 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module contains the generation of a 'FlatCurry' program term or+ a 'FlatCurry' interface out of an 'Annotated FlatCurry' module.+-}+module Generators.GenFlatCurry (genFlatCurry, genFlatInterface) where++import Curry.FlatCurry.Goodies+import Curry.FlatCurry.Type+import Curry.FlatCurry.Annotated.Goodies+import Curry.FlatCurry.Annotated.Type++-- transforms annotated FlatCurry code to FlatCurry code+genFlatCurry :: AProg TypeExpr -> Prog+genFlatCurry = trAProg+ (\name imps types funcs ops ->+ Prog name imps types (map genFlatFuncDecl funcs) ops)++genFlatFuncDecl :: AFuncDecl TypeExpr -> FuncDecl+genFlatFuncDecl = trAFunc+ (\name arity vis ty rule -> Func name arity vis ty $ genFlatRule rule)++genFlatRule :: ARule TypeExpr -> Rule+genFlatRule = trARule+ (\_ args e -> Rule (map fst args) $ genFlatExpr e)+ (const External)++genFlatExpr :: AExpr TypeExpr -> Expr+genFlatExpr = trAExpr+ (const Var)+ (const Lit)+ (\_ ct (name, _) args -> Comb ct name args)+ (const $ Let . map (\(v, e') -> (fst v, e')))+ (const $ Free . map fst)+ (const Or)+ (const Case)+ (Branch . genFlatPattern)+ (const Typed)++genFlatPattern :: APattern TypeExpr -> Pattern+genFlatPattern = trAPattern+ (\_ (name, _) args -> Pattern name $ map fst args)+ (const LPattern)++-- transforms a FlatCurry module to a FlatCurry interface+genFlatInterface :: Prog -> Prog+genFlatInterface =+ updProgFuncs $ map $ updFuncRule $ const $ Rule [] $ Var 0
+ src/Generators/GenTypedFlatCurry.hs view
@@ -0,0 +1,53 @@+{- |+ Module : $Header$+ Description : Generation of typed FlatCurry program terms+ Copyright : (c) 2017 Finn Teegen+ 2018 Kai-Oliver Prott+ License : BSD-3-clause++ Maintainer : fte@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module contains the generation of a typed 'FlatCurry' program term+ for a given module in the intermediate language.+-}+{-# LANGUAGE CPP #-}+module Generators.GenTypedFlatCurry (genTypedFlatCurry) where++import Curry.FlatCurry.Annotated.Type+import Curry.FlatCurry.Annotated.Goodies+import Curry.FlatCurry.Typed.Type++-- transforms annotated FlatCurry code to typed FlatCurry code+genTypedFlatCurry :: AProg TypeExpr -> TProg+genTypedFlatCurry = trAProg+ (\name imps types funcs ops ->+ TProg name imps types (map genTypedFuncDecl funcs) ops)++genTypedFuncDecl :: AFuncDecl TypeExpr -> TFuncDecl+genTypedFuncDecl = trAFunc+ (\name arity vis ty rule -> TFunc name arity vis ty $ genTypedRule rule)++genTypedRule :: ARule TypeExpr -> TRule+genTypedRule = trARule+ (\_ args e -> TRule args $ genTypedExpr e)+ TExternal++genTypedExpr :: AExpr TypeExpr -> TExpr+genTypedExpr = trAExpr+ TVarE+ TLit+ (\ty ct (name, _) args -> TComb ty ct name args)+ (const TLet)+ (const TFree)+ (const TOr)+ (const TCase)+ (TBranch . genTypedPattern)+ (const TTyped)++genTypedPattern :: APattern TypeExpr -> TPattern+genTypedPattern = trAPattern+ (\ty (name, _) args -> TPattern ty name args)+ TLPattern+
+ src/Html/CurryHtml.hs view
@@ -0,0 +1,185 @@+{- |+ Module : $Header$+ Description : Generating HTML documentation+ Copyright : (c) 2011 - 2016, Björn Peemöller+ 2016 , Jan Tikovsky+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module defines a function for generating HTML documentation pages+ for Curry source modules.+-}+{-# LANGUAGE TemplateHaskell #-}+module Html.CurryHtml (source2html) where++import Prelude as P+import Control.Monad.Writer+import Data.List (mapAccumL)+import Data.Maybe (fromMaybe, isJust)+import Data.ByteString as BS (ByteString, writeFile)+import Data.FileEmbed+import Network.URI (escapeURIString, isUnreserved)+import System.FilePath ((</>))++import Curry.Base.Ident ( ModuleIdent (..), Ident (..), QualIdent (..)+ , unqualify, moduleName)+import Curry.Base.Monad (CYIO)+import Curry.Base.Position (Position)+import Curry.Files.Filenames (htmlName)+import Curry.Syntax (Module (..), Token)++import Html.SyntaxColoring+++import CompilerOpts (Options (..))++-- |Read file via TemplateHaskell at compile time+cssContent :: ByteString+cssContent = $(makeRelativeToProject "data/currysource.css" >>= embedFile)++-- | Name of the css file+-- NOTE: The relative path is given above+cssFileName :: String+cssFileName = "currysource.css"++-- |Translate source file into HTML file with syntaxcoloring+source2html :: Options -> ModuleIdent -> [(Position, Token)] -> Module a+ -> CYIO ()+source2html opts mid toks mdl = do+ liftIO $ P.writeFile (outDir </> htmlName mid) doc+ updateCSSFile outDir+ where+ doc = program2html mid (genProgram mdl toks)+ outDir = fromMaybe "." (optHtmlDir opts)++-- |Update the CSS file+updateCSSFile :: FilePath -> CYIO ()+updateCSSFile dir = do+ let target = dir </> cssFileName+ liftIO $ BS.writeFile target cssContent++-- generates htmlcode with syntax highlighting+-- @param modulname+-- @param a program+-- @return HTMLcode+program2html :: ModuleIdent -> [Code] -> String+program2html m codes = unlines+ [ "<!DOCTYPE html>"+ , "<html lang=\"en\">"+ , "<head>"+ , "<meta charset=\"utf-8\">"+ , "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"+ , "<title>" ++ titleHtml ++ "</title>"+ , "<link rel=\"stylesheet\" href=\"" ++ cssFileName ++ "\">"+ , "</head>"+ , "<body>"+ , "<table><tbody><tr>"+ , "<td class=\"line-numbers\"><pre>" ++ lineHtml ++ "</pre></td>"+ , "<td class=\"source-code\"><pre>" ++ codeHtml ++ "</pre></td>"+ , "</tr></tbody></table>"+ , "</body>"+ , "</html>"+ ]+ where+ titleHtml = "Module " ++ moduleName m+ lineHtml = unlines $ map show [1 .. length (lines codeHtml)]+ codeHtml = concat $ snd $ mapAccumL (code2html m) [] codes++code2html :: ModuleIdent -> [QualIdent] -> Code -> ([QualIdent], String)+code2html m defs c+ | isCall c = (defs, maybe tag (addEntityLink m tag) (getQualIdent c))+ | isDecl c = case getQualIdent c of+ Just i | i `notElem` defs+ -> (i:defs, spanTag (code2class c) (escIdent i) (escCode c))+ _ -> (defs, tag)+ | otherwise = case c of+ ModuleName m' -> (defs, addModuleLink m m' tag)+ _ -> (defs, tag)+ where tag = spanTag (code2class c) "" (escCode c)++escCode :: Code -> String+escCode = htmlQuote . code2string++escIdent :: QualIdent -> String+escIdent = htmlQuote . idName . unqualify++spanTag :: String -> String -> String -> String+spanTag clV idV str+ | null clV && null idV = str+ | otherwise = "<span" ++ codeclass ++ idValue ++ ">"+ ++ str ++ "</span>"+ where+ codeclass = if null clV then "" else " class=\"" ++ clV ++ "\""+ idValue = if null idV then "" else " id=\"" ++ idV ++ "\""++-- which code has which css class+-- @param code+-- @return css class of the code+code2class :: Code -> String+code2class (Space _) = ""+code2class NewLine = ""+code2class (Keyword _) = "keyword"+code2class (Pragma _) = "pragma"+code2class (Symbol _) = "symbol"+code2class (TypeCons _ _ _) = "type"+code2class (DataCons _ _ _) = "cons"+code2class (Function _ _ _) = "func"+code2class (Identifier _ _ _) = "ident"+code2class (ModuleName _) = "module"+code2class (Commentary _) = "comment"+code2class (NumberCode _) = "number"+code2class (StringCode _) = "string"+code2class (CharCode _) = "char"++addModuleLink :: ModuleIdent -> ModuleIdent -> String -> String+addModuleLink m m' str+ = "<a href=\"" ++ makeRelativePath m m' ++ "\">" ++ str ++ "</a>"++addEntityLink :: ModuleIdent -> String -> QualIdent -> String+addEntityLink m str qid =+ "<a href=\"" ++ modPath ++ "#" ++ fragment ++ "\">" ++ str ++ "</a>"+ where+ modPath = maybe "" (makeRelativePath m) mmid+ fragment = string2urlencoded (idName ident)+ (mmid, ident) = (qidModule qid, qidIdent qid)++makeRelativePath :: ModuleIdent -> ModuleIdent -> String+makeRelativePath cur new | cur == new = ""+ | otherwise = htmlName new++isCall :: Code -> Bool+isCall (TypeCons TypeExport _ _) = True+isCall (TypeCons TypeImport _ _) = True+isCall (TypeCons TypeRefer _ _) = True+isCall (TypeCons _ _ _) = False+isCall (Identifier _ _ _) = False+isCall c = not (isDecl c) && isJust (getQualIdent c)++isDecl :: Code -> Bool+isDecl (DataCons ConsDeclare _ _) = True+isDecl (Function FuncDeclare _ _) = True+isDecl (TypeCons TypeDeclare _ _) = True+isDecl _ = False++-- Translates arbitrary strings into equivalent urlencoded string.+string2urlencoded :: String -> String+string2urlencoded = escapeURIString isUnreserved++htmlQuote :: String -> String+htmlQuote [] = []+htmlQuote (c : cs)+ | c == '<' = "<" ++ htmlQuote cs+ | c == '>' = ">" ++ htmlQuote cs+ | c == '&' = "&" ++ htmlQuote cs+ | c == '"' = """ ++ htmlQuote cs+ | c == 'ä' = "ä" ++ htmlQuote cs+ | c == 'ö' = "ö" ++ htmlQuote cs+ | c == 'ü' = "ü" ++ htmlQuote cs+ | c == 'Ä' = "Ä" ++ htmlQuote cs+ | c == 'Ö' = "Ö" ++ htmlQuote cs+ | c == 'Ü' = "Ü" ++ htmlQuote cs+ | c == 'ß' = "ß" ++ htmlQuote cs+ | otherwise = c : htmlQuote cs
+ src/Html/SyntaxColoring.hs view
@@ -0,0 +1,564 @@+{- |+ Module : $Header$+ Description : Split module into code fragments+ Copyright : (c) 2014 - 2016 Björn Peemöller+ 2016 Jan Tikovsky+ 2016 - 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module arranges the tokens of the module into different code+ categories for HTML presentation. The parsed and qualified module+ is used to establish links between used identifiers and their definitions.++ The fully qualified module is traversed to generate a list of code elements.+ Code elements representing identifiers are distinguished by their kind+ (type constructor, data constructor, function, (type) variable).+ They include information about their usage (i.e., declaration, call etc.)+ and whether the identifier occurs fully qualified in+ the source code or not. Initially, all identifier codes are fully qualified.++ In a next step, the token stream of the given program and the code list are+ traversed sequentially (see `encodeToks`). The information in the token+ stream is used to:++ * add code elements for newlines, spaces and pragmas+ * update the qualification information of identifiers in the code list.+-}++module Html.SyntaxColoring+ ( Code (..), TypeUsage (..), ConsUsage (..)+ , IdentUsage (..), FuncUsage (..)+ , genProgram, code2string, getQualIdent+ ) where++import Data.Function (on)+import Data.List (sortBy)++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Base.SpanInfo ()+import Curry.Syntax++import Base.Messages++-- |Type of codes which are distinguished for HTML output+-- the boolean flags indicate whether the corresponding identifier+-- occurs qualified in the source module+data Code+ = Keyword String+ | Space Int+ | NewLine+ | Pragma String+ | TypeCons TypeUsage Bool QualIdent+ | DataCons ConsUsage Bool QualIdent+ | Function FuncUsage Bool QualIdent+ | Identifier IdentUsage Bool QualIdent+ | ModuleName ModuleIdent+ | Commentary String+ | NumberCode String+ | StringCode String+ | CharCode String+ | Symbol String+ deriving Show++data TypeUsage+ = TypeDeclare+ | TypeRefer+ | TypeExport+ | TypeImport+ deriving Show++data ConsUsage+ = ConsDeclare+ | ConsPattern+ | ConsCall+ | ConsInfix+ | ConsExport+ | ConsImport+ deriving Show++data FuncUsage+ = FuncDeclare+ | FuncTypeSig+ | FuncCall+ | FuncInfix+ | FuncExport+ | FuncImport+ deriving Show++data IdentUsage+ = IdDeclare -- declare a (type) variable+ | IdRefer -- refer to a (type) variable+ | IdUnknown -- unknown usage+ deriving Show++-- @param fully qualified module+-- @param lex-Result+-- @return code list+genProgram :: Module a -> [(Position, Token)] -> [Code]+genProgram m pts = encodeToks (first "") (filter validCode (idsModule m)) pts++-- predicate to remove identifier codes for primitives+-- because they do not form valid link targets+validCode :: Code -> Bool+validCode (TypeCons _ _ t) = t `notElem` [qUnitId, qListId] && not (isQTupleId t)+validCode (DataCons _ _ c) = c `notElem` [qUnitId, qNilId, qConsId] && not (isQTupleId c)+validCode (Identifier _ _ i) = not $ isAnonId $ unqualify i+validCode _ = True++-- @param code+-- @return qid if available+getQualIdent :: Code -> Maybe QualIdent+getQualIdent (DataCons _ _ qid) = Just qid+getQualIdent (Function _ _ qid) = Just qid+getQualIdent (Identifier _ _ qid) = Just qid+getQualIdent (TypeCons _ _ qid) = Just qid+getQualIdent _ = Nothing++encodeToks :: Position -> [Code] -> [(Position, Token)] -> [Code]+encodeToks _ _ [] = []+encodeToks cur ids toks@((pos, tok) : ts)+ -- advance line+ | line cur < line pos = NewLine : encodeToks (nl cur) ids toks+ -- advance column+ | column cur < column pos = let d = column pos - column cur+ in Space d : encodeToks (incr cur d) ids toks+ -- pragma token+ | isPragmaToken tok = let (ps, (end:rest)) = break (isPragmaEnd . snd) toks+ s = unwords $ map (showToken . snd) (ps ++ [end])+ in Pragma s : encodeToks (incr cur (length s)) ids rest+ -- identifier token+ | isIdentTok tok = case ids of+ [] -> encodeTok tok : encodeToks newPos [] ts+ (i:is)+ | tokenStr == code2string i' -> i' : encodeToks newPos is ts+ -- the 'otherwise' case should never occur if the token stream and+ -- the qualified AST which was used to generate the code list correspond to+ -- the same module+ | otherwise -> encodeToks cur is toks+ where i' = setQualified (isQualIdentTok tok) i+ -- other token+ | otherwise = encodeTok tok : encodeToks newPos ids ts+ where+ tokenStr = showToken tok+ newPos = incr cur (length tokenStr)++setQualified :: Bool -> Code -> Code+setQualified b (DataCons u _ c) = DataCons u b c+setQualified b (Function u _ f) = Function u b f+setQualified b (Identifier u _ i) = Identifier u b i+setQualified b (TypeCons u _ t) = TypeCons u b t+setQualified _ m@(ModuleName _) = m+setQualified _ s@(Symbol _) = s+setQualified _ c = internalError $ "Html.SyntaxColoring.setQualified: " ++ show c++code2string :: Code -> String+code2string (Keyword s) = s+code2string (Space i) = replicate i ' '+code2string NewLine = "\n"+code2string (Pragma s) = s+code2string (DataCons _ b qid) = ident2string b qid+code2string (TypeCons _ b qid) = ident2string b qid+code2string (Function _ b qid) = ident2string b qid+code2string (Identifier _ b qid) = ident2string b qid+code2string (ModuleName mid) = moduleName mid+code2string (Commentary s) = s+code2string (NumberCode s) = s+code2string (StringCode s) = s+code2string (CharCode s) = s+code2string (Symbol s) = s++ident2string :: Bool -> QualIdent -> String+ident2string False q = idName $ unqualify q+ident2string True q = qualName q++encodeTok :: Token -> Code+encodeTok tok@(Token c _)+ | c `elem` numCategories = NumberCode (showToken tok)+ | c == CharTok = CharCode (showToken tok)+ | c == StringTok = StringCode (showToken tok)+ | c `elem` keywordCategories = Keyword (showToken tok)+ | c `elem` specialIdentCategories = Keyword (showToken tok)+ | c `elem` punctuationCategories = Symbol (showToken tok)+ | c `elem` reservedOpsCategories = Symbol (showToken tok)+ | c `elem` commentCategories = Commentary (showToken tok)+ | c `elem` identCategories = Identifier IdUnknown False $ qualify $ mkIdent+ $ showToken tok+ | c `elem` whiteSpaceCategories = Space 0+ | c `elem` pragmaCategories = Pragma (showToken tok)+ | otherwise = internalError $+ "SyntaxColoring.encodeTok: Unknown token " ++ showToken tok++numCategories :: [Category]+numCategories = [IntTok, FloatTok]++keywordCategories :: [Category]+keywordCategories =+ [ KW_case, KW_class, KW_data, KW_default, KW_deriving, KW_do, KW_else+ , KW_external, KW_fcase, KW_free, KW_if, KW_import, KW_in+ , KW_infix, KW_infixl, KW_infixr, KW_instance, KW_let, KW_module, KW_newtype+ , KW_of, KW_then, KW_type, KW_where+ ]++specialIdentCategories :: [Category]+specialIdentCategories =+ [ Id_as, Id_ccall, Id_forall, Id_hiding+ , Id_interface, Id_primitive, Id_qualified ]++punctuationCategories :: [Category]+punctuationCategories =+ [ LeftParen, RightParen, Semicolon, LeftBrace, RightBrace+ , LeftBracket, RightBracket, Comma, Underscore, Backquote ]++reservedOpsCategories :: [Category]+reservedOpsCategories =+ [ At, Colon, DotDot, DoubleArrow, DoubleColon, Equals, Backslash, Bar+ , LeftArrow, RightArrow, Tilde ]++commentCategories :: [Category]+commentCategories = [LineComment, NestedComment]++identCategories :: [Category]+identCategories = [Id, QId, Sym, QSym, SymDot, SymMinus, SymStar]++isPragmaToken :: Token -> Bool+isPragmaToken (Token c _) = c `elem` pragmaCategories++isPragmaEnd :: Token -> Bool+isPragmaEnd (Token c _) = c == PragmaEnd++isIdentTok :: Token -> Bool+isIdentTok (Token c _) = c `elem` identCategories++isQualIdentTok :: Token -> Bool+isQualIdentTok (Token c _) = c `elem` [QId, QSym]++whiteSpaceCategories :: [Category]+whiteSpaceCategories = [EOF, VSemicolon, VRightBrace]++pragmaCategories :: [Category]+pragmaCategories = [PragmaLanguage, PragmaOptions, PragmaEnd]++cmpDecl :: Decl a -> Decl a -> Ordering+cmpDecl = compare `on` getPosition++cmpImportDecl :: ImportDecl -> ImportDecl -> Ordering+cmpImportDecl = compare `on` getPosition++-- -----------------------------------------------------------------------------+-- Extract all identifiers mentioned in the source code as a Code entity+-- in the order of their occurrence. The extracted information is then used+-- to enrich the identifier tokens with additional information, e.g., for+-- link generation.+-- -----------------------------------------------------------------------------++idsModule :: Module a -> [Code]+idsModule (Module _ _ _ mid es is ds) =+ let hdrCodes = ModuleName mid : idsExportSpec es+ impCodes = concatMap idsImportDecl (sortBy cmpImportDecl is)+ dclCodes = concatMap idsDecl (sortBy cmpDecl ds)+ in hdrCodes ++ impCodes ++ dclCodes++-- Exports++idsExportSpec :: Maybe ExportSpec -> [Code]+idsExportSpec Nothing = []+idsExportSpec (Just (Exporting _ es)) = concatMap idsExport es++idsExport :: Export -> [Code]+idsExport (Export _ qid) = [Function FuncExport False qid]+idsExport (ExportTypeWith _ qid cs) = TypeCons TypeExport False qid :+ map (DataCons ConsExport False . qualify) cs+idsExport (ExportTypeAll _ qid) = [TypeCons TypeExport False qid]+idsExport (ExportModule _ mid) = [ModuleName mid]++-- Imports++idsImportDecl :: ImportDecl -> [Code]+idsImportDecl (ImportDecl _ mid _ mAlias spec)+ = ModuleName mid : aliasCode ++ maybe [] (idsImportSpec mid) spec+ where aliasCode = maybe [] ((:[]) . ModuleName) mAlias++idsImportSpec :: ModuleIdent -> ImportSpec -> [Code]+idsImportSpec mid (Importing _ is) = concatMap (idsImport mid) is+idsImportSpec mid (Hiding _ is) = concatMap (idsImport mid) is++idsImport :: ModuleIdent -> Import -> [Code]+idsImport mid (Import _ i) =+ [Function FuncImport False $ qualifyWith mid i]+idsImport mid (ImportTypeWith _ t cs) =+ TypeCons TypeImport False (qualifyWith mid t) :+ map (DataCons ConsImport False . qualifyWith mid) cs+idsImport mid (ImportTypeAll _ t) =+ [TypeCons TypeImport False $ qualifyWith mid t]++-- Declarations++idsDecl :: Decl a -> [Code]+idsDecl (InfixDecl _ _ _ ops) =+ map (Function FuncInfix False . qualify) ops+idsDecl (DataDecl _ d vs cds clss) =+ TypeCons TypeDeclare False (qualify d) :+ map (Identifier IdDeclare False . qualify) vs +++ concatMap idsConstrDecl cds ++ map (TypeCons TypeRefer False) clss+idsDecl (ExternalDataDecl _ d vs) =+ TypeCons TypeDeclare False (qualify d) :+ map (Identifier IdDeclare False . qualify) vs+idsDecl (NewtypeDecl _ t vs nc clss) =+ TypeCons TypeDeclare False (qualify t) :+ map (Identifier IdDeclare False . qualify) vs ++ idsNewConstrDecl nc +++ map (TypeCons TypeRefer False) clss+idsDecl (TypeDecl _ t vs ty) =+ TypeCons TypeDeclare False (qualify t) :+ map (Identifier IdDeclare False . qualify) vs ++ idsTypeExpr ty+idsDecl (TypeSig _ fs qty) =+ map (Function FuncTypeSig False . qualify) fs ++ idsQualTypeExpr qty+idsDecl (FunctionDecl _ _ _ eqs) = concatMap idsEquation eqs+idsDecl (ExternalDecl _ fs) =+ map (Function FuncDeclare False . qualify . varIdent) fs+idsDecl (PatternDecl _ p rhs) = idsPat p ++ idsRhs rhs+idsDecl (FreeDecl _ vs) =+ map (Identifier IdDeclare False . qualify . varIdent) vs+idsDecl (DefaultDecl _ tys) = concatMap idsTypeExpr tys+idsDecl (ClassDecl _ _ cx c v ds) =+ idsContext cx ++ TypeCons TypeDeclare False (qualify c) :+ Identifier IdDeclare False (qualify v) : concatMap idsClassDecl ds+idsDecl (InstanceDecl _ _ cx c ty ds) = idsContext cx +++ TypeCons TypeRefer False c : idsTypeExpr ty ++ concatMap idsInstanceDecl ds++idsConstrDecl :: ConstrDecl -> [Code]+idsConstrDecl (ConstrDecl _ c tys) =+ DataCons ConsDeclare False (qualify c) : concatMap idsTypeExpr tys+idsConstrDecl (ConOpDecl _ ty1 op ty2) =+ idsTypeExpr ty1 ++ (DataCons ConsDeclare False $ qualify op) : idsTypeExpr ty2+idsConstrDecl (RecordDecl _ c fs) =+ DataCons ConsDeclare False (qualify c) : concatMap idsFieldDecl fs++idsNewConstrDecl :: NewConstrDecl -> [Code]+idsNewConstrDecl (NewConstrDecl _ c ty) =+ DataCons ConsDeclare False (qualify c) : idsTypeExpr ty+idsNewConstrDecl (NewRecordDecl _ c (l,ty)) =+ DataCons ConsDeclare False (qualify c) :+ (Function FuncDeclare False $ qualify l) : idsTypeExpr ty++idsClassDecl :: Decl a -> [Code]+idsClassDecl (TypeSig _ fs qty) =+ map (Function FuncDeclare False . qualify) fs ++ idsQualTypeExpr qty+idsClassDecl (FunctionDecl _ _ _ eqs) = concatMap idsEquation eqs+idsClassDecl _ =+ internalError "SyntaxColoring.idsClassDecl"++idsInstanceDecl :: Decl a -> [Code]+idsInstanceDecl (FunctionDecl _ _ _ eqs) = concatMap idsEquation eqs+idsInstanceDecl _ =+ internalError "SyntaxColoring.idsInstanceDecl"++idsQualTypeExpr :: QualTypeExpr -> [Code]+idsQualTypeExpr (QualTypeExpr _ cx ty) = idsContext cx ++ idsTypeExpr ty++idsContext :: Context -> [Code]+idsContext = concatMap idsConstraint++idsConstraint :: Constraint -> [Code]+idsConstraint (Constraint _ qcls ty) =+ TypeCons TypeRefer False qcls : idsTypeExpr ty++idsTypeExpr :: TypeExpr -> [Code]+idsTypeExpr (ConstructorType _ qid) = [TypeCons TypeRefer False qid]+idsTypeExpr (ApplyType _ ty1 ty2) = concatMap idsTypeExpr [ty1, ty2]+idsTypeExpr (VariableType _ v) = [Identifier IdRefer False (qualify v)]+idsTypeExpr (TupleType _ tys) = concatMap idsTypeExpr tys+idsTypeExpr (ListType _ ty) = idsTypeExpr ty+idsTypeExpr (ArrowType _ ty1 ty2) = concatMap idsTypeExpr [ty1, ty2]+idsTypeExpr (ParenType _ ty) = idsTypeExpr ty+idsTypeExpr (ForallType _ vs ty) =+ map (Identifier IdDeclare False . qualify) vs ++ Symbol "." : idsTypeExpr ty++idsFieldDecl :: FieldDecl -> [Code]+idsFieldDecl (FieldDecl _ ls ty) =+ map (Function FuncDeclare False . qualify . unRenameIdent) ls ++ idsTypeExpr ty++idsEquation :: Equation a -> [Code]+idsEquation (Equation _ lhs rhs) = idsLhs lhs ++ idsRhs rhs++idsLhs :: Lhs a -> [Code]+idsLhs (FunLhs _ f ps) =+ Function FuncDeclare False (qualify f) : concatMap idsPat ps+idsLhs (OpLhs _ p1 op p2) =+ idsPat p1 ++ [Function FuncDeclare False $ qualify op] ++ idsPat p2+idsLhs (ApLhs _ lhs ps) = idsLhs lhs ++ concatMap idsPat ps++idsRhs :: Rhs a -> [Code]+idsRhs (SimpleRhs _ _ e ds) = idsExpr e ++ concatMap idsDecl ds+idsRhs (GuardedRhs _ _ ce ds) = concatMap idsCondExpr ce ++ concatMap idsDecl ds++idsCondExpr :: CondExpr a -> [Code]+idsCondExpr (CondExpr _ e1 e2) = idsExpr e1 ++ idsExpr e2++idsPat :: Pattern a -> [Code]+idsPat (LiteralPattern _ _ _) = []+idsPat (NegativePattern _ _ _) = []+idsPat (VariablePattern _ _ v) = [Identifier IdDeclare False (qualify v)]+idsPat (ConstructorPattern _ _ qid ps) =+ DataCons ConsPattern False qid : concatMap idsPat ps+idsPat (InfixPattern _ _ p1 qid p2) =+ idsPat p1 ++ DataCons ConsPattern False qid : idsPat p2+idsPat (ParenPattern _ p) = idsPat p+idsPat (RecordPattern _ _ qid fs) =+ DataCons ConsPattern False qid : concatMap (idsField idsPat) fs+idsPat (TuplePattern _ ps) = concatMap idsPat ps+idsPat (ListPattern _ _ ps) = concatMap idsPat ps+idsPat (AsPattern _ v p) =+ Identifier IdDeclare False (qualify v) : idsPat p+idsPat (LazyPattern _ p) = idsPat p+idsPat (FunctionPattern _ _ qid ps) =+ Function FuncCall False qid : concatMap idsPat ps+idsPat (InfixFuncPattern _ _ p1 f p2) =+ idsPat p1 ++ Function FuncInfix False f : idsPat p2++idsExpr :: Expression a -> [Code]+idsExpr (Literal _ _ _) = []+idsExpr (Variable _ _ qid)+ | isQualified qid = [Function FuncCall False qid]+ | hasGlobalScope (unqualify qid) = [Function FuncCall False qid]+ | otherwise = [Identifier IdRefer False qid]+idsExpr (Constructor _ _ qid) = [DataCons ConsCall False qid]+idsExpr (Paren _ e) = idsExpr e+idsExpr (Typed _ e qty) = idsExpr e ++ idsQualTypeExpr qty+idsExpr (Record _ _ qid fs) =+ DataCons ConsCall False qid : concatMap (idsField idsExpr) fs+idsExpr (RecordUpdate _ e fs) =+ idsExpr e ++ concatMap (idsField idsExpr) fs+idsExpr (Tuple _ es) = concatMap idsExpr es+idsExpr (List _ _ es) = concatMap idsExpr es+idsExpr (ListCompr _ e stmts) = idsExpr e ++ concatMap idsStmt stmts+idsExpr (EnumFrom _ e) = idsExpr e+idsExpr (EnumFromThen _ e1 e2) = concatMap idsExpr [e1, e2]+idsExpr (EnumFromTo _ e1 e2) = concatMap idsExpr [e1, e2]+idsExpr (EnumFromThenTo _ e1 e2 e3) = concatMap idsExpr [e1, e2, e3]+idsExpr (UnaryMinus _ e) = Symbol "-" : idsExpr e+idsExpr (Apply _ e1 e2) = idsExpr e1 ++ idsExpr e2+idsExpr (InfixApply _ e1 op e2) = idsExpr e1 ++ idsInfix op ++ idsExpr e2+idsExpr (LeftSection _ e op) = idsExpr e ++ idsInfix op+idsExpr (RightSection _ op e) = idsInfix op ++ idsExpr e+idsExpr (Lambda _ ps e) = concatMap idsPat ps ++ idsExpr e+idsExpr (Let _ _ ds e) = concatMap idsDecl ds ++ idsExpr e+idsExpr (Do _ _ stmts e) = concatMap idsStmt stmts ++ idsExpr e+idsExpr (IfThenElse _ e1 e2 e3) = concatMap idsExpr [e1, e2, e3]+idsExpr (Case _ _ _ e alts) = idsExpr e ++ concatMap idsAlt alts++idsField :: (a -> [Code]) -> Field a -> [Code]+idsField f (Field _ l x) = Function FuncCall False l : f x++idsInfix :: InfixOp a -> [Code]+idsInfix (InfixOp _ qid) = [Function FuncInfix False qid]+idsInfix (InfixConstr _ qid) = [DataCons ConsInfix False qid]++idsStmt :: Statement a -> [Code]+idsStmt (StmtExpr _ e) = idsExpr e+idsStmt (StmtDecl _ _ ds) = concatMap idsDecl ds+idsStmt (StmtBind _ p e) = idsPat p ++ idsExpr e++idsAlt :: Alt a -> [Code]+idsAlt (Alt _ p rhs) = idsPat p ++ idsRhs rhs++-- -----------------------------------------------------------------------------+-- Conversion from a token to a string+-- -----------------------------------------------------------------------------++showToken :: Token -> String+showToken (Token Id a) = showAttr a+showToken (Token QId a) = showAttr a+showToken (Token Sym a) = showAttr a+showToken (Token QSym a) = showAttr a+showToken (Token IntTok a) = showAttr a+showToken (Token FloatTok a) = showAttr a+showToken (Token CharTok a) = showAttr a+showToken (Token StringTok a) = showAttr a+showToken (Token LeftParen _) = "("+showToken (Token RightParen _) = ")"+showToken (Token Semicolon _) = ";"+showToken (Token LeftBrace _) = "{"+showToken (Token RightBrace _) = "}"+showToken (Token LeftBracket _) = "["+showToken (Token RightBracket _) = "]"+showToken (Token Comma _) = ","+showToken (Token Underscore _) = "_"+showToken (Token Backquote _) = "`"+showToken (Token VSemicolon _) = ""+showToken (Token VRightBrace _) = ""+showToken (Token At _) = "@"+showToken (Token Colon _) = ":"+showToken (Token DotDot _) = ".."+showToken (Token DoubleArrow _) = "=>"+showToken (Token DoubleColon _) = "::"+showToken (Token Equals _) = "="+showToken (Token Backslash _) = "\\"+showToken (Token Bar _) = "|"+showToken (Token LeftArrow _) = "<-"+showToken (Token RightArrow _) = "->"+showToken (Token Tilde _) = "~"+showToken (Token SymDot _) = "."+showToken (Token SymMinus _) = "-"+showToken (Token SymStar _) = "*"+showToken (Token KW_case _) = "case"+showToken (Token KW_class _) = "class"+showToken (Token KW_data _) = "data"+showToken (Token KW_default _) = "default"+showToken (Token KW_deriving _) = "deriving"+showToken (Token KW_do _) = "do"+showToken (Token KW_else _) = "else"+showToken (Token KW_external _) = "external"+showToken (Token KW_fcase _) = "fcase"+showToken (Token KW_free _) = "free"+showToken (Token KW_if _) = "if"+showToken (Token KW_import _) = "import"+showToken (Token KW_in _) = "in"+showToken (Token KW_infix _) = "infix"+showToken (Token KW_infixl _) = "infixl"+showToken (Token KW_infixr _) = "infixr"+showToken (Token KW_instance _) = "instance"+showToken (Token KW_let _) = "let"+showToken (Token KW_module _) = "module"+showToken (Token KW_newtype _) = "newtype"+showToken (Token KW_of _) = "of"+showToken (Token KW_then _) = "then"+showToken (Token KW_type _) = "type"+showToken (Token KW_where _) = "where"+showToken (Token Id_as _) = "as"+showToken (Token Id_ccall _) = "ccall"+showToken (Token Id_forall _) = "forall"+showToken (Token Id_hiding _) = "hiding"+showToken (Token Id_interface _) = "interface"+showToken (Token Id_primitive _) = "primitive"+showToken (Token Id_qualified _) = "qualified"+showToken (Token EOF _) = ""+showToken (Token PragmaHiding _) = "{-# HIDING"+showToken (Token PragmaLanguage _) = "{-# LANGUAGE"+showToken (Token PragmaOptions a) = "{-# OPTIONS" ++ showAttr a+showToken (Token PragmaMethod _) = "{-# METHOD"+showToken (Token PragmaModule _) = "{-# MODULE"+showToken (Token PragmaEnd _) = "#-}"+showToken (Token LineComment (StringAttributes s _)) = s+showToken (Token LineComment a ) = showAttr a+showToken (Token NestedComment (StringAttributes s _)) = s+showToken (Token NestedComment a) = showAttr a++showAttr :: Attributes -> [Char]+showAttr NoAttributes = ""+showAttr (CharAttributes c _) = show c+showAttr (IntAttributes i _) = show i+showAttr (FloatAttributes f _) = show f+showAttr (StringAttributes s _) = show s+showAttr (IdentAttributes m i)+ | null m = idName $ (mkIdent i)+ | otherwise = qualName $ qualifyWith (mkMIdent m) (mkIdent i)+showAttr (OptionsAttributes mt s) = showTool mt ++ ' ' : s++showTool :: Maybe String -> String+showTool Nothing = ""+showTool (Just t) = '_' : t
+ src/IL.hs view
@@ -0,0 +1,19 @@+{- |+ Module : $Header$+ Description : Intermediate language+ Copyright : (c) 2014, Björn Peemöller+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module is a simple re-export of the definition of the AST of IL+ and the pretty-printing of IL modules.+-}+module IL ( module IL.Type, module IL.Typing, ppModule, showModule ) where++import IL.Pretty (ppModule)+import IL.ShowModule (showModule)+import IL.Type+import IL.Typing
− src/IL/CurryToIL.lhs
@@ -1,598 +0,0 @@--% $Id: ILTrans.lhs,v 1.86 2004/02/13 19:23:58 wlux Exp $-%-% Copyright (c) 1999-2003, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{ILTrans.lhs}-\section{Translating Curry into the Intermediate Language}-After desugaring and lifting have been performed, the source code is-translated into the intermediate language. Besides translating from-source terms and expressions into intermediate language terms and-expressions this phase in particular has to implement the pattern-matching algorithm for equations and case expressions.--Because of name conflicts between the source and intermediate language-data structures, we can use only a qualified import for the-\texttt{IL} module.-\begin{verbatim}--> module IL.CurryToIL(ilTrans,ilTransIntf, translType) where--> import Data.Maybe-> import Data.List-> import qualified Data.Set as Set-> import qualified Data.Map as Map--> import Curry.Base.Position-> import Curry.Base.Ident-> import Curry.Syntax-> import Curry.Syntax.Utils--> import Types-> import Base-> import qualified IL.Type as IL-> import Utils----\end{verbatim}-\paragraph{Modules}-At the top-level, the compiler has to translate data type, newtype,-function, and external declarations. When translating a data type or-newtype declaration, we ignore the types in the declaration and lookup-the types of the constructors in the type environment instead because-these types are already fully expanded, i.e., they do not include any-alias types.-\begin{verbatim}--> ilTrans :: Bool -> ValueEnv -> TCEnv -> EvalEnv -> Module -> IL.Module-> ilTrans flat tyEnv tcEnv evEnv (Module m _ ds) = -> IL.Module m (imports m ds') ds'-> where ds' = concatMap (translGlobalDecl flat m tyEnv tcEnv evEnv) ds--> translGlobalDecl :: Bool -> ModuleIdent -> ValueEnv -> TCEnv -> EvalEnv-> -> Decl -> [IL.Decl]-> translGlobalDecl _ m tyEnv tcEnv _ (DataDecl _ tc tvs cs) =-> [translData m tyEnv tcEnv tc tvs cs]-> translGlobalDecl _ m tyEnv tcEnv _ (NewtypeDecl _ tc tvs nc) =-> [translNewtype m tyEnv tcEnv tc tvs nc]-> translGlobalDecl flat m tyEnv tcEnv evEnv (FunctionDecl pos f eqs) =-> [translFunction pos flat m tyEnv tcEnv evEnv f eqs]-> translGlobalDecl _ m tyEnv tcEnv _ (ExternalDecl _ cc ie f _) =-> [translExternal m tyEnv tcEnv f cc (fromJust ie)]-> translGlobalDecl _ _ _ _ _ _ = []--> translData :: ModuleIdent -> ValueEnv -> TCEnv -> Ident -> [Ident] -> [ConstrDecl]-> -> IL.Decl-> translData m tyEnv tcEnv tc tvs cs =-> IL.DataDecl (qualifyWith m tc) (length tvs)-> (map (translConstrDecl m tyEnv tcEnv) cs)--> translNewtype :: ModuleIdent -> ValueEnv -> TCEnv -> Ident -> [Ident] -> -> NewConstrDecl -> IL.Decl-> translNewtype m tyEnv tcEnv tc tvs (NewConstrDecl _ _ c _) =-> IL.NewtypeDecl (qualifyWith m tc) (length tvs)-> (IL.ConstrDecl c' (translType' m tyEnv tcEnv ty))-> -- (IL.ConstrDecl c' (translType ty))-> where c' = qualifyWith m c-> TypeArrow ty _ = constrType tyEnv c'--> translConstrDecl :: ModuleIdent -> ValueEnv -> TCEnv -> ConstrDecl-> -> IL.ConstrDecl [IL.Type]-> translConstrDecl m tyEnv tcEnv d =-> IL.ConstrDecl c' (map (translType' m tyEnv tcEnv)-> (arrowArgs (constrType tyEnv c')))-> -- IL.ConstrDecl c' (map translType (arrowArgs (constrType tyEnv c')))-> where c' = qualifyWith m (constr d)-> constr (ConstrDecl _ _ c _) = c-> constr (ConOpDecl _ _ _ op _) = op--> translExternal :: ModuleIdent -> ValueEnv -> TCEnv -> Ident -> CallConv-> -> String -> IL.Decl-> translExternal m tyEnv tcEnv f cc ie =-> IL.ExternalDecl f' (callConv cc) ie -> (translType' m tyEnv tcEnv (varType tyEnv f'))-> -- IL.ExternalDecl f' (callConv cc) ie (translType (varType tyEnv f'))-> where f' = qualifyWith m f-> callConv CallConvPrimitive = IL.Primitive-> callConv CallConvCCall = IL.CCall--\end{verbatim}-\paragraph{Interfaces}-In order to generate code, the compiler also needs to know the tags-and arities of all imported data constructors. For that reason we-compile the data type declarations of all interfaces into the-intermediate language, too. In this case we do not lookup the-types in the environment because the types in the interfaces are-already fully expanded. Note that we do not translate data types-which are imported into the interface from some other module.-\begin{verbatim}--> ilTransIntf :: ValueEnv -> TCEnv -> Interface -> [IL.Decl]-> ilTransIntf tyEnv tcEnv (Interface m ds) = -> foldr (translIntfDecl m tyEnv tcEnv) [] ds--> translIntfDecl :: ModuleIdent -> ValueEnv -> TCEnv -> IDecl -> [IL.Decl] -> -> [IL.Decl]-> translIntfDecl m tyEnv tcEnv (IDataDecl _ tc tvs cs) ds-> | not (isQualified tc) = -> translIntfData m tyEnv tcEnv (unqualify tc) tvs cs : ds-> translIntfDecl _ _ _ _ ds = ds--> translIntfData :: ModuleIdent -> ValueEnv -> TCEnv -> Ident -> [Ident] -> -> [Maybe ConstrDecl] -> IL.Decl-> translIntfData m tyEnv tcEnv tc tvs cs =-> IL.DataDecl (qualifyWith m tc) (length tvs)-> (map (maybe hiddenConstr -> (translIntfConstrDecl m tyEnv tcEnv tvs)) cs)-> where hiddenConstr = IL.ConstrDecl qAnonId []-> qAnonId = qualify anonId--> translIntfConstrDecl :: ModuleIdent -> ValueEnv -> TCEnv -> [Ident] -> -> ConstrDecl -> IL.ConstrDecl [IL.Type]-> translIntfConstrDecl m tyEnv tcEnv tvs (ConstrDecl _ _ c tys) =-> IL.ConstrDecl (qualifyWith m c) (map (translType' m tyEnv tcEnv)-> (toQualTypes m tvs tys))-> -- IL.ConstrDecl (qualifyWith m c) (map translType (toQualTypes m tvs tys))-> translIntfConstrDecl m tyEnv tcEnv tvs (ConOpDecl _ _ ty1 op ty2) =-> IL.ConstrDecl (qualifyWith m op)-> (map (translType' m tyEnv tcEnv)-> (toQualTypes m tvs [ty1,ty2]))-> -- IL.ConstrDecl (qualifyWith m op)-> -- (map translType (toQualTypes m tvs [ty1,ty2]))--\end{verbatim}-\paragraph{Types}-The type representation in the intermediate language is the same as-the internal representation except that it does not support-constrained type variables and skolem types. The former are fixed and-the later are replaced by fresh type constructors.--Due to possible occurrence of record types, it is necessary to transform-them back into their corresponding type constructors.-\begin{verbatim}--> translType' :: ModuleIdent -> ValueEnv -> TCEnv -> Type -> IL.Type-> translType' m tyEnv tcEnv ty =-> translType (elimRecordTypes m tyEnv tcEnv (maximum (0:(typeVars ty))) ty)--> translType :: Type -> IL.Type-> translType (TypeConstructor tc tys) =-> IL.TypeConstructor tc (map translType tys)-> translType (TypeVariable tv) = IL.TypeVariable tv-> translType (TypeConstrained tys _) = translType (head tys)-> translType (TypeArrow ty1 ty2) =-> IL.TypeArrow (translType ty1) (translType ty2)-> translType (TypeSkolem k) =-> IL.TypeConstructor (qualify (mkIdent ("_" ++ show k))) []--> elimRecordTypes :: ModuleIdent -> ValueEnv -> TCEnv -> Int -> Type -> Type-> elimRecordTypes m tyEnv tcEnv n (TypeConstructor t tys) =-> TypeConstructor t (map (elimRecordTypes m tyEnv tcEnv n) tys)-> elimRecordTypes m tyEnv tcEnv n (TypeVariable v) =-> TypeVariable v-> elimRecordTypes m tyEnv tcEnv n (TypeConstrained tys v) =-> TypeConstrained (map (elimRecordTypes m tyEnv tcEnv n) tys) v-> elimRecordTypes m tyEnv tcEnv n (TypeArrow t1 t2) =-> TypeArrow (elimRecordTypes m tyEnv tcEnv n t1)-> (elimRecordTypes m tyEnv tcEnv n t2)-> elimRecordTypes m tyEnv tcEnv n (TypeSkolem v) =-> TypeSkolem v-> elimRecordTypes m tyEnv tcEnv n (TypeRecord fs _)-> | null fs = internalError "elimRecordTypes: empty record type"-> | otherwise =-> case (lookupValue (fst (head fs)) tyEnv) of-> [Label _ r _] ->-> case (qualLookupTC r tcEnv) of-> [AliasType _ n' (TypeRecord fs' _)] ->-> let is = [0 .. n'-1]-> vs = foldl (matchTypeVars fs)-> Map.empty-> fs'-> tys = map (\i -> maybe (TypeVariable (i+n))-> (elimRecordTypes m tyEnv tcEnv n)-> (Map.lookup i vs))-> is -> in TypeConstructor r tys-> _ -> internalError "elimRecordTypes: no record type"-> _ -> internalError "elimRecordTypes: no label"--> matchTypeVars :: [(Ident,Type)] -> Map.Map Int Type -> (Ident,Type) -> -> Map.Map Int Type-> matchTypeVars fs vs (l,ty) =-> maybe vs (match vs ty) (lookup l fs)-> where-> match vs (TypeVariable i) ty' = Map.insert i ty' vs-> match vs (TypeConstructor _ tys) (TypeConstructor _ tys') =-> matchList vs tys tys'-> match vs (TypeConstrained tys _) (TypeConstrained tys' _) =-> matchList vs tys tys'-> match vs (TypeArrow ty1 ty2) (TypeArrow ty1' ty2') =-> matchList vs [ty1,ty2] [ty1',ty2']-> match vs (TypeSkolem _) (TypeSkolem _) = vs-> match vs (TypeRecord fs _) (TypeRecord fs' _) =-> foldl (matchTypeVars fs') vs fs-> match vs ty ty' = -> internalError ("matchTypeVars: " ++ show ty ++ "\n" ++ show ty')->-> matchList vs tys tys' = -> foldl (\vs' (ty,ty') -> match vs' ty ty') vs (zip tys tys')--\end{verbatim}-\paragraph{Functions}-Each function in the program is translated into a function of the-intermediate language. The arguments of the function are renamed such-that all variables occurring in the same position (in different-equations) have the same name. This is necessary in order to-facilitate the translation of pattern matching into a \texttt{case}-expression. We use the following simple convention here: The top-level-arguments of the function are named from left to right \texttt{\_1},-\texttt{\_2}, and so on. The names of nested arguments are constructed-by appending \texttt{\_1}, \texttt{\_2}, etc. from left to right to-the name that were assigned to a variable occurring at the position of-the constructor term.--Some special care is needed for the selector functions introduced by-the compiler in place of pattern bindings. In order to generate the-code for updating all pattern variables, the equality of names between-the pattern variables in the first argument of the selector function-and their repeated occurrences in the remaining arguments must be-preserved. This means that the second and following arguments of a-selector function have to be renamed according to the name mapping-computed for its first argument.--If an evaluation annotation is available for a function, it determines-the evaluation mode of the case expression. Otherwise, the function-uses flexible matching.-\begin{verbatim}--> type RenameEnv = Map.Map Ident Ident--> translFunction :: Position -> Bool -> ModuleIdent -> ValueEnv -> TCEnv-> -> EvalEnv -> Ident -> [Equation] -> IL.Decl-> translFunction pos flat m tyEnv tcEnv evEnv f eqs =-> -- - | f == mkIdent "fun" = error (show (translType' m tyEnv tcEnv ty))-> -- - | otherwise = -> IL.FunctionDecl f' vs (translType' m tyEnv tcEnv ty) expr-> -- = IL.FunctionDecl f' vs (translType ty)-> -- (match ev vs (map (translEquation tyEnv vs vs'') eqs))-> where f' = qualifyWith m f-> ty = varType tyEnv f'-> -- ty' = elimRecordType m tyEnv tcEnv (maximum (0:(typeVars ty))) ty-> ev' = Map.lookup f evEnv-> ev = maybe (defaultMode ty) evalMode ev'-> vs = if not flat && isFpSelectorId f then translArgs eqs vs' else vs'-> (vs',vs'') = splitAt (equationArity (head eqs)) -> (argNames (mkIdent ""))-> expr | ev' == Just EvalChoice-> = IL.Apply -> (IL.Function -> (qualifyWith preludeMIdent (mkIdent "commit"))-> 1)-> (match (srcRefOf pos) IL.Rigid vs -> (map (translEquation tyEnv vs vs'') eqs))-> | otherwise-> = match (srcRefOf pos) ev vs (map (translEquation tyEnv vs vs'') eqs)-> ----> -- (vs',vs'') = splitAt (arrowArity ty) (argNames (mkIdent ""))--> evalMode :: EvalAnnotation -> IL.Eval-> evalMode EvalRigid = IL.Rigid-> evalMode EvalChoice = error "eval choice is not yet supported"--> defaultMode :: Type -> IL.Eval-> defaultMode _ = IL.Flex->-> --defaultMode ty = if isIO (arrowBase ty) then IL.Rigid else IL.Flex-> -- where TypeConstructor qIOId _ = ioType undefined-> -- isIO (TypeConstructor tc [_]) = tc == qIOId-> -- isIO _ = False--> translArgs :: [Equation] -> [Ident] -> [Ident]-> translArgs [Equation _ (FunLhs _ (t:ts)) _] (v:_) =-> v : map (translArg (bindRenameEnv v t Map.empty)) ts-> where translArg env (VariablePattern v) = fromJust (Map.lookup v env)--> translEquation :: ValueEnv -> [Ident] -> [Ident] -> Equation-> -> ([NestedTerm],IL.Expression)-> translEquation tyEnv vs vs' (Equation _ (FunLhs _ ts) rhs) =-> (zipWith translTerm vs ts,-> translRhs tyEnv vs' (foldr2 bindRenameEnv Map.empty vs ts) rhs)--> translRhs :: ValueEnv -> [Ident] -> RenameEnv -> Rhs -> IL.Expression-> translRhs tyEnv vs env (SimpleRhs _ e _) = translExpr tyEnv vs env e---> equationArity :: Equation -> Int-> equationArity (Equation _ lhs _) = p_equArity lhs-> where-> p_equArity (FunLhs _ ts) = length ts-> p_equArity (OpLhs _ _ _) = 2-> p_equArity _ = error "ILTrans - illegal equation"---\end{verbatim}-\paragraph{Pattern Matching}-The pattern matching code searches for the left-most inductive-argument position in the left hand sides of all rules defining an-equation. An inductive position is a position where all rules have a-constructor rooted term. If such a position is found, a \texttt{case}-expression is generated for the argument at that position. The-matching code is then computed recursively for all of the alternatives-independently. If no inductive position is found, the algorithm looks-for the left-most demanded argument position, i.e., a position where-at least one of the rules has a constructor rooted term. If such a-position is found, an \texttt{or} expression is generated with those-cases that have a variable at the argument position in one branch and-all other rules in the other branch. If there is no demanded position,-the pattern matching is finished and the compiler translates the right-hand sides of the remaining rules, eventually combining them using-\texttt{or} expressions.--Actually, the algorithm below combines the search for inductive and-demanded positions. The function \texttt{match} scans the argument-lists for the left-most demanded position. If this turns out to be-also an inductive position, the function \texttt{matchInductive} is-called in order to generate a \texttt{case} expression. Otherwise, the-function \texttt{optMatch} is called that tries to find an inductive-position in the remaining arguments. If one is found,-\texttt{matchInductive} is called, otherwise the function-\texttt{optMatch} uses the demanded argument position found by-\texttt{match}.-\begin{verbatim}--> data NestedTerm = NestedTerm IL.ConstrTerm [NestedTerm] deriving Show--> pattern (NestedTerm t _) = t-> arguments (NestedTerm _ ts) = ts--> translLiteral :: Literal -> IL.Literal-> translLiteral (Char p c) = IL.Char p c-> translLiteral (Int id i) = IL.Int (srcRefOf (positionOfIdent id)) i-> translLiteral (Float p f) = IL.Float p f-> translLiteral _ = internalError "translLiteral"--> translTerm :: Ident -> ConstrTerm -> NestedTerm-> translTerm _ (LiteralPattern l) =-> NestedTerm (IL.LiteralPattern (translLiteral l)) []-> translTerm v (VariablePattern _) = NestedTerm (IL.VariablePattern v) []-> translTerm v (ConstructorPattern c ts) =-> NestedTerm (IL.ConstructorPattern c (take (length ts) vs))-> (zipWith translTerm vs ts)-> where vs = argNames v-> translTerm v (AsPattern _ t) = translTerm v t-> translTerm _ _ = internalError "translTerm"--> bindRenameEnv :: Ident -> ConstrTerm -> RenameEnv -> RenameEnv-> bindRenameEnv _ (LiteralPattern _) env = env-> bindRenameEnv v (VariablePattern v') env = Map.insert v' v env-> bindRenameEnv v (ConstructorPattern _ ts) env =-> foldr2 bindRenameEnv env (argNames v) ts-> bindRenameEnv v (AsPattern v' t) env = Map.insert v' v (bindRenameEnv v t env)-> bindRenameEnv _ _ env = internalError "bindRenameEnv"--> argNames :: Ident -> [Ident]-> argNames v = [mkIdent (prefix ++ show i) | i <- [1..]]-> where prefix = name v ++ "_"--> type Match = ([NestedTerm],IL.Expression)-> type Match' = ([NestedTerm] -> [NestedTerm],[NestedTerm],IL.Expression)--> isDefaultPattern :: IL.ConstrTerm -> Bool-> isDefaultPattern (IL.VariablePattern _) = True-> isDefaultPattern _ = False--> isDefaultMatch :: (IL.ConstrTerm,a) -> Bool-> isDefaultMatch = isDefaultPattern . fst--> match :: SrcRef -> IL.Eval -> [Ident] -> [Match] -> IL.Expression-> match _ ev [] alts = foldl1 IL.Or (map snd alts)-> match pos ev (v:vs) alts-> | null vars = e1-> | null nonVars = e2-> | otherwise = optMatch pos ev (IL.Or e1 e2) (v:) vs (map skipArg alts)-> where (vars,nonVars) = partition isDefaultMatch (map tagAlt alts)-> e1 = matchInductive pos ev id v vs nonVars-> e2 = match pos ev vs (map snd vars)-> tagAlt (t:ts,e) = (pattern t,(arguments t ++ ts,e))-> skipArg (t:ts,e) = ((t:),ts,e)--> optMatch :: SrcRef -> IL.Eval -> IL.Expression -> ([Ident] -> [Ident]) -> -> [Ident] ->[Match'] -> IL.Expression-> optMatch _ ev e prefix [] alts = e-> optMatch pos ev e prefix (v:vs) alts-> | null vars = matchInductive pos ev prefix v vs nonVars-> | otherwise = optMatch pos ev e (prefix . (v:)) vs (map skipArg alts)-> where (vars,nonVars) = partition isDefaultMatch (map tagAlt alts)-> tagAlt (prefix,t:ts,e) = (pattern t,(prefix (arguments t ++ ts),e))-> skipArg (prefix,t:ts,e) = (prefix . (t:),ts,e)--> matchInductive :: SrcRef -> IL.Eval -> ([Ident] -> [Ident]) -> Ident -> -> [Ident] ->[(IL.ConstrTerm,Match)] -> IL.Expression-> matchInductive pos ev prefix v vs alts =-> IL.Case pos ev (IL.Variable v) (matchAlts ev prefix vs alts)--> matchAlts :: IL.Eval -> ([Ident] -> [Ident]) -> [Ident] ->-> [(IL.ConstrTerm,Match)] -> [IL.Alt]-> matchAlts ev prefix vs [] = []-> matchAlts ev prefix vs ((t,alt):alts) =-> IL.Alt t (match (srcRefOf t) -> ev (prefix (vars t ++ vs)) (alt : map snd same)) :-> matchAlts ev prefix vs others-> where (same,others) = partition ((t ==) . fst) alts -> vars (IL.ConstructorPattern _ vs) = vs-> vars _ = []--\end{verbatim}-Matching in a \texttt{case}-expression works a little bit differently.-In this case, the alternatives are matched from the first to the last-alternative and the first matching alternative is chosen. All-remaining alternatives are discarded.--\ToDo{The case matching algorithm should use type information in order-to detect total matches and immediately discard all alternatives which-cannot be reached.}-\begin{verbatim}--> caseMatch :: SrcRef -> ([Ident] -> [Ident]) -> [Ident] -> [Match'] -> -> IL.Expression-> caseMatch _ prefix [] alts = thd3 (head alts)-> caseMatch r prefix (v:vs) alts-> | isDefaultMatch (head alts') =-> caseMatch r (prefix . (v:)) vs (map skipArg alts)-> | otherwise =-> IL.Case r IL.Rigid (IL.Variable v) (caseMatchAlts prefix vs alts')-> where alts' = map tagAlt alts-> tagAlt (prefix,t:ts,e) = (pattern t,(prefix,arguments t ++ ts,e))-> skipArg (prefix,t:ts,e) = (prefix . (t:),ts,e)--> caseMatchAlts ::-> ([Ident] -> [Ident]) -> [Ident] -> [(IL.ConstrTerm,Match')] -> [IL.Alt]-> caseMatchAlts prefix vs alts = map caseAlt (ts ++ ts')-> where (ts',ts) = partition isDefaultPattern (nub (map fst alts))-> caseAlt t =-> IL.Alt t (caseMatch (srcRefOf t) id (prefix (vars t ++ vs))-> (matchingCases t alts))-> matchingCases t =-> map (joinArgs (vars t)) . filter (matches t . fst)-> matches t t' = t == t' || isDefaultPattern t'-> joinArgs vs (IL.VariablePattern _,(prefix,ts,e)) =-> (id,prefix (map varPattern vs ++ ts),e)-> joinArgs _ (_,(prefix,ts,e)) = (id,prefix ts,e)-> varPattern v = NestedTerm (IL.VariablePattern v) []-> vars (IL.ConstructorPattern _ vs) = vs-> vars _ = []--\end{verbatim}-\paragraph{Expressions}-Note that the case matching algorithm assumes that the matched-expression is accessible through a variable. The translation of case-expressions therefore introduces a let binding for the scrutinized-expression and immediately throws it away after the matching -- except-if the matching algorithm has decided to use that variable in the-right hand sides of the case expression. This may happen, for-instance, if one of the alternatives contains an \texttt{@}-pattern.-\begin{verbatim}--> translExpr :: ValueEnv -> [Ident] -> RenameEnv -> Expression -> IL.Expression-> translExpr _ _ _ (Literal l) = IL.Literal (translLiteral l)-> translExpr tyEnv _ env (Variable v) =-> case lookupVar v env of-> Just v' -> IL.Variable v'-> Nothing -> IL.Function v (arrowArity (varType tyEnv v))-> where lookupVar v env-> | isQualified v = Nothing-> | otherwise = Map.lookup (unqualify v) env-> translExpr tyEnv _ _ (Constructor c) =-> IL.Constructor c (arrowArity (constrType tyEnv c))-> translExpr tyEnv vs env (Apply e1 e2) =-> IL.Apply (translExpr tyEnv vs env e1) (translExpr tyEnv vs env e2)-> translExpr tyEnv vs env (Let ds e) =-> case ds of-> [ExtraVariables _ vs] -> foldr IL.Exist e' vs-> [d] | all (`notElem` bv d) (qfv emptyMIdent d) ->-> IL.Let (translBinding env' d) e'-> _ -> IL.Letrec (map (translBinding env') ds) e'-> where e' = translExpr tyEnv vs env' e-> env' = foldr2 Map.insert env bvs bvs-> bvs = bv ds-> translBinding env (PatternDecl _ (VariablePattern v) rhs) =-> IL.Binding v (translRhs tyEnv vs env rhs)-> translBinding env p = error $ "unexpected binding: "++show p-> translExpr tyEnv ~(v:vs) env (Case r e alts) =-> case caseMatch r id [v] (map (translAlt v) alts) of-> IL.Case r mode (IL.Variable v') alts'-> | v == v' && v `notElem` fv alts' -> IL.Case r mode e' alts'-> e''-> | v `elem` fv e'' -> IL.Let (IL.Binding v e') e''-> | otherwise -> e''-> where e' = translExpr tyEnv vs env e-> translAlt v (Alt _ t rhs) =-> (id,-> [translTerm v t],-> translRhs tyEnv vs (bindRenameEnv v t env) rhs)-> translExpr _ _ _ _ = internalError "translExpr"--> instance Expr IL.Expression where-> fv (IL.Variable v) = [v]-> fv (IL.Apply e1 e2) = fv e1 ++ fv e2-> fv (IL.Case _ _ e alts) = fv e ++ fv alts-> fv (IL.Or e1 e2) = fv e1 ++ fv e2-> fv (IL.Exist v e) = filter (/= v) (fv e)-> fv (IL.Let (IL.Binding v e1) e2) = fv e1 ++ filter (/= v) (fv e2)-> fv (IL.Letrec bds e) = filter (`notElem` vs) (fv es ++ fv e)-> where (vs,es) = unzip [(v,e) | IL.Binding v e <- bds]-> fv _ = []--> instance Expr IL.Alt where-> fv (IL.Alt (IL.ConstructorPattern _ vs) e) = filter (`notElem` vs) (fv e)-> fv (IL.Alt (IL.VariablePattern v) e) = filter (v /=) (fv e)-> fv (IL.Alt _ e) = fv e--\end{verbatim}-\paragraph{Auxiliary Definitions}-The functions \texttt{varType} and \texttt{constrType} return the type-of variables and constructors, respectively. The quantifiers are-stripped from the types.-\begin{verbatim}--> varType :: ValueEnv -> QualIdent -> Type-> varType tyEnv f =-> case qualLookupValue f tyEnv of-> [Value _ (ForAll _ ty)] -> ty-> _ -> internalError ("varType: " ++ show f)--> constrType :: ValueEnv -> QualIdent -> Type-> constrType tyEnv c =-> case qualLookupValue c tyEnv of-> [DataConstructor _ (ForAllExist _ _ ty)] -> ty-> [NewtypeConstructor _ (ForAllExist _ _ ty)] -> ty-> _ -> internalError ("constrType: " ++ show c)--\end{verbatim}-The list of import declarations in the intermediate language code is-determined by collecting all module qualifiers used in the current-module.-\begin{verbatim}--> imports :: ModuleIdent -> [IL.Decl] -> [ModuleIdent]-> imports m = Set.toList . Set.delete m . Set.fromList . foldr modulesDecl []--> modulesDecl :: IL.Decl -> [ModuleIdent] -> [ModuleIdent]-> modulesDecl (IL.DataDecl _ _ cs) ms = foldr modulesConstrDecl ms cs-> where modulesConstrDecl (IL.ConstrDecl _ tys) ms = foldr modulesType ms tys-> modulesDecl (IL.NewtypeDecl _ _ (IL.ConstrDecl _ ty)) ms = modulesType ty ms-> modulesDecl (IL.FunctionDecl _ _ ty e) ms = modulesType ty (modulesExpr e ms)-> modulesDecl (IL.ExternalDecl _ _ _ ty) ms = modulesType ty ms--> modulesType :: IL.Type -> [ModuleIdent] -> [ModuleIdent]-> modulesType (IL.TypeConstructor tc tys) ms =-> modules tc (foldr modulesType ms tys)-> modulesType (IL.TypeVariable _) ms = ms-> modulesType (IL.TypeArrow ty1 ty2) ms = modulesType ty1 (modulesType ty2 ms)--> modulesExpr :: IL.Expression -> [ModuleIdent] -> [ModuleIdent]-> modulesExpr (IL.Function f _) ms = modules f ms-> modulesExpr (IL.Constructor c _) ms = modules c ms-> modulesExpr (IL.Apply e1 e2) ms = modulesExpr e1 (modulesExpr e2 ms)-> modulesExpr (IL.Case _ _ e as) ms = modulesExpr e (foldr modulesAlt ms as)-> where modulesAlt (IL.Alt t e) ms = modulesConstrTerm t (modulesExpr e ms)-> modulesConstrTerm (IL.ConstructorPattern c _) ms = modules c ms-> modulesConstrTerm _ ms = ms-> modulesExpr (IL.Or e1 e2) ms = modulesExpr e1 (modulesExpr e2 ms)-> modulesExpr (IL.Exist _ e) ms = modulesExpr e ms-> modulesExpr (IL.Let b e) ms = modulesBinding b (modulesExpr e ms)-> modulesExpr (IL.Letrec bs e) ms = foldr modulesBinding (modulesExpr e ms) bs-> modulesExpr _ ms = ms--> modulesBinding :: IL.Binding -> [ModuleIdent] -> [ModuleIdent]-> modulesBinding (IL.Binding _ e) = modulesExpr e--> modules :: QualIdent -> [ModuleIdent] -> [ModuleIdent]-> modules x ms = maybe ms (: ms) (qualidMod x)--\end{verbatim}-
+ src/IL/Pretty.hs view
@@ -0,0 +1,189 @@+{- |+ Module : $Header$+ Description : Pretty printer for IL+ Copyright : (c) 1999 - 2003 Wolfgang Lux+ Martin Engelke+ 2011 - 2015 Björn Peemöller+ 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module implements just another pretty printer, this time for the+ intermediate language. It was mainly adapted from the Curry pretty+ printer which, in turn, is based on Simon Marlow's pretty printer+ for Haskell.+-}+{-# LANGUAGE CPP #-}+module IL.Pretty (ppModule) where++#if __GLASGOW_HASKELL__ >= 804+import Prelude hiding ((<>))+#endif++import Curry.Base.Ident+import Curry.Base.Pretty+import IL.Type++dataIndent :: Int+dataIndent = 2++bodyIndent :: Int+bodyIndent = 2++exprIndent :: Int+exprIndent = 2++caseIndent :: Int+caseIndent = 2++altIndent :: Int+altIndent = 2++orIndent :: Int+orIndent = 2++ppModule :: Module -> Doc+ppModule (Module m is ds) = sepByBlankLine+ [ppHeader m, vcat (map ppImport is), sepByBlankLine (map ppDecl ds)]++ppHeader :: ModuleIdent -> Doc+ppHeader m = text "module" <+> text (moduleName m) <+> text "where"++ppImport :: ModuleIdent -> Doc+ppImport m = text "import" <+> text (moduleName m)++ppDecl :: Decl -> Doc+ppDecl (DataDecl tc ks cs) = sep $+ text "data" <+> ppTypeLhs tc (length ks) :+ map (nest dataIndent)+ (zipWith (<+>) (equals : repeat (char '|')) (map ppConstr cs))+ppDecl (NewtypeDecl tc ks nc) = sep $+ text "newtype" <+> ppTypeLhs tc (length ks) :+ [nest dataIndent (equals <+> ppNewConstr nc)]+ppDecl (ExternalDataDecl tc ks) =+ text "external data" <+> ppTypeLhs tc (length ks)+ppDecl (FunctionDecl f vs ty e) = ppTypeSig f ty $$ sep+ [ ppQIdent f <+> hsep (map (ppIdent . snd) vs) <+> equals+ , nest bodyIndent (ppExpr 0 e)]+ppDecl (ExternalDecl f _ ty) = text "external" <+> ppTypeSig f ty++ppTypeLhs :: QualIdent -> Int -> Doc+ppTypeLhs tc n = ppQIdent tc <+> hsep (map text (take n typeVars))++ppConstr :: ConstrDecl -> Doc+ppConstr (ConstrDecl c tys) = ppQIdent c <+> fsep (map (ppType 2) tys)++ppNewConstr :: NewConstrDecl -> Doc+ppNewConstr (NewConstrDecl c ty) = ppQIdent c <+> fsep [ppType 2 ty]++ppTypeSig :: QualIdent -> Type -> Doc+ppTypeSig f ty = ppQIdent f <+> text "::" <+> ppType 0 ty++ppType :: Int -> Type -> Doc+ppType p (TypeConstructor tc tys)+ | isQTupleId tc = parens+ (fsep (punctuate comma (map (ppType 0) tys)))+ | tc == qListId && length tys == 1 = brackets (ppType 0 (head tys))+ | otherwise = parenIf (p > 1 && not (null tys))+ (ppQIdent tc <+> fsep (map (ppType 2) tys))+ppType _ (TypeVariable n) = ppTypeVar n+ppType p (TypeArrow ty1 ty2) = parenIf (p > 0)+ (fsep (ppArrow (TypeArrow ty1 ty2)))+ where+ ppArrow (TypeArrow ty1' ty2') = ppType 1 ty1' <+> text "->" : ppArrow ty2'+ ppArrow ty = [ppType 0 ty]+ppType p (TypeForall ns ty)+ | null ns = ppType p ty+ | otherwise = parenIf (p > 0) $ ppQuantifiedTypeVars ns <+> ppType 0 ty++ppTypeVar :: Int -> Doc+ppTypeVar n+ | n >= 0 = text (typeVars !! n)+ | otherwise = text ('_':show (-n))++ppQuantifiedTypeVars :: [(Int, Kind)] -> Doc+ppQuantifiedTypeVars ns+ | null ns = empty+ | otherwise = text "forall" <+> hsep (map (ppTypeVar . fst) ns) <> char '.'++ppBinding :: Binding -> Doc+ppBinding (Binding v expr) = sep+ [ppIdent v <+> equals, nest bodyIndent (ppExpr 0 expr)]++ppAlt :: Alt -> Doc+ppAlt (Alt pat expr) = sep+ [ppConstrTerm pat <+> text "->", nest altIndent (ppExpr 0 expr)]++ppLiteral :: Literal -> Doc+ppLiteral (Char c) = text (show c)+ppLiteral (Int i) = integer i+ppLiteral (Float f) = double f++ppConstrTerm :: ConstrTerm -> Doc+ppConstrTerm (LiteralPattern _ l) = ppLiteral l+ppConstrTerm (ConstructorPattern _ c [(_, v1), (_, v2)])+ | isQInfixOp c = ppIdent v1 <+> ppQInfixOp c <+> ppIdent v2+ppConstrTerm (ConstructorPattern _ c vs)+ | isQTupleId c = parens $ fsep (punctuate comma $ map (ppIdent . snd) vs)+ | otherwise = ppQIdent c <+> fsep (map (ppIdent . snd) vs)+ppConstrTerm (VariablePattern _ v) = ppIdent v++ppExpr :: Int -> Expression -> Doc+ppExpr _ (Literal _ l) = ppLiteral l+ppExpr _ (Variable _ v) = ppIdent v+ppExpr _ (Function _ f _) = ppQIdent f+ppExpr _ (Constructor _ c _) = ppQIdent c+ppExpr p (Apply (Apply (Function _ f _) e1) e2)+ | isQInfixOp f = ppInfixApp p e1 f e2+ppExpr p (Apply (Apply (Constructor _ c _) e1) e2)+ | isQInfixOp c = ppInfixApp p e1 c e2+ppExpr p (Apply e1 e2) = parenIf (p > 2) $ sep+ [ppExpr 2 e1, nest exprIndent (ppExpr 3 e2)]+ppExpr p (Case ev e alts) = parenIf (p > 0) $+ text "case" <+> ppEval ev <+> ppExpr 0 e <+> text "of"+ $$ nest caseIndent (vcat $ map ppAlt alts)+ where ppEval Rigid = text "rigid"+ ppEval Flex = text "flex"+ppExpr p (Or e1 e2) = parenIf (p > 0) $ sep+ [nest orIndent (ppExpr 0 e1), char '|', nest orIndent (ppExpr 0 e2)]+ppExpr p (Exist v _ e) = parenIf (p > 0) $ sep+ [text "let" <+> ppIdent v <+> text "free" <+> text "in", ppExpr 0 e]+ppExpr p (Let b e) = parenIf (p > 0) $ sep+ [text "let" <+> ppBinding b <+> text "in",ppExpr 0 e]+ppExpr p (Letrec bs e) = parenIf (p > 0) $ sep+ [text "letrec" <+> vcat (map ppBinding bs) <+> text "in", ppExpr 0 e]+ppExpr p (Typed e ty) = parenIf (p > 0) $ sep+ [ppExpr 0 e, text "::", ppType 0 ty]++ppInfixApp :: Int -> Expression -> QualIdent -> Expression -> Doc+ppInfixApp p e1 op e2 = parenIf (p > 1) $ sep+ [ppExpr 2 e1 <+> ppQInfixOp op, nest exprIndent (ppExpr 2 e2)]++ppIdent :: Ident -> Doc+ppIdent ident+ | isInfixOp ident = parens (ppName ident)+ | otherwise = ppName ident++ppQIdent :: QualIdent -> Doc+ppQIdent ident+ | isQInfixOp ident = parens (ppQual ident)+ | otherwise = ppQual ident++ppQInfixOp :: QualIdent -> Doc+ppQInfixOp op+ | isQInfixOp op = ppQual op+ | otherwise = char '`' <> ppQual op <> char '`'++ppName :: Ident -> Doc+ppName x = text (idName x)++ppQual :: QualIdent -> Doc+ppQual x = text (qualName x)++typeVars :: [String]+typeVars = [mkTypeVar c i | i <- [0 .. ], c <- ['a' .. 'z']] where+ mkTypeVar :: Char -> Int -> String+ mkTypeVar c i = c : if i == 0 then [] else show i
− src/IL/Pretty.lhs
@@ -1,167 +0,0 @@-% $Id: ILPP.lhs,v 1.22 2003/10/28 05:43:43 wlux Exp $-%-% Copyright (c) 1999-2003 Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{ILPP.lhs}-\section{A pretty printer for the intermediate language}-This module implements just another pretty printer, this time for the-intermediate language. It was mainly adapted from the Curry pretty-printer (see sect.~\ref{sec:CurryPP}) which, in turn, is based on Simon-Marlow's pretty printer for Haskell.-\begin{verbatim}--> module IL.Pretty(ppModule) where-> -> import Text.PrettyPrint.HughesPJ--> import Curry.Base.Ident-> import IL.Type--> default(Int,Double)--> dataIndent = 2-> bodyIndent = 2-> exprIndent = 2-> caseIndent = 2-> altIndent = 2--> ppModule :: Module -> Doc-> ppModule (Module m is ds) =-> vcat (text "module" <+> text (show m) <+> text "where" :-> map ppImport is ++ map ppDecl ds)--> ppImport :: ModuleIdent -> Doc-> ppImport m = text "import" <+> text (show m)--> ppDecl :: Decl -> Doc-> ppDecl (DataDecl tc n cs) =-> sep (text "data" <+> ppTypeLhs tc n :-> map (nest dataIndent)-> (zipWith (<+>) (equals : repeat (char '|')) (map ppConstr cs)))-> ppDecl (NewtypeDecl tc n (ConstrDecl c ty)) =-> sep [text "newtype" <+> ppTypeLhs tc n <+> equals,-> nest dataIndent (ppConstr (ConstrDecl c [ty]))]-> ppDecl (FunctionDecl f vs ty exp) =-> ppTypeSig f ty $$-> sep [ppQIdent f <+> hsep (map ppIdent vs) <+> equals,-> nest bodyIndent (ppExpr 0 exp)]-> ppDecl (ExternalDecl f cc ie ty) =-> sep [text "external" <+> ppCallConv cc <+> text (show ie),-> nest bodyIndent (ppTypeSig f ty)]-> where ppCallConv Primitive = text "primitive"-> ppCallConv CCall = text "ccall"--> ppTypeLhs :: QualIdent -> Int -> Doc-> ppTypeLhs tc n = ppQIdent tc <+> hsep (map text (take n typeVars))--> ppConstr :: ConstrDecl [Type] -> Doc-> ppConstr (ConstrDecl c tys) = ppQIdent c <+> fsep (map (ppType 2) tys)--> ppTypeSig :: QualIdent -> Type -> Doc-> ppTypeSig f ty = ppQIdent f <+> text "::" <+> ppType 0 ty--> ppType :: Int -> Type -> Doc-> ppType p (TypeConstructor tc tys)-> | isQTupleId tc = parens (fsep (punctuate comma (map (ppType 0) tys)))-> | unqualify tc == nilId = brackets (ppType 0 (head tys))-> | otherwise =-> ppParen (p > 1 && not (null tys))-> (ppQIdent tc <+> fsep (map (ppType 2) tys))-> ppType _ (TypeVariable n)-> | n >= 0 = text (typeVars !! n)-> | otherwise = text ('_':show (-n))-> ppType p (TypeArrow ty1 ty2) =-> ppParen (p > 0) (fsep (ppArrow (TypeArrow ty1 ty2)))-> where ppArrow (TypeArrow ty1 ty2) =-> ppType 1 ty1 <+> text "->" : ppArrow ty2-> ppArrow ty = [ppType 0 ty]--> ppBinding :: Binding -> Doc-> ppBinding (Binding v exp) =-> sep [ppIdent v <+> equals,nest bodyIndent (ppExpr 0 exp)]--> ppAlt :: Alt -> Doc-> ppAlt (Alt pat exp) =-> sep [ppConstrTerm pat <+> text "->",nest altIndent (ppExpr 0 exp)]--> ppLiteral :: Literal -> Doc-> ppLiteral (Char _ c) = text (show c)-> ppLiteral (Int _ i) = integer i-> ppLiteral (Float _ f) = double f--> ppConstrTerm :: ConstrTerm -> Doc-> ppConstrTerm (LiteralPattern l) = ppLiteral l-> ppConstrTerm (ConstructorPattern c [v1,v2])-> | isQInfixOp c = ppIdent v1 <+> ppQInfixOp c <+> ppIdent v2-> ppConstrTerm (ConstructorPattern c vs)-> | isQTupleId c = parens (fsep (punctuate comma (map ppIdent vs)))-> | otherwise = ppQIdent c <+> fsep (map ppIdent vs)-> ppConstrTerm (VariablePattern v) = ppIdent v--> ppExpr :: Int -> Expression -> Doc-> ppExpr p (Literal l) = ppLiteral l-> ppExpr p (Variable v) = ppIdent v-> ppExpr p (Function f _) = ppQIdent f-> ppExpr p (Constructor c _) = ppQIdent c-> ppExpr p (Apply (Apply (Function f _) e1) e2)-> | isQInfixOp f = ppInfixApp p e1 f e2-> ppExpr p (Apply (Apply (Constructor c _) e1) e2)-> | isQInfixOp c = ppInfixApp p e1 c e2-> ppExpr p (Apply e1 e2) =-> ppParen (p > 2) (sep [ppExpr 2 e1,nest exprIndent (ppExpr 3 e2)])-> ppExpr p (Case _ ev e alts) =-> ppParen (p > 0)-> (text "case" <+> ppEval ev <+> ppExpr 0 e <+> text "of" $$-> nest caseIndent (vcat (map ppAlt alts)))-> where ppEval Rigid = text "rigid"-> ppEval Flex = text "flex"-> ppExpr p (Or e1 e2) =-> ppParen (p > 0) (sep [ppExpr 0 e1,char '|' <+> ppExpr 0 e2])-> ppExpr p (Exist v e) =-> ppParen (p > 0)-> (sep [text "let" <+> ppIdent v <+> text "free" <+> text "in",-> ppExpr 0 e])-> ppExpr p (Let b e) =-> ppParen (p > 0) (sep [text "let" <+> ppBinding b <+> text "in",ppExpr 0 e])-> ppExpr p (Letrec bs e) =-> ppParen (p > 0)-> (sep [text "letrec" <+> vcat (map ppBinding bs) <+> text "in",-> ppExpr 0 e])--> ppInfixApp :: Int -> Expression -> QualIdent -> Expression -> Doc-> ppInfixApp p e1 op e2 =-> ppParen (p > 1)-> (sep [ppExpr 2 e1 <+> ppQInfixOp op,nest exprIndent (ppExpr 2 e2)])--> ppIdent :: Ident -> Doc-> ppIdent ident-> | isInfixOp ident = parens (ppName ident)-> | otherwise = ppName ident--> ppQIdent :: QualIdent -> Doc-> ppQIdent ident-> | isQInfixOp ident = parens (ppQual ident)-> | otherwise = ppQual ident--> ppQInfixOp :: QualIdent -> Doc-> ppQInfixOp op-> | isQInfixOp op = ppQual op-> | otherwise = char '`' <> ppQual op <> char '`'--> ppName :: Ident -> Doc-> ppName x = text (name x)--> ppQual :: QualIdent -> Doc-> ppQual x = text (qualName x)--> typeVars :: [String]-> typeVars = [mkTypeVar c i | i <- [0..], c <- ['a' .. 'z']]-> where mkTypeVar c i = c : if i == 0 then [] else show i--> ppParen :: Bool -> Doc -> Doc-> ppParen p = if p then parens else id--\end{verbatim}
− src/IL/Scope.hs
@@ -1,124 +0,0 @@-module IL.Scope (getModuleScope,- insertDeclScope, insertConstrDeclScope,- insertCallConvScope, insertTypeScope,- insertLiteralScope, insertConstrTermScope,- insertExprScope, insertAltScope,- insertBindingScope) where--import Curry.Base.Ident--import IL.Type-import OldScopeEnv as ScopeEnv---------------------------------------------------------------------------------------getModuleScope :: Module -> ScopeEnv-getModuleScope (Module _ _ decls) = foldl insertDecl newScopeEnv decls------insertDeclScope :: ScopeEnv -> Decl -> ScopeEnv-insertDeclScope env (DataDecl _ _ _) = env-insertDeclScope env (NewtypeDecl _ _ _) = env-insertDeclScope env (FunctionDecl _ params _ _)- = foldr ScopeEnv.insertIdent (ScopeEnv.beginScope env) params-insertDeclScope env (ExternalDecl _ _ _ _) = env------insertConstrDeclScope :: ScopeEnv -> ConstrDecl [Type] -> ScopeEnv-insertConstrDeclScope env _ = env------insertCallConvScope :: ScopeEnv -> CallConv -> ScopeEnv-insertCallConvScope env _ = env------insertTypeScope :: ScopeEnv -> Type -> ScopeEnv-insertTypeScope env _ = env------insertLiteralScope :: ScopeEnv -> Literal -> ScopeEnv-insertLiteralScope env _ = env------insertConstrTermScope :: ScopeEnv -> ConstrTerm -> ScopeEnv-insertConstrTermScope env _ = env------insertExprScope :: ScopeEnv -> Expression -> ScopeEnv-insertExprScope env (Literal _) = env-insertExprScope env (Variable _) = env-insertExprScope env (Function _ _) = env-insertExprScope env (Constructor _ _) = env-insertExprScope env (Apply _ _) = env-insertExprScope env (Case _ _ _ _) = env-insertExprScope env (Or _ _) = env-insertExprScope env (Exist ident _)- = ScopeEnv.insertIdent ident (ScopeEnv.beginScope env)-insertExprScope env (Let bind _)- = insertBinding (beginScope env) bind-insertExprScope env (Letrec binds _)- = foldl insertBinding (beginScope env) binds------insertAltScope :: ScopeEnv -> Alt -> ScopeEnv-insertAltScope env (Alt cterm _)- = insertConstrTerm (ScopeEnv.beginScope env) cterm------insertBindingScope :: ScopeEnv -> Binding -> ScopeEnv-insertBindingScope env _ = env-----------------------------------------------------------------------------------------------------------------------------------------------------------------------insertDecl :: ScopeEnv -> Decl -> ScopeEnv-insertDecl env (DataDecl qident _ cdecls)- = foldl insertConstrDecl- (ScopeEnv.insertIdent (unqualify qident) env)- cdecls--insertDecl env (NewtypeDecl qident _ cdecl)- = insertConstrDecl (ScopeEnv.insertIdent (unqualify qident) env) cdecl--insertDecl env (FunctionDecl qident _ _ _)- = ScopeEnv.insertIdent (unqualify qident) env--insertDecl env (ExternalDecl qident _ _ _)- = ScopeEnv.insertIdent (unqualify qident) env------insertConstrDecl :: ScopeEnv -> ConstrDecl a -> ScopeEnv-insertConstrDecl env (ConstrDecl qident _)- = ScopeEnv.insertIdent (unqualify qident) env------insertConstrTerm :: ScopeEnv -> ConstrTerm -> ScopeEnv-insertConstrTerm env (LiteralPattern _) = env-insertConstrTerm env (ConstructorPattern _ params)- = foldr ScopeEnv.insertIdent env params-insertConstrTerm env (VariablePattern ident)- = ScopeEnv.insertIdent ident env------insertBinding :: ScopeEnv -> Binding -> ScopeEnv-insertBinding env (Binding ident _) = ScopeEnv.insertIdent ident env------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ src/IL/ShowModule.hs view
@@ -0,0 +1,263 @@+{- |+ Module : $Header$+ Description : Custom Show implementation for IL+ Copyright : (c) 2015 Björn Peemöller+ 2016 - 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module implements a generic show function comparable to the one+ obtained by @deriving Show@. However, the internal representation of+ identifiers is hidden to avoid syntactic clutter.+-}++module IL.ShowModule (showModule) where++import Curry.Base.Ident+import Curry.Base.Position++import IL.Type++-- |Show a IL module like by an devired 'Show' instance+showModule :: Module -> String+showModule m = showsModule m "\n"++showsModule :: Module -> ShowS+showsModule (Module mident imps decls)+ = showsString "Module "+ . showsModuleIdent mident . newline+ . showsList (\i -> showsModuleIdent i . newline) imps+ . showsList (\d -> showsDecl d . newline) decls++showsDecl :: Decl -> ShowS+showsDecl (DataDecl qident arity constrdecls)+ = showsString "(DataDecl "+ . showsQualIdent qident . space+ . shows arity . space+ . showsList showsConstrDecl constrdecls+ . showsString ")"+showsDecl (NewtypeDecl qident arity newconstrdecl)+ = showsString "(NewtypeDecl "+ . showsQualIdent qident . space+ . shows arity . space+ . showsNewConstrDecl newconstrdecl+ . showsString ")"+showsDecl (ExternalDataDecl qident arity)+ = showsString "(ExternalDataDecl "+ . showsQualIdent qident . space+ . shows arity+ . showsString ")"+showsDecl (FunctionDecl qident idents typ expr)+ = showsString "(FunctionDecl "+ . showsQualIdent qident . space+ . showsList (showsIdent . snd) idents . space+ . showsType typ . space+ . showsExpression expr+ . showsString ")"+showsDecl (ExternalDecl qident arity typ)+ = showsString "(ExternalDecl "+ . showsQualIdent qident . space+ . shows arity+ . showsType typ+ . showsString ")"++showsConstrDecl :: ConstrDecl -> ShowS+showsConstrDecl (ConstrDecl qident tys)+ = showsString "(ConstrDecl "+ . showsQualIdent qident . space+ . showsList showsType tys+ . showsString ")"++showsNewConstrDecl :: NewConstrDecl -> ShowS+showsNewConstrDecl (NewConstrDecl qident ty)+ = showsString "(NewConstrDecl "+ . showsQualIdent qident . space+ . showsType ty+ . showsString ")"++showsType :: Type -> ShowS+showsType (TypeConstructor qident types)+ = showsString "(TypeConstructor "+ . showsQualIdent qident . space+ . showsList showsType types+ . showsString ")"+showsType (TypeVariable int)+ = showsString "(TypeVariable "+ . shows int+ . showsString ")"+showsType (TypeArrow type1 type2)+ = showsString "(TypeArrow "+ . showsType type1 . space+ . showsType type2+ . showsString ")"+showsType (TypeForall ints typ)+ = showsString "(TypeForall "+ . showsList shows ints . space+ . showsType typ+ . showsString ")"++showsLiteral :: Literal -> ShowS+showsLiteral (Char c)+ = showsString "(Char "+ . shows c+ . showsString ")"+showsLiteral (Int n)+ = showsString "(Int "+ . shows n+ . showsString ")"+showsLiteral (Float x)+ = showsString "(Float "+ . shows x+ . showsString ")"++showsConstrTerm :: ConstrTerm -> ShowS+showsConstrTerm (LiteralPattern ty lit)+ = showsString "(LiteralPattern "+ . showsType ty+ . showsLiteral lit+ . showsString ")"+showsConstrTerm (ConstructorPattern ty qident idents)+ = showsString "(ConstructorPattern "+ . showsType ty+ . showsQualIdent qident . space+ . showsList (showsIdent . snd) idents+ . showsString ")"+showsConstrTerm (VariablePattern ty ident)+ = showsString "(VariablePattern "+ . showsType ty+ . showsIdent ident+ . showsString ")"++showsExpression :: Expression -> ShowS+showsExpression (Literal ty lit)+ = showsString "(Literal "+ . showsType ty+ . showsLiteral lit+ . showsString ")"+showsExpression (Variable ty ident)+ = showsString "(Variable "+ . showsType ty+ . showsIdent ident+ . showsString ")"+showsExpression (Function ty qident int)+ = showsString "(Function "+ . showsType ty+ . showsQualIdent qident . space+ . shows int+ . showsString ")"+showsExpression (Constructor ty qident int)+ = showsString "(Constructor "+ . showsType ty+ . showsQualIdent qident . space+ . shows int+ . showsString ")"+showsExpression (Apply exp1 exp2)+ = showsString "(Apply "+ . showsExpression exp1 . space+ . showsExpression exp2+ . showsString ")"+showsExpression (Case eval expr alts)+ = showsString "(Case "+ . showsEval eval . space+ . showsExpression expr . space+ . showsList showsAlt alts+ . showsString ")"+showsExpression (Or exp1 exp2)+ = showsString "(Or "+ . showsExpression exp1 . space+ . showsExpression exp2+ . showsString ")"+showsExpression (Exist ident ty expr)+ = showsString "(Exist "+ . showsIdent ident . space+ . showsType ty . space+ . showsExpression expr+ . showsString ")"+showsExpression (Let bind expr)+ = showsString "(Let "+ . showsBinding bind . space+ . showsExpression expr+ . showsString ")"+showsExpression (Letrec binds expr)+ = showsString "(Letrec "+ . showsList showsBinding binds . space+ . showsExpression expr+ . showsString ")"+showsExpression (Typed expr typ)+ = showsString "(Typed "+ . showsExpression expr . space+ . showsType typ+ . showsString ")"++showsEval :: Eval -> ShowS+showsEval Rigid = showsString "Rigid"+showsEval Flex = showsString "Flex"++showsAlt :: Alt -> ShowS+showsAlt (Alt constr expr)+ = showsString "(Alt "+ . showsConstrTerm constr . space+ . showsExpression expr+ . showsString ")"++showsBinding :: Binding -> ShowS+showsBinding (Binding ident expr)+ = showsString "(Binding "+ . showsIdent ident . space+ . showsExpression expr+ . showsString ")"++showsPosition :: Position -> ShowS+showsPosition Position { line = l, column = c } = showsPair shows shows (l, c)+showsPosition _ = showsString "(0,0)"++showsString :: String -> ShowS+showsString = (++)++space :: ShowS+space = showsString " "++newline :: ShowS+newline = showsString "\n"++showsMaybe :: (a -> ShowS) -> Maybe a -> ShowS+showsMaybe shs = maybe (showsString "Nothing")+ (\x -> showsString "(Just " . shs x . showsString ")")++showsList :: (a -> ShowS) -> [a] -> ShowS+showsList _ [] = showsString "[]"+showsList shs (x:xs)+ = showsString "["+ . foldl (\sys y -> sys . showsString "," . shs y) (shs x) xs+ . showsString "]"++showsPair :: (a -> ShowS) -> (b -> ShowS) -> (a,b) -> ShowS+showsPair sa sb (a,b)+ = showsString "(" . sa a . showsString "," . sb b . showsString ")"++showsIdent :: Ident -> ShowS+showsIdent (Ident spi x n)+ = showsString "(Ident " . showsPosition (getPosition spi) . space+ . shows x . space . shows n . showsString ")"++showsQualIdent :: QualIdent -> ShowS+showsQualIdent (QualIdent _ mident ident)+ = showsString "(QualIdent "+ . showsMaybe showsModuleIdent mident+ . space+ . showsIdent ident+ . showsString ")"++showsModuleIdent :: ModuleIdent -> ShowS+showsModuleIdent (ModuleIdent spi ss)+ = showsString "(ModuleIdent "+ . showsPosition (getPosition spi) . space+ . showsList (showsQuotes showsString) ss+ . showsString ")"++showsQuotes :: (a -> ShowS) -> a -> ShowS+showsQuotes sa a+ = showsString "\"" . sa a . showsString "\""
+ src/IL/Type.hs view
@@ -0,0 +1,155 @@+{- |+ Module : $Header$+ Description : Definition of the intermediate language (IL)+ Copyright : (c) 1999 - 2003 Wolfgang Lux+ Martin Engelke+ 2016 - 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ The module 'IL' defines the intermediate language which will be+ compiled into abstract machine code. The intermediate language removes+ a lot of syntactic sugar from the Curry source language. Top-level+ declarations are restricted to data type and function definitions. A+ newtype definition serves mainly as a hint to the backend that it must+ provide an auxiliary function for partial applications of the+ constructor (Newtype constructors must not occur in patterns+ and may be used in expressions only as partial applications.).++ Type declarations use a de-Bruijn indexing scheme (starting at 0) for+ type variables. In the type of a function, all type variables are+ numbered in the order of their occurence from left to right, i.e., a+ type '(Int -> b) -> (a,b) -> c -> (a,c)' is translated into the+ type (using integer numbers to denote the type variables)+ '(Int -> 0) -> (1,0) -> 2 -> (1,2)'.++ Pattern matching in an equation is handled via flexible and rigid+ 'Case' expressions. Overlapping rules are translated with the+ help of 'Or' expressions. The intermediate language has three+ kinds of binding expressions, 'Exist' expressions introduce a+ new logical variable, 'Let' expression support a single+ non-recursive variable binding, and 'Letrec' expressions+ introduce multiple variables with recursive initializer expressions.+ The intermediate language explicitly distinguishes (local) variables+ and (global) functions in expressions.++ Note: this modified version uses haskell type 'Integer'+ instead of 'Int' for representing integer values. This provides+ an unlimited range of integer constants in Curry programs.+-}++module IL.Type+ ( -- * Representation of (type) variables+ TypeVariableWithKind+ -- * Data types+ , Module (..), Decl (..), ConstrDecl (..), NewConstrDecl (..), Type (..)+ , Kind (..), Literal (..), ConstrTerm (..), Expression (..), Eval (..)+ , Alt (..), Binding (..)+ ) where++import Curry.Base.Ident++import Base.Expr++data Module = Module ModuleIdent [ModuleIdent] [Decl]+ deriving (Eq, Show)++data Decl+ = DataDecl QualIdent [Kind] [ConstrDecl]+ | NewtypeDecl QualIdent [Kind] NewConstrDecl+ | ExternalDataDecl QualIdent [Kind]+ | FunctionDecl QualIdent [(Type, Ident)] Type Expression+ | ExternalDecl QualIdent Int Type+ deriving (Eq, Show)++data NewConstrDecl = NewConstrDecl QualIdent Type+ deriving (Eq, Show)++data ConstrDecl = ConstrDecl QualIdent [Type]+ deriving (Eq, Show)++type TypeVariableWithKind = (Int, Kind)++data Type+ = TypeConstructor QualIdent [Type]+ | TypeVariable Int+ | TypeArrow Type Type+ | TypeForall [TypeVariableWithKind] Type+ deriving (Eq, Show)++data Kind+ = KindStar+ | KindVariable Int+ | KindArrow Kind Kind+ deriving (Eq, Ord, Show)++data Literal+ = Char Char+ | Int Integer+ | Float Double+ deriving (Eq, Show)++data ConstrTerm+ -- |literal patterns+ = LiteralPattern Type Literal+ -- |constructors+ | ConstructorPattern Type QualIdent [(Type, Ident)]+ -- |default+ | VariablePattern Type Ident+ deriving (Eq, Show)++data Expression+ -- |literal constants+ = Literal Type Literal+ -- |variables+ | Variable Type Ident+ -- |functions+ | Function Type QualIdent Int+ -- |constructors+ | Constructor Type QualIdent Int+ -- |applications+ | Apply Expression Expression+ -- |case expressions+ | Case Eval Expression [Alt]+ -- |non-deterministic or+ | Or Expression Expression+ -- |exist binding (introduction of a free variable)+ | Exist Ident Type Expression+ -- |let binding+ | Let Binding Expression+ -- |letrec binding+ | Letrec [Binding] Expression+ -- |typed expression+ | Typed Expression Type+ deriving (Eq, Show)++data Eval+ = Rigid+ | Flex+ deriving (Eq, Show)++data Alt = Alt ConstrTerm Expression+ deriving (Eq, Show)++data Binding = Binding Ident Expression+ deriving (Eq, Show)++instance Expr Expression where+ fv (Variable _ v) = [v]+ fv (Apply e1 e2) = fv e1 ++ fv e2+ fv (Case _ e alts) = fv e ++ fv alts+ fv (Or e1 e2) = fv e1 ++ fv e2+ fv (Exist v _ e) = filter (/= v) (fv e)+ fv (Let (Binding v e1) e2) = fv e1 ++ filter (/= v) (fv e2)+ fv (Letrec bds e) = filter (`notElem` vs) (fv es ++ fv e)+ where (vs, es) = unzip [(v, e') | Binding v e' <- bds]+ fv (Typed e _) = fv e+ fv _ = []++instance Expr Alt where+ fv (Alt (ConstructorPattern _ _ vs) e) = filter (`notElem` map snd vs) (fv e)+ fv (Alt (VariablePattern _ v) e) = filter (v /=) (fv e)+ fv (Alt _ e) = fv e
− src/IL/Type.lhs
@@ -1,112 +0,0 @@-> {-# LANGUAGE DeriveDataTypeable #-}--% $Id: IL.lhs,v 1.18 2003/10/28 05:43:38 wlux Exp $-%-% Copyright (c) 1999-2003 Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{IL.lhs}-\section{The intermediate language}-The module \texttt{IL} defines the intermediate language which will be-compiled into abstract machine code. The intermediate language removes-a lot of syntactic sugar from the Curry source language. Top-level-declarations are restricted to data type and function definitions. A-newtype definition serves mainly as a hint to the backend that it must-provide an auxiliary function for partial applications of the-constructor. \textbf{Newtype constructors must not occur in patterns-and may be used in expressions only as partial applications.}--Type declarations use a de-Bruijn indexing scheme (starting at 0) for-type variables. In the type of a function, all type variables are-numbered in the order of their occurence from left to right, i.e., a-type \texttt{(Int -> b) -> (a,b) -> c -> (a,c)} is translated into the-type (using integer numbers to denote the type variables)-\texttt{(Int -> 0) -> (1,0) -> 2 -> (1,2)}.--Pattern matching in an equation is handled via flexible and rigid-\texttt{Case} expressions. Overlapping rules are translated with the-help of \texttt{Or} expressions. The intermediate language has three-kinds of binding expressions, \texttt{Exist} expressions introduce a-new logical variable, \texttt{Let} expression support a single-non-recursive variable binding, and \texttt{Letrec} expressions-introduce multiple variables with recursive initializer expressions.-The intermediate language explicitly distinguishes (local) variables-and (global) functions in expressions.--\em{Note:} this modified version uses haskell type \texttt{Integer}-instead of \texttt{Int} for representing integer values. This provides-an unlimited range of integer constants in Curry programs.-\begin{verbatim}--> module IL.Type where--> import Data.Generics-> import Curry.Base.Ident-> import Curry.Base.Position (SrcRef(..))--> data Module = Module ModuleIdent [ModuleIdent] [Decl] deriving (Eq,Show)--> data Decl = -> DataDecl QualIdent Int [ConstrDecl [Type]]-> | NewtypeDecl QualIdent Int (ConstrDecl Type)-> | FunctionDecl QualIdent [Ident] Type Expression-> | ExternalDecl QualIdent CallConv String Type-> deriving (Eq,Show)--> data ConstrDecl a = ConstrDecl QualIdent a deriving (Eq,Show)-> data CallConv = Primitive | CCall deriving (Eq,Show)--> data Type =-> TypeConstructor QualIdent [Type]-> | TypeVariable Int-> | TypeArrow Type Type-> deriving (Eq,Show, Typeable, Data)--> data Literal = Char SrcRef Char | Int SrcRef Integer | Float SrcRef Double deriving (Eq,Show)--> data ConstrTerm =-> -- literal patterns-> LiteralPattern Literal-> -- constructors-> | ConstructorPattern QualIdent [Ident]-> -- default-> | VariablePattern Ident-> deriving (Eq,Show)--> data Expression =-> -- literal constants-> Literal Literal-> -- variables, functions, constructors-> | Variable Ident | Function QualIdent Int | Constructor QualIdent Int-> -- applications-> | Apply Expression Expression-> -- case expressions-> | Case SrcRef Eval Expression [Alt]-> -- non-determinisismic or-> | Or Expression Expression-> -- binding forms-> | Exist Ident Expression-> | Let Binding Expression-> | Letrec [Binding] Expression-> deriving (Eq,Show)--> data Eval = Rigid | Flex deriving (Eq,Show)-> data Alt = Alt ConstrTerm Expression deriving (Eq,Show)-> data Binding = Binding Ident Expression deriving (Eq,Show)--\end{verbatim}--> instance SrcRefOf ConstrTerm where-> srcRefOf (LiteralPattern l) = srcRefOf l-> srcRefOf (ConstructorPattern i _) = srcRefOf i-> srcRefOf (VariablePattern i) = srcRefOf i---> instance SrcRefOf Literal where-> srcRefOf (Char s _) = s-> srcRefOf (Int s _) = s-> srcRefOf (Float s _) = s --
+ src/IL/Typing.hs view
@@ -0,0 +1,44 @@+{- |+ Module : $Header$+ Description : TODO+ Copyright : (c) 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ TODO+-}++module IL.Typing (Typeable(..)) where++import Base.Messages (internalError)++import IL.Type++class Typeable a where+ typeOf :: a -> Type++instance Typeable ConstrTerm where+ typeOf (LiteralPattern ty _) = ty+ typeOf (ConstructorPattern ty _ _) = ty+ typeOf (VariablePattern ty _) = ty++instance Typeable Expression where+ typeOf (Literal ty _) = ty+ typeOf (Variable ty _) = ty+ typeOf (Function ty _ _) = ty+ typeOf (Constructor ty _ _) = ty+ typeOf (Apply e _) = case typeOf e of+ TypeArrow _ ty -> ty+ _ -> internalError "IL.Typing.typeOf: application"+ typeOf (Case _ _ as) = typeOf $ head as+ typeOf (Or e _) = typeOf e+ typeOf (Exist _ _ e) = typeOf e+ typeOf (Let _ e) = typeOf e+ typeOf (Letrec _ e) = typeOf e+ typeOf (Typed e _) = typeOf e++instance Typeable Alt where+ typeOf (Alt _ e) = typeOf e
− src/IL/XML.lhs
@@ -1,518 +0,0 @@--% $Id: ILxml.lhs,v 1.0 2001/06/19 12:19:18 rafa Exp $-%-% $Log: ILxml.lhs,v $-%-% Revision 1.1 2001/06/19 12:19:18 rafa-% Pretty printer in XML for the intermediate language added.-%-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{ILxml.lhs}-\section{A pretty printer in XML for the intermediate language}-This module implements just another pretty printer, this time in XML and for-the intermediate language. It was mainly adapted from the Curry pretty-printer (see sect.~\ref{sec:CurryPP}), which in turn is based on Simon-Marlow's pretty printer for Haskell. The format of the output intends to be-similar to that of Flat-Curry XML representation.-\begin{verbatim}--> module IL.XML(module IL.XML) where--> import Text.PrettyPrint.HughesPJ-> import Data.Maybe--> import Curry.Base.Ident-> import qualified Curry.Syntax as CS--> import IL.Type-> import CurryEnv----> -- identation level-> level::Int-> level = 3--> xmlModule :: CurryEnv -> Module -> Doc-> xmlModule cEnv m = text "<prog>" $$ nest level (xmlBody cEnv m) -> $$ text "</prog>"--> xmlBody :: CurryEnv -> Module -> Doc-> xmlBody cEnv (Module name imports decls) =-> xmlElement "module" xmlModuleDecl moduleDecl $$-> xmlElement "import" xmlImportDecl importDecl $$-> xmlElement "types" xmlTypeDecl typeDecl $$-> xmlElement "functions" xmlFunctionDecl functionDecl $$-> xmlElement "operators" xmlOperatorDecl operatorDecl $$-> xmlElement "translation" xmlTranslationDecl translationDecl-> where-> moduleDecl = [name]-> importDecl = imports-> operatorDecl = infixDecls cEnv-> translationDecl = foldl (qualIDeclId (moduleId cEnv))-> [] -> (interface cEnv)-> (functionDecl,typeDecl) = splitDecls decls--> -- =========================================================================--> xmlModuleDecl :: ModuleIdent -> Doc-> xmlModuleDecl name = xmlModuleIdent name--> -- =========================================================================--> xmlImportDecl :: ModuleIdent -> Doc-> xmlImportDecl name = xmlElement "module" xmlModuleDecl [name]---> -- =========================================================================-> -- T Y P E S-> -- =========================================================================--> xmlTypeDecl :: Decl -> Doc-> xmlTypeDecl (DataDecl tc arity cs) =-> beginType $$-> nest level (xmlTypeParams arity) $$-> xmlLines xmlConstructor cs $$-> endType-> where-> beginType = text "<type name=\"" <> (xmlQualIdent tc) <> text "\">"-> endType = text "</type>"--> xmlTypeParams :: Int -> Doc-> xmlTypeParams n = xmlElement "params" xmlTypeVar [0..(n-1)]--> xmlConstructor :: ConstrDecl [Type] -> Doc-> xmlConstructor (ConstrDecl ident []) = xmlConstructorBegin ident 0-> xmlConstructor (ConstrDecl ident l) =-> xmlConstructorBegin ident (length l) $$-> xmlLines xmlType l $$-> xmlConstructorEnd-> where-> xmlConstructorEnd = text "</cons>"--> xmlConstructorBegin :: QualIdent -> Int -> Doc-> xmlConstructorBegin ident n = xmlHeadingWithArity "cons" ident n (n==0)--> xmlHeadingWithArity :: String -> QualIdent -> Int -> Bool -> Doc-> xmlHeadingWithArity tagName ident n single =-> if single-> then prefix<>text "/>"-> else prefix<> text ">"-> where-> prefix = text ("<"++tagName++" name=\"") <> name <> text "\" " <> arity-> arity = text "arity=\"" <> xmlInt n <> text "\""-> name = xmlQualIdent ident---> xmlType :: Type -> Doc-> xmlType (TypeConstructor ident []) = xmlTypeConsBegin ident True-> xmlType (TypeConstructor ident l) = xmlTypeConsBegin ident False $$-> xmlLines xmlType l $$-> xmlTypeConsEnd-> where-> xmlTypeConsEnd = text "</tcons>"--> xmlType (TypeVariable n) = xmlTypeVar n-> xmlType (TypeArrow a b) = xmlTypeFun a b--> xmlTypeConsBegin :: QualIdent -> Bool -> Doc-> xmlTypeConsBegin ident single =-> if single-> then prefix <> text "/>"-> else prefix <> text ">"-> where-> name = xmlQualIdent ident-> prefix = text "<tcons name=\"" <> name <> text "\""--> xmlTypeVar :: Int -> Doc-> xmlTypeVar n = text "<tvar>"<> xmlInt n <> text "</tvar>"--> xmlTypeFun :: Type -> Type -> Doc-> xmlTypeFun a b = xmlElement "functype" xmlType [a,b]---> -- =========================================================================-> -- F U N C T I O N S-> -- =========================================================================--> xmlFunctionDecl :: Decl -> Doc-> xmlFunctionDecl (NewtypeDecl tc arity (ConstrDecl ident ty)) =-> xmlFunctionDecl (FunctionDecl ident [arg] ftype (Variable arg))-> where-> arg = mkIdent "_1"-> ftype = TypeArrow ty (TypeConstructor tc (map TypeVariable [0..arity-1]))--> xmlFunctionDecl (FunctionDecl ident largs fType expr) =-> heading $$ nest level (xmlRule largs expr) $$ end-> where-> heading = xmlBeginFunction ident (length largs) fType-> end = text "</func>"--> xmlFunctionDecl (ExternalDecl ident callConv internalName fType) =-> heading $$ external $$ end-> where-> heading = xmlBeginFunction ident (xmlFunctionArity fType) fType-> external = text ("<external>"-> ++ xmlFormat internalName-> ++ "</external>")-> end = text "</func>"--> xmlBeginFunction :: QualIdent -> Int -> Type -> Doc-> xmlBeginFunction ident n fType =-> heading $$ typeDecls-> where-> heading = xmlHeadingWithArity "func" ident n False-> typeDecls = nest level (xmlType fType)--> xmlEndFunction :: Doc-> xmlEndFunction = text "</func>"--> xmlFunctionArity :: Type -> Int-> xmlFunctionArity (TypeConstructor ident l) = 0-> xmlFunctionArity (TypeVariable n) = 0-> xmlFunctionArity (TypeArrow a b) = 1 + (xmlFunctionArity b)--> xmlRule :: [Ident] -> Expression -> Doc-> xmlRule lArgs e = text "<rule>" $$-> nest level (xmlLhs lArgs) $$-> nest level (xmlRhs lArgs e) $$-> text "</rule>"--> xmlLhs :: [Ident] -> Doc-> xmlLhs l = xmlElement "lhs" xmlVar [0..((length l)-1)]--> xmlRhs :: [Ident] -> Expression -> Doc-> xmlRhs l e = text "<rhs>" $$ nest level rhs $$ text "</rhs>"-> where-> varDicc = xmlBuildDicc l-> (rhs, _) = xmlExpr varDicc e--> -- =========================================================================--> -- =========================================================================-> -- E X P R E S S I O N S-> -- =========================================================================--> xmlExpr :: [(Int,Ident)] -> Expression -> (Doc,[(Int,Ident)])-> xmlExpr d (Literal lit) = (xmlLiteral (xmlLit lit),d)-> xmlExpr d (Variable ident) = xmlExprVar d ident-> xmlExpr d (Function ident arity) = (xmlSingleApp ident arity True,d)-> xmlExpr d (Constructor ident arity) = (xmlSingleApp ident arity False,d)-> xmlExpr d exp@(Apply e1 e2) = xmlApply d exp (xmlAppArgs exp)-> xmlExpr d (Case _ eval expr alt) = xmlCase d eval expr alt-> xmlExpr d (Or expr1 expr2) = xmlOr d expr1 expr2-> xmlExpr d (Exist ident expr) = xmlFree d ident expr-> xmlExpr d (Let binding expr) = xmlLet d binding expr-> xmlExpr d (Letrec lBinding expr) = xmlLetrec d lBinding expr-> --error "Recursive let bindings not supported in FlatCurry"--> -- =========================================================================--> xmlSingleApp :: QualIdent -> Int -> Bool -> Doc-> xmlSingleApp ident arity isFunction =-> if arity>0-> then xmlCombHeading identDoc (text "PartCall") True-> else xmlCombHeading identDoc (text totalApp) True-> where-> identDoc = xmlQualIdent ident-> totalApp = if isFunction then "FuncCall" else "ConsCall"---> xmlCombHeading :: Doc -> Doc -> Bool -> Doc-> xmlCombHeading name cType single =-> if single-> then prefix <> text " />"-> else prefix <> text ">"-> where-> prefix = text "<comb type=\""<>cType<>text "\" name=\""<>name<>text "\""--> -- =========================================================================--> xmlExprVar :: [(Int,Ident)] -> Ident -> (Doc,[(Int,Ident)])-> xmlExprVar d ident =-> if isNew-> then (xmlVar newVar, (newVar,ident):d)-> else (xmlVar var, d)-> where-> var = xmlLookUp ident d-> isNew = var == -1-> newVar = xmlNewVar d--> -- =========================================================================---> xmlApply :: [(Int,Ident)] -> Expression -> (Expression,[Expression]) ->-> (Doc,[(Int,Ident)])--> xmlApply d exp ((Function ident arity),lExp) =-> xmlApplyFunctor d ident arity lExp True--> xmlApply d exp ((Constructor ident arity),lExp) =-> xmlApplyFunctor d ident arity lExp False--> xmlApply d (Apply expr1 expr2) e' =-> (text "<apply>" $$ nest level e1 $$ nest level e2 $$ text "</apply>", d2)-> where-> (e1,d1) = xmlExpr d expr1-> (e2,d2) = xmlExpr d1 expr2--> xmlApplyFunctor ::[(Int,Ident)] -> QualIdent -> Int -> [Expression] ->-> Bool -> (Doc,[(Int,Ident)])-> xmlApplyFunctor d ident arity lArgs isFunction =-> xmlCombApply d (xmlQualIdent ident) (text cTypeS) n lArgs-> where-> n = length (lArgs)-> cTypeS = if n==arity-> then if isFunction-> then "FuncCall"-> else "ConsCall"-> else "PartCall"---> xmlCombApply :: [(Int,Ident)] -> Doc -> Doc -> Int ->-> [Expression] -> (Doc,[(Int,Ident)])-> xmlCombApply d name cType 0 lArgs =-> (xmlCombHeading name cType True,d)-> xmlCombApply d name cType n lArgs =-> (xmlCombHeading name cType False $$ xmlLines id lDocs$$ text "</comb>", d1)-> where-> (lDocs,d1) = xmlMapDicc d xmlExpr lArgs---> xmlAppArgs :: Expression -> (Expression,[Expression])-> xmlAppArgs (Apply e1 e2) = (e,lArgs++[e2])-> where-> (e,lArgs) = (xmlAppArgs e1)-> xmlAppArgs e = (e,[])-> -- =========================================================================---> -- =========================================================================--> xmlCase :: [(Int,Ident)] -> Eval -> Expression -> [Alt] -> (Doc,[(Int,Ident)])-> xmlCase d eval expr lAlt =-> (heading $$ nest level e1 $$ xmlLines id lDocs$$ end,d2)-> where-> sEval = if eval==Rigid then "\"Rigid\"" else "\"Flex\""-> heading = text "<case type=" <> text sEval <> text ">"-> end = text "</case>"-> (e1,_) = xmlExpr d expr-> (lDocs,d2) = xmlMapDicc d xmlBranch lAlt--> xmlOr :: [(Int,Ident)] -> Expression -> Expression -> (Doc,[(Int,Ident)])-> xmlOr d expr1 expr2 =-> (text "<or>" $$ nest level e1 $$ nest level e2 $$ text "</or>",d2)-> where-> (e1,d1) = xmlExpr d expr1-> (e2,d2) = xmlExpr d1 expr2---> xmlBranch :: [(Int,Ident)] -> Alt -> (Doc,[(Int,Ident)])-> xmlBranch d (Alt pattern expr) =-> (text "<branch>" $$ nest level e1 $$ nest level e2 $$ text "</branch>",d2)-> where-> (e1,d1) = xmlPattern d pattern-> (e2,d2) = xmlExpr d1 expr---> xmlPattern :: [(Int,Ident)] -> ConstrTerm -> (Doc,[(Int,Ident)])-> xmlPattern d (LiteralPattern lit) = (xmlLitPattern (xmlLit lit),d)-> xmlPattern d (ConstructorPattern ident lArgs) = xmlConsPattern d ident lArgs-> xmlPattern d (VariablePattern _) = error "Variable patterns not allowed in Flat Curry"--> xmlConsPattern :: [(Int,Ident)] -> QualIdent -> [Ident] -> (Doc,[(Int,Ident)])-> xmlConsPattern d ident lArgs =-> (heading $$ xmlLines id lDocs $$ end,d2)-> where-> heading = text "<pattern name=\""<> (xmlQualIdent ident) <>-> text "\"" <> endh-> endh = if (length lArgs)>0 then text ">" else text "/>"-> end = if (length lArgs)>0 then text "</pattern>" else empty-> (lDocs,d2) = xmlMapDicc d xmlExprVar lArgs--> -- =========================================================================---> xmlFree :: [(Int,Ident)] -> Ident -> Expression -> (Doc,[(Int,Ident)])-> xmlFree d ident exp =-> (text "<freevars>" $$ nest level v $$ nest level e $$ text "</freevars>",d2)-> where-> (v,d1) = xmlExprVar d ident-> (e,d2) = xmlExpr d1 exp---> -- =========================================================================--> xmlLet :: [(Int,Ident)] -> Binding -> Expression -> (Doc,[(Int,Ident)])-> xmlLet d binding exp =-> (text "<let>" $$ nest level b $$ nest level e $$ text "</let>", d2)-> where-> (b,d1) = xmlBinding d binding-> (e,d2) = xmlExpr d1 exp--> xmlBinding :: [(Int,Ident)] -> Binding -> (Doc,[(Int,Ident)])-> xmlBinding d (Binding ident exp) =-> (text "<binding>" $$ nest level v $$ nest level e $$ text "</binding>",d2)-> where-> (v,_) = xmlExprVar d ident-> (e,d2) = xmlExpr d exp--> -- =========================================================================--> xmlLetrec :: [(Int,Ident)] -> [Binding] -> Expression -> (Doc,[(Int,Ident)])-> xmlLetrec d lB exp =-> (text "<letrec>" $$ xmlLines id b $$ nest level e $$ text "</letrec>",d2)-> where-> (b,d1) = xmlMapDicc d xmlBinding lB-> (e,d2) = xmlExpr d1 exp--> -- =========================================================================---> -- =========================================================================-> -- A U X I L I A R Y F U N C T I O N S-> -- =========================================================================--> splitDecls :: [Decl] -> ([Decl],[Decl])-> splitDecls [] = ([],[])-> splitDecls (x:xs) = case x of-> DataDecl _ _ _ -> (functionDecl,x:typeDecl)-> NewtypeDecl _ _ _ -> (x:functionDecl,typeDecl)-> FunctionDecl _ _ _ _ -> (x:functionDecl,typeDecl)-> ExternalDecl _ _ _ _ -> (x:functionDecl,typeDecl)-> where-> (functionDecl,typeDecl) = splitDecls xs-----> xmlElement :: Eq a => String -> (a -> Doc) -> [a] -> Doc-> xmlElement name f [] = text ("<"++name++" />")-> xmlElement name f lDecls = beginElement $$ xmlLines f lDecls $$ endElement-> where-> beginElement = text ("<"++name++">")-> endElement = text ("</"++name++">")->--> xmlLines :: (a -> Doc) -> [a] -> Doc-> xmlLines f = (nest level).vcat.(map f)---> xmlMapDicc::[(Int,Ident)] -> ([(Int,Ident)] -> a -> (Doc,[(Int,Ident)])) ->-> [a] -> ([Doc],[(Int,Ident)])-> xmlMapDicc d f lArgs = foldl newArg ([],d) lArgs-> where-> newArg (l,d) e = (l++[v'],d')-> where (v',d') = f d e->---> -- The dictionary identifies var names with integers-> -- it will be ordered starting at the greatest integer-> xmlBuildDicc :: [Ident] -> [(Int,Ident)]-> xmlBuildDicc l = reverse (zip [0..((length l)-1)] l)--> -- looks for a ident in the dictorionary. If it appears returns its-> -- associated value. Otherwise, -1 is returned-> xmlLookUp :: Ident -> [(Int,Ident)] -> Int-> xmlLookUp ident [] = -1-> xmlLookUp ident ((n,name):xs) = if ident==name-> then n-> else xmlLookUp ident xs--> -- generates a integer corresponding to a new var-> xmlNewVar :: [(Int,Ident)] -> Int-> xmlNewVar [] = 0-> xmlNewVar ((n,ident):xs) = n+1--> xmlVar :: Int -> Doc-> xmlVar n = text "<var>" <> xmlInt n <> text "</var>"--> xmlLiteral :: Doc -> Doc-> xmlLiteral d = text "<lit>" $$ nest level d $$ text "</lit>"--> xmlLitPattern :: Doc -> Doc-> xmlLitPattern d = text "<lpattern>" $$ nest level d $$ text "</lpattern>"---> xmlLit :: Literal -> Doc-> xmlLit (Char _ c) = text "<charc>" <> xmlInt (fromEnum c) <> text "</charc>"-> xmlLit (Int _ n) = text "<intc>" <> xmlInteger n <> text "</intc>"-> xmlLit (Float _ n) = text "<floatc>" <> xmlFloat n <> text "</floatc>"--> xmlOperatorDecl :: CS.IDecl -> Doc-> xmlOperatorDecl (CS.IInfixDecl _ fixity prec qident) =-> text "<op fixity=\"" <> xmlFixity fixity -> <> text "\" prec=\"" <> xmlInteger prec <> text "\">"-> <> xmlIdent (unqualify qident)-> <> text "</op>"--> xmlFixity :: CS.Infix -> Doc-> xmlFixity CS.InfixL = text "InfixlOp"-> xmlFixity CS.InfixR = text "InfixrOp"-> xmlFixity CS.Infix = text "InfixOp"---> xmlTranslationDecl :: QualIdent -> Doc-> xmlTranslationDecl expId =-> text "<trans>" -> $$ nest level ( text "<name>" <> xmlIdent (unqualify expId) <> text "</name>"-> $$ text "<intname>" <> xmlQualIdent expId <> text "</intname>")-> $$ text "</trans>"---> xmlIdent :: Ident -> Doc-> xmlIdent ident = text (xmlFormat (name ident))--> xmlInt :: Int -> Doc-> xmlInt n = text (show n)--> xmlInteger :: Integer -> Doc-> xmlInteger n = text (show n)--> xmlFloat :: Double -> Doc-> xmlFloat n = text (show n)--> xmlQualIdent :: QualIdent -> Doc-> xmlQualIdent ident = text (xmlFormat (qualName ident))--> xmlModuleIdent:: ModuleIdent -> Doc-> xmlModuleIdent name = text (xmlFormat (moduleName name))--> xmlFormat :: String -> String-> xmlFormat [] = []-> xmlFormat ('>':xs) = ">"++xmlFormat xs-> xmlFormat ('<':xs) = "<"++xmlFormat xs-> xmlFormat ('&':xs) = "&"++xmlFormat xs-> xmlFormat (x:xs) = x:(xmlFormat xs)--> -- =========================================================================--> qualIDeclId :: ModuleIdent -> [QualIdent] -> CS.IDecl -> [QualIdent]-> qualIDeclId mid qids (CS.IDataDecl _ qid _ mcdecls)-> = foldl (qualConstrDeclId mid) (qid:qids) (catMaybes mcdecls)-> qualIDeclId mid qids (CS.INewtypeDecl _ qid _ ncdecl)-> = qualNewConstrDeclId mid (qid:qids) ncdecl-> qualIDeclId mid qids (CS.ITypeDecl _ qid _ _)-> = qid:qids-> qualIDeclId mid qids (CS.IFunctionDecl _ qid _ _)-> = qid:qids-> qualIDeclId mid qids _ = qids--> qualConstrDeclId :: ModuleIdent -> [QualIdent] -> CS.ConstrDecl -> -> [QualIdent]-> qualConstrDeclId mid qids (CS.ConstrDecl _ _ id _)-> = (qualifyWith mid id):qids-> qualConstrDeclId mid qids (CS.ConOpDecl _ _ _ id _)-> = (qualifyWith mid id):qids--> qualNewConstrDeclId :: ModuleIdent -> [QualIdent] -> CS.NewConstrDecl -> -> [QualIdent]-> qualNewConstrDeclId mid qids (CS.NewConstrDecl _ _ id _)-> = (qualifyWith mid id):qids---\end{verbatim}
+ src/Imports.hs view
@@ -0,0 +1,402 @@+{- |+ Module : $Header$+ Description : Importing interface declarations+ Copyright : (c) 2000 - 2003 Wolfgang Lux+ 2011 Björn Peemöller+ 2016 Jan Tikovsky+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module provides the function 'importModules' to bring the imported+ entities into the module's scope, and the function 'qualifyEnv' to+ qualify the environment prior to computing the export interface.+-}+module Imports (importInterfaces, importModules, qualifyEnv) where++import Data.List (nubBy, find)+import qualified Data.Map as Map+import Data.Maybe (catMaybes, fromMaybe, isJust)+import qualified Data.Set as Set++import Curry.Base.Ident+import Curry.Base.SpanInfo+import Curry.Base.Monad+import Curry.Syntax++import Base.CurryKinds (toKind')+import Base.CurryTypes ( toQualType, toQualTypes, toQualPredType, toConstrType+ , toMethodType )++import Base.Kinds+import Base.Messages+import Base.TopEnv+import Base.Types+import Base.TypeSubst++import Env.Class+import Env.Instance+import Env.Interface+import Env.ModuleAlias (importAliases, initAliasEnv)+import Env.OpPrec+import Env.TypeConstructor+import Env.Value++import CompilerEnv++importModules :: Monad m => Module a -> InterfaceEnv -> [ImportDecl]+ -> CYT m CompilerEnv+importModules mdl@(Module _ _ _ mid _ _ _) iEnv expImps+ = ok $ foldl importModule initEnv expImps+ where+ initEnv = (initCompilerEnv mid)+ { aliasEnv = importAliases expImps -- import module aliases+ , interfaceEnv = iEnv -- imported interfaces+ , extensions = knownExtensions mdl+ }+ importModule env (ImportDecl _ m q asM is) =+ case Map.lookup m iEnv of+ Just intf -> importInterface (fromMaybe m asM) q is intf env+ Nothing -> internalError $ "Imports.importModules: no interface for "+ ++ show m++-- |The function 'importInterfaces' brings the declarations of all+-- imported interfaces into scope for the current 'Interface'.+importInterfaces :: Interface -> InterfaceEnv -> CompilerEnv+importInterfaces (Interface m is _) iEnv+ = importUnifyData $ foldl importModule initEnv is+ where+ initEnv = (initCompilerEnv m) { aliasEnv = initAliasEnv, interfaceEnv = iEnv }+ importModule env (IImportDecl _ i) = case Map.lookup i iEnv of+ Just intf -> importInterfaceIntf intf env+ Nothing -> internalError $ "Imports.importInterfaces: no interface for "+ ++ show m++-- ---------------------------------------------------------------------------+-- Importing an interface into the module+-- ---------------------------------------------------------------------------++-- Four kinds of environments are computed from the interface:+--+-- 1. The operator precedences+-- 2. The type constructors+-- 3. The types of the data constructors and functions (values)+-- 4. The instances+--+-- Note that the original names of all entities defined in the imported module+-- are qualified appropriately. The same is true for type expressions.++-- When an interface is imported, the compiler first transforms the+-- interface into these environments. If an import specification is+-- present, the environments are restricted to only those entities which+-- are included in the specification or not hidden by it, respectively.+-- The resulting environments are then imported into the current module+-- using either a qualified import (if the module is imported qualified)+-- or both a qualified and an unqualified import (non-qualified import).+-- Regardless of the type of import, all instance declarations are always+-- imported into the current module.++importInterface :: ModuleIdent -> Bool -> Maybe ImportSpec -> Interface+ -> CompilerEnv -> CompilerEnv+importInterface m q is (Interface mid _ ds) env = env'+ where+ env' = env+ { opPrecEnv = importEntities (precs mid) m q vs id ds $ opPrecEnv env+ , tyConsEnv = importEntities (types mid) m q ts (importData vs) ds $ tyConsEnv env+ , valueEnv = importEntities (values mid) m q vs id ds $ valueEnv env+ , classEnv = importClasses mid ds $ classEnv env+ , instEnv = importInstances mid ds $ instEnv env+ }+ ts = isVisible addType is+ vs = isVisible addValue is++addType :: Import -> [Ident] -> [Ident]+addType (Import _ _) tcs = tcs+addType (ImportTypeWith _ tc _) tcs = tc : tcs+addType (ImportTypeAll _ _) _ = internalError "Imports.addType"++addValue :: Import -> [Ident] -> [Ident]+addValue (Import _ f) fs = f : fs+addValue (ImportTypeWith _ _ cs) fs = cs ++ fs+addValue (ImportTypeAll _ _) _ = internalError "Imports.addValue"++isVisible :: (Import -> [Ident] -> [Ident]) -> Maybe ImportSpec+ -> Ident -> Bool+isVisible _ Nothing = const True+isVisible add (Just (Importing _ xs)) = (`Set.member` Set.fromList (foldr add [] xs))+isVisible add (Just (Hiding _ xs)) = (`Set.notMember` Set.fromList (foldr add [] xs))++importEntities :: Entity a => (IDecl -> [a]) -> ModuleIdent -> Bool+ -> (Ident -> Bool) -> (a -> a) -> [IDecl] -> TopEnv a -> TopEnv a+importEntities ents m q isVisible' f ds env =+ foldr (uncurry (if q then qualImportTopEnv m else importUnqual m)) env+ [ (x, f y) | y <- concatMap ents ds+ , let x = unqualify (origName y), isVisible' x+ ]+ where importUnqual m' x y = importTopEnv m' x y . qualImportTopEnv m' x y++importData :: (Ident -> Bool) -> TypeInfo -> TypeInfo+importData isVisible' (DataType tc k cs) =+ DataType tc k $ catMaybes $ map (importConstr isVisible') cs+importData isVisible' (RenamingType tc k nc) =+ maybe (DataType tc k []) (RenamingType tc k) (importConstr isVisible' nc)+importData _ (AliasType tc k n ty) = AliasType tc k n ty+importData isVisible' (TypeClass qcls k ms) =+ TypeClass qcls k $ catMaybes $ map (importMethod isVisible') ms+importData _ (TypeVar _) = internalError "Imports.importData: type variable"++importConstr :: (Ident -> Bool) -> DataConstr -> Maybe DataConstr+importConstr isVisible' dc+ | isVisible' (constrIdent dc) = Just dc+ | otherwise = Nothing++importMethod :: (Ident -> Bool) -> ClassMethod -> Maybe ClassMethod+importMethod isVisible' mthd+ | isVisible' (methodName mthd) = Just mthd+ | otherwise = Nothing++importClasses :: ModuleIdent -> [IDecl] -> ClassEnv -> ClassEnv+importClasses m = flip $ foldr (bindClass m)++bindClass :: ModuleIdent -> IDecl -> ClassEnv -> ClassEnv+bindClass m (HidingClassDecl p cx cls k tv) =+ bindClass m (IClassDecl p cx cls k tv [] [])+bindClass m (IClassDecl _ cx cls _ _ ds ids) =+ bindClassInfo (qualQualify m cls) (sclss, ms)+ where sclss = map (\(Constraint _ scls _) -> qualQualify m scls) cx+ ms = map (\d -> (imethod d, isJust $ imethodArity d)) $ filter isVis ds+ isVis (IMethodDecl _ idt _ _ ) = idt `notElem` ids+bindClass _ _ = id++importInstances :: ModuleIdent -> [IDecl] -> InstEnv -> InstEnv+importInstances m = flip $ foldr (bindInstance m)++bindInstance :: ModuleIdent -> IDecl -> InstEnv -> InstEnv+bindInstance m (IInstanceDecl _ cx qcls ty is mm) = bindInstInfo+ (qualQualify m qcls, qualifyTC m $ typeConstr ty) (fromMaybe m mm, ps, is)+ where PredType ps _ = toQualPredType m [] $ QualTypeExpr NoSpanInfo cx ty+bindInstance _ _ = id++-- ---------------------------------------------------------------------------+-- Building the initial environment+-- ---------------------------------------------------------------------------++-- In a first step, the four export environments are initialized from+-- the interface's declarations.++-- operator precedences+precs :: ModuleIdent -> IDecl -> [PrecInfo]+precs m (IInfixDecl _ fix prec op) = [PrecInfo (qualQualify m op) (OpPrec fix prec)]+precs _ _ = []++hiddenTypes :: ModuleIdent -> IDecl -> [TypeInfo]+hiddenTypes m (HidingDataDecl _ tc k tvs) = [typeCon DataType m tc k tvs []]+hiddenTypes m (HidingClassDecl _ _ qcls k _) = [typeCls m qcls k []]+hiddenTypes m d = types m d++-- type constructors and type classes+types :: ModuleIdent -> IDecl -> [TypeInfo]+types m (IDataDecl _ tc k tvs cs _) =+ [typeCon DataType m tc k tvs (map mkData cs)]+ where+ mkData (ConstrDecl _ c tys) =+ DataConstr c (toQualTypes m tvs tys)+ mkData (ConOpDecl _ ty1 c ty2) =+ DataConstr c (toQualTypes m tvs [ty1, ty2])+ mkData (RecordDecl _ c fs) =+ RecordConstr c labels (toQualTypes m tvs tys)+ where (labels, tys) = unzip [(l, ty) | FieldDecl _ ls ty <- fs, l <- ls]+types m (INewtypeDecl _ tc k tvs nc _) =+ [typeCon RenamingType m tc k tvs (mkData nc)]+ where+ mkData (NewConstrDecl _ c ty) =+ DataConstr c [toQualType m tvs ty]+ mkData (NewRecordDecl _ c (l, ty)) =+ RecordConstr c [l] [toQualType m tvs ty]+types m (ITypeDecl _ tc k tvs ty) =+ [typeCon aliasType m tc k tvs (toQualType m tvs ty)]+ where+ aliasType tc' k' = AliasType tc' k' (length tvs)+types m (IClassDecl _ _ qcls k tv ds ids) =+ [typeCls m qcls k (map mkMethod $ filter isVis ds)]+ where+ isVis (IMethodDecl _ f _ _ ) = f `notElem` ids+ mkMethod (IMethodDecl _ f a qty) = ClassMethod f a $+ qualifyPredType m $ normalize 1 $ toMethodType qcls tv qty+types _ _ = []++-- type constructors+typeCon :: (QualIdent -> Kind -> a) -> ModuleIdent -> QualIdent+ -> Maybe KindExpr -> [Ident] -> a+typeCon f m tc k tvs = f (qualQualify m tc) (toKind' k (length tvs))++-- type classes+typeCls :: ModuleIdent -> QualIdent -> Maybe KindExpr -> [ClassMethod]+ -> TypeInfo+typeCls m qcls k ms = TypeClass (qualQualify m qcls) (toKind' k 0) ms++-- data constructors, record labels, functions and class methods+values :: ModuleIdent -> IDecl -> [ValueInfo]+values m (IDataDecl _ tc _ tvs cs hs) =+ map (dataConstr m tc' tvs)+ (filter ((\con -> con `notElem` hs || isHiddenButNeeded con)+ . constrId) cs) +++ map (recLabel m tc' tvs ty') (nubBy sameLabel clabels)+ where tc' = qualQualify m tc+ ty' = constrType tc' tvs+ labels = [ (l, lty) | RecordDecl _ _ fs <- cs+ , FieldDecl _ ls lty <- fs, l <- ls, l `notElem` hs+ ]+ clabels = [(l, constr l, ty) | (l, ty) <- labels]+ constr l = [constrId c | c <- cs, l `elem` recordLabels c]+ -- hidden constructors needed for record updates with visible labels+ hiddenCs = [c | (l, _) <- labels, c <- constr l, c `elem` hs]+ isHiddenButNeeded = flip elem hiddenCs+ sameLabel (l1,_,_) (l2,_,_) = l1 == l2+values m (INewtypeDecl _ tc _ tvs nc hs) =+ map (newConstr m tc' tvs) [nc | nconstrId nc `notElem` hs] +++ case nc of+ NewConstrDecl _ _ _ -> []+ NewRecordDecl _ c (l, lty) ->+ [recLabel m tc' tvs ty' (l, [c], lty) | l `notElem` hs]+ where tc' = qualQualify m tc+ ty' = constrType tc' tvs+values m (IFunctionDecl _ f Nothing a qty) =+ [Value (qualQualify m f) Nothing a (typeScheme (toQualPredType m [] qty))]+values m (IFunctionDecl _ f (Just tv) _ qty) =+ let mcls = case qty of+ QualTypeExpr _ ctx _ -> fmap (\(Constraint _ qcls _) -> qcls) $+ find (\(Constraint _ _ ty) -> isVar ty) ctx+ in [Value (qualQualify m f) mcls 0 (typeScheme (toQualPredType m [tv] qty))]+ where+ isVar (VariableType _ i) = i == tv+ isVar _ = False+values m (IClassDecl _ _ qcls _ tv ds hs) =+ map (classMethod m qcls' tv hs) ds+ where qcls' = qualQualify m qcls+values _ _ = []++dataConstr :: ModuleIdent -> QualIdent -> [Ident] -> ConstrDecl -> ValueInfo+dataConstr m tc tvs (ConstrDecl _ c tys) =+ DataConstructor (qualifyLike tc c) a labels $+ constrType' m tc tvs tys+ where a = length tys+ labels = replicate a anonId+dataConstr m tc tvs (ConOpDecl _ ty1 op ty2) =+ DataConstructor (qualifyLike tc op) 2 [anonId, anonId] $+ constrType' m tc tvs [ty1, ty2]+dataConstr m tc tvs (RecordDecl _ c fs) =+ DataConstructor (qualifyLike tc c) a labels $+ constrType' m tc tvs tys+ where fields = [(l, ty) | FieldDecl _ ls ty <- fs, l <- ls]+ (labels, tys) = unzip fields+ a = length labels++newConstr :: ModuleIdent -> QualIdent -> [Ident] -> NewConstrDecl -> ValueInfo+newConstr m tc tvs (NewConstrDecl _ c ty1) =+ NewtypeConstructor (qualifyLike tc c) anonId $+ constrType' m tc tvs [ty1]+newConstr m tc tvs (NewRecordDecl _ c (l, ty1)) =+ NewtypeConstructor (qualifyLike tc c) l $+ constrType' m tc tvs [ty1]++recLabel :: ModuleIdent -> QualIdent -> [Ident] -> TypeExpr+ -> (Ident, [Ident], TypeExpr) -> ValueInfo+recLabel m tc tvs ty0 (l, cs, lty) = Label ql qcs tySc+ where ql = qualifyLike tc l+ qcs = map (qualifyLike tc) cs+ tySc = polyType (toQualType m tvs (ArrowType NoSpanInfo ty0 lty))++constrType' :: ModuleIdent -> QualIdent -> [Ident] -> [TypeExpr] -> TypeScheme+constrType' m tc tvs tys = ForAll (length tvs) pty+ where pty = qualifyPredType m $ toConstrType tc tvs tys++constrType :: QualIdent -> [Ident] -> TypeExpr+constrType tc tvs = foldl (ApplyType NoSpanInfo) (ConstructorType NoSpanInfo tc)+ $ map (VariableType NoSpanInfo) tvs++-- We always enter class methods with an arity of 0 into the value environment+-- because there may be different implementations with different arities.++classMethod :: ModuleIdent -> QualIdent -> Ident -> [Ident] -> IMethodDecl+ -> ValueInfo+classMethod m qcls tv hs (IMethodDecl _ f _ qty) =+ Value (qualifyLike qcls f) mcls 0 $+ typeScheme $ qualifyPredType m $ toMethodType qcls tv qty+ where+ mcls = if f `elem` hs then Nothing else Just qcls++-- ---------------------------------------------------------------------------++-- After all modules have been imported, the compiler has to ensure that+-- all references to a data type use the same list of constructors.++importUnifyData :: CompilerEnv -> CompilerEnv+importUnifyData cEnv = cEnv { tyConsEnv = importUnifyData' $ tyConsEnv cEnv }++importUnifyData' :: TCEnv -> TCEnv+importUnifyData' tcEnv = fmap (setInfo allTyCons) tcEnv+ where+ setInfo tcs t = case Map.lookup (origName t) tcs of+ Nothing -> error "Imports.importUnifyData'"+ Just ty -> ty+ allTyCons = foldr (mergeData . snd) Map.empty $ allImports tcEnv+ mergeData t tcs =+ Map.insert tc (maybe t (sureMerge t) $ Map.lookup tc tcs) tcs+ where tc = origName t+ sureMerge x y = case merge x y of+ Nothing -> error "Imports.importUnifyData'.sureMerge"+ Just z -> z++-- ---------------------------------------------------------------------------++-- |+qualifyEnv :: CompilerEnv -> CompilerEnv+qualifyEnv env = qualifyLocal env+ $ foldl (flip importInterfaceIntf) initEnv+ $ Map.elems+ $ interfaceEnv env+ where initEnv = initCompilerEnv $ moduleIdent env++qualifyLocal :: CompilerEnv -> CompilerEnv -> CompilerEnv+qualifyLocal currentEnv initEnv = currentEnv+ { opPrecEnv = foldr bindQual pEnv $ localBindings $ opPrecEnv currentEnv+ , tyConsEnv = foldr bindQual tcEnv $ localBindings $ tyConsEnv currentEnv+ , valueEnv = foldr bindGlobal tyEnv $ localBindings $ valueEnv currentEnv+ , classEnv = Map.unionWith mergeClassInfo clsEnv $ classEnv currentEnv+ , instEnv = Map.union iEnv $ instEnv currentEnv+ }+ where+ pEnv = opPrecEnv initEnv+ tcEnv = tyConsEnv initEnv+ tyEnv = valueEnv initEnv+ clsEnv = classEnv initEnv+ iEnv = instEnv initEnv+ bindQual (_, y) = qualBindTopEnv (origName y) y+ bindGlobal (x, y)+ | hasGlobalScope x = bindQual (x, y)+ | otherwise = bindTopEnv x y++-- Importing an interface into another interface is somewhat simpler+-- because all entities are imported into the environment. In addition,+-- only a qualified import is necessary. Note that the hidden data types+-- are imported as well because they may be used in type expressions in+-- an interface.++importInterfaceIntf :: Interface -> CompilerEnv -> CompilerEnv+importInterfaceIntf (Interface m _ ds) env = env+ { opPrecEnv = importEntitiesIntf m (precs m) ds $ opPrecEnv env+ , tyConsEnv = importEntitiesIntf m (hiddenTypes m) ds $ tyConsEnv env+ , valueEnv = importEntitiesIntf m (values m) ds $ valueEnv env+ , classEnv = importClasses m ds $ classEnv env+ , instEnv = importInstances m ds $ instEnv env+ }++importEntitiesIntf :: Entity a => ModuleIdent -> (IDecl -> [a]) -> [IDecl]+ -> TopEnv a -> TopEnv a+importEntitiesIntf m ents ds env = foldr importEntity env (concatMap ents ds)+ where importEntity x = qualImportTopEnv (fromMaybe m (qidModule (origName x)))+ (unqualify (origName x)) x
− src/Imports.lhs
@@ -1,379 +0,0 @@--% $Id: Imports.lhs,v 1.25 2004/02/13 19:24:00 wlux Exp $-%-% Copyright (c) 2000-2003, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{Imports.lhs}-\section{Importing interfaces}-This module provides a few functions which can be used to import-interfaces into the current module.-\begin{verbatim}--> module Imports(importInterface,importInterfaceIntf,importUnifyData) where--> import Data.Maybe-> import qualified Data.Set as Set-> import qualified Data.Map as Map--> import Curry.Syntax-> import Types-> import Curry.Base.Position-> import Curry.Base.Ident-> import Base-> import TopEnv---\end{verbatim}-Four kinds of environments are computed from the interface, one-containing the operator precedences, another for the type-constructors, the third containing the types of the data-constructors and functions, and the last contains the arity for each-function and constructor. Note that the original names of all-entities defined in the imported module are qualified appropriately.-The same is true for type expressions.-\begin{verbatim}--> type ExpPEnv = Map.Map Ident PrecInfo-> type ExpTCEnv = Map.Map Ident TypeInfo-> type ExpValueEnv = Map.Map Ident ValueInfo-> type ExpArityEnv = Map.Map Ident ArityInfo--\end{verbatim}-When an interface is imported, the compiler first transforms the-interface into these environments. If an import specification is-present, the environments are restricted to only those entities which-are included in the specification or not hidden by it, respectively.-The resulting environments are then imported into the current module-using either a qualified import or both a qualified and an unqualified-import.-\begin{verbatim}--> importInterface :: Position -> ModuleIdent -> Bool -> Maybe ImportSpec-> -> Interface -> PEnv -> TCEnv -> ValueEnv -> ArityEnv-> -> (PEnv,TCEnv,ValueEnv,ArityEnv)-> importInterface p m q is i pEnv tcEnv tyEnv aEnv =-> (importEntities m q vs id mPEnv pEnv,-> importEntities m q ts (importData vs) mTCEnv tcEnv,-> importEntities m q vs id mTyEnv tyEnv,-> importEntities m q as id mAEnv aEnv)-> where mPEnv = intfEnv bindPrec i-> mTCEnv = intfEnv bindTC i-> mTyEnv = intfEnv bindTy i-> mAEnv = intfEnv bindA i-> is' = maybe [] (expandSpecs m mTCEnv mTyEnv) is-> ts = isVisible is (Set.fromList (foldr addType [] is'))-> vs = isVisible is (Set.fromList (foldr addValue [] is'))-> as = isVisible is (Set.fromList (foldr addArity [] is'))--> isVisible :: Maybe ImportSpec -> Set.Set Ident -> Ident -> Bool-> isVisible (Just (Importing _ _)) xs = (`Set.member` xs)-> isVisible (Just (Hiding _ _)) xs = (`Set.notMember` xs)-> isVisible _ _ = const True--> importEntities :: Entity a => ModuleIdent -> Bool -> (Ident -> Bool)-> -> (a -> a) -> Map.Map Ident a -> TopEnv a -> TopEnv a-> importEntities m q isVisible f mEnv env =-> foldr (uncurry (if q then qualImportTopEnv m else importUnqual m)) env-> [(x,f y) | (x,y) <- Map.toList mEnv, isVisible x]-> where importUnqual m x y = importTopEnv m x y . qualImportTopEnv m x y--> importData :: (Ident -> Bool) -> TypeInfo -> TypeInfo-> importData isVisible (DataType tc n cs) =-> DataType tc n (map (>>= importConstr isVisible) cs)-> importData isVisible (RenamingType tc n nc) =-> maybe (DataType tc n []) (RenamingType tc n) (importConstr isVisible nc)-> importData isVisible (AliasType tc n ty) = AliasType tc n ty--> importConstr :: (Ident -> Bool) -> Data a -> Maybe (Data a)-> importConstr isVisible (Data c n tys)-> | isVisible c = Just (Data c n tys)-> | otherwise = Nothing--\end{verbatim}-Importing an interface into another interface is somewhat simpler-because all entities are imported into the environment. In addition,-only a qualified import is necessary. Note that the hidden data types-are imported as well because they may be used in type expressions in-an interface.-\begin{verbatim}--> importInterfaceIntf :: Interface -> PEnv -> TCEnv -> ValueEnv -> ArityEnv-> -> (PEnv,TCEnv,ValueEnv,ArityEnv)-> importInterfaceIntf i pEnv tcEnv tyEnv aEnv =-> (importEntities m True (const True) id (intfEnv bindPrec i) pEnv,-> importEntities m True (const True) id (intfEnv bindTCHidden i) tcEnv,-> importEntities m True (const True) id (intfEnv bindTy i) tyEnv,-> importEntities m True (const True) id (intfEnv bindA i) aEnv)-> where Interface m _ = i--\end{verbatim}-In a first step, the three export environments are initialized from-the interface's declarations. This step also qualifies the names of-all entities defined in (but not imported into) the interface with its-module name. -\begin{verbatim}--> intfEnv :: (ModuleIdent -> IDecl -> Map.Map Ident a -> Map.Map Ident a)-> -> Interface -> Map.Map Ident a-> intfEnv bind (Interface m ds) = foldr (bind m) Map.empty ds--> bindPrec :: ModuleIdent -> IDecl -> ExpPEnv -> ExpPEnv-> bindPrec m (IInfixDecl _ fix p op) =-> Map.insert (unqualify op) (PrecInfo (qualQualify m op) (OpPrec fix p))-> bindPrec _ _ = id--> bindTC :: ModuleIdent -> IDecl -> ExpTCEnv -> ExpTCEnv-> bindTC m (IDataDecl _ tc tvs cs) mTCEnv -> | isJust (Map.lookup (unqualify tc) mTCEnv) =-> mTCEnv-> | otherwise =-> bindType DataType m tc tvs (map (fmap mkData) cs) mTCEnv-> where mkData (ConstrDecl _ evs c tys) =-> Data c (length evs) (toQualTypes m tvs tys)-> mkData (ConOpDecl _ evs ty1 c ty2) =-> Data c (length evs) (toQualTypes m tvs [ty1,ty2])-> bindTC m (INewtypeDecl _ tc tvs (NewConstrDecl _ evs c ty)) mTCEnv =-> bindType RenamingType m tc tvs -> (Data c (length evs) (toQualType m tvs ty)) mTCEnv-> bindTC m (ITypeDecl _ tc tvs ty) mTCEnv-> | isRecordExtId tc' = -> bindType AliasType m (qualify (fromRecordExtId tc')) tvs -> (toQualType m tvs ty) mTCEnv-> | otherwise =-> bindType AliasType m tc tvs (toQualType m tvs ty) mTCEnv-> where tc' = unqualify tc-> bindTC m _ mTCEnv = mTCEnv--> bindTCHidden :: ModuleIdent -> IDecl -> ExpTCEnv -> ExpTCEnv-> bindTCHidden m (HidingDataDecl _ tc tvs) =-> bindType DataType m (qualify tc) tvs []-> bindTCHidden m d = bindTC m d--> bindType :: (QualIdent -> Int -> a -> TypeInfo) -> ModuleIdent -> QualIdent-> -> [Ident] -> a -> ExpTCEnv -> ExpTCEnv-> bindType f m tc tvs =-> Map.insert (unqualify tc) . f (qualQualify m tc) (length tvs) --> bindTy :: ModuleIdent -> IDecl -> ExpValueEnv -> ExpValueEnv-> bindTy m (IDataDecl _ tc tvs cs) =-> flip (foldr (bindConstr m tc' tvs (constrType tc' tvs))) (catMaybes cs)-> where tc' = qualQualify m tc-> bindTy m (INewtypeDecl _ tc tvs nc) =-> bindNewConstr m tc' tvs (constrType tc' tvs) nc-> where tc' = qualQualify m tc-> --bindTy m (ITypeDecl _ r tvs (RecordType fs _)) =-> -- flip (foldr (bindRecLabel m r')) fs-> -- where r' = qualifyWith m (fromRecordExtId (unqualify r))-> bindTy m (IFunctionDecl _ f _ ty) =-> Map.insert (unqualify f)-> (Value (qualQualify m f) (polyType (toQualType m [] ty)))-> bindTy m _ = id--> bindConstr :: ModuleIdent -> QualIdent -> [Ident] -> TypeExpr -> ConstrDecl-> -> ExpValueEnv -> ExpValueEnv-> bindConstr m tc tvs ty0 (ConstrDecl _ evs c tys) =-> bindValue DataConstructor m tc tvs c evs (foldr ArrowType ty0 tys)-> bindConstr m tc tvs ty0 (ConOpDecl _ evs ty1 op ty2) =-> bindValue DataConstructor m tc tvs op evs-> (ArrowType ty1 (ArrowType ty2 ty0))--> bindNewConstr :: ModuleIdent -> QualIdent -> [Ident] -> TypeExpr-> -> NewConstrDecl -> ExpValueEnv -> ExpValueEnv-> bindNewConstr m tc tvs ty0 (NewConstrDecl _ evs c ty1) =-> bindValue NewtypeConstructor m tc tvs c evs (ArrowType ty1 ty0)--> --bindRecLabel :: ModuleIdent -> QualIdent -> ([Ident],TypeExpr)-> -- -> ExpValueEnv -> ExpValueEnv-> --bindRecLabel m r ([l],ty) =-> -- Map.insert l (Label (qualify l) r (polyType (toQualType m [] ty)))--> bindValue :: (QualIdent -> ExistTypeScheme -> ValueInfo) -> ModuleIdent-> -> QualIdent -> [Ident] -> Ident -> [Ident] -> TypeExpr-> -> ExpValueEnv -> ExpValueEnv-> bindValue f m tc tvs c evs ty = Map.insert c (f (qualifyLike tc c) sigma)-> where sigma = ForAllExist (length tvs) (length evs) (toQualType m tvs ty)-> qualifyLike x = maybe qualify qualifyWith (qualidMod x)--> bindA :: ModuleIdent -> IDecl -> ExpArityEnv -> ExpArityEnv-> bindA m (IDataDecl _ _ _ cs) expAEnv-> = foldr (bindConstrA m) expAEnv (catMaybes cs)-> bindA m (IFunctionDecl _ f a _) expAEnv-> = Map.insert (unqualify f) (ArityInfo (qualQualify m f) a) expAEnv-> bindA _ _ expAEnv = expAEnv--> bindConstrA :: ModuleIdent -> ConstrDecl -> ExpArityEnv -> ExpArityEnv-> bindConstrA m (ConstrDecl _ _ c tys) expAEnv-> = Map.insert c (ArityInfo (qualifyWith m c) (length tys)) expAEnv-> bindConstrA m (ConOpDecl _ _ _ c _) expAEnv-> = Map.insert c (ArityInfo (qualifyWith m c) 2) expAEnv--\end{verbatim}-After the environments have been initialized, the optional import-specifications can be checked. There are two kinds of import-specifications, a ``normal'' one, which names the entities that shall-be imported, and a hiding specification, which lists those entities-that shall not be imported.--There is a subtle difference between both kinds of-specifications. While it is not allowed to list a data constructor-outside of its type in a ``normal'' specification, it is allowed to-hide a data constructor explicitly. E.g., if module \texttt{A} exports-the data type \texttt{T} with constructor \texttt{C}, the data-constructor can be imported with one of the two specifications-\begin{verbatim}-import A(T(C))-import A(T(..))-\end{verbatim}-but can be hidden in three different ways:-\begin{verbatim}-import A hiding(C)-import A hiding(T(C))-import A hiding(T(..))-\end{verbatim}--The functions \texttt{expandImport} and \texttt{expandHiding} check-that all entities in an import specification are actually exported-from the module. In addition, all imports of type constructors are-changed into a \texttt{T()} specification and explicit imports for the-data constructors are added.-\begin{verbatim}--> expandSpecs :: ModuleIdent -> ExpTCEnv -> ExpValueEnv -> ImportSpec-> -> [Import]-> expandSpecs m tcEnv tyEnv (Importing _ is) =-> concat (map (expandImport m tcEnv tyEnv) is)-> expandSpecs m tcEnv tyEnv (Hiding _ is) =-> concat (map (expandHiding m tcEnv tyEnv) is)--> expandImport :: ModuleIdent -> ExpTCEnv -> ExpValueEnv -> Import-> -> [Import]-> expandImport m tcEnv tyEnv (Import x) = expandThing m tcEnv tyEnv x-> expandImport m tcEnv tyEnv (ImportTypeWith tc cs) =-> [expandTypeWith m tcEnv tc cs]-> expandImport m tcEnv tyEnv (ImportTypeAll tc) =-> [expandTypeAll m tcEnv tc]--> expandHiding :: ModuleIdent -> ExpTCEnv -> ExpValueEnv -> Import-> -> [Import]-> expandHiding m tcEnv tyEnv (Import x) = expandHide m tcEnv tyEnv x-> expandHiding m tcEnv tyEnv (ImportTypeWith tc cs) =-> [expandTypeWith m tcEnv tc cs]-> expandHiding m tcEnv tyEnv (ImportTypeAll tc) =-> [expandTypeAll m tcEnv tc]--> expandThing :: ModuleIdent -> ExpTCEnv -> ExpValueEnv -> Ident-> -> [Import]-> expandThing m tcEnv tyEnv tc =-> case Map.lookup tc tcEnv of-> Just _ -> expandThing' m tyEnv tc (Just [ImportTypeWith tc []])-> Nothing -> expandThing' m tyEnv tc Nothing--> expandThing' :: ModuleIdent -> ExpValueEnv -> Ident-> -> Maybe [Import] -> [Import]-> expandThing' m tyEnv f tcImport =-> case Map.lookup f tyEnv of-> Just v-> | isConstr v -> maybe (errorAt' (importDataConstr m f)) id tcImport-> | otherwise -> Import f : maybe [] id tcImport-> Nothing -> maybe (errorAt' (undefinedEntity m f)) id tcImport-> where isConstr (DataConstructor _ _) = True-> isConstr (NewtypeConstructor _ _) = True-> isConstr (Value _ _) = False--> expandHide :: ModuleIdent -> ExpTCEnv -> ExpValueEnv -> Ident-> -> [Import]-> expandHide m tcEnv tyEnv tc =-> case Map.lookup tc tcEnv of-> Just _ -> expandHide' m tyEnv tc (Just [ImportTypeWith tc []])-> Nothing -> expandHide' m tyEnv tc Nothing--> expandHide' :: ModuleIdent -> ExpValueEnv -> Ident-> -> Maybe [Import] -> [Import]-> expandHide' m tyEnv f tcImport =-> case Map.lookup f tyEnv of-> Just _ -> Import f : maybe [] id tcImport-> Nothing -> maybe (errorAt' (undefinedEntity m f)) id tcImport--> expandTypeWith :: ModuleIdent -> ExpTCEnv -> Ident -> [Ident]-> -> Import-> expandTypeWith m tcEnv tc cs =-> case Map.lookup tc tcEnv of-> Just (DataType _ _ cs') ->-> ImportTypeWith tc (map (checkConstr [c | Just (Data c _ _) <- cs']) cs)-> Just (RenamingType _ _ (Data c _ _)) ->-> ImportTypeWith tc (map (checkConstr [c]) cs)-> Just _ -> errorAt' (nonDataType m tc)-> Nothing -> errorAt' (undefinedEntity m tc)-> where checkConstr cs c-> | c `elem` cs = c-> | otherwise = errorAt' (undefinedDataConstr m tc c)--> expandTypeAll :: ModuleIdent -> ExpTCEnv -> Ident -> Import-> expandTypeAll m tcEnv tc =-> case Map.lookup tc tcEnv of-> Just (DataType _ _ cs) -> ImportTypeWith tc [c | Just (Data c _ _) <- cs]-> Just (RenamingType _ _ (Data c _ _)) -> ImportTypeWith tc [c]-> Just _ -> errorAt' (nonDataType m tc)-> Nothing -> errorAt' (undefinedEntity m tc)--\end{verbatim}-After all modules have been imported, the compiler has to ensure that-all references to a data type use the same list of constructors.-\begin{verbatim}--> importUnifyData :: TCEnv -> TCEnv-> importUnifyData tcEnv =-> fmap (setInfo (foldr (mergeData . snd) Map.empty (allImports tcEnv))) tcEnv-> where setInfo tcs t = fromJust (Map.lookup (origName t) tcs)-> mergeData t tcs =-> Map.insert tc (maybe t (fromJust . merge t) (Map.lookup tc tcs)) tcs-> where tc = origName t--\end{verbatim}-Auxiliary functions:-\begin{verbatim}--> addType :: Import -> [Ident] -> [Ident]-> addType (Import _) tcs = tcs-> addType (ImportTypeWith tc _) tcs = tc : tcs-> addType (ImportTypeAll _) _ = internalError "types"--> addValue :: Import -> [Ident] -> [Ident]-> addValue (Import f) fs = f : fs-> addValue (ImportTypeWith _ cs) fs = cs ++ fs-> addValue (ImportTypeAll _) _ = internalError "values"--> addArity :: Import -> [Ident] -> [Ident]-> addArity (Import f) ids = f:ids-> addArity (ImportTypeWith _ cs) ids = cs ++ ids-> addArity (ImportTypeAll _) _ = internalError "arities"--> constrType :: QualIdent -> [Ident] -> TypeExpr-> constrType tc tvs = ConstructorType tc (map VariableType tvs)--\end{verbatim}-Error messages:-\begin{verbatim}--> undefinedEntity :: ModuleIdent -> Ident -> (Position,String)-> undefinedEntity m x =-> (positionOfIdent x,-> "Module " ++ moduleName m ++ " does not export " ++ name x)--> undefinedDataConstr :: ModuleIdent -> Ident -> Ident -> (Position,String)-> undefinedDataConstr m tc c =-> (positionOfIdent c, -> name c ++ " is not a data constructor of type " ++ name tc)--> nonDataType :: ModuleIdent -> Ident -> (Position,String)-> nonDataType m tc = -> (positionOfIdent tc,-> name tc ++ " is not a data type")--> importDataConstr :: ModuleIdent -> Ident -> (Position,String)-> importDataConstr m c = -> (positionOfIdent c,-> "Explicit import for data constructor " ++ name c)--\end{verbatim}
− src/InterfaceCheck.hs
@@ -1,142 +0,0 @@---------------------------------------------------------------------------------------------------------------------------------------------------------------------- InterfaceCheck - Checks the equality of the interfaces of two FlatCurry --- programs ------ January 2006,--- Martin Engelke (men@informatik.uni-kiel.de)----module InterfaceCheck where--import Data.List--import Curry.ExtendedFlat.Type--------------------------------------------------------------------------------------- Checks whether the interfaces of two FlatCurry programs are equal -interfaceCheck :: Prog -> Prog -> Bool-interfaceCheck (Prog m1 is1 ts1 fs1 os1) (Prog m2 is2 ts2 fs2 os2)- = m1 == m2 - && sort is1 == sort is2- && checkTypeDecls ts1 ts2- && checkFuncDecls fs1 fs2- && checkOpDecls os1 os2-----------------------------------------------------------------------------------------------------------------------------------------------------------------------checkTypeDecls :: [TypeDecl] -> [TypeDecl] -> Bool-checkTypeDecls ts1 [] = null ts1-checkTypeDecls ts1 ((Type qname vis2 is2 cs2):ts2')- = let (mt,ts1') = extract (isDataType qname) ts1- in maybe False - (\ (Type _ vis1 is1 cs1) - -> vis1 == vis2 - && is1 == is2 - && checkConsDecls cs1 cs2- && checkTypeDecls ts1' ts2')- mt-checkTypeDecls ts1 ((TypeSyn qname vis2 is2 texpr2):ts2')- = let (mt,ts1') = extract (isTypeSyn qname) ts1- in maybe False- (\ (TypeSyn _ vis1 is1 texpr1)- -> vis1 == vis2- && is1 == is2- && texpr1 == texpr2- && checkTypeDecls ts1' ts2')- mt-----checkConsDecls :: [ConsDecl] -> [ConsDecl] -> Bool-checkConsDecls cs1 [] = null cs1-checkConsDecls cs1 ((Cons qname arity2 vis2 texprs2):cs2')- = let (mc,cs1') = extract (isCons qname) cs1- in maybe False- (\ (Cons _ arity1 vis1 texprs1)- -> arity1 == arity2- && vis1 == vis2- && texprs1 == texprs2- && checkConsDecls cs1' cs2')- mc-----checkFuncDecls :: [FuncDecl] -> [FuncDecl] -> Bool-checkFuncDecls fs1 [] = null fs1-checkFuncDecls fs1 ((Func qname arity2 vis2 texpr2 rule2):fs2')- = let (mf,fs1') = extract (isFunc qname) fs1- in maybe False- (\ (Func _ arity1 vis1 texpr1 rule1)- -> arity1 == arity2- && vis1 == vis2- && texpr1 == texpr2- && checkRule rule1 rule2- && checkFuncDecls fs1' fs2')- mf-----checkRule :: Rule -> Rule -> Bool-checkRule (Rule _ _) (Rule _ _) = True-checkRule (External _) (External _) = True-checkRule _ _ = False-----checkOpDecls :: [OpDecl] -> [OpDecl] -> Bool-checkOpDecls os1 [] = null os1-checkOpDecls os1 ((Op qname fix2 prec2):os2')- = let (mo,os1') = extract (isOp qname) os1- in maybe False- (\ (Op _ fix1 prec1)- -> prec1 == prec2- && fix1 == fix2- && checkOpDecls os1' os2')- mo---------------------------------------------------------------------------------------isDataType :: QName -> TypeDecl -> Bool-isDataType qname (Type qname' _ _ _) = qname == qname'-isDataType _ _ = False-----isTypeSyn :: QName -> TypeDecl -> Bool-isTypeSyn qname (TypeSyn qname' _ _ _) = qname == qname'-isTypeSyn _ _ = False-----isCons :: QName -> ConsDecl -> Bool-isCons qname (Cons qname' _ _ _) = qname == qname'-----isFunc :: QName -> FuncDecl -> Bool-isFunc qname (Func qname' _ _ _ _) = qname == qname'-----isOp :: QName -> OpDecl -> Bool-isOp qname (Op qname' _ _) = qname == qname'---------------------------------------------------------------------------------------extract :: (a -> Bool) -> [a] -> (Maybe a, [a])-extract _ [] = (Nothing, [])-extract c (x:xs) | c x = (Just x, xs)- | otherwise = let (res, xs') = extract c xs in (res, x:xs')--{---- Alternativ:-extract :: (a -> Bool) -> [a] -> (Maybe a, [a])-extract c xs = maybe (Nothing, xs) (\x -> (Just x, delete x xs)) (find c xs)--}------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ src/Interfaces.hs view
@@ -0,0 +1,151 @@+{- |+ Module : $Header$+ Description : Loading interfaces+ Copyright : (c) 2000 - 2004, Wolfgang Lux+ 2011 - 2013, Björn Peemöller+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ The compiler maintains a global environment holding all (directly or+ indirectly) imported interface declarations for a module.++ This module contains a function to load *all* interface declarations+ declared by the (directly or indirectly) imported modules, regardless+ whether they are included by the import specification or not.++ The declarations are later brought into the scope of the module via the+ function 'importModules', see module "Imports".++ Interface files are updated by the Curry builder when necessary,+ see module "CurryBuilder".+-}+{-# LANGUAGE CPP #-}+module Interfaces (loadInterfaces) where++#if __GLASGOW_HASKELL__ >= 804+import Prelude hiding ((<>))+#endif++import Control.Monad (unless)+import qualified Control.Monad.State as S (StateT, execStateT, gets, modify)+import qualified Data.Map as M (insert, member)++import Curry.Base.Ident+import Curry.Base.Monad+import Curry.Base.Position+import Curry.Base.SpanInfo ()+import Curry.Base.Pretty+import Curry.Files.PathUtils+import Curry.Syntax++import Base.Messages+import Env.Interface++import Checks.InterfaceSyntaxCheck (intfSyntaxCheck)++-- Interface accumulating monad+type IntfLoader a = S.StateT LoaderState IO a++data LoaderState = LoaderState+ { iEnv :: InterfaceEnv+ , spaths :: [FilePath]+ , errs :: [Message]+ }++-- Report an error.+report :: [Message] -> IntfLoader ()+report msg = S.modify $ \ s -> s { errs = msg ++ errs s }++-- Check whether a module interface is already loaded.+loaded :: ModuleIdent -> IntfLoader Bool+loaded m = S.gets $ \ s -> m `M.member` iEnv s++-- Retrieve the search paths+searchPaths :: IntfLoader [FilePath]+searchPaths = S.gets spaths++-- Add an interface to the environment.+addInterface :: ModuleIdent -> Interface -> IntfLoader ()+addInterface m intf = S.modify $ \ s -> s { iEnv = M.insert m intf $ iEnv s }++-- |Load the interfaces needed by a given module.+-- This function returns an 'InterfaceEnv' containing the 'Interface's which+-- were successfully loaded.+loadInterfaces :: [FilePath] -- ^ 'FilePath's to search in for interfaces+ -> Module a -- ^ 'Module' header with import declarations+ -> CYIO InterfaceEnv+loadInterfaces paths (Module _ _ _ m _ is _) = do+ res <- liftIO $ S.execStateT load (LoaderState initInterfaceEnv paths [])+ if null (errs res) then ok (iEnv res) else failMessages (reverse $ errs res)+ where load = mapM_ (loadInterface [m]) [(p, m') | ImportDecl p m' _ _ _ <- is]++-- |Load an interface into the given environment.+--+-- If an import declaration for a module is found, the compiler first+-- checks whether an import for the module is already pending.+-- In this case the module imports are cyclic which is not allowed in Curry.+-- Therefore, the import will be skipped and an error will be issued.+-- Otherwise, the compiler checks whether the module has already been imported.+-- If so, nothing needs to be done, otherwise the interface will be searched+-- for in the import paths and compiled.+loadInterface :: HasPosition a => [ModuleIdent] -> (a, ModuleIdent)+ -> IntfLoader ()+loadInterface ctxt (_, m)+ | m `elem` ctxt = report [errCyclicImport $ m : takeWhile (/= m) ctxt]+ | otherwise = do+ isLoaded <- loaded m+ unless isLoaded $ do+ paths <- searchPaths+ mbIntf <- liftIO $ lookupCurryInterface paths m+ case mbIntf of+ Nothing -> report [errInterfaceNotFound m]+ Just fn -> compileInterface ctxt m fn++-- |Compile an interface by recursively loading its dependencies.+--+-- After reading an interface, all imported interfaces are recursively+-- loaded and inserted into the interface's environment.+compileInterface :: [ModuleIdent] -> ModuleIdent -> FilePath+ -> IntfLoader ()+compileInterface ctxt m fn = do+ mbSrc <- liftIO $ readModule fn+ case mbSrc of+ Nothing -> report [errInterfaceNotFound m]+ Just src -> case runCYMIgnWarn (parseInterface fn src) of+ Left err -> report err+ Right intf@(Interface n is _) ->+ if m /= n+ then report [errWrongInterface m n]+ else do+ let (intf', intfErrs) = intfSyntaxCheck intf+ mapM_ report [intfErrs]+ mapM_ (loadInterface (m : ctxt)) [ (q, i) | IImportDecl q i <- is ]+ addInterface m intf'++-- Error message for required interface that could not be found.+errInterfaceNotFound :: ModuleIdent -> Message+errInterfaceNotFound m = spanInfoMessage m $+ text "Interface for module" <+> text (moduleName m) <+> text "not found"++-- Error message for an unexpected interface.+errWrongInterface :: ModuleIdent -> ModuleIdent -> Message+errWrongInterface m n = spanInfoMessage m $+ text "Expected interface for" <+> text (moduleName m)+ <> comma <+> text "but found" <+> text (moduleName n)++-- Error message for a cyclic import.+errCyclicImport :: [ModuleIdent] -> Message+errCyclicImport [] = internalError "Interfaces.errCyclicImport: empty list"+errCyclicImport [m] = spanInfoMessage m $+ text "Recursive import for module" <+> text (moduleName m)+errCyclicImport ms = spanInfoMessage (head ms) $+ text "Cyclic import dependency between modules"+ <+> hsep (punctuate comma (map text inits)) <+> text "and" <+> text lastm+ where+ (inits, lastm) = splitLast $ map moduleName ms+ splitLast [] = internalError "Interfaces.splitLast: empty list"+ splitLast (x : []) = ([] , x)+ splitLast (x : y : ys) = (x : xs, z) where (xs, z) = splitLast (y : ys)
− src/KindCheck.lhs
@@ -1,320 +0,0 @@--% $Id: KindCheck.lhs,v 1.33 2004/02/13 19:24:04 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{KindCheck.lhs}-\section{Checking Type Definitions}-After the source file has been parsed and all modules have been-imported, the compiler first performs kind checking on all type-definitions and signatures. Because Curry currently does not support-type classes, kind checking is rather trivial. All types must be of-first order kind ($\star$), i.e., all type constructor applications-must be saturated.--During kind checking, this module will also disambiguate nullary-constructors and type variables which -- in contrast to Haskell -- is-not possible on purely syntactic criteria. In addition it is checked-that all type constructors and type variables occurring on the right-hand side of a type declaration are actually defined and no identifier-is defined more than once.-\begin{verbatim}--> module KindCheck(kindCheck) where--> import Data.Maybe--> import Curry.Syntax-> import Curry.Syntax.Utils(isTypeDecl)-> import Curry.Base.Position-> import Curry.Base.Ident-> import Base hiding (bindArity)-> import TopEnv--\end{verbatim}-In order to check type constructor applications, the compiler-maintains an environment containing the kind information for all type-constructors. The function \texttt{kindCheck} first initializes this-environment by filtering out the arity of each type constructor from-the imported type environment. Next, the arities of all locally-defined type constructors are inserted into the environment, and,-finally, the declarations are checked within this environment.-\begin{verbatim}--> kindCheck :: ModuleIdent -> TCEnv -> [Decl] -> [Decl]-> kindCheck m tcEnv ds =-> case findDouble (map tconstr ds') of-> Nothing -> map (checkDecl m kEnv) ds-> Just tc -> errorAt' (duplicateType tc)-> where ds' = filter isTypeDecl ds-> kEnv = foldr (bindArity m) (fmap tcArity tcEnv) ds'--\end{verbatim}-The kind environment only needs to record the arity of each type constructor.-\begin{verbatim}--> type KindEnv = TopEnv Int--> bindArity :: ModuleIdent -> Decl -> KindEnv -> KindEnv-> bindArity m (DataDecl _ tc tvs _) = bindArity' m tc tvs-> bindArity m (NewtypeDecl _ tc tvs _) = bindArity' m tc tvs-> bindArity m (TypeDecl _ tc tvs _) = bindArity' m tc tvs-> bindArity _ _ = id--> bindArity' :: ModuleIdent -> Ident -> [Ident]-> -> KindEnv -> KindEnv-> bindArity' m tc tvs -> = bindTopEnv "KindCheck.bindArity'" tc n -> . qualBindTopEnv "KindCheck.bindArity'" (qualifyWith m tc) n-> where n = length tvs--> lookupKind :: Ident -> KindEnv -> [Int]-> lookupKind = lookupTopEnv--> qualLookupKind :: QualIdent -> KindEnv -> [Int]-> qualLookupKind = qualLookupTopEnv--\end{verbatim}-When type declarations are checked, the compiler will allow anonymous-type variables on the left hand side of the declaration, but not on-the right hand side. Function and pattern declarations must be-traversed because they can contain local type signatures.-\begin{verbatim}--> checkDecl :: ModuleIdent -> KindEnv -> Decl -> Decl-> checkDecl m kEnv (DataDecl p tc tvs cs) =-> DataDecl p tc tvs' (map (checkConstrDecl m kEnv tvs') cs)-> where tvs' = checkTypeLhs kEnv tvs-> checkDecl m kEnv (NewtypeDecl p tc tvs nc) =-> NewtypeDecl p tc tvs' (checkNewConstrDecl m kEnv tvs' nc)-> where tvs' = checkTypeLhs kEnv tvs-> checkDecl m kEnv (TypeDecl p tc tvs ty) =-> TypeDecl p tc tvs' (checkClosedType m kEnv tvs' ty)-> where tvs' = checkTypeLhs kEnv tvs-> checkDecl m kEnv (TypeSig p vs ty) =-> TypeSig p vs (checkType m kEnv ty)-> checkDecl m kEnv (FunctionDecl p f eqs) =-> FunctionDecl p f (map (checkEquation m kEnv) eqs)-> checkDecl m kEnv (PatternDecl p t rhs) =-> PatternDecl p t (checkRhs m kEnv rhs)-> checkDecl m kEnv (ExternalDecl p cc ie f ty) =-> ExternalDecl p cc ie f (checkType m kEnv ty)-> checkDecl _ _ d = d--> checkTypeLhs :: KindEnv -> [Ident] -> [Ident]-> checkTypeLhs kEnv (tv:tvs)-> | tv == anonId = tv : checkTypeLhs kEnv tvs-> | isTypeConstr tv = errorAt' (noVariable tv)-> | tv `elem` tvs = errorAt' (nonLinear tv)-> | otherwise = tv : checkTypeLhs kEnv tvs-> where isTypeConstr tv = not (null (lookupKind tv kEnv))-> checkTypeLhs _ [] = []--> checkConstrDecl :: ModuleIdent -> KindEnv -> [Ident] -> ConstrDecl -> ConstrDecl-> checkConstrDecl m kEnv tvs (ConstrDecl p evs c tys) =-> ConstrDecl p evs' c (map (checkClosedType m kEnv tvs') tys)-> where evs' = checkTypeLhs kEnv evs-> tvs' = evs' ++ tvs-> checkConstrDecl m kEnv tvs (ConOpDecl p evs ty1 op ty2) =-> ConOpDecl p evs' (checkClosedType m kEnv tvs' ty1) op-> (checkClosedType m kEnv tvs' ty2)-> where evs' = checkTypeLhs kEnv evs-> tvs' = evs' ++ tvs--> checkNewConstrDecl :: ModuleIdent -> KindEnv -> [Ident] -> NewConstrDecl -> -> NewConstrDecl-> checkNewConstrDecl m kEnv tvs (NewConstrDecl p evs c ty) =-> NewConstrDecl p evs' c (checkClosedType m kEnv tvs' ty)-> where evs' = checkTypeLhs kEnv evs-> tvs' = evs' ++ tvs--\end{verbatim}-Checking expressions is rather straight forward. The compiler must-only traverse the structure of expressions in order to find local-declaration groups.-\begin{verbatim}--> checkEquation :: ModuleIdent -> KindEnv -> Equation -> Equation-> checkEquation m kEnv (Equation p lhs rhs) = -> Equation p lhs (checkRhs m kEnv rhs)--> checkRhs :: ModuleIdent -> KindEnv -> Rhs -> Rhs-> checkRhs m kEnv (SimpleRhs p e ds) =-> SimpleRhs p (checkExpr m kEnv e) (map (checkDecl m kEnv) ds)-> checkRhs m kEnv (GuardedRhs es ds) =-> GuardedRhs (map (checkCondExpr m kEnv) es) (map (checkDecl m kEnv) ds)--> checkCondExpr :: ModuleIdent -> KindEnv -> CondExpr -> CondExpr-> checkCondExpr m kEnv (CondExpr p g e) =-> CondExpr p (checkExpr m kEnv g) (checkExpr m kEnv e)--> checkExpr :: ModuleIdent -> KindEnv -> Expression -> Expression-> checkExpr _ _ (Literal l) = Literal l-> checkExpr _ _ (Variable v) = Variable v-> checkExpr _ _ (Constructor c) = Constructor c-> checkExpr m kEnv (Paren e) = Paren (checkExpr m kEnv e)-> checkExpr m kEnv (Typed e ty) =-> Typed (checkExpr m kEnv e) (checkType m kEnv ty)-> checkExpr m kEnv (Tuple p es) = Tuple p (map (checkExpr m kEnv ) es)-> checkExpr m kEnv (List p es) = List p (map (checkExpr m kEnv ) es)-> checkExpr m kEnv (ListCompr p e qs) =-> ListCompr p (checkExpr m kEnv e) (map (checkStmt m kEnv ) qs)-> checkExpr m kEnv (EnumFrom e) = EnumFrom (checkExpr m kEnv e)-> checkExpr m kEnv (EnumFromThen e1 e2) =-> EnumFromThen (checkExpr m kEnv e1) (checkExpr m kEnv e2)-> checkExpr m kEnv (EnumFromTo e1 e2) =-> EnumFromTo (checkExpr m kEnv e1) (checkExpr m kEnv e2)-> checkExpr m kEnv (EnumFromThenTo e1 e2 e3) =-> EnumFromThenTo (checkExpr m kEnv e1) (checkExpr m kEnv e2)-> (checkExpr m kEnv e3)-> checkExpr m kEnv (UnaryMinus op e) = UnaryMinus op (checkExpr m kEnv e)-> checkExpr m kEnv (Apply e1 e2) =-> Apply (checkExpr m kEnv e1) (checkExpr m kEnv e2)-> checkExpr m kEnv (InfixApply e1 op e2) =-> InfixApply (checkExpr m kEnv e1) op (checkExpr m kEnv e2)-> checkExpr m kEnv (LeftSection e op) = LeftSection (checkExpr m kEnv e) op-> checkExpr m kEnv (RightSection op e) = RightSection op (checkExpr m kEnv e)-> checkExpr m kEnv (Lambda r ts e) = Lambda r ts (checkExpr m kEnv e)-> checkExpr m kEnv (Let ds e) =-> Let (map (checkDecl m kEnv) ds) (checkExpr m kEnv e)-> checkExpr m kEnv (Do sts e) =-> Do (map (checkStmt m kEnv ) sts) (checkExpr m kEnv e)-> checkExpr m kEnv (IfThenElse r e1 e2 e3) =-> IfThenElse r (checkExpr m kEnv e1) (checkExpr m kEnv e2)-> (checkExpr m kEnv e3)-> checkExpr m kEnv (Case r e alts) =-> Case r (checkExpr m kEnv e) (map (checkAlt m kEnv) alts)-> checkExpr m kEnv (RecordConstr fs) =-> RecordConstr (map (checkFieldExpr m kEnv) fs)-> checkExpr m kEnv (RecordSelection e l) =-> RecordSelection (checkExpr m kEnv e) l-> checkExpr m kEnv (RecordUpdate fs e) =-> RecordUpdate (map (checkFieldExpr m kEnv) fs) (checkExpr m kEnv e)--> checkStmt :: ModuleIdent -> KindEnv -> Statement -> Statement-> checkStmt m kEnv (StmtExpr p e) = StmtExpr p (checkExpr m kEnv e)-> checkStmt m kEnv (StmtBind p t e) = StmtBind p t (checkExpr m kEnv e)-> checkStmt m kEnv (StmtDecl ds) = StmtDecl (map (checkDecl m kEnv) ds)--> checkAlt :: ModuleIdent -> KindEnv -> Alt -> Alt-> checkAlt m kEnv (Alt p t rhs) = Alt p t (checkRhs m kEnv rhs)--> checkFieldExpr :: ModuleIdent -> KindEnv -> Field Expression-> -> Field Expression-> checkFieldExpr m kEnv (Field p l e) = Field p l (checkExpr m kEnv e)--\end{verbatim}-The parser cannot distinguish unqualified nullary type constructors-and type variables. Therefore, if the compiler finds an unbound-identifier in a position where a type variable is admissible, it will-interpret the identifier as such.-\begin{verbatim}--> checkClosedType :: ModuleIdent -> KindEnv -> [Ident] -> TypeExpr -> -> TypeExpr-> checkClosedType m kEnv tvs ty = checkClosed tvs (checkType m kEnv ty)--> checkType :: ModuleIdent -> KindEnv -> TypeExpr -> TypeExpr-> checkType m kEnv (ConstructorType tc tys) =-> case qualLookupKind tc kEnv of-> []-> | not (isQualified tc) && null tys -> VariableType (unqualify tc)-> | otherwise -> errorAt' (undefinedType tc)-> [n]-> | n == n' -> ConstructorType tc (map (checkType m kEnv ) tys)-> | otherwise -> errorAt' (wrongArity tc n n')-> _ -> case (qualLookupKind (qualQualify m tc) kEnv) of-> [n] -> | n == n' -> ConstructorType tc (map (checkType m kEnv ) tys)-> | otherwise -> errorAt' (wrongArity tc n n')-> _ -> errorAt' (ambiguousType tc)-> where n' = length tys -> checkType m kEnv (VariableType tv)-> | tv == anonId = VariableType tv-> | otherwise = checkType m kEnv (ConstructorType (qualify tv) [])-> checkType m kEnv (TupleType tys) =-> TupleType (map (checkType m kEnv ) tys)-> checkType m kEnv (ListType ty) =-> ListType (checkType m kEnv ty)-> checkType m kEnv (ArrowType ty1 ty2) =-> ArrowType (checkType m kEnv ty1) (checkType m kEnv ty2)-> checkType m kEnv (RecordType fs r) =-> RecordType (map (\ (ls,ty) -> (ls, checkType m kEnv ty)) fs)-> (maybe Nothing (Just . checkType m kEnv ) r)--> checkClosed :: [Ident] -> TypeExpr -> TypeExpr-> checkClosed tvs (ConstructorType tc tys) =-> ConstructorType tc (map (checkClosed tvs) tys)-> checkClosed tvs (VariableType tv)-> | tv == anonId || tv `notElem` tvs = errorAt' (unboundVariable tv)-> | otherwise = VariableType tv-> checkClosed tvs (TupleType tys) =-> TupleType (map (checkClosed tvs) tys)-> checkClosed tvs (ListType ty) =-> ListType (checkClosed tvs ty)-> checkClosed tvs (ArrowType ty1 ty2) =-> ArrowType (checkClosed tvs ty1) (checkClosed tvs ty2)-> checkClosed tvs (RecordType fs r) =-> RecordType (map (\ (ls,ty) -> (ls, checkClosed tvs ty)) fs)-> (maybe Nothing (Just . checkClosed tvs) r)-> --\end{verbatim}-Auxiliary definitions-\begin{verbatim}--> tconstr :: Decl -> Ident-> tconstr (DataDecl p tc _ _) = tc-> tconstr (NewtypeDecl p tc _ _) = tc-> tconstr (TypeDecl p tc _ _) = tc-> tconstr _ = internalError "tconstr"--\end{verbatim}-Error messages:-\begin{verbatim}--> undefinedType :: QualIdent -> (Position,String)-> undefinedType tc = -> (positionOfQualIdent tc,-> "Undefined type " ++ qualName tc)--> ambiguousType :: QualIdent -> (Position,String)-> ambiguousType tc = -> (positionOfQualIdent tc,-> "Ambiguous type " ++ qualName tc)--> duplicateType :: Ident -> (Position,String)-> duplicateType tc = -> (positionOfIdent tc,-> "More than one definition for type " ++ name tc)--> nonLinear :: Ident -> (Position,String)-> nonLinear tv =-> (positionOfIdent tv, -> "Type variable " ++ name tv ++-> " occurs more than once on left hand side of type declaration")--> noVariable :: Ident -> (Position,String)-> noVariable tv =-> (positionOfIdent tv, -> "Type constructor " ++ name tv ++-> " used in left hand side of type declaration")--> wrongArity :: QualIdent -> Int -> Int -> (Position,String)-> wrongArity tc arity argc =-> (positionOfQualIdent tc, -> "Type constructor " ++ qualName tc ++ " expects " ++ arguments arity ++-> " but is applied to " ++ show argc)-> where arguments 0 = "no arguments"-> arguments 1 = "1 argument"-> arguments n = show n ++ " arguments"--> unboundVariable :: Ident -> (Position,String)-> unboundVariable tv = -> (positionOfIdent tv,-> "Unbound type variable " ++ name tv)--\end{verbatim}
− src/Lift.lhs
@@ -1,307 +0,0 @@--% $Id: Lift.lhs,v 1.23 2004/02/13 14:02:54 wlux Exp $-%-% Copyright (c) 2001-2003, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{Lift.lhs}-\section{Lifting Declarations}-After desugaring and simplifying the code, the compiler lifts all-local function declarations to the top-level keeping only local-variable declarations. The algorithm used here is similar to-Johnsson's~\cite{Johnsson87:Thesis} (see also chapter 6-of~\cite{PeytonJonesLester92:Book}). It consists of two phases, first-we abstract each local function declaration, adding its free variables-as initial parameters and update all calls to take these variables-into account. Then all local function declarations are collected and-lifted to the top-level.-\begin{verbatim}--> module Lift(lift) where--> import Control.Monad-> import qualified Control.Monad.State as S-> import Data.List-> import qualified Data.Map as Map-> import qualified Data.Set as Set--> import Curry.Syntax-> import Curry.Syntax.Utils-> import Types-> import Curry.Base.Ident-> import Base-> import TopEnv-> import SCC--> lift :: ValueEnv -> EvalEnv -> Module -> (Module,ValueEnv,EvalEnv)-> lift tyEnv evEnv (Module m es ds) =-> (Module m es (concatMap liftFunDecl ds'),tyEnv',evEnv')-> where (ds',tyEnv',evEnv') =-> S.evalState (S.evalStateT (abstractModule m ds) tyEnv) evEnv--\end{verbatim}-\paragraph{Abstraction}-Besides adding the free variables to every (local) function, the-abstraction pass also has to update the type environment in order to-reflect the new types of the expanded functions. As usual we use a-state monad transformer in order to pass the type environment-through. The environment constructed in the abstraction phase maps-each local function declaration onto its replacement expression,-i.e. the function applied to its free variables.-\begin{verbatim}--> type AbstractState a = S.StateT ValueEnv (S.State EvalEnv) a-> type AbstractEnv = Map.Map Ident Expression--> abstractModule :: ModuleIdent -> [Decl]-> -> AbstractState ([Decl],ValueEnv,EvalEnv)-> abstractModule m ds =-> do-> ds' <- mapM (abstractDecl m "" [] Map.empty) ds-> tyEnv' <- S.get-> evEnv' <- S.lift S.get-> return (ds',tyEnv',evEnv')--> abstractDecl :: ModuleIdent -> String -> [Ident] -> AbstractEnv -> Decl-> -> AbstractState Decl-> abstractDecl m _ lvs env (FunctionDecl p f eqs) =-> liftM (FunctionDecl p f) (mapM (abstractEquation m lvs env) eqs)-> abstractDecl m pre lvs env (PatternDecl p t rhs) =-> liftM (PatternDecl p t) (abstractRhs m pre lvs env rhs)-> abstractDecl _ _ _ _ d = return d--> abstractEquation :: ModuleIdent -> [Ident] -> AbstractEnv -> Equation-> -> AbstractState Equation-> abstractEquation m lvs env (Equation p lhs@(FunLhs f ts) rhs) =-> liftM (Equation p lhs)-> (abstractRhs m (name f ++ ".") (lvs ++ bv ts) env rhs)--> abstractRhs :: ModuleIdent -> String -> [Ident] -> AbstractEnv -> Rhs-> -> AbstractState Rhs-> abstractRhs m pre lvs env (SimpleRhs p e _) =-> liftM (flip (SimpleRhs p) []) (abstractExpr m pre lvs env e)--\end{verbatim}-Within a declaration group we have to split the list of declarations-into the function and value declarations. Only the function-declarations are affected by the abstraction algorithm; the value-declarations are left unchanged except for abstracting their right-hand sides.--The abstraction of a recursive declaration group is complicated by the-fact that not all functions need to call each in a recursive-declaration group. E.g., in the following example neither g nor h-call each other.-\begin{verbatim}- f = g True- where x = f 1- f z = y + z- y = g False- g z = if z then x else 0-\end{verbatim}-Because of this fact, f and g can be abstracted separately by adding-only \texttt{y} to \texttt{f} and \texttt{x} to \texttt{g}. On the-other hand, in the following example-\begin{verbatim}- f x y = g 4- where g p = h p + x- h q = k + y + q- k = g x-\end{verbatim}-the local function \texttt{g} uses \texttt{h}, so the free variables-of \texttt{h} have to be added to \texttt{g} as well. However, because-\texttt{h} does not call \texttt{g} it is sufficient to add only-\texttt{k} and \texttt{y} (and not \texttt{x}) to its definition. We-handle this by computing the dependency graph between the functions-and splitting this graph into its strongly connected components. Each-component is then processed separately, adding the free variables in-the group to its functions.--We have to be careful with local declarations within desugared case-expressions. If some of the cases have guards, e.g.,-\begin{verbatim}- case e of- x | x < 1 -> 1- x -> let double y = y * y in double x-\end{verbatim}-the desugarer at present may duplicate code. While there is no problem-with local variable declaration being duplicated, we must avoid to-lift local function declarations more than once. Therefore-\texttt{abstractFunDecls} transforms only those function declarations-that have not been lifted and discards the other declarations. Note-that it is easy to check whether a function has been lifted by-checking whether an entry for its untransformed name is still present-in the type environment.-\begin{verbatim}--> abstractDeclGroup :: ModuleIdent -> String -> [Ident] -> AbstractEnv-> -> [Decl] -> Expression -> AbstractState Expression-> abstractDeclGroup m pre lvs env ds e =-> abstractFunDecls m pre (lvs ++ bv vds) env (scc bv (qfv m) fds) vds e-> where (fds,vds) = partition isFunDecl ds--> abstractFunDecls :: ModuleIdent -> String -> [Ident] -> AbstractEnv-> -> [[Decl]] -> [Decl] -> Expression-> -> AbstractState Expression-> abstractFunDecls m pre lvs env [] vds e =-> do-> vds' <- mapM (abstractDecl m pre lvs env) vds-> e' <- abstractExpr m pre lvs env e-> return (Let vds' e')-> abstractFunDecls m pre lvs env (fds:fdss) vds e =-> do-> fs' <- liftM (\tyEnv -> filter (not . isLifted tyEnv) fs) S.get-> S.modify (abstractFunTypes m pre fvs fs')-> S.lift (S.modify (abstractFunAnnots m pre fs'))-> fds' <- mapM (abstractFunDecl m pre fvs lvs env')-> [d | d <- fds, any (`elem` fs') (bv d)]-> e' <- abstractFunDecls m pre lvs env' fdss vds e-> return (Let fds' e')-> where fs = bv fds-> fvs = filter (`elem` lvs) (Set.toList fvsRhs)-> env' = foldr (bindF (map mkVar fvs)) env fs-> fvsRhs = Set.unions-> [Set.fromList (maybe [v] (qfv m) (Map.lookup v env)) | v <- qfv m fds]-> bindF fvs f = Map.insert f (apply (mkFun m pre f) fvs)-> isLifted tyEnv f = null (lookupValue f tyEnv)--> abstractFunTypes :: ModuleIdent -> String -> [Ident] -> [Ident]-> -> ValueEnv -> ValueEnv-> abstractFunTypes m pre fvs fs tyEnv = foldr abstractFunType tyEnv fs-> where tys = map (varType tyEnv) fvs-> abstractFunType f tyEnv =-> qualBindFun m (liftIdent pre f)-> (foldr TypeArrow (varType tyEnv f) tys)-> (unbindFun f tyEnv)--> abstractFunAnnots :: ModuleIdent -> String -> [Ident] -> EvalEnv -> EvalEnv-> abstractFunAnnots m pre fs evEnv = foldr abstractFunAnnot evEnv fs-> where abstractFunAnnot f evEnv =-> case Map.lookup f evEnv of-> Just ev -> Map.insert (liftIdent pre f) ev (Map.delete f evEnv)-> Nothing -> evEnv--> abstractFunDecl :: ModuleIdent -> String -> [Ident] -> [Ident]-> -> AbstractEnv -> Decl -> AbstractState Decl-> abstractFunDecl m pre fvs lvs env (FunctionDecl p f eqs) =-> abstractDecl m pre lvs env (FunctionDecl p f' (map (addVars f') eqs))-> where f' = liftIdent pre f-> addVars f (Equation p (FunLhs _ ts) rhs) =-> Equation p (FunLhs f (map VariablePattern fvs ++ ts)) rhs-> abstractFunDecl m pre _ lvs env (ExternalDecl p cc ie f ty) =-> return (ExternalDecl p cc ie (liftIdent pre f) ty)--> abstractExpr :: ModuleIdent -> String -> [Ident] -> AbstractEnv-> -> Expression -> AbstractState Expression-> abstractExpr _ _ _ _ (Literal l) = return (Literal l)-> abstractExpr m pre lvs env (Variable v)-> | isQualified v = return (Variable v)-> | otherwise = maybe (return (Variable v)) (abstractExpr m pre lvs env)-> (Map.lookup (unqualify v) env)-> abstractExpr _ _ _ _ (Constructor c) = return (Constructor c)-> abstractExpr m pre lvs env (Apply e1 e2) =-> do-> e1' <- abstractExpr m pre lvs env e1-> e2' <- abstractExpr m pre lvs env e2-> return (Apply e1' e2')-> abstractExpr m pre lvs env (Let ds e) = abstractDeclGroup m pre lvs env ds e-> abstractExpr m pre lvs env (Case r e alts) =-> do-> e' <- abstractExpr m pre lvs env e-> alts' <- mapM (abstractAlt m pre lvs env) alts-> return (Case r e' alts')-> abstractExpr m _ _ _ _ = internalError "abstractExpr"--> abstractAlt :: ModuleIdent -> String -> [Ident] -> AbstractEnv -> Alt-> -> AbstractState Alt-> abstractAlt m pre lvs env (Alt p t rhs) =-> liftM (Alt p t) (abstractRhs m pre (lvs ++ bv t) env rhs)--\end{verbatim}-\paragraph{Lifting}-After the abstraction pass, all local function declarations are lifted-to the top-level.-\begin{verbatim}--> liftFunDecl :: Decl -> [Decl]-> liftFunDecl (FunctionDecl p f eqs) = (FunctionDecl p f eqs' : concat dss')-> where (eqs',dss') = unzip (map liftEquation eqs)-> liftFunDecl d = [d]--> liftVarDecl :: Decl -> (Decl,[Decl])-> liftVarDecl (PatternDecl p t rhs) = (PatternDecl p t rhs',ds')-> where (rhs',ds') = liftRhs rhs-> liftVarDecl (ExtraVariables p vs) = (ExtraVariables p vs,[])--> liftEquation :: Equation -> (Equation,[Decl])-> liftEquation (Equation p lhs rhs) = (Equation p lhs rhs',ds')-> where (rhs',ds') = liftRhs rhs--> liftRhs :: Rhs -> (Rhs,[Decl])-> liftRhs (SimpleRhs p e _) = (SimpleRhs p e' [],ds')-> where (e',ds') = liftExpr e--> liftDeclGroup :: [Decl] -> ([Decl],[Decl])-> liftDeclGroup ds = (vds',concat (map liftFunDecl fds ++ dss'))-> where (fds,vds) = partition isFunDecl ds-> (vds',dss') = unzip (map liftVarDecl vds)--> liftExpr :: Expression -> (Expression,[Decl])-> liftExpr (Literal l) = (Literal l,[])-> liftExpr (Variable v) = (Variable v,[])-> liftExpr (Constructor c) = (Constructor c,[])-> liftExpr (Apply e1 e2) = (Apply e1' e2',ds' ++ ds'')-> where (e1',ds') = liftExpr e1-> (e2',ds'') = liftExpr e2-> liftExpr (Let ds e) = (mkLet ds' e',ds'' ++ ds''')-> where (ds',ds'') = liftDeclGroup ds-> (e',ds''') = liftExpr e-> mkLet ds e = if null ds then e else Let ds e-> liftExpr (Case r e alts) = (Case r e' alts',concat (ds':dss'))-> where (e',ds') = liftExpr e-> (alts',dss') = unzip (map liftAlt alts)-> liftExpr _ = internalError "liftExpr"--> liftAlt :: Alt -> (Alt,[Decl])-> liftAlt (Alt p t rhs) = (Alt p t rhs',ds')-> where (rhs',ds') = liftRhs rhs---\end{verbatim}-\paragraph{Auxiliary definitions}-\begin{verbatim}--> isFunDecl :: Decl -> Bool-> isFunDecl (FunctionDecl _ _ _) = True-> isFunDecl (ExternalDecl _ _ _ _ _) = True-> isFunDecl _ = False--> mkFun :: ModuleIdent -> String -> Ident -> Expression-> mkFun m pre f = Variable (qualifyWith m (liftIdent pre f))--> mkVar :: Ident -> Expression-> mkVar v = Variable (qualify v)--> apply :: Expression -> [Expression] -> Expression-> apply = foldl Apply--> qualBindFun :: ModuleIdent -> Ident -> Type -> ValueEnv -> ValueEnv-> qualBindFun m f ty -> = qualBindTopEnv "Lift.qualBindFun" f' (Value f' (polyType ty))-> where f' = qualifyWith m f--> unbindFun :: Ident -> ValueEnv -> ValueEnv-> unbindFun = unbindTopEnv--> varType :: ValueEnv -> Ident -> Type-> varType tyEnv v =-> case lookupValue v tyEnv of-> [Value _ (ForAll _ ty)] -> ty-> _ -> internalError ("varType " ++ show v)--> liftIdent :: String -> Ident -> Ident-> liftIdent prefix x =-> renameIdent (mkIdent (prefix ++ (show x))) (uniqueId x)-> --renameIdent (mkIdent (prefix ++ name x ++ show (uniqueId x))) (uniqueId x)--\end{verbatim}
+ src/Modules.hs view
@@ -0,0 +1,453 @@+{- |+ Module : $Header$+ Description : Compilation of a single module+ Copyright : (c) 1999 - 2004 Wolfgang Lux+ 2005 Martin Engelke+ 2007 Sebastian Fischer+ 2011 - 2015 Björn Peemöller+ 2016 Jan Tikovsky+ 2016 - 2017 Finn Teegen+ 2018 Kai-Oliver Prott+ License : BSD-3-clause++ Maintainer : fte@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module controls the compilation of modules.+-}++module Modules+ ( compileModule, loadAndCheckModule, loadModule, checkModule+ , parseModule, checkModuleHeader+ ) where++import qualified Control.Exception as C (catch, IOException)+import Control.Monad (liftM, unless, when)+import Data.Char (toUpper)+import qualified Data.Map as Map (elems, lookup)+import Data.Maybe (fromMaybe)+import System.Directory (getTemporaryDirectory, removeFile)+import System.Exit (ExitCode (..))+import System.FilePath (normalise)+import System.IO+ (IOMode (ReadMode), Handle, hClose, hGetContents, hPutStr, openFile+ , openTempFile)+import System.Process (system)++import Curry.Base.Ident+import Curry.Base.Monad+import Curry.Base.SpanInfo+import Curry.Base.Pretty+import Curry.Base.Span+import Curry.FlatCurry.InterfaceEquivalence (eqInterface)+import Curry.Files.Filenames+import Curry.Files.PathUtils+import Curry.Syntax.InterfaceEquivalence+import Curry.Syntax.Utils (shortenModuleAST)++import Base.Messages+import Base.Types++import Env.Interface++-- source representations+import qualified Curry.AbstractCurry as AC+import qualified Curry.FlatCurry as FC+import qualified Curry.Syntax as CS+import qualified IL++import Checks+import CompilerEnv+import CompilerOpts+import CondCompile (condCompile)+import Exports+import Generators+import Html.CurryHtml (source2html)+import Imports+import Interfaces (loadInterfaces)+import TokenStream (showTokenStream, showCommentTokenStream)+import Transformations++-- The function 'compileModule' is the main entry-point of this+-- module for compiling a Curry source module. Depending on the command+-- line options, it will emit either FlatCurry code or AbstractCurry code+-- (typed, untyped or with type signatures) for the module.+-- Usually, the first step is to check the module.+-- Then the code is translated into the intermediate+-- language. If necessary, this phase will also update the module's+-- interface file. The resulting code then is written out+-- to the corresponding file.+-- The untyped AbstractCurry representation is written+-- out directly after parsing and simple checking the source file.+-- The typed AbstractCurry code is written out after checking the module.+--+-- The compiler automatically loads the prelude when compiling any+-- module, except for the prelude itself, by adding an appropriate import+-- declaration to the module.+compileModule :: Options -> ModuleIdent -> FilePath -> CYIO ()+compileModule opts m fn = do+ mdl <- loadAndCheckModule opts m fn+ writeTokens opts (fst mdl)+ writeComments opts (fst mdl)+ writeParsed opts mdl+ let qmdl = qual mdl+ writeHtml opts qmdl+ writeAST opts (fst mdl, fmap (const ()) (snd mdl))+ writeShortAST opts (fst qmdl, fmap (const ()) (snd qmdl))+ mdl' <- expandExports opts mdl+ qmdl' <- dumpWith opts CS.showModule pPrint DumpQualified $ qual mdl'+ writeAbstractCurry opts qmdl'+ -- generate interface file+ let intf = uncurry exportInterface qmdl'+ writeInterface opts (fst mdl') intf+ when withFlat $ do+ ((env, il), mdl'') <- transModule opts qmdl'+ writeFlat opts env (snd mdl'') il+ where+ withFlat = any (`elem` optTargetTypes opts) [ AnnotatedFlatCurry+ , TypedFlatCurry+ , FlatCurry+ ]++loadAndCheckModule :: Options -> ModuleIdent -> FilePath+ -> CYIO (CompEnv (CS.Module PredType))+loadAndCheckModule opts m fn = do+ ce <- loadModule opts m fn >>= checkModule opts+ warnMessages $ uncurry (warnCheck opts) ce+ return ce++-- ---------------------------------------------------------------------------+-- Loading a module+-- ---------------------------------------------------------------------------++loadModule :: Options -> ModuleIdent -> FilePath+ -> CYIO (CompEnv (CS.Module ()))+loadModule opts m fn = do+ -- parse and check module header+ (toks, mdl) <- parseModule opts m fn+ -- load the imported interfaces into an InterfaceEnv+ let paths = map (addOutDir (optUseOutDir opts) (optOutDir opts))+ ("." : optImportPaths opts)+ let withPrel = importPrelude opts mdl+ iEnv <- loadInterfaces paths withPrel+ checkInterfaces opts iEnv+ is <- importSyntaxCheck iEnv withPrel+ -- add information of imported modules+ cEnv <- importModules withPrel iEnv is+ return (cEnv { filePath = fn, tokens = toks }, mdl)++parseModule :: Options -> ModuleIdent -> FilePath+ -> CYIO ([(Span, CS.Token)], CS.Module ())+parseModule opts m fn = do+ mbSrc <- liftIO $ readModule fn+ case mbSrc of+ Nothing -> failMessages [message $ text $ "Missing file: " ++ fn]+ Just src -> do+ ul <- liftCYM $ CS.unlit fn src+ prepd <- preprocess (optPrepOpts opts) fn ul+ condC <- condCompile (optCppOpts opts) fn prepd+ doDump ((optDebugOpts opts) { dbDumpEnv = False })+ (DumpCondCompiled, undefined, condC)+ -- We ignore the warnings issued by the lexer because+ -- they will be issued a second time during parsing.+ spanToks <- liftCYM $ silent $ CS.lexSource fn condC+ ast <- liftCYM $ CS.parseModule fn condC+ checked <- checkModuleHeader m fn ast+ return (spanToks, checked)++preprocess :: PrepOpts -> FilePath -> String -> CYIO String+preprocess opts fn src+ | not (ppPreprocess opts) = return src+ | otherwise = do+ res <- liftIO $ withTempFile $ \ inFn inHdl -> do+ hPutStr inHdl src+ hClose inHdl+ withTempFile $ \ outFn outHdl -> do+ hClose outHdl+ ec <- system $ unwords $+ [ppCmd opts, normalise fn, inFn, outFn] ++ ppOpts opts+ case ec of+ ExitFailure x -> return $ Left [message $ text $+ "Preprocessor exited with exit code " ++ show x]+ ExitSuccess -> Right `liftM` readFile outFn+ either failMessages ok res++withTempFile :: (FilePath -> Handle -> IO a) -> IO a+withTempFile act = do+ tmp <- getTemporaryDirectory+ (fn, hdl) <- openTempFile tmp "cymake.curry"+ res <- act fn hdl+ hClose hdl+ removeFile fn+ return res++checkModuleHeader :: Monad m => ModuleIdent -> FilePath+ -> CS.Module () -> CYT m (CS.Module ())+checkModuleHeader m fn = checkModuleId m+ . CS.patchModuleId fn++-- |Check whether the 'ModuleIdent' and the 'FilePath' fit together+checkModuleId :: Monad m => ModuleIdent -> CS.Module () -> CYT m (CS.Module ())+checkModuleId mid m@(CS.Module _ _ _ mid' _ _ _)+ | mid == mid' = ok m+ | otherwise = failMessages [errModuleFileMismatch mid']++-- An implicit import of the prelude is temporariliy added to the declarations+-- of every module, except for the prelude itself, or when the import is+-- disabled by a compiler option. If no explicit import for the prelude is+-- present, the prelude is imported unqualified,+-- otherwise a qualified import is added.++importPrelude :: Options -> CS.Module () -> CS.Module ()+importPrelude opts m@(CS.Module spi li ps mid es is ds)+ -- the Prelude itself+ | mid == preludeMIdent = m+ -- disabled by compiler option+ | noImpPrelude = m+ -- already imported+ | preludeMIdent `elem` imports = m+ -- let's add it!+ | otherwise = CS.Module spi li ps mid es (preludeImp:is) ds+ where+ noImpPrelude = NoImplicitPrelude `elem` optExtensions opts+ || m `CS.hasLanguageExtension` NoImplicitPrelude+ preludeImp = CS.ImportDecl NoSpanInfo preludeMIdent+ False -- qualified?+ Nothing -- no alias+ Nothing -- no selection of types, functions, etc.+ imports = [imp | (CS.ImportDecl _ imp _ _ _) <- is]++checkInterfaces :: Monad m => Options -> InterfaceEnv -> CYT m ()+checkInterfaces opts iEnv = mapM_ checkInterface (Map.elems iEnv)+ where+ checkInterface intf = do+ let env = importInterfaces intf iEnv+ interfaceCheck opts (env, intf)++importSyntaxCheck :: Monad m => InterfaceEnv -> CS.Module a -> CYT m [CS.ImportDecl]+importSyntaxCheck iEnv (CS.Module _ _ _ _ _ imps _) = mapM checkImportDecl imps+ where+ checkImportDecl (CS.ImportDecl p m q asM is) = case Map.lookup m iEnv of+ Just intf -> CS.ImportDecl p m q asM `liftM` importCheck intf is+ Nothing -> internalError $ "Modules.importModules: no interface for "+ ++ show m++-- ---------------------------------------------------------------------------+-- Checking a module+-- ---------------------------------------------------------------------------++-- TODO: The order of the checks should be improved!+checkModule :: Options -> CompEnv (CS.Module ())+ -> CYIO (CompEnv (CS.Module PredType))+checkModule opts mdl = do+ _ <- dumpCS DumpParsed mdl+ exc <- extensionCheck opts mdl >>= dumpCS DumpExtensionChecked+ tsc <- typeSyntaxCheck opts exc >>= dumpCS DumpTypeSyntaxChecked+ kc <- kindCheck opts tsc >>= dumpCS DumpKindChecked+ sc <- syntaxCheck opts kc >>= dumpCS DumpSyntaxChecked+ pc <- precCheck opts sc >>= dumpCS DumpPrecChecked+ dc <- deriveCheck opts pc >>= dumpCS DumpDeriveChecked+ inc <- instanceCheck opts dc >>= dumpCS DumpInstanceChecked+ tc <- typeCheck opts inc >>= dumpCS DumpTypeChecked+ ec <- exportCheck opts tc >>= dumpCS DumpExportChecked+ return ec+ where+ dumpCS :: (MonadIO m, Show a) => DumpLevel -> CompEnv (CS.Module a)+ -> m (CompEnv (CS.Module a))+ dumpCS = dumpWith opts CS.showModule pPrint++-- ---------------------------------------------------------------------------+-- Translating a module+-- ---------------------------------------------------------------------------++transModule :: Options -> CompEnv (CS.Module PredType)+ -> CYIO (CompEnv IL.Module, CompEnv (CS.Module Type))+transModule opts mdl = do+ derived <- dumpCS DumpDerived $ derive mdl+ desugared <- dumpCS DumpDesugared $ desugar derived+ dicts <- dumpCS DumpDictionaries $ insertDicts inlDi desugared+ newtypes <- dumpCS DumpNewtypes $ removeNewtypes remNT dicts+ simplified <- dumpCS DumpSimplified $ simplify newtypes+ lifted <- dumpCS DumpLifted $ lift simplified+ il <- dumpIL DumpTranslated $ ilTrans remIm lifted+ ilCaseComp <- dumpIL DumpCaseCompleted $ completeCase il+ return (ilCaseComp, newtypes)+ where+ optOpts = optOptimizations opts+ inlDi = optInlineDictionaries optOpts+ remIm = optRemoveUnusedImports optOpts+ remNT = optDesugarNewtypes optOpts+ dumpCS :: Show a => DumpLevel -> CompEnv (CS.Module a)+ -> CYIO (CompEnv (CS.Module a))+ dumpCS = dumpWith opts CS.showModule pPrint+ dumpIL = dumpWith opts IL.showModule IL.ppModule++-- ---------------------------------------------------------------------------+-- Writing output+-- ---------------------------------------------------------------------------++-- The functions \texttt{genFlat} and \texttt{genAbstract} generate+-- flat and abstract curry representations depending on the specified option.+-- If the interface of a modified Curry module did not change, the+-- corresponding file name will be returned within the result of 'genFlat'+-- (depending on the compiler flag "force") and other modules importing this+-- module won't be dependent on it any longer.++writeTokens :: Options -> CompilerEnv -> CYIO ()+writeTokens opts env = when tokTarget $ liftIO $+ writeModule (useSubDir $ tokensName (filePath env))+ (showTokenStream (tokens env))+ where+ tokTarget = Tokens `elem` optTargetTypes opts+ useSubDir = addOutDirModule (optUseOutDir opts) (optOutDir opts) (moduleIdent env)++writeComments :: Options -> CompilerEnv -> CYIO ()+writeComments opts env = when tokTarget $ liftIO $+ writeModule (useSubDir $ commentsName (filePath env))+ (showCommentTokenStream $ tokens env)+ where+ tokTarget = Comments `elem` optTargetTypes opts+ useSubDir = addOutDirModule (optUseOutDir opts) (optOutDir opts) (moduleIdent env)++-- |Output the parsed 'Module' on request+writeParsed :: Show a => Options -> CompEnv (CS.Module a) -> CYIO ()+writeParsed opts (env, mdl) = when srcTarget $ liftIO $+ writeModule (useSubDir $ sourceRepName (filePath env)) (CS.showModule mdl)+ where+ srcTarget = Parsed `elem` optTargetTypes opts+ useSubDir = addOutDirModule (optUseOutDir opts) (optOutDir opts) (moduleIdent env)++writeHtml :: Options -> CompEnv (CS.Module a) -> CYIO ()+writeHtml opts (env, mdl) = when htmlTarget $+ source2html opts (moduleIdent env) (map (\(sp, tok) -> (span2Pos sp, tok)) (tokens env)) mdl+ where htmlTarget = Html `elem` optTargetTypes opts++writeInterface :: Options -> CompilerEnv -> CS.Interface -> CYIO ()+writeInterface opts env intf@(CS.Interface m _ _)+ | optForce opts = outputInterface+ | otherwise = do+ equal <- liftIO $ C.catch (matchInterface interfaceFile intf)+ ignoreIOException+ unless equal outputInterface+ where+ ignoreIOException :: C.IOException -> IO Bool+ ignoreIOException _ = return False++ interfaceFile = interfName (filePath env)+ outputInterface = liftIO $ writeModule+ (addOutDirModule (optUseOutDir opts) (optOutDir opts) m interfaceFile)+ (show $ pPrint intf)++matchInterface :: FilePath -> CS.Interface -> IO Bool+matchInterface ifn i = do+ hdl <- openFile ifn ReadMode+ src <- hGetContents hdl+ case runCYMIgnWarn (CS.parseInterface ifn src) of+ Left _ -> hClose hdl >> return False+ Right i' -> return (i `intfEquiv` fixInterface i')++writeFlat :: Options -> CompilerEnv -> CS.Module Type -> IL.Module -> CYIO ()+writeFlat opts env mdl il = do+ _ <- dumpWith opts show (pPrint . genFlatCurry) DumpTypedFlatCurry (env, afcy)+ when afcyTarget $ liftIO $ FC.writeFlatCurry (useSubDir afcyName) afcy+ when tfcyTarget $ liftIO $ FC.writeFlatCurry (useSubDir tfcyName) tfcy+ when fcyTarget $ do+ _ <- dumpWith opts show pPrint DumpFlatCurry (env, fcy)+ liftIO $ FC.writeFlatCurry (useSubDir fcyName) fcy+ writeFlatIntf opts env fcy+ where+ afcy = genAnnotatedFlatCurry env mdl il+ afcyName = annotatedFlatName (filePath env)+ afcyTarget = AnnotatedFlatCurry `elem` optTargetTypes opts+ tfcy = genTypedFlatCurry afcy+ tfcyName = typedFlatName (filePath env)+ tfcyTarget = TypedFlatCurry `elem` optTargetTypes opts+ fcy = genFlatCurry afcy+ fcyName = flatName (filePath env)+ fcyTarget = FlatCurry `elem` optTargetTypes opts+ useSubDir = addOutDirModule (optUseOutDir opts) (optOutDir opts) (moduleIdent env)++writeFlatIntf :: Options -> CompilerEnv -> FC.Prog -> CYIO ()+writeFlatIntf opts env prog+ | not (optInterface opts) = return ()+ | optForce opts = outputInterface+ | otherwise = do+ mfint <- liftIO $ FC.readFlatInterface targetFile+ let oldInterface = fromMaybe emptyIntf mfint+ when (mfint == mfint) $ return () -- necessary to close file -- TODO+ unless (oldInterface `eqInterface` fint) outputInterface+ where+ targetFile = flatIntName (filePath env)+ emptyIntf = FC.Prog "" [] [] [] []+ fint = genFlatInterface prog+ useSubDir = addOutDirModule (optUseOutDir opts) (optOutDir opts) (moduleIdent env)+ outputInterface = liftIO $ FC.writeFlatCurry (useSubDir targetFile) fint++writeAbstractCurry :: Options -> CompEnv (CS.Module PredType) -> CYIO ()+writeAbstractCurry opts (env, mdl) = do+ when acyTarget $ liftIO+ $ AC.writeCurry (useSubDir $ acyName (filePath env))+ $ genTypedAbstractCurry env mdl+ when uacyTarget $ liftIO+ $ AC.writeCurry (useSubDir $ uacyName (filePath env))+ $ genUntypedAbstractCurry env mdl+ where+ acyTarget = AbstractCurry `elem` optTargetTypes opts+ uacyTarget = UntypedAbstractCurry `elem` optTargetTypes opts+ useSubDir = addOutDirModule (optUseOutDir opts) (optOutDir opts) (moduleIdent env)+++writeAST :: Options -> CompEnv (CS.Module ()) -> CYIO ()+writeAST opts (env, mdl) = when astTarget $ liftIO $+ writeModule (useSubDir $ astName (filePath env)) (CS.showModule mdl)+ where+ astTarget = AST `elem` optTargetTypes opts+ useSubDir = addOutDirModule (optUseOutDir opts) (optOutDir opts) (moduleIdent env)+++writeShortAST :: Options -> CompEnv (CS.Module ()) -> CYIO ()+writeShortAST opts (env, mdl) = when astTarget $ liftIO $+ writeModule (useSubDir $ shortASTName (filePath env))+ (CS.showModule $ shortenModuleAST mdl)+ where+ astTarget = ShortAST `elem` optTargetTypes opts+ useSubDir = addOutDirModule (optUseOutDir opts) (optOutDir opts) (moduleIdent env)+++type Dump = (DumpLevel, CompilerEnv, String)++dumpWith :: MonadIO m+ => Options -> (a -> String) -> (a -> Doc) -> DumpLevel+ -> CompEnv a -> m (CompEnv a)+dumpWith opts rawView view lvl res@(env, mdl) = do+ let str = if dbDumpRaw (optDebugOpts opts) then rawView mdl+ else show (view mdl)+ doDump (optDebugOpts opts) (lvl, env, str)+ return res++-- |Translate FlatCurry into the intermediate language 'IL'+-- |The 'dump' function writes the selected information to standard output.+doDump :: MonadIO m => DebugOpts -> Dump -> m ()+doDump opts (level, env, dump)+ = when (level `elem` dbDumpLevels opts) $ liftIO $ do+ putStrLn (heading (capitalize $ lookupHeader dumpLevel) '=')+ when (dbDumpEnv opts) $ do+ putStrLn (heading "Environment" '-')+ putStrLn (showCompilerEnv env (dbDumpAllBindings opts) (dbDumpSimple opts))+ putStrLn (heading "Source Code" '-')+ putStrLn dump+ where+ heading h s = '\n' : h ++ '\n' : replicate (length h) s+ lookupHeader [] = "Unknown dump level " ++ show level+ lookupHeader ((l,_,h):lhs)+ | level == l = h+ | otherwise = lookupHeader lhs+ capitalize = unwords . map firstUpper . words+ firstUpper "" = ""+ firstUpper (c:cs) = toUpper c : cs++errModuleFileMismatch :: ModuleIdent -> Message+errModuleFileMismatch mid = posMessage mid $ hsep $ map text+ [ "Module", moduleName mid, "must be in a file"+ , moduleName mid ++ ".(l)curry" ]
− src/Modules.lhs
@@ -1,700 +0,0 @@--% $Id: Modules.lhs,v 1.84 2004/02/10 17:46:07 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-% March 2007, extensions by Sebastian Fischer (sebf@informatik.uni-kiel.de)-%-\nwfilename{Modules.lhs}-\section{Modules}-This module controls the compilation of modules.--Since this version is only used as a frontend for PAKCS, some of the following -import declarations are commented out-\begin{verbatim}--> module Modules(compileModule,-> importPrelude, patchModuleId,-> loadInterfaces, transModule,-> simpleCheckModule, checkModule-> ) where--> import Text.PrettyPrint.HughesPJ-> import Data.List-> import qualified Data.Map as Map-> import System.IO-> import Data.Maybe-> import Control.Monad--> import Curry.Base.MessageMonad-> import Curry.Base.Position as P-> import Curry.Base.Ident--> import Curry.Files.Filenames-> import Curry.Files.PathUtils--> import Curry.Syntax-> import Curry.Syntax.Utils(isImportDecl)-> import Curry.Syntax.Pretty(ppModule,ppIDecl)-> import Curry.Syntax.ShowModule(showModule)--> import Curry.ExtendedFlat.Type-> import qualified Curry.ExtendedFlat.Type as EF --> import qualified IL.Type as IL-> import IL.CurryToIL(ilTrans)-> import qualified IL.Pretty(ppModule)-> import IL.XML(xmlModule)--> import Base-> import Types-> import KindCheck(kindCheck)-> import SyntaxCheck(syntaxCheck)-> import PrecCheck(precCheck)-> import TypeCheck(typeCheck)-> import WarnCheck(warnCheck)-> import Arity-> import Imports(importInterface,importInterfaceIntf,importUnifyData)-> import Exports(expandInterface,exportInterface)-> import Eval(evalEnv)-> import Qual(qual)-> import Desugar(desugar)-> import Simplify(simplify)-> import Lift(lift)--> import GenFlatCurry (genFlatCurry,genFlatInterface)-> import qualified Curry.AbstractCurry as AC-> import GenAbstractCurry-> import InterfaceCheck-> import CurryEnv--> import CurryCompilerOpts(Options(..),Dump(..))-> import CaseCompletion---> import TypeSubst-> import TopEnv---\end{verbatim}-The function \texttt{compileModule} is the main entry-point of this-module for compiling a Curry source module. Depending on the command-line options it will emit either C code or FlatCurry code (standard -or in XML-representation) or AbtractCurry code (typed, untyped or with type-signatures) for the module. Usually the first step is to-check the module. Then the code is translated into the intermediate-language. If necessary, this phase will also update the module's-interface file. The resulting code then is either written out (in-FlatCurry or XML format) or translated further into C code.-The untyped AbstractCurry representation is written-out directly after parsing and simple checking the source file. -The typed AbstractCurry code is written out after checking the module.--The compiler automatically loads the prelude when compiling any-module, except for the prelude itself, by adding an appropriate import-declaration to the module. --Since this modified version of the Muenster Curry Compiler is used-as a frontend for PAKCS, all functions for evaluating goals and generating C -code are obsolete and commented out.-\begin{verbatim}--> compileModule :: Options -> FilePath -> IO (Maybe FilePath)-> compileModule opts fn =-> do-> mod <- liftM (importPrelude fn . ok . parseModule likeFlat fn) (readModule fn)-> let m = patchModuleId fn mod-> checkModuleId fn m-> mEnv <- loadInterfaces (importPaths opts) m-> if uacy || src-> then -> do (tyEnv, tcEnv, aEnv, m', intf, _) <- simpleCheckModule opts mEnv m-> if uacy then genAbstract opts fn tyEnv tcEnv m'-> else do-> let outputFile = maybe (sourceRepName fn)-> id -> (output opts)-> outputMod = showModule m'-> writeModule (writeToSubdir opts) outputFile outputMod-> return Nothing-> else-> do -- checkModule checks types, and then transModule introduces new-> -- functions (by lambda lifting in 'desugar'). Consequence: The-> -- type of the newly introduced functions are not inferred (hsi)-> (tyEnv, tcEnv, aEnv, m', intf, _) <- checkModule opts mEnv m-> let (il,aEnv',dumps) = transModule fcy False False -> mEnv tyEnv tcEnv aEnv m'-> mapM_ (doDump opts) dumps-> genCode opts fn mEnv tyEnv tcEnv aEnv' intf m' il-> where acy = abstract opts-> uacy = untypedAbstract opts-> fcy = flat opts-> xml = flatXml opts-> src = parseOnly opts-> likeFlat = fcy || xml || acy || uacy || src-> -> genCode opts fn mEnv tyEnv tcEnv aEnv intf m il-> | fcy || xml = genFlat opts fn mEnv tyEnv tcEnv aEnv intf m il-> | acy = genAbstract opts fn tyEnv tcEnv m-> | otherwise = return Nothing--> loadInterfaces :: [FilePath] -> Module -> IO ModuleEnv-> loadInterfaces paths (Module m _ ds) =-> foldM (loadInterface paths [m]) Map.empty-> [(p,m) | ImportDecl p m _ _ _ <- ds]--> checkModuleId :: Monad m => FilePath -> Module -> m ()-> checkModuleId fn (Module mid _ _)-> | last (moduleQualifiers mid) == takeBaseName fn-> = return ()-> | otherwise-> = error ("module \"" ++ moduleName mid -> ++ "\" must be in a file \"" ++ moduleName mid-> ++ ".curry\"")--> simpleCheckModule :: Options -> ModuleEnv -> Module -> -> IO (ValueEnv,TCEnv,ArityEnv,Module,Interface,[WarnMsg])-> simpleCheckModule opts mEnv (Module m es ds) =-> do unless (noWarn opts) (printMessages msgs)-> return (tyEnv'', tcEnv, aEnv'', modul, intf, msgs)-> where (impDs,topDs) = partition isImportDecl ds-> iEnv = foldr bindAlias initIEnv impDs-> (pEnv,tcEnv,tyEnv,aEnv) = importModules mEnv impDs-> msgs = warnCheck m tyEnv impDs topDs-> withExt = withExtensions opts-> (pEnv',topDs') = precCheck m pEnv -> $ syntaxCheck withExt m iEnv aEnv tyEnv tcEnv-> $ kindCheck m tcEnv topDs-> ds' = impDs ++ qual m tyEnv topDs'-> modul = (Module m es ds') --expandInterface (Module m es ds') tcEnv tyEnv-> (_,tcEnv'',tyEnv'',aEnv'') -> = qualifyEnv mEnv pEnv' tcEnv tyEnv aEnv-> intf = exportInterface modul pEnv' tcEnv'' tyEnv''--> checkModule :: Options -> ModuleEnv -> Module -> -> IO (ValueEnv,TCEnv,ArityEnv,Module,Interface,[WarnMsg])-> checkModule opts mEnv (Module m es ds) =-> do unless (noWarn opts) (printMessages msgs)-> when (m == mkMIdent ["field114..."])-> (error (show es))-> return (tyEnv''', tcEnv', aEnv'', modul, intf, msgs)-> where (impDs,topDs) = partition isImportDecl ds-> iEnv = foldr bindAlias initIEnv impDs-> (pEnv,tcEnvI,tyEnvI,aEnv) = importModules mEnv impDs-> tcEnv = if withExtensions opts-> then fmap (expandRecordTC tcEnvI) tcEnvI-> else tcEnvI-> lEnv = importLabels mEnv impDs-> tyEnvL = addImportedLabels m lEnv tyEnvI-> tyEnv = if withExtensions opts-> then fmap (expandRecordTypes tcEnv) tyEnvL-> else tyEnvI-> msgs = warnCheck m tyEnv impDs topDs-> withExt = withExtensions opts-> -- fre: replaced the argument aEnv by aEnv'' in the-> -- expression below. This fixed a bug that occured-> -- when one imported a module qualified that-> -- exported a function from another module.-> -- However, there is now a cyclic dependecy -> -- but tests didn't show any problems.-> (pEnv',topDs') = precCheck m pEnv -> $ syntaxCheck withExt m iEnv aEnv'' tyEnv tcEnv-> $ kindCheck m tcEnv topDs-> (tcEnv',tyEnv') = typeCheck m tcEnv tyEnv topDs'-> ds' = impDs ++ qual m tyEnv' topDs'-> modul = expandInterface (Module m es ds') tcEnv' tyEnv'-> (pEnv'',tcEnv'',tyEnv'',aEnv'') -> = qualifyEnv mEnv pEnv' tcEnv' tyEnv' aEnv-> tyEnvL' = addImportedLabels m lEnv tyEnv''-> tyEnv''' = if withExtensions opts-> then fmap (expandRecordTypes tcEnv'') tyEnvL'-> else tyEnv''-> --tyEnv''' = addImportedLabels m lEnv tyEnv''-> intf = exportInterface modul pEnv'' tcEnv'' tyEnv'''--> transModule :: Bool -> Bool -> Bool -> ModuleEnv -> ValueEnv -> TCEnv-> -> ArityEnv -> Module -> (IL.Module,ArityEnv,[(Dump,Doc)])-> transModule flat debug trusted mEnv tyEnv tcEnv aEnv (Module m es ds) =-> (il',aEnv',dumps)-> where topDs = filter (not . isImportDecl) ds-> evEnv = evalEnv topDs-> (desugared,tyEnv') = desugar tyEnv tcEnv (Module m es topDs)-> (simplified,tyEnv'') = simplify flat tyEnv' evEnv desugared-> (lifted,tyEnv''',evEnv') = lift tyEnv'' evEnv simplified-> aEnv' = bindArities aEnv lifted-> il = ilTrans flat tyEnv''' tcEnv evEnv' lifted-> il' = completeCase mEnv il-> dumps = [(DumpRenamed,ppModule (Module m es ds)),-> (DumpTypes,ppTypes m (localBindings tyEnv)),-> (DumpDesugared,ppModule desugared),-> (DumpSimplified,ppModule simplified),-> (DumpLifted,ppModule lifted),-> (DumpIL,IL.Pretty.ppModule il),-> (DumpCase,IL.Pretty.ppModule il')-> ]--> qualifyEnv :: ModuleEnv -> PEnv -> TCEnv -> ValueEnv -> ArityEnv-> -> (PEnv,TCEnv,ValueEnv,ArityEnv)-> qualifyEnv mEnv pEnv tcEnv tyEnv aEnv =-> (foldr bindQual pEnv' (localBindings pEnv),-> foldr bindQual tcEnv' (localBindings tcEnv),-> foldr bindGlobal tyEnv' (localBindings tyEnv),-> foldr bindQual aEnv' (localBindings aEnv))-> where (pEnv',tcEnv',tyEnv',aEnv') =-> foldl importInterface initEnvs (Map.toList mEnv)-> importInterface (pEnv,tcEnv,tyEnv,aEnv) (m,ds) =-> importInterfaceIntf (Interface m ds) pEnv tcEnv tyEnv aEnv-> bindQual (_,y) = qualBindTopEnv "Modules.qualifyEnv" (origName y) y-> bindGlobal (x,y)-> | uniqueId x == 0 = bindQual (x,y)-> | otherwise = bindTopEnv "Modules.qualifyEnv" x y--> writeXML :: Bool -> Maybe FilePath -> FilePath -> CurryEnv -> IL.Module -> IO ()-> writeXML sub tfn sfn cEnv il = writeModule sub ofn (showln code)-> where ofn = fromMaybe (xmlName sfn) tfn-> code = (xmlModule cEnv il)--> writeFlat :: Options -> Maybe FilePath -> FilePath -> CurryEnv -> ModuleEnv -> -> ValueEnv -> TCEnv -> ArityEnv -> IL.Module -> IO Prog-> writeFlat opts tfn sfn cEnv mEnv tyEnv tcEnv aEnv il-> = writeFlatFile opts (genFlatCurry opts cEnv mEnv tyEnv tcEnv aEnv il)-> (fromMaybe (flatName sfn) tfn)--> writeFlatFile :: Options -> (Prog, [WarnMsg]) -> String -> IO Prog-> writeFlatFile opts@Options{extendedFlat=ext,writeToSubdir=sub} (res,msgs) fname = do-> unless (noWarn opts) (printMessages msgs)-> if ext then writeExtendedFlat sub fname res-> else writeFlatCurry sub fname res-> return res---> writeTypedAbs :: Bool -> Maybe FilePath -> FilePath -> ValueEnv -> TCEnv -> Module-> -> IO ()-> writeTypedAbs sub tfn sfn tyEnv tcEnv mod-> = AC.writeCurry sub fname (genTypedAbstract tyEnv tcEnv mod)-> where fname = fromMaybe (acyName sfn) tfn--> writeUntypedAbs :: Bool -> Maybe FilePath -> FilePath -> ValueEnv -> TCEnv -> -> Module -> IO ()-> writeUntypedAbs sub tfn sfn tyEnv tcEnv mod-> = AC.writeCurry sub fname (genUntypedAbstract tyEnv tcEnv mod)-> where fname = fromMaybe (uacyName sfn) tfn--> showln :: Show a => a -> String-> showln x = shows x "\n"--\end{verbatim}--The function \texttt{importModules} brings the declarations of all-imported modules into scope for the current module.-\begin{verbatim}--> importModules :: ModuleEnv -> [Decl] -> (PEnv,TCEnv,ValueEnv,ArityEnv)-> importModules mEnv ds = (pEnv,importUnifyData tcEnv,tyEnv,aEnv)-> where (pEnv,tcEnv,tyEnv,aEnv) = foldl importModule initEnvs ds-> importModule (pEnv,tcEnv,tyEnv,aEnv) (ImportDecl p m q asM is) =-> case Map.lookup m mEnv of-> Just ds -> importInterface p (fromMaybe m asM) q is-> (Interface m ds) pEnv tcEnv tyEnv aEnv-> Nothing -> internalError "importModule"-> importModule (pEnv,tcEnv,tyEnv,aEnv) _ = (pEnv,tcEnv,tyEnv,aEnv)--> initEnvs :: (PEnv,TCEnv,ValueEnv,ArityEnv)-> initEnvs = (initPEnv,initTCEnv,initDCEnv,initAEnv)--\end{verbatim}-Unlike unsual identifiers like in functions, types etc. identifiers-of labels are always represented unqualified within the whole context-of compilation. Since the common type environment (type \texttt{ValueEnv})-has some problems with handling imported unqualified identifiers, it is -necessary to add the type information for labels seperately. For this reason-the function \texttt{importLabels} generates an environment containing-all imported labels and the function \texttt{addImportedLabels} adds this-content to a type environment.-\begin{verbatim}--> importLabels :: ModuleEnv -> [Decl] -> LabelEnv-> importLabels mEnv ds = foldl importLabelTypes Map.empty ds-> where-> importLabelTypes lEnv (ImportDecl p m _ asM is) =-> case (Map.lookup m mEnv) of-> Just ds' -> foldl (importLabelType p (fromMaybe m asM) is) lEnv ds'-> Nothing -> internalError "importLabels"-> importLabelTypes lEnv _ = lEnv-> -> importLabelType p m is lEnv (ITypeDecl _ r _ (RecordType fs _)) =-> foldl (insertLabelType p m r' (getImportSpec r' is)) lEnv fs-> where r' = qualifyWith m (fromRecordExtId (unqualify r))-> importLabelType _ _ _ lEnv _ = lEnv-> -> insertLabelType p m r (Just (ImportTypeAll _)) lEnv ([l],ty) =-> bindLabelType l r (toType [] ty) lEnv-> insertLabelType p m r (Just (ImportTypeWith _ ls)) lEnv ([l],ty)-> | l `elem` ls = bindLabelType l r (toType [] ty) lEnv-> | otherwise = lEnv-> insertLabelType _ _ _ _ lEnv _ = lEnv-> -> getImportSpec r (Just (Importing _ is')) =-> find (isImported (unqualify r)) is'-> getImportSpec r Nothing = Just (ImportTypeAll (unqualify r))-> getImportSpec r _ = Nothing-> -> isImported r (Import r') = r == r'-> isImported r (ImportTypeWith r' _) = r == r'-> isImported r (ImportTypeAll r') = r == r'--> addImportedLabels :: ModuleIdent -> LabelEnv -> ValueEnv -> ValueEnv-> addImportedLabels m lEnv tyEnv = -> foldr addLabelType tyEnv (concatMap snd (Map.toList lEnv))-> where-> addLabelType (LabelType l r ty) tyEnv = -> let m' = fromMaybe m (qualidMod r)-> in importTopEnv m' l -> (Label (qualify l) (qualQualify m' r) (polyType ty)) -> tyEnv--\end{verbatim}-Fully expand all (imported) record types within the type constructor -environment and the type environment.-Note: the record types for the current module are expanded within the-type check.-\begin{verbatim}--> expandRecordTC :: TCEnv -> TypeInfo -> TypeInfo-> expandRecordTC tcEnv (DataType qid n args) =-> DataType qid n (map (maybe Nothing (Just . (expandData tcEnv))) args)-> expandRecordTC tcEnv (RenamingType qid n (Data id m ty)) =-> RenamingType qid n (Data id m (expandRecords tcEnv ty))-> expandRecordTC tcEnv (AliasType qid n ty) =-> AliasType qid n (expandRecords tcEnv ty)--> expandData :: TCEnv -> Data [Type] -> Data [Type]-> expandData tcEnv (Data id n tys) =-> Data id n (map (expandRecords tcEnv) tys)--> expandRecordTypes :: TCEnv -> ValueInfo -> ValueInfo-> expandRecordTypes tcEnv (DataConstructor qid (ForAllExist n m ty)) =-> DataConstructor qid (ForAllExist n m (expandRecords tcEnv ty))-> expandRecordTypes tcEnv (NewtypeConstructor qid (ForAllExist n m ty)) =-> NewtypeConstructor qid (ForAllExist n m (expandRecords tcEnv ty))-> expandRecordTypes tcEnv (Value qid (ForAll n ty)) =-> Value qid (ForAll n (expandRecords tcEnv ty))-> expandRecordTypes tcEnv (Label qid r (ForAll n ty)) =-> Label qid r (ForAll n (expandRecords tcEnv ty))--> expandRecords :: TCEnv -> Type -> Type-> expandRecords tcEnv (TypeConstructor qid tys) =-> case (qualLookupTC qid tcEnv) of-> [AliasType _ _ rty@(TypeRecord _ _)]-> -> expandRecords tcEnv -> (expandAliasType (map (expandRecords tcEnv) tys) rty)-> _ -> TypeConstructor qid (map (expandRecords tcEnv) tys)-> expandRecords tcEnv (TypeConstrained tys v) =-> TypeConstrained (map (expandRecords tcEnv) tys) v-> expandRecords tcEnv (TypeArrow ty1 ty2) =-> TypeArrow (expandRecords tcEnv ty1) (expandRecords tcEnv ty2)-> expandRecords tcEnv (TypeRecord fs rv) =-> TypeRecord (map (\ (l,ty) -> (l,expandRecords tcEnv ty)) fs) rv-> expandRecords _ ty = ty--\end{verbatim}-An implicit import of the prelude is added to the declarations of-every module, except for the prelude itself. If no explicit import for-the prelude is present, the prelude is imported unqualified, otherwise-only a qualified import is added.-\begin{verbatim}--> importPrelude :: FilePath -> Module -> Module-> importPrelude fn (Module m es ds) =-> Module m es (if m == preludeMIdent then ds else ds')-> where ids = [decl | decl@(ImportDecl _ _ _ _ _) <- ds]-> ds' = ImportDecl (P.first fn) preludeMIdent-> (preludeMIdent `elem` map importedModule ids)-> Nothing Nothing : ds-> importedModule (ImportDecl _ m q asM is) = fromMaybe m asM--\end{verbatim}-If an import declaration for a module is found, the compiler first-checks whether an import for the module is already pending. In this-case the module imports are cyclic which is not allowed in Curry. The-compilation will therefore be aborted. Next, the compiler checks-whether the module has been imported already. If so, nothing needs to-be done, otherwise the interface will be searched in the import paths-and compiled.-\begin{verbatim}--> loadInterface :: [FilePath] -> [ModuleIdent] -> ModuleEnv ->-> (Position,ModuleIdent) -> IO ModuleEnv-> loadInterface paths ctxt mEnv (p,m)-> | m `elem` ctxt = errorAt p (cyclicImport m (takeWhile (/= m) ctxt))-> | isLoaded m mEnv = return mEnv-> | otherwise =-> lookupInterface paths m >>=-> maybe (errorAt p (interfaceNotFound m))-> (compileInterface paths ctxt mEnv m)-> where isLoaded m mEnv = maybe False (const True) (Map.lookup m mEnv)--\end{verbatim}-After reading an interface, all imported interfaces are recursively-loaded and entered into the interface's environment. There is no need-to check FlatCurry-Interfaces, since these files contain automaticaly-generated FlatCurry terms (type \texttt{Prog}).-\begin{verbatim}--> compileInterface :: [FilePath] -> [ModuleIdent] -> ModuleEnv -> ModuleIdent-> -> FilePath -> IO ModuleEnv-> compileInterface paths ctxt mEnv m fn =-> do-> mintf <- readFlatInterface fn-> let intf = fromMaybe (errorAt (P.first fn) (interfaceNotFound m)) mintf-> (Prog mod _ _ _ _) = intf-> m' = mkMIdent [mod]-> unless (m' == m) (errorAt (P.first fn) (wrongInterface m m'))-> mEnv' <- loadFlatInterfaces paths ctxt mEnv intf-> return (bindFlatInterface intf mEnv')--> --loadIntfInterfaces :: [FilePath] -> [ModuleIdent] -> ModuleEnv -> Interface-> -- -> IO ModuleEnv-> --loadIntfInterfaces paths ctxt mEnv (Interface m ds) =-> -- foldM (loadInterface paths (m:ctxt)) mEnv [(p,m) | IImportDecl p m <- ds]---> loadFlatInterfaces :: [FilePath] -> [ModuleIdent] -> ModuleEnv -> Prog-> -> IO ModuleEnv-> loadFlatInterfaces paths ctxt mEnv (Prog m is _ _ _) =-> foldM (loadInterface paths ((mkMIdent [m]):ctxt)) -> mEnv -> (map (\i -> (p, mkMIdent [i])) is)-> where p = P.first m---Interface files are updated by the Curry builder when necessary.-(see module \texttt{CurryBuilder}).--\end{verbatim}-The \texttt{doDump} function writes the selected information to the-standard output.-\begin{verbatim}--> doDump :: Options -> (Dump,Doc) -> IO ()-> doDump opts (d,x) =-> when (d `elem` dump opts)-> (print (text hd $$ text (replicate (length hd) '=') $$ x))-> where hd = dumpHeader d--> dumpHeader :: Dump -> String-> dumpHeader DumpRenamed = "Module after renaming"-> dumpHeader DumpTypes = "Types"-> dumpHeader DumpDesugared = "Source code after desugaring"-> dumpHeader DumpSimplified = "Source code after simplification"-> dumpHeader DumpLifted = "Source code after lifting"-> dumpHeader DumpIL = "Intermediate code"-> dumpHeader DumpCase = "Intermediate code after case simplification"---\end{verbatim}-The functions \texttt{genFlat} and \texttt{genAbstract} generate-flat and abstract curry representations depending on the specified option.-If the interface of a modified Curry module did not change, the corresponding -file name will be returned within the result of \texttt{genFlat} (depending-on the compiler flag "force") and other modules importing this module won't-be dependent on it any longer.-\begin{verbatim}--> genFlat :: Options -> FilePath -> ModuleEnv -> ValueEnv -> TCEnv -> ArityEnv -> -> Interface -> Module -> IL.Module -> IO (Maybe FilePath)-> genFlat opts fname mEnv tyEnv tcEnv aEnv intf mod il-> | flat opts-> = do writeFlat opts Nothing fname cEnv mEnv tyEnv tcEnv aEnv il-> let (flatInterface,intMsgs) = genFlatInterface opts cEnv mEnv tyEnv tcEnv aEnv il-> if force opts-> then -> do writeInterface flatInterface intMsgs-> return Nothing-> else -> do mfint <- readFlatInterface fintName-> let flatIntf = fromMaybe emptyIntf mfint-> if mfint == mfint -- necessary to close the file 'fintName'-> && not (interfaceCheck flatIntf flatInterface)-> then -> do writeInterface flatInterface intMsgs-> return Nothing-> else return Nothing-> | flatXml opts-> = writeXML (writeToSubdir opts) (output opts) fname cEnv il >> -> return Nothing-> | otherwise-> = internalError "@Modules.genFlat: illegal option"-> where-> fintName = flatIntName fname-> cEnv = curryEnv mEnv tcEnv intf mod-> emptyIntf = Prog "" [] [] [] []-> writeInterface intf msgs = do-> unless (noWarn opts) (printMessages msgs)-> writeFlatCurry (writeToSubdir opts) fintName intf---> genAbstract :: Options -> FilePath -> ValueEnv -> TCEnv -> Module -> -> IO (Maybe FilePath)-> genAbstract opts@Options{writeToSubdir=sub} fname tyEnv tcEnv mod-> | abstract opts-> = do writeTypedAbs sub Nothing fname tyEnv tcEnv mod -> return Nothing-> | untypedAbstract opts-> = do writeUntypedAbs sub Nothing fname tyEnv tcEnv mod-> return Nothing-> | otherwise-> = internalError "@Modules.genAbstract: illegal option"--> printMessages :: [WarnMsg] -> IO ()-> printMessages [] = return ()-> printMessages msgs = hPutStrLn stderr $ unlines $ map showWarning msgs--\end{verbatim}-The function \texttt{ppTypes} is used for pretty-printing the types-from the type environment.-\begin{verbatim}--> ppTypes :: ModuleIdent -> [(Ident,ValueInfo)] -> Doc-> ppTypes m = vcat . map (ppIDecl . mkDecl) . filter (isValue . snd)-> where mkDecl (v,Value _ (ForAll _ ty)) =-> IFunctionDecl undefined (qualify v) (arrowArity ty) -> (fromQualType m ty)-> isValue (DataConstructor _ _) = False-> isValue (NewtypeConstructor _ _) = False-> isValue (Value _ _) = True-> isValue (Label _ _ _) = False---\end{verbatim}-A module which doesn't contain a \texttt{module ... where} declaration-obtains its filename as module identifier (unlike the definition in-Haskell and original MCC where a module obtains \texttt{main}).-\begin{verbatim}--> patchModuleId :: FilePath -> Module -> Module-> patchModuleId fn (Module mid mexports decls)-> | (moduleName mid) == "main"-> = Module (mkMIdent [takeBaseName fn]) mexports decls-> | otherwise-> = Module mid mexports decls---\end{verbatim}-Error functions.-\begin{verbatim}--> interfaceNotFound :: ModuleIdent -> String-> interfaceNotFound m = "Interface for module " ++ moduleName m ++ " not found"--> cyclicImport :: ModuleIdent -> [ModuleIdent] -> String-> cyclicImport m [] = "Recursive import for module " ++ moduleName m-> cyclicImport m ms =-> "Cyclic import dependency between modules " ++ moduleName m ++-> modules "" ms-> where modules comma [m] = comma ++ " and " ++ moduleName m-> modules _ (m:ms) = ", " ++ moduleName m ++ modules "," ms--> wrongInterface :: ModuleIdent -> ModuleIdent -> String-> wrongInterface m m' =-> "Expected interface for " ++ show m ++ " but found " ++ show m'--\end{verbatim}-----> bindFlatInterface :: Prog -> ModuleEnv -> ModuleEnv-> bindFlatInterface (Prog m imps ts fs os)-> = Map.insert (mkMIdent [m])-> ((map genIImportDecl imps)-> ++ (map genITypeDecl ts')-> ++ (map genIFuncDecl fs)-> ++ (map genIOpDecl os))-> where-> genIImportDecl :: String -> IDecl-> genIImportDecl imp = IImportDecl pos (mkMIdent [imp])->-> genITypeDecl :: TypeDecl -> IDecl-> genITypeDecl (Type qn _ is cs)-> | recordExt `isPrefixOf` localName qn-> = ITypeDecl pos-> (genQualIdent qn)-> (map (genVarIndexIdent "a") is)-> (RecordType (map genLabeledType cs) Nothing)-> | otherwise-> = IDataDecl pos -> (genQualIdent qn) -> (map (genVarIndexIdent "a") is) -> (map (Just . genConstrDecl) cs)-> genITypeDecl (TypeSyn qn _ is t)-> = ITypeDecl pos-> (genQualIdent qn)-> (map (genVarIndexIdent "a") is)-> (genTypeExpr t)->-> genIFuncDecl :: FuncDecl -> IDecl-> genIFuncDecl (Func qn a _ t _) -> = IFunctionDecl pos (genQualIdent qn) a (genTypeExpr t)->-> genIOpDecl :: OpDecl -> IDecl-> genIOpDecl (Op qn f p) = IInfixDecl pos (genInfix f) p (genQualIdent qn)->-> genConstrDecl :: ConsDecl -> ConstrDecl-> genConstrDecl (Cons qn _ _ ts)-> = ConstrDecl pos [] (mkIdent (localName qn)) (map genTypeExpr ts)->-> genLabeledType :: EF.ConsDecl -> ([Ident],Curry.Syntax.TypeExpr)-> genLabeledType (Cons qn _ _ [t])-> = ([renameLabel (fromLabelExtId (mkIdent $ localName qn))], genTypeExpr t)->-> genTypeExpr :: EF.TypeExpr -> Curry.Syntax.TypeExpr-> genTypeExpr (TVar i)-> = VariableType (genVarIndexIdent "a" i)-> genTypeExpr (FuncType t1 t2) -> = ArrowType (genTypeExpr t1) (genTypeExpr t2)-> genTypeExpr (TCons qn ts) -> = ConstructorType (genQualIdent qn) (map genTypeExpr ts)->-> genInfix :: EF.Fixity -> Infix-> genInfix EF.InfixOp = Infix-> genInfix EF.InfixlOp = InfixL-> genInfix EF.InfixrOp = InfixR->-> genQualIdent :: EF.QName -> QualIdent-> genQualIdent EF.QName{modName=mod,localName=name} = -> qualifyWith (mkMIdent [mod]) (mkIdent name)->-> genVarIndexIdent :: String -> Int -> Ident-> genVarIndexIdent v i = mkIdent (v ++ show i)->-> isSpecialPreludeType :: TypeDecl -> Bool-> isSpecialPreludeType (Type EF.QName{modName=mod,localName=name} _ _ _) -> = (name == "[]" || name == "()") && mod == "Prelude"-> isSpecialPreludeType _ = False->-> pos = P.first m-> ts' = filter (not . isSpecialPreludeType) ts-----\end{verbatim}-The label environment is used to store information of labels.-Unlike unsual identifiers like in functions, types etc. identifiers-of labels are always represented unqualified. Since the common type -environment (type \texttt{ValueEnv}) has some problems with handling -imported unqualified identifiers, it is necessary to process the type -information for labels seperately.-\begin{verbatim}--> data LabelInfo = LabelType Ident QualIdent Type deriving Show--> type LabelEnv = Map.Map Ident [LabelInfo]--> bindLabelType :: Ident -> QualIdent -> Type -> LabelEnv -> LabelEnv-> bindLabelType l r ty = Map.insertWith (++) l [LabelType l r ty]-
− src/NestEnv.lhs
@@ -1,77 +0,0 @@--% $Id: NestEnv.lhs,v 1.11 2003/10/04 17:04:23 wlux Exp $-%-% Copyright (c) 1999-2003, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{NestEnv.lhs}-\subsection{Nested Environments}-The \texttt{NestEnv} environment type extends top-level environments-(see section~\ref{sec:toplevel-env}) to manage nested scopes. Local-scopes allow only for a single, unambiguous definition.--As a matter of convenience, the module \texttt{TopEnv} is exported by-the module \texttt{NestEnv}. Thus, only the latter needs to be-imported.-\begin{verbatim}--> module NestEnv(module TopEnv, NestEnv, bindNestEnv,qualBindNestEnv,-> lookupNestEnv,qualLookupNestEnv,-> toplevelEnv,globalEnv,nestEnv) where--> import qualified Data.Map as Map--> import Curry.Base.Ident--> import TopEnv---> data NestEnv a = GlobalEnv (TopEnv a) | LocalEnv (NestEnv a) (Map.Map Ident a)-> -- deriving Show--> instance Functor NestEnv where-> fmap f (GlobalEnv env) = GlobalEnv (fmap f env)-> fmap f (LocalEnv genv env) = LocalEnv (fmap f genv) (fmap f env)--> bindNestEnv :: Ident -> a -> NestEnv a -> NestEnv a-> bindNestEnv x y (GlobalEnv env) -> = GlobalEnv (bindTopEnv "NestEnv.bindNestEnv" x y env)-> bindNestEnv x y (LocalEnv genv env) =-> case Map.lookup x env of-> Just _ -> error "internal error: bindNestEnv"-> Nothing -> LocalEnv genv (Map.insert x y env)--> qualBindNestEnv :: QualIdent -> a -> NestEnv a -> NestEnv a-> qualBindNestEnv x y (GlobalEnv env) -> = GlobalEnv (qualBindTopEnv "NestEnv.qualBindNestEnv" x y env)-> qualBindNestEnv x y (LocalEnv genv env)-> | isQualified x = error "internal error: qualBindNestEnv"-> | otherwise =-> case Map.lookup x' env of-> Just _ -> error "internal error: qualBindNestEnv"-> Nothing -> LocalEnv genv (Map.insert x' y env)-> where x' = unqualify x--> lookupNestEnv :: Ident -> NestEnv a -> [a]-> lookupNestEnv x (GlobalEnv env) = lookupTopEnv x env-> lookupNestEnv x (LocalEnv genv env) =-> case Map.lookup x env of-> Just y -> [y]-> Nothing -> lookupNestEnv x genv--> qualLookupNestEnv :: QualIdent -> NestEnv a -> [a]-> qualLookupNestEnv x env-> | isQualified x = qualLookupTopEnv x (toplevelEnv env)-> | otherwise = lookupNestEnv (unqualify x) env--> toplevelEnv :: NestEnv a -> TopEnv a-> toplevelEnv (GlobalEnv env) = env-> toplevelEnv (LocalEnv genv _) = toplevelEnv genv--> globalEnv :: TopEnv a -> NestEnv a-> globalEnv = GlobalEnv--> nestEnv :: NestEnv a -> NestEnv a-> nestEnv env = LocalEnv env Map.empty--\end{verbatim}
− src/OldScopeEnv.hs
@@ -1,165 +0,0 @@-module OldScopeEnv (ScopeEnv,- newScopeEnv,- insertIdent, getIdentLevel,- isVisible, isDeclared,- beginScope, endScope,- getLevel,- genIdent, genIdentList) where--import Data.Maybe-import qualified Data.Map as Map--import Curry.Base.Ident-------------------------------------------------------------------------------------- Type for representing an environment containing identifiers in several--- scope levels-type ScopeEnv = (IdEnv, [IdEnv], Int)------------------------------------------------------------------------------------- Generates a new instance of a scope table-newScopeEnv :: ScopeEnv-newScopeEnv = (Map.empty, [], 0)----- Inserts an identifier into the current level of the scope environment-insertIdent :: Ident -> ScopeEnv -> ScopeEnv-insertIdent ident (topleveltab, leveltabs, level)- = case leveltabs of- (lt:lts) -> (topleveltab, (insertId level ident lt):lts, level)- [] -> ((insertId level ident topleveltab), [], 0)----- Returns the declaration level of an identifier if it exists-getIdentLevel :: Ident -> ScopeEnv -> Maybe Int-getIdentLevel ident (topleveltab, leveltabs, _)- = case leveltabs of- (lt:_) -> maybe (getIdLevel ident topleveltab) Just (getIdLevel ident lt)- [] -> getIdLevel ident topleveltab----- Checks whether the specified identifier is visible in the current scope--- (i.e. checks whether the identifier occurs in the scope environment)-isVisible :: Ident -> ScopeEnv -> Bool-isVisible ident (topleveltab, leveltabs, _)- = case leveltabs of- (lt:_) -> idExists ident lt || idExists ident topleveltab- [] -> idExists ident topleveltab----- Checks whether the specified identifier is declared in the--- current scope (i.e. checks whether the identifier occurs in the--- current level of the scope environment)-isDeclared :: Ident -> ScopeEnv -> Bool-isDeclared ident (topleveltab, leveltabs, level)- = case leveltabs of- (lt:_) -> maybe False ((==) level) (getIdLevel ident lt)- [] -> maybe False ((==) 0) (getIdLevel ident topleveltab)----- Increases the level of the scope.-beginScope :: ScopeEnv -> ScopeEnv-beginScope (topleveltab, leveltabs, level)- = case leveltabs of- (lt:lts) -> (topleveltab, (lt:lt:lts), level + 1)- [] -> (topleveltab, [Map.empty], 1)----- Decreases the level of the scope. Identifier from higher levels--- will be lost.-endScope :: ScopeEnv -> ScopeEnv-endScope (topleveltab, leveltabs, level)- = case leveltabs of- (_:lts) -> (topleveltab, lts, level - 1)- [] -> (topleveltab, [], 0)----- Returns the level of the current scope. Top level is 0-getLevel :: ScopeEnv -> Int-getLevel (_, _, level) = level----- Generates a new identifier for the specified name. The new identifier is --- unique within the current scope. If no identifier can be generated for --- 'name' then 'Nothing' will be returned-genIdent :: String -> ScopeEnv -> Maybe Ident-genIdent name (topleveltab, leveltabs, _)- = case leveltabs of- (lt:_) -> genId name lt- [] -> genId name topleveltab----- Generates a list of new identifiers where each identifier has--- the prefix 'name' followed by an index (i.e. "var3" if 'name' was "var").--- All returned identifiers are unique within the current scope.-genIdentList :: Int -> String -> ScopeEnv -> [Ident]-genIdentList size name scopeenv = p_genIdentList size name scopeenv 0- where- p_genIdentList s n env i- | s == 0 - = []- | otherwise- = maybe (p_genIdentList s n env (i + 1))- (\ident -> ident:(p_genIdentList (s - 1) - n - (insertIdent ident env) - (i + 1)))- (genIdent (n ++ (show i)) env)---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Private declarations...--type IdEnv = Map.Map IdRep Int--data IdRep = Name String | Index Int deriving (Eq, Ord)----------------------------------------------------------------------------------------insertId :: Int -> Ident -> IdEnv -> IdEnv-insertId level ident env- = Map.insert (Name (name ident)) - level - (Map.insert (Index (uniqueId ident)) level env)------idExists :: Ident -> IdEnv -> Bool-idExists ident env = indexExists (uniqueId ident) env------getIdLevel :: Ident -> IdEnv -> Maybe Int-getIdLevel ident env = Map.lookup (Index (uniqueId ident)) env------genId n env- | nameExists n env = Nothing- | otherwise = Just (p_genId (mkIdent n) 0)- where- p_genId ident index- | indexExists index env = p_genId ident (index + 1)- | otherwise = renameIdent ident index------nameExists :: String -> IdEnv -> Bool-nameExists name env = isJust (Map.lookup (Name name) env)------indexExists :: Int -> IdEnv -> Bool-indexExists index env = isJust (Map.lookup (Index index) env)------------------------------------------------------------------------------------------------------------------------------------------------------------------
− src/PatchPrelude.hs
@@ -1,40 +0,0 @@-module PatchPrelude where---import Curry.ExtendedFlat.Type----- the prelude has to be extended by data declarations for list and tuples--prelude = "Prelude"--patchPreludeFCY :: Prog -> Prog-patchPreludeFCY (Prog name imports types funcs ops)- | name == prelude- = Prog name [] (prelude_types_fcy ++ types) funcs ops- | otherwise- = Prog name imports types funcs ops--prelude_types_fcy :: [TypeDecl]-prelude_types_fcy =- let unit = mkQName (prelude,"()")- nil = mkQName (prelude,"[]") in- [Type unit Public [] [(Cons unit 0 Public [])],- Type nil Public [0] - [Cons nil 0 Public [],- Cons (mkQName (prelude,":")) 2 Public - [TVar 0, TCons nil [TVar 0]]]] ++- map tupleType [2..maxTupleArity]--tupleType ar = - let tuplecons = mkQName (prelude,"("++take (ar-1) (repeat ',')++")") in- Type tuplecons Public [0..ar-1]- [Cons tuplecons ar Public (map TVar [0..ar-1])]---- Maximal arity of tuples:-maxTupleArity = 15-------------------------------------------------------------------------------------------------------------------------------------------------------------------
− src/PrecCheck.lhs
@@ -1,461 +0,0 @@--% $Id: PrecCheck.lhs,v 1.21 2004/02/15 22:10:34 wlux Exp $-%-% Copyright (c) 2001-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{PrecCheck.lhs}-\section{Checking Precedences of Infix Operators}-The parser does not know the relative precedences of infix operators-and therefore parses them as if they all associate to the right and-have the same precedence. After performing the definition checks,-the compiler is going to process the infix applications in the module-and rearrange infix applications according to the relative precedences-of the operators involved.-\begin{verbatim}--> module PrecCheck(precCheck) where--> import Data.List--> import Curry.Base.Position-> import Curry.Base.Ident-> import Curry.Syntax-> import Curry.Syntax.Utils--> import Base--\end{verbatim}-For each declaration group, including the module-level, the compiler-first checks that its fixity declarations contain no duplicates and-that there is a corresponding value or constructor declaration in that-group. The fixity declarations are then used for extending the-imported precedence environment.-\begin{verbatim}--> bindPrecs :: ModuleIdent -> [Decl] -> PEnv -> PEnv-> bindPrecs m ds pEnv =-> case findDouble ops of-> Nothing ->-> case [ op | op <- ops, op `notElem` bvs] of-> [] -> foldr bindPrec pEnv fixDs-> op : _ -> errorAt' (undefinedOperator op)-> Just op -> errorAt' (duplicatePrecedence op)-> where (fixDs,nonFixDs) = partition isInfixDecl ds-> bvs = concatMap boundValues nonFixDs-> ops = [ op | InfixDecl p _ _ ops <- fixDs, op <- ops]-> bindPrec (InfixDecl _ fix pr ops) pEnv-> | p == defaultP = pEnv-> | otherwise = foldr (flip (bindP m) p) pEnv ops-> where p = OpPrec fix pr--> boundValues :: Decl -> [Ident]-> boundValues (DataDecl _ _ _ cs) = map constr cs-> where constr (ConstrDecl _ _ c _) = c-> constr (ConOpDecl _ _ _ op _) = op-> boundValues (NewtypeDecl _ _ _ (NewConstrDecl _ _ c _)) = [c]-> boundValues (FunctionDecl _ f _) = [f]-> boundValues (ExternalDecl _ _ _ f _) = [f]-> boundValues (FlatExternalDecl _ fs) = fs-> boundValues (PatternDecl _ t _) = bv t-> boundValues (ExtraVariables _ vs) = vs-> boundValues _ = []--\end{verbatim}-With the help of the precedence environment, the compiler checks all-infix applications and sections in the program. This pass will modify-the parse tree such that for a nested infix application the operator-with the lowest precedence becomes the root and that two adjacent-operators with the same precedence will not have conflicting-associativities. Note that the top-level precedence environment has to-be returned because it is needed for constructing the module's-interface.-\begin{verbatim}--> precCheck :: ModuleIdent -> PEnv -> [Decl] -> (PEnv,[Decl])-> precCheck = checkDecls--> checkDecls :: ModuleIdent -> PEnv -> [Decl] -> (PEnv,[Decl])-> checkDecls m pEnv ds = pEnv' `seq` (pEnv',ds')-> where pEnv' = bindPrecs m ds pEnv-> ds' = map (checkDecl m pEnv') ds--> checkDecl :: ModuleIdent -> PEnv -> Decl -> Decl-> checkDecl m pEnv (FunctionDecl p f eqs) =-> FunctionDecl p f (map (checkEqn m pEnv) eqs)-> checkDecl m pEnv (PatternDecl p t rhs) =-> PatternDecl p (checkConstrTerm pEnv t) (checkRhs m pEnv rhs)-> checkDecl _ _ d = d--> checkEqn :: ModuleIdent -> PEnv -> Equation -> Equation-> checkEqn m pEnv (Equation p lhs rhs) =-> Equation p (checkLhs pEnv lhs) (checkRhs m pEnv rhs)--> checkLhs :: PEnv -> Lhs -> Lhs-> checkLhs pEnv (FunLhs f ts) = FunLhs f (map (checkConstrTerm pEnv) ts)-> checkLhs pEnv (OpLhs t1 op t2) = t1' `seq` t2' `seq` OpLhs t1' op t2'-> where t1' = checkOpL pEnv op (checkConstrTerm pEnv t1)-> t2' = checkOpR pEnv op (checkConstrTerm pEnv t2)-> checkLhs pEnv (ApLhs lhs ts) =-> ApLhs (checkLhs pEnv lhs) (map (checkConstrTerm pEnv) ts)--> checkConstrTerm :: PEnv -> ConstrTerm -> ConstrTerm-> checkConstrTerm _ (LiteralPattern l) = LiteralPattern l-> checkConstrTerm _ (NegativePattern op l) = NegativePattern op l-> checkConstrTerm _ (VariablePattern v) = VariablePattern v-> checkConstrTerm pEnv (ConstructorPattern c ts) =-> ConstructorPattern c (map (checkConstrTerm pEnv) ts)-> checkConstrTerm pEnv (InfixPattern t1 op t2) =-> fixPrecT pEnv InfixPattern-> (checkConstrTerm pEnv t1) op (checkConstrTerm pEnv t2)-> checkConstrTerm pEnv (ParenPattern t) =-> ParenPattern (checkConstrTerm pEnv t)-> checkConstrTerm pEnv (TuplePattern p ts) =-> TuplePattern p (map (checkConstrTerm pEnv) ts)-> checkConstrTerm pEnv (ListPattern p ts) =-> ListPattern p (map (checkConstrTerm pEnv) ts)-> checkConstrTerm pEnv (AsPattern v t) =-> AsPattern v (checkConstrTerm pEnv t)-> checkConstrTerm pEnv (LazyPattern p t) =-> LazyPattern p (checkConstrTerm pEnv t)-> checkConstrTerm pEnv (FunctionPattern f ts) =-> FunctionPattern f (map (checkConstrTerm pEnv) ts)-> checkConstrTerm pEnv (InfixFuncPattern t1 op t2) =-> fixPrecT pEnv InfixFuncPattern -> (checkConstrTerm pEnv t1) op (checkConstrTerm pEnv t2)-> checkConstrTerm pEnv (RecordPattern fs r) =-> RecordPattern (map (checkFieldPattern pEnv) fs)-> (maybe Nothing (Just . checkConstrTerm pEnv) r)--> checkFieldPattern :: PEnv -> Field ConstrTerm -> Field ConstrTerm-> checkFieldPattern pEnv (Field p label patt) =-> Field p label (checkConstrTerm pEnv patt)--> checkRhs :: ModuleIdent -> PEnv -> Rhs -> Rhs-> checkRhs m pEnv (SimpleRhs p e ds) = SimpleRhs p (checkExpr m pEnv' e) ds'-> where (pEnv',ds') = checkDecls m pEnv ds-> checkRhs m pEnv (GuardedRhs es ds) =-> GuardedRhs (map (checkCondExpr m pEnv') es) ds'-> where (pEnv',ds') = checkDecls m pEnv ds--> checkCondExpr :: ModuleIdent -> PEnv -> CondExpr -> CondExpr-> checkCondExpr m pEnv (CondExpr p g e) =-> CondExpr p (checkExpr m pEnv g) (checkExpr m pEnv e)--> checkExpr :: ModuleIdent -> PEnv -> Expression -> Expression-> checkExpr _ _ (Literal l) = Literal l-> checkExpr _ _ (Variable v) = Variable v-> checkExpr _ _ (Constructor c) = Constructor c-> checkExpr m pEnv (Paren e) = Paren (checkExpr m pEnv e)-> checkExpr m pEnv (Typed e ty) = Typed (checkExpr m pEnv e) ty-> checkExpr m pEnv (Tuple p es) = Tuple p (map (checkExpr m pEnv) es)-> checkExpr m pEnv (List p es) = List p (map (checkExpr m pEnv) es)-> checkExpr m pEnv (ListCompr p e qs) = ListCompr p (checkExpr m pEnv' e) qs'-> where (pEnv',qs') = mapAccumL (checkStmt m ) pEnv qs-> checkExpr m pEnv (EnumFrom e) = EnumFrom (checkExpr m pEnv e)-> checkExpr m pEnv (EnumFromThen e1 e2) =-> EnumFromThen (checkExpr m pEnv e1) (checkExpr m pEnv e2)-> checkExpr m pEnv (EnumFromTo e1 e2) =-> EnumFromTo (checkExpr m pEnv e1) (checkExpr m pEnv e2)-> checkExpr m pEnv (EnumFromThenTo e1 e2 e3) =-> EnumFromThenTo (checkExpr m pEnv e1)-> (checkExpr m pEnv e2)-> (checkExpr m pEnv e3)-> checkExpr m pEnv (UnaryMinus op e) = UnaryMinus op (checkExpr m pEnv e)-> checkExpr m pEnv (Apply e1 e2) =-> Apply (checkExpr m pEnv e1) (checkExpr m pEnv e2)-> checkExpr m pEnv (InfixApply e1 op e2) =-> fixPrec pEnv (checkExpr m pEnv e1) op (checkExpr m pEnv e2)-> checkExpr m pEnv (LeftSection e op) =-> checkLSection pEnv op (checkExpr m pEnv e)-> checkExpr m pEnv (RightSection op e) =-> checkRSection pEnv op (checkExpr m pEnv e)-> checkExpr m pEnv (Lambda r ts e) =-> Lambda r (map (checkConstrTerm pEnv) ts) (checkExpr m pEnv e)-> checkExpr m pEnv (Let ds e) = Let ds' (checkExpr m pEnv' e)-> where (pEnv',ds') = checkDecls m pEnv ds-> checkExpr m pEnv (Do sts e) = Do sts' (checkExpr m pEnv' e)-> where (pEnv',sts') = mapAccumL (checkStmt m ) pEnv sts-> checkExpr m pEnv (IfThenElse r e1 e2 e3) =-> IfThenElse r (checkExpr m pEnv e1)-> (checkExpr m pEnv e2)-> (checkExpr m pEnv e3)-> checkExpr m pEnv (Case r e alts) =-> Case r (checkExpr m pEnv e) (map (checkAlt m pEnv) alts)-> checkExpr m pEnv (RecordConstr fs) =-> RecordConstr (map (checkFieldExpr m pEnv) fs)-> checkExpr m pEnv (RecordSelection e label) =-> RecordSelection (checkExpr m pEnv e) label-> checkExpr m pEnv (RecordUpdate fs e) =-> RecordUpdate (map (checkFieldExpr m pEnv) fs) (checkExpr m pEnv e)--> checkFieldExpr :: ModuleIdent -> PEnv -> Field Expression -> Field Expression-> checkFieldExpr m pEnv (Field p label e) =-> Field p label (checkExpr m pEnv e)--> checkStmt :: ModuleIdent -> PEnv -> Statement -> (PEnv,Statement)-> checkStmt m pEnv (StmtExpr p e) = (pEnv,StmtExpr p (checkExpr m pEnv e))-> checkStmt m pEnv (StmtDecl ds) = pEnv' `seq` (pEnv',StmtDecl ds')-> where (pEnv',ds') = checkDecls m pEnv ds-> checkStmt m pEnv (StmtBind p t e) =-> (pEnv,StmtBind p (checkConstrTerm pEnv t) (checkExpr m pEnv e))--> checkAlt :: ModuleIdent -> PEnv -> Alt -> Alt-> checkAlt m pEnv (Alt p t rhs) =-> Alt p (checkConstrTerm pEnv t) (checkRhs m pEnv rhs)--\end{verbatim}-The functions \texttt{fixPrec}, \texttt{fixUPrec}, and-\texttt{fixRPrec} check the relative precedences of adjacent infix-operators in nested infix applications and unary negations. The-expressions will be reordered such that the infix operator with the-lowest precedence becomes the root of the expression. \emph{The-functions rely on the fact that the parser constructs infix-applications in a right-associative fashion}, i.e., the left argument-of an infix application will never be an infix application. In-addition, a unary negation will never have an infix application as-its argument.--The function \texttt{fixPrec} checks whether the left argument of an-infix application is a unary negation and eventually reorders the-expression if the precedence of the infix operator is higher than that-of the negation. This will be done with the help of the function-\texttt{fixUPrec}. In any case, the function \texttt{fixRPrec} is used-for fixing the precedence of the infix operator and that of its right-argument. Note that both arguments already have been checked before-\texttt{fixPrec} is called.-\begin{verbatim}--> fixPrec :: PEnv -> Expression -> InfixOp -> Expression-> -> Expression-> fixPrec pEnv (UnaryMinus uop e1) op e2-> | pr < 6 || pr == 6 && fix == InfixL =-> fixRPrec pEnv (UnaryMinus uop e1) op e2-> | pr > 6 = fixUPrec pEnv uop e1 op e2-> | otherwise = errorAt' $ ambiguousParse "unary" (qualify uop) (opName op)-> where OpPrec fix pr = opPrec op pEnv-> fixPrec pEnv e1 op e2 = fixRPrec pEnv e1 op e2--> fixUPrec :: PEnv -> Ident -> Expression -> InfixOp -> Expression-> -> Expression-> fixUPrec pEnv uop _ op (UnaryMinus _ _) =-> errorAt' $ ambiguousParse "operator" (opName op) (qualify uop)-> fixUPrec pEnv uop e1 op1 (InfixApply e2 op2 e3)-> | pr2 < 6 || pr2 == 6 && fix2 == InfixL =-> InfixApply (fixUPrec pEnv uop e1 op1 e2) op2 e3-> | pr2 > 6 = UnaryMinus uop (fixRPrec pEnv e1 op1 (InfixApply e2 op2 e3))-> | otherwise = errorAt' $ ambiguousParse "unary" (qualify uop) (opName op2)-> where OpPrec fix2 pr2 = opPrec op2 pEnv-> fixUPrec _ uop e1 op e2 = UnaryMinus uop (InfixApply e1 op e2)--> fixRPrec :: PEnv -> Expression -> InfixOp -> Expression-> -> Expression-> fixRPrec pEnv e1 op (UnaryMinus uop e2)-> | pr < 6 = InfixApply e1 op (UnaryMinus uop e2)-> | otherwise =-> errorAt' $ ambiguousParse "operator" (opName op) (qualify uop)-> where OpPrec _ pr = opPrec op pEnv-> fixRPrec pEnv e1 op1 (InfixApply e2 op2 e3)-> | pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR =-> InfixApply e1 op1 (InfixApply e2 op2 e3)-> | pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL =-> InfixApply (fixPrec pEnv e1 op1 e2) op2 e3-> | otherwise =-> errorAt' $ ambiguousParse "operator" (opName op1) (opName op2)-> where OpPrec fix1 pr1 = opPrec op1 pEnv-> OpPrec fix2 pr2 = opPrec op2 pEnv-> fixRPrec _ e1 op e2 = InfixApply e1 op e2--\end{verbatim}-The functions \texttt{checkLSection} and \texttt{checkRSection} are-used for handling the precedences inside left and right sections.-These functions only need to check that an infix operator occurring in-the section has either a higher precedence than the section operator-or both operators have the same precedence and are both left-associative for a left section and right associative for a right-section, respectively.-\begin{verbatim}--> checkLSection :: PEnv -> InfixOp -> Expression -> Expression-> checkLSection pEnv op e@(UnaryMinus uop _)-> | pr < 6 || pr == 6 && fix == InfixL = LeftSection e op-> | otherwise = errorAt' $ ambiguousParse "unary" (qualify uop) (opName op)-> where OpPrec fix pr = opPrec op pEnv-> checkLSection pEnv op1 e@(InfixApply _ op2 _)-> | pr1 < pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL =-> LeftSection e op1-> | otherwise =-> errorAt' $ ambiguousParse "operator" (opName op1) (opName op2)-> where OpPrec fix1 pr1 = opPrec op1 pEnv-> OpPrec fix2 pr2 = opPrec op2 pEnv-> checkLSection _ op e = LeftSection e op--> checkRSection :: PEnv -> InfixOp -> Expression -> Expression-> checkRSection pEnv op e@(UnaryMinus uop _)-> | pr < 6 = RightSection op e-> | otherwise = errorAt' $ ambiguousParse "unary" (qualify uop) (opName op)-> where OpPrec _ pr = opPrec op pEnv-> checkRSection pEnv op1 e@(InfixApply _ op2 _)-> | pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR =-> RightSection op1 e-> | otherwise =-> errorAt' $ ambiguousParse "operator" (opName op1) (opName op2)-> where OpPrec fix1 pr1 = opPrec op1 pEnv-> OpPrec fix2 pr2 = opPrec op2 pEnv-> checkRSection _ op e = RightSection op e--\end{verbatim}-The functions \texttt{fixPrecT} and \texttt{fixRPrecT} check the-relative precedences of adjacent infix operators in patterns. The-patterns will be reordered such that the infix operator with the-lowest precedence becomes the root of the term. \emph{The functions-rely on the fact that the parser constructs infix patterns in a-right-associative fashion}, i.e., the left argument of an infix pattern-will never be an infix pattern. The functions also check whether the-left and right arguments of an infix pattern are negative literals. In-this case, the negation must bind more tightly than the operator for-the pattern to be accepted.-\begin{verbatim}--> fixPrecT :: PEnv -> -> (ConstrTerm -> QualIdent -> ConstrTerm -> ConstrTerm)-> -> ConstrTerm -> QualIdent -> ConstrTerm -> -> ConstrTerm-> fixPrecT pEnv infixpatt t1@(NegativePattern uop l) op t2-> | pr < 6 || pr == 6 && fix == InfixL -> = fixRPrecT pEnv infixpatt t1 op t2-> | otherwise -> = errorAt' $ invalidParse "unary" uop op-> where OpPrec fix pr = prec op pEnv-> fixPrecT pEnv infixpatt t1 op t2 -> = fixRPrecT pEnv infixpatt t1 op t2--> fixRPrecT :: PEnv -> -> (ConstrTerm -> QualIdent -> ConstrTerm -> ConstrTerm)-> -> ConstrTerm -> QualIdent -> ConstrTerm-> -> ConstrTerm-> fixRPrecT pEnv infixpatt t1 op t2@(NegativePattern uop l)-> | pr < 6 = infixpatt t1 op t2-> | otherwise = errorAt' $ invalidParse "unary" uop op-> where OpPrec _ pr = prec op pEnv-> fixRPrecT pEnv infixpatt t1 op1 (InfixPattern t2 op2 t3)-> | pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR-> = infixpatt t1 op1 (InfixPattern t2 op2 t3)-> | pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL-> = InfixPattern (fixPrecT pEnv infixpatt t1 op1 t2) op2 t3-> | otherwise -> = errorAt' $ ambiguousParse "operator" op1 op2-> where OpPrec fix1 pr1 = prec op1 pEnv-> OpPrec fix2 pr2 = prec op2 pEnv-> fixRPrecT pEnv infixpatt t1 op1 (InfixFuncPattern t2 op2 t3)-> | pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR-> = infixpatt t1 op1 (InfixFuncPattern t2 op2 t3)-> | pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL-> = InfixFuncPattern (fixPrecT pEnv infixpatt t1 op1 t2) op2 t3-> | otherwise -> = errorAt' $ ambiguousParse "operator" op1 op2-> where OpPrec fix1 pr1 = prec op1 pEnv-> OpPrec fix2 pr2 = prec op2 pEnv-> fixRPrecT _ infixpatt t1 op t2 = infixpatt t1 op t2--> {-fixPrecT :: Position -> PEnv -> ConstrTerm -> QualIdent -> ConstrTerm-> -> ConstrTerm-> fixPrecT p pEnv t1@(NegativePattern uop l) op t2-> | pr < 6 || pr == 6 && fix == InfixL = fixRPrecT p pEnv t1 op t2-> | otherwise = errorAt p $ invalidParse "unary" uop op-> where OpPrec fix pr = prec op pEnv-> fixPrecT p pEnv t1 op t2 = fixRPrecT p pEnv t1 op t2-}--> {-fixRPrecT :: Position -> PEnv -> ConstrTerm -> QualIdent -> ConstrTerm-> -> ConstrTerm-> fixRPrecT p pEnv t1 op t2@(NegativePattern uop l)-> | pr < 6 = InfixPattern t1 op t2-> | otherwise = errorAt p $ invalidParse "unary" uop op-> where OpPrec _ pr = prec op pEnv-> fixRPrecT p pEnv t1 op1 (InfixPattern t2 op2 t3)-> | pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR =-> InfixPattern t1 op1 (InfixPattern t2 op2 t3)-> | pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL =-> InfixPattern (fixPrecT p pEnv t1 op1 t2) op2 t3-> | otherwise = errorAt p $ ambiguousParse "operator" op1 op2-> where OpPrec fix1 pr1 = prec op1 pEnv-> OpPrec fix2 pr2 = prec op2 pEnv-> fixRPrecT _ _ t1 op t2 = InfixPattern t1 op t2-}--\end{verbatim}-The functions \texttt{checkOpL} and \texttt{checkOpR} check the left-and right arguments of an operator declaration. If they are infix-patterns they must bind more tightly than the operator, otherwise the-left-hand side of the declaration is invalid.-\begin{verbatim}--> checkOpL :: PEnv -> Ident -> ConstrTerm -> ConstrTerm-> checkOpL pEnv op t@(NegativePattern uop l)-> | pr < 6 || pr == 6 && fix == InfixL = t-> | otherwise = errorAt' $ invalidParse "unary" uop (qualify op)-> where OpPrec fix pr = prec (qualify op) pEnv-> checkOpL pEnv op1 t@(InfixPattern _ op2 _)-> | pr1 < pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL = t-> | otherwise = errorAt' $ invalidParse "operator" op1 op2-> where OpPrec fix1 pr1 = prec (qualify op1) pEnv-> OpPrec fix2 pr2 = prec op2 pEnv-> checkOpL _ _ t = t--> checkOpR :: PEnv -> Ident -> ConstrTerm -> ConstrTerm-> checkOpR pEnv op t@(NegativePattern uop l)-> | pr < 6 = t-> | otherwise = errorAt' $ invalidParse "unary" uop (qualify op)-> where OpPrec _ pr = prec (qualify op) pEnv-> checkOpR pEnv op1 t@(InfixPattern _ op2 _)-> | pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR = t-> | otherwise = errorAt' $ invalidParse "operator" op1 op2-> where OpPrec fix1 pr1 = prec (qualify op1) pEnv-> OpPrec fix2 pr2 = prec op2 pEnv-> checkOpR _ _ t = t--\end{verbatim}-The functions \texttt{opPrec} and \texttt{prec} return the fixity and-operator precedence of an entity. Even though precedence checking is-performed after the renaming phase, we have to be prepared to see-ambiguous identifiers here. This may happen while checking the root of-an operator definition that shadows an imported definition.-\begin{verbatim}--> opPrec :: InfixOp -> PEnv -> OpPrec-> opPrec op = prec (opName op)--> prec :: QualIdent -> PEnv -> OpPrec-> prec op env =-> case qualLookupP op env of-> [] -> defaultP-> PrecInfo _ p : _ -> p--\end{verbatim}-Error messages.-\begin{verbatim}--> undefinedOperator :: Ident -> (Position,String)-> undefinedOperator op = -> (positionOfIdent op,-> "no definition for " ++ name op ++ " in this scope")--> duplicatePrecedence :: Ident -> (Position,String)-> duplicatePrecedence op = -> (positionOfIdent op,-> "More than one fixity declaration for " ++ name op)--> invalidParse :: String -> Ident -> QualIdent -> (Position,String)-> invalidParse what op1 op2 =-> (positionOfIdent op1,-> "Invalid use of " ++ what ++ " " ++ name op1 ++ " with " ++ qualName op2 ++-> (showLine $ positionOfQualIdent op2))--> ambiguousParse :: String -> QualIdent -> QualIdent -> (Position,String)-> ambiguousParse what op1 op2 =-> (positionOfQualIdent op1,-> "Ambiguous use of " ++ what ++ " " ++ qualName op1 ++-> " with " ++ qualName op2 ++ (showLine $ positionOfQualIdent op2))--\end{verbatim}
− src/Qual.lhs
@@ -1,165 +0,0 @@--% $Id: Qual.lhs,v 1.18 2004/02/15 22:10:36 wlux Exp $-%-% Copyright (c) 2001-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{Qual.lhs}-\section{Proper Qualification}-After checking the module and before starting the translation into the-intermediate language, the compiler properly qualifies all-constructors and (global) functions occurring in a pattern or-expression such that their module prefix matches the module of their-definition. This is done also for functions and constructors declared-in the current module. Only functions and variables declared in local-declarations groups as well as function arguments remain unchanged.--\em{Note:} The modified version also qualifies type constructors-\begin{verbatim}--> module Qual(qual) where--> import Curry.Base.Ident-> import Curry.Syntax--> import Base-> import TopEnv--> qual :: ModuleIdent -> ValueEnv -> [Decl] -> [Decl]-> qual m tyEnv ds = map (qualDecl m tyEnv) ds--> qualDecl :: ModuleIdent -> ValueEnv -> Decl -> Decl-> qualDecl m tyEnv (FunctionDecl p f eqs) =-> FunctionDecl p f (map (qualEqn m tyEnv) eqs)-> qualDecl m tyEnv (PatternDecl p t rhs) =-> PatternDecl p (qualTerm m tyEnv t) (qualRhs m tyEnv rhs)-> qualDecl _ _ d = d--> qualEqn :: ModuleIdent -> ValueEnv -> Equation -> Equation-> qualEqn m tyEnv (Equation p lhs rhs) =-> Equation p (qualLhs m tyEnv lhs) (qualRhs m tyEnv rhs)--> qualLhs :: ModuleIdent -> ValueEnv -> Lhs -> Lhs-> qualLhs m tyEnv (FunLhs f ts) = FunLhs f (map (qualTerm m tyEnv) ts)-> qualLhs m tyEnv (OpLhs t1 op t2) =-> OpLhs (qualTerm m tyEnv t1) op (qualTerm m tyEnv t2)-> qualLhs m tyEnv (ApLhs lhs ts) =-> ApLhs (qualLhs m tyEnv lhs) (map (qualTerm m tyEnv) ts)--> qualTerm :: ModuleIdent -> ValueEnv -> ConstrTerm -> ConstrTerm-> qualTerm _ _ (LiteralPattern l) = LiteralPattern l-> qualTerm _ _ (NegativePattern op l) = NegativePattern op l-> qualTerm _ _ (VariablePattern v) = VariablePattern v-> qualTerm m tyEnv (ConstructorPattern c ts) =-> ConstructorPattern (qualIdent m tyEnv c) (map (qualTerm m tyEnv) ts)-> qualTerm m tyEnv (InfixPattern t1 op t2) =-> InfixPattern (qualTerm m tyEnv t1) -> (qualIdent m tyEnv op) -> (qualTerm m tyEnv t2)-> qualTerm m tyEnv (ParenPattern t) = ParenPattern (qualTerm m tyEnv t)-> qualTerm m tyEnv (TuplePattern p ts) = TuplePattern p (map (qualTerm m tyEnv) ts)-> qualTerm m tyEnv (ListPattern p ts) = ListPattern p (map (qualTerm m tyEnv) ts)-> qualTerm m tyEnv (AsPattern v t) = AsPattern v (qualTerm m tyEnv t)-> qualTerm m tyEnv (LazyPattern p t) = LazyPattern p (qualTerm m tyEnv t)-> qualTerm m tyEnv (FunctionPattern f ts) =-> FunctionPattern (qualIdent m tyEnv f) (map (qualTerm m tyEnv) ts)-> qualTerm m tyEnv (InfixFuncPattern t1 op t2) =-> InfixFuncPattern (qualTerm m tyEnv t1) -> (qualIdent m tyEnv op) -> (qualTerm m tyEnv t2)-> qualTerm m tyEnv (RecordPattern fs rt) =-> RecordPattern (map (qualFieldPattern m tyEnv) fs)-> (maybe Nothing (Just . qualTerm m tyEnv) rt)--> qualFieldPattern :: ModuleIdent -> ValueEnv -> Field ConstrTerm-> -> Field ConstrTerm-> qualFieldPattern m tyEnv (Field p l t) = Field p l (qualTerm m tyEnv t)--> qualRhs :: ModuleIdent -> ValueEnv -> Rhs -> Rhs-> qualRhs m tyEnv (SimpleRhs p e ds) =-> SimpleRhs p (qualExpr m tyEnv e) (map (qualDecl m tyEnv) ds) -> qualRhs m tyEnv (GuardedRhs es ds) =-> GuardedRhs (map (qualCondExpr m tyEnv) es) (map (qualDecl m tyEnv) ds)--> qualCondExpr :: ModuleIdent -> ValueEnv -> CondExpr -> CondExpr-> qualCondExpr m tyEnv (CondExpr p g e) =-> CondExpr p (qualExpr m tyEnv g) (qualExpr m tyEnv e)--> qualExpr :: ModuleIdent -> ValueEnv -> Expression -> Expression-> qualExpr _ _ (Literal l) = Literal l-> qualExpr m tyEnv (Variable v) = Variable (qualIdent m tyEnv v)-> qualExpr m tyEnv (Constructor c) = Constructor (qualIdent m tyEnv c)-> qualExpr m tyEnv (Paren e) = Paren (qualExpr m tyEnv e)-> qualExpr m tyEnv (Typed e ty) = Typed (qualExpr m tyEnv e) ty-> qualExpr m tyEnv (Tuple p es) = Tuple p (map (qualExpr m tyEnv) es)-> qualExpr m tyEnv (List p es) = List p (map (qualExpr m tyEnv) es)-> qualExpr m tyEnv (ListCompr p e qs) =-> ListCompr p (qualExpr m tyEnv e) (map (qualStmt m tyEnv) qs)-> qualExpr m tyEnv (EnumFrom e) = EnumFrom (qualExpr m tyEnv e)-> qualExpr m tyEnv (EnumFromThen e1 e2) =-> EnumFromThen (qualExpr m tyEnv e1) (qualExpr m tyEnv e2)-> qualExpr m tyEnv (EnumFromTo e1 e2) =-> EnumFromTo (qualExpr m tyEnv e1) (qualExpr m tyEnv e2)-> qualExpr m tyEnv (EnumFromThenTo e1 e2 e3) =-> EnumFromThenTo (qualExpr m tyEnv e1) -> (qualExpr m tyEnv e2) -> (qualExpr m tyEnv e3)-> qualExpr m tyEnv (UnaryMinus op e) = UnaryMinus op (qualExpr m tyEnv e)-> qualExpr m tyEnv (Apply e1 e2) = -> Apply (qualExpr m tyEnv e1) (qualExpr m tyEnv e2)-> qualExpr m tyEnv (InfixApply e1 op e2) =-> InfixApply (qualExpr m tyEnv e1) (qualOp m tyEnv op) (qualExpr m tyEnv e2)-> qualExpr m tyEnv (LeftSection e op) =-> LeftSection (qualExpr m tyEnv e) (qualOp m tyEnv op)-> qualExpr m tyEnv (RightSection op e) =-> RightSection (qualOp m tyEnv op) (qualExpr m tyEnv e)-> qualExpr m tyEnv (Lambda r ts e) =-> Lambda r (map (qualTerm m tyEnv) ts) (qualExpr m tyEnv e)-> qualExpr m tyEnv (Let ds e) = -> Let (map (qualDecl m tyEnv) ds) (qualExpr m tyEnv e)-> qualExpr m tyEnv (Do sts e) = -> Do (map (qualStmt m tyEnv) sts) (qualExpr m tyEnv e)-> qualExpr m tyEnv (IfThenElse r e1 e2 e3) =-> IfThenElse r (qualExpr m tyEnv e1) -> (qualExpr m tyEnv e2) -> (qualExpr m tyEnv e3)-> qualExpr m tyEnv (Case r e alts) =-> Case r (qualExpr m tyEnv e) (map (qualAlt m tyEnv) alts)-> qualExpr m tyEnv (RecordConstr fs) =-> RecordConstr (map (qualFieldExpr m tyEnv) fs)-> qualExpr m tyEnv (RecordSelection e l) =-> RecordSelection (qualExpr m tyEnv e) l-> qualExpr m tyEnv (RecordUpdate fs e) =-> RecordUpdate (map (qualFieldExpr m tyEnv) fs) (qualExpr m tyEnv e)--> qualStmt :: ModuleIdent -> ValueEnv -> Statement -> Statement-> qualStmt m tyEnv (StmtExpr p e) = StmtExpr p (qualExpr m tyEnv e)-> qualStmt m tyEnv (StmtBind p t e) =-> StmtBind p (qualTerm m tyEnv t) (qualExpr m tyEnv e)-> qualStmt m tyEnv (StmtDecl ds) = StmtDecl (map (qualDecl m tyEnv) ds)--> qualAlt :: ModuleIdent -> ValueEnv -> Alt -> Alt-> qualAlt m tyEnv (Alt p t rhs) = -> Alt p (qualTerm m tyEnv t) (qualRhs m tyEnv rhs)--> qualFieldExpr :: ModuleIdent -> ValueEnv -> Field Expression-> -> Field Expression-> qualFieldExpr m tyEnv (Field p l e) = Field p l (qualExpr m tyEnv e)--> qualOp :: ModuleIdent -> ValueEnv -> InfixOp -> InfixOp-> qualOp m tyEnv (InfixOp op) = InfixOp (qualIdent m tyEnv op)-> qualOp m tyEnv (InfixConstr op) = InfixConstr (qualIdent m tyEnv op)--> qualIdent :: ModuleIdent -> ValueEnv -> QualIdent -> QualIdent-> qualIdent m tyEnv x-> | not (isQualified x) && uniqueId (unqualify x) /= 0 = x-> | otherwise =-> case (qualLookupValue x tyEnv) of-> [y] -> origName y-> vs -> case (qualLookupValue (qualQualify m x) tyEnv) of-> [y] -> origName y-> _ -> qualQualify m x -- internalError ("qualIdent: " ++ show x)--\end{verbatim}
− src/SCC.lhs
@@ -1,60 +0,0 @@--% $Id: SCC.lhs,v 1.3 2003/04/30 21:29:06 wlux Exp $-%-% Copyright (c) 2000,2002-2003, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{SCC.lhs}-\section{Computing strongly connected components}-At various places in the compiler we had to partition a list of-declarations into strongly connected components. The function-\texttt{scc} computes this relation in two steps. First, the list is-topologically sorted ``downwards'' using the \emph{defs} relation.-Then the resulting list is sorted ``upwards'' using the \emph{uses}-relation and partitioned into the connected components. Both relations-are computed within this module using the bound and free names of each-declaration.--In order to avoid useless recomputations, the code in the module first-decorates the declarations with their bound and free names and a-unique number. The latter is only used to provide a trivial ordering-so that the declarations can be used as set elements.-\begin{verbatim}--> module SCC(scc) where--> import qualified Data.Set as Set--> data Node a b = Node{ key::Int, bvs::[b], fvs::[b], node::a }--> instance Eq (Node a b) where-> n1 == n2 = key n1 == key n2-> instance Ord (Node b a) where-> n1 `compare` n2 = key n1 `compare` key n2--> scc :: Eq b => (a -> [b]) -- entities defined by node-> -> (a -> [b]) -- entities used by node-> -> [a] -- list of nodes-> -> [[a]] -- strongly connected components-> scc bvs fvs = map (map node) . tsort' . tsort . zipWith wrap [0..]-> where wrap i n = Node i (bvs n) (fvs n) n--> tsort :: Eq b => [Node a b] -> [Node a b]-> tsort xs = snd (dfs xs Set.empty [])-> where dfs [] marks stack = (marks,stack)-> dfs (x:xs) marks stack-> | x `Set.member` marks = dfs xs marks stack-> | otherwise = dfs xs marks' (x:stack')-> where (marks',stack') = dfs (defs x) (x `Set.insert` marks) stack-> defs x = filter (any (`elem` fvs x) . bvs) xs--> tsort' :: Eq b => [Node a b] -> [[Node a b]]-> tsort' xs = snd (dfs xs Set.empty [])-> where dfs [] marks stack = (marks,stack)-> dfs (x:xs) marks stack-> | x `Set.member` marks = dfs xs marks stack-> | otherwise = dfs xs marks' ((x:concat stack'):stack)-> where (marks',stack') = dfs (uses x) (x `Set.insert` marks) []-> uses x = filter (any (`elem` bvs x) . fvs) xs--\end{verbatim}
− src/ScopeEnv.hs
@@ -1,175 +0,0 @@---------------------------------------------------------------------------------------------------------------------------------------------------------------------- ScopeEnv - provides functions and data types for dealing with nested--- scope environments to store data from nested scopes------ This module should be imported using "import qualified" to avoid name--- clashes------ November 2005,--- Martin Engelke (men@informatik.uni-kiel.de)----module ScopeEnv (ScopeEnv,- new, insert, update, modify, lookup, sureLookup,- level, exists, beginScope, endScope, endScopeUp,- toList, toLevelList, currentLevel) where--import qualified Data.Map as Map-import Prelude hiding (lookup)--------------------------------------------------------------------------------------------------------------------------------------------------------------------- Data type for representing information in nested scopes.-data ScopeEnv a b = ScopeEnv Int (Map.Map a (b,Int)) [Map.Map a (b,Int)]- deriving Show--------------------------------------------------------------------------------------------------------------------------------------------------------------------- Returns an empty scope environment-new :: Ord a => ScopeEnv a b-new = ScopeEnv 0 Map.empty []----- Inserts a value under a key into the environment of the current scope-insert :: Ord a => a -> b -> ScopeEnv a b -> ScopeEnv a b-insert key val env = modifySE insertLev env- where- insertLev lev local = Map.insert key (val,lev) local----- Updates the value stored under an existing key in the environment of --- the current scope-update :: Ord a => a -> b -> ScopeEnv a b -> ScopeEnv a b-update key val env = modifySE updateLev env- where- updateLev lev local = maybe local - (\ (_,lev') -> Map.insert key (val,lev') local)- (Map.lookup key local)---- Modifies the value of an existing key by applying the function 'fun'--- in the environment of the current scope-modify :: Ord a => (b -> b) -> a -> ScopeEnv a b -> ScopeEnv a b-modify fun key env = modifySE modifyLev env- where- modifyLev lev local - = maybe local- (\ (val',lev') -> Map.insert key (fun val', lev') local)- (Map.lookup key local)----- Looks up the value which is stored under a key from the environment of--- the current scope-lookup :: Ord a => a -> ScopeEnv a b -> Maybe b-lookup key env = selectSE lookupLev env- where- lookupLev lev local = maybe Nothing (Just . fst) (Map.lookup key local)----- Similar to 'lookup', but returns an alternative value, if the key--- doesn't exist in the environment of the current scope-sureLookup :: Ord a => a -> b -> ScopeEnv a b -> b-sureLookup key alt env = maybe alt id (lookup key env)----- Returns the level of the last insertion of a key-level :: Ord a => a -> ScopeEnv a b -> Int-level key env = selectSE levelLev env- where- levelLev lev local = maybe (-1) snd (Map.lookup key local)----- Checks, whether a key exists in the environment of the current scope-exists :: Ord a => a -> ScopeEnv a b -> Bool-exists key env = selectSE existsLev env- where- existsLev lev local = maybe False (const True) (Map.lookup key local)----- Switches to the next scope (i.e. pushes the environment of the current--- scope onto the top of an scope stack and increments the level counter)-beginScope :: Ord a => ScopeEnv a b -> ScopeEnv a b-beginScope (ScopeEnv lev top [])- = ScopeEnv (lev + 1) top [top]-beginScope (ScopeEnv lev top (local:locals))- = ScopeEnv (lev + 1) top (local:local:locals)----- Switches to the previous scope (i.e. pops the environment from the top--- of the scope stack and decrements the level counter)-endScope :: Ord a => ScopeEnv a b -> ScopeEnv a b-endScope (ScopeEnv _ top [])- = ScopeEnv 0 top []-endScope (ScopeEnv lev top (_:locals))- = ScopeEnv (lev - 1) top locals----- Behaves like 'endScope' but additionally updates the environment of--- the previous scope by updating all keys with the corresponding values--- from the poped environment-endScopeUp :: Ord a => ScopeEnv a b -> ScopeEnv a b-endScopeUp (ScopeEnv _ top [])- = ScopeEnv 0 top []-endScopeUp (ScopeEnv lev top (local:[]))- = ScopeEnv 0 (foldr (updateSE local) top (Map.toList top)) []-endScopeUp (ScopeEnv lev top (local:local':locals))- = ScopeEnv (lev - 1) - top - ((foldr (updateSE local) local' (Map.toList local')):locals)----- Returns the environment of current scope as a (key,value) list-toList :: Ord a => ScopeEnv a b -> [(a,b)]-toList env = selectSE toListLev env- where- toListLev lev local = map (\ (key,(val,_)) -> (key,val)) (Map.toList local)----- Returns all (key,value) pairs from the environment of the current scope --- which has been inserted in the current level-toLevelList :: Ord a => ScopeEnv a b -> [(a,b)]-toLevelList env = selectSE toLevelListLev env- where- toLevelListLev lev local- = map (\ (key,(val,_)) -> (key,val))- (filter (\ (_,(_,lev')) -> lev' == lev) (Map.toList local))----- Returns the current level-currentLevel :: Ord a => ScopeEnv a b -> Int-currentLevel env = selectSE const env--------------------------------------------------------------------------------------------------------------------------------------------------------------------- Privates...-----modifySE :: (Int -> Map.Map a (b,Int) -> Map.Map a (b,Int)) -> ScopeEnv a b - -> ScopeEnv a b-modifySE f (ScopeEnv _ top []) - = ScopeEnv 0 (f 0 top) []-modifySE f (ScopeEnv lev top (local:locals))- = ScopeEnv lev top ((f lev local):locals)-----selectSE :: (Int -> Map.Map a (b,Int) -> c) -> ScopeEnv a b -> c-selectSE f (ScopeEnv _ top []) = f 0 top-selectSE f (ScopeEnv lev _ (local:_)) = f lev local-----updateSE :: Ord a => Map.Map a (b,Int) -> (a,(b,Int)) -> Map.Map a (b,Int) - -> Map.Map a (b,Int)-updateSE local (key,(_,lev)) local'- = maybe local' - (\ (val',lev') - -> if lev == lev' then Map.insert key (val',lev) local' - else local')- (Map.lookup key local)-------------------------------------------------------------------------------------------------------------------------------------------------------------------
− src/Simplify.lhs
@@ -1,475 +0,0 @@-% $Id: Simplify.lhs,v 1.10 2004/02/13 14:02:58 wlux Exp $-%-% Copyright (c) 2003, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{Simplify.lhs}-\section{Optimizing the Desugared Code}\label{sec:simplify}-After desugaring the source code, but before lifting local-declarations, the compiler performs a few simple optimizations to-improve the efficiency of the generated code. In addition, the-optimizer replaces pattern bindings with simple variable bindings and-selector functions.--Currently, the following optimizations are implemented:-\begin{itemize}-\item Remove unused declarations.-\item Inline simple constants.-\item Compute minimal binding groups.-\item Under certain conditions, inline local function definitions.-\end{itemize}-\begin{verbatim}--> module Simplify(simplify) where--> import Control.Monad.Reader as R-> import Control.Monad.State as S-> import qualified Data.Map as Map--> import Curry.Base.Position-> import Curry.Base.Ident-> import Curry.Syntax-> import Curry.Syntax.Utils--> import Types-> import Base-> import SCC-> import Typing---> type SimplifyState a = S.StateT ValueEnv (ReaderT EvalEnv (S.State Int)) a-> type InlineEnv = Map.Map Ident Expression-> type SimplifyFlags = Bool- -> flatFlag :: SimplifyFlags -> Bool-> flatFlag x = x--> simplify :: SimplifyFlags -> ValueEnv -> EvalEnv -> Module -> (Module,ValueEnv)-> simplify flags tyEnv evEnv m -> = S.evalState (R.runReaderT (S.evalStateT (simplifyModule flags m) tyEnv) evEnv) 1--> simplifyModule :: SimplifyFlags -> Module -> SimplifyState (Module,ValueEnv)-> simplifyModule flat (Module m es ds) =-> do-> ds' <- mapM (simplifyDecl flat m Map.empty) ds-> tyEnv <- S.get-> return (Module m es ds',tyEnv)--> simplifyDecl :: SimplifyFlags -> ModuleIdent -> InlineEnv -> Decl -> SimplifyState Decl-> simplifyDecl flat m env (FunctionDecl p f eqs) =-> liftM (FunctionDecl p f . concat) (mapM (simplifyEquation flat m env) eqs)-> simplifyDecl flat m env (PatternDecl p t rhs) =-> liftM (PatternDecl p t) (simplifyRhs flat m env rhs)-> simplifyDecl _ _ _ d = return d--\end{verbatim}-After simplifying the right hand side of an equation, the compiler-transforms declarations of the form-\begin{quote}\tt- $f\;t_1\dots t_{k-k'}\;x_{k-k'+1}\dots x_{k}$ =- let $f'\;t'_1\dots t'_{k'}$ = $e$ in- $f'\;x_1\dots x_{k'}$-\end{quote}-into the equivalent definition-\begin{quote}\tt- $f\;t_1\dots t_{k-k'}\;(x_{k-k'+1}$@$t'_1)\dots(x_k$@$t'_{k'})$ = $e$-\end{quote}-where the arities of $f$ and $f'$ are $k$ and $k'$, respectively, and-$x_{k-k'+1},\dots,x_{k}$ are variables. This optimization was-introduced in order to avoid an auxiliary function being generated for-definitions whose right-hand side is a $\lambda$-expression, e.g.,-\verb|f . g = \x -> f (g x)|. This declaration is transformed into-\verb|(.) f g x = let lambda x = f (g x) in lambda x| by desugaring-and in turn is optimized into \verb|(.) f g x = f (g x)|, here. The-transformation can obviously be generalized to the case where $f'$ is-defined by more than one equation. However, we must be careful not to-change the evaluation mode of arguments. Therefore, the transformation-is applied only if $f$ and $f'$ use them same evaluation mode or all-of the arguments $t'_1,\dots,t'_k$ are variables. Actually, the-transformation could be applied to the case where the arguments-$t_1,\dots,t_{k-k'}$ are all variables as well, but in this case the-evaluation mode of $f$ may have to be changed to match that of $f'$.--We have to be careful with this optimization in conjunction with-newtype constructors. It is possible that the local function is-applied only partially, e.g., for-\begin{verbatim}- newtype ST s a = ST (s -> (a,s))- returnST x = ST (\s -> (x,s))-\end{verbatim}-the desugared code is equivalent to-\begin{verbatim}- returnST x = let lambda1 s = (x,s) in lambda1-\end{verbatim}-We must not ``optimize'' this into \texttt{returnST x s = (x,s)}-because the compiler assumes that \texttt{returnST} is a unary-function.--Note that this transformation is not strictly semantic preserving as-the evaluation order of arguments can be changed. This happens if $f$-is defined by more than one rule with overlapping patterns and the-local functions of each rule have disjoint patterns. As an example,-consider the function-\begin{verbatim}- f (Just x) _ = let g (Left z) = x + z in g- f _ (Just y) = let h (Right z) = y + z in h-\end{verbatim}-The definition of \texttt{f} is non-deterministic because of the-overlapping patterns in the first and second argument. However, the-optimized definition-\begin{verbatim}- f (Just x) _ (Left z) = x + z- f _ (Just y) (Right z) = y + z-\end{verbatim}-is deterministic. It will evaluate and match the third argument first,-whereas the original definition is going to evaluate the first or the-second argument first, depending on the non-deterministic branch-chosen. As such definitions are presumably rare, and the optimization-avoids a non-deterministic split of the computation, we put up with-the change of evaluation order.--This transformation is actually just a special case of inlining a-(local) function definition. We are unable to handle the general case-because it would require to represent the pattern matching code-explicitly in a Curry expression.-\begin{verbatim}--> simplifyEquation :: SimplifyFlags -> ModuleIdent -> InlineEnv -> Equation-> -> SimplifyState [Equation]-> simplifyEquation flat m env (Equation p lhs rhs) =-> do-> rhs' <- simplifyRhs flat m env rhs-> tyEnv <- S.get-> evEnv <- S.lift R.ask-> return (inlineFun flat m tyEnv evEnv p lhs rhs')--> inlineFun :: SimplifyFlags -> ModuleIdent -> ValueEnv -> EvalEnv -> Position -> Lhs -> Rhs-> -> [Equation]-> inlineFun flags m tyEnv evEnv p (FunLhs f ts)-> (SimpleRhs _ (Let [FunctionDecl _ f' eqs'] e) _)-> | True -- False -- inlining of functions is deactivated (hsi)-> && f' `notElem` qfv m eqs' && e' == Variable (qualify f') &&-> n == arrowArity (funType m tyEnv (qualify f')) &&-> (evMode evEnv f == evMode evEnv f' ||-> and [all isVarPattern ts | Equation _ (FunLhs _ ts) _ <- eqs']) =-> map (mergeEqns p f ts' vs') eqs'-> where n :: Int -- type signature necessary for nhc-> (n,vs',ts',e') = etaReduce 0 [] (reverse ts) e-> mergeEqns p f ts vs (Equation _ (FunLhs _ ts') rhs) =-> Equation p (FunLhs f (ts ++ zipWith AsPattern vs ts')) rhs-> etaReduce n vs (VariablePattern v : ts) (Apply e (Variable v'))-> | qualify v == v' = etaReduce (n+1) (v:vs) ts e-> etaReduce n vs ts e = (n,vs,reverse ts,e)-> inlineFun _ _ _ _ p lhs rhs = [Equation p lhs rhs]--> simplifyRhs :: SimplifyFlags -> ModuleIdent -> InlineEnv -> Rhs -> SimplifyState Rhs-> simplifyRhs flat m env (SimpleRhs p e _) =-> do-> e' <- simplifyExpr flat m env e-> return (SimpleRhs p e' [])--\end{verbatim}-Variables that are bound to (simple) constants and aliases to other-variables are substituted. In terms of conventional compiler-technology these optimizations correspond to constant folding and copy-propagation, respectively. The transformation is applied recursively-to a substituted variable in order to handle chains of variable-definitions.--The bindings of a let expression are sorted topologically in-order to split them into minimal binding groups. In addition,-local declarations occurring on the right hand side of a pattern-declaration are lifted into the enclosing binding group using the-equivalence (modulo $\alpha$-conversion) of \texttt{let}-$x$~=~\texttt{let} \emph{decls} \texttt{in} $e_1$ \texttt{in} $e_2$-and \texttt{let} \emph{decls}\texttt{;} $x$~=~$e_1$ \texttt{in} $e_2$.-This transformation avoids the creation of some redundant lifted-functions in later phases of the compiler.-\begin{verbatim}--> simplifyExpr :: SimplifyFlags -> ModuleIdent -> InlineEnv -> Expression-> -> SimplifyState Expression-> simplifyExpr _ _ _ (Literal l) = return (Literal l)-> simplifyExpr flat m env (Variable v)-> | isQualified v = return (Variable v)-> | otherwise = maybe (return (Variable v)) (simplifyExpr flat m env)-> (Map.lookup (unqualify v) env)-> simplifyExpr _ _ _ (Constructor c) = return (Constructor c)-> simplifyExpr flags m env (Apply (Let ds e1) e2) -> = simplifyExpr flags m env (Let ds (Apply e1 e2))-> simplifyExpr flags m env (Apply (Case r e1 alts) e2) -> = simplifyExpr flags m env (Case r e1 (map (applyToAlt e2) alts))-> where applyToAlt e (Alt p t rhs) = Alt p t (applyRhs rhs e)-> applyRhs (SimpleRhs p e1 _) e2 = SimpleRhs p (Apply e1 e2) []-> simplifyExpr flat m env (Apply e1 e2) =-> do-> e1' <- simplifyExpr flat m env e1-> e2' <- simplifyExpr flat m env e2-> return (Apply e1' e2')-> simplifyExpr flags m env (Let ds e) =-> do-> tyEnv <- S.get-> dss' <- mapM (sharePatternRhs m tyEnv) ds-> simplifyLet flags m env-> (scc bv (qfv m) (foldr (hoistDecls flags) [] (concat dss'))) e-> simplifyExpr flat m env (Case r e alts) =-> do-> e' <- simplifyExpr flat m env e-> alts' <- mapM (simplifyAlt flat m env) alts-> return (Case r e' alts')-> --> simplifyAlt :: SimplifyFlags -> ModuleIdent -> InlineEnv -> Alt -> SimplifyState Alt-> simplifyAlt flat m env (Alt p t rhs) =-> liftM (Alt p t) (simplifyRhs flat m env rhs)--> hoistDecls :: SimplifyFlags -> Decl -> [Decl] -> [Decl]-> hoistDecls flags (PatternDecl p t (SimpleRhs p' (Let ds e) _)) ds' -> = foldr (hoistDecls flags) ds' (PatternDecl p t (SimpleRhs p' e []) : ds)-> hoistDecls _ d ds = d : ds--\end{verbatim}-The declaration groups of a let expression are first processed from-outside to inside, simplifying the right hand sides and collecting-inlineable expressions on the fly. At present, only simple constants-and aliases to other variables are inlined. A constant is considered-simple if it is either a literal, a constructor, or a non-nullary-function. Note that it is not possible to define nullary functions in-local declarations in Curry. Thus, an unqualified name always refers-to either a variable or a non-nullary function. Applications of-constructors and partial applications of functions to at least one-argument are not inlined because the compiler has to allocate space-for them, anyway. In order to prevent non-termination, recursive-binding groups are not processed.--With the list of inlineable expressions, the body of the let is-simplified and then the declaration groups are processed from inside-to outside to construct the simplified, nested let expression. In-doing so unused bindings are discarded. In addition, all pattern-bindings are replaced by simple variable declarations using selector-functions to access the pattern variables.-\begin{verbatim}--> simplifyLet :: SimplifyFlags -> ModuleIdent -> InlineEnv -> [[Decl]] -> Expression-> -> SimplifyState Expression-> simplifyLet flat m env [] e = simplifyExpr flat m env e-> simplifyLet flags m env (ds:dss) e =-> do-> ds' <- mapM (simplifyDecl flags m env) ds-> tyEnv <- S.get-> e' <- simplifyLet flags m (inlineVars flags m tyEnv ds' env) dss e-> dss'' <--> mapM (expandPatternBindings flags m tyEnv (qfv m ds' ++ qfv m e')) ds'-> return (foldr (mkLet flags m) e' -> (scc bv (qfv m) (concat dss'')))--> inlineVars :: SimplifyFlags -> ModuleIdent -> ValueEnv -> [Decl] -> InlineEnv -> InlineEnv-> inlineVars flags m tyEnv [PatternDecl _ (VariablePattern v) (SimpleRhs _ e _)] env-> | canInline e = Map.insert v e env-> where-> canInline (Literal _) = True-> canInline (Constructor _) = True-> canInline _ = False -- inlining of variables is deactivated (hsi)-> canInline (Variable v')-> | isQualified v' = arrowArity (funType m tyEnv v') > 0-> | otherwise = v /= unqualify v'-> canInline _ = False-> inlineVars _ _ _ _ env = env--> mkLet :: SimplifyFlags -> ModuleIdent -> [Decl] -> Expression -> Expression-> mkLet flags m [ExtraVariables p vs] e-> | null vs' = e-> | otherwise = Let [ExtraVariables p vs'] e-> where vs' = filter (`elem` qfv m e) vs-> mkLet flags m [PatternDecl _ (VariablePattern v) (SimpleRhs _ e _)] (Variable v')-> | v' == qualify v && v `notElem` qfv m e = e-> mkLet flags m ds e-> | null (filter (`elem` qfv m e) (bv ds)) = e-> | otherwise = Let ds e--\end{verbatim}-\label{pattern-binding}-In order to implement lazy pattern matching in local declarations,-pattern declarations $t$~\texttt{=}~$e$ where $t$ is not a variable-are transformed into a list of declarations-$v_0$~\texttt{=}~$e$\texttt{;} $v_1$~\texttt{=}~$f_1$~$v_0$\texttt{;}-\dots{} $v_n$~\texttt{=}~$f_n$~$v_0$ where $v_0$ is a fresh variable,-$v_1,\dots,v_n$ are the variables occurring in $t$ and the auxiliary-functions $f_i$ are defined by $f_i$~$t$~\texttt{=}~$v_i$ (see also-appendix D.8 of the Curry report~\cite{Hanus:Report}). The bindings-$v_0$~\texttt{=}~$e$ are introduced before splitting the declaration-groups of the enclosing let expression (cf. the \texttt{Let} case in-\texttt{simplifyExpr} above) so that they are placed in their own-declaration group whenever possible. In particular, this ensures that-the new binding is discarded when the expression $e$ is itself a-variable.--Unfortunately, this transformation introduces a well-known space-leak~\cite{Wadler87:Leaks,Sparud93:Leaks} because the matched-expression cannot be garbage collected until all of the matched-variables have been evaluated. Consider the following function:-\begin{verbatim}- f x | all (' ' ==) cs = c where (c:cs) = x-\end{verbatim}-One might expect the call \verb|f (replicate 10000 ' ')| to execute in-constant space because (the tail of) the long list of blanks is-consumed and discarded immediately by \texttt{all}. However, the-application of the selector function that extracts the head of the-list is not evaluated until after the guard has succeeded and thus-prevents the list from being garbage collected.--In order to avoid this space leak we use the approach-from~\cite{Sparud93:Leaks} and update all pattern variables when one-of the selector functions has been evaluated. Therefore all pattern-variables except for the matched one are passed as additional-arguments to each of the selector functions. Thus, each of these-variables occurs twice in the argument list of a selector function,-once in the first argument and also as one of the remaining arguments.-This duplication of names is used by the compiler to insert the code-that updates the variables when generating abstract machine code.--By its very nature, this transformation introduces cyclic variable-bindings. Since cyclic bindings are not supported by PAKCS, we revert-to a simpler translation when generating FlatCurry output.--We will add only those pattern variables as additional arguments which-are actually used in the code. This reduces the number of auxiliary-variables and can prevent the introduction of a recursive binding-group when only a single variable is used. It is also the reason for-performing this transformation here instead of in the \texttt{Desugar}-module. The selector functions are defined in a local declaration on-the right hand side of a projection declaration so that there is-exactly one declaration for each used variable.--Another problem of the translation scheme is the handling of pattern-variables with higher-order types, e.g.,-\begin{verbatim}- strange :: [a->a] -> Maybe (a->a)- strange xs = Just x- where (x:_) = xs-\end{verbatim}-By reusing the types of the pattern variables, the selector function-\verb|f (x:_) = x| has type \texttt{[a->a] -> a -> a} and therefore-seems to be binary function. Thus, in the goal \verb|strange []| the-selector is only applied partially and not evaluated. Note that this-goal will fail without the type annotation. In order to ensure that a-selector function is always evaluated when the corresponding variable-is used, we assume that the projection declarations -- ignoring the-additional arguments to prevent the space leak -- are actually defined-by $f_i$~$t$~\texttt{= I}~$v_i$, using a private renaming type-\begin{verbatim}- newtype Identity a = I a-\end{verbatim}-As newtype constructors are completely transparent to the compiler,-this does not change the generated code, but only the types of the-selector functions.-\begin{verbatim}--> sharePatternRhs :: ModuleIdent -> ValueEnv -> Decl -> SimplifyState [Decl]-> sharePatternRhs m tyEnv (PatternDecl p t rhs) =-> case t of-> VariablePattern _ -> return [PatternDecl p t rhs]-> _ -> -> do-> v0 <- freshIdent m patternId (monoType (typeOf tyEnv t))-> let v = addRefId (srcRefOf p) v0-> return [PatternDecl p t (SimpleRhs p (mkVar v) []),-> PatternDecl p (VariablePattern v) rhs]-> where patternId n = mkIdent ("_#pat" ++ show n)-> sharePatternRhs _ _ d = return [d]--> expandPatternBindings :: SimplifyFlags -> ModuleIdent -> ValueEnv -> [Ident] -> -> Decl -> SimplifyState [Decl]->-> expandPatternBindings flags m tyEnv fvs (PatternDecl p t (SimpleRhs p' e _)) =-> case t of-> VariablePattern _ -> return [PatternDecl p t (SimpleRhs p' e [])]-> _-> | flatFlag flags ->-> do-> fs <- sequence (zipWith getId tys vs)-> return (zipWith (flatProjectionDecl p t e) fs vs)-> | otherwise ->-> do-> fs <- mapM (freshIdent m fpSelectorId . selectorType ty)-> (shuffle tys)-> return (zipWith (projectionDecl p t e) fs (shuffle vs))->-> where getId t v = freshIdent m -> (\ i -> updIdentName ( ++'#':name v) (fpSelectorId i))-> (flatSelectorType ty t)-> -> vs = filter (`elem` fvs) (bv t)-> ty = typeOf tyEnv t-> tys = map (typeOf tyEnv) vs-> selectorType ty0 (ty:tys) =-> polyType (foldr TypeArrow (identityType ty) (ty0:tys))->-> selectorDecl p f t (v:vs) =-> funDecl p f (t:map VariablePattern vs) (mkVar v)-> projectionDecl p t e f (v:vs) =-> varDecl p v (Let [selectorDecl p f t (v:vs)]-> (foldl applyVar (Apply (mkVar f) e) vs))->-> flatSelectorType ty0 ty =-> polyType (TypeArrow ty0 (identityType ty))-> flatSelectorDecl p f t v = funDecl p f [t] (mkVar v)-> flatProjectionDecl p t e f v =-> varDecl p v (Let [flatSelectorDecl p f t v] (Apply (mkVar f) e))->-> expandPatternBindings _ _ _ _ d = return [d]--\end{verbatim}-Auxiliary functions-\begin{verbatim}--> isVarPattern :: ConstrTerm -> Bool-> isVarPattern (VariablePattern _) = True-> isVarPattern (AsPattern _ t) = isVarPattern t-> isVarPattern (ConstructorPattern _ _) = False-> isVarPattern (LiteralPattern _) = False--> funType :: ModuleIdent -> ValueEnv -> QualIdent -> Type-> funType m tyEnv f =-> case (qualLookupValue f tyEnv) of-> [Value _ (ForAll _ ty)] -> ty-> vs -> case (qualLookupValue (qualQualify m f) tyEnv) of-> [Value _ (ForAll _ ty)] -> ty-> _ -> internalError ("funType " ++ show f)--> evMode :: EvalEnv -> Ident -> Maybe EvalAnnotation-> evMode evEnv f = Map.lookup f evEnv--> freshIdent :: ModuleIdent -> (Int -> Ident) -> TypeScheme-> -> SimplifyState Ident-> freshIdent m f ty =-> do-> x <- liftM f (S.lift (R.lift ( S.modify succ >> S.get)))-> S.modify (bindFun m x ty)-> return x--> shuffle :: [a] -> [[a]]-> shuffle xs = shuffle id xs-> where shuffle _ [] = []-> shuffle f (x:xs) = (x : f xs) : shuffle (f . (x:)) xs--> mkVar :: Ident -> Expression-> mkVar = Variable . qualify--> applyVar :: Expression -> Ident -> Expression-> applyVar e v = Apply e (mkVar v)--> varDecl :: Position -> Ident -> Expression -> Decl-> varDecl p v e = PatternDecl p (VariablePattern v) (SimpleRhs p e [])--> funDecl :: Position -> Ident -> [ConstrTerm] -> Expression -> Decl-> funDecl p f ts e =-> FunctionDecl p f [Equation p (FunLhs f ts) (SimpleRhs p e [])]--> identityType :: Type -> Type-> identityType = TypeConstructor qIdentityId . return-> where qIdentityId = qualify (mkIdent "Identity")--\end{verbatim}
− src/Subst.lhs
@@ -1,124 +0,0 @@-% Copyright (c) 2002, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{Subst.lhs}-\section{Substitutions}-The module {\tt Subst} implements substitutions. A substitution-$\sigma = \left\{x_1\mapsto t_1,\dots,x_n\mapsto t_n\right\}$ is a-finite mapping from (finitely many) variables $x_1,\dots,x_n$ to-some kind of expression or term.--In order to implement substitutions efficiently composed-substitutions are marked with a boolean flag (see below).-\begin{verbatim}--> module Subst where--> import qualified Data.Map as Map--> data Subst a b = Subst Bool (Map.Map a b) deriving Show--> idSubst :: Ord a => Subst a b-> idSubst = Subst False Map.empty--> substToList :: Ord v => Subst v e -> [(v,e)]-> substToList (Subst _ sigma) = Map.toList sigma--> bindSubst :: Ord v => v -> e -> Subst v e -> Subst v e-> bindSubst v e (Subst comp sigma) = Subst comp (Map.insert v e sigma)--> unbindSubst :: Ord v => v -> Subst v e -> Subst v e-> unbindSubst v (Subst comp sigma) = Subst comp (Map.delete v sigma)--\end{verbatim}-For any substitution we have the following definitions:-\begin{displaymath}- \begin{array}{l}- \sigma(x) = \left\{\begin{array}{ll}- t_i&\mbox{if $x=x_i$}\\- x&\mbox{otherwise}\end{array}\right. \\- \mathop{{\mathcal D}om}(\sigma) = \left\{x_1,\dots,x_n\right\} \\- \mathop{{\mathcal C}odom}(\sigma) = \left\{t_1,\dots,t_n\right\}- \end{array} -\end{displaymath}-Note that obviously the set of variables must be a subset of the set-of expressions. Also it is usually possible to extend the substitution-to a homomorphism on the codomain of the substitution. This is-captured by the following class declaration:-\begin{verbatim}--class Ord v => Subst v e where- var :: v -> e- subst :: Subst v e -> e -> e--\end{verbatim}-With the help of the injection \texttt{var}, we can then compute the-substitution for a variable $\sigma(v)$ and also the composition of-two substitutions-$(\sigma_1 \circ \sigma_2)(e) \mathop{:=} \sigma_1(\sigma_2(e))$. A-naive implementation of the composition were-\begin{verbatim}- compose sigma sigma' =- foldr (uncurry bindSubst) sigma (substToList (fmap (subst sigma) sigma'))-\end{verbatim}-However, such an implementation is very inefficient because the-number of substiutions applied to a variable increases in-$\mathcal{O}(n)$ of the number of compositions.--A more efficient implementation is to apply \texttt{subst} again to-the value substituted for a variable in-$\mathop{{\mathcal D}om}(\sigma)$. However, this is correct only as-long as the result of the substitution does not include any variables-which are in $\mathop{{\mathcal D}om}(\sigma)$. For instance, it is-impossible to implement simple variable renamings in this way.--Therefore we use the simple strategy to apply \texttt{subst} again-only in case of a substitution which was returned from \texttt{compose}.-\begin{verbatim}--substVar :: Subst v e => Subst v e -> v -> e-substVar (Subst comp sigma) v = maybe (var v) subst' (Map.lookup v sigma)- where subst' = if comp then subst (Subst comp sigma) else id--> compose :: (Show v,Ord v,Show e) => Subst v e -> Subst v e -> Subst v e-> compose sigma sigma' =-> composed (foldr (uncurry bindSubst) sigma' (substToList sigma))-> where dom = domain sigma-> dom' = domain sigma'-> domain = map fst . substToList-> composed (Subst _ sigma) = Subst True sigma--\end{verbatim}-Unfortunately Haskell does not (yet) support multi-parameter type-classes. For that reason we have to define a separate class for each-kind of variable type for these functions. We implement-\texttt{substVar} as a function that takes the class functions as an-additional parameters. As an example for the use of this function the-module includes a class \texttt{IntSubst} for substitution whose-domain are integer numbers.-\begin{verbatim}--> substVar' :: Ord v => (v -> e) -> (Subst v e -> e -> e)-> -> Subst v e -> v -> e-> substVar' var subst (Subst comp sigma) v =-> maybe (var v) subst' (Map.lookup v sigma)-> where subst' = if comp then subst (Subst comp sigma) else id--> class IntSubst e where-> ivar :: Int -> e-> isubst :: Subst Int e -> e -> e--> isubstVar :: IntSubst e => Subst Int e -> Int -> e-> isubstVar = substVar' ivar isubst--\end{verbatim}-The function \texttt{restrictSubstTo} implements the restriction of a-substitution to a given subset of its domain.-\begin{verbatim}--> restrictSubstTo :: Ord v => [v] -> Subst v e -> Subst v e-> restrictSubstTo vs (Subst comp sigma) =-> foldr (uncurry bindSubst) (Subst comp Map.empty)-> (filter ((`elem` vs) . fst) (Map.toList sigma))--\end{verbatim}
− src/SyntaxCheck.lhs
@@ -1,1149 +0,0 @@--% $Id: SyntaxCheck.lhs,v 1.53 2004/02/15 22:10:37 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{SyntaxCheck.lhs}-\section{Syntax Checks}-After the type declarations have been checked, the compiler performs a-syntax check on the remaining declarations. This check disambiguates-nullary data constructors and variables which -- in contrast to-Haskell -- is not possible on purely syntactic criteria. In addition,-this pass checks for undefined as well as ambiguous variables and-constructors. In order to allow lifting of local definitions in-later phases, all local variables are renamed by adding a unique-key.\footnote{Actually, all variables defined in the same scope share-the same key.} Finally, all (adjacent) equations of a function are-merged into a single definition.-\begin{verbatim}--> module SyntaxCheck(syntaxCheck) where--> import Data.Maybe-> import Data.List-> import qualified Data.Map as Map-> import Control.Monad.State as S--> import Curry.Syntax-> import Curry.Syntax.Utils-> import Types-> import Curry.Base.Position-> import Curry.Base.Ident-> import Base-> import NestEnv-> import Utils--\end{verbatim}-The syntax checking proceeds as follows. First, the compiler extracts-information about all imported values and data constructors from the-imported (type) environments. Next, the data constructors defined in-the current module are entered into this environment. After this-all record labels are entered into the environment too. If a record-identifier is already assigned to a constructor, then an error will be-generated. Finally, all-declarations are checked within the resulting environment. In-addition, this process will also rename the local variables.-\begin{verbatim}--> syntaxCheck :: Bool -> ModuleIdent -> ImportEnv -> ArityEnv -> ValueEnv -> TCEnv -> [Decl] -> [Decl]-> syntaxCheck withExt m iEnv aEnv tyEnv tcEnv ds =-> case findDouble (concatMap constrs tds) of-> --Nothing -> tds ++ run (checkModule withExt m env vds)-> Nothing -> map (checkTypeDecl withExt m) tds-> ++ run (checkModule withExt m env2 vds)-> Just c -> errorAt' (duplicateData c)-> where (tds,vds) = partition isTypeDecl ds-> (rs, tds') = partition isRecordDecl tds-> env1 = foldr (bindTypes m) -- (bindConstrs m) -> (globalEnv (fmap (renameInfo tcEnv iEnv aEnv) tyEnv)) -> tds'-> env2 = foldr (bindTypes m) env1 rs--\end{verbatim}-A global state transformer is used for generating fresh integer keys-by which the variables get renamed.-\begin{verbatim}--> type RenameState a = S.State Int a--> run :: RenameState a -> a-> run m = S.evalState m (globalKey + 1)--> newId :: RenameState Int-> newId = S.modify succ >> S.get--\end{verbatim}-\ToDo{Probably the state transformer should use an \texttt{Integer} -counter.}--A nested environment is used for recording information about the data-constructors and variables in the module. For every data constructor-its arity is saved. This is used for checking that all constructor-applications in patterns are saturated. For local variables the-environment records the new name of the variable after renaming.-Global variables are recorded with qualified identifiers in order-to distinguish multiply declared entities.--Currently records must explicitly be declared together with their labels.-When constructing or updating a record, it is necessary to compute -all its labels using just one of them. Thus for each label -the record identifier and all its labels are entered into the environment--\em{Note:} the function \texttt{qualLookupVar} has been extended to-allow the usage of the qualified list constructor \texttt{(prelude.:)}.-\begin{verbatim}--> type RenameEnv = NestEnv RenameInfo-> data RenameInfo = Constr Int -> | GlobalVar Int QualIdent -> | LocalVar Int Ident-> | RecordLabel QualIdent [Ident]-> deriving (Eq,Show)--> globalKey :: Int-> globalKey = uniqueId (mkIdent "")--> renameInfo :: TCEnv -> ImportEnv -> ArityEnv -> ValueInfo -> RenameInfo-> renameInfo tcEnv iEnv aEnv (DataConstructor _ (ForAllExist _ _ ty)) -> = Constr (arrowArity ty)-> renameInfo tcEnv iEnv aEnv (NewtypeConstructor _ _) -> = Constr 1-> renameInfo tcEnv iEnv aEnv (Value qid _)-> = let (mmid, id) = (qualidMod qid, qualidId qid)-> qid' = maybe qid -> (\mid -> maybe qid -> (\mid' -> qualifyWith mid' id)-> (lookupAlias mid iEnv))-> mmid-> in case (lookupArity id aEnv) of-> [ArityInfo _ arity] -> GlobalVar arity qid-> rs -> case (qualLookupArity qid' aEnv) of-> [ArityInfo _ arity] -> GlobalVar arity qid-> _ -> maybe (internalError "renameInfo: missing arity")-> (\ (ArityInfo _ arity) -> GlobalVar arity qid)-> (find (\ (ArityInfo qid'' _) -> -> qid'' == qid) rs)-> renameInfo tcEnv iEnv aEnv (Label l r _)-> = case (qualLookupTC r tcEnv) of-> [AliasType _ _ (TypeRecord fs _)] ->-> RecordLabel r (map fst fs)-> _ -> internalError "renameInfo: no record"--\end{verbatim}-Since record types are currently translated into data types, it is-necessary to ensure that all identifiers for records and constructors-are different. Furthermore it is not allowed to declare a label more-than once.-\begin{verbatim}--> bindTypes :: ModuleIdent -> Decl -> RenameEnv -> RenameEnv-> bindTypes m (DataDecl _ tc _ cs) env = foldr (bindConstr m) env cs-> bindTypes m (NewtypeDecl _ tc _ nc) env = bindNewConstr m nc env-> bindTypes m (TypeDecl _ t _ (RecordType fs r)) env =-> -- - | isJust r = internalError "bindTypes: illegal record declaration"-> -- - | null fs = errorAt (positionOfIdent t) emptyRecord-> -- - | otherwise =-> case (qualLookupVar (qualifyWith m t) env) of-> [] -> foldr (bindRecordLabel m t (concatMap fst fs)) env fs-> rs | any isConstr rs -> errorAt' (illegalRecordId t)-> | otherwise-> -> foldr (bindRecordLabel m t (concatMap fst fs)) env fs-> bindTypes _ _ env = env--> bindRecordLabel :: ModuleIdent -> Ident -> [Ident] -> -> ([Ident],TypeExpr) -> RenameEnv -> RenameEnv-> bindRecordLabel m t labels (ls,_) env = -> foldr (\l -> case (lookupVar l env) of-> [] -> bindGlobal m l-> (RecordLabel (qualifyWith m t) labels)-> _ -> errorAt' (duplicateDefinition l)-> ) env ls--> --bindConstrs :: ModuleIdent -> Decl -> RenameEnv -> RenameEnv-> --bindConstrs m (DataDecl _ tc _ cs) env = foldr (bindConstr m) env cs-> --bindConstrs m (NewtypeDecl _ tc _ nc) env = bindNewConstr m nc env-> --bindConstrs _ _ env = env--> bindConstr :: ModuleIdent -> ConstrDecl -> RenameEnv -> RenameEnv-> bindConstr m (ConstrDecl _ _ c tys) = bindGlobal m c (Constr (length tys))-> bindConstr m (ConOpDecl _ _ _ op _) = bindGlobal m op (Constr 2)--> bindNewConstr :: ModuleIdent -> NewConstrDecl -> RenameEnv -> RenameEnv-> bindNewConstr m (NewConstrDecl _ _ c _) = bindGlobal m c (Constr 1)--> bindFuncDecl :: ModuleIdent -> Decl -> RenameEnv -> RenameEnv-> bindFuncDecl m (FunctionDecl _ id equs) env-> | null equs = internalError "bindFuncDecl: missing equations"-> | otherwise = let (_,ts) = getFlatLhs (head equs)-> in bindGlobal m -> id -> (GlobalVar (length ts) (qualifyWith m id))-> env-> bindFuncDecl m (ExternalDecl _ _ _ id texpr) env-> = bindGlobal m id (GlobalVar (typeArity texpr) (qualifyWith m id)) env-> bindFuncDecl m (TypeSig _ ids texpr) env-> = foldr bindTS env (map (qualifyWith m) ids)-> where-> bindTS qid env -> | null (qualLookupVar qid env)-> = bindGlobal m (unqualify qid) (GlobalVar (typeArity texpr) qid) env-> | otherwise-> = env-> bindFuncDecl _ _ env = env--> bindVarDecl :: Decl -> RenameEnv -> RenameEnv-> bindVarDecl (FunctionDecl _ id equs) env-> | null equs -> = internalError "bindFuncDecl: missing equations"-> | otherwise -> = let (_,ts) = getFlatLhs (head equs)-> in bindLocal (unRenameIdent id) (LocalVar (length ts) id) env-> bindVarDecl (PatternDecl p t _) env-> = foldr bindVar env (bv t)-> bindVarDecl (ExtraVariables p vs) env-> = foldr bindVar env vs -> bindVarDecl _ env = env--> bindVar :: Ident -> RenameEnv -> RenameEnv-> bindVar v env-> | v' == anonId = env-> | otherwise = bindLocal v' (LocalVar 0 v) env-> where v' = unRenameIdent v--> bindGlobal :: ModuleIdent -> Ident -> RenameInfo -> RenameEnv -> RenameEnv-> bindGlobal m c r = bindNestEnv c r . qualBindNestEnv (qualifyWith m c) r--> bindLocal :: Ident -> RenameInfo -> RenameEnv -> RenameEnv-> bindLocal f r = bindNestEnv f r--> lookupVar :: Ident -> RenameEnv -> [RenameInfo]-> lookupVar v env = lookupNestEnv v env ++! lookupTupleConstr v--> qualLookupVar :: QualIdent -> RenameEnv -> [RenameInfo]-> qualLookupVar v env =-> qualLookupNestEnv v env-> ++! qualLookupListCons v env-> ++! lookupTupleConstr (unqualify v)--> qualLookupListCons :: QualIdent -> RenameEnv -> [RenameInfo]-> qualLookupListCons v env-> | (isJust mmid) && ((fromJust mmid) == preludeMIdent) && (ident == consId)-> = qualLookupNestEnv (qualify ident) env-> | otherwise = []-> where (mmid, ident) = (qualidMod v, qualidId v)--> lookupTupleConstr :: Ident -> [RenameInfo]-> lookupTupleConstr v-> | isTupleId v = [Constr (tupleArity v)]-> | otherwise = []--\end{verbatim}-When a module is checked, the global declaration group is checked. The-resulting renaming environment can be discarded. The same is true for-a goal. Note that all declarations in the goal must be considered as-local declarations.-\begin{verbatim}--> checkModule :: Bool -> ModuleIdent -> RenameEnv -> [Decl] -> RenameState [Decl]-> checkModule withExt m env ds = liftM snd (checkTopDecls withExt m env ds)--> checkTopDecls :: Bool -> ModuleIdent -> RenameEnv -> [Decl]-> -> RenameState (RenameEnv,[Decl])-> checkTopDecls withExt m env ds = -> checkDeclGroup (bindFuncDecl m) withExt m globalKey env ds--> checkTypeDecl :: Bool -> ModuleIdent -> Decl -> Decl-> checkTypeDecl withExt m d@(TypeDecl p r tvs (RecordType fs rty))-> | not withExt = errorAt (positionOfIdent r) noRecordExt-> | isJust rty = internalError "checkTypeDecl - illegal record type"-> | null fs = errorAt (positionOfIdent r) emptyRecord-> | otherwise = TypeDecl p r tvs (RecordType fs Nothing)-> checkTypeDecl _ _ d = d--\end{verbatim}-Each declaration group opens a new scope and uses a distinct key-for renaming the variables in this scope. In a declaration group,-first the left hand sides of all declarations are checked, next the-compiler checks that there is a definition for every type signature-and evaluation annotation in this group. Finally, the right hand sides-are checked and adjacent equations for the same function are merged-into a single definition.--The function \texttt{checkDeclLhs} also handles the case where a-pattern declaration is recognized as a function declaration by the-parser. This happens, e.g., for the declaration \verb|where Just x = y|-because the parser cannot distinguish nullary constructors and-functions. Note that pattern declarations are not allowed on the-top-level.-\begin{verbatim}--> checkLocalDecls :: Bool -> ModuleIdent -> RenameEnv -> [Decl] -> -> RenameState (RenameEnv,[Decl])-> checkLocalDecls withExt m env ds =-> newId >>= \k -> checkDeclGroup bindVarDecl withExt m k (nestEnv env) ds--> checkDeclGroup :: (Decl -> RenameEnv -> RenameEnv) -> Bool -> ModuleIdent-> -> Int -> RenameEnv -> [Decl] -> -> RenameState (RenameEnv,[Decl])-> checkDeclGroup bindDecl withExt m k env ds =-> mapM (checkDeclLhs withExt k m env) ds' >>=-> checkDecls bindDecl withExt m env . joinEquations-> where ds' = sortFuncDecls ds--> checkDeclLhs :: Bool -> Int -> ModuleIdent -> RenameEnv -> Decl -> RenameState Decl-> checkDeclLhs withExt k _ _ (InfixDecl p fix pr ops) =-> return (InfixDecl p fix pr (map (flip renameIdent k) ops))-> checkDeclLhs withExt k _ env (TypeSig p vs ty) =-> return (TypeSig p (map (checkVar "type signature" k env) vs) ty)-> checkDeclLhs withExt k _ env (EvalAnnot p fs ev) =-> return (EvalAnnot p (map (checkVar "evaluation annotation" k env) fs) ev)-> checkDeclLhs withExt k m env (FunctionDecl p _ eqs) = -> checkEquationLhs withExt k m env p eqs-> checkDeclLhs withExt k _ env (ExternalDecl p cc ie f ty) =-> return (ExternalDecl p cc ie (checkVar "external declaration" k env f) ty)-> checkDeclLhs withExt k _ env (FlatExternalDecl p fs) =-> return (FlatExternalDecl p-> (map (checkVar "external declaration" k env) fs))-> checkDeclLhs withExt k m env (PatternDecl p t rhs) =-> do-> t' <- checkConstrTerm withExt k p m env t-> return (PatternDecl p t' rhs)-> checkDeclLhs withExt k _ env (ExtraVariables p vs) =-> return (ExtraVariables p-> (map (checkVar "free variables declaration" k env) vs))-> checkDeclLhs _ _ _ _ d = return d--> checkEquationLhs :: Bool -> Int -> ModuleIdent -> RenameEnv -> Position -> -> [Equation] -> RenameState Decl-> checkEquationLhs withExt k m env p [Equation p' lhs rhs] =-> either (return . funDecl) (checkDeclLhs withExt k m env . patDecl)-> (checkEqLhs m k env p' lhs)-> where funDecl (f,lhs) = FunctionDecl p f [Equation p' lhs rhs]-> patDecl t-> | k == globalKey = errorAt p noToplevelPattern-> | otherwise = PatternDecl p' t rhs-> checkEquationLhs _ _ _ _ _ _ = internalError "checkEquationLhs"--> checkEqLhs :: ModuleIdent -> Int -> RenameEnv -> Position -> Lhs-> -> Either (Ident,Lhs) ConstrTerm-> checkEqLhs m k env _ (FunLhs f ts)-> | isDataConstr f env-> = if k /= globalKey-> then Right (ConstructorPattern (qualify f) ts)-> else if null (qualLookupVar (qualifyWith m f) env)-> then Left (f',FunLhs f' ts)-> else errorAt (positionOfIdent f) noToplevelPattern-> | otherwise = Left (f',FunLhs f' ts)-> where f' = renameIdent f k-> checkEqLhs m k env p (OpLhs t1 op t2)-> | isDataConstr op env -> = if k /= globalKey-> then checkOpLhs k env (infixPattern t1 (qualify op)) t2-> else if null (qualLookupVar (qualifyWith m op) env)-> then Left (op',OpLhs t1 op' t2)-> else errorAt p noToplevelPattern-> | otherwise = Left (op',OpLhs t1 op' t2)-> where op' = renameIdent op k-> infixPattern (InfixPattern t1 op1 t2) op2 t3 =-> InfixPattern t1 op1 (infixPattern t2 op2 t3)-> infixPattern t1 op t2 = InfixPattern t1 op t2-> checkEqLhs m k env p (ApLhs lhs ts) =-> case checkEqLhs m k env p lhs of-> Left (f',lhs') -> Left (f',ApLhs lhs' ts)-> Right _ -> errorAt' $ nonVariable "curried definition" f-> where (f,_) = flatLhs lhs--> checkOpLhs :: Int -> RenameEnv -> (ConstrTerm -> ConstrTerm) -> ConstrTerm-> -> Either (Ident,Lhs) ConstrTerm-> checkOpLhs k env f (InfixPattern t1 op t2)-> | isJust m || isDataConstr op' env =-> checkOpLhs k env (f . InfixPattern t1 op) t2-> | otherwise = Left (op'',OpLhs (f t1) op'' t2)-> where (m,op') = (qualidMod op, qualidId op)-> op'' = renameIdent op' k-> checkOpLhs _ _ f t = Right (f t)--> checkVar :: String -> Int -> RenameEnv -> Ident -> Ident-> checkVar what k env v -> | False && isDataConstr v env = errorAt' (nonVariable what v)----------------> | otherwise = renameIdent v k---> checkDecls :: (Decl -> RenameEnv -> RenameEnv) -> Bool -> ModuleIdent-> -> RenameEnv -> [Decl] -> RenameState (RenameEnv,[Decl])-> checkDecls bindDecl withExt m env ds = -> case findDouble bvs of-> Nothing ->-> case findDouble tys of-> Nothing ->-> case findDouble evs of-> Nothing ->-> case filter (`notElem` tys) fs' of-> [] -> liftM ((,) env') -> (mapM (checkDeclRhs withExt bvs m env'') ds)-> f : _ -> errorAt' (noTypeSig f)-> Just v -> errorAt' (duplicateEvalAnnot v)-> Just v -> errorAt' (duplicateTypeSig v)-> Just v -> errorAt' (duplicateDefinition v)-> where vds = filter isValueDecl ds-> tds = filter isTypeSig ds-> bvs = concat (map vars vds)-> tys = concat (map vars tds)-> evs = concat (map vars (filter isEvalAnnot ds))-> fs' = [f | FlatExternalDecl _ fs <- ds, f <- fs]-> env' = foldr bindDecl env vds-> env'' = foldr bindDecl env' tds--> checkDeclRhs :: Bool -> [Ident] -> ModuleIdent -> RenameEnv -> Decl -> -> RenameState Decl-> checkDeclRhs withExt bvs _ _ (TypeSig p vs ty) =-> return (TypeSig p (map (checkLocalVar bvs ) vs) ty)-> checkDeclRhs withExt bvs _ _ (EvalAnnot p vs ev) =-> return (EvalAnnot p (map (checkLocalVar bvs ) vs) ev)-> checkDeclRhs withExt _ m env (FunctionDecl p f eqs) =-> liftM (FunctionDecl p f) (mapM (checkEquation withExt m env) eqs)-> checkDeclRhs withExt _ m env (PatternDecl p t rhs) =-> liftM (PatternDecl p t) (checkRhs withExt m env rhs)-> checkDeclRhs _ _ _ _ d = return d--> checkLocalVar :: [Ident] -> Ident -> Ident-> checkLocalVar bvs v-> | v `elem` bvs = v-> | otherwise = errorAt' (noBody v)--> joinEquations :: [Decl] -> [Decl]-> joinEquations [] = []-> joinEquations (FunctionDecl p f eqs : FunctionDecl p' f' [eq] : ds)-> | f == f' =-> if arity (head eqs) == arity eq then-> joinEquations (FunctionDecl p f (eqs ++ [eq]) : ds)-> else-> errorAt' (differentArity f)-> where arity (Equation _ lhs _) = length $ snd $ flatLhs lhs-> joinEquations (d : ds) = d : joinEquations ds--> checkEquation :: Bool -> ModuleIdent -> RenameEnv -> Equation -> RenameState Equation-> checkEquation withExt m env (Equation p lhs rhs) =-> do-> (env',lhs') <- checkLhs withExt p m env lhs-> rhs' <- checkRhs withExt m env' rhs-> return (Equation p lhs' rhs')--> checkLhs :: Bool -> Position -> ModuleIdent -> RenameEnv -> Lhs -> -> RenameState (RenameEnv,Lhs)-> checkLhs withExt p m env lhs =-> newId >>= \k ->-> checkLhsTerm withExt k p m env lhs >>=-> return . checkConstrTerms withExt (nestEnv env)--> checkLhsTerm :: Bool -> Int -> Position -> ModuleIdent -> RenameEnv -> Lhs -> -> RenameState Lhs-> checkLhsTerm withExt k p m env (FunLhs f ts) =-> do-> ts' <- mapM (checkConstrTerm withExt k p m env) ts-> return (FunLhs f ts')-> checkLhsTerm withExt k p m env (OpLhs t1 op t2) =-> let wrongCalls = concatMap (checkParenConstrTerm (Just (qualify op)))-> [t1,t2] in-> if not (null wrongCalls)-> then errorAt (positionOfIdent op) -> (infixWithoutParens wrongCalls)-> else do-> t1' <- checkConstrTerm withExt k p m env t1-> t2' <- checkConstrTerm withExt k p m env t2 -> return (OpLhs t1' op t2')->-> checkLhsTerm withExt k p m env (ApLhs lhs ts) =-> do-> lhs' <- checkLhsTerm withExt k p m env lhs-> ts' <- mapM (checkConstrTerm withExt k p m env) ts-> return (ApLhs lhs' ts')--> checkArgs :: Bool -> Position -> ModuleIdent -> RenameEnv -> [ConstrTerm]-> -> RenameState (RenameEnv,[ConstrTerm])-> checkArgs withExt p m env ts =-> newId >>= \k ->-> mapM (checkConstrTerm withExt k p m env) ts >>=-> return . checkConstrTerms withExt (nestEnv env)--> checkConstrTerms :: QuantExpr t => Bool -> RenameEnv -> t-> -> (RenameEnv,t)-> checkConstrTerms withExt env ts =-> case findDouble bvs of-> Nothing -> (foldr bindVar env bvs,ts)-> Just v -> errorAt' (duplicateVariable v)-> where bvs = bv ts--> checkConstrTerm :: Bool -> Int -> Position -> ModuleIdent -> RenameEnv-> -> ConstrTerm -> RenameState ConstrTerm-> checkConstrTerm _ _ _ _ _ (LiteralPattern l) =-> liftM LiteralPattern (renameLiteral l)-> checkConstrTerm _ _ _ _ _ (NegativePattern op l) =-> liftM (NegativePattern op) (renameLiteral l)-> checkConstrTerm withExt k p m env (VariablePattern v)-> | v == anonId -> = liftM (VariablePattern . renameIdent anonId) newId-> | otherwise -> = checkConstrTerm withExt k p m env (ConstructorPattern (qualify v) [])-> checkConstrTerm withExt k p m env (ConstructorPattern c ts) =-> case qualLookupVar c env of-> [Constr n]-> | n == n' ->-> liftM (ConstructorPattern c) -> (mapM (checkConstrTerm withExt k p m env) ts)-> | otherwise -> errorAt' (wrongArity c n n')-> where n' = length ts-> [r]-> | null ts && not (isQualified c) ->-> return (VariablePattern (renameIdent (varIdent r) k))-> | withExt ->-> do ts' <- mapM (checkConstrTerm withExt k p m env) ts-> if n' > n-> then let (ts1,ts2) = splitAt n ts'-> in return (genFuncPattAppl -> (FunctionPattern (qualVarIdent r) -> ts1) -> ts2)-> else return (FunctionPattern (qualVarIdent r) ts')-> | otherwise -> errorAt (positionOfQualIdent c) noFuncPattExt -> where n = arity r-> n' = length ts-> rs -> case (qualLookupVar (qualQualify m c) env) of-> []-> | null ts && not (isQualified c) ->-> return (VariablePattern (renameIdent (unqualify c) k))-> | null rs -> errorAt' (undefinedData c)-> | otherwise -> errorAt' (ambiguousData c)-> [Constr n]-> | n == n' ->-> liftM (ConstructorPattern (qualQualify m c)) -> (mapM (checkConstrTerm withExt k p m env) ts)-> | otherwise -> errorAt' (wrongArity c n n')-> where n' = length ts-> [r]-> | null ts && not (isQualified c) ->-> return (VariablePattern (renameIdent (varIdent r) k))-> | withExt ->-> do ts' <- mapM (checkConstrTerm withExt k p m env) ts-> if n' > n-> then let (ts1,ts2) = splitAt n ts'-> in return -> (genFuncPattAppl -> (FunctionPattern (qualVarIdent r) ts1) -> ts2)-> else return (FunctionPattern (qualVarIdent r) ts')-> | otherwise -> errorAt (positionOfQualIdent c) noFuncPattExt-> where n = arity r-> n' = length ts-> _ -> errorAt' (ambiguousData c)-> checkConstrTerm withExt k p m env (InfixPattern t1 op t2) =-> case (qualLookupVar op env) of-> [Constr n]-> | n == 2 ->-> do t1' <- checkConstrTerm withExt k p m env t1-> t2' <- checkConstrTerm withExt k p m env t2-> return (InfixPattern t1' op t2') -> | otherwise -> errorAt' (wrongArity op n 2)-> [r]-> | withExt ->-> do t1' <- checkConstrTerm withExt k p m env t1-> t2' <- checkConstrTerm withExt k p m env t2-> return (InfixFuncPattern t1' op t2')-> | otherwise -> errorAt p noFuncPattExt -> rs -> case (qualLookupVar (qualQualify m op) env) of-> [] | null rs -> errorAt' (undefinedData op)-> | otherwise -> errorAt' (ambiguousData op)-> [Constr n]-> | n == 2 ->-> do t1' <- checkConstrTerm withExt k p m env t1-> t2' <- checkConstrTerm withExt k p m env t2-> return (InfixPattern t1' (qualQualify m op) t2') -> | otherwise -> errorAt' (wrongArity op n 2)-> [r]-> | withExt ->-> do t1' <- checkConstrTerm withExt k p m env t1-> t2' <- checkConstrTerm withExt k p m env t2-> return (InfixFuncPattern t1' (qualQualify m op) t2')-> | otherwise -> errorAt p noFuncPattExt-> _ -> errorAt' (ambiguousData op)-> checkConstrTerm withExt k p m env (ParenPattern t) =-> liftM ParenPattern (checkConstrTerm withExt k p m env t)-> checkConstrTerm withExt k p m env (TuplePattern pos ts) =-> liftM (TuplePattern pos) (mapM (checkConstrTerm withExt k p m env) ts)-> checkConstrTerm withExt k p m env (ListPattern pos ts) =-> liftM (ListPattern pos) (mapM (checkConstrTerm withExt k p m env) ts)-> checkConstrTerm withExt k p m env (AsPattern v t) =-> liftM (AsPattern (checkVar "@ pattern" k env v))-> (checkConstrTerm withExt k p m env t)-> checkConstrTerm withExt k p m env (LazyPattern pos t) =-> liftM (LazyPattern pos) (checkConstrTerm withExt k p m env t)-> checkConstrTerm withExt k p m env (RecordPattern fs t)-> | not withExt = errorAt p noRecordExt-> | not (null fs) =-> let (Field _ label _) = head fs-> in case (lookupVar label env) of-> [] -> errorAt' (undefinedLabel label)-> [RecordLabel r ls]-> | not (null duplicates) ->-> errorAt' (duplicateLabel (head duplicates))-> | isNothing t && not (null missings) ->-> errorAt (positionOfIdent label) -> (missingLabel (head missings) r "record pattern")-> | maybe True ((==) (VariablePattern anonId)) t ->-> do fs' <- mapM (checkFieldPatt withExt k m r env) fs-> t' <- maybe (return Nothing)-> (\t' -> checkConstrTerm withExt k p m env t'-> >>= return . Just)-> t-> return (RecordPattern fs' t')-> | otherwise -> errorAt p illegalRecordPatt-> where ls' = map fieldLabel fs-> duplicates = maybeToList (dup ls')-> missings = ls \\ ls'-> [_] -> errorAt' (notALabel label)-> _ -> errorAt' (duplicateDefinition label)-> | otherwise = errorAt p emptyRecord--> checkFieldPatt :: Bool -> Int -> ModuleIdent -> QualIdent -> RenameEnv-> -> Field ConstrTerm -> RenameState (Field ConstrTerm)-> checkFieldPatt withExt k m r env (Field p l t)-> = case (lookupVar l env) of-> [] -> errorAt' (undefinedLabel l)-> [RecordLabel r' _]-> | r == r' -> do t' <- checkConstrTerm withExt k -> (positionOfIdent l) m env t-> return (Field p l t')-> | otherwise -> errorAt' (illegalLabel l r)-> [_] -> errorAt' (notALabel l)-> _ -> errorAt' (duplicateDefinition l)--> checkRhs :: Bool -> ModuleIdent -> RenameEnv -> Rhs -> RenameState Rhs-> checkRhs withExt m env (SimpleRhs p e ds) =-> do-> (env',ds') <- checkLocalDecls withExt m env ds-> e' <- checkExpr withExt p m env' e-> return (SimpleRhs p e' ds')-> checkRhs withExt m env (GuardedRhs es ds) =-> do-> (env',ds') <- checkLocalDecls withExt m env ds-> es' <- mapM (checkCondExpr withExt m env') es-> return (GuardedRhs es' ds')--> checkCondExpr :: Bool -> ModuleIdent -> RenameEnv -> CondExpr -> RenameState CondExpr-> checkCondExpr withExt m env (CondExpr p g e) =-> do-> g' <- checkExpr withExt p m env g-> e' <- checkExpr withExt p m env e-> return (CondExpr p g' e')--> checkExpr :: Bool -> Position -> ModuleIdent -> RenameEnv -> Expression -> -> RenameState Expression-> checkExpr _ _ _ _ (Literal l) = liftM Literal (renameLiteral l)-> checkExpr withExt _ m env (Variable v) =-> case (qualLookupVar v env) of-> [] -> errorAt' (undefinedVariable v)-> [Constr _] -> return (Constructor v)-> [GlobalVar _ _] -> return (Variable v)-> [LocalVar _ v'] -> return (Variable (qualify v'))-> rs -> case (qualLookupVar (qualQualify m v) env) of-> [] -> errorAt' (ambiguousIdent rs v)-> [Constr _] -> return (Constructor v)-> [GlobalVar _ _] -> return (Variable v)-> [LocalVar _ v'] -> return (Variable (qualify v'))-> rs' -> errorAt' (ambiguousIdent rs' v)-> checkExpr withExt p m env (Constructor c) = -> checkExpr withExt p m env (Variable c)-> checkExpr withExt p m env (Paren e) = -> liftM Paren (checkExpr withExt p m env e)-> checkExpr withExt p m env (Typed e ty) = -> liftM (flip Typed ty) (checkExpr withExt p m env e)-> checkExpr withExt p m env (Tuple pos es) = -> liftM (Tuple pos) (mapM (checkExpr withExt p m env) es)-> checkExpr withExt p m env (List pos es) = -> liftM (List pos) (mapM (checkExpr withExt p m env) es)-> checkExpr withExt p m env (ListCompr pos e qs) =-> do-> (env',qs') <- mapAccumM (checkStatement withExt p m) env qs-> e' <- checkExpr withExt p m env' e-> return (ListCompr pos e' qs')-> checkExpr withExt p m env (EnumFrom e) = -> liftM EnumFrom (checkExpr withExt p m env e)-> checkExpr withExt p m env (EnumFromThen e1 e2) =-> do-> e1' <- checkExpr withExt p m env e1-> e2' <- checkExpr withExt p m env e2-> return (EnumFromThen e1' e2')-> checkExpr withExt p m env (EnumFromTo e1 e2) =-> do-> e1' <- checkExpr withExt p m env e1-> e2' <- checkExpr withExt p m env e2-> return (EnumFromTo e1' e2')-> checkExpr withExt p m env (EnumFromThenTo e1 e2 e3) =-> do-> e1' <- checkExpr withExt p m env e1-> e2' <- checkExpr withExt p m env e2-> e3' <- checkExpr withExt p m env e3-> return (EnumFromThenTo e1' e2' e3')-> checkExpr withExt p m env (UnaryMinus op e) = -> liftM (UnaryMinus op) (checkExpr withExt p m env e)-> checkExpr withExt p m env (Apply e1 e2) =-> do-> e1' <- checkExpr withExt p m env e1-> e2' <- checkExpr withExt p m env e2-> return (Apply e1' e2')-> checkExpr withExt p m env (InfixApply e1 op e2) =-> do-> e1' <- checkExpr withExt p m env e1-> e2' <- checkExpr withExt p m env e2-> return (InfixApply e1' (checkOp m env op) e2')-> checkExpr withExt p m env (LeftSection e op) =-> liftM (flip LeftSection (checkOp m env op)) (checkExpr withExt p m env e)-> checkExpr withExt p m env (RightSection op e) =-> liftM (RightSection (checkOp m env op)) (checkExpr withExt p m env e)-> checkExpr withExt p m env (Lambda r ts e) =-> do-> (env',ts') <- checkArgs withExt p m env ts-> e' <- checkExpr withExt p m env' e-> return (Lambda r ts' e')-> checkExpr withExt p m env (Let ds e) =-> do-> (env',ds') <- checkLocalDecls withExt m env ds-> e' <- checkExpr withExt p m env' e-> return (Let ds' e')-> checkExpr withExt p m env (Do sts e) =-> do-> (env',sts') <- mapAccumM (checkStatement withExt p m) env sts-> e' <- checkExpr withExt p m env' e-> return (Do sts' e')-> checkExpr withExt p m env (IfThenElse r e1 e2 e3) =-> do-> e1' <- checkExpr withExt p m env e1-> e2' <- checkExpr withExt p m env e2-> e3' <- checkExpr withExt p m env e3-> return (IfThenElse r e1' e2' e3')-> checkExpr withExt p m env (Case r e alts) =-> do-> e' <- checkExpr withExt p m env e-> alts' <- mapM (checkAlt withExt m env) alts-> return (Case r e' alts')-> checkExpr withExt p m env (RecordConstr fs)-> | not withExt = errorAt p noRecordExt-> | not (null fs) = -> let (Field _ label _) = head fs-> in case (lookupVar label env) of-> [] -> errorAt' (undefinedLabel label)-> [RecordLabel r ls]-> | not (null duplicates) ->-> errorAt' (duplicateLabel (head duplicates))-> | not (null missings) ->-> errorAt (positionOfIdent label) -> (missingLabel (head missings) r "record construction")-> | otherwise ->-> do fs' <- mapM (checkFieldExpr withExt m r env) fs-> return (RecordConstr fs')-> where ls' = map fieldLabel fs-> duplicates = maybeToList (dup ls')-> missings = ls \\ ls'-> [_] -> errorAt' (notALabel label)-> _ -> errorAt' (duplicateDefinition label)-> | otherwise = errorAt p emptyRecord-> checkExpr withExt p m env (RecordSelection e l)-> | not withExt = errorAt p noRecordExt-> | otherwise =-> case (lookupVar l env) of-> [] -> errorAt' (undefinedLabel l)-> [RecordLabel r ls] ->-> do e' <- checkExpr withExt p m env e-> return (RecordSelection e' l)-> [_] -> errorAt' (notALabel l)-> _ -> errorAt' (duplicateDefinition l)-> checkExpr withExt p m env (RecordUpdate fs e)-> | not withExt = errorAt p noRecordExt-> | not (null fs) =-> let (Field _ label _) = head fs-> in case (lookupVar label env) of-> [] -> errorAt' (undefinedLabel label)-> [RecordLabel r ls]-> | not (null duplicates) ->-> errorAt' (duplicateLabel (head duplicates))-> | otherwise ->-> do fs' <- mapM (checkFieldExpr withExt m r env) fs-> e' <- checkExpr withExt (positionOfIdent label) m env e-> return (RecordUpdate fs' e')-> where duplicates = maybeToList (dup (map fieldLabel fs))-> [_] -> errorAt' (notALabel label)-> _ -> errorAt' (duplicateDefinition label)-> | otherwise = errorAt p emptyRecord--> checkStatement :: Bool -> Position -> ModuleIdent -> RenameEnv -> Statement-> -> RenameState (RenameEnv,Statement)-> checkStatement withExt p m env (StmtExpr pos e) =-> do-> e' <- checkExpr withExt p m env e-> return (env,StmtExpr pos e')-> checkStatement withExt p m env (StmtBind pos t e) =-> do-> e' <- checkExpr withExt p m env e-> (env',[t']) <- checkArgs withExt p m env [t]-> return (env',StmtBind pos t' e')-> checkStatement withExt _ m env (StmtDecl ds) =-> do-> (env',ds') <- checkLocalDecls withExt m env ds-> return (env',StmtDecl ds')--> checkAlt :: Bool -> ModuleIdent -> RenameEnv -> Alt -> RenameState Alt-> checkAlt withExt m env (Alt p t rhs) =-> do-> (env',[t']) <- checkArgs withExt p m env [t]-> rhs' <- checkRhs withExt m env' rhs-> return (Alt p t' rhs')--> checkFieldExpr :: Bool -> ModuleIdent -> QualIdent -> RenameEnv -> -> Field Expression -> RenameState (Field Expression)-> checkFieldExpr withExt m r env (Field p l e)-> = case (lookupVar l env) of-> [] -> errorAt' (undefinedLabel l)-> [RecordLabel r' _]-> | r == r' -> do e' <- checkExpr withExt (positionOfIdent l) m env e-> return (Field p l e')-> | otherwise -> errorAt' (illegalLabel l r)-> [_] -> errorAt' (notALabel l)-> _ -> errorAt' (duplicateDefinition l)---> checkOp :: ModuleIdent -> RenameEnv -> InfixOp -> InfixOp-> checkOp m env op =-> case (qualLookupVar v env) of-> [] -> errorAt' (undefinedVariable v)-> [Constr _] -> InfixConstr v-> [GlobalVar _ _] -> InfixOp v-> [LocalVar _ v'] -> InfixOp (qualify v')-> rs -> case (qualLookupVar (qualQualify m v) env) of-> [] -> errorAt' (ambiguousIdent rs v)-> [Constr _] -> InfixConstr v-> [GlobalVar _ _] -> InfixOp v-> [LocalVar _ v'] -> InfixOp (qualify v')-> rs' -> errorAt' (ambiguousIdent rs' v)-> where v = opName op--\end{verbatim}-Auxiliary definitions.-\begin{verbatim}--> constrs :: Decl -> [Ident]-> constrs (DataDecl _ _ _ cs) = map constr cs-> where constr (ConstrDecl _ _ c _) = c-> constr (ConOpDecl _ _ _ op _) = op-> constrs (NewtypeDecl _ _ _ (NewConstrDecl _ _ c _)) = [c]-> constrs _ = []--> vars :: Decl -> [Ident]-> vars (TypeSig p fs _) = fs-> vars (EvalAnnot p fs _) = fs-> vars (FunctionDecl p f _) = [f]-> vars (ExternalDecl p _ _ f _) = [f]-> vars (FlatExternalDecl p fs) = fs-> vars (PatternDecl p t _) = (bv t)-> vars (ExtraVariables p vs) = vs-> vars _ = []--> renameLiteral :: Literal -> RenameState Literal-> renameLiteral (Int v i) = liftM (flip Int i . renameIdent v) newId-> renameLiteral l = return l---Since the compiler expects all rules of the same function to be together,-it is necessary to sort the list of declarations.--> sortFuncDecls :: [Decl] -> [Decl]-> sortFuncDecls decls = sortFD Map.empty [] decls-> where-> sortFD env res [] = reverse res-> sortFD env res (decl:decls)-> = case decl of-> FunctionDecl _ ident _-> | isJust (Map.lookup ident env)-> -> sortFD env (insertBy cmpFuncDecl decl res) decls-> | otherwise-> -> sortFD (Map.insert ident () env) (decl:res) decls-> _ -> sortFD env (decl:res) decls--> cmpFuncDecl :: Decl -> Decl -> Ordering-> cmpFuncDecl (FunctionDecl _ id1 _) (FunctionDecl _ id2 _)-> | id1 == id2 = EQ-> | otherwise = GT-> cmpFuncDecl decl1 decl2 = GT--cmpPos :: Position -> Position -> Ordering-cmpPos p1 p2 | lp1 < lp2 = LT- | lp1 == lp2 = EQ- | otherwise = GT- where lp1 = line p1- lp2 = line p2---\end{verbatim}-Due to the lack of a capitalization convention in Curry, it is-possible that an identifier may ambiguously refer to a data-constructor and a function provided that both are imported from some-other module. When checking whether an identifier denotes a-constructor there are two options with regard to ambiguous-identifiers:-\begin{enumerate}-\item Handle the identifier as a data constructor if at least one of- the imported names is a data constructor.-\item Handle the identifier as a data constructor only if all imported- entities are data constructors.-\end{enumerate}-We choose the first possibility here because in the second case a-redefinition of a constructor can magically become possible if a-function with the same name is imported. It seems better to warn-the user about the fact that the identifier is ambiguous.-\begin{verbatim}--> isDataConstr :: Ident -> RenameEnv -> Bool-> isDataConstr v = any isConstr . lookupVar v . globalEnv . toplevelEnv--> isConstr :: RenameInfo -> Bool-> isConstr (Constr _) = True-> isConstr (GlobalVar _ _) = False-> isConstr (LocalVar _ _) = False-> isConstr (RecordLabel _ _) = False--> varIdent :: RenameInfo -> Ident-> varIdent (GlobalVar _ v) = unqualify v-> varIdent (LocalVar _ v) = v-> varIdent _ = internalError "not a variable"--> qualVarIdent :: RenameInfo -> QualIdent-> qualVarIdent (GlobalVar _ v) = v-> qualVarIdent (LocalVar _ v) = qualify v-> qualVarIdent _ = internalError "not a qualified variable"--> arity :: RenameInfo -> Int-> arity (Constr n) = n-> arity (GlobalVar n _) = n-> arity (LocalVar n _) = n-> arity (RecordLabel _ ls) = length ls--\end{verbatim}-Unlike expressions, constructor terms have no possibility to represent-over-applications in function patterns. Therefore it is necessary to-transform them to nested-function patterns using the prelude function \texttt{apply}. E.g. the-the function pattern \texttt{(id id 10)} is transformed to-\texttt{(apply (id id) 10)}-\begin{verbatim}--> genFuncPattAppl :: ConstrTerm -> [ConstrTerm] -> ConstrTerm-> genFuncPattAppl term [] = term-> genFuncPattAppl term (t:ts) -> = FunctionPattern qApplyId [genFuncPattAppl term ts, t]-> where-> qApplyId = qualifyWith preludeMIdent (mkIdent "apply")--\end{verbatim}-Miscellaneous functions.-\begin{verbatim}--> typeArity :: TypeExpr -> Int-> typeArity (ArrowType _ t2) = 1 + typeArity t2-> typeArity _ = 0--> getFlatLhs :: Equation -> (Ident,[ConstrTerm])-> getFlatLhs (Equation _ lhs _) = flatLhs lhs--> dup :: Eq a => [a] -> Maybe a-> dup [] = Nothing-> dup (x:xs) | elem x xs = Just x-> | otherwise = dup xs--\end{verbatim}-Error messages.-\begin{verbatim}--> undefinedVariable :: QualIdent -> (Position,String)-> undefinedVariable v = -> (positionOfQualIdent v,-> qualName v ++ " is undefined")--> undefinedData :: QualIdent -> (Position,String)-> undefinedData c = -> (positionOfQualIdent c,-> "Undefined data constructor " ++ qualName c)--> undefinedLabel :: Ident -> (Position,String)-> undefinedLabel l = -> (positionOfIdent l,-> "Undefined record label `" ++ name l ++ "`")--> ambiguousIdent :: [RenameInfo] -> QualIdent -> (Position,String)-> ambiguousIdent rs-> | any isConstr rs = ambiguousData-> | otherwise = ambiguousVariable--> ambiguousVariable :: QualIdent -> (Position,String)-> ambiguousVariable v = -> (positionOfQualIdent v,-> "Ambiguous variable " ++ qualName v)--> ambiguousData :: QualIdent -> (Position,String)-> ambiguousData c = -> (positionOfQualIdent c,-> "Ambiguous data constructor " ++ qualName c)--> duplicateDefinition :: Ident -> (Position,String)-> duplicateDefinition v =-> (positionOfIdent v,-> "More than one definition for `" ++ name v ++ "`")--> duplicateVariable :: Ident -> (Position,String)-> duplicateVariable v = -> (positionOfIdent v,-> name v ++ " occurs more than once in pattern")--> duplicateData :: Ident -> (Position,String)-> duplicateData c = -> (positionOfIdent c,-> "More than one definition for data constructor `"-> ++ name c ++ "`")--> duplicateTypeSig :: Ident -> (Position,String)-> duplicateTypeSig v = -> (positionOfIdent v,-> "More than one type signature for `" ++ name v ++ "`")--> duplicateEvalAnnot :: Ident -> (Position,String)-> duplicateEvalAnnot v = -> (positionOfIdent v,-> "More than one eval annotation for `" ++ name v ++ "`")--> duplicateLabel :: Ident -> (Position,String)-> duplicateLabel l = -> (positionOfIdent l,-> "Multiple occurrence of record label `" ++ name l ++ "`")--> missingLabel :: Ident -> QualIdent -> String -> String -> missingLabel l r what = -> "Missing label `" ++ name l -> ++ "` in the " ++ what ++ " of `" -> ++ name (unqualify r) ++ "`" --qualName r---> illegalLabel :: Ident -> QualIdent -> (Position,String)-> illegalLabel l r = -> (positionOfIdent l,-> "Label `" ++ name l ++ "` is not defined in record `" -> ++ name (unqualify r) ++ "`") --qualName r--> illegalRecordId :: Ident -> (Position,String)-> illegalRecordId r = -> (positionOfIdent r,-> "Record identifier `" ++ name r -> ++ "` already assigned to a data constructor")--> nonVariable :: String -> Ident -> (Position,String)-> nonVariable what c = -> (positionOfIdent c, -> "Data constructor `" ++ name c ++ "` in left hand side of " ++ what)--> noBody :: Ident -> (Position,String)-> noBody v = -> (positionOfIdent v, -> "No body for `" ++ name v ++ "`")--> noTypeSig :: Ident -> (Position,String)-> noTypeSig f = -> (positionOfIdent f, -> "No type signature for external function `" ++ name f ++ "`")--> noToplevelPattern :: String-> noToplevelPattern = "Pattern declaration not allowed at top-level"--> notALabel :: Ident -> (Position,String)-> notALabel l = -> (positionOfIdent l, -> "`" ++ name l ++ "` is not a record label")--> emptyRecord :: String-> emptyRecord = "empty records are not allowed"--> differentArity :: Ident -> (Position,String)-> differentArity f = -> (positionOfIdent f, -> "Equations for `" ++ name f ++ "` have different arities")--> wrongArity :: QualIdent -> Int -> Int -> (Position,String)-> wrongArity c arity argc = -> (positionOfQualIdent c, -> "Data constructor " ++ qualName c ++ " expects " ++ arguments arity ++-> " but is applied to " ++ show argc)-> where arguments 0 = "no arguments"-> arguments 1 = "1 argument"-> arguments n = show n ++ " arguments"--> illegalRecordPatt :: String-> illegalRecordPatt = "Expexting `_` after `|` in the record pattern"--> noFuncPattExt :: String-> noFuncPattExt = "function patterns are not supported in standard curry"-> ++ extMessage--> noRecordExt :: String-> noRecordExt = "records are not supported in standard curry"-> ++ extMessage--> extMessage :: String-> extMessage = "\n(Use flag -e to enable extended curry)"--> infixWithoutParens :: [(QualIdent,QualIdent)] -> String-> infixWithoutParens calls =-> "Missing parens in infix patterns: \n" ++-> unlines (map (\(q1,q2) -> show q1 ++ " " ++ -> showLine (positionOfQualIdent q1) ++ -> "calls " ++ show q2 ++ " " ++ -> showLine (positionOfQualIdent q2)) calls)--\end{verbatim}--checkParen -@param Aufrufende InfixFunktion-@param ConstrTerm-@return Liste mit fehlerhaften Funktionsaufrufen-\begin{verbatim}--> checkParenConstrTerm :: (Maybe QualIdent) -> ConstrTerm -> [(QualIdent,QualIdent)]-> checkParenConstrTerm _ (LiteralPattern _) = []-> checkParenConstrTerm _ (NegativePattern _ _) = []-> checkParenConstrTerm _ (VariablePattern _) = []-> checkParenConstrTerm _ (ConstructorPattern qualIdent constrTerms) =-> concatMap (checkParenConstrTerm Nothing) constrTerms-> checkParenConstrTerm mCaller (InfixPattern constrTerm1 qualIdent constrTerm2) =-> maybe [] (\c -> [(c,qualIdent)]) mCaller ++-> checkParenConstrTerm Nothing constrTerm1 ++-> checkParenConstrTerm Nothing constrTerm2-> checkParenConstrTerm _ (ParenPattern constrTerm) =-> checkParenConstrTerm Nothing constrTerm-> checkParenConstrTerm _ (TuplePattern _ constrTerms) =-> concatMap (checkParenConstrTerm Nothing) constrTerms-> checkParenConstrTerm _ (ListPattern _ constrTerms) =-> concatMap (checkParenConstrTerm Nothing) constrTerms-> checkParenConstrTerm mCaller (AsPattern _ constrTerm) =-> checkParenConstrTerm mCaller constrTerm-> checkParenConstrTerm mCaller (LazyPattern _ constrTerm) =-> checkParenConstrTerm mCaller constrTerm-> checkParenConstrTerm _ (FunctionPattern _ constrTerms) =-> concatMap (checkParenConstrTerm Nothing) constrTerms-> checkParenConstrTerm mCaller (InfixFuncPattern constrTerm1 qualIdent constrTerm2) =-> maybe [] (\c -> [(c,qualIdent)]) mCaller ++-> checkParenConstrTerm Nothing constrTerm1 ++-> checkParenConstrTerm Nothing constrTerm2-> checkParenConstrTerm _ (RecordPattern fieldConstrTerms mConstrTerm) = -> maybe [] (checkParenConstrTerm Nothing) mConstrTerm ++-> concatMap (\(Field _ _ constrTerm) -> checkParenConstrTerm Nothing constrTerm) -> fieldConstrTerms--\end{verbatim}
− src/SyntaxColoring.hs
@@ -1,800 +0,0 @@-module SyntaxColoring (Program,Code(..),TypeKind(..),ConstructorKind(..),- IdentifierKind(..),FunctionKind(..), genProgram,- code2string,getQualIdent, position2code,- area2codes) where--import Debug.Trace-import Data.Function(on)--import Data.Maybe-import Data.Either-import Data.List-import Data.Char hiding(Space)--import Curry.Base.Position-import Curry.Base.Ident-import Curry.Base.MessageMonad-import Curry.Syntax -import Curry.Syntax.Lexer----debug = False -- mergen von Token und Codes--trace' s x = if debug then trace s x else x---debug' = False -- messages--trace'' s x = if debug' then trace s x else x--type Program = [(Int,Int,Code)] --data Code = Keyword String- | Space Int- | NewLine- | ConstructorName ConstructorKind QualIdent- | TypeConstructor TypeKind QualIdent- | Function FunctionKind QualIdent- | ModuleName ModuleIdent- | Commentary String- | NumberCode String- | StringCode String- | CharCode String- | Symbol String- | Identifier IdentifierKind QualIdent- | CodeWarning [WarnMsg] Code- | NotParsed String- deriving Show- -data TypeKind = TypeDecla- | TypeUse- | TypeExport deriving Show --data ConstructorKind = ConstrPattern- | ConstrCall- | ConstrDecla- | OtherConstrKind deriving Show- -data IdentifierKind = IdDecl- | IdOccur- | UnknownId deriving Show - -data FunctionKind = InfixFunction- | TypSig- | FunDecl- | FunctionCall- | OtherFunctionKind deriving Show - - - - ---- @param plaintext---- @param list with parse-Results with descending quality e.g. [typingParse,fullParse,parse] ---- @param lex-Result---- @return program-genProgram :: String -> [MsgMonad Module] -> MsgMonad [(Position,Token)] -> Program -genProgram plainText parseResults m- = case runMsg m of- (Left e, msgs) -> buildMessagesIntoPlainText (e : msgs) plainText- (Right posNtokList, mess) - -> let messages = (prepareMessages (concatMap getMessages parseResults ++ mess))- mergedMessages = (mergeMessages' (trace' ("Messages: " ++ show messages) messages) posNtokList)- (nameList,codes) = catIdentifiers parseResults- in tokenNcodes2codes nameList 1 1 mergedMessages codes-- ---- @param Program---- @param line---- @param col---- @return Code at this Position -position2code :: Program -> Int -> Int -> Maybe Code -position2code [] _ _ = Nothing-position2code [_] _ _ = Nothing-position2code ((l,c,code):xs@((_,c2,_):_)) line col- | line == l && col >= c && col < c2 = Just code- | l > line = Nothing- | otherwise = position2code xs line col- -area2codes :: Program -> Position -> Position -> [Code] -area2codes [] _ _ = []-area2codes xxs@((l,c,code):xs) p1@Position{file=file} p2 - | p1 > p2 = area2codes xxs p2 p1- | posEnd >= p1 && posBegin <= p2 = code : area2codes xs p1 p2- | posBegin > p2 = []- | otherwise = area2codes xs p1 p2- where- posBegin = Position file l c noRef- posEnd = Position file l (c + length (code2string code)) noRef- - ---- @param code---- @return qualIdent if available -getQualIdent :: Code -> Maybe QualIdent-getQualIdent (ConstructorName _ qualIdent) = Just qualIdent-getQualIdent (Function _ qualIdent) = Just qualIdent-getQualIdent (Identifier _ qualIdent) = Just qualIdent -getQualIdent (TypeConstructor _ qualIdent) = Just qualIdent-getQualIdent _ = Nothing - - --- DEBUGGING----------- wird bald nicht mehr gebraucht--setMessagePosition :: WarnMsg -> WarnMsg-setMessagePosition m@(WarnMsg (Just p) _) = trace'' ("pos:" ++ show p ++ ":" ++ show m) m-setMessagePosition (WarnMsg _ m) = - let mes@(WarnMsg pos _) = (WarnMsg (getPositionFromString m) m) in- trace'' ("pos:" ++ show pos ++ ":" ++ show mes) mes--getPositionFromString :: String -> Maybe Position-getPositionFromString message =- if line > 0 && col > 0 - then Just Position{file=file,line=line,column=col,astRef=noRef}- else Nothing- where- file = takeWhile (/= '"') (tail (dropWhile (/= '"') message))- line = readInt (takeWhile (/= '.') (drop 7 (dropWhile (/= ',') message)))- col = readInt (takeWhile (/= ':') (tail (dropWhile (/= '.') (drop 7 (dropWhile (/= ',') message)))))- - -readInt :: String -> Int -readInt s = - let onlyNum = filter isDigit s in- if null onlyNum- then 0- else read onlyNum :: Int---- --------------------------- ---- ----------------------------flatCode :: Code -> Code-flatCode (CodeWarning _ code) = code-flatCode code = code- -- --- ----------Message--------------------------------------- - --getMessages :: MsgMonad a -> [WarnMsg]-getMessages = snd . runMsg --(Result mess _) = mess--- getMessages (Failure mess) = mess--lessMessage :: WarnMsg -> WarnMsg -> Bool-lessMessage (WarnMsg mPos1 _) (WarnMsg mPos2 _) = mPos1 < mPos2--nubMessages :: [WarnMsg] -> [WarnMsg] -nubMessages = nubBy eqMessage--eqMessage :: WarnMsg -> WarnMsg -> Bool-eqMessage (WarnMsg p1 s1) (WarnMsg p2 s2) = (p1 == p2) && (s1 == s2)--prepareMessages :: [WarnMsg] -> [WarnMsg] -prepareMessages = qsort lessMessage . map setMessagePosition . nubMessages---buildMessagesIntoPlainText :: [WarnMsg] -> String -> Program-buildMessagesIntoPlainText messages text = - buildMessagesIntoPlainText' messages (lines text) [] 1- where- buildMessagesIntoPlainText' :: [WarnMsg] -> [String] -> [String] -> Int -> Program- buildMessagesIntoPlainText' _ [] [] _ = - []- buildMessagesIntoPlainText' _ [] postStrs line = - [(line,1,NotParsed (unlines postStrs))] - buildMessagesIntoPlainText' [] preStrs postStrs line = - [(line,1,NotParsed (unlines (preStrs ++ postStrs)))] - - buildMessagesIntoPlainText' messages (str:preStrs) postStrs ln = - let (pre,post) = partition isLeq messages in- if null pre - then buildMessagesIntoPlainText' post preStrs (postStrs ++ [str]) (ln + 1)- else (ln,1,NotParsed (unlines postStrs)) : - (ln,1,CodeWarning pre (NotParsed str)) :- (ln,1,NewLine) :- buildMessagesIntoPlainText' post preStrs [] (ln + 1)- where - isLeq (WarnMsg (Just p) _) = line p <= ln - isLeq _ = True- - - -- ---- @param parse-Modules [typingParse,fullParse,parse] -catIdentifiers :: [MsgMonad Module] -> ([(ModuleIdent,ModuleIdent)],[Code])-catIdentifiers = catIds . rights_sc . map (fst . runMsg)- where - catIds [] = ([],[])- catIds [m] =- catIdentifiers' m Nothing- catIds rs@(m:y:ys) = - catIdentifiers' (last rs) (Just m)- --- not in base befoer base4--rights_sc xs = [ x | Right x <- xs]----- @param parse-Module---- @param Maybe betterParse-Module -catIdentifiers' :: Module -> Maybe Module -> ([(ModuleIdent,ModuleIdent)],[Code])-catIdentifiers' (Module moduleIdent maybeExportSpec decls)- Nothing =- let codes = (concatMap decl2codes (qsort lessDecl decls)) in- (concatMap renamedImports decls, - ModuleName moduleIdent :- maybe [] exportSpec2codes maybeExportSpec ++ codes)-catIdentifiers' (Module moduleIdent maybeExportSpec1 _)- (Just (Module _ maybeExportSpec2 decls)) =- let codes = (concatMap decl2codes (qsort lessDecl decls)) in- (concatMap renamedImports decls,- replaceFunctionCalls $ - map (addModuleIdent moduleIdent)- ([ModuleName moduleIdent] ++- mergeExports2codes - (maybe [] (\(Exporting _ i) -> i) maybeExportSpec1)- (maybe [] (\(Exporting _ i) -> i) maybeExportSpec2) ++- codes)) - - -renamedImports :: Decl -> [(ModuleIdent,ModuleIdent)]-renamedImports decl =- case decl of- (ImportDecl _ oldName _ (Just newName) _) -> [(oldName,newName)]- _ -> []- - -replaceFunctionCalls :: [Code] -> [Code] -replaceFunctionCalls codes = map (idOccur2functionCall qualIdents) codes- where- qualIdents = findFunctionDecls codes- --findFunctionDecls :: [Code] -> [QualIdent]-findFunctionDecls = mapMaybe getQualIdent . - filter isFunctionDecl . - map flatCode --isFunctionDecl :: Code -> Bool-isFunctionDecl (Function FunDecl _) = True-isFunctionDecl _ = False --idOccur2functionCall :: [QualIdent] -> Code -> Code-idOccur2functionCall qualIdents ide@(Identifier IdOccur qualIdent) - | isQualified qualIdent = Function FunctionCall qualIdent- | elem qualIdent qualIdents = Function FunctionCall qualIdent- | otherwise = ide-idOccur2functionCall qualIdents (CodeWarning mess code) =- CodeWarning mess (idOccur2functionCall qualIdents code)-idOccur2functionCall _ code = code- --addModuleIdent :: ModuleIdent -> Code -> Code-addModuleIdent moduleIdent c@(Function x qualIdent) - | uniqueId (unqualify qualIdent) == 0 =- Function x (qualQualify moduleIdent qualIdent)- | otherwise = c-addModuleIdent moduleIdent cn@(ConstructorName x qualIdent) - | not $ isQualified qualIdent =- ConstructorName x (qualQualify moduleIdent qualIdent)- | otherwise = cn -addModuleIdent moduleIdent tc@(TypeConstructor TypeDecla qualIdent) - | not $ isQualified qualIdent =- TypeConstructor TypeDecla (qualQualify moduleIdent qualIdent)- | otherwise = tc -addModuleIdent moduleIdent (CodeWarning mess code) =- CodeWarning mess (addModuleIdent moduleIdent code)-addModuleIdent _ c = c- --- ------------------------------------------mergeMessages' :: [WarnMsg] -> [(Position,Token)] -> [([WarnMsg],Position,Token)]-mergeMessages' _ [] = []-mergeMessages' [] ((p,t):ps) = ([],p,t) : mergeMessages' [] ps-mergeMessages' mss@(m@(WarnMsg mPos x):ms) ((p,t):ps) - | mPos <= Just p = trace' (show mPos ++ " <= " ++ show (Just p) ++ " Message: " ++ x) ([m],p,t) : mergeMessages' ms ps - | otherwise = ([],p,t) : mergeMessages' mss ps---tokenNcodes2codes :: [(ModuleIdent,ModuleIdent)] -> Int -> Int -> [([WarnMsg],Position,Token)] -> [Code] -> [(Int,Int,Code)]-tokenNcodes2codes _ _ _ [] _ = [] -tokenNcodes2codes nameList currLine currCol toks@((messages,pos@Position{line=line,column=col},token):ts) codes - | currLine < line = - trace' " NewLine: "- ((currLine,currCol,NewLine) :- tokenNcodes2codes nameList (currLine + 1) 1 toks codes)- | currCol < col = - trace' (" Space " ++ show (col - currCol))- ((currLine,currCol,Space (col - currCol)) : - tokenNcodes2codes nameList currLine col toks codes)- | isTokenIdentifier token && null codes = - trace' ("empty Code-List, Token: " ++ show (line,col) ++ show token)- (addMessage [(currLine,currCol,NotParsed tokenStr)] ++ tokenNcodes2codes nameList newLine newCol ts codes)- | not (isTokenIdentifier token) = - trace' (" Token ist kein Identifier: " ++ tokenStr ) - (addMessage [(currLine,currCol,token2code token)] ++ tokenNcodes2codes nameList newLine newCol ts codes) - | tokenStr == code2string (head codes) =- trace' (" Code wird genommen: " ++ show (head codes) )- (addMessage [(currLine,currCol,head codes)] ++ tokenNcodes2codes nameList newLine newCol ts (tail codes)) - | tokenStr == code2qualString (renameModuleIdents nameList (head codes)) =- let mIdent = maybe Nothing rename (getModuleIdent (head codes)) - lenMod = maybe 0 (length . moduleName) mIdent- startPos = maybe currCol (const (currCol + lenMod + 1)) mIdent- symbol = [(currLine,currCol + lenMod,Symbol ".")] - prefix = maybe [] - ( (: symbol) . - ( \i -> (currLine,- currCol,- ModuleName i))) - mIdent in- trace' (" Code wird genommen: " ++ show (head codes) )- (addMessage (prefix ++ [(currCol,startPos,head codes)]) ++ tokenNcodes2codes nameList newLine newCol ts (tail codes)) - | elem tokenStr (codeQualifiers (head codes)) =- trace' (" Token: "++ tokenStr ++" ist Modulname von: " ++ show (head codes) )- (addMessage [(currLine,currCol,ModuleName (mkMIdent [tokenStr]))] ++ - tokenNcodes2codes nameList newLine newCol ts codes) - | otherwise = - trace' (" Token: "++ - tokenStr ++- ",Code faellt weg:" ++ - code2string (head codes) ++ - "|" ++ - code2qualString (head codes))- (tokenNcodes2codes nameList currLine currCol toks (tail codes))- where- tokenStr = token2string token - newLine = (currLine + length (lines tokenStr)) - 1 - newCol = currCol + length tokenStr -- rename mid = Just $ fromMaybe mid (lookup mid nameList)-- addMessage [] = []- addMessage ((l,c,code):cs)- | null messages = (l,c,code):cs- | otherwise = trace' ("Warning bei code: " ++ show codes ++ ":" ++ show messages) - ((l,c,CodeWarning messages code): addMessage cs)- - -renameModuleIdents :: [(ModuleIdent,ModuleIdent)] -> Code -> Code-renameModuleIdents nameList c =- case c of- Function x qualIdent -> Function x (rename qualIdent (qualidMod qualIdent))- Identifier x qualIdent -> Identifier x (rename qualIdent (qualidMod qualIdent))- _ -> c- where- rename x (Nothing) = x- rename x (Just m) = maybe x (\ m' -> qualifyWith m' (qualidId x)) (lookup m nameList)- -{--codeWithoutUniqueID :: Code -> String-codeWithoutUniqueID code = maybe (code2string code) (name . unqualify) $ getQualIdent code- --codeUnqualify :: Code -> Code-codeUnqualify code = maybe code (setQualIdent code . qualify . unqualify) $ getQualIdent code --} - -codeQualifiers :: Code -> [String]-codeQualifiers = maybe [] moduleQualifiers . getModuleIdent--getModuleIdent :: Code -> Maybe ModuleIdent-getModuleIdent (ConstructorName _ qualIdent) = qualidMod qualIdent-getModuleIdent (Function _ qualIdent) = qualidMod qualIdent-getModuleIdent (ModuleName moduleIdent) = Just moduleIdent-getModuleIdent (Identifier _ qualIdent) = qualidMod qualIdent -getModuleIdent (TypeConstructor _ qualIdent) = qualidMod qualIdent-getModuleIdent _ = Nothing--- -{--setQualIdent :: Code -> QualIdent -> Code-setQualIdent (Keyword str) _ = (Keyword str)-setQualIdent (Space i) _ = (Space i)-setQualIdent NewLine _ = NewLine-setQualIdent (ConstructorName kind _) qualIdent = (ConstructorName kind qualIdent)-setQualIdent (Function kind _) qualIdent = (Function kind qualIdent)-setQualIdent (ModuleName moduleIdent) _ = (ModuleName moduleIdent)-setQualIdent (Commentary str) _ = (Commentary str)-setQualIdent (NumberCode str) _ = (NumberCode str)-setQualIdent (Symbol str) _ = (Symbol str)-setQualIdent (Identifier kind _) qualIdent = (Identifier kind qualIdent) -setQualIdent (TypeConstructor kind _) qualIdent = (TypeConstructor kind qualIdent)-setQualIdent (StringCode str) _ = (StringCode str) -setQualIdent (CharCode str) _ = (CharCode str) --}- -code2string (Keyword str) = str-code2string (Space i)= concat (replicate i " ")-code2string NewLine = "\n"-code2string (ConstructorName _ qualIdent) = name $ unqualify qualIdent-code2string (Function _ qualIdent) = name $ unqualify qualIdent-code2string (ModuleName moduleIdent) = moduleName moduleIdent-code2string (Commentary str) = str-code2string (NumberCode str) = str-code2string (Symbol str) = str-code2string (Identifier _ qualIdent) = name $ unqualify qualIdent -code2string (TypeConstructor _ qualIdent) = name $ unqualify qualIdent-code2string (StringCode str) = str -code2string (CharCode str) = str-code2string (NotParsed str) = str-code2string _ = "" -- error / warning- -code2qualString (ConstructorName _ qualIdent) = qualName qualIdent-code2qualString (Function _ qualIdent) = qualName qualIdent-code2qualString (Identifier _ qualIdent) = qualName qualIdent -code2qualString (TypeConstructor _ qualIdent) = qualName qualIdent-code2qualString x = code2string x----token2code :: Token -> Code-token2code tok@(Token cat _)- | elem cat [IntTok,FloatTok,IntegerTok]- = NumberCode (token2string tok)- | elem cat [KW_case,KW_choice,KW_data,KW_do,KW_else,KW_eval,KW_external,- KW_free,KW_if,KW_import,KW_in,KW_infix,KW_infixl,KW_infixr,- KW_let,KW_module,KW_newtype,KW_of,KW_rigid,KW_then,KW_type,- KW_where,Id_as,Id_ccall,Id_forall,Id_hiding,Id_interface,Id_primitive,- Id_qualified]- = Keyword (token2string tok)- | elem cat [LeftParen,RightParen,Semicolon,LeftBrace,RightBrace,LeftBracket,- RightBracket,Comma,Underscore,Backquote,- At,Colon,DotDot,DoubleColon,Equals,Backslash,Bar,LeftArrow,RightArrow,- Tilde]- = Symbol (token2string tok)- | elem cat [LineComment, NestedComment]- = Commentary (token2string tok)- | isTokenIdentifier tok- = Identifier UnknownId $ qualify $ mkIdent $ token2string tok- | cat == StringTok - = StringCode (token2string tok)- | cat == CharTok- = CharCode (token2string tok) - | elem cat [EOF,VSemicolon,VRightBrace] = Space 0 - -isTokenIdentifier :: Token -> Bool-isTokenIdentifier (Token cat _) = - elem cat [Id,QId,Sym,QSym,Sym_Dot,Sym_Minus,Sym_MinusDot]- --- DECL Position--getPosition :: Decl -> Position-getPosition (ImportDecl pos _ _ _ _) = pos -getPosition (InfixDecl pos _ _ _) = pos -getPosition (DataDecl pos _ _ _) = pos -getPosition (NewtypeDecl pos _ _ _) = pos-getPosition (TypeDecl pos _ _ _) = pos -getPosition (TypeSig pos _ _) = pos -getPosition (EvalAnnot pos _ _) = pos-getPosition (FunctionDecl pos _ _) = pos -getPosition (ExternalDecl pos _ _ _ _) = pos-getPosition (FlatExternalDecl pos _) = pos -getPosition (PatternDecl pos _ _) = pos -getPosition (ExtraVariables pos _) = pos- --lessDecl :: Decl -> Decl -> Bool-lessDecl = (<) `on` getPosition--qsort _ [] = []-qsort less (x:xs) = qsort less [y | y <- xs, less y x] ++ [x] ++ qsort less [y | y <- xs, not $ less y x]------ DECL TO CODE -------------------------------------------------------------------- ----exportSpec2codes :: ExportSpec -> [Code]-exportSpec2codes (Exporting _ exports) = concatMap (export2codes []) exports----- @param parse-Exports---- @param betterParse-Exports-mergeExports2codes :: [Export] -> [Export] -> [Code]-mergeExports2codes [] _ = []-mergeExports2codes (e:es) xs = concatMap (export2codes xs) (e:es)---export2codes :: [Export] -> Export -> [Code]-export2codes exports e@(Export qualIdent) - | length (filter checkDouble exports) /= 1 = - [Identifier UnknownId qualIdent]- | otherwise =- let [export] = (filter checkDouble exports) in- export2c export - where - checkDouble (ExportTypeWith q _) = eqQualIdent qualIdent q- checkDouble (Export q) = eqQualIdent qualIdent q- checkDouble _ = False- - eqQualIdent q1 q2 - | q1 == q2 = True- | not (isQualified q1) = unqualify q1 == unqualify q2- | otherwise = False- - export2c (Export qualIdent) = - [Function OtherFunctionKind qualIdent]- export2c _ = - [TypeConstructor TypeExport qualIdent]- - - - -export2codes _ (ExportTypeWith qualIdent idents) = - TypeConstructor TypeExport qualIdent : map (Function OtherFunctionKind . qualify) idents-export2codes _ (ExportTypeAll qualIdent) = - [TypeConstructor TypeExport qualIdent] -export2codes _ (ExportModule moduleIdent) = - [ModuleName moduleIdent]--decl2codes :: Decl -> [Code] -decl2codes (ImportDecl _ moduleIdent xQualified mModuleIdent importSpec) = - [ModuleName moduleIdent] ++- maybe [] ((:[]) . ModuleName) mModuleIdent ++- maybe [] (importSpec2codes moduleIdent) importSpec-decl2codes (InfixDecl _ _ _ idents) =- map (Function InfixFunction . qualify) idents-decl2codes (DataDecl _ ident idents constrDecls) =- TypeConstructor TypeDecla (qualify ident) : - map (Identifier UnknownId . qualify) idents ++- concatMap constrDecl2codes constrDecls-decl2codes (NewtypeDecl xPosition xIdent yIdents xNewConstrDecl) =- []-decl2codes (TypeDecl _ ident idents typeExpr) =- TypeConstructor TypeDecla (qualify ident) : - map (Identifier UnknownId . qualify) idents ++ - typeExpr2codes typeExpr-decl2codes (TypeSig _ idents typeExpr) =- map (Function TypSig . qualify) idents ++ typeExpr2codes typeExpr -decl2codes (EvalAnnot xPosition idents xEvalAnnotation) =- map (Function FunDecl . qualify) idents-decl2codes (FunctionDecl _ _ equations) =- concatMap equation2codes equations -decl2codes (ExternalDecl xPosition xCallConv xString xIdent xTypeExpr) =- []-decl2codes (FlatExternalDecl _ idents) =- map (Function FunDecl . qualify) idents -decl2codes (PatternDecl xPosition constrTerm rhs) =- constrTerm2codes constrTerm ++ rhs2codes rhs-decl2codes (ExtraVariables _ idents) =- map (Identifier IdDecl . qualify) idents- -equation2codes :: Equation -> [Code]-equation2codes (Equation _ lhs rhs) =- lhs2codes lhs ++ rhs2codes rhs- -lhs2codes :: Lhs -> [Code]-lhs2codes (FunLhs ident constrTerms) =- Function FunDecl (qualify ident) : concatMap constrTerm2codes constrTerms-lhs2codes (OpLhs constrTerm1 ident constrTerm2) =- constrTerm2codes constrTerm1 ++ [Function FunDecl $ qualify ident] ++ constrTerm2codes constrTerm2-lhs2codes (ApLhs lhs constrTerms) =- lhs2codes lhs ++ concatMap constrTerm2codes constrTerms --rhs2codes :: Rhs -> [Code]-rhs2codes (SimpleRhs _ expression decls) =- expression2codes expression ++ concatMap decl2codes decls-rhs2codes (GuardedRhs condExprs decls) =- concatMap condExpr2codes condExprs ++ concatMap decl2codes decls- -condExpr2codes :: CondExpr -> [Code]-condExpr2codes (CondExpr _ expression1 expression2) = - expression2codes expression1 ++ expression2codes expression2 - -constrTerm2codes :: ConstrTerm -> [Code]-constrTerm2codes (LiteralPattern literal) = []-constrTerm2codes (NegativePattern ident literal) = []-constrTerm2codes (VariablePattern ident) = [Identifier IdDecl (qualify ident)]-constrTerm2codes (ConstructorPattern qualIdent constrTerms) =- ConstructorName ConstrPattern qualIdent : concatMap constrTerm2codes constrTerms-constrTerm2codes (InfixPattern constrTerm1 qualIdent constrTerm2) =- constrTerm2codes constrTerm1 ++ [ConstructorName ConstrPattern qualIdent] ++ constrTerm2codes constrTerm2-constrTerm2codes (ParenPattern constrTerm) = constrTerm2codes constrTerm-constrTerm2codes (TuplePattern _ constrTerms) = concatMap constrTerm2codes constrTerms-constrTerm2codes (ListPattern _ constrTerms) = concatMap constrTerm2codes constrTerms-constrTerm2codes (AsPattern ident constrTerm) =- Function OtherFunctionKind (qualify ident) : constrTerm2codes constrTerm-constrTerm2codes (LazyPattern _ constrTerm) = constrTerm2codes constrTerm-constrTerm2codes (FunctionPattern qualIdent constrTerms) = - Function OtherFunctionKind qualIdent : concatMap constrTerm2codes constrTerms-constrTerm2codes (InfixFuncPattern constrTerm1 qualIdent constrTerm2) =- constrTerm2codes constrTerm1 ++ [Function InfixFunction qualIdent] ++ constrTerm2codes constrTerm2- -expression2codes :: Expression -> [Code]-expression2codes (Literal literal) = []-expression2codes (Variable qualIdent) = - [Identifier IdOccur qualIdent]-expression2codes (Constructor qualIdent) = - [ConstructorName ConstrCall qualIdent]-expression2codes (Paren expression) = - expression2codes expression-expression2codes (Typed expression typeExpr) = - expression2codes expression ++ typeExpr2codes typeExpr-expression2codes (Tuple _ expressions) = - concatMap expression2codes expressions-expression2codes (List _ expressions) = - concatMap expression2codes expressions-expression2codes (ListCompr _ expression statements) = - expression2codes expression ++ concatMap statement2codes statements-expression2codes (EnumFrom expression) = - expression2codes expression-expression2codes (EnumFromThen expression1 expression2) = - expression2codes expression1 ++ expression2codes expression2-expression2codes (EnumFromTo expression1 expression2) = - expression2codes expression1 ++ expression2codes expression2-expression2codes (EnumFromThenTo expression1 expression2 expression3) = - expression2codes expression1 ++ - expression2codes expression2 ++ - expression2codes expression3-expression2codes (UnaryMinus ident expression) = - Symbol (name ident) : expression2codes expression -expression2codes (Apply expression1 expression2) = - expression2codes expression1 ++ expression2codes expression2-expression2codes (InfixApply expression1 infixOp expression2) = - expression2codes expression1 ++ infixOp2codes infixOp ++ expression2codes expression2-expression2codes (LeftSection expression infixOp) = - expression2codes expression ++ infixOp2codes infixOp-expression2codes (RightSection infixOp expression) = - infixOp2codes infixOp ++ expression2codes expression-expression2codes (Lambda _ constrTerms expression) = - concatMap constrTerm2codes constrTerms ++ expression2codes expression-expression2codes (Let decls expression) = - concatMap decl2codes decls ++ expression2codes expression-expression2codes (Do statements expression) = - concatMap statement2codes statements ++ expression2codes expression-expression2codes (IfThenElse _ expression1 expression2 expression3) = - expression2codes expression1 ++ expression2codes expression2 ++ expression2codes expression3-expression2codes (Case _ expression alts) = - expression2codes expression ++ concatMap alt2codes alts- -infixOp2codes :: InfixOp -> [Code]-infixOp2codes (InfixOp qualIdent) = [Function InfixFunction qualIdent]-infixOp2codes (InfixConstr qualIdent) = [ConstructorName OtherConstrKind qualIdent]---statement2codes :: Statement -> [Code] -statement2codes (StmtExpr _ expression) =- expression2codes expression-statement2codes (StmtDecl decls) =- concatMap decl2codes decls-statement2codes (StmtBind _ constrTerm expression) =- constrTerm2codes constrTerm ++ expression2codes expression---alt2codes :: Alt -> [Code]-alt2codes (Alt _ constrTerm rhs) =- constrTerm2codes constrTerm ++ rhs2codes rhs- -constrDecl2codes :: ConstrDecl -> [Code]-constrDecl2codes (ConstrDecl _ idents ident typeExprs) =- ConstructorName ConstrDecla (qualify ident) : concatMap typeExpr2codes typeExprs-constrDecl2codes (ConOpDecl _ idents typeExpr1 ident typeExpr2) = - typeExpr2codes typeExpr1 ++ [ConstructorName ConstrDecla $ qualify ident] ++ typeExpr2codes typeExpr2-- -importSpec2codes :: ModuleIdent -> ImportSpec -> [Code]-importSpec2codes moduleIdent (Importing _ imports) = concatMap (import2codes moduleIdent) imports-importSpec2codes moduleIdent (Hiding _ imports) = concatMap (import2codes moduleIdent) imports--import2codes :: ModuleIdent -> Import -> [Code]-import2codes moduleIdent (Import ident) =- [Function OtherFunctionKind $ qualifyWith moduleIdent ident] -import2codes moduleIdent (ImportTypeWith ident idents) = - ConstructorName OtherConstrKind (qualifyWith moduleIdent ident) :- map (Function OtherFunctionKind . qualifyWith moduleIdent) idents-import2codes moduleIdent (ImportTypeAll ident) = - [ConstructorName OtherConstrKind $ qualifyWith moduleIdent ident] - -typeExpr2codes :: TypeExpr -> [Code] -typeExpr2codes (ConstructorType qualIdent typeExprs) = - TypeConstructor TypeUse qualIdent : concatMap typeExpr2codes typeExprs-typeExpr2codes (VariableType ident) = - [Identifier IdOccur (qualify ident)]-typeExpr2codes (TupleType typeExprs) = - concatMap typeExpr2codes typeExprs-typeExpr2codes (ListType typeExpr) = - typeExpr2codes typeExpr-typeExpr2codes (ArrowType typeExpr1 typeExpr2) = - typeExpr2codes typeExpr1 ++ typeExpr2codes typeExpr2---- TOKEN TO STRING --------------------------------------------------------------token2string (Token Id a) = attributes2string a-token2string (Token QId a) = attributes2string a-token2string (Token Sym a) = attributes2string a-token2string (Token QSym a) = attributes2string a-token2string (Token IntTok a) = attributes2string a-token2string (Token FloatTok a) = attributes2string a-token2string (Token CharTok a) = attributes2string a-token2string (Token IntegerTok a) = attributes2string a-token2string (Token StringTok a) = attributes2string a-token2string (Token LeftParen _) = "("-token2string (Token RightParen _) = ")"-token2string (Token Semicolon _) = ";"-token2string (Token LeftBrace _) = "{"-token2string (Token RightBrace _) = "}"-token2string (Token LeftBracket _) = "["-token2string (Token RightBracket _) = "]"-token2string (Token Comma _) = ","-token2string (Token Underscore _) = "_"-token2string (Token Backquote _) = "`"-token2string (Token VSemicolon _) = ""-token2string (Token VRightBrace _) = ""-token2string (Token At _) = "@"-token2string (Token Colon _) = ":"-token2string (Token DotDot _) = ".."-token2string (Token DoubleColon _) = "::"-token2string (Token Equals _) = "="-token2string (Token Backslash _) = "\\"-token2string (Token Bar _) = "|"-token2string (Token LeftArrow _) = "<-"-token2string (Token RightArrow _) = "->"-token2string (Token Tilde _) = "~"-token2string (Token Sym_Dot _) = "."-token2string (Token Sym_Minus _) = "-"-token2string (Token Sym_MinusDot _) = "-."-token2string (Token KW_case _) = "case"-token2string (Token KW_choice _) = "choice"-token2string (Token KW_data _) = "data"-token2string (Token KW_do _) = "do"-token2string (Token KW_else _) = "else"-token2string (Token KW_eval _) = "eval"-token2string (Token KW_external _) = "external"-token2string (Token KW_free _) = "free"-token2string (Token KW_if _) = "if"-token2string (Token KW_import _) = "import"-token2string (Token KW_in _) = "in"-token2string (Token KW_infix _) = "infix"-token2string (Token KW_infixl _) = "infixl"-token2string (Token KW_infixr _) = "infixr"-token2string (Token KW_let _) = "let"-token2string (Token KW_module _) = "module"-token2string (Token KW_newtype _) = "newtype"-token2string (Token KW_of _) = "of"-token2string (Token KW_rigid _) = "rigid"-token2string (Token KW_then _) = "then"-token2string (Token KW_type _) = "type"-token2string (Token KW_where _) = "where"-token2string (Token Id_as _) = "as"-token2string (Token Id_ccall _) = "ccall"-token2string (Token Id_forall _) = "forall"-token2string (Token Id_hiding _) = "hiding"-token2string (Token Id_interface _) = "interface"-token2string (Token Id_primitive _) = "primitive"-token2string (Token Id_qualified _) = "qualified"-token2string (Token EOF _) = ""-token2string (Token LineComment (StringAttributes sval _)) = sval-token2string (Token NestedComment (StringAttributes sval _)) = sval--attributes2string NoAttributes = ""-attributes2string (CharAttributes cval _) = showCh cval -attributes2string (IntAttributes ival _) = show ival-attributes2string (FloatAttributes fval _) = show fval-attributes2string (IntegerAttributes intval _) = show intval-attributes2string (StringAttributes sval _) = showSt sval -attributes2string (IdentAttributes mIdent ident) =concat (intersperse "." (mIdent ++ [ident])) ---showCh c - | c == '\\' = "'\\\\'"- | elem c ('\127' : ['\001' .. '\031']) = show c- | otherwise = toString c- where- toString c = '\'' : c : "'"--showSt = addQuotes . concatMap toGoodChar - where- addQuotes x = "\"" ++ x ++ "\""--toGoodChar c - | c == '\\' = "\\\\"- | elem c ('\127' : ['\001' .. '\031']) = justShow c- | c == '"' = "\\\""- | otherwise = c : "" - where- justShow = init . tail . show
+ src/TokenStream.hs view
@@ -0,0 +1,168 @@+{- |+ Module : $Header$+ Description : Generating List of Tokens and Spans+ Copyright : (c) 2015 - 2016, Katharina Rahf+ 2015 - 2016, Björn Peemöller+ 2015 - 2016, Jan Tikovsky++ This module defines a function for writing the list of tokens+ and spans of a Curry source module into a separate file.+-}++module TokenStream (showTokenStream, showCommentTokenStream) where++import Data.List (intercalate)++import Curry.Base.Position (Position (..))+import Curry.Base.Span (Span (..))+import Curry.Syntax (Token (..), Category (..), Attributes (..))++-- |Show a list of 'Span' and 'Token' tuples.+-- The list is split into one tuple on each line to increase readability.+showTokenStream :: [(Span, Token)] -> String+showTokenStream [] = "[]\n"+showTokenStream ts =+ "[ " ++ intercalate "\n, " (map showST filteredTs) ++ "\n]\n"+ where filteredTs = filter (not . isVirtual) ts+ showST (sp, t) = "(" ++ showSpanAsPair sp ++ ", " ++ showToken t ++ ")"++-- |Show a list of 'Span' and 'Token' tuples filtered by CommentTokens.+-- The list is split into one tuple on each line to increase readability.+showCommentTokenStream :: [(Span, Token)] -> String+showCommentTokenStream [] = "[]\n"+showCommentTokenStream ts =+ "[ " ++ intercalate "\n, " (map showST filteredTs) ++ "\n]\n"+ where filteredTs = filter isComment ts+ showST (sp, t) = "(" ++ showSpan sp ++ ", " ++ showToken t ++ ")"++isVirtual :: (Span, Token) -> Bool+isVirtual (_, Token cat _) = cat `elem` [EOF, VRightBrace, VSemicolon]++isComment :: (Span, Token) -> Bool+isComment (_, Token cat _) = cat `elem` [LineComment, NestedComment]++-- show 'span' as "((startLine, startColumn), (endLine, endColumn))"+showSpanAsPair :: Span -> String+showSpanAsPair sp =+ "(" ++ showPosAsPair (start sp) ++ ", " ++ showPos (end sp) ++ ")"++-- show 'span' as "(Span startPos endPos)"+showSpan :: Span -> String+showSpan NoSpan = "NoSpan"+showSpan Span { start = s, end = e } =+ "(Span " ++ showPos s ++ " " ++ showPos e ++ ")"++-- show 'position' as "(Position line column)"+showPos :: Position -> String+showPos NoPos = "NoPos"+showPos Position { line = l, column = c } =+ "(Position " ++ show l++ " " ++ show c ++ ")"++-- show 'Position' as "(line, column)"+showPosAsPair :: Position -> String+showPosAsPair p = "(" ++ show (line p) ++ ", " ++ show (column p) ++ ")"++-- |Show tokens and their value if needed+showToken :: Token -> String+-- literals+showToken (Token CharTok a) = "CharTok" +++ showAttributes a+showToken (Token IntTok a) = "IntTok" +++ showAttributes a+showToken (Token FloatTok a) = "FloatTok" +++ showAttributes a+showToken (Token StringTok a) = "StringTok" +++ showAttributes a+-- identifiers+showToken (Token Id a) = "Id" +++ showAttributes a+showToken (Token QId a) = "QId" +++ showAttributes a+showToken (Token Sym a) = "Sym" +++ showAttributes a+showToken (Token QSym a) = "QSym" +++ showAttributes a+-- punctuation symbols+showToken (Token LeftParen _) = "LeftParen"+showToken (Token RightParen _) = "RightParen"+showToken (Token Semicolon _) = "Semicolon"+showToken (Token LeftBrace _) = "LeftBrace"+showToken (Token RightBrace _) = "RightBrace"+showToken (Token LeftBracket _) = "LeftBracket"+showToken (Token RightBracket _) = "RightBracket"+showToken (Token Comma _) = "Comma"+showToken (Token Underscore _) = "Underscore"+showToken (Token Backquote _) = "Backquote"+-- layout+showToken (Token VSemicolon _) = "VSemicolon"+showToken (Token VRightBrace _) = "VRightBrace"+-- reserved keywords+showToken (Token KW_case _) = "KW_case"+showToken (Token KW_class _) = "KW_class"+showToken (Token KW_data _) = "KW_data"+showToken (Token KW_default _) = "KW_default"+showToken (Token KW_deriving _) = "KW_deriving"+showToken (Token KW_do _) = "KW_do"+showToken (Token KW_else _) = "KW_else"+showToken (Token KW_external _) = "KW_external"+showToken (Token KW_fcase _) = "KW_fcase"+showToken (Token KW_free _) = "KW_free"+showToken (Token KW_if _) = "KW_if"+showToken (Token KW_import _) = "KW_import"+showToken (Token KW_in _) = "KW_in"+showToken (Token KW_infix _) = "KW_infix"+showToken (Token KW_infixl _) = "KW_infixl"+showToken (Token KW_infixr _) = "KW_infixr"+showToken (Token KW_instance _) = "KW_instance"+showToken (Token KW_let _) = "KW_let"+showToken (Token KW_module _) = "KW_module"+showToken (Token KW_newtype _) = "KW_newtype"+showToken (Token KW_of _) = "KW_of"+showToken (Token KW_then _) = "KW_then"+showToken (Token KW_type _) = "KW_type"+showToken (Token KW_where _) = "KW_where"+-- reserved operators+showToken (Token At _) = "At"+showToken (Token Colon _) = "Colon"+showToken (Token DotDot _) = "DotDot"+showToken (Token DoubleColon _) = "DoubleColon"+showToken (Token Equals _) = "Equals"+showToken (Token Backslash _) = "Backslash"+showToken (Token Bar _) = "Bar"+showToken (Token LeftArrow _) = "LeftArrow"+showToken (Token RightArrow _) = "RightArrow"+showToken (Token Tilde _) = "Tilde"+showToken (Token DoubleArrow _) = "DoubleArrow"+-- special identifiers+showToken (Token Id_as _) = "Id_as"+showToken (Token Id_ccall _) = "Id_ccall"+showToken (Token Id_forall _) = "Id_forall"+showToken (Token Id_hiding _) = "Id_hiding"+showToken (Token Id_interface _) = "Id_interface"+showToken (Token Id_primitive _) = "Id_primitive"+showToken (Token Id_qualified _) = "Id_qualified"+-- special operators+showToken (Token SymDot _) = "SymDot"+showToken (Token SymMinus _) = "SymMinus"+-- special symbols+showToken (Token SymStar _) = "SymStar"+-- pragmas+showToken (Token PragmaLanguage _) = "PragmaLanguage"+showToken (Token PragmaOptions a) = "PragmaOptions" +++ showAttributes a+showToken (Token PragmaHiding _) = "PragmaHiding"+showToken (Token PragmaMethod _) = "PragmaMethod"+showToken (Token PragmaModule _) = "PragmaModule"+showToken (Token PragmaEnd _) = "PragmaEnd"+-- comments+showToken (Token LineComment a) = "LineComment" +++ showAttributes a+showToken (Token NestedComment a) = "NestedComment" +++ showAttributes a+-- end-of-file token+showToken (Token EOF _) = "EOF"++showAttributes :: Attributes -> String+showAttributes NoAttributes = ""+showAttributes (CharAttributes c _) = show c+showAttributes (IntAttributes i _) = show i+showAttributes (FloatAttributes f _) = show f+showAttributes (StringAttributes s _) = show s+showAttributes (IdentAttributes m i) = show $ intercalate "." (m ++ [i])+showAttributes (OptionsAttributes t a) = "(" ++ show t ++ ")" ++ ' ' : show a++-- Concatenate two 'String's with a smart space in between,+-- which is only added if both 'String's are non-empty+(+++) :: String -> String -> String+[] +++ t = t+s +++ [] = s+s +++ t = s ++ ' ' : t
− src/TopEnv.lhs
@@ -1,148 +0,0 @@--% $Id: TopEnv.lhs,v 1.20 2003/10/04 17:04:32 wlux Exp $-%-% Copyright (c) 1999-2003, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{TopEnv.lhs}-\subsection{Top-Level Environments}\label{sec:toplevel-env}-The module \texttt{TopEnv} implements environments for qualified and-possibly ambiguous identifiers. An identifier is ambiguous if two-different entities are imported under the same name or if a local-definition uses the same name as an imported entity. Following an idea-presented in \cite{DiatchkiJonesHallgren02:ModuleSystem}, an-identifier is associated with a list of entities in order to handle-ambiguous names properly.--In general, two entities are considered equal if the names of their-original definitions match. However, in the case of algebraic data-types it is possible to hide some or all of their data constructors on-import and export, respectively. In this case we have to merge both-imports such that all data constructors which are visible through any-import path are visible in the current module. The class-\texttt{Entity} is used to handle this merge.--The code in this module ensures that the list of entities returned by-the functions \texttt{lookupTopEnv} and \texttt{qualLookupTopEnv}-contains exactly one element for each imported entity regardless of-how many times and from which module(s) it was imported. Thus, the-result of these function is a list with exactly one element if and-only if the identifier is unambiguous. The module names associated-with an imported entity identify the modules from which the entity was-imported.-\begin{verbatim}--> module TopEnv(TopEnv(..), Entity(..), emptyTopEnv,-> predefTopEnv,qualImportTopEnv,importTopEnv,-> bindTopEnv,qualBindTopEnv,rebindTopEnv,qualRebindTopEnv,-> unbindTopEnv,lookupTopEnv,qualLookupTopEnv,-> allImports,moduleImports,localBindings-> ) where--> import Data.Maybe-> import qualified Data.Map as Map-> import Control.Arrow(second)-> import Curry.Base.Ident---> data Source = Local | Import [ModuleIdent] deriving (Eq,Show)--> class Entity a where-> origName :: a -> QualIdent-> merge :: a -> a -> Maybe a-> merge x y-> | origName x == origName y = Just x-> | otherwise = Nothing--> newtype TopEnv a = TopEnv { topEnvMap :: Map.Map QualIdent [(Source,a)] -> } deriving Show--> instance Functor TopEnv where-> fmap f (TopEnv env) = TopEnv (fmap (map (second f)) env)--> entities :: QualIdent -> Map.Map QualIdent [(Source,a)] -> [(Source,a)]-> entities x env = fromMaybe [] (Map.lookup x env)--> emptyTopEnv :: TopEnv a-> emptyTopEnv = TopEnv Map.empty--> predefTopEnv :: Entity a => QualIdent -> a -> TopEnv a -> TopEnv a-> predefTopEnv x y (TopEnv env) =-> case Map.lookup x env of-> Just _ -> error "internal error: predefTopEnv"-> Nothing -> TopEnv (Map.insert x [(Import [],y)] env)--> importTopEnv :: Entity a => ModuleIdent -> Ident -> a -> TopEnv a -> TopEnv a-> importTopEnv m x y (TopEnv env) =-> TopEnv (Map.insert x' (mergeImport m y (entities x' env)) env)-> where x' = qualify x--> qualImportTopEnv :: Entity a => ModuleIdent -> Ident -> a -> TopEnv a-> -> TopEnv a-> qualImportTopEnv m x y (TopEnv env) =-> TopEnv (Map.insert x' (mergeImport m y (entities x' env)) env)-> where x' = qualifyWith m x--> mergeImport :: Entity a => ModuleIdent -> a -> [(Source,a)] -> [(Source,a)]-> mergeImport m x [] = [(Import [m],x)]-> mergeImport m x ((Local,x') : xs) = (Local,x') : mergeImport m x xs-> mergeImport m x ((Import ms,x') : xs) =-> case merge x x' of-> Just x'' -> (Import (m:ms),x'') : xs-> Nothing -> (Import ms,x') : mergeImport m x xs--> bindTopEnv :: String -> Ident -> a -> TopEnv a -> TopEnv a-> bindTopEnv fun x y env = qualBindTopEnv fun (qualify x) y env--> qualBindTopEnv :: String -> QualIdent -> a -> TopEnv a -> TopEnv a-> qualBindTopEnv fun x y (TopEnv env) =-> TopEnv (Map.insert x (bindLocal y (entities x env)) env)-> where bindLocal y ys-> | null [y' | (Local,y') <- ys] = (Local,y) : ys-> | otherwise = error ("internal error: \"qualBindTopEnv " -> ++ show x ++ "\" failed in function \""-> ++ fun ++ "\"")--> rebindTopEnv :: Ident -> a -> TopEnv a -> TopEnv a-> rebindTopEnv = qualRebindTopEnv . qualify--> qualRebindTopEnv :: QualIdent -> a -> TopEnv a -> TopEnv a-> qualRebindTopEnv x y (TopEnv env) =-> TopEnv (Map.insert x (rebindLocal (entities x env)) env)-> where rebindLocal [] = error "internal error: qualRebindTopEnv"-> rebindLocal ((Local,_) : ys) = (Local,y) : ys-> rebindLocal ((Import ms,y) : ys) = (Import ms,y) : rebindLocal ys--> unbindTopEnv :: Ident -> TopEnv a -> TopEnv a-> unbindTopEnv x (TopEnv env) =-> TopEnv (Map.insert x' (unbindLocal (entities x' env)) env)-> where x' = qualify x-> unbindLocal [] = error "internal error: unbindTopEnv"-> unbindLocal ((Local,_) : ys) = ys-> unbindLocal ((Import ms,y) : ys) = (Import ms,y) : unbindLocal ys--> lookupTopEnv :: Ident -> TopEnv a -> [a]-> lookupTopEnv = qualLookupTopEnv . qualify--> qualLookupTopEnv :: QualIdent -> TopEnv a -> [a]-> qualLookupTopEnv x (TopEnv env) = map snd (entities x env)--> allImports :: TopEnv a -> [(QualIdent,a)]-> allImports (TopEnv env) =-> [(x,y) | (x,ys) <- Map.toList env, (Import _,y) <- ys]--> unqualBindings :: TopEnv a -> [(Ident,(Source,a))]-> unqualBindings (TopEnv env) =-> [(x',y) | (x,ys) <- takeWhile (not . isQualified . fst) (Map.toList env),-> let x' = unqualify x, y <- ys]--> moduleImports :: ModuleIdent -> TopEnv a -> [(Ident,a)]-> moduleImports m env =-> [(x,y) | (x,(Import ms,y)) <- unqualBindings env, m `elem` ms]--> localBindings :: TopEnv a -> [(Ident,a)]-> localBindings env = [(x,y) | (x,(Local,y)) <- unqualBindings env]--\end{verbatim}
+ src/Transformations.hs view
@@ -0,0 +1,89 @@+{- |+ Module : $Header$+ Description : Code transformations+ Copyright : (c) 2011, Björn Peemöller (bjp@informatik.uni-kiel.de)+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module subsumes the different transformations of the source code.+-}+module Transformations where++import Curry.Syntax++import Base.Types++import Transformations.CaseCompletion as CC (completeCase)+import Transformations.CurryToIL as IL (ilTrans, transType)+import Transformations.Derive as DV (derive)+import Transformations.Desugar as DS (desugar)+import Transformations.Dictionary as DI (insertDicts)+import Transformations.Lift as L (lift)+import Transformations.Newtypes as NT (removeNewtypes)+import Transformations.Qual as Q (qual)+import Transformations.Simplify as S (simplify)++import Env.TypeConstructor++import CompilerEnv+import Imports (qualifyEnv)+import qualified IL++-- |Fully qualify used constructors and functions.+qual :: CompEnv (Module a) -> CompEnv (Module a)+qual (env, mdl) = (qualifyEnv env, mdl')+ where mdl' = Q.qual (moduleIdent env) (tyConsEnv env) (valueEnv env) mdl++-- |Automatically derive instances.+derive :: CompEnv (Module PredType) -> CompEnv (Module PredType)+derive (env, mdl) = (env, mdl')+ where mdl' = DV.derive (tyConsEnv env) (valueEnv env) (instEnv env)+ (opPrecEnv env) mdl++-- |Remove any syntactic sugar, changes the value environment.+desugar :: CompEnv (Module PredType) -> CompEnv (Module PredType)+desugar (env, mdl) = (env { valueEnv = tyEnv' }, mdl')+ where (mdl', tyEnv') = DS.desugar (extensions env) (valueEnv env)+ (tyConsEnv env) mdl++-- |Insert dictionaries, changes the type constructor and value environments.+insertDicts :: Bool -> CompEnv (Module PredType) -> CompEnv (Module Type)+insertDicts inlDi (env, mdl) = (env { interfaceEnv = intfEnv'+ , tyConsEnv = tcEnv'+ , valueEnv = vEnv'+ , opPrecEnv = pEnv' }, mdl')+ where (mdl', intfEnv', tcEnv', vEnv', pEnv') =+ DI.insertDicts inlDi (interfaceEnv env) (tyConsEnv env)+ (valueEnv env) (classEnv env) (instEnv env)+ (opPrecEnv env) mdl++-- |Remove newtype constructors.+removeNewtypes :: Bool -> CompEnv (Module Type) -> CompEnv (Module Type)+removeNewtypes remNT (env, mdl) = (env, mdl')+ where mdl' = NT.removeNewtypes remNT (valueEnv env) mdl++-- |Simplify the source code, changes the value environment.+simplify :: CompEnv (Module Type) -> CompEnv (Module Type)+simplify (env, mdl) = (env { valueEnv = tyEnv' }, mdl')+ where (mdl', tyEnv') = S.simplify (valueEnv env) mdl++-- |Lift local declarations, changes the value environment.+lift :: CompEnv (Module Type) -> CompEnv (Module Type)+lift (env, mdl) = (env { valueEnv = tyEnv' }, mdl')+ where (mdl', tyEnv') = L.lift (valueEnv env) mdl++-- |Translate into the intermediate language+ilTrans :: Bool -> CompEnv (Module Type) -> CompEnv IL.Module+ilTrans remIm (env, mdl) = (env, il)+ where il = IL.ilTrans remIm (valueEnv env) (tyConsEnv env) mdl++transType :: TCEnv -> Type -> IL.Type+transType = IL.transType++-- |Add missing case branches+completeCase :: CompEnv IL.Module -> CompEnv IL.Module+completeCase (env, mdl) =+ (env, CC.completeCase (interfaceEnv env) (tyConsEnv env) mdl)
+ src/Transformations/CaseCompletion.hs view
@@ -0,0 +1,479 @@+{- |+ Module : $Header$+ Description : CaseCompletion+ Copyright : (c) 2005 Martin Engelke+ 2011 - 2015 Björn Peemöller+ 2016 Jan Tikovsky+ 2016 - 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ This module expands case branches with missing constructors.++ The MCC translates case expressions into the intermediate language+ representation (IL) without completing them (i.e. without generating+ case branches for missing contructors), because the intermediate language+ supports variable patterns for the fallback case.+ In contrast, the FlatCurry representation of patterns only allows+ literal and constructor patterns, which requires the expansion+ default branches to all missing constructors.++ This is only necessary for *rigid* case expressions, because any+ *flexible* case expression with more than one branch and a variable+ pattern is non-deterministic. In consequence, these overlapping patterns+ have already been eliminated in the pattern matching compilation+ process (see module CurryToIL).++ To summarize, this module expands all rigid case expressions.+-}+{-# LANGUAGE CPP #-}+module Transformations.CaseCompletion (completeCase) where++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative ((<$>), (<*>))+#endif+import qualified Control.Monad.State as S (State, evalState, gets, modify)+import Data.List (find)+import Data.Maybe (fromMaybe, listToMaybe)++import Curry.Base.Ident+import qualified Curry.Syntax as CS++import Base.CurryTypes (toType)+import Base.Expr+import Base.Messages (internalError)+import Base.Types ( boolType, charType, floatType+ , intType, listType+ )+import Base.Subst++import Env.TypeConstructor+import Env.Interface (InterfaceEnv, lookupInterface)++import Transformations.CurryToIL (transType)+import Transformations.Dictionary (qImplMethodId)++import IL++-- Completes case expressions by adding branches for missing constructors.+-- The interface environment 'iEnv' is needed to compute these constructors.+completeCase :: InterfaceEnv -> TCEnv -> Module -> Module+completeCase iEnv tcEnv mdl@(Module mid is ds) = Module mid is ds'+ where ds'= S.evalState (mapM ccDecl ds) (CCState mdl iEnv 0 tcEnv )++-- -----------------------------------------------------------------------------+-- Internally used state monad+-- -----------------------------------------------------------------------------++data CCState = CCState+ { modul :: Module+ , interfaceEnv :: InterfaceEnv+ , nextId :: Int+ , tyconEnv :: TCEnv+ }++type CCM a = S.State CCState a++getModule :: CCM Module+getModule = S.gets modul++getTCEnv :: CCM TCEnv+getTCEnv = S.gets tyconEnv++getInterfaceEnv :: CCM InterfaceEnv+getInterfaceEnv = S.gets interfaceEnv++-- Create a fresh identifier+freshIdent :: CCM Ident+freshIdent = do+ nid <- S.gets nextId+ S.modify $ \s -> s { nextId = succ nid }+ return $ mkIdent $ "_#comp" ++ show nid++-- -----------------------------------------------------------------------------+-- The following functions traverse an IL term searching for case expressions+-- -----------------------------------------------------------------------------++ccDecl :: Decl -> CCM Decl+ccDecl dd@(DataDecl _ _ _) = return dd+ccDecl edd@(ExternalDataDecl _ _) = return edd+ccDecl (FunctionDecl qid vs ty e) = FunctionDecl qid vs ty <$> ccExpr e+ccDecl ed@(ExternalDecl _ _ _) = return ed+ccDecl nd@(NewtypeDecl _ _ _) = return nd++ccExpr :: Expression -> CCM Expression+ccExpr l@(Literal _ _) = return l+ccExpr v@(Variable _ _) = return v+ccExpr f@(Function _ _ _) = return f+ccExpr c@(Constructor _ _ _) = return c+ccExpr (Apply e1 e2) = Apply <$> ccExpr e1 <*> ccExpr e2+ccExpr (Case ea e bs) = do+ e' <- ccExpr e+ bs' <- mapM ccAlt bs+ ccCase ea e' bs'+ccExpr (Or e1 e2) = Or <$> ccExpr e1 <*> ccExpr e2+ccExpr (Exist v ty e) = Exist v ty <$> ccExpr e+ccExpr (Let b e) = Let <$> ccBinding b <*> ccExpr e+ccExpr (Letrec bs e) = Letrec <$> mapM ccBinding bs <*> ccExpr e+ccExpr (Typed e ty) = flip Typed ty <$> ccExpr e++ccAlt :: Alt -> CCM Alt+ccAlt (Alt p e) = Alt p <$> ccExpr e++ccBinding :: Binding -> CCM Binding+ccBinding (Binding v e) = Binding v <$> ccExpr e++-- ---------------------------------------------------------------------------+-- Functions for completing case alternatives+-- ---------------------------------------------------------------------------+ccCase :: Eval -> Expression -> [Alt] -> CCM Expression+-- flexible cases are not completed+ccCase Flex e alts = return $ Case Flex e alts+ccCase Rigid _ [] = internalError $ "CaseCompletion.ccCase: "+ ++ "empty alternative list"+ccCase Rigid e as@(Alt p _:_) = case p of+ ConstructorPattern _ _ _ -> completeConsAlts Rigid e as+ LiteralPattern _ _ -> completeLitAlts Rigid e as+ VariablePattern _ _ -> completeVarAlts e as++-- Completes a case alternative list which branches via constructor patterns+-- by adding alternatives. Thus, case expressions of the form+-- case <ce> of+-- <C_1> -> <expr_1>+-- :+-- <C_n> -> <expr_n>+-- [<var> -> <default_expr>]+-- are in general extended to+-- let x = <ce> in+-- let y = <default_expr>[<var>/x] in+-- case x of+-- <C_1> -> <expr_1>+-- :+-- <C_n> -> <expr_n>+-- <C'_1> -> y+-- :+-- <C'_m> -> y+-- where the C'_j are the complementary constructor patterns of the C_i,+-- @x@ and @y@ are fresh variables, and "default_expr" is the expression+-- from the first alternative containing a variable pattern. If there is no such+-- alternative, the default expression is set to the prelude function 'failed'.+-- In addition, there are a few optimizations performed to avoid the+-- construction of unnecessary let-bindings:+-- - If there are no complementary patterns, the expression remains unchanged.+-- - If there is only one complementary pattern,+-- the binding for @y@ is avoided (see @bindDefVar@).+-- - If the variable @<var>@ does not occur in the default expression,+-- the binding for @x@ is avoided (see @mkCase@).+completeConsAlts :: Eval -> Expression -> [Alt] -> CCM Expression+completeConsAlts ea ce alts = do+ mdl <- getModule+ menv <- getInterfaceEnv+ tcEnv <- getTCEnv+ -- complementary constructor patterns+ complPats <- mapM genPat $ getComplConstrs mdl menv tcEnv+ [ c | (Alt (ConstructorPattern _ c _) _) <- consAlts ]+ v <- freshIdent+ w <- freshIdent+ return $ case (complPats, defaultAlt v) of+ (_:_, Just e') -> bindDefVar v ce w e' complPats+ _ -> Case ea ce consAlts+ where+ -- existing contructor pattern alternatives+ consAlts = [ a | a@(Alt (ConstructorPattern _ _ _) _) <- alts ]++ -- unifier for data type and concrete pattern type+ dataTy = let TypeConstructor qid tys = patTy+ in TypeConstructor qid $ map TypeVariable [0 .. length tys - 1]+ patTy = let Alt pat _ = head consAlts in typeOf pat+ tySubst = matchType dataTy patTy idSubst++ -- generate a new constructor pattern+ genPat (qid, tys) = ConstructorPattern patTy qid <$>+ mapM (\ty' -> freshIdent >>= \v -> return (ty', v)) (subst tySubst tys)++ -- default alternative, if there is one+ defaultAlt v = listToMaybe [ replaceVar x (Variable ty v) e+ | Alt (VariablePattern ty x) e <- alts ]++ -- create a binding for @v = e@ if needed+ bindDefVar v e w e' ps+ | v `elem` fv e' = mkBinding v e $ mkCase (Variable (typeOf e) v) w e' ps+ | otherwise = mkCase e w e' ps++ -- create a binding for @w = e'@ if needed, and a case expression+ -- @case e of { consAlts ++ (ps -> w) }@+ mkCase e w e' ps = case ps of+ [p] -> Case ea e (consAlts ++ [Alt p e'])+ _ -> mkBinding w e'+ $ Case ea e (consAlts ++ [Alt p (Variable (typeOf e') w) | p <- ps])++-- If the alternatives' branches contain literal patterns, a complementary+-- constructor list cannot be generated because it would become potentially+-- infinite. Thus, function 'completeLitAlts' transforms case expressions like+-- case <ce> of+-- <lit_1> -> <expr_1>+-- <lit_2> -> <expr_2>+-- :+-- <lit_n> -> <expr_n>+-- [<var> -> <default_expr>]+-- to+-- let x = <ce> in+-- case (v == <lit_1>) of+-- True -> <expr_1>+-- False -> case (x == <lit_2>) of+-- True -> <expr_2>+-- False -> case ...+-- :+-- -> case (x == <lit_n>) of+-- True -> <expr_n>+-- False -> <default_expr>+-- If the default expression is missing, @failed@ is used instead.+completeLitAlts :: Eval -> Expression -> [Alt] -> CCM Expression+completeLitAlts ea ce alts = do+ x <- freshIdent+ return $ mkBinding x ce $ nestedCases x alts+ where+ nestedCases _ [] = failedExpr (typeOf $ head alts)+ nestedCases x (Alt p ae : as) = case p of+ LiteralPattern ty l -> Case ea (Variable ty x `eqExpr` Literal ty l)+ [ Alt truePatt ae+ , Alt falsePatt (nestedCases x as)+ ]+ VariablePattern ty v -> replaceVar v (Variable ty x) ae+ _ -> internalError "CaseCompletion.completeLitAlts: illegal alternative"++-- For the unusual case of only one alternative containing a variable pattern,+-- it is necessary to tranform it to a 'let' term because FlatCurry does not+-- support variable patterns in case alternatives. So the case expression+-- case <ce> of+-- x -> <ae>+-- is transformed to+-- let x = <ce> in <ae>+completeVarAlts :: Expression -> [Alt] -> CCM Expression+completeVarAlts _ [] = internalError $+ "CaseCompletion.completeVarAlts: empty alternative list"+completeVarAlts ce (Alt p ae : _) = case p of+ VariablePattern _ x -> return $ mkBinding x ce ae+ _ -> internalError $+ "CaseCompletion.completeVarAlts: variable pattern expected"++-- Smart constructor for non-recursive let-binding. @mkBinding v e e'@+-- evaluates to @e'[v/e]@ if @e@ is a variable, or @let v = e in e'@ otherwise.+mkBinding :: Ident -> Expression -> Expression -> Expression+mkBinding v e e' = case e of+ Variable _ _ -> replaceVar v e e'+ _ -> Let (Binding v e) e'++-- ---------------------------------------------------------------------------+-- This part of the module contains functions for replacing variables+-- with expressions. This is necessary in the case of having a default+-- alternative like+-- v -> <expr>+-- where the variable v occurs in the default expression <expr>. When+-- building additional alternatives for this default expression, the variable+-- must be replaced with the newly generated constructors.+replaceVar :: Ident -> Expression -> Expression -> Expression+replaceVar v e x@(Variable _ w)+ | v == w = e+ | otherwise = x+replaceVar v e (Apply e1 e2)+ = Apply (replaceVar v e e1) (replaceVar v e e2)+replaceVar v e (Case ev e' bs)+ = Case ev (replaceVar v e e') (map (replaceVarInAlt v e) bs)+replaceVar v e (Or e1 e2)+ = Or (replaceVar v e e1) (replaceVar v e e2)+replaceVar v e (Exist w ty e')+ | v == w = Exist w ty e'+ | otherwise = Exist w ty (replaceVar v e e')+replaceVar v e (Let b e')+ | v `occursInBinding` b = Let b e'+ | otherwise = Let (replaceVarInBinding v e b)+ (replaceVar v e e')+replaceVar v e (Letrec bs e')+ | any (occursInBinding v) bs = Letrec bs e'+ | otherwise = Letrec (map (replaceVarInBinding v e) bs)+ (replaceVar v e e')+replaceVar _ _ e' = e'++replaceVarInAlt :: Ident -> Expression -> Alt -> Alt+replaceVarInAlt v e (Alt p e')+ | v `occursInPattern` p = Alt p e'+ | otherwise = Alt p (replaceVar v e e')++replaceVarInBinding :: Ident -> Expression -> Binding -> Binding+replaceVarInBinding v e (Binding w e')+ | v == w = Binding w e'+ | otherwise = Binding w (replaceVar v e e')++occursInPattern :: Ident -> ConstrTerm -> Bool+occursInPattern v (VariablePattern _ w) = v == w+occursInPattern v (ConstructorPattern _ _ vs) = v `elem` map snd vs+occursInPattern _ _ = False++occursInBinding :: Ident -> Binding -> Bool+occursInBinding v (Binding w _) = v == w++-- ---------------------------------------------------------------------------+-- The following functions generate several IL expressions and patterns++failedExpr :: Type -> Expression+failedExpr ty = Function ty (qualifyWith preludeMIdent (mkIdent "failed")) 0++--TODO: Add note about arity of 0 because of the predefined functions in the Prelude+eqExpr :: Expression -> Expression -> Expression+eqExpr e1 e2 = Apply (Apply (Function eqTy eq 0) e1) e2+ where eq = qImplMethodId preludeMIdent qDataId ty $ mkIdent "==="+ ty = case e2 of+ Literal _ l -> case l of+ Char _ -> charType+ Int _ -> intType+ Float _ -> floatType+ _ -> internalError "CaseCompletion.eqExpr: no literal"+ ty' = case e2 of+ Literal _ l -> case l of+ Char _ -> charType'+ Int _ -> intType'+ Float _ -> floatType'+ _ -> internalError "CaseCompletion.eqExpr: no literal"+ eqTy = TypeArrow ty' (TypeArrow ty' boolType')++truePatt :: ConstrTerm+truePatt = ConstructorPattern boolType' qTrueId []++falsePatt :: ConstrTerm+falsePatt = ConstructorPattern boolType' qFalseId []++boolType' :: Type+boolType' = IL.TypeConstructor qBoolId []++charType' :: Type+charType' = IL.TypeConstructor qCharId []++intType' :: Type+intType' = IL.TypeConstructor qIntId []++floatType' :: Type+floatType' = IL.TypeConstructor qFloatId []++-- ---------------------------------------------------------------------------+-- The following functions compute the missing constructors for generating+-- missing case alternatives++-- Computes the complementary constructors for a given list of constructors.+-- All specified constructors must be of the same type.+-- This functions uses the module environment 'menv', which contains all+-- imported constructors, except for the built-in list constructors.+-- TODO: Check if the list constructors are in the menv.+getComplConstrs :: Module -> InterfaceEnv -> TCEnv+ -> [QualIdent] -> [(QualIdent, [Type])]+getComplConstrs _ _ _ []+ = internalError "CaseCompletion.getComplConstrs: empty constructor list"+getComplConstrs (Module mid _ ds) menv tcEnv cs@(c:_)+ -- built-in lists+ | c `elem` [qNilId, qConsId] = complementary cs+ [ (qNilId, [])+ , (qConsId, [TypeVariable 0, transType tcEnv (listType boolType)])+ ]+ -- current module+ | mid' == mid = getCCFromDecls cs ds+ -- imported module+ | otherwise = maybe [] (getCCFromIDecls mid' cs tcEnv)+ (lookupInterface mid' menv)+ where mid' = fromMaybe mid (qidModule c)++-- Find complementary constructors within the declarations of the+-- current module+getCCFromDecls :: [QualIdent] -> [Decl] -> [(QualIdent, [Type])]+getCCFromDecls cs ds = complementary cs cinfos+ where+ cinfos = map constrInfo+ $ maybe [] extractConstrDecls (find (`declares` head cs) ds)++ decl `declares` qid = case decl of+ DataDecl _ _ cs' -> any (`declaresConstr` qid) cs'+ _ -> False++ declaresConstr (ConstrDecl cid _) qid = cid == qid++ extractConstrDecls (DataDecl _ _ cs') = cs'+ extractConstrDecls _ = []++ constrInfo (ConstrDecl cid tys) = (cid, tys)++-- Find complementary constructors within the module environment+getCCFromIDecls :: ModuleIdent -> [QualIdent] -> TCEnv-> CS.Interface+ -> [(QualIdent, [Type])]+getCCFromIDecls mid cs tcEnv (CS.Interface _ _ ds) = complementary cs cinfos+ where+ cinfos = map (uncurry constrInfo)+ $ maybe [] extractConstrDecls (find (`declares` head cs) ds)++ decl `declares` qid = case decl of+ CS.IDataDecl _ _ _ _ cs' _ -> any (`declaresConstr` qid) cs'+ CS.INewtypeDecl _ _ _ _ nc _ -> isNewConstrDecl qid nc+ _ -> False++ declaresConstr (CS.ConstrDecl _ cid _) qid = unqualify qid == cid+ declaresConstr (CS.ConOpDecl _ _ oid _) qid = unqualify qid == oid+ declaresConstr (CS.RecordDecl _ cid _) qid = unqualify qid == cid++ isNewConstrDecl qid (CS.NewConstrDecl _ cid _) = unqualify qid == cid+ isNewConstrDecl qid (CS.NewRecordDecl _ cid _) = unqualify qid == cid++ extractConstrDecls (CS.IDataDecl _ _ _ vs cs' _) = zip (repeat vs) cs'+ extractConstrDecls _ = []++ constrInfo vs (CS.ConstrDecl _ cid tys) =+ (qualifyWith mid cid, map (transType' vs) tys)+ constrInfo vs (CS.ConOpDecl _ ty1 oid ty2) =+ (qualifyWith mid oid, map (transType' vs) [ty1, ty2])+ constrInfo vs (CS.RecordDecl _ cid fs) =+ ( qualifyWith mid cid+ , [transType' vs ty | CS.FieldDecl _ ls ty <- fs, _ <- ls]+ )++ transType' vs = transType tcEnv . toType vs++-- Compute complementary constructors+complementary :: [QualIdent] -> [(QualIdent, [Type])] -> [(QualIdent, [Type])]+complementary known others = filter ((`notElem` known) . fst) others++-- ---------------------------------------------------------------------------+-- The following section contains defintions to compute a type substitution+-- for generating the type annotations for missing case alternatives++type TypeSubst = Subst Int Type++class SubstType a where+ subst :: TypeSubst -> a -> a++instance SubstType a => SubstType [a] where+ subst sigma = map (subst sigma)++instance SubstType Type where+ subst sigma (TypeConstructor q tys) = TypeConstructor q $ subst sigma tys+ subst sigma (TypeVariable tv) = substVar' TypeVariable subst sigma tv+ subst sigma (TypeArrow ty1 ty2)+ = TypeArrow (subst sigma ty1) (subst sigma ty2)+ subst sigma (TypeForall tvs ty)+ = TypeForall tvs (subst (foldr (unbindSubst . fst) sigma tvs) ty)++matchType :: Type -> Type -> TypeSubst -> TypeSubst+matchType ty1 ty2 = fromMaybe noMatch (matchType' ty1 ty2)+ where+ noMatch = internalError $ "Transformations.CaseCompletion.matchType: " +++ showsPrec 11 ty1 " " ++ showsPrec 11 ty2 ""++matchType' :: Type -> Type -> Maybe (TypeSubst -> TypeSubst)+matchType' (TypeVariable tv) ty+ | ty == TypeVariable tv = Just id+ | otherwise = Just (bindSubst tv ty)+matchType' (TypeConstructor tc1 tys1) (TypeConstructor tc2 tys2)+ | tc1 == tc2 = Just $ foldr (\(ty1, ty2) -> (matchType ty1 ty2 .)) id $ tys+ where tys = zip tys1 tys2+matchType' (TypeArrow ty11 ty12) (TypeArrow ty21 ty22) =+ Just (matchType ty11 ty21 . matchType ty12 ty22)+matchType' _ _ = Nothing
+ src/Transformations/CurryToIL.hs view
@@ -0,0 +1,704 @@+{- |+ Module : $Header$+ Description : Translation of Curry into IL+ Copyright : (c) 1999 - 2003 Wolfgang Lux+ Martin Engelke+ 2011 - 2015 Björn Peemöller+ 2015 Jan Tikovsky+ 2016 - 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ After desugaring and lifting have been performed, the source code is+ translated into the intermediate language. Besides translating from+ source terms and expressions into intermediate language terms and+ expressions, this phase in particular has to implement the pattern+ matching algorithm for equations and case expressions.++ Because of name conflicts between the source and intermediate language+ data structures, we can use only a qualified import for the 'IL' module.+-}+{-# LANGUAGE CPP #-}+module Transformations.CurryToIL (ilTrans, transType) where++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative ((<$>), (<*>))+#endif++import Control.Monad.Extra (concatMapM)+import qualified Control.Monad.Reader as R+import qualified Control.Monad.State as S+import Data.List (nub, partition)+import Data.Maybe (fromJust)+import qualified Data.Map as Map+import qualified Data.Set as Set (Set, empty, insert, delete, toList)++import Curry.Base.Ident+import Curry.Syntax hiding (caseAlt)++import Base.Expr+import Base.Messages (internalError)+import Base.Types hiding (polyType)+import Base.Kinds+import Base.Typing+import Base.Utils (foldr2)++import Env.TypeConstructor+import Env.Value (ValueEnv, ValueInfo (..), qualLookupValue)++import qualified IL as IL++ilTrans :: Bool -> ValueEnv -> TCEnv -> Module Type -> IL.Module+ilTrans remIm vEnv tcEnv (Module _ _ _ m _ im ds) = IL.Module m im' ds'+ where ds' = R.runReader (concatMapM trDecl ds) (TransEnv m vEnv tcEnv)+ im' = preludeMIdent : if remIm then imports m ds' else map moduleImport im+ moduleImport (ImportDecl _ mdl _ _ _) = mdl+++-- -----------------------------------------------------------------------------+-- Computation of necessary imports+-- -----------------------------------------------------------------------------++-- The list of import declarations in the intermediate language code is+-- determined by collecting all module qualifiers used in the current module.++imports :: ModuleIdent -> [IL.Decl] -> [ModuleIdent]+imports m = Set.toList . Set.delete m . foldr mdlsDecl Set.empty++mdlsDecl :: IL.Decl -> Set.Set ModuleIdent -> Set.Set ModuleIdent+mdlsDecl (IL.DataDecl _ _ cs) ms = foldr mdlsConstrsDecl ms cs+ where mdlsConstrsDecl (IL.ConstrDecl _ tys) ms' = foldr mdlsType ms' tys+mdlsDecl (IL.NewtypeDecl _ _ nc) ms = mdlsNewConstrDecl nc+ where mdlsNewConstrDecl (IL.NewConstrDecl _ ty) = mdlsType ty ms+mdlsDecl (IL.ExternalDataDecl _ _) ms = ms+mdlsDecl (IL.FunctionDecl _ _ ty e) ms = mdlsType ty (mdlsExpr e ms)+mdlsDecl (IL.ExternalDecl _ _ ty) ms = mdlsType ty ms++mdlsType :: IL.Type -> Set.Set ModuleIdent -> Set.Set ModuleIdent+mdlsType (IL.TypeConstructor tc tys) ms = modules tc (foldr mdlsType ms tys)+mdlsType (IL.TypeVariable _) ms = ms+mdlsType (IL.TypeArrow ty1 ty2) ms = mdlsType ty1 (mdlsType ty2 ms)+mdlsType (IL.TypeForall _ ty) ms = mdlsType ty ms++mdlsExpr :: IL.Expression -> Set.Set ModuleIdent -> Set.Set ModuleIdent+mdlsExpr (IL.Function _ f _) ms = modules f ms+mdlsExpr (IL.Constructor _ c _) ms = modules c ms+mdlsExpr (IL.Apply e1 e2) ms = mdlsExpr e1 (mdlsExpr e2 ms)+mdlsExpr (IL.Case _ e as) ms = mdlsExpr e (foldr mdlsAlt ms as)+ where+ mdlsAlt (IL.Alt t e') = mdlsPattern t . mdlsExpr e'+ mdlsPattern (IL.ConstructorPattern _ c _) = modules c+ mdlsPattern _ = id+mdlsExpr (IL.Or e1 e2) ms = mdlsExpr e1 (mdlsExpr e2 ms)+mdlsExpr (IL.Exist _ _ e) ms = mdlsExpr e ms+mdlsExpr (IL.Let b e) ms = mdlsBinding b (mdlsExpr e ms)+mdlsExpr (IL.Letrec bs e) ms = foldr mdlsBinding (mdlsExpr e ms) bs+mdlsExpr _ ms = ms++mdlsBinding :: IL.Binding -> Set.Set ModuleIdent -> Set.Set ModuleIdent+mdlsBinding (IL.Binding _ e) = mdlsExpr e++modules :: QualIdent -> Set.Set ModuleIdent -> Set.Set ModuleIdent+modules x ms = maybe ms (`Set.insert` ms) (qidModule x)++-- -----------------------------------------------------------------------------+-- Internal reader monad+-- -----------------------------------------------------------------------------++data TransEnv = TransEnv+ { moduleIdent :: ModuleIdent+ , valueEnv :: ValueEnv+ , tyconEnv :: TCEnv+ }++type TransM a = R.Reader TransEnv a++getValueEnv :: TransM ValueEnv+getValueEnv = R.asks valueEnv++getTCEnv :: TransM TCEnv+getTCEnv = R.asks tyconEnv++trQualify :: Ident -> TransM QualIdent+trQualify i = flip qualifyWith i <$> R.asks moduleIdent++getArity :: QualIdent -> TransM Int+getArity qid = do+ vEnv <- getValueEnv+ return $ case qualLookupValue qid vEnv of+ [DataConstructor _ a _ _] -> a+ [NewtypeConstructor _ _ _] -> 1+ [Value _ _ a _] -> a+ [Label _ _ _] -> 1+ _ ->+ internalError $ "CurryToIL.getArity: " ++ show qid++-- Return the type of a constructor+constrType :: QualIdent -> TransM Type+constrType c = do+ vEnv <- getValueEnv+ case qualLookupValue c vEnv of+ [DataConstructor _ _ _ (ForAll _ (PredType _ ty))] -> return ty+ [NewtypeConstructor _ _ (ForAll _ (PredType _ ty))] -> return ty+ _ -> internalError $ "CurryToIL.constrType: " ++ show c++-- Return the kinds of a type constructor's type variables+tcTVarKinds :: QualIdent -> TransM [Kind]+tcTVarKinds qid = do+ tcEnv <- getTCEnv+ let mid = fromJust $ qidModule qid+ kind = tcKind mid qid tcEnv+ return $ kindArgs kind++-- -----------------------------------------------------------------------------+-- Translation+-- -----------------------------------------------------------------------------++-- At the top-level, the compiler has to translate data type, newtype,+-- function, and external declarations. When translating a data type or+-- newtype declaration, we ignore the types in the declaration and lookup+-- the types of the constructors in the type environment instead because+-- these types are already fully expanded, i.e., they do not include any+-- alias types.++trDecl :: Decl Type -> TransM [IL.Decl]+trDecl (DataDecl _ tc tvs cs _) = (:[]) <$> trData tc tvs cs+trDecl (NewtypeDecl _ tc tvs nc _) = (:[]) <$> trNewtype tc tvs nc+trDecl (ExternalDataDecl _ tc tvs) = (:[]) <$> trExternalData tc tvs+trDecl (FunctionDecl _ _ f eqs) = (:[]) <$> trFunction f eqs+trDecl (ExternalDecl _ vs) = mapM trExternal vs+trDecl _ = return []++trData :: Ident -> [Ident] -> [ConstrDecl] -> TransM IL.Decl+trData tc tvs cs = do+ tc' <- trQualify tc+ ks <- tcTVarKinds tc'+ IL.DataDecl tc' (transKind <$> ks) <$> mapM trConstrDecl cs++trNewtype :: Ident -> [Ident] -> NewConstrDecl -> TransM IL.Decl+trNewtype tc tvs nc = do+ tc' <- trQualify tc+ ks <- tcTVarKinds tc'+ IL.NewtypeDecl tc' (transKind <$> ks) <$> trNewConstrDecl nc++trConstrDecl :: ConstrDecl -> TransM IL.ConstrDecl+trConstrDecl d = do+ c' <- trQualify (constr d)+ ty' <- arrowArgs <$> constrType c'+ tcEnv <- getTCEnv+ return $ IL.ConstrDecl c' (map (transType tcEnv) ty')+ where+ constr (ConstrDecl _ c _) = c+ constr (ConOpDecl _ _ op _) = op+ constr (RecordDecl _ c _) = c++trNewConstrDecl :: NewConstrDecl -> TransM IL.NewConstrDecl+trNewConstrDecl d = do+ c' <- trQualify (constr d)+ ty' <- arrowArgs <$> constrType c'+ tcEnv <- getTCEnv+ case ty' of+ [ty] -> return $ IL.NewConstrDecl c' (transType tcEnv ty)+ _ -> internalError "CurryToIL.trNewConstrDecl: invalid constructor type"+ where+ constr (NewConstrDecl _ c _) = c+ constr (NewRecordDecl _ c _) = c++trExternalData :: Ident -> [Ident] -> TransM IL.Decl+trExternalData tc tvs = do+ tc' <- trQualify tc+ ks <- tcTVarKinds tc'+ return $ IL.ExternalDataDecl tc' (transKind <$> ks)++trExternal :: Var Type -> TransM IL.Decl+trExternal (Var ty f) = do+ tcEnv <- getTCEnv+ f' <- trQualify f+ a <- getArity f'+ return $ IL.ExternalDecl f' a (transType tcEnv $ polyType ty)++-- The type representation in the intermediate language does not support+-- types with higher order kinds. Therefore, the type transformations has+-- to transform all types to first order terms. To that end, we assume the+-- existence of a type synonym 'type Apply f a = f a'. In addition, the type+-- representation of the intermediate language does not support constrained+-- type variables and skolem types. The former are fixed and the later are+-- replaced by fresh type constructors.++transType :: TCEnv -> Type -> IL.Type+transType tcEnv ty' = transType' ty' []+ where+ ks = transTVars tcEnv ty'+ transType' (TypeConstructor tc) = IL.TypeConstructor tc+ transType' (TypeApply ty1 ty2) = transType' ty1 . (transType' ty2 [] :)+ transType' (TypeVariable tv) = foldl applyType' (IL.TypeVariable tv)+ transType' (TypeConstrained tys _) = transType' (head tys)+ transType' (TypeArrow ty1 ty2) =+ foldl applyType' (IL.TypeArrow (transType' ty1 []) (transType' ty2 []))+ transType' (TypeForall tvs ty) =+ foldl applyType' (IL.TypeForall tvs' (transType' ty []))+ where tvs' = filter ((`elem` tvs) . fst) ks++applyType' :: IL.Type -> IL.Type -> IL.Type+applyType' ty1 ty2 =+ IL.TypeConstructor (qualifyWith preludeMIdent (mkIdent "Apply")) [ty1, ty2]++-- We need to existentially quantify all variables in some types+polyType :: Type -> Type+polyType (TypeForall _ ty) = polyType ty+polyType ty =+ let vs = nub $ typeVars ty+ in if null vs then ty else TypeForall vs ty++-- We need to infer kinds for the quantified variables.+-- We already checked the correctness of all Kinds earlier,+-- thus we know that we will be able to unify all the inferred equations.+-- We can also keep a flat environment,+-- as all variables have already been renamed.++data KIS = KIS+ { _nextId :: Int+ , kinds :: Map.Map Int IL.Kind+ }++freshId :: S.State KIS Int+freshId = do+ KIS i ks <- S.get+ S.put (KIS (i+1) ks)+ return i++transTVars :: TCEnv -> Type -> [(Int, IL.Kind)]+transTVars tcEnv ty' =+ Map.toList $ kinds $ S.execState (build ty' IL.KindStar) (KIS 0 Map.empty)+ where+ build :: Type -> IL.Kind -> S.State KIS ()+ build (TypeArrow ty1 ty2) _ =+ build ty1 IL.KindStar >> build ty2 IL.KindStar+ build (TypeConstrained tys _) k =+ build (head tys) k+ build (TypeForall _ ty) k =+ build ty k+ build (TypeVariable tv) k = do+ KIS i ks <- S.get+ -- get current kind+ let k' = Map.findWithDefault k tv ks+ -- unify it+ let s = unifyKind k k'+ -- apply substitution+ let ks' = fmap (applyKindSubst s) $ Map.insert tv k' ks+ S.put (KIS i ks')+ build (TypeConstructor _) _ = return ()+ build ta@(TypeApply _ _) k =+ let (ty, tys) = unapplyType True ta+ in case ty of+ TypeConstructor tc -> do+ let k' = tcKind (fromJust $ qidModule tc) tc tcEnv+ mapM_ (uncurry build) (zip tys $ unarrowKind $ transKind k')+ _ -> do -- var of forall+ -- construct new kind vars+ ks <- mapM (const (freshId >>= return . IL.KindVariable)) tys+ -- infer kind for v+ build ty (foldr IL.KindArrow k ks)+ -- infer kinds for args+ mapM_ (uncurry build) (zip tys ks)++type KindSubst = Map.Map Int IL.Kind++transKind :: Kind -> IL.Kind+transKind KindStar = IL.KindStar+transKind (KindVariable _) = IL.KindStar+transKind (KindArrow k1 k2) = IL.KindArrow (transKind k1) (transKind k2)++unarrowKind :: IL.Kind -> [IL.Kind]+unarrowKind (IL.KindArrow k1 k2) = k1 : unarrowKind k2+unarrowKind k = [k]++applyKindSubst :: KindSubst -> IL.Kind -> IL.Kind+applyKindSubst _ IL.KindStar =+ IL.KindStar+applyKindSubst s (IL.KindArrow k1 k2) =+ IL.KindArrow (applyKindSubst s k1) (applyKindSubst s k2)+applyKindSubst s v@(IL.KindVariable i) =+ Map.findWithDefault v i s++composeKindSubst :: KindSubst -> KindSubst -> KindSubst+composeKindSubst s1 s2 = Map.map (applyKindSubst s1) s2 `Map.union` s1++unifyKind :: IL.Kind -> IL.Kind -> KindSubst+unifyKind IL.KindStar IL.KindStar = Map.empty+unifyKind (IL.KindVariable i) k = Map.singleton i k+unifyKind k (IL.KindVariable i) = Map.singleton i k+unifyKind (IL.KindArrow k1 k2) (IL.KindArrow k1' k2') =+ let s1 = unifyKind k1 k1'+ s2 = unifyKind (applyKindSubst s1 k2) (applyKindSubst s1 k2')+ in s1 `composeKindSubst` s2+unifyKind k1 k2 = error $ "Transformation.CurryToIL.unifyKind: " ++ show k1 ++ ", " ++ show k2++-- Each function in the program is translated into a function of the+-- intermediate language. The arguments of the function are renamed such+-- that all variables occurring in the same position (in different+-- equations) have the same name. This is necessary in order to+-- facilitate the translation of pattern matching into a 'case' expression.+-- We use the following simple convention here: The top-level+-- arguments of the function are named from left to right '_1', '_2',+-- and so on. The names of nested arguments are constructed by appending+-- '_1', '_2', etc. from left to right to the name that were assigned+-- to a variable occurring at the position of the constructor term.++-- Some special care is needed for the selector functions introduced by+-- the compiler in place of pattern bindings. In order to generate the+-- code for updating all pattern variables, the equality of names between+-- the pattern variables in the first argument of the selector function+-- and their repeated occurrences in the remaining arguments must be+-- preserved. This means that the second and following arguments of a+-- selector function have to be renamed according to the name mapping+-- computed for its first argument.++trFunction :: Ident -> [Equation Type] -> TransM IL.Decl+trFunction f eqs = do+ f' <- trQualify f+ tcEnv <- getTCEnv+ let tys = map typeOf ts+ ty' = transType tcEnv $ polyType $ foldr TypeArrow (typeOf rhs) tys+ vs' = zip (map (transType tcEnv) tys) vs+ alts <- mapM (trEquation vs ws) eqs+ return $ IL.FunctionDecl f' vs' ty' (flexMatch vs' alts)+ where+ -- vs are the variables needed for the function: _1, _2, etc.+ -- ws is an infinite list for introducing additional variables later+ Equation _ lhs rhs = head eqs+ (_, ts) = flatLhs lhs+ (vs, ws) = splitAt (length ts) (argNames (mkIdent ""))++trEquation :: [Ident] -- identifiers for the function's parameters+ -> [Ident] -- infinite list of additional identifiers+ -> Equation Type -- equation to be translated+ -> TransM Match -- nested constructor terms + translated RHS+trEquation vs vs' (Equation _ (FunLhs _ _ ts) rhs) = do+ -- construct renaming of variables inside constructor terms+ let patternRenaming = foldr2 bindRenameEnv Map.empty vs ts+ -- translate right-hand-side+ rhs' <- trRhs vs' patternRenaming rhs+ -- convert patterns+ tcEnv <- getTCEnv+ return (zipWith (trPattern tcEnv) vs ts, rhs')+trEquation _ _ _+ = internalError "Translation of non-FunLhs euqation not defined"++type RenameEnv = Map.Map Ident Ident++-- Construct a renaming of all variables inside the pattern to fresh identifiers+bindRenameEnv :: Ident -> Pattern a -> RenameEnv -> RenameEnv+bindRenameEnv _ (LiteralPattern _ _ _) env = env+bindRenameEnv v (VariablePattern _ _ v') env = Map.insert v' v env+bindRenameEnv v (ConstructorPattern _ _ _ ts) env+ = foldr2 bindRenameEnv env (argNames v) ts+bindRenameEnv v (AsPattern _ v' t) env+ = Map.insert v' v (bindRenameEnv v t env)+bindRenameEnv _ _ _+ = internalError "CurryToIL.bindRenameEnv"++trRhs :: [Ident] -> RenameEnv -> Rhs Type -> TransM IL.Expression+trRhs vs env (SimpleRhs _ _ e _) = trExpr vs env e+trRhs _ _ (GuardedRhs _ _ _ _) = internalError "CurryToIL.trRhs: GuardedRhs"++-- Note that the case matching algorithm assumes that the matched+-- expression is accessible through a variable. The translation of case+-- expressions therefore introduces a let binding for the scrutinized+-- expression and immediately throws it away after the matching -- except+-- if the matching algorithm has decided to use that variable in the+-- right hand sides of the case expression. This may happen, for+-- instance, if one of the alternatives contains an as-pattern.++trExpr :: [Ident] -> RenameEnv -> Expression Type -> TransM IL.Expression+trExpr _ _ (Literal _ ty l) = do+ tcEnv <- getTCEnv+ return $ IL.Literal (transType tcEnv ty) (trLiteral l)+trExpr _ env (Variable _ ty v)+ | isQualified v = getTCEnv >>= fun+ | otherwise = do+ tcEnv <- getTCEnv+ case Map.lookup (unqualify v) env of+ Nothing -> error $ "unexpected variable" ++ show v --TODO: Replace case by fromJust?+ Just v' -> return $ IL.Variable (transType tcEnv ty) v' -- apply renaming+ where+ fun tcEnv = IL.Function (transType tcEnv ty) v <$> getArity v+trExpr _ _ (Constructor _ ty c) = do+ tcEnv <- getTCEnv+ IL.Constructor (transType tcEnv ty) c <$> getArity c+trExpr vs env (Apply _ e1 e2)+ = IL.Apply <$> trExpr vs env e1 <*> trExpr vs env e2+trExpr vs env (Let _ _ ds e) = do+ e' <- trExpr vs env' e+ case ds of+ [FreeDecl _ vs']+ -> do tcEnv <- getTCEnv+ return $+ foldr (\ (Var ty v) -> IL.Exist v (transType tcEnv ty)) e' vs'+ [d] | all (`notElem` bv d) (qfv emptyMIdent d)+ -> flip IL.Let e' <$> trBinding d+ _ -> flip IL.Letrec e' <$> mapM trBinding ds+ where+ env' = foldr2 Map.insert env bvs bvs+ bvs = bv ds+ trBinding (PatternDecl _ (VariablePattern _ _ v) rhs)+ = IL.Binding v <$> trRhs vs env' rhs+ trBinding p = error $ "unexpected binding: " ++ show p+trExpr (v:vs) env (Case _ _ ct e alts) = do+ -- the ident v is used for the case expression subject, as this could+ -- be referenced in the case alternatives by a variable pattern+ e' <- trExpr vs env e+ tcEnv <- getTCEnv+ let matcher = if ct == Flex then flexMatch else rigidMatch+ ty' = transType tcEnv $ typeOf e+ expr <- matcher [(ty', v)] <$> mapM (trAlt (v:vs) env) alts+ return $ case expr of+ IL.Case mode (IL.Variable _ v') alts'+ -- subject is not referenced -> forget v and insert subject+ | v == v' && v `notElem` fv alts' -> IL.Case mode e' alts'+ _+ -- subject is referenced -> introduce binding for v as subject+ | v `elem` fv expr -> IL.Let (IL.Binding v e') expr+ | otherwise -> expr+trExpr vs env (Typed _ e _) = do+ tcEnv <- getTCEnv+ e' <- trExpr vs env e+ return $ IL.Typed e' (transType tcEnv $ typeOf e)+trExpr _ _ _ = internalError "CurryToIL.trExpr"++trAlt :: [Ident] -> RenameEnv -> Alt Type -> TransM Match+trAlt ~(v:vs) env (Alt _ t rhs) = do+ tcEnv <- getTCEnv+ rhs' <- trRhs vs (bindRenameEnv v t env) rhs+ return ([trPattern tcEnv v t], rhs')++trLiteral :: Literal -> IL.Literal+trLiteral (Char c) = IL.Char c+trLiteral (Int i) = IL.Int i+trLiteral (Float f) = IL.Float f+trLiteral _ = internalError "CurryToIL.trLiteral"++-- -----------------------------------------------------------------------------+-- Translation of Patterns+-- -----------------------------------------------------------------------------++data NestedTerm = NestedTerm IL.ConstrTerm [NestedTerm] deriving Show++pattern :: NestedTerm -> IL.ConstrTerm+pattern (NestedTerm t _) = t++arguments :: NestedTerm -> [NestedTerm]+arguments (NestedTerm _ ts) = ts++trPattern :: TCEnv -> Ident -> Pattern Type -> NestedTerm+trPattern tcEnv _ (LiteralPattern _ ty l)+ = NestedTerm (IL.LiteralPattern (transType tcEnv ty) $ trLiteral l) []+trPattern tcEnv v (VariablePattern _ ty _)+ = NestedTerm (IL.VariablePattern (transType tcEnv ty) v) []+trPattern tcEnv v (ConstructorPattern _ ty c ts)+ = NestedTerm (IL.ConstructorPattern (transType tcEnv ty) c vs')+ (zipWith (trPattern tcEnv) vs ts)+ where vs = argNames v+ vs' = zip (map (transType tcEnv . typeOf) ts) vs+trPattern tcEnv v (AsPattern _ _ t)+ = trPattern tcEnv v t+trPattern _ _ _+ = internalError "CurryToIL.trPattern"++argNames :: Ident -> [Ident]+argNames v = [mkIdent (prefix ++ show i) | i <- [1 :: Integer ..] ]+ where prefix = idName v ++ "_"++-- -----------------------------------------------------------------------------+-- Flexible Pattern Matching Algorithm+-- -----------------------------------------------------------------------------++-- The pattern matching code searches for the left-most inductive+-- argument position in the left hand sides of all rules defining an+-- equation. An inductive position is a position where all rules have a+-- constructor rooted term. If such a position is found, a flexible 'case'+-- expression is generated for the argument at that position. The+-- matching code is then computed recursively for all of the alternatives+-- independently. If no inductive position is found, the algorithm looks+-- for the left-most demanded argument position, i.e., a position where+-- at least one of the rules has a constructor rooted term. If such a+-- position is found, an 'or' expression is generated with those+-- cases that have a variable at the argument position in one branch and+-- all other rules in the other branch. If there is no demanded position,+-- the pattern matching is finished and the compiler translates the right+-- hand sides of the remaining rules, eventually combining them using+-- 'or' expressions.++-- Actually, the algorithm below combines the search for inductive and+-- demanded positions. The function 'flexMatch' scans the argument+-- lists for the left-most demanded position. If this turns out to be+-- also an inductive position, the function 'flexMatchInductive' is+-- called in order to generate a flexible 'case' expression. Otherwise, the+-- function 'optFlexMatch' is called that tries to find an inductive+-- position in the remaining arguments. If one is found,+-- 'flexMatchInductive' is called, otherwise the function+-- 'optFlexMatch' uses the demanded argument position found by 'flexMatch'.++-- a @Match@ is a list of patterns and the respective expression.+type Match = ([NestedTerm], IL.Expression)+-- a @Match'@ is a @Match@ with skipped patterns during the search for an+-- inductive position.+type Match' = (FunList NestedTerm, [NestedTerm], IL.Expression)+-- Functional lists+type FunList a = [a] -> [a]++flexMatch :: [(IL.Type, Ident)] -- variables to be matched+ -> [Match] -- alternatives+ -> IL.Expression -- result expression+flexMatch [] alts = foldl1 IL.Or (map snd alts)+flexMatch (v:vs) alts+ | notDemanded = varExp+ | isInductive = conExp+ | otherwise = optFlexMatch (IL.Or conExp varExp) (v:) vs (map skipPat alts)+ where+ isInductive = null varAlts+ notDemanded = null conAlts+ -- separate variable and constructor patterns+ (varAlts, conAlts) = partition isVarMatch (map tagAlt alts)+ -- match variables+ varExp = flexMatch vs (map snd varAlts)+ -- match constructors+ conExp = flexMatchInductive id v vs (map prep conAlts)+ prep (p, (ts, e)) = (p, (id, ts, e))++-- Search for the next inductive position+optFlexMatch :: IL.Expression -- default expression+ -> FunList (IL.Type, Ident) -- skipped variables+ -> [(IL.Type, Ident)] -- next variables+ -> [Match'] -- alternatives+ -> IL.Expression+optFlexMatch def _ [] _ = def+optFlexMatch def prefix (v:vs) alts+ | isInductive = flexMatchInductive prefix v vs alts'+ | otherwise = optFlexMatch def (prefix . (v:)) vs (map skipPat' alts)+ where+ isInductive = not (any isVarMatch alts')+ alts' = map tagAlt' alts++-- Generate a case expression matching the inductive position+flexMatchInductive :: FunList (IL.Type, Ident) -- skipped variables+ -> (IL.Type, Ident) -- current variable+ -> [(IL.Type, Ident)] -- next variables+ -> [(IL.ConstrTerm, Match')] -- alternatives+ -> IL.Expression+flexMatchInductive prefix v vs as+ = IL.Case IL.Flex (uncurry IL.Variable v) (flexMatchAlts as)+ where+ -- create alternatives for the different constructors+ flexMatchAlts [] = []+ flexMatchAlts ((t, e) : alts) = IL.Alt t expr : flexMatchAlts others+ where+ -- match nested patterns for same constructors+ expr = flexMatch (prefix (vars t ++ vs)) (map expandVars (e : map snd same))+ expandVars (pref, ts1, e') = (pref ts1, e')+ -- split into same and other constructors+ (same, others) = partition ((t ==) . fst) alts++-- -----------------------------------------------------------------------------+-- Rigid Pattern Matching Algorithm+-- -----------------------------------------------------------------------------++-- Matching in a 'case'-expression works a little bit differently.+-- In this case, the alternatives are matched from the first to the last+-- alternative and the first matching alternative is chosen. All+-- remaining alternatives are discarded.++-- TODO: The case matching algorithm should use type information in order+-- to detect total matches and immediately discard all alternatives which+-- cannot be reached.++rigidMatch :: [(IL.Type, Ident)] -> [Match] -> IL.Expression+rigidMatch vs alts = rigidOptMatch (snd $ head alts) id vs (map prepare alts)+ where prepare (ts, e) = (id, ts, e)++rigidOptMatch :: IL.Expression -- default expression+ -> FunList (IL.Type, Ident) -- variables to be matched next+ -> [(IL.Type, Ident)] -- variables to be matched afterwards+ -> [Match'] -- translated equations+ -> IL.Expression+-- if there are no variables left: return the default expression+rigidOptMatch def _ [] _ = def+rigidOptMatch def prefix (v : vs) alts+ | isDemanded = rigidMatchDemanded prefix v vs alts'+ | otherwise = rigidOptMatch def (prefix . (v:)) vs (map skipPat' alts)+ where+ isDemanded = not $ isVarMatch (head alts')+ alts' = map tagAlt' alts++-- Generate a case expression matching the demanded position.+-- This algorithm constructs a branch for all contained patterns, where+-- the right-hand side then respects the order of the patterns.+-- Thus, the expression+-- case x of+-- [] -> []+-- ys -> ys+-- y:ys -> [y]+-- gets translated to+-- case x of+-- [] -> []+-- y:ys -> x+-- x -> x+rigidMatchDemanded :: FunList (IL.Type, Ident) -- skipped variables+ -> (IL.Type, Ident) -- current variable+ -> [(IL.Type, Ident)] -- next variables+ -> [(IL.ConstrTerm, Match')] -- alternatives+ -> IL.Expression+rigidMatchDemanded prefix v vs alts = IL.Case IL.Rigid (uncurry IL.Variable v)+ $ map caseAlt (consPats ++ varPats)+ where+ -- N.B.: @varPats@ is either empty or a singleton list due to nub+ (varPats, consPats) = partition isVarPattern $ nub $ map fst alts+ caseAlt t = IL.Alt t expr+ where+ expr = rigidMatch (prefix $ vars t ++ vs) (matchingCases alts)+ -- matchingCases selects the matching alternatives+ -- and recursively matches the remaining patterns+ matchingCases a = map (expandVars (vars t)) $ filter (matches . fst) a+ matches t' = t == t' || isVarPattern t'+ expandVars vs' (p, (pref, ts1, e)) = (pref ts2, e)+ where ts2 | isVarPattern p = map var2Pattern vs' ++ ts1+ | otherwise = ts1+ var2Pattern v' = NestedTerm (uncurry IL.VariablePattern v') []++-- -----------------------------------------------------------------------------+-- Pattern Matching Auxiliaries+-- -----------------------------------------------------------------------------++isVarPattern :: IL.ConstrTerm -> Bool+isVarPattern (IL.VariablePattern _ _) = True+isVarPattern _ = False++isVarMatch :: (IL.ConstrTerm, a) -> Bool+isVarMatch = isVarPattern . fst++vars :: IL.ConstrTerm -> [(IL.Type, Ident)]+vars (IL.ConstructorPattern _ _ vs) = vs+vars _ = []++-- tagAlt extracts the structure of the first pattern+tagAlt :: Match -> (IL.ConstrTerm, Match)+tagAlt (t:ts, e) = (pattern t, (arguments t ++ ts, e))+tagAlt ([] , _) = error "CurryToIL.tagAlt: empty pattern list"++-- skipPat skips the current pattern position for later matching+skipPat :: Match -> Match'+skipPat (t:ts, e) = ((t:), ts, e)+skipPat ([] , _) = error "CurryToIL.skipPat: empty pattern list"++-- tagAlt' extracts the next pattern+tagAlt' :: Match' -> (IL.ConstrTerm, Match')+tagAlt' (pref, t:ts, e') = (pattern t, (pref, arguments t ++ ts, e'))+tagAlt' (_ , [] , _ ) = error "CurryToIL.tagAlt': empty pattern list"++-- skipPat' skips the current argument for later matching+skipPat' :: Match' -> Match'+skipPat' (pref, t:ts, e') = (pref . (t:), ts, e')+skipPat' (_ , [] , _ ) = error "CurryToIL.skipPat': empty pattern list"
+ src/Transformations/Derive.hs view
@@ -0,0 +1,729 @@+{- |+ Module : $Header$+ Description : Deriving instances+ Copyright : (c) 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ TODO+-}+{-# LANGUAGE CPP #-}+module Transformations.Derive (derive) where++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative ((<$>))+#endif+import Control.Monad (replicateM)+import qualified Control.Monad.State as S (State, evalState, gets, modify)+import Data.List (intercalate, intersperse)+import Data.Maybe (fromJust, isJust)+import qualified Data.Set as Set (deleteMin, union)++import Curry.Base.Ident+import Curry.Base.SpanInfo+import Curry.Syntax++import Base.CurryTypes (fromPredType)+import Base.Messages (internalError)+import Base.Types+import Base.TypeSubst (instanceType)+import Base.Typing (typeOf)+import Base.Utils (snd3, mapAccumM)++import Env.Instance+import Env.OpPrec+import Env.TypeConstructor+import Env.Value++data DVState = DVState+ { moduleIdent :: ModuleIdent+ , tyConsEnv :: TCEnv+ , valueEnv :: ValueEnv+ , instEnv :: InstEnv+ , opPrecEnv :: OpPrecEnv+ , nextId :: Integer+ }++type DVM = S.State DVState++derive :: TCEnv -> ValueEnv -> InstEnv -> OpPrecEnv -> Module PredType+ -> Module PredType+derive tcEnv vEnv inEnv pEnv (Module spi li ps m es is ds) = Module spi li ps m es is $+ ds ++ concat (S.evalState (deriveAllInstances tds) initState)+ where tds = filter isTypeDecl ds+ initState = DVState m tcEnv vEnv inEnv pEnv 1++getModuleIdent :: DVM ModuleIdent+getModuleIdent = S.gets moduleIdent++getTyConsEnv :: DVM TCEnv+getTyConsEnv = S.gets tyConsEnv++getValueEnv :: DVM ValueEnv+getValueEnv = S.gets valueEnv++getInstEnv :: DVM InstEnv+getInstEnv = S.gets instEnv++getPrecEnv :: DVM OpPrecEnv+getPrecEnv = S.gets opPrecEnv++getNextId :: DVM Integer+getNextId = do+ nid <- S.gets nextId+ S.modify $ \s -> s { nextId = succ nid }+ return nid++-- TODO: Comment (here and below)++type ConstrInfo = (Int, QualIdent, Maybe [Ident], [Type])++deriveAllInstances :: [Decl PredType] -> DVM [[Decl PredType]]+deriveAllInstances ds = do+ derived <- mapM deriveInstances ds+ inst <- getInstEnv+ mid <- getModuleIdent+ let dds = filter (hasDataInstance inst mid) ds+ datains <- mapM deriveDataInstance dds+ return (datains:derived)++-- If we ever entered a data instance for this datatype into the instance+-- environment, we can safely derive a data instance+hasDataInstance :: InstEnv -> ModuleIdent -> Decl PredType -> Bool+hasDataInstance inst mid (DataDecl _ tc _ _ _) =+ maybe False (\(mid', _, _) -> mid == mid') $+ lookupInstInfo (qDataId, qualifyWith mid tc) inst+hasDataInstance inst mid (NewtypeDecl _ tc _ _ _) =+ maybe False (\(mid', _, _) -> mid == mid') $+ lookupInstInfo (qDataId, qualifyWith mid tc) inst+hasDataInstance _ _ _ =+ False++deriveDataInstance :: Decl PredType -> DVM (Decl PredType)+deriveDataInstance (DataDecl p tc tvs _ _) =+ head <$> deriveInstances (DataDecl p tc tvs [] [qDataId])+deriveDataInstance (NewtypeDecl p tc tvs _ _) =+ deriveDataInstance $ DataDecl p tc tvs [] []+deriveDataInstance _ =+ internalError "Derive.deriveDataInstance: No DataDel"++-- An instance declaration is created for each type class of a deriving clause.+-- Newtype declaration are simply treated as data declarations.++deriveInstances :: Decl PredType -> DVM [Decl PredType]+deriveInstances (DataDecl _ tc tvs _ clss) = do+ m <- getModuleIdent+ tcEnv <- getTyConsEnv+ let otc = qualifyWith m tc+ cis = constructors m otc tcEnv+ mapM (deriveInstance otc tvs cis) clss+deriveInstances (NewtypeDecl p tc tvs _ clss) =+ deriveInstances $ DataDecl p tc tvs [] clss+deriveInstances _ = return []++deriveInstance :: QualIdent -> [Ident] -> [ConstrInfo] -> QualIdent+ -> DVM (Decl PredType)+deriveInstance tc tvs cis cls = do+ inEnv <- getInstEnv+ let ps = snd3 $ fromJust $ lookupInstInfo (cls, tc) inEnv+ ty = applyType (TypeConstructor tc) $+ take (length tvs) $ map TypeVariable [0 ..]+ QualTypeExpr _ cx inst = fromPredType tvs $ PredType ps ty+ ds <- deriveMethods cls ty cis ps+ return $ InstanceDecl NoSpanInfo WhitespaceLayout cx cls inst ds++-- Note: The methods and arities of the generated instance declarations have to+-- correspond to the methods and arities entered previously into the instance+-- environment (see instance check).++deriveMethods :: QualIdent -> Type -> [ConstrInfo] -> PredSet+ -> DVM [Decl PredType]+deriveMethods cls+ | cls == qEqId = deriveEqMethods+ | cls == qOrdId = deriveOrdMethods+ | cls == qEnumId = deriveEnumMethods+ | cls == qBoundedId = deriveBoundedMethods+ | cls == qReadId = deriveReadMethods+ | cls == qShowId = deriveShowMethods+ | cls == qDataId = deriveDataMethods+ | otherwise = internalError $ "Derive.deriveMethods: " ++ show cls++-- Binary Operators:++type BinOpExpr = Int+ -> [Expression PredType]+ -> Int+ -> [Expression PredType]+ -> Expression PredType++deriveBinOp :: QualIdent -> Ident -> BinOpExpr -> Type -> [ConstrInfo]+ -> PredSet -> DVM (Decl PredType)+deriveBinOp cls op expr ty cis ps = do+ pty <- getInstMethodType ps cls ty op+ eqs <- mapM (deriveBinOpEquation op expr ty) $ sequence [cis, cis]+ return $ FunctionDecl NoSpanInfo pty op $+ if null eqs+ then [mkEquation NoSpanInfo op [] $+ preludeFailed $ instType $ unpredType pty]+ else eqs++deriveBinOpEquation :: Ident -> BinOpExpr -> Type -> [ConstrInfo]+ -> DVM (Equation PredType)+deriveBinOpEquation op expr ty [(i1, c1, _, tys1), (i2, c2, _, tys2)] = do+ vs1 <- mapM (freshArgument . instType) tys1+ vs2 <- mapM (freshArgument . instType) tys2+ let pat1 = constrPattern pty c1 vs1+ pat2 = constrPattern pty c2 vs2+ es1 = map (uncurry mkVar) vs1+ es2 = map (uncurry mkVar) vs2+ return $ mkEquation NoSpanInfo op [pat1, pat2] $ expr i1 es1 i2 es2+ where pty = predType $ instType ty+deriveBinOpEquation _ _ _ _ = internalError "Derive.deriveBinOpEquation"++-- Equality:++deriveEqMethods :: Type -> [ConstrInfo] -> PredSet -> DVM [Decl PredType]+deriveEqMethods ty cis ps = sequence+ [deriveBinOp qEqId eqOpId eqOpExpr ty cis ps]++eqOpExpr :: BinOpExpr+eqOpExpr i1 es1 i2 es2+ | i1 == i2 = if null es1 then prelTrue+ else foldl1 prelAnd $ zipWith prelEq es1 es2+ | otherwise = prelFalse++-- Data:++deriveDataMethods :: Type -> [ConstrInfo] -> PredSet -> DVM [Decl PredType]+deriveDataMethods ty cis ps = sequence+ [ deriveBinOp qDataId dataEqId dataEqOpExpr ty cis ps+ , deriveAValue ty cis ps]++dataEqOpExpr :: BinOpExpr+dataEqOpExpr i1 es1 i2 es2+ | i1 == i2 = if null es1 then prelTrue+ else foldl1 prelAnd $ zipWith prelDataEq es1 es2+ | otherwise = prelFalse++deriveAValue :: Type -> [ConstrInfo] -> PredSet -> DVM (Decl PredType)+deriveAValue ty cis ps = do+ pty <- getInstMethodType ps qDataId ty aValueId+ return $ FunctionDecl NoSpanInfo pty aValueId $+ if null cis+ then [mkEquation NoSpanInfo aValueId [] $ preludeFailed $ instType ty]+ else map (aValueEquation ty) cis++aValueEquation :: Type -> ConstrInfo -> Equation PredType+aValueEquation ty (arity, cns, _, tys)+ | arity >= 0 = mkEquation NoSpanInfo aValueId [] $ predType <$>+ foldl (Apply NoSpanInfo)+ (Constructor NoSpanInfo constrType cns)+ (map mkAValue tys')+ | otherwise = internalError "Derive.aValueEquation: negative arity"+ where+ constrType = foldr TypeArrow (instType ty) tys'+ mkAValue argTy = Variable NoSpanInfo argTy qAValueId+ tys' = map instType tys++-- Ordering:++deriveOrdMethods :: Type -> [ConstrInfo] -> PredSet -> DVM [Decl PredType]+deriveOrdMethods ty cis ps = sequence+ [deriveBinOp qOrdId leqOpId leqOpExpr ty cis ps]++leqOpExpr :: BinOpExpr+leqOpExpr i1 es1 i2 es2+ | i1 < i2 = prelTrue+ | i1 > i2 = prelFalse+ | otherwise = if null es1 then prelTrue+ else foldl1 prelOr $ map innerAnd [0 .. n - 1]+ where n = length es1+ innerAnd i = foldl1 prelAnd $ map (innerOp i) [0 .. i]+ innerOp i j | j == n - 1 = prelLeq (es1 !! j) (es2 !! j)+ | j == i = prelLt (es1 !! j) (es2 !! j)+ | otherwise = prelEq (es1 !! j) (es2 !! j)++-- Enumerations:++deriveEnumMethods :: Type -> [ConstrInfo] -> PredSet -> DVM [Decl PredType]+deriveEnumMethods ty cis ps = sequence+ [ deriveSuccOrPred succId ty cis (tail cis) ps+ , deriveSuccOrPred predId ty (tail cis) cis ps+ , deriveToEnum ty cis ps+ , deriveFromEnum ty cis ps+ , deriveEnumFrom ty (last cis) ps+ , deriveEnumFromThen ty (head cis) (last cis) ps+ ]++deriveSuccOrPred :: Ident -> Type -> [ConstrInfo] -> [ConstrInfo] -> PredSet+ -> DVM (Decl PredType)+deriveSuccOrPred f ty cis1 cis2 ps = do+ pty <- getInstMethodType ps qEnumId ty f+ FunctionDecl NoSpanInfo pty f <$>+ if null eqs+ then do+ v <- freshArgument $ instType ty+ return [mkEquation NoSpanInfo f [uncurry (VariablePattern NoSpanInfo) v] $+ preludeFailed $ instType ty]+ else return eqs+ where eqs = zipWith (succOrPredEquation f ty) cis1 cis2++succOrPredEquation :: Ident -> Type -> ConstrInfo -> ConstrInfo+ -> Equation PredType+succOrPredEquation f ty (_, c1, _, _) (_, c2, _, _) =+ mkEquation NoSpanInfo f [ConstructorPattern NoSpanInfo pty c1 []] $+ Constructor NoSpanInfo pty c2+ where pty = predType $ instType ty++deriveToEnum :: Type -> [ConstrInfo] -> PredSet -> DVM (Decl PredType)+deriveToEnum ty cis ps = do+ pty <- getInstMethodType ps qEnumId ty toEnumId+ return $ FunctionDecl NoSpanInfo pty toEnumId eqs+ where eqs = zipWith (toEnumEquation ty) [0 ..] cis++toEnumEquation :: Type -> Integer -> ConstrInfo -> Equation PredType+toEnumEquation ty i (_, c, _, _) =+ mkEquation NoSpanInfo toEnumId+ [LiteralPattern NoSpanInfo (predType intType) (Int i)] $+ Constructor NoSpanInfo (predType $ instType ty) c++deriveFromEnum :: Type -> [ConstrInfo] -> PredSet -> DVM (Decl PredType)+deriveFromEnum ty cis ps = do+ pty <- getInstMethodType ps qEnumId ty fromEnumId+ return $ FunctionDecl NoSpanInfo pty fromEnumId eqs+ where eqs = zipWith (fromEnumEquation ty) cis [0 ..]++fromEnumEquation :: Type -> ConstrInfo -> Integer -> Equation PredType+fromEnumEquation ty (_, c, _, _) i =+ mkEquation NoSpanInfo fromEnumId [ConstructorPattern NoSpanInfo pty c []] $+ Literal NoSpanInfo (predType intType) $ Int i+ where pty = predType $ instType ty++deriveEnumFrom :: Type -> ConstrInfo -> PredSet -> DVM (Decl PredType)+deriveEnumFrom ty (_, c, _, _) ps = do+ pty <- getInstMethodType ps qEnumId ty enumFromId+ v <- freshArgument $ instType ty+ return $ funDecl NoSpanInfo pty enumFromId+ [uncurry (VariablePattern NoSpanInfo) v] $+ enumFromExpr v c++enumFromExpr :: (PredType, Ident) -> QualIdent -> Expression PredType+enumFromExpr v c = prelEnumFromTo (uncurry mkVar v) $+ Constructor NoSpanInfo (fst v) c++deriveEnumFromThen :: Type -> ConstrInfo -> ConstrInfo -> PredSet+ -> DVM (Decl PredType)+deriveEnumFromThen ty (_, c1, _, _) (_, c2, _, _) ps = do+ pty <- getInstMethodType ps qEnumId ty enumFromId+ vs <- replicateM 2 ((freshArgument . instType) ty)+ let [v1, v2] = vs+ return $ funDecl NoSpanInfo pty enumFromThenId+ (map (uncurry (VariablePattern NoSpanInfo)) vs) $+ enumFromThenExpr v1 v2 c1 c2++enumFromThenExpr :: (PredType, Ident) -> (PredType, Ident) -> QualIdent+ -> QualIdent -> Expression PredType+enumFromThenExpr v1 v2 c1 c2 =+ prelEnumFromThenTo (uncurry mkVar v1) (uncurry mkVar v2) boundedExpr+ where boundedExpr = IfThenElse NoSpanInfo+ (prelLeq+ (prelFromEnum $ uncurry mkVar v1)+ (prelFromEnum $ uncurry mkVar v2))+ (Constructor NoSpanInfo (fst v1) c2)+ (Constructor NoSpanInfo (fst v1) c1)++-- Upper and Lower Bounds:++deriveBoundedMethods :: Type -> [ConstrInfo] -> PredSet -> DVM [Decl PredType]+deriveBoundedMethods ty cis ps = sequence+ [ deriveMaxOrMinBound qMinBoundId ty (head cis) ps+ , deriveMaxOrMinBound qMaxBoundId ty (last cis) ps+ ]++deriveMaxOrMinBound :: QualIdent -> Type -> ConstrInfo -> PredSet+ -> DVM (Decl PredType)+deriveMaxOrMinBound f ty (_, c, _, tys) ps = do+ pty <- getInstMethodType ps qBoundedId ty $ unqualify f+ return $ funDecl NoSpanInfo pty (unqualify f) [] $ maxOrMinBoundExpr f c ty tys++maxOrMinBoundExpr :: QualIdent -> QualIdent -> Type -> [Type]+ -> Expression PredType+maxOrMinBoundExpr f c ty tys =+ apply (Constructor NoSpanInfo pty c) $+ map (flip (Variable NoSpanInfo) f . predType) instTys+ where instTy:instTys = map instType $ ty : tys+ pty = predType $ foldr TypeArrow instTy instTys++-- Read:++deriveReadMethods :: Type -> [ConstrInfo] -> PredSet -> DVM [Decl PredType]+deriveReadMethods ty cis ps = sequence [deriveReadsPrec ty cis ps]++deriveReadsPrec :: Type -> [ConstrInfo] -> PredSet -> DVM (Decl PredType)+deriveReadsPrec ty cis ps = do+ pty <- getInstMethodType ps qReadId ty readsPrecId+ d <- freshArgument intType+ r <- freshArgument stringType+ let pats = map (uncurry (VariablePattern NoSpanInfo)) [d, r]+ funDecl NoSpanInfo pty readsPrecId pats <$>+ deriveReadsPrecExpr ty cis (uncurry mkVar d) (uncurry mkVar r)++deriveReadsPrecExpr :: Type -> [ConstrInfo] -> Expression PredType+ -> Expression PredType -> DVM (Expression PredType)+deriveReadsPrecExpr ty cis d r = do+ es <- mapM (deriveReadsPrecReadParenExpr ty d) cis+ return $ foldr1 prelAppend $ map (flip (Apply NoSpanInfo) r) es++deriveReadsPrecReadParenExpr :: Type -> Expression PredType -> ConstrInfo+ -> DVM (Expression PredType)+deriveReadsPrecReadParenExpr ty d ci@(_, c, _, _) = do+ pEnv <- getPrecEnv+ let p = precedence c pEnv+ e <- deriveReadsPrecLambdaExpr ty ci p+ return $ prelReadParen (readsPrecReadParenCondExpr ci d p) e++readsPrecReadParenCondExpr :: ConstrInfo -> Expression PredType -> Precedence+ -> Expression PredType+readsPrecReadParenCondExpr (_, c, _, tys) d p+ | null tys = prelFalse+ | isQInfixOp c && length tys == 2 =+ prelLt (Literal NoSpanInfo predIntType $ Int p) d+ | otherwise =+ prelLt (Literal NoSpanInfo predIntType $ Int 10) d++deriveReadsPrecLambdaExpr :: Type -> ConstrInfo -> Precedence+ -> DVM (Expression PredType)+deriveReadsPrecLambdaExpr ty (_, c, ls, tys) p = do+ r <- freshArgument stringType+ (stmts, vs, s) <- deriveReadsPrecStmts (unqualify c) (p + 1) r ls tys+ let pty = predType $ foldr (TypeArrow . instType) (instType ty) tys+ e = Tuple NoSpanInfo+ [ apply (Constructor NoSpanInfo pty c) $ map (uncurry mkVar) vs+ , uncurry mkVar s+ ]+ return $ Lambda NoSpanInfo [uncurry (VariablePattern NoSpanInfo) r]+ $ ListCompr NoSpanInfo e stmts++deriveReadsPrecStmts+ :: Ident -> Precedence -> (PredType, Ident) -> Maybe [Ident] -> [Type]+ -> DVM ([Statement PredType], [(PredType, Ident)], (PredType, Ident))+deriveReadsPrecStmts c p r ls tys+ | null tys = deriveReadsPrecNullaryConstrStmts c r+ | isJust ls =+ deriveReadsPrecRecordConstrStmts c r (fromJust ls) tys+ | isInfixOp c && length tys == 2 = deriveReadsPrecInfixConstrStmts c p r tys+ | otherwise = deriveReadsPrecConstrStmts c r tys++deriveReadsPrecNullaryConstrStmts+ :: Ident -> (PredType, Ident)+ -> DVM ([Statement PredType], [(PredType, Ident)], (PredType, Ident))+deriveReadsPrecNullaryConstrStmts c r = do+ (s, stmt) <- deriveReadsPrecLexStmt (idName c) r+ return ([stmt], [], s)++deriveReadsPrecRecordConstrStmts+ :: Ident -> (PredType, Ident) -> [Ident] -> [Type]+ -> DVM ([Statement PredType], [(PredType, Ident)], (PredType, Ident))+deriveReadsPrecRecordConstrStmts c r ls tys = do+ (s, stmt1) <- deriveReadsPrecLexStmt (idName c) r+ (t, ress) <-+ mapAccumM deriveReadsPrecFieldStmts s $ zip3 ("{" : repeat ",") ls tys+ let (stmtss, vs) = unzip ress+ (u, stmt2) <- deriveReadsPrecLexStmt "}" t+ return (stmt1 : concat stmtss ++ [stmt2], vs, u)++deriveReadsPrecFieldStmts+ :: (PredType, Ident) -> (String, Ident, Type)+ -> DVM ((PredType, Ident), ([Statement PredType], (PredType, Ident)))+deriveReadsPrecFieldStmts r (pre, l, ty) = do+ (s, stmt1) <- deriveReadsPrecLexStmt pre r+ (t, stmt2) <- deriveReadsPrecLexStmt (idName l) s+ (u, stmt3) <- deriveReadsPrecLexStmt "=" t+ (w, (stmt4, v)) <- deriveReadsPrecReadsPrecStmt 0 u ty+ return (w, ([stmt1, stmt2, stmt3, stmt4], v))++deriveReadsPrecInfixConstrStmts+ :: Ident -> Precedence -> (PredType, Ident) -> [Type]+ -> DVM ([Statement PredType], [(PredType, Ident)], (PredType, Ident))+deriveReadsPrecInfixConstrStmts c p r tys = do+ (s, (stmt1, v1)) <- deriveReadsPrecReadsPrecStmt (p + 1) r $ head tys+ (t, stmt2) <- deriveReadsPrecLexStmt (idName c) s+ (u, (stmt3, v2)) <- deriveReadsPrecReadsPrecStmt (p + 1) t $ head $ tail tys+ return ([stmt1, stmt2, stmt3], [v1, v2], u)++deriveReadsPrecConstrStmts+ :: Ident -> (PredType, Ident) -> [Type]+ -> DVM ([Statement PredType], [(PredType, Ident)], (PredType, Ident))+deriveReadsPrecConstrStmts c r tys = do+ (s, stmt) <- deriveReadsPrecLexStmt (idName c) r+ (t, ress) <- mapAccumM (deriveReadsPrecReadsPrecStmt 11) s tys+ let (stmts, vs) = unzip ress+ return (stmt : stmts, vs, t)++deriveReadsPrecLexStmt :: String -> (PredType, Ident)+ -> DVM ((PredType, Ident), Statement PredType)+deriveReadsPrecLexStmt str r = do+ s <- freshArgument stringType+ let pat = TuplePattern NoSpanInfo+ [ LiteralPattern NoSpanInfo predStringType $ String str+ , uncurry (VariablePattern NoSpanInfo) s+ ]+ stmt = StmtBind NoSpanInfo pat $ preludeLex $ uncurry mkVar r+ return (s, stmt)++deriveReadsPrecReadsPrecStmt :: Precedence -> (PredType, Ident) -> Type+ -> DVM ((PredType, Ident), (Statement PredType, (PredType, Ident)))+deriveReadsPrecReadsPrecStmt p r ty = do+ v <- freshArgument $ instType ty+ s <- freshArgument $ stringType+ let pat = TuplePattern NoSpanInfo $+ map (uncurry (VariablePattern NoSpanInfo)) [v, s]+ stmt = StmtBind NoSpanInfo pat $ preludeReadsPrec (instType ty) p $+ uncurry mkVar r+ return (s, (stmt, v))++-- Show:++deriveShowMethods :: Type -> [ConstrInfo] -> PredSet -> DVM [Decl PredType]+deriveShowMethods ty cis ps = sequence [deriveShowsPrec ty cis ps]++deriveShowsPrec :: Type -> [ConstrInfo] -> PredSet -> DVM (Decl PredType)+deriveShowsPrec ty cis ps = do+ pty <- getInstMethodType ps qShowId ty showsPrecId+ eqs <- mapM (deriveShowsPrecEquation ty) cis+ return $ FunctionDecl NoSpanInfo pty showsPrecId eqs++deriveShowsPrecEquation :: Type -> ConstrInfo -> DVM (Equation PredType)+deriveShowsPrecEquation ty (_, c, ls, tys) = do+ d <- freshArgument intType+ vs <- mapM (freshArgument . instType) tys+ let pats = [uncurry (VariablePattern NoSpanInfo) d, constrPattern pty c vs]+ pEnv <- getPrecEnv+ return $ mkEquation NoSpanInfo showsPrecId pats $ showsPrecExpr (unqualify c)+ (precedence c pEnv) ls (uncurry mkVar d) $ map (uncurry mkVar) vs+ where pty = predType $ instType ty++showsPrecExpr :: Ident -> Precedence -> Maybe [Ident] -> Expression PredType+ -> [Expression PredType] -> Expression PredType+showsPrecExpr c p ls d vs+ | null vs = showsPrecNullaryConstrExpr c+ | isJust ls = showsPrecShowParenExpr d 10 $+ showsPrecRecordConstrExpr c (fromJust ls) vs+ | isInfixOp c && length vs == 2 = showsPrecShowParenExpr d p $+ showsPrecInfixConstrExpr c p vs+ | otherwise = showsPrecShowParenExpr d 10 $+ showsPrecConstrExpr c vs++showsPrecNullaryConstrExpr :: Ident -> Expression PredType+showsPrecNullaryConstrExpr c = preludeShowString $ showsConstr c ""++showsPrecShowParenExpr :: Expression PredType -> Precedence+ -> Expression PredType -> Expression PredType+showsPrecShowParenExpr d p =+ prelShowParen $ prelLt (Literal NoSpanInfo predIntType $ Int p) d++showsPrecRecordConstrExpr :: Ident -> [Ident] -> [Expression PredType]+ -> Expression PredType+showsPrecRecordConstrExpr c ls vs = foldr prelDot (preludeShowString "}") $+ (:) (preludeShowString $ showsConstr c " {") $+ intercalate [preludeShowString ", "] $ zipWith showsPrecFieldExpr ls vs++showsPrecFieldExpr :: Ident -> Expression PredType -> [Expression PredType]+showsPrecFieldExpr l v =+ [preludeShowString $ showsConstr l " = ", preludeShowsPrec 0 v]++showsPrecInfixConstrExpr :: Ident -> Precedence -> [Expression PredType]+ -> Expression PredType+showsPrecInfixConstrExpr c p vs = foldr1 prelDot+ [ preludeShowsPrec (p + 1) $ head vs+ , preludeShowString $ ' ' : idName c ++ " "+ , preludeShowsPrec (p + 1) $ head $ tail vs+ ]++showsPrecConstrExpr :: Ident -> [Expression PredType] -> Expression PredType+showsPrecConstrExpr c vs = foldr1 prelDot $+ preludeShowString (showsConstr c " ") :+ intersperse (preludeShowString " ") (map (preludeShowsPrec 11) vs)++-- -----------------------------------------------------------------------------+-- Generating variables+-- -----------------------------------------------------------------------------++freshArgument :: Type -> DVM (PredType, Ident)+freshArgument = freshVar "_#arg"++freshVar :: String -> Type -> DVM (PredType, Ident)+freshVar name ty =+ ((,) (predType ty)) . mkIdent . (name ++) . show <$> getNextId++-- -----------------------------------------------------------------------------+-- Auxiliary functions+-- -----------------------------------------------------------------------------++constructors :: ModuleIdent -> QualIdent -> TCEnv -> [ConstrInfo]+constructors m tc tcEnv = zipWith (mkConstrInfo m) [1 ..] $+ case qualLookupTypeInfo tc tcEnv of+ [DataType _ _ cs] -> cs+ [RenamingType _ _ nc] -> [nc]+ _ -> internalError $ "Derive.constructors: " ++ show tc++mkConstrInfo :: ModuleIdent -> Int -> DataConstr -> ConstrInfo+mkConstrInfo m i (DataConstr c tys) =+ (i, qualifyWith m c, Nothing, tys)+mkConstrInfo m i (RecordConstr c ls tys) =+ (i, qualifyWith m c, Just ls, tys)++showsConstr :: Ident -> ShowS+showsConstr c = showParen (isInfixOp c) $ showString $ idName c++precedence :: QualIdent -> OpPrecEnv -> Precedence+precedence op pEnv = case qualLookupP op pEnv of+ [] -> defaultPrecedence+ PrecInfo _ (OpPrec _ p) : _ -> p++instType :: Type -> Type+instType (TypeConstructor tc) = TypeConstructor tc+instType (TypeVariable tv) = TypeVariable (-1 - tv)+instType (TypeApply ty1 ty2) = TypeApply (instType ty1) (instType ty2)+instType (TypeArrow ty1 ty2) = TypeArrow (instType ty1) (instType ty2)+instType ty = ty++-- Returns the type for a given instance's method of a given class. To this+-- end, the class method's type is stripped of its first predicate (which is+-- the implicit class constraint) and the class variable is replaced with the+-- instance's type. The remaining predicate set is then united with the+-- instance's predicate set.++getInstMethodType :: PredSet -> QualIdent -> Type -> Ident -> DVM PredType+getInstMethodType ps cls ty f = do+ vEnv <- getValueEnv+ return $ instMethodType vEnv ps cls ty f++instMethodType :: ValueEnv -> PredSet -> QualIdent -> Type -> Ident -> PredType+instMethodType vEnv ps cls ty f = PredType (ps `Set.union` ps'') ty''+ where PredType ps' ty' = case qualLookupValue (qualifyLike cls f) vEnv of+ [Value _ _ _ (ForAll _ pty)] -> pty+ _ -> internalError "Derive.instMethodType"+ PredType ps'' ty'' = instanceType ty $ PredType (Set.deleteMin ps') ty'++-- -----------------------------------------------------------------------------+-- Prelude entities+-- -----------------------------------------------------------------------------++prelTrue :: Expression PredType+prelTrue = Constructor NoSpanInfo predBoolType qTrueId++prelFalse :: Expression PredType+prelFalse = Constructor NoSpanInfo predBoolType qFalseId++prelAppend :: Expression PredType -> Expression PredType -> Expression PredType+prelAppend e1 e2 = foldl1 (Apply NoSpanInfo)+ [Variable NoSpanInfo pty qAppendOpId, e1, e2]+ where pty = predType $ foldr1 TypeArrow $ replicate 3 $ typeOf e1++prelDot :: Expression PredType -> Expression PredType -> Expression PredType+prelDot e1 e2 = foldl1 (Apply NoSpanInfo)+ [Variable NoSpanInfo pty qDotOpId, e1, e2]+ where ty1@(TypeArrow _ ty12) = typeOf e1+ ty2@(TypeArrow ty21 _ ) = typeOf e2+ pty = predType $ foldr1 TypeArrow [ty1, ty2, ty21, ty12]++prelAnd :: Expression PredType -> Expression PredType -> Expression PredType+prelAnd e1 e2 = foldl1 (Apply NoSpanInfo)+ [Variable NoSpanInfo pty qAndOpId, e1, e2]+ where pty = predType $ foldr1 TypeArrow $ replicate 3 boolType++prelEq :: Expression PredType -> Expression PredType -> Expression PredType+prelEq e1 e2 = foldl1 (Apply NoSpanInfo)+ [Variable NoSpanInfo pty qEqOpId, e1, e2]+ where ty = typeOf e1+ pty = predType $ foldr1 TypeArrow [ty, ty, boolType]++prelDataEq :: Expression PredType -> Expression PredType -> Expression PredType+prelDataEq e1 e2 = foldl1 (Apply NoSpanInfo)+ [Variable NoSpanInfo pty qDataEqId, e1, e2]+ where ty = typeOf e1+ pty = predType $ foldr1 TypeArrow [ty, ty, boolType]++prelLeq :: Expression PredType -> Expression PredType -> Expression PredType+prelLeq e1 e2 = foldl1 (Apply NoSpanInfo)+ [Variable NoSpanInfo pty qLeqOpId, e1, e2]+ where ty = typeOf e1+ pty = predType $ foldr1 TypeArrow [ty, ty, boolType]++prelLt :: Expression PredType -> Expression PredType -> Expression PredType+prelLt e1 e2 = foldl1 (Apply NoSpanInfo)+ [Variable NoSpanInfo pty qLtOpId, e1, e2]+ where ty = typeOf e1+ pty = predType $ foldr1 TypeArrow [ty, ty, boolType]++prelOr :: Expression PredType -> Expression PredType -> Expression PredType+prelOr e1 e2 = foldl1 (Apply NoSpanInfo)+ [Variable NoSpanInfo pty qOrOpId, e1, e2]+ where pty = predType $ foldr1 TypeArrow $ replicate 3 boolType++prelFromEnum :: Expression PredType -> Expression PredType+prelFromEnum e = Apply NoSpanInfo (Variable NoSpanInfo pty qFromEnumId) e+ where pty = predType $ TypeArrow (typeOf e) intType++prelEnumFromTo :: Expression PredType -> Expression PredType+ -> Expression PredType+prelEnumFromTo e1 e2 = apply (Variable NoSpanInfo pty qEnumFromToId) [e1, e2]+ where ty = typeOf e1+ pty = predType $ foldr1 TypeArrow [ty, ty, listType ty]++prelEnumFromThenTo :: Expression PredType -> Expression PredType+ -> Expression PredType -> Expression PredType+prelEnumFromThenTo e1 e2 e3 =+ apply (Variable NoSpanInfo pty qEnumFromThenToId) [e1, e2, e3]+ where ty = typeOf e1+ pty = predType $ foldr1 TypeArrow [ty, ty, ty, listType ty]++prelReadParen :: Expression PredType -> Expression PredType+ -> Expression PredType+prelReadParen e1 e2 = apply (Variable NoSpanInfo pty qReadParenId) [e1, e2]+ where ty = typeOf e2+ pty = predType $ foldr1 TypeArrow [boolType, ty, ty]++prelShowParen :: Expression PredType -> Expression PredType+ -> Expression PredType+prelShowParen e1 e2 = apply (Variable NoSpanInfo pty qShowParenId) [e1, e2]+ where pty = predType $ foldr1 TypeArrow [ boolType+ , TypeArrow stringType stringType+ , stringType, stringType+ ]++preludeLex :: Expression PredType -> Expression PredType+preludeLex = Apply NoSpanInfo (Variable NoSpanInfo pty qLexId)+ where pty = predType $ TypeArrow stringType $+ listType $ tupleType [stringType, stringType]++preludeReadsPrec :: Type -> Integer -> Expression PredType+ -> Expression PredType+preludeReadsPrec ty p e = flip (Apply NoSpanInfo) e $+ Apply NoSpanInfo (Variable NoSpanInfo pty qReadsPrecId) $+ Literal NoSpanInfo predIntType $ Int p+ where pty = predType $ foldr1 TypeArrow [ intType, stringType+ , listType $ tupleType [ ty+ , stringType+ ]+ ]++preludeShowsPrec :: Integer -> Expression PredType -> Expression PredType+preludeShowsPrec p e = flip (Apply NoSpanInfo) e $+ Apply NoSpanInfo (Variable NoSpanInfo pty qShowsPrecId) $+ Literal NoSpanInfo predIntType $ Int p+ where pty = predType $ foldr1 TypeArrow [ intType, typeOf e+ , stringType, stringType+ ]++preludeShowString :: String -> Expression PredType+preludeShowString s = Apply NoSpanInfo (Variable NoSpanInfo pty qShowStringId) $+ Literal NoSpanInfo predStringType $ String s+ where pty = predType $ foldr1 TypeArrow $ replicate 3 stringType++preludeFailed :: Type -> Expression PredType+preludeFailed ty = Variable NoSpanInfo (predType ty) qFailedId
+ src/Transformations/Desugar.hs view
@@ -0,0 +1,1168 @@+{- |+ Module : $Header$+ Description : Desugaring Curry Expressions+ Copyright : (c) 2001 - 2004 Wolfgang Lux+ Martin Engelke+ 2011 - 2015 Björn Peemöller+ 2015 Jan Tikovsky+ 2016 - 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ The desugaring pass removes all syntactic sugar from the module.+ In particular, the output of the desugarer will have the following+ properties.++ * No guarded right hand sides occur in equations, pattern declarations,+ and case alternatives. In addition, the declaration lists (`where`-blocks)+ of the right hand sides are empty; local declarations are transformed+ into let expressions.++ * Patterns in equations and case alternatives are composed only of+ - literals,+ - variables,+ - constructor applications, and+ - as patterns applied to literals or constructor applications.++ * Expressions are composed only of+ - literals,+ - variables,+ - constructors,+ - (binary) applications,+ - case expressions,+ - let expressions, and+ - expressions with a type signature.++ * Functional patterns are replaced by variables and are integrated+ in a guarded right hand side using the (=:<=) operator.++ * Records are transformed into ordinary data types by removing the fields.+ Record construction and pattern matching are represented using solely the+ record constructor. Record selections are represented using selector+ functions which are generated for each record declaration, and record+ updated are represented using case-expressions that perform the update.++ * The type environment will be extended by new function declarations for:+ - Record selections, and+ - Converted lambda expressions.++ As we are going to insert references to real prelude entities,+ all names must be properly qualified before calling this module.+-}+{-# LANGUAGE CPP #-}+module Transformations.Desugar (desugar) where++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative ((<$>), (<*>))+#endif+import Control.Arrow (first, second)+import Control.Monad (liftM2)+import Control.Monad.Extra (concatMapM)+import qualified Control.Monad.State as S (State, runState, gets, modify)+import Data.Foldable (foldrM)+import Data.List ( (\\), elemIndex, nub, partition+ , tails )+import Data.Maybe (fromMaybe)+import qualified Data.Set as Set (Set, empty, member, insert)++import Curry.Base.Ident+import Curry.Base.SpanInfo+import Curry.Syntax++import Base.Expr+import Base.CurryTypes+import Base.Messages (internalError)+import Base.TypeExpansion+import Base.Types+import Base.TypeSubst+import Base.Typing+import Base.Utils (fst3, mapAccumM)++import Env.TypeConstructor (TCEnv, TypeInfo (..), qualLookupTypeInfo)+import Env.Value (ValueEnv, ValueInfo (..), qualLookupValue)++-- TODO: some types keep their spanInfo, some don't. Probably none of them are needed++-- The desugaring phase keeps only the type, function, and value+-- declarations of the module, i.e., type signatures are discarded.+-- While record declarations are transformed into ordinary data/newtype+-- declarations, the remaining type declarations are not desugared.+-- Since they cannot occur in local declaration groups, they are filtered+-- out separately. Actually, the transformation is slightly more general than+-- necessary as it allows value declarations at the top-level of a module.++desugar :: [KnownExtension] -> ValueEnv -> TCEnv -> Module PredType+ -> (Module PredType, ValueEnv)+desugar xs vEnv tcEnv (Module spi li ps m es is ds)+ = (Module spi li ps m es is ds', valueEnv s')+ where (ds', s') = S.runState (desugarModuleDecls ds)+ (DesugarState m xs tcEnv vEnv 1)++-- ---------------------------------------------------------------------------+-- Desugaring monad and accessor functions+-- ---------------------------------------------------------------------------++-- New identifiers may be introduced while desugaring pattern declarations,+-- case and lambda-expressions, list comprehensions, and record selections+-- and updates. As usual, we use a state monad transformer for generating+-- unique names. In addition, the state is also used for passing through the+-- type environment, which must be augmented with the types of these new+-- variables.++data DesugarState = DesugarState+ { moduleIdent :: ModuleIdent -- read-only+ , extensions :: [KnownExtension] -- read-only+ , tyConsEnv :: TCEnv -- read-only+ , valueEnv :: ValueEnv -- will be extended+ , nextId :: Integer -- counter+ }++type DsM a = S.State DesugarState a++getModuleIdent :: DsM ModuleIdent+getModuleIdent = S.gets moduleIdent++checkNegativeLitsExtension :: DsM Bool+checkNegativeLitsExtension = S.gets (\s -> NegativeLiterals `elem` extensions s)++getTyConsEnv :: DsM TCEnv+getTyConsEnv = S.gets tyConsEnv++getValueEnv :: DsM ValueEnv+getValueEnv = S.gets valueEnv++getNextId :: DsM Integer+getNextId = do+ nid <- S.gets nextId+ S.modify $ \s -> s { nextId = succ nid }+ return nid++-- ---------------------------------------------------------------------------+-- Generation of fresh names+-- ---------------------------------------------------------------------------++-- Create a fresh variable ident for a given prefix with a monomorphic type+freshVar :: Typeable t => String -> t -> DsM (PredType, Ident)+freshVar prefix t = do+ v <- (mkIdent . (prefix ++) . show) <$> getNextId+ return (predType $ typeOf t, v)++-- ---------------------------------------------------------------------------+-- Desugaring+-- ---------------------------------------------------------------------------++desugarModuleDecls :: [Decl PredType] -> DsM [Decl PredType]+desugarModuleDecls ds = do+ ds' <- concatMapM dsRecordDecl ds+ ds'' <- concatMapM dsTypeDecl ds'+ ds''' <- mapM dsClassAndInstanceDecl ds''+ ds'''' <- dsDeclGroup ds'''+ return $ filter (not . liftM2 (||) isValueDecl isTypeSig) ds''' ++ ds''''++-- -----------------------------------------------------------------------------+-- Desugaring of type declarations+-- -----------------------------------------------------------------------------++dsTypeDecl :: Decl PredType -> DsM [Decl PredType]+dsTypeDecl (DataDecl si tc tvs cs clss) = do+ cs' <- mapM dsConstrDecl cs+ return $ [DataDecl si tc tvs cs' clss]+dsTypeDecl (NewtypeDecl si tc tvs nc clss) = do+ nc' <- dsNewConstrDecl nc+ return $ [NewtypeDecl si tc tvs nc' clss]+dsTypeDecl (TypeDecl _ _ _ _) = return []+dsTypeDecl d = return [d]++dsConstrDecl :: ConstrDecl -> DsM ConstrDecl+dsConstrDecl (ConstrDecl si c tys) = ConstrDecl si c <$> mapM dsTypeExpr tys+dsConstrDecl (ConOpDecl si ty1 op ty2) =+ ConstrDecl si op <$> mapM dsTypeExpr [ty1, ty2]+dsConstrDecl cd = internalError $ "Desugar.dsConstrDecl: " ++ show cd++dsNewConstrDecl :: NewConstrDecl -> DsM NewConstrDecl+dsNewConstrDecl (NewConstrDecl si c ty) = NewConstrDecl si c <$> dsTypeExpr ty+dsNewConstrDecl nc = internalError $ "Desugar.dsNewConstrDecl: " ++ show nc++-- -----------------------------------------------------------------------------+-- Desugaring of class and instance declarations+-- -----------------------------------------------------------------------------++dsClassAndInstanceDecl :: Decl PredType -> DsM (Decl PredType)+dsClassAndInstanceDecl (ClassDecl p li cx cls tv ds) = do+ tds' <- mapM dsTypeSig tds+ vds' <- dsDeclGroup vds+ return $ ClassDecl p li cx cls tv $ tds' ++ vds'+ where (tds, vds) = partition isTypeSig ds+dsClassAndInstanceDecl (InstanceDecl p li cx cls ty ds) =+ InstanceDecl p li cx cls ty <$> dsDeclGroup ds+dsClassAndInstanceDecl d = return d++dsTypeSig :: Decl PredType -> DsM (Decl PredType)+dsTypeSig (TypeSig s fs qty) = TypeSig s fs <$> dsQualTypeExpr qty+dsTypeSig d = internalError $ "Desugar.dsTypeSig: " ++ show d++-- -----------------------------------------------------------------------------+-- Desugaring of type declarations: records+-- -----------------------------------------------------------------------------++-- As an extension to the Curry language, the compiler supports Haskell's+-- record syntax, which introduces field labels for data and renaming types.+-- Field labels can be used in constructor declarations, patterns,+-- and expressions. For further convenience, an implicit selector+-- function is introduced for each field label.++-- Generate selector functions for record labels and replace record+-- constructor declarations by ordinary constructor declarations.+dsRecordDecl :: Decl PredType -> DsM [Decl PredType]+dsRecordDecl (DataDecl p tc tvs cs clss) = do+ m <- getModuleIdent+ let qcs = map (qualifyWith m . constrId) cs+ selFuns <- mapM (genSelFun p qcs) (nub $ concatMap recordLabels cs)+ return $ DataDecl p tc tvs (map unlabelConstr cs) clss : selFuns+dsRecordDecl (NewtypeDecl p tc tvs nc clss) = do+ m <- getModuleIdent+ let qc = qualifyWith m (nconstrId nc)+ selFun <- mapM (genSelFun p [qc]) (nrecordLabels nc)+ return $ NewtypeDecl p tc tvs (unlabelNewConstr nc) clss : selFun+dsRecordDecl d = return [d]++-- Generate a selector function for a single record label+genSelFun :: SpanInfo -> [QualIdent] -> Ident -> DsM (Decl PredType)+genSelFun p qcs l = do+ m <- getModuleIdent+ vEnv <- getValueEnv+ let ForAll _ pty = varType (qualifyWith m l) vEnv+ FunctionDecl p pty l <$> concatMapM (genSelEqn p l) qcs++-- Generate a selector equation for a label and a constructor if the label+-- is applicable, otherwise the empty list is returned.+genSelEqn :: SpanInfo -> Ident -> QualIdent -> DsM [Equation PredType]+genSelEqn p l qc = do+ vEnv <- getValueEnv+ let (ls, ty) = conType qc vEnv+ (tys, ty0) = arrowUnapply (instType ty)+ case elemIndex l ls of+ Just n -> do+ vs <- mapM (freshVar "_#rec") tys+ let pat = constrPattern (predType ty0) qc vs+ return [mkEquation p l [pat] (uncurry mkVar (vs !! n))]+ Nothing -> return []++-- Remove any labels from a data constructor declaration+unlabelConstr :: ConstrDecl -> ConstrDecl+unlabelConstr (RecordDecl p c fs) = ConstrDecl p c tys+ where tys = [ty | FieldDecl _ ls ty <- fs, _ <- ls]+unlabelConstr c = c++-- Remove any labels from a newtype constructor declaration+unlabelNewConstr :: NewConstrDecl -> NewConstrDecl+unlabelNewConstr (NewRecordDecl p nc (_, ty)) = NewConstrDecl p nc ty+unlabelNewConstr c = c++-- -----------------------------------------------------------------------------+-- Desugaring of value declarations+-- -----------------------------------------------------------------------------++-- Within a declaration group, all type signatures are discarded. First,+-- the patterns occurring in the left hand sides of pattern declarations+-- and external declarations are desugared. Due to lazy patterns, the former+-- may add further declarations to the group that must be desugared as well.+dsDeclGroup :: [Decl PredType] -> DsM [Decl PredType]+dsDeclGroup ds = concatMapM dsDeclLhs (filter isValueDecl ds) >>= mapM dsDeclRhs++dsDeclLhs :: Decl PredType -> DsM [Decl PredType]+dsDeclLhs (PatternDecl p t rhs) = do+ (ds', t') <- dsPat p [] t+ dss' <- mapM dsDeclLhs ds'+ return $ PatternDecl p t' rhs : concat dss'+dsDeclLhs d = return [d]++-- TODO: Check if obsolete and remove+-- After desugaring its right hand side, each equation is eta-expanded+-- by adding as many variables as necessary to the argument list and+-- applying the right hand side to those variables (Note: eta-expansion+-- is disabled in the version for PAKCS).+-- Furthermore every occurrence of a record type within the type of a function+-- is simplified to the corresponding type constructor from the record+-- declaration. This is possible because currently records must not be empty+-- and a record label belongs to only one record declaration.++-- Desugaring of the right-hand-side of declarations+dsDeclRhs :: Decl PredType -> DsM (Decl PredType)+dsDeclRhs (FunctionDecl p pty f eqs) =+ FunctionDecl p pty f <$> mapM dsEquation eqs+dsDeclRhs (PatternDecl p t rhs) = PatternDecl p t <$> dsRhs id rhs+dsDeclRhs d@(FreeDecl _ _) = return d+dsDeclRhs d@(ExternalDecl _ _) = return d+dsDeclRhs _ =+ error "Desugar.dsDeclRhs: no pattern match"++-- Desugaring of an equation+dsEquation :: Equation PredType -> DsM (Equation PredType)+dsEquation (Equation p lhs rhs) = do+ ( cs1, ts1) <- dsNonLinearity ts+ (ds1, cs2, ts2) <- dsFunctionalPatterns p ts1+ (ds2, ts3) <- mapAccumM (dsPat p) [] ts2+ rhs' <- dsRhs (constrain cs2 . constrain cs1)+ (addDecls (ds1 ++ ds2) rhs)+ return $ Equation p (FunLhs NoSpanInfo f ts3) rhs'+ where (f, ts) = flatLhs lhs++-- Constrain an expression by a list of constraints.+-- @constrain [] e == e@+-- @constrain c_n e == (c_1 & ... & c_n) &> e@+constrain :: [Expression PredType] -> Expression PredType -> Expression PredType+constrain cs e = if null cs then e else foldr1 (&) cs &> e++-- -----------------------------------------------------------------------------+-- Desugaring of right-hand sides+-- -----------------------------------------------------------------------------++-- A list of boolean guards is expanded into a nested if-then-else+-- expression, whereas a constraint guard is replaced by a case+-- expression. Note that if the guard type is 'Success' only a+-- single guard is allowed for each equation (This change was+-- introduced in version 0.8 of the Curry report.). We check for the+-- type 'Bool' of the guard because the guard's type defaults to+-- 'Success' if it is not restricted by the guard expression.++dsRhs :: (Expression PredType -> Expression PredType)+ -> Rhs PredType -> DsM (Rhs PredType)+dsRhs f rhs = expandRhs (prelFailed (typeOf rhs)) f rhs+ >>= dsExpr (getSpanInfo rhs)+ >>= return . simpleRhs (getSpanInfo rhs)++expandRhs :: Expression PredType -> (Expression PredType -> Expression PredType)+ -> Rhs PredType -> DsM (Expression PredType)+expandRhs _ f (SimpleRhs _ _ e ds) = return $ mkLet ds (f e)+expandRhs e0 f (GuardedRhs _ _ es ds) = mkLet ds . f+ <$> expandGuards e0 es++expandGuards :: Expression PredType -> [CondExpr PredType]+ -> DsM (Expression PredType)+expandGuards e0 es =+ return $ if boolGuards es then foldr mkIfThenElse e0 es else mkCond es+ where+ mkIfThenElse (CondExpr _ g e) = IfThenElse NoSpanInfo g e+ mkCond [CondExpr _ g e] = g &> e+ mkCond _ = error "Desugar.expandGuards.mkCond: non-unary list"++boolGuards :: [CondExpr PredType] -> Bool+boolGuards [] = False+boolGuards (CondExpr _ g _ : es) = not (null es) || typeOf g == boolType++-- Add additional declarations to a right-hand side+addDecls :: [Decl PredType] -> Rhs PredType -> Rhs PredType+addDecls ds (SimpleRhs p li e ds') = SimpleRhs p li e (ds ++ ds')+addDecls ds (GuardedRhs spi li es ds') = GuardedRhs spi li es (ds ++ ds')++-- -----------------------------------------------------------------------------+-- Desugaring of non-linear patterns+-- -----------------------------------------------------------------------------++-- The desugaring traverses a pattern in depth-first order and collects+-- all variables. If it encounters a variable which has been previously+-- introduced, the second occurrence is changed to a fresh variable+-- and a new pair (newvar, oldvar) is saved to generate constraints later.+-- Non-linear patterns inside single functional patterns are not desugared,+-- as this special case is handled later.+dsNonLinearity :: [Pattern PredType]+ -> DsM ([Expression PredType], [Pattern PredType])+dsNonLinearity ts = do+ ((_, cs), ts') <- mapAccumM dsNonLinear (Set.empty, []) ts+ return (reverse cs, ts')++type NonLinearEnv = (Set.Set Ident, [Expression PredType])++dsNonLinear :: NonLinearEnv -> Pattern PredType+ -> DsM (NonLinearEnv, Pattern PredType)+dsNonLinear env l@(LiteralPattern _ _ _) = return (env, l)+dsNonLinear env n@(NegativePattern _ _ _) = return (env, n)+dsNonLinear env t@(VariablePattern _ _ v)+ | isAnonId v = return (env, t)+ | v `Set.member` vis = do+ v' <- freshVar "_#nonlinear" t+ return ((vis, mkStrictEquality v v' : eqs),+ uncurry (VariablePattern NoSpanInfo) v')+ | otherwise = return ((Set.insert v vis, eqs), t)+ where (vis, eqs) = env+dsNonLinear env (ConstructorPattern _ pty c ts)+ = second (ConstructorPattern NoSpanInfo pty c) <$> mapAccumM dsNonLinear env ts+dsNonLinear env (InfixPattern _ pty t1 op t2) = do+ (env1, t1') <- dsNonLinear env t1+ (env2, t2') <- dsNonLinear env1 t2+ return (env2, InfixPattern NoSpanInfo pty t1' op t2')+dsNonLinear env (ParenPattern _ t) =+ second (ParenPattern NoSpanInfo) <$> dsNonLinear env t+dsNonLinear env (RecordPattern _ pty c fs) =+ second (RecordPattern NoSpanInfo pty c)+ <$> mapAccumM (dsField dsNonLinear) env fs+dsNonLinear env (TuplePattern _ ts) =+ second (TuplePattern NoSpanInfo) <$> mapAccumM dsNonLinear env ts+dsNonLinear env (ListPattern _ pty ts) =+ second (ListPattern NoSpanInfo pty) <$> mapAccumM dsNonLinear env ts+dsNonLinear env (AsPattern _ v t) = do+ let pty = predType $ typeOf t+ (env1, pat) <- dsNonLinear env (VariablePattern NoSpanInfo pty v)+ let VariablePattern _ _ v' = pat+ (env2, t') <- dsNonLinear env1 t+ return (env2, AsPattern NoSpanInfo v' t')+dsNonLinear env (LazyPattern _ t) =+ second (LazyPattern NoSpanInfo) <$> dsNonLinear env t+dsNonLinear env fp@(FunctionPattern _ _ _ _) = dsNonLinearFuncPat env fp+dsNonLinear env fp@(InfixFuncPattern _ _ _ _ _) = dsNonLinearFuncPat env fp++dsNonLinearFuncPat :: NonLinearEnv -> Pattern PredType+ -> DsM (NonLinearEnv, Pattern PredType)+dsNonLinearFuncPat (vis, eqs) fp = do+ let fpVars = map (\(v, _, pty) -> (pty, v)) $ patternVars fp+ vs = filter ((`Set.member` vis) . snd) fpVars+ vs' <- mapM (freshVar "_#nonlinear" . uncurry (VariablePattern NoSpanInfo)) vs+ let vis' = foldr (Set.insert . snd) vis fpVars+ fp' = substPat (zip (map snd vs) (map snd vs')) fp+ return ((vis', zipWith mkStrictEquality (map snd vs) vs' ++ eqs), fp')++mkStrictEquality :: Ident -> (PredType, Ident) -> Expression PredType+mkStrictEquality x (pty, y) = mkVar pty x =:= mkVar pty y++substPat :: [(Ident, Ident)] -> Pattern a -> Pattern a+substPat _ l@(LiteralPattern _ _ _) = l+substPat _ n@(NegativePattern _ _ _) = n+substPat s (VariablePattern _ a v) =+ VariablePattern NoSpanInfo a $ fromMaybe v (lookup v s)++substPat s (ConstructorPattern _ a c ps) =+ ConstructorPattern NoSpanInfo a c $ map (substPat s) ps+substPat s (InfixPattern _ a p1 op p2) =+ InfixPattern NoSpanInfo a (substPat s p1) op (substPat s p2)+substPat s (ParenPattern _ p) =+ ParenPattern NoSpanInfo (substPat s p)+substPat s (RecordPattern _ a c fs) =+ RecordPattern NoSpanInfo a c (map substField fs)+ where substField (Field pos l pat) = Field pos l (substPat s pat)+substPat s (TuplePattern _ ps) =+ TuplePattern NoSpanInfo $ map (substPat s) ps+substPat s (ListPattern _ a ps) =+ ListPattern NoSpanInfo a $ map (substPat s) ps+substPat s (AsPattern _ v p) =+ AsPattern NoSpanInfo (fromMaybe v (lookup v s)) (substPat s p)+substPat s (LazyPattern _ p) =+ LazyPattern NoSpanInfo (substPat s p)+substPat s (FunctionPattern _ a f ps) =+ FunctionPattern NoSpanInfo a f $ map (substPat s) ps+substPat s (InfixFuncPattern _ a p1 op p2) =+ InfixFuncPattern NoSpanInfo a (substPat s p1) op (substPat s p2)++-- -----------------------------------------------------------------------------+-- Desugaring of functional patterns+-- -----------------------------------------------------------------------------++-- Desugaring of functional patterns works in the following way:+-- 1. The patterns are recursively traversed from left to right+-- to extract every functional pattern (note that functional patterns+-- can not be nested).+-- Each pattern is replaced by a fresh variable and a pair+-- (variable, functional pattern) is generated.+-- 2. The variable-pattern pairs of the form @(v, p)@ are collected and+-- transformed into additional constraints of the form @p =:<= v@,+-- where the pattern @p@ is converted to the corresponding expression.+-- In addition, any variable occurring in @p@ is declared as a fresh+-- free variable.+-- Multiple constraints will later be combined using the @&>@-operator+-- such that the patterns are evaluated from left to right.++dsFunctionalPatterns+ :: SpanInfo -> [Pattern PredType]+ -> DsM ([Decl PredType], [Expression PredType], [Pattern PredType])+dsFunctionalPatterns p ts = do+ -- extract functional patterns+ (bs, ts') <- mapAccumM elimFP [] ts+ -- generate declarations of free variables and constraints+ let (ds, cs) = genFPExpr p (concatMap patternVars ts') (reverse bs)+ -- return (declarations, constraints, desugared patterns)+ return (ds, cs, ts')++type LazyBinding = (Pattern PredType, (PredType, Ident))++elimFP :: [LazyBinding] -> Pattern PredType+ -> DsM ([LazyBinding], Pattern PredType)+elimFP bs p@(LiteralPattern _ _ _) = return (bs, p)+elimFP bs p@(NegativePattern _ _ _) = return (bs, p)+elimFP bs p@(VariablePattern _ _ _) = return (bs, p)+elimFP bs (ConstructorPattern _ pty c ts) =+ second (ConstructorPattern NoSpanInfo pty c) <$> mapAccumM elimFP bs ts+elimFP bs (InfixPattern _ pty t1 op t2) = do+ (bs1, t1') <- elimFP bs t1+ (bs2, t2') <- elimFP bs1 t2+ return (bs2, InfixPattern NoSpanInfo pty t1' op t2')+elimFP bs (ParenPattern _ t) =+ second (ParenPattern NoSpanInfo) <$> elimFP bs t+elimFP bs (RecordPattern _ pty c fs) =+ second (RecordPattern NoSpanInfo pty c) <$> mapAccumM (dsField elimFP) bs fs+elimFP bs (TuplePattern _ ts) =+ second (TuplePattern NoSpanInfo) <$> mapAccumM elimFP bs ts+elimFP bs (ListPattern _ pty ts) =+ second (ListPattern NoSpanInfo pty) <$> mapAccumM elimFP bs ts+elimFP bs (AsPattern _ v t) =+ second (AsPattern NoSpanInfo v) <$> elimFP bs t+elimFP bs (LazyPattern _ t) =+ second (LazyPattern NoSpanInfo) <$> elimFP bs t+elimFP bs p@(FunctionPattern _ _ _ _) = do+ (pty, v) <- freshVar "_#funpatt" p+ return ((p, (pty, v)) : bs, VariablePattern NoSpanInfo pty v)+elimFP bs p@(InfixFuncPattern _ _ _ _ _) = do+ (pty, v) <- freshVar "_#funpatt" p+ return ((p, (pty, v)) : bs, VariablePattern NoSpanInfo pty v)++genFPExpr :: SpanInfo -> [(Ident, Int, PredType)] -> [LazyBinding]+ -> ([Decl PredType], [Expression PredType])+genFPExpr p vs bs+ | null bs = ([] , [])+ | null free = ([] , cs)+ | otherwise = ([FreeDecl p (map (\(v, _, pty) -> Var pty v) free)], cs)+ where+ mkLB (t, (pty, v)) = let (t', es) = fp2Expr t+ in (t' =:<= mkVar pty v) : es+ cs = concatMap mkLB bs+ free = nub $ filter (not . isAnonId . fst3) $+ concatMap patternVars (map fst bs) \\ vs++fp2Expr :: Pattern PredType -> (Expression PredType, [Expression PredType])+fp2Expr (LiteralPattern _ pty l) = (Literal NoSpanInfo pty l, [])+fp2Expr (NegativePattern _ pty l) =+ (Literal NoSpanInfo pty (negateLiteral l), [])+fp2Expr (VariablePattern _ pty v) = (mkVar pty v, [])+fp2Expr (ConstructorPattern _ pty c ts) =+ let (ts', ess) = unzip $ map fp2Expr ts+ pty' = predType $ foldr TypeArrow (unpredType pty) $ map typeOf ts+ in (apply (Constructor NoSpanInfo pty' c) ts', concat ess)+fp2Expr (InfixPattern _ pty t1 op t2) =+ let (t1', es1) = fp2Expr t1+ (t2', es2) = fp2Expr t2+ pty' = predType $ foldr TypeArrow (unpredType pty) [typeOf t1, typeOf t2]+ in (InfixApply NoSpanInfo t1' (InfixConstr pty' op) t2', es1 ++ es2)+fp2Expr (ParenPattern _ t) = first (Paren NoSpanInfo) (fp2Expr t)+fp2Expr (TuplePattern _ ts) =+ let (ts', ess) = unzip $ map fp2Expr ts+ in (Tuple NoSpanInfo ts', concat ess)+fp2Expr (ListPattern _ pty ts) =+ let (ts', ess) = unzip $ map fp2Expr ts+ in (List NoSpanInfo pty ts', concat ess)+fp2Expr (FunctionPattern _ pty f ts) =+ let (ts', ess) = unzip $ map fp2Expr ts+ pty' = predType $ foldr TypeArrow (unpredType pty) $ map typeOf ts+ in (apply (Variable NoSpanInfo pty' f) ts', concat ess)+fp2Expr (InfixFuncPattern _ pty t1 op t2) =+ let (t1', es1) = fp2Expr t1+ (t2', es2) = fp2Expr t2+ pty' = predType $ foldr TypeArrow (unpredType pty) $ map typeOf [t1, t2]+ in (InfixApply NoSpanInfo t1' (InfixOp pty' op) t2', es1 ++ es2)+fp2Expr (AsPattern _ v t) =+ let (t', es) = fp2Expr t+ pty = predType $ typeOf t+ in (mkVar pty v, (t' =:<= mkVar pty v) : es)+fp2Expr (RecordPattern _ pty c fs) =+ let (fs', ess) = unzip [ (Field p f e, es) | Field p f t <- fs+ , let (e, es) = fp2Expr t]+ in (Record NoSpanInfo pty c fs', concat ess)+fp2Expr t = internalError $+ "Desugar.fp2Expr: Unexpected constructor term: " ++ show t++-- -----------------------------------------------------------------------------+-- Desugaring of ordinary patterns+-- -----------------------------------------------------------------------------++-- The transformation of patterns is straight forward except for lazy+-- patterns. A lazy pattern '~t' is replaced by a fresh+-- variable 'v' and a new local declaration 't = v' in the+-- scope of the pattern. In addition, as-patterns 'v@t' where+-- 't' is a variable or an as-pattern are replaced by 't' in combination+-- with a local declaration for 'v'.++-- Record patterns are transformed into normal constructor patterns by+-- rearranging fields in the order of the record's declaration, adding+-- fresh variables in place of omitted fields, and discarding the field+-- labels.++-- Note: By rearranging fields here we loose the ability to comply+-- strictly with the Haskell 98 pattern matching semantics, which matches+-- fields of a record pattern in the order of their occurrence in the+-- pattern. However, keep in mind that Haskell matches alternatives from+-- top to bottom and arguments within an equation or alternative from+-- left to right, which is not the case in Curry except for rigid case+-- expressions.++dsLiteralPat :: PredType -> Literal+ -> Either (Pattern PredType) (Pattern PredType)+dsLiteralPat pty c@(Char _) = Right (LiteralPattern NoSpanInfo pty c)+dsLiteralPat pty (Int i) =+ Right (LiteralPattern NoSpanInfo pty (fixLiteral (unpredType pty)))+ where fixLiteral (TypeConstrained tys _) = fixLiteral (head tys)+ fixLiteral ty+ | ty == floatType = Float $ fromInteger i+ | otherwise = Int i+dsLiteralPat pty f@(Float _) = Right (LiteralPattern NoSpanInfo pty f)+dsLiteralPat pty (String cs) =+ Left $ ListPattern NoSpanInfo pty $+ map (LiteralPattern NoSpanInfo pty' . Char) cs+ where pty' = predType $ elemType $ unpredType pty++dsPat :: SpanInfo -> [Decl PredType] -> Pattern PredType+ -> DsM ([Decl PredType], Pattern PredType)+dsPat _ ds v@(VariablePattern _ _ _) = return (ds, v)+dsPat p ds (LiteralPattern _ pty l) =+ either (dsPat p ds) (return . (,) ds) (dsLiteralPat pty l)+dsPat p ds (NegativePattern _ pty l) =+ dsPat p ds (LiteralPattern NoSpanInfo pty (negateLiteral l))+dsPat p ds (ConstructorPattern _ pty c ts) =+ second (ConstructorPattern NoSpanInfo pty c) <$> mapAccumM (dsPat p) ds ts+dsPat p ds (InfixPattern _ pty t1 op t2) =+ dsPat p ds (ConstructorPattern NoSpanInfo pty op [t1, t2])+dsPat p ds (ParenPattern _ t) = dsPat p ds t+dsPat p ds (RecordPattern _ pty c fs) = do+ vEnv <- getValueEnv+ --TODO: Rework+ let (ls, tys) = argumentTypes (unpredType pty) c vEnv+ tsMap = map field2Tuple fs+ anonTs <- mapM ((uncurry (VariablePattern NoSpanInfo) <$>) .+ freshVar "_#recpat") tys+ let maybeTs = map (flip lookup tsMap) ls+ ts = zipWith fromMaybe anonTs maybeTs+ dsPat p ds (ConstructorPattern NoSpanInfo pty c ts)+dsPat p ds (TuplePattern _ ts) =+ dsPat p ds (ConstructorPattern NoSpanInfo pty (qTupleId $ length ts) ts)+ where pty = predType (tupleType (map typeOf ts))+dsPat p ds (ListPattern _ pty ts) =+ second (dsList cons nil) <$> mapAccumM (dsPat p) ds ts+ where nil = ConstructorPattern NoSpanInfo pty qNilId []+ cons t ts' = ConstructorPattern NoSpanInfo pty qConsId [t, ts']+dsPat p ds (AsPattern _ v t) = dsAs p v <$> dsPat p ds t+dsPat p ds (LazyPattern _ t) = dsLazy p ds t+dsPat p ds (FunctionPattern _ pty f ts) =+ second (FunctionPattern NoSpanInfo pty f) <$> mapAccumM (dsPat p) ds ts+dsPat p ds (InfixFuncPattern _ pty t1 f t2) =+ dsPat p ds (FunctionPattern NoSpanInfo pty f [t1, t2])++dsAs :: SpanInfo -> Ident -> ([Decl PredType], Pattern PredType)+ -> ([Decl PredType], Pattern PredType)+dsAs p v (ds, t) = case t of+ VariablePattern _ pty v' -> (varDecl p pty v (mkVar pty v') : ds,t)+ AsPattern _ v' t' -> (varDecl p pty' v (mkVar pty' v') : ds,t)+ where pty' = predType $ typeOf t'+ _ -> (ds, AsPattern NoSpanInfo v t)++dsLazy :: SpanInfo -> [Decl PredType] -> Pattern PredType+ -> DsM ([Decl PredType], Pattern PredType)+dsLazy p ds t = case t of+ VariablePattern _ _ _ -> return (ds, t)+ ParenPattern _ t' -> dsLazy p ds t'+ AsPattern _ v t' -> dsAs p v <$> dsLazy p ds t'+ LazyPattern _ t' -> dsLazy p ds t'+ _ -> do+ (pty, v') <- freshVar "_#lazy" t+ return (patDecl NoSpanInfo t (mkVar pty v') : ds,+ VariablePattern NoSpanInfo pty v')++{-+-- -----------------------------------------------------------------------------+-- Desugaring of expressions+-- -----------------------------------------------------------------------------++-- Record construction expressions are transformed into normal+-- constructor applications by rearranging fields in the order of the+-- record's declaration, passing `Prelude.unknown` in place of+-- omitted fields, and discarding the field labels. The transformation of+-- record update expressions is a bit more involved as we must match the+-- updated expression with all valid constructors of the expression's+-- type. As stipulated by the Haskell 98 Report, a record update+-- expression @e { l_1 = e_1, ..., l_k = e_k }@ succeeds only if @e@ reduces to+-- a value @C e'_1 ... e'_n@ such that @C@'s declaration contains all+-- field labels @l_1,...,l_k@. In contrast to Haskell, we do not report+-- an error if this is not the case, but call failed instead.+-}+dsExpr :: SpanInfo -> Expression PredType -> DsM (Expression PredType)+dsExpr p (Literal _ pty l) =+ either (dsExpr p) return (dsLiteral pty l)+dsExpr _ var@(Variable _ pty v)+ | isAnonId (unqualify v) = return $ prelUnknown $ unpredType pty+ | otherwise = return var+dsExpr _ c@(Constructor _ _ _) = return c+dsExpr p (Paren _ e) = dsExpr p e+dsExpr p (Typed _ e qty) = Typed NoSpanInfo+ <$> dsExpr p e <*> dsQualTypeExpr qty+dsExpr p (Record _ pty c fs) = do+ vEnv <- getValueEnv+ --TODO: Rework+ let (ls, tys) = argumentTypes (unpredType pty) c vEnv+ esMap = map field2Tuple fs+ unknownEs = map prelUnknown tys+ maybeEs = map (flip lookup esMap) ls+ es = zipWith fromMaybe unknownEs maybeEs+ dsExpr p (applyConstr pty c tys es)+dsExpr p (RecordUpdate _ e fs) = do+ alts <- constructors tc >>= concatMapM updateAlt+ dsExpr p $ mkCase Flex e (map (uncurry (caseAlt p)) alts)+ where ty = typeOf e+ pty = predType ty+ tc = rootOfType (arrowBase ty)+ updateAlt (RecordConstr c ls _)+ | all (`elem` qls2) (map fieldLabel fs)= do+ let qc = qualifyLike tc c+ vEnv <- getValueEnv+ let (qls, tys) = argumentTypes ty qc vEnv+ vs <- mapM (freshVar "_#rec") tys+ let pat = constrPattern pty qc vs+ esMap = map field2Tuple fs+ originalEs = map (uncurry mkVar) vs+ maybeEs = map (flip lookup esMap) qls+ es = zipWith fromMaybe originalEs maybeEs+ return [(pat, applyConstr pty qc tys es)]+ where qls2 = map (qualifyLike tc) ls+ updateAlt _ = return []+dsExpr p (Tuple _ es) =+ apply (Constructor NoSpanInfo pty $ qTupleId $ length es)+ <$> mapM (dsExpr p) es+ where pty = predType (foldr TypeArrow (tupleType tys) tys)+ tys = map typeOf es+dsExpr p (List _ pty es) = dsList cons nil <$> mapM (dsExpr p) es+ where nil = Constructor NoSpanInfo pty qNilId+ cons = (Apply NoSpanInfo) . (Apply NoSpanInfo)+ (Constructor NoSpanInfo+ (predType $ consType $ elemType $ unpredType pty) qConsId)+dsExpr p (ListCompr _ e qs) = dsListComp p e qs+dsExpr p (EnumFrom _ e) =+ Apply NoSpanInfo (prelEnumFrom (typeOf e)) <$> dsExpr p e+dsExpr p (EnumFromThen _ e1 e2) =+ apply (prelEnumFromThen (typeOf e1)) <$> mapM (dsExpr p) [e1, e2]+dsExpr p (EnumFromTo _ e1 e2) = apply (prelEnumFromTo (typeOf e1))+ <$> mapM (dsExpr p) [e1, e2]+dsExpr p (EnumFromThenTo _ e1 e2 e3) = apply (prelEnumFromThenTo (typeOf e1))+ <$> mapM (dsExpr p) [e1, e2, e3]+dsExpr p (UnaryMinus _ e) = do+ e' <- dsExpr p e+ negativeLitsEnabled <- checkNegativeLitsExtension+ return $ case e' of+ Literal _ pty l | negativeLitsEnabled ->+ Literal NoSpanInfo pty $ negateLiteral l+ _ ->+ Apply NoSpanInfo (prelNegate $ typeOf e') e'+dsExpr p (Apply _ e1 e2) = Apply NoSpanInfo <$> dsExpr p e1 <*> dsExpr p e2+dsExpr p (InfixApply _ e1 op e2) = do+ op' <- dsExpr p (infixOp op)+ e1' <- dsExpr p e1+ e2' <- dsExpr p e2+ return $ apply op' [e1', e2']+dsExpr p (LeftSection _ e op) =+ Apply NoSpanInfo <$> dsExpr p (infixOp op) <*> dsExpr p e+dsExpr p (RightSection _ op e) = do+ op' <- dsExpr p (infixOp op)+ e' <- dsExpr p e+ return $ apply (prelFlip ty1 ty2 ty3) [op', e']+ where TypeArrow ty1 (TypeArrow ty2 ty3) = typeOf (infixOp op)+dsExpr p expr@(Lambda _ ts e) = do+ (pty, f) <- freshVar "_#lambda" expr+ dsExpr p $ mkLet [funDecl p pty f ts e] $ mkVar pty f+dsExpr p (Let _ _ ds e) = do+ ds' <- dsDeclGroup ds+ e' <- dsExpr p e+ return $ mkLet ds' e'+dsExpr p (Do _ _ sts e) = dsDo sts e >>= dsExpr p+dsExpr p (IfThenElse _ e1 e2 e3) = do+ e1' <- dsExpr p e1+ e2' <- dsExpr p e2+ e3' <- dsExpr p e3+ return $ mkCase Rigid e1'+ [caseAlt p truePat e2', caseAlt p falsePat e3']+dsExpr p (Case _ _ ct e alts) = dsCase p ct e alts++-- We ignore the context in the type signature of a typed expression, since+-- there should be no possibility to provide an non-empty context without+-- scoped type-variables.+-- TODO: Verify++dsQualTypeExpr :: QualTypeExpr -> DsM QualTypeExpr+dsQualTypeExpr (QualTypeExpr _ cx ty) =+ QualTypeExpr NoSpanInfo cx <$> dsTypeExpr ty++dsTypeExpr :: TypeExpr -> DsM TypeExpr+dsTypeExpr ty = do+ m <- getModuleIdent+ tcEnv <- getTyConsEnv+ let tvs = typeVariables ty+ return $ fromType tvs $ expandType m tcEnv $ toType tvs ty++-- -----------------------------------------------------------------------------+-- Desugaring of case expressions+-- -----------------------------------------------------------------------------++-- If an alternative in a case expression has boolean guards and all of+-- these guards return 'False', the enclosing case expression does+-- not fail but continues to match the remaining alternatives against the+-- selector expression. In order to implement this semantics, which is+-- compatible with Haskell, we expand an alternative with boolean guards+-- such that it evaluates a case expression with the remaining cases that+-- are compatible with the matched pattern when the guards fail.++dsCase :: SpanInfo -> CaseType -> Expression PredType -> [Alt PredType]+ -> DsM (Expression PredType)+dsCase p ct e alts+ | null alts = internalError "Desugar.dsCase: empty list of alternatives"+ | otherwise = do+ m <- getModuleIdent+ e' <- dsExpr p e+ v <- freshVar "_#case" e+ alts' <- mapM dsAltLhs alts+ alts'' <- mapM (expandAlt v ct) (init (tails alts')) >>= mapM dsAltRhs+ return (mkMyCase m v e' alts'')+ where+ mkMyCase m (pty, v) e' bs+ | v `elem` qfv m bs = mkLet [varDecl p pty v e']+ (mkCase ct (mkVar pty v) bs)+ | otherwise = mkCase ct e' bs++dsAltLhs :: Alt PredType -> DsM (Alt PredType)+dsAltLhs (Alt p t rhs) = do+ (ds', t') <- dsPat p [] t+ return $ Alt p t' (addDecls ds' rhs)++dsAltRhs :: Alt PredType -> DsM (Alt PredType)+dsAltRhs (Alt p t rhs) = Alt p t <$> dsRhs id rhs++expandAlt :: (PredType, Ident) -> CaseType -> [Alt PredType]+ -> DsM (Alt PredType)+expandAlt _ _ [] = error "Desugar.expandAlt: empty list"+expandAlt v ct (Alt p t rhs : alts) = caseAlt p t <$> expandRhs e0 id rhs+ where+ e0 | ct == Flex || null compAlts = prelFailed (typeOf rhs)+ | otherwise = mkCase ct (uncurry mkVar v) compAlts+ compAlts = filter (isCompatible t . altPattern) alts+ altPattern (Alt _ t1 _) = t1++isCompatible :: Pattern a -> Pattern a -> Bool+isCompatible (VariablePattern _ _ _) _ = True+isCompatible _ (VariablePattern _ _ _) = True+isCompatible (AsPattern _ _ t1) t2 = isCompatible t1 t2+isCompatible t1 (AsPattern _ _ t2) = isCompatible t1 t2+isCompatible (ConstructorPattern _ _ c1 ts1) (ConstructorPattern _ _ c2 ts2)+ = and ((c1 == c2) : zipWith isCompatible ts1 ts2)+isCompatible (LiteralPattern _ _ l1) (LiteralPattern _ _ l2) = l1 == l2+isCompatible _ _ = False++-- -----------------------------------------------------------------------------+-- Desugaring of do-Notation+-- -----------------------------------------------------------------------------++-- The do-notation is desugared in the following way:+--+-- `dsDo([] , e)` -> `e`+-- `dsDo(e' ; ss, e)` -> `e' >> dsDo(ss, e)`+-- `dsDo(p <- e'; ss, e)` -> `e' >>= \v -> case v of+-- p -> dsDo(ss, e)+-- _ -> fail "..."`+-- `dsDo(let ds ; ss, e)` -> `let ds in dsDo(ss, e)`+dsDo :: [Statement PredType] -> Expression PredType -> DsM (Expression PredType)+dsDo sts e = foldrM dsStmt e sts++dsStmt :: Statement PredType -> Expression PredType -> DsM (Expression PredType)+dsStmt (StmtExpr _ e1) e' =+ return $ apply (prelBind_ (typeOf e1) (typeOf e')) [e1, e']+dsStmt (StmtBind _ t e1) e' = do+ v <- freshVar "_#var" t+ failable <- checkFailableBind t+ let func = mkLambda [uncurry (VariablePattern NoSpanInfo) v] $+ mkCase Rigid (uncurry mkVar v) $+ caseAlt NoSpanInfo t e' :+ if failable+ then [caseAlt NoSpanInfo+ (uncurry (VariablePattern NoSpanInfo) v)+ (failedPatternMatch $ typeOf e')]+ else []+ return $ apply (prelBind (typeOf e1) (typeOf t) (typeOf e')) [e1, func]+ where failedPatternMatch ty =+ apply (prelFail ty)+ [Literal NoSpanInfo predStringType $ String "Pattern match failed!"]+dsStmt (StmtDecl _ _ ds) e' = return $ mkLet ds e'++checkFailableBind :: Pattern a -> DsM Bool+checkFailableBind (ConstructorPattern _ _ idt ps ) = do+ tcEnv <- getTyConsEnv+ case qualLookupTypeInfo idt tcEnv of+ [RenamingType _ _ _ ] -> or <$> mapM checkFailableBind ps -- or [] == False+ [DataType _ _ cs]+ | length cs == 1 -> or <$> mapM checkFailableBind ps+ | otherwise -> return True+ _ -> return True+checkFailableBind (InfixPattern _ _ p1 idt p2) = do+ tcEnv <- getTyConsEnv+ case qualLookupTypeInfo idt tcEnv of+ [RenamingType _ _ _ ] -> (||) <$> checkFailableBind p1+ <*> checkFailableBind p2+ [DataType _ _ cs]+ | length cs == 1 -> (||) <$> checkFailableBind p1+ <*> checkFailableBind p2+ | otherwise -> return True+ _ -> return True+checkFailableBind (RecordPattern _ _ idt fs ) = do+ tcEnv <- getTyConsEnv+ case qualLookupTypeInfo idt tcEnv of+ [RenamingType _ _ _ ] -> or <$> mapM (checkFailableBind . fieldContent) fs+ [DataType _ _ cs]+ | length cs == 1 -> or <$> mapM (checkFailableBind . fieldContent) fs+ | otherwise -> return True+ _ -> return True+ where fieldContent (Field _ _ c) = c+checkFailableBind (TuplePattern _ ps ) =+ or <$> mapM checkFailableBind ps+checkFailableBind (AsPattern _ _ p ) = checkFailableBind p+checkFailableBind (ParenPattern _ p ) = checkFailableBind p+checkFailableBind (LazyPattern _ _ ) = return False+checkFailableBind (VariablePattern _ _ _ ) = return False+checkFailableBind _ = return True+-- -----------------------------------------------------------------------------+-- Desugaring of List Comprehensions+-- -----------------------------------------------------------------------------++-- In general, a list comprehension of the form+-- '[e | t <- l, qs]'+-- is transformed into an expression 'foldr f [] l' where 'f'+-- is a new function defined as+--+-- f x xs =+-- case x of+-- t -> [e | qs] ++ xs+-- _ -> xs+--+-- Note that this translation evaluates the elements of 'l' rigidly,+-- whereas the translation given in the Curry report is flexible.+-- However, it does not seem very useful to have the comprehension+-- generate instances of 't' which do not contribute to the list.+-- TODO: Unfortunately, this is incorrect.++-- Actually, we generate slightly better code in a few special cases.+-- When 't' is a plain variable, the 'case' expression degenerates+-- into a let-binding and the auxiliary function thus becomes an alias+-- for '(++)'. Instead of 'foldr (++)' we use the+-- equivalent prelude function 'concatMap'. In addition, if the+-- remaining list comprehension in the body of the auxiliary function has+-- no qualifiers -- i.e., if it is equivalent to '[e]' -- we+-- avoid the construction of the singleton list by calling '(:)'+-- instead of '(++)' and 'map' in place of 'concatMap', respectively.++dsListComp :: SpanInfo -> Expression PredType -> [Statement PredType]+ -> DsM (Expression PredType)+dsListComp p e [] =+ dsExpr p (List NoSpanInfo (predType $ listType $ typeOf e) [e])+dsListComp p e (q:qs) = dsQual p q (ListCompr NoSpanInfo e qs)++dsQual :: SpanInfo -> Statement PredType -> Expression PredType+ -> DsM (Expression PredType)+dsQual p (StmtExpr _ b) e =+ dsExpr p (IfThenElse NoSpanInfo b e (List NoSpanInfo (predType $ typeOf e) []))+dsQual p (StmtDecl _ _ ds) e = dsExpr p (mkLet ds e)+dsQual p (StmtBind _ t l) e+ | isVariablePattern t = dsExpr p (qualExpr t e l)+ | otherwise = do+ v <- freshVar "_#var" t+ l' <- freshVar "_#var" e+ dsExpr p (apply (prelFoldr (typeOf t) (typeOf e))+ [foldFunct v l' e, List NoSpanInfo (predType $ typeOf e) [], l])+ where+ qualExpr v (ListCompr NoSpanInfo e1 []) l1+ = apply (prelMap (typeOf v) (typeOf e1)) [mkLambda [v] e1, l1]+ qualExpr v e1 l1+ = apply (prelConcatMap (typeOf v) (elemType $ typeOf e1))+ [mkLambda [v] e1, l1]+ foldFunct v l1 e1+ = mkLambda (map (uncurry (VariablePattern NoSpanInfo)) [v, l1])+ (mkCase Rigid (uncurry mkVar v)+ [ caseAlt p t (append e1 (uncurry mkVar l1))+ , caseAlt p (uncurry (VariablePattern NoSpanInfo) v)+ (uncurry mkVar l1)])++ append (ListCompr _ e1 []) l1 = apply (prelCons (typeOf e1)) [e1, l1]+ append e1 l1 =+ apply (prelAppend (elemType $ typeOf e1)) [e1, l1]+ prelCons ty =+ Constructor NoSpanInfo (predType $ consType ty) $ qConsId++-- -----------------------------------------------------------------------------+-- Desugaring of Lists, labels, fields, and literals+-- -----------------------------------------------------------------------------++dsList :: (b -> b -> b) -> b -> [b] -> b+dsList = foldr++--dsLabel :: a -> [(QualIdent, a)] -> QualIdent -> a+--dsLabel def fs l = fromMaybe def (lookup l fs)++dsField :: (a -> b -> DsM (a, b)) -> a -> Field b -> DsM (a, Field b)+dsField ds z (Field p l x) = second (Field p l) <$> ds z x++dsLiteral :: PredType -> Literal+ -> Either (Expression PredType) (Expression PredType)+dsLiteral pty (Char c) = Right $ Literal NoSpanInfo pty $ Char c+dsLiteral pty (Int i) = Right $ fixLiteral (unpredType pty)+ where fixLiteral (TypeConstrained tys _) = fixLiteral (head tys)+ fixLiteral ty+ | ty == intType = Literal NoSpanInfo pty $ Int i+ | ty == floatType = Literal NoSpanInfo pty $ Float $ fromInteger i+ | otherwise = Apply NoSpanInfo (prelFromInt $ unpredType pty) $+ Literal NoSpanInfo predIntType $ Int i+dsLiteral pty f@(Float _) = Right $ fixLiteral (unpredType pty)+ where fixLiteral (TypeConstrained tys _) = fixLiteral (head tys)+ fixLiteral ty+ | ty == floatType = Literal NoSpanInfo pty f+ | otherwise = Apply NoSpanInfo (prelFromFloat $ unpredType pty) $+ Literal NoSpanInfo predFloatType f+dsLiteral pty (String cs) =+ Left $ List NoSpanInfo pty $ map (Literal NoSpanInfo pty' . Char) cs+ where pty' = predType $ elemType $ unpredType pty++negateLiteral :: Literal -> Literal+negateLiteral (Int i) = Int (-i)+negateLiteral (Float f) = Float (-f)+negateLiteral _ = internalError "Desugar.negateLiteral"++-- ---------------------------------------------------------------------------+-- Prelude entities+-- ---------------------------------------------------------------------------++preludeFun :: [Type] -> Type -> String -> Expression PredType+preludeFun tys ty = Variable NoSpanInfo (predType $ foldr TypeArrow ty tys)+ . preludeIdent++preludeIdent :: String -> QualIdent+preludeIdent = qualifyWith preludeMIdent . mkIdent++prelBind :: Type -> Type -> Type -> Expression PredType+prelBind ma a mb = preludeFun [ma, TypeArrow a mb] mb ">>="++prelBind_ :: Type -> Type -> Expression PredType+prelBind_ ma mb = preludeFun [ma, mb] mb ">>"++prelFlip :: Type -> Type -> Type -> Expression PredType+prelFlip a b c = preludeFun [TypeArrow a (TypeArrow b c), b, a] c "flip"++prelFromInt :: Type -> Expression PredType+prelFromInt a = preludeFun [intType] a "fromInt"++prelFromFloat :: Type -> Expression PredType+prelFromFloat a = preludeFun [floatType] a "fromFloat"++prelEnumFrom :: Type -> Expression PredType+prelEnumFrom a = preludeFun [a] (listType a) "enumFrom"++prelEnumFromTo :: Type -> Expression PredType+prelEnumFromTo a = preludeFun [a, a] (listType a) "enumFromTo"++prelEnumFromThen :: Type -> Expression PredType+prelEnumFromThen a = preludeFun [a, a] (listType a) "enumFromThen"++prelEnumFromThenTo :: Type -> Expression PredType+prelEnumFromThenTo a = preludeFun [a, a, a] (listType a) "enumFromThenTo"++prelNegate :: Type -> Expression PredType+prelNegate a = preludeFun [a] a "negate"++prelFail :: Type -> Expression PredType+prelFail ma = preludeFun [stringType] ma "fail"++prelFailed :: Type -> Expression PredType+prelFailed a = preludeFun [] a "failed"++prelUnknown :: Type -> Expression PredType+prelUnknown a = preludeFun [] a "unknown"++prelMap :: Type -> Type -> Expression PredType+prelMap a b = preludeFun [TypeArrow a b, listType a] (listType b) "map"++prelFoldr :: Type -> Type -> Expression PredType+prelFoldr a b =+ preludeFun [TypeArrow a (TypeArrow b b), b, listType a] b "foldr"++prelAppend :: Type -> Expression PredType+prelAppend a = preludeFun [listType a, listType a] (listType a) "++"++prelConcatMap :: Type -> Type -> Expression PredType+prelConcatMap a b =+ preludeFun [TypeArrow a (listType b), listType a] (listType b) "concatMap"++(=:<=) :: Expression PredType -> Expression PredType -> Expression PredType+e1 =:<= e2 = apply (preludeFun [typeOf e1, typeOf e2] boolType "=:<=") [e1, e2]++(=:=) :: Expression PredType -> Expression PredType -> Expression PredType+e1 =:= e2 = apply (preludeFun [typeOf e1, typeOf e2] boolType "=:=") [e1, e2]++(&>) :: Expression PredType -> Expression PredType -> Expression PredType+e1 &> e2 = apply (preludeFun [boolType, typeOf e2] (typeOf e2) "cond") [e1, e2]++(&) :: Expression PredType -> Expression PredType -> Expression PredType+e1 & e2 = apply (preludeFun [boolType, boolType] boolType "&") [e1, e2]++truePat :: Pattern PredType+truePat = ConstructorPattern NoSpanInfo predBoolType qTrueId []++falsePat :: Pattern PredType+falsePat = ConstructorPattern NoSpanInfo predBoolType qFalseId []++-- ---------------------------------------------------------------------------+-- Auxiliary definitions+-- ---------------------------------------------------------------------------++conType :: QualIdent -> ValueEnv -> ([Ident], TypeScheme)+conType c vEnv = case qualLookupValue c vEnv of+ [DataConstructor _ _ ls ty] -> (ls , ty)+ [NewtypeConstructor _ l ty] -> ([l], ty)+ _ -> internalError $ "Desguar.conType: " ++ show c++varType :: QualIdent -> ValueEnv -> TypeScheme+varType v vEnv = case qualLookupValue v vEnv of+ Value _ _ _ tySc : _ -> tySc+ Label _ _ tySc : _ -> tySc+ _ -> internalError $ "Desugar.varType: " ++ show v++elemType :: Type -> Type+elemType (TypeApply (TypeConstructor tc) ty) | tc == qListId = ty+elemType ty = internalError $ "Base.Types.elemType " ++ show ty++applyConstr :: PredType -> QualIdent -> [Type] -> [Expression PredType]+ -> Expression PredType+applyConstr pty c tys =+ apply (Constructor NoSpanInfo+ (predType (foldr TypeArrow (unpredType pty) tys)) c)++-- The function 'instType' instantiates the universally quantified+-- type variables of a type scheme with fresh type variables. Since this+-- function is used only to instantiate the closed types of record+-- constructors (recall that no existentially quantified type+-- variables are allowed for records), the compiler can reuse the same+-- monomorphic type variables for every instantiated type.++instType :: TypeScheme -> Type+instType (ForAll _ pty) = inst $ unpredType pty+ where inst (TypeConstructor tc) = TypeConstructor tc+ inst (TypeApply ty1 ty2) = TypeApply (inst ty1) (inst ty2)+ inst (TypeVariable tv) = TypeVariable (-1 - tv)+ inst (TypeArrow ty1 ty2) = TypeArrow (inst ty1) (inst ty2)+ inst ty = ty++-- Retrieve all constructors of a type+constructors :: QualIdent -> DsM [DataConstr]+constructors tc = getTyConsEnv >>= \tcEnv -> return $+ case qualLookupTypeInfo tc tcEnv of+ [DataType _ _ cs] -> cs+ [RenamingType _ _ nc] -> [nc]+ _ ->+ internalError $ "Transformations.Desugar.constructors: " ++ show tc++-- The function 'argumentTypes' returns the labels and the argument types+-- of a data constructor instantiated at a particular type.++argumentTypes :: Type -> QualIdent -> ValueEnv -> ([QualIdent], [Type])+argumentTypes ty c vEnv =+ (map (qualifyLike c) ls, map (subst (matchType ty0 ty idSubst)) tys)+ where (ls, ForAll _ (PredType _ ty')) = conType c vEnv+ (tys, ty0) = arrowUnapply ty'
+ src/Transformations/Dictionary.hs view
@@ -0,0 +1,1143 @@+{- |+ Module : $Header$+ Description : Dictionary insertion+ Copyright : (c) 2016 - 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ TODO+-}++{-# LANGUAGE CPP #-}+module Transformations.Dictionary+ ( insertDicts+ , dictTypeId, qDictTypeId, dictConstrId, qDictConstrId+ , defaultMethodId, qDefaultMethodId, superDictStubId, qSuperDictStubId+ , instFunId, qInstFunId, implMethodId, qImplMethodId+ ) where++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative ((<$>), (<*>))+import Data.Traversable (traverse)+#endif+import Control.Monad.Extra ( concatMapM, liftM, maybeM, when+ , zipWithM )+import qualified Control.Monad.State as S (State, runState, gets, modify)++import Data.List (inits, nub, partition, tails, zipWith4)+import qualified Data.Map as Map ( Map, empty, insert, lookup, mapWithKey+ , toList )+import Data.Maybe (fromMaybe, isJust)+import qualified Data.Set as Set ( deleteMin, fromList, null, size, toAscList+ , toList, union )++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Base.SpanInfo+import Curry.Syntax++import Base.CurryTypes+import Base.Expr+import Base.Kinds+import Base.Messages (internalError)+import Base.TopEnv+import Base.Types+import Base.TypeSubst+import Base.Typing++import Env.Class+import Env.Instance+import Env.Interface+import Env.OpPrec+import Env.TypeConstructor+import Env.Value++data DTState = DTState+ { moduleIdent :: ModuleIdent+ , tyConsEnv :: TCEnv+ , valueEnv :: ValueEnv+ , classEnv :: ClassEnv+ , instEnv :: InstEnv+ , opPrecEnv :: OpPrecEnv+ , dictEnv :: DictEnv -- for dictionary insertion+ , specEnv :: SpecEnv -- for dictionary specialization+ , nextId :: Integer+ }++type DTM = S.State DTState++insertDicts :: Bool -> InterfaceEnv -> TCEnv -> ValueEnv -> ClassEnv+ -> InstEnv -> OpPrecEnv -> Module PredType+ -> (Module Type, InterfaceEnv, TCEnv, ValueEnv, OpPrecEnv)+insertDicts inlDi intfEnv tcEnv vEnv clsEnv inEnv pEnv mdl@(Module _ _ _ m _ _ _) =+ (mdl', intfEnv', tcEnv', vEnv', pEnv')+ where initState =+ DTState m tcEnv vEnv clsEnv inEnv pEnv emptyDictEnv emptySpEnv 1+ (mdl', tcEnv', vEnv', pEnv') =+ runDTM (dictTrans mdl >>= (if inlDi then specialize else return) >>= cleanup) initState+ intfEnv' = dictTransInterfaces vEnv' clsEnv intfEnv++runDTM :: DTM a -> DTState -> (a, TCEnv, ValueEnv, OpPrecEnv)+runDTM dtm s =+ let (a, s') = S.runState dtm s in (a, tyConsEnv s', valueEnv s', opPrecEnv s')++getModuleIdent :: DTM ModuleIdent+getModuleIdent = S.gets moduleIdent++getTyConsEnv :: DTM TCEnv+getTyConsEnv = S.gets tyConsEnv++modifyTyConsEnv :: (TCEnv -> TCEnv) -> DTM ()+modifyTyConsEnv f = S.modify $ \s -> s { tyConsEnv = f $ tyConsEnv s }++getValueEnv :: DTM ValueEnv+getValueEnv = S.gets valueEnv++modifyValueEnv :: (ValueEnv -> ValueEnv) -> DTM ()+modifyValueEnv f = S.modify $ \s -> s { valueEnv = f $ valueEnv s }++withLocalValueEnv :: DTM a -> DTM a+withLocalValueEnv act = do+ oldEnv <- getValueEnv+ res <- act+ modifyValueEnv $ const oldEnv+ return res++getClassEnv :: DTM ClassEnv+getClassEnv = S.gets classEnv++getInstEnv :: DTM InstEnv+getInstEnv = S.gets instEnv++modifyInstEnv :: (InstEnv -> InstEnv) -> DTM ()+modifyInstEnv f = S.modify $ \s -> s { instEnv = f $ instEnv s }++getPrecEnv :: DTM OpPrecEnv+getPrecEnv = S.gets opPrecEnv++modifyPrecEnv :: (OpPrecEnv -> OpPrecEnv) -> DTM ()+modifyPrecEnv f = S.modify $ \s -> s { opPrecEnv = f $ opPrecEnv s }++getDictEnv :: DTM DictEnv+getDictEnv = S.gets dictEnv++modifyDictEnv :: (DictEnv -> DictEnv) -> DTM ()+modifyDictEnv f = S.modify $ \s -> s { dictEnv = f $ dictEnv s }++withLocalDictEnv :: DTM a -> DTM a+withLocalDictEnv act = do+ oldEnv <- getDictEnv+ res <- act+ modifyDictEnv $ const oldEnv+ return res++getSpEnv :: DTM SpecEnv+getSpEnv = S.gets specEnv++setSpEnv :: SpecEnv -> DTM ()+setSpEnv spEnv = S.modify $ \s -> s { specEnv = spEnv }++getNextId :: DTM Integer+getNextId = do+ nid <- S.gets nextId+ S.modify $ \s -> s { nextId = succ nid }+ return nid++-- -----------------------------------------------------------------------------+-- Lifting class and instance declarations+-- -----------------------------------------------------------------------------++-- When we lift class and instance declarations, we can remove the optional+-- default declaration since it has already been considered during the type+-- check.++liftDecls :: Decl PredType -> DTM [Decl PredType]+liftDecls (DefaultDecl _ _) = return []+liftDecls (ClassDecl _ _ _ cls tv ds) = do+ m <- getModuleIdent+ liftClassDecls (qualifyWith m cls) tv ds+liftDecls (InstanceDecl _ _ cx cls ty ds) = do+ clsEnv <- getClassEnv+ let PredType ps ty' = toPredType [] $ QualTypeExpr NoSpanInfo cx ty+ ps' = minPredSet clsEnv ps+ liftInstanceDecls ps' cls ty' ds+liftDecls d = return [d]++liftClassDecls :: QualIdent -> Ident -> [Decl PredType] -> DTM [Decl PredType]+liftClassDecls cls tv ds = do+ dictDecl <- createClassDictDecl cls tv ods+ clsEnv <- getClassEnv+ let fs = classMethods cls clsEnv+ methodDecls <- mapM (createClassMethodDecl cls ms) fs+ return $ dictDecl : methodDecls+ where (vds, ods) = partition isValueDecl ds+ ms = methodMap vds++liftInstanceDecls :: PredSet -> QualIdent -> Type -> [Decl PredType]+ -> DTM [Decl PredType]+liftInstanceDecls ps cls ty ds = do+ dictDecl <- createInstDictDecl ps cls ty+ clsEnv <- getClassEnv+ let fs = classMethods cls clsEnv+ methodDecls <- mapM (createInstMethodDecl ps cls ty ms) fs+ return $ dictDecl : methodDecls+ where ms = methodMap ds++-- Since not every class method needs to be implemented in a class or instance+-- declaration, we use a map to associate a class method identifier with its+-- implementation.++type MethodMap = [(Ident, Decl PredType)]++-- We have to unrename the method's identifiers here because the syntax check+-- has renamed them before.++methodMap :: [Decl PredType] -> MethodMap+methodMap ds = [(unRenameIdent f, d) | d@(FunctionDecl _ _ f _) <- ds]++createClassDictDecl :: QualIdent -> Ident -> [Decl a] -> DTM (Decl a)+createClassDictDecl cls tv ds = do+ c <- createClassDictConstrDecl cls tv ds+ return $ DataDecl NoSpanInfo (dictTypeId cls) [tv] [c] []++createClassDictConstrDecl :: QualIdent -> Ident -> [Decl a] -> DTM ConstrDecl+createClassDictConstrDecl cls tv ds = do+ let tvs = tv : filter (unRenameIdent tv /=) identSupply+ mtys = map (fromType tvs . generalizeMethodType . transformMethodPredType)+ [toMethodType cls tv qty | TypeSig _ fs qty <- ds, _ <- fs]+ return $ ConstrDecl NoSpanInfo (dictConstrId cls) mtys++classDictConstrPredType :: ValueEnv -> ClassEnv -> QualIdent -> PredType+classDictConstrPredType vEnv clsEnv cls = PredType ps $ foldr TypeArrow ty mtys+ where sclss = superClasses cls clsEnv+ ps = Set.fromList [Pred scls (TypeVariable 0) | scls <- sclss]+ fs = classMethods cls clsEnv+ mptys = map (classMethodType vEnv cls) fs+ ty = dictType $ Pred cls $ TypeVariable 0+ mtys = map (generalizeMethodType . transformMethodPredType) mptys++createInstDictDecl :: PredSet -> QualIdent -> Type -> DTM (Decl PredType)+createInstDictDecl ps cls ty = do+ pty <- PredType ps . arrowBase <$> getInstDictConstrType cls ty+ funDecl NoSpanInfo pty (instFunId cls ty) [ConstructorPattern NoSpanInfo predUnitType qUnitId []] <$> createInstDictExpr cls ty++createInstDictExpr :: QualIdent -> Type -> DTM (Expression PredType)+createInstDictExpr cls ty = do+ ty' <- instType <$> getInstDictConstrType cls ty+ m <- getModuleIdent+ clsEnv <- getClassEnv+ let fs = map (qImplMethodId m cls ty) $ classMethods cls clsEnv+ return $ apply (Constructor NoSpanInfo (predType ty') (qDictConstrId cls))+ (zipWith (Variable NoSpanInfo . predType) (arrowArgs ty') fs)++getInstDictConstrType :: QualIdent -> Type -> DTM Type+getInstDictConstrType cls ty = do+ vEnv <- getValueEnv+ clsEnv <- getClassEnv+ return $ instanceType ty $ unpredType $ classDictConstrPredType vEnv clsEnv cls++createClassMethodDecl :: QualIdent -> MethodMap -> Ident -> DTM (Decl PredType)+createClassMethodDecl cls =+ createMethodDecl (defaultMethodId cls) (defaultClassMethodDecl cls)++defaultClassMethodDecl :: QualIdent -> Ident -> DTM (Decl PredType)+defaultClassMethodDecl cls f = do+ pty@(PredType _ ty) <- getClassMethodType cls f+ return $ funDecl NoSpanInfo pty f [] $ preludeError (instType ty) $+ "No instance or default method for class operation " ++ escName f++getClassMethodType :: QualIdent -> Ident -> DTM PredType+getClassMethodType cls f = do+ vEnv <- getValueEnv+ return $ classMethodType vEnv cls f++classMethodType :: ValueEnv -> QualIdent -> Ident -> PredType+classMethodType vEnv cls f = pty+ where ForAll _ pty = funType (qualifyLike cls f) vEnv++createInstMethodDecl :: PredSet -> QualIdent -> Type -> MethodMap -> Ident+ -> DTM (Decl PredType)+createInstMethodDecl ps cls ty =+ createMethodDecl (implMethodId cls ty) (defaultInstMethodDecl ps cls ty)++defaultInstMethodDecl :: PredSet -> QualIdent -> Type -> Ident+ -> DTM (Decl PredType)+defaultInstMethodDecl ps cls ty f = do+ vEnv <- getValueEnv+ let pty@(PredType _ ty') = instMethodType vEnv ps cls ty f+ return $ funDecl NoSpanInfo pty f [] $+ Variable NoSpanInfo (predType $ instType ty') (qDefaultMethodId cls f)++-- Returns the type for a given instance's method of a given class. To this+-- end, the class method's type is stripped of its first predicate (which is+-- the implicit class constraint) and the class variable is replaced with the+-- instance's type. The remaining predicate set is then united with the+-- instance's predicate set.++instMethodType :: ValueEnv -> PredSet -> QualIdent -> Type -> Ident -> PredType+instMethodType vEnv ps cls ty f = PredType (ps `Set.union` ps'') ty''+ where PredType ps' ty' = classMethodType vEnv cls f+ PredType ps'' ty'' = instanceType ty $ PredType (Set.deleteMin ps') ty'++createMethodDecl :: (Ident -> Ident) -> (Ident -> DTM (Decl PredType))+ -> MethodMap -> Ident -> DTM (Decl PredType)+createMethodDecl methodId defaultDecl ms f =+ liftM (renameDecl $ methodId f) $ maybe (defaultDecl f) return (lookup f ms)++-- We have to rename the left hand side of lifted function declarations+-- accordingly which is done by the function 'renameDecl'.++renameDecl :: Ident -> Decl a -> Decl a+renameDecl f (FunctionDecl p a _ eqs) = FunctionDecl p a f $ map renameEq eqs+ where renameEq (Equation p' lhs rhs) = Equation p' (renameLhs lhs) rhs+ renameLhs (FunLhs _ _ ts) = FunLhs NoSpanInfo f ts+ renameLhs _ = internalError "Dictionary.renameDecl.renameLhs"+renameDecl _ _ = internalError "Dictionary.renameDecl"++-- -----------------------------------------------------------------------------+-- Creating stub declarations+-- -----------------------------------------------------------------------------++-- For each class method f defined in the processed module we have to introduce+-- a stub method with the same name that selects the appropriate function from+-- the provided dictionary and applies the remaining arguments to it. We also+-- create a stub method for each super class selecting the corresponding super+-- class dictionary from the provided class dictionary.++createStubs :: Decl PredType -> DTM [Decl Type]+createStubs (ClassDecl _ _ _ cls _ _) = do+ m <- getModuleIdent+ vEnv <- getValueEnv+ clsEnv <- getClassEnv+ let ocls = qualifyWith m cls+ sclss = superClasses ocls clsEnv+ fs = classMethods ocls clsEnv+ dictConstrPty = classDictConstrPredType vEnv clsEnv ocls+ (superDictAndMethodTys, dictTy) =+ arrowUnapply $ transformPredType dictConstrPty+ (superDictTys, methodTys) =+ splitAt (length sclss) superDictAndMethodTys+ (superStubTys, methodStubTys) =+ splitAt (length sclss) $ map (TypeArrow dictTy) superDictAndMethodTys+ superDictVs <- mapM (freshVar "_#super" . instType) superDictTys+ methodVs <- mapM (freshVar "_#meth" . instType) methodTys+ let patternVs = superDictVs ++ methodVs+ pattern = createDictPattern (instType dictTy) ocls patternVs+ superStubs = zipWith3 (createSuperDictStubDecl pattern ocls)+ superStubTys sclss superDictVs+ methodStubs = zipWith3 (createMethodStubDecl pattern)+ methodStubTys fs methodVs+ return $ superStubs ++ methodStubs+createStubs _ = return []++createDictPattern :: Type -> QualIdent -> [(Type, Ident)] -> Pattern Type+createDictPattern a cls = constrPattern a (qDictConstrId cls)++createSuperDictStubDecl :: Pattern Type -> QualIdent -> Type -> QualIdent+ -> (Type, Ident) -> Decl Type+createSuperDictStubDecl t cls a super v =+ createStubDecl t a (superDictStubId cls super) v++createMethodStubDecl :: Pattern Type -> Type -> Ident -> (Type, Ident) -> Decl Type+createMethodStubDecl = createStubDecl++createStubDecl :: Pattern Type -> Type -> Ident -> (Type, Ident) -> Decl Type+createStubDecl t a f v =+ FunctionDecl NoSpanInfo a f [createStubEquation t f v]++createStubEquation :: Pattern Type -> Ident -> (Type, Ident) -> Equation Type+createStubEquation t f v = + mkEquation NoSpanInfo f [VariablePattern NoSpanInfo (TypeArrow unitType (typeOf t)) (mkIdent "_#temp")] $+ mkLet [FunctionDecl NoSpanInfo (TypeArrow (typeOf t) (fst v)) (mkIdent "_#lambda")+ [mkEquation NoSpanInfo (mkIdent "_#lambda") [t] $ uncurry mkVar v]]+ (apply (Variable NoSpanInfo (TypeArrow (typeOf t) (fst v)) (qualify $ mkIdent "_#lambda"))+ [apply (Variable NoSpanInfo (TypeArrow unitType (typeOf t)) (qualify $ mkIdent "_#temp"))+ [Constructor NoSpanInfo unitType qUnitId]])++superDictStubType :: QualIdent -> QualIdent -> Type -> Type+superDictStubType cls super ty =+ TypeArrow (rtDictType $ Pred cls ty) (rtDictType $ Pred super ty)++-- -----------------------------------------------------------------------------+-- Entering new bindings into the environments+-- -----------------------------------------------------------------------------++bindDictTypes :: ModuleIdent -> ClassEnv -> TCEnv -> TCEnv+bindDictTypes m clsEnv tcEnv =+ foldr (bindDictType m clsEnv) tcEnv (allEntities tcEnv)++bindDictType :: ModuleIdent -> ClassEnv -> TypeInfo -> TCEnv -> TCEnv+bindDictType m clsEnv (TypeClass cls k ms) = bindEntity m tc ti+ where ti = DataType tc (KindArrow k KindStar) [c]+ tc = qDictTypeId cls+ c = DataConstr (dictConstrId cls) (map rtDictType (Set.toAscList ps) ++ tys)+ sclss = superClasses cls clsEnv+ ps = Set.fromList [Pred scls (TypeVariable 0) | scls <- sclss]+ tys = map (generalizeMethodType . transformMethodPredType . methodType) ms+bindDictType _ _ _ = id++bindClassDecls :: ModuleIdent -> TCEnv -> ClassEnv -> ValueEnv -> ValueEnv+bindClassDecls m tcEnv clsEnv =+ flip (foldr $ bindClassEntities m clsEnv) $ allEntities tcEnv++-- It is safe to use 'fromMaybe 0' in 'bindClassEntities', because the+-- augmentation has already replaced the 'Nothing' value for the arity+-- of a method's implementation with 'Just 1' (despite the fact that+-- maybe no default implementation has been provided) if the method has+-- been augmented.++bindClassEntities :: ModuleIdent -> ClassEnv -> TypeInfo -> ValueEnv -> ValueEnv+bindClassEntities m clsEnv (TypeClass cls _ ms) =+ bindClassDict m clsEnv cls . bindSuperStubs m cls sclss .+ bindDefaultMethods m cls fs+ where fs = zip (map methodName ms) (map (fromMaybe 0 . methodArity) ms)+ sclss = superClasses cls clsEnv+bindClassEntities _ _ _ = id++bindClassDict :: ModuleIdent -> ClassEnv -> QualIdent -> ValueEnv -> ValueEnv+bindClassDict m clsEnv cls vEnv = bindEntity m c dc vEnv+ where c = qDictConstrId cls+ dc = DataConstructor c a (replicate a anonId) tySc+ a = Set.size ps + arrowArity ty+ pty@(PredType ps ty) = classDictConstrPredType vEnv clsEnv cls+ tySc = ForAll 1 pty++bindDefaultMethods :: ModuleIdent -> QualIdent -> [(Ident, Int)] -> ValueEnv+ -> ValueEnv+bindDefaultMethods m = flip . foldr . bindDefaultMethod m++bindDefaultMethod :: ModuleIdent -> QualIdent -> (Ident, Int) -> ValueEnv+ -> ValueEnv+bindDefaultMethod m cls (f, n) vEnv =+ bindMethod m (qDefaultMethodId cls f) n (classMethodType vEnv cls f) vEnv++bindSuperStubs :: ModuleIdent -> QualIdent -> [QualIdent] -> ValueEnv+ -> ValueEnv+bindSuperStubs m = flip . foldr . bindSuperStub m++bindSuperStub :: ModuleIdent -> QualIdent -> QualIdent -> ValueEnv -> ValueEnv+bindSuperStub m cls scls = bindEntity m f $ Value f Nothing 1 $ polyType ty+ where f = qSuperDictStubId cls scls+ ty = superDictStubType cls scls (TypeVariable 0)++bindInstDecls :: ModuleIdent -> TCEnv -> ClassEnv -> InstEnv -> ValueEnv+ -> ValueEnv+bindInstDecls m tcEnv clsEnv =+ flip (foldr $ bindInstFuns m tcEnv clsEnv) . Map.toList++bindInstFuns :: ModuleIdent -> TCEnv -> ClassEnv -> (InstIdent, InstInfo)+ -> ValueEnv -> ValueEnv+bindInstFuns m tcEnv clsEnv ((cls, tc), (m', ps, is)) =+ bindInstDict m cls ty m' ps . bindInstMethods m clsEnv cls ty m' ps is+ where ty = applyType (TypeConstructor tc) (take n (map TypeVariable [0..]))+ n = kindArity (tcKind m tc tcEnv) - kindArity (clsKind m cls tcEnv)++bindInstDict :: ModuleIdent -> QualIdent -> Type -> ModuleIdent -> PredSet+ -> ValueEnv -> ValueEnv+bindInstDict m cls ty m' ps =+ bindMethod m (qInstFunId m' cls ty) 1 $ PredType ps $ rtDictType $ Pred cls ty++bindInstMethods :: ModuleIdent -> ClassEnv -> QualIdent -> Type -> ModuleIdent+ -> PredSet -> [(Ident, Int)] -> ValueEnv -> ValueEnv+bindInstMethods m clsEnv cls ty m' ps is =+ flip (foldr (bindInstMethod m cls ty m' ps is)) (classMethods cls clsEnv)++bindInstMethod :: ModuleIdent -> QualIdent -> Type -> ModuleIdent+ -> PredSet -> [(Ident, Int)] -> Ident -> ValueEnv -> ValueEnv+bindInstMethod m cls ty m' ps is f vEnv = bindMethod m f' a pty vEnv+ where f' = qImplMethodId m' cls ty f+ a = fromMaybe 0 $ lookup f is+ pty = instMethodType vEnv ps cls ty f++bindMethod :: ModuleIdent -> QualIdent -> Int -> PredType -> ValueEnv+ -> ValueEnv+bindMethod m f n pty = bindEntity m f $ Value f Nothing n $ typeScheme pty++-- The function 'bindEntity' introduces a binding for an entity into a top-level+-- environment. Depending on whether the entity is defined in the current module+-- or not, either an unqualified and a qualified local binding or a qualified+-- import are added to the environment.++bindEntity :: Entity a => ModuleIdent -> QualIdent -> a -> TopEnv a+ -> TopEnv a+bindEntity m x = case qidModule (qualUnqualify m x) of+ Just m' | m /= m' -> qualImportTopEnv m' x'+ _ -> qualBindTopEnv (qualifyWith m x')+ where x' = unqualify x++-- -----------------------------------------------------------------------------+-- Transforming the environments+-- -----------------------------------------------------------------------------++dictTransTypes :: TCEnv -> TCEnv+dictTransTypes = fmap dictTransTypeInfo++dictTransTypeInfo :: TypeInfo -> TypeInfo+dictTransTypeInfo (DataType tc k cs) =+ DataType tc k $ map dictTransDataConstr cs+dictTransTypeInfo (RenamingType tc k nc) =+ RenamingType tc k $ dictTransDataConstr nc+dictTransTypeInfo ti@(AliasType _ _ _ _) = ti+dictTransTypeInfo (TypeClass cls k ms) =+ TypeClass cls k $ map dictTransClassMethod ms+dictTransTypeInfo (TypeVar _) =+ internalError "Dictionary.dictTransTypeInfo: type variable"++dictTransDataConstr :: DataConstr -> DataConstr+dictTransDataConstr (DataConstr c tys) = DataConstr c tys+dictTransDataConstr (RecordConstr c _ tys) =+ dictTransDataConstr $ DataConstr c tys++-- For the same reason as in 'bindClassEntities' it is safe to use 'fromMaybe 0'+-- in 'dictTransClassMethod'. Note that type classes are removed anyway in the+-- cleanup phase.++dictTransClassMethod :: ClassMethod -> ClassMethod+dictTransClassMethod (ClassMethod f a pty) = ClassMethod f a' $ predType ty+ where a' = Just $ fromMaybe 0 a + arrowArity ty - arrowArity (unpredType pty)+ ty = transformPredType pty++dictTransValues :: ValueEnv -> ValueEnv+dictTransValues = fmap dictTransValueInfo++dictTransValueInfo :: ValueInfo -> ValueInfo+dictTransValueInfo (DataConstructor c a ls (ForAll n pty)) =+ DataConstructor c a' ls' $ ForAll n $ predType ty+ where a' = arrowArity ty+ ls' = replicate (a' - a) anonId ++ ls+ ty = transformPredType pty+dictTransValueInfo (NewtypeConstructor c l (ForAll n pty)) =+ NewtypeConstructor c l (ForAll n (predType (unpredType pty)))+dictTransValueInfo (Value f cm a (ForAll n pty)) =+ Value f Nothing a' $ ForAll n $ predType ty+ where a' = a + if isJust cm then 1 else arrowArity ty - arrowArity (unpredType pty)+ ty = transformPredType pty+dictTransValueInfo (Label l cs (ForAll n pty)) =+ Label l cs $ ForAll n $ predType $ unpredType pty++-- -----------------------------------------------------------------------------+-- Adding exports+-- -----------------------------------------------------------------------------++addExports :: Maybe ExportSpec -> [Export] -> Maybe ExportSpec+addExports (Just (Exporting p es)) es' = Just $ Exporting p $ es ++ es'+addExports Nothing _ = internalError "Dictionary.addExports"++dictExports :: Decl a -> DTM [Export]+dictExports (ClassDecl _ _ _ cls _ _) = do+ m <- getModuleIdent+ clsEnv <- getClassEnv+ return $ classExports m clsEnv cls+dictExports (InstanceDecl _ _ _ cls ty _) = do+ m <- getModuleIdent+ clsEnv <- getClassEnv+ return $ instExports m clsEnv cls (toType [] ty)+dictExports _ = return []++classExports :: ModuleIdent -> ClassEnv -> Ident -> [Export]+classExports m clsEnv cls =+ ExportTypeWith NoSpanInfo (qDictTypeId qcls) [dictConstrId qcls] :+ map (Export NoSpanInfo . qSuperDictStubId qcls) (superClasses qcls clsEnv) +++ map (Export NoSpanInfo . qDefaultMethodId qcls) (classMethods qcls clsEnv)+ where qcls = qualifyWith m cls++instExports :: ModuleIdent -> ClassEnv -> QualIdent -> Type -> [Export]+instExports m clsEnv cls ty =+ Export NoSpanInfo (qInstFunId m cls ty) :+ map (Export NoSpanInfo . qImplMethodId m cls ty) (classMethods cls clsEnv)++-- -----------------------------------------------------------------------------+-- Transforming the module+-- -----------------------------------------------------------------------------++type DictEnv = [(Pred, Expression Type)]++emptyDictEnv :: DictEnv+emptyDictEnv = []++class DictTrans a where+ dictTrans :: a PredType -> DTM (a Type)++instance DictTrans Module where+ dictTrans (Module spi li ps m es is ds) = do+ liftedDs <- concatMapM liftDecls ds+ stubDs <- concatMapM createStubs ds+ tcEnv <- getTyConsEnv+ clsEnv <- getClassEnv+ inEnv <- getInstEnv+ modifyValueEnv $ bindClassDecls m tcEnv clsEnv+ modifyValueEnv $ bindInstDecls m tcEnv clsEnv inEnv+ modifyTyConsEnv $ bindDictTypes m clsEnv+ transDs <- mapM dictTrans liftedDs+ modifyValueEnv $ dictTransValues+ modifyTyConsEnv $ dictTransTypes+ dictEs <- addExports es <$> concatMapM dictExports ds+ return $ Module spi li ps m dictEs is $ transDs ++ stubDs++-- We use and transform the type from the type constructor environment for+-- transforming a constructor declaration as it contains the reduced and+-- restricted predicate set for each data constructor.++-- The pattern declaration case of the DictTrans Decl instance converts+-- variable declarations with an overloaded type into function declarations.+-- This is necessary so that the compiler can add the implicit dictionary+-- arguments to the declaration.++instance DictTrans Decl where+ dictTrans (InfixDecl p fix prec ops) = return $ InfixDecl p fix prec ops+ dictTrans (DataDecl p tc tvs cs _) = do+ m <- getModuleIdent+ tcEnv <- getTyConsEnv+ let DataType _ _ cs' = head $ qualLookupTypeInfo (qualifyWith m tc) tcEnv+ return $ DataDecl p tc tvs (zipWith (dictTransConstrDecl tvs) cs cs') []+ dictTrans (ExternalDataDecl p tc tvs) = return $ ExternalDataDecl p tc tvs+ dictTrans (NewtypeDecl p tc tvs nc _) =+ return $ NewtypeDecl p tc tvs nc []+ dictTrans (TypeDecl p tc tvs ty) = return $ TypeDecl p tc tvs ty+ dictTrans (FunctionDecl p pty f eqs) =+ FunctionDecl p (transformPredType pty) f <$> mapM dictTrans eqs+ dictTrans (PatternDecl p t rhs) = case t of+ VariablePattern _ pty@(PredType ps _) v | not (Set.null ps) ->+ dictTrans $ FunctionDecl p pty v [Equation p (FunLhs NoSpanInfo v []) rhs]+ _ -> withLocalDictEnv $ PatternDecl p <$> dictTrans t <*> dictTrans rhs+ dictTrans d@(FreeDecl _ _) = return $ fmap unpredType d+ dictTrans d@(ExternalDecl _ _) = return $ fmap transformPredType d+ dictTrans d =+ internalError $ "Dictionary.dictTrans: " ++ show d++dictTransConstrDecl :: [Ident] -> ConstrDecl -> DataConstr -> ConstrDecl+dictTransConstrDecl tvs (ConstrDecl p c tes) dc =+ ConstrDecl p c $ map (fromType $ tvs ++ bvs) (constrTypes dc)+ where bvs = nub $ bv tes+dictTransConstrDecl tvs (ConOpDecl p ty1 op ty2) dc =+ dictTransConstrDecl tvs (ConstrDecl p op [ty1, ty2]) dc+dictTransConstrDecl _ d _ = internalError $ "Dictionary.dictTrans: " ++ show d++instance DictTrans Equation where+ dictTrans (Equation p (FunLhs _ f ts) rhs) = withLocalValueEnv $ do+ m <- getModuleIdent+ pls <- matchPredList (varType m f) $+ foldr (TypeArrow . typeOf) (typeOf rhs) ts+ ts' <- addDictArgs pls ts+ modifyValueEnv $ bindPatterns ts'+ Equation p (FunLhs NoSpanInfo f ts') <$> dictTrans rhs+ dictTrans eq =+ internalError $ "Dictionary.dictTrans: " ++ show eq++instance DictTrans Rhs where+ dictTrans (SimpleRhs p _ e []) = simpleRhs p <$> dictTrans e+ dictTrans rhs =+ internalError $ "Dictionary.dictTrans: " ++ show rhs++instance DictTrans Pattern where+ dictTrans (LiteralPattern _ pty l) =+ return $ LiteralPattern NoSpanInfo (unpredType pty) l+ dictTrans (VariablePattern _ pty v) =+ return $ VariablePattern NoSpanInfo (unpredType pty) v+ dictTrans (ConstructorPattern _ pty c ts) = do+ pls <- matchPredList (conType c) $+ foldr (TypeArrow . typeOf) (unpredType pty) ts+ ConstructorPattern NoSpanInfo (unpredType pty) c <$> addDictArgs pls ts+ dictTrans (AsPattern _ v t) =+ AsPattern NoSpanInfo v <$> dictTrans t+ dictTrans t =+ internalError $ "Dictionary.dictTrans: " ++ show t++instance DictTrans Expression where+ dictTrans (Literal _ pty l) =+ return $ Literal NoSpanInfo (unpredType pty) l+ dictTrans (Variable _ pty v) = do+ pls <- matchPredList (funType v) (unpredType pty)+ es <- mapM dictArg pls+ let ty = foldr (TypeArrow . typeOf) (unpredType pty) es+ return $ apply (Variable NoSpanInfo ty v) es+ dictTrans (Constructor _ pty c) = do+ pls <- matchPredList (conType c) (unpredType pty)+ es <- mapM dictArg pls+ let ty = foldr (TypeArrow . typeOf) (unpredType pty) es+ return $ apply (Constructor NoSpanInfo ty c) es+ dictTrans (Apply _ e1 e2) =+ Apply NoSpanInfo <$> dictTrans e1 <*> dictTrans e2+ dictTrans (Typed _ e qty) =+ Typed NoSpanInfo <$> dictTrans e <*> dictTransQualTypeExpr qty+ dictTrans (Lambda _ ts e) = withLocalValueEnv $ withLocalDictEnv $ do+ ts' <- mapM dictTrans ts+ modifyValueEnv $ bindPatterns ts'+ mkLambda ts' <$> dictTrans e+ dictTrans (Let _ _ ds e) = withLocalValueEnv $ do+ modifyValueEnv $ bindDecls ds+ mkLet <$> mapM dictTrans ds <*> dictTrans e+ dictTrans (Case _ _ ct e as) =+ mkCase ct <$> dictTrans e <*> mapM dictTrans as+ dictTrans e =+ internalError $ "Dictionary.dictTrans: " ++ show e++-- Just like before in desugaring, we ignore the context in the type signature+-- of a typed expression, since there should be no possibility to provide an+-- non-empty context without scoped type-variables.+-- TODO: Verify++dictTransQualTypeExpr :: QualTypeExpr -> DTM QualTypeExpr+dictTransQualTypeExpr (QualTypeExpr spi _ ty) = return $ QualTypeExpr spi [] ty++instance DictTrans Alt where+ dictTrans (Alt p t rhs) = withLocalValueEnv $ withLocalDictEnv $ do+ t' <- dictTrans t+ modifyValueEnv $ bindPattern t'+ Alt p t' <$> dictTrans rhs++addDictArgs :: [Pred] -> [Pattern PredType] -> DTM [Pattern Type]+addDictArgs pls ts = do+ dictVars <- mapM (freshVar "_#dict" . rtDictType) pls+ clsEnv <- getClassEnv+ modifyDictEnv $ (++) $ dicts clsEnv $ zip pls (map (uncurry mkVar) dictVars)+ (++) (map (uncurry (VariablePattern NoSpanInfo )) dictVars)+ <$> mapM dictTrans ts+ where dicts clsEnv vs+ | null vs = vs+ | otherwise = vs ++ dicts clsEnv (concatMap (superDicts clsEnv) vs)+ superDicts clsEnv (Pred cls ty, e) =+ map (superDict cls ty e) (superClasses cls clsEnv)+ superDict cls ty e scls =+ (Pred scls ty, Apply NoSpanInfo (superDictExpr cls scls ty) e)+ superDictExpr cls scls ty =+ Variable NoSpanInfo (superDictStubType cls scls ty)+ (qSuperDictStubId cls scls)++-- The function 'dictArg' constructs the dictionary argument for a predicate+-- from the predicates of a class method or an overloaded function. It checks+-- whether a dictionary for the predicate is available in the dictionary+-- environment, which is the case when the predicate's type is a type variable,+-- and uses 'instDict' otherwise in order to supply a new dictionary using the+-- appropriate instance dictionary construction function. If the corresponding+-- instance declaration has a non-empty context, the dictionary construction+-- function is applied to the dictionaries computed for the context instantiated+-- at the appropriate types.++dictArg :: Pred -> DTM (Expression Type)+dictArg p = maybeM (instDict p) return (lookup p <$> getDictEnv)++instDict :: Pred -> DTM (Expression Type)+instDict p = instPredList p >>= flip (uncurry instFunApp) p++instFunApp :: ModuleIdent -> [Pred] -> Pred -> DTM (Expression Type)+instFunApp m pls p@(Pred cls ty) = apply (Variable NoSpanInfo ty' f)+ <$> mapM dictArg pls+ where f = qInstFunId m cls ty+ ty' = foldr1 TypeArrow $ map rtDictType $ pls ++ [p]++instPredList :: Pred -> DTM (ModuleIdent, [Pred])+instPredList (Pred cls ty) = case unapplyType True ty of+ (TypeConstructor tc, tys) -> do+ inEnv <- getInstEnv+ case lookupInstInfo (cls, tc) inEnv of+ Just (m, ps, _) -> return (m, expandAliasType tys $ Set.toAscList ps)+ Nothing -> internalError $ "Dictionary.instPredList: " ++ show (cls, tc)+ _ -> internalError $ "Dictionary.instPredList: " ++ show ty++-- When adding dictionary arguments on the left hand side of an equation and+-- in applications, respectively, the compiler must unify the function's type+-- with the concrete instance at which that type is used in order to determine+-- the correct context.++-- Polymorphic methods make things a little bit more complicated. When an+-- instance dictionary constructor is applied to an instance method, the+-- suffix of the instance method type's context that corresponds to the+-- additional constraints of the type class method must be discarded and+-- no dictionaries must be added for these constraints. Unfortunately, the+-- dictionary transformation has already been applied to the component types+-- of the dictionary constructor. Therefore, the function 'matchPredList'+-- tries to find a suffix of the context whose transformation matches the+-- initial arrows of the instance type.++matchPredList :: (ValueEnv -> TypeScheme) -> Type -> DTM [Pred]+matchPredList tySc ty2 = do+ ForAll _ (PredType ps ty1) <- tySc <$> getValueEnv+ return $ foldr (\(pls1, pls2) pls' ->+ fromMaybe pls' $ qualMatch pls1 ty1 pls2 ty2)+ (internalError $ "Dictionary.matchPredList: " ++ show ps)+ (splits $ Set.toAscList ps)++qualMatch :: [Pred] -> Type -> [Pred] -> Type -> Maybe [Pred]+qualMatch pls1 ty1 pls2 ty2 = case predListMatch pls2 ty2 of+ Just ty2' -> Just $ subst (matchType ty1 ty2' idSubst) pls1+ Nothing -> Nothing++predListMatch :: [Pred] -> Type -> Maybe Type+predListMatch [] ty = Just ty+predListMatch (p:ps) ty = case ty of+ TypeForall _ ty' -> predListMatch (p : ps) ty'+ TypeArrow ty1 ty2 | ty1 == rtDictType (instPred p) -> predListMatch ps ty2+ _ -> Nothing++splits :: [a] -> [([a], [a])]+splits xs = zip (inits xs) (tails xs)++-- -----------------------------------------------------------------------------+-- Optimizing method calls+-- -----------------------------------------------------------------------------++-- Whenever a type class method is applied at a known type, the compiler can+-- apply the type instance's implementation directly.++type SpecEnv = Map.Map (QualIdent, QualIdent) QualIdent++emptySpEnv :: SpecEnv+emptySpEnv = Map.empty++initSpEnv :: ClassEnv -> InstEnv -> SpecEnv+initSpEnv clsEnv = foldr (uncurry bindInstance) emptySpEnv . Map.toList+ where bindInstance (cls, tc) (m, _, _) =+ flip (foldr $ bindInstanceMethod m cls tc) $ classMethods cls clsEnv+ bindInstanceMethod m cls tc f = Map.insert (f', d) f''+ where f' = qualifyLike cls f+ d = qInstFunId m cls ty+ f'' = qImplMethodId m cls ty f+ ty = TypeConstructor tc++class Specialize a where+ specialize :: a Type -> DTM (a Type)++instance Specialize Module where+ specialize (Module spi li ps m es is ds) = do+ clsEnv <- getClassEnv+ inEnv <- getInstEnv+ setSpEnv $ initSpEnv clsEnv inEnv+ Module spi li ps m es is <$> mapM specialize ds++instance Specialize Decl where+ specialize (FunctionDecl p ty f eqs) =+ FunctionDecl p ty f <$> mapM specialize eqs+ specialize (PatternDecl p t rhs) = PatternDecl p t <$> specialize rhs+ specialize d = return d++instance Specialize Equation where+ specialize (Equation p lhs rhs) = Equation p lhs <$> specialize rhs++instance Specialize Rhs where+ specialize (SimpleRhs p _ e []) = simpleRhs p <$> specialize e+ specialize rhs =+ internalError $ "Dictionary.specialize: " ++ show rhs++instance Specialize Expression where+ specialize e = specialize' e []++specialize' :: Expression Type -> [Expression Type] -> DTM (Expression Type)+specialize' l@(Literal _ _ _) es = return $ apply l es+specialize' v@(Variable _ _ v') es = do+ spEnv <- getSpEnv+ return $ case Map.lookup (v', f) spEnv of+ Just f' -> apply (Variable NoSpanInfo ty' f') $ es'' ++ es'+ Nothing -> apply v es+ where d:es' = es+ (Variable _ _ f, es'') = unapply d []+ ty' = foldr (TypeArrow . typeOf) (typeOf $ Apply NoSpanInfo v d) es''+specialize' c@(Constructor _ _ _) es = return $ apply c es+specialize' (Typed _ e qty) es = do+ e' <- specialize e+ return $ apply (Typed NoSpanInfo e' qty) es+specialize' (Apply _ e1 e2) es = do+ e2' <- specialize e2+ specialize' e1 $ e2' : es+specialize' (Lambda _ ts e) es = do+ e' <- specialize e+ return $ apply (Lambda NoSpanInfo ts e') es+specialize' (Let _ _ ds e) es = do+ ds' <- mapM specialize ds+ e' <- specialize e+ return $ apply (mkLet ds' e') es+specialize' (Case _ _ ct e as) es = do+ e' <- specialize e+ as' <- mapM specialize as+ return $ apply (mkCase ct e' as') es+specialize' e _ =+ internalError $ "Dictionary.specialize': " ++ show e++instance Specialize Alt where+ specialize (Alt p t rhs) = Alt p t <$> specialize rhs++-- -----------------------------------------------------------------------------+-- Cleaning up+-- -----------------------------------------------------------------------------++-- After we have transformed the module we have to remove class exports from+-- the export list and type classes from the type constructor environment.+-- Furthermore, we may have to remove some infix declarations and operators+-- from the precedence environment as functions with class constraint have+-- been supplemented with addiontal dictionary arguments during the dictionary+-- transformation.++cleanup :: Module a -> DTM (Module a)+cleanup (Module spi li ps m es is ds) = do+ cleanedEs <- traverse cleanupExportSpec es+ cleanedDs <- concatMapM cleanupInfixDecl ds+ cleanupTyConsEnv+ cleanupPrecEnv+ return $ Module spi li ps m cleanedEs is cleanedDs++cleanupExportSpec :: ExportSpec -> DTM ExportSpec+cleanupExportSpec (Exporting p es) = Exporting p <$> concatMapM cleanupExport es++cleanupExport :: Export -> DTM [Export]+cleanupExport e@(Export _ _) = return [e]+cleanupExport e@(ExportTypeWith spi tc cs) = do+ tcEnv <- getTyConsEnv+ case qualLookupTypeInfo tc tcEnv of+ [TypeClass _ _ _] -> return $ map (Export spi . qualifyLike tc) cs+ _ -> return [e]+cleanupExport e =+ internalError $ "Dictionary.cleanupExport: " ++ show e++cleanupInfixDecl :: Decl a -> DTM [Decl a]+cleanupInfixDecl (InfixDecl p fix pr ops) = do+ m <- getModuleIdent+ vEnv <- getValueEnv+ let opArity = arrowArity . rawType . flip opType vEnv . qualifyWith m+ ops' = filter ((== 2) . opArity) ops+ return [InfixDecl p fix pr ops' | not (null ops')]+cleanupInfixDecl d = return [d]++cleanupTyConsEnv :: DTM ()+cleanupTyConsEnv = getTyConsEnv >>= mapM_ (cleanupTyCons . fst) . allBindings++cleanupTyCons :: QualIdent -> DTM ()+cleanupTyCons tc = do+ tcEnv <- getTyConsEnv+ case qualLookupTypeInfo tc tcEnv of+ [TypeClass _ _ _] -> modifyTyConsEnv $ qualUnbindTopEnv tc+ _ -> return ()++cleanupPrecEnv :: DTM ()+cleanupPrecEnv = getPrecEnv >>= mapM_ (cleanupOp . fst) . allBindings++cleanupOp :: QualIdent -> DTM ()+cleanupOp op = do+ opArity <- arrowArity . rawType . opType op <$> getValueEnv+ when (opArity /= 2) $ modifyPrecEnv $ qualUnbindTopEnv op++-- -----------------------------------------------------------------------------+-- Transforming interfaces+-- -----------------------------------------------------------------------------++-- The following functions expect an already transformed value environment.+-- The transformation of interface declarations with it is quite simple and+-- straightforward.++dictTransInterfaces :: ValueEnv -> ClassEnv -> InterfaceEnv -> InterfaceEnv+dictTransInterfaces vEnv clsEnv = fmap $ dictTransInterface vEnv clsEnv++dictTransInterface :: ValueEnv -> ClassEnv -> Interface -> Interface+dictTransInterface vEnv clsEnv (Interface m is ds) =+ Interface m is $ concatMap (dictTransIDecl m vEnv clsEnv) ds++dictTransIDecl :: ModuleIdent -> ValueEnv -> ClassEnv -> IDecl -> [IDecl]+dictTransIDecl m vEnv _ d@(IInfixDecl _ _ _ op)+ | arrowArity (rawType $ opType (qualQualify m op) vEnv) /= 2 = []+ | otherwise = [d]+dictTransIDecl _ _ _ d@(HidingDataDecl _ _ _ _) = [d]+dictTransIDecl m _ _ (IDataDecl p tc k tvs cs hs) =+ [IDataDecl p tc k tvs (map (dictTransIConstrDecl m tvs) cs) hs]+dictTransIDecl _ _ _ d@(INewtypeDecl _ _ _ _ _ _) = [d]+dictTransIDecl _ _ _ d@(ITypeDecl _ _ _ _ _) = [d]+dictTransIDecl m vEnv _ (IFunctionDecl _ f _ _ _) =+ [iFunctionDeclFromValue m vEnv (qualQualify m f)]+dictTransIDecl _ _ _ (HidingClassDecl p _ cls k tv) =+ [HidingDataDecl p (qDictTypeId cls) (fmap (flip ArrowKind Star) k) [tv]]+dictTransIDecl m vEnv clsEnv (IClassDecl p _ cls k _ _ hs) =+ dictDecl : defaults ++ methodStubs ++ superDictStubs+ where qcls = qualQualify m cls+ sclss = superClasses qcls clsEnv+ ms = classMethods qcls clsEnv+ dictDecl = IDataDecl p (qDictTypeId cls)+ (fmap (flip ArrowKind Star) k)+ [head identSupply] [constrDecl] []+ constrDecl = iConstrDeclFromDataConstructor m vEnv $ qDictConstrId qcls+ defaults = map (iFunctionDeclFromValue m vEnv .+ qDefaultMethodId qcls) ms+ methodStubs = map (iFunctionDeclFromValue m vEnv . qualifyLike qcls) $+ filter (`notElem` hs) ms+ superDictStubs = map (iFunctionDeclFromValue m vEnv .+ qSuperDictStubId qcls) sclss+dictTransIDecl m vEnv clsEnv (IInstanceDecl _ _ cls ty _ mm) =+ iFunctionDeclFromValue m vEnv (qInstFunId m' qcls ty') :+ map (iFunctionDeclFromValue m vEnv . qImplMethodId m' qcls ty') ms+ where m' = fromMaybe m mm+ qcls = qualQualify m cls+ ty' = toQualType m [] ty+ ms = classMethods qcls clsEnv++dictTransIConstrDecl :: ModuleIdent -> [Ident] -> ConstrDecl -> ConstrDecl+dictTransIConstrDecl _ _ (ConOpDecl p ty1 op ty2) = ConstrDecl p op [ty1, ty2]+dictTransIConstrDecl _ _ cd = cd++iFunctionDeclFromValue :: ModuleIdent -> ValueEnv -> QualIdent -> IDecl+iFunctionDeclFromValue m vEnv f = case qualLookupValue f vEnv of+ [Value _ _ a (ForAll _ pty)] ->+ IFunctionDecl NoPos (qualUnqualify m f) Nothing a $+ fromQualPredType m identSupply pty+ _ -> internalError $ "Dictionary.iFunctionDeclFromValue: " ++ show f++iConstrDeclFromDataConstructor :: ModuleIdent -> ValueEnv -> QualIdent+ -> ConstrDecl+iConstrDeclFromDataConstructor m vEnv c = case qualLookupValue c vEnv of+ [DataConstructor _ _ _ (ForAll _ pty)] ->+ ConstrDecl NoSpanInfo (unqualify c) tys+ where tys = map (fromQualType m identSupply) $ arrowArgs $ unpredType pty+ _ -> internalError $ "Dictionary.iConstrDeclFromDataConstructor: " ++ show c++-- -----------------------------------------------------------------------------+-- Functions for naming newly created types, functions and parameters+-- -----------------------------------------------------------------------------++dictTypeId :: QualIdent -> Ident+dictTypeId cls = mkIdent $ "_Dict#" ++ idName (unqualify cls)++qDictTypeId :: QualIdent -> QualIdent+qDictTypeId cls = qualifyLike cls $ dictTypeId cls++dictConstrId :: QualIdent -> Ident+dictConstrId = dictTypeId++qDictConstrId :: QualIdent -> QualIdent+qDictConstrId cls = qualifyLike cls $ dictConstrId cls++defaultMethodId :: QualIdent -> Ident -> Ident+defaultMethodId cls f = mkIdent $ "_def#" ++ idName f ++ '#' : qualName cls++qDefaultMethodId :: QualIdent -> Ident -> QualIdent+qDefaultMethodId cls = qualifyLike cls . defaultMethodId cls++superDictStubId :: QualIdent -> QualIdent -> Ident+superDictStubId cls scls = mkIdent $+ "_super#" ++ qualName cls ++ '#' : qualName scls++qSuperDictStubId :: QualIdent -> QualIdent -> QualIdent+qSuperDictStubId cls = qualifyLike cls . superDictStubId cls++instFunId :: QualIdent -> Type -> Ident+instFunId cls ty = mkIdent $+ "_inst#" ++ qualName cls ++ '#' : qualName (rootOfType ty)++qInstFunId :: ModuleIdent -> QualIdent -> Type -> QualIdent+qInstFunId m cls = qualifyWith m . instFunId cls++implMethodId :: QualIdent -> Type -> Ident -> Ident+implMethodId cls ty f = mkIdent $+ "_impl#" ++ idName f ++ '#' : qualName cls ++ '#' : qualName (rootOfType ty)++qImplMethodId :: ModuleIdent -> QualIdent -> Type -> Ident -> QualIdent+qImplMethodId m cls ty = qualifyWith m . implMethodId cls ty++-- -----------------------------------------------------------------------------+-- Generating variables+-- -----------------------------------------------------------------------------++freshVar :: String -> Type -> DTM (Type, Ident)+freshVar name ty = ((,) ty) . mkIdent . (name ++) . show <$> getNextId++-- -----------------------------------------------------------------------------+-- Auxiliary functions+-- -----------------------------------------------------------------------------++-- The function 'dictType' returns the type of the dictionary corresponding to+-- a particular C-T instance.++rtDictType :: Pred -> Type+rtDictType = TypeArrow unitType . dictType++dictType :: Pred -> Type+dictType (Pred cls ty) = TypeApply (TypeConstructor $ qDictTypeId cls) ty++-- The function 'transformPredType' replaces each predicate with a new+-- dictionary type argument.++transformPredType :: PredType -> Type+transformPredType (PredType ps ty) =+ foldr (TypeArrow . rtDictType) ty $ Set.toList ps++-- The function 'transformMethodPredType' first deletes the implicit class+-- constraint and then transforms the resulting predicated type as above.++transformMethodPredType :: PredType -> Type+transformMethodPredType (PredType ps ty) =+ transformPredType $ PredType (Set.deleteMin ps) ty++-- The function 'generalizeMethodType' generalizes an already transformed+-- method type to a forall type by quantifying all occuring type variables+-- except for the class variable whose index is 0.+generalizeMethodType :: Type -> Type+generalizeMethodType ty+ | null tvs = ty+ | otherwise = TypeForall tvs ty+ where tvs = nub $ filter (/= 0) $ typeVars ty++instTypeVar :: Int -> Int+instTypeVar tv = -1 - tv++instType :: Type -> Type+instType (TypeConstructor tc) = TypeConstructor tc+instType (TypeVariable tv) = TypeVariable (instTypeVar tv)+instType (TypeApply ty1 ty2) = TypeApply (instType ty1) (instType ty2)+instType (TypeArrow ty1 ty2) = TypeArrow (instType ty1) (instType ty2)+instType (TypeForall tvs ty) = TypeForall (map instTypeVar tvs) (instType ty)+instType ty = ty++instPred :: Pred -> Pred+instPred (Pred cls ty) = Pred cls (instType ty)++unRenameIdentIf :: Bool -> Ident -> Ident+unRenameIdentIf b = if b then unRenameIdent else id++-- The string for the error message for a class method's default method+-- implementation has to be constructed in its desugared form since the+-- desugaring has already taken place.++preludeError :: Type -> String -> Expression PredType+preludeError a =+ Apply NoSpanInfo (Variable NoSpanInfo+ (predType (TypeArrow stringType a)) qErrorId) . stringExpr++stringExpr :: String -> Expression PredType+stringExpr = foldr (consExpr . Literal NoSpanInfo (predType charType) . Char)+ nilExpr+ where+ nilExpr = Constructor NoSpanInfo (predType stringType) qNilId+ consExpr = (Apply NoSpanInfo) . (Apply NoSpanInfo)+ (Constructor NoSpanInfo (predType $ consType charType) qConsId)++-- The function 'varType' is able to lookup both local and global identifiers.+-- Since the environments have been qualified before, global declarations are+-- only visible under their original name whereas local declarations are always+-- entered unqualified.++varType :: ModuleIdent -> Ident -> ValueEnv -> TypeScheme+varType m v vEnv = case qualLookupValue (qualify v) vEnv of+ Value _ _ _ tySc : _ -> tySc+ Label _ _ tySc : _ -> tySc+ _ -> case qualLookupValue (qualifyWith m v) vEnv of+ Value _ _ _ tySc : _ -> tySc+ Label _ _ tySc : _ -> tySc+ _ -> internalError $ "Dictionary.varType: " ++ show v++conType :: QualIdent -> ValueEnv -> TypeScheme+conType c vEnv = case qualLookupValue c vEnv of+ [DataConstructor _ _ _ (ForAll n pty)] -> ForAll n pty+ [NewtypeConstructor _ _ (ForAll n pty)] -> ForAll n pty+ _ -> internalError $ "Dictionary.conType: " ++ show c++funType :: QualIdent -> ValueEnv -> TypeScheme+funType f vEnv = case qualLookupValue f vEnv of+ [Value _ _ _ tySc] -> tySc+ [Label _ _ tySc] -> tySc+ _ -> internalError $ "Dictionary.funType " ++ show f++opType :: QualIdent -> ValueEnv -> TypeScheme+opType op vEnv = case qualLookupValue op vEnv of+ [DataConstructor _ _ _ (ForAll n pty)] -> ForAll n pty+ [NewtypeConstructor _ _ (ForAll n pty)] -> ForAll n pty+ [Value _ _ _ tySc] -> tySc+ [Label _ _ tySc] -> tySc+ _ -> internalError $ "Dictionary.opType " ++ show op
+ src/Transformations/Lift.hs view
@@ -0,0 +1,451 @@+{- |+ Module : $Header$+ Description : Lifting of lambda-expressions and local functions+ Copyright : (c) 2001 - 2003 Wolfgang Lux+ 2011 - 2015 Björn Peemöller+ 2016 - 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ After desugaring and simplifying the code, the compiler lifts all local+ function declarations to the top-level keeping only local variable+ declarations. The algorithm used here is similar to Johnsson's, consisting+ of two phases. First, we abstract each local function declaration,+ adding its free variables as initial parameters and update all calls+ to take these variables into account. Second, all local function+ declarations are collected and lifted to the top-level.+-}+{-# LANGUAGE CPP #-}+module Transformations.Lift (lift) where++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative ((<$>), (<*>))+#endif+import Control.Arrow (first)+import qualified Control.Monad.State as S (State, runState, gets, modify)+import Data.List+import qualified Data.Map as Map (Map, empty, insert, lookup)+import Data.Maybe (mapMaybe, fromJust)+import qualified Data.Set as Set (fromList, toList, unions)++import Curry.Base.Ident+import Curry.Base.SpanInfo+import Curry.Syntax++import Base.AnnotExpr+import Base.Expr+import Base.Messages (internalError)+import Base.SCC+import Base.Types+import Base.TypeSubst+import Base.Typing+import Base.Utils++import Env.Value++lift :: ValueEnv -> Module Type -> (Module Type, ValueEnv)+lift vEnv (Module spi li ps m es is ds) = (lifted, valueEnv s')+ where+ (ds', s') = S.runState (mapM (absDecl "" []) ds) initState+ initState = LiftState m vEnv Map.empty+ lifted = Module spi li ps m es is $ concatMap liftFunDecl ds'++-- -----------------------------------------------------------------------------+-- Abstraction+-- -----------------------------------------------------------------------------++-- Besides adding the free variables to every (local) function, the+-- abstraction pass also has to update the type environment in order to+-- reflect the new types of the abstracted functions. As usual, we use a+-- state monad transformer in order to pass the type environment+-- through. The environment constructed in the abstraction phase maps+-- each local function declaration onto its replacement expression,+-- i.e. the function applied to its free variables. In order to generate+-- correct type annotations for an inserted replacement expression, we also+-- save a function's original type. The original type is later unified with+-- the concrete type of the replaced expression to obtain a type substitution+-- which is then applied to the replacement expression.++type AbstractEnv = Map.Map Ident (Expression Type, Type)++data LiftState = LiftState+ { moduleIdent :: ModuleIdent+ , valueEnv :: ValueEnv+ , abstractEnv :: AbstractEnv+ }++type LiftM a = S.State LiftState a++getModuleIdent :: LiftM ModuleIdent+getModuleIdent = S.gets moduleIdent++getValueEnv :: LiftM ValueEnv+getValueEnv = S.gets valueEnv++modifyValueEnv :: (ValueEnv -> ValueEnv) -> LiftM ()+modifyValueEnv f = S.modify $ \s -> s { valueEnv = f $ valueEnv s }++getAbstractEnv :: LiftM AbstractEnv+getAbstractEnv = S.gets abstractEnv++withLocalAbstractEnv :: AbstractEnv -> LiftM a -> LiftM a+withLocalAbstractEnv ae act = do+ old <- getAbstractEnv+ S.modify $ \s -> s { abstractEnv = ae }+ res <- act+ S.modify $ \s -> s { abstractEnv = old }+ return res++absDecl :: String -> [Ident] -> Decl Type -> LiftM (Decl Type)+absDecl _ lvs (FunctionDecl p ty f eqs) = FunctionDecl p ty f+ <$> mapM (absEquation lvs) eqs+absDecl pre lvs (PatternDecl p t rhs) = PatternDecl p t+ <$> absRhs pre lvs rhs+absDecl _ _ d = return d++absEquation :: [Ident] -> Equation Type -> LiftM (Equation Type)+absEquation lvs (Equation p lhs@(FunLhs _ f ts) rhs) =+ Equation p lhs <$> absRhs (idName f ++ ".") lvs' rhs+ where lvs' = lvs ++ bv ts+absEquation _ _ = error "Lift.absEquation: no pattern match"++absRhs :: String -> [Ident] -> Rhs Type -> LiftM (Rhs Type)+absRhs pre lvs (SimpleRhs p _ e _) = simpleRhs p <$> absExpr pre lvs e+absRhs _ _ _ = error "Lift.absRhs: no simple RHS"++-- Within a declaration group we have to split the list of declarations+-- into the function and value declarations. Only the function+-- declarations are affected by the abstraction algorithm; the value+-- declarations are left unchanged except for abstracting their right+-- hand sides.++-- The abstraction of a recursive declaration group is complicated by the+-- fact that not all functions need to call each in a recursive+-- declaration group. E.g., in the following example neither 'g' nor 'h'+-- call each other.+--+-- f = g True+-- where x = h 1+-- h z = y + z+-- y = g False+-- g z = if z then x else 0+--+-- Because of this fact, 'g' and 'h' can be abstracted separately by adding+-- only 'y' to 'h' and 'x' to 'g'. On the other hand, in the following example+--+-- f x y = g 4+-- where g p = h p + x+-- h q = k + y + q+-- k = g x+--+-- the local function 'g' uses 'h', so the free variables+-- of 'h' have to be added to 'g' as well. However, because+-- 'h' does not call 'g' it is sufficient to add only+-- 'k' and 'y' (and not 'x') to its definition. We handle this by computing+-- the dependency graph between the functions and splitting this graph into+-- its strongly connected components. Each component is then processed+-- separately, adding the free variables in the group to its functions.++-- We have to be careful with local declarations within desugared case+-- expressions. If some of the cases have guards, e.g.,+--+-- case e of+-- x | x < 1 -> 1+-- x -> let double y = y * y in double x+--+-- the desugarer at present may duplicate code. While there is no problem+-- with local variable declaration being duplicated, we must avoid to+-- lift local function declarations more than once. Therefore+-- 'absFunDecls' transforms only those function declarations+-- that have not been lifted and discards the other declarations. Note+-- that it is easy to check whether a function has been lifted by+-- checking whether an entry for its transformed name is present+-- in the value environment.++absDeclGroup :: String -> [Ident] -> [Decl Type] -> Expression Type+ -> LiftM (Expression Type)+absDeclGroup pre lvs ds e = do+ m <- getModuleIdent+ absFunDecls pre lvs' (scc bv (qfv m) fds) vds e+ where lvs' = lvs ++ bv vds+ (fds, vds) = partition isFunDecl ds++absFunDecls :: String -> [Ident] -> [[Decl Type]] -> [Decl Type]+ -> Expression Type -> LiftM (Expression Type)+absFunDecls pre lvs [] vds e = do+ vds' <- mapM (absDecl pre lvs) vds+ e' <- absExpr pre lvs e+ return (mkLet vds' e')+absFunDecls pre lvs (fds:fdss) vds e = do+ m <- getModuleIdent+ env <- getAbstractEnv+ vEnv <- getValueEnv+ let -- defined functions+ fs = bv fds+ -- function types+ ftys = map extractFty fds+ extractFty (FunctionDecl _ _ f (Equation _ (FunLhs _ _ ts) rhs : _)) =+ (f, foldr TypeArrow (typeOf rhs) $ map typeOf ts)+ extractFty _ =+ internalError "Lift.absFunDecls.extractFty"+ -- typed free variables on the right-hand sides+ fvsRhs = Set.unions+ [ Set.fromList (filter (not . isDummyType . fst)+ (maybe [(ty, v)]+ (qafv' ty)+ (Map.lookup v env)))+ | (ty, v) <- concatMap (qafv m) fds ]+ -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!+ -- !!! HACK: When calculating the typed free variables on the !!!+ -- !!! right-hand side, we have to filter out the ones annotated !!!+ -- !!! with dummy types (see below). Additionally, we have to be !!!+ -- !!! careful when we calculate the typed free variables in a !!!+ -- !!! replacement expression: We have to unify the original !!!+ -- !!! function type with the instantiated function type in order !!!+ -- !!! to obtain a type substitution that can then be applied to !!!+ -- !!! the typed free variables in the replacement expression. !!!+ -- !!! This is analogous to the procedure when inserting a !!!+ -- !!! replacement expression with a correct type annotation !!!+ -- !!! (see 'absType' in 'absExpr' below). !!!+ -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!+ qafv' ty (re, fty) =+ let unifier = matchType fty ty idSubst+ in map (\(ty', v) -> (subst unifier ty', v)) $ qafv m re+ -- free variables that are local+ fvs = filter ((`elem` lvs) . snd) (Set.toList fvsRhs)+ -- extended abstraction environment+ env' = foldr bindF env fs+ -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!+ -- !!! HACK: Since we do not know how to annotate the function !!!+ -- !!! call within the replacement expression until the replace- !!! !!!+ -- !!! ment expression is actually inserted (see 'absType' in !!!+ -- !!! 'absExpr' below), we use a dummy type for this. In turn, !!!+ -- !!! this dummy type has to be filtered out when calculating !!!+ -- !!! the typed free variables on right-hand sides (see above). !!! !!!+ -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!+ bindF f =+ Map.insert f ( apply (mkFun m pre dummyType f) (map (uncurry mkVar) fvs)+ , fromJust $ lookup f ftys )+ -- newly abstracted functions+ fs' = filter (\f -> null $ lookupValue (liftIdent pre f) vEnv) fs+ withLocalAbstractEnv env' $ do+ -- add variables to functions+ fds' <- mapM (absFunDecl pre fvs lvs) [d | d <- fds, any (`elem` fs') (bv d)]+ -- abstract remaining declarations+ e' <- absFunDecls pre lvs fdss vds e+ return (mkLet fds' e')++-- When the free variables of a function are abstracted, the type of the+-- function must be changed as well.++absFunDecl :: String -> [(Type, Ident)] -> [Ident] -> Decl Type+ -> LiftM (Decl Type)+absFunDecl pre fvs lvs (FunctionDecl p _ f eqs) = do+ m <- getModuleIdent+ d <- absDecl pre lvs $ FunctionDecl p undefined f' eqs'+ let FunctionDecl _ _ _ eqs'' = d+ modifyValueEnv $ bindGlobalInfo+ (\qf tySc -> Value qf Nothing (eqnArity $ head eqs') tySc) m f' $+ polyType ty''+ return $ FunctionDecl p ty'' f' eqs''+ where f' = liftIdent pre f+ ty' = foldr TypeArrow (typeOf rhs') (map typeOf ts')+ where Equation _ (FunLhs _ _ ts') rhs' = head eqs'+ ty'' = genType ty'+ eqs' = map addVars eqs+ genType ty''' = subst (foldr2 bindSubst idSubst tvs tvs') ty'''+ where tvs = nub (typeVars ty''')+ tvs' = map TypeVariable [0 ..]+ addVars (Equation p' (FunLhs _ _ ts) rhs) =+ Equation p' (FunLhs NoSpanInfo+ f' (map (uncurry (VariablePattern NoSpanInfo)) fvs ++ ts)) rhs+ addVars _ = error "Lift.absFunDecl.addVars: no pattern match"+absFunDecl pre _ _ (ExternalDecl p vs) = ExternalDecl p <$> mapM (absVar pre) vs+absFunDecl _ _ _ _ = error "Lift.absFunDecl: no pattern match"++absVar :: String -> Var Type -> LiftM (Var Type)+absVar pre (Var ty f) = do+ m <- getModuleIdent+ modifyValueEnv $ bindGlobalInfo+ (\qf tySc -> Value qf Nothing (arrowArity ty) tySc) m f' $ polyType ty+ return $ Var ty f'+ where f' = liftIdent pre f++absExpr :: String -> [Ident] -> Expression Type -> LiftM (Expression Type)+absExpr _ _ l@(Literal _ _ _) = return l+absExpr pre lvs var@(Variable _ ty v)+ | isQualified v = return var+ | otherwise = do+ getAbstractEnv >>= \env -> case Map.lookup (unqualify v) env of+ Nothing -> return var+ Just (e, fty) -> let unifier = matchType fty ty idSubst+ in absExpr pre lvs $ fmap (subst unifier) $ absType ty e+ where -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!+ -- !!! HACK: When inserting the replacement expression for an !!!+ -- !!! abstracted function, we have to unify the original !!!+ -- !!! function type with the instantiated function type in order !!!+ -- !!! to obtain a type substitution that can then be applied to !!!+ -- !!! the type annotations in the replacement expression. !!!+ -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!+ absType ty' (Variable spi _ v') = Variable spi ty' v'+ absType ty' (Apply spi e1 e2) =+ Apply spi (absType (TypeArrow (typeOf e2) ty') e1) e2+ absType _ _ = internalError "Lift.absExpr.absType"+absExpr _ _ c@(Constructor _ _ _) = return c+absExpr pre lvs (Apply spi e1 e2) = Apply spi <$> absExpr pre lvs e1+ <*> absExpr pre lvs e2+absExpr pre lvs (Let _ _ ds e) = absDeclGroup pre lvs ds e+absExpr pre lvs (Case _ _ ct e bs) =+ mkCase ct <$> absExpr pre lvs e <*> mapM (absAlt pre lvs) bs+absExpr pre lvs (Typed spi e ty) =+ flip (Typed spi) ty <$> absExpr pre lvs e+absExpr _ _ e = internalError $ "Lift.absExpr: " ++ show e++absAlt :: String -> [Ident] -> Alt Type -> LiftM (Alt Type)+absAlt pre lvs (Alt p t rhs) = Alt p t <$> absRhs pre lvs' rhs+ where lvs' = lvs ++ bv t++-- -----------------------------------------------------------------------------+-- Lifting+-- -----------------------------------------------------------------------------++-- After the abstraction pass, all local function declarations are lifted+-- to the top-level.++liftFunDecl :: Eq a => Decl a -> [Decl a]+liftFunDecl (FunctionDecl p a f eqs) =+ FunctionDecl p a f eqs' : map renameFunDecl (concat dss')+ where (eqs', dss') = unzip $ map liftEquation eqs+liftFunDecl d = [d]++liftVarDecl :: Eq a => Decl a -> (Decl a, [Decl a])+liftVarDecl (PatternDecl p t rhs) = (PatternDecl p t rhs', ds')+ where (rhs', ds') = liftRhs rhs+liftVarDecl ex@(FreeDecl _ _) = (ex, [])+liftVarDecl _ = error "Lift.liftVarDecl: no pattern match"++liftEquation :: Eq a => Equation a -> (Equation a, [Decl a])+liftEquation (Equation p lhs rhs) = (Equation p lhs rhs', ds')+ where (rhs', ds') = liftRhs rhs++liftRhs :: Eq a => Rhs a -> (Rhs a, [Decl a])+liftRhs (SimpleRhs p _ e _) = first (simpleRhs p) (liftExpr e)+liftRhs _ = error "Lift.liftRhs: no pattern match"++liftDeclGroup :: Eq a => [Decl a] -> ([Decl a], [Decl a])+liftDeclGroup ds = (vds', concat (map liftFunDecl fds ++ dss'))+ where (fds , vds ) = partition isFunDecl ds+ (vds', dss') = unzip $ map liftVarDecl vds++liftExpr :: Eq a => Expression a -> (Expression a, [Decl a])+liftExpr l@(Literal _ _ _) = (l, [])+liftExpr v@(Variable _ _ _) = (v, [])+liftExpr c@(Constructor _ _ _) = (c, [])+liftExpr (Apply spi e1 e2) = (Apply spi e1' e2', ds1 ++ ds2)+ where (e1', ds1) = liftExpr e1+ (e2', ds2) = liftExpr e2+liftExpr (Let _ _ ds e) = (mkLet ds' e', ds1 ++ ds2)+ where (ds', ds1) = liftDeclGroup ds+ (e' , ds2) = liftExpr e+liftExpr (Case _ _ ct e alts) = (mkCase ct e' alts', concat $ ds' : dss')+ where (e' , ds' ) = liftExpr e+ (alts', dss') = unzip $ map liftAlt alts+liftExpr (Typed spi e ty) =+ (Typed spi e' ty, ds) where (e', ds) = liftExpr e+liftExpr _ = internalError "Lift.liftExpr"++liftAlt :: Eq a => Alt a -> (Alt a, [Decl a])+liftAlt (Alt p t rhs) = (Alt p t rhs', ds') where (rhs', ds') = liftRhs rhs++-- -----------------------------------------------------------------------------+-- Renaming+-- -----------------------------------------------------------------------------++-- After all local function declarations have been lifted to top-level, we+-- may have to rename duplicate function arguments. Due to polymorphic let+-- declarations it could happen that an argument was added multiple times+-- instantiated with different types during the abstraction pass beforehand.++type RenameMap a = [((a, Ident), Ident)]++renameFunDecl :: Eq a => Decl a -> Decl a+renameFunDecl (FunctionDecl p a f eqs) =+ FunctionDecl p a f (map renameEquation eqs)+renameFunDecl d = d++renameEquation :: Eq a => Equation a -> Equation a+renameEquation (Equation p lhs rhs) = Equation p lhs' (renameRhs rm rhs)+ where (rm, lhs') = renameLhs lhs++renameLhs :: Eq a => Lhs a -> (RenameMap a, Lhs a)+renameLhs (FunLhs spi f ts) = (rm, FunLhs spi f ts')+ where (rm, ts') = foldr renamePattern ([], []) ts+renameLhs _ = error "Lift.renameLhs"++renamePattern :: Eq a => Pattern a -> (RenameMap a, [Pattern a])+ -> (RenameMap a, [Pattern a])+renamePattern (VariablePattern spi a v) (rm, ts)+ | v `elem` varPatNames ts =+ let v' = updIdentName (++ ("." ++ show (length rm))) v+ in (((a, v), v') : rm, VariablePattern spi a v' : ts)+renamePattern t (rm, ts) = (rm, t : ts)++renameRhs :: Eq a => RenameMap a -> Rhs a -> Rhs a+renameRhs rm (SimpleRhs p _ e _) = simpleRhs p (renameExpr rm e)+renameRhs _ _ = error "Lift.renameRhs"++renameExpr :: Eq a => RenameMap a -> Expression a -> Expression a+renameExpr _ l@(Literal _ _ _) = l+renameExpr rm v@(Variable spi a v')+ | isQualified v' = v+ | otherwise = case lookup (a, unqualify v') rm of+ Just v'' -> Variable spi a (qualify v'')+ _ -> v+renameExpr _ c@(Constructor _ _ _) = c+renameExpr rm (Typed spi e ty) = Typed spi (renameExpr rm e) ty+renameExpr rm (Apply spi e1 e2) =+ Apply spi (renameExpr rm e1) (renameExpr rm e2)+renameExpr rm (Let _ _ ds e) =+ mkLet (map (renameDecl rm) ds) (renameExpr rm e)+renameExpr rm (Case _ _ ct e alts) =+ mkCase ct (renameExpr rm e) (map (renameAlt rm) alts)+renameExpr _ _ = error "Lift.renameExpr"++renameDecl :: Eq a => RenameMap a -> Decl a -> Decl a+renameDecl rm (PatternDecl p t rhs) = PatternDecl p t (renameRhs rm rhs)+renameDecl _ d = d++renameAlt :: Eq a => RenameMap a -> Alt a -> Alt a+renameAlt rm (Alt p t rhs) = Alt p t (renameRhs rm rhs)++-- ---------------------------------------------------------------------------+-- Auxiliary definitions+-- ---------------------------------------------------------------------------++isFunDecl :: Decl a -> Bool+isFunDecl (FunctionDecl _ _ _ _) = True+isFunDecl (ExternalDecl _ _ ) = True+isFunDecl _ = False++mkFun :: ModuleIdent -> String -> a -> Ident -> Expression a+mkFun m pre a = Variable NoSpanInfo a . qualifyWith m . liftIdent pre++liftIdent :: String -> Ident -> Ident+liftIdent prefix x = renameIdent (mkIdent $ prefix ++ showIdent x) $ idUnique x++varPatNames :: [Pattern a] -> [Ident]+varPatNames = mapMaybe varPatName++varPatName :: Pattern a -> Maybe Ident+varPatName (VariablePattern _ _ i) = Just i+varPatName _ = Nothing++dummyType :: Type+dummyType = TypeForall [] undefined++isDummyType :: Type -> Bool+isDummyType (TypeForall [] _) = True+isDummyType _ = False
+ src/Transformations/Newtypes.hs view
@@ -0,0 +1,113 @@+{- |+ Module : $Header$+ Description : Removing newtype constructors+ Copyright : (c) 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : fte@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ After inserting dictionaries, the compiler removes all occurences of+ newtype declarations. Applications 'N x' in patterns and expressions,+ where 'N' is a newtype constructor, are replaced by a 'x'. The newtype+ declarations are replaced by type synonyms and partial applications of+ newtype constructors are changed into calls to 'Prelude.id'.+-}+{-# LANGUAGE CPP #-}+module Transformations.Newtypes (removeNewtypes) where++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative ((<$>), (<*>))+#endif+import qualified Control.Monad.Reader as R++import Curry.Base.Ident+import Curry.Syntax++import Base.Messages (internalError)+import Base.Types++import Env.Value (ValueEnv, ValueInfo (..), qualLookupValue)++removeNewtypes :: Bool -> ValueEnv -> Module Type -> Module Type+removeNewtypes remNT vEnv mdl+ | remNT = R.runReader (nt mdl) vEnv+ | otherwise = mdl++type NTM a = R.Reader ValueEnv a++class Show a => Newtypes a where+ nt :: a -> NTM a++instance Newtypes a => Newtypes [a] where+ nt = mapM nt++instance Show a => Newtypes (Module a) where+ nt (Module spi li ps m es is ds) = Module spi li ps m es is <$> mapM nt ds++instance Show a => Newtypes (Decl a) where+ nt d@(InfixDecl _ _ _ _) = return d+ nt d@(DataDecl _ _ _ _ _) = return d+ nt d@(ExternalDataDecl _ _ _) = return d+ nt (NewtypeDecl p tc vs nc []) = return $ TypeDecl p tc vs $ nconstrType nc+ nt d@(TypeDecl _ _ _ _) = return d+ nt (FunctionDecl p a f eqs) = FunctionDecl p a f <$> nt eqs+ nt d@(ExternalDecl _ _) = return d+ nt (PatternDecl p t rhs) = PatternDecl p <$> nt t <*> nt rhs+ nt d@(FreeDecl _ _) = return d+ nt d = internalError $+ "Newtypes.Newtypes.nt: unexpected declaration: " ++ show d++instance Show a => Newtypes (Equation a) where+ nt (Equation p lhs rhs) = Equation p <$> nt lhs <*> nt rhs++instance Show a => Newtypes (Lhs a) where+ nt (FunLhs spi f ts) = FunLhs spi f <$> nt ts+ nt lhs = internalError $+ "Newtypes.Newtypes.nt: unexpected left-hand-side: " ++ show lhs++instance Show a => Newtypes (Rhs a) where+ nt (SimpleRhs p li e []) = flip (SimpleRhs p li) [] <$> nt e+ nt rhs = internalError $+ "Newtypes.Newtypes.nt: unexpected right-hand-side: " ++ show rhs++instance Show a => Newtypes (Pattern a) where+ nt t@(LiteralPattern _ _ _) = return t+ nt t@(VariablePattern _ _ _) = return t+ nt (ConstructorPattern spi a c ts) = case ts of+ [t] -> do+ isNc <- isNewtypeConstr c+ if isNc then nt t+ else ConstructorPattern spi a c <$> ((: []) <$> nt t)+ _ -> ConstructorPattern spi a c <$> mapM nt ts+ nt (AsPattern spi v t) = AsPattern spi v <$> nt t+ nt t = internalError $+ "Newtypes.Newtypes.nt: unexpected pattern: " ++ show t++instance Show a => Newtypes (Expression a) where+ nt e@(Literal _ _ _) = return e+ nt e@(Variable _ _ _) = return e+ nt (Constructor spi a c) = do+ isNc <- isNewtypeConstr c+ return $ if isNc then Variable spi a qIdId else Constructor spi a c+ nt (Apply spi e1 e2) = case e1 of+ Constructor _ _ c -> do+ isNc <- isNewtypeConstr c+ if isNc then nt e2 else Apply spi <$> nt e1 <*> nt e2+ _ -> Apply spi <$> nt e1 <*> nt e2+ nt (Case spi li ct e as) = Case spi li ct <$> nt e <*> mapM nt as+ nt (Let spi li ds e) = Let spi li <$> nt ds <*> nt e+ nt (Typed spi e qty) = flip (Typed spi) qty <$> nt e+ nt e = internalError $+ "Newtypes.Newtypes.nt: unexpected expression: " ++ show e++instance Show a => Newtypes (Alt a) where+ nt (Alt p t rhs) = Alt p <$> nt t <*> nt rhs++isNewtypeConstr :: QualIdent -> NTM Bool+isNewtypeConstr c = R.ask >>= \vEnv -> return $+ case qualLookupValue c vEnv of+ [NewtypeConstructor _ _ _] -> True+ [DataConstructor _ _ _ _] -> False+ _ -> internalError $ "Newtypes.isNewtypeConstr: " ++ show c
+ src/Transformations/Qual.hs view
@@ -0,0 +1,250 @@+{- |+ Module : $Header$+ Description : Proper Qualification+ Copyright : (c) 2001 - 2004 Wolfgang Lux+ 2005 Martin Engelke+ 2011 - 2015 Björn Peemöller+ 2016 - 2017 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ After checking the module and before starting the translation into the+ intermediate language, the compiler properly qualifies all type+ constructors, data constructors and (global) functions+ occurring in a pattern or expression such that their module prefix+ matches the module of their definition.+ This is done also for functions and constructors declared+ in the current module.+ Only functions and variables declared in local declarations groups+ as well as function arguments remain unchanged.+-}+{-# LANGUAGE CPP #-}+module Transformations.Qual (qual) where++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative ((<$>), (<*>), pure)+#endif+import qualified Control.Monad.Reader as R (Reader, asks, runReader)+import Data.Traversable+import Prelude hiding (mapM)++import Curry.Base.Ident+import Curry.Syntax++import Base.TopEnv (origName)++import Env.TypeConstructor (TCEnv , qualLookupTypeInfo)+import Env.Value (ValueEnv, qualLookupValue)++data QualEnv = QualEnv+ { moduleIdent :: ModuleIdent+ , tyConsEnv :: TCEnv+ , valueEnv :: ValueEnv+ }++type Qual a = a -> R.Reader QualEnv a++qual :: ModuleIdent -> TCEnv -> ValueEnv -> Module a -> Module a+qual m tcEnv tyEnv mdl = R.runReader (qModule mdl) (QualEnv m tcEnv tyEnv)++qModule :: Qual (Module a)+qModule (Module spi li ps m es is ds) = do+ es' <- qExportSpec es+ ds' <- mapM qDecl ds+ return (Module spi li ps m es' is ds')++qExportSpec :: Qual (Maybe ExportSpec)+qExportSpec Nothing = return Nothing+qExportSpec (Just (Exporting p es)) = (Just . Exporting p) <$> mapM qExport es++qExport :: Qual Export+qExport (Export spi x) = Export spi <$> qIdent x+qExport (ExportTypeWith spi t cs) = flip (ExportTypeWith spi) cs <$> qConstr t+qExport (ExportTypeAll spi t) = ExportTypeAll spi <$> qConstr t+qExport m@(ExportModule _ _) = return m++qDecl :: Qual (Decl a)+qDecl i@(InfixDecl _ _ _ _) = return i+qDecl (DataDecl p n vs cs clss) = DataDecl p n vs <$>+ mapM qConstrDecl cs <*> mapM qClass clss+qDecl e@(ExternalDataDecl _ _ _) = return e+qDecl (NewtypeDecl p n vs nc clss) = NewtypeDecl p n vs <$>+ qNewConstrDecl nc <*> mapM qClass clss+qDecl (TypeDecl p n vs ty) = TypeDecl p n vs <$> qTypeExpr ty+qDecl (TypeSig p fs qty) = TypeSig p fs <$> qQualTypeExpr qty+qDecl (FunctionDecl a p f eqs) = FunctionDecl a p f <$> mapM qEquation eqs+qDecl e@(ExternalDecl _ _) = return e+qDecl (PatternDecl p t rhs) = PatternDecl p <$> qPattern t <*> qRhs rhs+qDecl vs@(FreeDecl _ _) = return vs+qDecl (DefaultDecl p tys) = DefaultDecl p <$> mapM qTypeExpr tys+qDecl (ClassDecl p li cx cls tv ds) = ClassDecl p li <$>+ qContext cx <*> pure cls <*> pure tv <*> mapM qDecl ds+qDecl (InstanceDecl p li cx qcls ty ds) = InstanceDecl p li <$>+ qContext cx <*> qClass qcls <*> qTypeExpr ty <*> mapM qDecl ds++qConstrDecl :: Qual ConstrDecl+qConstrDecl (ConstrDecl p n tys) =+ ConstrDecl p n <$> mapM qTypeExpr tys+qConstrDecl (ConOpDecl p ty1 op ty2) =+ ConOpDecl p <$> qTypeExpr ty1 <*> pure op <*> qTypeExpr ty2+qConstrDecl (RecordDecl p c fs) =+ RecordDecl p c <$> mapM qFieldDecl fs++qNewConstrDecl :: Qual NewConstrDecl+qNewConstrDecl (NewConstrDecl p n ty)+ = NewConstrDecl p n <$> qTypeExpr ty+qNewConstrDecl (NewRecordDecl p n (f, ty))+ = (\ty' -> NewRecordDecl p n (f, ty')) <$> qTypeExpr ty++qFieldDecl :: Qual FieldDecl+qFieldDecl (FieldDecl p fs ty) = FieldDecl p fs <$> qTypeExpr ty++qConstraint :: Qual Constraint+qConstraint (Constraint spi cls ty) =+ Constraint spi <$> qClass cls <*> qTypeExpr ty++qContext :: Qual Context+qContext = mapM qConstraint++qTypeExpr :: Qual TypeExpr+qTypeExpr (ConstructorType spi c) = ConstructorType spi <$> qConstr c+qTypeExpr (ApplyType spi ty1 ty2) = ApplyType spi <$> qTypeExpr ty1+ <*> qTypeExpr ty2+qTypeExpr v@(VariableType _ _) = return v+qTypeExpr (TupleType spi tys) = TupleType spi <$> mapM qTypeExpr tys+qTypeExpr (ListType spi ty) = ListType spi <$> qTypeExpr ty+qTypeExpr (ArrowType spi ty1 ty2) = ArrowType spi <$> qTypeExpr ty1+ <*> qTypeExpr ty2+qTypeExpr (ParenType spi ty) = ParenType spi <$> qTypeExpr ty+qTypeExpr (ForallType spi vs ty) = ForallType spi vs <$> qTypeExpr ty++qQualTypeExpr :: Qual QualTypeExpr+qQualTypeExpr (QualTypeExpr spi cx ty) = QualTypeExpr spi <$> qContext cx+ <*> qTypeExpr ty++qEquation :: Qual (Equation a)+qEquation (Equation p lhs rhs) = Equation p <$> qLhs lhs <*> qRhs rhs++qLhs :: Qual (Lhs a)+qLhs (FunLhs sp f ts) = FunLhs sp f <$> mapM qPattern ts+qLhs (OpLhs sp t1 op t2) = flip (OpLhs sp) op <$> qPattern t1 <*> qPattern t2+qLhs (ApLhs sp lhs ts) = ApLhs sp <$> qLhs lhs <*> mapM qPattern ts++qPattern :: Qual (Pattern a)+qPattern l@(LiteralPattern _ _ _) = return l+qPattern n@(NegativePattern _ _ _) = return n+qPattern v@(VariablePattern _ _ _) = return v+qPattern (ConstructorPattern spi a c ts) =+ ConstructorPattern spi a <$> qIdent c <*> mapM qPattern ts+qPattern (InfixPattern spi a t1 op t2) =+ InfixPattern spi a <$> qPattern t1 <*> qIdent op <*> qPattern t2+qPattern (ParenPattern spi t) = ParenPattern spi <$> qPattern t+qPattern (RecordPattern spi a c fs) = RecordPattern spi a <$> qIdent c+ <*> mapM (qField qPattern) fs+qPattern (TuplePattern spi ts) =+ TuplePattern spi <$> mapM qPattern ts+qPattern (ListPattern spi a ts) =+ ListPattern spi a <$> mapM qPattern ts+qPattern (AsPattern spi v t) = AsPattern spi v <$> qPattern t+qPattern (LazyPattern spi t) = LazyPattern spi <$> qPattern t+qPattern (FunctionPattern spi a f ts) =+ FunctionPattern spi a <$> qIdent f <*> mapM qPattern ts+qPattern (InfixFuncPattern spi a t1 op t2) =+ InfixFuncPattern spi a <$> qPattern t1 <*> qIdent op <*> qPattern t2++qRhs :: Qual (Rhs a)+qRhs (SimpleRhs spi li e ds) =+ SimpleRhs spi li <$> qExpr e <*> mapM qDecl ds+qRhs (GuardedRhs spi li es ds) =+ GuardedRhs spi li <$> mapM qCondExpr es <*> mapM qDecl ds++qCondExpr :: Qual (CondExpr a)+qCondExpr (CondExpr p g e) = CondExpr p <$> qExpr g <*> qExpr e++qExpr :: Qual (Expression a)+qExpr l@(Literal _ _ _) = return l+qExpr (Variable spi a v) = Variable spi a <$> qIdent v+qExpr (Constructor spi a c) = Constructor spi a <$> qIdent c+qExpr (Paren spi e) = Paren spi <$> qExpr e+qExpr (Typed spi e qty) = Typed spi <$> qExpr e+ <*> qQualTypeExpr qty+qExpr (Record spi a c fs) =+ Record spi a <$> qIdent c <*> mapM (qField qExpr) fs+qExpr (RecordUpdate spi e fs) =+ RecordUpdate spi <$> qExpr e <*> mapM (qField qExpr) fs+qExpr (Tuple spi es) = Tuple spi <$> mapM qExpr es+qExpr (List spi a es) = List spi a <$> mapM qExpr es+qExpr (ListCompr spi e qs) = ListCompr spi <$> qExpr e+ <*> mapM qStmt qs+qExpr (EnumFrom spi e) = EnumFrom spi <$> qExpr e+qExpr (EnumFromThen spi e1 e2) = EnumFromThen spi <$> qExpr e1+ <*> qExpr e2+qExpr (EnumFromTo spi e1 e2) = EnumFromTo spi <$> qExpr e1+ <*> qExpr e2+qExpr (EnumFromThenTo spi e1 e2 e3) = EnumFromThenTo spi <$> qExpr e1+ <*> qExpr e2+ <*> qExpr e3+qExpr (UnaryMinus spi e) = UnaryMinus spi <$> qExpr e+qExpr (Apply spi e1 e2) = Apply spi <$> qExpr e1+ <*> qExpr e2+qExpr (InfixApply spi e1 op e2) = InfixApply spi <$> qExpr e1+ <*> qInfixOp op+ <*> qExpr e2+qExpr (LeftSection spi e op) = LeftSection spi <$> qExpr e+ <*> qInfixOp op+qExpr (RightSection spi op e) = RightSection spi <$> qInfixOp op+ <*> qExpr e+qExpr (Lambda spi ts e) = Lambda spi <$> mapM qPattern ts+ <*> qExpr e+qExpr (Let spi li ds e) = Let spi li <$> mapM qDecl ds <*> qExpr e+qExpr (Do spi li sts e) = Do spi li <$> mapM qStmt sts <*> qExpr e+qExpr (IfThenElse spi e1 e2 e3) = IfThenElse spi <$> qExpr e1 <*> qExpr e2+ <*> qExpr e3+qExpr (Case spi li ct e as) = Case spi li ct <$> qExpr e <*> mapM qAlt as++qStmt :: Qual (Statement a)+qStmt (StmtExpr spi e) = StmtExpr spi <$> qExpr e+qStmt (StmtBind spi t e) = StmtBind spi <$> qPattern t <*> qExpr e+qStmt (StmtDecl spi li ds) = StmtDecl spi li <$> mapM qDecl ds++qAlt :: Qual (Alt a)+qAlt (Alt p t rhs) = Alt p <$> qPattern t <*> qRhs rhs++qField :: Qual a -> Qual (Field a)+qField q (Field p l x) = Field p <$> qIdent l <*> q x++qInfixOp :: Qual (InfixOp a)+qInfixOp (InfixOp a op) = InfixOp a <$> qIdent op+qInfixOp (InfixConstr a op) = InfixConstr a <$> qIdent op++qIdent :: Qual QualIdent+qIdent x | isQualified x = x'+ | hasGlobalScope (unqualify x) = x'+ | otherwise = return x+ where+ x' = do+ m <- R.asks moduleIdent+ tyEnv <- R.asks valueEnv+ return $ case qualLookupValue x tyEnv of+ [y] -> origName y+ _ -> case qualLookupValue qmx tyEnv of+ [y] -> origName y+ _ -> qmx+ where qmx = qualQualify m x++qConstr :: Qual QualIdent+qConstr x = do+ m <- R.asks moduleIdent+ tcEnv <- R.asks tyConsEnv+ return $ case qualLookupTypeInfo x tcEnv of+ [y] -> origName y+ _ -> case qualLookupTypeInfo qmx tcEnv of+ [y] -> origName y+ _ -> qmx+ where qmx = qualQualify m x++qClass :: Qual QualIdent+qClass = qConstr
+ src/Transformations/Simplify.hs view
@@ -0,0 +1,347 @@+{- |+ Module : $Header$+ Description : Optimizing the Desugared Code+ Copyright : (c) 2003 Wolfgang Lux+ Martin Engelke+ 2011 - 2015 Björn Peemöller+ 2016 Finn Teegen+ License : BSD-3-clause++ Maintainer : bjp@informatik.uni-kiel.de+ Stability : experimental+ Portability : portable++ After desugaring the source code, but before lifting local+ declarations, the compiler performs a few simple optimizations to+ improve the efficiency of the generated code. In addition, the+ optimizer replaces pattern bindings with simple variable bindings and+ selector functions.++ Currently, the following optimizations are implemented:++ * Under certain conditions, inline local function definitions.+ * Remove unused declarations.+ * Compute minimal binding groups for let expressions.+ * Remove pattern bindings to constructor terms+ * Inline simple constants.+-}+{-# LANGUAGE CPP #-}+module Transformations.Simplify (simplify) where++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative ((<$>), (<*>))+#endif+import Control.Monad.Extra (concatMapM)+import Control.Monad.State as S (State, runState, gets, modify)+import qualified Data.Map as Map (Map, empty, insert, lookup)++import Curry.Base.Ident+import Curry.Base.SpanInfo+import Curry.Syntax++import Base.Expr+import Base.Messages (internalError)+import Base.SCC+import Base.Types+import Base.Typing+import Base.Utils++import Env.Value (ValueEnv, ValueInfo (..), qualLookupValue)++-- -----------------------------------------------------------------------------+-- Simplification+-- -----------------------------------------------------------------------------++simplify :: ValueEnv -> Module Type -> (Module Type, ValueEnv)+simplify vEnv mdl@(Module _ _ _ m _ _ _) = (mdl', valueEnv s')+ where (mdl', s') = S.runState (simModule mdl) (SimplifyState m vEnv 1)++-- -----------------------------------------------------------------------------+-- Internal state monad+-- -----------------------------------------------------------------------------++data SimplifyState = SimplifyState+ { moduleIdent :: ModuleIdent -- read-only!+ , valueEnv :: ValueEnv -- updated for new pattern selection functions+ , nextId :: Int -- counter+ }++type SIM = S.State SimplifyState++getModuleIdent :: SIM ModuleIdent+getModuleIdent = S.gets moduleIdent++getNextId :: SIM Int+getNextId = do+ nid <- S.gets nextId+ S.modify $ \s -> s { nextId = succ nid }+ return nid++getFunArity :: QualIdent -> SIM Int+getFunArity f = do+ vEnv <- getValueEnv+ return $ case qualLookupValue f vEnv of+ [Value _ _ a _] -> a+ [Label _ _ _] -> 1+ _ -> internalError $ "Simplify.funType " ++ show f++getValueEnv :: SIM ValueEnv+getValueEnv = S.gets valueEnv++freshIdent :: (Int -> Ident) -> SIM Ident+freshIdent f = f <$> getNextId++-- -----------------------------------------------------------------------------+-- Simplification+-- -----------------------------------------------------------------------------++simModule :: Module Type -> SIM (Module Type)+simModule (Module spi li ps m es is ds) = Module spi li ps m es is+ <$> mapM (simDecl Map.empty) ds++-- Inline an expression for a variable+type InlineEnv = Map.Map Ident (Expression Type)++simDecl :: InlineEnv -> Decl Type -> SIM (Decl Type)+simDecl env (FunctionDecl p ty f eqs) = FunctionDecl p ty f+ <$> concatMapM (simEquation env) eqs+simDecl env (PatternDecl p t rhs) = PatternDecl p t <$> simRhs env rhs+simDecl _ d = return d++simEquation :: InlineEnv -> Equation Type -> SIM [Equation Type]+simEquation env (Equation p lhs rhs) = do+ rhs' <- simRhs env rhs+ inlineFun env p lhs rhs'++simRhs :: InlineEnv -> Rhs Type -> SIM (Rhs Type)+simRhs env (SimpleRhs p _ e _) = simpleRhs p <$> simExpr env e+simRhs _ (GuardedRhs _ _ _ _) = error "Simplify.simRhs: guarded rhs"++-- -----------------------------------------------------------------------------+-- Inlining of Functions+-- -----------------------------------------------------------------------------++-- After simplifying the right hand side of an equation, the compiler+-- transforms declarations of the form+--+-- f t_1 ... t_{k-l} x_{k-l+1} ... x_k =+-- let g y_1 ... y_l = e+-- in g x_{k-l+1} ... x_k+--+-- into the equivalent definition+--+-- f t_1 ... t_{k-l} x_{k-l+1} x_k = let y_1 = x_{k-l+1}+-- ...+-- y_l = x_k+-- in e+--+-- where the arities of 'f' and 'g' are 'k' and 'l', respectively, and+-- 'x_{k-l+1}, ... ,x_k' are variables. The transformation can obviously be+-- generalized to the case where 'g' is defined by more than one equation.+-- However, we must be careful not to change the evaluation mode of arguments.+-- Therefore, the transformation is applied only all of the arguments of 'g'+-- are variables.+--+-- This transformation is actually just a special case of inlining a+-- (local) function definition. We are unable to handle the general case+-- because it would require to represent the pattern matching code+-- explicitly in a Curry expression.++inlineFun :: InlineEnv -> SpanInfo -> Lhs Type -> Rhs Type+ -> SIM [Equation Type]+inlineFun env p lhs rhs = do+ m <- getModuleIdent+ case rhs of+ SimpleRhs _ _ (Let _ _ [FunctionDecl _ _ f' eqs'] e) _+ | -- @f'@ is not recursive+ f' `notElem` qfv m eqs'+ -- @f'@ does not perform any pattern matching+ && and [all isVariablePattern ts1 | Equation _ (FunLhs _ _ ts1) _ <- eqs']+ -> do+ let a = eqnArity $ head eqs'+ (n, vs', e') = etaReduce 0 [] (reverse (snd $ flatLhs lhs)) e+ if -- the eta-reduced rhs of @f@ is a call to @f'@+ setSpanInfo NoSpanInfo e' == Variable NoSpanInfo (typeOf e') (qualify f')+ -- @f'@ was fully applied before eta-reduction+ && n == a+ then mapM (mergeEqns p vs') eqs'+ else return [Equation p lhs rhs]+ _ -> return [Equation p lhs rhs]+ where+ etaReduce n1 vs (VariablePattern _ ty v : ts1)+ (Apply _ e1 (Variable _ _ v'))+ | qualify v == v' = etaReduce (n1 + 1) ((ty, v) : vs) ts1 e1+ etaReduce n1 vs _ e1 = (n1, vs, e1)++ mergeEqns p1 vs (Equation _ (FunLhs _ _ ts2) (SimpleRhs p2 _ e _))+ = Equation p1 lhs <$> simRhs env (simpleRhs p2 (mkLet ds e))+ where+ ds = zipWith (\t v -> PatternDecl NoSpanInfo t (simpleRhs p2 (uncurry mkVar v)))+ ts2+ vs+ mergeEqns _ _ _ = error "Simplify.inlineFun.mergeEqns: no pattern match"++-- -----------------------------------------------------------------------------+-- Simplification of Expressions+-- -----------------------------------------------------------------------------++-- Variables that are bound to (simple) constants and aliases to other+-- variables are substituted. In terms of conventional compiler technology,+-- these optimizations correspond to constant propagation and copy propagation,+-- respectively. The transformation is applied recursively to a substituted+-- variable in order to handle chains of variable definitions.++-- Applications of let-expressions and case-expressions to other expressions+-- are simplified according to the following rules:+-- (let ds in e_1) e_2 -> let ds in (e1 e2)+-- (case e_1 of p'_n -> e'_n) e_2 -> case e_1 of p'_n -> (e'n e_2)++-- The bindings of a let expression are sorted topologically in+-- order to split them into minimal binding groups. In addition,+-- local declarations occurring on the right hand side of a pattern+-- declaration are lifted into the enclosing binding group using the+-- equivalence (modulo alpha-conversion) of 'let x = let ds in e_1 in e_2'+-- and 'let ds; x = e_1 in e_2'.+-- This transformation avoids the creation of some redundant lifted+-- functions in later phases of the compiler.++simExpr :: InlineEnv -> Expression Type -> SIM (Expression Type)+simExpr _ l@(Literal _ _ _) = return l+simExpr _ c@(Constructor _ _ _) = return c+-- subsitution of variables+simExpr env v@(Variable _ ty x)+ | isQualified x = return v+ | otherwise =+ maybe (return v) (simExpr env . withType ty) (Map.lookup (unqualify x) env)+-- simplification of application+simExpr env (Apply _ e1 e2) = case e1 of+ Let _ _ ds e' -> simExpr env (mkLet ds (Apply NoSpanInfo e' e2))+ Case _ _ ct e' bs -> simExpr env (mkCase ct e' (map (applyToAlt e2) bs))+ _ -> Apply NoSpanInfo <$> simExpr env e1 <*> simExpr env e2+ where+ applyToAlt e (Alt p t rhs) = Alt p t (applyToRhs e rhs)+ applyToRhs e (SimpleRhs p _ e1' _) = simpleRhs p (Apply NoSpanInfo e1' e)+ applyToRhs _ (GuardedRhs _ _ _ _) = error "Simplify.simExpr.applyRhs: Guarded rhs"+-- simplification of declarations+simExpr env (Let _ _ ds e) = do+ m <- getModuleIdent+ dss <- mapM sharePatternRhs ds+ simplifyLet env (scc bv (qfv m) (foldr hoistDecls [] (concat dss))) e+simExpr env (Case _ _ ct e bs) =+ mkCase ct <$> simExpr env e <*> mapM (simplifyAlt env) bs+simExpr env (Typed _ e qty) =+ flip (Typed NoSpanInfo) qty <$> simExpr env e+simExpr _ _ = error "Simplify.simExpr: no pattern match"++-- Simplify a case alternative+simplifyAlt :: InlineEnv -> Alt Type -> SIM (Alt Type)+simplifyAlt env (Alt p t rhs) = Alt p t <$> simRhs env rhs++-- Transform a pattern declaration @t = e@ into two declarations+-- @t = v, v = e@ whenever @t@ is not a variable. This is used to share+-- the expression @e@ using the fresh variable @v@.+sharePatternRhs :: Decl Type -> SIM [Decl Type]+--TODO: change to patterns instead of case+sharePatternRhs (PatternDecl p t rhs) = case t of+ VariablePattern _ _ _ -> return [PatternDecl p t rhs]+ _ -> do+ let ty = typeOf t+ v <- freshIdent patternId+ return [ PatternDecl p t (simpleRhs p (mkVar ty v))+ , PatternDecl p (VariablePattern NoSpanInfo ty v) rhs+ ]+ where patternId n = mkIdent ("_#pat" ++ show n)+sharePatternRhs d = return [d]++-- Lift up nested let declarations in pattern declarations, i.e., replace+-- @let p = let ds' in e'; ds in e@ by @let ds'; p = e'; ds in e@.+hoistDecls :: Decl a -> [Decl a] -> [Decl a]+hoistDecls (PatternDecl p t (SimpleRhs p' _ (Let _ _ ds' e) _)) ds+ = foldr hoistDecls ds (PatternDecl p t (simpleRhs p' e) : ds')+hoistDecls d ds = d : ds++-- The declaration groups of a let expression are first processed from+-- outside to inside, simplifying the right hand sides and collecting+-- inlineable expressions on the fly. At present, only simple constants+-- and aliases to other variables are inlined. A constant is considered+-- simple if it is either a literal, a constructor, or a non-nullary+-- function. Note that it is not possible to define nullary functions in+-- local declarations in Curry. Thus, an unqualified name always refers+-- to either a variable or a non-nullary function. Applications of+-- constructors and partial applications of functions to at least one+-- argument are not inlined because the compiler has to allocate space+-- for them, anyway. In order to prevent non-termination, recursive+-- binding groups are not processed for inlining.++-- With the list of inlineable expressions, the body of the let is+-- simplified and then the declaration groups are processed from inside+-- to outside to construct the simplified, nested let expression. In+-- doing so, unused bindings are discarded. In addition, all pattern+-- bindings are replaced by simple variable declarations using selector+-- functions to access the pattern variables.++simplifyLet :: InlineEnv -> [[Decl Type]] -> Expression Type+ -> SIM (Expression Type)+simplifyLet env [] e = simExpr env e+simplifyLet env (ds:dss) e = do+ m <- getModuleIdent+ ds' <- mapM (simDecl env) ds -- simplify declarations+ env' <- inlineVars env ds' -- inline a simple variable binding+ e' <- simplifyLet env' dss e -- simplify remaining bindings+ ds'' <- concatMapM (expandPatternBindings (qfv m ds' ++ qfv m e')) ds'+ return $ foldr (mkLet' m) e' (scc bv (qfv m) ds'')++inlineVars :: InlineEnv -> [Decl Type] -> SIM InlineEnv+inlineVars env ds = case ds of+ [PatternDecl _ (VariablePattern _ _ v) (SimpleRhs _ _ e _)] -> do+ allowed <- canInlineVar v e+ return $ if allowed then Map.insert v e env else env+ _ -> return env+ where+ canInlineVar _ (Literal _ _ _) = return True+ canInlineVar _ (Constructor _ _ _) = return True+ canInlineVar v (Variable _ _ v')+ | isQualified v' = (> 0) <$> getFunArity v'+ | otherwise = return $ v /= unqualify v'+ canInlineVar _ _ = return False++mkLet' :: ModuleIdent -> [Decl Type] -> Expression Type -> Expression Type+mkLet' m [FreeDecl p vs] e+ | null vs' = e+ | otherwise = mkLet [FreeDecl p vs'] e -- remove unused free variables+ where vs' = filter ((`elem` qfv m e) . varIdent) vs+mkLet' m [PatternDecl _ (VariablePattern _ ty v) (SimpleRhs _ _ e _)] (Variable _ _ v')+ | v' == qualify v && v `notElem` qfv m e = withType ty e -- inline single binding+mkLet' m ds e+ | not (any (`elem` qfv m e) (bv ds)) = e -- removed unused bindings+ | otherwise = mkLet ds e++-- In order to implement lazy pattern matching in local declarations,+-- pattern declarations 't = e' where 't' is not a variable+-- are transformed into a list of declarations+-- 'v_0 = e; v_1 = f_1 v_0; ...; v_n = f_n v_0' where 'v_0' is a fresh+-- variable, 'v_1,...,v_n' are the variables occurring in 't' and the+-- auxiliary functions 'f_i' are defined by 'f_i t = v_i' (see also+-- appendix D.8 of the Curry report). The bindings 'v_0 = e' are introduced+-- before splitting the declaration groups of the enclosing let expression+-- (cf. the 'Let' case in 'simExpr' above) so that they are placed in their own+-- declaration group whenever possible. In particular, this ensures that+-- the new binding is discarded when the expression 'e' is itself a variable.++-- fvs contains all variables used in the declarations and the body+-- of the let expression.+expandPatternBindings :: [Ident] -> Decl Type -> SIM [Decl Type]+expandPatternBindings fvs d@(PatternDecl p t (SimpleRhs _ _ e _)) = case t of+ VariablePattern _ _ _ -> return [d]+ _ ->+ -- used variables+ mapM mkSelectorDecl (filter ((`elem` fvs) . fst3) (patternVars t))+ where+ pty = typeOf t -- type of pattern+ mkSelectorDecl (v, _, vty) = do+ let fty = TypeArrow pty vty+ f <- freshIdent (updIdentName (++ '#' : idName v) . fpSelectorId)+ return $ varDecl p vty v $+ mkLet [funDecl p fty f [t] (mkVar vty v)]+ (Apply NoSpanInfo (mkVar fty f) e)+expandPatternBindings _ d = return [d]
− src/TypeCheck.lhs
@@ -1,1331 +0,0 @@--% $Id: TypeCheck.lhs,v 1.90 2004/11/06 18:34:07 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{TypeCheck.lhs}-\section{Type Checking Curry Programs}-This module implements the type checker of the Curry compiler. The-type checker is invoked after the syntactic correctness of the program-has been verified. Local variables have been renamed already. Thus the-compiler can maintain a flat type environment (which is necessary in-order to pass the type information to later phases of the compiler).-The type checker now checks the correct typing of all expressions and-also verifies that the type signatures given by the user match the-inferred types. The type checker uses algorithm-W~\cite{DamasMilner82:Principal} for inferring the types of-unannotated declarations, but allows for polymorphic recursion when a-type annotation is present.-\begin{verbatim}--> module TypeCheck(typeCheck) where--> import Text.PrettyPrint.HughesPJ-> import Control.Monad.State as S-> import Data.List-> import Data.Maybe-> import qualified Data.Map as Map-> import qualified Data.Set as Set--> import Curry.Base.Position-> import Curry.Base.Ident-> import Curry.Syntax-> import Curry.Syntax.Pretty-> import Curry.Syntax.Utils---> import Base-> import Types-> import TopEnv-> import SCC-> import TypeSubst-> import Utils--> infixl 5 $-$--> ($-$) :: Doc -> Doc -> Doc-> x $-$ y = x $$ space $$ y--\end{verbatim}-Type checking proceeds as follows. First, the type constructor-environment is initialized by adding all types defined in the current-module. Next, the types of all data constructors and field labels-are entered into the type environment and then a type inference -for all function and value definitions is performed. -The type checker returns the resulting type-constructor and type environments.-\begin{verbatim}--> typeCheck :: ModuleIdent -> TCEnv -> ValueEnv -> [Decl] -> (TCEnv,ValueEnv)-> typeCheck m tcEnv tyEnv ds =-> run (tcDecls m tcEnv' Map.empty vds >>-> S.lift S.get >>= \theta -> S.get >>= \tyEnv' ->-> return (tcEnv',subst theta tyEnv'))-> (bindLabels m tcEnv' (bindConstrs m tcEnv' tyEnv))-> where (tds,vds) = partition isTypeDecl ds-> tcEnv' = bindTypes m tds tcEnv--\end{verbatim}--The type checker makes use of nested state monads in order to-maintain the type environment, the current substitution, and a counter-which is used for generating fresh type variables.-\begin{verbatim}--> type TcState a = S.StateT ValueEnv (S.StateT TypeSubst (S.State Int)) a--> run :: TcState a -> ValueEnv -> a-> run m tyEnv = S.evalState (S.evalStateT (S.evalStateT m tyEnv) idSubst) 0--\end{verbatim}-\paragraph{Defining Types}-Before type checking starts, the types defined in the local module-have to be entered into the type constructor environment. All type-synonyms occurring in the definitions are fully expanded and all type-constructors are qualified with the name of the module in which they-are defined. This is possible because Curry does not allow (mutually)-recursive type synonyms. In order to simplify the expansion of type-synonyms, the compiler first performs a dependency analysis on the-type definitions. This also makes it easy to identify (mutually)-recursive synonyms.--Note that \texttt{bindTC} is passed the \emph{final} type constructor-environment in order to handle the expansion of type synonyms. This-does not lead to a termination problem because \texttt{sortTypeDecls}-already has checked that there are no recursive type synonyms.--We have to be careful with existentially quantified type variables for-data constructors. An existentially quantified type variable may-shadow a universally quantified variable from the left hand side of-the type declaration. In order to avoid wrong indices being assigned-to these variables, we replace all shadowed variables in the left hand-side by \texttt{anonId} before passing them to \texttt{expandMonoType}-and \texttt{expandMonoTypes}, respectively.-\begin{verbatim}--> bindTypes :: ModuleIdent -> [Decl] -> TCEnv -> TCEnv-> bindTypes m ds tcEnv = tcEnv'-> where tcEnv' = foldr (bindTC m tcEnv') tcEnv (sortTypeDecls m ds)--> bindTC :: ModuleIdent -> TCEnv -> Decl -> TCEnv -> TCEnv-> bindTC m tcEnv (DataDecl _ tc tvs cs) =-> bindTypeInfo DataType m tc tvs (map (Just . mkData) cs)-> where mkData (ConstrDecl _ evs c tys) = Data c (length evs) tys'-> where tys' = expandMonoTypes m tcEnv (cleanTVars tvs evs) tys-> mkData (ConOpDecl _ evs ty1 op ty2) = Data op (length evs) tys'-> where tys' = expandMonoTypes m tcEnv (cleanTVars tvs evs) [ty1,ty2]-> bindTC m tcEnv (NewtypeDecl _ tc tvs (NewConstrDecl _ evs c ty)) =-> bindTypeInfo RenamingType m tc tvs (Data c (length evs) ty')-> where ty' = expandMonoType m tcEnv (cleanTVars tvs evs) ty-> bindTC m tcEnv (TypeDecl _ tc tvs ty) =-> bindTypeInfo AliasType m tc tvs (expandMonoType m tcEnv tvs ty)-> bindTC _ _ _ = id--> cleanTVars :: [Ident] -> [Ident] -> [Ident]-> cleanTVars tvs evs = [if tv `elem` evs then anonId else tv | tv <- tvs]--> sortTypeDecls :: ModuleIdent -> [Decl] -> [Decl]-> sortTypeDecls m = map (typeDecl m) . scc bound free-> where bound (DataDecl _ tc _ _) = [tc]-> bound (NewtypeDecl _ tc _ _) = [tc]-> bound (TypeDecl _ tc _ _) = [tc]-> free (DataDecl _ _ _ _) = []-> free (NewtypeDecl _ _ _ _) = []-> free (TypeDecl _ _ _ ty) = ft m ty []--> typeDecl :: ModuleIdent -> [Decl] -> Decl-> typeDecl _ [] = internalError "typeDecl"-> typeDecl _ [d@(DataDecl _ _ _ _)] = d-> typeDecl _ [d@(NewtypeDecl _ _ _ _)] = d-> typeDecl m [d@(TypeDecl p tc _ ty)]-> | tc `elem` ft m ty [] = errorAt' (recursiveTypes [tc])-> | otherwise = d-> typeDecl _ (TypeDecl p tc _ _ : ds) =-> errorAt' (recursiveTypes (tc : [tc' | TypeDecl _ tc' _ _ <- ds]))--> ft :: ModuleIdent -> TypeExpr -> [Ident] -> [Ident]-> ft m (ConstructorType tc tys) tcs =-> maybe id (:) (localIdent m tc) (foldr (ft m) tcs tys)-> ft _ (VariableType _) tcs = tcs-> ft m (TupleType tys) tcs = foldr (ft m) tcs tys-> ft m (ListType ty) tcs = ft m ty tcs-> ft m (ArrowType ty1 ty2) tcs = ft m ty1 $ ft m ty2 $ tcs-> ft m (RecordType fs rty) tcs = -> foldr (ft m) (maybe tcs (\ty -> ft m ty tcs) rty) (map snd fs)--\end{verbatim}-\paragraph{Defining Data Constructors}-In the next step, the types of all data constructors are entered into-the type environment using the information just entered into the type-constructor environment. Thus, we can be sure that all type variables-have been properly renamed and all type synonyms are already expanded.-\begin{verbatim}--> bindConstrs :: ModuleIdent -> TCEnv -> ValueEnv -> ValueEnv-> bindConstrs m tcEnv tyEnv =-> foldr (bindData . snd) tyEnv (localBindings tcEnv)-> where bindData (DataType tc n cs) tyEnv =-> foldr (bindConstr m n (constrType tc n)) tyEnv (catMaybes cs)-> bindData (RenamingType tc n (Data c n' ty)) tyEnv =-> bindGlobalInfo NewtypeConstructor m c-> (ForAllExist n n' (TypeArrow ty (constrType tc n)))-> tyEnv-> bindData (AliasType _ _ _) tyEnv = tyEnv-> bindConstr m n ty (Data c n' tys) =-> bindGlobalInfo DataConstructor m c-> (ForAllExist n n' (foldr TypeArrow ty tys))-> constrType tc n = TypeConstructor tc (map TypeVariable [0..n-1])--\end{verbatim}-\paragraph{Defining Field Labels}-Records can only be declared as type aliases. So currently there is-nothing more to do than entering all typed record fields (labels) -which occur in record types on the right-hand-side of type aliases -into the type environment. Since we use the type constructor environment-again, we can be sure that all type variables-have been properly renamed and all type synonyms are already expanded.-\begin{verbatim}--> bindLabels :: ModuleIdent -> TCEnv -> ValueEnv -> ValueEnv-> bindLabels m tcEnv tyEnv =-> foldr (bindFieldLabels . snd) tyEnv (localBindings tcEnv)-> where bindFieldLabels (AliasType r _ (TypeRecord fs _)) tyEnv =-> foldr (bindField r) tyEnv fs-> bindFieldLabels _ tyEnv = tyEnv-> -> bindField r (l,ty) tyEnv =-> case (lookupValue l tyEnv) of-> [] -> bindLabel l r (polyType ty) tyEnv -> _ -> tyEnv--\end{verbatim}-\paragraph{Type Signatures}-The type checker collects type signatures in a flat environment. All-anonymous variables occurring in a signature are replaced by fresh-names. However, the type is not expanded so that the signature is-available for use in the error message that is printed when the-inferred type is less general than the signature.-\begin{verbatim}--> type SigEnv = Map.Map Ident TypeExpr--> bindTypeSig :: Ident -> TypeExpr -> SigEnv -> SigEnv-> bindTypeSig = Map.insert--> bindTypeSigs :: Decl -> SigEnv -> SigEnv-> bindTypeSigs (TypeSig _ vs ty) env =-> foldr (flip bindTypeSig (nameSigType ty)) env vs -> bindTypeSigs _ env = env--> lookupTypeSig :: Ident -> SigEnv -> Maybe TypeExpr-> lookupTypeSig = Map.lookup--> qualLookupTypeSig :: ModuleIdent -> QualIdent -> SigEnv -> Maybe TypeExpr-> qualLookupTypeSig m f sigs = localIdent m f >>= flip lookupTypeSig sigs--> nameSigType :: TypeExpr -> TypeExpr-> nameSigType ty = fst (nameType ty (filter (`notElem` fv ty) nameSupply))--> nameTypes :: [TypeExpr] -> [Ident] -> ([TypeExpr],[Ident])-> nameTypes (ty:tys) tvs = (ty':tys',tvs'')-> where (ty',tvs') = nameType ty tvs-> (tys',tvs'') = nameTypes tys tvs'-> nameTypes [] tvs = ([],tvs)--> nameType :: TypeExpr -> [Ident] -> (TypeExpr,[Ident])-> nameType (ConstructorType tc tys) tvs = (ConstructorType tc tys',tvs')-> where (tys',tvs') = nameTypes tys tvs-> nameType (VariableType tv) (tv':tvs)-> | tv == anonId = (VariableType tv',tvs)-> | otherwise = (VariableType tv,tv':tvs)-> nameType (TupleType tys) tvs = (TupleType tys',tvs')-> where (tys',tvs') = nameTypes tys tvs-> nameType (ListType ty) tvs = (ListType ty',tvs')-> where (ty',tvs') = nameType ty tvs-> nameType (ArrowType ty1 ty2) tvs = (ArrowType ty1' ty2',tvs'')-> where (ty1',tvs') = nameType ty1 tvs-> (ty2',tvs'') = nameType ty2 tvs'-> nameType (RecordType fs rty) tvs = -> (RecordType (zip ls tys') (listToMaybe rty'), tvs)-> where (ls, tys) = unzip fs-> (tys', _) = nameTypes tys tvs-> (rty', _) = nameTypes (maybeToList rty) tvs- -\end{verbatim}-\paragraph{Type Inference}-Before type checking a group of declarations, a dependency analysis is-performed and the declaration group is eventually transformed into-nested declaration groups which are checked separately. Within each-declaration group, first the left hand sides of all declarations are-typed. Next, the right hand sides of the declarations are typed in the-extended type environment. Finally, the types for the left and right-hand sides are unified and the types of all defined functions are-generalized. The generalization step will also check that the type-signatures given by the user match the inferred types.--Argument and result types of foreign functions using the-\texttt{ccall} calling convention are restricted to the basic types-\texttt{Bool}, \texttt{Char}, \texttt{Int}, and \texttt{Float}. In-addition, \texttt{IO}~$t$ is a legitimate result type when $t$ is-either one of the basic types or \texttt{()}.--\ToDo{Extend the set of legitimate types to match the types admitted- by the Haskell Foreign Function Interface- Addendum.~\cite{Chakravarty03:FFI}}-\begin{verbatim}--> tcDecls :: ModuleIdent -> TCEnv -> SigEnv -> [Decl] -> TcState ()-> tcDecls m tcEnv sigs ds =-> mapM_ (tcDeclGroup m tcEnv (foldr bindTypeSigs sigs ods))-> (scc bv (qfv m) vds)-> where (vds,ods) = partition isValueDecl ds--> tcDeclGroup :: ModuleIdent -> TCEnv -> SigEnv -> [Decl] -> TcState ()-> --tcDeclGroup m tcEnv _ [ForeignDecl p cc _ f ty] =-> -- tcForeignFunct m tcEnv p cc f ty-> tcDeclGroup m tcEnv _ [ExternalDecl _ _ _ f ty] =-> tcExternalFunct m tcEnv f ty-> tcDeclGroup m tcEnv sigs [FlatExternalDecl _ fs] =-> mapM_ (tcFlatExternalFunct m tcEnv sigs) fs-> tcDeclGroup m tcEnv sigs [ExtraVariables _ vs] =-> mapM_ (tcExtraVar m tcEnv sigs ) vs-> tcDeclGroup m tcEnv sigs ds =-> do-> tyEnv0 <- S.get-> tysLhs <- mapM (tcDeclLhs m tcEnv sigs) ds-> tysRhs <- mapM (tcDeclRhs m tcEnv tyEnv0 sigs) ds-> sequence_ (zipWith3 (unifyDecl m) ds tysLhs tysRhs)-> theta <- S.lift S.get-> mapM_ (genDecl m tcEnv sigs (fvEnv (subst theta tyEnv0)) theta) ds--> --tcForeignFunct :: ModuleIdent -> TCEnv -> Position -> CallConv -> Ident-> -- -> TypeExpr -> TcState ()-> --tcForeignFunct m tcEnv p cc f ty =-> -- S.modify (bindFun m f (checkForeignType cc (expandPolyType tcEnv ty)))-> -- where checkForeignType CallConvPrimitive ty = ty-> -- checkForeignType CallConvCCall (ForAll n ty) =-> -- ForAll n (checkCCallType ty)-> -- checkCCallType (TypeArrow ty1 ty2)-> -- | isCArgType ty1 = TypeArrow ty1 (checkCCallType ty2)-> -- | otherwise = errorAt p (invalidCType "argument" m ty1)-> -- checkCCallType ty-> -- | isCResultType ty = ty-> -- | otherwise = errorAt p (invalidCType "result" m ty)-> -- isCArgType (TypeConstructor tc []) = tc `elem` basicTypeId-> -- isCArgType _ = False-> -- isCResultType (TypeConstructor tc []) = tc `elem` basicTypeId-> -- isCResultType (TypeConstructor tc [ty]) =-> -- tc == qIOId && (ty == unitType || isCArgType ty)-> -- isCResultType _ = False-> -- basicTypeId = [qBoolId,qCharId,qIntId,qFloatId]--> tcExternalFunct :: ModuleIdent -> TCEnv -> Ident -> TypeExpr -> TcState ()-> tcExternalFunct m tcEnv f ty =-> S.modify (bindFun m f (expandPolyType m tcEnv ty))--> tcFlatExternalFunct :: ModuleIdent -> TCEnv -> SigEnv -> Ident -> TcState ()-> tcFlatExternalFunct m tcEnv sigs f =-> typeOf f tcEnv sigs >>= S.modify . bindFun m f-> where typeOf f tcEnv sigs =-> case lookupTypeSig f sigs of-> Just ty -> return (expandPolyType m tcEnv ty)-> Nothing -> internalError "tcFlatExternalFunct"--> tcExtraVar :: ModuleIdent -> TCEnv -> SigEnv -> Ident-> -> TcState ()-> tcExtraVar m tcEnv sigs v =-> typeOf v tcEnv sigs >>= S.modify . bindFun m v . monoType-> where typeOf v tcEnv sigs =-> case lookupTypeSig v sigs of-> Just ty-> | n == 0 -> return ty'-> | otherwise -> errorAt' (polymorphicFreeVar v)-> where ForAll n ty' = expandPolyType m tcEnv ty-> Nothing -> freshTypeVar--> tcDeclLhs :: ModuleIdent -> TCEnv -> SigEnv -> Decl -> TcState Type-> tcDeclLhs m tcEnv sigs (FunctionDecl p f _) =-> tcConstrTerm m tcEnv sigs p (VariablePattern f)-> tcDeclLhs m tcEnv sigs (PatternDecl p t _) = tcConstrTerm m tcEnv sigs p t--> tcDeclRhs :: ModuleIdent -> TCEnv -> ValueEnv -> SigEnv -> Decl-> -> TcState Type-> tcDeclRhs m tcEnv tyEnv0 sigs (FunctionDecl _ f (eq:eqs)) =-> tcEquation m tcEnv tyEnv0 sigs eq >>= flip tcEqns eqs-> where tcEqns ty [] = return ty-> tcEqns ty (eq@(Equation p _ _):eqs) =-> tcEquation m tcEnv tyEnv0 sigs eq >>=-> unify p "equation" (ppDecl (FunctionDecl p f [eq])) m ty >>-> tcEqns ty eqs-> tcDeclRhs m tcEnv tyEnv0 sigs (PatternDecl _ _ rhs) =-> tcRhs m tcEnv tyEnv0 sigs rhs--> unifyDecl :: ModuleIdent -> Decl -> Type -> Type -> TcState ()-> unifyDecl m (FunctionDecl p f _) =-> unify p "function binding" (text "Function:" <+> ppIdent f) m-> unifyDecl m (PatternDecl p t _) =-> unify p "pattern binding" (ppConstrTerm 0 t) m--\end{verbatim}-In Curry we cannot generalize the types of let-bound variables because-they can refer to logic variables. Without this monomorphism-restriction unsound code like-\begin{verbatim}-bug = x =:= 1 & x =:= 'a'- where x :: a- x = fresh-fresh :: a-fresh = x where x free-\end{verbatim}-could be written. Note that \texttt{fresh} has the polymorphic type-$\forall\alpha.\alpha$. This is correct because \texttt{fresh} is a-function and therefore returns a different variable at each-invocation.--The code in \texttt{genVar} below also verifies that the inferred type-for a variable or function matches the type declared in a type-signature. As the declared type is already used for assigning an initial-type to a variable when it is used, the inferred type can only be more-specific. Therefore, if the inferred type does not match the type-signature the declared type must be too general.-\begin{verbatim}--> genDecl :: ModuleIdent -> TCEnv -> SigEnv -> Set.Set Int -> TypeSubst -> Decl-> -> TcState ()-> genDecl m tcEnv sigs lvs theta (FunctionDecl _ f _) =-> S.modify (genVar True m tcEnv sigs lvs theta f)-> genDecl m tcEnv sigs lvs theta (PatternDecl p t _) =-> mapM_ (S.modify . genVar False m tcEnv sigs lvs theta ) (bv t)--> genVar :: Bool -> ModuleIdent -> TCEnv -> SigEnv -> Set.Set Int -> TypeSubst-> -> Ident -> ValueEnv -> ValueEnv-> genVar poly m tcEnv sigs lvs theta v tyEnv =-> case lookupTypeSig v sigs of-> Just sigTy-> | cmpTypes sigma (expandPolyType m tcEnv sigTy) -> tyEnv'-> | otherwise -> errorAt (positionOfIdent v) -> (typeSigTooGeneral m what sigTy sigma)-> Nothing -> tyEnv'-> where what = text (if poly then "Function:" else "Variable:") <+> ppIdent v-> tyEnv' = rebindFun m v sigma tyEnv-> sigma = genType poly (subst theta (varType v tyEnv))-> genType poly (ForAll n ty)-> | n > 0 = internalError ("genVar: " ++ showLine (positionOfIdent v) ++ -> show v ++ " :: " ++ show ty)-> | poly = gen lvs ty-> | otherwise = monoType ty-> cmpTypes (ForAll _ t1) (ForAll _ t2) = equTypes t1 t2--> tcEquation :: ModuleIdent -> TCEnv -> ValueEnv -> SigEnv -> Equation-> -> TcState Type-> tcEquation m tcEnv tyEnv0 sigs (Equation p lhs rhs) =-> do-> tys <- mapM (tcConstrTerm m tcEnv sigs p) ts-> ty <- tcRhs m tcEnv tyEnv0 sigs rhs-> checkSkolems p m (text "Function: " <+> ppIdent f) tyEnv0-> (foldr TypeArrow ty tys)-> where (f,ts) = flatLhs lhs--> tcLiteral :: ModuleIdent -> Literal -> TcState Type-> tcLiteral _ (Char _ _) = return charType-> tcLiteral m (Int v _) = --return intType-> do-> ty <- freshConstrained [intType,floatType]-> S.modify (bindFun m v (monoType ty))-> return ty-> tcLiteral _ (Float _ _) = return floatType-> tcLiteral _ (String _ _) = return stringType--> tcConstrTerm :: ModuleIdent -> TCEnv -> SigEnv -> Position -> ConstrTerm-> -> TcState Type-> tcConstrTerm m tcEnv sigs _ (LiteralPattern l) = tcLiteral m l-> tcConstrTerm m tcEnv sigs _ (NegativePattern _ l) = tcLiteral m l-> tcConstrTerm m tcEnv sigs _ (VariablePattern v) =-> do -> ty <- case lookupTypeSig v sigs of-> Just t -> inst (expandPolyType m tcEnv t)-> Nothing -> freshTypeVar-> S.modify (bindFun m v (monoType ty))-> return ty-> -> tcConstrTerm m tcEnv sigs p t@(ConstructorPattern c ts) =-> do-> tyEnv <- S.get-> ty <- skol (constrType m c tyEnv)-> unifyArgs (ppConstrTerm 0 t) ts ty-> where unifyArgs _ [] ty = return ty-> unifyArgs doc (t:ts) (TypeArrow ty1 ty2) =-> tcConstrTerm m tcEnv sigs p t >>=-> unify p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)-> m ty1 >>-> unifyArgs doc ts ty2-> unifyArgs _ _ _ = internalError "tcConstrTerm"-> tcConstrTerm m tcEnv sigs p t@(InfixPattern t1 op t2) =-> do-> tyEnv <- S.get-> ty <- skol (constrType m op tyEnv)-> unifyArgs (ppConstrTerm 0 t) [t1,t2] ty-> where unifyArgs _ [] ty = return ty-> unifyArgs doc (t:ts) (TypeArrow ty1 ty2) =-> tcConstrTerm m tcEnv sigs p t >>=-> unify p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)-> m ty1 >>-> unifyArgs doc ts ty2-> unifyArgs _ _ _ = internalError "tcConstrTerm"-> tcConstrTerm m tcEnv sigs p (ParenPattern t) = tcConstrTerm m tcEnv sigs p t-> tcConstrTerm m tcEnv sigs p (TuplePattern _ ts)-> | null ts = return unitType-> | otherwise = liftM tupleType $ mapM (tcConstrTerm m tcEnv sigs p) ts-> tcConstrTerm m tcEnv sigs p t@(ListPattern _ ts) =-> freshTypeVar >>= flip (tcElems (ppConstrTerm 0 t)) ts-> where tcElems _ ty [] = return (listType ty)-> tcElems doc ty (t:ts) =-> tcConstrTerm m tcEnv sigs p t >>=-> unify p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)-> m ty >>-> tcElems doc ty ts-> tcConstrTerm m tcEnv sigs p t@(AsPattern v t') =-> do-> ty1 <- tcConstrTerm m tcEnv sigs p (VariablePattern v)-> ty2 <- tcConstrTerm m tcEnv sigs p t'-> unify p "pattern" (ppConstrTerm 0 t) m ty1 ty2-> return ty1-> tcConstrTerm m tcEnv sigs p (LazyPattern _ t) = tcConstrTerm m tcEnv sigs p t-> tcConstrTerm m tcEnv sigs p t@(FunctionPattern f ts) =-> do-> tyEnv <- S.get-> ty <- inst (funType m f tyEnv) --skol (constrType m c tyEnv)-> unifyArgs (ppConstrTerm 0 t) ts ty-> where unifyArgs _ [] ty = return ty-> unifyArgs doc (t:ts) ty@(TypeVariable _) =-> do (alpha,beta) <- tcArrow p "function pattern" doc m ty-> ty' <- tcConstrTermFP m tcEnv sigs p t-> unify p "function pattern"-> (doc $-$ text "Term:" <+> ppConstrTerm 0 t)-> m ty' alpha-> unifyArgs doc ts beta-> unifyArgs doc (t:ts) (TypeArrow ty1 ty2) =-> tcConstrTermFP m tcEnv sigs p t >>=-> unify p "function pattern" -> (doc $-$ text "Term:" <+> ppConstrTerm 0 t)-> m ty1 >>-> unifyArgs doc ts ty2-> unifyArgs _ _ ty = internalError ("tcConstrTerm: " ++ show ty)-> tcConstrTerm m tcEnv sigs p t@(InfixFuncPattern t1 op t2) =-> tcConstrTerm m tcEnv sigs p (FunctionPattern op [t1,t2])-> tcConstrTerm m tcEnv sigs p r@(RecordPattern fs rt)-> | isJust rt =-> do-> ty <- tcConstrTerm m tcEnv sigs p (fromJust rt)-> fts <- mapM (tcFieldPatt (tcConstrTerm m tcEnv sigs) m) fs-> alpha <- freshVar id-> let rty = TypeRecord fts (Just alpha)-> unify p "record pattern" (ppConstrTerm 0 r) m ty rty-> return rty-> | otherwise =-> do-> fts <- mapM (tcFieldPatt (tcConstrTerm m tcEnv sigs) m) fs-> return (TypeRecord fts Nothing)--\end{verbatim}-In contrast to usual patterns, the type checking routine for arguments of -function patterns \texttt{tcConstrTermFP} differs from \texttt{tcConstrTerm}-because of possibly multiple occurrences of variables.-\begin{verbatim}--> tcConstrTermFP :: ModuleIdent -> TCEnv -> SigEnv -> Position -> ConstrTerm-> -> TcState Type-> tcConstrTermFP m tcEnv sigs p (LiteralPattern l) = tcLiteral m l-> tcConstrTermFP m tcEnv sigs p (NegativePattern _ l) = tcLiteral m l-> tcConstrTermFP m tcEnv sigs p (VariablePattern v) =-> do-> ty <- maybe freshTypeVar -> (inst . expandPolyType m tcEnv) -> (lookupTypeSig v sigs)-> tyEnv <- S.get-> ty' <- maybe (S.modify (bindFun m v (monoType ty)) >> return ty)-> (\ (ForAll _ t) -> return t)-> (sureVarType v tyEnv)-> return ty' -> tcConstrTermFP m tcEnv sigs p t@(ConstructorPattern c ts) =-> do-> tyEnv <- S.get-> ty <- skol (constrType m c tyEnv)-> unifyArgs (ppConstrTerm 0 t) ts ty-> where unifyArgs _ [] ty = return ty-> unifyArgs doc (t:ts) (TypeArrow ty1 ty2) =-> tcConstrTermFP m tcEnv sigs p t >>=-> unify p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)-> m ty1 >>-> unifyArgs doc ts ty2-> unifyArgs _ _ _ = internalError "tcConstrTermFP"-> tcConstrTermFP m tcEnv sigs p t@(InfixPattern t1 op t2) =-> do-> tyEnv <- S.get-> ty <- skol (constrType m op tyEnv)-> unifyArgs (ppConstrTerm 0 t) [t1,t2] ty-> where unifyArgs _ [] ty = return ty-> unifyArgs doc (t:ts) (TypeArrow ty1 ty2) =-> tcConstrTermFP m tcEnv sigs p t >>=-> unify p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)-> m ty1 >>-> unifyArgs doc ts ty2-> unifyArgs _ _ _ = internalError "tcConstrTermFP"-> tcConstrTermFP m tcEnv sigs p (ParenPattern t) = tcConstrTermFP m tcEnv sigs p t-> tcConstrTermFP m tcEnv sigs p (TuplePattern _ ts)-> | null ts = return unitType-> | otherwise = liftM tupleType $ mapM (tcConstrTermFP m tcEnv sigs p) ts-> tcConstrTermFP m tcEnv sigs p t@(ListPattern _ ts) =-> freshTypeVar >>= flip (tcElems (ppConstrTerm 0 t)) ts-> where tcElems _ ty [] = return (listType ty)-> tcElems doc ty (t:ts) =-> tcConstrTermFP m tcEnv sigs p t >>=-> unify p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)-> m ty >>-> tcElems doc ty ts-> tcConstrTermFP m tcEnv sigs p t@(AsPattern v t') =-> do-> ty1 <- tcConstrTermFP m tcEnv sigs p (VariablePattern v)-> ty2 <- tcConstrTermFP m tcEnv sigs p t'-> unify p "pattern" (ppConstrTerm 0 t) m ty1 ty2-> return ty1-> tcConstrTermFP m tcEnv sigs p (LazyPattern _ t) = tcConstrTermFP m tcEnv sigs p t-> tcConstrTermFP m tcEnv sigs p t@(FunctionPattern f ts) =-> do-> tyEnv <- S.get-> ty <- inst (funType m f tyEnv) --skol (constrType m c tyEnv)-> unifyArgs (ppConstrTerm 0 t) ts ty-> where unifyArgs _ [] ty = return ty-> unifyArgs doc (t:ts) ty@(TypeVariable _) =-> do (alpha,beta) <- tcArrow p "function pattern" doc m ty-> ty' <- tcConstrTermFP m tcEnv sigs p t-> unify p "function pattern"-> (doc $-$ text "Term:" <+> ppConstrTerm 0 t)-> m ty' alpha-> unifyArgs doc ts beta-> unifyArgs doc (t:ts) (TypeArrow ty1 ty2) =-> tcConstrTermFP m tcEnv sigs p t >>=-> unify p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)-> m ty1 >>-> unifyArgs doc ts ty2-> unifyArgs _ _ _ = internalError "tcConstrTermFP"-> tcConstrTermFP m tcEnv sigs p t@(InfixFuncPattern t1 op t2) =-> tcConstrTermFP m tcEnv sigs p (FunctionPattern op [t1,t2])-> tcConstrTermFP m tcEnv sigs p r@(RecordPattern fs rt)-> | isJust rt =-> do-> ty <- tcConstrTermFP m tcEnv sigs p (fromJust rt)-> fts <- mapM (tcFieldPatt (tcConstrTermFP m tcEnv sigs) m) fs-> alpha <- freshVar id-> let rty = TypeRecord fts (Just alpha)-> unify p "record pattern" (ppConstrTerm 0 r) m ty rty-> return rty-> | otherwise =-> do-> fts <- mapM (tcFieldPatt (tcConstrTermFP m tcEnv sigs) m) fs-> return (TypeRecord fts Nothing)--> tcFieldPatt :: (Position -> ConstrTerm -> TcState Type) -> ModuleIdent-> -> Field ConstrTerm -> TcState (Ident,Type)-> tcFieldPatt tcPatt m f@(Field _ l t) =-> do-> tyEnv <- S.get-> let p = positionOfIdent l-> lty <- maybe (freshTypeVar-> >>= (\lty' ->-> S.modify-> (bindLabel l (qualifyWith m (mkIdent "#Rec"))-> (polyType lty'))-> >> return lty'))-> (\ (ForAll _ lty') -> return lty')-> (sureLabelType l tyEnv)-> ty <- tcPatt p t-> unify p "record" (text "Field:" <+> ppFieldPatt f) m lty ty-> return (l,ty)--> tcRhs :: ModuleIdent -> TCEnv -> ValueEnv -> SigEnv -> Rhs -> TcState Type-> tcRhs m tcEnv tyEnv0 sigs (SimpleRhs p e ds) =-> do-> tcDecls m tcEnv sigs ds-> ty <- tcExpr m tcEnv sigs p e-> checkSkolems p m (text "Expression:" <+> ppExpr 0 e) tyEnv0 ty-> tcRhs m tcEnv tyEnv0 sigs (GuardedRhs es ds) =-> do-> tcDecls m tcEnv sigs ds-> tcCondExprs m tcEnv tyEnv0 sigs es--> tcCondExprs :: ModuleIdent -> TCEnv -> ValueEnv -> SigEnv -> [CondExpr]-> -> TcState Type-> tcCondExprs m tcEnv tyEnv0 sigs es =-> do-> gty <- if length es > 1 then return boolType-> else freshConstrained [successType,boolType]-> ty <- freshTypeVar-> tcCondExprs' gty ty es-> where tcCondExprs' gty ty [] = return ty-> tcCondExprs' gty ty (e:es) =-> tcCondExpr gty ty e >> tcCondExprs' gty ty es-> tcCondExpr gty ty (CondExpr p g e) =-> tcExpr m tcEnv sigs p g >>=-> unify p "guard" (ppExpr 0 g) m gty >>-> tcExpr m tcEnv sigs p e >>=-> checkSkolems p m (text "Expression:" <+> ppExpr 0 e) tyEnv0 >>=-> unify p "guarded expression" (ppExpr 0 e) m ty--> tcExpr :: ModuleIdent -> TCEnv -> SigEnv -> Position -> Expression-> -> TcState Type-> tcExpr m _ _ _ (Literal l) = tcLiteral m l-> tcExpr m tcEnv sigs p (Variable v) =-> case qualLookupTypeSig m v sigs of-> Just ty -> inst (expandPolyType m tcEnv ty)-> Nothing -> S.get >>= inst . funType m v-> tcExpr m tcEnv sigs p (Constructor c) = S.get >>= instExist . constrType m c-> tcExpr m tcEnv sigs p (Typed e sig) =-> do-> tyEnv0 <- S.get-> ty <- tcExpr m tcEnv sigs p e-> inst sigma' >>=-> flip (unify p "explicitly typed expression" (ppExpr 0 e) m) ty-> theta <- S.lift S.get-> let sigma = gen (fvEnv (subst theta tyEnv0)) (subst theta ty)-> unless (sigma == sigma')-> (errorAt p (typeSigTooGeneral m (text "Expression:" <+> ppExpr 0 e)-> sig' sigma))-> return ty-> where sig' = nameSigType sig-> sigma' = expandPolyType m tcEnv sig'-> tcExpr m tcEnv sigs p (Paren e) = tcExpr m tcEnv sigs p e-> tcExpr m tcEnv sigs p (Tuple _ es)-> | null es = return unitType-> | otherwise = liftM tupleType $ mapM (tcExpr m tcEnv sigs p) es-> tcExpr m tcEnv sigs p e@(List _ es) = freshTypeVar >>= tcElems (ppExpr 0 e) es-> where tcElems _ [] ty = return (listType ty)-> tcElems doc (e:es) ty =-> tcExpr m tcEnv sigs p e >>=-> unify p "expression" (doc $-$ text "Term:" <+> ppExpr 0 e)-> m ty >>-> tcElems doc es ty-> tcExpr m tcEnv sigs p (ListCompr _ e qs) =-> do-> tyEnv0 <- S.get-> mapM_ (tcQual m tcEnv sigs p) qs-> ty <- tcExpr m tcEnv sigs p e-> checkSkolems p m (text "Expression:" <+> ppExpr 0 e) tyEnv0 (listType ty)-> tcExpr m tcEnv sigs p e@(EnumFrom e1) =-> do-> ty1 <- tcExpr m tcEnv sigs p e1-> unify p "arithmetic sequence"-> (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1) m intType ty1-> return (listType intType)-> tcExpr m tcEnv sigs p e@(EnumFromThen e1 e2) =-> do-> ty1 <- tcExpr m tcEnv sigs p e1-> ty2 <- tcExpr m tcEnv sigs p e2-> unify p "arithmetic sequence"-> (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1) m intType ty1-> unify p "arithmetic sequence"-> (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e2) m intType ty2-> return (listType intType)-> tcExpr m tcEnv sigs p e@(EnumFromTo e1 e2) =-> do-> ty1 <- tcExpr m tcEnv sigs p e1-> ty2 <- tcExpr m tcEnv sigs p e2-> unify p "arithmetic sequence"-> (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1) m intType ty1-> unify p "arithmetic sequence"-> (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e2) m intType ty2-> return (listType intType)-> tcExpr m tcEnv sigs p e@(EnumFromThenTo e1 e2 e3) =-> do-> ty1 <- tcExpr m tcEnv sigs p e1-> ty2 <- tcExpr m tcEnv sigs p e2-> ty3 <- tcExpr m tcEnv sigs p e3-> unify p "arithmetic sequence"-> (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1) m intType ty1-> unify p "arithmetic sequence"-> (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e2) m intType ty2-> unify p "arithmetic sequence"-> (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e3) m intType ty3-> return (listType intType)-> tcExpr m tcEnv sigs p e@(UnaryMinus op e1) =-> do-> opTy <- opType op-> ty1 <- tcExpr m tcEnv sigs p e1-> unify p "unary negation" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1)-> m opTy ty1-> return ty1-> where opType op-> | op == minusId = freshConstrained [intType,floatType]-> | op == fminusId = return floatType-> | otherwise = internalError ("tcExpr unary " ++ name op)-> tcExpr m tcEnv sigs p e@(Apply e1 e2) =-> do-> ty1 <- tcExpr m tcEnv sigs p e1-> ty2 <- tcExpr m tcEnv sigs p e2-> (alpha,beta) <--> tcArrow p "application" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1)-> m ty1-> unify p "application" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e2)-> m alpha ty2-> return beta-> tcExpr m tcEnv sigs p e@(InfixApply e1 op e2) =-> do-> opTy <- tcExpr m tcEnv sigs p (infixOp op)-> ty1 <- tcExpr m tcEnv sigs p e1-> ty2 <- tcExpr m tcEnv sigs p e2-> (alpha,beta,gamma) <--> tcBinary p "infix application"-> (ppExpr 0 e $-$ text "Operator:" <+> ppOp op) m opTy-> unify p "infix application" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1)-> m alpha ty1-> unify p "infix application" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e2)-> m beta ty2-> return gamma-> tcExpr m tcEnv sigs p e@(LeftSection e1 op) =-> do-> opTy <- tcExpr m tcEnv sigs p (infixOp op)-> ty1 <- tcExpr m tcEnv sigs p e1-> (alpha,beta) <--> tcArrow p "left section" (ppExpr 0 e $-$ text "Operator:" <+> ppOp op)-> m opTy-> unify p "left section" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1)-> m alpha ty1-> return beta-> tcExpr m tcEnv sigs p e@(RightSection op e1) =-> do-> opTy <- tcExpr m tcEnv sigs p (infixOp op)-> ty1 <- tcExpr m tcEnv sigs p e1-> (alpha,beta,gamma) <--> tcBinary p "right section"-> (ppExpr 0 e $-$ text "Operator:" <+> ppOp op) m opTy-> unify p "right section" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1)-> m beta ty1-> return (TypeArrow alpha gamma)-> tcExpr m tcEnv sigs p exp@(Lambda r ts e) =-> do-> tyEnv0 <- S.get-> tys <- mapM (tcConstrTerm m tcEnv sigs p) ts-> ty <- tcExpr m tcEnv sigs p e-> checkSkolems p m (text "Expression:" <+> ppExpr 0 exp) tyEnv0-> (foldr TypeArrow ty tys)-> tcExpr m tcEnv sigs p (Let ds e) =-> do-> tyEnv0 <- S.get-> theta <- S.lift S.get-> tcDecls m tcEnv sigs ds-> ty <- tcExpr m tcEnv sigs p e-> checkSkolems p m (text "Expression:" <+> ppExpr 0 e) tyEnv0 ty-> tcExpr m tcEnv sigs p (Do sts e) =-> do-> tyEnv0 <- S.get-> mapM_ (tcStmt m tcEnv sigs p) sts-> alpha <- freshTypeVar-> ty <- tcExpr m tcEnv sigs p e-> unify p "statement" (ppExpr 0 e) m (ioType alpha) ty-> checkSkolems p m (text "Expression:" <+> ppExpr 0 e) tyEnv0 ty-> tcExpr m tcEnv sigs p e@(IfThenElse _ e1 e2 e3) =-> do-> ty1 <- tcExpr m tcEnv sigs p e1-> unify p "expression" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1)-> m boolType ty1-> ty2 <- tcExpr m tcEnv sigs p e2-> ty3 <- tcExpr m tcEnv sigs p e3-> unify p "expression" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e3)-> m ty2 ty3-> return ty3-> tcExpr m tcEnv sigs p (Case _ e alts) =-> do-> tyEnv0 <- S.get-> ty <- tcExpr m tcEnv sigs p e-> alpha <- freshTypeVar-> tcAlts tyEnv0 ty alpha alts-> where tcAlts tyEnv0 _ ty [] = return ty-> tcAlts tyEnv0 ty1 ty2 (alt:alts) =-> tcAlt (ppAlt alt) tyEnv0 ty1 ty2 alt >> tcAlts tyEnv0 ty1 ty2 alts-> tcAlt doc tyEnv0 ty1 ty2 (Alt p t rhs) =-> tcConstrTerm m tcEnv sigs p t >>=-> unify p "case pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)-> m ty1 >>-> tcRhs m tcEnv tyEnv0 sigs rhs >>=-> unify p "case branch" doc m ty2-> tcExpr m tcEnv sigs p (RecordConstr fs) =-> do -> fts <- mapM (tcFieldExpr m tcEnv sigs equals) fs-> --when (1 == length fs)-> -- (error (show fs ++ "\n" ++ show fts))-> return (TypeRecord fts Nothing)-> tcExpr m tcEnv sigs p r@(RecordSelection e l) =-> do-> ty <- tcExpr m tcEnv sigs p e-> tyEnv <- S.get-> lty <- maybe (freshTypeVar -> >>= (\lty' -> -> S.modify -> (bindLabel l (qualifyWith m (mkIdent "#Rec"))-> (monoType lty'))-> >> return lty'))-> (\ (ForAll _ lty') -> return lty')-> (sureLabelType l tyEnv)-> alpha <- freshVar id-> let rty = TypeRecord [(l,lty)] (Just alpha)-> unify p "record selection" (ppExpr 0 r) m ty rty-> return lty-> tcExpr m tcEnv sigs p r@(RecordUpdate fs e) =-> do-> ty <- tcExpr m tcEnv sigs p e-> fts <- mapM (tcFieldExpr m tcEnv sigs (text ":=")) fs-> alpha <- freshVar id-> let rty = TypeRecord fts (Just alpha)-> unify p "record update" (ppExpr 0 r) m ty rty-> return ty--> tcQual :: ModuleIdent -> TCEnv -> SigEnv -> Position -> Statement-> -> TcState ()-> tcQual m tcEnv sigs p (StmtExpr _ e) =-> do-> ty <- tcExpr m tcEnv sigs p e-> unify p "guard" (ppExpr 0 e) m boolType ty-> tcQual m tcEnv sigs p q@(StmtBind _ t e) =-> do-> ty1 <- tcConstrTerm m tcEnv sigs p t-> ty2 <- tcExpr m tcEnv sigs p e-> unify p "generator" (ppStmt q $-$ text "Term:" <+> ppExpr 0 e)-> m (listType ty1) ty2-> tcQual m tcEnv sigs p (StmtDecl ds) = tcDecls m tcEnv sigs ds--> tcStmt :: ModuleIdent -> TCEnv -> SigEnv -> Position -> Statement-> -> TcState ()-> tcStmt m tcEnv sigs p (StmtExpr _ e) =-> do-> alpha <- freshTypeVar-> ty <- tcExpr m tcEnv sigs p e-> unify p "statement" (ppExpr 0 e) m (ioType alpha) ty-> tcStmt m tcEnv sigs p st@(StmtBind _ t e) =-> do-> ty1 <- tcConstrTerm m tcEnv sigs p t-> ty2 <- tcExpr m tcEnv sigs p e-> unify p "statement" (ppStmt st $-$ text "Term:" <+> ppExpr 0 e)-> m (ioType ty1) ty2-> tcStmt m tcEnv sigs p (StmtDecl ds) = tcDecls m tcEnv sigs ds--> tcFieldExpr :: ModuleIdent -> TCEnv -> SigEnv -> Doc -> Field Expression-> -> TcState (Ident,Type)-> tcFieldExpr m tcEnv sigs comb f@(Field _ l e) =-> do-> tyEnv <- S.get-> let p = positionOfIdent l-> lty <- maybe (freshTypeVar -> >>= (\lty' -> -> S.modify -> (bindLabel l (qualifyWith m (mkIdent "#Rec"))-> (monoType lty'))-> >> return lty'))-> inst-> (sureLabelType l tyEnv)-> ty <- tcExpr m tcEnv sigs p e-> unify p "record" (text "Field:" <+> ppFieldExpr comb f) m lty ty-> return (l,ty)--\end{verbatim}-The function \texttt{tcArrow} checks that its argument can be used as-an arrow type $\alpha\rightarrow\beta$ and returns the pair-$(\alpha,\beta)$. Similarly, the function \texttt{tcBinary} checks-that its argument can be used as an arrow type-$\alpha\rightarrow\beta\rightarrow\gamma$ and returns the triple-$(\alpha,\beta,\gamma)$.-\begin{verbatim}--> tcArrow :: Position -> String -> Doc -> ModuleIdent -> Type-> -> TcState (Type,Type)-> tcArrow p what doc m ty =-> do-> theta <- S.lift S.get-> unaryArrow (subst theta ty)-> where unaryArrow (TypeArrow ty1 ty2) = return (ty1,ty2)-> unaryArrow (TypeVariable tv) =-> do-> alpha <- freshTypeVar-> beta <- freshTypeVar-> S.lift (S.modify (bindVar tv (TypeArrow alpha beta)))-> return (alpha,beta)-> unaryArrow ty = errorAt p (nonFunctionType what doc m ty)--> tcBinary :: Position -> String -> Doc -> ModuleIdent -> Type-> -> TcState (Type,Type,Type)-> tcBinary p what doc m ty = tcArrow p what doc m ty >>= uncurry binaryArrow-> where binaryArrow ty1 (TypeArrow ty2 ty3) = return (ty1,ty2,ty3)-> binaryArrow ty1 (TypeVariable tv) =-> do-> beta <- freshTypeVar-> gamma <- freshTypeVar-> S.lift (S.modify (bindVar tv (TypeArrow beta gamma)))-> return (ty1,beta,gamma)-> binaryArrow ty1 ty2 =-> errorAt p (nonBinaryOp what doc m (TypeArrow ty1 ty2))--\end{verbatim}-\paragraph{Unification}-The unification uses Robinson's algorithm (cf., e.g., Chap.~9-of~\cite{PeytonJones87:Book}).-\begin{verbatim}--> unify :: Position -> String -> Doc -> ModuleIdent -> Type -> Type-> -> TcState ()-> unify p what doc m ty1 ty2 =-> S.lift $-> do-> theta <- S.get-> let ty1' = subst theta ty1-> let ty2' = subst theta ty2-> either (errorAt p . typeMismatch what doc m ty1' ty2')-> (S.modify . compose)-> (unifyTypes m ty1' ty2')--> unifyTypes :: ModuleIdent -> Type -> Type -> Either Doc TypeSubst-> unifyTypes _ (TypeVariable tv1) (TypeVariable tv2)-> | tv1 == tv2 = Right idSubst-> | otherwise = Right (bindSubst tv1 (TypeVariable tv2) idSubst)-> unifyTypes m (TypeVariable tv) ty-> | tv `elem` typeVars ty = Left (recursiveType m tv ty)-> | otherwise = Right (bindSubst tv ty idSubst)-> unifyTypes m ty (TypeVariable tv)-> | tv `elem` typeVars ty = Left (recursiveType m tv ty)-> | otherwise = Right (bindSubst tv ty idSubst)-> unifyTypes _ (TypeConstrained tys1 tv1) (TypeConstrained tys2 tv2)-> | tv1 == tv2 = Right idSubst-> | tys1 == tys2 = Right (bindSubst tv1 (TypeConstrained tys2 tv2) idSubst)-> unifyTypes m (TypeConstrained tys tv) ty =-> foldr (choose . unifyTypes m ty) (Left (incompatibleTypes m ty (head tys)))-> tys-> where choose (Left _) theta' = theta'-> choose (Right theta) _ = Right (bindSubst tv ty theta)-> unifyTypes m ty (TypeConstrained tys tv) =-> foldr (choose . unifyTypes m ty) (Left (incompatibleTypes m ty (head tys)))-> tys-> where choose (Left _) theta' = theta'-> choose (Right theta) _ = Right (bindSubst tv ty theta)-> unifyTypes m (TypeConstructor tc1 tys1) (TypeConstructor tc2 tys2)-> | tc1 == tc2 = unifyTypeLists m tys1 tys2-> unifyTypes m (TypeArrow ty11 ty12) (TypeArrow ty21 ty22) =-> unifyTypeLists m [ty11,ty12] [ty21,ty22]-> unifyTypes _ (TypeSkolem k1) (TypeSkolem k2)-> | k1 == k2 = Right idSubst-> unifyTypes m (TypeRecord fs1 Nothing) tr2@(TypeRecord fs2 Nothing)-> | length fs1 == length fs2 = unifyTypedLabels m fs1 tr2-> unifyTypes m tr1@(TypeRecord fs1 Nothing) tr2@(TypeRecord fs2 (Just a2)) =-> either Left-> (\res -> either Left -> (Right . compose res) -> (unifyTypes m (TypeVariable a2) tr1))-> (unifyTypedLabels m fs2 tr1)-> unifyTypes m tr1@(TypeRecord _ (Just _)) tr2@(TypeRecord _ Nothing) =-> unifyTypes m tr2 tr1-> unifyTypes m (TypeRecord fs1 (Just a1)) tr2@(TypeRecord fs2 (Just a2)) =-> let (fs1', rs1, rs2) = splitFields fs1 fs2-> in either -> Left-> (\res -> -> either -> Left -> (\res' -> Right (compose res res'))-> (unifyTypeLists m [TypeVariable a1,-> TypeRecord (fs1 ++ rs2) Nothing]-> [TypeVariable a2,-> TypeRecord (fs2 ++ rs1) Nothing]))-> (unifyTypedLabels m fs1' tr2)-> where-> splitFields fs1 fs2 = split' [] [] fs2 fs1-> split' fs1' rs1 rs2 [] = (fs1',rs1,rs2)-> split' fs1' rs1 rs2 ((l,ty):fs1) =-> maybe (split' fs1' ((l,ty):rs1) rs2 fs1)-> (const (split' ((l,ty):fs1') rs1 (remove l rs2) fs1))-> (lookup l rs2)-> unifyTypes m ty1 ty2 = Left (incompatibleTypes m ty1 ty2)--> unifyTypeLists :: ModuleIdent -> [Type] -> [Type] -> Either Doc TypeSubst-> unifyTypeLists _ [] _ = Right idSubst-> unifyTypeLists _ _ [] = Right idSubst-> unifyTypeLists m (ty1:tys1) (ty2:tys2) =-> either Left (unifyTypesTheta m ty1 ty2) (unifyTypeLists m tys1 tys2)-> where unifyTypesTheta m ty1 ty2 theta =-> either Left (Right . flip compose theta)-> (unifyTypes m (subst theta ty1) (subst theta ty2))--> unifyTypedLabels :: ModuleIdent -> [(Ident,Type)] -> Type -> -> Either Doc TypeSubst-> unifyTypedLabels m [] (TypeRecord _ _) = Right idSubst-> unifyTypedLabels m ((l,ty):fs1) tr@(TypeRecord fs2 _) =-> either Left-> (\r -> -> maybe (Left (missingLabel m l tr))-> (\ty' -> -> either (const (Left (incompatibleLabelTypes m l ty ty')))-> (Right . flip compose r)-> (unifyTypes m ty ty'))-> (lookup l fs2))-> (unifyTypedLabels m fs1 tr)-> unifyTypedLabels _ _ _ = internalError "unifyTypedLabels"--\end{verbatim}-For each declaration group, the type checker has to ensure that no-skolem type escapes its scope.-\begin{verbatim}--> checkSkolems :: Position -> ModuleIdent -> Doc -> ValueEnv -> Type-> -> TcState Type-> checkSkolems p m what tyEnv ty =-> do-> theta <- S.lift S.get-> let ty' = subst theta ty-> fs = fsEnv (subst theta tyEnv)-> unless (all (`Set.member` fs) (typeSkolems ty'))-> (errorAt p (skolemEscapingScope m what ty'))-> --error (show ty ++ " ## " ++ show (subst theta ty))-> return ty'--\end{verbatim}-\paragraph{Instantiation and Generalization}-We use negative offsets for fresh type variables.-\begin{verbatim}--> fresh :: (Int -> a) -> TcState a-> fresh f = liftM f (S.lift (S.lift (S.modify succ >> S.get)))--> freshVar :: (Int -> a) -> TcState a-> freshVar f = fresh (\n -> f (- n - 1))--> freshTypeVar :: TcState Type-> freshTypeVar = freshVar TypeVariable--> freshConstrained :: [Type] -> TcState Type-> freshConstrained tys = freshVar (TypeConstrained tys)--> freshSkolem :: TcState Type-> freshSkolem = fresh TypeSkolem--> inst :: TypeScheme -> TcState Type-> inst (ForAll n ty) =-> do-> tys <- replicateM n freshTypeVar-> return (expandAliasType tys ty)--> instExist :: ExistTypeScheme -> TcState Type-> instExist (ForAllExist n n' ty) =-> do-> tys <- replicateM (n + n') freshTypeVar-> return (expandAliasType tys ty)--> skol :: ExistTypeScheme -> TcState Type-> skol (ForAllExist n n' ty) =-> do-> tys <- replicateM n freshTypeVar-> tys' <- replicateM n' freshSkolem-> return (expandAliasType (tys ++ tys') ty)--> gen :: Set.Set Int -> Type -> TypeScheme-> gen gvs ty =-> ForAll (length tvs) (subst (foldr2 bindSubst idSubst tvs tvs') ty)-> where tvs = [tv | tv <- nub (typeVars ty), tv `Set.notMember` gvs]-> tvs' = map TypeVariable [0..]--\end{verbatim}-\paragraph{Auxiliary Functions}-The functions \texttt{constrType}, \texttt{varType}, and-\texttt{funType} are used to retrieve the type of constructors,-pattern variables, and variables in expressions, respectively, from-the type environment. Because the syntactical correctness has already-been verified by the syntax checker, none of these functions should-fail.--Note that \texttt{varType} can handle ambiguous identifiers and-returns the first available type. This function is used for looking up-the type of an identifier on the left hand side of a rule where it-unambiguously refers to the local definition.-\begin{verbatim}--> constrType :: ModuleIdent -> QualIdent -> ValueEnv -> ExistTypeScheme-> constrType m c tyEnv =-> case qualLookupValue c tyEnv of-> [DataConstructor _ sigma] -> sigma-> [NewtypeConstructor _ sigma] -> sigma-> _ -> case (qualLookupValue (qualQualify m c) tyEnv) of-> [DataConstructor _ sigma] -> sigma-> [NewtypeConstructor _ sigma] -> sigma-> _ -> internalError ("constrType " ++ show c)--> varType :: Ident -> ValueEnv -> TypeScheme-> varType v tyEnv =-> case lookupValue v tyEnv of-> Value _ sigma : _ -> sigma-> _ -> internalError ("varType " ++ show v)--> sureVarType :: Ident -> ValueEnv -> Maybe TypeScheme-> sureVarType v tyEnv =-> case lookupValue v tyEnv of-> Value _ sigma : _ -> Just sigma-> _ -> Nothing--> funType :: ModuleIdent -> QualIdent -> ValueEnv -> TypeScheme-> funType m f tyEnv =-> case (qualLookupValue f tyEnv) of-> [Value _ sigma] -> sigma-> vs -> case (qualLookupValue (qualQualify m f) tyEnv) of-> [Value _ sigma] -> sigma-> _ -> internalError ("funType " ++ show f)--> sureLabelType :: Ident -> ValueEnv -> Maybe TypeScheme-> sureLabelType l tyEnv =-> case lookupValue l tyEnv of-> Label _ _ sigma : _ -> Just sigma-> _ -> Nothing---\end{verbatim}-The function \texttt{expandType} expands all type synonyms in a type-and also qualifies all type constructors with the name of the module-in which the type was defined.-\begin{verbatim}--> expandMonoType :: ModuleIdent -> TCEnv -> [Ident] -> TypeExpr -> Type-> expandMonoType m tcEnv tvs ty = expandType m tcEnv (toType tvs ty)--> expandMonoTypes :: ModuleIdent -> TCEnv -> [Ident] -> [TypeExpr] -> [Type]-> expandMonoTypes m tcEnv tvs tys = map (expandType m tcEnv) (toTypes tvs tys)--> expandPolyType :: ModuleIdent -> TCEnv -> TypeExpr -> TypeScheme-> expandPolyType m tcEnv ty = -> polyType $ normalize $ expandMonoType m tcEnv [] ty--> expandType :: ModuleIdent -> TCEnv -> Type -> Type-> expandType m tcEnv (TypeConstructor tc tys) =-> case qualLookupTC tc tcEnv of-> [DataType tc' _ _] -> TypeConstructor tc' tys'-> [RenamingType tc' _ _] -> TypeConstructor tc' tys'-> [AliasType _ _ ty] -> expandAliasType tys' ty-> _ -> case (qualLookupTC (qualQualify m tc) tcEnv) of-> [DataType tc' _ _] -> TypeConstructor tc' tys'-> [RenamingType tc' _ _] -> TypeConstructor tc' tys'-> [AliasType _ _ ty] -> expandAliasType tys' ty-> _ -> internalError ("expandType " ++ show tc)-> where tys' = map (expandType m tcEnv) tys-> expandType _ _ (TypeVariable tv) = TypeVariable tv-> expandType _ _ (TypeConstrained tys tv) = TypeConstrained tys tv-> expandType m tcEnv (TypeArrow ty1 ty2) =-> TypeArrow (expandType m tcEnv ty1) (expandType m tcEnv ty2)-> expandType _ tcEnv (TypeSkolem k) = TypeSkolem k-> expandType m tcEnv (TypeRecord fs rv) =-> TypeRecord (map (\ (l,ty) -> (l, expandType m tcEnv ty)) fs) rv--\end{verbatim}-The functions \texttt{fvEnv} and \texttt{fsEnv} compute the set of-free type variables and free skolems of a type environment,-respectively. We ignore the types of data constructors here because we-know that they are closed.-\begin{verbatim}--> fvEnv :: ValueEnv -> Set.Set Int-> fvEnv tyEnv =-> Set.fromList [tv | ty <- localTypes tyEnv, tv <- typeVars ty, tv < 0]--> fsEnv :: ValueEnv -> Set.Set Int-> fsEnv tyEnv = Set.unions (map (Set.fromList . typeSkolems) (localTypes tyEnv))--> localTypes :: ValueEnv -> [Type]-> localTypes tyEnv = [ty | (_,Value _ (ForAll _ ty)) <- localBindings tyEnv]--\end{verbatim}-Miscellaneous functions.-\begin{verbatim}--> remove :: Eq a => a -> [(a,b)] -> [(a,b)]-> remove _ [] = []-> remove k ((k',e):kes) | k == k' = kes-> | otherwise = (k',e):(remove k kes) --\end{verbatim}-Error functions.-\begin{verbatim}--> recursiveTypes :: [Ident] -> (Position,String)-> recursiveTypes [tc] = -> (positionOfIdent tc,-> "Recursive synonym type " ++ name tc)-> recursiveTypes (tc:tcs) =-> (positionOfIdent tc,-> "Recursive synonym types " ++ name tc ++ types "" tcs)-> where types comma [tc] = comma ++ " and " ++ name tc ++-> showLine (positionOfIdent tc) -> types _ (tc:tcs) = ", " ++ name tc ++ -> showLine (positionOfIdent tc) ++ -> types "," tcs--> polymorphicFreeVar :: Ident -> (Position,String)-> polymorphicFreeVar v =-> (positionOfIdent v,-> "Free variable " ++ name v ++ " has a polymorphic type")--> typeSigTooGeneral :: ModuleIdent -> Doc -> TypeExpr -> TypeScheme -> String-> typeSigTooGeneral m what ty sigma = show $-> vcat [text "Type signature too general", what,-> text "Inferred type:" <+> ppTypeScheme m sigma,-> text "Type signature:" <+> ppTypeExpr 0 ty]--> nonFunctionType :: String -> Doc -> ModuleIdent -> Type -> String-> nonFunctionType what doc m ty = show $-> vcat [text "Type error in" <+> text what, doc,-> text "Type:" <+> ppType m ty,-> text "Cannot be applied"]--> nonBinaryOp :: String -> Doc -> ModuleIdent -> Type -> String-> nonBinaryOp what doc m ty = show $-> vcat [text "Type error in" <+> text what, doc,-> text "Type:" <+> ppType m ty,-> text "Cannot be used as binary operator"]--> typeMismatch :: String -> Doc -> ModuleIdent -> Type -> Type -> Doc -> String-> typeMismatch what doc m ty1 ty2 reason = show $-> vcat [text "Type error in" <+> text what, doc,-> text "Inferred type:" <+> ppType m ty2,-> text "Expected type:" <+> ppType m ty1,-> reason]--> skolemEscapingScope :: ModuleIdent -> Doc -> Type -> String-> skolemEscapingScope m what ty = show $-> vcat [text "Existential type escapes out of its scope", what,-> text "Type:" <+> ppType m ty]--> recursiveType :: ModuleIdent -> Int -> Type -> Doc-> recursiveType m tv ty = incompatibleTypes m (TypeVariable tv) ty--> missingLabel :: ModuleIdent -> Ident -> Type -> Doc-> missingLabel m l rty =-> sep [text "Missing field for label" <+> ppIdent l,-> text "in the record type" <+> ppType m rty]--> incompatibleTypes :: ModuleIdent -> Type -> Type -> Doc-> incompatibleTypes m ty1 ty2 =-> sep [text "Types" <+> ppType m ty1,-> nest 2 (text "and" <+> ppType m ty2),-> text "are incompatible"]--> incompatibleLabelTypes :: ModuleIdent -> Ident -> Type -> Type -> Doc-> incompatibleLabelTypes m l ty1 ty2 =-> sep [text "Labeled types" <+> ppIdent l <> text "::" <> ppType m ty1,-> nest 10 (text "and" <+> ppIdent l <> text "::" <> ppType m ty2),-> text "are incompatible"]--\end{verbatim}---\end{verbatim}-The following functions implement pretty-printing for types.-\begin{verbatim}--> ppType :: ModuleIdent -> Type -> Doc-> ppType m = ppTypeExpr 0 . fromQualType m--> ppTypeScheme :: ModuleIdent -> TypeScheme -> Doc-> ppTypeScheme m (ForAll _ ty) = ppType m ty
− src/TypeSubst.lhs
@@ -1,104 +0,0 @@--% $Id: TypeSubst.lhs,v 1.2 2004/02/08 22:14:01 wlux Exp $-%-% Copyright (c) 2003, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{TypeSubst.lhs}-\section{Type Substitutions}-This module implements substitutions on types.-\begin{verbatim}--> module TypeSubst(module TypeSubst, idSubst,bindSubst,compose) where---> import Data.Maybe-> import Data.List--> import Types--> import Subst-> import Base-> import TopEnv--> type TypeSubst = Subst Int Type--> class SubstType a where-> subst :: TypeSubst -> a -> a--> bindVar :: Int -> Type -> TypeSubst -> TypeSubst-> bindVar tv ty = compose (bindSubst tv ty idSubst)--> substVar :: TypeSubst -> Int -> Type-> substVar = substVar' TypeVariable subst--> instance SubstType Type where-> subst sigma (TypeConstructor tc tys) =-> TypeConstructor tc (map (subst sigma) tys)-> subst sigma (TypeVariable tv) = substVar sigma tv-> subst sigma (TypeConstrained tys tv) =-> case substVar sigma tv of-> TypeVariable tv -> TypeConstrained tys tv-> ty -> ty-> subst sigma (TypeArrow ty1 ty2) =-> TypeArrow (subst sigma ty1) (subst sigma ty2)-> subst sigma (TypeSkolem k) = TypeSkolem k-> subst sigma (TypeRecord fs rv)-> | isJust rv =-> case substVar sigma (fromJust rv) of-> TypeVariable tv -> TypeRecord fs' (Just tv)-> ty -> ty-> | otherwise = TypeRecord fs' Nothing-> where fs' = map (\ (l,ty) -> (l, subst sigma ty)) fs--> instance SubstType TypeScheme where-> subst sigma (ForAll n ty) =-> ForAll n (subst (foldr unbindSubst sigma [0..n-1]) ty)--> instance SubstType ExistTypeScheme where-> subst sigma (ForAllExist n n' ty) =-> ForAllExist n n' (subst (foldr unbindSubst sigma [0..n+n'-1]) ty)--> instance SubstType ValueInfo where-> subst theta (DataConstructor c ty) = DataConstructor c ty-> subst theta (NewtypeConstructor c ty) = NewtypeConstructor c ty-> subst theta (Value v ty) = Value v (subst theta ty)-> subst theta (Label l r ty) = Label l r (subst theta ty)--> instance SubstType a => SubstType (TopEnv a) where-> subst = fmap . subst--\end{verbatim}-The function \texttt{expandAliasType} expands all occurrences of a-type synonym in a type. After the expansion we have to reassign the-type indices for all type variables. Otherwise, expanding a type-synonym like \verb|type Pair' a b = (b,a)| could break the invariant-that the universally quantified type variables are assigned indices in-the order of their occurrence. This is handled by the function-\texttt{normalize}.-\begin{verbatim}--> expandAliasType :: [Type] -> Type -> Type-> expandAliasType tys (TypeConstructor tc tys') =-> TypeConstructor tc (map (expandAliasType tys) tys')-> expandAliasType tys (TypeVariable n)-> | n >= 0 = tys !! n-> | otherwise = TypeVariable n-> expandAliasType _ (TypeConstrained tys n) = TypeConstrained tys n-> expandAliasType tys (TypeArrow ty1 ty2) =-> TypeArrow (expandAliasType tys ty1) (expandAliasType tys ty2)-> expandAliasType _ (TypeSkolem k) = TypeSkolem k-> expandAliasType tys (TypeRecord fs rv)-> | isJust rv =-> let (TypeVariable tv) = expandAliasType tys (TypeVariable (fromJust rv))-> in TypeRecord fs' (Just tv)-> | otherwise =-> TypeRecord fs' Nothing-> where fs' = map (\ (l,ty) -> (l, expandAliasType tys ty)) fs--> normalize :: Type -> Type-> normalize ty = expandAliasType [TypeVariable (occur tv) | tv <- [0..]] ty-> where tvs = zip (nub (filter (>= 0) (typeVars ty))) [0..]-> occur tv = fromJust (lookup tv tvs)--\end{verbatim}
− src/Types.lhs
@@ -1,251 +0,0 @@-% $Id: Types.lhs,v 1.11 2004/02/08 22:14:02 wlux Exp $-%-% Copyright (c) 2002, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{Types.lhs}-\section{Types}-This module modules provides the definitions for the internal -representation of types in the compiler.-\begin{verbatim}--> module Types where--> import Data.List-> import Data.Maybe--> import Curry.Base.Ident--\end{verbatim}-A type is either a type variable, an application of a type constructor-to a list of arguments, or an arrow type. The \texttt{TypeConstrained}-case is used for representing type variables that are restricted to a-particular set of types. At present, this is used for typing guard-expressions, which are restricted to be either of type \texttt{Bool}-or of type \texttt{Success}, and integer literals, which are-restricted to types \texttt{Int} and \texttt{Float}. If the type is-not restricted it defaults to the first type from the constraint list.-The case \texttt{TypeSkolem} is used for handling skolem types, which-result from the use of existentially quantified data constructors.--Type variables are represented with deBruijn style indices. Universally-quantified type variables are assigned indices in the order of their-occurrence in the type from left to right. This leads to a canonical-representation of types where $\alpha$-equivalence of two types-coincides with equality of the representation.--Note that even though \texttt{TypeConstrained} variables use indices-as well, these variables must never be quantified.-\begin{verbatim}--> data Type =-> TypeConstructor QualIdent [Type]-> | TypeVariable Int-> | TypeConstrained [Type] Int-> | TypeArrow Type Type-> | TypeSkolem Int-> | TypeRecord [(Ident,Type)] (Maybe Int)-> deriving (Show, Eq)--\end{verbatim}-The function \texttt{isArrowType} checks whether a type is a function-type $t_1 \rightarrow t_2 \rightarrow \dots \rightarrow t_n$ . The-function \texttt{arrowArity} computes the arity $n$ of a function type-and \texttt{arrowBase} returns the type $t_n$.-\begin{verbatim}--> isArrowType :: Type -> Bool-> isArrowType (TypeArrow _ _) = True-> isArrowType _ = False--> arrowArity :: Type -> Int-> arrowArity (TypeArrow _ ty) = 1 + arrowArity ty-> arrowArity _ = 0--> arrowArgs :: Type -> [Type]-> arrowArgs (TypeArrow ty1 ty2) = ty1 : arrowArgs ty2-> arrowArgs ty = []--> arrowBase :: Type -> Type-> arrowBase (TypeArrow _ ty) = arrowBase ty-> arrowBase ty = ty--\end{verbatim}-The functions \texttt{typeVars}, \texttt{typeConstrs},-\texttt{typeSkolems} return a list of all type variables, type-constructors, or skolems occurring in a type $t$, respectively. Note-that \texttt{TypeConstrained} variables are not included in the set of-type variables because they cannot be generalized.-\begin{verbatim}--> typeVars :: Type -> [Int]-> typeVars ty = vars ty []-> where vars (TypeConstructor _ tys) tvs = foldr vars tvs tys-> vars (TypeVariable tv) tvs = tv : tvs-> vars (TypeConstrained _ _) tvs = tvs-> vars (TypeArrow ty1 ty2) tvs = vars ty1 (vars ty2 tvs)-> vars (TypeSkolem _) tvs = tvs-> vars (TypeRecord fs rtv) tvs =-> foldr vars (maybe tvs (: tvs) rtv) (map snd fs)--> typeConstrs :: Type -> [QualIdent]-> typeConstrs ty = types ty []-> where types (TypeConstructor tc tys) tcs = tc : foldr types tcs tys-> types (TypeVariable _) tcs = tcs-> types (TypeConstrained _ _) tcs = tcs-> types (TypeArrow ty1 ty2) tcs = types ty1 (types ty2 tcs)-> types (TypeSkolem _) tcs = tcs-> types (TypeRecord fs _) tcs =-> foldr types tcs (map snd fs)--> typeSkolems :: Type -> [Int]-> typeSkolems ty = skolems ty []-> where skolems (TypeConstructor _ tys) sks = foldr skolems sks tys-> skolems (TypeVariable _) sks = sks-> skolems (TypeConstrained _ _) sks = sks-> skolems (TypeArrow ty1 ty2) sks = skolems ty1 (skolems ty2 sks)-> skolems (TypeSkolem k) sks = k : sks-> skolems (TypeRecord fs _) sks =-> foldr skolems sks (map snd fs)--> equTypes :: Type -> Type -> Bool-> equTypes t1 t2 = fst (equ [] t1 t2)-> where -> equ is (TypeConstructor qid1 ts1) (TypeConstructor qid2 ts2)-> | qid1 == qid2 = equs is ts1 ts2-> | otherwise = (False, is)-> equ is (TypeVariable i1) (TypeVariable i2)-> = maybe (True, (i1,i2):is) -> (\ i2' -> (i2 == i2', is))-> (lookup i1 is)-> equ is (TypeConstrained ts1 i1) (TypeConstrained ts2 i2)-> = let (res, is') = equs is ts1 ts2-> in maybe (res, (i1,i2):is')-> (\ i2' -> (res && i2 == i2', is'))-> (lookup i1 is')-> equ is (TypeArrow tf1 tt1) (TypeArrow tf2 tt2)-> = let (res1, is1) = equ is tf1 tf2-> (res2, is2) = equ is1 tt1 tt2-> in (res1 && res2, is2)-> equ is (TypeSkolem i1) (TypeSkolem i2)-> = maybe (True, (i1,i2):is)-> (\ i2' -> (i2 == i2', is))-> (lookup i1 is)-> equ is (TypeRecord fs1 r1) (TypeRecord fs2 r2)-> | isJust r1 && isJust r2-> = let (res1, is1) = equ is (TypeVariable (fromJust r1))-> (TypeVariable (fromJust r2))-> (res2, is2) = equRecords is1 fs1 fs2-> in (res1 && res2, is2)-> | isNothing r1 && isNothing r2 = equRecords is fs1 fs2-> | otherwise = (False, is)-> equ is _ _ = (False, is)-> -> equRecords is fs1 fs2 | length fs1 == length fs2 = equrec is fs1 fs2-> | otherwise = (False, is)-> where-> equrec is [] fs2 = (True, is)-> equrec is ((l,t):fs1) fs2-> = let (res1, is1) = maybe (False,is) (equ is t) (lookup l fs2)-> (res2, is2) = equrec is1 fs1 fs2-> in (res1 && res2, is2)->-> equs is [] [] = (True, is)-> equs is (t1:ts1) (t2:ts2)-> = let (res1, is1) = equ is t1 t2-> (res2, is2) = equs is1 ts1 ts2-> in (res1 && res2, is2)--\end{verbatim}-We support two kinds of quantifications of types here, universally-quantified type schemes $\forall\overline{\alpha} .-\tau(\overline{\alpha})$ and universally and existentially quantified-type schemes $\forall\overline{\alpha} \exists\overline{\eta} .-\tau(\overline{\alpha},\overline{\eta})$. In both, quantified type-variables are assigned ascending indices starting from 0. Therefore it-is sufficient to record the numbers of quantified type variables in-the \texttt{ForAll} and \texttt{ForAllExist} constructors. In case of-the latter, the first of the two numbers is the number of universally-quantified variables and the second the number of existentially-quantified variables.-\begin{verbatim}--> data TypeScheme = ForAll Int Type deriving (Show, Eq)-> data ExistTypeScheme = ForAllExist Int Int Type deriving (Show, Eq)--\end{verbatim}-The functions \texttt{monoType} and \texttt{polyType} translate a type-$\tau$ into a monomorphic type scheme $\forall.\tau$ and a polymorphic-type scheme $\forall\overline{\alpha}.\tau$ where $\overline{\alpha} =-\textrm{fv}(\tau)$, respectively. \texttt{polyType} assumes that all-universally quantified variables in the type are assigned indices-starting with 0 and does not renumber the variables.-\begin{verbatim}--> monoType, polyType :: Type -> TypeScheme-> monoType ty = ForAll 0 ty-> polyType ty = ForAll (maximum (-1 : typeVars ty) + 1) ty--\end{verbatim}-There are a few predefined types:-\begin{verbatim}--> unitType,boolType,charType,intType,floatType,stringType,successType :: Type-> unitType = primType unitId []-> boolType = primType boolId []-> charType = primType charId []-> intType = primType intId []-> floatType = primType floatId []-> stringType = listType charType-> successType = primType successId []--> listType,ioType :: Type -> Type-> listType ty = primType listId [ty]-> ioType ty = primType ioId [ty]--> tupleType :: [Type] -> Type-> tupleType tys = primType (tupleId (length tys)) tys--> primType :: Ident -> [Type] -> Type-> primType = TypeConstructor . qualifyWith preludeMIdent--> typeVar :: Int -> Type-> typeVar = TypeVariable--\end{verbatim}----> qualifyType :: ModuleIdent -> Type -> Type-> qualifyType m (TypeConstructor tc tys)-> | isTupleId tc' = tupleType tys'-> | tc' == unitId && n == 0 = unitType-> | tc' == listId && n == 1 = listType (head tys')-> | otherwise = TypeConstructor (qualQualify m tc) tys'-> where n = length tys'-> tc' = unqualify tc-> tys' = map (qualifyType m) tys-> qualifyType _ (TypeVariable tv) = TypeVariable tv-> qualifyType m (TypeConstrained tys tv) =-> TypeConstrained (map (qualifyType m) tys) tv-> qualifyType m (TypeArrow ty1 ty2) =-> TypeArrow (qualifyType m ty1) (qualifyType m ty2)-> qualifyType _ (TypeSkolem k) = TypeSkolem k-> qualifyType m (TypeRecord fs rty) =-> TypeRecord (map (\ (l,ty) -> (l, qualifyType m ty)) fs) rty---> unqualifyType :: ModuleIdent -> Type -> Type-> unqualifyType m (TypeConstructor tc tys) =-> TypeConstructor (qualUnqualify m tc) (map (unqualifyType m) tys)-> unqualifyType _ (TypeVariable tv) = TypeVariable tv-> unqualifyType m (TypeConstrained tys tv) =-> TypeConstrained (map (unqualifyType m) tys) tv-> unqualifyType m (TypeArrow ty1 ty2) =-> TypeArrow (unqualifyType m ty1) (unqualifyType m ty2)-> unqualifyType m (TypeSkolem k) = TypeSkolem k-> unqualifyType m (TypeRecord fs rty) =-> TypeRecord (map (\ (l,ty) -> (l, unqualifyType m ty)) fs) rty-
− src/Typing.lhs
@@ -1,406 +0,0 @@--% $Id: Typing.lhs,v 1.7 2004/02/12 19:13:12 wlux Exp $-%-% Copyright (c) 2003-2006, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{Typing.lhs}-\section{Computing the Type of Curry Expressions}-\begin{verbatim}--> module Typing(Typeable(..)) where--> import Data.Maybe-> import Control.Monad-> import Control.Monad.State as S--> import Curry.Base.Ident-> import Curry.Syntax-> import Curry.Syntax.Utils--> import Types-> import Base-> import TypeSubst-> import TopEnv-> import Utils---\end{verbatim}-During the transformation of Curry source code into the intermediate-language, the compiler has to recompute the types of expressions. This-is simpler than type checking because the types of all variables are-known. Yet, the compiler still must handle functions and constructors-with polymorphic types and instantiate their type schemes using fresh-type variables. Since all types computed by \texttt{typeOf} are-monomorphic, we can use type variables with non-negative offsets for-the instantiation of type schemes here without risk of name conflicts.-Using non-negative offsets also makes it easy to distinguish these-fresh variables from free type variables introduce during type-inference, which must be regarded as constants here.--However, using non-negative offsets for fresh type variables gives-rise to two problems when those types are entered back into the type-environment, e.g., while introducing auxiliary variables during-desugaring. The first is that those type variables now appear to be-universally quantified variables, but with indices greater than the-number of quantified type variables.\footnote{To be precise, this can- happen only for auxiliary variables, which have monomorphic types,- whereas auxiliary functions will be assigned polymorphic types and- these type variables will be properly quantified. However, in this- case the assigned types may be too general.} This results in an-internal error (``Prelude.!!: index too large'') whenever such a type-is instantiated. The second problem is that there may be inadvertent-name captures because \texttt{computeType} always uses indices-starting at 0 for the fresh type variables. In order to avoid these-problems, \texttt{computeType} renames all type variables with-non-negative offsets after the final type has been computed, using-negative indices below the one with the smallest value occurring in-the type environment. Computing the minimum index of all type-variables in the type environment seems prohibitively inefficient.-However, recall that, thanks to laziness, the minimum is computed only-when the final type contains any type variables with non-negative-indices. This happens, for instance, 36 times while compiling the-prelude (for 159 evaluated applications of \texttt{typeOf}) and only-twice while compiling the standard \texttt{IO} module (for 21-applications of \texttt{typeOf}).\footnote{These numbers were obtained- for version 0.9.9.}--A careful reader will note that inadvertent name captures are still-possible if one computes the types of two or more auxiliary variables-before actually entering their types into the environment. Therefore,-make sure that you enter the types of these auxiliary variables-immediately into the type environment, unless you are sure that those-types cannot contain fresh type variables. One such case are the free-variables of a goal.--\ToDo{In the long run, this module should be made obsolete by adding-attributes to the abstract syntax tree -- e.g., along the lines of-Chap.~6 in~\cite{PeytonJonesLester92:Book} -- and returning an-abstract syntax tree attributed with type information together with-the type environment from type inference. This also would allow-getting rid of the identifiers in the representation of integer-literals, which are used in order to implement overloading of-integer constants.}--\ToDo{When computing the type of an expression with a type signature-make use of the annotation instead of recomputing its type. In order-to do this, we must either ensure that the types are properly-qualified and expanded or we need access to the type constructor-environment.}-\begin{verbatim}--> type TyState a = S.StateT TypeSubst (S.State Int) a--> run :: TyState a -> ValueEnv -> a-> run m tyEnv = S.evalState (S.evalStateT m idSubst) 0--> class Typeable a where-> typeOf :: ValueEnv -> a -> Type--> instance Typeable Ident where-> typeOf = computeType identType--> instance Typeable ConstrTerm where-> typeOf = computeType argType--> instance Typeable Expression where-> typeOf = computeType exprType--> instance Typeable Rhs where-> typeOf = computeType rhsType--> computeType f tyEnv x = normalize (run doComputeType tyEnv)-> where doComputeType =-> do-> ty <- f tyEnv x-> theta <- S.get-> return (fixTypeVars tyEnv (subst theta ty))--> fixTypeVars :: ValueEnv -> Type -> Type-> fixTypeVars tyEnv ty = subst (foldr2 bindSubst idSubst tvs tvs') ty-> where tvs = filter (>= 0) (typeVars ty)-> tvs' = map TypeVariable [n - 1,n - 2 ..]-> n = minimum (0 : concatMap typeVars tys)-> tys = [ty | (_,Value _ (ForAll _ ty)) <- localBindings tyEnv]--> identType :: ValueEnv -> Ident -> TyState Type-> identType tyEnv x = instUniv (varType x tyEnv)--> litType :: ValueEnv -> Literal -> TyState Type-> litType _ (Char _ _) = return charType-> litType tyEnv (Int v _) = identType tyEnv v-> litType _ (Float _ _) = return floatType-> litType _ (String _ _) = return stringType--> argType :: ValueEnv -> ConstrTerm -> TyState Type-> argType tyEnv (LiteralPattern l) = litType tyEnv l-> argType tyEnv (NegativePattern _ l) = litType tyEnv l-> argType tyEnv (VariablePattern v) = identType tyEnv v-> argType tyEnv (ConstructorPattern c ts) =-> do-> ty <- instUnivExist (constrType c tyEnv)-> tys <- mapM (argType tyEnv) ts-> unifyList (init (flatten ty)) tys-> return (last (flatten ty))-> where flatten (TypeArrow ty1 ty2) = ty1 : flatten ty2-> flatten ty = [ty]-> argType tyEnv (InfixPattern t1 op t2) =-> argType tyEnv (ConstructorPattern op [t1,t2])-> argType tyEnv (ParenPattern t) = argType tyEnv t-> argType tyEnv (TuplePattern _ ts)-> | null ts = return unitType-> | otherwise = liftM tupleType $ mapM (argType tyEnv) ts-> argType tyEnv (ListPattern _ ts) = freshTypeVar >>= flip elemType ts-> where elemType ty [] = return (listType ty)-> elemType ty (t:ts) =-> argType tyEnv t >>= unify ty >> elemType ty ts-> argType tyEnv (AsPattern v _) = argType tyEnv (VariablePattern v)-> argType tyEnv (LazyPattern _ t) = argType tyEnv t-> argType tyEnv (FunctionPattern f ts) =-> do -> ty <- instUniv (funType f tyEnv)-> tys <- mapM (argType tyEnv) ts-> unifyList (init (flatten ty)) tys-> return (last (flatten ty))-> where flatten (TypeArrow ty1 ty2) = ty1 : flatten ty2-> flatten ty = [ty]-> argType tyEnv (InfixFuncPattern t1 op t2) =-> argType tyEnv (FunctionPattern op [t1,t2])-> argType tyEnv (RecordPattern fs r)-> | isJust r =-> do-> tys <- mapM (fieldPattType tyEnv) fs-> rty <- argType tyEnv (fromJust r)-> (TypeVariable i) <- freshTypeVar-> unify rty (TypeRecord tys (Just i))-> return rty-> | otherwise =-> do-> tys <- mapM (fieldPattType tyEnv) fs-> return (TypeRecord tys Nothing)--> fieldPattType :: ValueEnv -> Field ConstrTerm -> TyState (Ident,Type)-> fieldPattType tyEnv (Field _ l t) =-> do-> lty <- instUniv (labelType l tyEnv)-> ty <- argType tyEnv t-> unify lty ty-> return (l,lty)--> exprType :: ValueEnv -> Expression -> TyState Type-> exprType tyEnv (Literal l) = litType tyEnv l-> exprType tyEnv (Variable v) = instUniv (funType v tyEnv)-> exprType tyEnv (Constructor c) = instUnivExist (constrType c tyEnv)-> exprType tyEnv (Typed e _) = exprType tyEnv e-> exprType tyEnv (Paren e) = exprType tyEnv e-> exprType tyEnv (Tuple _ es)-> | null es = return unitType-> | otherwise = liftM tupleType $ mapM (exprType tyEnv) es-> exprType tyEnv (List _ es) = freshTypeVar >>= flip elemType es-> where elemType ty [] = return (listType ty)-> elemType ty (e:es) =-> exprType tyEnv e >>= unify ty >> elemType ty es-> exprType tyEnv (ListCompr _ e _) = liftM listType $ exprType tyEnv e-> exprType tyEnv (EnumFrom _) = return (listType intType)-> exprType tyEnv (EnumFromThen _ _) = return (listType intType)-> exprType tyEnv (EnumFromTo _ _) = return (listType intType)-> exprType tyEnv (EnumFromThenTo _ _ _) = return (listType intType)-> exprType tyEnv (UnaryMinus _ e) = exprType tyEnv e-> exprType tyEnv (Apply e1 e2) =-> do-> (ty1,ty2) <- exprType tyEnv e1 >>= unifyArrow-> exprType tyEnv e2 >>= unify ty1-> return ty2-> exprType tyEnv (InfixApply e1 op e2) =-> do-> (ty1,ty2,ty3) <- exprType tyEnv (infixOp op) >>= unifyArrow2-> exprType tyEnv e1 >>= unify ty1-> exprType tyEnv e2 >>= unify ty2-> return ty3-> exprType tyEnv (LeftSection e op) =-> do-> (ty1,ty2,ty3) <- exprType tyEnv (infixOp op) >>= unifyArrow2-> exprType tyEnv e >>= unify ty1-> return (TypeArrow ty2 ty3)-> exprType tyEnv (RightSection op e) =-> do-> (ty1,ty2,ty3) <- exprType tyEnv (infixOp op) >>= unifyArrow2-> exprType tyEnv e >>= unify ty2-> return (TypeArrow ty1 ty3)-> exprType tyEnv (Lambda _ args e) =-> do-> tys <- mapM (argType tyEnv) args-> ty <- exprType tyEnv e-> return (foldr TypeArrow ty tys)-> exprType tyEnv (Let _ e) = exprType tyEnv e-> exprType tyEnv (Do _ e) = exprType tyEnv e-> exprType tyEnv (IfThenElse _ e1 e2 e3) =-> do-> exprType tyEnv e1 >>= unify boolType-> ty2 <- exprType tyEnv e2-> ty3 <- exprType tyEnv e3-> unify ty2 ty3-> return ty3-> exprType tyEnv (Case _ _ alts) = freshTypeVar >>= flip altType alts-> where altType ty [] = return ty-> altType ty (Alt _ _ rhs:alts) =-> rhsType tyEnv rhs >>= unify ty >> altType ty alts-> exprType tyEnv (RecordConstr fs) =-> do -> tys <- mapM (fieldExprType tyEnv) fs-> return (TypeRecord tys Nothing)-> exprType tyEnv (RecordSelection r l) =-> do -> lty <- instUniv (labelType l tyEnv)-> rty <- exprType tyEnv r-> (TypeVariable i) <- freshTypeVar-> unify rty (TypeRecord [(l,lty)] (Just i))-> return lty-> exprType tyEnv (RecordUpdate fs r) =-> do-> tys <- mapM (fieldExprType tyEnv) fs-> rty <- exprType tyEnv r-> (TypeVariable i) <- freshTypeVar-> unify rty (TypeRecord tys (Just i))-> return rty--> rhsType :: ValueEnv -> Rhs -> TyState Type-> rhsType tyEnv (SimpleRhs _ e _) = exprType tyEnv e-> rhsType tyEnv (GuardedRhs es _) = freshTypeVar >>= flip condExprType es-> where condExprType ty [] = return ty-> condExprType ty (CondExpr _ _ e:es) =-> exprType tyEnv e >>= unify ty >> condExprType ty es--> fieldExprType :: ValueEnv -> Field Expression -> TyState (Ident,Type)-> fieldExprType tyEnv (Field _ l e) =-> do-> lty <- instUniv (labelType l tyEnv)-> ty <- exprType tyEnv e-> unify lty ty-> return (l,lty)--\end{verbatim}-In order to avoid name conflicts with non-generalized type variables-in a type we instantiate quantified type variables using non-negative-offsets here.-\begin{verbatim}--> freshTypeVar :: TyState Type-> freshTypeVar = liftM TypeVariable $ S.lift (S.modify succ >> S.get)--> instType :: Int -> Type -> TyState Type-> instType n ty =-> do-> tys <- sequence (replicate n freshTypeVar)-> return (expandAliasType tys ty)--> instUniv :: TypeScheme -> TyState Type-> instUniv (ForAll n ty) = instType n ty--> instUnivExist :: ExistTypeScheme -> TyState Type-> instUnivExist (ForAllExist n n' ty) = instType (n + n') ty--\end{verbatim}-When unifying two types, the non-generalized variables, i.e.,-variables with negative offsets, must not be substituted. Otherwise,-the unification algorithm is identical to the one used by the type-checker.-\begin{verbatim}--> unify :: Type -> Type -> TyState ()-> unify ty1 ty2 =-> S.modify (\theta -> unifyTypes (subst theta ty1) (subst theta ty2) theta)--> unifyList :: [Type] -> [Type] -> TyState ()-> unifyList tys1 tys2 = sequence_ (zipWith unify tys1 tys2)--> unifyArrow :: Type -> TyState (Type,Type)-> unifyArrow ty =-> do-> theta <- S.get-> case subst theta ty of-> TypeVariable tv-> | tv >= 0 ->-> do-> ty1 <- freshTypeVar-> ty2 <- freshTypeVar-> S.modify (bindVar tv (TypeArrow ty1 ty2))-> return (ty1,ty2)-> TypeArrow ty1 ty2 -> return (ty1,ty2)-> ty' -> internalError ("unifyArrow (" ++ show ty' ++ ")")--> unifyArrow2 :: Type -> TyState (Type,Type,Type)-> unifyArrow2 ty =-> do-> (ty1,ty2) <- unifyArrow ty-> (ty21,ty22) <- unifyArrow ty2-> return (ty1,ty21,ty22)--> unifyTypes :: Type -> Type -> TypeSubst -> TypeSubst-> unifyTypes (TypeVariable tv1) (TypeVariable tv2) theta-> | tv1 == tv2 = theta-> unifyTypes (TypeVariable tv) ty theta-> | tv >= 0 = bindVar tv ty theta-> unifyTypes ty (TypeVariable tv) theta-> | tv >= 0 = bindVar tv ty theta-> unifyTypes (TypeConstructor tc1 tys1) (TypeConstructor tc2 tys2) theta-> | tc1 == tc2 = foldr2 unifyTypes theta tys1 tys2-> unifyTypes (TypeConstrained tys1 tv1) (TypeConstrained tys2 tv2) theta-> | tv1 == tv2 = theta-> unifyTypes (TypeArrow ty11 ty12) (TypeArrow ty21 ty22) theta =-> unifyTypes ty11 ty21 (unifyTypes ty12 ty22 theta)-> unifyTypes (TypeSkolem k1) (TypeSkolem k2) theta-> | k1 == k2 = theta-> unifyTypes (TypeRecord fs1 Nothing) (TypeRecord fs2 Nothing) theta-> | length fs1 == length fs2 = foldr (unifyTypedLabels fs1) theta fs2-> unifyTypes tr1@(TypeRecord fs1 Nothing) (TypeRecord fs2 (Just a2)) theta =-> unifyTypes (TypeVariable a2)-> tr1-> (foldr (unifyTypedLabels fs1) theta fs2)-> unifyTypes tr1@(TypeRecord _ (Just _)) tr2@(TypeRecord _ Nothing) theta =-> unifyTypes tr2 tr1 theta-> unifyTypes (TypeRecord fs1 (Just a1)) (TypeRecord fs2 (Just a2)) theta =-> unifyTypes (TypeVariable a1)-> (TypeVariable a2)-> (foldr (unifyTypedLabels fs1) theta fs2)-> unifyTypes ty1 ty2 _ =-> internalError ("unify: (" ++ show ty1 ++ ") (" ++ show ty2 ++ ")")--> unifyTypedLabels :: [(Ident,Type)] -> (Ident,Type) -> TypeSubst -> TypeSubst-> unifyTypedLabels fs1 (l,ty) theta =-> maybe theta (\ty1 -> unifyTypes ty1 ty theta) (lookup l fs1)--\end{verbatim}-The functions \texttt{constrType}, \texttt{varType}, and-\texttt{funType} are used for computing the type of constructors,-pattern variables, and variables.--\ToDo{These functions should be shared with the type checker.}-\begin{verbatim}--> constrType :: QualIdent -> ValueEnv -> ExistTypeScheme-> constrType c tyEnv =-> case qualLookupValue c tyEnv of-> [DataConstructor _ sigma] -> sigma-> [NewtypeConstructor _ sigma] -> sigma-> _ -> internalError ("constrType " ++ show c)--> varType :: Ident -> ValueEnv -> TypeScheme-> varType v tyEnv =-> case lookupValue v tyEnv of-> [Value _ sigma] -> sigma-> _ -> internalError ("varType " ++ show v)--> funType :: QualIdent -> ValueEnv -> TypeScheme-> funType f tyEnv =-> case qualLookupValue f tyEnv of-> [Value _ sigma] -> sigma-> _ -> internalError ("funType " ++ show f)--> labelType :: Ident -> ValueEnv -> TypeScheme-> labelType l tyEnv =-> case lookupValue l tyEnv of-> [Label _ _ sigma] -> sigma-> _ -> internalError ("labelType " ++ show l)--\end{verbatim}
− src/Utils.lhs
@@ -1,92 +0,0 @@-% $Id: Utils.lhs,v 1.4 2003/10/04 17:04:38 wlux Exp $-%-% Copyright (c) 2001-2003, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{Utils.lhs}-\section{Utility Functions}-The module \texttt{Utils} provides a few simple functions that are-commonly used in the compiler, but not implemented in the Haskell-\texttt{Prelude} or standard library.-\begin{verbatim}--> module Utils where--> infixr 5 ++!--\end{verbatim}-\paragraph{Triples}-The \texttt{Prelude} does not contain standard functions for-triples. We provide projection, (un-)currying, and mapping for triples-here.-\begin{verbatim}--> fst3 (x,_,_) = x-> snd3 (_,y,_) = y-> thd3 (_,_,z) = z--> apFst3 f (x,y,z) = (f x,y,z)-> apSnd3 f (x,y,z) = (x,f y,z)-> apThd3 f (x,y,z) = (x,y,f z)--> curry3 f x y z = f (x,y,z)-> uncurry3 f (x,y,z) = f x y z--\end{verbatim}-\paragraph{Lists}-The function \texttt{(++!)} is variant of the list concatenation-operator \texttt{(++)} that ignores the second argument if the first-is a non-empty list. When lists are used to encode non-determinism in-Haskell, this operator has the same effect as the cut operator in-Prolog, hence the \texttt{!} in the name.-\begin{verbatim}--> (++!) :: [a] -> [a] -> [a]-> xs ++! ys = if null xs then ys else xs--\end{verbatim}-\paragraph{Strict fold}-The function \texttt{foldl\_strict} is a strict version of-\texttt{foldl}, i.e., it evaluates the binary applications before-the recursion. This has the advantage that \texttt{foldl\_strict} does-not construct a large application which is then evaluated in the base-case of the recursion.-\begin{verbatim}--foldl_strict :: (a -> b -> a) -> a -> [b] -> a-foldl_strict = foldl'---\end{verbatim}-\paragraph{Folding with two lists}-Fold operations with two arguments lists can be defined using-\texttt{zip} and \texttt{foldl} or \texttt{foldr}, resp. Our-definitions are unfolded for efficiency reasons.-\begin{verbatim}--> foldl2 :: (a -> b -> c -> a) -> a -> [b] -> [c] -> a-> foldl2 f z [] _ = z-> foldl2 f z _ [] = z-> foldl2 f z (x:xs) (y:ys) = foldl2 f (f z x y) xs ys--> foldr2 :: (a -> b -> c -> c) -> c -> [a] -> [b] -> c-> foldr2 f z [] _ = z-> foldr2 f z _ [] = z-> foldr2 f z (x:xs) (y:ys) = f x y (foldr2 f z xs ys)--\end{verbatim}-\paragraph{Monadic fold with an accumulator}-The function \texttt{mapAccumM} is a generalization of-\texttt{mapAccumL} to monads like \texttt{foldM} is for-\texttt{foldl}.-\begin{verbatim}--> mapAccumM :: Monad m => (a -> b -> m (a,c)) -> a -> [b] -> m (a,[c])-> mapAccumM _ s [] = return (s,[])-> mapAccumM f s (x:xs) =-> do-> (s',y) <- f s x-> (s'',ys) <- mapAccumM f s' xs-> return (s'',y:ys)--\end{verbatim}
− src/WarnCheck.hs
@@ -1,872 +0,0 @@-------------------------------------------------------------------------------------- WarnCheck - Searches for potentially irregular code and generates--- warning messages--- --- February 2006,--- Martin Engelke (men@informatik.uni-kiel.de)----module WarnCheck (warnCheck) where--import Control.Monad.State-import qualified Data.Map as Map-import Data.List--import Curry.Base.Ident-import Curry.Base.Position-import Curry.Base.MessageMonad-import Curry.Syntax--import Base (ValueEnv, ValueInfo(..), qualLookupValue)-import TopEnv-import qualified ScopeEnv-import ScopeEnv (ScopeEnv)-------------------------------------------------------------------------------------- Data type for representing the current state of generating warnings.--- The monadic representation of the state allows the usage of monadic --- syntax (do expression) for dealing easier and safer with its--- contents.--type CheckState = State CState--data CState = CState {messages :: [WarnMsg],- scope :: ScopeEnv QualIdent IdInfo,- values :: ValueEnv,- moduleId :: ModuleIdent }---- Runs a 'CheckState' action and returns the list of messages-run :: CheckState a -> [WarnMsg]-run f- = reverse (messages (execState f emptyState))--emptyState :: CState-emptyState = CState {messages = [],- scope = ScopeEnv.new,- values = emptyTopEnv,- moduleId = mkMIdent []- }------------------------------------------------------------------------------------- Find potentially incorrect code in a Curry program and generate--- the following warnings for:--- - unreferenced variables--- - shadowing variables--- - idle case alternatives--- - overlapping case alternatives--- - function rules which are not together-warnCheck :: ModuleIdent -> ValueEnv -> [Decl] -> [Decl] -> [WarnMsg]-warnCheck mid vals imports decls- = run (do addImportedValues vals- addModuleId mid- checkImports imports- foldM' insertDecl decls- foldM' (checkDecl mid) decls- checkDeclOccurrences decls- )-----------------------------------------------------------------------------------------------------------------------------------------------------------------------checkDecl :: ModuleIdent -> Decl -> CheckState ()-checkDecl mid (DataDecl pos ident params cdecls)- = do beginScope- foldM' insertTypeVar params- foldM' (checkConstrDecl mid) cdecls- params' <- filterM isUnrefTypeVar params- when (not (null params')) - (foldM' genWarning' (map unrefTypeVar params'))- endScope-checkDecl mid (TypeDecl _ ident params texpr)- = do beginScope- foldM' insertTypeVar params- checkTypeExpr mid texpr- params' <- filterM isUnrefTypeVar params- when (not (null params'))- (foldM' genWarning' (map unrefTypeVar params'))- endScope-checkDecl mid (FunctionDecl pos ident equs)- = do beginScope- foldM' (checkEquation mid) equs- c <- isConsId ident- idents' <- returnUnrefVars- when (not (c || null idents')) - (foldM' genWarning' (map unrefVar idents'))- endScope-checkDecl mid (PatternDecl _ cterm rhs)- = do checkConstrTerm mid cterm- checkRhs mid rhs-checkDecl _ _ = return ()---- Checks locally declared identifiers (i.e. functions and logic variables)--- for shadowing-checkLocalDecl :: Decl -> CheckState ()-checkLocalDecl (FunctionDecl pos ident _)- = do s <- isShadowingVar ident- when s (genWarning' (shadowingVar ident))-checkLocalDecl (ExtraVariables pos idents)- = do idents' <- filterM isShadowingVar idents- when (not (null idents'))- (foldM' genWarning' (map shadowingVar idents'))-checkLocalDecl (PatternDecl _ constrTerm _)- = checkConstrTerm (mkMIdent []) constrTerm-checkLocalDecl _ = return ()-----checkConstrDecl :: ModuleIdent -> ConstrDecl -> CheckState ()-checkConstrDecl mid (ConstrDecl _ _ ident texprs)- = do visitId ident- foldM' (checkTypeExpr mid) texprs-checkConstrDecl mid (ConOpDecl _ _ texpr1 ident texpr2)- = do visitId ident- checkTypeExpr mid texpr1- checkTypeExpr mid texpr2---checkTypeExpr :: ModuleIdent -> TypeExpr -> CheckState ()-checkTypeExpr mid (ConstructorType qid texprs)- = do maybe (return ()) visitTypeId (localIdent mid qid)- foldM' (checkTypeExpr mid ) texprs-checkTypeExpr mid (VariableType ident)- = visitTypeId ident-checkTypeExpr mid (TupleType texprs)- = foldM' (checkTypeExpr mid ) texprs-checkTypeExpr mid (ListType texpr)- = checkTypeExpr mid texpr-checkTypeExpr mid (ArrowType texpr1 texpr2)- = do checkTypeExpr mid texpr1- checkTypeExpr mid texpr2-checkTypeExpr mid (RecordType fields restr)- = do foldM' (checkTypeExpr mid ) (map snd fields)- maybe (return ()) (checkTypeExpr mid ) restr-----checkEquation :: ModuleIdent -> Equation -> CheckState ()-checkEquation mid (Equation _ lhs rhs)- = do checkLhs mid lhs- checkRhs mid rhs-----checkLhs :: ModuleIdent -> Lhs -> CheckState ()-checkLhs mid (FunLhs ident cterms)- = do visitId ident- foldM' (checkConstrTerm mid) cterms- foldM' (insertConstrTerm False) cterms-checkLhs mid (OpLhs cterm1 ident cterm2)- = checkLhs mid (FunLhs ident [cterm1, cterm2])-checkLhs mid (ApLhs lhs cterms)- = do checkLhs mid lhs- foldM' (checkConstrTerm mid ) cterms- foldM' (insertConstrTerm False) cterms-----checkRhs :: ModuleIdent -> Rhs -> CheckState ()-checkRhs mid (SimpleRhs _ expr decls)- = do beginScope -- function arguments can be overwritten by local decls- foldM' checkLocalDecl decls- foldM' insertDecl decls- foldM' (checkDecl mid) decls- checkDeclOccurrences decls- checkExpression mid expr- idents' <- returnUnrefVars- when (not (null idents'))- (foldM' genWarning' (map unrefVar idents'))- endScope-checkRhs mid (GuardedRhs cexprs decls)- = do beginScope- foldM' checkLocalDecl decls- foldM' insertDecl decls- foldM' (checkDecl mid) decls- checkDeclOccurrences decls- foldM' (checkCondExpr mid) cexprs- idents' <- returnUnrefVars- when (not (null idents'))- (foldM' genWarning' (map unrefVar idents'))- endScope------checkCondExpr :: ModuleIdent -> CondExpr -> CheckState ()-checkCondExpr mid (CondExpr _ cond expr)- = do checkExpression mid cond- checkExpression mid expr---- -checkConstrTerm :: ModuleIdent -> ConstrTerm -> CheckState ()-checkConstrTerm mid (VariablePattern ident)- = do s <- isShadowingVar ident- when s (genWarning' (shadowingVar ident))-checkConstrTerm mid (ConstructorPattern _ cterms)- = foldM' (checkConstrTerm mid ) cterms-checkConstrTerm mid (InfixPattern cterm1 qident cterm2)- = checkConstrTerm mid (ConstructorPattern qident [cterm1, cterm2])-checkConstrTerm mid (ParenPattern cterm)- = checkConstrTerm mid cterm-checkConstrTerm mid (TuplePattern _ cterms)- = foldM' (checkConstrTerm mid ) cterms-checkConstrTerm mid (ListPattern _ cterms)- = foldM' (checkConstrTerm mid ) cterms-checkConstrTerm mid (AsPattern ident cterm)- = do s <- isShadowingVar ident- when s (genWarning' (shadowingVar ident))- checkConstrTerm mid cterm-checkConstrTerm mid (LazyPattern _ cterm)- = checkConstrTerm mid cterm-checkConstrTerm mid (FunctionPattern _ cterms)- = foldM' (checkConstrTerm mid ) cterms-checkConstrTerm mid (InfixFuncPattern cterm1 qident cterm2)- = checkConstrTerm mid (FunctionPattern qident [cterm1, cterm2])-checkConstrTerm mid (RecordPattern fields restr)- = do foldM' (checkFieldPattern mid) fields- maybe (return ()) (checkConstrTerm mid ) restr-checkConstrTerm _ _ = return ()-----checkExpression :: ModuleIdent -> Expression -> CheckState ()-checkExpression mid (Variable qident)- = maybe (return ()) visitId (localIdent mid qident)-checkExpression mid (Paren expr)- = checkExpression mid expr-checkExpression mid (Typed expr _)- = checkExpression mid expr-checkExpression mid (Tuple _ exprs)- = foldM' (checkExpression mid ) exprs-checkExpression mid (List _ exprs)- = foldM' (checkExpression mid ) exprs-checkExpression mid (ListCompr _ expr stmts)- = do beginScope- foldM' (checkStatement mid ) stmts- checkExpression mid expr- idents' <- returnUnrefVars- when (not (null idents'))- (foldM' genWarning' (map unrefVar idents'))- endScope-checkExpression mid (EnumFrom expr)- = checkExpression mid expr-checkExpression mid (EnumFromThen expr1 expr2)- = foldM' (checkExpression mid ) [expr1, expr2]-checkExpression mid (EnumFromTo expr1 expr2)- = foldM' (checkExpression mid ) [expr1, expr2]-checkExpression mid (EnumFromThenTo expr1 expr2 expr3)- = foldM' (checkExpression mid ) [expr1, expr2, expr3]-checkExpression mid (UnaryMinus _ expr)- = checkExpression mid expr-checkExpression mid (Apply expr1 expr2)- = foldM' (checkExpression mid ) [expr1, expr2]-checkExpression mid (InfixApply expr1 op expr2)- = do maybe (return ()) (visitId) (localIdent mid (opName op))- foldM' (checkExpression mid ) [expr1, expr2]-checkExpression mid (LeftSection expr _)- = checkExpression mid expr-checkExpression mid (RightSection _ expr)- = checkExpression mid expr-checkExpression mid (Lambda _ cterms expr)- = do beginScope- foldM' (checkConstrTerm mid ) cterms- foldM' (insertConstrTerm False) cterms- checkExpression mid expr- idents' <- returnUnrefVars- when (not (null idents'))- (foldM' genWarning' (map unrefVar idents'))- endScope-checkExpression mid (Let decls expr)- = do beginScope- foldM' checkLocalDecl decls- foldM' insertDecl decls- foldM' (checkDecl mid) decls- checkDeclOccurrences decls- checkExpression mid expr- idents' <- returnUnrefVars- when (not (null idents'))- (foldM' genWarning' (map unrefVar idents'))- endScope-checkExpression mid (Do stmts expr)- = do beginScope- foldM' (checkStatement mid ) stmts- checkExpression mid expr- idents' <- returnUnrefVars- when (not (null idents'))- (foldM' genWarning' (map unrefVar idents'))- endScope-checkExpression mid (IfThenElse _ expr1 expr2 expr3)- = foldM' (checkExpression mid ) [expr1, expr2, expr3]-checkExpression mid (Case _ expr alts)- = do checkExpression mid expr- foldM' (checkAlt mid) alts- checkCaseAlternatives mid alts-checkExpression mid (RecordConstr fields)- = foldM' (checkFieldExpression mid) fields-checkExpression mid (RecordSelection expr ident)- = checkExpression mid expr -- Hier auch "visitId ident" ?-checkExpression mid (RecordUpdate fields expr)- = do foldM' (checkFieldExpression mid) fields- checkExpression mid expr-checkExpression _ _ = return ()-----checkStatement :: ModuleIdent -> Statement -> CheckState ()-checkStatement mid (StmtExpr _ expr)- = checkExpression mid expr-checkStatement mid (StmtDecl decls)- = do foldM' checkLocalDecl decls- foldM' insertDecl decls- foldM' (checkDecl mid) decls- checkDeclOccurrences decls-checkStatement mid (StmtBind _ cterm expr)- = do checkConstrTerm mid cterm- insertConstrTerm False cterm- checkExpression mid expr-----checkAlt :: ModuleIdent -> Alt -> CheckState ()-checkAlt mid (Alt pos cterm rhs)- = do beginScope - checkConstrTerm mid cterm- insertConstrTerm False cterm- checkRhs mid rhs- idents' <- returnUnrefVars- when (not (null idents'))- (foldM' genWarning' (map unrefVar idents'))- endScope-----checkFieldExpression :: ModuleIdent -> Field Expression -> CheckState ()-checkFieldExpression mid (Field _ ident expr)- = checkExpression mid expr -- Hier auch "visitId ident" ?-----checkFieldPattern :: ModuleIdent -> Field ConstrTerm -> CheckState ()-checkFieldPattern mid (Field _ ident cterm)- = checkConstrTerm mid cterm---- Check for idle and overlapping case alternatives-checkCaseAlternatives :: ModuleIdent -> [Alt] -> CheckState ()-checkCaseAlternatives mid alts- = do checkIdleAlts mid alts- checkOverlappingAlts mid alts------- FIXME this looks buggy: is alts' required to be non-null or not? (hsi)-checkIdleAlts :: ModuleIdent -> [Alt] -> CheckState ()-checkIdleAlts mid alts- = do alts' <- dropUnless' isVarAlt alts- let idles = tail_ [] alts'- (Alt pos _ _) = head idles- unless (null idles) (genWarning pos idleCaseAlts)- where- isVarAlt (Alt _ (VariablePattern id) _) - = isVarId id- isVarAlt (Alt _ (ParenPattern (VariablePattern id)) _) - = isVarId id- isVarAlt (Alt _ (AsPattern _ (VariablePattern id)) _)- = isVarId id- isVarAlt _ = return False-----checkOverlappingAlts :: ModuleIdent -> [Alt] -> CheckState ()-checkOverlappingAlts mid [] = return ()-checkOverlappingAlts mid (alt:alts)- = do (altsr, alts') <- partition' (equalAlts alt) alts- mapM_ (\ (Alt pos _ _) -> genWarning pos overlappingCaseAlt) altsr- checkOverlappingAlts mid alts'- where- equalAlts (Alt _ cterm1 _) (Alt _ cterm2 _) = equalConstrTerms cterm1 cterm2-- equalConstrTerms (LiteralPattern l1) (LiteralPattern l2)- = return (l1 == l2)- equalConstrTerms (NegativePattern id1 l1) (NegativePattern id2 l2) - = return (id1 == id2 && l1 == l2)- equalConstrTerms (VariablePattern id1) (VariablePattern id2)- = do p <- isConsId id1 - return (p && id1 == id2)- equalConstrTerms (ConstructorPattern qid1 cs1)- (ConstructorPattern qid2 cs2)- = if qid1 == qid2- then all' (\ (c1,c2) -> equalConstrTerms c1 c2) (zip cs1 cs2)- else return False- equalConstrTerms (InfixPattern lcs1 qid1 rcs1)- (InfixPattern lcs2 qid2 rcs2)- = equalConstrTerms (ConstructorPattern qid1 [lcs1, rcs1])- (ConstructorPattern qid2 [lcs2, rcs2])- equalConstrTerms (ParenPattern cterm1) (ParenPattern cterm2)- = equalConstrTerms cterm1 cterm2- equalConstrTerms (TuplePattern _ cs1) (TuplePattern _ cs2)- = equalConstrTerms (ConstructorPattern (qTupleId 2) cs1)- (ConstructorPattern (qTupleId 2) cs2)- equalConstrTerms (ListPattern _ cs1) (ListPattern _ cs2)- = cmpListM equalConstrTerms cs1 cs2- equalConstrTerms (AsPattern id1 cterm1) (AsPattern id2 cterm2)- = equalConstrTerms cterm1 cterm2- equalConstrTerms (LazyPattern _ cterm1) (LazyPattern _ cterm2)- = equalConstrTerms cterm1 cterm2- equalConstrTerms _ _ = return False----- Find function rules which are not together-checkDeclOccurrences :: [Decl] -> CheckState ()-checkDeclOccurrences decls = checkDO (mkIdent "") Map.empty decls- where- checkDO prevId env [] = return ()- checkDO prevId env ((FunctionDecl pos ident _):decls)- = do c <- isConsId ident- if not (c || prevId == ident)- then (maybe (checkDO ident (Map.insert ident pos env) decls)- (\pos' -> genWarning' (rulesNotTogether ident pos')- >> checkDO ident env decls)- (Map.lookup ident env))- else checkDO ident env decls- checkDO _ env (_:decls) - = checkDO (mkIdent "") env decls----- check import declarations for multiply imported modules-checkImports :: [Decl] -> CheckState ()-checkImports imps = checkImps Map.empty imps- where- checkImps env [] = return ()- checkImps env ((ImportDecl pos mid _ _ spec):imps)- | mid /= preludeMIdent- = maybe (checkImps (Map.insert mid (fromImpSpec spec) env) imps)- (\ishs -> checkImpSpec env pos mid ishs spec- >>= (\env' -> checkImps env' imps))- (Map.lookup mid env)- | otherwise- = checkImps env imps- checkImps env (_:imps) = checkImps env imps-- checkImpSpec env pos mid (is,hs) Nothing- = genWarning' (multiplyImportedModule mid) >> return env- checkImpSpec env pos mid (is,hs) (Just (Importing _ is'))- | null is && any (\i' -> notElem i' hs) is'- = do genWarning' (multiplyImportedModule mid)- return (Map.insert mid (is',hs) env)- | null iis- = return (Map.insert mid (is' ++ is,hs) env)- | otherwise- = do foldM' genWarning'- (map ((multiplyImportedSymbol mid) . impName) iis)- return (Map.insert mid (unionBy cmpImport is' is,hs) env)- where iis = intersectBy cmpImport is' is- checkImpSpec env pos mid (is,hs) (Just (Hiding _ hs'))- | null ihs- = return (Map.insert mid (is,hs' ++ hs) env)- | otherwise- = do foldM' genWarning' - (map ((multiplyHiddenSymbol mid) . impName) ihs)- return (Map.insert mid (is,unionBy cmpImport hs' hs) env)- where ihs = intersectBy cmpImport hs' hs-- cmpImport (ImportTypeWith id1 cs1) (ImportTypeWith id2 cs2)- = id1 == id2 && null (intersect cs1 cs2)- cmpImport i1 i2 = (impName i1) == (impName i2)-- impName (Import id) = id- impName (ImportTypeAll id) = id- impName (ImportTypeWith id _) = id-- fromImpSpec Nothing = ([],[])- fromImpSpec (Just (Importing _ is)) = (is,[])- fromImpSpec (Just (Hiding _ hs)) = ([],hs)------------------------------------------------------------------------------------- For detecting unreferenced variables, the following functions updates the --- current check state by adding identifiers occuring in declaration left hand --- sides.-----insertDecl :: Decl -> CheckState ()-insertDecl (DataDecl _ ident _ cdecls)- = do insertTypeConsId ident- foldM' insertConstrDecl cdecls-insertDecl (TypeDecl _ ident _ texpr)- = do insertTypeConsId ident- insertTypeExpr texpr-insertDecl (FunctionDecl _ ident _)- = do c <- isConsId ident- unless c (insertVar ident)-insertDecl (ExternalDecl _ _ _ ident _)- = insertVar ident-insertDecl (FlatExternalDecl _ idents)- = foldM' insertVar idents-insertDecl (PatternDecl _ cterm _)- = insertConstrTerm False cterm-insertDecl (ExtraVariables _ idents)- = foldM' insertVar idents-insertDecl _ = return ()-----insertTypeExpr :: TypeExpr -> CheckState ()-insertTypeExpr (VariableType _) = return ()-insertTypeExpr (ConstructorType _ texprs)- = foldM' insertTypeExpr texprs-insertTypeExpr (TupleType texprs)- = foldM' insertTypeExpr texprs-insertTypeExpr (ListType texpr)- = insertTypeExpr texpr-insertTypeExpr (ArrowType texpr1 texpr2)- = foldM' insertTypeExpr [texpr1,texpr2]-insertTypeExpr (RecordType fields restr)- = do --foldM' insertVar (concatMap fst fields)- maybe (return ()) insertTypeExpr restr-----insertConstrDecl :: ConstrDecl -> CheckState ()-insertConstrDecl (ConstrDecl _ _ ident _)- = insertConsId ident-insertConstrDecl (ConOpDecl _ _ _ ident _)- = insertConsId ident---- Notes: --- - 'fp' indicates whether 'checkConstrTerm' deals with the arguments--- of a function pattern or not.--- - Since function patterns are not recognized before syntax check, it is--- necessary to determine, whether a constructor pattern represents a--- constructor or a function. -insertConstrTerm :: Bool -> ConstrTerm -> CheckState ()-insertConstrTerm fp (VariablePattern ident)- | fp = do c <- isConsId ident- v <- isVarId ident- unless c (if (name ident) /= "_" && v- then visitId ident- else insertVar ident)- | otherwise = do c <- isConsId ident- unless c (insertVar ident)-insertConstrTerm fp (ConstructorPattern qident cterms)- = do c <- isQualConsId qident- if c then foldM' (insertConstrTerm fp) cterms- else foldM' (insertConstrTerm True) cterms-insertConstrTerm fp (InfixPattern cterm1 qident cterm2)- = insertConstrTerm fp (ConstructorPattern qident [cterm1, cterm2])-insertConstrTerm fp (ParenPattern cterm)- = insertConstrTerm fp cterm-insertConstrTerm fp (TuplePattern _ cterms)- = foldM' (insertConstrTerm fp) cterms-insertConstrTerm fp (ListPattern _ cterms)- = foldM' (insertConstrTerm fp) cterms-insertConstrTerm fp (AsPattern ident cterm)- = do insertVar ident- insertConstrTerm fp cterm-insertConstrTerm fp (LazyPattern _ cterm)- = insertConstrTerm fp cterm-insertConstrTerm _ (FunctionPattern _ cterms)- = foldM' (insertConstrTerm True) cterms-insertConstrTerm _ (InfixFuncPattern cterm1 qident cterm2)- = insertConstrTerm True (FunctionPattern qident [cterm1, cterm2])-insertConstrTerm fp (RecordPattern fields restr)- = do foldM' (insertFieldPattern fp) fields- maybe (return ()) (insertConstrTerm fp) restr-insertConstrTerm _ _ = return ()-----insertFieldPattern :: Bool -> Field ConstrTerm -> CheckState ()-insertFieldPattern fp (Field _ _ cterm)- = insertConstrTerm fp cterm--------------------------------------------------------------------------------------------------------------------------------------------------------------------- Data type for distinguishing identifiers as either (type) constructors or--- (type) variables (including functions).--- The Boolean flag in 'VarInfo' is used to mark variables when they are used --- within expressions.-data IdInfo = ConsInfo | VarInfo Bool deriving Show-----isVariable :: IdInfo -> Bool-isVariable (VarInfo _) = True-isVariable _ = False-----isConstructor :: IdInfo -> Bool-isConstructor ConsInfo = True-isConstructor _ = False-----variableVisited :: IdInfo -> Bool-variableVisited (VarInfo v) = v-variableVisited _ = True-----visitVariable :: IdInfo -> IdInfo-visitVariable info = case info of- VarInfo _ -> VarInfo True- _ -> info------modifyScope :: (ScopeEnv QualIdent IdInfo -> ScopeEnv QualIdent IdInfo)- -> CState -> CState-modifyScope f state = state{ scope = f (scope state) }------genWarning :: Position -> String -> CheckState ()-genWarning pos msg- = modify (\state -> state{ messages = warnMsg:(messages state) })- where warnMsg = WarnMsg (Just pos) msg- -genWarning' :: (Position, String) -> CheckState ()-genWarning' (pos, msg)- = modify (\state -> state{ messages = warnMsg:(messages state) })- where warnMsg = WarnMsg (Just pos) msg -----insertVar :: Ident -> CheckState ()-insertVar id - | isAnnonId id = return ()- | otherwise- = modify - (\state -> modifyScope - (ScopeEnv.insert (commonId id) (VarInfo False)) state)-----insertTypeVar :: Ident -> CheckState ()-insertTypeVar id- | isAnnonId id = return ()- | otherwise - = modify - (\state -> modifyScope - (ScopeEnv.insert (typeId id) (VarInfo False)) state)-----insertConsId :: Ident -> CheckState ()-insertConsId id- = modify - (\state -> modifyScope (ScopeEnv.insert (commonId id) ConsInfo) state)-----insertTypeConsId :: Ident -> CheckState ()-insertTypeConsId id- = modify - (\state -> modifyScope (ScopeEnv.insert (typeId id) ConsInfo) state)-----isVarId :: Ident -> CheckState Bool-isVarId id- = gets (\state -> isVar state (commonId id))-----isConsId :: Ident -> CheckState Bool-isConsId id - = gets (\state -> isCons state (qualify id))-----isQualConsId :: QualIdent -> CheckState Bool-isQualConsId qid- = gets (\state -> isCons state qid)-----isShadowingVar :: Ident -> CheckState Bool-isShadowingVar id - = gets (\state -> isShadowing state (commonId id))-----visitId :: Ident -> CheckState ()-visitId id - = modify - (\state -> modifyScope - (ScopeEnv.modify visitVariable (commonId id)) state)-----visitTypeId :: Ident -> CheckState ()-visitTypeId id - = modify - (\state -> modifyScope - (ScopeEnv.modify visitVariable (typeId id)) state)-----isUnrefTypeVar :: Ident -> CheckState Bool-isUnrefTypeVar id- = gets (\state -> isUnref state (typeId id))-----returnUnrefVars :: CheckState [Ident]-returnUnrefVars - = gets (\state -> - let ids = map fst (ScopeEnv.toLevelList (scope state))- unrefs = filter (isUnref state) ids- in map unqualify unrefs )-----addModuleId :: ModuleIdent -> CheckState ()-addModuleId mid = modify (\state -> state{ moduleId = mid })------withScope :: CheckState a -> CheckState ()-withScope m = beginScope >> m >> endScope-----beginScope :: CheckState ()-beginScope = modify (\state -> modifyScope ScopeEnv.beginScope state)-----endScope :: CheckState ()-endScope = modify (\state -> modifyScope ScopeEnv.endScopeUp state)----- Adds the content of a value environment to the state-addImportedValues :: ValueEnv -> CheckState ()-addImportedValues vals = modify (\state -> state{ values = vals })-----foldM' :: (a -> CheckState ()) -> [a] -> CheckState ()-foldM' f [] = return ()-foldM' f (x:xs) = f x >> foldM' f xs-----dropUnless' :: (a -> CheckState Bool) -> [a] -> CheckState [a]-dropUnless' mpred [] = return []-dropUnless' mpred (x:xs)- = do p <- mpred x- if p then return (x:xs) else dropUnless' mpred xs-----partition' :: (a -> CheckState Bool) -> [a] -> CheckState ([a],[a])-partition' mpred xs = part mpred [] [] xs- where- part mpred ts fs [] = return (reverse ts, reverse fs)- part mpred ts fs (x:xs)- = do p <- mpred x- if p then part mpred (x:ts) fs xs- else part mpred ts (x:fs) xs-----all' :: (a -> CheckState Bool) -> [a] -> CheckState Bool-all' mpred [] = return True-all' mpred (x:xs)- = do p <- mpred x- if p then all' mpred xs else return False----------------------------------------------------------------------------------------isShadowing :: CState -> QualIdent -> Bool-isShadowing state qid- = let sc = scope state- in maybe False isVariable (ScopeEnv.lookup qid sc)- && ScopeEnv.level qid sc < ScopeEnv.currentLevel sc-----isUnref :: CState -> QualIdent -> Bool-isUnref state qid - = let sc = scope state- in maybe False (not . variableVisited) (ScopeEnv.lookup qid sc)- && ScopeEnv.level qid sc == ScopeEnv.currentLevel sc-----isVar :: CState -> QualIdent -> Bool-isVar state qid = maybe (isAnnonId (unqualify qid)) - isVariable - (ScopeEnv.lookup qid (scope state))-----isCons :: CState -> QualIdent -> Bool-isCons state qid = maybe (isImportedCons state qid)- isConstructor- (ScopeEnv.lookup qid (scope state))- where- isImportedCons state qid- = case (qualLookupValue qid (values state)) of- (DataConstructor _ _):_ -> True- (NewtypeConstructor _ _):_ -> True- _ -> False------isAnnonId :: Ident -> Bool-isAnnonId id = (name id) == "_"----- Since type identifiers and normal identifiers (e.g. functions, variables--- or constructors) don't share the same namespace, it is necessary--- to distinguish them in the scope environment of the check state.--- For this reason type identifiers are annotated with 1 and normal--- identifiers are annotated with 0.----commonId :: Ident -> QualIdent-commonId id = qualify (unRenameIdent id)-----typeId :: Ident -> QualIdent-typeId id = qualify (renameIdent id 1)------------------------------------------------------------------------------------- Warnings...--unrefTypeVar :: Ident -> (Position, String)-unrefTypeVar id = - (positionOfIdent id,- "unreferenced type variable \"" ++ show id ++ "\"")--unrefVar :: Ident -> (Position, String)-unrefVar id = - (positionOfIdent id,- "unused declaration of variable \"" ++ show id ++ "\"")--shadowingVar :: Ident -> (Position, String)-shadowingVar id = - (positionOfIdent id,- "shadowing symbol \"" ++ show id ++ "\"")--idleCaseAlts :: String-idleCaseAlts = "idle case alternative(s)"--overlappingCaseAlt :: String-overlappingCaseAlt = "redundant overlapping case alternative"--rulesNotTogether :: Ident -> Position -> (Position, String)-rulesNotTogether id pos- = (positionOfIdent id,- "rules for function \"" ++ show id ++ "\" " - ++ "are not together "- ++ "(first occurrence at " - ++ show (line pos) ++ "." ++ show (column pos) ++ ")")--multiplyImportedModule :: ModuleIdent -> (Position, String)-multiplyImportedModule mid - = (positionOfModuleIdent mid,- "module \"" ++ show mid ++ "\" was imported more than once")--multiplyImportedSymbol :: ModuleIdent -> Ident -> (Position, String)-multiplyImportedSymbol mid ident- = (positionOfIdent ident,- "symbol \"" ++ show ident ++ "\" was imported from module \""- ++ show mid ++ "\" more than once")--multiplyHiddenSymbol :: ModuleIdent -> Ident -> (Position, String)-multiplyHiddenSymbol mid ident- = (positionOfIdent ident,- "symbol \"" ++ show ident ++ "\" from module \"" ++ show mid- ++ "\" was hidden more than once")------------------------------------------------------------------------------------- Miscellaneous---- safer versions of 'tail' and 'head'-tail_ :: [a] -> [a] -> [a]-tail_ alt [] = alt-tail_ _ (_:xs) = xs------cmpListM :: Monad m => (a -> a -> m Bool) -> [a] -> [a] -> m Bool-cmpListM cmpM [] [] = return True-cmpListM cmpM (x:xs) (y:ys) = do c <- cmpM x y- if c then cmpListM cmpM xs ys - else return False-cmpListM cmpM _ _ = return False------------------------------------------------------------------------------------------------------------------------------------------------------------------
− src/currydoc.css
@@ -1,34 +0,0 @@-/* Use monospace fonts for typewriter styles */-pre, tt, code { font-family: monospace }--/* Use always white background */-body { background: white; color: black }--/* Show hyperlinks without underscore */-a:visited, a:link, a:active { text-decoration: none }--.keyword { color:blue }-.constructorname_constrpattern { color : #FF00FF }-.constructorname_constrcall { color : #FF00FF }-.constructorname_constrdecla { color : #FF00FF }-.constructorname_otherconstrkind { color : #FF00FF }-.typeconstructor_typedecla { color : #ff7f50 }-.typeconstructor_typeuse { color : #ff7f50 }-.typeconstructor_typeexport { color : #ff7f50 }-.function_infixfunction { color : #800080 }-.function_typsig { color : #800080 }-.function_fundecl { color : #800080 }-.function_functioncall { color : #800080 }-.function_otherfunctionkind { color : #800080 }-.moduleName { color : #800000 }-.commentary { color : green }-.numberCode { color : #008080 }-.stringCode { color : #800000 }-.charCode { color : #800000 }-.symbol { color : #C0C0C0 }-.identifier_iddecl { color : black }-.identifier_idoccur { color : black }-.identifier_unknownid { color : black }-.codeWarning {font-weight: bold;font-style:italic; color : red }-.codeError { font-style:italic; color : #a52a2a }-.notParsed { font-style:italic; color : #C0C0C0 }
− src/cymake.hs
@@ -1,97 +0,0 @@--- -------------------------------------------------------------------------------- |--- cymake - The Curry builder------ Command line tool for generating Curry representations (e.g.--- FlatCurry, AbstractCurry) for a Curry source file including--- all imported modules.------ September 2005, Martin Engelke (men@informatik.uni-kiel.de)------ -------------------------------------------------------------------------------module Main(main) where--import Data.List-import Data.Maybe-import System.Console.GetOpt-import System.Environment(getArgs, getProgName)-import System.Exit(ExitCode(..), exitWith)-import System.IO-import Control.Monad (unless)--import CurryBuilder(buildCurry)-import CurryCompilerOpts-import CurryHtml-import Curry.Files.CymakePath (cymakeVersion)----- | The command line tool cymake-main :: IO ()-main = do- prog <- getProgName- args <- getArgs- cymake prog args---- | Checks the command line arguments and invokes the curry builder-cymake :: String -> [String] -> IO ()-cymake prog args- | elem Help opts = printUsage prog- | null files = badUsage prog ["no files"]- | null errs'- && not (elem Html opts) = do- unless (noVerb options')- (putStrLn $ "This is cymake, version " ++ cymakeVersion)- mapM_ (buildCurry options') files- | null errs' = do- let importFiles = nub $ importPaths opts'- outputFile = maybe "" id (output opts')- mapM_ (source2html importFiles outputFile) files- | otherwise = badUsage prog errs'- where- (opts, files, errs) = getOpt Permute options args- opts' = foldr selectOption defaultOpts opts- options' = if flat opts' || flatXml opts' || abstract opts'- || untypedAbstract opts' || parseOnly opts'- then opts'- else opts'{ flat = True }- errs' = errs ++ check options' files---- | Prints usage information of the command line tool.-printUsage :: String -> IO ()-printUsage prog = do- putStrLn (usageInfo header options)- exitWith ExitSuccess- where header = "usage: " ++ prog ++ " [OPTION] ... MODULE ..."---- | Prints errors-badUsage :: String -> [String] -> IO ()-badUsage prog errs = do- putErrsLn $ map (\err -> prog ++ ": " ++ err) errs- abortWith ["Try '" ++ prog ++ " -" ++ "-help' for more information"]---- | Checks options and files and return a list of error messages-check :: Options -> [String] -> [String]-check opts files- | null files- = ["no files"]- | isJust (output opts) && length files > 1- = ["cannot specify -o with multiple targets"]- | otherwise- = []---- | Prints an error message on 'stderr'-putErrLn :: String -> IO ()-putErrLn = hPutStrLn stderr---- | Prints a list of error messages on 'stderr'-putErrsLn :: [String] -> IO ()-putErrsLn = mapM_ putErrLn---- | Prints a list of error messages on 'stderr' and aborts the program with--- exit code 1-abortWith :: [String] -> IO a-abortWith errs = putErrsLn errs >> exitWith (ExitFailure 1)---- -------------------------------------------------------------------------------- -----------------------------------------------------------------------------
+ test/TestFrontend.hs view
@@ -0,0 +1,359 @@+--------------------------------------------------------------------------------+-- Test Suite for the Curry Frontend+--------------------------------------------------------------------------------+--+-- This Test Suite supports three kinds of tests:+--+-- 1) tests which should pass+-- 2) tests which should pass with a specific warning+-- 3) tests which should fail yielding a specific error message+--+-- In order to add a test to this suite, proceed as follows:+--+-- 1) Store your test code in a file (please use descriptive names) and put it+-- in the corresponding subfolder (i.e. test/pass for passing tests,+-- test/fail for failing tests and test/warning for passing tests producing+-- warnings)+-- 2) Extend the corresponding test information list (there is one for each test+-- group at the end of this file) with the required information (i.e. name of+-- the Curry module to be tested and expected warning/failure message(s))+-- 3) Run 'cabal test'++{-# LANGUAGE CPP #-}+module TestFrontend (tests) where++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative ((<$>))+#endif+import qualified Control.Exception as E (SomeException, catch)++import Data.List (isInfixOf, sort)+import qualified Data.Map as Map (insert)+import Distribution.TestSuite ( Test (..), TestInstance (..)+ , Progress (..), Result (..)+ , OptionDescr)+import System.FilePath (FilePath, (</>), (<.>))++import Curry.Base.Message (Message, message, ppMessages, ppError)+import Curry.Base.Monad (CYIO, runCYIO)+import Curry.Base.Pretty (text)+import qualified CompilerOpts as CO ( Options (..), WarnOpts (..)+ , WarnFlag (..), Verbosity (VerbQuiet)+ , CppOpts (..)+ , defaultOptions)+import CurryBuilder (buildCurry)++tests :: IO [Test]+tests = return [failingTests, passingTests, warningTests]++runSecure :: CYIO a -> IO (Either [Message] (a, [Message]))+runSecure act = runCYIO act `E.catch` handler+ where handler e = return (Left [message $ text $ show (e :: E.SomeException)])++-- Execute a test by calling cymake+runTest :: CO.Options -> String -> [String] -> IO Progress+runTest opts test errorMsgs =+ if null errorMsgs+ then passOrFail <$> runSecure (buildCurry opts' test)+ else catchE <$> runSecure (buildCurry opts' test)+ where+ cppOpts = CO.optCppOpts opts+ cppDefs = Map.insert "__PAKCS__" 3 (CO.cppDefinitions cppOpts)+ wOpts = CO.optWarnOpts opts+ wFlags = CO.WarnUnusedBindings+ : CO.WarnUnusedGlobalBindings+ : CO.wnWarnFlags wOpts+ opts' = opts { CO.optForce = True+ , CO.optWarnOpts = wOpts+ { CO.wnWarnFlags = wFlags }+ , CO.optCppOpts = cppOpts+ { CO.cppDefinitions = cppDefs }+ }+ passOrFail = Finished . either fail (const Pass)+ catchE = Finished . either pass (pass . snd)+ fail msgs+ | null msgs = Pass+ | otherwise = Fail $ "An unexpected failure occurred: " +++ showMessages msgs+ pass msgs+ | null otherMsgs = Pass+ | otherwise = Fail $ "Expected warnings/failures did not occur: " +++ unwords otherMsgs+ where+ errorStr = showMessages msgs+ otherMsgs = filter (not . flip isInfixOf errorStr) errorMsgs++showMessages :: [Message] -> String+showMessages = show . ppMessages ppError . sort++-- group of test which should fail yielding a specific error message+failingTests :: Test+failingTests = Group { groupName = "Failing Tests"+, concurrently = False+, groupTests = map (mkTest "test/fail/") failInfos+}++-- group of tests which should pass+passingTests :: Test+passingTests = Group { groupName = "Passing Tests"+ , concurrently = False+ , groupTests = map (mkTest "test/pass/") passInfos+ }++-- group of tests which should pass producing a specific warning message+warningTests :: Test+warningTests = Group { groupName = "Warning Tests"+ , concurrently = False+ , groupTests = map (mkTest "test/warning/") warnInfos+ }++-- create a new test+mkTest :: FilePath -> TestInfo -> Test+mkTest path (testName, testTags, testOpts, mSetOpts, errorMsgs) =+ let file = path </> testName <.> "curry"+ opts = CO.defaultOptions { CO.optVerbosity = CO.VerbQuiet+ , CO.optImportPaths = [path]+ }+ test = TestInstance+ { run = runTest opts file errorMsgs+ , name = testName+ , tags = testTags+ , options = testOpts+ , setOption = maybe (\_ _ -> Right test) id mSetOpts+ }+ in Test test++-- Information for a test instance:+-- * name of test+-- * tags to classify a test+-- * options+-- * function to set options+-- * optional warning/error message which should be thrown on execution of test+type TestInfo = (String, [String], [OptionDescr], Maybe SetOption, [String])++type SetOption = String -> String -> Either String TestInstance++--------------------------------------------------------------------------------+-- Definition of failing tests+--------------------------------------------------------------------------------++-- generate a simple failing test+mkFailTest :: String -> [String] -> TestInfo+mkFailTest name errorMsgs = (name, [], [], Nothing, errorMsgs)++-- To add a failing test to the test suite simply add the module name of the+-- test code and the expected error message(s) to the following list+failInfos :: [TestInfo]+failInfos = map (uncurry mkFailTest)+ [ ("DataFail",+ [ "Missing instance for Prelude.Data Test1"+ , "Missing instance for Prelude.Data (Test2"+ , "Missing instance for Prelude.Data (Test2"+ , "Missing instance for Prelude.Data Test1"+ ]+ )+ , ("ErrorMultipleSignature", ["More than one type signature for `f'"])+ , ("ErrorMultipleSignature", ["More than one type signature for `f'"])+ , ("ExportCheck/AmbiguousName", ["Ambiguous name `not'"])+ , ("ExportCheck/AmbiguousType", ["Ambiguous type `Bool'"])+ , ("ExportCheck/ModuleNotImported", ["Module `Foo' not imported"])+ , ("ExportCheck/MultipleName", ["Multiple exports of name `not'"])+ , ("ExportCheck/MultipleType", ["Multiple exports of type `Bool'"])+ , ("ExportCheck/NoDataType", ["`Foo' is not a data type"])+ , ("ExportCheck/OutsideTypeConstructor", ["Data constructor `False' outside type export in export list"])+ , ("ExportCheck/OutsideTypeLabel", ["Label `value' outside type export in export list"])+ , ("ExportCheck/UndefinedElement", ["`foo' is not a constructor or label of type `Bool'"])+ , ("ExportCheck/UndefinedName", ["Undefined name `foo' in export list"])+ , ("ExportCheck/UndefinedType", ["Undefined type or class `Foo' in export list"])+ , ("FP_Cyclic", ["Function `g' used in functional pattern depends on `f' causing a cyclic dependency"])+ , ("FP_Restrictions",+ [ "Functional patterns are not supported inside a case expression"+ , "Functional patterns are not supported inside a case expression"+ , "Functional patterns are not supported inside a list comprehension"+ , "Functional patterns are not supported inside a do sequence"+ ]+ )+ , ("HaskellRecordsFail", ["Unexpected token `,'"])+ , ("FP_NonGlobal", ["Function `f1' in functional pattern is not global"])+ , ("ImportError",+ [ "Module Prelude does not export foo"+ , "Module Prelude does not export bar"+ ]+ )+ , ("KindCheck",+ [ "Type variable a occurs more than once in left hand side of type declaration"+ , "Type variable b occurs more than once in left hand side of type declaration"+ ]+ )+ , ("MissingLabelInUpdate",+ ["Undefined record label `l1'"] )+ , ("MultipleArities", ["Equations for `test' have different arities"])+ , ("MultipleDefinitions",+ ["Multiple definitions for data/record constructor `Rec'"]+ )+ , ("MultiplePrecedence",+ ["More than one fixity declaration for `f'"]+ )+ , ("PatternRestrictions",+ [ "Lazy patterns are not supported inside a functional pattern"]+ )+ , ("PragmaError", ["Unknown language extension"])+ , ("PrecedenceRange", ["Precedence out of range"])+ , ("RecordLabelIDs", ["Multiple declarations of `RecordLabelIDs.id'"])+ , ("RecursiveTypeSyn", ["Mutually recursive synonym and/or renaming types A and B (line 12.6)"])+ , ("SyntaxError", ["Type error in application"])+ , ("TypedFreeVariables",+ ["Variable x has a polymorphic type", "Type error in equation"]+ )+ , ("TypeError1", ["Type error in explicitly typed expression"])+ , ("TypeError2", ["Missing instance for Prelude.Num Prelude.Bool"])+ , ("TypeSigTooGeneral",+ [ "Type signature too general"+ , "Function: h"+ , "Type signature too general"+ , "Function: g'"+ , "Type signature too general"+ , "Function: n"+ ]+ )+ , ("UnboundTypeVariable",+ [ "Unbound type variable b"+ , "Unbound type variable c"+ ]+ )+ ]++--------------------------------------------------------------------------------+-- Definition of passing tests+--------------------------------------------------------------------------------++-- generate a simple passing test+mkPassTest :: String -> TestInfo+mkPassTest = flip mkFailTest []++-- To add a passing test to the test suite simply add the module name of the+-- test code to the following list+passInfos :: [TestInfo]+passInfos = map mkPassTest+ [ "AbstractCurryBug"+ , "ACVisibility"+ , "AnonymVar"+ , "CaseComplete"+ , "DataPass"+ , "DefaultPrecedence"+ , "Dequeue"+ , "EmptyWhere"+ , "ExplicitLayout"+ , "FCase"+ , "FP_Lifting"+ , "FP_NonCyclic"+ , "FP_NonLinearity"+ , "FunctionalPatterns"+ , "HaskellRecords"+ , "HaskellRecordsPass"+ , "Hierarchical"+ , "ImportRestricted"+ , "ImportRestricted2"+ , "Infix"+ , "Inline"+ , "Lambda"+ , "Maybe"+ , "NegLit"+ , "Newtype1"+ , "Newtype2"+ , "NonLinearLHS"+ , "OperatorDefinition"+ , "PatDecl"+ , "Prelude"+ , "Pretty"+ , "RecordsPolymorphism"+ , "RecordTest1"+ , "RecordTest2"+ , "RecordTest3"+ , "ReexportTest"+ , "SelfExport"+ , "SpaceLeak"+ , "TyConsTest"+ , "TypedExpr"+ , "UntypedAcy"+ , "Unzip"+ , "WhereAfterDo"+ ]++--------------------------------------------------------------------------------+-- Definition of warning tests+--------------------------------------------------------------------------------++-- To add a warning test to the test suite simply add the module name of the+-- test code and the expected warning message(s) to the following list+warnInfos :: [TestInfo]+warnInfos = map (uncurry mkFailTest)+ [+ ("AliasClash",+ [ "The module alias `AliasClash' overlaps with the current module name"+ , "Overlapping module aliases"+ , "Module List is imported more than once"+ ]+ )+ , ("Case1", ["Pattern matches are non-exhaustive", "In an equation for `h'"])+ , ("Case2",+ [ "An fcase expression is potentially non-deterministic due to overlapping rules"+ , "Pattern matches are non-exhaustive", "In an fcase alternative"+ , "In a case alternative", "In an equation for `fp'"+ , "Pattern matches are potentially unreachable"+ , "Function `fp' is potentially non-deterministic due to overlapping rules"+ , "Pattern matches are non-exhaustive"+ ]+ )+ , ("CaseModeH",+ [ "Wrong case mode in symbol `B' due to selected case mode `haskell`, try renaming to b instead"+ , "Wrong case mode in symbol `B' due to selected case mode `haskell`, try renaming to b instead"+ , "Wrong case mode in symbol `Xs' due to selected case mode `haskell`, try renaming to xs instead"+ , "Wrong case mode in symbol `c' due to selected case mode `haskell`, try renaming to C instead"+ , "Wrong case mode in symbol `f' due to selected case mode `haskell`, try renaming to F instead"+ ]+ )+ , ("CaseModeP",+ [ "Wrong case mode in symbol `a' due to selected case mode `prolog`, try renaming to A instead"+ , "Wrong case mode in symbol `a' due to selected case mode `prolog`, try renaming to A instead"+ , "Wrong case mode in symbol `mf' due to selected case mode `prolog`, try renaming to Mf instead"+ , "Wrong case mode in symbol `E' due to selected case mode `prolog`, try renaming to e instead"+ ]+ )+ , ("CheckSignature",+ [ "Top-level binding with no type signature: hw"+ , "Top-level binding with no type signature: f"+ , "Unused declaration of variable `answer'"+ ]+ )+ , ("NonExhaustivePattern",+ [ "Pattern matches are non-exhaustive", "In a case alternative"+ , "In an equation for `test2'", "In an equation for `and'"+ , "In an equation for `plus'", "In an equation for `len2'"+ , "In an equation for `tuple'", "In an equation for `tuple2'"+ , "In an equation for `g'", "In an equation for `rec'"]+ )+ , ("NoRedundant", [])+ , ("OverlappingPatterns",+ [ "Pattern matches are potentially unreachable", "In a case alternative"+ , "An fcase expression is potentially non-deterministic due to overlapping rules"+ , "Function `i' is potentially non-deterministic due to overlapping rules"+ , "Function `j' is potentially non-deterministic due to overlapping rules"+ , "Function `k' is potentially non-deterministic due to overlapping rules"+ ]+ )+ , ("QualRedundant",+ [ "Redundant context in type signature for function `f': 'P.Eq a'"]+ )+ , ("Redundant",+ [ "Redundant context in type signature for function `f': 'Eq a'"]+ )+ , ("ShadowingSymbols",+ [ "Unused declaration of variable `x'", "Shadowing symbol `x'"])+ , ("TabCharacter",+ [ "Tab character"])+ , ("UnexportedFunction",+ [ "Unused declaration of variable `q'"+ , "Unused declaration of variable `g'" ]+ )+ ]