alms 0.5.0 → 0.6.0
raw patch · 195 files changed
+20657/−14048 lines, 195 filesdep +fgldep +incremental-sat-solverdep +stm
Dependencies added: fgl, incremental-sat-solver, stm, transformers, tuple
Files
- Makefile +18/−5
- alms.cabal +147/−70
- alms.cabal.sh +108/−0
- examples/echoServer.alms +13/−15
- examples/ex01-poly.alms +2/−5
- examples/ex01.alms +2/−6
- examples/ex02-poly-type-error.alms +3/−9
- examples/ex02-type-error.alms +5/−9
- examples/ex03-blame-error.alms +5/−7
- examples/ex03-poly-blame-error.alms +5/−7
- examples/ex04-poly.alms +6/−8
- examples/ex04.alms +6/−10
- examples/ex05-poly.alms +3/−8
- examples/ex05.alms +4/−4
- examples/ex06-poly-type-error.alms +7/−8
- examples/ex06-type-error.alms +5/−5
- examples/ex07-poly.alms +9/−10
- examples/ex07.alms +6/−6
- examples/ex08-blame-error.alms +6/−6
- examples/ex08-poly-blame-error.alms +9/−10
- examples/ex09-dynamic-promotion-poly.alms +10/−11
- examples/ex09-dynamic-promotion.alms +6/−6
- examples/ex10-dynamic-promotion-blame-error.alms +6/−6
- examples/ex10-dynamic-promotion-poly-blame-error.alms +10/−11
- examples/ex11-affine-type-error.alms +1/−1
- examples/ex24-io.alms +41/−0
- examples/ex25-io-type-error.alms +41/−0
- examples/ex25-io.alms +0/−41
- examples/ex26-let-bang-array.alms +12/−13
- examples/ex27-focusing-and-adoption.alms +35/−46
- examples/ex28-focusing-and-adoption.alms +38/−55
- examples/ex33-session-types.alms +14/−18
- examples/ex34-session-types.alms +6/−10
- examples/ex35-session-types-type-error.alms +7/−10
- examples/ex36-session-types-type-error.alms +12/−15
- examples/ex37-session-types-type-error.alms +8/−11
- examples/ex38-session-types-type-error.alms +7/−10
- examples/ex50-signatures.alms +1/−1
- examples/ex53-signatures.alms +2/−2
- examples/ex54-signatures-type-error.alms +2/−2
- examples/ex55-signatures-type-error.alms +2/−2
- examples/ex56-signatures-type-error.alms +2/−2
- examples/ex58-signatures-type-error.alms +7/−0
- examples/ex61-popl-AfArray.alms +16/−18
- examples/ex63-popl-CapArray.alms +13/−12
- examples/ex64-popl-CapLockArray.alms +2/−2
- examples/ex65-popl-Fractional.alms +2/−1
- examples/ex66-popl-RWLock.alms +15/−15
- examples/futures1.alms +15/−19
- examples/netcat.alms +18/−20
- examples/session-types-interactive.alms +8/−11
- examples/session-types-polygons.alms +51/−70
- examples/session-types-polygons2.alms +76/−101
- examples/skewness-dynamic-bad.alms +58/−61
- examples/skewness-good.alms +45/−47
- examples/skewness-static-bad.alms +52/−53
- examples/threads1.alms +9/−12
- examples/threads2.alms +13/−18
- examples/threads3.alms +19/−24
- examples/threads4.alms +17/−24
- lib/libachan.alms +15/−15
- lib/libarray.alms +4/−4
- lib/libarraycap.alms +42/−47
- lib/libbasis.alms +126/−94
- lib/libqueue.alms +42/−34
- lib/libsessiontype.alms +14/−16
- lib/libsessiontype2.alms +16/−16
- lib/libsocket.alms +3/−3
- lib/libsocketcap.alms +91/−92
- lib/libsocketcap2.alms +18/−19
- src/AST.hs +164/−0
- src/AST/Anti.hs +404/−0
- src/AST/Decl.hs +343/−0
- src/AST/Decl.hs-boot +26/−0
- src/AST/Expr.hs +403/−0
- src/AST/Ident.hs +547/−0
- src/AST/Ident.hs-boot +12/−0
- src/AST/Kind.hs +261/−0
- src/AST/Lit.hs +16/−0
- src/AST/Notable.hs +55/−0
- src/AST/Patt.hs +165/−0
- src/AST/SyntaxTable.hs +185/−0
- src/AST/Type.hs +222/−0
- src/AST/TypeAnnotation.hs +148/−0
- src/Alt/Graph.hs +147/−0
- src/Alt/NodeMap.hs +151/−0
- src/Alt/Parsec.hs +21/−0
- src/Alt/PrettyPrint.hs +189/−0
- src/Alt/Token.hs +493/−0
- src/Basis.hs +99/−77
- src/Basis/Array.hs +7/−12
- src/Basis/Channel.hs +6/−11
- src/Basis/Exn.hs +6/−9
- src/Basis/Future.hs +9/−14
- src/Basis/IO.hs +17/−25
- src/Basis/MVar.hs +15/−20
- src/Basis/Row.hs +113/−0
- src/Basis/Socket.hs +29/−37
- src/Basis/Thread.hs +7/−12
- src/BasisUtils.hs +76/−62
- src/Coercion.hs +0/−145
- src/Compat.hs +0/−2
- src/Data/Empty.hs +25/−0
- src/Data/Lattice.hs +69/−0
- src/Data/Loc.hs +187/−0
- src/Data/OptionalClass.hs +43/−0
- src/Data/Perhaps.hs +105/−0
- src/Data/UnionFind.hs +95/−0
- src/Dynamics.hs +191/−104
- src/Env.hs +41/−108
- src/Error.hs +449/−0
- src/ErrorMessage.hs +0/−118
- src/ErrorST.hs +0/−143
- src/Lexer.hs +0/−295
- src/Loc.hs +0/−222
- src/Main.hs +131/−176
- src/Makefile +32/−5
- src/Message/AST.hs +11/−7
- src/Message/Parser.hs +3/−2
- src/Message/Quasi.hs +5/−11
- src/Message/Render.hs +23/−13
- src/Meta/DeriveNotable.hs +2/−6
- src/Meta/Quasi.hs +45/−27
- src/Meta/QuoteData.hs +0/−5
- src/Meta/THHelpers.hs +4/−9
- src/PDNF.hs +0/−242
- src/Parser.hs +0/−1310
- src/Paths.hs +11/−5
- src/Ppr.hs +0/−514
- src/PprClass.hs +0/−301
- src/Prec.hs +0/−75
- src/PrettyPrint.hs +0/−180
- src/Printing.hs +0/−78
- src/Rename.hs +0/−974
- src/Sigma.hs +0/−519
- src/Statics.hs +247/−1681
- src/Statics/Coercion.hs +134/−0
- src/Statics/Constraint.hs +1587/−0
- src/Statics/Decl.hs +430/−0
- src/Statics/Decl.hs-boot +12/−0
- src/Statics/Env.hs +202/−0
- src/Statics/Error.hs +107/−0
- src/Statics/Expr.hs +425/−0
- src/Statics/InstGen.hs +277/−0
- src/Statics/Patt.hs +209/−0
- src/Statics/Rename.hs +1072/−0
- src/Statics/Sealing.hs +418/−0
- src/Statics/Sig.hs +80/−0
- src/Statics/Subsume.hs +98/−0
- src/Statics/Type.hs +203/−0
- src/Syntax.hs +0/−140
- src/Syntax/Anti.hs +0/−378
- src/Syntax/Construction.hs +267/−0
- src/Syntax/Decl.hs +0/−331
- src/Syntax/Decl.hs-boot +0/−26
- src/Syntax/Expr.hs +0/−325
- src/Syntax/Ident.hs +0/−265
- src/Syntax/Ident.hs-boot +0/−12
- src/Syntax/ImplicitThreading.hs +1141/−0
- src/Syntax/Kind.hs +0/−263
- src/Syntax/Lexer.hs +351/−0
- src/Syntax/Lit.hs +0/−18
- src/Syntax/Notable.hs +0/−60
- src/Syntax/POClass.hs +0/−87
- src/Syntax/Parser.hs +1376/−0
- src/Syntax/Patt.hs +0/−121
- src/Syntax/Ppr.hs +638/−0
- src/Syntax/PprClass.hs +394/−0
- src/Syntax/Prec.hs +80/−0
- src/Syntax/Strings.hs +146/−0
- src/Syntax/SyntaxTable.hs +0/−133
- src/Syntax/Type.hs +0/−136
- src/Token.hs +0/−494
- src/Type.hs +22/−1067
- src/Type/Analyses.hs +78/−0
- src/Type/ArrowAnnotations.hs +143/−0
- src/Type/Internal.hs +847/−0
- src/Type/Ppr.hs +108/−0
- src/Type/Rank.hs +30/−0
- src/Type/Recursive.hs +136/−0
- src/Type/Reduce.hs +155/−0
- src/Type/Subst.hs +453/−0
- src/Type/Syntax.hs +212/−0
- src/Type/TyVar.hs +239/−0
- src/TypeRel.hs +0/−1051
- src/Util.hs +383/−147
- src/Util/Bogus.hs +41/−0
- src/Util/Eq1.hs +26/−0
- src/Util/MonadRef.hs +122/−0
- src/Util/Trace.hs +268/−0
- src/Util/UndoIO.hs +77/−0
- src/Util/Viewable.hs +58/−0
- src/Value.hs +94/−57
- src/Viewable.hs +0/−52
- src/extensions.txt +24/−0
Makefile view
@@ -2,9 +2,19 @@ GHC = ghc EXAMPLES = examples SRC = $(HS_SRC) $(HSBOOT_SRC)-HS_SRC = src/*.hs src/Basis/*.hs src/Basis/Channel/*.hs \- src/Syntax/*.hs src/Message/*.hs src/Meta/*.hs-HSBOOT_SRC = src/Syntax/*.hs-boot+HS_SRC = src/*.hs \+ src/Alt/*.hs \+ src/AST/*.hs \+ src/Basis/*.hs \+ src/Basis/Channel/*.hs \+ src/Data/*.hs \+ src/Message/*.hs \+ src/Meta/*.hs \+ src/Statics/*.hs \+ src/Syntax/*.hs \+ src/Type/*.hs \+ src/Util/*.hs+HSBOOT_SRC = src/AST/*.hs-boot src/Statics/*.hs-boot DOC = dist/doc/html/alms/alms/ @@ -12,8 +22,11 @@ ./Setup build cp dist/build/alms/alms . +alms.cabal: alms.cabal.sh Makefile src/extensions.txt $(HS_SRC)+ ./alms.cabal.sh > alms.cabal+ dist/setup-config config: Setup alms.cabal- ./Setup configure --flags="$(FLAGS)"+ ./Setup configure --user --flags="$(FLAGS)" Setup: Setup.hs $(GHC) -o $@ --make $<@@ -50,7 +63,7 @@ $(RM) html -VERSION = 0.5.0+VERSION = 0.6.0 DISTDIR = alms-$(VERSION) TARBALL = $(DISTDIR).tar.gz
alms.cabal view
@@ -1,6 +1,6 @@ Name: alms-Version: 0.5.0-Copyright: 2010, Jesse A. Tov+Version: 0.6.0+Copyright: 2011, Jesse A. Tov Cabal-Version: >= 1.8 License: BSD3 License-File: LICENSE@@ -11,7 +11,9 @@ Category: Compilers/Interpreters Synopsis: a practical affine language Build-type: Simple-Data-files: lib/*.alms examples/*.alms examples/*.sh+Extra-Source-Files:+ alms.cabal.sh src/extensions.txt+Data-Files: lib/*.alms examples/*.alms examples/*.sh examples/*.in examples/*.out README Makefile @@ -29,6 +31,13 @@ system to naturally and directly express a variety of resource management protocols from special-purpose type systems. +Source-Repository head+ Type: git+ Location: git://github.com/tov/alms.git++Flag unicode+ Description: Use Unicode symbols for pretty-printing+ Flag editline Description: Enable line editing using the editline package @@ -44,78 +53,147 @@ Hs-Source-Dirs: src GHC-Options: -O3 CPP-Options: -DALMS_CABAL_BUILD- Build-Depends: haskell98,+ Build-Depends:+ haskell98, base == 4.*,- syb >= 0.1,- pretty >= 1,+ HUnit >= 1.2,+ QuickCheck >= 2,+ array >= 0.3, containers >= 0.1,- mtl >= 1.1,+ directory >= 1.0,+ fgl >= 5, filepath >= 1.1,+ incremental-sat-solver >= 0.1.7,+ mtl >= 1.1, network >= 2.2,- directory >= 1.0,- template-haskell >= 2.0,- QuickCheck >= 2,- HUnit >= 1.2,+ pretty >= 1, random >= 1,- array >= 0.3- Other-Modules: Basis,- Basis.Array,- Basis.Channel,- Basis.Channel.Haskell,- Basis.Exn,- Basis.Future,- Basis.IO,- Basis.MVar,- Basis.Socket,- Basis.Thread,- BasisUtils,- Coercion,- Compat,- Dynamics,- Env,- ErrorMessage,- ErrorST,- Lexer,- Loc,- Message.AST,- Message.Parser,- Message.Quasi,- Message.Render,- Meta.DeriveNotable,- Meta.FileString,- Meta.Quasi,- Meta.QuoteData,- Meta.THHelpers,- PDNF,- Parser,- Paths,- Ppr,- PprClass,- Prec,- PrettyPrint,- Printing,- Rename,- Sigma,- Statics,- Syntax,- Syntax.Anti,- Syntax.Decl,- Syntax.Expr,- Syntax.Ident,- Syntax.Kind,- Syntax.Lit,- Syntax.Notable,- Syntax.POClass,- Syntax.Patt,- Syntax.SyntaxTable,- Syntax.Type,- Token,- Type,- TypeRel,- Util,- Value,- Viewable+ stm >= 2.0,+ syb >= 0.1,+ template-haskell >= 2.0,+ transformers >= 0.2,+ tuple >= 0.2+ Other-Modules:+ Alt.Graph+ Alt.NodeMap+ Alt.Parsec+ Alt.PrettyPrint+ Alt.Token+ AST.Anti+ AST.Decl+ AST.Expr+ AST.Ident+ AST.Kind+ AST.Lit+ AST.Notable+ AST.Patt+ AST.SyntaxTable+ AST.Type+ AST.TypeAnnotation+ AST+ Basis.Array+ Basis.Channel.Haskell+ Basis.Channel+ Basis.Exn+ Basis.Future+ Basis.IO+ Basis.MVar+ Basis.Row+ Basis.Socket+ Basis.Thread+ Basis+ BasisUtils+ Compat+ Data.Empty+ Data.Lattice+ Data.Loc+ Data.OptionalClass+ Data.Perhaps+ Data.UnionFind+ Dynamics+ Env+ Error+ Main+ Message.AST+ Message.Parser+ Message.Quasi+ Message.Render+ Meta.DeriveNotable+ Meta.FileString+ Meta.Quasi+ Meta.QuoteData+ Meta.THHelpers+ Paths+ Statics.Coercion+ Statics.Constraint+ Statics.Decl+ Statics.Env+ Statics.Error+ Statics.Expr+ Statics.InstGen+ Statics.Patt+ Statics.Rename+ Statics.Sealing+ Statics.Sig+ Statics.Subsume+ Statics.Type+ Statics+ Syntax.Construction+ Syntax.ImplicitThreading+ Syntax.Lexer+ Syntax.Parser+ Syntax.Ppr+ Syntax.PprClass+ Syntax.Prec+ Syntax.Strings+ Type.Analyses+ Type.ArrowAnnotations+ Type.Internal+ Type.Ppr+ Type.Rank+ Type.Recursive+ Type.Reduce+ Type.Subst+ Type.Syntax+ Type.TyVar+ Type+ Util.Bogus+ Util.Eq1+ Util.MonadRef+ Util.Trace+ Util.UndoIO+ Util.Viewable+ Util+ Value+ Extensions:+ BangPatterns+ CPP+ DeriveDataTypeable+ DeriveFunctor+ EmptyDataDecls+ ExistentialQuantification+ FlexibleContexts+ FlexibleInstances+ FunctionalDependencies+ GeneralizedNewtypeDeriving+ MultiParamTypeClasses+ ParallelListComp+ PatternGuards+ QuasiQuotes+ RankNTypes+ ScopedTypeVariables+ StandaloneDeriving+ TemplateHaskell+ TupleSections+ TypeOperators+ TypeSynonymInstances+ UndecidableInstances+ UnicodeSyntax+ ViewPatterns + if flag(unicode)+ CPP-Options: -DUNICODE+ if flag(readline) Build-Depends: readline >= 1.0 CPP-Options: -DUSE_READLINE=System.Console.Readline@@ -130,4 +208,3 @@ else Build-Depends: parsec == 2.* CPP-Options: -DPARSEC_VERSION=2-
+ alms.cabal.sh view
@@ -0,0 +1,108 @@+#!/bin/sh++cat <<EOF+Name: alms+Version: `./util`+Copyright: 2011, Jesse A. Tov+Cabal-Version: >= 1.8+License: BSD3+License-File: LICENSE+Stability: experimental+Author: Jesse A. Tov <tov@ccs.neu.edu>+Maintainer: tov@ccs.neu.edu+Homepage: http://www.ccs.neu.edu/~tov/pubs/alms+Category: Compilers/Interpreters+Synopsis: a practical affine language+Build-type: Simple+Extra-Source-Files:+ alms.cabal.sh src/extensions.txt+Data-Files: lib/*.alms examples/*.alms examples/*.sh+ examples/*.in examples/*.out+ README Makefile++Description:+ Alms is an experimental, general-purpose programming language that+ supports practical affine types. To offer the expressiveness of+ Girard’s linear logic while keeping the type system light and+ convenient, Alms uses expressive kinds that minimize notation while+ maximizing polymorphism between affine and unlimited types.++ A key feature of Alms is the ability to introduce abstract affine types+ via ML-style signature ascription. In Alms, an interface can impose+ stiffer resource usage restrictions than the principal usage+ restrictions of its implementation. This form of sealing allows the type+ system to naturally and directly express a variety of resource+ management protocols from special-purpose type systems.++Source-Repository head+ Type: git+ Location: git://github.com/tov/alms.git++Flag unicode+ Description: Use Unicode symbols for pretty-printing++Flag editline+ Description: Enable line editing using the editline package++Flag parsec3+ Description: Use version 3 of the parsec package++Flag readline+ Description: Enable line editing using the readline package+ Default: False++Executable alms+ Main-Is: Main.hs+ Hs-Source-Dirs: src+ GHC-Options: -O3+ CPP-Options: -DALMS_CABAL_BUILD+ Build-Depends:+ haskell98,+ base == 4.*,+ HUnit >= 1.2,+ QuickCheck >= 2,+ array >= 0.3,+ containers >= 0.1,+ directory >= 1.0,+ fgl >= 5,+ filepath >= 1.1,+ incremental-sat-solver >= 0.1.7,+ mtl >= 1.1,+ network >= 2.2,+ pretty >= 1,+ random >= 1,+ stm >= 2.0,+ syb >= 0.1,+ template-haskell >= 2.0,+ transformers >= 0.2,+ tuple >= 0.2+ Other-Modules:+EOF++find src -name \*.hs |+ sed 's@^src/@ @;s@\.hs$@@;s@/@.@g;/^Main$/d'++echo " Extensions:"++sed 's/^/ /' src/extensions.txt++cat <<EOF++ if flag(unicode)+ CPP-Options: -DUNICODE++ if flag(readline)+ Build-Depends: readline >= 1.0+ CPP-Options: -DUSE_READLINE=System.Console.Readline+ else+ if flag(editline)+ Build-Depends: editline >= 0.2.1+ CPP-Options: -DUSE_READLINE=System.Console.Editline.Readline++ if flag(parsec3)+ Build-Depends: parsec == 3.*+ CPP-Options: -DPARSEC_VERSION=3+ else+ Build-Depends: parsec == 2.*+ CPP-Options: -DPARSEC_VERSION=2+EOF
examples/echoServer.alms view
@@ -7,27 +7,25 @@ (* This is a bit different than the version in the paper, because * it uses exceptions. *)- let handleClient['t] (sock: 't socket) (f: string -> string)- (cap: 't connected) : unit =- let rec loop (cap: 't connected): unit =+ let handleClient sock f cap =+ let rec loop cap = let (str, cap) = recv sock 1024 cap in let cap = send sock (f str) cap in loop cap in try loop cap- with SocketError _ -> ()+ with SocketError _ → () - let rec acceptLoop['t] (sock: 't socket) (f: string -> string)- (cap: 't listening) : unit =- let (('s, clientsock, clientcap), cap) = accept sock cap in+ let rec acceptLoop sock f cap =+ let ((clientsock, clientcap), cap) = accept sock cap in putStrLn "Opened connection";- (Thread.fork :> (unit -o unit) -> Thread.thread)- (fun () -> handleClient clientsock f clientcap;- putStrLn "Closed connection");+ (Thread.fork :> (unit -A> unit) → Thread.thread)+ (λ _ → handleClient clientsock f clientcap;+ putStrLn "Closed connection"); acceptLoop sock f cap - let serve (port: int) (f: string -> string) =- let ('t, sock, cap) = socket () in+ let serve port f =+ let (sock, cap) = socket () in let cap = bind sock port cap in let cap = listen sock cap in acceptLoop sock f cap@@ -35,9 +33,9 @@ let serverFun (s: string) = s -let main (argv: string list) =+let main argv = match argv with- | Cons (port, Nil) -> EchoServer.serve (int_of_string port) serverFun- | _ -> failwith "Usage: echoServer.aff PORT\n"+ | [port] → EchoServer.serve (int_of_string port) serverFun+ | _ → failwith "Usage: echoServer.aff PORT\n" in main (getArgs ())
examples/ex01-poly.alms view
@@ -1,10 +1,7 @@ (* Polymorphic version: A Type-Correct, Blame-Free Program *) -let ap =- fun `a `b (f: `a -o `b) (x: `a) ->- f x+let ap (f: `a -A> `b) x = f x -let inc =- fun y: int -> ap (fun z:int -> z + 1) y+let inc y = ap ((+) 1) y in print (inc 5)
examples/ex01.alms view
@@ -1,11 +1,7 @@ (* A Type-Correct, Blame-Free Program *) -let ap =- fun f: (int -o int) ->- fun x: int ->- f x+let ap (f: int -A> int) x = f x -let inc =- fun y: int -> ap (fun z:int -> z + 1) y+let inc y = ap ((+) 1) y in print (inc 5)
examples/ex02-poly-type-error.alms view
@@ -1,15 +1,9 @@ (* Polymorphic version: An Ill-Typed Module (type error) *) -let ap =- fun `a ->- fun `b ->- fun f: (`a -o `b) ->- fun x: `a ->- f x+let ap (f: `a -A> `b) x = f x -let inc2 =- fun y: int ->- let g = ap (fun z: int -> z + 1) in+let inc2 y =+ let g = ap ((+) 1) in g (g y) (* g: (int -o int) is used twice here *) in print (inc2 5)
examples/ex02-type-error.alms view
@@ -1,13 +1,9 @@ (* An Ill-Typed Module (type error) *) -let ap =- fun f: (int -o int) ->- fun x: int ->- f x+let ap (f: int -o int) x = f x -let inc2 =- fun y: int ->- let g = ap (fun z: int -> z + 1) in- g (g y) (* g: (int -o int) is used twice here *)+let inc2 y =+ let g = ap ((+) 1) in+ g (g y) (* g: (int -o int) is used twice here *) -in print[int] (inc2 5)+in print (inc2 5)
examples/ex03-blame-error.alms view
@@ -1,12 +1,10 @@ (* A Blameworthy Coercion *) -let ap =- fun f: (int -o int) ->- ( (fun x: int -> f x) :> int -> int )+let ap (f: int -o int) =+ ((fun x -> f x) :> int -> int) -let inc2 =- fun y: int ->- let g = ap (fun z: int -> z + 1) in- g (g y) (* g is used twice here *)+let inc2 y =+ let g = ap ((+) 1) in+ g (g y) (* g is used twice here *) in print (inc2 5)
examples/ex03-poly-blame-error.alms view
@@ -1,12 +1,10 @@ (* Polymorphic version: A Blameworthy Coercion *) -let ap =- fun 'a 'b (f: 'a -o 'b) (x: 'a) -> f x+let ap (f: 'a -o 'b) x = f x -let inc2 =- fun y: int ->- let g = (ap :> all 'a 'b. ('a -A> 'b) -> 'a -U> 'b)- (fun z: int -> z + 1) in- g (g y) (* g is used twice here *)+let inc2 y =+ let g = (ap :> ('a -A> 'b) -> 'a -U> 'b)+ ((+) 1) in+ g (g y) (* g is used twice here *) in print (inc2 5)
examples/ex04-poly.alms view
@@ -1,12 +1,10 @@ (* Polymorphic version: ex03 corrected *) -let ap : all 'a 'b. ('a -o 'b) -> 'a -o 'b =- fun 'a 'b (f: 'a -o 'b) (x : 'a) -> f x+let ap : all 'a 'b. ('a -o 'b) -> 'a -o 'b = fun f x -> f x -let inc2 : int -> int =- fun y: int ->- let g = ap[int,int] (fun z: int -> z + 1) in- let h = ap[int,int] (fun z: int -> z + 1) in- h (g y)+let inc2 y =+ let g = ap ((+) 1) in+ let h = ap ((+) 1) in+ h (g y) -in print[int] (inc2 5)+in print (inc2 5)
examples/ex04.alms view
@@ -1,14 +1,10 @@ (* Ex04 Corrected *) -let ap : (int -o int) -> int -o int =- fun f: (int -o int) ->- fun x: int ->- f x+let ap : (int -o int) -> int -o int = fun f x -> f x -let inc2 : int -> int =- fun y: int ->- let g = ap (fun z: int -> z + 1) in- let h = ap (fun z: int -> z + 1) in- h (g y)+let inc2 y =+ let g = ap ((+) 1) in+ let h = ap ((+) 1) in+ h (g y) -in print[int] (inc2 5)+in print (inc2 5)
examples/ex05-poly.alms view
@@ -1,10 +1,5 @@-let ap : all 'a 'b. ('a -> 'b) -> 'a -> 'b =- fun 'a 'b ->- fun f: ('a -> 'b) ->- fun x: 'a ->- f x+let ap : all 'a 'b. ('a -> 'b) -> 'a -> 'b = fun f x -> f x -let inc : int -> int =- fun y: int -> ap[int,int] (fun z: int -> z + 1) y+let inc y = ap ((+) 1) y -in print[int] (inc 5)+in print (inc 5)
examples/ex05.alms view
@@ -1,9 +1,9 @@ let ap : (int -> int) -> int -> int =- fun f: (int -> int) ->- fun x: int ->+ fun (f: int -> int) ->+ fun (x: int) -> f x let inc : int -> int =- fun y: int -> ap (fun z: int -> z + 1) y+ fun (y: int) -> ap (fun (z: int) -> z + 1) y -in print[int] (inc 5)+in print (inc 5)
examples/ex06-poly-type-error.alms view
@@ -1,12 +1,11 @@-let ap : all 'a 'b. ('a -> 'b) -> 'a -> 'b =- fun 'a 'b ->- fun f: ('a -> 'b) ->- fun x: 'a ->+let ap : all 'c 'd. ('c -> 'd) -> 'c -> 'd =+ fun (f: 'a -> 'b) ->+ fun (x: 'a) -> f x let inc : int -> int =- fun y: int ->- let g = (fun z:int -> z + 1 : int -> int :> int -o int) in- ap[int,int] g y (* g: (int -o int) is used as an (int -> int) *)+ fun (y: int) ->+ let g = (fun (z:int) -> z + 1 : int -> int :> int -o int) in+ ap g y (* g: (int -o int) is used as an (int -> int) *) -in print[int] (inc 5)+in print (inc 5)
examples/ex06-type-error.alms view
@@ -1,11 +1,11 @@ let ap : (int -> int) -> int -> int =- fun f: (int -> int) ->- fun x: int ->+ fun (f: int -> int) ->+ fun (x: int) -> f x let inc : int -> int =- fun y: int ->- let g = (fun z:int -> z + 1 : int -> int :> int -o int) in+ fun (y: int) ->+ let g = (fun (z:int) -> z + 1 : int -> int :> int -o int) in ap g y (* g: (int -o int) is used as an (int -> int) *) -in print[int] (inc 5)+in print (inc 5)
examples/ex07-poly.alms view
@@ -1,17 +1,16 @@ (* Polymorphic version: An Interface Intervenes *) -let ap : all 'a 'b. ('a -> 'b) -> 'a -> 'b =- fun 'a 'b ->- fun f: ('a -> 'b) ->- fun x: 'a ->- f x+let ap : all 'c 'd. ('c -> 'd) -> 'c -> 'd =+ fun (f: 'a -> 'b) ->+ fun (x: 'a) ->+ f x let iap = (ap :> all 'a 'b. ('a -o 'b) -> 'a -o 'b) let inc : int -> int =- fun y: int ->- (fun g: (int -o int) ->- iap[int,int] g y)- (fun z: int -> z + 1)+ fun (y: int) ->+ (fun (g: int -o int) ->+ iap g y)+ (fun (z: int) -> z + 1) -in print[int] (inc 5)+in print (inc 5)
examples/ex07.alms view
@@ -1,16 +1,16 @@ (* An Interface Intervenes *) let ap : (int -> int) -> int -> int =- fun f: (int -> int) ->- fun x: int ->+ fun (f: int -> int) ->+ fun (x: int) -> f x let iap = (ap :> (int -o int) -> int -o int) let inc : int -> int =- fun y: int ->- (fun g: (int -o int) ->+ fun (y: int) ->+ (fun (g: int -o int) -> iap g y)- (fun z: int -> z + 1)+ (fun (z: int) -> z + 1) -in print[int] (inc 5)+in print (inc 5)
examples/ex08-blame-error.alms view
@@ -1,16 +1,16 @@ (* A Lying Interface *) let ap : (int -> int) -> int -> int =- fun f: (int -> int) ->- fun x: int ->+ fun (f: int -> int) ->+ fun (x: int) -> f (f x) (* f is used twice here, despite what iap2 claims *) let iap2 = (ap :> (int -o int) -> int -o int) let inc : int -> int =- fun y: int ->- (fun g: (int -o int) ->+ fun (y: int) ->+ (fun (g: int -o int) -> iap2 g y)- (fun z: int -> z + 1)+ (fun (z: int) -> z + 1) -in print[int] (inc 5)+in print (inc 5)
examples/ex08-poly-blame-error.alms view
@@ -1,17 +1,16 @@ (* A Lying Interface *) -let ap : all 'a. ('a -> 'a) -> 'a -> 'a =- fun 'a ->- fun f: ('a -> 'a) ->- fun x: 'a ->- f (f x) (* f is used twice here, despite what iap2 claims *)+let ap : all 'c. ('c -> 'c) -> 'c -> 'c =+ fun (f: 'a -> 'a) ->+ fun (x: 'a) ->+ f (f x) (* f is used twice here, despite what iap2 claims *) let iap2 = (ap :> all 'a. ('a -o 'a) -> 'a -o 'a) let inc : int -> int =- fun y: int ->- (fun g: (int -o int) ->- iap2[int] g y)- (fun z: int -> z + 1)+ fun (y: int) ->+ (fun (g: int -o int) ->+ iap2 g y)+ (fun (z: int) -> z + 1) -in print[int] (inc 5)+in print (inc 5)
examples/ex09-dynamic-promotion-poly.alms view
@@ -1,16 +1,15 @@ (* Polymorphic version: A Dynamic Promotion Intervenes (like ex7.aff) *) -let ap : all 'a. ('a -> 'a) -> 'a -> 'a =- fun 'a ->- fun f: ('a -> 'a) ->- fun x: 'a ->- f x+let ap : all 'c. ('c -> 'c) -> 'c -> 'c =+ fun (f: 'a -> 'a) ->+ fun (x: 'a) ->+ f x let inc : int -> int =- fun y: int ->- (fun g: (int -o int) ->- (ap[int] : (int -> int) -> int -> int- :> (int -o int) -> int -o int) g y)- (fun z: int -> z + 1)+ fun (y: int) ->+ (fun (g: int -o int) ->+ (ap : (int -> int) -> int -> int+ :> (int -o int) -> int -o int) g y)+ (fun (z: int) -> z + 1) -in print[int] (inc 5)+in print (inc 5)
examples/ex09-dynamic-promotion.alms view
@@ -1,15 +1,15 @@ (* A Dynamic Promotion Intervenes (like ex7.aff) *) let ap : (int -> int) -> int -> int =- fun f: (int -> int) ->- fun x: int ->+ fun (f: int -> int) ->+ fun (x: int) -> f x let inc : int -> int =- fun y: int ->- (fun g: (int -o int) ->+ fun (y: int) ->+ (fun (g: int -o int) -> (ap : (int -> int) -> int -> int :> (int -o int) -> int -o int) g y)- (fun z: int -> z + 1)+ (fun (z: int) -> z + 1) -in print[int] (inc 5)+in print (inc 5)
examples/ex10-dynamic-promotion-blame-error.alms view
@@ -1,15 +1,15 @@ (* A Lying Dynamic Promotion (like ex8.aff -- blame inc(:>)) *) let ap : (int -> int) -> int -> int =- fun f: (int -> int) ->- fun x: int ->+ fun (f: int -> int) ->+ fun (x: int) -> f (f x) (* f is used twice here, despite what iap2 claims *) let inc : int -> int =- fun y: int ->- (fun g: (int -o int) ->+ fun (y: int) ->+ (fun (g: int -o int) -> (ap : (int -> int) -> int -> int :> (int -o int) -> int -o int) g y) (* This cast goes bad *)- (fun z: int -> z + 1)+ ((+) 1) -in print[int] (inc 5)+in print (inc 5)
examples/ex10-dynamic-promotion-poly-blame-error.alms view
@@ -1,16 +1,15 @@ (* Polymorphic: A Lying Dynamic Promotion (like ex8.aff -- blame inc(:>)) *) -let ap : all 'a. ('a -> 'a) -> 'a -> 'a =- fun 'a ->- fun f: ('a -> 'a) ->- fun x: 'a ->- f (f x) (* f is used twice here, despite what iap2 claims *)+let ap : all 'c. ('c -> 'c) -> 'c -> 'c =+ fun (f: 'a -> 'a) ->+ fun (x: 'a) ->+ f (f x) (* f is used twice here, despite what iap2 claims *) let inc : int -> int =- fun y: int ->- (fun g: (int -o int) ->- (ap[int] : (int -> int) -> int -> int (* This cast goes bad *)- :> (int -o int) -> int -o int) g y)- (fun z: int -> z + 1)+ fun (y: int) ->+ (fun (g: int -o int) ->+ (ap : (int -> int) -> int -> int (* This cast goes bad *)+ :> (int -o int) -> int -o int) g y)+ (fun (z: int) -> z + 1) -in print[int] (inc 5)+in print (inc 5)
examples/ex11-affine-type-error.alms view
@@ -1,3 +1,3 @@ (* Can't duplicate type `a (type error) *) -let dup[`a] (x: `a) = (x, x)+let dup : ∀ `a. `a → `a * `a = λ x → (x, x)
+ examples/ex24-io.alms view
@@ -0,0 +1,41 @@+(* Typestate file IO *)++open IO++abstype in_channel' = InChannel of handle with+ let open_in s = InChannel (openFile s ReadMode)+ let input_char (InChannel h) = hGetChar h+ let input_line (InChannel h) = hGetLine h+ let eof_in (InChannel h) = hIsEOF h+ let close_in (InChannel h) = hClose h+end++abstype out_channel = OutChannel of handle with+ let open_out s = OutChannel (openFile s WriteMode)+ let output_char (OutChannel h) = hPutChar h+ let output_string (OutChannel h) = hPutStr h+ let eof_out (OutChannel h) = hIsEOF h+ let close_out (OutChannel h) = hClose h+end++abstype in_channel : A = InChannel of in_channel' with+ let a_open_in s = InChannel (open_in s)+ let a_input_char (InChannel rep as ic) =+ (input_char rep, ic)+ let a_input_line (InChannel rep as ic) =+ (input_line rep, ic)+ let a_close_in (InChannel rep) =+ close_in rep+ let a_eof_in (InChannel rep as ic) =+ if eof_in rep+ then close_in rep; None+ else Some ic+end++let cat filename =+ let rec loop ic =+ match a_eof_in ic with+ | None -> ()+ | Some ic -> let (c, ic) = a_input_char ic in+ putChar c; loop ic+ in loop (a_open_in filename)
+ examples/ex25-io-type-error.alms view
@@ -0,0 +1,41 @@+(* Typestate file IO *)++open IO++abstype in_channel' = InChannel of handle with+ let open_in s = InChannel (openFile s ReadMode)+ let input_char (InChannel h) = hGetChar h+ let input_line (InChannel h) = hGetLine h+ let eof_in (InChannel h) = hIsEOF h+ let close_in (InChannel h) = hClose h+end++abstype out_channel = OutChannel of handle with+ let open_out s = OutChannel (openFile s WriteMode)+ let output_char (OutChannel h) = hPutChar h+ let output_string (OutChannel h) = hPutStr h+ let eof_out (OutChannel h) = hIsEOF h+ let close_out (OutChannel h) = hClose h+end++abstype in_channel : A = InChannel of in_channel' with+ let a_open_in s = InChannel (open_in s)+ let a_input_char (InChannel rep as ic) =+ (input_char rep, ic)+ let a_input_line (InChannel rep as ic) =+ (input_line rep, ic)+ let a_close_in (InChannel rep) =+ close_in rep+ let a_eof_in (InChannel rep as ic) =+ if eof_in rep+ then close_in rep; None+ else Some ic+end++let cat filename =+ let rec loop ic =+ match a_eof_in ic with+ | None -> ()+ | Some ic -> let (c, _) = a_input_char ic in+ putChar c; loop ic+ in loop (a_open_in filename)
− examples/ex25-io.alms
@@ -1,41 +0,0 @@-(* Typestate file IO *)--open IO--abstype in_channel' = InChannel of handle with- let open_in (s: string) = InChannel (openFile s ReadMode)- let input_char (InChannel h: in_channel') = hGetChar h- let input_line (InChannel h: in_channel') = hGetLine h- let eof_in (InChannel h: in_channel') = hIsEOF h- let close_in (InChannel h: in_channel') = hClose h-end--abstype out_channel = OutChannel of handle with- let open_out (s: string) = OutChannel (openFile s WriteMode)- let output_char (OutChannel h: out_channel) = hPutChar h- let output_string (OutChannel h: out_channel) = hPutStr h- let eof_out (OutChannel h: out_channel) = hIsEOF h- let close_out (OutChannel h: out_channel) = hClose h-end--abstype in_channel qualifier A = InChannel of in_channel' with- let a_open_in (s: string) = InChannel (open_in s)- let a_input_char (InChannel rep as ic: in_channel) =- (input_char rep, ic)- let a_input_line (InChannel rep as ic: in_channel) =- (input_line rep, ic)- let a_close_in (InChannel rep: in_channel) =- close_in rep- let a_eof_in (InChannel rep as ic: in_channel) =- if eof_in rep- then close_in rep; None[in_channel]- else Some ic-end--let cat (filename: string) =- let rec loop (ic: in_channel): unit =- match a_eof_in ic with- | None -> ()- | Some ic -> let (c, ic) = a_input_char ic in- putChar c; loop ic- in loop (a_open_in filename)
examples/ex26-let-bang-array.alms view
@@ -16,8 +16,8 @@ (* We represent this thing with (essentially) as a spinlock. Acquire the spinlock: *)- let acquireBang['t, 'c] (r: ('t, 'c) ureadcap_rep ref) =- let rec loop (): ('t, 'c) readcap =+ let acquireBang (r: ('t, 'c) ureadcap_rep ref) =+ let rec loop () = match r <- CheckedOut with | Available c -> c | CheckedOut -> loop ()@@ -27,9 +27,9 @@ (* Given a capability, create a temporary, unlimited read capability and pass that to a call-back. Return the result of the callback and the restored capability. *)- let letBang['t, 'c, `a] (c: ('t, 'c) readcap)|- (k: ('t, 'c) ureadcap -o `a)- : `a * ('t, 'c) readcap =+ let letBang (c: ('t, 'c) readcap)+ (k: ('t, 'c) ureadcap -o `a)+ : `a * ('t, 'c) readcap = let r = ref (Available c) in let uc = MkCap r in let a = k uc in@@ -37,16 +37,15 @@ r <- Defunct; (a, c) - let applyBang['t,'c,`r]+ let applyBang (k: ('t, 'c) readcap -o `r * ('t, 'c) readcap)- | (MkCap r: ('t, 'c) ureadcap) : `r = let (result, c) = k (acquireBang r) in r <- Available c; result - let liftBang['t,'c,`r]+ let liftBang (k: ('t, 'c) readcap -> `r * ('t, 'c) readcap) (MkCap r: ('t, 'c) ureadcap) : `r =@@ -54,11 +53,11 @@ r <- Available c; result - let getAU['a,'t,'c] (a: ('a, 't) array) (ix: int) =- liftBang (get['a,'t,'c] a ix)+ let getAU (a: ('a, 't) array) (ix: int) =+ liftBang (get a ix) - let putAU['a,'t] (a: ('a, 't) array) (ix: int) (new: 'a) =- let f (cap: 't writecap) = ((), set['a,'t] a ix new cap) in+ let putAU (a: ('a, 't) array) (ix: int) (new: 'a) =+ let f (cap: 't writecap) = ((), set a ix new cap) in liftBang f end end@@ -67,7 +66,7 @@ let test () = let n = 10 in- let Pack('t, a, cap) = new[int] n 0 in+ let (a, cap) = new n 0 in let rec loop (i: int) (cap: 't writecap): 't writecap = if i >= n then cap
examples/ex27-focusing-and-adoption.alms view
@@ -12,74 +12,60 @@ x, y: `a stored value xs: `a list region representation - T[[ { p |-> t } ]] = (p, T[[ t ]]) region1- T[[ { p |->^w t } ]] = (p, T[[ t ]]) region+ T[[ { p |→ t } ]] = (p, T[[ t ]]) region1+ T[[ { p |→^w t } ]] = (p, T[[ t ]]) region T[[ Ptr t ]] = T[[ t ]] ptr *) -let length[`a] (xs: `a list) : int * `a list =- foldr (fun (x: `a) (n: int, xs: `a list) ->- (n + 1, Cons (x, xs)))- (0, Nil[`a]) xs--let snoc[`a] (x: `a) |[a] (xs: `a list) : `a list =- foldr (fun (x: `a) (xs: `a list) -> Cons (x, xs))- (Cons (x, Nil[`a])) xs--let revAppN =- let rec loop[`a] (n: int) (xs: `a list) |[a] (acc: `a list)- : `a list * `a list =- match n with- | 0 -> (acc, xs)- | _ -> match xs with- | Cons(x, xs) -> loop (n - 1) xs (Cons (x, acc))- | xs -> (acc, xs)- in loop+let snoc x xs = append xs [x] -let rev[`a] (xs: `a list) : `a list =- let (_, acc) = revAppN (-1) xs Nil[`a] - in acc+let rec revAppN n xs acc =+ match n with+ | 0 → (acc, xs)+ | _ → match xs with+ | x ∷ xs → revAppN (n - 1) xs (x ∷ acc)+ | xs → (acc, xs) -let swapN[`a] (ix: int) (y: `a) |[a] (xs: `a list)- : `a * `a list =- let (Cons(x, xs), acc) = revAppN ix xs Nil[`a] in- let (xs, _) = revAppN (-1) acc (Cons (y, xs)) in- (x, xs)+let swapN ix y xs =+ let (x ∷ xs, acc) = revAppN ix xs [] in+ (x, revApp acc (y ∷ xs)) -module Region : sig- type ('t, `a) region : A+module type REGION = sig+ type ('t, `a) region : A type ('t, `a) region1 : A type 't ptr - val newRgn : unit -> ex 't. ('t,`a) region- val mallocIn : ('t,`a) region -> `a -o 't ptr * ('t,`a) region- val swap : ('t,`a) region -> 't ptr -o `a -o `a * ('t,`a) region- val malloc : unit -> ex 't. ('t,unit) region1 * 't ptr- val free : ('t,`a) region1 -> unit- val adopt : ('t1,`a) region -> ('t2,`a) region1 -o 't2 ptr -o+ val newRgn : unit → ∃ 't. ('t,`a) region+ val mallocIn : ('t,`a) region → `a -A> 't ptr * ('t,`a) region+ val swap : ('t,`a) region → 't ptr -A> `a -A> `a * ('t,`a) region+ val malloc : unit → ∃ 't. ('t,unit) region1 * 't ptr+ val free : ('t,`a) region1 → unit+ val adopt : ('t1,`a) region → ('t2,`a) region1 -A> 't2 ptr -A> 't1 ptr * ('t1,`a) region- val focus : ('t,`a) region -> 't ptr -o- ex 't1. ('t1,`a) region1 * 't1 ptr *- (('t1,`a) region1 -o ('t,`a) region)-end = struct+ val focus : ('t,`a) region → 't ptr -A>+ ∃ 't1. ('t1,`a) region1 * 't1 ptr *+ (('t1,`a) region1 -A> ('t,`a) region)+end++module Region : REGION = struct type ('t, `a) region = `a list type ('t, `a) region1 = `a type 't ptr = int - let newRgn () = Nil+ let newRgn () = [] : ∃ 't. ('t,`a) region let freeRgn _ = () let mallocIn (xs: `a list) (a: `a) =- let (ix, xs) = length xs in+ let (ix, xs) = lengthA xs in (ix, snoc a xs) let swap (xs: `a list) (ix: 't ptr) (x: `a) = let (y, xs) = swapN ix x xs in (y, xs) - let malloc () = ((), 0)+ let malloc () = ((), 0) : ∃ 't. ('t,unit) region1 * 't ptr let swap1 (x: `a) _ (y: `b) = (x, y) @@ -88,7 +74,10 @@ let adopt (rgn: `a list) (x: `a) _ = mallocIn rgn x - let focus (xs: `a list) (ix: 't ptr) =- let (Cons (x, xs), acc) = revAppN ix xs Nil in- (x, 0, fun (y: `a) -> fst (revAppN (-1) acc (Cons (y, xs))))+ let focus xs ix+ : ∃ 't1. ('t1,`a) region1 * 't1 ptr *+ (('t1,`a) region1 -A> ('t,`a) region)+ =+ let (x ∷ xs, acc) = revAppN ix xs [] in+ (x, 0, λ y → revApp acc (y ∷ xs)) end
examples/ex28-focusing-and-adoption.alms view
@@ -6,75 +6,58 @@ 't 's capability name *) -let length[`a] (xs: `a list) : int * `a list =- foldr (fun (x: `a) (n: int, xs: `a list) ->- (n + 1, Cons (x, xs)))- (0, Nil[`a]) xs--let snoc[`a] (x: `a) |[a] (xs: `a list) : `a list =- foldr (fun (x: `a) (xs: `a list) -> Cons (x, xs))- (Cons (x, Nil[`a])) xs+let snoc x xs = append xs [x] -let revAppN =- let rec loop[`a] (n: int) (xs: `a list) | (acc: `a list)- : `a list * `a list =- match n with- | 0 -> (acc, xs)- | _ -> match xs with- | Cons(x, xs) -> loop (n - 1) xs (Cons (x, acc))- | xs -> (acc, xs)- in loop+let rec revAppN n xs acc =+ match n with+ | 0 → (acc, xs)+ | _ → match xs with+ | x ∷ xs → revAppN (n - 1) xs (x ∷ acc)+ | xs → (acc, xs) -let swapN[`a] (ix: int) (y: `a) |[a] (xs: `a list)- : `a * `a list =- let (Cons(x, xs), acc) = revAppN ix xs Nil[`a] in- let (xs, _) = revAppN (-1) acc (Cons (y, xs)) in- (x, xs)+let swapN ix y xs =+ let (x ∷ xs, acc) = revAppN ix xs [] in+ (x, revApp acc (y ∷ xs)) -abstype 't tr qualifier U = Tr- and ('t, `a) cap qualifier A = Cap of `a * (unit -o unit) list- and ('t, `a) guarded qualifier U =- Guarded of (`a * (unit -o unit) list) option ref+abstype 't tr = Tr+ and ('t, `a) cap : A = Cap of `a * (unit -A> unit) list+ and ('t, `a) guarded =+ Guarded of (`a * (unit -A> unit) list) option ref with- let new[`a] (x: `a) : ex 't. ('t, `a) cap * 't tr =- Pack[ex 't. ('t, `a) cap * 't tr]- (unit, Cap[unit, `a] (x, Nil[unit -o unit]), Tr[unit])- let swap[`a,`b,'t] ((Cap (x, fs), _) : ('t, `a) cap * 't tr) |- (y : `b)- : ('t, `b) cap * `a =- (Cap['t] (y, fs), x)- let free[`a, 't] (Cap (_, fs): ('t, `a) cap) =- let rec loop (fs : (unit -o unit) list) : unit =- match fs with- | Nil -> ()- | Cons(f, fs) -> f (); loop fs- in loop fs+ let new (x: `a) : ∃ 't. ('t, `a) cap * 't tr =+ (Cap (x, []), Tr) - let adoptByThen[`a,'ta,`b,'tb]- ((Cap adoptee, _) : ('ta, `a) cap * 'ta tr) |+ let swap ((Cap (x, fs), _) : ('t, `a) cap * 't tr) (y : `b)+ : ('t, `b) cap * `a =+ (Cap (y, fs), x)++ let free (Cap (_, fs)) = map (λ f → f ()) fs; ()++ let adoptByThen+ ((Cap adoptee, _) : ('ta, `a) cap * 'ta tr) ((Cap (adoptor, destructors), _) : ('tb, `b) cap * 'tb tr)- (destroy : ('ta, `a) cap -o unit)+ (destroy : ('ta, `a) cap -A> unit) : ('tb, `b) cap * ('tb, `a) guarded = let r = ref (Some adoptee) in let g () = match r <- None with- | None -> failwith "Can't happen"- | Some c -> destroy (Cap['ta] c) in- (Cap['tb] (adoptor, Cons(g, destructors)), Guarded['tb] r)- let adoptBy[`a,'ta,`b,'tb]- (adoptee : ('ta, `a) cap * 'ta tr) |+ | None → failwith "Can't happen"+ | Some c → destroy (Cap c) in+ (Cap (adoptor, g ∷ destructors), Guarded r)+ let adoptBy+ (adoptee : ('ta, `a) cap * 'ta tr) (adoptor : ('tb, `b) cap * 'tb tr) : ('tb, `b) cap * ('tb, `a) guarded- = adoptByThen adoptee adoptor (fun (_: ('ta, `a) cap) -> ())+ = adoptByThen adoptee adoptor (λ (_: ('ta, `a) cap) → ()) - let focusIn[`a,'t,`b,`r]- ((guard, Guarded r) : ('t, `a) cap * ('t, `b) guarded) |- (body : (all 's. ('s, `b) cap * 's tr -o- ('s, `b) cap * `r))+ let focusIn+ ((guard, Guarded r) : ('t, `a) cap * ('t, `b) guarded)+ (body : (∀ 's. ('s, `b) cap * 's tr -A>+ ('s, `b) cap * `r)) : ('t, `a) cap * `r = match r <- None with- | None -> failwith "Can't happen"- | Some c ->- let (Cap c, result) = body[unit] (Cap[unit] c, Tr[unit])+ | None → failwith "Can't happen"+ | Some c →+ let (Cap c, result) = body (Cap c, Tr) in r <- Some c; (guard, result) end
examples/ex33-session-types.alms view
@@ -7,25 +7,21 @@ type protocol = !int; !int; ?int; 1 -let server =- fun c : protocol dual channel ->- let (x, c) = recv c in- let (y, c) = recv c in- send c (x + y);- ()+let server c =+ let (x, c) = recv c in+ let (y, c) = recv c in+ send c (x + y);+ () -let client =- fun c : protocol channel ->- fun (x : int) (y : int) ->- let c = send c x in- let c = send c y in- let (r, _) = recv c in- r+let client c x y =+ let c = send c x in+ let c = send c y in+ let (r, _) = recv c in+ r -let main =- fun (x : int) (y : int) ->- let rv = newRendezvous[protocol] () in- AThread.fork (fun () -> server (accept rv));- client (request rv) x y+let main x y =+ let rv : protocol rendezvous = newRendezvous () in+ AThread.fork (λ _ → server (accept rv));+ client (request rv) x y in print (main 3 4)
examples/ex34-session-types.alms view
@@ -9,8 +9,7 @@ |+| !'a; ?'a; 1 -let server =- fun c : int protocol dual channel ->+let server (c : int protocol dual channel) = match follow c with | Left c -> let (x, c) = recv c in@@ -22,19 +21,16 @@ send c (0 - x); () -let client =- fun c : int protocol channel ->- fun (x : int) (y : int) ->+let client c x y = let c = sel1 c in let c = send c x in let c = send c y in let (r, _) = recv c in r -let main =- fun (x : int) (y : int) ->- let rv = newRendezvous[int protocol] () in- AThread.fork (fun () -> server (accept rv));- client (request rv) x y+let main x y =+ let rv = newRendezvous () in+ AThread.fork (fun () -> server (accept rv));+ client (request rv) x y in print (main 3 4)
examples/ex35-session-types-type-error.alms view
@@ -9,8 +9,8 @@ |+| !'a; ?'a; 1 -let server =- fun c : int protocol dual channel ->+(* reuses channel *)+let server (c : int protocol dual channel) = match follow c with | Left c -> let (x, _) = recv c in@@ -22,19 +22,16 @@ send c (0 - x); () -let client =- fun c : int protocol channel ->- fun (x : int) (y : int) ->+let client c x y = let c = sel1 c in let c = send c x in let c = send c y in let (r, _) = recv c in r -let main =- fun (x : int) (y : int) ->- let rv = newRendezvous[int protocol] () in- AThread.fork (fun () -> server (accept rv));- client (request rv) x y+let main x y =+ let rv = newRendezvous () in+ AThread.fork (fun () -> server (accept rv));+ client (request rv) x y in print (main 3 4)
examples/ex36-session-types-type-error.alms view
@@ -6,35 +6,32 @@ open SessionType type 'a protocol = !'a; !'a; ?'a; 1- |+|+ |+| !'a; ?'a; 1 -let server =- fun c : int protocol dual channel ->+(* switched branches *)+let server (c : int protocol dual channel) = match follow c with- | Left c ->- let (x, c) = recv c in- send c (0 - x);- () | Right c -> let (x, c) = recv c in let (y, c) = recv c in send c (x + y); ()+ | Left c ->+ let (x, c) = recv c in+ send c (0 - x);+ () -let client =- fun c : int protocol channel ->- fun (x : int) (y : int) ->+let client c x y = let c = sel1 c in let c = send c x in let c = send c y in let (r, _) = recv c in r -let main =- fun (x : int) (y : int) ->- let rv = newRendezvous[int protocol] () in- AThread.fork (fun () -> server (accept rv));- client (request rv) x y+let main x y =+ let rv = newRendezvous () in+ AThread.fork (fun () -> server (accept rv));+ client (request rv) x y in print (main 3 4)
examples/ex37-session-types-type-error.alms view
@@ -6,11 +6,10 @@ open SessionType type 'a protocol = !'a; !'a; ?'a; 1- |+|+ |+| !'a; ?'a; 1 -let server =- fun c : int protocol dual channel ->+let server (c : int protocol dual channel) = match follow c with | Left c -> let (x, c) = recv c in@@ -22,19 +21,17 @@ send c (0 - x); () -let client =- fun c : int protocol channel ->- fun (x : int) (y : int) ->+(* sends string where int expected *)+let client c x y = let c = sel1 c in let c = send c (string_of_int x) in let c = send c y in let (r, _) = recv c in r -let main =- fun (x : int) (y : int) ->- let rv = newRendezvous[int protocol] () in- AThread.fork (fun () -> server (accept rv));- client (request rv) x y+let main x y =+ let rv = newRendezvous () in+ AThread.fork (fun () -> server (accept rv));+ client (request rv) x y in print (main 3 4)
examples/ex38-session-types-type-error.alms view
@@ -9,8 +9,7 @@ |+| !'a; ?'a; 1 -let server =- fun c : int protocol dual channel ->+let server (c : int protocol dual channel) = match follow c with | Left c -> let (x, c) = recv c in@@ -22,19 +21,17 @@ send c (0 - x); () -let client =- fun c : int protocol channel ->- fun (x : int) (y : int) ->+(* swaps receive and send *)+let client c x y = let c = sel1 c in let c = send c x in let (r, c) = recv c in let _ = send c y in r -let main =- fun (x : int) (y : int) ->- let rv = newRendezvous[int protocol] () in- AThread.fork (fun () -> server (accept rv));- client (request rv) x y+let main x y =+ let rv = newRendezvous () in+ AThread.fork (fun () -> server (accept rv));+ client (request rv) x y in print (main 3 4)
examples/ex50-signatures.alms view
@@ -1,4 +1,4 @@-(* Signature tests -- should print type error *)+(* Signature tests *) module type S = sig type t
examples/ex53-signatures.alms view
@@ -4,7 +4,7 @@ type `a t qualifier a end = struct type `a t = unit- let f[`b] (x: `b t) = (x, x)+ let f (x: `b t) = (x, x) end -let f['b] (x: 'b A.t) = (x, x)+let f (x: 'b A.t) = (x, x)
examples/ex54-signatures-type-error.alms view
@@ -4,7 +4,7 @@ type `a t qualifier a end = struct type `a t = unit- let f[`b] (x: `b t) = (x, x)+ let f (x: `b t) = (x, x) end -let f[`b] (x: `b A.t) = (x, x)+let f (x: unit aref A.t) = (x, x)
examples/ex55-signatures-type-error.alms view
@@ -1,7 +1,7 @@ (* Signature tests -- should print type error *) module A : sig- type `a t+ type `a t (* qualifier is U *) end = struct- type `a t = `a+ type `a t = `a (* qualifier is A *) end
examples/ex56-signatures-type-error.alms view
@@ -1,7 +1,7 @@ (* Signature tests -- should print type error *) module A : sig- type -`a t qualifier a+ type +`a t end = struct- type `a t = `a+ type `a t = `a → `a end
+ examples/ex58-signatures-type-error.alms view
@@ -0,0 +1,7 @@+(* Signature tests -- should print type error *)++module A : sig+ type -`a t qualifier a+end = struct+ type `a t = `a → unit+end
examples/ex61-popl-AfArray.alms view
@@ -38,14 +38,14 @@ module A = AfArray (* Swap the values at the given array indices *)-let swapIndices (a: 'a A.array) (i: int) (j: int) =+let swapIndices a i j = let (ai, a) = A.get a i in let (aj, a) = A.get a j in A.set (A.set a i aj) j ai (* Fisher-Yates shuffle *)-let inPlaceShuffle (a: 'a A.array) =- let rec loop (i: int) (a: 'a A.array) : 'a A.array =+let inPlaceShuffle a =+ let rec loop i a = if i == 0 then a else let j = random_int () % (i + 1) in@@ -54,12 +54,11 @@ loop (n - 1) a (* Quicksort *)-let inPlaceSort (a: int A.array) =- let rec quicksort (start: int) (limit: int) (a: int A.array) : int A.array =+let inPlaceSort a =+ let rec quicksort start limit a = if limit > start then let (pivot, a) = A.get a limit in- let rec loop (i: int) (j: int) (a: int A.array)- : int * int A.array =+ let rec loop i j a = if i < limit then let (ai, a) = A.get a i in if ai ≤ pivot@@ -75,27 +74,26 @@ quicksort 0 (n - 1) a (* For testing: *)-let listToArray (Cons(x,xs): 'a list) =+let listToArray (x ∷ xs) = let n = length xs + 1 in- let rec loop (i: int) (xs: 'a list) (a: 'a A.array) : 'a A.array =+ let rec loop i xs a = match xs with- | Nil → a- | Cons(x,xs) → loop (i + 1) xs (A.set a i x)+ | [] → a+ | x ∷ xs → loop (i + 1) xs (A.set a i x) in loop 1 xs (A.new n x) -let arrayToList (a: 'a A.array) =+let arrayToList a = let (n, a) = A.size a in- let rec loop (i: int) (xs: 'a list) (a: 'a A.array)- : 'a list * 'a A.array =+ let rec loop i xs a = if i < 0 then (xs, a) else let (ai, a) = A.get a i in- loop (i - 1) (Cons(ai, xs)) a- in loop (n - 1) Nil a+ loop (i - 1) (ai ∷ xs) a+ in loop (n - 1) [] a module Tests = struct- let unsorted = Cons(4,Cons(1,Cons(0,Cons(3,Cons(2,Nil)))))- let sorted = Cons(0,Cons(1,Cons(2,Cons(3,Cons(4,Nil)))))+ let unsorted = [4, 1, 0, 3, 2]+ let sorted = [0, 1, 2, 3, 4] let sorted' = fst(arrayToList(inPlaceSort(listToArray(unsorted)))) let () = if sorted == sorted' then ()
examples/ex63-popl-CapArray.alms view
@@ -19,7 +19,8 @@ type ('a,'b) array = 'a A.array type 'a cap = unit - let new (size: int) (init: 'a) = (A.new size init, ())+ let new (size: int) (init: 'a) : ∃'b. ('a,'b) array × 'b cap =+ (A.new size init, ()) let set (a: ('a,'b) array) (ix: int) (v: 'a) _ = A.set a ix v let get (a: ('a,'b) array) (ix: int) _ =@@ -64,33 +65,33 @@ (Future.sync f1, Future.sync f2) (* For testing: *)-let listToArray (Cons(x,xs): 'a list) =- let n = length xs + 1 in- let ('b, a, cap) = A.new n x in+let listToArray (x ∷ xs) =+ let n = length xs + 1 in+ let (a, cap) = A.new n x in let rec loop (i: int) (xs: 'a list) (cap: 'b A.cap) : 'b A.cap = match xs with- | Nil → cap- | Cons(x,xs) → loop (i + 1) xs (A.set a i x cap)- in Pack('b, a, loop 1 xs cap)+ | [] → cap+ | x ∷ xs → loop (i + 1) xs (A.set a i x cap)+ in (a, loop 1 xs cap) let dirtyArrayToList (a: ('a,'b) A.array) = let n = A.size a in let rec loop (i: int) (xs: 'a list) : 'a list = if i < 0 then xs- else loop (i - 1) (Cons(A.dirtyGet a i, xs))- in loop (n - 1) Nil+ else loop (i - 1) (A.dirtyGet a i ∷ xs)+ in loop (n - 1) [] let randomIntList = let rec loop (acc: int list) (len: int) : int list = if len == 0 then acc- else loop (Cons(random_int (), acc)) (len - 1)- in loop Nil+ else loop (random_int () ∷ acc) (len - 1)+ in loop [] module Tests = struct let test (size: int) =- let ('b, a, cap) = listToArray (randomIntList size) in+ let (a, cap) = listToArray (randomIntList size) in let correctsum = dirtySumArray a in let (_, dirtysum) = shuffleAndDirtySum a cap in if correctsum == dirtysum
examples/ex64-popl-CapLockArray.alms view
@@ -18,14 +18,14 @@ type ('a,'b) array = ('a,'b) CapArray.array × 'b cap MVar.mvar let new' (size: int) (init: 'a) =- let ('b, a, cap) = new size init in+ let (a, cap) = new size init in (a, MVar.new cap) let acquire (a: ('a,'b) array) = MVar.take (snd a) let release (a: ('a,'b) array) = MVar.put (snd a) let new (size: int) (init: 'a) =- let a = new' size init in (a, acquire a)+ let (a : ('a,'b) array) = new' size init in (a, acquire a) let set (a: ('a,'b) array) = set (fst a) let get (a: ('a,'b) array) = get (fst a)
examples/ex65-popl-Fractional.alms view
@@ -28,7 +28,8 @@ type 'c / 'd type ('b,'c) cap = unit - let new (size: int) (init: 'a) = (A.new size init, ())+ let new (size: int) (init: 'a) : ∃'b. ('a,'b) array × ('b,1) cap =+ (A.new size init, ()) let get (ar: 'a A.array) (ix: int) _ = (A.get ar ix, ()) let set (ar: 'a A.array) (ix: int) (new: 'a) _ =
examples/ex66-popl-RWLock.alms view
@@ -45,9 +45,9 @@ type write type 'β@'γ = unit - let new (size: int) (init: 'α) =+ let new (size: int) (init: 'α) : ∃'β. ('α, 'β) array = (A.new size init, MVar.new ((Queue.empty : queue), 0))- let build (size: int) (builder: int → 'α) =+ let build (size: int) (builder: int → 'α) : ∃'β. ('α, 'β) array = (A.build size builder, MVar.new ((Queue.empty : queue), 0)) (* To see what's happening, uncomment the rest of show. *)@@ -95,7 +95,7 @@ let acquireR ((rep, lock) : ('α,'t) array) = let (q, count) = MVar.take lock in show "acquireR" (q, count);- let wait = MVar.newEmpty[unit] () in+ let wait = MVar.newEmpty () in MVar.put lock (Queue.enqueue (Left wait) q, count); wake lock; MVar.take wait@@ -104,7 +104,7 @@ let acquireW ((rep, lock) : ('α,'β) array) = let (q, count) = MVar.take lock in show "acquireW" (q, count);- let wait = MVar.newEmpty[unit] () in+ let wait = MVar.newEmpty () in MVar.put lock (Queue.enqueue (Right wait) q, count); wake lock; MVar.take wait@@ -179,18 +179,18 @@ else ()) let go (iters: int) =- let next = makeCounter () in- let ('β,a) = build 10 (fun x:int → x) in- let rec start (n: int) : U Future.future list =+ let next = makeCounter () in+ let a = build 10 (fun x → x) in+ let rec start (n: int) = if n < 1- then Nil[any]- else Cons (if random_int () % 8 == 0- then writer (next ()) a- else reader (next ()) a,- start (n - 1)) in- let rec stop (fs: U Future.future list) : unit =+ then []+ else (if random_int () % 8 == 0+ then writer (next ()) a+ else reader (next ()) a)+ ∷ start (n - 1) in+ let rec stop fs = match fs with- | Nil → ()- | Cons(f, fs) → Future.sync f; stop fs in+ | [] → ()+ | f ∷ fs → Future.sync f; stop fs in stop (start iters) end
examples/futures1.alms view
@@ -2,26 +2,22 @@ #load "libthread" -let prompt : unit -> string Future.future =- fun _:unit -> Future.new getLine+let prompt () = Future.new getLine -let printDots : int -> int -> unit =- let rec loop (count : int) (delay : int) : unit =- if count <= 0- then ()- else- putStr ".";- flush ();- AThread.delay (1000 * delay);- loop (count - 1) delay- in loop+let rec printDots count delay =+ if count <= 0+ then ()+ else+ putStr ".";+ flush ();+ AThread.delay (1000 * delay);+ printDots (count - 1) delay -let main : string -> unit =- fun message: string ->- putStrLn message;- let future = prompt () in- printDots 80 20;- putStrLn "";- putStrLn (Future.sync future)+let main message =+ putStrLn message;+ let future = prompt () in+ printDots 80 20;+ putStrLn "";+ putStrLn (Future.sync future) in main "whadday say? "
examples/netcat.alms view
@@ -5,7 +5,7 @@ local open IO with- let rec sendThread (sock: socket): unit =+ let rec sendThread sock = if hIsEOF stdin then shutdown sock ShutdownSend@@ -14,39 +14,37 @@ send sock (getLine () ^ "\r\n"); sendThread sock with- IOError _ -> ()+ IOError _ → () - let rec recvThread (sock: socket): unit =+ let rec recvThread sock = try- putStr (recv sock 1024); recvThread sock+ putStr (recv sock 1024);+ recvThread sock with- IOError _ -> ()+ IOError _ → () end -let setupConnection (addr: sockAddr): socket =+let setupConnection addr = let s = socket AF_INET Stream defaultProtocol in connect s addr; s -let teardownConnection (sock: socket): unit =- close sock--let getAddr (): sockAddr =+let getAddr () = match getArgs () with- | Cons(host, Cons(port, Nil))- -> let info = AddrInfo(Nil[addrInfoFlag], AF_INET,- Stream, defaultProtocol,- SockAddrInet(PortNum 0, 0), None[string]) in- (match getAddrInfo (Some info) (Some host) (Some port) with- | Cons (AddrInfo (_, _, _, _, sockAddr, _), _) -> sockAddr- | _ -> failwith ("Could not resolve address "^host^":"^port))- | _ -> failwith ("Usage: " ^ getProgName () ^ " HOST SERVICE")+ | [host, port]+ → let info = AddrInfo([], AF_INET,+ Stream, defaultProtocol,+ SockAddrInet(PortNum 0, 0), None) in+ (match getAddrInfo (Some info) (Some host) (Some port) with+ | AddrInfo (_, _, _, _, sockAddr, _) ∷ _ → sockAddr+ | _ → failwith ("Could not resolve address "^host^":"^port))+ | _ → failwith ("Usage: " ^ getProgName () ^ " HOST SERVICE") let main () = let sock = setupConnection (getAddr ()) in- let wait = Future.new (fun () -> recvThread sock) in+ let wait = Future.new (λ () → recvThread sock) in sendThread sock; Future.sync wait;- teardownConnection sock+ close sock in main ()
examples/session-types-interactive.alms view
@@ -10,20 +10,18 @@ type protocol = ?int; 1 |+| !int; protocol let server =- let rec loop (acc : int)- (c : protocol dual channel)- : unit =+ let rec loop acc (c : protocol dual channel) = match follow c with- | Left c ->+ | Left c → send c acc; ()- | Right c ->+ | Right c → let (x, c) = recv c in loop (acc + x) c in loop 0 let client =- let rec loop (c : protocol channel) : int =+ let rec loop (c : protocol channel) = let s = getLine () in if s == "" then@@ -36,11 +34,10 @@ loop c in loop -let main =- fun _ : unit ->- let rv = newRendezvous[protocol] () in- AThread.fork (fun _:unit -> server (accept rv));- client (request rv)+let main () =+ let rv : protocol rendezvous = newRendezvous () in+ AThread.fork (λ () -> server (accept rv));+ client (request rv) in print (main ())
examples/session-types-polygons.alms view
@@ -5,43 +5,41 @@ open SessionType -let putAny 'a (x: 'a) = putStr (string_of x)- -- -- We first build a tiny 3-D geometry library -- -- Points and planes in R^3.-type point = Point of float * float * float-type plane = Plane of float * float * float * float+type point = { x, y, z : float }+type plane = [ `Plane of float * float * float * float ] --- We use the plane Plane(a, b, c, d) to represent the open half-space+-- We use the plane `Plane(a, b, c, d) to represent the open half-space -- { Point(x, y, z) | ax + by + cz + d > 0 } -let string_of_point (Point(x, y, z): point) =- "(" ^ string_of x ^ ", " ^ string_of y ^ ", " ^ string_of z ^ ")"+let string_of_point p =+ "(" ^ string_of p.x ^ ", " ^ string_of p.y ^ ", " ^ string_of p.z ^ ")" -let string_of_plane (Plane(a, b, c, d): plane) =+let string_of_plane (`Plane(a, b, c, d): plane) = string_of a ^ "x + " ^ string_of b ^ "y + " ^ string_of c ^ "z + " ^ string_of d ^ " > 0" (* Some of this should be in the library! *)-let splitWhile['a] : ('a -> bool) -> 'a list -> 'a list * 'a list- = fun pred: ('a -> bool) ->+let splitWhile : ('a -> bool) -> 'a list -> 'a list * 'a list+ = fun pred -> let rec loop (acc: 'a list) (xs: 'a list) : 'a list * 'a list = match xs with- | Nil -> (rev acc, Nil['a])- | Cons(x,xs') -> if pred x- then loop (Cons(x,acc)) xs'+ | [] -> (rev acc, [])+ | (x ∷ xs') -> if pred x+ then loop (x ∷ acc) xs' else (rev acc, xs)- in loop Nil['a]+ in loop [] let not (b: bool) = if b then false else true -let notp['a] (pred: 'a -> bool): 'a -> bool =- fun a: 'a -> not (pred a)+let notp (pred: 'a -> bool): 'a -> bool =+ fun a -> not (pred a) -let isSpace (c: int): bool =+let isSpace (c: char): bool = match c with | ' ' -> true | '\t' -> true@@ -49,65 +47,48 @@ | '\r' -> true | _ -> false -let dropSpace (cs : int list) : int list =+let dropSpace (cs : char list) : char list = let (_, result) = splitWhile isSpace cs in result let parsePoint (s : string) : point =- let foil (x: int list) = float_of_string (implode x) in+ let foil (x: char list) = float_of_string (implode x) in let cs = explode s in- let Cons('(', cs) = dropSpace cs in- let (x, Cons(_,cs)) = splitWhile (notp ((==) ',')) (dropSpace cs) in- let (y, Cons(_,cs)) = splitWhile (notp ((==) ',')) (dropSpace cs) in- let (z, Cons(_,cs)) = splitWhile (notp ((==) ')')) (dropSpace cs) in- Point (foil x, foil y, foil z)+ let ('(' ∷ cs) = dropSpace cs in+ let (x, (_ ∷ cs)) = splitWhile (notp ((==) ',')) (dropSpace cs) in+ let (y, (_ ∷ cs)) = splitWhile (notp ((==) ',')) (dropSpace cs) in+ let (z, (_ ∷ cs)) = splitWhile (notp ((==) ')')) (dropSpace cs) in+ { x = foil x, y = foil y, z = foil z } let parsePlane (s: string) : plane =- let foil (x: int list) = float_of_string (implode x) in+ let foil (x: char list) = float_of_string (implode x) in let cs = explode s in- let (a, Cons(_,cs)) = splitWhile (notp ((==) 'x')) (dropSpace cs) in- let Cons('+',cs) = dropSpace cs in- let (b, Cons(_,cs)) = splitWhile (notp ((==) 'y')) (dropSpace cs) in- let Cons('+',cs) = dropSpace cs in- let (c, Cons(_,cs)) = splitWhile (notp ((==) 'z')) (dropSpace cs) in- let Cons('+',cs) = dropSpace cs in- let (d, Cons(_,cs)) = splitWhile (notp ((==) '>')) (dropSpace cs) in- let Cons('0',cs) = dropSpace cs in- Plane (foil a, foil b, foil c, foil d)+ let (a, (_ ∷ cs)) = splitWhile (notp ((==) 'x')) (dropSpace cs) in+ let ('+' ∷ cs) = dropSpace cs in+ let (b, (_ ∷ cs)) = splitWhile (notp ((==) 'y')) (dropSpace cs) in+ let ('+' ∷ cs) = dropSpace cs in+ let (c, (_ ∷ cs)) = splitWhile (notp ((==) 'z')) (dropSpace cs) in+ let ('+' ∷ cs) = dropSpace cs in+ let (d, (_ ∷ cs)) = splitWhile (notp ((==) '>')) (dropSpace cs) in+ let ('0' ∷ cs) = dropSpace cs in+ `Plane (foil a, foil b, foil c, foil d) -- Is the point above the plane? (i.e., in the semi-space)-let isPointAbovePlane (Point(x, y, z): point)- (Plane(a, b, c, d): plane): bool =+let isPointAbovePlane { x, y, z } (`Plane(a, b, c, d)) = a *. x +. b *. y +. c *. z +. d >. 0.0 -- Does the line segment between the two points intersect the plane, -- and if so, where?-let intersect (Point(x1, y1, z1) as p1 : point)- (Point(x2, y2, z2) as p2 : point)- (Plane(a, b, c, d) as plane : plane): point option =+let intersect p1 p2 (`Plane(a, b, c, d) as plane) = if isPointAbovePlane p1 plane == isPointAbovePlane p2 plane- then None[point]- else let t = (a *. x1 +. b *. y1 +. c *. z1 +. d) /.- (a *. (x1 -. x2) +.- b *. (y1 -. y2) +.- c *. (z1 -. z2)) in- let x = x1 +. (x2 -. x1) *. t in- let y = y1 +. (y2 -. y1) *. t in- let z = z1 +. (z2 -. z1) *. t in- Some (Point (x, y, z))------- When we implement the algorithm in A, we will treat points--- and planes as opaque objects, so there's no need to marshal them,--- but we do need to marshal options for the result of intersect.--- The standard way to do this is to write an elimination function--- in the "from" sublanguage and then call the elimination function--- with "to" constructors in the "to" sublanguage:-----let maybeC['a,'r] (some: 'a -> 'r) (none: 'r) (opt: 'a option): 'r =- match opt with- | Some a -> some a- | None -> none+ then None+ else let t = (a *. p1.x +. b *. p1.y +. c *. p1.z +. d) /.+ (a *. (p1.x -. p2.x) +.+ b *. (p1.y -. p2.y) +.+ c *. (p1.z -. p2.z)) in+ let x = p1.x +. (p2.x -. p1.x) *. t in+ let y = p1.y +. (p2.y -. p1.y) *. t in+ let z = p1.z +. (p2.z -. p1.z) *. t in+ Some { x, y, z } -- -- In sublanguage A, our protocol is to send an unbounded@@ -123,7 +104,7 @@ -- let clipper (plane: plane)- (ic: point stream channel)|+ (ic: point stream channel) (oc: point stream dual channel): unit = let finish (oc: point stream dual channel) = sel1 oc; () in@@ -143,7 +124,7 @@ | Left _ -> finish oc | Right ic -> let (pt0, ic) = recv ic in- let rec loop (ic: point stream channel)|+ let rec loop (ic: point stream channel) (oc: point stream dual channel) (pt: point) : unit = let oc = putVisible oc pt in@@ -189,21 +170,21 @@ match follow ic with | Left ic -> (rev acc, ic) | Right ic -> let (plane, ic) = recv ic in- get_planes (Cons(plane,acc)) ic in+ get_planes (plane ∷ acc) ic in let rec connect (planes: plane list) (ic: point stream channel) : point stream channel = match planes with- | Nil -> ic- | Cons(plane,rest) ->- let outrv = newRendezvous[point stream] () in+ | [] -> ic+ | plane ∷ rest ->+ let outrv : point stream rendezvous = newRendezvous () in AThread.fork (fun () -> clipper plane ic (accept outrv)); connect rest (request outrv) in fun () ->- let rv = newRendezvous[main_prot] () in+ let rv = newRendezvous () : main_prot rendezvous in let _ = AThread.fork (fun () -> parser (accept rv)) in- let (planes, ic) = get_planes Nil[plane] (request rv) in+ let (planes, ic) = get_planes [] (request rv) in let ic = connect planes ic in printer ic
examples/session-types-polygons2.alms view
@@ -5,9 +5,6 @@ open SessionType --- Some basic, low-level stuff-let putAny 'a (x: 'a) = putStr (string_of x)- -- -- We first build a 3-D geometry library in sublanguage C: --@@ -19,26 +16,26 @@ -- We use the plane Plane(a, b, c, d) to represent the open half-space -- { Point(x, y, z) | ax + by + cz + d > 0 } -let string_of_point (Point(x, y, z): point) =+let string_of_point (Point(x, y, z)) = "(" ^ string_of x ^ ", " ^ string_of y ^ ", " ^ string_of z ^ ")" -let string_of_plane (Plane(a, b, c, d): plane) =+let string_of_plane (Plane(a, b, c, d)) = string_of a ^ "x + " ^ string_of b ^ "y + " ^ string_of c ^ "z + " ^ string_of d ^ " > 0" -let splitWhile['a] : ('a -> bool) -> 'a list -> 'a list * 'a list- = fun pred: ('a -> bool) ->+let splitWhile : ('a -> bool) -> 'a list -> 'a list * 'a list+ = fun pred -> let rec loop (acc: 'a list) (xs: 'a list) : 'a list * 'a list = match xs with- | Nil -> (rev acc, Nil['a])- | Cons(x,xs') -> if pred x- then loop (Cons(x,acc)) xs'- else (rev acc, xs)- in loop Nil['a]+ | [] -> (rev acc, [])+ | x ∷ xs' -> if pred x+ then loop (x ∷ acc) xs'+ else (rev acc, xs)+ in loop [] -let notp['a] (pred: 'a -> bool) (x: 'a) = not (pred x)+let notp (pred: 'a -> bool) (x: 'a) = not (pred x) -let isSpace (c: int): bool =+let isSpace c = match c with | ' ' -> true | '\t' -> true@@ -46,29 +43,28 @@ | '\r' -> true | _ -> false -let dropSpace (cs : int list) : int list =- let (_, result) = splitWhile isSpace cs in result+let dropSpace cs = snd (splitWhile isSpace cs) let parsePoint (s : string) : point =- let foil (x: int list) = float_of_string (implode x) in+ let foil (x: char list) = float_of_string (implode x) in let cs = explode s in- let Cons('(', cs) = dropSpace cs in- let (x, Cons(_,cs)) = splitWhile (notp ((==) ',')) (dropSpace cs) in- let (y, Cons(_,cs)) = splitWhile (notp ((==) ',')) (dropSpace cs) in- let (z, Cons(_,cs)) = splitWhile (notp ((==) ')')) (dropSpace cs) in+ let '(' ∷ cs = dropSpace cs in+ let (x, _ ∷ cs) = splitWhile (notp ((==) ',')) (dropSpace cs) in+ let (y, _ ∷ cs) = splitWhile (notp ((==) ',')) (dropSpace cs) in+ let (z, _ ∷ cs) = splitWhile (notp ((==) ')')) (dropSpace cs) in Point (foil x, foil y, foil z) let parsePlane (s: string) : plane =- let foil (x: int list) = float_of_string (implode x) in+ let foil (x: char list) = float_of_string (implode x) in let cs = explode s in- let (a, Cons(_,cs)) = splitWhile (notp ((==) 'x')) (dropSpace cs) in- let Cons('+',cs) = dropSpace cs in- let (b, Cons(_,cs)) = splitWhile (notp ((==) 'y')) (dropSpace cs) in- let Cons('+',cs) = dropSpace cs in- let (c, Cons(_,cs)) = splitWhile (notp ((==) 'z')) (dropSpace cs) in- let Cons('+',cs) = dropSpace cs in- let (d, Cons(_,cs)) = splitWhile (notp ((==) '>')) (dropSpace cs) in- let Cons('0',cs) = dropSpace cs in+ let (a, _ ∷ cs) = splitWhile (notp ((==) 'x')) (dropSpace cs) in+ let '+' ∷ cs = dropSpace cs in+ let (b, _ ∷ cs) = splitWhile (notp ((==) 'y')) (dropSpace cs) in+ let '+' ∷ cs = dropSpace cs in+ let (c, _ ∷ cs) = splitWhile (notp ((==) 'z')) (dropSpace cs) in+ let '+' ∷ cs = dropSpace cs in+ let (d, _ ∷ cs) = splitWhile (notp ((==) '>')) (dropSpace cs) in+ let '0' ∷ cs = dropSpace cs in Plane (foil a, foil b, foil c, foil d) -- Is the point above the plane? (i.e., in the semi-space)@@ -79,10 +75,10 @@ -- Does the line segment between the two points intersect the plane, -- and if so, where? let intersect (Point(x1, y1, z1) as p1 : point)- (Point(x2, y2, z2) as p2 : point)- (Plane(a, b, c, d) as plane : plane): point option =+ (Point(x2, y2, z2) as p2 : point)+ (Plane(a, b, c, d) as plane : plane): point option = if isPointAbovePlane p1 plane == isPointAbovePlane p2 plane- then None[point]+ then None else let t = (a *. x1 +. b *. y1 +. c *. z1 +. d) /. (a *. (x1 -. x2) +. b *. (y1 -. y2) +.@@ -93,20 +89,6 @@ Some (Point (x, y, z)) ----- When we implement the algorithm in A, we will treat points--- and planes as opaque objects, so there's no need to marshal them,--- but we do need to marshal options for the result of intersect.--- The standard way to do this is to write an elimination function--- in the "from" sublanguage and then call the elimination function--- with "to" constructors in the "to" sublanguage:-----let maybeC['a,'r] (some: 'a -> 'r) (none: 'r) (opt: 'a option): 'r =- match opt with- | Some a -> some a- | None -> none---- -- In sublanguage A, our protocol is to send an unbounded -- sequence of points: --@@ -121,44 +103,38 @@ -- which it will send points. -- -let clipper (plane: plane)- !(ic: point stream channel, oc: point stream dual channel)- : unit * (1 channel * 1 channel) =- let finish !(oc: point stream dual channel) =- choose Done[point] oc in- let put (pt: point) !(oc: point stream dual channel) =- choose Next[point] oc;- send pt oc in- let putCross (p1: point) (p2: point)- !(oc: point stream dual channel) =- match intersect p1 p2 plane with- | Some pt -> put pt oc- | None -> () in- let putVisible (pt: point)- !(oc: point stream dual channel) =- if isPointAbovePlane pt plane- then put pt oc- else () in- follow ic;- match ic with- | Done ic -> finish oc- | Next ic ->- let pt0 = recv ic in- let rec loop (pt: point)- !(ic: point stream channel,- oc: point stream dual channel)- : unit * (1 channel * 1 channel) =- putVisible pt oc;- follow ic;- match ic with- | Done ic -> putCross pt pt0 oc;- finish oc- | Next ic -> let pt' = recv ic in- putCross pt pt' oc;- loop pt' (ic, oc)- in loop pt0 (ic, oc)+let clipper plane+ !(ic: point stream channel, oc: point stream dual channel) =+ let finish () =+ choose Done oc in+ let put pt =+ choose Next oc;+ send pt oc in+ let putCross p1 p2 =+ match intersect p1 p2 plane with+ | Some pt -> put pt+ | None -> () in+ let putVisible pt =+ if isPointAbovePlane pt plane+ then put pt+ else ()+ in follow ic;+ match ic with+ | Done ic -> finish ()+ | Next ic ->+ let pt0 = recv ic in+ let rec loop pt =+ putVisible pt;+ follow ic;+ match ic with+ | Done ic -> putCross pt pt0;+ finish ()+ | Next ic -> let pt' = recv ic in+ putCross pt pt';+ loop pt'+ in loop pt0 -let rec printer !(ic: point stream channel): unit * 1 channel =+let rec printer !(ic: point stream channel) = follow ic; match ic with | Done ic -> ()@@ -171,43 +147,42 @@ and main2 = Planes of (?plane; main_prot) channel | Points of point stream channel -let parser : main_prot dual channel -> unit * 1 channel =- let rec plane_loop !(oc: main_prot dual channel): unit * 1 channel =+let parser (!oc: main_prot dual channel) =+ let rec plane_loop () = match getLine () with | "" -> choose Points oc;- point_loop oc+ point_loop () | s -> choose Planes oc; send (parsePlane s) oc;- plane_loop oc- and point_loop !(oc: point stream dual channel): unit * 1 channel =+ plane_loop ()+ and point_loop () = match getLine () with- | "" -> choose Done[point] oc- | s -> choose Next[point] oc;+ | "" -> choose Done oc+ | s -> choose Next oc; send (parsePoint s) oc;- point_loop oc- in plane_loop+ point_loop ()+ in plane_loop () let main =- let rec get_planes (acc: plane list) !(ic: main_prot channel)- : plane list * point stream channel =+ let rec get_planes (acc: plane list) !(ic: main_prot channel) = follow ic; match ic with | Points ic -> rev acc- | Planes ic -> get_planes (Cons(recv ic,acc)) ic in+ | Planes ic -> get_planes (recv ic ∷ acc) ic in let rec connect (planes: plane list) (ic: point stream channel) : point stream channel = match planes with- | Nil -> ic- | Cons(plane,rest) ->- let outrv = newRendezvous[point stream] () in+ | [] -> ic+ | plane ∷ rest ->+ let outrv = newRendezvous () in AThread.fork (fun () -> clipper plane (ic, accept outrv); ()); connect rest (request outrv) in fun () ->- let rv = newRendezvous[main_prot] () in+ let rv = newRendezvous () in let _ = AThread.fork (fun () -> parser (accept rv); ()) in- let (planes, ic) = get_planes Nil[plane] (request rv) in+ let (planes, ic) = get_planes [] (request rv) in let ic = connect planes ic in printer ic
examples/skewness-dynamic-bad.alms view
@@ -1,4 +1,4 @@-(* Demonstrates (affine) abstract types. Correct. *)+(* Demonstrates (affine) abstract types. Blame error. *) (* This program demonstrats how a dynamic promotion is prevented from@@ -12,104 +12,101 @@ open AArray module SkewnessExample = struct- let sum ['t,'c] (a: (float, 't) array) (c: ('t, 'c) readcap) =+ let sum (a: (float, 't) array) (c: ('t, 'c) readcap) = fold (+.) 0.0 a c-- let mean ['t, 'c] (a: (float, 't) array) (c: ('t, 'c) readcap) =+ + let mean (a: (float, 't) array) (c: ('t, 'c) readcap) = let (total, c) = sum a c in (total /. float_of_int (size a), c)-- let stdDev ['t, 'c] (a: (float, 't) array) (c: ('t, 'c) readcap) =+ + let stdDev (a: (float, 't) array) (c: ('t, 'c) readcap) = let (mean, c) = mean a c in let (num, c) = fold (fun (x: float) (acc: float) -> acc +. (x -. mean) ** 2.0) 0.0 a c in (sqrt (num /. float_of_int (size a)), c)-- let skewness ['t, 'c] (a: (float, 't) array) (c: ('t, 'c) readcap) =+ + let skewness (a: (float, 't) array) (c: ('t, 'c) readcap) = let n = float_of_int (size a) in let (m, c) = mean a c in let (s, c) = stdDev a c in let (devs, c) = fold (fun (x: float) (acc: float) ->- (x -. m) ** 3.0 +. acc)+ (x -. m) ** 3.0 +. acc) 0.0 a c in (devs /. ((n -. 1.0) *. s ** 3.0), c)-+ type transformation = T of string * (float -> float)-- let reduceSkewness ['t]- (ts: transformation list)- (a: (float, 't) array)- (c0: 't writecap) =- let get_c0 = (fun () -> c0 :> unit -> 't writecap) in+ + let reduceSkewness (ts: transformation list)+ (a: (float, 't) array)+ (c0: 't writecap) =+ let get_c0 = (fun () -> c0) :> unit -> 't writecap in let rec replace (i: int) (T(_, ft) as t: transformation) (c: 't writecap) : 't writecap = if i < size a- then let (x, c) = at a i c in- let c = update a i (ft x) c in+ then let (x, c) = get a i c in+ let c = set a i (ft x) c in replace (i + 1) t c else c in- let rec find ['c] (ix: int)- (ts: transformation list)- (c: ('t, 'c) readcap)- : float * transformation * ('t, 'c) readcap =- match ts with- | Nil -> let (sk, c) = skewness a c in- (sk, T("identity", fun f: float -> f), c)- | Cons(T(_, ft) as t, ts)- -> let ((sk1, t1), (sk2, t2), c) =- par- (fun 'c (c: ('t, 'c) readcap) -> find['c] (ix + 1) ts c)- (fun 'c (c: ('t, 'c) readcap) ->- let (Pack('s, b, d), c) = map ft a c in+ (* Need type annotation for polymorphic recursion: *)+ let rec find :+ ∀ 'd. int → transformation list → ('t, 'd) readcap →+ float * transformation * ('t, 'd) readcap =+ λ ix ts c →+ match ts with+ | [] -> let (sk, c) = skewness a c in+ (sk, T("identity", fun f -> f), c)+ | (T(_, ft) as t) ∷ ts+ -> let ((sk1, t1), (sk2, t2), c) =+ par+ (fun (c: ('t, 'c) readcap) -> find (ix + 1) ts c)+ (fun (c: ('t, 'c) readcap) ->+ let ((b, d), c) = map ft a c in let (sk, d) = skewness b d in (sk, t, c))- c- in if absf sk2 <. absf sk1- then (replace 0 t1 (get_c0 ()); (sk2, t2, c))- else (sk1, t1, c) in+ c+ in if absf sk2 <. absf sk1+ then (replace 0 t1 (get_c0 ()); (sk2, t2, c))+ else (sk1, t1, c) in let (sk, t, c) = find 0 ts (get_c0 ()) in (sk, t, replace 0 t c)-- let newDistribution- (n: int) (T(_, gen): transformation)- : ex 't. (float, 't) array * 't writecap =- let Pack('t, a, c) = new[float] n in- let rec loop (i: int) (c: 't writecap): 't writecap =+ + let newDistribution (n: int) (T(_, gen): transformation)+ : ex 't. (float, 't) array * 't writecap =+ let (a, c) = new n 0.0 in+ let rec loop (i: int) c = if i < n- then loop (i + 1) (update a i (gen (float_of_int (i + 1))) c)+ then loop (i + 1) (set a i (gen (float_of_int (i + 1))) c) else c in- Pack[ex 't. (float, 't) array * 't writecap]('t, a, loop 0 c)-- let (^:) 'a (t: 'a) (ts: 'a list) = Cons(t, ts)-+ (a, loop 0 c)+ let functions (n: int) =- T("1", fun (ix: float) -> 1.0) ^:- T("x", fun (ix: float) -> ix) ^:- T("x^2", flip ( ** ) 2.0) ^:- T("sqrt x", sqrt) ^:- T("x^5", flip ( ** ) 5.0) ^:- T("x^1/5", flip ( ** ) 0.2) ^:- T("e^x", ( ** ) 2.718) ^:- T("log x", log) ^:- T("1/x", (/.) 1.0) ^:- T("-x", (-.) (float_of_int n)) ^:- Nil-+ [T("1", fun (ix: float) -> 1.0)+ ,T("x", fun (ix: float) -> ix)+ ,T("x^2", flip ( ** ) 2.0)+ ,T("sqrt x", sqrt)+ ,T("x^5", flip ( ** ) 5.0)+ ,T("x^1/5", flip ( ** ) 0.2)+ ,T("e^x", ( ** ) 2.718)+ ,T("log x", log)+ ,T("1/x", (/.) 1.0)+ ,T("-x", (-.) (float_of_int n))+ ]+ let testCase (n: int) (T(name, _) as t: transformation) =- let Pack('t, a, c) = newDistribution n t in- let (sk0, c) = skewness a c in+ let (a, c) = newDistribution n t in+ let (sk0, c) = skewness a c in let (sk, T(name', _), c) = reduceSkewness (functions n) a c in putStrLn ("Distribution: " ^ name); putStrLn ("Original skewness: " ^ string_of sk0); putStrLn ("Improved skewness: " ^ string_of sk); putStrLn ("Winning function: " ^ name'); putStrLn ""-+ let tests (n: int) = foldl (fun (t: transformation) () -> testCase n t) () (functions n)
examples/skewness-good.alms view
@@ -13,14 +13,14 @@ open AArray module SkewnessExample = struct- let sum ['t,'c] (a: (float, 't) array) (c: ('t, 'c) readcap) =+ let sum (a: (float, 't) array) (c: ('t, 'c) readcap) = fold (+.) 0.0 a c - let mean ['t, 'c] (a: (float, 't) array) (c: ('t, 'c) readcap) =+ let mean (a: (float, 't) array) (c: ('t, 'c) readcap) = let (total, c) = sum a c in (total /. float_of_int (size a), c) - let stdDev ['t, 'c] (a: (float, 't) array) (c: ('t, 'c) readcap) =+ let stdDev (a: (float, 't) array) (c: ('t, 'c) readcap) = let (mean, c) = mean a c in let (num, c) = fold (fun (x: float) (acc: float) ->@@ -28,7 +28,7 @@ 0.0 a c in (sqrt (num /. float_of_int (size a)), c) - let skewness ['t, 'c] (a: (float, 't) array) (c: ('t, 'c) readcap) =+ let skewness (a: (float, 't) array) (c: ('t, 'c) readcap) = let n = float_of_int (size a) in let (m, c) = mean a c in let (s, c) = stdDev a c in@@ -40,67 +40,65 @@ type transformation = T of string * (float -> float) - let reduceSkewness ['t]- (ts: transformation list)- (a: (float, 't) array)- (c0: 't writecap) =+ let reduceSkewness (ts: transformation list)+ (a: (float, 't) array)+ (c0: 't writecap) = let rec replace (i: int) (T(_, ft) as t: transformation) (c: 't writecap) : 't writecap = if i < size a- then let (x, c) = at a i c in- let c = update a i (ft x) c in+ then let (x, c) = get a i c in+ let c = set a i (ft x) c in replace (i + 1) t c else c in- let rec find ['c] (ix: int)- (ts: transformation list)- (c: ('t, 'c) readcap)- : float * transformation * ('t, 'c) readcap =- match ts with- | Nil -> let (sk, c) = skewness a c in- (sk, T("identity", fun f: float -> f), c)- | Cons(T(_, ft) as t, ts)- -> let ((sk1, t1), (sk2, t2), c) =- par- (fun 'c (c: ('t, 'c) readcap) -> find['c] (ix + 1) ts c)- (fun 'c (c: ('t, 'c) readcap) ->- let (Pack('s, b, d), c) = map ft a c in- let (sk, d) = skewness b d in- (sk, t, c))- c- in if absf sk2 <. absf sk1- then (sk2, t2, c)- else (sk1, t1, c) in+ (* Need type annotation for polymorphic recursion: *)+ let rec find :+ ∀ 'd. int → transformation list → ('t, 'd) readcap →+ float * transformation * ('t, 'd) readcap =+ λ ix ts c →+ match ts with+ | [] -> let (sk, c) = skewness a c in+ (sk, T("identity", fun f -> f), c)+ | (T(_, ft) as t) ∷ ts+ -> let ((sk1, t1), (sk2, t2), c) =+ par+ (fun (c: ('t, 'c) readcap) -> find (ix + 1) ts c)+ (fun (c: ('t, 'c) readcap) ->+ let ((b, d), c) = map ft a c in+ let (sk, d) = skewness b d in+ (sk, t, c))+ c+ in if absf sk2 <. absf sk1+ then (sk2, t2, c)+ else (sk1, t1, c) in let (sk, t, c) = find 0 ts c0 in (sk, t, replace 0 t c) let newDistribution (n: int) (T(_, gen): transformation) : ex 't. (float, 't) array * 't writecap =- let Pack('t, a, c) = new[float] n in- let rec loop (i: int) (c: 't writecap): 't writecap =+ let (a, c) = new n 0.0 in+ let rec loop (i: int) c = if i < n- then loop (i + 1) (update a i (gen (float_of_int (i + 1))) c)+ then loop (i + 1) (set a i (gen (float_of_int (i + 1))) c) else c in- Pack[ex 't. (float, 't) array * 't writecap]('t, a, loop 0 c)- - let (^:) `a (t: `a) (ts: `a list) = Cons(t, ts)+ (a, loop 0 c) let functions (n: int) =- T("1", fun (ix: float) -> 1.0) ^:- T("x", fun (ix: float) -> ix) ^:- T("x^2", flip ( ** ) 2.0) ^:- T("sqrt x", sqrt) ^:- T("x^5", flip ( ** ) 5.0) ^:- T("x^1/5", flip ( ** ) 0.2) ^:- T("e^x", ( ** ) 2.718) ^:- T("log x", log) ^:- T("1/x", (/.) 1.0) ^:- T("-x", (-.) (float_of_int n)) ^:- Nil+ [T("1", fun (ix: float) -> 1.0)+ ,T("x", fun (ix: float) -> ix)+ ,T("x^2", flip ( ** ) 2.0)+ ,T("sqrt x", sqrt)+ ,T("x^5", flip ( ** ) 5.0)+ ,T("x^1/5", flip ( ** ) 0.2)+ ,T("e^x", ( ** ) 2.718)+ ,T("log x", log)+ ,T("1/x", (/.) 1.0)+ ,T("-x", (-.) (float_of_int n))+ ] let testCase (n: int) (T(name, _) as t: transformation) =- let Pack('t, a, c) = newDistribution n t in+ let (a, c) = newDistribution n t in let (sk0, c) = skewness a c in let (sk, T(name', _), c) = reduceSkewness (functions n) a c in putStrLn ("Distribution: " ^ name);
examples/skewness-static-bad.alms view
@@ -10,21 +10,22 @@ open AArray module SkewnessExample = struct- let sum ['t,'c] (a: (float, 't) array) (c: ('t, 'c) readcap) =+ let sum (a: (float, 't) array) (c: ('t, 'c) readcap) = fold (+.) 0.0 a c - let mean ['t, 'c] (a: (float, 't) array) (c: ('t, 'c) readcap) =+ let mean (a: (float, 't) array) (c: ('t, 'c) readcap) = let (total, c) = sum a c in (total /. float_of_int (size a), c) - let stdDev ['t, 'c] (a: (float, 't) array) (c: ('t, 'c) readcap) =+ let stdDev (a: (float, 't) array) (c: ('t, 'c) readcap) = let (mean, c) = mean a c in let (num, c) = fold- (fun (x: float) (acc: float) -> (x -. mean) ** 2.0)+ (fun (x: float) (acc: float) ->+ acc +. (x -. mean) ** 2.0) 0.0 a c in (sqrt (num /. float_of_int (size a)), c) - let skewness ['t, 'c] (a: (float, 't) array) (c: ('t, 'c) readcap) =+ let skewness (a: (float, 't) array) (c: ('t, 'c) readcap) = let n = float_of_int (size a) in let (m, c) = mean a c in let (s, c) = stdDev a c in@@ -36,67 +37,65 @@ type transformation = T of string * (float -> float) - let reduceSkewness ['t]- (ts: transformation list)- (a: (float, 't) array)- (c0: 't writecap) =+ let reduceSkewness (ts: transformation list)+ (a: (float, 't) array)+ (c0: 't writecap) = let rec replace (i: int) (T(_, ft) as t: transformation) (c: 't writecap) : 't writecap = if i < size a- then let (x, c) = at a i c in- let c = update a i (ft x) c in+ then let (x, c) = get a i c in+ let c = set a i (ft x) c in replace (i + 1) t c else c in- let rec find ['c] (ix: int)- (ts: transformation list)- (c: ('t, 'c) readcap)- : float * transformation * ('t, 'c) readcap =- match ts with- | Nil -> let (sk, c) = skewness a c in- (sk, T("identity", fun f: float -> f), c)- | Cons(T(_, ft) as t, ts)- -> let ((sk1, t1), (sk2, t2), c) =- par- (fun 'c (c: ('t, 'c) readcap) -> find['c] (ix + 1) ts c)- (fun 'c (c: ('t, 'c) readcap) ->- let (Pack('s, b, d), c) = map ft a c in- let (sk, d) = skewness b d in- (sk, t, c))- c- in if absf sk2 <. absf sk1- then (replace 0 t1 c0; (sk2, t2, c))- else (sk1, t1, c) in- find 0 ts c0+ (* Need type annotation for polymorphic recursion: *)+ let rec find :+ ∀ 'd. int → transformation list → ('t, 'd) readcap →+ float * transformation * ('t, 'd) readcap =+ λ ix ts c →+ match ts with+ | [] -> let (sk, c) = skewness a c in+ (sk, T("identity", fun f -> f), c)+ | (T(_, ft) as t) ∷ ts+ -> let ((sk1, t1), (sk2, t2), c) =+ par+ (fun (c: ('t, 'c) readcap) -> find (ix + 1) ts c)+ (fun (c: ('t, 'c) readcap) ->+ let ((b, d), c) = map ft a c in+ let (sk, d) = skewness b d in+ (sk, t, c))+ c+ in if absf sk2 <. absf sk1+ then replace 0 t1 c0; (sk2, t2, c)+ else (sk1, t1, c) in+ let (sk, t, c) = find 0 ts c0 in+ (sk, t, replace 0 t c) - let newDistribution- (n: int) (T(_, gen): transformation)- : ex 't. (float, 't) array * 't writecap =- let Pack('t, a, c) = new[float] n in- let rec loop (i: int) (c: 't writecap): 't writecap =+ let newDistribution (n: int) (T(_, gen): transformation)+ : ex 't. (float, 't) array * 't writecap =+ let (a, c) = new n 0.0 in+ let rec loop (i: int) c = if i < n- then loop (i + 1) (update a i (gen (float_of_int (i + 1))) c)+ then loop (i + 1) (set a i (gen (float_of_int (i + 1))) c) else c in- Pack[ex 't. (float, 't) array * 't writecap]('t, a ,loop 0 c)- - let (^:) `a (t: `a) (ts: `a list) = Cons(t, ts)+ (a, loop 0 c) let functions (n: int) =- T("1", fun (ix: float) -> 1.0) ^:- T("x", fun (ix: float) -> ix) ^:- T("x^2", flip ( ** ) 2.0) ^:- T("sqrt x", sqrt) ^:- T("x^5", flip ( ** ) 5.0) ^:- T("x^1/5", flip ( ** ) 0.2) ^:- T("e^x", ( ** ) 2.718) ^:- T("log x", log) ^:- T("1/x", (/.) 1.0) ^:- T("-x", (-.) (float_of_int n)) ^:- Nil+ [T("1", fun (ix: float) -> 1.0)+ ,T("x", fun (ix: float) -> ix)+ ,T("x^2", flip ( ** ) 2.0)+ ,T("sqrt x", sqrt)+ ,T("x^5", flip ( ** ) 5.0)+ ,T("x^1/5", flip ( ** ) 0.2)+ ,T("e^x", ( ** ) 2.718)+ ,T("log x", log)+ ,T("1/x", (/.) 1.0)+ ,T("-x", (-.) (float_of_int n))+ ] let testCase (n: int) (T(name, _) as t: transformation) =- let Pack('t, a, c) = newDistribution n t in+ let (a, c) = newDistribution n t in let (sk0, c) = skewness a c in let (sk, T(name', _), c) = reduceSkewness (functions n) a c in putStrLn ("Distribution: " ^ name);@@ -104,7 +103,7 @@ putStrLn ("Improved skewness: " ^ string_of sk); putStrLn ("Winning function: " ^ name'); putStrLn ""-+ let tests (n: int) = foldl (fun (t: transformation) () -> testCase n t) () (functions n)
examples/threads1.alms view
@@ -1,17 +1,14 @@ (* An example with threads. *) -let printer : unit -> unit =- let rec loop (_ : unit) : unit =- Thread.delay 100000;- putStr "x";- flush ();- loop ()- in loop+let rec printer () =+ Thread.delay 100000;+ putStr "x";+ flush ();+ printer () -let timer : unit -> unit =- fun _: unit ->- let id = Thread.fork printer in- Thread.delay 2000000;- Thread.kill id+let timer () =+ let id = Thread.fork printer in+ Thread.delay 2000000;+ Thread.kill id in timer ()
examples/threads2.alms view
@@ -1,25 +1,20 @@ (* Another example with threads. *) -let printer : unit -> unit =- let rec loop (_ : unit) : unit =- Thread.delay 100000;- putStr "x";- flush ();- loop ()- in loop+let rec printer () =+ Thread.delay 100000;+ putStr "x";+ flush ();+ printer () -let startStop : unit -> unit -o unit =- fun _: unit ->- let id = Thread.fork printer in- let id = Thread.print id in- fun _: unit ->- Thread.kill id+let startStop () =+ let id = Thread.fork printer in+ let id = Thread.print id in+ λ () → Thread.kill id -let timer : unit -> unit =- fun _: unit ->- let stop = startStop () in- Thread.delay 2000000;- stop ()+let timer () =+ let stop = startStop () in+ Thread.delay 2000000;+ stop () in timer ()
examples/threads3.alms view
@@ -1,32 +1,27 @@ (* A bad example with threads. (type error!) *) -let printer : unit -> unit =- let rec loop (_ : unit) : unit =- Thread.delay 100000;- putStr "x";- flush ();- loop ()- in loop+#load "libthread" -let startStop : unit -> unit -o unit =- fun _: unit ->- let id = Thread.fork printer in- let id = Thread.print id in- fun _: unit ->- Thread.kill id+let rec printer () =+ AThread.delay 100000;+ putStr "x";+ flush ();+ printer () -let after : int -> (unit -o unit) -> unit =- fun delay: int ->- fun stop: (unit -o unit) ->- Thread.fork (fun _:unit -> Thread.delay delay; stop ());- ()+let startStop () =+ let id = AThread.fork printer in+ let id = AThread.print id in+ λ _ → AThread.kill id -let main : unit -> unit =- fun _: unit ->- let stop = startStop () in- after 2000000 stop;- getLine ();- stop () (* stop used twice! *)+let after delay stop =+ AThread.fork (λ _ → AThread.delay delay; stop ());+ ()++let main () =+ let stop = startStop () in+ after 2000000 stop;+ getLine ();+ stop () (* stop used twice! *) in main ()
examples/threads4.alms view
@@ -13,33 +13,26 @@ #load "libthread" -let printer : unit -> unit =- let rec loop (_ : unit) : unit =- AThread.delay 100000;- putStr "x";- flush ();- loop ()- in loop+let rec printer () =+ AThread.delay 100000;+ putStr "x";+ flush ();+ printer () -let startStop : unit -> unit -> unit =- fun _: unit ->- let id = AThread.fork printer in- let id = AThread.print id in- (fun () -> AThread.kill id :> unit -> unit)+let startStop () =+ let id = AThread.fork printer in+ let id = AThread.print id in+ (λ _ → AThread.kill id) :> unit → unit -let after : int -> (unit -o unit) -> unit =- fun delay: int ->- fun stop: (unit -o unit) ->- AThread.fork (fun () -> AThread.delay delay; stop ());- ()+let after delay stop =+ AThread.fork (λ _ → AThread.delay delay; stop ());+ () -let main : unit -> unit =- fun _: unit ->- putStrLn "Press <ENTER> to exit.";- let stop = startStop () in- after 4000000 stop;- getLine ();- stop ()+let main () =+ let stop = startStop () in+ after 2000000 stop;+ getLine ();+ stop () (* stop used twice! *) in main ()
lib/libachan.alms view
@@ -20,46 +20,46 @@ type 'a achan = 'a repr M.mvar - let new['a] () = M.new (Writers Q.empty['a])+ let new () = M.new (Writers Q.empty) - let recv['a] (mv : 'a achan) =+ let recv (mv : 'a achan) = let wait (readers : 'a mvar queue) =- let reader = M.newEmpty['a] () in+ let reader = M.newEmpty () in (Readers (Q.enqueue reader readers), fun () -> M.take reader) in- M.modify mv (fun repr : 'a repr ->+ M.modify mv (fun repr -> match repr with | Readers readers -> wait readers | Writers writers -> match Q.dequeueA writers with- | None -> wait Q.empty['a mvar]+ | None -> wait Q.empty | Some (x, xs) -> (Writers xs, fun () -> x)) () - let send['a] (mv : 'a achan) (x : 'a) =- M.modify_ mv (fun repr : 'a repr ->+ let send (mv : 'a achan) (x : 'a) =+ M.modify_ mv (fun repr -> match repr with | Writers writers -> Writers (Q.enqueue x writers) | Readers readers -> match Q.dequeueA readers with- | None -> Writers (Q.enqueue x Q.empty['a])+ | None -> Writers (Q.enqueue x Q.empty) | Some (reader, readers') -> M.put reader x; Readers readers') - let tryRecv['a] (mv : 'a achan) =- M.modify mv (fun repr : 'a repr ->+ let tryRecv (mv : 'a achan) =+ M.modify mv (fun repr -> match repr with- | Readers readers -> (repr, None['a])+ | Readers readers -> (repr, None) | Writers writers -> match Q.dequeueA writers with- | None -> (repr, None['a])+ | None -> (repr, None) | Some (x, xs) -> (Writers xs, Some x)) (* Send always succeeds, but trySend succeeds only if there's a reader ready to receive the send. *)- let trySend['a] (mv : 'a achan) (x : 'a) =- M.modify mv (fun repr : 'a repr ->+ let trySend (mv : 'a achan) (x : 'a) =+ M.modify mv (fun repr -> match repr with | Writers writers -> (repr, false) | Readers readers ->@@ -69,7 +69,7 @@ -> M.put reader x; (Readers readers', true)) - let size['a] (mv : 'a achan) =+ let size (mv : 'a achan) = match M.read mv with | Writers writers -> Q.size writers | Readers readers -> ~(Q.size readers)
lib/libarray.alms view
@@ -20,13 +20,13 @@ exception ArrayIndex type `a array = `a Prim.Array.array - let new['a] (size : int) (elt : 'a) =- build size (fun (_: int) -> elt)+ let new (size : int) (elt : 'a) =+ build size (fun _ -> elt) - let swap[`a] (a : `a array) (ix : int) (elt : `a) =+ let swap (a : `a array) (ix : int) (elt : `a) = try swap a ix elt with _ -> raise ArrayIndex - let set[`a] (a : `a array) (ix : int) (elt : `a) =+ let set (a : `a array) (ix : int) (elt : `a) = swap a ix elt; () end
lib/libarraycap.alms view
@@ -12,37 +12,37 @@ type ('t, 'c) readcap qualifier A type 't writecap = ('t, 1) readcap - val new : all 'a. int -> 'a -> ex 't. ('a, 't) array * 't writecap- val build : all 'a. int -> (int -> 'a) ->- ex 't. ('a, 't) array * 't writecap- val split : all 't 'c. ('t, 'c) readcap ->+ val new : ∀ 'a. int → 'a → ∃ 't. ('a, 't) array * 't writecap+ val build : ∀ 'a. int → (int → 'a) →+ ∃ 't. ('a, 't) array * 't writecap+ val split : ∀ 't 'c. ('t, 'c) readcap → ('t, 'c/2) readcap * ('t, 'c/2) readcap- val join : all 't 'c. ('t, 'c/2) readcap * ('t, 'c/2) readcap ->+ val join : ∀ 't 'c. ('t, 'c/2) readcap * ('t, 'c/2) readcap → ('t, 'c) readcap- val get : all 'a 't 'c. ('a, 't) array -> int -> ('t, 'c) readcap ->+ val get : ∀ 'a 't 'c. ('a, 't) array → int → ('t, 'c) readcap → 'a * ('t, 'c) readcap- val set : all 'a 't. ('a, 't) array -> int -> 'a ->- 't writecap -> 't writecap- val size : all 'a 't. ('a, 't) array -> int+ val set : ∀ 'a 't. ('a, 't) array → int → 'a →+ 't writecap → 't writecap+ val size : ∀ 'a 't. ('a, 't) array → int end module AArray : sig include AARRAY_PRIM - val par : all 't 'c `r1 `r2.- (all 'd. ('t, 'd) readcap -> `r1 * ('t, 'd) readcap) ->- (all 'd. ('t, 'd) readcap -> `r2 * ('t, 'd) readcap) ->- ('t, 'c) readcap ->+ val par : ∀ 't 'c `r1 `r2.+ (∀ 'd. ('t, 'd) readcap → `r1 * ('t, 'd) readcap) →+ (∀ 'd. ('t, 'd) readcap → `r2 * ('t, 'd) readcap) →+ ('t, 'c) readcap → `r1 * `r2 * ('t, 'c) readcap- val fold : all 'a 't 'c `r.- ('a -> `r -> `r) -> `r -> ('a, 't) array -[r]>- ('t, 'c) readcap -[r]>+ val fold : ∀ 'a 't 'c `r.+ ('a → `r → `r) → `r → ('a, 't) array -r>+ ('t, 'c) readcap -r> `r * ('t, 'c) readcap- val map : all 'a 't 'c 'b.- ('a -> 'b) -> ('a, 't) array -> ('t, 'c) readcap ->- (ex 's. ('b, 's) array * 's writecap) * ('t, 'c) readcap+ val map : ∀ 'a 't 'c 'b.+ ('a → 'b) → ('a, 't) array → ('t, 'c) readcap →+ (∃ 's. ('b, 's) array * 's writecap) * ('t, 'c) readcap val putArray- : all 'a 't 'c. ('a, 't) array -> ('t, 'c) readcap ->+ : ∀ 'a 't 'c. ('a, 't) array → ('t, 'c) readcap → ('t, 'c) readcap end = struct module A = Array@@ -55,43 +55,39 @@ type ('t, 'c) readcap = unit type 't writecap = ('t, 1) readcap - let new['a] (size: int) (x : 'a) =- Pack[ex 't. ('a, 't) array * unit]- (unit, A.new['a] size x, ())+ let new size x : ∃ 't. ('a, 't) array * 't writecap =+ (A.new size x, ()) - let build['a] (size: int) (builder : int -> 'a) =- Pack[ex 't. ('a, 't) array * unit]- (unit, A.build['a] size builder, ())+ let build size builder : ∃ 't. ('a, 't) array * 't writecap =+ (A.build size builder, ()) - let split['t,'c] () = ((), ())+ let split () = ((), ()) - let join['t,'c] (_: unit * unit) = ()+ let join (_: unit * unit) = () - let get['a,'t,'c] (arr: ('a, 't) array) (ix: int) () =+ let get (arr: ('a, 't) array) (ix: int) () = (A.get arr ix, ()) - let set['a,'t] (arr: ('a, 't) array) (ix: int) (new: 'a) () =+ let set (arr: ('a, 't) array) (ix: int) (new: 'a) () = A.set arr ix new - let size['a,'t] (arr: ('a, 't) array) =+ let size (arr: ('a, 't) array) = A.size arr end : AARRAY_PRIM - let par ['t,'c,`r1,`r2]- (left: all 'd. ('t, 'd) readcap -> `r1 * ('t, 'd) readcap)- (right: all 'd. ('t, 'd) readcap -> `r2 * ('t, 'd) readcap)+ let par (left: ∀ 'd. ('t, 'd) readcap → `r1 * ('t, 'd) readcap)+ (right: ∀ 'd. ('t, 'd) readcap → `r2 * ('t, 'd) readcap) (c: ('t, 'c) readcap) : `r1 * `r2 * ('t, 'c) readcap = let (c1, c2) = split c in- let future = Future.new (fun () -> left c1) in+ let future = Future.new (λ () → left c1) in let (r2, c2) = right c2 in let (r1, c1) = Future.sync future in (r1, r2, join (c1, c2)) - let fold ['a,'t,'c,`r]- (f: 'a -> `r -> `r) (z: `r)+ let fold (f: 'a → `r → `r) (z: `r) (a: ('a, 't) array) (c: ('t, 'c) readcap) =- let rec loop (i: int) (z: `r)| (c: ('t, 'c) readcap)+ let rec loop (i: int) (z: `r) (c: ('t, 'c) readcap) : `r * ('t, 'c) readcap = if i < size a then let (elt, c) = get a i c in@@ -99,26 +95,25 @@ else (z, c) in loop 0 z c - let map ['a,'t,'c,'b]- (f: 'a -> 'b)+ let map (f: 'a → 'b) (a: ('a, 't) array) (c: ('t, 'c) readcap)- : (ex 's. ('b, 's) array * 's writecap) * ('t, 'c) readcap =+ : (∃ 's. ('b, 's) array * 's writecap) * ('t, 'c) readcap = let holder = ref (Some c) in let builder (ix : int) = match holder <- None with- | None -> failwith "can't happen"- | Some c ->+ | None → failwith "can't happen"+ | Some c → let (x, c) = get a ix c in holder <- Some c; f x in let res = build (size a) builder in match holder <- None with- | None -> failwith "can't happen"- | Some c -> (res, c)+ | None → failwith "can't happen"+ | Some c → (res, c) - let putArray['a,'t,'c] (a: ('a, 't) array) (c: ('t, 'c) readcap) =+ let putArray (a: ('a, 't) array) (c: ('t, 'c) readcap) = putStr "["; let (_, c) =- fold (fun (x: 'a) (comma: bool) ->+ fold (λ (x: 'a) (comma: bool) → (if comma then putStr "," else ()); putStr (string_of x); true)
lib/libbasis.alms view
@@ -1,4 +1,6 @@ module INTERNALS = struct+ module PrimTypes = INTERNALS.PrimTypes+ module Exn = struct open Prim.Exn @@ -11,11 +13,11 @@ let failwith (msg: string) = raise (Failure msg) - let tryfun[`a] (thunk: unit -o `a) : exn + `a =+ let tryfun (thunk: unit -o `a) : exn + `a = match tryfun_string thunk with- | Right a -> Right[exn,`a] a- | Left (Left e) -> Left[exn,`a] e- | Left (Right s) -> Left[exn,`a] (IOError s)+ | Right a -> Right a+ | Left (Left e) -> Left e+ | Left (Right s) -> Left (IOError s) let raiseBlame (who: string) (what: string) = raise (Blame (who, what))@@ -23,7 +25,8 @@ local module INTERNALS = struct- module Exn = Exn+ module Exn = Exn+ module PrimTypes = PrimTypes end with module Contract = struct@@ -32,50 +35,50 @@ type `a contract = party * party -> `a -> `a (* Flat contracts for unlimited values. *)- let flat['a] (pred: 'a -> bool) : 'a contract =- fun (neg: party, pos: party) (a: 'a) ->+ let flat (pred: 'a -> bool) : 'a contract =+ λ (neg: party, pos: party) (a: 'a) -> if pred a then a else Exn.raiseBlame pos "violated contract" (* Flat contracts for affine values. *)- let flatA[`a] (pred: `a -> bool * `a) : `a contract =- fun (neg: party, pos: party) (a: `a) ->+ let flatA (pred: `a -> bool * `a) : `a contract =+ λ (neg: party, pos: party) (a: `a) -> match pred a with | (true, a) -> a | (false, _) -> Exn.raiseBlame pos "violated contract" (* The identity contract. *)- let any[`a] : `a contract =- fun (_: party, _: party) (a: `a) -> a+ let any : `a contract =+ λ (_: party, _: party) (a: `a) -> a (* Add domain and codomain contracts to a function. *)- let func[`q]- [`a1, `a2] (dom: (`a1, `a2) coercion)- [`b1, `b2] (cod: (`b1, `b2) coercion)+ let func+ (dom: (`a1, `a2) coercion)+ (cod: (`b1, `b2) coercion) : (`a2 -[`q]> `b1, `a1 -[`q]> `b2) coercion =- fun (neg: party, pos: party) (f: `a2 -[`q]> `b1) ->- fun (a: `a1) -> cod (neg, pos) (f (dom (pos, neg) a))+ λ (neg: party, pos: party) (f: `a2 -[`q]> `b1) ->+ λ (a: `a1) -> cod (neg, pos) (f (dom (pos, neg) a)) (* Coerce an affine function to an unlimited function, and check dynamically that it's applied only once. *)- let affunc[`a1, `a2] (dom: (`a1, `a2) coercion)- [`b1, `b2] (cod: (`b1, `b2) coercion)+ let affunc (dom: (`a1, `a2) coercion)+ (cod: (`b1, `b2) coercion) : (`a2 -o `b1, `a1 -> `b2) coercion =- fun (neg: party, pos: party) (f: `a2 -o `b1) ->+ λ (neg: party, pos: party) (f: `a2 -o `b1) -> let rf = ref (Some f) in- fun (a: `a1) ->- match rf <- None[`a2 -o `b1] with+ λ (a: `a1) ->+ match rf <- None with | Some f -> cod (neg, pos) (f (dom (pos, neg) a)) | None -> Exn.raiseBlame neg "reused one-shot function" (* Check that an ostensibly unlimited function is actually unlimited. *)- let unfunc[`a1, `a2] (dom: (`a1, `a2) coercion)- [`b1, `b2] (cod: (`b1, `b2) coercion)+ let unfunc (dom: (`a1, `a2) coercion)+ (cod: (`b1, `b2) coercion) : (`a2 -> `b1, `a1 -> `b2) coercion =- fun (neg: party, pos: party) (f: `a2 -> `b1) ->- fun (x: `a1) ->+ λ (neg: party, pos: party) (f: `a2 -> `b1) ->+ λ (x: `a1) -> let x' = dom (pos, neg) x in let y = try f x' with | Exn.Blame(p, "reused one-shot function")@@ -85,84 +88,113 @@ end end -let not (b: bool) = if b then false else true-let (!=)['a] (x: 'a) (y: 'a) = not (x == y)+module Function = struct+ let id x = x+ let const _ x = x+ let flip f y x = f x y+ let curry f x y = f (x, y)+ let uncurry f (x, y) = f x y+ let compose f g x = f (g x)+ let ($) f x = f x+end -let flip['a,'b,'c] (f: 'a -> 'b -> 'c) (y: 'b) (x: 'a) = f x y+open Function -let (<) (x: int) (y: int) = not (y <= x)-let (>) = flip (<)-let (>=) = flip (<=)-let (>.) = flip (<.)-let (>=.) = flip (<=.)+module Bool = struct+ let not (b: bool) = if b then false else true+ let (!=) (x: 'a) (y: 'a) = not (x == y)+end -type `a × `b = `a * `b-(* These have too-tight precedences *)-let (≠) = (!=)-let (≤) = (<=)-let (≥) = (>=)-let (≤.) = (<=.)-let (≥.) = (>=.)+open Bool -let null = fun 'a (x : 'a list) ->- match x with- | Nil -> true- | _ -> false-let anull = fun `a (xs : `a list) ->- match xs with- | Nil -> (Nil[`a], true)- | Cons(x, xs') -> (Cons(x, xs'), false)-let hd = fun 'a (xs : 'a list) ->- let Cons(x, _) = xs in x-let tl = fun 'a (xs : 'a list) ->- let Cons(_, xs') = xs in xs'-let foldr =- let rec foldr `a `b (f : `a -> `b -o `b)- (z : `b) |[b](xs : `a list) : `b =- match xs with- | Nil -> z- | Cons(x,xs) -> f x (foldr f z xs)- in foldr-let foldl =- let rec foldl `a `b (f : `a -> `b -o `b)- (z : `b) |[b](xs : `a list) : `b =- match xs with- | Nil -> z- | Cons(x,xs) -> foldl f (f x z) xs- in foldl-let map `a `b (f: `a -> `b) (xs: `a list) =- foldr (fun (x: `a) (xs': `b list) -> Cons (f x, xs')) Nil xs-let filter 'a (f: 'a -> bool) (xs: 'a list) =- foldr (fun (x: 'a) (xs': 'a list) ->- if f x then Cons(x, xs') else xs')- Nil-let mapFilterA `a `b (f: `a -> `b option) (xs: `a list) =- foldr (fun (x: `a) (xs': `b list) ->- match f x with- | Some y -> Cons(y, xs')- | None -> xs')- Nil- xs-let revApp[`c] (xs : `c list) (ys : `c list) =- let cons (x : `c) (acc : `c list) = Cons (x, acc) in- foldl cons ys xs-let rev[`b] (xs : `b list) = revApp xs Nil-let append[`a] (xs : `a list) = revApp (rev xs)-let length[`a] (xs : `a list) =- foldr (fun (x : `a) -> (+) 1) 0 xs-let lengthA[`a] (xs : `a list) =- let count (x : `a) (n : int, xs' : `a list) =- (1 + n, Cons (x, xs')) in- foldr count (0, Nil[`a]) xs+module Int = struct+ let (<) (x: int) (y: int) = not (y <= x)+ let (>) = flip (<)+ let (>=) = flip (<=)+ let (>.) = flip (<.)+ let (>=.) = flip (<=.) -let fst[`a,`b] (x: `a, _: `b) = x-let snd[`a,`b] (_: `a, y: `b) = y+ type `a × `b = `a * `b+ (* These have too-tight precedences *)+ let (≠) = (!=)+ let (≤) = (<=)+ let (≥) = (>=)+ let (≤.) = (<=.)+ let (≥.) = (>=.)+end -let (=>!) [`a] (x: `a) [`b] (y: `b) = (y, x)+open Int++module List = struct+ let null x =+ match x with+ | [] -> true+ | _ -> false++ let anull xs =+ match xs with+ | [] -> ([], true)+ | x :: xs' -> (x :: xs', false)++ let hd (x :: _) = x++ let tl (_ :: xs) = xs++ let rec foldr f z xs =+ match xs with+ | [] -> z+ | x :: xs -> f x (foldr f z xs)++ let rec foldl f z xs =+ match xs with+ | [] -> z+ | x :: xs -> foldl f (f x z) xs++ let map f = foldr (λ x xs' -> f x :: xs') []++ let filter f xs = foldr (λ x xs' -> if f x then x :: xs' else xs') []++ let mapFilterA f =+ foldr (λ x xs' ->+ match f x with+ | Some y -> y :: xs'+ | None -> xs')+ []++ let revApp xs ys =+ let cons x acc = x :: acc in+ foldl cons ys xs++ let rev xs = revApp xs []++ let append xs = revApp (rev xs)++ let length = foldr (λ _ -> (+) 1) 0++ let lengthA xs =+ let count x (n, xs') = (1 + n, x :: xs') in+ foldr count (0, []) xs++ let rec openFoldr f z o xs = match xs with+ | #Nil -> z+ | #Cons(x,xs') -> f x (openFoldr f z o xs')+ | other -> o other+end++open List++let fst (x, _) = x+let snd (_, y) = y++let (=>!) x y = (y, x) let (⇒) = (=>!) let (←) = (<-) let (⇐) = (<-!) -open INTERNALS+type (|->) = type Prim.Row.(|->)+let rowCase = Prim.Row.rowCase++module Exn = INTERNALS.Exn+module Contract = INTERNALS.Contract open Exn
lib/libqueue.alms view
@@ -1,19 +1,19 @@ module type QUEUE = sig- type +`a queue qualifier `a+ type +`a queue : `a exception Empty - val emptyA : all `a. unit -> `a queue- val isEmptyA : all `a. `a queue -> bool * `a queue- val sizeA : all `a. `a queue -> int * `a queue- val dequeueA : all `a. `a queue -> (`a * `a queue) option+ val emptyA : unit → `a queue+ val isEmptyA : `a queue → bool * `a queue+ val sizeA : `a queue → int * `a queue+ val dequeueA : `a queue → (`a * `a queue) option - val enqueue : all `a. `a -> `a queue -[a]> `a queue+ val enqueue : `a → `a queue → `a queue - val empty : all 'a. 'a queue- val isEmpty : all 'a. 'a queue -> bool- val size : all 'a. 'a queue -> int- val first : all 'a. 'a queue -> 'a- val dequeue : all 'a. 'a queue -> 'a queue+ val empty : 'a queue+ val isEmpty : 'a queue → bool+ val size : 'a queue → int+ val first : 'a queue → 'a+ val dequeue : 'a queue → 'a queue end module Queue : QUEUE = struct@@ -21,38 +21,46 @@ exception Empty - let emptyA[`a] () = (Nil[`a], Nil[`a])- let isEmptyA[`a] (q : `a queue) =+ let emptyA () = ([], [])++ let isEmptyA q = match q with- | (Nil, Nil) -> (true, (Nil[`a], Nil[`a]))- | q -> (false, q)- let sizeA[`a] ((front, back) : `a queue) =+ | ([], []) → (true, ([], []))+ | q → (false, q)++ let sizeA (front, back) = let (lenf, front) = lengthA front in let (lenb, back) = lengthA back in (lenf + lenb, (front, back))- let dequeueA[`a] ((front, back) : `a queue) =++ let dequeueA (front, back) = match front with- | Cons (x, xs) -> Some (x, (xs, back))- | Nil ->+ | x ∷ xs → Some (x, (xs, back))+ | [] → match rev back with- | Cons (x, xs) -> Some (x, (xs, Nil[`a]))- | Nil -> None[`a * `a queue]+ | x ∷ xs → Some (x, (xs, []))+ | [] → None - let empty['a] = (Nil['a], Nil['a])- let isEmpty[`a] (q : `a queue) =+ let empty = ([], [])++ let isEmpty q = match q with- | (Nil, Nil) -> true- | _ -> false- let enqueue[`a] (x : `a) ((front, back) : `a queue) =- (front, Cons (x, back))- let first[`a] (q : `a queue) =+ | ([], []) → true+ | _ → false++ let enqueue x (front, back) =+ (front, x ∷ back)++ let first q = match dequeueA q with- | Some (x, _) -> x- | None -> raise Empty- let dequeue[`a] (q : `a queue) =+ | Some (x, _) → x+ | None → raise Empty++ let dequeue q = match dequeueA q with- | Some (_, q') -> q'- | None -> raise Empty- let size[`a] ((front, back) : `a queue) =+ | Some (_, q') → q'+ | None → raise Empty++ let size (front, back) = length front + length back end
lib/libsessiontype.alms view
@@ -4,7 +4,7 @@ module type SESSION_TYPE = sig type 1- type +'a ; +'s+ type +'a ; +'s rec 's type ! -`a type ? +`a type +'a |+| +'b@@ -51,35 +51,33 @@ type 's channel = rep type 's rendezvous = rep C.channel - let newRendezvous['s] () =- (C.new['s channel] ())+ let newRendezvous () = C.new () - let request['s] (r: 's rendezvous) =- C.recv r+ let request (r: 's rendezvous) = C.recv r - let accept['s] (r: 's rendezvous) =- let c = C.new[bool] () in+ let accept (r: 's rendezvous) =+ let c = C.new () in C.send r c; c - let send[`a, 's] (c: rep)| (a: `a) =- C.send c (Unsafe.unsafeCoerce[bool] a);+ let send (c: rep) (a: `a) =+ C.send c (Unsafe.unsafeCoerce a); c - let recv[`a, 's] (c: rep) =- (Unsafe.unsafeCoerce[`a] (C.recv c), c)+ let recv (c: rep) =+ (Unsafe.unsafeCoerce (C.recv c), c) - let sel1['s1, 's2] (c: ('s1 |+| 's2) channel)+ let sel1 (c: ('s1 |+| 's2) channel) : 's1 channel = C.send c true; c - let sel2['s1, 's2] (c: rep) =+ let sel2 (c: rep) = C.send c false; c - let follow['s1, 's2] (c: rep) =+ let follow (c: rep) = if C.recv c- then Left [rep, rep] c- else Right[rep, rep] c+ then Left c+ else Right c end
lib/libsessiontype2.alms view
@@ -18,17 +18,16 @@ type 's rendezvous type +'s channel qualifier A - val newRendezvous : all 's. unit -> 's rendezvous+ val newRendezvous : unit → 's rendezvous - val request : all 's. 's rendezvous -> 's channel- val accept : all 's. 's rendezvous -> 's dual channel+ val request : 's rendezvous → 's channel+ val accept : 's rendezvous → 's dual channel - val send : all `a. `a -> all 's. (!`a; 's) channel -[a]>- unit * 's channel- val recv : all `a 's. (?`a; 's) channel -> `a * 's channel+ val send : `a → (!`a; 's) channel → unit * 's channel+ val recv : (?`a; 's) channel → `a * 's channel - val follow : all `c. ?-> `c channel -> unit * `c- val choose : all 's `c. ('s channel -> `c) -> !-> `c channel ->+ val follow : ?-> `c channel → unit * `c+ val choose : ('s channel → `c) → !-> `c channel → unit * 's dual channel end @@ -47,11 +46,11 @@ type ?-> `c = ?`c; 1 type !-> `c = !`c; 1 - type rep = any C.channel+ type rep = int C.channel type 's channel = rep type 's rendezvous = rep C.channel - let newRendezvous () = C.new[rep] ()+ let newRendezvous () = C.new () let request (r: unit rendezvous) = C.recv r @@ -64,16 +63,16 @@ let c = C.new () in (c, c) - let send[`a] (a: `a) (c: rep) =+ let send (a: `a) (c: rep) = C.send c (Unsafe.unsafeCoerce a); ((), c) - let recv[`a] (c: rep) = (C.recv c, c)+ let recv (c: rep) = (Unsafe.unsafeCoerce (C.recv c), c) let follow (c: rep) = let (c', _) = recv c in ((), c') - let choose[`c] (ctor: rep -> `c) (c: rep) =+ let choose (ctor: rep → `c) (c: rep) = let (theirs, mine) = newPair () in send (ctor theirs) c; ((), mine)@@ -87,12 +86,13 @@ | More of (!int; ?->state2) channel | Again of (?int; state1) channel + let client (c: state1 channel) =- let rec s1 !(c: state1 channel) : int * 1 channel =+ let rec s1 !c = send 1 c; follow c; s2 c- and s2 !(c: state2) : int * 1 channel =+ and s2 !c = match c with | Done c -> recv c | More c -> send 2 c;@@ -103,7 +103,7 @@ in fst (s1 c) let server (c: state1 dual channel) =- let rec s1 !(c : state1 dual channel) : unit * 1 channel =+ let rec s1 !c = match recv c with | 0 -> choose More c; let z' = recv c in
lib/libsocket.alms view
@@ -7,11 +7,11 @@ module S = Prim.Socket with let getAddrByName (host: string) (port: string) : S.sockAddr =- let info = S.AddrInfo(Nil[S.addrInfoFlag], S.AF_INET,+ let info = S.AddrInfo([], S.AF_INET, S.Stream, S.defaultProtocol,- S.SockAddrInet(S.PortNum 0, 0), None[string]) in+ S.SockAddrInet(S.PortNum 0, 0), None) in match S.getAddrInfo (Some info) (Some host) (Some port) with- | Cons (S.AddrInfo (_, _, _, _, sockAddr, _), _) -> sockAddr+ | S.AddrInfo (_, _, _, _, sockAddr, _) ∷ _ -> sockAddr | _ -> failwith ("Could not resolve address "^host^":"^port) type socket = S.socket
lib/libsocketcap.alms view
@@ -14,63 +14,63 @@ type 't socket (* The socket states *)- type 't initial qualifier A- type 't bound qualifier A- type 't listening qualifier A- type 't connected qualifier A+ type 't initial : A+ type 't bound : A+ type 't listening : A+ type 't connected : A (* Socket operations *)- val socket : unit -> ex 't. 't socket * 't initial- val bind : all 't. 't socket -> int -> 't initial -> 't bound- val connect : all 't. 't socket -> string -> string ->- 't initial + 't bound -> 't connected- val listen : all 't. 't socket -> 't bound -> 't listening- val accept : all 't. 't socket -> 't listening ->- (ex 's. 's socket * 's connected) * 't listening- val send : all 't. 't socket -> string ->- 't connected -> 't connected- val recv : all 't. 't socket -> int ->- 't connected -> string * 't connected- val close : all 't.'t socket -> 't connected -> unit+ val socket : unit → ∃ 't. 't socket × 't initial+ val bind : 't socket → int → 't initial → 't bound+ val connect : 't socket → string → string →+ 't initial + 't bound → 't connected+ val listen : 't socket → 't bound → 't listening+ val accept : 't socket → 't listening →+ (∃ 's. 's socket × 's connected) × 't listening+ val send : 't socket → string →+ 't connected → 't connected+ val recv : 't socket → int →+ 't connected → string × 't connected+ val close : 't socket → 't connected → unit (* When we raise an exception, we "freeze" the capability. * We can thaw the frozen capability if we have the socket that * it goes with. (This requires a dynamic check.) This lets us * recover the capability with a type paramater that matches any * extant sockets that go with it. *)- type frozenInitial qualifier A- type frozenBound qualifier A- type frozenListening qualifier A- type frozenConnected qualifier A+ type frozenInitial : A+ type frozenBound : A+ type frozenListening : A+ type frozenConnected : A (* Operations for reassociating frozen capabilities with their sockets. *)- val thawInitial : all 't. 't socket -> frozenInitial ->+ val thawInitial : 't socket → frozenInitial → frozenInitial + 't initial- val thawBound : all 't. 't socket -> frozenBound ->+ val thawBound : 't socket → frozenBound → frozenBound + 't bound- val thawListening : all 't. 't socket -> frozenListening ->+ val thawListening : 't socket → frozenListening → frozenListening + 't listening- val thawConnected : all 't. 't socket -> frozenConnected ->+ val thawConnected : 't socket → frozenConnected → frozenConnected + 't connected (* Operations for catching the error state associated with a given socket. *)- val catchInitial : all 't `a. 't socket ->- (unit -o `a) -> ('t initial -o `a) -o `a- val catchBound : all 't `a. 't socket ->- (unit -o `a) -> ('t bound -o `a) -o `a- val catchListening : all 't `a. 't socket ->- (unit -o `a) -> ('t listening -o `a) -o `a- val catchConnected : all 't `a. 't socket ->- (unit -o `a) -> ('t connected -o `a) -o `a+ val catchInitial : 't socket →+ (unit -o `a) → ('t initial -o `a) -o `a+ val catchBound : 't socket →+ (unit -o `a) → ('t bound -o `a) -o `a+ val catchListening : 't socket →+ (unit -o `a) → ('t listening -o `a) -o `a+ val catchConnected : 't socket →+ (unit -o `a) → ('t connected -o `a) -o `a (* Socket exceptions *) exception SocketError of string- exception StillInitial of frozenInitial * string- exception StillBound of frozenBound * string- exception StillListening of frozenListening * string- exception StillConnected of frozenConnected * string+ exception StillInitial of frozenInitial × string+ exception StillBound of frozenBound × string+ exception StillListening of frozenListening × string+ exception StillConnected of frozenConnected × string end module ASocket : ASOCKET = struct@@ -80,60 +80,70 @@ type rep = S.socket type 't socket = S.socket + type 't initial = unit+ type 't bound = unit+ type 't listening = unit+ type 't connected = unit++ type frozenInitial = rep+ type frozenBound = rep+ type frozenListening = rep+ type frozenConnected = rep+ exception SocketError of string- exception StillInitial of rep * string- exception StillBound of rep * string- exception StillListening of rep * string- exception StillConnected of rep * string+ exception StillInitial of rep × string+ exception StillBound of rep × string+ exception StillListening of rep × string+ exception StillConnected of rep × string - let socket () =+ let socket () : ∃'t. 't socket × 't initial = try (S.socket (), ()) with- IOError s -> raise (SocketError s)+ IOError s → raise (SocketError s) - let bind['t] (sock: rep) (port: int) () =+ let bind (sock: rep) (port: int) () = try S.bind sock port with- IOError msg -> raise (StillInitial (sock, msg))+ IOError msg → raise (StillInitial (sock, msg)) - let connect['t] (sock: rep) (host: string) (port: string)- (cap: unit + unit) =+ let connect (sock: rep) (host: string) (port: string)+ (cap: unit + unit) = try S.connect sock host port with- IOError msg -> match cap with- | Left _ -> raise (StillInitial (sock, msg))- | Right _ -> raise (StillBound (sock, msg))+ IOError msg → match cap with+ | Left _ → raise (StillInitial (sock, msg))+ | Right _ → raise (StillBound (sock, msg)) - let listen['t] (sock: rep) () =+ let listen (sock: rep) () = try S.listen sock with- IOError msg -> raise (StillBound (sock, msg))+ IOError msg → raise (StillBound (sock, msg)) - let accept['t] (sock: rep) () =- try (S.accept sock, (), ())+ let accept (sock: rep) () =+ try ((S.accept sock, ()) : ∃'s. 's socket × 's connected, ()) with- IOError msg -> raise (StillListening (sock, msg))+ IOError msg → raise (StillListening (sock, msg)) - let send['t] (sock: rep) (data: string) () =+ let send (sock: rep) (data: string) () = try S.send sock data; () with- IOError msg -> raise (SocketError msg)+ IOError msg → raise (SocketError msg) - let recv['t] (sock: rep) (len: int) () =+ let recv (sock: rep) (len: int) () = try (S.recv sock len, ()) with- IOError msg -> raise (SocketError msg)+ IOError msg → raise (SocketError msg) - let close['t] (sock: rep) () =+ let close (sock: rep) () = try S.close sock with- IOError msg -> raise (SocketError msg)+ IOError msg → raise (SocketError msg) (* Convenience functions for catching and thawing frozen socket * capabilities. *)- let thaw ['t] (sock: rep) (sock': rep) =+ let thaw (sock: rep) (sock': rep) = if sock == sock' then Right () else Left sock'@@ -143,47 +153,36 @@ let thawListening = thaw let thawConnected = thaw - let catchInitial['t,`a] (sock: rep) (body: unit -o `a)- (handler: unit -o `a) =+ let catchInitial (sock: rep) (body: unit -o `a)+ (handler: unit -o `a) = try body () with- | StillInitial (frz, msg) ->+ | StillInitial (frz, msg) → match thawInitial sock frz with- | Left frz -> raise (StillInitial (frz, msg))- | Right cap -> handler cap+ | Left frz → raise (StillInitial (frz, msg))+ | Right cap → handler cap - let catchBound['t,`a] (sock: rep) (body: unit -o `a)- (handler: unit -o `a) =+ let catchBound (sock: rep) (body: unit -o `a)+ (handler: unit -o `a) = try body () with- | StillBound (frz, msg) ->+ | StillBound (frz, msg) → match thawBound sock frz with- | Left frz -> raise (StillBound (frz, msg))- | Right cap -> handler cap+ | Left frz → raise (StillBound (frz, msg))+ | Right cap → handler cap - let catchListening['t,`a] (sock: rep) (body: unit -o `a)- (handler: unit -o `a) =+ let catchListening (sock: rep) (body: unit -o `a)+ (handler: unit -o `a) = try body () with- | StillListening (frz, msg) ->+ | StillListening (frz, msg) → match thawListening sock frz with- | Left frz -> raise (StillListening (frz, msg))- | Right cap -> handler cap+ | Left frz → raise (StillListening (frz, msg))+ | Right cap → handler cap - let catchConnected['t,`a] (sock: rep) (body: unit -o `a)- (handler: unit -o `a) =+ let catchConnected (sock: rep) (body: unit -o `a)+ (handler: unit -o `a) = try body () with- | StillConnected (frz, msg) ->+ | StillConnected (frz, msg) → match thawConnected sock frz with- | Left frz -> raise (StillConnected (frz, msg))- | Right cap -> handler cap-- (* Types for the interface *)- type 't initial = unit- type 't bound = unit- type 't listening = unit- type 't connected = unit-- type frozenInitial = rep- type frozenBound = rep- type frozenListening = rep- type frozenConnected = rep+ | Left frz → raise (StillConnected (frz, msg))+ | Right cap → handler cap end
lib/libsocketcap2.alms view
@@ -41,7 +41,7 @@ * extant sockets that go with it. *) type 'a frozen qualifier A - val thaw : all 't. 't socket -> all 's. 's frozen -> 's frozen + 't@@'s+ val thaw : all 't 's. 't socket -> 's frozen -> 's frozen + 't@@'s (* Operations for catching the error state associated with a given socket. *)@@ -70,6 +70,13 @@ type rep = S.socket type 't socket = S.socket + type 't @@ 's = unit+ type initial+ type bound+ type listening+ type connected+ type 's frozen = rep+ type socketError = StillInitial of rep | StillBound of rep | StillListening of rep@@ -81,7 +88,7 @@ raise (SocketError (se, msg)) let socket () =- try (S.socket (), ())+ try (S.socket (), ()) : ∃ 't. 't socket × 't@@initial with IOError msg -> error Disconnected msg @@ -104,7 +111,7 @@ IOError msg -> error (StillBound sock) msg let accept (sock: rep) () =- try (S.accept sock, (), ())+ try ((S.accept sock, ()) : ∃ 't. 't socket × 't@@initial, ()) with IOError msg -> error (StillListening sock) msg @@ -132,44 +139,36 @@ then Right () else Left sock' - let catchInitial[`a] (sock: rep) (body: unit -o `a)- (handler: unit -o `a) =+ let catchInitial (sock: rep) (body: unit -o `a)+ (handler: unit -o `a) = try body () with | SocketError (StillInitial frz, msg) -> match thaw sock frz with | Left frz -> error (StillInitial frz) msg | Right cap -> handler cap - let catchBound[`a] (sock: rep) (body: unit -o `a)- (handler: unit -o `a) =+ let catchBound (sock: rep) (body: unit -o `a)+ (handler: unit -o `a) = try body () with | SocketError (StillBound frz, msg) -> match thaw sock frz with | Left frz -> error (StillBound frz) msg | Right cap -> handler cap - let catchListening[`a] (sock: rep) (body: unit -o `a)- (handler: unit -o `a) =+ let catchListening (sock: rep) (body: unit -o `a)+ (handler: unit -o `a) = try body () with | SocketError (StillListening frz, msg) -> match thaw sock frz with | Left frz -> error (StillListening frz) msg | Right cap -> handler cap - let catchConnected[`a] (sock: rep) (body: unit -o `a)- (handler: unit -o `a) =+ let catchConnected (sock: rep) (body: unit -o `a)+ (handler: unit -o `a) = try body () with | SocketError (StillConnected frz, msg) -> match thaw sock frz with | Left frz -> error (StillConnected frz) msg | Right cap -> handler cap-- (* Types for the interface *)- type 't @@ 's = unit- type initial- type bound- type listening- type connected- type 's frozen = rep end
+ src/AST.hs view
@@ -0,0 +1,164 @@+-----------------------------------------------------------------------------+-- |+-- This module provides abstract syntax and basic syntax operations.+--+-----------------------------------------------------------------------------++module AST (+ module AST.Anti,+ module AST.Notable,+ module AST.Ident,+ module AST.Kind,+ module AST.Type,+ module AST.Lit,+ module AST.Patt,+ module AST.Expr,+ module AST.Decl,+ module AST.SyntaxTable,+ module Data.Lattice,++ -- * Unfold syntax to lists+ unfoldExAbs, unfoldTyQu, unfoldTyMu, unfoldTyRow,+ unfoldExApp, unfoldPaRec, unfoldTyFun,+ unfoldTupleExpr, unfoldTuplePatt, unfoldSeWith,+) where++import Prelude ()++import AST.Anti+import AST.Notable+import AST.Ident+import AST.Kind+import AST.Type+import AST.Lit+import AST.Patt+import AST.Expr+import AST.Decl+import AST.SyntaxTable++import Util+import Data.Lattice++deriveAntibles syntaxTable++instance Antible (Prog i) where+ injAnti _ = error "BUG! injAnti: Cannot inject into Prog"+ prjAnti = const Nothing+ dictOf = const noAntis++-- These should be generated:+instance Antible (Ident i) where+ injAnti = J [] . Var . injAnti+ prjAnti (J [] (Var l)) = prjAnti l+ prjAnti _ = Nothing+ dictOf = const idAntis++instance Antible (QLid i) where+ injAnti = J [] . injAnti+ prjAnti (J [] i) = prjAnti i+ prjAnti _ = Nothing+ dictOf = const qlidAntis++instance Antible (QUid i) where+ injAnti = J [] . injAnti+ prjAnti (J [] i) = prjAnti i+ prjAnti _ = Nothing+ dictOf = const quidAntis++instance Antible (QTypId i) where+ injAnti = J [] . injAnti+ prjAnti (J [] i) = prjAnti i+ prjAnti _ = Nothing+ dictOf = const qtypIdAntis++instance Antible (QVarId i) where+ injAnti = J [] . injAnti+ prjAnti (J [] i) = prjAnti i+ prjAnti _ = Nothing+ dictOf = const qvarIdAntis++instance Antible (QConId i) where+ injAnti = J [] . injAnti+ prjAnti (J [] i) = prjAnti i+ prjAnti _ = Nothing+ dictOf = const qconIdAntis++instance Antible (QModId i) where+ injAnti = J [] . injAnti+ prjAnti (J [] i) = prjAnti i+ prjAnti _ = Nothing+ dictOf = const qmodIdAntis++instance Antible (QSigId i) where+ injAnti = J [] . injAnti+ prjAnti (J [] i) = prjAnti i+ prjAnti _ = Nothing+ dictOf = const qsigIdAntis++-- Unfolding various sequences++-- | Get the list of formal parameters and body of a+-- lambda/typelambda expression+unfoldExAbs :: Expr i -> ([Patt i], Expr i)+unfoldExAbs = unscanr each where+ each e = case view e of+ ExAbs x e' -> Just (x, e')+ _ -> Nothing++-- | Get the list of formal parameters and body of a qualified type+unfoldTyQu :: Quant -> Type i -> ([TyVar i], Type i)+unfoldTyQu u = unscanr each where+ each (N _ (TyQu u' x t)) | u == u' = Just (x, t)+ each _ = Nothing++-- | Get the list of mu-bound tvs of a recursive type+unfoldTyMu :: Type i -> ([TyVar i], Type i)+unfoldTyMu = unscanr each where+ each (N _ (TyMu x t)) = Just (x, t)+ each _ = Nothing++-- | Get the list of labels and types in a row type+unfoldTyRow :: Type i -> ([(Uid i, Type i)], Type i)+unfoldTyRow = unscanr each where+ each (N _ (TyRow i t1 t2)) = Just ((i, t1), t2)+ each _ = Nothing++-- | Get the list of actual parameters and body of a value application+unfoldExApp :: Expr i -> ([Expr i], Expr i)+unfoldExApp = unscanl each where+ each e = case view e of+ ExApp e1 e2 -> Just (e2, e1)+ _ -> Nothing++-- | Get the list of argument types and result type of a function type+unfoldPaRec :: Patt i -> ([(Uid i, Patt i)], Patt i)+unfoldPaRec = unscanr each where+ each (N _ (PaRec u π1 π2)) = Just ((u, π1), π2)+ each _ = Nothing++-- | Get the list of argument types and result type of a function type+unfoldTyFun :: Type i -> ([Type i], Type i)+unfoldTyFun = unscanr each where+ each (N _ (TyFun ta _ tr)) = Just (ta, tr)+ each _ = Nothing++-- | Get the elements of a tuple as a list+unfoldTupleExpr :: Expr i -> ([Expr i], Expr i)+unfoldTupleExpr = unscanl each where+ each e = case view e of+ ExPair e1 e2 -> Just (e2, e1)+ _ -> Nothing++-- | Get the elements of a tuple pattere as a list+unfoldTuplePatt :: Patt i -> ([Patt i], Patt i)+unfoldTuplePatt = unscanl each where+ each p = case view p of+ PaPair p1 p2 -> Just (p2, p1)+ _ -> Nothing++-- | Get all the "with type" clauses on a signature expression+unfoldSeWith :: SigExp i -> ([(QTypId i, [TyVar i], Type i)], SigExp i)+unfoldSeWith = unscanl each where+ each p = case view p of+ SeWith se ql tvs t -> Just ((ql, tvs, t), se)+ _ -> Nothing
+ src/AST/Anti.hs view
@@ -0,0 +1,404 @@+module AST.Anti (+ -- * Representation of antiquotes+ Anti(..),+ -- ** Raising errors when encountering antiquotes+ AntiFail(..), AntiError(..),+ -- * Generic anti projection/injection+ Antible(..), deriveAntibles,+ -- * Generic location expansion+ LocAst(..), deriveLocAsts,+ -- * Antiquote expansion+ -- ** Generic expander construction+ expandAntibles, expandAntible, expandAntibleType,+ -- * Syntax classes and antiquote tables+ -- ** Antiquote tables+ -- *** Types+ AntiDict, PreTrans, Trans(..),+ -- *** Constructors+ (=:), (=:!), (=:<), (=:•), (=:••), (&),+ -- ** Syntax classs+ -- *** Types+ SyntaxClass(..), SyntaxTable,+ -- *** Constructors+ (=::), ($:), (!:), (>:)+) where++import Data.Loc as Loc+import Meta.THHelpers+import AST.Notable+import Util++import Prelude ()+import Data.Generics (Typeable, Data, extQ)+import Data.List (elemIndex)+import qualified Data.Map as M+import Language.Haskell.TH as TH++--+-- Representation of antiquotes+--++data Anti = Anti {+ anType :: String,+ anName :: String+ }+ deriving (Eq, Ord, Typeable, Data)++instance Show Anti where+ show (Anti "" aid) = '$' : aid+ show (Anti atag aid) = '$' : atag ++ ':' : aid++class AntiFail a where+ antifail :: a++instance Monad m => AntiFail (String -> Anti -> m b) where+ antifail who what = fail $+ "BUG! " ++ who ++ ": encountered antiquote " ++ show what++instance AntiFail (Name -> TH.ExpQ) where+ antifail a = do+ loc <- TH.location+ [| antifail $(stringE (show (fromTHLoc loc))) $(varE a) |]++instance AntiFail (TH.Q TH.Exp) where+ antifail = antifail (mkName "a")++class AntiError a where+ antierror :: a++instance AntiError (String -> Anti -> b) where+ antierror who what = error $+ "BUG! " ++ who ++ ": encountered antiquote " ++ show what++instance AntiError (Name -> TH.ExpQ) where+ antierror a = do+ loc <- TH.location+ [| antierror $(stringE (show (fromTHLoc loc))) $(varE a) |]++instance AntiError (TH.Q TH.Exp) where+ antierror = antierror (mkName "a")++class Antible a where+ injAnti :: Anti -> a+ prjAnti :: a -> Maybe Anti+ dictOf :: a -> AntiDict++ injAntiList :: Anti -> [a]+ prjAntiList :: [a] -> Maybe Anti+ dictOfList :: [a] -> AntiDict++ injAntiList = return . injAnti+ prjAntiList [a] = prjAnti a+ prjAntiList _ = Nothing+ dictOfList = const listAntis++instance Antible a => Antible [a] where+ injAnti = injAntiList+ prjAnti = prjAntiList+ dictOf = dictOfList++instance Antible a => Antible (Maybe a) where+ injAnti = return . injAnti+ prjAnti = (prjAnti =<<)+ dictOf = const optAntis++optAntis, listAntis :: AntiDict++listAntis + = "list" =: Nothing+ & "nil" =: Just (\_ -> conS '[] [])+ & "list1" =: Just (\v -> listS [varS (TH.mkName v) []])++optAntis+ = "opt" =: Nothing+ & "some" =:< 'Just+ & "none" =: Just (\_ -> conS 'Nothing [])++---+--- Deriving antiquotes+---++-- Given the syntax table, we need to derive instances of Antible+-- and antiquoters+deriveAntibles :: SyntaxTable -> TH.Q [TH.Dec]+deriveAntibles = concatMapM each where+ each SyntaxClass { scDict = Nothing } = return []+ each sc@SyntaxClass { scDict = Just dict } = do+ TH.TyConI tc <- reify (scName sc)+ tvs <- case tc of+ TH.DataD _ _ tvs _ _ -> return tvs+ TH.NewtypeD _ _ tvs _ _ -> return tvs+ TH.TySynD _ tvs _ -> return tvs+ _ -> fail "deriveAntibles requires type"+ a <- TH.newName "a"+ let wrapper p = case scWrap sc of+ Nothing -> p+ Just _ -> TH.conP 'N [TH.wildP, p]+ [InstanceD context hd decs] <-+ [d| instance Antible $(foldl TH.appT (TH.conT (scName sc))+ (map typeOfTyVarBndr tvs)) where+ injAnti = $(foldl+ (\e1 n2 -> [| $e1 . $(conE n2) |])+ (varE (maybe 'id id (scWrap sc)))+ (scAnti sc))+ prjAnti stx = $(caseE [| stx |] [+ match (wrapper+ (foldr+ (TH.conP <$.> (:[]))+ (TH.varP a)+ (scAnti sc)))+ (TH.normalB [| Just $(TH.varE a) |])+ [],+ match TH.wildP+ (TH.normalB [| Nothing |])+ []+ ])+ dictOf _ = $(varE dict)+ injAntiList = return . injAnti+ prjAntiList [b] = prjAnti b+ prjAntiList _ = Nothing+ dictOfList = const listAntis+ |]+ context' <- buildContext tvs (scCxt sc)+ return [InstanceD (context' ++ context) hd decs]++--+-- Location expanders+--++-- | Show a name, and strip "Notable." from it if necessary+showNot :: Show a => a -> String+showNot a = case show a of+ 'A':'S':'T':'.':rest+ -> "AST." ++ last (splitBy (== '.') rest)+ s -> s++class LocAst stx where+ toLocAstQ :: ToSyntax ast => TH.Name -> stx -> TH.Q ast++deriveLocAst :: Name -> SyntaxClass -> TH.Q [TH.Dec]+deriveLocAst _ SyntaxClass { scWrap = Nothing } = return []+deriveLocAst build SyntaxClass { scName = name, scCxt = context } = do+ info <- reify name+ case info of+ -- Located t i+ TyConI (TySynD _ _ (AppT (AppT _ (ConT _)) _)) ->+ thenNote ''LocNote+ -- N (note i) (t i)+ TyConI (TySynD _ _ (AppT (AppT _ (AppT (ConT note) _))+ (AppT (ConT _) _))) ->+ thenNote note+ _ -> return []+ where+ --+ thenNote note = do+ info <- reify note+ case info of+ TyConI (DataD _ _ _ [con] _) -> thenCon con+ TyConI (NewtypeD _ _ _ con _) -> thenCon con+ _ -> runIO (print (name, info)) >> return []+ --+ thenCon (ForallC _ _ con) = thenCon con+ thenCon (InfixC st1 dcon st2) = thenDCon dcon [snd st1, snd st2]+ thenCon (NormalC dcon sts) = thenDCon dcon (map snd sts)+ thenCon (RecC dcon vsts) = thenDCon dcon [t | (_,_,t) <- vsts]+ --+ thenDCon dcon ts+ | Just ix <- elemIndex (ConT ''Loc.Loc) ts = do+ i <- newName "i"+ [InstanceD [] hd decls] <-+ [d| instance LocAst ($(conT name) $(varT i)) where+ toLocAstQ loc stx =+ do+ let _ignore = $(stringE (showNot name))+ ast <- $(varE build) stx+ case ast of+ VarE _ -> return ast+ _ -> varS $(stringE (showNot 'setLoc))+ [return ast, varS loc []]+ `whichS'`+ do+ let pat preAstQ =+ conS $(stringE (showNot 'N))+ [ conS $(stringE (showNot dcon))+ $(listE [ if j == ix+ then [| varS loc [] |]+ else [| wildS |]+ | j <- [0 .. length ts - 1] ])+ , preAstQ ]+ ast <- $(varE build) stx+ case ast of+ VarP v -> asP v (pat wildP)+ ConP _ [_, preAst] -> pat (return preAst)+ _ -> fail $+ "BUG! toLocAstQ did not recognize " +++ "expanded code: " ++ show ast+ |]+ context' <- buildContext [PlainTV i] ((''Data, [0]) : context)+ return [InstanceD context' hd decls]+ | otherwise = return []++deriveLocAsts :: Name -> SyntaxTable -> TH.Q [TH.Dec]+deriveLocAsts name = concatMapM (deriveLocAst name)++--+-- Antiquote expanders+--++expandAntibles :: [Name] -> Name -> SyntaxTable -> ExpQ+expandAntibles params name = foldr each [| id |] where+ each sc rest = [| $(expandAntible params name sc) . $rest |]++expandAntible :: [Name] -> Name -> SyntaxClass -> ExpQ+expandAntible params build SyntaxClass { scName = name, scWrap = wrap } = do+ info <- reify name+ case info of+ TyConI (DataD _ _ [_] _ _) -> expandAntible1 params build wrap name+ TyConI (NewtypeD _ _ [_] _ _) -> expandAntible1 params build wrap name+ TyConI (TySynD _ [_] _) -> expandAntible1 params build wrap name+ _ -> expandAntible0 build wrap name++expandAntible0 :: Name -> Maybe Name -> Name -> ExpQ+expandAntible0 build maybeWrap typeName =+ [| $(expandAntibleType build maybeWrap [t| $_t |]) |]+ where _t = conT typeName++expandAntible1 :: [Name] -> Name -> Maybe Name -> Name -> ExpQ+expandAntible1 params build maybeWrap typeName =+ foldr (\a b -> [| $a . $b |]) [| id |]+ [ expandAntibleType build maybeWrap [t| $_t $(conT _p) |]+ | _p <- params ]+ where _t = conT typeName++expandAntibleType :: Name -> Maybe Name -> TypeQ -> ExpQ+expandAntibleType build maybeWrap _t =+ let main = case maybeWrap of+ Nothing ->+ [| \x -> expandAntiFun (x:: $_t) |]+ Just wrap ->+ [| \x -> expandWrappedAntiFun+ $(varE build)+ (mkName $(stringE (showNot wrap)))+ (x:: $_t) |]+ in+ [| (`extQ` $main)+ . (`extQ` (\x -> expandAntiFun (x:: Maybe $_t)))+ . (`extQ` (\x -> expandAntiFun (x:: [$_t]))) |]++expandWrappedAntiFun :: (Antible (N note a), ToSyntax b) =>+ (a -> Q b) -> Name -> N note a -> Maybe (Q b)+expandWrappedAntiFun build wrap stx =+ Just $ case prjAnti stx of+ Just (Anti tag name) -> case M.lookup tag (dictOf stx) of+ Just (Trans trans) -> case trans of+ Just f -> doWrap (f name)+ Nothing -> varS name []+ Nothing -> fail $+ "Unrecognized antiquote tag: `" ++ tag ++ "'"+ Nothing -> doWrap (build (dataOf stx))+ where+ doWrap preStx = varS wrap [preStx] `whichS` conS 'N [wildS, preStx]++expandAntiFun :: (Antible a, ToSyntax b) => a -> Maybe (Q b)+expandAntiFun stx = do+ Anti tag name <- prjAnti stx+ case M.lookup tag (dictOf stx) of+ Just trans -> return $ case unTrans trans of+ Just f -> f name+ Nothing -> varS name []+ Nothing -> fail $ "Unrecognized antiquote tag: `" ++ tag ++ "'"++--+-- Antiquote and syntax table+--++-- | A pat/exp-generic parser+type PreTrans = forall b. ToSyntax b => Maybe (String -> Q b)+-- | A pat/exp-generic parser, wrapped+newtype Trans = Trans { unTrans :: PreTrans }+-- | A dictionary mapping antiquote tags to parsers+type AntiDict = M.Map String Trans++-- | A descriptor for a syntactic category, used for generating+-- antiquotes+data SyntaxClass = SyntaxClass {+ scName :: Name,+ -- | The name of the constructor for antiquotes+ scAnti :: [Name],+ -- | The safe injection from the underlying type to the main type+ scWrap :: Maybe Name,+ -- | The dictionary of splice tags+ scDict :: Maybe Name,+ -- | Type class context required for wrapping+ scCxt :: [(Name, [Int])]+}++type SyntaxTable = [SyntaxClass]++-- | Construct a single syntax class from the type name and antiquote+-- constructor+class MkSyntaxClass a b where+ (=::) :: a -> b -> SyntaxClass++instance MkSyntaxClass TH.Name [TH.Name] where+ name =:: antis = SyntaxClass {+ scName = name,+ scAnti = antis,+ scWrap = Nothing,+ scDict = Nothing,+ scCxt = []+ }++instance MkSyntaxClass TH.Name TH.Name where+ name =:: anti = name =:: [anti]++-- | Extend a syntax class with the name of a function that lifts+-- from pre-syntax to syntax+(!:) :: SyntaxClass -> TH.Name -> SyntaxClass+tab !: name = tab { scWrap = Just name }++-- | Extend a syntax class with the name of an antiquote dictionary+($:) :: SyntaxClass -> TH.Name -> SyntaxClass+tab $: dict = tab { scDict = Just dict }++-- | Extend a syntax class with a context+(>:) :: SyntaxClass -> (Name, [Int]) -> SyntaxClass+tab >: context = tab { scCxt = context : scCxt tab }++infixl 2 =::, !:, $:, >:++-- | Append two antiquote dictionaries+(&) :: AntiDict -> AntiDict -> AntiDict+(&) = M.union++infixr 1 &++-- | Construct a singleton antiquote dictionary from a key and+-- generic parser+(=:) :: String -> PreTrans -> AntiDict+a =: b = M.singleton a (Trans b)++-- | Create singleton dictionary with default (tagless) entry+(=:!) :: String -> PreTrans -> AntiDict+a =:! b = M.union ("" =: b) (a =: b)++-- | Construct an antiquote dictionary for matching a+-- simple constructor+(=:<) :: String -> TH.Name -> AntiDict+a =:< n = a =:• [n]++-- | Construct an antiquote dictionary for matching a+-- composition of simple constructors+(=:•) :: String -> [TH.Name] -> AntiDict+a =:• ns = a =: Just (\v -> foldr (conS <$.> (:[])) (varS v []) ns)++-- | Construct an antiquote dictionary for matching sequences+-- of constructors, where there may be a different sequence+-- for expressions and patterns.+(=:••) :: String -> ([TH.Name], [TH.Name]) -> AntiDict+a =:•• (ins, outs) =+ a =: Just (\v -> head (foldr ((:[]) <$$> varS) [varS v []] ins)+ `whichS` head (foldr ((:[]) <$$> conS) [wildS, varS v []] outs))++infix 2 =:, =:!, =:<, =:•, =:••+
+ src/AST/Decl.hs view
@@ -0,0 +1,343 @@+module AST.Decl (+ -- * Declarations+ Decl'(..), Decl, DeclNote(..), newDecl,+ -- ** Type declarations+ TyDec'(..), TyDec, AbsTy'(..), AbsTy,+ -- ** Modules+ ModExp'(..), ModExp, newModExp,+ -- ** Signature+ SigExp'(..), SigExp, newSigExp,+ SigItem'(..), SigItem, newSigItem,+ -- ** Synthetic constructors+ -- | These fill in the source location fields with a bogus location+ dcLet, dcLetRec, dcTyp, dcAli, dcAbs, dcMod, dcSig, dcOpn,+ dcLoc, dcExn, dcAnti,+ absTy, absTyAnti,+ tdAbs, tdSyn, tdDat, tdAnti,+ meStr, meName, meAsc, meAnti,+ sgVal, sgTyp, sgAli, sgMod, sgSig, sgInc, sgExn, sgAnti,+ seSig, seName, seWith, seAnti,+ prog,++ -- * Programs+ Prog'(..), Prog,+ prog2decls+) where++import Util+import Meta.DeriveNotable+import AST.Notable+import AST.Anti+import AST.Kind+import AST.Ident+import AST.Type+import AST.Patt+import AST.Expr++import Prelude ()+import Data.Generics (Typeable(..), Data(..))+import qualified Data.Map as M++type Decl i = N (DeclNote i) (Decl' i)+type ModExp i = N (DeclNote i) (ModExp' i)+type SigItem i = N (DeclNote i) (SigItem' i)+type SigExp i = N (DeclNote i) (SigExp' i)+type Prog i = Located Prog' i+type AbsTy i = Located AbsTy' i+type TyDec i = Located TyDec' i++-- | A program is a sequence of declarations, maybe followed by an+-- expression+data Prog' i = Prog [Decl i] (Maybe (Expr i))+ deriving (Typeable, Data)++-- | Declarations+data Decl' i+ -- | Constant declaration+ = DcLet (Patt i) (Expr i)+ -- | Recursive value declaration+ | DcLetRec [Binding i]+ -- | Type declaration+ | DcTyp [TyDec i]+ -- | Type alias+ | DcAli (TypId i) (QTypId i)+ -- | Abstype block declaration+ | DcAbs [AbsTy i] [Decl i]+ -- | Module declaration+ | DcMod (ModId i) (ModExp i)+ -- | Signature declaration+ | DcSig (SigId i) (SigExp i)+ -- | Module open+ | DcOpn (ModExp i)+ -- | Local block+ | DcLoc [Decl i] [Decl i]+ -- | Exception declaration+ | DcExn (ConId i) (Maybe (Type i))+ -- | Antiquote+ | DcAnti Anti+ deriving (Typeable, Data)++-- | A module expression+data ModExp' i+ -- | A module literal+ = MeStr [Decl i]+ -- | A module variable+ | MeName (QModId i) [QVarId i]+ -- | A signature ascription+ | MeAsc (ModExp i) (SigExp i)+ -- | An antiquote+ | MeAnti Anti+ deriving (Typeable, Data)++-- | A signature item+data SigItem' i+ -- | A value+ = SgVal (VarId i) (Type i)+ -- | A type+ | SgTyp [TyDec i]+ -- | Type alias+ | SgAli (TypId i) (QTypId i)+ -- | A module+ | SgMod (ModId i) (SigExp i)+ -- | A signature+ | SgSig (SigId i) (SigExp i)+ -- | Signature inclusion+ | SgInc (SigExp i)+ -- | An exception+ | SgExn (ConId i) (Maybe (Type i))+ -- | An antiquote+ | SgAnti Anti+ deriving (Typeable, Data)++-- | A module type expression+data SigExp' i+ -- | A signature literal+ = SeSig [SigItem i]+ -- | A signature variable+ | SeName (QSigId i) [QVarId i]+ -- | Type-level fibration+ | SeWith (SigExp i) (QTypId i) [TyVar i] (Type i)+ -- | An antiquote+ | SeAnti Anti+ deriving (Typeable, Data)++-- | Affine language type declarations+data TyDec' i+ -- | An abstract (empty) type+ = TdAbs {+ tdName :: TypId i,+ tdParams :: [TyVar i],+ -- | The variance of each parameter+ tdVariances :: [Variance],+ -- | Which the parameters guard equirecursion?+ tdGuards :: [TyVar i],+ -- | Whether each parameter contributes to the qualifier+ tdQual :: QExp i+ }+ -- | A type operator or synonym+ | TdSyn {+ tdName :: TypId i,+ tdClauses :: [([TyPat i], Type i)]+ }+ -- | An algebraic datatype+ | TdDat {+ tdName :: TypId i,+ tdParams :: [TyVar i],+ tdAlts :: [(ConId i, Maybe (Type i))]+ }+ | TdAnti Anti+ deriving (Typeable, Data)++-- | An abstract type needs to specify variances and the qualifier+data AbsTy' i+ = AbsTy {+ atvariance :: [Variance],+ atquals :: QExp i,+ atdecl :: TyDec i+ }+ | AbsTyAnti Anti+ deriving (Typeable, Data)++data DeclNote i+ = DeclNote {+ -- | source location+ dloc_ :: !Loc,+ -- | free variables+ dfv_ :: FvMap i,+ -- | defined variables+ ddv_ :: [QVarId i]+ }+ deriving (Typeable, Data)++instance Locatable (DeclNote i) where+ getLoc = dloc_++instance Relocatable (DeclNote i) where+ setLoc note loc = note { dloc_ = loc }++instance Notable (DeclNote i) where+ newNote = DeclNote bogus M.empty mempty++newDecl :: Tag i => Decl' i -> Decl i+newDecl d0 = flip N d0 $ case d0 of+ DcLet p1 e2 ->+ newNote {+ dloc_ = getLoc (p1, e2),+ dfv_ = fv e2,+ ddv_ = qdv p1+ }+ DcLetRec bns ->+ newNote {+ dloc_ = getLoc bns,+ dfv_ = fv bns,+ ddv_ = map (J [] . bnvar . dataOf) bns+ }+ DcTyp tds ->+ newNote {+ dloc_ = getLoc tds+ }+ DcAli _ _ ->+ newNote+ DcAbs at1 ds2 ->+ newNote {+ dloc_ = getLoc (at1, ds2),+ dfv_ = fv ds2,+ ddv_ = concatMap qdv ds2+ }+ DcMod u1 me2 ->+ newNote {+ dloc_ = getLoc me2,+ dfv_ = fv me2,+ ddv_ = (u1 <.>) <$> qdv me2+ }+ DcSig _ se2 ->+ newNote {+ dloc_ = getLoc se2+ }+ DcOpn me1 ->+ newNote {+ dloc_ = getLoc me1,+ dfv_ = fv me1,+ ddv_ = qdv me1+ }+ DcLoc ds1 ds2 ->+ newNote {+ dloc_ = getLoc (ds1, ds2),+ dfv_ = fv ds1 |+| (fv ds2 |--| qdv ds1),+ ddv_ = qdv ds2+ }+ DcExn _ t2 ->+ newNote {+ dloc_ = getLoc t2+ }+ DcAnti a ->+ newNote {+ dfv_ = antierror "fv" a,+ ddv_ = antierror "dv" a+ }++newModExp :: Tag i => ModExp' i -> ModExp i+newModExp me0 = flip N me0 $ case me0 of+ MeStr ds ->+ newNote {+ dloc_ = getLoc ds,+ dfv_ = fv ds,+ ddv_ = qdv ds+ }+ MeName _ qls ->+ newNote {+ ddv_ = qls+ }+ MeAsc me se ->+ newNote {+ dloc_ = getLoc (me, se),+ dfv_ = fv me,+ ddv_ = qdv se+ }+ MeAnti a ->+ newNote {+ dfv_ = antierror "fv" a,+ ddv_ = antierror "dv" a+ }++newSigItem :: Tag i => SigItem' i -> SigItem i+newSigItem d0 = flip N d0 $ case d0 of+ SgVal l1 t2 ->+ newNote {+ dloc_ = getLoc t2,+ ddv_ = [J [] l1]+ }+ SgTyp tds ->+ newNote {+ dloc_ = getLoc tds+ }+ SgAli _ _ ->+ newNote+ SgMod u1 se2 ->+ newNote {+ dloc_ = getLoc se2,+ ddv_ = (u1 <.>) <$> qdv se2+ }+ SgSig _ se2 ->+ newNote {+ dloc_ = getLoc se2+ }+ SgInc se1 ->+ newNote {+ dloc_ = getLoc se1,+ ddv_ = qdv se1+ }+ SgExn _ t2 ->+ newNote {+ dloc_ = getLoc t2+ }+ SgAnti a ->+ newNote {+ dfv_ = antierror "fv" a,+ ddv_ = antierror "dv" a+ }++newSigExp :: Tag i => SigExp' i -> SigExp i+newSigExp se0 = flip N se0 $ case se0 of+ SeSig sis ->+ newNote {+ dloc_ = getLoc sis,+ ddv_ = qdv sis+ }+ SeName _ qls ->+ newNote {+ ddv_ = qls+ }+ SeWith se1 _ _ t3 ->+ newNote {+ dloc_ = getLoc (se1, t3),+ ddv_ = qdv se1+ }+ SeAnti a ->+ newNote {+ dfv_ = antierror "fv" a,+ ddv_ = antierror "dv" a+ }++instance Tag i => Fv (N (DeclNote i) a) i where fv = dfv_ . noteOf+instance Tag i => Dv (N (DeclNote i) a) i where qdv = ddv_ . noteOf++deriveNotable 'newDecl (''Tag, [0]) ''Decl+deriveNotable 'newModExp (''Tag, [0]) ''ModExp+deriveNotable 'newSigItem (''Tag, [0]) ''SigItem+deriveNotable 'newSigExp (''Tag, [0]) ''SigExp+deriveNotable ''AbsTy+deriveNotable ''TyDec+deriveNotable ''Prog++---+--- Syntax Utils+---++-- | Turn a program into a sequence of declarations by replacing+-- the final expression with a declaration of variable 'it'.+prog2decls :: Tag i => Prog i -> [Decl i]+prog2decls (N _ (Prog ds (Just e)))+ = ds ++ [dcLet (paVar (ident "it")) e]+prog2decls (N _ (Prog ds Nothing))+ = ds
+ src/AST/Decl.hs-boot view
@@ -0,0 +1,26 @@+-- vim: ft=haskell+{-# LANGUAGE+ FlexibleInstances,+ MultiParamTypeClasses,+ TypeFamilies,+ TypeSynonymInstances #-}+{-# OPTIONS_GHC -w #-}+module AST.Decl where++import AST.Notable+import AST.Ident (Tag, Fv, Dv)++import Data.Data (Data, Typeable1)++data DeclNote i+data Decl' i+type Decl i = N (DeclNote i) (Decl' i)++instance Typeable1 DeclNote+instance Typeable1 Decl'+instance Tag i => Data (DeclNote i)+instance Tag i => Data (Decl' i)+instance Locatable (DeclNote i)+instance Notable (DeclNote i)+instance Tag i => Fv (N (DeclNote i) a) i+instance Tag i => Dv (N (DeclNote i) a) i
+ src/AST/Expr.hs view
@@ -0,0 +1,403 @@+module AST.Expr (+ -- * Expressions+ Expr'(..), Expr, ExprNote(..), newExpr,+ -- ** Letrec and case+ Binding'(..), Binding, newBinding,+ CaseAlt'(..), CaseAlt, newCaseAlt,+ Field'(..), Field, newField,++ -- * Two-level expression constructors+ -- | These fill in the source location field based on the+ -- subexpressions and perform the free variable analysis+ -- | variables+ exVar, exLit, exCon, exLet, exCase, exLetRec, exLetDecl,+ exPair, exAbs, exApp, exInj, exEmb, exCast, exRec, exSel, exAnti,++ caClause, caPrj, caAnti,+ bnBind, bnAnti,+ fdField, fdAnti,+ -- ** Synthetic expression constructors+ exBVar, exBCon,+ exChar, exStr, exInt, exFloat,+ exSeq,+ exUnit, exNilRecord,+ exNil, exCons,+ ToExpr(..),++ -- * Expression accessors and updaters+ syntacticValue, isAnnotated, getExprAnnot, cafakepatt,+) where++import Util+import AST.Notable+import AST.Anti+import AST.Ident+import AST.Type+import AST.Lit+import AST.Patt+import {-# SOURCE #-} AST.Decl++import Meta.DeriveNotable++import Prelude ()+import Data.Generics (Typeable(..), Data(..))+import qualified Data.Map as M++type Expr i = N (ExprNote i) (Expr' i)+type Binding i = N (ExprNote i) (Binding' i)+type CaseAlt i = N (ExprNote i) (CaseAlt' i)+type Field i = N (ExprNote i) (Field' i)++-- | The underlying expression type, which we can pattern match without+-- dealing with the common fields above.+data Expr' i+ -- | variables+ = ExVar (QVarId i)+ -- | literals+ | ExLit Lit+ -- | data construction+ | ExCon (QConId i) (Maybe (Expr i))+ -- | let expressions+ | ExLet (Patt i) (Expr i) (Expr i)+ -- | case expressions (including desugared @if@)+ | ExCase (Expr i) [CaseAlt i]+ -- | recursive let expressions+ | ExLetRec [Binding i] (Expr i)+ -- | nested declarations+ | ExLetDecl (Decl i) (Expr i)+ -- | pair construction+ | ExPair (Expr i) (Expr i)+ -- | lambda+ | ExAbs (Patt i) (Expr i)+ -- | application+ | ExApp (Expr i) (Expr i)+ -- | open variant construction+ | ExInj (Uid i) (Maybe (Expr i))+ -- | open variant embedding+ | ExEmb (Uid i) (Expr i)+ -- | record extension+ -- (@True@ means additive rather than multiplicative records)+ | ExRec Bool [Field i] (Expr i)+ -- | record lookup+ | ExSel (Expr i) (Uid i)+ -- | dynamic promotion (True) or static type ascription (False)+ | ExCast (Expr i) (Type i) Bool+ -- | antiquotes+ | ExAnti Anti+ deriving (Typeable, Data)++-- | Let-rec bindings require us to give types+data Binding' i+ = BnBind {+ bnvar :: VarId i,+ bnexpr :: Expr i+ }+ | BnAnti Anti+ deriving (Typeable, Data)++data CaseAlt' i+ -- | Normal match clauses+ = CaClause {+ capatt :: Patt i,+ caexpr :: Expr i+ }+ -- | Open variant elimination+ | CaPrj {+ calab :: Uid i,+ campatt :: Maybe (Patt i),+ caexpr :: Expr i+ }+ -- | Antiquote+ | CaAnti Anti+ deriving (Typeable, Data)++data Field' i+ -- | Normal match clauses+ = FdField {+ fdsel :: Uid i,+ fdexpr :: Expr i+ }+ -- | Antiquote+ | FdAnti Anti+ deriving (Typeable, Data)++-- | The annotation on every expression+data ExprNote i+ = ExprNote {+ -- | source location+ eloc_ :: !Loc,+ -- | free variables+ efv_ :: FvMap i+ }+ deriving (Typeable, Data)++instance Locatable (ExprNote i) where+ getLoc = eloc_++instance Relocatable (ExprNote i) where+ setLoc note loc = note { eloc_ = loc }++-- | Types with free variable analyses+instance Tag i => Fv (N (ExprNote i) a) i where fv = efv_ . noteOf++instance Dv (N (ExprNote i) (Binding' i)) i where+ dv (N _ (BnBind f _)) = [f]+ dv (N _ (BnAnti _)) = []++instance Notable (ExprNote i) where+ newNote = ExprNote {+ eloc_ = bogus,+ efv_ = M.empty+ }++newExpr :: Tag i => Expr' i -> Expr i+newExpr e0 = flip N e0 $ case e0 of+ ExVar v ->+ newNote {+ efv_ = M.singleton v 1+ }+ ExLit _ -> newNote+ ExCon _ me2 ->+ newNote {+ efv_ = fv me2,+ eloc_ = getLoc me2+ }+ ExLet x1 e2 e3 ->+ newNote {+ efv_ = fv e2 |*| (fv e3 |--| qdv x1),+ eloc_ = getLoc (x1, e2, e3)+ }+ ExCase e1 cas ->+ newNote {+ efv_ = fv e1 |*| fv (ADDITIVE cas),+ eloc_ = getLoc (e1, cas)+ }+ ExLetRec bns e2 ->+ newNote {+ efv_ = let vs = map (J [] . bnvar . dataOf) bns+ pot = fv e2 |*| fv bns+ in foldl (|-|) pot vs,+ eloc_ = getLoc (bns, e2)+ }+ ExLetDecl d1 e2 ->+ newNote {+ efv_ = fv d1 |*| (fv e2 |--| qdv d1),+ eloc_ = getLoc (d1, e2)+ }+ ExPair e1 e2 ->+ newNote {+ efv_ = fv e1 |*| fv e2,+ eloc_ = getLoc (e1, e2)+ }+ ExAbs p1 e2 ->+ newNote {+ efv_ = fv e2 |--| qdv p1,+ eloc_ = getLoc (p1, e2)+ }+ ExApp e1 e2 ->+ newNote {+ efv_ = fv e1 |*| fv e2,+ eloc_ = getLoc (e1, e2)+ }+ ExInj _ me2 ->+ newNote {+ efv_ = fv me2,+ eloc_ = getLoc me2+ }+ ExEmb _ e2 ->+ newNote {+ efv_ = fv e2,+ eloc_ = getLoc e2+ }+ ExRec True flds e2 ->+ newNote {+ efv_ = fv (ADDITIVE flds) |*| fv e2,+ eloc_ = getLoc (flds, e2)+ }+ ExRec False flds e2 ->+ newNote {+ efv_ = fv flds |*| fv e2,+ eloc_ = getLoc (flds, e2)+ }+ ExSel e1 _ ->+ newNote {+ efv_ = fv e1,+ eloc_ = getLoc e1+ }+ ExCast e1 t2 _ ->+ newNote {+ efv_ = fv e1,+ eloc_ = getLoc (e1, t2)+ }+ ExAnti a ->+ newNote {+ efv_ = antierror "fv" a+ }++newBinding :: Tag i => Binding' i -> Binding i+newBinding b0 = flip N b0 $ case b0 of+ BnBind x e ->+ newNote {+ efv_ = fv e |-| J [] x,+ eloc_ = getLoc e+ }+ BnAnti a ->+ newNote {+ efv_ = antierror "fv" a+ }++newCaseAlt :: Tag i => CaseAlt' i -> CaseAlt i+newCaseAlt ca0 = flip N ca0 $ case ca0 of+ CaClause x e ->+ newNote {+ efv_ = fv e |--| qdv x,+ eloc_ = getLoc (x, e)+ }+ CaPrj _ mx e ->+ newNote {+ efv_ = fv e |--| qdv mx,+ eloc_ = getLoc (mx, e)+ }+ CaAnti a ->+ newNote {+ efv_ = antierror "fv" a+ }++newField :: Tag i => Field' i -> Field i+newField f0 = flip N f0 $ case f0 of+ FdField _ e ->+ newNote {+ efv_ = fv e,+ eloc_ = getLoc e+ }+ FdAnti a ->+ newNote {+ efv_ = antierror "fv" a+ }++deriveNotable 'newExpr (''Tag, [0]) ''Expr+deriveNotable 'newCaseAlt (''Tag, [0]) ''CaseAlt+deriveNotable 'newBinding (''Tag, [0]) ''Binding+deriveNotable 'newField (''Tag, [0]) ''Field++exBVar :: Tag i => VarId i -> Expr i+exBVar = exVar . J []++exBCon :: Tag i => ConId i -> Maybe (Expr i) -> Expr i+exBCon = exCon . J []++exChar :: Tag i => Char -> Expr i+exChar = exLit . LtChar++exStr :: Tag i => String -> Expr i+exStr = exLit . LtStr++exInt :: (Tag i, Integral a) => a -> Expr i+exInt = exLit . LtInt . toInteger++exFloat :: Tag i => Double -> Expr i+exFloat = exLit . LtFloat++exSeq :: Tag i => Expr i -> Expr i -> Expr i+exSeq e1 e2 = exLet paWild e1 e2++exUnit, exNilRecord :: Tag i => Expr i+exUnit = exCon idUnitVal Nothing+exNilRecord = exVar idNilRecord++exCons :: Tag i => Expr i -> Expr i -> Expr i+exCons = exCon idConsList . Just <$$> exPair++exNil :: Tag i => Expr i+exNil = exCon idNilList Nothing++class ToExpr a i | a → i where+ toExpr ∷ a → Expr i++instance ToExpr (Expr i) i where+ toExpr = id++instance Tag i ⇒ ToExpr (QVarId i) i where+ toExpr = exVar++instance Tag i ⇒ ToExpr (VarId i) i where+ toExpr = exBVar++instance (Tag i, ToExpr a i, ToExpr b i) ⇒ ToExpr (a, b) i where+ toExpr (a, b) = exPair (toExpr a) (toExpr b)++instance Tag i ⇒ ToExpr String i where+ toExpr = exStr++instance Tag i ⇒ ToExpr Int i where+ toExpr = exInt++instance Tag i ⇒ ToExpr Char i where+ toExpr = exChar++instance Tag i ⇒ ToExpr Double i where+ toExpr = exFloat++-- | Is the expression conservatively side-effect free?+syntacticValue :: Expr i -> Bool+syntacticValue e = case view e of+ ExVar _ → True+ ExLit _ → True+ ExCon _ me → maybe True syntacticValue me+ ExLet _ e1 e2 → syntacticValue e1 && syntacticValue e2+ ExCase _ _ → False+ ExLetRec bs e2 → all eachBinding bs && syntacticValue e2 where+ eachBinding bn = case view bn of+ BnBind { bnexpr = e' } → syntacticValue e'+ BnAnti a → antierror "syntacticValue" a+ ExLetDecl _ _ → False+ ExPair e1 e2 → syntacticValue e1 && syntacticValue e2+ ExAbs _ _ → True+ ExApp _ _ → False+ ExInj _ me → maybe True syntacticValue me+ ExEmb _ e1 → syntacticValue e1+ ExRec b flds e2+ → b ||+ (and [ syntacticValue ei | FdField _ ei ← view <$> flds ]+ && syntacticValue e2)+ ExSel _ _ → False+ ExCast e1 _ b → syntacticValue e1 && not b+ ExAnti a → antierror "syntacticValue" a++-- | Is the expression annotated with a type ascription or dynamic cast?+isAnnotated ∷ Expr i → Bool+isAnnotated e = case view e of+ ExVar _ → False+ ExLit _ → False+ ExCon _ _ → False+ ExLet _ _ e2 → isAnnotated e2+ ExCase _ cs → all eachClause cs where+ eachClause c = case view c of+ CaClause { caexpr = e' } → isAnnotated e'+ CaPrj { caexpr = e' } → isAnnotated e'+ CaAnti a → antierror "isAnnotated" a+ ExLetRec _ e2 → isAnnotated e2+ ExLetDecl _ e2 → isAnnotated e2+ ExPair _ _ → False+ ExAbs _ _ → False+ ExApp _ _ → False+ ExInj _ _ → False+ ExEmb _ _ → False+ ExRec _ _ _ → False+ ExSel _ _ → False+ ExCast _ _ _ → True+ ExAnti a → antierror "syntacticValue" a++-- | Get the (static) type annotation on an expression+getExprAnnot ∷ Expr i → Maybe (Type i)+getExprAnnot e0 = case view e0 of+ ExCast _ annot False → Just annot+ _ → Nothing++-- | Given a case alternative, produce a (potentially fake)+-- representation of its pattern, suitable for printing.+cafakepatt ∷ Tag i ⇒ CaseAlt i → Patt i+cafakepatt ca0 = case view ca0 of+ CaClause x _ → x+ CaPrj u mx _ → paCon (qident ('#':idName u)) mx+ CaAnti a → $antierror
+ src/AST/Ident.hs view
@@ -0,0 +1,547 @@+{-# LANGUAGE TypeFamilies #-}+module AST.Ident (+ -- * Identifier classes+ Id(..),+ -- ** Tags+ Tag(..), Raw(..), Renamed(..), renamed0, renTrivial,+ -- *** Dirty tricks+ dirtyTrivialRename,+ -- * Identifiers+ -- ** High level+ TypId(..), QTypId,+ VarId(..), QVarId,+ ConId(..), QConId,+ ModId(..), QModId,+ SigId(..), QSigId,+ TyVar(..), tvUn, tvAf,+ -- ** Low level+ Path(..), (<.>),+ Lid(..), QLid,+ Uid(..), QUid,+ BIdent(..), Ident,+ -- *** Operations+ isOperator, uidToLid, lidToUid,+ -- * Fresh names+ tvalphabet, freshName, freshNames,+ -- * Build-in names+ idUnitVal, idNilRecord, idNilList, idConsList,+ idTrueValue, idFalseValue,+ internalPath, internalName, internalIdent,+ -- * Free and defined vars+ Occurrence, occToQLit,+ FvMap, Fv(..), Dv(..), ADDITIVE(..),+ (|*|), (|+|), (|-|), (|--|),+) where++import Env (Path(..), (:>:)(..), (<.>))+import Util+import AST.Anti+import AST.Notable+import AST.Kind (QLit(..))+import qualified Syntax.Strings as Strings++import Prelude ()+import Data.Char (isAlpha, isDigit, isUpper, toUpper, toLower)+import Data.Generics (Typeable(..), Typeable1, Data(..), everywhere, mkT)+import qualified Data.List as List+import qualified Data.Map as M+import qualified Data.Set as S+import qualified Unsafe.Coerce++class (IsBogus i, Data i) => Tag i where+ -- The trivial identity tag, used when the identity tag is+ -- insufficient to distinguish different thing+ trivialId :: i+ trivialId = bogus+ -- Check for triviality+ isTrivial :: i -> Bool+ isTrivial = isBogus+ -- Compare two identifiers, given a secondary criterion to use if+ -- necessary+ compareId :: i -> i -> Ordering -> Ordering++data Raw = Raw_+ deriving (Data, Typeable, Show)++newtype Renamed = Ren_ Int+ deriving (Data, Typeable, Enum, Eq, Ord)++instance Bogus Raw where+ bogus = Raw_++instance IsBogus Raw where+ isBogus _ = True++instance Tag Raw where+ compareId _ _ = id++instance Show Renamed where+ showsPrec p (Ren_ z) = showsPrec p z++instance Bogus Renamed where+ bogus = Ren_ 0++instance IsBogus Renamed where+ isBogus (Ren_ 0) = True+ isBogus _ = False++instance Tag Renamed where+ compareId (Ren_ 0) (Ren_ 0) next = next+ compareId (Ren_ 0) _ _ = LT+ compareId _ (Ren_ 0) _ = GT+ compareId (Ren_ a) (Ren_ b) _ = a `compare` b++renamed0 :: Renamed+renamed0 = Ren_ 1++-- | This is super dirty+{-# NOINLINE dirtyTrivialRename #-}+dirtyTrivialRename :: forall f i j. (Tag i, Tag j, Data (f i)) => f i -> f j+dirtyTrivialRename = Unsafe.Coerce.unsafeCoerce . everywhere (mkT each) where+ each :: i -> i+ each _ = Unsafe.Coerce.unsafeCoerce (trivialId :: j)++---+--- Generic identifiers+---++-- | A module path to an identifier+type Q a i = Path (ModId i) (a i)++-- | Generic identifiers and operations+class (Typeable1 a,+ Data (a Raw), Eq (a Raw), Ord (a Raw), Bogus (a Raw),+ Data (a Renamed), Eq (a Renamed), Ord (a Renamed), Bogus (a Renamed))+ ⇒+ Id a where+ idTag ∷ a i → i+ idName ∷ a i → String+ ident ∷ Tag i ⇒ String → a i+ identT ∷ i → String → a i+ qident ∷ Tag i ⇒ String → Path (ModId i) (a i)+ renId ∷ i' → a i → a i'+ --+ ident = identT bogus+ qident s = case reverse (splitBy (=='.') s) of+ [] -> J [] (ident "")+ x:xs -> J (map ident (reverse xs)) (ident x)+ renId = identT <$.> idName++renTrivial ∷ (Id a, Tag i) ⇒ a i' → a i+renTrivial = renId trivialId++---+--- LOW-LEVEL IDENTIFIERS+---++--+-- Lowercase+--++-- | lowercase identifiers (variables, tycons)+data Lid i+ = Lid {+ lidUnique :: !i,+ unLid :: !String+ }+ | LidAnti Anti+ deriving (Typeable, Data)++-- | path-qualified lowecase identifiers+type QLid i = Q Lid i++instance Tag i => Eq (Lid i) where+ a == b = compare a b == EQ++instance Tag i => Ord (Lid i) where+ Lid u1 s1 `compare` Lid u2 s2 = compareId u1 u2 (compare s1 s2)+ LidAnti a `compare` _ = antierror "Lid#compare" a+ _ `compare` LidAnti a = antierror "Lid#compare" a++instance Tag i => Bogus (Lid i) where+ bogus = Lid bogus "<bogus>"++instance Id Lid where+ idTag = lidUnique+ idName = unLid+ identT = Lid++-- | Is the lowercase identifier an infix operator?+isOperator :: Lid i -> Bool+isOperator l = case show l of+ '(':_ -> True+ _ -> False++--+-- Uppercase+--++-- | uppercase identifiers (modules, datacons)+data Uid i+ = Uid {+ uidUnique :: !i,+ unUid :: !String+ }+ | UidAnti Anti+ deriving (Typeable, Data)++-- | path-qualified uppercase identifiers+type QUid i = Q Uid i++instance Tag i => Eq (Uid i) where+ a == b = compare a b == EQ++instance Tag i => Ord (Uid i) where+ Uid u1 s1 `compare` Uid u2 s2 = compareId u1 u2 (compare s1 s2)+ UidAnti a `compare` _ = antierror "Uid#compare" a+ _ `compare` UidAnti a = antierror "Uid#compare" a++instance Tag i => Bogus (Uid i) where+ bogus = Uid bogus "<bogus>"++instance Id Uid where+ idTag = uidUnique+ idName = unUid+ identT = Uid++--+-- Mixed upper and lower+--++uidToLid :: Uid i -> Lid i+uidToLid (Uid ix s) = Lid ix (mapHead toLower s)+uidToLid (UidAnti a) = antierror "uidToLid" a++lidToUid :: Lid i -> Uid i+lidToUid (Lid ix s) = Uid ix (mapHead toUpper s)+lidToUid (LidAnti a) = antierror "lidToUid" a++-- | Bare (unqualified) identifers of unknown sort+data BIdent i = Var { unVar :: !(Lid i) }+ | Con { unCon :: !(Uid i) }+ deriving (Eq, Ord, Typeable, Data)++-- | Path-qualified identifiers+type Ident i = Q BIdent i++instance Tag i => Bogus (BIdent i) where+ bogus = Var bogus++instance Id BIdent where+ idTag (Var n) = idTag n+ idTag (Con n) = idTag n+ idName (Var n) = idName n+ idName (Con n) = idName n+ identT i s =+ if isUpperIdentifier s+ then Con (identT i s)+ else Var (identT i s)+ where+ -- | Is the string an uppercase identifier? (Special case: @true@ and+ -- @false@ are consider uppercase.)+ -- (This code is duplicated from Syntax.Lexer!)+ isUpperIdentifier "true" = True+ isUpperIdentifier "false" = True+ isUpperIdentifier "()" = True+ isUpperIdentifier (c:_) = isUpper c+ isUpperIdentifier _ = False++---+--- Specific identifiers+---++-- | Type names+newtype TypId i = TypId { unTypId ∷ Lid i }+ deriving (Typeable, Data, Eq, Ord, Bogus)++-- | Variable names+newtype VarId i = VarId { unVarId ∷ Lid i }+ deriving (Typeable, Data, Eq, Ord, Bogus)++-- | Data constructor names+newtype ConId i = ConId { unConId ∷ Uid i }+ deriving (Typeable, Data, Eq, Ord, Bogus)++-- | Module names+newtype ModId i = ModId { unModId ∷ Uid i }+ deriving (Typeable, Data, Eq, Ord, Bogus)++-- | Module type names+newtype SigId i = SigId { unSigId ∷ Uid i }+ deriving (Typeable, Data, Eq, Ord, Bogus)++-- | Qualified type names+type QTypId i = Q TypId i+-- | Qualified variable names+type QVarId i = Q VarId i+-- | Qualified data constructor names+type QConId i = Q ConId i+-- | Qualified module names+type QModId i = Q ModId i+-- | Qualified module type names+type QSigId i = Q SigId i++instance Id TypId where+ idName = idName . unTypId+ idTag = idTag . unTypId+ identT = TypId <$$> identT++instance Id VarId where+ idName = idName . unVarId+ idTag = idTag . unVarId+ identT = VarId <$$> identT++instance Id ConId where+ idName = idName . unConId+ idTag = idTag . unConId+ identT = ConId <$$> identT++instance Id ModId where+ idName = idName . unModId+ idTag = idTag . unModId+ identT = ModId <$$> identT++instance Id SigId where+ idName = idName . unSigId+ idTag = idTag . unSigId+ identT = SigId <$$> identT++--+-- Type variables+--++-- | Type variables include qualifiers+data TyVar i+ = TV {+ tvname :: !(Lid i),+ tvqual :: !QLit,+ tvloc :: !Loc+ }+ | TVAnti Anti+ deriving (Typeable, Data)++tvUn, tvAf :: Tag i => String -> TyVar i+tvUn s = TV (ident s) Qu bogus+tvAf s = TV (ident s) Qa bogus++instance Tag i => Eq (TyVar i) where+ a == b = tvname a == tvname b && tvqual a == tvqual b++instance Tag i => Ord (TyVar i) where+ a `compare` b = tvname a `compare` tvname b+ `thenCmp` tvqual a `compare` tvqual b++instance Locatable (TyVar i) where+ getLoc TV { tvloc = loc } = loc+ getLoc _ = bogus++instance Relocatable (TyVar i) where+ setLoc tv@TV { } loc = tv { tvloc = loc }+ setLoc tv _ = tv++instance Tag i => Bogus (TyVar i) where+ bogus = TV bogus Qa bogus++instance Id TyVar where+ idName (TV n _ _) = idName n+ idName (TVAnti a) = antierror "idName" a+ idTag (TV n _ _) = idTag n+ idTag (TVAnti a) = antierror "idTag" a+ identT i n = TV (identT i n) Qa bogus+ renId i (TV n q l) = TV (renId i n) q l+ renId _ (TVAnti a) = antierror "renId" a++---+--- 'Show' INSTANCES+---++instance Show (Lid i) where+ showsPrec _ (Lid _ s) = showsIdent s+ showsPrec p (LidAnti a) = showsPrec p a++instance Show (Uid i) where+ showsPrec _ (Uid _ s@('?':_)) = showString s+ showsPrec _ (Uid _ s) = showsIdent s+ showsPrec p (UidAnti a) = showsPrec p a++-- | Show an identifier with parens if necessary+showsIdent ∷ String → ShowS+showsIdent s = case s of+ '_':_ -> (s++)+ c :_ | isAlpha c -> (s++)+ c :_ | isDigit c -> (s++)+ _ :_ | head s == '*' || last s == '*'+ -> ("( "++) . (s++) . (" )"++)+ _ -> ('(':) . (s++) . (')':)++instance Show (BIdent i) where+ showsPrec p (Var x) = showsPrec p x+ showsPrec p (Con k) = showsPrec p k++instance Show (TypId i) where showsPrec p = showsPrec p . unTypId+instance Show (VarId i) where showsPrec p = showsPrec p . unVarId+instance Show (ConId i) where showsPrec p = showsPrec p . unConId+instance Show (ModId i) where showsPrec p = showsPrec p . unModId+instance Show (SigId i) where showsPrec p = showsPrec p . unSigId++instance Show (TyVar i) where+ showsPrec _ (TV x Qu _) = showString Strings.unlimited . showString (unLid x)+ showsPrec _ (TV x Qa _) = showString Strings.affine . showString (unLid x)+ showsPrec _ (TVAnti a) = showString Strings.affine . shows a++instance Viewable (Path (ModId i) (BIdent i)) where+ type View (Path (ModId i) (BIdent i)) = Either (QLid i) (QUid i)+ view (J p (Var n)) = Left (J p n)+ view (J p (Con n)) = Right (J p n)++-- | Simple keys embed into path keyspace+instance (Ord p, (:>:) k k') =>+ (:>:) (Path p k) k' where liftKey = J [] . liftKey++instance Tag i => (:>:) (BIdent i) (Lid i) where liftKey = Var+instance Tag i => (:>:) (BIdent i) (Uid i) where liftKey = Con++---+--- Name generation+---++-- | Given a base name, produces the list of names starting with the+-- base name, then with a prime added, and then with numeric+-- subscripts increasing from 1.+namesFrom ∷ String → [String]+namesFrom s = [ c:n | n ← "" : map numberSubscript [0 ..], c ← s ]++-- | Given a natural number, represent it as a string of number+-- subscripts.+numberSubscript ∷ Int → String+numberSubscript 0 = [head Strings.digits]+numberSubscript n0+ | n0 < 0 = error "BUG! numberSubscript requires non-negative Int"+ | otherwise = reverse $ List.unfoldr each n0 where+ each 0 = Nothing+ each n = Just (Strings.digits !! ones, rest)+ where (rest, ones) = n `divMod` 10++-- | Clear the primes and subscripts from the end of a name+clearScripts ∷ String → String+clearScripts n = case reverse (dropWhile (`elem` scripts) (reverse n)) of+ [] → n+ n' → n'+ where scripts = "'′" ++ Strings.unicodeDigits ++ Strings.asciiDigits++tvalphabet ∷ [String]+tvalphabet = namesFrom Strings.tvNames++-- | @freshName sugg qlit avoid cands@ attempts to generate a fresh+-- type variable name as follows:+--+-- * if @sugg@ is @Here n@, then it returns @n@ if @n@ is not in+-- @avoid@, and otherwise subscripts @n@ until if finds a fresh+-- name.+--+-- * Otherwise, return the first name from @cands@ that isn't in+-- @avoid@.+--+freshName ∷ Optional t ⇒ t String → [String] → [String] → String+freshName pn avoid cands = case coerceOpt pn of+ Just n+ | okay n → n+ | otherwise → takeFrom (namesFrom (clearScripts n))+ Nothing → takeFrom (cands ++ namesFrom "a")+ where+ avoidSet = S.fromList (Strings.normalizeChar <$$> avoid)+ takeFrom = head . filter okay+ okay n = S.notMember (Strings.normalizeChar <$> n) avoidSet++-- | Like 'freshName', but produces a list of fresh names+freshNames ∷ Optional t ⇒ [t String] → [String] → [String] → [String]+freshNames [] _ _ = []+freshNames (pn:pns) avoid cands =+ let n' = freshName pn avoid cands+ in n' : freshNames pns (n':avoid) cands++---+--- SOME BUILT-IN NAMES+---++{-# INLINE internalPath #-}+internalPath ∷ String+internalPath = "INTERNALS.PrimTypes"++{-# INLINE internalName #-}+internalName ∷ String → String+internalName = (internalPath ++) . ('.':)++{-# INLINE internalIdent #-}+internalIdent ∷ (Id a, Tag i) ⇒ String → Q a i+internalIdent = qident . internalName++idUnitVal, idNilList, idConsList, idTrueValue, idFalseValue+ ∷ Tag i ⇒ QConId i+idNilRecord ∷ Tag i ⇒ QVarId i++idUnitVal = internalIdent "()"+idNilRecord = internalIdent "nilRecord"+idNilList = internalIdent "[]"+idConsList = internalIdent "::"+idTrueValue = internalIdent "true"+idFalseValue = internalIdent "false"++---+--- FREE VARIABLES and OCCURRENCE ANALYSIS+---++-- | A count of maximum variables occurrences+type Occurrence = Int++-- | The qualifier bound for a given number of occurrences+occToQLit ∷ Occurrence → QLit+occToQLit n = if n > 1 then Qu else Qa++-- | Our free variables function returns not merely a set,+-- but a map from names to a count of maximum occurrences.+type FvMap i = M.Map (QVarId i) Occurrence++-- | The free variables analysis+class Tag i => Fv a i | a -> i where+ fv :: a -> FvMap i++-- | The defined variables analysis+class Dv a i | a -> i where+ qdv :: a -> [QVarId i]+ dv :: a -> [VarId i]++ qdv = J [] <$$> dv+ dv a = [ v | J [] v <- qdv a ]++instance Dv (VarId i) i where dv a = [a]+instance Dv (QVarId i) i where qdv a = [a]++instance Fv a i => Fv [a] i where+ fv = foldr (|*|) M.empty . map fv++instance Dv a i => Dv [a] i where+ qdv = concatMap qdv++instance Fv a i => Fv (Maybe a) i where+ fv = maybe mempty fv++instance Dv a i => Dv (Maybe a) i where+ qdv = maybe [] qdv++newtype ADDITIVE a = ADDITIVE [a]++instance Fv a i => Fv (ADDITIVE a) i where+ fv (ADDITIVE a) = foldr (|+|) M.empty (map fv a)++-- | Used by the free variables analysis+(|*|), (|+|) :: Tag i => FvMap i -> FvMap i -> FvMap i+(|*|) = M.unionWith (+)+(|+|) = M.unionWith max++(|-|) :: Tag i => FvMap i -> QVarId i -> FvMap i+(|-|) = flip M.delete++(|--|) :: (Foldable f, Tag i) => FvMap i -> f (QVarId i) -> FvMap i+(|--|) = foldr' M.delete+
+ src/AST/Ident.hs-boot view
@@ -0,0 +1,12 @@+module AST.Ident where++import Data.Data (Data, Typeable1)++class Tag i++data TyVar i++instance Typeable1 TyVar+instance Data i => Data (TyVar i)+instance Tag i => Ord (TyVar i)+instance Tag i => Eq (TyVar i)
+ src/AST/Kind.hs view
@@ -0,0 +1,261 @@+module AST.Kind (+ -- * Qualifiers and variance+ QLit(..), Variance(..),+ -- ** Qualifier expressions+ QExp, QExp'(..), qeLit, qeVar, qeAnti, qeJoin,+ -- ** Qualifier operations+ (\-\), elimQLit, qLitSigil,+ -- ** Variance operations+ isQVariance,++ -- * Modules+) where++import Util+import Meta.DeriveNotable+import Data.Lattice+import AST.Anti+import AST.Notable+import {-# SOURCE #-} AST.Ident+import qualified Syntax.Strings as Strings++import Prelude ()+import Data.Generics (Typeable, Data)++---+--- QUALIFIERS, VARIANCES+---++{- | Usage qualifier literals++ A+ |+ U++-}+data QLit+ -- | unlimited+ = Qu+ -- | affine+ | Qa+ deriving (Eq, Ord, Bounded, Typeable, Data)++type QExp i = Located QExp' i++-- | Usage qualifier expressions+data QExp' i+ -- | qualifier literal+ = QeLit QLit+ -- | type variable+ | QeVar (TyVar i)+ -- | join+ | QeJoin (QExp i) (QExp i)+ -- | antiquote+ | QeAnti Anti+ deriving (Typeable, Data)++deriveNotable ''QExp++{- |+Type constructor variance forms a seven point lattice, which keeps track+of both polarity and parameters that should be treated as qualifiers.+In particular, given a unary type constructor T with variance +, T S <:+T U when S <: U; but if T has variance Q+, then T S <: T U when+|S| ≤ |U|, where |⋅| gives the qualifier of a type.++ =+ /|\+ / | \+ / | \+ + Q= -+ | / \ |+ |/ \ |+ Q+ Q-+ \ /+ \ /+ \ /+ 0++-}+data Variance+ -- | 0+ = Omnivariant+ -- | Q++ | QCovariant+ -- | Q-+ | QContravariant+ -- | Q=+ | QInvariant+ -- | ++ | Covariant+ -- | -+ | Contravariant+ -- | =+ | Invariant+ deriving (Eq, Ord, Typeable, Data)++---+--- Order instances+---++instance Lattice QLit where+ Qa ⊔ _ = Qa+ Qu ⊔ ql = ql+ Qu ⊓ _ = Qu+ Qa ⊓ ql = ql+ Qa ⊑ Qu = False+ _ ⊑ _ = True++-- | Variances are a four point lattice with 'Invariant' on top and+-- 'Omnivariant' on the bottom+instance Bounded Variance where+ minBound = Omnivariant+ maxBound = Invariant++instance Lattice Variance where+ Omnivariant ⊔ v2 = v2+ v1 ⊔ Omnivariant = v1+ QCovariant ⊔ Covariant = Covariant+ Covariant ⊔ QCovariant = Covariant+ QContravariant ⊔ Contravariant = Contravariant+ Contravariant ⊔ QContravariant = Contravariant+ v1 ⊔ v2+ | v1 == v2 = v1+ | isQVariance v1 && isQVariance v2+ = QInvariant+ | otherwise = Invariant+ --+ Invariant ⊓ v2 = v2+ v1 ⊓ Invariant = v1+ QCovariant ⊓ Covariant = QCovariant+ Covariant ⊓ QCovariant = QCovariant+ QInvariant ⊓ Covariant = QCovariant+ Covariant ⊓ QInvariant = QCovariant+ QContravariant ⊓ Contravariant = QContravariant+ Contravariant ⊓ QContravariant = QContravariant+ QInvariant ⊓ Contravariant = QContravariant+ Contravariant ⊓ QInvariant = QContravariant+ QInvariant ⊓ QCovariant = QCovariant+ QCovariant ⊓ QInvariant = QCovariant+ QInvariant ⊓ QContravariant = QContravariant+ QContravariant ⊓ QInvariant = QContravariant+ v1 ⊓ v2+ | v1 == v2 = v1+ | otherwise = Omnivariant+ --+ Omnivariant ⊑ _ = True+ QCovariant ⊑ Covariant = True+ QContravariant ⊑ Contravariant = True+ QCovariant ⊑ QInvariant = True+ QContravariant ⊑ QInvariant = True+ _ ⊑ Invariant = True+ v1 ⊑ v2 = v1 == v2++instance Bounded (QExp' i) where+ minBound = QeLit Qu+ maxBound = QeLit Qa++---+--- Other instances+---++instance Show QLit where+ showsPrec _ Qu = ('U':)+ showsPrec _ Qa = ('A':)++instance Show Variance where+ show Invariant = Strings.invariant+ show Covariant = Strings.covariant+ show Contravariant = Strings.contravariant+ show Omnivariant = Strings.omnivariant+ show QInvariant = Strings.qinvariant+ show QCovariant = Strings.qcovariant+ show QContravariant = Strings.qcontravariant++instance Monoid QLit where+ mempty = minBound+ mappend = (⊔)++instance Monoid Variance where+ mempty = minBound+ mappend = (⊔)++-- | Variances work like abstract sign arithmetic, where:+-- Omnivariant = { 0 }+-- Covariant = ℤ₊ = { 0, 1, 2, ... }+-- Contravariant = ℤ₋ = { ..., -2, -1, 0 }+-- Invariant = ℤ+-- QCovariant = 2ℤ₊ = { 0, 2, 4, ... }+-- QContravariant = 2ℤ₋ = { ..., -4, -2, 0 }+-- QInvariant = 2ℤ = { ..., -4, -2, 0, 2, 4, ... }+--- In this view, addition gives the join for the variance lattice,+-- and multiplication gives the variance of composing type constructors+-- of the given variances (more or less).+instance Num Variance where+ (+) = (⊔)+ --+ Omnivariant * _ = Omnivariant+ Covariant * v2 = v2+ v1 * Covariant = v1+ Contravariant * v2 = negate v2+ v1 * Contravariant = negate v1+ QCovariant * v2 = v2 ⊓ QInvariant+ v1 * QCovariant = v1 ⊓ QInvariant+ QContravariant * v2 = negate v2 ⊓ QInvariant+ v1 * QContravariant = negate v1 ⊓ QInvariant+ QInvariant * _ = QInvariant+ _ * QInvariant = QInvariant+ _ * _ = Invariant+ --+ abs Omnivariant = Omnivariant+ abs v | isQVariance v = QCovariant+ | otherwise = Covariant+ --+ signum QCovariant = Covariant+ signum QContravariant = Contravariant+ signum QInvariant = Invariant+ signum v = v+ --+ negate Covariant = Contravariant+ negate Contravariant = Covariant+ negate QCovariant = QContravariant+ negate QContravariant = QCovariant+ negate v = v+ --+ fromInteger i+ | i > 0 = if even i then QCovariant else Covariant+ | i < 0 = if even i then QContravariant else Contravariant+ | otherwise = Omnivariant++---+--- Operations+---++--+-- Qualifiers+--++-- | @a \-\ b@ is the least @c@ such that+-- @a ⊑ b ⊔ c@. (This is sort of dual to a pseudocomplement.)+(\-\) ∷ QLit → QLit → QLit+Qa \-\ Qu = Qu+_ \-\ _ = Qu++elimQLit ∷ a → a → QLit → a+elimQLit u _ Qu = u+elimQLit _ a Qa = a++qLitSigil ∷ QLit → String+qLitSigil Qu = Strings.unlimited+qLitSigil Qa = Strings.affine++--+-- Variances+--++isQVariance ∷ Variance → Bool+isQVariance QCovariant = True+isQVariance QContravariant = True+isQVariance QInvariant = True+isQVariance _ = False+
+ src/AST/Lit.hs view
@@ -0,0 +1,16 @@+module AST.Lit (+ Lit(..)+) where++import AST.Anti++import Data.Generics (Typeable, Data)++-- | Literals+data Lit+ = LtInt Integer+ | LtChar Char+ | LtStr String+ | LtFloat Double+ | LtAnti Anti+ deriving (Eq, Typeable, Data)
+ src/AST/Notable.hs view
@@ -0,0 +1,55 @@+{-# LANGUAGE TypeFamilies #-}+module AST.Notable (+ Notable(..), N(..), Located,+ LocNote(..), module Data.Loc+) where++import Data.Data++import Data.Loc+import Util.Viewable++class Notable note where+ newNote :: note+ newN :: a -> N note a+ newN = N newNote+ locN :: Relocatable note => Loc -> a -> N note a+ locN loc a = newN a `setLoc` loc++data N note a+ = N {+ noteOf :: !note,+ dataOf :: !a+ }+ deriving (Typeable, Data, Functor)++instance Eq a => Eq (N note a) where+ a == b = dataOf a == dataOf b++instance Ord a => Ord (N note a) where+ a `compare` b = dataOf a `compare` dataOf b++instance (Notable note, Bounded a) => Bounded (N note a) where+ minBound = newN minBound+ maxBound = newN maxBound++instance Locatable note => Locatable (N note a) where+ getLoc (N note _) = getLoc note++instance Relocatable note => Relocatable (N note a) where+ setLoc (N note val) loc = N (setLoc note loc) val++instance Viewable (N note a) where+ type View (N note a) = a+ view = dataOf++newtype LocNote i = LocNote { unLocNote :: Loc }+ deriving (Eq, Ord, Data, Typeable, Locatable, Relocatable)++instance Show (LocNote i) where+ showsPrec p = showsPrec p . unLocNote++type Located f i = N (LocNote i) (f i)++instance Notable (LocNote i) where+ newNote = LocNote bogus
+ src/AST/Patt.hs view
@@ -0,0 +1,165 @@+module AST.Patt (+ -- * Patterns+ Patt'(..), Patt, PattNote(..), newPatt,+ -- ** Constructors+ paWild, paVar, paCon, paPair, paLit, paAs, paInj, paAnn,+ paBang, paRec, paAnti,+ -- ** Synthetic pattern constructors+ paChar, paStr, paInt, paFloat, paUnit, paCons, paNil,+ ToPatt(..),+) where++import Util+import Meta.DeriveNotable+import AST.Notable+import AST.Anti+import AST.Ident+import AST.Lit+import AST.Type++import Prelude ()+import Data.Generics (Typeable, Data)++type Patt i = N (PattNote i) (Patt' i)++-- | Patterns+data Patt' i+ -- | wildcard+ = PaWild+ -- | variable pattern+ | PaVar (VarId i)+ -- | datacon, possibly with parameter, possibly an exception+ | PaCon (QConId i) (Maybe (Patt i))+ -- | pair pattern+ | PaPair (Patt i) (Patt i)+ -- | literal pattern+ | PaLit Lit+ -- | bind an identifer and a pattern (@as@)+ | PaAs (Patt i) (VarId i)+ -- | open variant+ | PaInj (Uid i) (Maybe (Patt i))+ -- | type annotation on a pattern+ | PaAnn (Patt i) (Type i)+ -- | record pattern+ | PaRec (Uid i) (Patt i) (Patt i)+ -- | imperative/threaded binding+ | PaBang (Patt i)+ -- | antiquote+ | PaAnti Anti+ deriving (Typeable, Data)++data PattNote i+ = PattNote {+ -- | source location+ ploc_ :: !Loc,+ -- | defined variables+ pdv_ :: [VarId i]+ }+ deriving (Typeable, Data)++instance Locatable (PattNote i) where+ getLoc = ploc_++instance Relocatable (PattNote i) where+ setLoc note loc = note { ploc_ = loc }++instance Notable (PattNote i) where+ newNote = PattNote bogus mempty++newPatt :: Tag i => Patt' i -> Patt i+newPatt p0 = flip N p0 $ case p0 of+ PaWild ->+ newNote {+ pdv_ = mempty+ }+ PaVar x ->+ newNote {+ pdv_ = [x]+ }+ PaCon _ mx ->+ newNote {+ pdv_ = maybe mempty dv mx+ }+ PaPair x y ->+ newNote {+ pdv_ = dv x `mappend` dv y+ }+ PaLit _ ->+ newNote {+ pdv_ = mempty+ }+ PaAs x y ->+ newNote {+ pdv_ = dv x ++ [y]+ }+ PaInj _ my ->+ newNote {+ pdv_ = maybe mempty dv my+ }+ PaAnn x _ ->+ newNote {+ pdv_ = dv x+ }+ PaRec _ x y ->+ newNote {+ pdv_ = dv x `mappend` dv y+ }+ PaBang x ->+ newNote {+ pdv_ = dv x+ }+ PaAnti a ->+ newNote {+ pdv_ = antierror "dv" a+ }++instance Dv (N (PattNote i) a) i where+ dv = pdv_ . noteOf++deriveNotable 'newPatt (''Tag, [0]) ''Patt++paChar :: Tag i => Char -> Patt i+paChar = paLit . LtChar++paStr :: Tag i => String -> Patt i+paStr = paLit . LtStr++paInt :: (Tag i, Integral a) => a -> Patt i+paInt = paLit . LtInt . toInteger++paFloat :: Tag i => Double -> Patt i+paFloat = paLit . LtFloat++paUnit :: Tag i => Patt i+paUnit = paCon idUnitVal Nothing++paCons :: Tag i => Patt i -> Patt i -> Patt i+paCons = paCon idConsList . Just <$$> paPair++paNil :: Tag i => Patt i+paNil = paCon idNilList Nothing++class ToPatt a i | a → i where+ toPatt ∷ a → Patt i++instance ToPatt (Patt i) i where+ toPatt = id++instance Tag i ⇒ ToPatt (VarId i) i where+ toPatt = paVar++instance (Tag i, ToPatt a i, ToPatt b i) ⇒ ToPatt (a, b) i where+ toPatt (a, b) = paPair (toPatt a) (toPatt b)++instance Tag i ⇒ ToPatt String i where+ toPatt = paStr++instance Tag i ⇒ ToPatt Int i where+ toPatt = paInt++instance Tag i ⇒ ToPatt Char i where+ toPatt = paChar++instance Tag i ⇒ ToPatt Double i where+ toPatt = paFloat+
+ src/AST/SyntaxTable.hs view
@@ -0,0 +1,185 @@+module AST.SyntaxTable where++import Meta.THHelpers+import AST.Anti+import AST.Notable+import AST.Ident+import AST.Kind+import AST.Type+import AST.Lit+import AST.Patt+import AST.Expr+import AST.Decl++import qualified Data.Map as M+import qualified Language.Haskell.TH as TH++litAntis, pattAntis,+ exprAntis, bindingAntis, caseAltAntis, fieldAntis,+ typeAntis, tyPatAntis, quantAntis, qExpAntis, tyVarAntis,+ declAntis, tyDecAntis, absTyAntis, modExpAntis,+ sigExpAntis, sigItemAntis,+ lidAntis, uidAntis,+ typIdAntis, varIdAntis, conIdAntis, modIdAntis, sigIdAntis,+ qlidAntis, quidAntis,+ qtypIdAntis, qvarIdAntis, qconIdAntis, qmodIdAntis, qsigIdAntis,+ idAntis, noAntis+ :: AntiDict++litAntis+ = "lit" =: Nothing+ & "str" =:< 'LtStr+ & "int" =:< 'LtInt+ & "flo" =:< 'LtFloat+ & "float" =:< 'LtFloat+ & "char" =:< 'LtChar+ & "antiL" =:< 'LtAnti+pattAntis+ = "patt" =:! Nothing+ & "anti" =:< 'PaAnti+exprAntis+ = "expr" =:! Nothing+ & "anti" =:< 'ExAnti+bindingAntis+ = "bind" =:! Nothing+ & "antiB" =:< 'BnAnti+caseAltAntis+ = "case" =: Nothing+ & "antiC" =:< 'CaAnti+fieldAntis+ = "field" =: Nothing+ & "antiF" =:< 'FdAnti+typeAntis+ = "type" =:! Nothing+ & "anti" =:< 'TyAnti+tyPatAntis+ = "typat" =:! Nothing+ & "antiP" =:< 'TpAnti+quantAntis+ = "quant" =: Nothing+ & "antiQ" =:< 'QuantAnti+qExpAntis+ = "qexp" =:! Nothing+ & "qlit" =:< 'QeLit+ & "qvar" =:< 'QeVar+ & "anti" =:< 'QeAnti+tyVarAntis+ = "tyvar" =:! Nothing+ & "anti" =:< 'TVAnti+declAntis+ = "decl" =:! Nothing+ & "anti" =:< 'DcAnti+tyDecAntis+ = "tydec" =:! Nothing+ & "anti" =:< 'TdAnti+absTyAntis+ = "absty" =:! Nothing+ & "anti" =:< 'AbsTyAnti+modExpAntis+ = "mod" =:! Nothing+ & "anti" =:< 'MeAnti+sigExpAntis+ = "sig" =:! Nothing+ & "anti" =:< 'SeAnti+sigItemAntis+ = "sgitem" =:! Nothing+ & "anti" =:< 'SgAnti+lidAntis+ = "lid" =: Nothing+ & "name" =:•• (['ident], ['Lid])+ & "antiLid"=:< 'LidAnti+uidAntis+ = "uid" =: Nothing+ & "uname" =:•• (['ident], ['Uid])+ & "antiUid"=:< 'LidAnti+typIdAntis+ = "tid" =: Nothing+ & "lid" =:< 'TypId+ & "lname" =:•• (['ident], ['TypId, 'Lid])+ & "antiTI" =:• ['TypId, 'LidAnti]+varIdAntis+ = "vid" =: Nothing+ & "lid" =:< 'VarId+ & "lname" =:•• (['ident], ['VarId, 'Lid])+ & "antiVI" =:• ['VarId, 'LidAnti]+conIdAntis+ = "cid" =: Nothing+ & "uid" =:< 'ConId+ & "uname" =:•• (['ident], ['ConId, 'Uid])+ & "antiCI" =:• ['ConId, 'UidAnti]+modIdAntis+ = "mid" =: Nothing+ & "uid" =:< 'ModId+ & "uname" =:•• (['ident], ['SigId, 'Uid])+ & "antiMI" =:• ['ModId, 'UidAnti]+sigIdAntis+ = "sid" =: Nothing+ & "uid" =:< 'SigId+ & "uname" =:•• (['ident], ['SigId, 'Uid])+ & "antiSI" =:• ['SigId, 'UidAnti]+qlidAntis+ = "qlid" =: Nothing+ & "qname" =: appFun 'qident -- error in pattern context+quidAntis+ = "quid" =: Nothing+ & "quname" =: appFun 'qident -- error in pattern context+qtypIdAntis+ = "qtid" =: Nothing+ & "qname" =: appFun 'qident -- error in pattern context+qvarIdAntis+ = "qvid" =: Nothing+ & "qname" =: appFun 'qident -- error in pattern context+qconIdAntis+ = "qcid" =: Nothing+ & "quname" =: appFun 'qident -- error in pattern context+qmodIdAntis+ = "qmid" =: Nothing+ & "quname" =: appFun 'qident -- error in pattern context+qsigIdAntis+ = "qsid" =: Nothing+ & "quname" =: appFun 'qident -- error in pattern context+idAntis+ = "id" =: Nothing+noAntis+ = M.empty++appFun :: ToSyntax b => TH.Name -> Maybe (String -> TH.Q b)+appFun n = Just (\v -> varS n [varS v []])++syntaxTable :: SyntaxTable+syntaxTable =+ [ ''Prog =:: 'Prog !: 'newN >: (''Tag, [0])+ , ''Lit =:: 'LtAnti $: 'litAntis+ , ''Patt =:: 'PaAnti $: 'pattAntis !: 'newPatt >: (''Tag, [0])+ , ''Expr =:: 'ExAnti $: 'exprAntis !: 'newExpr >: (''Tag, [0])+ , ''Binding =:: 'BnAnti $: 'bindingAntis !: 'newBinding >: (''Tag, [0])+ , ''CaseAlt =:: 'CaAnti $: 'caseAltAntis !: 'newCaseAlt >: (''Tag, [0])+ , ''Field =:: 'FdAnti $: 'fieldAntis !: 'newField >: (''Tag, [0])+ , ''Type =:: 'TyAnti $: 'typeAntis !: 'newN+ , ''TyPat =:: 'TpAnti $: 'tyPatAntis !: 'newN+ , ''Quant =:: 'QuantAnti $: 'quantAntis+ , ''QExp =:: 'QeAnti $: 'qExpAntis !: 'newN+ , ''TyVar =:: 'TVAnti $: 'tyVarAntis+ , ''Decl =:: 'DcAnti $: 'declAntis !: 'newDecl >: (''Tag, [0])+ , ''TyDec =:: 'TdAnti $: 'tyDecAntis !: 'newN+ , ''AbsTy =:: 'AbsTyAnti $: 'absTyAntis !: 'newN+ , ''ModExp =:: 'MeAnti $: 'modExpAntis !: 'newModExp >: (''Tag, [0])+ , ''SigExp =:: 'SeAnti $: 'sigExpAntis !: 'newSigExp >: (''Tag, [0])+ , ''SigItem =:: 'SgAnti $: 'sigItemAntis !: 'newSigItem >: (''Tag, [0])+ , ''Lid =:: 'LidAnti $: 'lidAntis+ , ''Uid =:: 'UidAnti $: 'uidAntis+ , ''TypId =:: ['TypId, 'LidAnti] $: 'typIdAntis+ , ''VarId =:: ['VarId, 'LidAnti] $: 'varIdAntis+ , ''ConId =:: ['ConId, 'UidAnti] $: 'conIdAntis+ , ''ModId =:: ['ModId, 'UidAnti] $: 'modIdAntis+ , ''SigId =:: ['SigId, 'UidAnti] $: 'sigIdAntis+ , ''QLid =:: '()+ , ''QUid =:: '()+ , ''QTypId =:: '()+ , ''QVarId =:: '()+ , ''QConId =:: '()+ , ''QModId =:: '()+ , ''QSigId =:: '()+ , ''Ident =:: '()+ ]+
+ src/AST/Type.hs view
@@ -0,0 +1,222 @@+{-# LANGUAGE TypeFamilies #-}+module AST.Type (+ -- * Types+ Quant(..), Type'(..), Type, TyPat'(..), TyPat,+ -- ** Constructors+ tyApp, tyVar, tyFun, tyQu, tyMu, tyRow, tyAnti,+ tpVar, tpApp, tpRow, tpAnti,+ TyAppN(..),++ -- * Built-in types+ tyUnit, tyRowEnd, tyVariant, tyRecord, tyRowDots, tyRowMap, tyRowHole,+ tyTuple, tyUn, tyAf,+ -- ** Type construtor names+ tnUnit, tnRowEnd, tnVariant, tnRecord, tnRowDots, tnRowMap, tnRowHole,+ tnTuple, tnUn, tnAf,+ -- ** Convenience constructors+ tyArr, tyLol,+ tyAll, tyEx,+ tyRecordAdditive, tyRecordMultiplicative,++ -- * Miscellany+ dumpType+) where++import Util+import Meta.DeriveNotable+import AST.Notable+import AST.Anti+import AST.Kind+import AST.Ident+import qualified Syntax.Strings as Strings++import Prelude ()+import Data.Generics (Typeable, Data)++-- | Type quantifers+data Quant = Forall | Exists | QuantAnti Anti+ deriving (Typeable, Data, Eq, Ord)++type Type i = Located Type' i+type TyPat i = Located TyPat' i++-- | Types are parameterized by [@i@], the type of information+-- associated with each tycon+data Type' i+ = TyApp (QTypId i) [Type i]+ | TyVar (TyVar i)+ | TyFun (Type i) (Maybe (QExp i)) (Type i)+ | TyQu Quant (TyVar i) (Type i)+ | TyMu (TyVar i) (Type i)+ | TyRow (Uid i) (Type i) (Type i)+ | TyAnti Anti+ deriving (Typeable, Data)++-- | Type patterns for defining type operators+data TyPat' i+ -- | type variables+ = TpVar (TyVar i) Variance+ -- | type constructor applications+ | TpApp (QTypId i) [TyPat i]+ -- | each element of a row+ | TpRow (TyVar i) Variance+ -- | antiquotes+ | TpAnti Anti+ deriving (Typeable, Data)++deriveNotable ''Type+deriveNotable ''TyPat++-- | Convenience constructors for qualified types+tyAll, tyEx :: TyVar i -> Type i -> Type i+tyAll = tyQu Forall+tyEx = tyQu Exists++tyArr :: Type i -> Type i -> Type i+tyArr = tyFun <-> Nothing++tyLol :: Type i -> Type i -> Type i+tyLol = tyFun <-> Just maxBound++infixr 8 `tyArr`, `tyLol`++instance Show Quant where+ show Forall = Strings.all+ show Exists = Strings.ex+ show (QuantAnti a) = show a++---+--- Built-in types+---++-- | Names of built-in types+tnUnit, tnRowEnd, tnVariant, tnRecord, tnRowDots, tnRowMap, tnRowHole,+ tnTuple, tnUn, tnAf :: String++tnUnit = "INTERNALS.PrimTypes.unit"+tnRowEnd = "INTERNALS.PrimTypes.rowend"+tnVariant = "INTERNALS.PrimTypes.variant"+tnRecord = "INTERNALS.PrimTypes.record"+tnRowDots = "rowdots#"+tnRowMap = "rowmap#"+tnRowHole = "rowhole#"+tnTuple = "INTERNALS.PrimTypes.*"+tnUn = "INTERNALS.PrimTypes.unlimited"+tnAf = "INTERNALS.PrimTypes.affine"++--- Convenience constructors++-- Types++-- | Class defining variadic function 'tyAppN' for constructing+-- type constructor applications.+class TyApp' r i ⇒ TyAppN n r i | r → i where+ tyAppN ∷ n → r++instance TyApp' r i ⇒ TyAppN (Path (ModId i) (TypId i)) r i where+ tyAppN ql = tyApp' ql []++instance TyApp' r i ⇒ TyAppN (TypId i) r i where+ tyAppN l = tyApp' (J [] l) []++instance (Tag i, TyApp' r i) ⇒ TyAppN String r i where+ tyAppN s = tyApp' (qident s) []++-- | Helper class for @TyApp'@.+class TyApp' r i | r → i where+ tyApp' ∷ QTypId i → [Type i] → r++instance TyApp' (Type i) i where+ tyApp' = tyApp++instance (TyApp' r i, a ~ Type i) ⇒ TyApp' (a → r) i where+ tyApp' ql ts t = tyApp' ql (ts++[t])++tyUnit :: Tag i => Type i+tyUnit = tyAppN tnUnit++tyRowEnd :: Tag i => Type i+tyRowEnd = tyAppN tnRowEnd++tyVariant :: Tag i => Type i -> Type i+tyVariant = tyAppN tnVariant++tyRecord :: Tag i => Type i -> Type i -> Type i+tyRecord = tyAppN tnRecord++tyRowDots :: Tag i => Type i -> Type i+tyRowDots = tyAppN tnRowDots++tyRowMap :: Tag i => Type i -> Type i -> Type i+tyRowMap = tyAppN tnRowMap++tyRowHole :: Tag i => Type i -> Type i+tyRowHole = tyAppN tnRowHole++tyTuple :: Tag i => Type i -> Type i -> Type i+tyTuple = tyAppN tnTuple++tyUn :: Tag i => Type i+tyUn = tyAppN tnUn++tyAf :: Tag i => Type i+tyAf = tyAppN tnAf++tyRecordAdditive, tyRecordMultiplicative :: Tag i => Type i -> Type i+tyRecordAdditive = tyRecord tyAf+tyRecordMultiplicative = tyRecord tyUn++---+--- Debugging+---++-- | Noisy type printer for debugging+dumpType :: Tag i => Int -> Type i -> IO ()+dumpType i0 nt0 = do+ putStr (replicate i0 ' ')+ noIndent i0 nt0+ where+ noIndent i nt@(N _ t0) =+ case t0 of+ TyApp n ps -> do+ putStrLn $ show n ++ " {"+ mapM_ (dumpType (i + 2)) ps+ putStrLn (replicate i ' ' ++ "}")+ TyFun dom mq cod -> do+ putStrLn $ case mq of+ Just q -> "-[" ++ dumpQExp q ++ "]> {"+ Nothing -> "-> {"+ dumpType (i + 2) dom+ dumpType (i + 2) cod+ putStrLn (replicate i ' ' ++ "}")+ TyVar tv -> print tv+ TyQu u a t -> do+ print $ show u ++ " " ++ show a ++ ". {"+ dumpType (i + 2) t+ putStrLn (replicate i ' ' ++ "}")+ TyMu a t -> do+ print $ "mu " ++ show a ++ ". {"+ dumpType (i + 2) t+ putStrLn (replicate i ' ' ++ "}")+ TyRow _ _ _ -> do+ putStr "ro"+ dumpRow (i + 2) 'w' nt+ TyAnti a -> do+ print a+ --+ dumpRow i c (N _ (TyRow n t1 t2)) = do+ let lab = show n+ putStr (c:' ':lab++": ")+ noIndent (i + length lab + 4) t1+ putStr (replicate i ' ')+ dumpRow i '|' t2+ dumpRow i c t = do+ putStr (c:" ")+ noIndent (i + 2) t+ --+ dumpQExp (N _ q0) = case q0 of+ QeLit ql → show ql+ QeVar tv → show tv+ QeJoin qe1 qe2 → dumpQExp qe1 ++ ',' : dumpQExp qe2+ QeAnti _ → "ANTI"+
+ src/AST/TypeAnnotation.hs view
@@ -0,0 +1,148 @@+-- | For treating syntactic types as type annotations.+module AST.TypeAnnotation (+ Annot, HasAnnotations(..),+) where++import Util+import AST+import Meta.Quasi++import Prelude ()+import qualified Data.Map as M+import qualified Data.Set as S++-- | A type annotation is merely a syntactic type+type Annot i = Type i++-- | Find out the free variables of a type annotation. Minimal+-- definition: @annotFtvMap@+class Tag i ⇒ HasAnnotations a i | a → i where+ -- | Accumulate information about type variables.+ annotFtvMap ∷ (TyVar i → r) →+ (QTypId i → Int → r → r) →+ (r → r → r) →+ a →+ M.Map (TyVar i) r+ -- | Just the set of type variables, please.+ annotFtvSet ∷ a → S.Set (TyVar i)+ annotFtvSet = M.keysSet . annotFtvMap (\_ → ()) (\_ _ () → ()) (\_ _ → ())++-- | Shorter-named alias+afm ∷ HasAnnotations a i ⇒+ (TyVar i → r) →+ (QTypId i → Int → r → r) →+ (r → r → r) →+ a →+ M.Map (TyVar i) r+afm = annotFtvMap++--+-- Generic instances+--++instance (HasAnnotations a i, HasAnnotations b i) ⇒+ HasAnnotations (a, b) i where+ annotFtvMap var con cmb (a, b) =+ M.unionWith cmb (afm var con cmb a) (afm var con cmb b)++instance (HasAnnotations a i, HasAnnotations b i, HasAnnotations c i) ⇒+ HasAnnotations (a, b, c) i where+ annotFtvMap var con cmb (a, b, c) = afm var con cmb (a, (b, c))++instance HasAnnotations a i ⇒ HasAnnotations [a] i where+ annotFtvMap var con cmb = M.unionsWith cmb . map (afm var con cmb)++instance HasAnnotations a i ⇒ HasAnnotations (Maybe a) i where+ annotFtvMap var con cmb = maybe mempty (afm var con cmb)++instance HasAnnotations a i ⇒ HasAnnotations (N note a) i where+ annotFtvMap = afm <$$$.> dataOf++--+-- Specific instances for syntax.+--++instance Tag i ⇒ HasAnnotations (TyVar i) i where+ annotFtvMap _ _ _ (TVAnti a) = $antierror+ annotFtvMap var _ _ tv = M.singleton tv (var tv)++instance Tag i ⇒ HasAnnotations (QExp' i) i where+ annotFtvMap var con cmb qe0 = case qe0 of+ [qeQ|' $qlit:_ |] → mempty+ [qeQ|' '$tv |] → afm var con cmb tv+ [qeQ|' $qe1 ⋁ $qe2 |] → afm var con cmb (qe1, qe2)+ [qeQ|' $anti:a |] → $antierror++instance Tag i ⇒ HasAnnotations (Type' i) i where+ annotFtvMap var con cmb t0 = case t0 of+ [ty|' ($list:ts) $qtid:ql |] →+ M.unionsWith cmb+ [ con ql ix <$> afm var con cmb t+ | t ← ts+ | ix ← [ 0 .. ] ]+ [ty|' '$tv |] → afm var con cmb tv+ [ty|' $t1 -[$opt:qe]> $t2 |] →+ let t1m = con (qident "->") 0 <$> afm var con cmb t1+ qem = con (qident "->") 1 <$> afm var con cmb qe+ t2m = con (qident "->") 2 <$> afm var con cmb t2+ in M.unionsWith cmb [t1m, qem, t2m]+ [ty|' $quant:_ `$tv. $t |] → M.delete tv $ afm var con cmb t+ [ty|' μ `$tv. $t |] → M.delete tv $ afm var con cmb t+ [ty|' `$uid:_ of $t1 | $t2 |] → afm var con cmb (t1, t2)+ [ty|' $anti:a |] → $antierror++instance Tag i => HasAnnotations (Patt' i) i where+ annotFtvMap var con cmb x0 = case x0 of+ [pa|' _ |] → mempty+ [pa|' $lid:_ |] → mempty+ [pa|' $qcid:_ $opt:mx |] → afm var con cmb mx+ [pa|' ($x, $y) |] → afm var con cmb (x, y)+ [pa|' $lit:_ |] → mempty+ [pa|' $x as $vid:_ |] → afm var con cmb x+ [pa|' `$uid:_ $opt:mx |] → afm var con cmb mx+ [pa|' $x : $t |] → afm var con cmb (x, t)+ [pa|' {$uid:_ = $x | $y} |] → afm var con cmb (x, y)+ [pa|' ! $x |] → afm var con cmb x+ [pa|' $anti:a |] → $antierror++instance Tag i ⇒ HasAnnotations (Expr' i) i where+ annotFtvMap var con cmb e0 = case e0 of+ [ex|' $qvid:_ |] → mempty+ [ex|' $lit:_ |] → mempty+ [ex|' $qcid:_ $opt:me |] → afm var con cmb me+ [ex|' let $x = $e in $e' |] → afm var con cmb (x, e, e')+ [ex|' match $e with $list:cas |]+ → afm var con cmb (e, cas)+ [ex|' let rec $list:bns in $e |]+ → afm var con cmb (bns, e)+ [ex|' let $decl:_ in $e |] → afm var con cmb e+ [ex|' ($e1, $e2) |] → afm var con cmb (e1, e2)+ [ex|' λ $x → $e |] → afm var con cmb (x, e)+ [ex|' $e1 $e2 |] → afm var con cmb (e1, e2)+ [ex|' `$uid:_ $opt:me |] → afm var con cmb me+ [ex|' #$uid:_ $e |] → afm var con cmb e+ [ex|' { $list:flds | $e2 } |]+ → afm var con cmb (flds, e2)+ [ex|' {+ $list:flds | $e2 +} |]+ → afm var con cmb (flds, e2)+ [ex|' $e1.$uid:_ |] → afm var con cmb e1+ [ex|' $e : $t |] → afm var con cmb (e, t)+ [ex|' $e :> $t |] → afm var con cmb (e, t)+ [ex|' $anti:a |] → $antierror++instance Tag i ⇒ HasAnnotations (CaseAlt' i) i where+ annotFtvMap var con cmb ca0 = case ca0 of+ [caQ|' $x → $e |] → afm var con cmb (x, e)+ [caQ|' #$uid:_ $opt:mx → $e |]+ → afm var con cmb (mx, e)+ [caQ|' $antiC:a |] → $antierror++instance Tag i ⇒ HasAnnotations (Binding' i) i where+ annotFtvMap var con cmb bn0 = case bn0 of+ [bnQ|' $lid:_ = $e |] → afm var con cmb e+ [bnQ|' $antiB:a |] → $antierror++instance Tag i ⇒ HasAnnotations (Field' i) i where+ annotFtvMap var con cmb bn0 = case bn0 of+ [fdQ|' $uid:_ = $e |] → afm var con cmb e+ [fdQ|' $antiF:a |] → $antierror
+ src/Alt/Graph.hs view
@@ -0,0 +1,147 @@+-- | A wrapper around the fgs graph library.+module Alt.Graph (+ Gr, ShowGraph(..),+ trcnr, untransitive, nmLab, labelNode, labScc,+ pathScc, erdffWith, xpdffWith, xpdfWith,+ labComponents, labNodeEdges,+ module Data.Graph.Inductive.Basic,+ module Data.Graph.Inductive.Graph,+ module Data.Graph.Inductive.Query.DFS,+ module Data.Graph.Inductive.Query.TransClos,+ module NM,+) where+++-- Mine:+import Util+import Alt.NodeMap as NM++import Prelude ()+import qualified Data.List as List+import qualified Data.Tree as Tree++-- From fgs:+import Data.Graph.Inductive.PatriciaTree (Gr)+import Data.Graph.Inductive.Basic+import Data.Graph.Inductive.Graph+import Data.Graph.Inductive.Query.DFS+import Data.Graph.Inductive.Query.TransClos++-- | Transitive, non-reflexive closure+trcnr ∷ DynGraph gr ⇒ gr a b → gr a ()+trcnr g = insEdges newEdges (insNodes lns empty) where+ lns = labNodes g+ newEdges = [ (n, n', ())+ | (n, _) ← lns+ , n' ← reachable n g+ , n /= n' ]++-- | Compute the transitive reduction of a transitive, acyclic graph.+untransitive ∷ DynGraph gr ⇒ gr a b → gr a b+untransitive g = foldl' eachEdge g (edges g) where+ eachEdge g' (n1, n2) = foldl' eachSuc g' (suc g' n1) where+ eachSuc g'' n' =+ if n' /= n1 && n' /= n2 && n2 `elem` suc g'' n'+ then delEdge (n1, n2) g''+ else g''++-- | Look up the node index of a node label+nmLab ∷ Ord a ⇒ NM.NodeMap a → a → Node+nmLab = fst <$$> NM.mkNode_++labelNode ∷ Graph gr ⇒ gr a b → Node → LNode a+labelNode g n = case lab g n of+ Just ln → (n, ln)+ Nothing → error "labelNode: node not found"++labScc ∷ Graph gr ⇒ gr a b → [[LNode a]]+labScc g = map preorder (rdffWith labNode' (topsort g) g)++pathScc ∷ Graph gr ⇒ gr a b → [Either (LNode a) [(LNode a, b)]]+pathScc g = map (addCycle . preorder) (erdffWith labNode' (topsort g) g)+ where+ addCycle [((n, a), Nothing)] =+ case lookup n (lpre g n) of+ Just b → Right [((n, a), b)]+ Nothing → Left (n, a)+ addCycle (((n, a), Nothing):rest) =+ case catMaybes [ lookup n' (lsuc g n) | ((n', _), _) ← rest ] of+ b:_ → Right (((n, a), b) : map (second fromJust) rest)+ [] → error "pathScc: bug!"+ addCycle _ = error "pathScc: bug!"++erdffWith ∷ Graph gr ⇒+ CFun a b c → [Node] → gr a b → [Tree.Tree (c, Maybe b)]+erdffWith = xpdffWith (map (second Just) . lpre') <$.> map (\n → (n, Nothing))++rdffWith ∷ Graph gr ⇒ CFun a b c → [Node] → gr a b → [Tree.Tree c]+rdffWith = xdffWith pre'++_g ∷ Gr Int String+_g = mkGraph ns es where+ ns = (id &&& id) <$> [0 .. 20]+ es = map addLab $+ [ (0,5), (1,5), (2,5), (3,5), (4,5),+ (0,6), (1,6), (2,6), (3,6), (4,6),+ (5,7), (6,7), (5,8), (6,8),+ (7,9), (8,9), (7,10), (8,10),+ (9,0), (9,1), (9,2), (9,3), (9,4),+ (10,0), (10,1), (10,2), (10,3), (10,4)+ ]+ addLab (i, j) = (i, j, show i ++ "->" ++ show j)++-- | A generalized, path-sensitive depth-first forest. Along with+-- each starting node, it takes a value to associate with that node,+-- and the next-finding function produces new values to go with+-- each node as well.+xpdffWith ∷ Graph gr ⇒+ CFun a b [(Node, d)] → CFun a b c →+ [(Node, d)] → gr a b → [Tree.Tree (c, d)]+xpdffWith = fst <$$$$> xpdfWith++xpdfWith ∷ Graph gr ⇒+ CFun a b [(Node, d)] → CFun a b c →+ [(Node, d)] → gr a b → ([Tree.Tree (c, d)], gr a b)+xpdfWith _ _ [] g = ([],g)+xpdfWith _ _ _ g | isEmpty g = ([],g)+xpdfWith d f ((v,e):vs) g =+ case match v g of+ (Nothing, g1) → xpdfWith d f vs g1+ (Just c, g1) → (Tree.Node (f c, e) ts:ts', g3)+ where (ts, g2) = xpdfWith d f (d c) g1+ (ts', g3) = xpdfWith d f vs g2++-- | Partition a graph into components of /labeled/ nodes+labComponents ∷ Graph gr ⇒ gr a b → [[LNode a]]+labComponents = componentsWith labNode'+ where+ udffWith ∷ Graph gr ⇒ CFun a b c → [Node] → gr a b → [Tree.Tree c]+ udffWith = xdffWith neighbors'+ --+ udffWith' ∷ Graph gr ⇒ CFun a b c → gr a b → [Tree.Tree c]+ udffWith' f g = udffWith f (nodes g) g+ --+ componentsWith ∷ Graph gr ⇒ CFun a b c → gr a b → [[c]]+ componentsWith = preorder <$$$> udffWith'++-- | Get the edges of a graph as pairs of node labels+labNodeEdges ∷ Graph gr ⇒ gr n e → [(n, n)]+labNodeEdges g =+ [ (α, β)+ | (n1, n2) ← edges g+ , let Just α = lab g n1+ , let Just β = lab g n2+ ]++-- | For showing graphs+newtype ShowGraph gr v = ShowGraph { unShowGraph ∷ gr v () }++instance (Graph gr, Show v) ⇒ Show (ShowGraph gr v) where+ showsPrec _ (ShowGraph gr) =+ showChar '{' .+ foldr (.) id+ (List.intersperse (showString ", ")+ [ shows n1 . showString "<" . shows n2+ | (n1, n2) ← labNodeEdges gr ])+ . showChar '}'+
+ src/Alt/NodeMap.hs view
@@ -0,0 +1,151 @@+-- | A generalization of @Data.Graph.Inductive.NodeMap@ from the fgs package+module Alt.NodeMap (+ MonadNM(..),+ module Data.Graph.Inductive.NodeMap,+) where++import Data.Graph.Inductive (DynGraph, LNode, LEdge, insNode, lab)+import Data.Graph.Inductive.NodeMap+ hiding (mkNodeM, mkNodesM, mkEdgeM, mkEdgesM,+ insMapNodeM, insMapEdgeM, delMapNodeM, delMapEdgeM,+ insMapNodesM, insMapEdgesM, delMapNodesM, delMapEdgesM)+import Control.Monad.State.Lazy as Lazy+import Control.Monad.State.Strict as Strict+import Control.Monad.Reader+import Control.Monad.Writer.Lazy as Lazy+import Control.Monad.Writer.Strict as Strict+import Control.Monad.RWS.Lazy as Lazy+import Control.Monad.RWS.Strict as Strict+import Control.Arrow++insNewMapNode ∷ (Ord a, DynGraph gr) ⇒+ NodeMap a → a → gr a b → (gr a b, NodeMap a, LNode a)+insNewMapNode nm a gr = (gr', nm', node) where+ (node@(n, _), nm') = mkNode nm a+ gr' = maybe (insNode node gr) (const gr) (lab gr n)++insNewMapNodes ∷ (Ord a, DynGraph gr) ⇒+ NodeMap a → [a] → gr a b → (gr a b, NodeMap a, [LNode a])+insNewMapNodes nm [] gr = (gr, nm, [])+insNewMapNodes nm (a:as) gr = (gr'', nm'', node:nodes) where+ (gr', nm', node) = insNewMapNode nm a gr+ (gr'', nm'', nodes) = insNewMapNodes nm' as gr'++class (Ord a, DynGraph g, Monad m) ⇒+ MonadNM a b g m | m → a b g where+ putNMState ∷ (NodeMap a, g a b) → m ()+ putNodeMap ∷ NodeMap a → m ()+ putGraph ∷ g a b → m ()+ getNMState ∷ m (NodeMap a, g a b)+ getNodeMap ∷ m (NodeMap a)+ getGraph ∷ m (g a b)+ --+ modifyNMState ∷ ((NodeMap a, g a b) → (NodeMap a, g a b)) → m ()+ modifyNodeMap ∷ (NodeMap a → NodeMap a) → m ()+ modifyGraph ∷ (g a b → g a b) → m ()+ getsNMState ∷ ((NodeMap a, g a b) → r) → m r+ getsNodeMap ∷ (NodeMap a → r) → m r+ getsGraph ∷ (g a b → r) → m r+ --+ putNMState (nm, g) = putNodeMap nm >> putGraph g+ putNodeMap nm = modifyNMState (first (const nm))+ putGraph gr = modifyNMState (second (const gr))+ getNMState = liftM2 (,) getNodeMap getGraph+ getNodeMap = getsNMState fst+ getGraph = getsNMState snd+ modifyNMState = getsNMState >=> putNMState+ modifyNodeMap = getsNMState . first >=> putNMState+ modifyGraph = getsNMState . second >=> putNMState+ getsNMState f = liftM f getNMState+ getsNodeMap f = liftM (f . fst) getNMState+ getsGraph f = liftM (f . snd) getNMState+ --+ modifyNMG ∷ (NodeMap a → g a b → (g a b, NodeMap a, r)) → m r+ modifyNMG f = do+ (nm, g) ← getNMState+ let (g', nm', r) = f nm g+ putNMState (nm', g')+ return r+ --+ modifyG ∷ (NodeMap a → g a b → g a b) → m ()+ modifyG f = do+ (nm, g) ← getNMState+ putGraph (f nm g)+ --+ modifyNM ∷ (NodeMap a → (r, NodeMap a)) → m r+ modifyNM f = do+ nm ← getNodeMap+ let (r, nm') = f nm+ putNodeMap nm'+ return r+ --+ mkNodeM ∷ a → m (LNode a)+ mkNodesM ∷ [a] → m [LNode a]+ mkEdgeM ∷ (a, a, b) → m (Maybe (LEdge b))+ mkEdgesM ∷ [(a, a, b)] → m (Maybe [LEdge b])+ insMapNodeM ∷ a → m (LNode a)+ insNewMapNodeM ∷ a → m (LNode a)+ insMapEdgeM ∷ (a, a, b) → m ()+ delMapNodeM ∷ a → m ()+ delMapEdgeM ∷ (a, a) → m ()+ insMapNodesM ∷ [a] → m [LNode a]+ insNewMapNodesM ∷ [a] → m [LNode a]+ insMapEdgesM ∷ [(a, a, b)] → m ()+ delMapNodesM ∷ [a] → m ()+ delMapEdgesM ∷ [(a, a)] → m ()+ mkNodeM = modifyNM . flip mkNode+ mkNodesM = modifyNM . flip mkNodes+ mkEdgeM e = getsNMState (flip mkEdge e . fst)+ mkEdgesM es = getsNMState (flip mkEdges es . fst)+ insMapNodeM = modifyNMG . flip insMapNode+ insNewMapNodeM = modifyNMG . flip insNewMapNode+ insMapEdgeM = modifyG . flip insMapEdge+ delMapNodeM = modifyG . flip delMapNode+ delMapEdgeM = modifyG . flip delMapEdge+ insMapNodesM = modifyNMG . flip insMapNodes+ insNewMapNodesM = modifyNMG . flip insNewMapNodes+ insMapEdgesM = modifyG . flip insMapEdges+ delMapNodesM = modifyG . flip delMapNodes+ delMapEdgesM = modifyG . flip delMapEdges++instance MonadNM a b g m ⇒ MonadNM a b g (ReaderT r m) where+ getNMState = lift getNMState+ putNMState = lift . putNMState++instance (MonadNM a b g m, Monoid w) ⇒ MonadNM a b g (Strict.WriterT w m) where+ getNMState = lift getNMState+ putNMState = lift . putNMState++instance (MonadNM a b g m, Monoid w) ⇒ MonadNM a b g (Lazy.WriterT w m) where+ getNMState = lift getNMState+ putNMState = lift . putNMState++instance MonadNM a b g m ⇒ MonadNM a b g (Strict.StateT s m) where+ getNMState = lift getNMState+ putNMState = lift . putNMState++instance MonadNM a b g m ⇒ MonadNM a b g (Lazy.StateT s m) where+ getNMState = lift getNMState+ putNMState = lift . putNMState++instance (MonadNM a b g m, Monoid w) ⇒ MonadNM a b g (Strict.RWST r w s m) where+ getNMState = lift getNMState+ putNMState = lift . putNMState++instance (MonadNM a b g m, Monoid w) ⇒ MonadNM a b g (Lazy.RWST r w s m) where+ getNMState = lift getNMState+ putNMState = lift . putNMState++---+--- Instances+---++instance (Ord a, DynGraph g, Monad m) ⇒+ MonadNM a b g (Strict.StateT (NodeMap a, g a b) m) where+ getNMState = get+ putNMState = put++instance (Ord a, DynGraph g, Monad m) ⇒+ MonadNM a b g (Lazy.StateT (NodeMap a, g a b) m) where+ getNMState = get+ putNMState = put
+ src/Alt/Parsec.hs view
@@ -0,0 +1,21 @@+module Alt.Parsec (+ module Text.ParserCombinators.Parsec,+) where++import Text.ParserCombinators.Parsec hiding ((<|>), many, optional)++#if PARSEC_VERSION == 2+import qualified Text.ParserCombinators.Parsec as Parsec+import Control.Applicative+import Control.Monad++-- | Parsec parsers are Applicatives, which lets us write slightly+-- more pleasant, non-monadic-looking parsers+instance Applicative (GenParser a b) where+ pure = return+ (<*>) = ap++instance Alternative (GenParser a b) where+ empty = pzero+ (<|>) = (Parsec.<|>)+#endif
+ src/Alt/PrettyPrint.hs view
@@ -0,0 +1,189 @@+{- | A layer over 'P.Doc' for propagating context information. (I think+ Template Haskell has a version of this.) -}+module Alt.PrettyPrint (+ -- * Environment-parameterized pretty-printing document+ Doc(..),+ -- ** Environment operations+ mapD, askD, asksD, localD,+ -- * Document combinators+ -- ** Binary operations+ ($$), ($+$), (<+>), (<>),+ -- ** Unary operations+ braces, brackets, doubleQuotes, quotes, parens,+ -- ** List operations+ cat, fcat, fsep, hcat, hsep, sep, vcat,+ -- ** Miscellaneous operations+ nest, hang, punctuate,+ -- ** Nullary operations (documents)+ colon, comma, equals, lbrace, lbrack,+ lparen, rbrace, rbrack, rparen, semi, space,+ -- *** Unary functions returning documents+ char, double, float, int, integer, ptext, rational, text, zeroWidthText,+ -- * Rendering and queries+ toDocIn, isEmptyIn, renderIn, renderStyleIn, fullRenderIn,+ toDoc, isEmpty, render, renderStyle, fullRender,+ -- ** Rendering constants+ P.Mode(..), P.Style(..), P.TextDetails(..), P.style,+ -- * Module exports+ module Data.Monoid,+) where++import qualified Text.PrettyPrint as P+import Control.Applicative+import Data.Monoid++-- Document parameterized by type @e@.+newtype Doc e = Doc { unDoc :: e -> P.Doc }++--+-- Environment manipulation+--++mapD :: (e' -> e) -> Doc e -> Doc e'+mapD f d = Doc (unDoc d . f)++askD :: (e -> Doc e) -> Doc e+askD f = Doc (unDoc <$> f <*> id)++asksD :: (e -> a) -> (a -> Doc e) -> Doc e+asksD g f = askD (f . g)++localD :: e' -> Doc e' -> Doc e+localD = mapD . const++--+-- Lifts+--++liftD0 :: P.Doc -> Doc e+liftD0 = Doc . const++liftD :: (P.Doc -> P.Doc) -> Doc e -> Doc e+liftD f d = Doc (f <$> unDoc d)++liftD2 :: (P.Doc -> P.Doc -> P.Doc) ->+ Doc e -> Doc e -> Doc e+liftD2 f d1 d2 = Doc (f <$> unDoc d1 <*> unDoc d2)++liftDList :: ([P.Doc] -> P.Doc) -> [Doc e] -> Doc e+liftDList f ds = Doc (\e -> f [ d e | Doc d <- ds ])++--+-- Pretty-printing combinators+--++($$), ($+$), (<+>), (<>) :: Doc e -> Doc e -> Doc e+($$) = liftD2 (P.$$)+($+$) = liftD2 (P.$+$)+(<+>) = liftD2 (P.<+>)+(<>) = liftD2 (P.<>)++infixl 5 $$, $+$+infixl 6 <+>, <>++braces, brackets, doubleQuotes, parens, quotes :: Doc e -> Doc e+braces = liftD P.braces+brackets = liftD P.brackets+doubleQuotes = liftD P.doubleQuotes+quotes = liftD P.quotes+parens = liftD P.parens++nest :: Int -> Doc e -> Doc e+nest = liftD . P.nest++hang :: Doc e -> Int -> Doc e -> Doc e+hang d1 n = liftD2 (flip P.hang n) d1++punctuate :: Doc e -> [Doc e] -> [Doc e]+punctuate _ [] = []+punctuate _ [d] = [d]+punctuate d1 (d:ds) = d<>d1 : punctuate d1 ds++cat, fcat, fsep, hcat, hsep, sep, vcat :: [Doc e] -> Doc e+cat = liftDList P.cat+fcat = liftDList P.fcat+fsep = liftDList P.fsep+hcat = liftDList P.hcat+hsep = liftDList P.hsep+sep = liftDList P.sep+vcat = liftDList P.vcat++char :: Char -> Doc e+double :: Double -> Doc e+float :: Float -> Doc e+int :: Int -> Doc e+integer :: Integer -> Doc e+ptext :: String -> Doc e+rational :: Rational -> Doc e+text :: String -> Doc e+zeroWidthText :: String -> Doc e++char = liftD0 . P.char+double = liftD0 . P.double+float = liftD0 . P.float+int = liftD0 . P.int+integer = liftD0 . P.integer+ptext = liftD0 . P.ptext+rational = liftD0 . P.rational+text = liftD0 . P.text+zeroWidthText = liftD0 . P.zeroWidthText++colon, comma, equals, lbrace, lbrack, lparen, rbrace,+ rbrack, rparen, semi, space :: Doc e+colon = liftD0 P.colon+comma = liftD0 P.comma+equals = liftD0 P.equals+lbrace = liftD0 P.lbrace+lbrack = liftD0 P.lbrack+lparen = liftD0 P.lparen+rbrace = liftD0 P.rbrace+rbrack = liftD0 P.rbrack+rparen = liftD0 P.rparen+semi = liftD0 P.semi+space = liftD0 P.space++--+-- Rendering and queries+--++toDocIn :: e -> Doc e -> P.Doc+toDocIn = flip unDoc++isEmptyIn :: e -> Doc e -> Bool+isEmptyIn e = P.isEmpty . toDocIn e++renderIn :: e -> Doc e -> String+renderIn e = P.render . toDocIn e++renderStyleIn :: e -> P.Style -> Doc e -> String+renderStyleIn e sty = P.renderStyle sty . toDocIn e++fullRenderIn :: e ->+ P.Mode -> Int -> Float ->+ (P.TextDetails -> a -> a) -> a ->+ Doc e -> a+fullRenderIn e mode cols ribbon f z =+ P.fullRender mode cols ribbon f z . toDocIn e++toDoc :: Monoid e => Doc e -> P.Doc+toDoc = toDocIn mempty++isEmpty :: Monoid e => Doc e -> Bool+isEmpty = isEmptyIn mempty++render :: Monoid e => Doc e -> String+render = renderIn mempty++renderStyle :: Monoid e => P.Style -> Doc e -> String+renderStyle = renderStyleIn mempty++fullRender :: Monoid e =>+ P.Mode -> Int -> Float ->+ (P.TextDetails -> a -> a) -> a ->+ Doc e -> a+fullRender = fullRenderIn mempty++instance Monoid (Doc e) where+ mempty = liftD0 P.empty+ mappend = (<>)+ mconcat = hcat
+ src/Alt/Token.hs view
@@ -0,0 +1,493 @@+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-+ This is a modified version of the Parsec module whose copyright is+ below, which supports figuring out where a token has ended *before*+ ensuing whitespace.++ In particular, it defines a type class for functionally updating the+ state with a SourcePos, and then lexeme always stashes the position+ there before discarding whitespace.+-}+-----------------------------------------------------------------------------+-- |+-- Module : Text.ParserCombinators.Parsec.Token+-- Copyright : (c) Daan Leijen 1999-2001+-- License : BSD-style (see the file libraries/parsec/LICENSE)+--+-- Maintainer : daan@cs.uu.nl+-- Stability : provisional+-- Portability : non-portable (uses existentially quantified data constructors)+--+-- A helper module to parse lexical elements (tokens).+--+-----------------------------------------------------------------------------++module Alt.Token+ ( TokenEnd (..)+ , LanguageDef (..)+ , TokenParser (..)+ , makeTokenParser+ ) where++import Data.Char (isAlpha,toLower,toUpper,isSpace,digitToInt)+import Data.List (nub,sort)+import Text.ParserCombinators.Parsec++class TokenEnd st where+ saveTokenEnd :: CharParser st ()++instance TokenEnd () where+ saveTokenEnd = return ()++-----------------------------------------------------------+-- Language Definition+-----------------------------------------------------------+data LanguageDef st+ = LanguageDef+ { commentStart :: String+ , commentEnd :: String+ , commentLine :: String+ , nestedComments :: Bool+ , identStart :: CharParser st Char+ , identLetter :: CharParser st Char+ , opStart :: CharParser st Char+ , opLetter :: CharParser st Char+ , reservedNames :: [String]+ , reservedOpNames:: [String]+ , caseSensitive :: Bool+ }++-----------------------------------------------------------+-- A first class module: TokenParser+-----------------------------------------------------------+data TokenParser st+ = TokenParser{ identifier :: CharParser st String+ , reserved :: String -> CharParser st ()+ , operator :: CharParser st String+ , reservedOp :: String -> CharParser st ()++ , charLiteral :: CharParser st Char+ , stringLiteral :: CharParser st String+ , natural :: CharParser st Integer+ , integer :: CharParser st Integer+ , float :: CharParser st Double+ , naturalOrFloat :: CharParser st (Either Integer Double)+ , decimal :: CharParser st Integer+ , hexadecimal :: CharParser st Integer+ , octal :: CharParser st Integer++ , symbol :: String -> CharParser st String+ , lexeme :: forall a. CharParser st a -> CharParser st a+ , whiteSpace :: CharParser st ()++ , parens :: forall a. CharParser st a -> CharParser st a+ , braces :: forall a. CharParser st a -> CharParser st a+ , angles :: forall a. CharParser st a -> CharParser st a+ , brackets :: forall a. CharParser st a -> CharParser st a+ -- "squares" is deprecated+ , squares :: forall a. CharParser st a -> CharParser st a++ , semi :: CharParser st String+ , comma :: CharParser st String+ , colon :: CharParser st String+ , dot :: CharParser st String+ , semiSep :: forall a . CharParser st a -> CharParser st [a]+ , semiSep1 :: forall a . CharParser st a -> CharParser st [a]+ , commaSep :: forall a . CharParser st a -> CharParser st [a]+ , commaSep1 :: forall a . CharParser st a -> CharParser st [a]+ }++-----------------------------------------------------------+-- Given a LanguageDef, create a token parser.+-----------------------------------------------------------+makeTokenParser :: TokenEnd st => LanguageDef st -> TokenParser st+makeTokenParser languageDef+ = TokenParser{ identifier = identifier+ , reserved = reserved+ , operator = operator+ , reservedOp = reservedOp++ , charLiteral = charLiteral+ , stringLiteral = stringLiteral+ , natural = natural+ , integer = integer+ , float = float+ , naturalOrFloat = naturalOrFloat+ , decimal = decimal+ , hexadecimal = hexadecimal+ , octal = octal++ , symbol = symbol+ , lexeme = lexeme+ , whiteSpace = whiteSpace++ , parens = parens+ , braces = braces+ , angles = angles+ , brackets = brackets+ , squares = brackets+ , semi = semi+ , comma = comma+ , colon = colon+ , dot = dot+ , semiSep = semiSep+ , semiSep1 = semiSep1+ , commaSep = commaSep+ , commaSep1 = commaSep1+ }+ where++ -----------------------------------------------------------+ -- Bracketing+ -----------------------------------------------------------+ parens p = between (symbol "(") (symbol ")") p+ braces p = between (symbol "{") (symbol "}") p+ angles p = between (symbol "<") (symbol ">") p+ brackets p = between (symbol "[") (symbol "]") p++ semi = symbol ";"+ comma = symbol ","+ dot = symbol "."+ colon = symbol ":"++ commaSep p = sepBy p comma+ semiSep p = sepBy p semi++ commaSep1 p = sepBy1 p comma+ semiSep1 p = sepBy1 p semi+++ -----------------------------------------------------------+ -- Chars & Strings+ -----------------------------------------------------------+ -- charLiteral :: CharParser st Char+ charLiteral = lexeme (between (char '\'')+ (char '\'' <?> "end of character")+ characterChar )+ <?> "character"++ characterChar = charLetter <|> charEscape+ <?> "literal character"++ charEscape = do{ char '\\'; escapeCode }+ charLetter = satisfy (\c -> (c /= '\'') && (c /= '\\') && (c > '\026'))++++ -- stringLiteral :: CharParser st String+ stringLiteral = lexeme (+ do{ str <- between (char '"')+ (char '"' <?> "end of string")+ (many stringChar)+ ; return (foldr (maybe id (:)) "" str)+ }+ <?> "literal string")++ -- stringChar :: CharParser st (Maybe Char)+ stringChar = do{ c <- stringLetter; return (Just c) }+ <|> stringEscape+ <?> "string character"++ stringLetter = satisfy (\c -> (c /= '"') && (c /= '\\') && (c > '\026'))++ stringEscape = do{ char '\\'+ ; do{ escapeGap ; return Nothing }+ <|> do{ escapeEmpty; return Nothing }+ <|> do{ esc <- escapeCode; return (Just esc) }+ }++ escapeEmpty = char '&'+ escapeGap = do{ many1 space+ ; char '\\' <?> "end of string gap"+ }++++ -- escape codes+ escapeCode = charEsc <|> charNum <|> charAscii <|> charControl+ <?> "escape code"++ -- charControl :: CharParser st Char+ charControl = do{ char '^'+ ; code <- upper+ ; return (toEnum (fromEnum code - fromEnum 'A'))+ }++ -- charNum :: CharParser st Char+ charNum = do{ code <- decimal+ <|> do{ char 'o'; number 8 octDigit }+ <|> do{ char 'x'; number 16 hexDigit }+ ; return (toEnum (fromInteger code))+ }++ charEsc = choice (map parseEsc escMap)+ where+ parseEsc (c,code) = do{ char c; return code }++ charAscii = choice (map parseAscii asciiMap)+ where+ parseAscii (asc,code) = try (do{ string asc; return code })+++ -- escape code tables+ escMap = zip ("abfnrtv\\\"\'") ("\a\b\f\n\r\t\v\\\"\'")+ asciiMap = zip (ascii3codes ++ ascii2codes) (ascii3 ++ ascii2)++ ascii2codes = ["BS","HT","LF","VT","FF","CR","SO","SI","EM",+ "FS","GS","RS","US","SP"]+ ascii3codes = ["NUL","SOH","STX","ETX","EOT","ENQ","ACK","BEL",+ "DLE","DC1","DC2","DC3","DC4","NAK","SYN","ETB",+ "CAN","SUB","ESC","DEL"]++ ascii2 = ['\BS','\HT','\LF','\VT','\FF','\CR','\SO','\SI',+ '\EM','\FS','\GS','\RS','\US','\SP']+ ascii3 = ['\NUL','\SOH','\STX','\ETX','\EOT','\ENQ','\ACK',+ '\BEL','\DLE','\DC1','\DC2','\DC3','\DC4','\NAK',+ '\SYN','\ETB','\CAN','\SUB','\ESC','\DEL']+++ -----------------------------------------------------------+ -- Numbers+ -----------------------------------------------------------+ -- naturalOrFloat :: CharParser st (Either Integer Double)+ naturalOrFloat = lexeme (natFloat) <?> "number"++ float = lexeme floating <?> "float"+ integer = lexeme int <?> "integer"+ natural = lexeme nat <?> "natural"+++ -- floats+ floating = do{ n <- decimal+ ; fractExponent n+ }+++ natFloat = do{ char '0'+ ; zeroNumFloat+ }+ <|> decimalFloat++ zeroNumFloat = do{ n <- hexadecimal <|> octal+ ; return (Left n)+ }+ <|> decimalFloat+ <|> fractFloat 0+ <|> return (Left 0)++ decimalFloat = do{ n <- decimal+ ; option (Left n)+ (fractFloat n)+ }++ fractFloat n = do{ f <- fractExponent n+ ; return (Right f)+ }++ fractExponent n = do{ fract <- fraction+ ; expo <- option 1.0 exponent'+ ; return ((fromInteger n + fract)*expo)+ }+ <|>+ do{ expo <- exponent'+ ; return ((fromInteger n)*expo)+ }++ fraction = do{ char '.'+ ; digits <- many1 digit <?> "fraction"+ ; return (foldr op 0.0 digits)+ }+ <?> "fraction"+ where+ op d f = (f + fromIntegral (digitToInt d))/10.0++ exponent' = do{ oneOf "eE"+ ; f <- sign+ ; e <- decimal <?> "exponent"+ ; return (power (f e))+ }+ <?> "exponent"+ where+ power e | e < 0 = 1.0/power(-e)+ | otherwise = fromInteger (10^e)+++ -- integers and naturals+ int = do{ f <- lexeme sign+ ; n <- nat+ ; return (f n)+ }++ -- sign :: CharParser st (Integer -> Integer)+ sign = (char '-' >> return negate)+ <|> (char '+' >> return id)+ <|> return id++ nat = zeroNumber <|> decimal++ zeroNumber = do{ char '0'+ ; hexadecimal <|> octal <|> decimal <|> return 0+ }+ <?> ""++ decimal = number 10 digit+ hexadecimal = do{ oneOf "xX"; number 16 hexDigit }+ octal = do{ oneOf "oO"; number 8 octDigit }++ -- number :: Integer -> CharParser st Char -> CharParser st Integer+ number base baseDigit+ = do{ digits <- many1 baseDigit+ ; let n = foldl (\x d -> base*x + toInteger (digitToInt d)) 0 digits+ ; seq n (return n)+ }++ -----------------------------------------------------------+ -- Operators & reserved ops+ -----------------------------------------------------------+ reservedOp name =+ lexeme $ try $+ do{ string name+ ; notFollowedBy (opLetter languageDef) <?> ("end of " ++ show name)+ }++ operator =+ lexeme $ try $+ do{ name <- oper+ ; if (isReservedOp name)+ then unexpected ("reserved operator " ++ show name)+ else return name+ }++ oper =+ do{ c <- (opStart languageDef)+ ; cs <- many (opLetter languageDef)+ ; return (c:cs)+ }+ <?> "operator"++ isReservedOp name =+ isReserved (sort (reservedOpNames languageDef)) name+++ -----------------------------------------------------------+ -- Identifiers & Reserved words+ -----------------------------------------------------------+ reserved name =+ lexeme $ try $+ do{ caseString name+ ; notFollowedBy (identLetter languageDef) <?> ("end of " ++ show name)+ }++ caseString name+ | caseSensitive languageDef = string name+ | otherwise = do{ walk name; return name }+ where+ walk [] = return ()+ walk (c:cs) = do{ caseChar c <?> msg; walk cs }++ caseChar c | isAlpha c = char (toLower c) <|> char (toUpper c)+ | otherwise = char c++ msg = show name+++ identifier =+ lexeme $ try $+ do{ name <- ident+ ; if (isReservedName name)+ then unexpected ("reserved word " ++ show name)+ else return name+ }+++ ident+ = do{ c <- identStart languageDef+ ; cs <- many (identLetter languageDef)+ ; return (c:cs)+ }+ <?> "identifier"++ isReservedName name+ = isReserved theReservedNames caseName+ where+ caseName | caseSensitive languageDef = name+ | otherwise = map toLower name+++ isReserved names name+ = scan names+ where+ scan [] = False+ scan (r:rs) = case (compare r name) of+ LT -> scan rs+ EQ -> True+ GT -> False++ theReservedNames+ | caseSensitive languageDef = sortedNames+ | otherwise = map (map toLower) sortedNames+ where+ sortedNames = sort (reservedNames languageDef)++++ -----------------------------------------------------------+ -- White space & symbols+ -----------------------------------------------------------+ symbol name+ = lexeme (string name)++ lexeme p+ = do+ x <- p+ saveTokenEnd+ whiteSpace+ return x+++ --whiteSpace+ whiteSpace+ | noLine && noMulti = skipMany (simpleSpace <?> "")+ | noLine = skipMany (simpleSpace <|> multiLineComment <?> "")+ | noMulti = skipMany (simpleSpace <|> oneLineComment <?> "")+ | otherwise = skipMany (simpleSpace <|> oneLineComment <|> multiLineComment <?> "")+ where+ noLine = null (commentLine languageDef)+ noMulti = null (commentStart languageDef)+++ simpleSpace =+ skipMany1 (satisfy isSpace)++ oneLineComment =+ do{ try (string (commentLine languageDef))+ ; skipMany (satisfy (/= '\n'))+ ; return ()+ }++ multiLineComment =+ do { try (string (commentStart languageDef))+ ; inComment+ }++ inComment+ | nestedComments languageDef = inCommentMulti+ | otherwise = inCommentSingle++ inCommentMulti+ = do{ try (string (commentEnd languageDef)) ; return () }+ <|> do{ multiLineComment ; inCommentMulti }+ <|> do{ skipMany1 (noneOf startEnd) ; inCommentMulti }+ <|> do{ oneOf startEnd ; inCommentMulti }+ <?> "end of comment"+ where+ startEnd = nub (commentEnd languageDef ++ commentStart languageDef)++ inCommentSingle+ = do{ try (string (commentEnd languageDef)); return () }+ <|> do{ skipMany1 (noneOf startEnd) ; inCommentSingle }+ <|> do{ oneOf startEnd ; inCommentSingle }+ <?> "end of comment"+ where+ startEnd = nub (commentEnd languageDef ++ commentStart languageDef)+
src/Basis.hs view
@@ -1,21 +1,15 @@ -- | Built-in operations and types-{-# LANGUAGE- DeriveDataTypeable,- QuasiQuotes,- TemplateHaskell #-} module Basis ( primBasis, srcBasis, basis2venv, basis2tenv ) where import Util import BasisUtils-import Value (Valuable(..), Value(..))-import Syntax+import Value (Valuable(..), Value(..), VRecord(..))+import AST import Type -import qualified Loc-import qualified Syntax.Notable-import qualified Syntax.Decl+import qualified Data.Loc import qualified Basis.IO import qualified Basis.Socket@@ -25,11 +19,13 @@ import qualified Basis.MVar import qualified Basis.Future import qualified Basis.Array+import qualified Basis.Row import qualified IO import qualified System.Environment as Env import Data.IORef (IORef, newIORef, readIORef, atomicModifyIORef) import System.Random (randomIO)+import System.Exit (exitWith, ExitCode(..)) import Data.Typeable -- Primitive operations implemented in Haskell@@ -42,145 +38,170 @@ --- name -: type -= value -- Primitive types:- "unit" `primtype` tcUnit,- "any" `primtype` tcBot,- "exn" `primtype` tcExn,- dec [$dc| type bool = false | true |],- "int" `primtype` tcInt,- dec [$dc| type char = int |],- "float" `primtype` tcFloat,- "string" `primtype` tcString,- "U" `primtype` tcUn,- "A" `primtype` tcAf,- "*" `primtype` tcTuple,+ "unit" `primtype` tcUnit,+ "exn" `primtype` tcExn,+ "int" `primtype` tcInt,+ "char" `primtype` tcChar,+ "float" `primtype` tcFloat,+ "string" `primtype` tcString,+ "unlimited" `primtype` tcUn,+ "affine" `primtype` tcAf,+ "*" `primtype` tcTuple,+ "record" `primtype` tcRecord,+ "variant" `primtype` tcVariant,+ "rowend" `primtype` tcRowEnd,+ "rowdots#" `primtype` tcRowDots, -- Needed by renamer+ "\\/" `primtype` tcJoin,+ "->" `primtype` tcFun, - -- Sums- dec [$dc| type `a option = None | Some of `a |],- dec [$dc| type `a + `b = Left of `a | Right of `b |],+ -- Bool needs to be known to the parser for if expression+ dec [sgQ| type bool = false | true |], - -- Lists- dec [$dc| type `a list = Nil | Cons of `a * `a list |],+ -- Lists need to be known by the parser for list syntax+ dec [sgQ| type `a list = [] | (::) of `a * `a list |], + submod "INTERNALS" [+ submod "PrimTypes" [+ dec [sgQ| type unit = type unit |],+ dec [sgQ| type variant = type variant |],+ dec [sgQ| type record = type record |],+ dec [sgQ| type rowend = type rowend |],+ dec [sgQ| type unlimited = type unlimited |],+ dec [sgQ| type affine = type affine |],+ dec [sgQ| type bool = type bool |],+ dec [sgQ| type list = type list |],+ val "nilRecord" -: [ty| (unlimited, rowend) record |]+ -= MultiplicativeRecord []+ ]+ ],++ -- Sums+ dec [sgQ| type `a option = None | Some of `a |],+ dec [sgQ| type `a + `b = Left of `a | Right of `b |],+ -- Arithmetic binArith "+" (+), binArith "-" (-), binArith "*" (*), binArith "/" div, binArith "%" mod,- fun "~" -: [$ty| int -> int |]+ fun "~" -: [ty| int -> int |] -= (negate :: Integer -> Integer),- fun "abs" -: [$ty| int -> int |]+ fun "abs" -: [ty| int -> int |] -= (abs :: Integer -> Integer) ,- fun "<=" -: [$ty| int -> int -> bool |]+ fun "<=" -: [ty| int -> int -> bool |] -= ((<=) :: Integer -> Integer -> Bool),- fun "string_of_int" -: [$ty| int -> string |]+ fun "string_of_int" -: [ty| int -> string |] -= (show :: Integer -> String),- fun "int_of_string" -: [$ty| string -> int |]+ fun "int_of_string" -: [ty| string -> int |] -= (read :: String -> Integer),- fun "random_int" -: [$ty| unit -> int |]+ fun "random_int" -: [ty| unit -> int |] -= \() -> (randomIO :: IO Int), -- Floating point arithmetic- fun "<=." -: [$ty| float -> float -> bool |]+ fun "<=." -: [ty| float -> float -> bool |] -= ((<=) :: Double -> Double -> Bool),- fun "<." -: [$ty| float -> float -> bool |]+ fun "<." -: [ty| float -> float -> bool |] -= ((<) :: Double -> Double -> Bool),- fun "+." -: [$ty| float -> float -> float |]+ fun "+." -: [ty| float -> float -> float |] -= ((+) :: Double -> Double -> Double),- fun "-." -: [$ty| float -> float -> float |]+ fun "-." -: [ty| float -> float -> float |] -= ((-) :: Double -> Double -> Double),- fun "*." -: [$ty| float -> float -> float |]+ fun "*." -: [ty| float -> float -> float |] -= ((*) :: Double -> Double -> Double),- fun "/." -: [$ty| float -> float -> float |]+ fun "/." -: [ty| float -> float -> float |] -= ((/) :: Double -> Double -> Double),- fun "**" -: [$ty| float -> float -> float |]+ fun "**" -: [ty| float -> float -> float |] -= ((**) :: Double -> Double -> Double),- fun "~." -: [$ty| float -> float |]+ fun "~." -: [ty| float -> float |] -= (negate :: Double -> Double),- fun "sqrt" -: [$ty| float -> float |]+ fun "sqrt" -: [ty| float -> float |] -= (sqrt :: Double -> Double),- fun "log" -: [$ty| float -> float |]+ fun "log" -: [ty| float -> float |] -= (log :: Double -> Double),- fun "absf" -: [$ty| float -> float |]+ fun "absf" -: [ty| float -> float |] -= (abs :: Double -> Double),- fun "float_of_int" -: [$ty| int -> float |]+ fun "float_of_int" -: [ty| int -> float |] -= (fromIntegral :: Integer -> Double),- fun "int_of_float" -: [$ty| float -> int |]+ fun "int_of_float" -: [ty| float -> int |] -= (round :: Double -> Integer),- fun "string_of_float" -: [$ty| float -> string |]+ fun "string_of_float" -: [ty| float -> string |] -= (show :: Double -> String),- fun "float_of_string" -: [$ty| string -> float |]+ fun "float_of_string" -: [ty| string -> float |] -= (read :: String -> Double), -- Strings- fun "explode" -: [$ty| string -> char list |]- -= map char2integer,- fun "implode" -: [$ty| char list -> string |]- -= map integer2char,- fun "^" -: [$ty| string -> string -> string |]+ fun "explode" -: [ty| string -> char list |]+ -= (map vinj ∷ String → [Value]),+ fun "implode" -: [ty| char list -> string |]+ -= (map vprj ∷ [Value] → String),+ fun "^" -: [ty| string -> string -> string |] -= ((++) :: String -> String -> String),- fun "string_of" -: [$ty| all 'a. 'a -> string |]+ fun "string_of" -: [ty| all 'a. 'a -> string |] -= (return . show :: Value -> IO String),- fun "string_length" -: [$ty| string -> int |]+ fun "string_length" -: [ty| string -> int |] -= \s -> toInteger (length (s :: String)), -- "Magic" equality and print; failure- fun "==" -: [$ty| all 'a. 'a -> 'a -> bool |]+ fun "==" -: [ty| all 'a. 'a -> 'a -> bool |] -= ((==) :: Value -> Value -> Bool),- fun "print" -: [$ty| all 'a. 'a -> unit |]+ fun "print" -: [ty| all 'a. 'a -> unit |] -= (print :: Value -> IO ()), -- I/O- fun "putChar" -: [$ty| char -> unit |]+ fun "putChar" -: [ty| char -> unit |] -= putChar . integer2char,- fun "getChar" -: [$ty| unit -> char |]+ fun "getChar" -: [ty| unit -> char |] -= \() -> fmap char2integer getChar,- fun "flush" -: [$ty| unit -> unit |]+ fun "flush" -: [ty| unit -> unit |] -= \() -> IO.hFlush IO.stdout,- fun "putStr" -: [$ty| string -> unit |]+ fun "putStr" -: [ty| string -> unit |] -= putStr,- fun "putStrLn" -: [$ty| string -> unit |]+ fun "putStrLn" -: [ty| string -> unit |] -= putStrLn,- fun "getLine" -: [$ty| unit -> string |]+ fun "getLine" -: [ty| unit -> string |] -= \() -> getLine, - -- The environment- fun "getArgs" -: [$ty| unit -> string list |]+ -- System and the environment+ fun "getArgs" -: [ty| unit -> string list |] -= \() -> Env.getArgs,- fun "getProgName" -: [$ty| unit -> string |]+ fun "getProgName" -: [ty| unit -> string |] -= \() -> Env.getProgName,- fun "getEnv" -: [$ty| string -> string |]+ fun "getEnv" -: [ty| string -> string |] -= Env.getEnv,- fun "getEnvironment" -: [$ty| unit -> (string * string) list |]+ fun "getEnvironment" -: [ty| unit -> (string * string) list |] -= \() -> Env.getEnvironment,+ fun "exit" -: [ty| ∀ `a. int -> `a |]+ -= \z ->+ exitWith (if z == 0 then ExitSuccess else ExitFailure z) ∷ IO (), -- References- dec [$dc| type `a ref qualifier U |],- dec [$dc| type `a aref qualifier A |],- fun "ref" -: [$ty| all `a. `a -> `a ref |]+ dec [sgQ| type `a ref qualifier U |],+ dec [sgQ| type `a aref qualifier A |],+ fun "ref" -: [ty| all `a. `a -> `a ref |] -= (\v -> Ref `fmap` newIORef v),- fun "aref" -: [$ty| all `a. `a -> `a aref |]+ fun "aref" -: [ty| all `a. `a -> `a aref |] -= (\v -> Ref `fmap` newIORef v), - fun "!" -: [$ty| all 'a. 'a ref -> 'a |]+ fun "!" -: [ty| all 'a. 'a ref -> 'a |] -= (\r -> readIORef (unRef r)),- fun "!!" -: [$ty| all 'a. 'a aref -> 'a aref * 'a |]+ fun "!!" -: [ty| all 'a. 'a aref -> 'a aref * 'a |] -= (\r -> do v <- readIORef (unRef r) return (r, v)),- fun "<-" -: [$ty| all `a. `a ref -> `a -> `a |]+ fun "<-" -: [ty| all `a. `a ref -> `a -> `a |] -= (\r v -> do atomicModifyIORef (unRef r) (\v' -> (v, v'))),- fun "<-!" -: [$ty| all `a `b. `a aref ->+ fun "<-!" -: [ty| all `a `b. `a aref -> `b -o `b aref * `a |] -= (\r v -> do atomicModifyIORef (unRef r) (\v' -> (v, (r, v')))), submod "Unsafe" [ -- Unsafe coercions- fun "unsafeCoerce" -: [$ty| all `b `a. `a -> `b |]+ fun "unsafeCoerce" -: [ty| all `b `a. `a -> `b |] -= (id :: Value -> Value),- fun "unsafeDup" -: [$ty| all `a. `a -> `a * `a |]+ fun "unsafeDup" -: [ty| all `a. `a -> `a * `a |] -= ((\v -> (v, v)) :: Value -> (Value, Value)) ], @@ -193,7 +214,8 @@ submod "Prim" [ submod "Socket" Basis.Socket.entries, submod "Exn" Basis.Exn.entries,- submod "Array" Basis.Array.entries+ submod "Array" Basis.Array.entries,+ submod "Row" Basis.Row.entries ] ]
src/Basis/Array.hs view
@@ -1,17 +1,12 @@-{-# LANGUAGE- DeriveDataTypeable,- QuasiQuotes #-} module Basis.Array (entries) where import Data.Typeable (Typeable) import BasisUtils-import Syntax+import AST import Util import Value (Value, Valuable(..)) -import qualified Loc-import qualified Syntax.Notable-import qualified Syntax.Decl+import qualified Data.Loc import qualified Data.Array.IO as A @@ -27,23 +22,23 @@ entries :: [Entry Raw] entries = [- dec [$dc| type `a array |],- fun "build" -: [$ty| all `a. int -> (int -> `a) -> `a array |]+ dec [sgQ| type `a array |],+ fun "build" -: [ty| all `a. int -> (int -> `a) -> `a array |] -= \size builder -> io $ do a <- A.newArray_ (0, size - 1) forM_ [ 0 .. size - 1 ] $ \i -> vapp builder i >>= A.writeArray a i return (Array a),- fun "size" -: [$ty| all `a. `a array -> int |]+ fun "size" -: [ty| all `a. `a array -> int |] -= \a -> io $ do (_, limit) <- A.getBounds (unArray a) return (limit + 1),- fun "swap" -: [$ty| all `a. `a array -> int -> `a -> `a |]+ fun "swap" -: [ty| all `a. `a array -> int -> `a -> `a |] -= \(Array a) ix new -> io $ do old <- A.readArray a ix A.writeArray a ix new return old,- fun "get" -: [$ty| all 'a. 'a array -> int -> 'a |]+ fun "get" -: [ty| all 'a. 'a array -> int -> 'a |] -= \(Array a) ix -> io $ A.readArray a ix ]
src/Basis/Channel.hs view
@@ -1,16 +1,11 @@-{-# LANGUAGE- DeriveDataTypeable,- QuasiQuotes #-} module Basis.Channel (Channel, entries) where import Data.Typeable (Typeable) import BasisUtils-import Syntax+import AST import Value (Value, Valuable(..)) -import qualified Loc-import qualified Syntax.Notable-import qualified Syntax.Decl+import qualified Data.Loc import qualified Basis.Channel.Haskell as C @@ -23,13 +18,13 @@ entries :: [Entry Raw] entries = [- dec [$dc| type 'a channel |],- fun "new" -: [$ty| all 'a. unit -> 'a channel |]+ dec [sgQ| type 'a channel |],+ fun "new" -: [ty| all 'a. unit -> 'a channel |] -= \() -> Channel `fmap` C.newChan,- fun "send" -: [$ty| all 'a. 'a channel -> 'a -> unit |]+ fun "send" -: [ty| all 'a. 'a channel -> 'a -> unit |] -= \c a -> do C.writeChan (unChannel c) a return (),- fun "recv" -: [$ty| all 'a. 'a channel -> 'a |]+ fun "recv" -: [ty| all 'a. 'a channel -> 'a |] -= \c -> C.readChan (unChannel c) ]
src/Basis/Exn.hs view
@@ -1,25 +1,22 @@-{-# LANGUAGE- QuasiQuotes #-} module Basis.Exn ( entries ) where import BasisUtils import Value-import Syntax+import AST -import qualified Loc-import qualified Syntax.Notable+import qualified Data.Loc import Control.Exception entries :: [Entry Raw] entries = [- fun "raise" -: [$ty| all `a. exn -> `a |]+ fun "raise" -: [ty| all `a. exn -> `a |] -= \exn -> throw (VExn exn :: VExn) :: IO Value, fun "tryfun_string"- -: [$ty| all `a. (unit -o `a) -> (exn + string) + `a |]- -= \(VaFun _ f) -> do- fmap Right (f vaUnit) `catches`+ -: [ty| all `a. (unit -o `a) -> (exn + string) + `a |]+ -= \f -> do+ fmap Right (vapp f vaUnit) `catches` [ Handler $ \(VExn v) -> return (Left (Left v)) , Handler $ \e -> return (Left (Right (show (e:: IOError)))) ] ]
src/Basis/Future.hs view
@@ -1,16 +1,11 @@-{-# LANGUAGE- DeriveDataTypeable,- QuasiQuotes #-} module Basis.Future (entries) where import Data.Typeable (Typeable) import BasisUtils-import Syntax+import AST import Value (Value, Valuable(..)) -import qualified Loc-import qualified Syntax.Notable-import qualified Syntax.Decl+import qualified Data.Loc import qualified Control.Concurrent as CC import qualified Control.Concurrent.MVar as MV@@ -26,24 +21,24 @@ entries :: [Entry Raw] entries = [ -- Futures- dec [$dc| type +`a future qualifier A |],- dec [$dc| type -`a cofuture qualifier A |],+ dec [sgQ| type +`a future qualifier A |],+ dec [sgQ| type -`a cofuture qualifier A |], - fun "new" -: [$ty| all `a. (unit -o `a) -> `a future |]+ fun "new" -: [ty| all `a. (unit -o `a) -> `a future |] -= \f -> do future <- MV.newEmptyMVar CC.forkIO (vapp f () >>= MV.putMVar future) return (Future future),- fun "sync" -: [$ty| all `a. `a future -> `a |]+ fun "sync" -: [ty| all `a. `a future -> `a |] -= (MV.takeMVar . unFuture),- fun "coNew" -: [$ty| all `a. (`a future -o unit) -> `a cofuture |]+ fun "coNew" -: [ty| all `a. (`a future -o unit) -> `a cofuture |] -= \f -> do future <- MV.newEmptyMVar CC.forkIO (vapp f (Future future) >> return ()) return (Future future),- fun "coSync" -: [$ty| all `a. `a cofuture -> `a -o unit |]+ fun "coSync" -: [ty| all `a. `a cofuture -> `a -o unit |] -= \future value -> MV.putMVar (unFuture future) value,- fun "newPair" -: [$ty| all `a. unit -> `a future * `a cofuture |]+ fun "newPair" -: [ty| all `a. unit -> `a future * `a cofuture |] -= \() -> do future <- MV.newEmptyMVar return (Future future, Future future)
src/Basis/IO.hs view
@@ -1,21 +1,13 @@-{-# LANGUAGE- DeriveDataTypeable,- QuasiQuotes,- StandaloneDeriving- #-} module Basis.IO ( entries ) where -import qualified IO--import Data.Data (Typeable, Data)+import qualified Data.Loc import BasisUtils-import Syntax+import AST import Util import Value (Valuable(..), vinjData, vprjDataM) -import qualified Loc-import qualified Syntax.Notable-import qualified Syntax.Decl+import qualified IO+import Data.Data (Typeable, Data) instance Valuable IO.Handle where veq = (==)@@ -31,30 +23,30 @@ entries :: [Entry Raw] entries = [- dec [$dc| type handle |],- dec [$dc| type ioMode = ReadMode+ dec [sgQ| type handle |],+ dec [sgQ| type ioMode = ReadMode | WriteMode | AppendMode | ReadWriteMode |], -- File operations- fun "openFile" -: [$ty| string -> ioMode -> handle |]+ fun "openFile" -: [ty| string -> ioMode -> handle |] -= IO.openFile,- fun "hGetChar" -: [$ty| handle -> char |]+ fun "hGetChar" -: [ty| handle -> char |] -= fmap char2integer . IO.hGetChar,- fun "hGetLine" -: [$ty| handle -> string |]+ fun "hGetLine" -: [ty| handle -> string |] -= IO.hGetLine,- fun "hIsEOF" -: [$ty| handle -> bool |]+ fun "hIsEOF" -: [ty| handle -> bool |] -= IO.hIsEOF,- fun "hPutChar" -: [$ty| handle -> char -> unit |]+ fun "hPutChar" -: [ty| handle -> char -> unit |] -= \h -> IO.hPutChar h . integer2char,- fun "hPutStr" -: [$ty| handle -> string -> unit |]+ fun "hPutStr" -: [ty| handle -> string -> unit |] -= IO.hPutStr,- fun "hClose" -: [$ty| handle -> unit |]+ fun "hClose" -: [ty| handle -> unit |] -= IO.hClose,- fun "hFlush" -: [$ty| handle -> unit |]+ fun "hFlush" -: [ty| handle -> unit |] -= IO.hFlush, - val "stdin" -: [$ty| handle |] -= IO.stdin,- val "stdout" -: [$ty| handle |] -= IO.stdout,- val "stderr" -: [$ty| handle |] -= IO.stderr+ val "stdin" -: [ty| handle |] -= IO.stdin,+ val "stdout" -: [ty| handle |] -= IO.stdout,+ val "stderr" -: [ty| handle |] -= IO.stderr ]
src/Basis/MVar.hs view
@@ -1,17 +1,12 @@-{-# LANGUAGE- DeriveDataTypeable,- QuasiQuotes #-} module Basis.MVar (entries) where import Data.Typeable (Typeable) import BasisUtils-import Syntax+import AST import Util import Value (Value, Valuable(..)) -import qualified Loc-import qualified Syntax.Notable-import qualified Syntax.Decl+import qualified Data.Loc import qualified Control.Concurrent.MVar as MV @@ -24,41 +19,41 @@ entries :: [Entry Raw] entries = [- dec [$dc| type `a mvar qualifier U |],- fun "new" -: [$ty| all `a. `a -> `a mvar |]+ dec [sgQ| type `a mvar qualifier U |],+ fun "new" -: [ty| all `a. `a -> `a mvar |] -= liftM MVar . MV.newMVar, fun "newEmpty"- -: [$ty| all `a. unit -> `a mvar |]+ -: [ty| all `a. unit -> `a mvar |] -= \() -> MVar `liftM` MV.newEmptyMVar, fun "take"- -: [$ty| all `a. `a mvar -> `a |]+ -: [ty| all `a. `a mvar -> `a |] -= MV.takeMVar . unMVar, fun "put"- -: [$ty| all `a. `a mvar -> `a -> unit |]+ -: [ty| all `a. `a mvar -> `a -> unit |] -= MV.putMVar . unMVar, fun "read"- -: [$ty| all 'a. 'a mvar -> 'a |] -- important!+ -: [ty| all 'a. 'a mvar -> 'a |] -- important! -= MV.readMVar . unMVar, fun "swap"- -: [$ty| all `a. `a mvar -> `a -> `a |]+ -: [ty| all `a. `a mvar -> `a -> `a |] -= MV.swapMVar . unMVar, fun "tryTake"- -: [$ty| all `a. `a mvar -> `a option |]+ -: [ty| all `a. `a mvar -> `a option |] -= MV.tryTakeMVar . unMVar, fun "tryPut"- -: [$ty| all `a. `a mvar -> `a -> bool |]+ -: [ty| all `a. `a mvar -> `a -> bool |] -= MV.tryPutMVar . unMVar, fun "isEmpty"- -: [$ty| all `a. `a mvar -> bool |]+ -: [ty| all `a. `a mvar -> bool |] -= MV.isEmptyMVar . unMVar, fun "callWith"- -: [$ty| all `a `b. `a mvar -> (`a -> `b) -> `b |]+ -: [ty| all `a `b. `a mvar -> (`a -> `b) -> `b |] -= \mv callback -> MV.withMVar (unMVar mv) (vapp callback), fun "modify_"- -: [$ty| all `a. `a mvar -> (`a -> `a) -> unit |]+ -: [ty| all `a. `a mvar -> (`a -> `a) -> unit |] -= \mv callback -> MV.modifyMVar_ (unMVar mv) (vapp callback), fun "modify"- -: [$ty| all `a `b. `a mvar -> (`a -> `a * `b) -> `b |]+ -: [ty| all `a `b. `a mvar -> (`a -> `a * `b) -> `b |] -= \mv callback -> MV.modifyMVar (unMVar mv) $ \v -> do result <- vapp callback v (vprjM result :: IO (Value, Value))
+ src/Basis/Row.hs view
@@ -0,0 +1,113 @@+module Basis.Row ( entries ) where++import Util+import BasisUtils+import Value+import AST++import qualified Data.Loc++entries :: [Entry Raw]+entries = [+ dec [sgQ| type `a ... |-> `b = {+ (`a -A> `b) ... +} |],+ fun "rowCase" -: [ty| ∀ `a `b. [ `a ] → (`a |-> `b) → `b |]+ -= \variant record → case variant of+ VaLab ix lab v → do+ f ← getField ix lab record+ vapp f v+ _ → throwFailure "case: expected variant",++ fun "isVariant" -: [ty| ∀ `a. `a → bool |]+ -= \variant → case variant of+ VaLab _ _ _ → True+ _ → False,+ fun "variantLabel" -: [ty| ∀ `a. [ `a ] → int * string |]+ -= \variant → case variant of+ VaLab ix lab _ → return (ix, show lab)+ _ → throwFailure "variantLabel: not a variant",+ fun "unsafeVariantValue" -: [ty| ∀ `a `b. [ `a ] → `b |]+ -= \variant → case variant of+ VaLab _ _ v → return v+ _ → throwFailure "variantValue: not a variant",+ fun "unsafeMakeVariant" -: [ty| ∀ `a `b. int → string → `a → [ `b ] |]+ -= \ix lab v → VaLab ix (ident lab) v,++ fun "isRecord" -: [ty| ∀ `a. `a → bool |]+ -= \v → do+ case vprjM v of+ Just (AdditiveRecord _) → True+ Just (MultiplicativeRecord _) → True+ _ → False,+ fun "isAddRecord" -: [ty| ∀ `a. `a → bool |]+ -= \v → do+ case vprjM v of+ Just (AdditiveRecord _) → True+ _ → False,+ fun "isMulRecord" -: [ty| ∀ `a. `a → bool |]+ -= \v → do+ case vprjM v of+ Just (MultiplicativeRecord _) → True+ _ → False,+ fun "recordLabels" -: [ty| ∀ `a. {+ `a +} → string list |]+ -= \v → do+ record ← vprjM v+ case record of+ AdditiveRecord fields → map (show . uidToLid . fst) fields+ MultiplicativeRecord fields → map (show . uidToLid . fst) fields,+ fun "unsafeGetRecordField"+ -: [ty| ∀ `a `b. int → string → { `a } → `b |]+ -= \ix lab v → getField ix (lidToUid (ident lab)) v,+ fun "unsafeGetRecordFieldThunk"+ -: [ty| ∀ `a `b. int → string → {+ `a +} → unit → `b |]+ -= \ix lab v → do+ io ← getFieldThunk ix (lidToUid (ident lab)) v+ return (VaFun (FNAnonymous []) (\_ → io)),+ fun "unsafeRecordAddField"+ -: [ty| ∀ `a `b `c. string → `a → { `b } → { `c } |]+ -= \lab v1 v2 → do+ MultiplicativeRecord fields ← vprjM v2+ return . vinj . MultiplicativeRecord $+ (lidToUid (ident lab), v1) : fields+ ∷ IO Value,+ fun "unsafeRecordAddFieldThunk"+ -: [ty| ∀ `a `b `c. string → (unit -A> `a) → {+ `b +} → {+ `c +} |]+ -= \lab thunk v2 → do+ AdditiveRecord fields ← vprjM v2+ return . vinj . AdditiveRecord $+ (lidToUid (ident lab),+ (vapp thunk (vinj ()), vppr thunk)) : fields+ ∷ IO Value,+ fun "unsafeRecordRemoveField"+ -: [ty| ∀ `a `b `q. string → (`q, `a) record → (`q, `b) record |]+ -= \lab v → do+ record ← vprjM v+ return . vinj $ case record of+ AdditiveRecord fields →+ AdditiveRecord (remField (lidToUid (ident lab)) fields)+ MultiplicativeRecord fields →+ MultiplicativeRecord (remField (lidToUid (ident lab)) fields)+ ∷ IO Value+ ]++getField ∷ Int → Uid Renamed → Value → IO Value+getField = join <$$$> getFieldThunk++getFieldThunk ∷ Int → Uid Renamed → Value → IO (IO Value)+getFieldThunk ix0 lab v = do+ record ← vprjM v+ case record of+ AdditiveRecord fields → fst <$> findNth ix0 fields+ MultiplicativeRecord fields → return <$> findNth ix0 fields+ where+ findNth _ [] = throwFailure "record field not found"+ findNth ix ((lab', v'):fields')+ | lab == lab' = if ix == 0+ then return v'+ else findNth (ix - 1) fields'+ | otherwise = findNth ix fields'++remField ∷ Uid Renamed → [(Uid Renamed, v)] → [(Uid Renamed, v)]+remField _ [] = []+remField k ((k',v'):kvs)+ | k == k' = kvs+ | otherwise = (k',v') : remField k kvs
src/Basis/Socket.hs view
@@ -1,8 +1,3 @@-{-# LANGUAGE- DeriveDataTypeable,- QuasiQuotes,- StandaloneDeriving- #-} module Basis.Socket ( entries ) where import Data.Data as Data@@ -11,12 +6,9 @@ import Basis.IO () import BasisUtils-import Syntax+import AST import Value--import qualified Loc-import qualified Syntax.Notable-import qualified Syntax.Decl+import qualified Data.Loc instance Valuable S.Socket where veq = (==)@@ -102,68 +94,68 @@ entries :: [Entry Raw] entries = [- dec [$dc| type portNumber = PortNum of int |],- dec [$dc| type socket |],+ dec [sgQ| type portNumber = PortNum of int |],+ dec [sgQ| type socket |], typ (enumTypeDecl S.AF_INET), typ (enumTypeDecl S.Stream),- dec [$dc| type protocolNumber = int |],- dec [$dc| type hostAddress = int |],- dec [$dc| type flowInfo = int |],- dec [$dc| type hostAddress6 = int * int * int * int |],- dec [$dc| type scopeID = int |],- dec [$dc| type sockAddr+ dec [sgQ| type protocolNumber = int |],+ dec [sgQ| type hostAddress = int |],+ dec [sgQ| type flowInfo = int |],+ dec [sgQ| type hostAddress6 = int * int * int * int |],+ dec [sgQ| type scopeID = int |],+ dec [sgQ| type sockAddr = SockAddrInet of portNumber * hostAddress | SockAddrInet6 of portNumber * flowInfo * hostAddress6 * scopeID | SockAddrUnix of string |], typ (enumTypeDecl S.AI_ALL), typ (enumTypeDecl S.ShutdownSend),- dec [$dc| type addrInfo+ dec [sgQ| type addrInfo = AddrInfo of addrInfoFlag list * family * socketType * protocolNumber * sockAddr * string option |],- dec [$dc| type hostName = string |],- dec [$dc| type serviceName = string |],+ dec [sgQ| type hostName = string |],+ dec [sgQ| type serviceName = string |], - val "inaddr_any" -: [$ty| hostAddress |]+ val "inaddr_any" -: [ty| hostAddress |] -= S.iNADDR_ANY,- val "defaultProtocol" -: [$ty| protocolNumber |]+ val "defaultProtocol" -: [ty| protocolNumber |] -= S.defaultProtocol,- val "defaultHints" -: [$ty| addrInfo |]+ val "defaultHints" -: [ty| addrInfo |] -= S.defaultHints { S.addrAddress = S.SockAddrInet S.aNY_PORT S.iNADDR_ANY, S.addrCanonName = Nothing }, fun "getAddrInfo"- -: [$ty| addrInfo option -> hostName option ->+ -: [ty| addrInfo option -> hostName option -> serviceName option -> addrInfo list |] -= S.getAddrInfo,- fun "inet_addr" -: [$ty| string -> hostAddress |]+ fun "inet_addr" -: [ty| string -> hostAddress |] -= S.inet_addr, - fun "socket" -: [$ty| family -> socketType -> protocolNumber -> socket |]+ fun "socket" -: [ty| family -> socketType -> protocolNumber -> socket |] -= S.socket,- fun "bind" -: [$ty| socket -> sockAddr -> unit |]+ fun "bind" -: [ty| socket -> sockAddr -> unit |] -= S.bindSocket,- fun "connect" -: [$ty| socket -> sockAddr -> unit |]+ fun "connect" -: [ty| socket -> sockAddr -> unit |] -= S.connect,- fun "listen" -: [$ty| socket -> int -> unit |]+ fun "listen" -: [ty| socket -> int -> unit |] -= S.listen,- fun "accept" -: [$ty| socket -> socket * sockAddr |]+ fun "accept" -: [ty| socket -> socket * sockAddr |] -= S.accept,- fun "send" -: [$ty| socket -> string -> int |]+ fun "send" -: [ty| socket -> string -> int |] -= \sock str -> S.send sock str,- fun "recv" -: [$ty| socket -> int -> string |]+ fun "recv" -: [ty| socket -> int -> string |] -= \sock len -> S.recv sock len,- fun "shutdown" -: [$ty| socket -> shutdownCmd -> unit |]+ fun "shutdown" -: [ty| socket -> shutdownCmd -> unit |] -= S.shutdown,- fun "close" -: [$ty| socket -> unit |]+ fun "close" -: [ty| socket -> unit |] -= S.sClose, - fun "isReadable" -: [$ty| socket -> bool |]+ fun "isReadable" -: [ty| socket -> bool |] -= S.sIsReadable,- fun "isWritable" -: [$ty| socket -> bool |]+ fun "isWritable" -: [ty| socket -> bool |] -= S.sIsWritable ]
src/Basis/Thread.hs view
@@ -1,28 +1,23 @@-{-# LANGUAGE- DeriveDataTypeable,- QuasiQuotes #-} module Basis.Thread (entries) where import BasisUtils-import Syntax+import AST import Value (Vinj(..)) -import qualified Loc-import qualified Syntax.Notable-import qualified Syntax.Decl+import qualified Data.Loc import qualified Control.Concurrent as CC entries :: [Entry Raw] entries = [ -- Threads- dec [$dc| type thread |],- fun "fork" -: [$ty| (unit -> unit) -> thread |]+ dec [sgQ| type thread |],+ fun "fork" -: [ty| (unit -> unit) -> thread |] -= \f -> Vinj `fmap` CC.forkIO (vapp f () >> return ()),- fun "kill" -: [$ty| thread -> unit |]+ fun "kill" -: [ty| thread -> unit |] -= CC.killThread . unVinj,- fun "delay" -: [$ty| int -> unit |]+ fun "delay" -: [ty| int -> unit |] -= CC.threadDelay . (fromIntegral :: Integer -> Int),- fun "print" -: [$ty| thread -> thread |]+ fun "print" -: [ty| thread -> thread |] -= \t -> do print (t :: Vinj CC.ThreadId); return t ]
src/BasisUtils.hs view
@@ -1,8 +1,5 @@ -- | Tools for implementing primitive operations -- essentially an -- object-language/meta-language FFI.-{-# LANGUAGE- FlexibleInstances,- QuasiQuotes #-} module BasisUtils ( -- | * Initial environment entries Entry,@@ -17,61 +14,62 @@ (-:), (-=), -- ** Default location for entries _loc,- module Loc,+ module Data.Loc, -- ** Environment construction- basis2venv, basis2tenv, basis2renv,+ basis2renv, basis2tenv, basis2venv, -- * Function embedding MkFun(..), baseMkFun, vapp, -- * Re-exports- text, Uid(..),+ text, Id(..), throwFailure, module Meta.Quasi, ) where -import Dynamics (E, addVal, addMod)-import Env (GenEmpty(..))-import ErrorMessage (AlmsMonad)-import Meta.Quasi-import Parser (ptd)-import Ppr (ppr, pprPrec, text, precApp)-import Rename-import Statics (S, env0, runTC, tcMapM, addVal, addDecl, addType, addMod)-import Syntax-import qualified Syntax.Notable-import qualified Syntax.Decl-import Type (TyCon, tcName)-import Loc (Loc(Loc), mkBogus, setLoc) import Util+import Util.MonadRef+import Dynamics (E, addVal, addMod, throwFailure)+import Env (GenEmpty(..), domain)+import Error (MonadAlmsError, almsBug, throwAlms, Phase(DynamicsPhase))+import Meta.Quasi+import Syntax.Parser (ptd)+import Syntax.Ppr (ppr, pprPrec, text, precApp)+import Statics+import Statics.Rename as Rename+import AST+import Type (TyCon, tcName, tcCons)+import Data.Loc (Loc(Loc), mkBogus, setLoc) import Value (Valuable(..), FunName(..), funNameDocs, Value(..)) +import Prelude ()+ -- | Kind of identifier used in this module type R = Raw --- | Default source location for primitives-_loc :: Loc-_loc = mkBogus "<primitive>"+-- | The default location for primitive bindings+_loc :: Loc+_loc = mkBogus "<primitive>" -- | An entry in the initial environment data Entry i -- | A value entry has a name, a types, and a value = ValEn {- enName :: Lid i,- enType :: Type i,- enValue :: Value+ enVarName :: VarId i,+ enType :: Type i,+ enValue :: Value } -- | A declaration entry | DecEn {- enSrc :: Decl i+ enSrc :: SigItem i } -- | A type entry associates a tycon name with information about it | TypEn {- enName :: Lid i,- enTyCon :: TyCon+ enTypName :: TypId i,+ enTyCon :: TyCon } -- | A module entry associates a module name with a list of entries | ModEn {- enModName :: Uid i,+ enModName :: ModId i, enEnts :: [Entry i] } @@ -113,31 +111,31 @@ -- | Make a value entry for a Haskell non-function. val :: Valuable v => String -> Type R -> v -> Entry Raw-val name t v = ValEn (lid name) t (vinj v)+val name t v = ValEn (ident name) t (vinj v) -- | Make a value entry for a Haskell function, given a names and types -- for the sublanguages. (Leave blank to leave the binding out of -- that language. fun :: (MkFun r, Valuable v) => String -> Type R -> (v -> r) -> Entry Raw-fun name t f = ValEn (lid name) t- (mkFun (FNNamed (ppr (lid name :: Lid R))) f)+fun name t f = ValEn vid t (mkFun (FNNamed (ppr vid)) f)+ where vid = ident name typ :: String -> Entry Raw-typ s = DecEn [$dc| type $tydec:td |] where td = ptd s+typ s = DecEn [sgQ| type $tydec:td |] where td = ptd s -- | Creates a declaration entry-dec :: Decl R -> Entry Raw+dec :: SigItem R -> Entry Raw dec = DecEn -- | Creates a module entry submod :: String -> [Entry Raw] -> Entry Raw-submod = ModEn . uid+submod = ModEn . ident --- | Creates a primitve type entry, binding a name to a type tag--- (which is usually defined in Syntax.hs)+-- | Creates a primitive type entry, binding a name to a type tag+-- (which is usually defined in AST.hs) primtype :: String -> TyCon -> Entry Raw-primtype = TypEn . lid+primtype = TypEn . ident -- | Application (-:), (-=) :: (a -> b) -> a -> b@@ -149,51 +147,67 @@ -- | Instance of 'fun' for making binary arithmetic functions binArith :: String -> (Integer -> Integer -> Integer) -> Entry Raw-binArith name = fun name [$ty| int -> int -> int |]+binArith name = fun name [ty| int -> int -> int |] -- | Apply an object language function (as a 'Value') vapp :: Valuable a => Value -> a -> IO Value-vapp = \(VaFun _ f) x -> f (vinj x)+vapp (VaFun _ f) x = f (vinj x)+vapp _ _ = throwAlms+ $ almsBug DynamicsPhase "vapp" "applied non-function" infixr 0 `vapp` -- | Build the renaming environment and rename the entries-basis2renv :: AlmsMonad m =>+basis2renv :: MonadAlmsError m => [Entry Raw] -> m ([Entry Renamed], RenameState) basis2renv = runRenamingM False _loc renameState0 . renameMapM each where- each ValEn { enName = u, enType = t, enValue = v } = do+ each ValEn { enVarName = u, enType = t, enValue = v } = do u' <- Rename.addVal u t' <- renameType t- return ValEn { enName = u', enType = t', enValue = v }+ return ValEn { enVarName = u', enType = t', enValue = v } each DecEn { enSrc = d } = do- d' <- renameDecl d+ d' <- renameSigItem d return DecEn { enSrc = d' }- each TypEn { enName = l, enTyCon = tc } = do- l' <- Rename.addType l (lidUnique (jname (tcName tc)))- return TypEn { enName = l', enTyCon = tc }+ each TypEn { enTypName = l, enTyCon = tc } = do+ l' <- Rename.addType l (idTag (jname (tcName tc)))+ (dirtyTrivialRename <$> domain (tcCons tc))+ return TypEn { enTypName = l', enTyCon = tc } each ModEn { enModName = u, enEnts = es } = do (u', es') <- Rename.addMod u $ renameMapM each es return ModEn { enModName = u', enEnts = es' } +-- | Build the static environment+basis2tenv :: (MonadAlmsError m, MonadRef r m) =>+ StaticsState r -> [Entry Renamed] -> m (StaticsState r)+basis2tenv ss0 entries = addSignature ss1 sigexp+ where+ ss1 = foldl' (uncurry . addPrimType) ss0 prims+ (sigexp, prims) = evalRWS (eachEntries entries) [] (0 :: Int)+ eachEntries es = do+ sigitems <- mapM eachEntry es+ return [seQ|+ sig $list:sigitems end |]+ eachEntry ValEn { enVarName = n, enType = t }+ = return [sgQ|+ val $vid:n : $t |]+ eachEntry DecEn { enSrc = sigitem }+ = return sigitem+ eachEntry TypEn { enTypName = n, enTyCon = tc }+ = do+ ix <- get+ put (ix + 1)+ tell [(n, tc)]+ return [sgQ|+ type $tid:n = type $tid:n |]+ eachEntry ModEn { enModName = n, enEnts = es }+ = do+ sig <- eachEntries es+ return [sgQ|+ module $mid:n : $sig |]+ -- | Build the dynamic environment-basis2venv :: AlmsMonad m => [Entry Renamed] -> m E+basis2venv :: MonadAlmsError m => [Entry Renamed] -> m E basis2venv es = foldM add genEmpty es where- add :: AlmsMonad m => E -> Entry Renamed -> m E- add e (ValEn { enName = n, enValue = v })+ add :: MonadAlmsError m => E -> Entry Renamed -> m E+ add e (ValEn { enVarName = n, enValue = v }) = return (Dynamics.addVal e n v) add e (ModEn { enModName = n, enEnts = es' }) = Dynamics.addMod e n `liftM` basis2venv es' add e _ = return e---- | Build the static environment-basis2tenv :: AlmsMonad m => [Entry Renamed] -> m S-basis2tenv = liftM snd . runTC env0 . tcMapM each where- each ValEn { enName = n, enType = t }- = Statics.addVal n t- each DecEn { enSrc = decl }- = Statics.addDecl decl- each TypEn { enName = n, enTyCon = i }- = Statics.addType n i- each ModEn { enModName = n, enEnts = es }- = Statics.addMod n $ tcMapM each es
− src/Coercion.hs
@@ -1,145 +0,0 @@--- | Converts coercion expressions to dynamic checks.-{-# LANGUAGE- PatternGuards,- QuasiQuotes,- ViewPatterns #-}-module Coercion (- coerceExpression,- translate, translateDecls, TEnv, tenv0-) where--import Loc-import Meta.Quasi-import Ppr ()-import qualified Syntax-import qualified Syntax.Expr-import qualified Syntax.Notable-import qualified Syntax.Patt-import Syntax hiding (Type, Type'(..))-import Type-import TypeRel ()-import Util-import ErrorMessage--import qualified Data.Map as M-import qualified Control.Monad.State as CMS---- | The translation environment. This currently doesn't carry--- any information, but we keep it in the interface for later use.-type TEnv = ()---- | The initial translation environment-tenv0 :: TEnv-tenv0 = ()---- | Translate a whole program-translate :: TEnv -> Prog Renamed -> Prog Renamed-translate _ = id---- | Location to use for constructed code-_loc :: Loc-_loc = mkBogus "<coercion>"---- | Translation a sequence of declarations in the context--- of a translation environment, returning a new translation--- environment-translateDecls :: TEnv -> [Decl Renamed] -> (TEnv, [Decl Renamed])-translateDecls tenv decls = (tenv, decls)--coerceExpression :: AlmsMonad m =>- Expr Renamed -> Type -> Type -> m (Expr Renamed)-coerceExpression e tfrom tto = do- prj <- CMS.evalStateT (build True M.empty tfrom tto) 0- return $ exApp (exApp prj (exPair (exStr neg) (exStr pos))) e- where- neg = "context at " ++ show (getLoc e)- pos = "value at " ++ show (getLoc e)--build :: AlmsMonad m =>- Bool -> M.Map (TyVarR, TyVarR) (Maybe (Lid Renamed)) ->- Type -> Type -> CMS.StateT Integer m (Expr Renamed)-build b recs tfrom tto- | (tvs, TyFun qd t1 t2) <- vtQus Forall tfrom,- (tvs', TyFun qd' t1' t2') <- vtQus Forall tto,- length tvs == length tvs'- = do- let which = case (qConstBound qd, qConstBound qd') of- (Qa, Qu) -> [$ex|+ INTERNALS.Contract.affunc |]- (Qu, _ ) -> [$ex|+ INTERNALS.Contract.func[U] |]- (_ , Qa) -> [$ex|+ INTERNALS.Contract.func[A] |]- recs' = foldr2- M.insert- (shadow tvs tvs' recs)- (zip tvs tvs')- (repeat Nothing)- dom <- build (not b) recs' t1' t1- cod <- build b recs' t2 t2'- let body = [$ex|+ $which $dom $cod |]- return $ if null tvs- then body- else absContract $- exAbsVar' (lid "f") (typeToStx' tfrom) $- foldr (\tv0 acc -> exTAbs tv0 . acc) id tvs $- exAbsVar' (lid "x") (typeToStx' t1') $- instContract body `exApp`- foldl (\acc tv0 -> exTApp acc (Syntax.tyVar tv0))- (exBVar (lid "f")) tvs `exApp`- exBVar (lid "x")-build b recs (view -> TyQu Exists tv t) (view -> TyQu Exists tv' t') = do- let recs' = M.insert (tv, tv') Nothing (shadow [tv] [tv'] recs)- body <- instContract `liftM` build b recs' t t'- let tv'' = freshTyVar tv (ftv (tv, tv'))- tstx = typeToStx' t- tstx' = typeToStx' t'- return $- absContract $- [$ex|+ fun (Pack('$tv'', e) : ex '$tv. $tstx) ->- Pack[ex '$tv'. $tstx']('$tv'', $body e) |]-build b recs (view -> TyMu tv t) (view -> TyMu tv' t') = do- l <- freshLid- let recs' = M.insert (tv, tv') (Just l) (shadow [tv] [tv'] recs)- body <- build b recs' t t'- let tstx = typeToStx' t- tstx' = typeToStx' t'- return $- [$ex|+- let rec $lid:l- (parties : string * string)- : (mu '$tv. $tstx) -> mu '$tv'. $tstx'- = $body parties- in $lid:l- |]-build b recs (view -> TyVar tv) (view -> TyVar tv')- | Just (Just l) <- M.lookup (if b then (tv, tv') else (tv', tv)) recs- = return [$ex|+ $lid:l |]- | Just Nothing <- M.lookup (if b then (tv, tv') else (tv', tv)) recs- = return [$ex|+ INTERNALS.Contract.any ['$tv'] |]-build _ _ t t' =- if t <: t'- then let tstx' = typeToStx' t' in- return [$ex|+ INTERNALS.Contract.any [$tstx'] |]- else CMS.lift . throwAlms $ AlmsException StaticsPhase bogus [$msg|- <dl>- <dt>from type: <dd>$t- <dt>to type: <dd>$t'.- </dl>- |]--shadow :: [TyVarR] -> [TyVarR] ->- M.Map (TyVarR, TyVarR) a -> M.Map (TyVarR, TyVarR) a-shadow tvs tvs' = M.filterWithKey- (\(tv, tv') _ -> tv `notElem` tvs && tv' `notElem` tvs')--absContract :: Expr Renamed -> Expr Renamed-absContract body =- [$ex|+ fun (neg: string, pos: string) -> $body |]--instContract :: Expr Renamed -> Expr Renamed-instContract con = [$ex|+ $con (neg, pos) |]--freshLid :: Monad m => CMS.StateT Integer m (Lid Renamed)-freshLid = do- n <- CMS.get- CMS.put (n + 1)- return (lid ("c" ++ show n))-
src/Compat.hs view
@@ -1,5 +1,3 @@-{-# LANGUAGE- TemplateHaskell #-} -- | Compatibility layer for different GHC and library versions module Compat ( mask, newQuasi,
+ src/Data/Empty.hs view
@@ -0,0 +1,25 @@+-- | An uninhabited type+module Data.Empty (+ Empty, elimEmpty, elimEmptyF,+) where++import Data.Generics (Typeable, Data)+import Unsafe.Coerce (unsafeCoerce)++-- | An uninhabited type+data Empty deriving Typeable++deriving instance Data Empty++-- | Elimination for 'Empty'+elimEmpty ∷ Empty → a+elimEmpty = const undefined++-- | Elimination for 'Empty' under any functor, implemented as a no-op.+elimEmptyF ∷ Functor f ⇒ f Empty → f a+elimEmptyF = unsafeCoerce++instance Eq Empty where _ == _ = True+instance Ord Empty where _ `compare` _ = EQ+instance Show Empty where show = elimEmpty+
+ src/Data/Lattice.hs view
@@ -0,0 +1,69 @@+module Data.Lattice (+ -- * Lattices+ Lattice(..), BoundedLattice(..),+ -- ** Dual lattices+ DUAL(..),+) where++import Util++import Prelude ()+import qualified Data.Set as S++-- | Lattices.+-- Minimal complete definition is '(⊔)' and '(⊓)'.+class Eq a ⇒ Lattice a where+ (⊔), (⊓) ∷ a → a → a+ (⊑), (⊒) ∷ a → a → Bool+ a ⊑ b = a ⊔ b == b+ a ⊒ b = b ⊑ a++infixl 6 ⊔+infixl 7 ⊓+infix 4 ⊑, ⊒++-- | Bounded lattices are 'Lattice's that are 'Bounded'.+class (Bounded a, Lattice a) ⇒ BoundedLattice a where+ bigJoin, bigMeet ∷ [a] → a++instance (Bounded a, Lattice a) ⇒ BoundedLattice a where+ bigJoin = foldr (⊔) minBound+ bigMeet = foldr (⊓) maxBound++-- 'Nothing' is a new point.+instance Lattice a ⇒ Lattice (Maybe a) where+ Just a ⊔ Just b = Just (a ⊔ b)+ Nothing ⊔ b = b+ a ⊔ Nothing = a+ Just a ⊓ Just b = Just (a ⊓ b)+ Nothing ⊓ _ = Nothing+ _ ⊓ Nothing = Nothing++instance Ord a ⇒ Lattice (S.Set a) where+ (⊔) = S.union+ (⊓) = S.intersection+ (⊑) = S.isSubsetOf++instance (Lattice a, Lattice b) ⇒ Lattice (a, b) where+ (a, b) ⊔ (a', b') = (a ⊔ a', b ⊔ b')+ (a, b) ⊓ (a', b') = (a ⊓ a', b ⊓ b')+ (a, b) ⊑ (a', b') = a ⊑ a' && b ⊑ b'++instance (Lattice a, Lattice b, Lattice c) ⇒ Lattice (a, b, c) where+ (a, b, c) ⊔ (a', b', c') = (a ⊔ a', b ⊔ b', c ⊔ c')+ (a, b, c) ⊓ (a', b', c') = (a ⊓ a', b ⊓ b', c ⊓ c')+ (a, b, c) ⊑ (a', b', c') = a ⊑ a' && b ⊑ b' && c ⊑ c'++-- | Injection for the dual lattice.+newtype DUAL a = DUAL { dual ∷ a } deriving (Eq, Show)++instance Lattice a ⇒ Lattice (DUAL a) where+ DUAL a ⊔ DUAL b = DUAL (a ⊓ b)+ DUAL a ⊓ DUAL b = DUAL (a ⊔ b)++instance Bounded a ⇒ Bounded (DUAL a) where+ minBound = DUAL maxBound+ maxBound = DUAL minBound++instance Ord a ⇒ Ord (DUAL a) where+ DUAL a `compare` DUAL b = b `compare` a
+ src/Data/Loc.hs view
@@ -0,0 +1,187 @@+-- | Source locations+module Data.Loc (+ -- * Type and constructors+ Loc(..),+ initial, spanLocs, mkBogus, bogus,+ -- * Destructors+ isBogus, startOfLoc, endOfLoc,++ -- * Generic function for clearing source locations everywhere+ scrub, scrubWhen,++ -- ** Type class interface+ Locatable(..), Relocatable(..), (<<@),++ -- * Interface to 'Parsec' and 'TH' source positions+ toSourcePos, fromSourcePos, fromSourcePosSpan, fromTHLoc+) where++import Util.Bogus++import Data.Generics (Typeable, Data, everywhere, mkT)+import Text.ParserCombinators.Parsec.Pos+import qualified Language.Haskell.TH as TH++-- | Source locations+data Loc = Loc {+ file :: !String,+ line1 :: !Int,+ col1 :: !Int,+ line2 :: !Int,+ col2 :: !Int+ }+ deriving (Eq, Ord, Typeable, Data)++-- | Construct a location spanning two locations; assumes the locations+-- are correctly ordered.+spanLocs :: Loc -> Loc -> Loc+spanLocs loc1 loc2+ | isBogus loc2 = loc1+ | isBogus loc1 = loc2+ | otherwise =+ Loc (file loc1) (line1 loc1) (col1 loc1) (line2 loc2) (col2 loc2)++-- | Get a single-point location from the start of a span+startOfLoc :: Loc -> Loc+startOfLoc loc = Loc (file loc) (line1 loc) (col1 loc) (line1 loc) (col1 loc)++-- | Get a single-point location from the end of a span+endOfLoc :: Loc -> Loc+endOfLoc loc = Loc (file loc) (line2 loc) (col2 loc) (line2 loc) (col2 loc)++-- | Extract a 'Parsec' source position+toSourcePos :: Loc -> SourcePos+toSourcePos loc = newPos (file loc) (line1 loc) (col1 loc)++-- | Create from a 'Parsec' source position+fromSourcePos :: SourcePos -> Loc+fromSourcePos pos+ = Loc (sourceName pos) (sourceLine pos) (sourceColumn pos)+ (sourceLine pos) (sourceColumn pos)++-- | Create a span from two 'Parsec' source positions+fromSourcePosSpan :: SourcePos -> SourcePos -> Loc+fromSourcePosSpan pos1 pos2+ = Loc (sourceName pos1) (sourceLine pos1) (sourceColumn pos1)+ (sourceLine pos2) (sourceColumn pos2)++fromTHLoc :: TH.Loc -> Loc+fromTHLoc loc = Loc (TH.loc_filename loc)+ (fst (TH.loc_start loc))+ (snd (TH.loc_start loc))+ (fst (TH.loc_end loc))+ (snd (TH.loc_end loc))++-- | The initial location for a named source file+initial :: String -> Loc+initial = fromSourcePos . initialPos++-- | A named bogus location; useful to provide default locations+-- for generated code without losing real locations.+mkBogus :: String -> Loc+mkBogus s = Loc s (-1) (-1) (-1) (-1)++-- | The bogus location.+-- (Avoids need for @Maybe Loc@ and lifting)+instance Bogus Loc where+ bogus = mkBogus "<bogus>"++instance IsBogus Loc where+ isBogus (Loc _ (-1) _ _ _) = True+ isBogus _ = False++-- | Class for types that carry source locations+class Locatable a where+ getLoc :: a -> Loc++-- | Class for types that can have their source locations updated+class Relocatable a where+ setLoc :: a -> Loc -> a++instance Locatable Loc where+ getLoc = id++instance Relocatable Loc where+ setLoc a b+ | isBogus b = a+ | otherwise = b++instance Locatable a => Locatable (Maybe a) where+ getLoc Nothing = bogus+ getLoc (Just a) = getLoc a++instance Relocatable a => Relocatable (Maybe a) where+ setLoc Nothing _ = Nothing+ setLoc (Just a) l = l `seq` a `seq` Just (setLoc a l)++instance Locatable a => Locatable [a] where+ getLoc = foldr spanLocs bogus . map getLoc++instance (Locatable a, Locatable b) => Locatable (Either a b) where+ getLoc (Left x) = getLoc x+ getLoc (Right x) = getLoc x++instance (Relocatable a, Relocatable b) => Relocatable (Either a b) where+ setLoc (Left x) l = Left (setLoc x l)+ setLoc (Right x) l = Right (setLoc x l)++instance (Locatable a, Locatable b) => Locatable (a, b) where+ getLoc (x, y) = getLoc x `spanLocs` getLoc y++instance (Locatable a, Locatable b, Locatable c) =>+ Locatable (a, b, c) where+ getLoc (x, y, z) = getLoc x `spanLocs` getLoc y `spanLocs` getLoc z++instance (Locatable a, Locatable b, Locatable c, Locatable d) =>+ Locatable (a, b, c, d) where+ getLoc (x, y, z, v) = getLoc x `spanLocs` getLoc y `spanLocs` getLoc z+ `spanLocs` getLoc v++instance (Locatable a, Locatable b, Locatable c, Locatable d, Locatable e) =>+ Locatable (a, b, c, d, e) where+ getLoc (x, y, z, v, w) = getLoc x `spanLocs` getLoc y `spanLocs` getLoc z+ `spanLocs` getLoc v `spanLocs` getLoc w++instance Relocatable b => Relocatable (a -> b) where+ setLoc f loc x = setLoc (f x) loc++-- | Copy the source location from the second operand to the first+(<<@) :: (Relocatable a, Locatable b) => a -> b -> a+a <<@ b = setLoc a (getLoc b)++-- | Bogosify all source locations (as far as SYB can find them)+scrub :: Data a => a -> a+scrub = scrubWhen (const True)++-- | Bogosify all source locations satisfying a predicate+-- (as far as SYB can find them)+scrubWhen :: Data a => (Loc -> Bool) -> a -> a+scrubWhen p a = everywhere (mkT bogosify) a where+ bogosify loc | p loc = bogus+ | otherwise = loc++instance Show Loc where+ showsPrec _ loc+ | isBogus loc = showString (showFile (file loc))+ | otherwise =+ showString (showFile (file loc)) . showChar ':' . showCoords+ where+ showCoords =+ if line1 loc == line2 loc then+ shows (line1 loc) . showChar ':' . shows (col1 loc) .+ if col1 loc + 1 >= col2 loc then+ id+ else+ showChar '-' . shows (col2 loc)+ else+ shows (line1 loc) .+ showChar ':' . shows (col1 loc) .+ showChar '-' . shows (line2 loc) .+ showChar ':' . shows (col2 loc)+ showFile "-" = "<stdin>"+ showFile s =+ let shown = show s+ in if shown == '"' : s ++ "\""+ then s+ else shown+
+ src/Data/OptionalClass.hs view
@@ -0,0 +1,43 @@+-- | A generalization of 'Maybe'+module Data.OptionalClass (+ Optional(..),+ coerceOpt, catOpt, fromOptSome, fromOpt,+ isOptSome, isOptNone,+ mapOpt,+) where++class Functor f ⇒ Optional f where+ foldOpt ∷ b → (a → b) → f a → b+ optSome ∷ a → f a+ optNone ∷ f a++instance Optional Maybe where+ foldOpt = maybe+ optSome = Just+ optNone = Nothing++instance Optional [] where+ foldOpt z f = foldr (const . f) z+ optSome = return+ optNone = []++-- | Coerce between optional types+coerceOpt ∷ (Optional f, Optional g) ⇒ f a → g a+coerceOpt = foldOpt optNone optSome++catOpt ∷ Optional f ⇒ [f a] → [a]+catOpt = foldr (foldOpt id (:)) []++fromOptSome ∷ Optional f ⇒ f a → a+fromOptSome = foldOpt (error "fromOptSome: got optNone") id++fromOpt ∷ Optional f ⇒ a → f a → a+fromOpt = flip foldOpt id++isOptSome, isOptNone ∷ Optional f ⇒ f a → Bool+isOptSome = foldOpt False (const True)+isOptNone = not . isOptSome++mapOpt ∷ Optional f ⇒ (a → f b) → [a] → [b]+mapOpt f = foldr (foldOpt id (:) . f) []+
+ src/Data/Perhaps.hs view
@@ -0,0 +1,105 @@+-- | Like maybe, but 'Eq' and 'Ord' instances are collapsed so that all+-- values of type @Perhaps a@ are equal. Useful for hiding optional+-- information from derived instances in other datatypes.+module Data.Perhaps (+ Perhaps(..),+ catPerhaps, mapPerhaps,+ fromHere, fromPerhaps, isHere, isNope,+ listToPerhaps, perhapsToList, perhapsToMaybe, maybeToPerhaps,+) where++import Control.Applicative+import Control.Arrow+import Control.Monad+import Control.Monad.Fix+import Data.Monoid++import Data.OptionalClass+import Data.Generics (Typeable, Data)++-- | This is like @Maybe@, except all values of the type compare as+-- equal, which is useful for “suggestions” in the syntax that have+-- no semantic significance.+data Perhaps a+ = Nope+ | Here a+ deriving (Functor, Typeable, Data)++instance Optional Perhaps where+ foldOpt = perhaps+ optSome = Here+ optNone = Nope++perhaps ∷ b → (a → b) → Perhaps a → b+perhaps nope _ Nope = nope+perhaps _ here (Here x) = here x++catPerhaps ∷ [Perhaps a] → [a]+catPerhaps = foldr (perhaps id (:)) []++fromHere ∷ Perhaps a → a+fromHere = perhaps (error "fromHere: got Nope") id++fromPerhaps ∷ a → Perhaps a → a+fromPerhaps = flip perhaps id++isHere, isNope ∷ Perhaps a → Bool+isHere = perhaps False (const True)+isNope = not . isHere++listToPerhaps ∷ [a] → Perhaps a+listToPerhaps = foldr (const . Here) Nope++mapPerhaps ∷ (a → Perhaps b) → [a] → [b]+mapPerhaps f = foldr (perhaps id (:) . f) []++perhapsToList ∷ Perhaps a → [a]+perhapsToList = perhaps [] (:[])++perhapsToMaybe ∷ Perhaps a → Maybe a+perhapsToMaybe = perhaps Nothing Just++maybeToPerhaps ∷ Maybe a → Perhaps a+maybeToPerhaps = maybe Nope Here++instance Eq (Perhaps a) where+ _ == _ = True++instance Monad Perhaps where+ return = Here+ (>>=) = perhaps (const Nope) (flip ($))++instance Ord (Perhaps a) where+ _ `compare` _ = EQ++instance Read a ⇒ Read (Perhaps a) where+ readsPrec p s = case readsPrec p s of+ [] → [ (Nope, s) ]+ xs → map (first Here) xs++instance Show a ⇒ Show (Perhaps a) where+ showsPrec = perhaps id . showsPrec++instance MonadFix Perhaps where+ mfix f = let a = f (unHere a) in a+ where unHere (Here x) = x+ unHere Nope = error "mfix Perhaps: Nope"++instance MonadPlus Perhaps where+ mzero = Nope+ mplus = perhaps id (const . Here)++instance Applicative Perhaps where+ pure = return+ (<*>) = ap++instance Monoid a ⇒ Monoid (Perhaps a) where+ mempty = Nope+ Here x1 `mappend` Here x2 = Here (x1 `mappend` x2)+ p1 `mappend` Nope = p1+ Nope `mappend` p2 = p2++instance Alternative Perhaps where+ empty = mzero+ (<|>) = mplus+
+ src/Data/UnionFind.hs view
@@ -0,0 +1,95 @@+{- | Based on Simonet's Dalton constraint solver -}+module Data.UnionFind (+ -- * An implementation on top of 'MonadRef'+ Proxy,+ create, desc, setDesc, repr,+ sameRepr, isRepr, coalesce, coalesce_, linkto,+) where++import Util+import Util.Eq1+import Util.MonadRef++import Prelude ()++---+--- Representaiton and basic, low-level operations+---++newtype Proxy p a = Proxy { unProxy ∷ p (Either a (Proxy p a)) }++instance Eq1 p ⇒ Eq1 (Proxy p) where+ Proxy p1 `eq1` Proxy p2 = p1 `eq1` p2++-- | To create a new set with the given representative+create ∷ MonadRef p m ⇒ a → m (Proxy p a)+create = liftM Proxy . newRef . Left++-- | To follow a link, either to the end or to another link+follow ∷ MonadRef p m ⇒ Proxy p a → m (Either a (Proxy p a))+follow = readRef . unProxy++-- | To replace the contents of a link with a representative+-- or another link+replace ∷ MonadRef p m ⇒ Proxy p a → Either a (Proxy p a) → m ()+replace = writeRef . unProxy++-- | Find the representative of a set+repr ∷ MonadRef p m ⇒ Proxy p a → m (Proxy p a)+repr = liftM fst . loop where+ loop proxy = do+ link ← follow proxy+ case link of+ Left _ → return (proxy, False)+ Right proxy' → do+ (proxy'', changed) ← loop proxy'+ when changed $ replace proxy (Right proxy'')+ return (proxy'', True)++-- | Find the descriptor of a set+desc ∷ MonadRef p m ⇒ Proxy p a → m a+desc proxy = do+ link ← follow proxy+ case link of+ Left a → return a+ Right proxy' → desc =<< repr proxy'++-- | Change the descriptor of a set+setDesc ∷ MonadRef p m ⇒ Proxy p a → a → m ()+setDesc proxy a = flip replace (Left a) =<< repr proxy++-- | Join two proxies, using the given function to combine their+-- descriptors.+coalesce ∷ MonadRef p m ⇒+ (a → a → m (a, b)) → Proxy p a → Proxy p a → m (Maybe b)+coalesce combine proxy1 proxy2 = do+ proxy1' ← repr proxy1+ proxy2' ← repr proxy2+ if (proxy1' `eq1` proxy2')+ then return Nothing+ else do+ a1 ← desc proxy1'+ a2 ← desc proxy2'+ (a', b) ← combine a1 a2+ replace proxy1' (Right proxy2')+ replace proxy2' (Left a')+ return (Just b)++coalesce_ ∷ MonadRef p m ⇒ (a → a → m a) → Proxy p a → Proxy p a → m ()+coalesce_ combine proxy1 proxy2 = do+ coalesce (liftM (,()) <$$> combine) proxy1 proxy2+ return ()++-- | Make the first proxy point to the second, keeping the second+-- proxy's descriptor+linkto ∷ MonadRef p m ⇒ Proxy p a → Proxy p a → m ()+linkto = coalesce_ (const . return)++-- | Is the given proxy object the representative of its set?+isRepr ∷ MonadRef p m ⇒ Proxy p a → m Bool+isRepr = liftM (either (const True) (const False)) . follow++-- | Are two proxy objects from the same set?+sameRepr ∷ MonadRef p m ⇒ Proxy p a → Proxy p a → m Bool+sameRepr proxy1 proxy2 = liftM2 eq1 (repr proxy1) (repr proxy2)+
src/Dynamics.hs view
@@ -1,14 +1,11 @@-{-# LANGUAGE- FlexibleInstances,- MultiParamTypeClasses,- QuasiQuotes,- TemplateHaskell #-} -- | The dynamics of the interpreter module Dynamics ( -- * Static API E, addVal, addMod, NewValues, -- * Dynamic API eval, addDecls, Result,+ -- * Throwing exceptions+ throwFailure, -- * Re-export to remove warning (!) -- | We need to import Quasi for the TH phase, but using it at the -- TH phase isn't sufficient to prevent an unused import warning.@@ -18,17 +15,13 @@ import Meta.Quasi import Value import Util-import Syntax-import qualified Syntax.Decl-import qualified Syntax.Expr-import qualified Syntax.Notable-import qualified Syntax.Patt+import AST import Env-import Ppr (Ppr(..), Doc, text, precApp)-import ErrorMessage+import Syntax.Ppr (Ppr(..), Doc, text, precApp)+import Error +import Prelude () import Data.IORef (newIORef, readIORef, writeIORef)-import Control.Exception (throw) -- -- Our semantic domains@@ -46,26 +39,22 @@ type E = [Scope] -- | Each scope binds paths of uppercase identifiers to flat value -- and exn environments-type Scope = PEnv (Uid R) Level+type Scope = PEnv (ModId R) Level -- | A level binds values and exceptions data Level = Level { vlevel :: !VE } -- | We bind 'IO' 'Value's rather than values, so that we can use -- 'IORef' to set up recursion-type VE = Env (Lid R) (IO Value)---- | To distinguish exn names from path components.-newtype ExnName = ExnName (Uid R)- deriving (Eq, Ord)+type VE = Env (VarId R) (IO Value) instance GenEmpty Level where- genEmpty = Level empty-instance GenLookup Level (Lid R) (IO Value) where+ genEmpty = Level Env.empty+instance GenLookup Level (VarId R) (IO Value) where level =..= k = vlevel level =..= k instance GenExtend Level Level where Level ve =+= Level ve' = Level (ve =+= ve')-instance GenExtend Level (Env (Lid R) (IO Value)) where+instance GenExtend Level (Env (VarId R) (IO Value)) where level =+= ve' = level =+= Level ve' -- | Domain for the meaning of an expression:@@ -86,15 +75,17 @@ evalDecls = (flip . foldM . flip) evalDecl evalDecl :: Decl R -> DDecl-evalDecl [$dc| let $x : $opt:_ = $e |] = evalLet x e-evalDecl [$dc| type $list:_ |] = return-evalDecl [$dc| abstype $list:_ with $list:ds end |] = evalDecls ds-evalDecl [$dc| open $b |] = evalOpen b-evalDecl [$dc| module $uid:n = $b |] = evalMod n b-evalDecl [$dc| module type $uid:_ = $_ |] = return-evalDecl [$dc| local $list:d0 with $list:d1 end |] = evalLocal d0 d1-evalDecl [$dc| exception $uid:n of $opt:mt |] = evalExn n mt-evalDecl [$dc| $anti:a |] = $antifail+evalDecl [dc| let $x = $e |] = evalLet x e+evalDecl [dc| let rec $list:bns |] = evalLetRec bns+evalDecl [dc| type $list:_ |] = return+evalDecl [dc| type $tid:_ = type $qtid:_ |] = return+evalDecl [dc| abstype $list:_ with $list:ds end |] = evalDecls ds+evalDecl [dc| open $b |] = evalOpen b+evalDecl [dc| module $mid:n = $b |] = evalMod n b+evalDecl [dc| module type $sid:_ = $_ |] = return+evalDecl [dc| local $list:d0 with $list:d1 end |] = evalLocal d0 d1+evalDecl [dc| exception $cid:n of $opt:mt |] = evalExn n mt+evalDecl [dc| $anti:a |] = $antifail evalLet :: Patt R -> Expr R -> DDecl evalLet x e env = do@@ -103,12 +94,28 @@ Just env' -> return env' Nothing -> throwPatternMatch v [show x] env +evalLetRec :: [Binding R] -> DDecl+evalLetRec bs env = do+ let extend (envI, rs) (N _ b) = do+ r <- newIORef $ throwBadLetRec (idName (bnvar b))+ return (envI =+=+ bnvar b =:= (nameFun (bnvar b) <$> join (readIORef r)),+ r : rs)+ (env', rev_rs) <- foldM extend (env, []) bs+ zipWithM_+ (\r (N _ b) -> do+ v <- valOf (bnexpr b) env'+ writeIORef r (return v))+ (reverse rev_rs)+ bs+ return env'+ evalOpen :: ModExp R -> DDecl evalOpen b env = do e <- evalModExp b env return (env =+= e) -evalMod :: Uid R -> ModExp R -> DDecl+evalMod :: ModId R -> ModExp R -> DDecl evalMod x b env = do e <- evalModExp b env return (env =+= x =:= e)@@ -120,150 +127,230 @@ return (env2 =+= scope) evalModExp :: ModExp R -> E -> IO Scope-evalModExp [$me| struct $list:ds end |] env = do+evalModExp [meQ| struct $list:ds end |] env = do scope:_ <- evalDecls ds (genEmpty:env) return scope-evalModExp [$me| $quid:n $list:_ |] env = do+evalModExp [meQ| $qmid:n $list:_ |] env = do case env =..= n of Just scope -> return scope- Nothing -> runtimeBug _loc "evalModExp" $+ Nothing -> runtimeBug "evalModExp" $ "Unknown module: ‘" ++ show n ++ "’"-evalModExp [$me| $me1 : $_ |] env = do+evalModExp [meQ| $me1 : $_ |] env = do evalModExp me1 env-evalModExp [$me| $anti:a |] _ = $antifail+evalModExp [meQ| $anti:a |] _ = $antifail -evalExn :: Uid R -> Maybe (Type R) -> DDecl+evalExn :: ConId R -> Maybe (Type R) -> DDecl evalExn _ _ env = return env eval :: E -> Prog R -> Result-eval env0 [$prQ| $list:ds in $e0 |] = evalDecls ds env0 >>= valOf e0-eval env0 [$prQ| $list:ds |] = evalDecls ds env0 >> return (vinj ())+eval env0 [prQ| $list:ds in $e0 |] = evalDecls ds env0 >>= valOf e0+eval env0 [prQ| $list:ds |] = evalDecls ds env0 >> return vaUnit -- The meaning of an expression valOf :: Expr R -> D valOf e env = case e of- [$ex| $id:ident |] -> case view ident of- Left x -> case env =..= x of+ [ex| $qvid:n |] -> case env =..= n of Just v -> v- Nothing -> runtimeBug _loc "valOf" $- "unbound identifier: ‘" ++ show x ++ "’"- Right c -> return (VaCon (jname c) Nothing)- [$ex| $str:s |] -> return (vinj s)- [$ex| $int:z |] -> return (vinj z)- [$ex| $flo:f |] -> return (vinj f)- [$ex| $antiL:a |] -> $antifail- [$ex| match $e1 with $list:clauses |] -> do+ Nothing -> runtimeBug "valOf" $+ "unbound identifier: ‘" ++ show n ++ "’"+ [ex| $str:s |] -> return (vinj s)+ [ex| $int:z |] -> return (vinj z)+ [ex| $flo:f |] -> return (vinj f)+ [ex| $char:c |] -> return (vinj c)+ [ex| $antiL:a |] -> $antifail+ [ex| $qcid:n $opt:me1 |]+ -> do+ mv1 <- mapM (valOf <-> env) me1+ return (VaCon (jname n) mv1)+ [ex| `$uid:lab $opt:me1 |] -> do+ v1 <- maybe (return vaUnit) (valOf <-> env) me1+ return (VaLab 0 lab v1)+ [ex| #$uid:lab $e1 |] -> do v1 <- valOf e1 env- let loop (N _ (CaClause xi ei):rest) = case bindPatt xi v1 env of- Just env' -> valOf ei env'- Nothing -> loop rest- loop [] = throwPatternMatch v1- (map (show . capatt . dataOf) clauses) env- loop (N _ (CaAnti a):_) = $antifail- loop clauses- [$ex| let rec $list:bs in $e2 |] -> do- let extend (envI, rs) (N _ b) = do- r <- newIORef $ throwBadLetRec (unLid (bnvar b))- return (envI =+= bnvar b =:= join (readIORef r), r : rs)- (env', rev_rs) <- foldM extend (env, []) bs- zipWithM_- (\r (N _ b) -> do- v <- valOf (bnexpr b) env'- writeIORef r (return v))- (reverse rev_rs)- bs+ case v1 of+ VaLab n lab' v1' | lab == lab' -> return (VaLab (n + 1) lab v1')+ _ -> return v1+ [ex| match $e1 with $list:clauses |] -> do+ let loop ([caQ| $xi → $ei |]:rest) v1 =+ case bindPatt xi v1 env of+ Just env' -> valOf ei env'+ Nothing -> loop rest v1+ loop ([caQ| #$uid:lab $opt:mxi → $ei |]:rest) v1 =+ case v1 of+ VaLab 0 lab' v1'+ | lab == lab' -> case mxi of+ Nothing -> valOf ei env+ Just xi -> case bindPatt xi v1' env of+ Just env' -> valOf ei env'+ Nothing -> loop [] v1+ VaLab n lab' v1'+ | lab == lab' -> loop rest (VaLab (n - 1) lab' v1')+ _ -> loop rest v1+ loop [] v1 =+ throwPatternMatch v1 (map (show . cafakepatt) clauses) env+ loop ([caQ| $antiC:a |]:_) _ = $antifail+ loop clauses =<< valOf e1 env+ [ex| let $x = $e1 in $e2 |] -> do+ v1 <- valOf e1 env+ env' <- case bindPatt x v1 env of+ Just env' -> return env'+ Nothing -> throwPatternMatch v1 [show x] env valOf e2 env'- [$ex| let $decl:d in $e2 |] -> do+ [ex| let rec $list:bs in $e2 |] -> do+ env' <- evalLetRec bs env+ valOf e2 env'+ [ex| let $decl:d in $e2 |] -> do env' <- evalDecl d env valOf e2 env'- [$ex| ($e1, $e2) |] -> do+ [ex| ($e1, $e2) |] -> do v1 <- valOf e1 env v2 <- valOf e2 env return (vinj (v1, v2))- [$ex| fun $x : $_ -> $e' |] ->- return (VaFun (FNAnonymous [pprPrec (precApp + 1) e])- (\v -> bindPatt x v env >>= valOf e'))- [$ex| $e1 $e2 |] -> do+ [ex| fun $x -> $e' |] ->+ return .+ VaFun (FNAnonymous [pprPrec (precApp + 1) e]) $ \v ->+ case bindPatt x v env of+ Just env' -> valOf e' env'+ Nothing -> throwPatternMatch v [show x] env+ [ex| $e1 $e2 |] -> do v1 <- valOf e1 env v2 <- valOf e2 env case v1 of VaFun n f -> f v2 >>! nameApp n (pprPrec (precApp + 1) v2) - VaCon c _ -> return (VaCon c (Just v2))- _ -> runtimeBug _loc "valOf" $+ _ -> runtimeBug "valOf" $ "applied non-function ‘" ++ show v1 ++ "’ to argument ‘" ++ show v2 ++ "’"- [$ex| fun '$_ -> $e1 |] -> valOf e1 env- [$ex| $e1 [$_] |] -> valOf e1 env- [$ex| Pack[$opt:_]($_, $e1) |] -> valOf e1 env- [$ex| ( $e1 : $_ ) |] -> valOf e1 env- [$ex| ( $e1 :> $_ ) |] -> valOf e1 env- [$ex| $anti:a |] -> $antifail+ [ex| { $list:flds | $e2 } |] -> do+ newFields ← sequence+ [ (ui,) <$> valOf ei env+ | [fdQ|! $uid:ui = $ei |] ← flds ]+ v2 ← valOf e2 env+ MultiplicativeRecord oldFields ← vprjM v2+ return . vinj $ MultiplicativeRecord (newFields ++ oldFields)+ [ex| {+ $list:flds | $e2 +} |] -> do+ let newFields = [ (ui, (valOf ei env, ppr ei))+ | [fdQ|! $uid:ui = $ei |] ← flds ]+ v2 ← valOf e2 env+ record ← vprjM v2+ let oldFields = case record of+ AdditiveRecord olds → olds+ MultiplicativeRecord olds →+ [ (ui, (return vi, ppr vi)) | (ui, vi) ← olds ]+ return . vinj $ AdditiveRecord (newFields ++ oldFields)+ [ex| $e1.$uid:u |] -> do+ v1 ← valOf e1 env+ record ← vprjM v1+ case record of+ AdditiveRecord flds → case lookup u flds of+ Just (mv, _) → mv+ Nothing → runtimeBug "valOf" "missing record field (&)"+ MultiplicativeRecord flds → case lookup u flds of+ Just v → return v+ Nothing → runtimeBug "valOf" "missing record field (⊗)"+ [ex| ( $e1 : $_ ) |] -> valOf e1 env+ [ex| ( $_ :> $_ ) |] -> runtimeBug "valOf" "encountered cast"+ [ex| $anti:a |] -> $antifail bindPatt :: Monad m => Patt R -> Value -> E -> m E bindPatt x0 v env = case x0 of- [$pa| _ |] + [pa| _ |] -> return env- [$pa| $lid:l |]+ [pa| $vid:l |] -> return (env =+= l =:!= (l `nameFun` v))- [$pa| $quid:qu $opt:mx |]+ [pa| $qcid:qu $opt:mx |] -> let u = jname qu in case (mx, v) of (Nothing, VaCon u' Nothing) | u == u' -> return env (Just x, VaCon u' (Just v')) | u == u' -> bindPatt x v' env _ -> perr- [$pa| ($x, $y) |]+ [pa| `$uid:lab $opt:mx |]+ -> case v of+ VaLab 0 lab' v' | lab' == lab ->+ case mx of+ Nothing -> return env+ Just x -> bindPatt x v' env+ _ -> perr+ [pa| ($x, $y) |] -> case vprjM v of Just (vx, vy) -> bindPatt x vx env >>= bindPatt y vy Nothing -> perr- [$pa| $str:s |]+ [pa| $str:s |] -> if v == vinj s then return env else perr- [$pa| $int:z |]+ [pa| $int:z |] -> if v == vinj z then return env else perr- [$pa| $float:f |]+ [pa| $float:f |] -> if v == vinj f then return env else perr- [$pa| Pack('$_, $x) |]- -> bindPatt x v env- [$pa| $x as $lid:l |]+ [pa| $char:c |]+ -> if v == vinj c+ then return env+ else perr+ [pa| $x as $vid:l |] -> do env' <- bindPatt x v env return (env' =+= l =:!= v)- [$pa| $anti:a |]+ [pa| $x : $_ |]+ -> bindPatt x v env+ [pa| { $uid:u = $x | $y } |]+ -> do+ MultiplicativeRecord fields <- vprjM v+ (v', fields') <- extractField u fields+ env' <- bindPatt x v' env+ bindPatt y (vinj (MultiplicativeRecord fields')) env'+ [pa| ! $x |]+ -> bindPatt x v env+ [pa| $anti:a |] -> antifail "dynamics" a- [$pa| $antiL:a |]+ [pa| $antiL:a |] -> antifail "dynamics" a where perr = fail $ "BUG! In bindPat, pattern match failure should " ++ "raise PatternMatch exception, but didn’t!" +-- | Extract the first matching field from an associating list,+-- returning the remaining list as well.+extractField ∷ (Eq k, Monad m) =>+ k -> [(k, v)] -> m (v, [(k, v)])+extractField _ [] = fail "BUG! missing record field in pattern match"+extractField k ((k',v):kvs)+ | k == k' = return (v, kvs)+ | otherwise = second ((k',v):) `liftM` extractField k kvs+ throwPatternMatch :: Value -> [String] -> E -> IO a throwPatternMatch v ps _ = throw VExn {- exnValue = VaCon (uid "PatternMatch") (Just (vinj (show v, ps)))+ exnValue = VaCon (ident "PatternMatch") (Just (vinj (show v, ps))) } throwBadLetRec :: String -> IO a throwBadLetRec v = throw VExn {- exnValue = VaCon (uid "UninitializedLetRec") (Just (vinj v))+ exnValue = VaCon (ident "UninitializedLetRec") (Just (vinj v)) } -runtimeBug :: Loc -> String -> String -> IO a-runtimeBug = throwAlms <$$$> almsBug DynamicsPhase+throwFailure :: String -> IO a+throwFailure v =+ throw VExn {+ exnValue = VaCon (ident "Failure") (Just (vinj v))+ } +runtimeBug :: String -> String -> IO a+runtimeBug = throwAlms <$$> almsBug DynamicsPhase+ --- --- helpful stuff --- -- Add the given name to an anonymous function-nameFun :: Lid R -> Value -> Value-nameFun (Lid r x) (VaFun (FNAnonymous _) lam)- | x /= "it" || not (isTrivial r) = VaFun (FNNamed (text x)) lam+nameFun :: VarId R -> Value -> Value+nameFun n (VaFun (FNAnonymous _) lam)+ | idName n /= "it"+ = VaFun (FNNamed (text (idName n))) lam nameFun _ value = value -- Get the name of an applied function@@ -279,7 +366,7 @@ -- | For printing in the REPL, 'addDecls' returns an environment -- mapping any newly bound names to their values-type NewValues = Env (Lid R) Value+type NewValues = Env (VarId R) Value -- | Interpret declarations by adding to the environment, potentially -- with side effects@@ -291,11 +378,11 @@ return (env', vl') -- | Bind a name to a value-addVal :: E -> Lid R -> Value -> E+addVal :: E -> VarId R -> Value -> E addVal e n v = e =+= n =:= (return v :: IO Value) -- | Bind a name to a module, which is represented as a nested -- environment-addMod :: E -> Uid R -> E -> E+addMod :: E -> ModId R -> E -> E addMod e n e' = e =+= n =:= collapse e'
src/Env.hs view
@@ -1,42 +1,37 @@+{-# LANGUAGE OverlappingInstances #-} -- | Flat, deep, and generalized environments-{-# LANGUAGE- DeriveDataTypeable,- FlexibleInstances,- FunctionalDependencies,- MultiParamTypeClasses,- OverlappingInstances,- ScopedTypeVariables,- TypeOperators,- UndecidableInstances #-} module Env ( -- * Basic type and operations Env(unEnv), -- ** Key subsumption (:>:)(..), -- ** Constructors- empty, (-:-), (-::-),+ Env.empty, (-:-), (-::-), (-:+-), (-+-), (-\-), (-\\-), (-|-), -- ** Destructors- isEmpty, (-.-),+ isEmpty, numberOfKeys, (-.-), -- ** Higher-order constructors unionWith, unionSum, unionProduct, -- ** Higher-order destructors mapVals, mapValsM, mapAccum, mapAccumM, -- ** List conversions- toList, fromList, domain, range,+ Env.toList, fromList, domain, range, -- * Deep environments PEnv(..), Path(..), ROOT(..), (<.>), -- * Generalized environments GenEmpty(..),- GenExtend(..), (=++=), GenModify(..), GenRemove(..),+ GenExtend(..), (=++=), GenLookup(..),+ GenNewEnv(..), -- * Aliases (why?)- (=:=), (=::=), (=:+=)+ (=:=), (=:*=), (=::=), (=:+=) ) where +import Prelude ()+ import Util import qualified Data.Map as M import qualified Data.Set as S@@ -45,7 +40,7 @@ infix 6 -:-, -::-, -:+- infixl 6 -.--infixr 5 -+-+infixl 5 -+- infixl 5 -\-, -\\-, -|- -- | The basic type, mapping keys @k@ to values @v@@@ -73,6 +68,10 @@ isEmpty :: Env k v -> Bool isEmpty = M.null . unEnv +-- | The number of bindings in the environment+numberOfKeys :: Env k v -> Int+numberOfKeys = M.size . unEnv+ -- | Create a singleton environment (-:-) :: Ord k => k -> v -> Env k v k -:- v = Env (M.singleton k v)@@ -125,7 +124,7 @@ infix 5 `unionSum`, `unionProduct` -instance Ord k => Functor (Env k) where+instance Functor (Env k) where fmap f = Env . M.map f . unEnv -- | Map over the values of an environment@@ -158,7 +157,7 @@ helper a' ((k, w) : acc) rest -- | Get an association list-toList :: Ord k => Env k v -> [(k, v)]+toList :: Env k v -> [(k, v)] toList = M.toList . unEnv -- | Make an environment from an association list@@ -166,18 +165,18 @@ fromList = Env . M.fromList -- | The keys-domain :: Ord k => Env k v -> [k]+domain :: Env k v -> [k] domain = M.keys . unEnv -- | The values-range :: Ord k => Env k v -> [v]+range :: Env k v -> [v] range = M.elems . unEnv instance Ord k => Monoid (Env k v) where- mempty = empty+ mempty = Env.empty mappend m n = Env (M.unionWith (\_ v -> v) (unEnv m) (unEnv n)) -instance (Ord k, Show k, Show v) => Show (Env k v) where+instance (Show k, Show v) => Show (Env k v) where showsPrec _ env = foldr (.) id [ shows k . (" : "++) . shows v . ('\n':) | (k, v) <- M.toList (unEnv env) ]@@ -191,17 +190,11 @@ infix 6 =:=, =::=, =:+= infixl 6 =.=, =..=-infixr 5 =+=, =++=-infixl 5 =\=, =\\=+infixl 5 =+=, =++= instance (k :>: k') => GenExtend (Env k v) (Env k' v) where (=+=) = (-+-)-instance Ord k => GenRemove (Env k v) k where (=\=) = (-\-) instance (k :>: k') => GenLookup (Env k v) k' v where (=..=) = (-.-)-instance (k :>: k') => GenModify (Env k v) k' v where- genModify e k fv = case e =..= k of- Nothing -> e- Just v -> e =+= k -:- fv v-instance GenEmpty (Env k v) where genEmpty = empty+instance GenEmpty (Env k v) where genEmpty = Env.empty -- | A path environment maps paths of @p@ components to @e@. data PEnv p e = PEnv {@@ -234,6 +227,9 @@ instance Ord p => Functor (PEnv p) where fmap f (PEnv envs vals) = PEnv (fmap (fmap f) envs) (f vals) +instance Bogus k => Bogus (Path p k) where+ bogus = J [] bogus+ instance (Show p, Show k) => Show (Path p k) where showsPrec _ (J ps k) = foldr (\p r -> shows p . ('.':) . r) (shows k) ps @@ -263,9 +259,6 @@ instance GenEmpty e => GenEmpty [e] where genEmpty = [genEmpty] -instance GenRemove e k => GenRemove [e] k where- e =\= k = map (=\= k) e- -- | A generalization of environment union. If the environments -- have different types, we assume the right type may be lifted -- to the left types.@@ -286,7 +279,7 @@ penv =+= e = penv { envenv = envenv penv =+= e } instance Ord p => GenExtend (PEnv p e) (Env p e) where- penv =+= e = penv =+= fmap (PEnv (empty :: Env p (PEnv p e))) e+ penv =+= e = penv =+= fmap (PEnv (Env.empty :: Env p (PEnv p e))) e instance GenExtend e e' => GenExtend (PEnv p e) e' where@@ -298,7 +291,7 @@ instance (Ord p, Ord k, GenEmpty e, GenExtend e (Env k v)) => GenExtend (PEnv p e) (Env (Path p k) v) where- penv =+= env = foldr (flip (=+=)) penv (toList env)+ penv =+= env = foldr (flip (=+=)) penv (Env.toList env) instance (Ord p, Ord k, GenEmpty e, GenExtend e (Env k v)) => GenExtend (PEnv p e) (Path p k, v) where@@ -343,86 +336,13 @@ penv =..= J path k = penv =..= path >>= (=.= k) instance GenLookup e k v => GenLookup (ROOT (PEnv p e)) k v where- ROOT penv =..= k = valenv penv =..= k + ROOT penv =..= k = valenv penv =..= k -- alias for looking up a simple key (=.=) :: GenLookup e k v => PEnv p e -> k -> Maybe v (=.=) = (=..=) . ROOT --- | Generalization of a value update operation------ We can modify a nested env at------ * one path component------ * a path to a nested env------ * a path to an env------ * a path to a key------ * a single key (ROOT)-class GenModify e k v where- genModify :: e -> k -> (v -> v) -> e -instance Ord p => GenModify (PEnv p e) p (PEnv p e) where- genModify penv p f = genModify penv [p] f--instance Ord p => GenModify (PEnv p e) [p] (PEnv p e) where- genModify penv [] f = f penv- genModify penv (p:ps) f = case envenv penv =..= p of- Nothing -> penv- Just penv' -> penv =+= p =:= genModify penv' ps f--instance Ord p => GenModify (PEnv p e) [p] e where- genModify penv path fe = genModify penv path fpenv where- fpenv :: PEnv p e -> PEnv p e- fpenv penv' = penv' { valenv = fe (valenv penv') }--instance (Ord p, GenModify e k v) =>- GenModify (PEnv p e) (Path p k) v where- genModify penv (J path k) fv = genModify penv path fe where- fe :: e -> e- fe e = genModify e k fv--instance GenModify e k v => GenModify (ROOT (PEnv p e)) k v where- genModify (ROOT penv) k fv = ROOT (penv { valenv = fe (valenv penv) })- where- fe :: e -> e- fe e = genModify e k fv---- | Generalization class for key removal------ We can remove at------ * a single path component------ * a path to a key------ * a path to a path------ * a single key (using 'ROOT')-class GenRemove e k where- (=\=) :: e -> k -> e- (=\\=) :: e -> S.Set k -> e- e =\\= set = foldl (=\=) e (S.toList set)--instance Ord p => GenRemove (PEnv p e) p where- penv =\= p = penv { envenv = envenv penv =\= p }--instance (Ord p, GenRemove e k) => GenRemove (PEnv p e) (Path p k) where- penv =\= J path k = genModify penv path fe where- fe :: e -> e- fe = (=\= k)--instance Ord p => GenRemove (PEnv p e) (Path p p) where- penv =\= J path p = genModify penv path fpenv where- fpenv :: PEnv p e -> PEnv p e- fpenv = (=\= p)--instance GenRemove e k => GenRemove (ROOT (PEnv p e)) k where- ROOT penv =\= k = ROOT (penv { valenv = valenv penv =\= k })- -- | Generalization of the empty environment class GenEmpty e where genEmpty :: e@@ -431,3 +351,16 @@ instance GenEmpty e => GenEmpty (PEnv p e) where genEmpty = PEnv genEmpty genEmpty +-- Make new environments from a variety of things+class GenNewEnv k' v' k v | k' v' → k v where+ (-:*-) ∷ k' → v' → Env k v+ (-::*-) ∷ Monad m ⇒ k' → v' → Env k (m v)+ k' -::*- v' = return <$> (k' -:*- v')++instance Ord k ⇒ GenNewEnv [k] [v] k v where+ ks -:*- vs = fromList (zip ks vs)++(=:*=) :: GenNewEnv k' v' k v ⇒ k' → v' → Env k v+(=:*=) = (-:*-)++infix 6 -:*-, -::*-, =:*=
+ src/Error.hs view
@@ -0,0 +1,449 @@+module Error (+ AlmsError(..), Phase(..),+ almsBug, (!::),+ wordsMsg, quoteMsg, pprMsg, showMsg, emptyMsg,+ throw,++ MonadAlmsError(..),+ unTryAlms, finallyAlms,+ addErrorContext,+ bailoutIfError,++ AlmsErrorT(..), runAlmsErrorT,+ mapAlmsErrorT, liftCallCC, liftCatch, liftListen, liftPass,++ AlmsErrorIO(..), runAlmsErrorIO,++ module Message.Quasi,+) where++import Util+import Util.MonadRef+import Util.Trace+import Data.Loc+import Syntax.PprClass+import Message.AST+import Message.Render ()+import Message.Quasi++import Prelude ()+import Data.Typeable (Typeable)+import Control.Applicative+import Control.Exception (Exception, throwIO, throw, catch)++import qualified Control.Monad.Cont as Cont+import qualified Control.Monad.Trans.Identity as Identity+import qualified Control.Monad.Trans.Maybe as Maybe+import qualified Control.Monad.Trans.List as List+import qualified Control.Monad.Error as Error+import qualified Control.Monad.Trans.Reader as Reader+import qualified Control.Monad.Trans.RWS.Strict as StrictRWS+import qualified Control.Monad.Trans.RWS.Lazy as LazyRWS+import qualified Control.Monad.Trans.State.Strict as StrictState+import qualified Control.Monad.Trans.State.Lazy as LazyState+import qualified Control.Monad.Trans.Writer.Strict as StrictWriter+import qualified Control.Monad.Trans.Writer.Lazy as LazyWriter++--+-- Representation of Alms errors+--++-- | Alms internal exceptions+data AlmsError+ = AlmsError {+ exnPhase :: Phase, -- | When did it happen?+ exnLoc :: Loc, -- | Where in the source did it happen?+ exnMessage :: Message V -- | What happened?+ }+ deriving (Typeable, Eq)++-- | The phases in which an error might occur:+data Phase+ = ParserPhase+ | RenamerPhase+ | StaticsPhase+ | DynamicsPhase+ | OtherError String+ deriving (Eq, Ord, Show)++-- | Error constructors++almsBug :: Phase -> String -> String -> AlmsError+almsBug phase culprit0 msg0 =+ let culprit = if null culprit0+ then "unknown"+ else culprit0 in+ AlmsError (OtherError "BUG! in Alms implementation")+ bogus+ [msg|+ This shouldn’t happen, so it probably+ indicates a bug in the Alms implementation.+ <p>+ Details:+ <dl>+ <dt>who: <dd>$words:culprit+ <dt>what: <dd>$words:msg0+ <dt>when: <dd>$show:phase+ </dl>+ <p>+ Please report to <exact><tov@ccs.neu.edu></exact>.+ |]++(!::) :: Ppr a => String -> a -> Message d+msg0 !:: thing = [msg| $words:msg0 <q>$thing</q> |]+infix 1 !::++---+--- 'AlmsError' Instances+---++instance Ppr AlmsError where+ ppr (AlmsError phase loc msg0) =+ (text phaseString <+> locString <> colon)+ $$+ ppr (Indent msg0)+ where locString = if isBogus loc+ then mempty+ else text "at" <+> text (show loc)+ phaseString = case phase of+ ParserPhase -> "Syntax error"+ RenamerPhase -> "Type error"+ StaticsPhase -> "Type error"+ DynamicsPhase -> "Run-time error"+ OtherError s -> s++instance Show AlmsError where showsPrec = showFromPpr++instance Exception AlmsError++instance Error AlmsError where+ strMsg = AlmsError (OtherError "Error") bogus . Words++---+--- The MonadAlmsError class for carrying alms errors+---++-- | A class for managing multiple errors with messages and source+-- locations. Minimal complete definition: @getLocation@,+-- @withLocation_@, @bailoutAlms_@, @reportAlms_@, and @catchAlms@.+class Monad m => MonadAlmsError m where+ -- | Find out the current source location.+ getLocation :: m Loc+ -- | Run a computation in the context of the given source location.+ withLocation :: Locatable loc ⇒ loc -> m a -> m a+ -- | Add an error to the collection of errors, but keep running.+ reportAlms :: AlmsError -> m ()+ -- | Report an error and give up running.+ throwAlms :: AlmsError -> m a+ -- | Report some errors and give up running.+ throwAlmsList :: [AlmsError] -> m a+ -- | If any errors have occurred, collect them and give them to+ -- a handler. The list should be non-empty.+ catchAlms :: m a -> ([AlmsError] -> m a) -> m a+ -- | Map any errors propagating upward+ mapAlmsErrors :: (AlmsError -> AlmsError) -> m a -> m a+ --+ -- Low-level methods (not intended for client use)+ --+ withLocation_ :: Loc -> m a -> m a+ bailoutAlms_ :: m a+ reportAlms_ :: AlmsError -> m ()+ --+ -- Default implementations+ --+ withLocation locatable =+ let loc = getLoc locatable+ in if isBogus loc+ then id+ else withLocation_ loc+ reportAlms e = do+ if isBogus (exnLoc e)+ then do+ loc <- getLocation+ reportAlms_ e { exnLoc = loc }+ else reportAlms_ e+ throwAlms e = reportAlms e >> bailoutAlms_+ throwAlmsList es = mapM reportAlms es >> bailoutAlms_++unTryAlms :: MonadAlmsError m =>+ m (Either [AlmsError] a) -> m a+unTryAlms = (either throwAlmsList return =<<)++infixl 1 `catchAlms`++finallyAlms :: MonadAlmsError m =>+ m a -> m () -> m a+finallyAlms action cleanup = do+ result <- action `catchAlms` (>>) cleanup . throwAlmsList+ cleanup+ return result++infixl 1 `finallyAlms`++addErrorContext :: MonadAlmsError m =>+ m a ->+ Message d ->+ m a+addErrorContext action message =+ mapAlmsErrors eachError action+ where+ eachError exn = + exn { exnMessage = [msg| $1 <br> $2 |] message (exnMessage exn) }++infixl 1 `addErrorContext`++bailoutIfError :: MonadAlmsError m => m a -> m a+bailoutIfError action = action `catchAlms` throwAlmsList++--+-- Instances+--++-- | This doesn't work very well+instance MonadAlmsError IO where+ getLocation = return bogus+ withLocation_ _ = id+ bailoutAlms_ = fail ""+ reportAlms_ = throwIO+ catchAlms action handler = Control.Exception.catch action handler'+ where handler' e = handler [e]+ mapAlmsErrors f action = Control.Exception.catch action (throwIO . f)++--+-- A monad transformer+--++newtype AlmsErrorT m a+ = AlmsErrorT {+ unAlmsErrorT :: Maybe.MaybeT (StrictRWS.RWST LocMap [AlmsError] () m) a+ }+type LocMap = (Loc, AlmsError -> AlmsError)++instance Monad m => Functor (AlmsErrorT m) where+ fmap = liftM++instance Monad m => Applicative (AlmsErrorT m) where+ pure = return+ (<*>) = ap++instance Monad m => Monad (AlmsErrorT m) where+ return = AlmsErrorT . return+ m >>= k = AlmsErrorT (unAlmsErrorT m >>= (unAlmsErrorT . k))+ fail s = throwAlms (strMsg s)++instance MonadTrans AlmsErrorT where+ lift = AlmsErrorT . lift . lift++instance Monad m => MonadAlmsError (AlmsErrorT m) where+ getLocation = AlmsErrorT (lift (asks fst))+ withLocation_ loc =+ AlmsErrorT . local (first (const loc)) . unAlmsErrorT+ bailoutAlms_ = AlmsErrorT (Maybe.MaybeT (return Nothing))+ reportAlms_ e = AlmsErrorT . lift $ do+ f <- asks snd+ tell [f e]+ catchAlms action handler+ = either handler return =<< lift (runAlmsErrorT action)+ mapAlmsErrors f =+ AlmsErrorT . local (second (. f)) . unAlmsErrorT++runAlmsErrorT :: Monad m =>+ AlmsErrorT m a -> m (Either [AlmsError] a)+runAlmsErrorT (AlmsErrorT action) = do+ (mresult, es) <- StrictRWS.evalRWST (Maybe.runMaybeT action) (bogus, id) ()+ case (mresult, es) of+ (Just a, []) -> return (Right a)+ (_, []) -> return $+ Left [almsBug (OtherError "Unknown")+ "AlmsErrorT" "got empty error list"]+ (_, _) -> return (Left es)++-- | Map a higher order operation through the 'AlmsErrorT' monad+mapAlmsErrorT ∷ (m (Maybe a, (), [AlmsError]) →+ n (Maybe b, (), [AlmsError])) →+ AlmsErrorT m a → AlmsErrorT n b+mapAlmsErrorT f =+ AlmsErrorT . Maybe.mapMaybeT (StrictRWS.mapRWST f) . unAlmsErrorT++-- | Lift a @callCC@ operation through the 'AlmsErrorT' monad+liftCallCC ∷+ ((((Maybe a, (), [AlmsError]) → m (Maybe b, (), [AlmsError])) →+ m (Maybe a, (), [AlmsError])) → m (Maybe a, (), [AlmsError])) →+ ((a → AlmsErrorT m b) → AlmsErrorT m a) →+ AlmsErrorT m a+liftCallCC callCC0 kont =+ AlmsErrorT $+ Maybe.liftCallCC (StrictRWS.liftCallCC callCC0)+ (unAlmsErrorT . kont . (AlmsErrorT .))++-- | Lift a @catch@ operation through the 'AlmsErrorT' monad+liftCatch ∷ (∀ s. m s → (e → m s) → m s) →+ AlmsErrorT m a → (e → AlmsErrorT m a) →+ AlmsErrorT m a+liftCatch catch0 action handle =+ AlmsErrorT $+ Maybe.liftCatch (StrictRWS.liftCatch catch0)+ (unAlmsErrorT action)+ (unAlmsErrorT . handle)++-- | Lift a @listen@ operation through the 'AlmsErrorT' monad+liftListen ∷ Monad m ⇒+ (∀ s. m s → m (s, w)) →+ AlmsErrorT m a → AlmsErrorT m (a, w)+liftListen listen' = mapAlmsErrorT $ \action → do+ ((mresult, st, es), w) ← listen' action+ return $! case mresult of+ Nothing → (Nothing, st, es)+ Just v → (Just (v, w), st, es)++-- | Lift a @pass@ operation through the 'AlmsErrorT' monad+liftPass ∷ Monad m ⇒+ (∀ s. m (s, w → w) → m s) →+ AlmsErrorT m (a, w → w) → AlmsErrorT m a+liftPass pass' = mapAlmsErrorT $ \action → pass' $ do+ (mresult, st, es) ← action+ return $! case mresult of+ Nothing → ((Nothing, st, es), id)+ Just (v, f) → ((Just v, st, es), f)++---+--- Running in IO+---++newtype AlmsErrorIO = AlmsErrorIO { unAlmsErrorIO ∷ [AlmsError] }+ deriving (Typeable)++instance Show AlmsErrorIO where+ show = concatMap ((++ "\n") . ('\n' :) . show) . unAlmsErrorIO++instance Exception AlmsErrorIO++-- | Run in the IO monad, accumulating all errors.+runAlmsErrorIO ∷ MonadIO m ⇒ AlmsErrorT m a → m a+runAlmsErrorIO = either (liftIO . throwIO . AlmsErrorIO) return <=< runAlmsErrorT++--+-- AlmsErrorT Pass-through instances+--++instance MonadReader r m ⇒ MonadReader r (AlmsErrorT m) where+ ask = lift ask+ local = mapAlmsErrorT . local++instance MonadState s m ⇒ MonadState s (AlmsErrorT m) where+ get = lift get+ put = lift . put++instance MonadWriter w m ⇒ MonadWriter w (AlmsErrorT m) where+ tell = lift . tell+ listen = liftListen listen+ pass = liftPass pass++instance MonadError e m ⇒ MonadError e (AlmsErrorT m) where+ throwError = lift . throwError+ catchError = liftCatch catchError++instance Cont.MonadCont m ⇒ Cont.MonadCont (AlmsErrorT m) where+ callCC = liftCallCC Cont.callCC++instance MonadRef r m ⇒ MonadRef r (AlmsErrorT m) where+ newRef = lift <$> newRef+ readRef = lift <$> readRef+ writeRef = lift <$$> writeRef++instance MonadTrace m ⇒ MonadTrace (AlmsErrorT m) where+ getTraceIndent = lift getTraceIndent+ putTraceIndent = lift <$> putTraceIndent+ putTraceString = lift <$> putTraceString++instance MonadIO m ⇒ MonadIO (AlmsErrorT m) where+ liftIO = lift . liftIO++--+-- MonadAlmsError Pass-through instances+--++instance MonadAlmsError m => MonadAlmsError (Identity.IdentityT m) where+ getLocation = lift getLocation+ withLocation_ = Identity.mapIdentityT . withLocation_+ bailoutAlms_ = lift bailoutAlms_+ reportAlms_ = lift . reportAlms_+ catchAlms = Identity.liftCatch catchAlms+ mapAlmsErrors = Identity.mapIdentityT . mapAlmsErrors++instance MonadAlmsError m => MonadAlmsError (Maybe.MaybeT m) where+ getLocation = lift getLocation+ withLocation_ = Maybe.mapMaybeT . withLocation_+ bailoutAlms_ = lift bailoutAlms_+ reportAlms_ = lift . reportAlms_+ catchAlms = Maybe.liftCatch catchAlms+ mapAlmsErrors = Maybe.mapMaybeT . mapAlmsErrors++instance MonadAlmsError m => MonadAlmsError (ListT m) where+ getLocation = lift getLocation+ withLocation_ = mapListT . withLocation_+ bailoutAlms_ = lift bailoutAlms_+ reportAlms_ = lift . reportAlms_+ catchAlms = List.liftCatch catchAlms+ mapAlmsErrors = mapListT . mapAlmsErrors++instance MonadAlmsError m => MonadAlmsError (ReaderT r m) where+ getLocation = lift getLocation+ withLocation_ = mapReaderT . withLocation_+ bailoutAlms_ = lift bailoutAlms_+ reportAlms_ = lift . reportAlms_+ catchAlms = Reader.liftCatch catchAlms+ mapAlmsErrors = mapReaderT . mapAlmsErrors++instance (MonadAlmsError m, Monoid w) =>+ MonadAlmsError (StrictRWS.RWST r w s m) where+ getLocation = lift getLocation+ withLocation_ = StrictRWS.mapRWST . withLocation_+ bailoutAlms_ = lift bailoutAlms_+ reportAlms_ = lift . reportAlms_+ catchAlms = StrictRWS.liftCatch catchAlms+ mapAlmsErrors = StrictRWS.mapRWST . mapAlmsErrors++instance (MonadAlmsError m, Monoid w) =>+ MonadAlmsError (LazyRWS.RWST r w s m) where+ getLocation = lift getLocation+ withLocation_ = LazyRWS.mapRWST . withLocation_+ bailoutAlms_ = lift bailoutAlms_+ reportAlms_ = lift . reportAlms_+ catchAlms = LazyRWS.liftCatch catchAlms+ mapAlmsErrors = LazyRWS.mapRWST . mapAlmsErrors++instance (MonadAlmsError m, Monoid w) =>+ MonadAlmsError (StrictWriter.WriterT w m) where+ getLocation = lift getLocation+ withLocation_ = StrictWriter.mapWriterT . withLocation_+ bailoutAlms_ = lift bailoutAlms_+ reportAlms_ = lift . reportAlms_+ catchAlms = StrictWriter.liftCatch catchAlms+ mapAlmsErrors = StrictWriter.mapWriterT . mapAlmsErrors++instance (MonadAlmsError m, Monoid w) =>+ MonadAlmsError (LazyWriter.WriterT w m) where+ getLocation = lift getLocation+ withLocation_ = LazyWriter.mapWriterT . withLocation_+ bailoutAlms_ = lift bailoutAlms_+ reportAlms_ = lift . reportAlms_+ catchAlms = LazyWriter.liftCatch catchAlms+ mapAlmsErrors = LazyWriter.mapWriterT . mapAlmsErrors++instance MonadAlmsError m => MonadAlmsError (StrictState.StateT s m) where+ getLocation = lift getLocation+ withLocation_ = StrictState.mapStateT . withLocation_+ bailoutAlms_ = lift bailoutAlms_+ reportAlms_ = lift . reportAlms_+ catchAlms = StrictState.liftCatch catchAlms+ mapAlmsErrors = StrictState.mapStateT . mapAlmsErrors++instance MonadAlmsError m => MonadAlmsError (LazyState.StateT s m) where+ getLocation = lift getLocation+ withLocation_ = LazyState.mapStateT . withLocation_+ bailoutAlms_ = lift bailoutAlms_+ reportAlms_ = lift . reportAlms_+ catchAlms = LazyState.liftCatch catchAlms+ mapAlmsErrors = LazyState.mapStateT . mapAlmsErrors+
− src/ErrorMessage.hs
@@ -1,118 +0,0 @@-{-# LANGUAGE- DeriveDataTypeable,- FlexibleInstances,- MultiParamTypeClasses,- QuasiQuotes- #-}-module ErrorMessage (- AlmsException(..), Phase(..), AlmsMonad(..),- almsBug, (!::),- wordsMsg, quoteMsg, pprMsg, showMsg, emptyMsg,- module Message.Quasi,-) where--import Loc-import PprClass-import Message.AST-import Message.Render ()-import Message.Quasi--import Data.Typeable (Typeable)-import Control.Exception (Exception, throwIO, catch)-import Control.Monad.Error (Error(..))------- Representation of Alms errors------- | Alms internal exceptions-data AlmsException- = AlmsException {- exnPhase :: Phase, -- | When did it happen?- exnLoc :: Loc, -- | Where in the source did it happen?- exnMessage :: Message V -- | What happened?- }- deriving Typeable---- | The phases in which an error might occur:-data Phase- = ParserPhase- | RenamerPhase- | StaticsPhase- | DynamicsPhase- | OtherError String- deriving Show---- | Error constructors--almsBug :: Phase -> Loc -> String -> String -> AlmsException-almsBug phase loc culprit0 msg0 =- let culprit = if null culprit0- then "unknown"- else culprit0 in- AlmsException (OtherError "BUG! in Alms implementation")- bogus- [$msg|- This shouldn’t happen, so it probably- indicates a bug in the Alms implementation.- <p>- Details:- <dl>- <dt>who: <dd>$words:culprit- <dt>what: <dd>$words:msg0- <dt>where:<dd>$show:loc- <dt>when: <dd>$show:phase- </dl>- <p>- Please report to <exact><tov@ccs.neu.edu></exact>.- |]--(!::) :: Ppr a => String -> a -> Message d-msg0 !:: thing = [$msg| $words:msg0 <q>$thing</q> |]-infix 1 !::--------- The AlmsMonad class for carrying alms errors------class Monad m => AlmsMonad m where- throwAlms :: AlmsException -> m a- catchAlms :: m a -> (AlmsException -> m a) -> m a- unTryAlms :: m (Either AlmsException a) -> m a- unTryAlms = (>>= either throwAlms return)--instance AlmsMonad IO where- throwAlms = throwIO- catchAlms = Control.Exception.catch--instance AlmsMonad (Either AlmsException) where- throwAlms = Left- catchAlms (Right a) _ = Right a- catchAlms (Left e) k = k e--------- Instances------instance Ppr AlmsException where- ppr (AlmsException phase loc msg0) =- (text phaseString <+> locString <> colon)- $$- ppr (Indent msg0)- where locString = if isBogus loc- then empty- else text "at" <+> text (show loc)- phaseString = case phase of- ParserPhase -> "Syntax error"- RenamerPhase -> "Type error"- StaticsPhase -> "Type error"- DynamicsPhase -> "Run-time error"- OtherError s -> s--instance Show AlmsException where showsPrec = showFromPpr--instance Exception AlmsException--instance Error AlmsException where- strMsg = AlmsException (OtherError "Error") bogus . Words-
− src/ErrorST.hs
@@ -1,143 +0,0 @@--- | A semi-transactional version of the ST monad-{-# LANGUAGE- DeriveDataTypeable,- FlexibleInstances,- GeneralizedNewtypeDeriving,- MultiParamTypeClasses,- RankNTypes #-}-module ErrorST (- -- * The 'ST' monad with errors- ST,- -- ** Operations- runST, transaction, liftST,- catchError, throwError,- -- * 'STRef's- STRef,- -- ** Operations- newSTRef, newTransSTRef, readSTRef, writeSTRef, modifySTRef,- unsafeIOToST-) where--import Control.Applicative-import Control.Monad.Error-import Control.Monad.State-import qualified Control.Monad.ST as Super-import Data.Data-import qualified Data.STRef as S---- | Like the 'ST' monad, but with errors and transactions. Each STRef--- is declared to be transaction alor not. Transaction STRefs lose--- any changes made between an exception handler and an exception--- being thrown.-newtype ST s e a = ST { unST :: Rep s e a }- deriving (Functor, Monad, Typeable)-type Rep s e a = ErrorT e (StateT (Super.ST s ()) (Super.ST s)) a--instance Error e => Applicative (ST s e) where- pure = return- (<*>) = ap--instance Error e => MonadError e (ST s e) where- throwError = ST . throwError- catchError body handler = ST $ do- oldUndo <- get- put (return ())- do res <- unST body- modify (>> oldUndo)- return res- `catchError` \e -> do- newUndo <- get- put oldUndo- liftST_ newUndo- unST (handler e)--runST :: (Error e, MonadError e m) => (forall s. ST s e a) -> m a-runST block =- either throwError return $- Super.runST (evalStateT (runErrorT (unST (transaction block))) (return ()))---- | Run something directly in the underlying ST monad-liftST :: Error e => Super.ST s a -> ST s e a-liftST = ST . liftST_--transaction :: Error e => ST s e a -> ST s e a-transaction block = block `catchError` throwError--data STRef s a- = NonTr {- getRef :: !(S.STRef s a)- }- | Trans {- getRef :: !(S.STRef s a)- }- deriving Typeable---- | Create a new 'STRef' whose changes survive failed transactions-newSTRef :: Error e => a -> ST s e (STRef s a)-newSTRef = liftM NonTr . ST . liftST_ . S.newSTRef---- | Create a new 'STRef' whose changes are reverted by failed transactions-newTransSTRef :: Error e => a -> ST s e (STRef s a)-newTransSTRef = liftM Trans . ST . liftST_ . S.newSTRef--readSTRef :: Error e => STRef s a -> ST s e a-readSTRef = ST . liftST_ . S.readSTRef . getRef--writeSTRef :: Error e => STRef s a -> a -> ST s e ()-writeSTRef (NonTr r) a = ST . liftST_ . S.writeSTRef r $ a-writeSTRef (Trans r) a = ST $ do- old <- liftST_ (S.readSTRef r)- addUndo_ (S.writeSTRef r old)- liftST_ (S.writeSTRef r a)--modifySTRef :: Error e => STRef s a -> (a -> a) -> ST s e ()-modifySTRef (NonTr r) f = ST . liftST_ . S.modifySTRef r $ f-modifySTRef (Trans r) f = ST $ do- old <- liftST_ (S.readSTRef r)- addUndo_ (S.writeSTRef r old)- liftST_ (S.writeSTRef r (f old))--unsafeIOToST :: Error e => IO a -> ST s e a-unsafeIOToST = ST . liftST_ . Super.unsafeIOToST---- helpers--addUndo_ :: Error e => Super.ST s () -> Rep s e ()-addUndo_ = modify . (>>)--liftST_ :: Error e => Super.ST s a -> Rep s e a-liftST_ = lift . lift--{--test :: IO ()-test = either fail id . runST $ do- a <- newSTRef "a0"- b <- newTransSTRef "b0"- c <- newSTRef "c0"- d <- newTransSTRef "d0"- e <- newSTRef "e0"- f <- newTransSTRef "f0"- do- writeSTRef a "a1"- writeSTRef b "b1"- writeSTRef d "d1"- transaction $ do- writeSTRef c "c2"- writeSTRef d "d2"- throwError "ERROR!"- writeSTRef a "a3"- writeSTRef b "b3"- `catchError` \_ -> do- writeSTRef e "e4"- writeSTRef f "f4"- ra <- readSTRef a- rb <- readSTRef b- rc <- readSTRef c- rd <- readSTRef d- re <- readSTRef e- rf <- readSTRef f- return $- print [(ra, "a1"), (rb, "b0"),- (rc, "c2"), (rd, "d0"),- (re, "e4"), (rf, "f4")]--}
− src/Lexer.hs
@@ -1,295 +0,0 @@--- | Lexer setup for parsec-module Lexer (- -- * Class for saving pre-whitespace position- T.TokenEnd(..),- -- * Identifier tokens- isUpperIdentifier, lid, uid,-- -- * Operators- semis, bang, star, slash, plus,- sharpLoad, sharpInfo, sharpPrec,- lolli, arrow, funbraces,- lambda, forall, exists, mu,- qualbox,- qualU, qualA, qdisj, qconj,- opP,-- -- * Token parsers from Parsec- identifier, reserved, operator, reservedOp, charLiteral,- stringLiteral, natural, integer, integerOrFloat, float,- naturalOrFloat, decimal, hexadecimal, octal, symbol, lexeme,- whiteSpace, parens, braces, angles, brackets, squares, semi, comma,- colon, dot, semiSep, semiSep1, commaSep, commaSep1-) where--import Prec-import Util--import Data.Char-import Text.ParserCombinators.Parsec-import qualified Token as T--tok :: T.TokenEnd st => T.TokenParser st-tok = T.makeTokenParser T.LanguageDef {- T.commentStart = "(*",- T.commentEnd = "*)",- T.commentLine = "--",- T.nestedComments = True,- T.identStart = upper <|> lower <|> oneOf "_",- T.identLetter = alphaNum <|> oneOf "_'",- T.opStart = satisfy isOpStart,- T.opLetter = satisfy isOpLetter,- T.reservedNames = ["fun", "λ",- "if", "then", "else",- "match", "with", "as", "_",- "try",- "local", "open", "exception",- "let", "rec", "and", "in",- "Pack",- "interface", "abstype", "end",- "module", "struct",- "sig", "val", "include",- "all", "ex", "mu", "μ", "of",- "type", "qualifier"],- T.reservedOpNames = ["|", "=", ":", ":>", "->", "→", "⊸",- "∀", "∃" ],- T.caseSensitive = True- }--isOpStart, isOpLetter :: Char -> Bool-isOpStart c- | isAscii c = c `elem` "!$%&*+-/<=>?@^|~"- | otherwise = case generalCategory c of- ConnectorPunctuation -> True- DashPunctuation -> True- OtherPunctuation -> True- MathSymbol -> True- CurrencySymbol -> True- OtherSymbol -> True- _ -> False-isOpLetter c- | isAscii c = c `elem` "!$%&*+-/<=>?@^|~.:"- | otherwise = case generalCategory c of- ConnectorPunctuation -> True- DashPunctuation -> True- OtherPunctuation -> True- MathSymbol -> True- CurrencySymbol -> True- OtherSymbol -> True- ModifierSymbol -> True -- not in OpStart- -- OpenPunctuation- -- ClosePunctuation- -- InitialQuote- -- FinalQuote- _ -> False--identifier :: T.TokenEnd st => CharParser st String-identifier = T.identifier tok-reserved :: T.TokenEnd st => String -> CharParser st ()-reserved = T.reserved tok-operator :: T.TokenEnd st => CharParser st String-operator = T.operator tok-reservedOp :: T.TokenEnd st => String -> CharParser st ()-reservedOp = T.reservedOp tok-charLiteral :: T.TokenEnd st => CharParser st Char-charLiteral = T.charLiteral tok-stringLiteral :: T.TokenEnd st => CharParser st String-stringLiteral = T.stringLiteral tok-natural :: T.TokenEnd st => CharParser st Integer-natural = T.natural tok-integer :: T.TokenEnd st => CharParser st Integer-integer = lexeme $ try $ do- sign <- choice [- char '+' >> return id,- char '-' >> return negate,- return id- ]- nat <- natural- return (sign nat)-integerOrFloat :: T.TokenEnd st => CharParser st (Either Integer Double)-integerOrFloat = lexeme $ try $ do- sign <- choice [- char '+' >> return id,- char '-' >> return (either (Left . negate) (Right . negate)),- return id- ]- nof <- naturalOrFloat- return (sign nof)- -float :: T.TokenEnd st => CharParser st Double-float = T.float tok-naturalOrFloat :: T.TokenEnd st => CharParser st (Either Integer Double)-naturalOrFloat = T.naturalOrFloat tok-decimal :: T.TokenEnd st => CharParser st Integer-decimal = T.decimal tok-hexadecimal :: T.TokenEnd st => CharParser st Integer-hexadecimal = T.hexadecimal tok-octal :: T.TokenEnd st => CharParser st Integer-octal = T.octal tok-symbol :: T.TokenEnd st => String -> CharParser st String-symbol = T.symbol tok-lexeme :: T.TokenEnd st => CharParser st a -> CharParser st a-lexeme = T.lexeme tok-whiteSpace :: T.TokenEnd st => CharParser st ()-whiteSpace = T.whiteSpace tok-parens :: T.TokenEnd st => CharParser st a -> CharParser st a-parens = T.parens tok-braces :: T.TokenEnd st => CharParser st a -> CharParser st a-braces = T.braces tok-angles :: T.TokenEnd st => CharParser st a -> CharParser st a-angles = T.angles tok-brackets :: T.TokenEnd st => CharParser st a -> CharParser st a-brackets = T.brackets tok-squares :: T.TokenEnd st => CharParser st a -> CharParser st a-squares = T.squares tok-semi :: T.TokenEnd st => CharParser st String-semi = T.semi tok-comma :: T.TokenEnd st => CharParser st String-comma = T.comma tok-colon :: T.TokenEnd st => CharParser st String-colon = T.reservedOp tok ":" >> return ":"-dot :: T.TokenEnd st => CharParser st String-dot = T.dot tok-semiSep :: T.TokenEnd st => CharParser st a -> CharParser st [a]-semiSep = T.semiSep tok-semiSep1 :: T.TokenEnd st => CharParser st a -> CharParser st [a]-semiSep1 = T.semiSep1 tok-commaSep :: T.TokenEnd st => CharParser st a -> CharParser st [a]-commaSep = T.commaSep tok-commaSep1 :: T.TokenEnd st => CharParser st a -> CharParser st [a]-commaSep1 = T.commaSep1 tok---- | The @#load@ pragma-sharpLoad :: T.TokenEnd st => CharParser st ()-sharpLoad = reserved "#l" <|> reserved "#load"---- | The @#info@ pragma-sharpInfo :: T.TokenEnd st => CharParser st ()-sharpInfo = reserved "#i" <|> reserved "#info"---- | The @#prec@ pragma-sharpPrec :: T.TokenEnd st => CharParser st ()-sharpPrec = reserved "#p" <|> reserved "#prec"---- | @!@, which has special meaning in let patterns-bang :: T.TokenEnd st => CharParser st String-bang = symbol "!"---- | The @-o@ type operator, which violates our other lexer rules-lolli :: T.TokenEnd st => CharParser st ()-lolli = reserved "-o" <|> reservedOp "⊸"---- | The @->@ type operator-arrow :: T.TokenEnd st => CharParser st ()-arrow = reservedOp "->" <|> reservedOp "→"---- | The left part of the $-_>$ operator-funbraceLeft :: T.TokenEnd st => CharParser st ()-funbraceLeft = try (symbol "-") >> return ()---- | The right part of the $-_>$ operator-funbraceRight :: T.TokenEnd st => CharParser st ()-funbraceRight = try (symbol ">") >> return ()---- | The left part of the $-[_]>$ operator-oldFunbraceLeft :: T.TokenEnd st => CharParser st ()-oldFunbraceLeft = try (symbol "-[") >> return ()---- | The right part of the $-[_]>$ operator-oldFunbraceRight :: T.TokenEnd st => CharParser st ()-oldFunbraceRight = try (symbol "]>") >> return ()--funbraces :: T.TokenEnd st => CharParser st a -> CharParser st a-funbraces = liftM2 (<|>) (between oldFunbraceLeft oldFunbraceRight)- (between funbraceLeft funbraceRight)---- | The left part of the $|[_]$ annotation-qualboxLeft :: T.TokenEnd st => CharParser st ()-qualboxLeft = try (symbol "|[") >> return ()---- | The right part of the $|[_]$ annotation-qualboxRight :: T.TokenEnd st => CharParser st ()-qualboxRight = try (symbol "]") >> return ()--qualbox :: T.TokenEnd st => CharParser st a -> CharParser st a-qualbox = between qualboxLeft qualboxRight---- | The function keyword-lambda :: T.TokenEnd st => CharParser st ()-lambda = reserved "fun" <|> reservedOp "λ" <|> reservedOp "Λ"---- | The universal quantifier keyword-forall :: T.TokenEnd st => CharParser st ()-forall = reserved "all" <|> reservedOp "∀"---- | The existential quantifier keyword-exists :: T.TokenEnd st => CharParser st ()-exists = reserved "ex" <|> reservedOp "∃"---- | The recursive type binder-mu :: T.TokenEnd st => CharParser st ()-mu = reserved "mu" <|> reservedOp "μ"---- | @;@, @;;@, ...-semis :: T.TokenEnd st => CharParser st String-semis = lexeme (many1 (char ';'))---- | @*@, which is reserved in types but not in expressions-star :: T.TokenEnd st => CharParser st String-star = symbol "*" <|> symbol "×"---- | @/@, which is reserved in types but not in expressions-slash :: T.TokenEnd st => CharParser st String-slash = symbol "/"---- | @+@, which is reserved in types but not in expressions-plus :: T.TokenEnd st => CharParser st String-plus = symbol "+"---- | Qualifier @U@ (not reserved)-qualU :: T.TokenEnd st => CharParser st ()-qualU = reserved "U"--- | Qualifier @A@ (not reserved)-qualA :: T.TokenEnd st => CharParser st ()-qualA = reserved "A"---- | Infix operator for qualifier disjunction-qdisj :: T.TokenEnd st => CharParser st ()-qdisj = reservedOp "," <|> reservedOp "\\/" <|> reservedOp "⋁"---- | Infix operator for qualifier conjunction-qconj :: T.TokenEnd st => CharParser st ()-qconj = reservedOp "/\\" <|> reservedOp "⋀"---- | Is the string an uppercase identifier? (Special case: @true@ and--- @false@ are consider uppercase.)-isUpperIdentifier :: String -> Bool-isUpperIdentifier "true" = True-isUpperIdentifier "false" = True-isUpperIdentifier "()" = True-isUpperIdentifier (c:_) = isUpper c-isUpperIdentifier _ = False---- | Lex a lowercase identifer-lid :: T.TokenEnd st => CharParser st String-lid = try $ do- s <- identifier- if isUpperIdentifier s- then pzero <?> "lowercase identifier"- else return s--- | Lex an uppercase identifer-uid :: T.TokenEnd st => CharParser st String-uid = try $ do- s <- identifier <|> symbol "()"- if isUpperIdentifier s- then return s- else pzero <?> "uppercase identifier"---- | Accept an operator having the specified precedence-opP :: T.TokenEnd st => Prec -> CharParser st String-opP p = try $ do- op <- operator- if precOp op == p- then return op- else pzero-
− src/Loc.hs
@@ -1,222 +0,0 @@--- | Source locations-{-# LANGUAGE- DeriveDataTypeable,- TypeFamilies #-}-module Loc (- -- * Type and constructors- Loc(..),- initial, spanLocs, mkBogus, bogus,- -- * Destructors- isBogus, startOfLoc, endOfLoc,-- -- * Generic function for clearing source locations everywhere- scrub,-- -- * For locating things- -- ** Datatype interface- {-- Located(..), mkBogL, bogL,- -}-- -- ** Type class interface- Locatable(..), Relocatable(..), (<<@),-- -- * Interface to 'Parsec' and 'TH' source positions- toSourcePos, fromSourcePos, fromSourcePosSpan, fromTHLoc-) where--import Data.Generics (Typeable, Data, everywhere, mkT)-import Text.ParserCombinators.Parsec.Pos-import qualified Language.Haskell.TH as TH---- | Source locations-data Loc = Loc {- file :: !String,- line1 :: !Int,- col1 :: !Int,- line2 :: !Int,- col2 :: !Int- }- deriving (Eq, Ord, Typeable, Data)---- | Construct a location spanning two locations; assumes the locations--- are correctly ordered.-spanLocs :: Loc -> Loc -> Loc-spanLocs loc1 loc2- | isBogus loc2 = loc1- | isBogus loc1 = loc2- | otherwise =- Loc (file loc1) (line1 loc1) (col1 loc1) (line2 loc2) (col2 loc2)---- | Get a single-point location from the start of a span-startOfLoc :: Loc -> Loc-startOfLoc loc = Loc (file loc) (line1 loc) (col1 loc) (line1 loc) (col1 loc)---- | Get a single-point location from the end of a span-endOfLoc :: Loc -> Loc-endOfLoc loc = Loc (file loc) (line2 loc) (col2 loc) (line2 loc) (col2 loc)---- | Extract a 'Parsec' source position-toSourcePos :: Loc -> SourcePos-toSourcePos loc = newPos (file loc) (line1 loc) (col1 loc)---- | Create from a 'Parsec' source position-fromSourcePos :: SourcePos -> Loc-fromSourcePos pos- = Loc (sourceName pos) (sourceLine pos) (sourceColumn pos)- (sourceLine pos) (sourceColumn pos)---- | Create a span from two 'Parsec' source positions-fromSourcePosSpan :: SourcePos -> SourcePos -> Loc-fromSourcePosSpan pos1 pos2- = Loc (sourceName pos1) (sourceLine pos1) (sourceColumn pos1)- (sourceLine pos2) (sourceColumn pos2)--fromTHLoc :: TH.Loc -> Loc-fromTHLoc loc = Loc (TH.loc_filename loc)- (fst (TH.loc_start loc))- (snd (TH.loc_start loc))- (fst (TH.loc_end loc))- (snd (TH.loc_end loc))---- | The initial location for a named source file-initial :: String -> Loc-initial = fromSourcePos . initialPos---- | The bogus location.--- (Avoids need for @Maybe Loc@ and lifting)-bogus :: Loc-bogus = mkBogus "<bogus>"---- | A named bogus location; useful to provide default locations--- for generated code without losing real locations.-mkBogus :: String -> Loc-mkBogus s = Loc s (-1) (-1) (-1) (-1)---- | Is the location bogus?-isBogus :: Loc -> Bool-isBogus (Loc _ (-1) _ _ _) = True-isBogus _ = False---- | A value with a location attached-{--data Located a = L {- locatedLoc :: !Loc,- locatedVal :: !a- }- deriving (Eq, Ord, Typeable, Data)--mkBogL :: String -> a -> Located a-mkBogL = L . mkBogus--bogL :: a -> Located a-bogL = mkBogL "<bogus>"--instance Show a => Show (Located a) where- showsPrec p = showsPrec p . locatedVal--instance Viewable (Located a) where- type View (Located a) = a- view = locatedVal--}---- | Class for types that carry source locations-class Locatable a where- getLoc :: a -> Loc---- | Class for types that can have their source locations updated-class Relocatable a where- setLoc :: a -> Loc -> a--{--instance Locatable (Located a) where- getLoc (L loc _) = loc--instance Relocatable (Located a) where- setLoc (L _ a) loc = L loc a--}--instance Locatable Loc where- getLoc = id--instance Relocatable Loc where- setLoc a b- | isBogus b = a- | otherwise = b--instance Locatable a => Locatable (Maybe a) where- getLoc Nothing = bogus- getLoc (Just a) = getLoc a--instance Relocatable a => Relocatable (Maybe a) where- setLoc Nothing _ = Nothing- setLoc (Just a) l = l `seq` a `seq` Just (setLoc a l)--instance Locatable a => Locatable [a] where- getLoc = foldr spanLocs bogus . map getLoc--instance (Locatable a, Locatable b) => Locatable (Either a b) where- getLoc (Left x) = getLoc x- getLoc (Right x) = getLoc x--instance (Relocatable a, Relocatable b) => Relocatable (Either a b) where- setLoc (Left x) l = Left (setLoc x l)- setLoc (Right x) l = Right (setLoc x l)--instance (Locatable a, Locatable b) => Locatable (a, b) where- getLoc (x, y) = getLoc x `spanLocs` getLoc y--instance (Locatable a, Locatable b, Locatable c) =>- Locatable (a, b, c) where- getLoc (x, y, z) = getLoc x `spanLocs` getLoc y `spanLocs` getLoc z--instance (Locatable a, Locatable b, Locatable c, Locatable d) =>- Locatable (a, b, c, d) where- getLoc (x, y, z, v) = getLoc x `spanLocs` getLoc y `spanLocs` getLoc z- `spanLocs` getLoc v--instance (Locatable a, Locatable b, Locatable c, Locatable d, Locatable e) =>- Locatable (a, b, c, d, e) where- getLoc (x, y, z, v, w) = getLoc x `spanLocs` getLoc y `spanLocs` getLoc z- `spanLocs` getLoc v `spanLocs` getLoc w--instance Relocatable b => Relocatable (a -> b) where- setLoc f loc x = setLoc (f x) loc---- | Copy the source location from the second operand to the first-(<<@) :: (Relocatable a, Locatable b) => a -> b -> a-a <<@ b = setLoc a (getLoc b)---- | Bogosify all source locations (as far as SYB can find them)-scrub :: Data a => a -> a-scrub a = everywhere (mkT bogosify) a where- bogosify :: Loc -> Loc- bogosify = const bogus--instance Show Loc where- showsPrec _ loc- | isBogus loc = showString (showFile (file loc))- | otherwise =- showString (showFile (file loc)) . showString " (" .- showCoords . showString ")"- where- showCoords =- if line1 loc == line2 loc then- showString "line " . shows (line1 loc) . showString ", " .- if col1 loc + 1 >= col2 loc then- showString "column " . shows (col1 loc)- else- showString "columns " . shows (col1 loc) .- showString "-" . shows (col2 loc)- else- showString "line " . shows (line1 loc) .- showString ", col. " . shows (col1 loc) .- showString " to line " . shows (line2 loc) .- showString ", col. " . shows (col2 loc)- showFile "-" = "<stdin>"- showFile s =- let shown = show s- in if shown == '"' : s ++ "\""- then shown- else s-
src/Main.hs view
@@ -1,37 +1,40 @@ -- | The main driver program, which performs all manner of unpleasant -- tasks to tie everything together-{-# LANGUAGE CPP #-} module Main (- main+ main,+ -- * For interactive exploration from GHCi+ makeRS0, check, ) where import Util-import Ppr (Doc, Ppr(..), (<+>), (<>), text, char, hang,- ($$), nest, printDoc, hPrintDoc)-import qualified Ppr-import Parser (parseFile, REPLCommand(..), parseCommand)-import Prec (precOp)+import Util.MonadRef+import Util.UndoIO+import Syntax.ImplicitThreading+import Syntax.Ppr (Doc, Ppr(..), (<+>), (<>), text, char, hang,+ printDoc, hPrintDoc)+import qualified Syntax.Ppr as Ppr+import Syntax.Parser (parseFile, REPLCommand(..), parseCommand)+import Syntax.Prec (precOp) import Paths (findAlmsLib, findAlmsLibRel, versionString, shortenPath)-import Printing (addTyNameContext)-import Rename (RenameState, runRenamingM, renameDecls, renameProg,- getRenamingInfo, RenamingInfo(..))-import Statics (tcProg, tcDecls, S, runTC, runTCNew, Module(..),- getExnParam, tyConToDec, getVarInfo, getTypeInfo,- getConInfo)-import Coercion (translate, translateDecls, TEnv, tenv0)+import Meta.Quasi+import Statics import Value (VExn(..), vppr) import Dynamics (eval, addDecls, E, NewValues) import Basis (primBasis, srcBasis) import BasisUtils (basis2venv, basis2tenv, basis2renv)-import Syntax (Prog, Decl, TyDec, BIdent(..), prog2decls,+import qualified AST+import AST (Prog, Decl, SigItem, prog2decls, Ident, Raw, Renamed) import Env (empty, (=..=))-import Loc (isBogus, initial, bogus)-import qualified ErrorMessage as EM+import Error import qualified Message.AST as Msg+import Type.Ppr (TyConInfo(..)) +import Prelude () import Data.Char (isSpace)-import System.Exit (exitFailure)+import Data.List (nub)+import Data.IORef (IORef)+import System.Exit (exitFailure, exitSuccess, ExitCode) import System.Environment (getArgs, getProgName, withProgName, withArgs) import System.IO.Error (ioeGetErrorString, isUserError) import IO (hPutStrLn, hFlush, stdout, stderr)@@ -42,7 +45,6 @@ #endif data Option = Don'tExecute- | Don'tCoerce | NoBasis | Verbose | Quiet@@ -50,23 +52,29 @@ | NoLineEdit deriving Eq +data ReplState = RS {+ rsStatics :: StaticsState IORef,+ rsDynamics :: E+}++instance Show ReplState where showsPrec = showsPrec <$.> rsStatics+ -- | The main procedure main :: IO () main = do args <- getArgs processArgs [] args $ \opts mmsrc filename -> do- (primBasis', r0) <- basis2renv primBasis- g0 <- basis2tenv primBasis'- e0 <- basis2venv primBasis'+ st0 <- makeRS0 case mmsrc of Nothing | Quiet `notElem` opts -> hPutStrLn stderr versionString _ -> return ()- let st0 = RS r0 g0 tenv0 e0- st1 <- if NoBasis `elem` opts- then return st0- else findAlmsLib srcBasis >>= tryLoadFile st0 srcBasis+ st1 <- (if NoBasis `elem` opts+ then return st0+ else findAlmsLib srcBasis >>= tryLoadFile st0 srcBasis)+ `handleExns` (st0, exitFailure) st2 <- foldM (\st n -> findAlmsLibRel n "." >>= tryLoadFile st n) st1 (reverse [ name | LoadFile name <- opts ])+ `handleExns` (st1, exitFailure) maybe interactive (batch filename) mmsrc (`elem` opts) st2 `handleExns` (st2, exitFailure) @@ -83,112 +91,102 @@ name' <- shortenPath name loadString st name' src +makeRS0 :: IO ReplState+makeRS0 = do+ (primBasis', r0) <- basis2renv primBasis+ g0 <- basis2tenv (staticsState0 r0) primBasis'+ e0 <- basis2venv primBasis'+ return (RS g0 e0)++-- For trying things from GHCi+check :: ReplState -> String -> IO ReplState+check rs = loadString rs "<check>"+ loadString :: ReplState -> String -> String -> IO ReplState loadString st name src = do case parseFile name src of Left e -> Exn.throwIO e- Right ast0 -> do- (st1, ast1) <- renaming (st, prog2decls (ast0 :: Prog Raw))- (st2, _, ast2) <- statics False (st1, ast1)- (st3, ast3) <- translation (st2, ast2)- (st4, _) <- dynamics (st3, ast3)- return st4+ Right ast -> do+ ast1 <- runAlmsErrorIO (mapM threadDecl (prog2decls ast))+ (st2, _, ast2) <- runAlmsErrorIO (statics (st, ast1))+ (st3, _) <- dynamics (st2, ast2)+ return st3 batch :: String -> IO String -> (Option -> Bool) -> ReplState -> IO ()-batch filename msrc opt st0 = do+batch filename msrc opt st = do src <- msrc case parseFile filename src of Left e -> Exn.throwIO e- Right ast -> rename ast where- rename :: Prog Raw -> IO ()- check :: Prog Renamed -> IO ()- coerce :: Prog Renamed -> IO ()- execute :: Prog Renamed -> IO ()-- rename ast0 = do- (ast1, _) <- runRenamingM True (initial filename)- (rsRenaming st0) (renameProg ast0)- check ast1+ Right ast -> thread ast where+ thread :: Prog Raw -> IO ()+ typecheck :: Prog Raw -> IO ()+ execute :: Prog Renamed -> IO () - check ast0 = do- ((t, ast1), _) <- runTC (rsStatics st0) (tcProg ast0)+ thread ast0 = do+ ast1 <- runAlmsErrorIO (threadProg ast0) when (opt Verbose) $- mumble "TYPE" t- coerce ast1+ mumble "THREADING" ast1+ typecheck ast1 - coerce ast1 =- if opt Don'tCoerce- then execute ast1- else do- let ast2 = translate (rsTranslation st0) ast1- when (opt Verbose) $- mumble "TRANSLATION" ast2- execute ast2+ typecheck ast1 = do+ (ast2, mt) <- runAlmsErrorIO (typeCheckProg (rsStatics st) ast1)+ when (opt Verbose) $+ mumble "TYPE" mt+ execute ast2 execute ast2 = unless (opt Don'tExecute) $ do- v <- eval (rsDynamics st0) ast2+ v <- eval (rsDynamics st) ast2 when (opt Verbose) $ mumble "RESULT" v -data ReplState = RS {- rsRenaming :: RenameState,- rsStatics :: S,- rsTranslation :: TEnv,- rsDynamics :: E-}--renaming :: (ReplState, [Decl Raw]) -> IO (ReplState, [Decl Renamed])-statics :: Bool -> (ReplState, [Decl Renamed]) ->- IO (ReplState, Module, [Decl Renamed])-translation :: (ReplState, [Decl Renamed]) -> IO (ReplState, [Decl Renamed])+statics :: (MonadRef IORef m, MonadAlmsError m) ⇒+ (ReplState, [Decl Raw]) ->+ m (ReplState, [SigItem Renamed], [Decl Renamed]) dynamics :: (ReplState, [Decl Renamed]) -> IO (ReplState, NewValues) -renaming (st, ast) = do- (ast', r') <- runRenamingM True (initial "-")- (rsRenaming st) (renameDecls ast)- return (st { rsRenaming = r' }, ast')--statics _ (rs, ast) = do- (ast', new, s') <- runTCNew (rsStatics rs) (tcDecls ast)- return (rs { rsStatics = s' }, new, ast')--translation (rs, ast) = do- let (menv', ast') = translateDecls (rsTranslation rs) ast- return (rs { rsTranslation = menv' }, ast')+statics (rs, ast) = do+ (ast', sig, s') <- typeCheckDecls (rsStatics rs) ast+ return (rs { rsStatics = s' }, sig, ast') dynamics (rs, ast) = do (e', new) <- addDecls (rsDynamics rs) ast return (rs { rsDynamics = e' }, new) carp :: String -> IO ()-carp msg = do+carp message = do prog <- getProgName- hPutStrLn stderr (prog ++ ": " ++ msg)+ hPutStrLn stderr (prog ++ ": " ++ message) handleExns :: IO a -> (ReplState, IO a) -> IO a handleExns body (st, handler) = body `Exn.catches`- [ Exn.Handler $ \e@(VExn { }) -> do+ [ Exn.Handler $ \(e ∷ ExitCode) -> Exn.throwIO e,+ Exn.Handler $ \e@(VExn { }) -> do prog <- getProgName- continue $ EM.AlmsException- (EM.OtherError ("Uncaught exception"))- bogus- (Msg.Table [- ("in program:", Msg.Exact prog),- ("exception:", Msg.Printable (-1) (vppr e))- ]),+ continue1 $+ AlmsError+ (OtherError ("Uncaught exception"))+ bogus+ (Msg.Table [+ ("in program:", Msg.Exact prog),+ ("exception:", Msg.Printable (-1) (vppr e))+ ]),+ Exn.Handler continue1, Exn.Handler continue, Exn.Handler $ \err ->- continue $ EM.AlmsException EM.DynamicsPhase bogus $+ continue1 $ AlmsError DynamicsPhase bogus $ Msg.Flow [Msg.Words (errorString err)], Exn.Handler $ \(Exn.SomeException err) ->- continue $ EM.AlmsException EM.DynamicsPhase bogus $+ continue1 $ AlmsError DynamicsPhase bogus $ Msg.Flow [Msg.Words (show err)] ] where- continue err = do- hPrintDoc stderr (withRS st (ppr (err :: EM.AlmsException)))+ continue1 err = continue (AlmsErrorIO [err])+ continue errs = do+ for (nub (unAlmsErrorIO errs)) $ \err -> do+ hPrintDoc stderr (withRS st (ppr err))+ hPutStrLn stderr "" handler interactive :: (Option -> Bool) -> ReplState -> IO ()@@ -201,53 +199,26 @@ case mres of Nothing -> return () Just (row', ast) -> do- st' <- doLine st ast- `handleExns` (st, return st)+ st' <- doLine st ast `handleExns` (st, return st) repl row' st'- doLine st ast = let- rename :: (ReplState, [Decl Raw]) -> IO ReplState- check :: (ReplState, [Decl Renamed]) -> IO ReplState- coerce :: Module -> (ReplState, [Decl Renamed]) -> IO ReplState- execute :: Module -> (ReplState, [Decl Renamed]) -> IO ReplState- display :: Module -> NewValues -> ReplState -> IO ReplState-- rename (st0, ast0) = do- renaming (st0, ast0) >>= check-- check stast0 = do- (st1, newDefs, ast1) <- statics True stast0- coerce newDefs (st1, ast1)-- coerce newDefs stast1- = if opt Don'tCoerce- then execute newDefs stast1- else do- stast2 <- translation stast1- when (opt Verbose) $- mumbles "TRANSLATION" (snd stast2)- execute newDefs stast2-- execute newDefs stast2- = if opt Don'tExecute- then display newDefs empty (fst stast2)- else do- (st3, newVals) <- dynamics stast2- display newDefs newVals st3-- display newDefs newVals st3- = do printResult st3 newDefs newVals- return st3-- in rename (st, ast)- getln = if opt NoLineEdit then getline else readline+ doLine st ast = do+ ast1 <- runAlmsErrorIO (threadDecls ast)+ when (opt Verbose) (mumble "THREADING" ast1)+ (st2, newDefs, ast2) <- runUndoIO (runAlmsErrorIO (statics (st, ast1)))+ (st3, newVals) <- if opt Don'tExecute+ then return (st2, empty)+ else dynamics (st2, ast2)+ printResult newDefs newVals+ return st3 say = if opt Quiet then const (return ()) else printDoc- get = if opt Quiet then const (getln "") else getln+ getln' = if opt NoLineEdit then getline else readline+ getln = if opt Quiet then const (getln' "") else getln' reader :: Int -> ReplState -> IO (Maybe (Int, [Decl Raw])) reader row st = loop 1 [] where fixup = unlines . mapTail (" " ++) . reverse loop count acc = do- mline <- get (if null acc then "#- " else "#= ")+ mline <- getln (if null acc then "#- " else "#= ") case (mline, acc) of (Nothing, []) -> return Nothing (Nothing, (_,err):_) -> do@@ -268,70 +239,59 @@ mapM_ printPrec lids addHistory line loop (count + 1) acc+ GetConstraintCmd -> do+ say (getConstraint (rsStatics st))+ addHistory line+ loop (count + 1) acc+ QuitCmd -> exitSuccess DeclsCmd ast -> do addHistory cmd return (Just (row + count, ast)) ParseError derr -> loop (count + 1) ((line, derr) : acc)- printResult :: ReplState -> Module -> NewValues -> IO ()- printResult st md00 values = say (withRS st (loop True md00)) where- loop tl md0 = case md0 of- MdNil -> Ppr.empty- MdApp md1 md2 -> loop tl md1 $$ loop tl md2- MdValue (Var l) t -> pprValue tl l t (values =..= l)- MdValue (Con u) t -> case getExnParam t of- Nothing -> Ppr.empty- Just Nothing -> text "exception"<+>ppr u- Just (Just t') -> text "exception"<+>ppr u<+>text "of"<+>ppr t'- MdTycon _ tc ->- text "type" <+>- Ppr.askTyNames (\tn -> ppr (tyConToDec tn tc :: TyDec Renamed))- MdModule u md1 -> Ppr.enterTyNames u $- text "module" <+> ppr u <+> char ':' <+> text "sig"- $$ nest 2 (loop False md1)- $$ text "end"- MdSig u md1 ->- text "module type" <+> ppr u <+> char '=' <+> text "sig"- $$ nest 2 (loop False md1)- $$ text "end"- pprValue tl x t mv =- addHang '=' (if tl then fmap ppr mv else Nothing) $- addHang ':' (Just (ppr t)) $- (if tl then ppr x else text "val" <+> ppr x)+ printResult :: [SigItem Renamed] -> NewValues -> IO ()+ printResult types values = mapM_ (say . eachItem) types+ where+ eachItem sigitem = case sigitem of+ [sgQ| val $vid:n : $t |]+ → addHang '=' (ppr <$> values =..= n) $+ addHang ':' (Just (ppr t)) $+ ppr n+ _ → ppr sigitem addHang c m d = case m of Nothing -> d Just t -> hang (d <+> char c) 2 t printInfo :: ReplState -> Ident Raw -> IO ()-printInfo st ident = case getRenamingInfo ident (rsRenaming st) of+printInfo st ident = case getRenamingInfo ident s of [] -> putStrLn $ "Not bound: ‘" ++ show ident ++ "’" ris -> mapM_ each ris where each (SigAt loc x') =- mention "module type" (ppr x') Ppr.empty loc+ mention "module type" (ppr x') mempty loc each (ModuleAt loc x') =- mention "module" (ppr x') Ppr.empty loc+ mention "module" (ppr x') mempty loc each (VariableAt loc x') = case getVarInfo x' s of- Nothing -> mention "val" (ppr x') Ppr.empty loc+ Nothing -> mention "val" (ppr x') mempty loc Just t -> mention "val" (ppr x') (char ':' <+> ppr t) loc each (TyconAt loc x') = case getTypeInfo x' s of- Nothing -> mention "type" (ppr x') Ppr.empty loc- Just tc -> mention "type" Ppr.empty (ppr tc) loc+ Nothing -> mention "type" (ppr x') mempty loc+ Just tc -> mention "type" mempty (ppr (TyConInfo tc)) loc each (DataconAt loc x') = case getConInfo x' s of- Nothing -> mention "val" (ppr x') Ppr.empty loc- Just (Left mt) ->+ Nothing -> mention "val" (ppr x') mempty loc+ Just (Left tc) ->+ mention "type" mempty (ppr (TyConInfo tc)) loc+ Just (Right mt) -> mention "type" (text "exn") (Ppr.sep [ text "= ...", char '|' <+> ppr x' <+> case mt of- Nothing -> Ppr.empty+ Nothing -> mempty Just t -> text "of" <+> ppr t ]) loc- Just (Right tc) ->- mention "type" Ppr.empty (ppr tc) loc -- s = rsStatics st --@@ -347,7 +307,7 @@ -- Add the ReplState to the pretty-printing context. withRS :: ReplState -> Doc -> Doc-withRS rs = addTyNameContext (rsRenaming rs) (rsStatics rs)+withRS = addTyNameContext . rsStatics printPrec :: String -> IO () printPrec oper = printDoc $@@ -358,9 +318,6 @@ mumble :: Ppr a => String -> a -> IO () mumble s a = printDoc $ hang (text s <> char ':') 2 (ppr a) -mumbles :: Ppr a => String -> [a] -> IO ()-mumbles s as = printDoc $ hang (text s <> char ':') 2 (Ppr.vcat (map ppr as))- errorString :: IOError -> String errorString e | isUserError e = ioeGetErrorString e | otherwise = show e@@ -380,7 +337,6 @@ = loop (LoadFile name:opts) r loop opts ("-b":r) = loop (NoBasis:opts) r loop opts ("-x":r) = loop (Don'tExecute:opts) r- loop opts ("-c":r) = loop (Don'tCoerce:opts) r loop opts ("-v":r) = loop (Verbose:opts) r loop opts ("-q":r) = loop (Quiet:opts) r loop opts ("-e":r) = loop (NoLineEdit:opts) r@@ -405,9 +361,8 @@ hPutStrLn stderr "" hPutStrLn stderr "Debugging options:" hPutStrLn stderr " -b Don't load libbasis.alms"- hPutStrLn stderr " -c Don't add contracts" hPutStrLn stderr " -x Don't execute"- hPutStrLn stderr " -v Verbose (show translation, results, types)"+ hPutStrLn stderr " -v Verbose (show results, types)" exitFailure initialize :: IO ()
src/Makefile view
@@ -2,33 +2,60 @@ ## preferred way to build, but sometimes this is convenient. GHC = ghc+GHCI = ghci EXE = alms EXAMPLES = ../examples SRC = $(HS_SRC) $(HSBOOT_SRC)-HS_SRC = *.hs Basis/*.hs Basis/Channel/*.hs Syntax/*.hs \- Message/*.hs Meta/*.hs-HSBOOT_SRC = Syntax/*.hs-boot+HS_SRC = *.hs \+ Alt/*.hs \+ AST/*.hs \+ Basis/*.hs \+ Basis/Channel/*.hs \+ Data/*.hs \+ Message/*.hs \+ Meta/*.hs \+ Statics/*.hs \+ Syntax/*.hs \+ Type/*.hs \+ Util/*.hs+HSBOOT_SRC = AST/*.hs-boot Statics/*.hs-boot -HCOPTS = -W -Wall -O0 $(EDITING) $(PARSEC) $(NOWARN) $(IMPARR)+HCOPTS = -W -Wall -O0 $(EDITING) $(PARSEC) $(HIOPTS)+HIOPTS = $(NOWARN) $(IMPARR) $(UNICODE) $(LANGUAGE) EDITING = -DUSE_READLINE=System.Console.Editline.Readline PARSEC = -DPARSEC_VERSION=3 # IMPARR = -DANNOTATION_PRINTING_RULE=Rule0 NOWARN = -fno-warn-unused-do-bind -fno-warn-orphans+UNICODE = -DUNICODE+LANGUAGE= `sed 's/^/-X/' extensions.txt` $(EXE) $(EXE)-%: $(SRC) $(GHC) -o $@ --make Main.hs $(HCOPTS) +%.hi: $(HS_SRC) $(HSBOOT_SRC)+ $(GHC) --make `echo "$*" | sed 's@\.@/@g'`.hs $(HCOPTS)++%.i:+ $(GHCI) \*`echo "$*" | sed 's@\.@/@g'` $(HIOPTS)+ $(EXE)-%: GHC = ghc-$* $(EXE)-6.8.%: EDITING = -DUSE_READLINE=System.Console.Readline $(EXE)-6.%: PARSEC = -DPARSEC_VERSION=2 +not-compiled:+ @find . -name \*.hs | sed 's@^\./@@' | while read hs; do \+ hi=`echo $$hs | sed 's/hs$$/hi/'`; \+ test -f $$hi || echo $$hs; \+ done+ clean: $(RM) $(HS_SRC:.hs=.hi) $(HS_SRC:.hs=.o) $(RM) $(HSBOOT_SRC:.hs-boot=.hi-boot) $(HSBOOT_SRC:.hs-boot=.o-boot) $(RM) $(EXE) $(EXE)-6.* wc.%:- find .. -name \*."$*" | xargs wc -l+ find .. -name \*."$*" | xargs wc -l | sed 's/$$/ lines/'+ @find .. -name \*."$*" | wc -l | sed 's/$$/ total .$* files/' test tests: $(EXE) @$(EXAMPLES)/run-tests.sh ./$(EXE) $(EXAMPLES)
src/Message/AST.hs view
@@ -1,14 +1,11 @@-{-# LANGUAGE- EmptyDataDecls,- GADTs- #-}+{-# LANGUAGE GADTs #-} module Message.AST ( Message(..), H, V, StackStyle(..), wordsMsg, quoteMsg, pprMsg, showMsg, emptyMsg, ) where -import PprClass+import Syntax.PprClass -- | Simple message markup data Message d where@@ -24,8 +21,15 @@ Showable :: Show a => a -> Message d AntiMsg :: String -> String -> Message d -data H-data V+-- | 'H' and 'V' need constructors or pattern matching on+-- @'Message' 'H'@ gives non-exhaustiveness warnings for unreachable+-- cases.+data H = H+data V = V++-- | Don't warn about the fact that 'H' and 'V' aren't used.+_don'tWarnAbout :: (H, V)+_don'tWarnAbout = (H, V) -- | Types of lists data StackStyle
src/Message/Parser.hs view
@@ -2,13 +2,14 @@ parseMessageQ, tokensT, messageP, ) where -import Loc+import Data.Loc import Message.AST import Util+import Alt.Parsec +import Prelude () import Data.Char import Language.Haskell.TH-import Text.ParserCombinators.Parsec -- | Given the string representation of a message, parse it, -- using the Template Haskell monad to get an initial source
src/Message/Quasi.hs view
@@ -1,11 +1,4 @@-{-# LANGUAGE- FlexibleInstances,- GADTs,- GeneralizedNewtypeDeriving,- MultiParamTypeClasses,- PatternGuards,- TemplateHaskell- #-}+{-# LANGUAGE GADTs #-} module Message.Quasi ( msg, Message(), H, V, ) where@@ -13,9 +6,10 @@ import Message.AST import Message.Parser import Meta.THHelpers-import PprClass-import Util+import Syntax.PprClass+import Util hiding (lift) +import Prelude () import qualified Data.Map as M import Language.Haskell.TH import Language.Haskell.TH.Quote (QuasiQuoter(..))@@ -69,7 +63,7 @@ where each (s,msg') = [| ($(lift s), $(loop msg')) |] Indent msg' -> [| Indent $(loop msg') |] Printable d a- -> [| Exact $(lift (show (PprClass.pprDepth d a))) |]+ -> [| Exact $(lift (show (pprDepth d a))) |] Showable a -> [| Exact $(lift (show a)) |] AntiMsg tag name -> case tag of "words" -> [| Words $var |]
src/Message/Render.hs view
@@ -1,14 +1,9 @@-{-# LANGUAGE- FlexibleInstances,- GADTs,- ParallelListComp,- QuasiQuotes- #-}+{-# LANGUAGE GADTs #-} module Message.Render (- module PprClass+ module Syntax.PprClass ) where -import PprClass+import Syntax.PprClass import Message.AST -- | Context for message rendering@@ -21,20 +16,33 @@ } rc0 :: RenderContext-rc0 = RenderContext (-1) 0 empty empty+rc0 = RenderContext (-1) 0 mempty mempty getQuotes :: RenderContext -> (String, String) getQuotes cxt = if even (rcQtLevel cxt)+#ifdef UNICODE then ("‘", "’") else ("“", "”")+#else+ then ("'", "'")+ else ("\"", "\"")+#endif +bullet :: Char+#if UNICODE+bullet = '•'+#else+bullet = '-'+#endif++ incQuotes :: RenderContext -> RenderContext incQuotes cxt = cxt { rcQtLevel = rcQtLevel cxt + 1 } clearLeft, clearRight :: RenderContext -> RenderContext-clearLeft cxt = cxt { rcLeft = empty }-clearRight cxt = cxt { rcRight = empty }+clearLeft cxt = cxt { rcLeft = mempty }+clearRight cxt = cxt { rcRight = mempty } addQuotes :: RenderContext -> Doc -> Doc addQuotes cxt doc = rcLeft cxt <> doc <> rcRight cxt@@ -46,7 +54,7 @@ renderMessageH cxt msg0 = case msg0 of Words s -> renderMessageH cxt (Flow (map Exact (words s))) Exact s -> [addQuotes cxt (text s)]- Flow [] -> [addQuotes cxt empty]+ Flow [] -> [addQuotes cxt mempty] Flow [msg'] -> renderMessageH cxt msg' Flow (m:ms) -> renderMessageH (clearRight cxt) m ++ concatMap (renderMessageH cxt') (init ms) ++@@ -84,7 +92,7 @@ | i <- [ 1 .. ] ] where len = length msgs dent = length (show len)- Bulleted -> vcat [ text " •" <+> nest 3 (renderMessage cxt msg')+ Bulleted -> vcat [ space <> char bullet <+> nest 3 (renderMessage cxt msg') | msg' <- msgs ] Separated -> vcat (punctuate (char '\n') (map (renderMessage cxt) msgs))@@ -104,3 +112,5 @@ instance Ppr (Message d) where ppr = renderMessage rc0 instance Show (Message d) where showsPrec = showFromPpr +instance Eq (Message d) where+ msg1 == msg2 = show msg1 == show msg2
src/Meta/DeriveNotable.hs view
@@ -1,13 +1,9 @@-{-# LANGUAGE- FlexibleInstances,- MultiParamTypeClasses,- TemplateHaskell,- TypeFamilies #-}+{-# LANGUAGE TypeFamilies #-} module Meta.DeriveNotable ( deriveNotable ) where -import Syntax.Notable+import AST.Notable import Meta.THHelpers import Data.Char (toLower)
src/Meta/Quasi.hs view
@@ -1,20 +1,12 @@-{-# LANGUAGE- FlexibleContexts,- FlexibleInstances,- QuasiQuotes,- RankNTypes,- ScopedTypeVariables,- TemplateHaskell,- TypeSynonymInstances #-} module Meta.Quasi (- pa, ty, ex, dc, me,- prQ, tdQ, atQ, caQ, bnQ, qeQ, tpQ, seQ, sgQ,+ pa, ty, ex, dc,+ prQ, tdQ, atQ, caQ, bnQ, fdQ, meQ, qeQ, tpQ, seQ, sgQ, ) where import Meta.QuoteData import Meta.THHelpers-import Parser-import Syntax+import Syntax.Parser+import AST import Util import Data.Generics@@ -22,16 +14,31 @@ import Language.Haskell.TH.Quote (QuasiQuoter(..)) toAstQ :: (Data a, ToSyntax b) => a -> TH.Q b-toAstQ x = whichS' (toExpQ x) (toPatQ x)+toAstQ x = whichS' (toExpQ False x) (toPatQ False x) -toExpQ :: Data a => a -> TH.ExpQ-toExpQ = dataToExpQ antiExp moduleQuals+toAstQ' :: (Data a, ToSyntax b) => a -> TH.Q b+toAstQ' x = whichS' (toExpQ True x) (toPatQ True x) -toPatQ :: Data a => a -> TH.PatQ-toPatQ = dataToPatQ antiPat moduleQuals+toExpQ :: Data a => Bool -> a -> TH.ExpQ+toExpQ False x = dataToExpQ antiExp moduleQuals x+toExpQ True x = do+ TH.AppE _ stx <- dataToExpQ antiExp moduleQuals x+ return stx +toPatQ :: Data a => Bool -> a -> TH.PatQ+toPatQ False x = dataToPatQ antiPat moduleQuals x+toPatQ True x = do+ TH.ConP _ [_, stx] <- dataToPatQ antiPat moduleQuals x+ return stx+ moduleQuals :: [(String, String)]-moduleQuals = [ ("Syntax.Type", "Syntax") ]+moduleQuals = [ ("AST.Type", "AST"),+ ("AST.Kind", "AST"),+ ("AST.Patt", "AST"),+ ("AST.Ident", "AST"),+ ("AST.Expr", "AST"),+ ("AST.Decl", "AST"),+ ("AST.Notable", "AST") ] antiExp :: Data a => a -> Maybe TH.ExpQ antiExp = antiGen@@ -70,19 +77,20 @@ --- Quasiquoters --- -pa, ty, ex, dc, me, prQ, tdQ, atQ, caQ, bnQ, qeQ, tpQ, seQ, sgQ+pa, ty, ex, dc, meQ, prQ, tdQ, atQ, caQ, bnQ, fdQ, qeQ, tpQ, seQ, sgQ :: QuasiQuoter ex = mkQuasi "ex" parseExpr dc = mkQuasi "dc" parseDecl-ty = mkQuasi "ty" parseType-me = mkQuasi "me" parseModExp+ty = mkQuasi "ty" (withDots True parseType) pa = mkQuasi "pa" parsePatt+meQ = mkQuasi "meQ" parseModExp prQ = mkQuasi "prQ" parseProg tdQ = mkQuasi "tdQ" parseTyDec atQ = mkQuasi "atQ" parseAbsTy caQ = mkQuasi "caQ" parseCaseAlt bnQ = mkQuasi "bnQ" parseBinding+fdQ = mkQuasi "fdQ" parseField qeQ = mkQuasi "qeQ" parseQExp tpQ = mkQuasi "tpQ" parseTyPat seQ = mkQuasi "seQ" parseSigExp@@ -94,21 +102,31 @@ Data (note Renamed), Data (stx Renamed), LocAst (N (note Renamed) (stx Renamed))) => String ->- (forall i. Id i => P (N (note i) (stx i))) ->+ (forall i. Tag i => P (N (note i) (stx i))) -> QuasiQuoter mkQuasi name parser = (newQuasi name) { quoteExp = qast, quotePat = qast } where qast s = join $- parseQuasi s $ \iflag lflag ->+ parseQuasi s $ \filename iflag lflag -> case iflag of- Just '+' -> do+ "+'" -> do stx <- parser :: P (N (note Renamed) (stx Renamed))- convert lflag stx+ convert' filename stx+ "+" -> do+ stx <- parser :: P (N (note Renamed) (stx Renamed))+ convert filename lflag stx+ "'" -> do+ stx <- parser :: P (N (note Raw) (stx Raw))+ convert' filename stx _ -> do stx <- parser :: P (N (note Raw) (stx Raw))- convert lflag stx- convert flag stx = return $ maybe toAstQ toLocAstQ flag (scrub stx)+ convert filename lflag stx+ convert filename flag stx =+ return . maybe toAstQ toLocAstQ flag $+ scrubWhen (\loc -> file loc == filename) stx+ convert' filename stx = do+ return . toAstQ' $ scrubWhen (\loc -> file loc == filename) stx deriveLocAsts 'toAstQ syntaxTable
src/Meta/QuoteData.hs view
@@ -1,11 +1,6 @@ --- --- My verson of Language.Haskell.TH.Quote ----{-# LANGUAGE- RankNTypes,- RelaxedPolyRec,- PatternGuards,- ScopedTypeVariables #-} module Meta.QuoteData (dataToExpQ, dataToPatQ) where import Language.Haskell.TH
src/Meta/THHelpers.hs view
@@ -1,9 +1,3 @@-{-# LANGUAGE- CPP,- DeriveDataTypeable,- RankNTypes,- TemplateHaskell,- TypeSynonymInstances #-} module Meta.THHelpers ( -- * Simplified TH quasiquote th,@@ -15,14 +9,15 @@ buildContext, typeOfTyVarBndr, conName, ) where -import Lexer (lid, uid)+import Syntax.Lexer (lid, uid) import Util import Compat (newQuasi)+import Alt.Parsec +import Prelude () import Data.Generics (Typeable, Data, everything, mkQ) import Language.Haskell.TH import Language.Haskell.TH.Quote-import Text.ParserCombinators.Parsec import Text.ParserCombinators.Parsec.Language (haskell) import Text.ParserCombinators.Parsec.Token @@ -93,7 +88,7 @@ -- | Qualify a string literal with qstringL :: String -> Lit-qstringL s = stringL ("Syntax." ++ s)+qstringL s = stringL ("AST." ++ s) -- | Does the given AST contain an antiquote named '_'? If so, we -- create an implicit parameter and fill it in there.
− src/PDNF.hs
@@ -1,242 +0,0 @@-{-# LANGUAGE DeriveDataTypeable #-}--- | Positive Disjunctive Normal Form-module PDNF (- -- * Abstract representation- PDNF,- -- * Construction- variable, conjunct, disjunct, disjoinClause, conjoinClause,- -- * Queries- isUnsat, isValid, support,- -- ** Assignments- Assignment, satisfies, findUnsat,- -- * Resolution and substitution- assume, replace, mapVars, mapVarsM, mapReplace, mapReplaceM,- -- * To and from lists- fromLists, fromListsUnsafe, toLists,- -- * Tests- tests-) where--import Syntax.POClass-import Util--import Data.Generics (Typeable, Data)-import Data.List (intersperse, nub, sort)-import qualified Data.Set as S-import qualified Test.QuickCheck as QC---- | The type of a Positive DNF over some type 'a'-newtype PDNF a = PDNF { unPDNF :: [S.Set a] }- deriving (Typeable, Data)---- | Is the formula unsatisfiable?--- O(1)-isUnsat :: PDNF a -> Bool-isUnsat = null . unPDNF---- | Is the formula valid?-isValid :: Eq a => PDNF a -> Bool-isValid = (== [S.empty]) . unPDNF---- | To update the formula to reflect an assumption about the--- assignment for a particular variable.-assume :: Ord a => Bool -> a -> PDNF a -> PDNF a-assume True v formula = PDNF . normalize' $- map (S.delete v) (unPDNF formula)-assume False v formula = PDNF $- filter (S.notMember v) (unPDNF formula)---- | To substitute a PDNF formula for a given variable in another--- formula.-replace :: Ord a => a -> PDNF a -> PDNF a -> PDNF a-replace v (PDNF f1) (PDNF f2) = PDNF $- normalize' $ concatMap eachClause f2- where- eachClause clause- | v `S.member` clause = conjoinClause' (S.delete v clause) f1- | otherwise = [clause]---- | To map every variable in a formula-mapVars :: (Ord a, Ord b) => (a -> b) -> PDNF a -> PDNF b-mapVars f = PDNF . normalize' . map (S.map f) . unPDNF---- | To map every variable in a formula, in an arbitrary monad-mapVarsM :: (Ord a, Ord b, Monad m) =>- (a -> m b) -> PDNF a -> m (PDNF b)-mapVarsM f = liftM fromLists . mapM (mapM f) . toLists'---- | To map every variable in a formula to a formula, possibly over--- a different type-mapReplace :: (Ord a, Ord b) =>- PDNF a -> (a -> PDNF b) -> PDNF b-mapReplace m k = bigVee [ bigWedge [ k var | var <- clause ]- | clause <- toLists' m ]---- | To map every variable in a formula to a formula, possibly over--- a different type, in an arbitrary monad-mapReplaceM :: (Ord a, Ord b, Monad m) =>- PDNF a -> (a -> m (PDNF b)) -> m (PDNF b)-mapReplaceM m k = liftM bigVee (mapM (liftM bigWedge . mapM k) (toLists' m))---- | To construct a formula of a single variable-variable :: a -> PDNF a-variable = PDNF . return . S.singleton---- | To find the support of a PDNF-support :: Ord a => PDNF a -> S.Set a-support = foldr S.union S.empty . unPDNF---- | To construct a formula of one conjuction-conjunct :: Ord a => [a] -> PDNF a-conjunct = PDNF . return . S.fromList--disjunct :: Ord a => [a] -> PDNF a-disjunct = PDNF . map S.singleton . nub--instance Ord a => PO (PDNF a) where- f1 \/ f2 = PDNF $ foldr disjoinClause' (unPDNF f1) (unPDNF f2)- f1 /\ f2 = PDNF $- normalize' [ clause1 `S.union` clause2- | clause1 <- unPDNF f1- , clause2 <- unPDNF f2 ]- PDNF ant <: PDNF con- = all (\clause -> any (`S.isSubsetOf` clause) con) ant--instance Bounded (PDNF a) where- minBound = PDNF []- maxBound = PDNF [S.empty]--instance Ord a => Eq (PDNF a) where- f1 == f2 = compare f1 f2 == EQ--instance Ord a => Ord (PDNF a) where- f1 `compare` f2 = toLists f1 `compare` toLists f2---- | To add a clause to a formula-disjoinClause :: Ord a => [a] -> PDNF a -> PDNF a-disjoinClause c' = PDNF . disjoinClause' (S.fromList c') . unPDNF---- | To distribute a clause over a formula-conjoinClause :: Ord a => [a] -> PDNF a -> PDNF a-conjoinClause c' = PDNF . conjoinClause' (S.fromList c') . unPDNF--disjoinClause' :: Ord a => S.Set a -> [S.Set a] -> [S.Set a]-disjoinClause' c' [] = [c']-disjoinClause' c' (c:cs) =- if c' `S.isSubsetOf` c- then disjoinClause' c' cs- else if c `S.isSubsetOf` c'- then c:cs- else c:disjoinClause' c' cs--conjoinClause' :: Ord a => S.Set a -> [S.Set a] -> [S.Set a]-conjoinClause' c' cs = map (S.union c') cs--normalize' :: Ord a => [S.Set a] -> [S.Set a]-normalize' = foldr disjoinClause' []---- | To construct a PDNF.-fromLists :: Ord a => [[a]] -> PDNF a-fromLists = foldr (\/) minBound . map conjunct---- | To construct a PDNF quickly, assuming that no list is a superset--- of an other list.-fromListsUnsafe :: Ord a => [[a]] -> PDNF a-fromListsUnsafe = PDNF . map S.fromList---- | To construct a canonical list of lists of variables.-toLists :: Ord a => PDNF a -> [[a]]-toLists = sort . map S.toAscList . unPDNF--toLists' :: PDNF a -> [[a]]-toLists' = map S.toList . unPDNF--instance (Eq a, Show a) => Show (PDNF a) where- showsPrec _ pdnf- | isValid pdnf = showString "#t"- | isUnsat pdnf = showString "#f"- showsPrec p (PDNF formula) =- showParen (p > 5) $- foldr (.) id $- intersperse (showString " | ")- [ foldr (.) id $- intersperse (showString " & ") $- [ showsPrec 6 lit- | lit <- S.toList clause ]- | clause <- formula ]--------- Assignments-------- | An assignment is a map from variables to booleans, represented--- as a list of variables to map to true, with all others mapped--- to false.-type Assignment a = [a]---- | Does the given assignment satisfy the PDNF?-satisfies :: Ord a => PDNF a -> Assignment a -> Bool-satisfies pdnf vs = isValid (foldr (assume True) pdnf vs)---- | Find an assignment that satisfies the first PDNF but not--- the second.-findUnsat :: Ord a => PDNF a -> PDNF a -> [Assignment a]-findUnsat (PDNF f1) (PDNF f2) =- [ S.toList clause- | clause <- f1- , not (any (`S.isSubsetOf` clause) f2) ]--------- Tests------assignFor :: Ord a => PDNF a -> QC.Gen (Assignment a)-assignFor pdnf =- genSublist (S.toList (support pdnf))- where- genSublist :: [a] -> QC.Gen [a]- genSublist lst = do- let den = length lst- num <- QC.choose (0, den `div` 2)- let each rest elt = do- pick <- QC.choose (1, den)- return $ if pick > num- then elt:rest- else rest- foldM each [] lst--instance (Ord a, QC.Arbitrary a) => QC.Arbitrary (PDNF a) where- arbitrary = fromLists `fmap` QC.arbitrary- shrink = map fromLists . QC.shrink . toLists--prop_Impl :: PDNF Int -> PDNF Int -> QC.Property-prop_Impl f1 f2 =- if f1 <: f2 then- impl f1 f2- else if f2 <: f1 then- impl f2 f1- else- QC.classify True "counterexample" $- not (null (findUnsat f1 f2))- where impl f1' f2' =- QC.classify True "implication" $- QC.forAll (assignFor (f1' \/ f2')) $ \s ->- satisfies f1' s QC.==> satisfies f2' s--prop_Disj :: PDNF Int -> PDNF Int -> Bool-prop_Disj f1 f2 = f1 <: f1 \/ f2--prop_Conj :: PDNF Int -> PDNF Int -> Bool-prop_Conj f1 f2 = f1 /\ f2 <: f1--prop_Replace :: PDNF Int -> Bool -> QC.Property-prop_Replace pdnf b =- QC.forAll (QC.elements (S.toList (support pdnf))) $ \v ->- replace v (if b then maxBound else minBound) pdnf == assume b v pdnf--tests :: IO ()-tests = do- QC.quickCheck prop_Replace- QC.quickCheck prop_Impl- QC.quickCheck prop_Disj- QC.quickCheck prop_Conj
− src/Parser.hs
@@ -1,1310 +0,0 @@-{-# LANGUAGE- PatternGuards,- ScopedTypeVariables,- TypeFamilies,- TypeSynonymInstances #-}--- | Parser-module Parser (- -- * The parsing monad- P, parse,- -- ** Errors- ParseError,- -- ** Quasiquote parsing- parseQuasi,- -- ** File and REPL command parsing- parseFile,- REPLCommand(..), parseCommand,- -- ** Parsers- parseProg, parseRepl, parseDecls, parseDecl, parseModExp,- parseTyDec, parseAbsTy, parseType, parseTyPat,- parseQExp, parseExpr, parsePatt,- parseCaseAlt, parseBinding,- parseSigExp, parseSigItem,- -- * Convenience parsers (quick and dirty)- pp, pds, pd, pme, ptd, pt, ptp, pqe, pe, px-) where--import Util-import Paths-import Prec-import Syntax-import Sigma-import Lexer-import ErrorMessage (AlmsException(..), Phase(ParserPhase))-import qualified Message.AST as Msg--import qualified Data.Map as M-import qualified Data.List as L-import qualified Language.Haskell.TH as TH-import Text.ParserCombinators.Parsec hiding (parse)-import qualified Text.ParserCombinators.Parsec.Error as PE-import System.IO.Unsafe (unsafePerformIO)--data St = St {- stSigma :: Bool,- stAnti :: Bool,- stPos :: SourcePos- }--instance TokenEnd St where- saveTokenEnd = do- pos <- getPosition- updateState $ \st -> st { stPos = pos }---- | A 'Parsec' character parser, with abstract state-type P a = CharParser St a--state0 :: St-state0 = St {- stSigma = False,- stAnti = False,- stPos = toSourcePos bogus- }---- | Run a parser, given the source file name, on a given string-parse :: P a -> SourceName -> String -> Either ParseError a-parse p = runParser p state0---- | Run a parser on the given string in quasiquote mode-parseQuasi :: String -> (Maybe Char -> Maybe TH.Name -> P a) -> TH.Q a-parseQuasi str p = do- setter <- TH.location >>! mkSetter- let parser = do- setter- iflag <- optionMaybe (char '+')- lflag <- choice [- do char '@'- choice [ char '=' >> identp_no_ws >>! Just,- char '!' >> return Nothing ],- char '!' >> return Nothing,- return (Just "_loc")- ]- p iflag (fmap TH.mkName lflag)- case runParser parser state0 { stAnti = True } "<quasi>" str of- Left e -> fail (show e)- Right a -> return a- where- mkSetter = setPosition . toSourcePos . fromTHLoc---- | REPL-level commands-data REPLCommand- = GetInfoCmd [Ident Raw]- | GetPrecCmd [String]- | DeclsCmd [Decl Raw]- | ParseError AlmsException---- | Parse a line typed into the REPL-parseCommand :: Int -> String -> String -> REPLCommand-parseCommand row line cmd =- case parseGetInfo line of- Just ids -> GetInfoCmd ids- _ -> case parseGetPrec line of- Just lids -> GetPrecCmd lids- _ -> case parseInteractive row cmd of- Right ast -> DeclsCmd ast- Left err -> ParseError (almsParseError err)---- | Given a file name and source, parse it-parseFile :: Id i => String -> String -> Either AlmsException (Prog i)-parseFile = (almsParseError +++ id) <$$> parse parseProg--almsParseError :: ParseError -> AlmsException-almsParseError e =- AlmsException ParserPhase (fromSourcePos (errorPos e)) message- where- message =- Msg.Stack Msg.Broken [- flow ";" messages,- (if null messages then id else Msg.Indent)- (Msg.Table (unlist ++ explist))- ]- unlist = case unexpects of- [] -> []- s:_ -> [("unexpected:", Msg.Words s)]- explist = case expects of- [] -> []- _ -> [("expected:", flow "," expects)]- messages = [ s | PE.Message s <- PE.errorMessages e, not$null s ]- unexpects = [ s | PE.UnExpect s <- PE.errorMessages e, not$null s ]- ++ [ s | PE.SysUnExpect s <- PE.errorMessages e, not$null s ]- expects = [ s | PE.Expect s <- PE.errorMessages e, not$null s ]- flow c = Msg.Flow . map Msg.Words . punct c . L.nub- punct _ [] = []- punct _ [s] = [s]- punct c (s:ss) = (s++c) : punct c ss--parseGetInfo :: String -> Maybe [Ident Raw]-parseGetInfo = (const Nothing ||| Just) . runParser parser state0 "-"- where- parser = finish $- sharpInfo *>- many1 (identp- <|> fmap Var <$> qlidnatp- <|> J [] . Var . Syntax.lid <$> (operator <|> semis))--parseGetPrec :: String -> Maybe [String]-parseGetPrec = (const Nothing ||| Just) . runParser parser state0 "-"- where- parser = finish $- sharpPrec *>- many1 (operator <|> semis)--parseInteractive :: Id i => Int -> String -> Either ParseError [Decl i]-parseInteractive line src = parse p "-" src where- p = do- pos <- getPosition- setPosition (pos `setSourceLine` line)- optional whiteSpace- r <- replp- eof- return r--withSigma :: Bool -> P a -> P a-withSigma = mapSigma . const--mapSigma :: (Bool -> Bool) -> P a -> P a-mapSigma f p = do- st <- getState- setState st { stSigma = f (stSigma st) }- r <- p- setState st- return r--getSigma :: P Bool-getSigma = stSigma `fmap` getState---- | Get the ending position of the last token, before trailing whitespace-getEndPosition :: P SourcePos-getEndPosition = stPos <$> getState---- | Parse something and return the span of its location-withLoc :: P a -> P (a, Loc)-withLoc p = do- before <- getPosition- a <- p- after <- getEndPosition- return (a, fromSourcePosSpan before after)--addLoc :: Relocatable a => P a -> P a-addLoc = uncurry (<<@) <$$> withLoc--class Nameable a where- (@@) :: String -> a -> a--infixr 0 @@--instance Relocatable a => Nameable (P a) where- s @@ p = addLoc p <?> s--instance Nameable r => Nameable (a -> r) where- s @@ p = \x -> s @@ p x--punit :: P ()-punit = pure ()--delimList :: P pre -> (P [a] -> P [a]) -> P sep -> P a -> P [a]-delimList before around delim each =- choice [- before >> choice [- around (each `sepBy` delim),- each >>! \x -> [x]- ],- return []- ]--chainl1last :: P a -> P (a -> a -> a) -> P a -> P a-chainl1last each sep final = start where- start = each >>= loop- loop a = option a $ do- build <- sep- choice- [ each >>= loop . build a,- final >>= return . build a ]--chainr1last :: P a -> P (a -> a -> a) -> P a -> P a-chainr1last each sep final = start where- start = do- a <- each- builder <- loop- return (builder a)- loop = option id $ do- build <- sep- choice- [ do- b <- each- builder <- loop- return (\a -> a `build` builder b),- do- b <- final- return (\a -> a `build` b) ]--foldlp :: (a -> b -> a) -> P a -> P b -> P a-foldlp make start follow = foldl make <$> start <*> many follow---- Antiquote-antip :: AntiDict -> P Anti-antip dict = antilabels . lexeme . try $ do- char '$' <?> ""- (s1, s2) <- (,) <$> option "" (try (option "" identp_no_ws <* char ':'))- <*> identp_no_ws- assertAnti- case M.lookup s1 dict of- Just _ -> return (Anti s1 s2)- Nothing -> unexpected $ "antiquote tag: `" ++ s1 ++ "'"- where- antilabels p = do- st <- getState- if (stAnti st)- then labels p [ "antiquote `" ++ key ++ "'"- | key <- M.keys dict, key /= "" ]- else p--identp_no_ws :: P String-identp_no_ws = do- c <- lower <|> char '_'- cs <- many (alphaNum <|> oneOf "_'")- return (c:cs)---- Fail if we should not recognize antiquotes-assertAnti :: P ()-assertAnti = do- st <- getState- unless (stAnti st) (unexpected "antiquote")---- | Parse an antiquote and inject into syntax-antiblep :: forall a. Antible a => P a-antiblep = antip (dictOf (undefined::a)) >>! injAnti--antioptp :: Antible a => P a -> P (Maybe a)-antioptp = antioptaroundp id--antioptaroundp :: Antible a =>- (P (Maybe a) -> P (Maybe a)) ->- P a -> P (Maybe a)-antioptaroundp wrap p = wrap present <|> pure Nothing- where present = antiblep- <|> Just <$> antiblep- <|> Just <$> p--antilist1p :: Antible a => P b -> P a -> P [a]-antilist1p sep p = antiblep- <|> sepBy1 (antiblep <|> p) sep---- Just uppercase identifiers-uidp :: Id i => P (Uid i)-uidp = Syntax.uid <$> Lexer.uid- <|> antiblep- <?> "uppercase identifier"---- Just lowercase identifiers-lidp :: Id i => P (Lid i)-lidp = Syntax.lid <$> Lexer.lid- <|> antiblep- <?> "lowercase identifier"---- Lowercase identifiers or naturals--- - tycon declarations-lidnatp :: Id i => P (Lid i)-lidnatp = Syntax.lid <$> (Lexer.lid <|> show <$> natural)- <|> operatorp- <|> Syntax.lid <$> try (parens semis)- <|> antiblep- <?> "type name"---- Just operators-operatorp :: Id i => P (Lid i)-operatorp = try (parens operator) >>! Syntax.lid- <?> "operator name"---- Add a path before something-pathp :: Id i => P ([Uid i] -> b) -> P b-pathp p = try $ do- path <- many $ try $ uidp <* dot- make <- p- return (make path)---- Qualified uppercase identifiers:--- - module names occurences--- - datacons in patterns (though path is ignored)-quidp :: Id i => P (QUid i)-quidp = pathp (uidp >>! flip J)- <|> antiblep- <?> "uppercase identifier"---- Qualified lowercase identifiers:--- - module name identifier lists-qlidp :: Id i => P (QLid i)-qlidp = pathp (lidp >>! flip J)- <|> antiblep- <?> "lowercase identifier"---- Qualified lowercase identifiers or naturals:--- - tycon occurences-qlidnatp :: Id i => P (QLid i)-qlidnatp = pathp (lidnatp >>! flip J)- <|> antiblep- <?> "type name"---- Lowercase identifiers and operators--- - variable bindings-varp :: Id i => P (Lid i)-varp = lidp <|> operatorp- <?> "variable name"---- Qualified lowercase identifers and operators--- - variable occurences--- qvarp :: Id i => P (QLid i)--- qvarp = pathp (varp >>! flip J)---- Identifier expressions-identp :: Id i => P (Ident i)-identp = antiblep- <|> pathp (flip J <$> (Var <$> varp <|> Con <$> uidp))- <?> "identifier"---- Type variables-tyvarp :: Id i => P (TyVar i)-tyvarp = char '\'' *> (antiblep <|> TV <$> lidp <*> pure Qu)- <|> char '`' *> (antiblep <|> TV <$> lidp <*> pure Qa)- <?> "type variable"--oplevelp :: Id i => Prec -> P (Lid i)-oplevelp = (<?> "operator") . liftM Syntax.lid . opP--quantp :: P Quant-quantp = Forall <$ forall- <|> Exists <$ exists- <|> antiblep- <?> "quantifier"--typep :: Id i => P (Type i)-typep = typepP precStart--typepP :: Id i => Int -> P (Type i)-typepP p = "type" @@ case () of- _ | p == precStart- -> do- tc <- tyQu <$> quantp- <|> tyMu <$ mu- tvs <- many tyvarp- dot- t <- typepP p- return (foldr tc t tvs)- <|> typepP (p + 1)- | p == precArr- -> chainr1last- (typepP (p + 1))- (choice- [ tyArr <$ arrow,- tyLol <$ lolli,- funbraces (tyFun <$> (antiblep <|> Just <$> qExpp)),- tybinopp (Right precArr) ])- (typepP precStart)- | p == precSemi- -> chainr1last (typepP (p + 1))- (tyBinOp <$> semis)- (typepP precStart)- | Just (Left _) <- fixities p- -> chainl1last (typepP (p + 1))- (tybinopp (Left p))- (typepP precStart)- | Just (Right _) <- fixities p- -> chainr1last (typepP (p + 1))- (tybinopp (Right p))- (typepP precStart)- | p == precApp -- this case ensures termination- -> tyarg >>= tyapp'- | p < precApp- -> typepP (p + 1)- | otherwise- -> typepP precStart- where- tyarg :: Id i => P [Type i]- tyarg = choice- [ (:[]) <$> tyatom,- parens $ antiblep <|> commaSep1 (typepP precStart) ]- --- tyatom :: Id i => P (Type i)- tyatom = tyVar <$> tyvarp- <|> tyApp <$> qlidnatp <*> pure []- <|> antiblep- <|> tyUn <$ qualU- <|> tyAf <$ qualA- <|> do- ops <- many1 $ addLoc $- oplevelp (Right precBang) >>! tyApp . J []- arg <- tyatom <|> parens (typepP precStart)- return (foldr (\op t -> op [t]) arg ops)- --- tyapp' :: Id i => [Type i] -> P (Type i)- tyapp' [t] = option t $ do- tc <- qlidnatp- tyapp' [tyApp tc [t]]- tyapp' ts = do- tc <- qlidnatp- tyapp' [tyApp tc ts]--tybinopp :: Id i => Prec -> P (Type i -> Type i -> Type i)-tybinopp p = try $ do- op <- oplevelp p- when (unLid op == "-") pzero- return (\t1 t2 -> tyApp (J [] op) [t1, t2])--progp :: Id i => P (Prog i)-progp = choice [- do ds <- declsp- when (null ds) pzero- e <- antioptaroundp (reserved "in" `between` punit) exprp- return (prog ds e),- antioptp exprp >>! prog []- ]--replp :: Id i => P [Decl i]-replp = choice [- try $ do- ds <- declsp- when (null ds) pzero- eof- return ds,- exprp >>! (prog2decls . prog [] . Just)- ]--declsp :: Id i => P [Decl i]-declsp = antiblep <|> loop- where loop =- choice [- do- d <- declp- ds <- loop- return (d : ds),- (<?> "#load") $ do- sharpLoad- name <- stringLiteral- rel <- sourceName `liftM` getPosition- let mcontents = unsafePerformIO $ do- mfile <- findAlmsLibRel name rel- gmapM readFile mfile- contents <- case mcontents of- Just contents -> return contents- Nothing -> fail $ "Could not load: " ++ name- ds <- case parse parseProg name contents of- Left e -> fail (show e)- Right p -> return (prog2decls p)- ds' <- loop- return (ds ++ ds'),- return []- ]--declp :: Id i => P (Decl i)-declp = "declaration" @@ choice [- do- reserved "type"- tyDecsp >>! dcTyp,- letp,- do- reserved "open"- modexpp >>! dcOpn,- do- reserved "module"- choice [- do- reserved "type"- n <- uidp- reservedOp "="- s <- sigexpp- return (dcSig n s),- do- n <- uidp- asc <- option id $ do- colon- sigexpp >>! flip meAsc- reservedOp "="- b <- modexpp >>! asc- return (dcMod n b)- ],- do- reserved "local"- ds0 <- declsp- reserved "with"- ds1 <- declsp- reserved "end"- return (dcLoc ds0 ds1),- do- reserved "abstype"- at <- absTysp- reserved "with"- ds <- declsp- reserved "end"- return (dcAbs at ds),- do- reserved "exception"- n <- uidp- t <- antioptaroundp (reserved "of" `between` punit) typep- return (dcExn n t),- antiblep- ]--modexpp :: Id i => P (ModExp i)-modexpp = "structure" @@ foldlp meAsc body ascription where- body = choice [- meStr <$> between (reserved "struct") (reserved "end") declsp,- meName <$> quidp- <*> option [] (antilist1p comma qlidp),- antiblep- ]- ascription = colon *> sigexpp--sigexpp :: Id i => P (SigExp i)-sigexpp = "signature" @@ do- se <- choice [- seSig <$> between (reserved "sig") (reserved "end")- (antiblep <|> many sigitemp),- seName <$> quidp- <*> option [] (antilist1p comma qlidp),- antiblep- ]- specs <- many $ do- reserved "with"- reserved "type"- flip sepBy1 (reserved "and") $ "signature specialization" @@ do- (tvs, tc) <- tyAppp (antiblep <|>) tyvarp (J []) qlidnatp- reservedOp "="- t <- typep- return (\sig -> seWith sig tc tvs t)- return (foldl (flip ($)) se (concat specs))--sigitemp :: Id i => P (SigItem i)-sigitemp = "signature item" @@ choice [- do- reserved "val"- n <- lidp- colon- t <- typep- return (sgVal n t),- do- reserved "type"- sgTyp <$> tyDecsp,- do- reserved "module"- choice [- do- reserved "type"- n <- uidp- reservedOp "="- s <- sigexpp- return (sgSig n s),- do- n <- uidp- colon- s <- sigexpp- return (sgMod n s)- ],- do- reserved "include"- sgInc <$> sigexpp,- do- reserved "exception"- n <- uidp- t <- antioptaroundp (reserved "of" `between` punit) typep- return (sgExn n t),- antiblep- ]--tyDecsp :: Id i => P [TyDec i]-tyDecsp = antilist1p (reserved "and") tyDecp--tyDecp :: Id i => P (TyDec i)-tyDecp = "type declaration" @@ addLoc $ choice- [ antiblep- , do- optional (reservedOp "|")- tp <- typatp- (name, ps) <- checkHead tp- case checkTVs ps of- Just (True, tvs, arity) ->- reservedOp "=" *>- (tdDat name tvs <$> altsp- <|> tryTySyn name ps)- <|> tdAbs name tvs arity <$> qualsp- Just (_, tvs, arity) ->- reservedOp "=" *> tryTySyn name ps- <|> tdAbs name tvs arity <$> qualsp- Nothing ->- reservedOp "=" *> tryTySyn name ps- ]- where- tryTySyn name ps = do- t <- typep- alts <- many $ do- reservedOp "|"- tp <- typatp- (name', ps') <- checkHead tp- unless (name == name') $- unexpected $- "non-matching type operators `" ++ show name' ++- "' and `" ++ show name ++ "' in type pattern"- reservedOp "="- ti <- typep- return (ps', ti)- return (tdSyn name ((ps,t):alts))- --- checkHead tp = case dataOf tp of- TpApp (J [] name) ps -> return (name, ps)- TpApp _ _ -> unexpected "qualified identifier"- TpVar _ _ -> unexpected "type variable"- TpAnti _ -> unexpected "antiquote"- --- checkTVs [] = return (True, [], [])- checkTVs (N _ (TpVar tv var):rest) = do- (b, tvs, vars) <- checkTVs rest- return (b && var == Invariant, tv:tvs, var:vars)- checkTVs _ = Nothing--tyAppp :: Id i => (P [a] -> P [a]) -> P a -> (Lid i -> b) -> P b -> P ([a], b)-tyAppp wrap param oper suffix = choice [- do- l <- oplevelp (Right precBang)- p1 <- param- return ([p1], oper l),- try $ do- p1 <- param- n <- choice [ semis, operator ]- when (n == "-" || precOp n == Right precBang) pzero- p2 <- param- return ([p1, p2], oper (Syntax.lid n)),- do- ps <- wrap (delimList punit parens comma param)- name <- suffix- return (ps, name)- ]--tyProtp :: Id i => P ([(Variance, TyVar i)], Lid i)-tyProtp = tyAppp id paramVp id lidnatp--typatp :: Id i => P (TyPat i)-typatp = typatpP precStart--typatpP :: Id i => Int -> P (TyPat i)-typatpP p = "type pattern" @@ case () of- _ | p == precSemi- -> chainr1last (typatpP (p + 1))- (tpBinOp . J [] . Syntax.lid <$> semis)- (typatpP precStart)- | Just (Left _) <- fixities p- -> chainl1last (typatpP (p + 1))- (tpBinOp . J [] <$> oplevelp (Left p))- (typatpP precStart)- | Just (Right _) <- fixities p- -> chainr1last (typatpP (p + 1))- (tpBinOp . J [] <$> oplevelp (Right p))- (typatpP precStart)- | p == precApp -- this case ensures termination- -> tparg >>= tpapp'- | p < precApp- -> typatpP (p + 1)- | otherwise- -> typatpP precStart- where- tpBinOp ql tp1 tp2 = tpApp ql [tp1, tp2]- --- tparg :: Id i => P [TyPat i]- tparg = choice- [ (:[]) <$> tpatom,- parens $ antiblep <|> commaSep1 (typatpP precStart) ]- --- tpatom :: Id i => P (TyPat i)- tpatom = uncurry (flip tpVar) <$> paramVp- <|> tpApp <$> qlidnatp <*> pure []- <|> antiblep- <|> tpApp (qlid "U") [] <$ qualU- <|> tpApp (qlid "A") [] <$ qualA- <|> do- ops <- many1 $ addLoc $- oplevelp (Right precBang) >>! tpApp . J []- arg <- tpatom <|> parens (typatpP precStart)- return (foldr (\op t -> op [t]) arg ops)- tpapp' :: Id i => [TyPat i] -> P (TyPat i)- tpapp' [t] = option t $ do- tc <- qlidnatp- tpapp' [tpApp tc [t]]- tpapp' ts = do- tc <- qlidnatp- tpapp' [tpApp tc ts]--letp :: Id i => P (Decl i)-letp = do- reserved "let"- choice [- do- reserved "rec"- bindings <- flip sepBy1 (reserved "and") $ do- f <- varp- (sigma, fixt, fixe) <- afargsp- colon- t <- typep- reservedOp "="- e <- withSigma sigma exprp- return (bnBind f (fixt t) (fixe e))- let names = map (bnvar . dataOf) bindings- namesExp = foldl1 exPair (map exBVar names)- namesPat = foldl1 paPair (map paVar names)- tempVar = Syntax.lid "#letrec"- decls0 = [ dcLet (paVar tempVar) Nothing $- exLetRec bindings namesExp ]- decls1 = [ dcLet (paVar (bnvar binding)) Nothing $- exLet namesPat (exBVar tempVar) $- exBVar (bnvar binding)- | N _ binding <- bindings ]- return $ dcLoc decls0 decls1,- do- f <- varp- (sigma, fixt, fixe) <- afargsp- t <- antioptaroundp (colon `between` punit) typep- reservedOp "="- e <- withSigma sigma exprp- return (dcLet (paVar f) (fmap fixt t) (fixe e)),- dcLet <$> pattp- <*> antioptaroundp (colon `between` punit) typep- <* reservedOp "="- <*> exprp- ]--absTysp :: Id i => P [AbsTy i]-absTysp = antilist1p (reserved "and") $ absTyp--absTyp :: Id i => P (AbsTy i)-absTyp = addLoc $ antiblep <|> do- ((arity, tvs), name) <- tyProtp >>! first unzip- quals <- qualsp- reservedOp "="- alts <- altsp- return (absTy arity quals (tdDat name tvs alts))--paramVp :: Id i => P (Variance, TyVar i)-paramVp = do- v <- variancep- tv <- tyvarp- return (v, tv)--variancep :: P Variance-variancep =- choice- [ char '+' >> return Covariant,- char '-' >> return Contravariant,- char '*' >> return Omnivariant,- char '=' >> return Invariant,- return Invariant ]--qualsp :: Id i => P (QExp i)-qualsp = option minBound $- (reserved "qualifier" <|> reservedOp ":") *> qExpp--qExpp :: Id i => P (QExp i)-qExpp = "qualifier expression" @@ qexp where- qexp = addLoc $ qeDisj <$> sepBy1 qterm qdisj- qterm = addLoc $ qeConj <$> sepBy1 qfact qconj- qfact = addLoc $ parens qexp <|> qatom- qatom = addLoc $- qeLit Qu <$ qualU- <|> qeLit Qa <$ qualA- <|> clean <$> tyvarp- <|> qeLid <$> lidp- <|> antiblep- qeLid = qeVar . flip TV Qa- clean (TV _ Qu) = minBound- clean tv = qeVar tv--altsp :: Id i => P [(Uid i, Maybe (Type i))]-altsp = sepBy1 altp (reservedOp "|")--altp :: Id i => P (Uid i, Maybe (Type i))-altp = do- k <- try $ uidp <* try (dot *> pzero <|> punit)- t <- optionMaybe $ do- reserved "of"- typep- return (k, t)--exprp :: Id i => P (Expr i)-exprp = expr0 where- onlyOne [x] = [x True]- onlyOne xs = map ($ False) xs- mark = ("expression" @@)- expr0 = mark $ choice- [ do reserved "let"- choice- [ do reserved "rec"- bs <- antilist1p (reserved "and") $ bindingp- reserved "in"- e2 <- expr0- return (exLetRec bs e2),- do (x, sigma, lift) <- pattbangp- if sigma- then do- reservedOp "="- e1 <- expr0- reserved "in"- e2 <- withSigma True expr0- return (lift True (flip exLet e1) x e2)- else do- (sigma', args) <- argsp- reservedOp "="- e1 <- withSigma sigma' expr0- reserved "in"- e2 <- expr0- return (exLet x (args e1) e2),- do reserved "let"- unexpected "let",- do d <- withSigma False declp- reserved "in"- e2 <- expr0- return (exLetDecl d e2) ],- do reserved "if"- ec <- expr0- clt <- addLoc $ do- reserved "then"- caClause (paCon (quid "true") Nothing) <$> expr0- clf <- addLoc $ do- reserved "else"- caClause (paCon (quid "false") Nothing) <$> expr0- return (exCase ec [clt, clf]),- do reserved "match"- e1 <- expr0- reserved "with"- choice [- exCase e1 <$> antiblep,- do- optional (reservedOp "|")- clauses <- flip sepBy1 (reservedOp "|") preCasealtp- return (exCase e1 (onlyOne clauses)) ],- do reserved "try"- e1 <- expr0- reserved "with"- optional (reservedOp "|")- clauses <- flip sepBy1 (reservedOp "|") $ addLoc $ do- (xi, sigma, lift) <- pattbangp- arrow- ei <- mapSigma (sigma ||) expr0- return $- lift False- (\xi' ei' ->- -- TODO: Make this robust to redefinition of- -- Left and Right- caClause (paCon (quid "Left") (Just xi')) ei')- xi ei- let tryQ = qlid $- "INTERNALS.Exn.tryfun"- return $- exCase (exApp (exVar tryQ)- (exAbs paWild tyUnit- e1)) $- caClause (paCon (quid "Right")- (Just (paVar (Syntax.lid "x"))))- (exVar (qlid "x"))- :- clauses ++- [caClause- (paCon (quid "Left")- (Just (paVar (Syntax.lid "e"))))- (exApp (exVar (qlid "INTERNALS.Exn.raise"))- (exVar (qlid "e")))- ],- do lambda- (sigma, build) <- choice- [- argsp1,- do- (x, sigma, lift) <- pattbangp- colon- t <- typepP (precArr + 1)- return (sigma, lift True (flip exAbs t) x)- ]- arrow- withSigma sigma expr0 >>! build,- expr1 ]- expr1 = mark $ do- e1 <- expr3- choice- [ do semi- e2 <- expr0- return (exSeq e1 e2),- return e1 ]- expr3 = mark $ chainl1last expr4 (opappp (Left 3)) expr0- expr4 = mark $ chainr1last expr5 (opappp (Right 4)) expr0- expr5 = mark $ chainl1last expr6 (opappp (Left 5)) expr0- expr6 = mark $ chainl1last expr7 (opappp (Left 6)) expr0- expr7 = expr8- expr8 = mark $ chainr1last expr9 (opappp (Right 8)) expr0- expr9 = mark $ choice- [ chainl1 expr10 (addLoc (return exApp)),- do- reserved "Pack"- t1 <- antioptaroundp brackets typep- parens $ do- t2 <- typep- comma- e <- exprN1- return (exPack t1 t2 e)- ]- expr10 = mark $ do- ops <- many $ addLoc $ oplevelp (Right 10) >>! exBVar- arg <- expr11- return (foldr exApp arg ops)- expr11 = mark $ do- e <- exprA- ts <- many . brackets $ commaSep1 typep- return (foldl exTApp e (concat ts))- exprA = mark $ choice- [ identp >>! exId,- litp >>! exLit,- antiblep,- parens (exprN1 <|> return (exBCon (Syntax.uid "()")))- ]- exprN1 = mark $ do- e1 <- expr0- choice- [ do colon- t1 <- typep- let e1' = exCast e1 t1 False- option e1' $ do- reservedOp ":>"- t2 <- typep- return (exCast e1' t2 True),- do reservedOp ":>"- t2 <- typep- return (exCast e1 t2 True),- do comma- es <- commaSep1 expr0- return (foldl exPair e1 es),- return e1 ]--preCasealtp :: Id i => P (Bool -> CaseAlt i)-preCasealtp = "match clause" @@ (const <$> antiblep) <|> do- (xi, sigma, lift) <- pattbangp- arrow- ei <- mapSigma (sigma ||) exprp- return (\b -> lift b caClause xi ei)--casealtp :: Id i => P (CaseAlt i)-casealtp = preCasealtp >>! ($ False)--bindingp :: Id i => P (Binding i)-bindingp = "let rec binding" @@ antiblep <|> do- x <- varp- (sigma, ft, fe) <- afargsp- colon- t <- typep- reservedOp "="- e <- withSigma sigma exprp- return (bnBind x (ft t) (fe e))---- Parse an infix operator at given precedence-opappp :: Id i => Prec -> P (Expr i -> Expr i -> Expr i)-opappp p = do- op <- addLoc (oplevelp p >>! exBVar)- return (\e1 e2 -> op `exApp` e1 `exApp` e2)---- Zero or more of (pat:typ, ...), (), or tyvar, recognizing '|'--- to introduce affine arrows-afargsp :: Id i => P (Bool, Type i -> Type i, Expr i -> Expr i)-afargsp = choice- [ do (tvt, tve) <- tyargp- (b, ft, fe) <- afargsp- return (b, tvt . ft, tve . fe),- do arrcon <- arrconp- (b, ft, fe) <- vargp arrcon- if b- then return (b, ft, fe)- else do- (b', fts, fes) <- afargsp- return (b', ft . fts, fe . fes),- return (False, id, id) ]- where- arrconp = option tyArr $ choice- [ tyFun . Just <$> qualbox qExpp,- do- reservedOp "|"- return tyLol ]---- One or more of (pat:typ, ...), (), tyvar-argsp1 :: Id i => P (Bool, Expr i -> Expr i)-argsp1 = do- (b, fe) <- argp- if b- then return (b, fe)- else second (fe .) `fmap` option (False, id) argsp1---- Zero or more of (pat:typ, ...), (), tyvar-argsp :: Id i => P (Bool, Expr i -> Expr i)-argsp = option (False, id) $ do- (b, fe) <- argp- if b- then return (b, fe)- else second (fe .) `fmap` argsp---- Parse a (pat:typ, ...), (), or tyvar-argp :: Id i => P (Bool, Expr i -> Expr i)-argp = choice [- do- (_, fe) <- tyargp- return (False, fe),- do- (b, _, fe) <- vargp const- return (b, fe)- ]---- Parse a (pat:typ, ...) or () argument-vargp :: Id i =>- (Type i -> Type i -> Type i) ->- P (Bool, Type i -> Type i, Expr i -> Expr i)-vargp arrcon = do- inBang <- bangp- ((p, t), loc) <- withLoc paty- return (inBang, arrcon t, condSigma inBang True (flip exAbs t) p <<@ loc)---- Parse a (pat:typ, ...) or () argument-paty :: Id i => P (Patt i, Type i)-paty = do- (p, mt) <- pamty- case (dataOf p, mt) of- (_, Just t) -> return (p, t)- (PaCon (J [] (Uid _ "()")) Nothing, Nothing)- -> return (p, tyUnit)- (PaWild, Nothing)- -> return (p, tyAf)- _ -> pzero <?> ":"---- Parse a (), (pat:typ, ...) or (pat) argument-pamty :: Id i => P (Patt i, Maybe (Type i))-pamty = choice- [ (paWild, Nothing) <$ reserved "_",- parens $ do- tvs <- many (tyvarp <* comma)- (p, mt) <- choice- [ do- (p, mt) <- pamty- maybe (maybecolon p) (morepts p) mt,- do- p <- pattp- maybecolon p,- return (paCon (quid "()") Nothing, Nothing)- ]- return (foldr paPack p tvs,- fmap (\t -> foldr tyEx t tvs) mt)- ]- where- maybecolon p = choice- [- do- colon- t <- typep- morepts p t,- moreps p- ]- moreps p = do- ps <- many (comma >> pattp)- return (foldl paPair p ps, Nothing)- morepts p0 t0 = do- (ps, ts) <- liftM unzip . many $ do- comma- choice- [- do- (p, mt) <- pamty- case mt of- Just t -> return (p, t)- Nothing -> colonType p,- do- p <- pattp- colonType p- ]- return (foldl paPair p0 ps, Just (foldl tyTuple t0 ts))- colonType p = do- colon- t <- typep- return (p, t)---- Parse a sequence of one or more tyvar arguments-tyargp :: Id i => P (Type i -> Type i, Expr i -> Expr i)-tyargp = do- tvs <- liftM return loctv <|> brackets (commaSep1 loctv)- return (\t -> foldr (\(tv, _ ) -> tyAll tv) t tvs,- \e -> foldr (\(tv, loc) -> exTAbs tv <<@ loc) e tvs)- where- loctv = withLoc tyvarp--pattbangp :: Id i =>- P (Patt i, Bool,- Bool -> (Patt i -> Expr i -> b) -> Patt i -> Expr i -> b)-pattbangp = do- inSigma <- getSigma- inBang <- bangp- x <- pattp- let trans = inBang && not inSigma- wrap = inBang && inSigma- return (condMakeBang wrap x, inBang, condSigma trans)--condSigma :: Id i =>- Bool -> Bool ->- (Patt i -> Expr i -> a) ->- Patt i -> Expr i -> a-condSigma True = exSigma-condSigma False = const id--condMakeBang :: Id i => Bool -> Patt i -> Patt i-condMakeBang True = makeBangPatt-condMakeBang False = id--bangp :: P Bool-bangp = (bang >> return True) <|> return False--pattp :: Id i => P (Patt i)-pattp = patt0 where- mark = ("pattern" @@)- patt0 = mark $ do- x <- patt9- choice- [ do- reserved "as"- y <- varp- return (paAs x y),- return x- ]- patt9 = mark $ choice- [ do- reserved "Pack"- parens $ do- tv <- tyvarp- comma- x <- pattN1- return (paPack tv x),- paCon <$> quidp- <*> antioptp (try pattA),- pattA ]- pattA = mark $ choice- [ paWild <$ reserved "_",- paVar <$> varp,- paLit <$> litp,- paCon <$> quidp- <*> pure Nothing,- antiblep,- parens pattN1- ]- pattN1 = mark $ choice- [ paPack <$> try (tyvarp <* comma)- <*> pattN1,- do- xs <- commaSep patt0- case xs of- [] -> return (paCon (quid "()") Nothing)- x:xs' -> return (foldl paPair x xs') ]--litp :: P Lit-litp = (<?> "literal") $ choice [- integerOrFloat >>! either LtInt LtFloat,- charLiteral >>! (LtInt . fromIntegral . fromEnum),- stringLiteral >>! LtStr,- antiblep- ]--finish :: P a -> P a-finish p = do- optional (whiteSpace)- r <- p- eof- return r---- | Parse a program-parseProg :: Id i => P (Prog i)--- | Parse a REPL line-parseRepl :: Id i => P [Decl i]--- | Parse a sequence of declarations-parseDecls :: Id i => P [Decl i]--- | Parse a declaration-parseDecl :: Id i => P (Decl i)--- | Parse a module expression-parseModExp :: Id i => P (ModExp i)--- | Parse a type declaration-parseTyDec :: Id i => P (TyDec i)--- | Parse a abstype declaration-parseAbsTy :: Id i => P (AbsTy i)--- | Parse a type-parseType :: Id i => P (Type i)--- | Parse a type pattern-parseTyPat :: Id i => P (TyPat i)--- | Parse a qualifier expression-parseQExp :: Id i => P (QExp i)--- | Parse an expression-parseExpr :: Id i => P (Expr i)--- | Parse a pattern-parsePatt :: Id i => P (Patt i)--- | Parse a case alternative-parseCaseAlt :: Id i => P (CaseAlt i)--- | Parse a let rec binding-parseBinding :: Id i => P (Binding i)--- | Parse a signature-parseSigExp :: Id i => P (SigExp i)--- | Parse a signature item-parseSigItem :: Id i => P (SigItem i)--parseProg = finish progp-parseRepl = finish replp-parseDecls = finish declsp-parseDecl = finish declp-parseModExp = finish modexpp-parseTyDec = finish tyDecp-parseAbsTy = finish absTyp-parseType = finish typep-parseTyPat = finish typatp-parseQExp = finish qExpp-parseExpr = finish exprp-parsePatt = finish pattp-parseCaseAlt = finish casealtp-parseBinding = finish bindingp-parseSigExp = finish sigexpp-parseSigItem = finish sigitemp---- Convenience functions for quick-and-dirty parsing:---- | Parse a program-pp :: String -> Prog Renamed-pp = makeQaD parseProg---- | Parse a sequence of declarations-pds :: String -> [Decl Renamed]-pds = makeQaD parseDecls---- | Parse a declaration-pd :: String -> Decl Renamed-pd = makeQaD parseDecl--pme :: String -> ModExp Renamed-pme = makeQaD parseModExp---- | Parse a type declaration-ptd :: String -> TyDec Raw-ptd = makeQaD parseTyDec---- | Parse a type-pt :: String -> Type Renamed-pt = makeQaD parseType---- | Parse a type pattern-ptp :: String -> TyPat Renamed-ptp = makeQaD parseTyPat---- | Parse a qualifier expression-pqe :: String -> QExp Renamed-pqe = makeQaD parseQExp---- | Parse an expression-pe :: String -> Expr Renamed-pe = makeQaD parseExpr---- | Parse a pattern-px :: String -> Patt Renamed-px = makeQaD parsePatt--makeQaD :: P a -> String -> a-makeQaD parser =- either (error . show) id . runParser parser state0 "<string>"
src/Paths.hs view
@@ -1,6 +1,3 @@-{-# LANGUAGE- CPP,- TemplateHaskell #-} module Paths ( findFirstInPath, findInPath, almsLibPath, findAlmsLib, findAlmsLibRel,@@ -10,6 +7,7 @@ import Util +import Prelude () import Language.Haskell.TH import System.FilePath import System.Directory (doesFileExist, getCurrentDirectory)@@ -73,7 +71,7 @@ findAlmsLib :: FilePath -> IO (Maybe FilePath) findAlmsLib name = do path <- almsLibPath- findFirstInPath [ name, name <.> "alms" ] path+ findFirstInPath (nameAdjustments name) path -- | Find an Alms library with the given name, first looking -- relative to the given path@@ -84,7 +82,15 @@ "." -> "." "-" -> "." _ -> dropFileName rel- findFirstInPath [ name, name <.> "alms" ] (rel' : path)+ findFirstInPath (nameAdjustments name) (rel' : path)++-- | Produce a sequence of names to try to load based on a base name+nameAdjustments ∷ FilePath -> [FilePath]+nameAdjustments name =+ [ name , name <.> "alms" ]+ ++ if pathSeparator `elem` name+ then []+ else [ "lib" ++ name <.> "alms" ] shortenPath :: FilePath -> IO FilePath shortenPath fp = do
− src/Ppr.hs
@@ -1,514 +0,0 @@--- | Pretty-printing-{-# LANGUAGE- PatternGuards,- QuasiQuotes,- TypeSynonymInstances- #-}-module Ppr (- pprTyApp,- -- * Re-exports- module PprClass,- module Prec-) where--import Meta.Quasi-import PprClass-import Prec-import Syntax-import Util--import qualified Syntax.Decl-import qualified Syntax.Expr-import qualified Syntax.Notable-import qualified Syntax.Patt-import qualified Loc--import Data.List (intersperse)--instance IsInfix (Type i) where- isInfix [$ty| ($_, $_) $lid:n |] = isOperator n- isInfix [$ty| $_ -[$_]> $_ |] = True- isInfix _ = False---- | For printing infix expressions. Given a splitter function that--- splits expressions into a left operand, operator name, and right--- operand (if possible), and an expression to print, pretty-prints--- the expression, but only if there is one level of infix to be--- done.-pprInfix :: Ppr a =>- (a -> Maybe (a, String, Maybe a)) ->- a -> Maybe Doc-pprInfix inspect x0- | Just (x1, op, Nothing) <- inspect x0- , precOp op == Right precBang- = let rloop x'- | Just (x1', op', Nothing) <- inspect x'- , precOp op == Right precBang- = first (op':) (rloop x1')- | otherwise- = ([], x')- (ops, x) = first (op:) (rloop x1)- in Just $- fsep (mapTail (nest 2) $ map text ops)- <> pprPrec precBang x- | Just (_, op, Just _) <- inspect x0- , isOperator (lid op :: Lid Raw)- , p <- precOp op- , p /= Right precBang- = Just $- prec (id|||id $ p) $- fcat $ mapTail (nest 2) $ loop p empty x0- | otherwise- = Nothing- where- loop p suf x- | Just (x1, op, Just x2) <- inspect x- , precOp op == p- = case precOp op of- Left _ -> loop p (oper op) x1 ++ [ppr1 x2 <> suf]- Right _ -> ppr1 x1 <> oper op : loop p suf x2- loop _ suf x = [ ppr x <> suf ]- oper s = case s of- '@':_ -> text s- ';':_ -> text s <> space- _ -> space <> text s <> space--instance Ppr (Type i) where- -- pprPrec p (TyFun q t1 t2)- ppr [$ty| $t1 -> $t2 |]- = prec precArr $- sep [ ppr1 t1, text "->" <+> pprRight t2 ]- ppr [$ty| $t1 -[$q]> $t2 |]- = prec precArr $- sep [ ppr1 t1,- text "-" <> ppr0 q <> text ">" <+> pprRight t2 ]- ppr t@[$ty| ($list:ts) $qlid:n |]- | Just doc <- pprInfix unfoldType t- = doc- | null ts = ppr n- | otherwise = prec precApp $ sep [ ppr ts, ppr n ]- -- debugging: <> text (show (ttId (unsafeCoerce tag :: TyTag)))- ppr [$ty| '$x |] = ppr x- ppr [$ty| $quant:qu '$x. $t |]- = prec precDot $- ppr qu <+>- fsep (map ppr1 tvs) <>- char '.'- >+> ppr body- where (tvs, body) = unfoldTyQu qu [$ty| $quant:qu '$x. $t |]- ppr [$ty| mu '$x. $t |]- = prec precDot $- text "mu" <+>- ppr1 x <>- char '.'- >+> ppr t- ppr [$ty| $anti:a |] = ppr a--unfoldType :: Type i -> Maybe (Type i, String, Maybe (Type i))-unfoldType [$ty| ($t1, $t2) $name:n |] = Just (t1, n, Just t2)-unfoldType [$ty| $t1 $name:n |] = Just (t1, n, Nothing)-unfoldType _ = Nothing--instance Ppr (TyPat i) where- ppr tp0 = case tp0 of- _ | Just doc <- pprInfix unfoldTyPat tp0- -> doc- N _ (TpVar tv var) -> pprParamV var tv- [$tpQ| $qlid:ql |] -> ppr ql- [$tpQ| ($list:tps) $qlid:ql |]- -> prec precApp $ sep [ppr tps, ppr ql]- [$tpQ| $antiP:a |] -> ppr a--unfoldTyPat :: TyPat i -> Maybe (TyPat i, String, Maybe (TyPat i))-unfoldTyPat [$tpQ| ($t1, $t2) $name:n |] = Just (t1, n, Just t2)-unfoldTyPat [$tpQ| $t1 $name:n |] = Just (t1, n, Nothing)-unfoldTyPat _ = Nothing--instance Ppr (QExp i) where- ppr [$qeQ| $qlit:qu |] = ppr qu- ppr [$qeQ| $qvar:v |] = ppr (tvname v)- ppr [$qeQ| $qdisj:qes |] = case qes of- [] -> ppr Qu- [qe] -> ppr qe- _ -> prec precPlus $- hcat $- intersperse (text ",") $- map ppr1 qes- ppr [$qeQ| $qconj:qes |] = case qes of- [] -> ppr Qa- [qe] -> ppr qe- _ -> prec precStar $- hcat $- intersperse (text "/\\") $- map ppr1 qes- ppr [$qeQ| $anti:a |] = ppr a--instance Ppr (Prog i) where- ppr [$prQ| $list:ms |] = vcat (map ppr0 ms)- ppr [$prQ| $expr:e |] = ppr e- ppr [$prQ| $list:ms in $e |] = vcat (map ppr0 ms) $+$- (text "in" >+> ppr e)--instance Ppr (Decl i) where- ppr [$dc| let $x = $e |] = sep- [ text "let" <+> ppr x,- nest 2 $ equals <+> ppr e ]- ppr [$dc| let $x : $t = $e |] = sep- [ text "let" <+> ppr x,- nest 2 $ colon <+> ppr t,- nest 4 $ equals <+> ppr e ]- ppr [$dc| type $list:tds |] = pprTyDecs tds- ppr [$dc| abstype $list:ats0 with $list:ds end |] =- case ats0 of- [] ->- vcat [- text "abstype with",- nest 2 $ vcat (map ppr ds),- text "end"- ]- at:ats ->- vcat [- vcat (text "abstype" <+> pprAbsTy at :- [ nest 4 $ text "and" <+> pprAbsTy ati | ati <- ats ])- <+> text "with",- nest 2 $ vcat (map ppr ds),- text "end"- ]- ppr [$dc| open $b |] = pprModExp (text "open" <+>) b- ppr [$dc| module $uid:n : $s = $b |] = pprModExp add1 b where- add1 body = pprSigExp add2 s <+> equals <+> body- add2 body = text "module" <+> ppr n <+> colon <+> body- ppr [$dc| module $uid:n = $b |] = pprModExp add b where- add body = text "module" <+> ppr n <+> equals <+> body- ppr [$dc| module type $uid:n = $s |] = pprSigExp add s where- add body = text "module type" <+> ppr n <+> equals <+> body- ppr [$dc| local $list:d0 with $list:d1 end |] =- vcat [- text "local",- nest 2 (vcat (map ppr d0)),- text "with",- nest 2 (vcat (map ppr d1)),- text "end"- ]- ppr [$dc| exception $uid:n of $opt:mt |] =- pprExcDec n mt- ppr [$dc| $anti:a |] = ppr a--pprTyDecs :: [TyDec i] -> Doc-pprTyDecs tds =- vcat $- mapHead (text "type" <+>) $- mapTail ((nest 1) . (text "and" <+>)) $- map ppr tds--pprExcDec :: Uid i -> Maybe (Type i) -> Doc-pprExcDec u Nothing =- text "exception" <+> ppr u-pprExcDec u (Just t) =- text "exception" <+> ppr u <+> text "of" <+> ppr t--instance Ppr (TyDec i) where- ppr td = case view td of- TdAbs n ps vs qs -> pprProtoV n vs ps >?> pprQuals qs- TdSyn n [(ps,t)] -> pprProto n ps >+> equals <+> ppr t- TdSyn n cs -> vcat [ char '|' <+> each ci | ci <- cs ]- where- each (ps, rhs) = pprProto n ps- >+> char '=' <+> ppr rhs- TdDat n ps alts -> pprProtoV n (repeat Invariant) ps- >?> pprAlternatives alts- TdAnti a -> ppr a--pprAbsTy :: AbsTy i -> Doc-pprAbsTy at = case view at of- AbsTy variances qual (N _ (TdDat name params alts)) ->- pprProtoV name variances params- >?> pprQuals qual- >?> pprAlternatives alts- AbsTy _ _ td -> ppr td -- shouldn't happen (yet)- AbsTyAnti a -> ppr a--pprProto :: Lid i -> [TyPat i] -> Doc-pprProto n ps = ppr (tpApp (J [] n) ps)--pprProtoV :: Lid i -> [Variance] -> [TyVar i] -> Doc-pprProtoV n vs tvs = pprProto n (zipWith tpVar tvs vs)--pprParamV :: Variance -> TyVar i -> Doc-pprParamV Invariant tv = ppr tv-pprParamV v tv = ppr v <> ppr tv--pprQuals :: QExp i -> Doc-pprQuals [$qeQ| U |] = empty-pprQuals qs = text ":" <+> pprPrec precApp qs--pprAlternatives :: [(Uid i, Maybe (Type i))] -> Doc-pprAlternatives [] = equals-pprAlternatives (a:as) = sep $- equals <+> alt a : [ char '|' <+> alt a' | a' <- as ]- where- alt (u, Nothing) = ppr u- alt (u, Just t) = ppr u <+> text "of" <+> pprPrec precDot t--pprModExp :: (Doc -> Doc) -> ModExp i -> Doc-pprModExp add modexp = case modexp of- [$me| $quid:n |] -> add (ppr n)- [$me| $quid:n $list:qls |] ->- add (ppr n) <+>- brackets (fsep (punctuate comma (map ppr qls)))- [$me| struct $list:ds end |] ->- add (text "struct")- $$ nest 2 (vcat (map ppr0 ds))- $$ text "end"- [$me| $me1 : $se2 |] ->- pprSigExp (pprModExp add me1 <+> colon <+>) se2- [$me| $anti:a |] -> add (ppr a)--pprSigExp :: (Doc -> Doc) -> SigExp i -> Doc-pprSigExp add se0 = body >+> withs where- (wts, se1) = unfoldSeWith se0- body = case se1 of- [$seQ| $quid:n |] -> add (ppr n)- [$seQ| $quid:n $list:qls |] ->- add (ppr n) <+>- brackets (fsep (punctuate comma (map ppr qls)))- [$seQ| sig $list:sgs end |] ->- add (text "sig")- $$ nest 2 (vcat (map ppr0 sgs))- $$ text "end"- [$seQ| $_ with type $list:_ $qlid:_ = $_ |] ->- error "BUG! can't happen in pprSigExp"- [$seQ| $anti:a |] -> add (ppr a)- withs =- atPrec 0 $ sep $- mapHead (text "with type" <+>) $- mapTail ((nest 6) . (text "and" <+>)) $- [ pprTyApp tc tvs <+> equals <+> ppr t- | (tc, tvs, t) <- wts ]--instance Ppr (SigItem i) where- ppr sg0 = case sg0 of- [$sgQ| val $lid:n : $t |] ->- text "val" <+> ppr n >+> colon <+> ppr t- [$sgQ| type $list:tds |] ->- pprTyDecs tds- [$sgQ| module $uid:u : $s |] ->- pprSigExp add s where- add body = text "module" <+> ppr u <+> colon <+> body- [$sgQ| module type $uid:u = $s |] ->- pprSigExp add s where- add body = text "module type" <+> ppr u <+> equals <+> body- [$sgQ| include $s |] ->- pprSigExp (text "include" <+>) s- [$sgQ| exception $uid:u of $opt:mt |] ->- pprExcDec u mt- [$sgQ| $anti:a |] ->- ppr a--instance Ppr (Expr i) where- ppr e0 = case e0 of- _ | Just doc <- pprInfix unfoldExpr e0- -> doc- [$ex| $id:x |] -> ppr x- [$ex| $lit:lt |] -> ppr lt- [$ex| if $ec then $et else $ef |] ->- prec precDot $- sep [ text "if" <+> ppr ec,- nest 2 $ text "then" <+> ppr0 et,- nest 2 $ text "else" <+> ppr ef ]- [$ex| $_; $_ |] ->- prec precDot $- sep (unfold e0)- where unfold [$ex| $e1; $e2 |] = ppr1 e1 <> semi : unfold e2- unfold e = [ ppr0 e ]- [$ex| let $x = $e1 in $e2 |] ->- pprLet (ppr x) e1 e2- [$ex| match $e1 with $list:clauses |] ->- prec precDot $- vcat (sep [ text "match",- nest 2 $ ppr0 e1,- text "with" ] : map alt clauses)- where- alt (N _ (CaClause xi ei)) =- hang (char '|' <+> ppr xi <+> text "->")- 4- (ppr ei)- alt (N _ (CaAnti a)) = char '|' <+> ppr a- [$ex| let rec $list:bs in $e2 |] ->- prec precDot $- text "let" <+>- vcat (zipWith each ("rec" : repeat "and") bs) $$- text "in" <+> ppr e2- where- each kw (N _ (BnBind x t e)) =- -- This could be better by pulling some args out.- hang (hang (text kw <+> ppr x)- 6- (colon <+> ppr t <+> equals))- 2- (ppr e)- each kw (N _ (BnAnti a)) = text kw <+> ppr a- [$ex| let $decl:d in $e2 |] ->- prec precDot $- text "let" <+> ppr0 d $$- (text "in" >+> ppr e2)- [$ex| ($e1, $e2) |] ->- prec precCom $- sep [ ppr e1 <> comma, ppr1 e2 ]- [$ex| fun $_ : $_ -> $_ |] -> pprAbs e0- [$ex| $e1 $e2 |]- -> prec precApp $- sep [ ppr e1, ppr1 e2 ]- [$ex| fun '$_ -> $_ |] -> pprAbs e0- [$ex| $_ [$_] |] ->- prec precTApp $- cat [ ppr op,- brackets . fsep . punctuate comma $- map (pprPrec precCom) args ]- where - (args, op) = unfoldExTApp e0- [$ex| Pack[$opt:t1]($t2, $e) |] ->- prec precApp $- text "Pack" <> maybe empty (brackets . ppr0) t1 <+>- prec precCom (sep [ ppr1 t2 <> comma, ppr e ])- [$ex| ( $e : $t1 :> $t2 ) |] ->- prec precCast $- atPrec (precCast + 2) $- sep [ ppr e,- colon <+> ppr t1,- text ":>" <+> ppr t2 ]- [$ex| ( $e : $t1 ) |] ->- prec precCast $- atPrec (precCast + 2) $- sep [ ppr e,- colon <+> ppr t1 ]- [$ex| ( $e :> $t1 ) |] ->- prec precCast $- atPrec (precCast + 2) $- sep [ ppr e,- text ":>" <+> ppr t1 ]- [$ex| $anti:a |] -> ppr a- where- unfoldExpr [$ex| ($name:x $e1) $e2 |] = Just (e1, x, Just e2)- unfoldExpr [$ex| $name:x $e1 |] = Just (e1, x, Nothing)- unfoldExpr _ = Nothing--pprLet :: Doc -> Expr i -> Expr i -> Doc-pprLet pat e1 e2 = prec precDot $- hang (text "let" <+> pat <+> pprArgList args <+> equals- >+> ppr body <+> text "in")- (if isLet (view e2)- then 0- else 2)- (ppr e2)- where- (args, body) = unfoldExAbs e1- isLet (ExCase _ [_]) = True- isLet _ = False--pprAbs :: Expr i -> Doc-pprAbs e = prec precDot $- text "fun" <+> argsDoc <+> text "->"- >+> ppr body- where (args, body) = unfoldExAbs e- argsDoc = case args of- [Left ([$pa| _ |], [$ty|@! unit |])]- -> parens empty- [Left (x, t)] -> ppr x <+> char ':' <+> pprPrec (precArr + 1) t- _ -> pprArgList args--pprArgList :: [Either (Patt i, Type i) (TyVar i)] -> Doc-pprArgList = fsep . map eachArg . combine where- eachArg (Left ([$pa| _ |], [$ty|@! unit |]))- = parens empty- eachArg (Left (x, t)) = parens $- ppr0 x- >+> colon <+> ppr0 t- eachArg (Right tvs) = brackets .- sep .- punctuate comma $- map ppr tvs- --- combine :: [Either a b] -> [Either a [b]]- combine = foldr each [] where- each (Right b) (Right bs : es) = Right (b : bs) : es- each (Right b) es = Right [b] : es- each (Left a) es = Left a : es--instance Ppr (Patt i) where- ppr [$pa| _ |] = text "_"- ppr [$pa| $lid:l |] = ppr l- ppr [$pa| $quid:qu |] = ppr qu- ppr [$pa| $quid:qu $x |] = prec precApp $- ppr qu <+> ppr1 x- ppr [$pa| ($x, $y) |] = prec precCom $- ppr x <> comma <+> ppr1 y- ppr [$pa| $lit:lt |] = ppr lt- ppr [$pa| $x as $lid:l |] = prec precDot $- ppr1 x <+> text "as" <+> ppr l- ppr [$pa| Pack('$tv,$x) |] = prec precApp $- text "Pack" <+> pprPrec precCom (sep pair)- where pair = [ ppr1 tv <> comma, ppr x ]- ppr [$pa| $anti:a |] = ppr a--instance Ppr Lit where- ppr (LtInt i) = integer i- ppr (LtFloat f) = double f- ppr (LtStr s) = text (show s)- ppr (LtAnti a) = ppr a------- Helper for pretty-printing type-like things -- doesn't require--- underlying types, but does need to see the operator name.-----data PprTyAppHelper i a- = PTAHBranch (QLid i) [a]- | PTAHLeaf a--instance Ppr a => Ppr (PprTyAppHelper i a) where- ppr (PTAHLeaf a) = ppr a- ppr _ = error "BUG! in PprTyAppHelper.ppr"--unfoldPTAH :: PprTyAppHelper i a ->- Maybe (PprTyAppHelper i a, String, Maybe (PprTyAppHelper i a))-unfoldPTAH (PTAHBranch (J [] l) [a, b])- = Just (PTAHLeaf a, unLid l, Just (PTAHLeaf b))-unfoldPTAH (PTAHBranch (J [] l) [a])- = Just (PTAHLeaf a, unLid l, Nothing)-unfoldPTAH _- = Nothing--pprTyApp :: Ppr a => QLid i -> [a] -> Doc-pprTyApp ql ts- | Just doc <- pprInfix unfoldPTAH (PTAHBranch ql ts)- = doc-pprTyApp ql [] = ppr ql-pprTyApp ql ts = prec precApp $ sep [ ppr ts, ppr ql ]------- Instances-----instance Show (Prog i) where showsPrec = showFromPpr-instance Show (Decl i) where showsPrec = showFromPpr-instance Show (TyDec i) where showsPrec = showFromPpr-instance Show (Expr i) where showsPrec = showFromPpr-instance Show (Patt i) where showsPrec = showFromPpr-instance Show Lit where showsPrec = showFromPpr-instance Show (Type i) where showsPrec = showFromPpr-instance Show (TyPat i) where showsPrec = showFromPpr-instance Show (QExp i) where showsPrec = showFromPpr-instance Show (SigItem i)where showsPrec = showFromPpr--instance Ppr Loc where pprPrec = pprFromShow-instance Ppr QLit where pprPrec = pprFromShow-instance Ppr Variance where pprPrec = pprFromShow-instance Ppr Quant where pprPrec = pprFromShow-instance Ppr (Lid i) where pprPrec = pprFromShow-instance Ppr (Uid i) where pprPrec = pprFromShow-instance Ppr (BIdent i)where pprPrec = pprFromShow-instance Ppr (TyVar i) where pprPrec = pprFromShow-instance Ppr Anti where pprPrec = pprFromShow-instance (Show p, Show k) => Ppr (Path p k) where pprPrec = pprFromShow-
− src/PprClass.hs
@@ -1,301 +0,0 @@-{-# LANGUAGE- FlexibleInstances- #-}-module PprClass (- -- * Documents- Doc,- -- * Pretty-printing class- Ppr(..), IsInfix(..), ListStyle(..),- -- ** Helpers- ppr0, ppr1, pprDepth,- -- ** Context operations- prec, mapPrec, prec1, descend, atPrec, atDepth,- askPrec, askDepth,- trimList, trimCat,- -- *** For type name shortening- TyNames(..), tyNames0,- setTyNames, askTyNames, enterTyNames, lookupTyNames,- -- * Pretty-printing combinators- (>+>), (>?>), ifEmpty,- vcat, sep, cat, fsep, fcat,- -- * Renderers- render, renderS, printDoc, printPpr, hPrintDoc, hPrintPpr,- -- ** Instance helpers- showFromPpr, pprFromShow,- -- * Re-exports- module PrettyPrint-) where--import PrettyPrint hiding (Doc(..), render, vcat, sep, cat, fsep, fcat)-import qualified PrettyPrint as P--import Syntax.Ident (QLid, Uid, Renamed)--import System.IO (Handle, stdout, hPutChar, hPutStr)---- | Context for pretty-printing.-data PprContext- = PprContext {- pcPrec :: !Int,- pcDepth :: !Int,- pcTyName :: !TyNames- }--data TyNames =- TyNames {- tnLookup :: Int -> QLid Renamed -> QLid Renamed,- tnEnter :: Uid Renamed -> TyNames- }---- | Default context-pprContext0 :: PprContext-pprContext0 = PprContext {- pcPrec = 0,- pcDepth = -1,- pcTyName = tyNames0-}--tyNames0 :: TyNames-tyNames0 = TyNames {- tnLookup = const id,- tnEnter = const tyNames0-}--type Doc = P.Doc PprContext--data ListStyle - = ListStyle {- listStyleBegin, listStyleEnd, listStylePunct :: Doc,- listStyleDelimitEmpty, listStyleDelimitSingleton :: Bool,- listStyleJoiner :: [Doc] -> Doc- }---- | Class for pretty-printing at different types------ Minimal complete definition is one of:------ * 'pprPrec'------ * 'ppr'-class Ppr p where- -- | Print current precedence- ppr :: p -> Doc- -- | Print at the specified enclosing precedence- pprPrec :: Int -> p -> Doc- -- | Print a list in the default style- pprList :: [p] -> Doc- -- | Print a list in the specified style- pprStyleList :: ListStyle -> [p] -> Doc- -- | Style for printing lists- listStyle :: [p] -> ListStyle- --- --- ppr = asksD pcPrec . flip pprPrec- pprPrec p = prec p . ppr- pprList xs = pprStyleList (listStyle xs) xs- --- pprStyleList st [] =- if listStyleDelimitEmpty st- then listStyleBegin st <> listStyleEnd st- else empty- pprStyleList st [x] =- if listStyleDelimitSingleton st- then listStyleBegin st <> ppr x <> listStyleEnd st- else ppr x- pprStyleList st xs =- listStyleBegin st <>- listStyleJoiner st (punctuate (listStylePunct st) (map ppr xs))- <> listStyleEnd st- --- listStyle _ = ListStyle {- listStyleBegin = lparen,- listStyleEnd = rparen,- listStylePunct = comma,- listStyleDelimitEmpty = False,- listStyleDelimitSingleton = False,- listStyleJoiner = fsep- }---- | Print at top level.-ppr0 :: Ppr p => p -> Doc-ppr0 = atPrec 0 . ppr---- | Print at next level.-ppr1 :: Ppr p => p -> Doc-ppr1 = prec1 . ppr---- | Print to the given depth.-pprDepth :: Ppr p => Int -> p -> Doc-pprDepth d = atDepth d . ppr---- | Enter the given precedence level, drawing parentheses if necessary,--- and count it as a descent in depth as well.-prec :: Int -> Doc -> Doc-prec p doc = asksD pcPrec $ \p' ->- if p' > p- then descend $ parens (atPrec (min p 0) doc)- else atPrec p doc---- | Adjust the precedence with the given function.-mapPrec :: (Int -> Int) -> Doc -> Doc-mapPrec f doc = askPrec (\p -> prec (f p) doc)---- | Go to the next (tigher) precedence level.-prec1 :: Doc -> Doc-prec1 = mapD (\e -> e { pcPrec = pcPrec e + 1 })---- | Descend a level, elliding if the level counter runs out-descend :: Doc -> Doc-descend doc = askD $ \e ->- case pcDepth e of- -1 -> doc- 0 -> text "..."- k -> localD e { pcDepth = k - 1 } doc---- | Set the precedence, but check or draw parentheses-atPrec :: Int -> Doc -> Doc-atPrec p = mapD (\e -> e { pcPrec = p })---- | Set the precedence, but check or draw parentheses-atDepth :: Int -> Doc -> Doc-atDepth k = mapD (\e -> e { pcDepth = k })---- | Find out the precedence-askPrec :: (Int -> Doc) -> Doc-askPrec = asksD pcPrec---- | Find out the depth-askDepth :: (Int -> Doc) -> Doc-askDepth = asksD pcDepth---- | Change the type name lookup function-setTyNames :: TyNames -> Doc -> Doc-setTyNames f = mapD (\e -> e { pcTyName = f })---- | Retrieve the type name lookup function-askTyNames :: (TyNames -> Doc) -> Doc-askTyNames = asksD pcTyName---- | Render a document with a module opened-enterTyNames :: Uid Renamed -> Doc -> Doc-enterTyNames u doc = askTyNames $ \tn ->- setTyNames (tnEnter tn u) doc---- | Look up a type name in the rendering context-lookupTyNames :: Int -> QLid Renamed -> (QLid Renamed -> Doc) -> Doc-lookupTyNames tag ql kont = askTyNames $ \tn ->- kont (tnLookup tn tag ql)---- | Trim a list to (about) the given number of elements, with--- "..." in the middle.-trimList :: Int -> [Doc] -> [Doc]-trimList (-1) ds = ds-trimList n2 ds = if k <= 2 * n- then ds- else take n ds ++ text "... " : drop (k - n) ds- where- n = (n2 + 1) `div` 2- k = length ds---- | Lift a concatenation function to respect depth.-trimCat :: ([Doc] -> Doc) -> [Doc] -> Doc-trimCat xcat docs = asksD pcDepth $ \d -> case d of- -1 -> xcat docs- _ -> atDepth ((d + 1) `div` 2) (xcat (trimList d docs))--vcat, sep, cat, fsep, fcat :: [Doc] -> Doc-vcat = trimCat P.vcat-sep = trimCat P.sep-cat = trimCat P.cat-fsep = trimCat P.fsep-fcat = trimCat P.fcat--instance Ppr a => Ppr [a] where- ppr = pprList--instance Ppr a => Ppr (Maybe a) where- pprPrec _ Nothing = empty- pprPrec p (Just a) = pprPrec p a---- | Class to check if a particular thing will print infix. Adds--- an operation to print at the given precedence only if the given--- thing is infix. (We use this for printing arrows without too--- many parens.)-class Ppr a => IsInfix a where- isInfix :: a -> Bool- pprRight :: a -> Doc- pprRight a =- if isInfix a- then ppr a- else ppr0 a--instance Ppr Int where ppr = int-instance Ppr Integer where ppr = integer-instance Ppr Double where ppr = double--instance Ppr Char where- ppr = text . show- pprStyleList _ = text--instance Ppr (P.Doc PprContext) where ppr = id-instance Show (P.Doc PprContext) where showsPrec = showFromPpr---- Render a document in the preferred style, given a string continuation-renderS :: Doc -> ShowS-renderS doc rest = fullRenderIn pprContext0 PageMode 80 1.1 each rest doc- where each (Chr c) s' = c:s'- each (Str s) s' = s++s'- each (PStr s) s' = s++s'---- Render a document in the preferred style-render :: Doc -> String-render doc = renderS doc ""---- Render and display a document in the preferred style-printDoc :: Doc -> IO ()-printDoc = hPrintDoc stdout---- Pretty-print, render and display in the preferred style-printPpr :: Ppr a => a -> IO ()-printPpr = hPrintPpr stdout---- Render and display a document in the preferred style-hPrintDoc :: Handle -> Doc -> IO ()-hPrintDoc h = fullRenderIn pprContext0 PageMode 80 1.1 each (putChar '\n')- where each (Chr c) io = hPutChar h c >> io- each (Str s) io = hPutStr h s >> io- each (PStr s) io = hPutStr h s >> io--hPrintPpr :: Ppr a => Handle -> a -> IO ()-hPrintPpr h = hPrintDoc h . ppr--showFromPpr :: Ppr a => Int -> a -> ShowS-showFromPpr p t = renderS (pprPrec p t)--pprFromShow :: Show a => Int -> a -> Doc-pprFromShow p t = text (showsPrec p t "")------- Some indentation operations-----liftEmpty :: (Doc -> Doc -> Doc) -> Doc -> Doc -> Doc-liftEmpty joiner d1 d2 = askD f where- f e | isEmptyIn e d1 = d2- | isEmptyIn e d2 = d1- | otherwise = joiner d1 d2--ifEmpty :: Doc -> Doc -> Doc -> Doc-ifEmpty dc dt df = askD $ \e ->- if isEmptyIn e dc- then dt- else df--(>+>) :: Doc -> Doc -> Doc-(>+>) = flip hang 2--(>?>) :: Doc -> Doc -> Doc-(>?>) = liftEmpty (>+>)--infixr 5 >+>, >?>-
− src/Prec.hs
@@ -1,75 +0,0 @@--- | Operator precdences------ We use operator precedences from Ocaml. The precence and--- associativity of an operator is determined by its first character.-module Prec (- Prec, precOp, fixities,- -- * Precedences for reserved operators needed by the parser- precMin, precStart, precMax,- precCast, precCom, precDot, precSemi, precEq, precCaret, precArr,- precPlus, precStar, precAt, precApp, precBang, precTApp-) where--import Data.Char---- | Precedence and associativity, e.g. @Right 4@ is right-associative--- at level 4. Higher precedences bind tighter, with application--- at precedence 9.-type Prec = Either Int Int--precOp :: String -> Prec-precOp ('*':'*':_) = Right precAt-precOp ('-':'>':_) = Right precArr-precOp ('-':'o':_) = Right precArr-precOp "-[]>" = Right precArr-precOp (';':_) = Right precSemi-precOp "!=" = Left precEq-precOp (c:_)- | c `elem` "=<>|&$" = Left precEq- | c `elem` "*×/%" = Left precStar- | c `elem` "+-" = Left precPlus- | c `elem` "^" = Right precCaret- | c `elem` "@" = Right precAt- | c `elem` "!~?" = Right precBang- | otherwise = case generalCategory c of- CurrencySymbol -> Left precEq- MathSymbol -> Left precStar- DashPunctuation -> Left precPlus- OtherSymbol -> Left precPlus- ConnectorPunctuation -> Right precCaret- OtherPunctuation -> Right precAt- _ -> Left precApp -- defaulty-precOp "" = Left precApp--precMin, precStart, precMax,- precCast, precCom, precDot, precSemi, precEq, precCaret, precArr,- precPlus, precStar, precAt, precApp, precBang, precTApp :: Int-precMin = -2-precCast = -2 -- :>-precCom = -1 -- ,-precStart = 0-precDot = 1 -- in, else, as, of, .-precArr = 2 -- ->-precEq = 3 -- != = < > | & $-precCaret = 4 -- ^ (infixr)-precPlus = 5 -- - +-precStar = 6 -- % / *-precSemi = 7 -- ; (types only)-precAt = 8 -- @ ** (infixr)-precApp = 9 -- f x-precBang = 10 -- ! ~ ? (prefix)-precTApp = 11 -- f[t]-precMax = 11---- To find out the fixity of a precedence level-fixities :: Int -> Maybe Prec-fixities n- | n == precArr = Just $ Right precArr- | n == precEq = Just $ Left precEq- | n == precCaret= Just $ Right precCaret- | n == precPlus = Just $ Left precPlus- | n == precStar = Just $ Left precStar- | n == precSemi = Just $ Right precSemi- | n == precAt = Just $ Right precAt- | n == precBang = Just $ Right precBang- | otherwise = Nothing
− src/PrettyPrint.hs
@@ -1,180 +0,0 @@-{- | A layer over 'P.Doc' for propagating context information. (I think- Template Haskell has a version of this. -}-module PrettyPrint (- -- * Environment-parameterized pretty-printing document- Doc(..),- -- ** Environment operations- mapD, askD, asksD, localD,- -- * Document combinators- -- ** Binary operations- ($$), ($+$), (<+>), (<>),- -- ** Unary operations- braces, brackets, doubleQuotes, quotes, parens,- -- ** List operations- cat, fcat, fsep, hcat, hsep, sep, vcat,- -- ** Miscellaneous operations- nest, hang, punctuate,- -- ** Nullary operations (documents)- colon, comma, empty, equals, lbrace, lbrack,- lparen, rbrace, rbrack, rparen, semi, space,- -- *** Unary functions returning documents- char, double, float, int, integer, ptext, rational, text, zeroWidthText,- -- * Rendering and queries- toDocIn, isEmptyIn, renderIn, renderStyleIn, fullRenderIn,- toDoc, isEmpty, render, renderStyle, fullRender,- -- ** Rendering constants- P.Mode(..), P.Style(..), P.TextDetails(..), P.style-) where--import qualified Text.PrettyPrint as P-import Control.Applicative hiding (empty)-import Data.Monoid---- Document parameterized by type @e@.-newtype Doc e = Doc { unDoc :: e -> P.Doc }------- Environment manipulation-----mapD :: (e' -> e) -> Doc e -> Doc e'-mapD f d = Doc (unDoc d . f)--askD :: (e -> Doc e) -> Doc e-askD f = Doc (unDoc <$> f <*> id)--asksD :: (e -> a) -> (a -> Doc e) -> Doc e-asksD g f = askD (f . g)--localD :: e' -> Doc e' -> Doc e-localD = mapD . const------- Lifts-----liftD0 :: P.Doc -> Doc e-liftD0 = Doc . const--liftD :: (P.Doc -> P.Doc) -> Doc e -> Doc e-liftD f d = Doc (f <$> unDoc d)--liftD2 :: (P.Doc -> P.Doc -> P.Doc) ->- Doc e -> Doc e -> Doc e-liftD2 f d1 d2 = Doc (f <$> unDoc d1 <*> unDoc d2)--liftDList :: ([P.Doc] -> P.Doc) -> [Doc e] -> Doc e-liftDList f ds = Doc (\e -> f [ d e | Doc d <- ds ])------- Pretty-printing combinators-----($$), ($+$), (<+>), (<>) :: Doc e -> Doc e -> Doc e-($$) = liftD2 (P.$$)-($+$) = liftD2 (P.$+$)-(<+>) = liftD2 (P.<+>)-(<>) = liftD2 (P.<>)--braces, brackets, doubleQuotes, parens, quotes :: Doc e -> Doc e-braces = liftD P.braces-brackets = liftD P.brackets-doubleQuotes = liftD P.doubleQuotes-quotes = liftD P.quotes-parens = liftD P.parens--nest :: Int -> Doc e -> Doc e-nest = liftD . P.nest--hang :: Doc e -> Int -> Doc e -> Doc e-hang d1 n = liftD2 (flip P.hang n) d1--punctuate :: Doc e -> [Doc e] -> [Doc e]-punctuate _ [] = []-punctuate _ [d] = [d]-punctuate d1 (d:ds) = d<>d1 : punctuate d1 ds--cat, fcat, fsep, hcat, hsep, sep, vcat :: [Doc e] -> Doc e-cat = liftDList P.cat-fcat = liftDList P.fcat-fsep = liftDList P.fsep-hcat = liftDList P.hcat-hsep = liftDList P.hsep-sep = liftDList P.sep-vcat = liftDList P.vcat--char :: Char -> Doc e-double :: Double -> Doc e-float :: Float -> Doc e-int :: Int -> Doc e-integer :: Integer -> Doc e-ptext :: String -> Doc e-rational :: Rational -> Doc e-text :: String -> Doc e-zeroWidthText :: String -> Doc e--char = liftD0 . P.char-double = liftD0 . P.double-float = liftD0 . P.float-int = liftD0 . P.int-integer = liftD0 . P.integer-ptext = liftD0 . P.ptext-rational = liftD0 . P.rational-text = liftD0 . P.text-zeroWidthText = liftD0 . P.zeroWidthText--colon, comma, empty, equals, lbrace, lbrack, lparen, rbrace,- rbrack, rparen, semi, space :: Doc e-colon = liftD0 P.colon-comma = liftD0 P.comma-empty = liftD0 P.empty-equals = liftD0 P.equals-lbrace = liftD0 P.lbrace-lbrack = liftD0 P.lbrack-lparen = liftD0 P.lparen-rbrace = liftD0 P.rbrace-rbrack = liftD0 P.rbrack-rparen = liftD0 P.rparen-semi = liftD0 P.semi-space = liftD0 P.space------- Rendering and queries-----toDocIn :: e -> Doc e -> P.Doc-toDocIn = flip unDoc--isEmptyIn :: e -> Doc e -> Bool-isEmptyIn e = P.isEmpty . toDocIn e--renderIn :: e -> Doc e -> String-renderIn e = P.render . toDocIn e--renderStyleIn :: e -> P.Style -> Doc e -> String-renderStyleIn e sty = P.renderStyle sty . toDocIn e--fullRenderIn :: e ->- P.Mode -> Int -> Float ->- (P.TextDetails -> a -> a) -> a ->- Doc e -> a-fullRenderIn e mode cols ribbon f z =- P.fullRender mode cols ribbon f z . toDocIn e--toDoc :: Monoid e => Doc e -> P.Doc-toDoc = toDocIn mempty--isEmpty :: Monoid e => Doc e -> Bool-isEmpty = isEmptyIn mempty--render :: Monoid e => Doc e -> String-render = renderIn mempty--renderStyle :: Monoid e => P.Style -> Doc e -> String-renderStyle = renderStyleIn mempty--fullRender :: Monoid e =>- P.Mode -> Int -> Float ->- (P.TextDetails -> a -> a) -> a ->- Doc e -> a-fullRender = fullRenderIn mempty
− src/Printing.hs
@@ -1,78 +0,0 @@-{-# LANGUAGE- PatternGuards #-}--- Miscellaneous high-level printing routines. These can't go in, say,--- Ppr, because they depend on Rename and Statics.-module Printing (- addTyNameContext-) where--import Data.List (tails)-import PprClass-import Rename (RenameState, RenamingInfo(..),- getRenamingInfo, renamingEnterScope)-import Statics (S, getTypeInfo, staticsEnterScope)-import Syntax.Ident-import Type-import Util---- | The status of a type name in an environment-data NameStatus- -- | Bound to the expected type- = Match- -- | Not bound- | NoMatch- -- | Shadowed- | Interfere- deriving Eq---- | In the given environment, what is the status of the given--- type name?-getNameStatus :: RenameState -> S -> Int -> QLid i -> NameStatus-getNameStatus r s tag ql =- case [ ql' | TyconAt _ ql' <- getRenamingInfo ident r ] of- ql':_ ->- case getTypeInfo ql' s of- Just tc | tcId tc == tag -> Match- | otherwise -> Interfere- _ -> NoMatch- _ -> NoMatch- where ident = J (map (uid . unUid) (jpath ql))- (Var (lid (unLid (jname ql))))---- | Find the best name to refer to a type constructor.--- The goal here is to get the shortest unambiguous name.--- 1. If the first parameter is True, we want an accurate name, so--- skip to step 3.--- 2. If the unqualified name is bound to either the same type--- or to nothing, then use the unqualified name.--- 3. Try qualifiying the name, starting with the last segment--- and adding one at a time, and if any of these match, then--- use that.--- 4. Otherwise, uglify the name, because it's probably gone--- out of scope.-getBestName :: RenameState -> S ->- Int -> QLid Renamed -> QLid Renamed-getBestName r s tag ql =- case tryQuals (jpath ql) (jname ql) of- Just ql' -> ql'- _ | isTrivial (lidUnique (jname ql)),- NoMatch <- getNameStatus r s tag ql- -> ql- _ -> uglify- where- tryQuals us l = msum- [ case getNameStatus r s tag (J us' l) of- Match -> Just (J us' l)- _ -> Nothing- | us' <- reverse (tails us) ]- uglify = ql { jpath = uid ('?':show tag) : jpath ql }--makeTyNames :: RenameState -> S -> TyNames-makeTyNames r s = TyNames {- tnLookup = getBestName r s,- tnEnter = \u -> makeTyNames (renamingEnterScope u r)- (staticsEnterScope u s)-}--addTyNameContext :: RenameState -> S -> Doc -> Doc-addTyNameContext = setTyNames <$$> makeTyNames
− src/Rename.hs
@@ -1,974 +0,0 @@-{-# LANGUAGE- FlexibleContexts,- FlexibleInstances,- GeneralizedNewtypeDeriving,- MultiParamTypeClasses,- QuasiQuotes,- RankNTypes,- RelaxedPolyRec,- TemplateHaskell,- TypeSynonymInstances #-}-module Rename (- -- * The renaming monad and runners- Renaming, runRenaming, runRenamingM,- renameMapM,- -- * State between renaming steps- RenameState, renameState0,- -- ** Adding the basis- addVal, addType, addMod,- -- * Renamers- renameProg, renameDecls, renameDecl, renameType,- -- * REPL query- getRenamingInfo, RenamingInfo(..),- renamingEnterScope,-) where--import ErrorMessage--import Meta.Quasi-import Syntax hiding ((&))-import qualified Loc-import qualified Syntax.Decl-import qualified Syntax.Expr-import qualified Syntax.Notable-import qualified Syntax.Patt-import Util-import Ppr (Ppr(..))--import qualified Data.List as List-import Data.Monoid-import qualified Data.Map as M-import qualified Data.Set as S-import Control.Monad.RWS as RWST-import qualified Control.Monad.State as M.S-import Control.Monad.Error as M.E---- | The type to save the state of the renamer between calls-data RenameState = RenameState {- savedEnv :: Env,- savedCounter :: Renamed-} deriving Show---- | The initial state-renameState0 :: RenameState-renameState0 = RenameState {- savedEnv = mempty {- datacons = M.singleton (uid "()") (uid "()", mkBogus "built-in", ())- },- savedCounter = renamed0-}---- | Generate a renamer error.-renameError :: Message V -> R a-renameError msg0 = do- loc <- R (asks location)- throwAlms (AlmsException RenamerPhase loc msg0)--renameBug :: String -> String -> R a-renameBug culprit msg0 = do- loc <- R (asks location)- throwAlms (almsBug RenamerPhase loc culprit msg0)---- | The renaming monad: Reads a context, writes a module, and--- keeps track of a renaming counter state.-newtype Renaming a = R {- unR :: RWST Context Module Renamed (Either AlmsException) a-} deriving Functor--instance Monad Renaming where- return = R . return- m >>= k = R (unR m >>= unR . k)- fail = renameError . [$msg| $words:1 |]--instance Applicative Renaming where- pure = return- (<*>) = ap--instance MonadWriter Module Renaming where- listen = R . listen . unR- tell = R . tell- pass = R . pass . unR--instance MonadReader Env Renaming where- ask = R (asks env)- local f = R . local (\cxt -> cxt { env = f (env cxt) }) . unR--instance MonadError AlmsException Renaming where- throwError = R . throwError- catchError body handler =- R (catchError (unR body) (unR . handler))--instance AlmsMonad Renaming where- throwAlms = throwError- catchAlms = catchError---- | The renaming environment-data Env = Env {- tycons, vars :: !(EnvMap Lid ()),- datacons :: !(EnvMap Uid ()),- modules, sigs :: !(EnvMap Uid (Module, Env)),- tyvars :: !(EnvMap TyVar Bool)-} deriving Show--type EnvMap f i = M.Map (f Raw) (f Renamed, Loc, i)---- | A module item is one of 5 renaming entries, an empty module, r--- a pair of modules. Note that while type variables are not actual--- module items, they are exported from patterns, so it's useful to--- have them here.-data Module- = MdNil- | MdApp !Module !Module- | MdTycon !Loc !(Lid Raw) !(Lid Renamed)- | MdVar !Loc !(Lid Raw) !(Lid Renamed)- | MdDatacon !Loc !(Uid Raw) !(Uid Renamed)- | MdModule !Loc !(Uid Raw) !(Uid Renamed) !Module- | MdSig !Loc !(Uid Raw) !(Uid Renamed) !Module- | MdTyvar !Loc !(TyVar Raw) !(TyVar Renamed)- deriving Show---- | The renaming context, which includes the environment (which is--- persistant), and other information with is not-data Context = Context {- env :: !Env,- allocate :: !Bool,- location :: !Loc-}---- | Run a renaming computation-runRenaming :: Bool -> Loc -> RenameState -> Renaming a ->- Either AlmsException (a, RenameState)-runRenaming nonTrivial loc saved action = do- (result, counter, md) <-- runRWST (unR action)- Context {- env = savedEnv saved,- allocate = nonTrivial,- location = loc- }- (savedCounter saved)- let env' = savedEnv saved `mappend` envify md- return (result, RenameState env' counter)---- | Run a renaming computation-runRenamingM :: AlmsMonad m =>- Bool -> Loc -> RenameState -> Renaming a ->- m (a, RenameState)-runRenamingM = unTryAlms . return <$$$$> runRenaming---- | Alias-type R a = Renaming a--instance Monoid Env where- mempty = Env M.empty M.empty M.empty M.empty M.empty M.empty- mappend (Env a1 a2 a3 a4 a5 a6) (Env b1 b2 b3 b4 b5 b6) =- Env (a1 & b1) (a2 & b2) (a3 & b3) (a4 & b4) (a5 & b5) (a6 & b6)- where a & b = M.union b a--instance Monoid Module where- mempty = MdNil- mappend = MdApp---- | Open a module into an environment-envify :: Module -> Env-envify MdNil = mempty-envify (MdApp md1 md2) = envify md1 `mappend` envify md2-envify (MdTycon loc l l')- = mempty { tycons = M.singleton l (l', loc, ()) }-envify (MdVar loc l l')- = mempty { vars = M.singleton l (l', loc, ()) }-envify (MdDatacon loc u u')- = mempty { datacons = M.singleton u (u', loc, ()) }-envify (MdModule loc u u' md)- = mempty { modules = M.singleton u (u',loc,(md,envify md)) }-envify (MdSig loc u u' md)- = mempty { sigs = M.singleton u (u',loc,(md,envify md)) }-envify (MdTyvar loc tv tv')- = mempty { tyvars = M.singleton tv (tv',loc,True) }---- | Like 'asks', but in the 'R' monad-withContext :: (Context -> R a) -> R a-withContext = R . (ask >>=) . fmap unR---- | Run in the context of a given source location-withLoc :: Locatable loc => loc -> R a -> R a-withLoc loc =- R . local (\cxt -> cxt { location = location cxt <<@ loc }) . unR---- | Append a module to the current environment-inModule :: Module -> R a -> R a-inModule m = local (\e -> e `mappend` envify m)---- | Run in the environment consisting of only the given module-onlyInModule :: Module -> R a -> R a-onlyInModule = local (const mempty) <$$> inModule---- | Temporarily stop allocating unique ids-don'tAllocate :: R a -> R a-don'tAllocate = R . local (\cxt -> cxt { allocate = False }) . unR---- | Generate an unbound name error-unbound :: Ppr a => String -> a -> R b-unbound ns a =- renameError [$msg| $words:ns not in scope: $q:a |]---- | Generate an error about a name declared twice-repeated :: Ppr a => String -> a -> String -> [Loc] -> R b-repeated what a inwhat locs =- renameError [$msg|- $words:what $q:a- repeated $words:times in $words:inwhat $words:at- $ul:slocs- |]- where- times = case length locs of- 0 -> ""- 1 -> ""- 2 -> "twice"- 3 -> "thrice"- _ -> show (length locs) ++ " times"- at = if length locs > 1 then "at:" else ""- slocs = map [$msg| $show:1 |] locs---- | Are all keys of the list unique? If not, return a pair of--- values-unique :: Ord a => (b -> a) -> [b] -> Maybe (b, b)-unique getKey = loop M.empty where- loop _ [] = Nothing- loop seen (x:xs) =- let k = getKey x- in case M.lookup k seen of- Nothing -> loop (M.insert k x seen) xs- Just x' -> Just (x', x)---- | Grab the module produced by a computation, and--- produce no module-steal :: R a -> R (a, Module)-steal = R . censor (const mempty) . listen . unR---- | Get all the variable names, included qualified, bound in a module-getAllVariables :: Module -> [QLid Renamed]-getAllVariables = S.toList . loop where- loop (MdApp md1 md2) = loop md1 `S.union` loop md2- loop (MdVar _ _ l') = S.singleton (J [] l')- loop (MdModule _ _ u' md) = S.mapMonotonic (\(J us l) -> J (u':us) l)- (loop md)- loop _ = S.empty---- | Temporarily hide the type variables in scope, and pass the--- continuation a function to bring them back-hideTyvars :: R a -> R a-hideTyvars = local (\e -> e { tyvars = M.map each (tyvars e) })- where each (tv, loc, _) = (tv, loc, False)---- | Look up something in an environment-envLookup :: (Ord k, Show k) =>- (Env -> M.Map k k') ->- Path (Uid Raw) k ->- Env ->- Either (Maybe (Path (Uid Renamed) (Uid Raw)))- (Path (Uid Renamed) k')-envLookup prj = loop [] where- loop ms' (J [] x) e = case M.lookup x (prj e) of- Just x' -> Right (J (reverse ms') x')- Nothing -> Left Nothing- loop ms' (J (m:ms) x) e = case M.lookup m (modules e) of- Just (m', _, (_, e')) -> loop (m':ms') (J ms x) e'- Nothing -> Left (Just (J (reverse ms') m))---- | Look up something in the environment-getGenericFull :: (Ord k, Show k) =>- String -> (Env -> M.Map k k') ->- Path (Uid Raw) k -> R (Path (Uid Renamed) k')-getGenericFull what prj qx = do- e <- ask- case envLookup prj qx e of- Right qx' -> return qx'- Left Nothing -> unbound what qx- Left (Just m) -> unbound "Module" m---- | Look up something in the environment-getGeneric :: (Ord (f Raw), Show (f Raw)) =>- String -> (Env -> EnvMap f i) ->- Path (Uid Raw) (f Raw) -> R (Path (Uid Renamed) (f Renamed))-getGeneric = liftM (fmap (\(qx', _, _) -> qx')) <$$$> getGenericFull---- | Look up a variable in the environment-getVar :: QLid Raw -> R (QLid Renamed)-getVar = getGeneric "Variable" vars---- | Look up a data constructor in the environment-getDatacon :: QUid Raw -> R (QUid Renamed)-getDatacon = getGeneric "Data constructor" datacons---- | Look up a variable in the environment-getTycon :: QLid Raw -> R (QLid Renamed)-getTycon = getGeneric "Type constructor" tycons---- | Look up a module in the environment-getModule :: QUid Raw -> R (QUid Renamed, Module, Env)-getModule = liftM pull . getGenericFull "Structure" modules- where- pull (J ps (qu, _, (m, e))) = (J ps qu, m, e)---- | Look up a module in the environment-getSig :: QUid Raw -> R (QUid Renamed, Module, Env)-getSig = liftM pull . getGenericFull "Signature" sigs- where- pull (J ps (qu, _, (m, e))) = (J ps qu, m, e)---- | Look up a variable in the environment-getTyvar :: TyVar Raw -> R (TyVar Renamed)-getTyvar tv = do- e <- asks tyvars- case M.lookup tv e of- Nothing -> unbound "Type variable" tv- Just (tv', _, True) -> return tv'- Just (_, loc, False) -> renameError [$msg|- Type variable $tv not in scope.- <indent>- (It was bound at $loc, but a nested declaration- cannot see type variables from its parent expression.)- </indent>- |]---- | Get a new name for a variable binding-bindGeneric :: (Ord ident, Show ident, Antible ident) =>- (Renamed -> ident -> ident') ->- (Loc -> ident -> ident' -> Module) ->- ident -> R ident'-bindGeneric ren build x = R $ do- case prjAnti x of- Just a -> $antifail- Nothing -> return ()- doAlloc <- asks allocate- x' <- if doAlloc- then do- counter <- get- put (succ counter)- return (ren counter x)- else do- return (ren trivialId x)- loc <- asks location- tell (build loc x x')- return x'---- | Get a new name for a variable binding-bindVar :: Lid Raw -> R (Lid Renamed)-bindVar = bindGeneric (\r -> Lid r . unLid) MdVar---- | Get a new name for a variable binding-bindTycon :: Lid Raw -> R (Lid Renamed)-bindTycon = bindGeneric (\r -> Lid r . unLid) MdTycon---- | Get a new name for a data constructor binding-bindDatacon :: Uid Raw -> R (Uid Renamed)-bindDatacon = bindGeneric (\r -> Uid r . unUid) MdDatacon---- | Get a new name for a module, and bind it in the environment-bindModule :: Uid Raw -> Module -> R (Uid Renamed)-bindModule u0 md = bindGeneric (\r -> Uid r . unUid) build u0- where build loc old new = MdModule loc old new md---- | Get a new name for a signature, and bind it in the environment-bindSig :: Uid Raw -> Module -> R (Uid Renamed)-bindSig u0 md = bindGeneric (\r -> Uid r . unUid) build u0- where build loc old new = MdSig loc old new md---- | Add a type variable to the scope-bindTyvar :: TyVar Raw -> R (TyVar Renamed)-bindTyvar = bindGeneric (\r (TV l q) -> TV (Lid r (unLid l)) q) MdTyvar---- | Map a function over a list, allowing the exports of each item--- to be in scope for the rest-renameMapM :: (a -> R b) -> [a] -> R [b]-renameMapM _ [] = return []-renameMapM f (x:xs) = do- (x', md) <- listen (f x)- xs' <- inModule md $ renameMapM f xs- return (x':xs')---- | Rename a program-renameProg :: Prog Raw -> R (Prog Renamed)-renameProg [$prQ| $list:ds in $opt:me1 |] = do- (ds', md) <- listen $ renameDecls ds- me1' <- inModule md $ gmapM renameExpr me1- return [$prQ|+ $list:ds' in $opt:me1' |]---- | Rename a list of declarations and return the environment--- that they bind-renameDecls :: [Decl Raw] -> R [Decl Renamed]-renameDecls = renameMapM renameDecl---- | Rename a declaration and return the environment that it binds-renameDecl :: Decl Raw -> R (Decl Renamed)-renameDecl d0 = withLoc d0 $ case d0 of- [$dc| let $x : $opt:mt = $e |] -> do- x' <- renamePatt x- mt' <- gmapM renameType (fmap closeType mt)- e' <- renameExpr (closeExpr e)- return [$dc|+ let $x' : $opt:mt' = $e' |]- [$dc| type $list:tds |] -> do- tds' <- renameTyDecs tds- return [$dc|+ type $list:tds' |]- [$dc| abstype $list:ats with $list:ds end |] -> do- let bindEach [$atQ| $anti:a |] = $antifail- bindEach (N _ (AbsTy _ _ [$tdQ| $anti:a |])) = $antifail- bindEach (N note at) = withLoc note $ do- let l = (tdName (dataOf (atdecl at)))- bindTycon l- return (l, getLoc note)- (llocs, mdT) <- listen $ mapM bindEach ats- case unique fst llocs of- Nothing -> return ()- Just ((l, loc1), (_, loc2)) ->- repeated "Type declaration for" l "abstype group" [loc1, loc2]- (ats', mdD) <-- steal $- inModule mdT $- forM ats $ \at -> withLoc at $ case dataOf at of- AbsTy variances qe td -> do- (Just qe', td') <- renameTyDec (Just qe) td- return (absTy variances qe' td' <<@ at)- AbsTyAnti a -> $antifail- -- Don't tell mdD upward, since we're censoring the datacons- ds' <- inModule (mdT `mappend` mdD) $ renameDecls ds- return [$dc|+ abstype $list:ats' with $list:ds' end |]- [$dc| module INTERNALS = $me1 |] ->- R $ local (\context -> context { allocate = False }) $ unR $ do- let u = uid "INTERNALS"- (me1', md) <- steal $ renameModExp me1- u' <- bindModule u md- return [$dc|+ module $uid:u' = $me1' |]- [$dc| module $uid:u = $me1 |] -> do- (me1', md) <- steal $ renameModExp me1- u' <- bindModule u md- return [$dc|+ module $uid:u' = $me1' |]- [$dc| module type $uid:u = $se1 |] -> do- (se1', md) <- steal $ renameSigExp se1- u' <- bindSig u md- return [$dc|+ module type $uid:u' = $se1' |]- [$dc| open $me1 |] -> do- me1' <- renameModExp me1- return [$dc|+ open $me1' |]- [$dc| local $list:ds1 with $list:ds2 end |] -> do- (ds1', md) <- steal $ renameDecls ds1- ds2' <- inModule md $ renameDecls ds2- return [$dc| local $list:ds1' with $list:ds2' end |]- [$dc| exception $uid:u of $opt:mt |] -> do- u' <- bindDatacon u- mt' <- gmapM renameType mt- return [$dc|+ exception $uid:u' of $opt:mt' |]- [$dc| $anti:a |] -> $antifail--renameTyDecs :: [TyDec Raw] -> R [TyDec Renamed]-renameTyDecs tds = do- let bindEach [$tdQ| $anti:a |] = $antifail- bindEach (N note td) = withLoc note $ do- bindTycon (tdName td)- return (tdName td, getLoc note)- (llocs, md) <- listen $ mapM bindEach tds- case unique fst llocs of- Nothing -> return ()- Just ((l, loc1), (_, loc2)) ->- repeated "Type declaration for" l "type group" [loc1, loc2]- inModule md $ mapM (liftM snd . renameTyDec Nothing) tds--renameTyDec :: Maybe (QExp Raw) -> TyDec Raw ->- R (Maybe (QExp Renamed), TyDec Renamed)-renameTyDec _ (N _ (TdAnti a)) = $antierror-renameTyDec mqe (N note (TdSyn l clauses)) = withLoc note $ do- case mqe of- Nothing -> return ()- Just _ ->- renameBug "renameTyDec" "can’t rename QExp in context of type synonym"- J [] l' <- getTycon (J [] l)- clauses' <- forM clauses $ \(ps, rhs) -> withLoc ps $ do- (ps', md) <- steal $ renameTyPats ps- rhs' <- inModule md $ renameType rhs- return (ps', rhs')- return (Nothing, tdSyn l' clauses' <<@ note)-renameTyDec mqe (N note td) = withLoc note $ do- J [] l' <- getTycon (J [] (tdName td))- let tvs = tdParams td- case unique id tvs of- Nothing -> return ()- Just (tv, _) ->- repeated "Type variable" tv "type parameters" []- (tvs', mdTvs) <- steal $ mapM bindTyvar tvs- inModule mdTvs $ do- mqe' <- gmapM renameQExp mqe- td' <- case td of- TdAbs _ _ variances qe -> do- qe' <- renameQExp qe- return (tdAbs l' tvs' variances qe')- TdSyn _ _ -> renameBug "renameTyDec" "unexpected TdSyn"- TdDat _ _ cons -> do- case unique fst cons of- Nothing -> return ()- Just ((u, _), (_, _)) ->- repeated "Data constructor" u "type declaration" []- cons' <- forM cons $ \(u, mt) -> withLoc mt $ do- let u' = uid (unUid u)- tell (MdDatacon (getLoc mt) u u')- mt' <- gmapM renameType mt- return (u', mt')- return (tdDat l' tvs' cons')- TdAnti a -> $antifail- return (mqe', td' <<@ note)--renameModExp :: ModExp Raw -> R (ModExp Renamed)-renameModExp me0 = withLoc me0 $ case me0 of- [$me| struct $list:ds end |] -> do- ds' <- renameDecls ds- return [$me|+ struct $list:ds' end |]- [$me| $quid:qu $list:_ |] -> do- (qu', md, _) <- getModule qu- let qls = getAllVariables md- tell md- return [$me|+ $quid:qu' $list:qls |]- [$me| $me1 : $se2 |] -> do- (me1', md1) <- steal $ renameModExp me1- (se2', md2) <- steal $ renameSigExp se2- onlyInModule md1 $ sealWith md2- return [$me| $me1' : $se2' |]- [$me| $anti:a |] -> $antifail--renameSigExp :: SigExp Raw -> R (SigExp Renamed)-renameSigExp se0 = withLoc se0 $ case se0 of- [$seQ| sig $list:sgs end |] -> do- (sgs', md) <- listen $ don'tAllocate $ renameMapM renameSigItem sgs- onlyInModule mempty $ checkSigDuplicates md- return [$seQ|+ sig $list:sgs' end |]- [$seQ| $quid:qu $list:_ |] -> do- (qu', md, _) <- getSig qu- let qls = getAllVariables md- tell md- return [$seQ|+ $quid:qu' $list:qls |]- [$seQ| $se1 with type $list:tvs $qlid:ql = $t |] -> do- (se1', md) <- listen $ renameSigExp se1- ql' <- onlyInModule md $ getTycon ql- case unique id tvs of- Nothing -> return ()- Just (tv, _) -> repeated "Type variable" tv "with-type" []- (tvs', mdtvs) <- steal $ mapM bindTyvar tvs- t' <- inModule mdtvs $ renameType t- return [$seQ|+ $se1' with type $list:tvs' $qlid:ql' = $t' |]- [$seQ| $anti:a |] -> $antifail--checkSigDuplicates :: Module -> R ()-checkSigDuplicates md = case md of- MdNil -> return ()- MdApp md1 md2 -> do- checkSigDuplicates md1- inModule md1 $ checkSigDuplicates md2- MdTycon loc l _ -> mustFail loc "Type" l $ getTycon (J [] l)- MdVar loc l _ -> mustFail loc "Variable" l $ getVar (J [] l)- MdDatacon loc u _ -> mustFail loc "Constructor" u $ getDatacon (J [] u)- MdModule loc u _ _ -> mustFail loc "Structure" u $ getModule (J [] u)- MdSig loc u _ _ -> mustFail loc "Signature" u $ getSig (J [] u)- MdTyvar loc tv _ -> mustFail loc "Tyvar" tv $ getTyvar tv- where- mustFail loc kind which check = do- failed <- (False <$ check) `M.E.catchError` \_ -> return True- unless failed $ do- withLoc loc $- repeated kind which "signature" []--sealWith :: Module -> R ()-sealWith = loop Nothing where- loop b md = case md of- MdNil -> return ()- MdApp md1 md2 -> do loop b md1; loop b md2- MdTycon _ l _ -> do- (l', loc, _) <- find b "type constructor" tycons l- tell (MdTycon loc l l')- MdVar _ l _ -> do- (l', loc, _) <- find b "variable" vars l- tell (MdVar loc l l')- MdDatacon _ u _ -> do- (u', loc, _) <- find b "data constructor" datacons u- tell (MdDatacon loc u u')- MdModule _ u _ md2 -> do- (u', loc, (md1, _)) <- find b "module" modules u- ((), md1') <- steal $ onlyInModule md1 $ loop b md2- tell (MdModule loc u u' md1')- MdSig _ u _ md2 -> do- (u', loc, (md1, _)) <- find b "module type" sigs u- ((), _ ) <- steal $ onlyInModule md2 $ loop (Just (Left u)) md1- ((), md1') <- steal $ onlyInModule md1 $ loop (Just (Right u)) md2- tell (MdSig loc u u' md1')- MdTyvar _ _ _ ->- renameBug "sealWith" "signature can’t declare type variable"- find b what prj ident = do- m <- asks prj- case M.lookup ident m of- Just ident' -> return ident'- Nothing -> renameError $- case b of- Nothing -> [$msg|- In signature matching, structure is missing- $words:what $q:ident,- which is present in ascribed signature.- |]- Just (Left u) -> [$msg|- In exact signature matching (for nested signature $u)- found unexpected $words:what $q:ident.- |]- Just (Right u) -> [$msg|- In exact signature matching (for nested signature $u)- missing expected $words:what $q:ident.- |]---- | Rename a signature item and return the environment--- that they bind-renameSigItem :: SigItem Raw -> R (SigItem Renamed)-renameSigItem sg0 = case sg0 of- [$sgQ| val $lid:l : $t |] -> do- l' <- bindVar l- t' <- renameType (closeType t)- return [$sgQ|+ val $lid:l' : $t' |]- [$sgQ| type $list:tds |] -> do- tds' <- renameTyDecs tds- return [$sgQ|+ type $list:tds' |]- [$sgQ| module $uid:u : $se1 |] -> do- (se1', md) <- steal $ renameSigExp se1- u' <- bindModule u md- return [$sgQ|+ module $uid:u' : $se1' |]- [$sgQ| module type $uid:u = $se1 |] -> do- (se1', md) <- steal $ renameSigExp se1- u' <- bindSig u md- return [$sgQ|+ module type $uid:u' = $se1' |]- [$sgQ| include $se1 |] -> do- se1' <- renameSigExp se1- return [$sgQ|+ include $se1' |]- [$sgQ| exception $uid:u of $opt:mt |] -> do- u' <- bindDatacon u- mt' <- gmapM renameType mt- return [$sgQ|+ exception $uid:u' of $opt:mt' |]- [$sgQ| $anti:a |] -> $antifail---- | Rename an expression-renameExpr :: Expr Raw -> R (Expr Renamed)-renameExpr e0 = withLoc e0 $ case e0 of- [$ex| $id:x |] -> case view x of- Left ql -> do- ql' <- getVar ql- let x' = fmap Var ql'- return [$ex|+ $id:x' |]- Right qu -> do- qu' <- getDatacon qu- let x' = fmap Con qu'- return [$ex|+ $id:x' |]- [$ex| $lit:lit |] -> do- lit' <- renameLit lit- return [$ex|+ $lit:lit' |]- [$ex| match $e1 with $list:cas |] -> do- e1' <- renameExpr e1- cas' <- mapM renameCaseAlt cas- return [$ex|+ match $e1' with $list:cas' |]- [$ex| let rec $list:bns in $e |] -> do- (bns', md) <- renameBindings bns- e' <- inModule md $ renameExpr e- return [$ex|+ let rec $list:bns' in $e' |]- [$ex| let $decl:d in $e |] -> do- (d', md) <- steal $ hideTyvars $ renameDecl d- e' <- inModule md (renameExpr e)- return [$ex|+ let $decl:d' in $e' |]- [$ex| ($e1, $e2) |] -> do- e1' <- renameExpr e1- e2' <- renameExpr e2- return [$ex|+ ($e1', $e2') |]- [$ex| fun $x : $t -> $e |] -> do- t' <- renameType t- (x', md) <- steal $ renamePatt x- e' <- inModule md $ renameExpr e- return [$ex|+ fun $x' : $t' -> $e' |]- [$ex| $e1 $e2 |] -> do- e1' <- renameExpr e1- e2' <- renameExpr e2- return [$ex|+ $e1' $e2' |]- [$ex| fun '$tv -> $e |] -> do- (tv', md) <- steal $ bindTyvar tv- e' <- inModule md $ renameExpr e- return [$ex|+ fun '$tv' -> $e' |]- [$ex| $e [$t] |] -> do- e' <- renameExpr e- t' <- renameType t- return [$ex|+ $e' [$t'] |]- [$ex| Pack[$opt:mt]($t, $e) |] -> do- mt' <- gmapM renameType mt- t' <- renameType t- e' <- renameExpr e- return [$ex|+ Pack[$opt:mt']($t', $e') |]- [$ex| ( $e : $t) |] -> do- e' <- renameExpr e- t' <- renameType t- return [$ex| ( $e' : $t' ) |]- [$ex| ( $e :> $t) |] -> do- e' <- renameExpr e- t' <- renameType t- return [$ex| ( $e' :> $t' ) |]- [$ex| $anti:a |] -> $antifail---- | Rename a literal (no-op, except fails on antiquotes)-renameLit :: Lit -> R Lit-renameLit lit0 = case lit0 of- LtAnti a -> $antifail- _ -> return lit0---- | Rename a case alternative-renameCaseAlt :: CaseAlt Raw -> R (CaseAlt Renamed)-renameCaseAlt ca0 = withLoc ca0 $ case ca0 of- [$caQ| $x -> $e |] -> do- (x', md) <- steal $ renamePatt x- e' <- inModule md $ renameExpr e- return [$caQ|+ $x' -> $e' |]- [$caQ| $antiC:a |] -> $antifail---- | Rename a set of let rec bindings-renameBindings :: [Binding Raw] -> R ([Binding Renamed], Module)-renameBindings bns = do- lxtes <- forM bns $ \bn ->- case bn of- [$bnQ| $lid:x : $t = $e |] -> return (_loc, x, t, e)- [$bnQ| $antiB:a |] -> $antifail- case unique (\(_,x,_,_) -> x) lxtes of- Nothing -> return ()- Just ((l1,x,_,_),(l2,_,_,_)) ->- repeated "Variable binding for" x "let-rec" [l1, l2]- let bindEach rest (l,x,t,e) = withLoc l $ do- x' <- bindVar x- return ((l,x',t,e):rest)- (lxtes', md) <- steal $ foldM bindEach [] lxtes- bns' <- inModule md $- forM (reverse lxtes') $ \(l,x',t,e) -> withLoc l $ do- let _loc = l- t' <- renameType t- e' <- renameExpr e- return [$bnQ|+ $lid:x' : $t' = $e' |]- return (bns', md)---- | Rename a type-renameType :: Type Raw -> R (Type Renamed)-renameType t0 = case t0 of- [$ty| ($list:ts) $qlid:ql |] -> do- ql' <- getTycon ql- ts' <- mapM renameType ts- return [$ty|+ ($list:ts') $qlid:ql' |]- [$ty| '$tv |] -> do- tv' <- getTyvar tv- return [$ty|+ '$tv' |]- [$ty| $t1 -[$opt:mqe]> $t2 |] -> do- t1' <- renameType t1- mqe' <- gmapM renameQExp mqe- t2' <- renameType t2- return [$ty|+ $t1' -[$opt:mqe']> $t2' |]- [$ty| $quant:u '$tv. $t |] -> do- (tv', md) <- steal $ bindTyvar tv- t' <- inModule md $ renameType t- return [$ty|+ $quant:u '$tv'. $t' |]- [$ty| mu '$tv. $t |] -> do- (tv', md) <- steal $ bindTyvar tv- t' <- inModule md $ renameType t- return [$ty|+ mu '$tv'. $t' |]- [$ty| $anti:a |] -> $antifail---- | Rename a type pattern-renameTyPats :: [TyPat Raw] -> R [TyPat Renamed]-renameTyPats x00 =- withLoc x00 $- M.S.evalStateT (mapM loop x00) M.empty where- loop :: TyPat Raw ->- M.S.StateT (M.Map (TyVar Raw) Loc) Renaming (TyPat Renamed)- loop x0 = case x0 of- [$tpQ| $antiP:a |] -> $antifail- N note (TpVar tv var) -> do- tv' <- tyvar (getLoc note) tv- return (tpVar tv' var <<@ note)- [$tpQ| ($list:tps) $qlid:ql |] -> do- ql' <- lift (withLoc _loc (getTycon ql))- tps' <- mapM loop tps- return [$tpQ|+ ($list:tps') $qlid:ql' |]- --- tyvar :: Loc -> TyVar Raw ->- M.S.StateT (M.Map (TyVar Raw) Loc) Renaming (TyVar Renamed)- tyvar loc1 tv = do- seen <- get- case M.lookup tv seen of- Just loc2 ->- lift (repeated "Type variable" tv "type pattern" [loc1, loc2])- Nothing -> do- put (M.insert tv loc1 seen)- lift (bindTyvar tv)---- | Rename a qualifier expression-renameQExp :: QExp Raw -> R (QExp Renamed)-renameQExp qe0 = case qe0 of- [$qeQ| $qlit:qlit |] -> do- return [$qeQ|+ $qlit:qlit |]- [$qeQ| $qvar:tv |] -> do- tv' <- getTyvar tv- return [$qeQ| $qvar:tv' |]- [$qeQ| $qdisj:qes |] -> do- qes' <- mapM renameQExp qes- return [$qeQ| $qdisj:qes' |]- [$qeQ| $qconj:qes |] -> do- qes' <- mapM renameQExp qes- return [$qeQ| $qconj:qes' |]- [$qeQ| $anti:a |] -> do- $antifail---- | Rename a pattern-renamePatt :: Patt Raw -> R (Patt Renamed)-renamePatt x00 =- withLoc x00 $- M.S.evalStateT (loop x00) M.empty where- loop :: Patt Raw ->- M.S.StateT (M.Map (Either (Lid Raw) (TyVar Raw)) Loc)- Renaming (Patt Renamed)- loop x0 = case x0 of- [$pa| _ |] ->- return [$pa|+ _ |]- [$pa| $lid:l |] -> do- l' <- var _loc l- return [$pa|+ $lid:l' |]- [$pa| $quid:qu |] -> do- qu' <- lift $ getDatacon qu- return [$pa|+ $quid:qu' |]- [$pa| $quid:qu $x |] -> do- qu' <- lift $ getDatacon qu- x' <- loop x- return [$pa|+ $quid:qu' $x' |]- [$pa| ($x1, $x2) |] -> do- x1' <- loop x1- x2' <- loop x2- return [$pa|+ ($x1', $x2') |]- [$pa| $lit:lit |] -> do- lit' <- lift $ renameLit lit- return [$pa|+ $lit:lit' |]- [$pa| $x as $lid:l |] -> do- x' <- loop x- l' <- var _loc l- return [$pa|+ $x' as $lid:l' |]- [$pa| Pack('$tv, $x) |] -> do- tv' <- tyvar _loc tv- x' <- loop x- return [$pa|+ Pack('$tv', $x') |]- [$pa| $anti:a |] -> do- $antifail- --- var loc1 l = do- seen <- get- case M.lookup (Left l) seen of- Just loc2 -> lift (repeated "Variable" l "pattern" [loc1, loc2])- Nothing -> do- put (M.insert (Left l) loc1 seen)- lift (withLoc loc1 (bindVar l))- --- tyvar loc1 tv = do- seen <- get- case M.lookup (Right tv) seen of- Just loc2 -> lift (repeated "Type variable" tv "pattern" [loc1, loc2])- Nothing -> do- put (M.insert (Right tv) loc1 seen)- lift (bindTyvar tv)---- | Univerally-quantify all free type variables-closeType :: Type Raw -> Type Raw-closeType t = foldr tyAll t (ftvList t)---- | Add type abstractions for free type variables in--- function arguments-closeExpr :: Expr Raw -> Expr Raw-closeExpr e = foldr exTAbs e (ftvList e)--class FtvList a where- ftvList :: a -> [TyVar Raw]--instance FtvList a => FtvList [a] where- ftvList = foldr List.union [] . map ftvList--instance FtvList a => FtvList (Maybe a) where- ftvList = maybe [] ftvList---- | Get the free type variables in a QExp, in order of appearance-instance FtvList (QExp Raw) where- ftvList qe0 = case qe0 of- [$qeQ| $qlit:_ |] -> []- [$qeQ| '$tv |] -> [tv]- [$qeQ| $qdisj:qes |] -> ftvList qes- [$qeQ| $qconj:qes |] -> ftvList qes- [$qeQ| $anti:a |] -> $antierror---- | Get the free type variables in a type, in order of appearance-instance FtvList (Type Raw) where- ftvList t0 = case t0 of- [$ty| ($list:ts) $qlid:_ |] -> ftvList ts- [$ty| '$tv |] -> [tv]- [$ty| $t1 -[$opt:mqe]> $t2 |] ->- ftvList t1 `List.union` ftvList mqe `List.union` ftvList t2- [$ty| $quant:_ '$tv. $t |] -> List.delete tv (ftvList t)- [$ty| mu '$tv. $t |] -> List.delete tv (ftvList t)- [$ty| $anti:a |] -> $antierror--instance FtvList (Expr Raw) where- ftvList e0 = case e0 of- [$ex| fun ($_ : $t) -> $e |] ->- ftvList t `List.union` ftvList e- [$ex| fun '$tv -> $e |] ->- List.delete tv (ftvList e)- _ -> []--addVal :: Lid Raw -> R (Lid Renamed)-addType :: Lid Raw -> Renamed -> R (Lid Renamed)-addMod :: Uid Raw -> R a -> R (Uid Renamed, a)--addVal = bindVar--addType l i = do- let l' = Lid i (unLid l)- loc <- R $ asks location- tell (MdTycon loc l l')- return l'--addMod u body = do- let u' = uid (unUid u)- (a, md) <- steal body- loc <- R $ asks location- tell (MdModule loc u u' md)- return (u', a)---- | Result for 'getRenamingInfo'-data RenamingInfo- = ModuleAt { renInfoLoc :: Loc, renInfoQUid :: QUid Renamed }- | SigAt { renInfoLoc :: Loc, renInfoQUid :: QUid Renamed }- | VariableAt { renInfoLoc :: Loc, renInfoQLid :: QLid Renamed }- | TyconAt { renInfoLoc :: Loc, renInfoQLid :: QLid Renamed }- | DataconAt { renInfoLoc :: Loc, renInfoQUid :: QUid Renamed }- deriving Show---- | For the REPL to find out where identifiers are bound and their--- renamed name for looking up type info-getRenamingInfo :: Ident Raw -> RenameState -> [RenamingInfo]-getRenamingInfo ident RenameState { savedEnv = e } =- catMaybes $ case view ident of- Left ql -> [ look tycons ql TyconAt,- look vars ql VariableAt ]- Right qu -> [ look sigs qu SigAt,- look modules qu ModuleAt,- look datacons qu DataconAt ]- where- look prj qx build = case envLookup prj qx e of- Left _ -> Nothing- Right (J ps (x', loc, _)) -> Just (build loc (J ps x'))---- Open the given module, if it exists.-renamingEnterScope :: Uid i -> RenameState -> RenameState-renamingEnterScope u r =- let e = savedEnv r in- case M.lookup (uid (unUid u)) (modules e) of- Nothing -> r- Just (_, _, (_, e'))- -> r { savedEnv = e `mappend` e' }-
− src/Sigma.hs
@@ -1,519 +0,0 @@-{-# LANGUAGE- GeneralizedNewtypeDeriving,- PatternGuards,- ViewPatterns #-}-module Sigma (- makeBangPatt, parseBangPatt, exSigma-) where--import Syntax-import Util--import qualified Control.Monad.State as CMS-import Data.Generics (Data, everywhere, mkT, extT)-import qualified Data.List as L-import qualified Data.Map as M-import qualified Data.Set as S-import Data.Foldable (Foldable, toList)---- | To lift a binder to bind effect variables rather than--- normal variables. (Boolean specifies whether the result--- should include the effect variables.)-exSigma :: Id i =>- Bool ->- (Patt i -> Expr i -> a) ->- Patt i -> Expr i -> a-exSigma ret binder patt body =- let (b_vars, b_code) = transform (dv patt) body in- binder (ren patt) $- exLet' (paVar r1 -:: b_vars) b_code $- if ret- then exPair (exBVar r1) (patt2expr (ren (flatpatt patt)))- else exBVar r1---- | To lift a binder to bind effect variables rather than--- normal variables.-exAddSigma :: Id i =>- Bool ->- ([Lid i] -> Patt i -> Expr i -> a) ->- S.Set (Lid i) -> Patt i -> Expr i -> a-exAddSigma ret binder env patt body =- let env' = dv patt- (b_vars, b_code) = transform (env' `S.union` env) body- vars = [ v | v <- b_vars, v `S.notMember` ren env' ]- in binder vars (ren patt) $- exLet' (paVar r1 -:: b_vars) b_code $- if ret- then exPair (exBVar r1) (patt2expr (ren (flatpatt patt))) +:: vars- else exBVar r1 +:: vars--{------ The one variable case:-- (x is the variable name, y is the fresh state name)-- fun !(x:t) -> e === fun y:t -> [[ e ]]- let !x = e1 in e2 === let y = e1 in [[ e ]]-- [[ e1 x ]] = let (r, y) = [[ e1 ]] in- r y- [[ e1 e2 ]] = let (r1, y) = [[ e1 ]] in- let (r2, y) = [[ e2 ]] in- (r1 r2, y)- [[ x ]] = (y, ())- [[ v ]] = (v, y)- [[ match e with- | p1 -> e1- | ...- | pk -> ek ]]- = let (r, y) = [[ e ]] in- match r with- | p1 -> [[ e1 ]]- | ...- | pk -> [[ ek ]]- [[ e [t] ]] = let (r, y) = [[ e ]] in- (r [t], y)- [[ c e ]] = let (r, y) = [[ e ]] in- (c r, y)---- The pattern case (2):-- (p! is a renaming of p)-- fun !(p:t) -> e === fun p!:t -> - let (r1, e.vars) = e.code- in (r1, p!)- where e.env = dv p in- let !p = e1 in e2 === let p! = e1 in- let (r1, e.vars) = e.code- in (r1, p!)- where e.env = dv p in-- e ::= e1 p2 | dv p2 `subseteq` dv e.env && dv p2 != empty-- e1.env = e.env- e.vars = e1.vars `union` dv p2!- e.code = let (r1, e1.vars) = e1.code in- let (r2, p2!) = r1 p2! in- (r2, e.vars)-- e ::= e1 e2-- e1.env = e2.env = e.env- e.vars = e1.vars `union` e2.vars- e.code = let (r1, e1.vars) = e1.code in- let (r2, e2.vars) = e2.code in- (r1 r2, e.vars)-- e ::= x | x `member` dv p-- e.vars = x!- e.code = (x!, ())-- e ::= v-- e.vars = fv v `intersect` env- e.code = let e.vars = e.vars! in- (v, [ () | _ <- e.vars ])-- e ::= match p0 with- | p1 -> e1- | ...- | pk -> ek- | dv p0 `subseteq` dv e.env && dv p0 != empty-- if p1 is a bang pattern- then e1.env = e.env `union` dv p1- else e1.env = e.env - (dv p1 - dv p0)- ...- if pk is a bang pattern- then ek.env = e.env `union` dv pk- else ek.env = e.env - (dv pk - dv p0)-- e.vars = e.env `intersection` (e1.vars `union` ... `union` ek.vars)- e.code = match p0! with- | p1[p0!/p0] -> let (p0 - p1)! = ((), ..., ()) in- let (r2, e1.vars) = e1.code in (r2, e.vars)- | ...- (if pk is not a bang pattern then)- | pk[p0!/p0] -> let (p0 - pk)! = ((), ..., ()) in- let (r2, e1.vars) = e1.code in (r2, e.vars)- (else)- | pk! -> let (p0 - pk)! = ((), ..., ()) in- let (r2, e1.vars) = e1.code in (r2, e.vars)-- e ::= match e0 with- | p1 -> e1- | ...- | pk -> ek-- e0.env = e.env- e1.env = e.env - dv p1- ...- ek.env = e.env - dv pk-- e.vars = e.env `intersection`- (e0.vars `union` e1.vars `union` ... `union` ek.vars)- e.code = let (r1, e0.vars) = e0.code in- match r1 with- | p1 -> let (r2, e1.vars) = e1.code in (r2, e.vars)- | ...- | pk -> let (r2, ek.vars) = ek.code in (r2, e.vars)-- e ::= let rec f1 = v1- and ...- and fk = vk- in e1-- captured = { x `in` (fv v1 `union` ... `union` fv vk)- | x! `in` e.env }-- e1.env = e.env - { f1, ..., fk }- e.vars = e1.vars `union` captured!- e.code = let captured = captured! in- let captured! = ((), ..., ()) in- let rec f1 = v1- and ...- and fk = vk- in let (r1, e1.vars) = e1.code- in (r1, e.vars)-- e ::= e1[t]-- e1.env = e.env- e.vars = e1.vars- e.code = let (r1, e1.vars) = e1.code in- (r1[t], e.vars)-- e ::= let !p1 = e1 in e2-- e1.env = e.env- e2.env = e.env `union` dv p1- e.vars = e1.vars `union` (e2.vars `intersection` e.env)- e.code = let (p1!, e1.vars) = e1.code in- let (r2, e2.vars) = e2.code in- ((r2, p1!), e.vars)- [assuming no shadowing]--}--transform :: Id i => S.Set (Lid i) -> Expr i -> ([Lid i], Expr i)-transform env = loop where- capture e1- | vars <- [ v | J [] v <- M.keys (fv e1),- v `S.member` env ],- code <- translate paVar (exBVar . ren) vars .- kill (ren vars)- = Just (ren vars, code)- | otherwise- = Nothing-- unop kont (e1_vars, e1_code)- | Just (k_vars, k_code) <- capture (kont exUnit),- vars <- k_vars `L.union` e1_vars,- code <- k_code $- exLet' (paVar r1 -:: e1_vars) e1_code $- (kont (exBVar r1) +:: vars)- = (vars, code)- unop kont ([], e1_code)- = ([], kont e1_code +:: [])- unop kont (e1_vars, e1_code)- | vars <- e1_vars,- code <- exLet' (paPair (paVar r1) (paVar r2)) e1_code $- exPair (kont (exBVar r1)) (exBVar r2)- = (vars, code)-- binder kont (e1_vars, e1_code)- | Just (k_vars, k_code) <- capture (kont exUnit),- vars <- k_vars `L.union` e1_vars,- code <- k_code $- kont $- exLet' (paVar r1 -:: e1_vars) e1_code $- (exBVar r1 +:: vars)- = (vars, code)- | vars <- e1_vars,- code <- kont e1_code- = (vars, code)-- binop kont e1 e2 =- case (loop e1, loop e2) of- (([], e1_code), ([], e2_code))- -> ([], kont e1_code e2_code +:: [])- (([], e1_code), (e2_vars, e2_code))- | syntacticValue e1_code,- vars <- e2_vars,- code <- exLet' (paVar r2 -:: e2_vars) e2_code $- kont e1_code (exBVar r2) +:: vars- -> (vars, code)- ((e1_vars, e1_code), ([], e2_code))- | syntacticValue e2_code,- vars <- e1_vars,- code <- exLet' (paVar r1 -:: e1_vars) e1_code $- kont (exBVar r1) e2_code +:: vars- -> (vars, code)- ((e1_vars, e1_code), (e2_vars, e2_code))- | vars <- e1_vars `L.union` e2_vars,- code <- exLet' (paVar r1 -:: e1_vars) e1_code $- exLet' (paVar r2 -:: e2_vars) e2_code $- kont (exBVar r1) (exBVar r2) +:: vars- -> (vars, code)-- shadow vs e = transform (env `S.difference` vs) e-- loop e = let (vars, e') = loop' e in (vars, e' <<@ e)-- loop' e = case view e of- ExId (J [] (Var x))- | x `S.member` env,- vars <- [ren x]- -> (vars, ren (exBVar x) +:+ [exUnit])-- ExCase e0 bs- | Just p0 <- expr2patt env S.empty e0,- not (dv p0 `disjoint` env),- e0_vars <- toList (dv (ren p0)),- e0_code <- ren e0,- bs' <-- [ case parseBangPatt pj of- Nothing ->- (renOnly (dv p0) pj,- shadow (dv pj `S.difference` dv p0) ej)- Just pj' ->- (ren pj',- transform (env `S.union` dv pj) ej)- | N _ (CaClause pj ej) <- bs ],- vars <- [ v | v <- foldl L.union e0_vars (map (fst . snd) bs'),- v `S.member` ren env ],- code <- exCase e0_code $- [ caClause pj (kill (dv (ren p0) `S.difference` dv pj) $- exLet' (paVar r1 -:: ej_vars) ej_code $- (exBVar r1 +:: vars))- | (pj, (ej_vars, ej_code)) <- bs' ]- -> (vars, code)-- | (e0_vars, e0_code) <- loop e0,- bs' <-- [ case parseBangPatt pj of- Nothing -> (pj, shadow (dv pj) ej)- Just pj' -> exAddSigma- (length bs == 1)- (\vars patt expr -> (patt, (vars, expr)))- env pj' ej- | N _ (CaClause pj ej) <- bs ],- vars <- foldl L.union e0_vars (map (fst . snd) bs'),- code <- exLet' (paVar r1 -:: e0_vars) e0_code $- exCase (exBVar r1) $- [ caClause pj- (exLet' (paVar r2 -:: ej_vars) ej_code $- exBVar r2 +:: vars)- | (pj, (ej_vars, ej_code)) <- bs' ]- -> (vars, code)-- ExLetRec bs e1- -> binder (exLetRec bs)- (shadow (S.fromList (map (bnvar . dataOf) bs)) e1)-- ExLetDecl ds e1- -> binder (exLetDecl ds) (loop e1)-- ExPair e1 e2- -> binop exPair e1 e2-- ExApp e1 e2- | Just p2 <- expr2patt env S.empty e2,- not (dv p2 `disjoint` env),- (e1_vars, e1_code) <- loop e1,- vars <- e1_vars `L.union` toList (dv (ren p2)),- (v1, f1) <- if null e1_vars- then (e1_code, id)- else (exBVar r1,- exLet' (paVar r1 -:: e1_vars) e1_code),- code <- f1 $- exLet' (paPair (paVar r2) (flatpatt (ren p2)))- (exApp v1 (ren e2)) $- exBVar r2 +:: vars- -> (vars, code)-- | otherwise- -> binop exApp e1 e2-- ExTApp e1 t2- -> unop (flip exTApp t2) (loop e1)-- ExPack mt t1 e2- -> unop (exPack mt t1) (loop e2)-- ExCast e1 t2 b- -> unop (flip (flip exCast t2) b) (loop e1)-- _ | Just (k_vars, k_code) <- capture e- -> (k_vars, k_code $ e +:: k_vars)-- | vars <- []- -> (vars, e +:: vars)--(+:+) :: Id i => Expr i -> [Expr i] -> Expr i-(+:+) = foldl exPair--(+::) :: Id i => Expr i -> [Lid i] -> Expr i-e +:: vs = e +:+ map exBVar vs--(-:-) :: Id i => Patt i -> [Patt i] -> Patt i-(-:-) = foldl paPair--(-::) :: Id i => Patt i -> [Lid i] -> Patt i-p -:: vs = p -:- map paVar vs--r1, r2 :: Id i => Lid i-r1 = lid "r1.!"-r2 = lid "r2.!"--{--expr2vs :: Expr i -> Maybe [Lid i]-expr2vs e = case view e of- ExId (J [] (Var l)) -> return [l]- ExPair e1 e2- | ExId (J [] (Var l)) <- view e2 -> do- vs <- expr2vs e1- return (vs ++ [l])- _ -> mzero--}--makeBangPatt :: Id i => Patt i -> Patt i-makeBangPatt p = paCon (J [] (uid "!")) (Just p)--parseBangPatt :: Id i => Patt i -> Maybe (Patt i)-parseBangPatt (dataOf -> PaCon (J [] (Uid i "!")) mp)- | isTrivial i = mp-parseBangPatt _ = Nothing--{--fbvSet :: Expr i -> S.Set (Lid i)-fbvSet e = S.fromList [ lid | J [] lid <- M.keys (fv e) ]--}--disjoint :: Ord a => S.Set a -> S.Set a -> Bool-disjoint s1 s2 = S.null (s1 `S.intersection` s2)---- | Transform an expression into a pattern, if possible, using only--- the specified variables and type variables-expr2patt :: Id i =>- S.Set (Lid i) -> S.Set (TyVar i) -> Expr i -> Maybe (Patt i)-expr2patt vs0 tvs0 e0 = CMS.evalStateT (loop e0) (vs0, tvs0) where- loop e = case view e of- ExId ident -> case view ident of- Left (J [] l) -> do- sawVar l- return (paVar l)- Left (J _ _) -> mzero- Right qu -> return (paCon qu Nothing)- -- no string or integer literals- ExPair e1 e2 -> do- p1 <- loop e1- p2 <- loop e2- return (paPair p1 p2)- ExApp e1 e2 |- ExId ident <- view (snd (unfoldExTApp e1)),- Right qu <- view ident- -> do- p2 <- loop e2- return (paCon qu (Just p2))- ExTApp e1 _ -> loop e1- ExPack Nothing (dataOf -> TyVar tv) e2 -> do- sawTyVar tv- p2 <- loop e2- return (paPack tv p2)- _ -> mzero-- sawVar v = do- (vs, tvs) <- CMS.get- if v `S.member` vs- then CMS.put (v `S.delete` vs, tvs)- else mzero-- sawTyVar tv = do- (vs, tvs) <- CMS.get- if tv `S.member` tvs- then CMS.put (vs, tv `S.delete` tvs)- else mzero---- | Transform a pattern to an expression.-patt2expr :: Id i => Patt i -> Expr i-patt2expr p = case dataOf p of- PaWild -> exUnit- PaVar l -> exBVar l- PaCon u Nothing- -> exCon u- PaCon u (Just p2)- -> exApp e1 e2 where- e1 = patt2expr (paCon u Nothing)- e2 = patt2expr p2- PaPair p1 p2 -> exPair e1 e2 where- e1 = patt2expr p1- e2 = patt2expr p2- PaLit lt -> exLit lt- PaAs _ l -> exBVar l- PaPack a p2 -> exPack Nothing (tyVar a) (patt2expr p2)- PaAnti a -> antierror "exSigma" a---- | Transform a pattern to a flattened pattern.-flatpatt :: Id i => Patt i -> Patt i-flatpatt p0 = case loop p0 of- [] -> paUnit- p:ps -> foldl paPair p ps- where- loop p = case dataOf p of- PaWild -> []- PaVar l -> [paVar l]- PaCon _ Nothing- -> []- PaCon _ (Just p2)- -> loop p2- PaPair p1 p2 -> loop p1 ++ loop p2- PaLit _ -> []- PaAs _ l -> [paVar l]- PaPack a p2 -> [paPack a (flatpatt p2)]- PaAnti a -> antierror "exSigma" a--ren :: Data a => a -> a-ren = everywhere (mkT eachRaw `extT` eachRen) where- eachRaw :: Lid Raw -> Lid Raw- eachRen :: Lid Renamed -> Lid Renamed- eachRaw = each; eachRen = each- each (Lid _ s) = lid (s ++ "!")- each (LidAnti a) = LidAnti a--renOnly :: (Data a, Id i) => S.Set (Lid i) -> a -> a-renOnly set = everywhere (mkT each) where- each l | l `S.member` set = lid (unLid l ++ "!")- | otherwise = l--{--remove :: Data a => S.Set Lid -> a -> a-remove set = everywhere (mkT expr `extT` patt) where- patt (PaVar v)- | v `S.member` set = paUnit- patt p = p- expr :: Ident -> Ident- expr (J [] (Var v))- | v `S.member` set = J [] (Con (Uid "()"))- expr e = e- -}--kill :: (Id i, Foldable f) => f (Lid i) -> Expr i -> Expr i-kill = translate paVar (const exUnit)--translate :: (Id i, Foldable f) =>- (Lid i -> Patt i) -> (Lid i -> Expr i) ->- f (Lid i) -> Expr i -> Expr i-translate mkpatt mkexpr set =- case toList set of- [] -> id- v:vs -> exLet' (mkpatt v -:- map mkpatt vs)- (mkexpr v +:+ map mkexpr vs)--exUnit :: Id i => Expr i-exUnit = exCon (quid "()")--paUnit :: Id i => Patt i-paUnit = paCon (quid "()") Nothing-
src/Statics.hs view
@@ -1,1682 +1,248 @@--- | The type checker-{-# LANGUAGE- DeriveDataTypeable,- FlexibleContexts,- FlexibleInstances,- ImplicitParams,- MultiParamTypeClasses,- ParallelListComp,- PatternGuards,- QuasiQuotes,- ScopedTypeVariables,- TemplateHaskell,- TypeSynonymInstances,- UndecidableInstances,- ViewPatterns #-}-{-# OPTIONS_GHC -fno-warn-unused-imports #-}-module Statics (- -- * The type checking monad- TC, runTC, tcMapM,- -- * Static environments- S, env0,- -- ** Environment construction- addVal, addType, addMod, addDecl,- -- * Type checking- tcProg, tcDecls,- -- * Type checking results for the REPL- runTCNew, Module(..), getExnParam, tyConToDec,- getVarInfo, getTypeInfo, getConInfo,- staticsEnterScope,-) where--import Meta.Quasi-import Util-import qualified Syntax-import qualified Syntax.Decl-import qualified Syntax.Expr-import qualified Syntax.Notable-import qualified Syntax.Patt-import Syntax hiding (Type, Type'(..), tyAll, tyEx, tyUn, tyAf,- tyTuple, tyUnit, tyArr, tyApp,- TyPat, TyPat'(..))-import Loc-import Env as Env-import Ppr (Ppr, TyNames)-import Type-import TypeRel-import Coercion (coerceExpression)-import ErrorMessage-import Message.AST--import Control.Monad.RWS as RWS-import Control.Monad.Error as Error-import System.IO (hPutStrLn, stderr)-import Data.Data (Typeable, Data)-import Data.Generics (everywhere, mkT)-import Data.List (transpose, tails)-import Data.Monoid-import qualified Data.Map as M-import qualified Data.Set as S--import System.IO.Unsafe (unsafePerformIO)-pP :: Show a => a -> b -> b-pP a b = unsafePerformIO (print a) `seq` b-pM :: (Show a, Monad m) => a -> m ()-pM a = if pP a True then return () else fail "wibble"-ioM :: Monad m => IO a -> m ()-ioM a = if unsafePerformIO a `seq` True then return () else fail "wibble"---- The kind of names we're using.-type R = Renamed--------- Type checking environment-------- | Mapping from identifiers to value types (includes datacons)-type VE = Env (BIdent R) Type--- | Mapping from type constructor names to tycon info-type TE = Env (Lid R) TyCon--- | Mapping from module names to modules-type ME = Env (Uid R) (Module, E)--- | Mapping from module type names to signatures-type SE = Env SIGVAR (Module, E)--- | An environment-data E = E {- vlevel :: VE, -- values- tlevel :: TE, -- types- mlevel :: ME, -- modules- slevel :: SE -- module types- }- deriving (Typeable, Data)---- | To distinguish signature variables from module variables--- in overloaded situations-newtype SIGVAR = SIGVAR { unSIGVAR :: Uid R }- deriving (Eq, Ord, Typeable, Data)--instance Show SIGVAR where- showsPrec p (SIGVAR u) = showsPrec p u---- | A module item is empty, a pair of modules, a value entry (variable--- or data constructor), a type constructor, or a module.-data Module- = MdNil- | MdApp !Module !Module- | MdValue !(BIdent R) !Type- | MdTycon !(Lid R) !TyCon- | MdModule !(Uid R) !Module- | MdSig !(Uid R) !Module- deriving (Typeable, Data, Show)---- | Convert an ordered module into an un-ordered environment-envify :: Module -> E-envify MdNil = genEmpty-envify (MdApp md1 md2) = envify md1 =+= envify md2-envify (MdValue x t) = genEmpty =+= x =:= t-envify (MdTycon l tc) = genEmpty =+= l =:= tc-envify (MdModule u md) = genEmpty =+= u =:= (md, envify md)-envify (MdSig u md) = genEmpty =+= SIGVAR u =:= (md, envify md)--instance Monoid Module where- mempty = MdNil- mappend = MdApp--instance Monoid E where- mempty = E empty empty empty empty- mappend (E a1 a2 a3 a4) (E b1 b2 b3 b4)- = E (a1 =+= b1) (a2 =+= b2) (a3 =+= b3) (a4 =+= b4)---- Instances for generalizing environment operations over--- the whole environment structure--instance GenEmpty E where- genEmpty = mempty--instance GenExtend E E where- (=+=) = mappend-instance GenExtend E VE where- e =+= ve' = e =+= E ve' empty empty empty-instance GenExtend E TE where- e =+= te' = e =+= E empty te' empty empty-instance GenExtend E ME where- e =+= me' = e =+= E empty empty me' empty-instance GenExtend E SE where- e =+= se' = e =+= E empty empty empty se'-instance GenLookup E (BIdent R) Type where- e =..= k = vlevel e =..= k-instance GenLookup E (Lid R) TyCon where- e =..= k = tlevel e =..= k-instance GenLookup E (Uid R) (Module, E) where- e =..= k = mlevel e =..= k-instance GenLookup E SIGVAR (Module, E) where- e =..= k = slevel e =..= k-instance GenLookup E k v =>- GenLookup E (Path (Uid R) k) v where- e =..= J [] k = e =..= k- e =..= J (p:ps) k = do- (_, e') <- e =..= p- e' =..= J ps k--------- Type checking context and state-------- | The type checking context-data Context = Context {- environment :: !E,- modulePath :: ![Uid R]-}---- | The packaged-up state of the type-checker, which needs to be--- threaded from one interaction to the next by the REPL-data S = S {- -- | The environment- sEnv :: E,- -- | Index for gensyms- currIx :: !Int- }--instance GenLookup E k v =>- GenLookup Context (Path (Uid R) k) v where- cxt =..= k = environment cxt =..= k--instance GenExtend Context E where- cxt =+= e = cxt { environment = environment cxt =+= e }-instance GenExtend Context VE where- cxt =+= venv = cxt =+= E venv empty empty empty-instance GenExtend Context TE where- cxt =+= tenv = cxt =+= E empty tenv empty empty-instance GenExtend Context ME where- cxt =+= menv = cxt =+= E empty empty menv empty-instance GenExtend Context SE where- cxt =+= senv = cxt =+= E empty empty empty senv--------- The type-checking monad-------- | The type checking monad reads an environment, writes a module,--- and keeps track of a gensym counter (currently unused).-newtype TC m a = TC {- unTC :: RWST Context Module Int (ErrorT AlmsException m) a-}--instance Monad m => Monad (TC m) where- return = TC . return- m >>= k = TC (unTC m >>= unTC . k)- fail = let ?loc = bogus in typeError . [$msg| $words:1 |]--instance Monad m => Functor (TC m) where- fmap = liftM--instance Monad m => Applicative (TC m) where- pure = return- (<*>) = ap--instance Monad m => MonadWriter Module (TC m) where- tell = TC . tell- listen = TC . listen . unTC- pass = TC . pass . unTC--instance Monad m => MonadReader Context (TC m) where- ask = TC ask- local f = TC . local f . unTC--instance Monad m => MonadError AlmsException (TC m) where- throwError = TC . throwError- catchError body handler =- TC (catchError (unTC body) (unTC . handler))--instance Monad m => AlmsMonad (TC m) where- throwAlms = throwError- catchAlms = catchError---- | Generate a type error.-typeError :: (AlmsMonad m, ?loc :: Loc) => Message V -> m a-typeError msg0 = throwAlms (AlmsException StaticsPhase ?loc msg0)---- | Indicate a type checker bug.-typeBug :: AlmsMonad m => String -> String -> m a-typeBug culprit msg0 = throwAlms (almsBug StaticsPhase bogus culprit msg0)---- | Like 'ask', but monadic-asksM :: MonadReader r m => (r -> m a) -> m a-asksM = (ask >>=)---- | Run a type checking computation with the given initial state,--- returning the result and the updated state-runTC :: AlmsMonad m => S -> TC m a -> m (a, S)-runTC = liftM prj <$$> runTCNew where- prj (a, _, s) = (a, s)---- | Run a type checking computation with the given initial state,--- returning the result and the updated state-runTCNew :: AlmsMonad m => S -> TC m a -> m (a, Module, S)-runTCNew s action = unTryAlms . runErrorT $ do- let cxt = Context (sEnv s) []- ix = currIx s- (a, ix', md) <- runRWST (unTC action) cxt ix- let e' = sEnv s =+= envify md- return (a, md, S e' ix')---- | Generate a fresh integer for use as a 'TyCon' id-newIndex :: Monad m => TC m Int-newIndex = TC $ do- i <- get- put (i + 1)- return i---- | Add a module to the current module path-enterModule :: Monad m => Uid R -> TC m a -> TC m a-enterModule u = local $ \cxt ->- cxt { modulePath = u : modulePath cxt }---- | Forget the module path (for type checking signatures)-forgetModulePath :: Monad m => TC m a -> TC m a-forgetModulePath = local $ \cxt -> cxt { modulePath = [] }---- | Find out the current module path-currentModulePath :: Monad m => TC m [Uid R]-currentModulePath = asks (reverse . modulePath)---- | Add a variable binding to the generated module-bindVar :: Monad m => Lid R -> Type -> TC m ()-bindVar l t = tell (MdValue (Var l) t)---- | Add a data constructor binding to the generated module-bindCon :: Monad m => Uid R -> Type -> TC m ()-bindCon u t = tell (MdValue (Con u) t)---- | Add a type constructor binding to the generated module-bindTycon :: Monad m => Lid R -> TyCon -> TC m ()-bindTycon l tc = tell (MdTycon l tc)---- | Add a module binding to the generated module-bindModule :: Monad m => Uid R -> Module -> TC m ()-bindModule u md = tell (MdModule u md)---- | Add a module type binding to the generated module-bindSig :: Monad m => Uid R -> Module -> TC m ()-bindSig u md = tell (MdSig u md)---- | Run some computation with the context extended by a module-inModule :: Monad m => Module -> TC m a -> TC m a-inModule md = local (=+= envify md)---- | Run in the environment consisting of only the given module-onlyInModule :: Monad m => Module -> TC m a -> TC m a-onlyInModule = local (\cxt -> cxt { environment = mempty }) <$$> inModule---- | Grab the module generated by a computate, and generate the empty--- module in turn-steal :: Monad m => TC m a -> TC m (a, Module)-steal = censor (const mempty) . listen---- | Map a function over a list, allowing the exports of each item--- to be in scope for the rest-tcMapM :: Monad m => (a -> TC m b) -> [a] -> TC m [b]-tcMapM _ [] = return []-tcMapM f (x:xs) = do- (x', md) <- listen (f x)- xs' <- inModule md $ tcMapM f xs- return (x':xs')--{- -- deprecated?--- | Abstract the given type by removing its datacon or synonym info-withoutConstructors :: Monad m =>- TyCon -> TC m a -> TC m a-withoutConstructors tc = TC . M.R.local clean . unTC where- -- Note: only filters immediate scope -- should be right.- clean (TCEnv env) = TCEnv (map eachScope env)- eachScope :: Scope -> Scope - eachScope scope = genModify scope emptyPath flevel- flevel :: Level -> Level- flevel level = level { vlevel = eachVe (vlevel level) }- eachVe :: VE -> VE- eachVe = fromList . filter keep . toList- keep :: (BIdent R, Type) -> Bool- keep (Con _, TyFun _ _ (TyApp tc' _ _)) = tc' /= tc- keep (Con _, TyApp tc' _ _) = tc' /= tc- keep _ = True--}---- | Try to look up any environment binding (value, tycon, ...)-find :: (Monad m, GenLookup Context k v, Show k) =>- k -> TC m v-find k = asksM $ \cxt -> case cxt =..= k of- Just v -> return v- Nothing -> typeBug "find" ("got unbound identifier: " ++ show k)---- | Try to look up any environment binding (value, tycon, ...)-tryFind :: (Monad m, GenLookup Context k v, Show k) =>- k -> TC m (Maybe v)-tryFind k = asks (=..= k)--------- Type errors-------- | A type checking "assertion" raises a type error if the--- asserted condition is false.-tassert :: (?loc :: Loc, AlmsMonad m) =>- Bool -> Message V -> m ()-tassert True _ = return ()-tassert False m = typeError m---- | A common form of type error: A got B where C expected-terrgot :: (?loc :: Loc, AlmsMonad m) =>- String -> Type -> String -> m a-terrgot who got expected = typeError- [$msg| $words:who got $q:got where $words:expected expected. |]---- | Combination of 'tassert and 'terrgot'-tassgot :: (?loc :: Loc, AlmsMonad m) =>- Bool -> String -> Type -> String -> m ()-tassgot False = terrgot-tassgot True = \_ _ _ -> return ()---- | Common message pattern, actual vs. expected-terrexp :: (?loc :: Loc, AlmsMonad m) =>- Message V -> Message V -> Message V -> m a-terrexp = typeError <$$$> [$msg|- $msg:1- <dl>- <dt>actual: <dd>$msg:2- <dt>expected: <dd>$msg:3- </dl>-|]---- | Common message pattern, actual vs. expected-tassexp :: (?loc :: Loc, AlmsMonad m) =>- Bool -> Message V -> Message V -> Message V -> m ()-tassexp False = terrexp-tassexp True = \_ _ _ -> return ()---- | Conveniently weak-head normalize a type-hnT :: Monad m => Type -> m Type-hnT = headNormalizeTypeM 100---- | Check type for closed-ness and and defined-ness, and add info-tcType :: (?loc :: Loc, Monad m) =>- Syntax.Type R -> TC m Type-tcType stxtype0 = do- t <- tc iaeInit stxtype0- return t- where- tc :: Monad m => CurrentImpArrRule -> Syntax.Type R -> TC m Type- tc iae [$ty| '$tv |] = do- return (TyVar tv)- tc iae [$ty| $t1 -[$opt:mq]> $t2 |] = do- qd <- iaeInterpret iae mq- t1' <- tc (iaeLeft iae) t1- t2' <- tc (iaeRight iae qd t1') t2- return (TyFun qd t1' t2')- tc iae [$ty| ($list:ts) $qlid:n |] = do- tc' <- find n- ts' <- zipWithM (tc . iaeUnder iae) (tcArity tc') ts- checkLength (length (tcArity tc'))- checkBound (tcBounds tc') ts'- return (tyApp tc' ts')- where- actualLen = length ts- checkLength len =- tassexp (actualLen == len)- [$msg| Type constructor $q:n got wrong number of parameters: |]- [$msg| $actualLen |]- [$msg| $len |]- checkBound quals ts' =- tassexp (all2 (\qlit t -> qualConst t <: qlit) quals ts')- [$msg| Type constructor $q:n used on higher- qualifiers than permitted: |]- ([$msg| $1 |] (map (qRepresent . qualifier) ts'))- [$msg| $quals (or less) |]- tc iae [$ty| $quant:u '$tv . $t |] =- TyQu u tv <$> tc iae t- tc iae t0@[$ty| mu '$tv . $t |] = do- case unfoldTyMu t of- (_, N _ (Syntax.TyVar tv')) | tv == tv' ->- typeError [$msg| Recursive type is not contractive: $t0 |]- _ -> return ()- t' <- tc iae t- let actqual = qualConst t'- expqual = tvqual tv- tassert (actqual == expqual)- [$msg| Recursive type has qualifier that does- not match its own bound type variable:- <dl>- <dt>actual qualifier: <dd>$actqual- <dt>expected qualifier: <dd>$expqual- <dt>in type: <dd>$5:t0- </dl> |]- return (TyMu tv t')- tc _ [$ty| $anti:a |] = $antifail---- | Type check an A expression-tcExpr :: Monad m => Expr R -> TC m (Type, Expr R)-tcExpr = tc where- tc :: Monad m => Expr R -> TC m (Type, Expr R)- tc e0 = let ?loc = getLoc e0 in case e0 of- [$ex| $id:x |] -> do- tx <- find x- x' <- case view x of- Left _ -> return x- Right qu -> return (fmap Con qu)- return (tx, [$ex|+ $id:x' |])- [$ex| $str:s |] -> return (tyString, [$ex|+ $str:s |])- [$ex| $int:z |] -> return (tyInt, [$ex|+ $int:z |])- [$ex| $flo:f |] -> return (tyFloat, [$ex|+ $flo:f |])- [$ex| match $e with $list:clauses |] -> do- (t0, e') <- tc e- (t1:ts, clauses') <- liftM unzip . forM clauses $ \(N note ca) -> do- (xi', md) <- steal $ tcPatt t0 (capatt ca)- (ti, ei') <- inModule md $ tc (caexpr ca)- checkSharing "match or let" (caexpr ca) md- return (ti, caClause xi' ei' <<@ note)- tr <- foldM (\ti' ti -> case ti' \/? ti of- Right tr' -> return tr'- Left (_ :: String) -> typeError [$msg|- Mismatch in branches of match or let. Cannot unify:- <ul>- <li>$ti- <li>$ti'- </ul>- |]) t1 ts- return (tr, [$ex|+ match $e' with $list:clauses' |])- [$ex| let rec $list:bsN in $e2 |] -> do- let bs = map dataOf bsN- (tfs, md) <- steal $ forM bs $ \b -> do- t' <- tcType (bntype b)- tassert (syntacticValue (bnexpr b)) $- "Not a syntactic value in let rec:" !:: bnexpr b- tassgot (qualConst t' <: Qu)- "Let rec binding" t' "unlimited type"- bindVar (bnvar b) t'- return t'- (tas, e's) <- liftM unzip $ inModule md $ mapM (tc . bnexpr) bs- zipWithM_ (\tf ta ->- tassexp (ta <: tf)- [$msg| In let rec, actual type does not- agree with declared type: |]- [$msg| $ta |]- [$msg| $tf |])- tfs tas- (t2, e2') <- inModule md $ tc e2- let b's =- zipWith3- (\b tf e' -> newBinding b { bntype = typeToStx' tf,- bnexpr = e' })- bs tfs e's- return (t2, [$ex|+ let rec $list:b's in $e2' |])- [$ex| let $decl:d in $e2 |] -> do- (d', md) <- steal $ tcDecl d- (t2, e2') <- inModule md $ tc e2- return (t2, [$ex|+ let $decl:d' in $e2' |])- [$ex| ($e1, $e2) |] -> do- (t1, e1') <- tc e1- (t2, e2') <- tc e2- return (t1 .*. t2, [$ex|+ ($e1', $e2') |])- [$ex| fun ($x : $t) -> $e |] -> do- t' <- tcType t- (x', md) <- steal $ tcPatt t' x- checkSharing "function body" e md- (te, e') <- inModule md $ tc e- q <- getWorthiness e0- let stxt' = typeToStx' t'- return (TyFun q t' te, [$ex|+ fun ($x' : $stxt') -> $e' |])- [$ex| $_ $_ |] -> do- tcExApp tc e0- [$ex| fun '$tv -> $e |] -> do- tassert (syntacticValue e) $- "Not a syntactic value under type abstraction:" !:: show e0- (t, e') <- tc e- return (tyAll tv t, [$ex|+ fun '$tv -> $e' |])- [$ex| $e1 [$t2] |] -> do- (t1, e1') <- tc e1- t2' <- tcType t2- t1' <- tapply t1 t2'- let stxt2' = typeToStx' t2'- return (t1', [$ex|+ $e1' [$stxt2'] |])- [$ex| Pack[$opt:mt1]($t2, $e) |] -> do- t2' <- tcType t2- (te, e') <- tc e- t1' <- case mt1 of- Just t1 -> tcType t1- Nothing -> return (makeExType te t2')- case t1' of- TyQu Exists tv t11' -> do- te' <- tapply (tyAll tv t11') t2'- tassert (te <: te')- [$msg| Could not pack existential:- <dl>- <dt>concrete type: <dd>$te- <dt>hiding: <dd>$t2- <dt>to get: <dd>$t1'- </dl> |]- let stxt1' = typeToStx' t1'- stxt2' = typeToStx' t2'- return (t1', [$ex| Pack[$stxt1']($stxt2', $e') |])- _ -> terrgot "Pack[-]" t1' "existential type"- [$ex| ( $e1 : $t2 ) |] -> do- (t1, e1') <- tc e1- t2' <- tcType t2- tassexp (t1 <: t2')- [$msg| Type ascription mismatch: |]- [$msg| $t1 |]- [$msg| $t2' |]- return (t2', e1')- [$ex| ( $e1 :> $t2 ) |] -> do- (t1, e1') <- tc e1- t2' <- tcType t2- tassgot (castableType t2')- "Coercion (:>)" t1 "function type"- e1'' <- coerceExpression (e1' <<@ e0) t1 t2'- `catchAlms` \AlmsException { exnMessage = m } ->- typeError [$msg|- Cannot constructor coercion- <dl>- <dt>from type: <dd>$t1- <dt>to type: <dd>$t2',- </dl>- because there is no coercion available- $vmsg:m- |]- -- tcExpr e1'' -- re-type check the coerced expression- return (t2', e1'')- [$ex| $anti:a |] -> $antifail- [$ex| $antiL:a |] -> $antifail- --- -- | Assert that type given to a name is allowed by its usage- checkSharing :: (Monad m, ?loc :: Loc) =>- String -> Expr R -> Module -> TC m ()- checkSharing name e = loop where- loop md0 = case md0 of- MdApp md1 md2 -> do loop md1; loop md2- MdValue (Var l) t ->- tassert (qualConst t <: usage (J [] l) e)- [$msg| Affine variable $q:l of type $q:t- duplicated in $words:name. |]- _ -> return ()- --- -- | What is the join of the qualifiers of all free variables- -- of the given expression?- getWorthiness e =- liftM bigVee . forM (M.keys (fv e)) $ \x -> do- mtx <- tryFind (fmap Var x)- return $ case mtx of- Just tx -> qualifier tx- _ -> minBound---- | Remove all instances of t2 from t1, replacing with--- a new type variable -makeExType :: Type -> Type -> Type-makeExType t1 t2 = TyQu Exists tv $ everywhere (mkT erase) t1 where- tv = fastFreshTyVar (TV (lid "a") (qualConst t2)) (maxtv (t1, t2))- erase t' = if t' == t2 then TyVar tv else t'---- Get the usage (sharing) of a variable in an expression:-usage :: QLid R -> Expr R -> QLit-usage x e = case M.lookup x (fv e) of- Just u | u > 1 -> Qu- _ -> Qa---- | Type check an application, given the type subsumption--- relation, the appropriate type checking function, and the--- expression to check.------ This is highly ad-hoc, as it does significant local type inference.--- Ick.-tcExApp :: (?loc :: Loc, Monad m) =>- (Expr R -> TC m (Type, Expr R)) ->- Expr R -> TC m (Type, Expr R)-tcExApp tc e0 = do- let foralls t1 ts = do- let (tvs, t1f) = vtQus Forall t1 -- peel off quantification- (tas, _) = vtFuns t1f -- peel off arg types- nargs = min (length tas) (length ts)- tup ps = foldl tyTuple tyUnit (take nargs ps)- -- try to find types to unify formals and actuals, and apply- t1' <- tryUnify tvs (tup tas) (tup ts) >>= foldM tapply t1- arrows t1' ts- arrows tr [] = return tr- arrows t'@(view -> TyQu Forall _ _) ts = foralls t' ts- arrows (view -> TyFun _ ta tr) (t:ts) = do- b <- unifies [] t ta- tassexp b- [$msg| In application, operand type not in operator’s domain: |]- [$msg| $t |]- [$msg| $ta |]- arrows tr ts- arrows (view -> TyMu tv t') ts = arrows (tysubst tv (TyMu tv t') t') ts- arrows t' (t:_) =- terrexp- [$msg| In application, operator is not a function: |]- [$msg| $t' |]- [$msg| $t -[...]> ... |]- unifies tvs ta tf = do- ts <- tryUnify tvs ta tf- ta' <- foldM tapply (foldr tyAll ta tvs) ts- if (ta' <: tf)- then return True- else deeper- `catchAlms` \_ -> deeper- where- deeper = case ta of- TyQu Forall tv ta1 -> unifies (tvs++[tv]) ta1 tf- _ -> return False- let (es, e1) = unfoldExApp e0 -- get operator and args- (t1, e1') <- tc e1 -- check operator- (ts, es') <- unzip `liftM` mapM tc es -- check args- tr <- foralls t1 ts- return (tr, foldl exApp e1' es')---- | Figure out the result type of a type application, given--- the type of the function and the argument type-tapply :: (?loc :: Loc, AlmsMonad m) =>- Type -> Type -> m Type-tapply (view -> TyQu Forall tv t1') t2 = do- tassert (qualConst t2 <: tvqual tv) $- [$msg| Type application cannot instantiate type variable:- <dl>- <dt>type variable: <dd>$tv- <dt>expected qualifier:<dd>$1- <dt>type given: <dd>$t2- <dt>actual qualifier: <dd>$2- </dl> |] (tvqual tv) (qRepresent (qualifier t2))- return (tysubst tv t2 t1')-tapply t1 _ = terrgot "Type application" t1 "forall type"---- Given the type of thing to match and a pattern, return--- the type environment bound by that pattern.-tcPatt :: (?loc :: Loc, Monad m) =>- Type -> Patt R -> TC m (Patt R)-tcPatt t x0 = case x0 of- [$pa| _ |] -> return x0- [$pa| $lid:x |] -> x0 <$ bindVar x t- [$pa| $quid:u $opt:mx |] -> do- t' <- hnT t- case t' of- TyApp _ ts _ -> do- tu <- find (fmap Con u)- (params, mt, res) <- case vtQus Forall tu of- (params, TyFun _ arg res)- -> return (params, Just arg, res)- (params, res)- -> return (params, Nothing, res)- let te = tysubsts params ts res- tassert (t' <: te)- [$msg| Pattern got wrong type:- <dl>- <dt>actual: <dd>$t'- <dt>expected: <dd>$te- <dt>in pattern: <dd>$x0- </dl> |]- case (mt, mx) of- (Nothing, Nothing) ->- return [$pa|+ $quid:u |]- (Just t1, Just x1) -> do- let t1' = tysubsts params ts t1- x1' <- tcPatt t1' x1- return [$pa|+ $quid:u $x1' |]- (Nothing, Just _) -> typeError $- "Pattern has parameter where none expected:" !:: x0- (Just _, Nothing) -> typeError $- "Pattern has no parameter but expects one of type" !:: t- _ | isBotType t' -> case mx of- Nothing -> return x0- Just x -> tcPatt tyBot x- | otherwise ->- typeError [$msg| Pattern got wrong type:- <dl>- <dt>type: <dd>$t'- <dt>pattern: <dd>$x0- </dl> |]- [$pa| ($x, $y) |] -> do- t' <- hnT t >>! mapBottom (tyApp tcTuple . replicate 2)- case t' of- TyApp tc [xt, yt] _ | tc == tcTuple -> do- x' <- tcPatt xt x- y' <- tcPatt yt y- return [$pa| ($x', $y') |]- _ -> terrgot "Pattern " t' "pair type"- [$pa| $str:_ |] -> do- tassgot (t <: tyString)- "Pattern" t "string"- return x0- [$pa| $int:_ |] -> do- tassgot (t <: tyInt)- "Pattern" t "int"- return x0- [$pa| $flo:_ |] -> do- tassgot (t <: tyFloat)- "Pattern" t "float"- return x0- [$pa| $x as $lid:y |] -> do- x' <- tcPatt t x- bindVar y t- return [$pa| $x' as $lid:y |]- [$pa| Pack('$tv, $x) |] -> do- t' <- hnT t >>! mapBottom (tyEx tv)- case t' of- TyQu Exists tve te -> do- let qexp = tvqual tv- qact = tvqual tve- tassert (qact <: qexp)- [$msg| Existential unpacking pattern cannot- instantiate type variable:- <dl>- <dt>pattern type variable: <dd>$tv- <dt>expected qualifier: <dd>$qexp- <dt>actual type variable: <dd>$tve- <dt>actual qualifier: <dd>$qact- </dl> |]- let te' = tysubst tve (TyVar tv) te- x' <- tcPatt te' x- return [$pa| Pack('$tv, $x') |]- _ -> terrgot "Pattern" t' "existential type"- [$pa| $antiL:a |] -> $antifail- [$pa| $anti:a |] -> $antifail---- | Check if type is bottom, and if so, apply the given function--- to it-mapBottom :: (Type -> Type) -> Type -> Type-mapBottom ft t- | isBotType t = ft t- | otherwise = t---- Given a list of type variables tvs, a type t in which tvs--- may be free, and a type t', tries to substitute for tvs in t--- to produce a type that *might* unify with t'-tryUnify :: (?loc :: Loc, AlmsMonad m) =>- [TyVarR] -> Type -> Type -> m [Type]-tryUnify [] _ _ = return []-tryUnify tvs t t' = - case subtype 100 [] t' tvs t of- Left s -> giveUp (s :: String)- Right (_, ts) -> return ts- where- giveUp _ = typeError $- [$msg| In application, cannot find substitution for type- $msg:1 to unify types:- <dl>- <dt>actual: <dd>$t'- <dt>expected:<dd>$t- </dl> |] $- case tvs of- [tv] -> [$msg| variable $tv |]- [tv1,tv2] -> [$msg| variables $tv1 and $tv2 |]- _ -> [$msg| variables $flow:1 |]- (map [$msg| $1 |] tvs)---- | Convert qualset representations from a list of all tyvars and--- list of qualifier-significant tyvars to a set of type parameter--- indices-indexQuals :: (?loc :: Loc, Monad m) =>- Lid R -> [TyVarR] -> QExp R -> TC m (QDen Int)-indexQuals name tvs qexp = do- qden <- qInterpretM qexp- numberQDenM unbound tvs qden where- unbound tv = typeError- [$msg| Unbound type variable $tv in qualifier list- for type $q:name. |]---- BEGIN type decl checking---- | Run a computation in the context of type declarations-tcTyDecs :: (?loc :: Loc, Monad m) =>- [TyDec R] -> TC m [TyDec R]-tcTyDecs tds0 = do- let (atds, stds, dtds) = foldr partition ([], [], []) tds0- -- stds <- topSort getEdge stds0- (_, stub) <- steal $ forM (atds ++ dtds ++ stds) $ \td0 ->- case dataOf td0 of- TdDat name params _ -> allocStub name (map tvqual params)- TdSyn name ((ps,_):_) -> allocStub name (map (const Qa) ps)- TdAbs name params variances quals -> do- quals' <- indexQuals name params quals- ix <- newIndex- us <- currentModulePath- let tc' = mkTC ix (J us name) quals'- [ (tvqual parm, var)- | var <- variances- | parm <- params ]- bindTycon name tc'- _ -> return ()- let loop md = do- ((changed, tcs), md') <-- steal $- inModule md $- liftM unzip $- mapM tcTyDec (atds ++ dtds ++ stds)- if or changed- then loop md'- else return (tcs, md')- (tcs, md') <- loop stub- forM_ tcs $ \tc -> do- case tcNext tc of- Nothing -> return ()- Just clauses -> forM_ clauses $ \(tps, rhs) -> do- tassert (rhs /= tyPatToType (TpApp tc {tcNext = Nothing} tps)) $- "Recursive type synonym is not contractive:" !:: tc- tell (replaceTyCons tcs md')- return tds0- where- allocStub name params = do- ix <- newIndex- us <- currentModulePath- let tc = mkTC ix (J us name)- [ (q, Omnivariant) | q <- params ]- bindTycon name tc- --- getEdge td0 = case dataOf td0 of- TdSyn name cs -> (name, S.unions (map (tyConsOfType . snd) cs))- TdAbs name _ _ _ -> (name, S.empty)- TdDat name _ alts -> (name, names) where- names = S.unions [ tyConsOfType t | (_, Just t) <- alts ]- TdAnti a -> $antierror- --- partition td (atds, stds, dtds) =- case dataOf td of- TdAbs _ _ _ _ -> (td : atds, stds, dtds)- TdSyn _ _ -> (atds, td : stds, dtds)- TdDat _ _ _ -> (atds, stds, td : dtds)- TdAnti a -> $antierror---- tcTyDec types a type declaration, but in addition to--- returnng a declaration, it returns a boolean that indicates--- whether the type metadata has changed, which allows for iterating--- to a fixpoint.-tcTyDec :: (?loc :: Loc, Monad m) =>- TyDec R -> TC m (Bool, TyCon)-tcTyDec td0 = case dataOf td0 of- TdAbs name _ _ _ -> do- tc <- find (J [] name :: QLid R)- bindTycon name tc- return (False, tc)- TdSyn name cs -> do- tc <- find (J [] name :: QLid R)- let nparams = length (fst (head cs))- tassert (all ((==) nparams . length . fst) cs) $- [$msg| In definition of type operator $q:name, not all- clauses have the same number of parameters. |]- (cs', quals, vqs) <- liftM unzip3 $ forM cs $ \(tps, rhs) -> do- rhs' <- tcType rhs- let vs1 = ftvVs rhs'- (tps', tvses, vqs) <- liftM unzip3 $ forM tps $ \tp -> do- tp' <- tcTyPat tp- let tpt = tyPatToType tp'- vs2 = ftvVs tpt- vs' = M.intersectionWith (*) vs1 vs2- var = bigVee (M.elems vs')- qp = qualConst tpt- tvs = qDenFtv (qualifier tpt)- return (tp', tvs, (var, qp))- let tvmap = M.unions [ M.fromDistinctAscList- [ (tv, i) | tv <- S.toAscList tvs ]- | tvs <- tvses- | i <- [ 0 .. ] ]- qual = numberQDenMap tvqual tvmap (qualifier rhs')- return ((tps', rhs'), qual, vqs)- let (arity, bounds) = unzip (map bigVee (transpose vqs))- qual = bigVee quals- changed = arity /= tcArity tc- || qual /= tcQual tc- tc' = tc { tcArity = arity, tcQual = qual,- tcNext = Just cs', tcBounds = bounds }- bindTycon name tc'- return (changed, tc')- TdDat name params alts -> do- tc <- find (J [] name :: QLid R)- alts' <- sequence- [ case mt of- Nothing -> return (cons, Nothing)- Just t -> do- t' <- tcType t- return (cons, Just t')- | (cons, mt) <- alts ]- let t' = foldl tyTuple tyUnit [ t | (_, Just t) <- alts' ]- qual = numberQDen params (qualifier t')- arity = typeVariances params t'- changed = arity /= tcArity tc- || qual /= tcQual tc- tc' = tc { tcArity = arity, tcQual = qual,- tcCons = (params, fromList alts') }- bindTycon name tc'- bindAlts params tc' alts'- return (changed, tc')- TdAnti a -> $antifail---- | Build a module of datacon types from a datatype's--- alternatives-bindAlts :: Monad m => [TyVarR] -> TyCon -> [(Uid R, Maybe Type)] -> TC m ()-bindAlts params tc = mapM_ each where- each (u, Nothing) = bindCon u (alls result)- each (u, Just t) = bindCon u (alls (t .->. result))- alls t = foldr tyAll t params- result = tyApp tc (map TyVar params)---- | Compute the variances at which some type variables occur--- in an open type expression-typeVariances :: [TyVarR] -> Type -> [Variance]-typeVariances d0 = finish . ftvVs where- finish m = [ maybe 0 id (M.lookup tv m)- | tv <- d0 ]---- | Generic topological sort------ Uses an adjacency-list graph representation. Given a--- function from abstract node values to comparable nodes,--- and a list of node values, returns a list of node values (or--- fails if there's a cycle).-topSort :: forall node m a.- (?loc :: Loc, AlmsMonad m, Ord node, Ppr node) =>- (a -> (node, S.Set node)) -> [a] -> m [a]-topSort getEdge edges = do- (_, w) <- RWS.execRWST visitAll S.empty S.empty- return w- where- visitAll = mapM_ visit (M.keys graph)- --- visit :: node -> RWS.RWST (S.Set node) [a] (S.Set node) m ()- visit node = do- stack <- RWS.ask- lift $- tassert (not (node `S.member` stack)) $- "Unproductive cycle in type definitions via type" !:: node- seen <- RWS.get- if node `S.member` seen- then return ()- else do- RWS.put (S.insert node seen)- case M.lookup node graph of- Just (succs, info) -> do- RWS.local (S.insert node) $- mapM_ visit succs- RWS.tell [info]- Nothing ->- return ()- --- graph :: M.Map node ([node], a)- graph = M.fromList [ let (node, succs) = getEdge info- in (node, (S.toList succs, info))- | info <- edges ]---- | The (unqualified) tycons that appear in a syntactic type-tyConsOfType :: Syntax.Type R -> S.Set (Lid R)-tyConsOfType [$ty| ($list:ts) $qlid:n |] =- case n of- J [] l -> S.singleton l- _ -> S.empty- `S.union` S.unions (map tyConsOfType ts)-tyConsOfType [$ty| '$_ |] = S.empty-tyConsOfType [$ty| $t1 -[$opt:_]> $t2 |] =- tyConsOfType t1 `S.union` tyConsOfType t2-tyConsOfType [$ty| $quant:_ '$_. $t |] = tyConsOfType t-tyConsOfType [$ty| mu '$_. $t |] = tyConsOfType t-tyConsOfType [$ty| $anti:a |] = $antierror--tcTyPat :: Monad m => Syntax.TyPat R -> TC m TyPat-tcTyPat (N note (Syntax.TpVar tv var)) = do- let ?loc = getLoc note- tassert (var == Invariant)- [$msg| Type pattern variable $tv has a variance annotation- $q:var. Variances may not be specified for parameters- of type operators, but are inferred. |]- return (TpVar tv)-tcTyPat tp@[$tpQ| ($list:tps) $qlid:qu |] = do- let ?loc = _loc- tc <- find qu- tassert (isNothing (tcNext tc)) $- "Type operator pattern is also a type operator:" !:: tp- TpApp tc <$> mapM tcTyPat tps-tcTyPat [$tpQ| $antiP:a |] = $antifail---- END type decl checking---- | Type check a signature-tcSigExp :: (?loc :: Loc, Monad m) =>- SigExp R -> TC m (SigExp R)-tcSigExp [$seQ| sig $list:ds end |] = do- ds' <- forgetModulePath $ tcMapM tcSigItem ds- return [$seQ| sig $list:ds' end |]-tcSigExp [$seQ| $quid:n $list:qls |] = do- (md, _) <- find (fmap SIGVAR n)- tell md- return [$seQ| $quid:n $list:qls |]-tcSigExp [$seQ| $se1 with type $list:tvs $qlid:tc = $t |] = do- (se1', md) <- steal $ tcSigExp se1- t' <- tcType t- fibrate tvs tc t' md- return [$seQ| $se1' with type $list:tvs $qlid:tc = $t |]-tcSigExp [$seQ| $anti:a |] = $antifail--fibrate :: (?loc :: Loc, Monad m) =>- [TyVar R] -> QLid R -> Type -> Module -> TC m ()-fibrate tvs ql t md = do- let Just tc = findTycon ql md- tassert (isAbstractTyCon tc) $- "Signature fibration (with-type) cannot update concrete" ++- "type constructor:" !:: ql- let actlen = length tvs- explen = length (tcArity tc)- tassert (actlen == explen)- [$msg| In signature fibration (with type), wrong number of- parameters to type:- <dl>- <dt>actual count: <dd>$actlen- <dt>expected count: <dd>$explen- <dt>for type: <dd>$ql- </dl> |]- let amap = ftvVs t- arity = map (\tv -> fromJust (M.lookup tv amap)) tvs- bounds = map tvqual tvs- qual = numberQDen tvs (qualifier t)- next = Just [(map TpVar tvs, t)]- tc' = tc {- tcArity = arity,- tcBounds = bounds,- tcQual = qual,- tcNext = next- }- tell (replaceTyCon tc' md)- where- findTycon ql0 md0 = case md0 of- MdNil -> mzero- MdApp md1 md2 -> findTycon ql0 md1 `mplus` findTycon ql0 md2- MdTycon l tc -> if J [] l == ql0 then return tc else mzero- MdModule u md1 -> case ql0 of- J (u':us) l | u == u' -> findTycon (J us l) md1- _ -> mzero- MdSig _ _ -> mzero- MdValue _ _ -> mzero--tcSigItem :: (?loc :: Loc, Monad m) =>- SigItem R -> TC m (SigItem R)-tcSigItem sg0 = case sg0 of- [$sgQ| val $lid:l : $t |] -> do- t' <- tcType t- bindVar l t'- return [$sgQ| val $lid:l : $t |]- [$sgQ| type $list:tds |] -> do- tds' <- tcTyDecs tds- return [$sgQ| type $list:tds' |]- [$sgQ| module $uid:u : $se1 |] -> do- (se', md) <- steal $ tcSigExp se1- bindModule u md- return [$sgQ| module $uid:u : $se' |]- [$sgQ| module type $uid:u = $se1 |] -> do- se' <- tcSig u se1- return [$sgQ| module type $uid:u = $se' |]- [$sgQ| include $se1 |] -> do- se' <- tcSigExp se1- return [$sgQ| include $se' |]- [$sgQ| exception $uid:u of $opt:mt |] -> do- mt' <- tcException u mt- return [$sgQ| exception $uid:u of $opt:mt' |]- [$sgQ| $anti:a |] -> $antifail---- | Run a computation in the context of a let declaration-tcLet :: (?loc :: Loc, Monad m) =>- Patt R -> Maybe (Syntax.Type R) -> Expr R ->- TC m (Patt R, Maybe (Syntax.Type R), Expr R)-tcLet x mt e = do- tassert (S.null (dtv x)) $- "Attempt to unpack existential in top-level binding:" !:: x- (te, e') <- tcExpr e- t' <- case mt of- Just t -> do- t' <- tcType t- tassert (qualConst t' == Qu) $- [$msg| Declared type of let declaration of $q:x is not unlimited |]- tassert (te <: t')- [$msg| Mismatch in declared type for let declaration:- <dl>- <dt>actual: <dd>$te- <dt>expected: <dd>$t'- <dt>in pattern: <dd>$x- </dl> |]- return t'- Nothing -> do- tassert (qualConst te == Qu) $- [$msg| Type of let declaration binding is not unlimited:- <dl>- <dt>type: <dd>$te- <dt>qualifier: <dd>$1- <dt>in pattern: <dd>$x- </dl> |] (qRepresent (qualifier te))- return te- x' <- tcPatt t' x- -- ioM (hPutStrLn stderr (show te))- return (x', Just (typeToStx' t'), e')---- | Run a computation in the context of a module open declaration-tcOpen :: (?loc :: Loc, Monad m) =>- ModExp R -> TC m (ModExp R)-tcOpen b = tcModExp b---- | Run a computation in the context of a local block (that is, after--- the block)-tcLocal :: (?loc :: Loc, Monad m) =>- [Decl R] -> [Decl R] ->- TC m ([Decl R], [Decl R])-tcLocal ds1 ds2 = do- (ds1', md1) <- steal $ tcDecls ds1- ds2' <- inModule md1 $ tcDecls ds2- return (ds1', ds2')---- | Run a computation in the context of a new exception variant-tcException :: (?loc :: Loc, Monad m) =>- Uid R -> Maybe (Syntax.Type R) ->- TC m (Maybe (Syntax.Type R))-tcException n mt = do- mt' <- gmapM tcType mt- bindCon n (maybe tyExn (`tyArr` tyExn) mt')- return (fmap typeToStx' mt')---- | Type check and bind a module-tcMod :: (?loc :: Loc, Monad m) =>- Uid R -> ModExp R -> TC m (ModExp R)-tcMod u me0 = do- (me', md) <- steal $ enterModule u $ tcModExp me0- bindModule u md- return me'---- | Type check and bind a signature-tcSig :: (?loc :: Loc, Monad m) =>- Uid R -> SigExp R -> TC m (SigExp R)-tcSig u se0 = do- (se', md) <- steal $ tcSigExp se0- bindSig u md- return se'---- | Type check a module body-tcModExp :: (?loc :: Loc, Monad m) =>- ModExp R -> TC m (ModExp R)-tcModExp [$me| struct $list:ds end |] = do- ds' <- tcDecls ds- return [$me| struct $list:ds' end |]-tcModExp [$me| $quid:n $list:qls |] = do- (md, _) <- find n- tell md- return [$me| $quid:n $list:qls |]-tcModExp [$me| $me1 : $se2 |] = do- (me1', md1) <- steal $ tcModExp me1- (se2', md2) <- steal $ tcSigExp se2- ascribeSignature md1 md2- return [$me| $me1' : $se2' |]-tcModExp [$me| $anti:a |] = $antifail---- | Run a computation in the context of an abstype block-tcAbsTy :: (?loc :: Loc, Monad m) =>- [AbsTy R] -> [Decl R] ->- TC m ([AbsTy R], [Decl R])-tcAbsTy atds ds = do- (_, md1) <- steal $ tcTyDecs (map (atdecl . dataOf) atds)- (ds', md2) <- steal $ inModule md1 $ tcDecls ds- tcs <- forM atds $ \at0 -> case view at0 of- AbsTy arity quals (N _ (TdDat name params _)) -> do- let env = envify md1- tc = fromJust (env =..= name)- qualSet <- indexQuals name params quals- if length params == length (tcArity tc)- then return ()- else typeBug "tcAbsTy" $- "in abstype declaration " ++ show (length params) ++- " parameters given for type " ++ show name ++- " which has " ++ show (length (tcArity tc))- let actualArity = tcArity tc- actualQual = tcQual tc- tassexp (all2 (<:) actualArity arity)- [$msg| In abstype declaration, declared parameter variance for- type $q:name is more permissive than actual variance: |]- (pprMsg actualArity)- (pprMsg arity)- tassexp (actualQual <: qualSet)- [$msg| In abstype declaration, declared qualifier for- type $q:name is more permissive than actual qualifier: |]- (showMsg actualQual)- (showMsg qualSet)- return $ abstractTyCon tc {- tcQual = qualSet,- tcArity = arity,- tcCons = ([], empty)- }- _ -> typeBug "tcAbsTy" "Can’t do abstype with non-datatypes"- tell (replaceTyCons tcs (md1 `mappend` md2))- return (atds, ds')---- | Type check a declaration-tcDecl :: Monad m => Decl R -> TC m (Decl R)-tcDecl decl =- let ?loc = getLoc decl in- case decl of- [$dc| let $x : $opt:t = $e |] -> do- (x', t', e') <- tcLet x t e- return [$dc| let $x' : $opt:t' = $e' |] - [$dc| type $list:tds |] -> do- tds' <- tcTyDecs tds- return [$dc| type $list:tds' |]- [$dc| abstype $list:at with $list:ds end |] -> do- (at', ds') <- tcAbsTy at ds- return [$dc| abstype $list:at' with $list:ds' end |]- [$dc| module $uid:x = $b |] -> do- b' <- tcMod x b- return [$dc| module $uid:x = $b' |]- [$dc| module type $uid:x = $b |] -> do- b' <- tcSig x b- return [$dc| module type $uid:x = $b' |]- [$dc| open $b |] -> do- b' <- tcOpen b- return [$dc| open $b' |]- [$dc| local $list:ds0 with $list:ds1 end |] -> do- (ds0', ds1') <- tcLocal ds0 ds1- return [$dc| local $list:ds0' with $list:ds1' end |]- [$dc| exception $uid:n of $opt:mt |] -> do- mt' <- tcException n mt- return [$dc| exception $uid:n of $opt:mt' |]- [$dc| $anti:a |] -> $antifail---- | Type check a sequence of declarations-tcDecls :: Monad m => [Decl R] -> TC m [Decl R]-tcDecls = tcMapM tcDecl--------- Module sealing-------- | For mapping renamed names (from structures) into unrenamed names--- (in signatures)-data NameMap- = NameMap {- nmValues :: Env (BIdent R) (BIdent R),- nmTycons :: Env (Lid R) (Lid R),- nmModules :: Env (Uid R) (Uid R, NameMap),- nmSigs :: Env (Uid R) (Uid R)- }--instance Monoid NameMap where- mempty = NameMap empty empty empty empty- mappend (NameMap a1 a2 a3 a4) (NameMap b1 b2 b3 b4) =- NameMap (a1 =+= b1) (a2 =+= b2) (a3 =+= b3) (a4 =+= b4) where--instance GenEmpty NameMap where- genEmpty = mempty-instance GenExtend NameMap NameMap where- (=+=) = mappend-instance GenLookup NameMap (BIdent R) (BIdent R) where- e =..= k = nmValues e =..= k-instance GenLookup NameMap (Lid R) (Lid R) where- e =..= k = nmTycons e =..= k-instance GenLookup NameMap (Uid R) (Uid R, NameMap) where- e =..= k = nmModules e =..= k-instance GenLookup NameMap SIGVAR (Uid R) where- e =..= k = nmSigs e =..= unSIGVAR k---- | Given a module, construct a 'NameMap' mapping raw versions of its--- names to the actual renamed version.-makeNameMap :: Module -> NameMap-makeNameMap md0 = case md0 of- MdNil -> mempty- MdApp md1 md2 -> makeNameMap md1 =+= makeNameMap md2- MdValue x _ -> mempty { nmValues = unnameBIdent x =:= x }- MdTycon x _ -> mempty { nmTycons = unnameLid x =:= x }- MdModule x md1 -> mempty { nmModules = unnameUid x =:= (x, makeNameMap md1) }- MdSig x _ -> mempty { nmSigs = unnameUid x =:= x }- where- unnameLid :: Lid R -> Lid R- unnameLid = lid . unLid- unnameUid :: Uid R -> Uid R- unnameUid = uid . unUid- unnameBIdent :: BIdent R -> BIdent R- unnameBIdent (Var l) = Var (unnameLid l)- unnameBIdent (Con u) = Con (unnameUid u)---- | Given a module and a signature, ascribe the signature to the module--- and write the result.-ascribeSignature :: (?loc :: Loc, Monad m) =>- Module -> Module -> TC m ()-ascribeSignature md1 md2 = do- us <- currentModulePath- let md2' = renameSig (makeNameMap md1) us md2- onlyInModule md1 $ do- subst <- matchSigTycons md2'- subsumeSig (applyTyConSubstInSig subst md2')- let tcs = getGenTycons md2' []- tcs' <- forM tcs $ \tc -> do- ix <- newIndex- return tc { tcId = ix }- tell (substTyCons tcs tcs' md2')---- | Make the names in a signature match the names from the module it's--- being applied to.-renameSig :: NameMap -> [Uid Renamed] -> Module -> Module-renameSig nm0 us = loop where- loop md0 = case md0 of- MdNil -> MdNil- MdApp md1 md2 -> MdApp (loop md1) (loop md2)- MdValue x t -> MdValue (fromJust (nm0 =..= x)) t- MdTycon x tc -> MdTycon (fromJust (nm0 =..= x)) tc'- where tc' = tc { tcName = J us (jname (tcName tc)) }- MdModule x md1 ->- let Just (x', nm1) = nm0 =..= x- in MdModule x' (renameSig nm1 (us++[x']) md1)- MdSig x md1 -> MdSig (fromJust (nm0 =..= SIGVAR x)) md1---- | Given a signature, find the tycon substitutions necessary to--- unify it with the module in the environment.-matchSigTycons :: Monad m => Module -> TC m TyConSubst-matchSigTycons = loop [] where- loop path md0 = case md0 of- MdNil -> return mempty- MdApp md1 md2 -> mappend <$> loop path md1 <*> loop path md2- MdValue _ _ -> return mempty- MdTycon x tc -> do- tc' <- find (J path x)- return (makeTyConSubst [tc] [tc'])- MdModule x md1 -> loop (path++[x]) md1- MdSig _ _ -> return mempty---- | Given a tycon substitution, apply it to all the values and--- RIGHT-HAND-SIDES of type definitions in a signature. In--- particular, don't replace any tycon bindings directly, but do--- replace any references to other types in their definitions.-applyTyConSubstInSig :: TyConSubst -> Module -> Module-applyTyConSubstInSig subst = loop where- loop md0 = case md0 of- MdNil -> MdNil- MdApp md1 md2 -> MdApp (loop md1) (loop md2)- MdValue x t -> MdValue x (applyTyConSubst subst t)- MdTycon x tc -> MdTycon x (applyTyConSubstInTyCon subst tc)- MdModule x md1 -> MdModule x (loop md1)- MdSig x md1 -> MdSig x (loop md1)---- | Get a list of all the tycons that need a new index allocated--- because they're generative.-getGenTycons :: Module -> [TyCon] -> [TyCon]-getGenTycons = loop where- loop MdNil = id- loop (MdApp md1 md2) = loop md1 . loop md2- loop (MdValue _ _) = id- loop (MdTycon _ tc) = if varietyOf tc == OperatorType- then id- else (tc:)- loop (MdModule _ md1) = loop md1- loop (MdSig _ _) = id---- | Check whether the given signature subsumes the signature--- implicit in the environment.-subsumeSig :: (?loc :: Loc, Monad m) =>- Module -> TC m ()-subsumeSig = loop where- loop md0 = case md0 of- MdNil -> return ()- MdApp md1 md2 -> do loop md1; loop md2- MdValue x t -> do- t' <- find (J [] x :: Ident R)- tassexp (t' <: t)- [$msg| In signature matching, type mismatch for $q:x: |]- [$msg| $t' |]- [$msg| $t |]- MdTycon x tc -> do- tc' <- find (J [] x :: QLid R)- case varietyOf tc of- AbstractType -> do- let sigass assertion thing getter =- tassexp assertion- ([$msg| In signature matching, cannot match the- definition for type $q:1 because the- $words:thing does not match: |] (tcName tc))- (showMsg (getter tc'))- (showMsg (getter tc))- sigass (length (tcArity tc') == length (tcArity tc))- "number of type parameters" (length . tcArity)- sigass (all2 (<:) (tcArity tc') (tcArity tc))- "variance" tcArity- sigass (all2 (<:) (tcBounds tc') (tcBounds tc))- "parameter bounds" tcBounds- sigass (tcQual tc' <: tcQual tc)- "qualifier" tcQual- OperatorType -> matchTycons tc' tc- DataType -> matchTycons tc' tc- MdModule x md1 -> do- (md2, _) <- find (J [] x :: QUid R)- onlyInModule md2 $ subsumeSig md1- MdSig x md1 -> do- (md2, _) <- find (J [] (SIGVAR x) :: Path (Uid R) SIGVAR)- matchSigs md2 md1---- | Check that two signatures match EXACTLY.--- First signature is what we have, and second is what we want.-matchSigs :: (?loc :: Loc, Monad m) =>- Module -> Module -> TC m ()-matchSigs md10 md20 = loop (linearize md10 []) (linearize md20 []) where- loop [] [] = return ()- loop (MdValue x1 t1 : sgs1) (MdValue x2 t2 : sgs2)- | x1 == x2 && t1 == t2 = loop sgs1 sgs2- loop (MdTycon x1 tc1 : sgs1) (MdTycon x2 tc2 : sgs2)- | x1 == x2 = do- matchTycons tc1 tc2- loop (substTyCon tc1 tc2 sgs1) sgs2- loop (MdModule x1 md1 : sgs1) (MdModule x2 md2 : sgs2)- | x1 == x2 = do- matchSigs md1 md2- loop sgs1 sgs2- loop (MdSig x1 md1 : sgs1) (MdSig x2 md2 : sgs2)- | x1 == x2 = do- matchSigs md1 md2- loop sgs1 sgs2- loop [] (sg : _) = do- (x, what) <- whatIs sg- typeError [$msg|- In exact signature matching, missing expected $what $qmsg:x.- |]- loop (sg : _) [] = do- (x, what) <- whatIs sg- typeError [$msg|- In exact signature matching, found unexpected $what $qmsg:x.- |]- loop (sg1 : _) (sg2 : _) = do- (x1, what1) <- whatIs sg1- (x2, what2) <- whatIs sg2- typeError [$msg|- In exact signature matching (for signatures as entries in- signatures being matched), got signature items didn’t match:- <dl>- <dt>actual: <dd>$what1 $qmsg:x1- <dt>expected: <dd>$what2 $qmsg:x2- </dl>- |]- --- whatIs (MdValue x _) = return (pprMsg x, "value")- whatIs (MdTycon x _) = return (pprMsg x, "type")- whatIs (MdModule x _) = return (pprMsg x, "module")- whatIs (MdSig x _) = return (pprMsg x, "module type")- whatIs _ = typeBug "matchSigs" "weird signature item"---- | Extensional equality for type constructors-tyconExtEq :: TyCon -> TyCon -> Bool-tyconExtEq tc1 tc2 | tcBounds tc1 == tcBounds tc2 =- let tvs = zipWith (TyVar .) tvalphabet (tcBounds tc1)- in tyApp tc1 tvs == tyApp tc2 tvs-tyconExtEq _ _ = False---- | Check that two type constructors match exactly.-matchTycons :: (?loc :: Loc, Monad m) =>- TyCon -> TyCon -> TC m ()-matchTycons tc1 tc2 = case (varietyOf tc1, varietyOf tc2) of- (AbstractType, AbstractType) -> do- tassert (tcArity tc1 == tcArity tc2) $- estr "the arity or variance"- (show (tcArity tc1)) (show (tcArity tc2))- tassert (tcBounds tc1 == tcBounds tc2) $- estr "parameter bound" (show (tcBounds tc1)) (show (tcBounds tc2))- tassert (tcQual tc1 == tcQual tc2) $- estr "qualifier" (show (tcQual tc1)) (show (tcQual tc2))- (DataType, DataType) -> do- let (tvs1, rhs1) = tcCons tc1- (tvs2, rhs2) = tcCons tc2- tassert (length tvs1 == length tvs2) $- estr "number of parameters" (show (length tvs1)) (show (length tvs2))- let mtv = maxtv (tvs1, tvs2, Env.range rhs1, Env.range rhs2)- tvs' = fastFreshTyVars tvs1 mtv- rhs1' = Env.mapVals (fmap (tysubsts tvs1 (map TyVar tvs'))) rhs1- rhs2' = Env.mapVals (fmap (tysubsts tvs2 (map TyVar tvs'))) rhs2- forM_ (Env.toList rhs1') $ \(k, t1) ->- let Just t2 = rhs2' =..= k- in tassert (t1 == t2) $ estr- ("constructor ‘" ++ show k ++ "’")- (maybe "nothing" show t1)- (maybe "nothing" show t2)- (OperatorType, _) | tyconExtEq tc1 tc2 -> return ()- (_, OperatorType) | tyconExtEq tc1 tc2 -> return ()- (OperatorType, OperatorType) -> do- let next1 = fromJust (tcNext tc1)- next2 = fromJust (tcNext tc2)- tassert (length next1 == length next2) $- estr "number of clauses" (show (length next1)) (show (length next2))- forM_ (zip3 next1 next2 [1 :: Int .. ]) $- \((tp1, t1), (tp2, t2), ix) -> do- tassert (length tp1 == length tp2) $- estr ("number of parameters in clause " ++ show ix)- (show (length tp1)) (show (length tp2))- (tvs1, tvs2) <- mconcat `liftM` zipWithM matchTypats tp1 tp2- let mtv = maxtv (tvs1, tvs2, t1, t2)- tvs' = fastFreshTyVars tvs1 mtv- t1' = tysubsts tvs1 (map TyVar tvs') t1- t2' = tysubsts tvs2 (map TyVar tvs') t2- tassert (t1' == t2') $- estr ("type operator right-hand sides in clause " ++ show ix)- (show t1') (show t2')- (v1, v2) -> typeError $ estr "kind of definition" (show v1) (show v2)- where- estr what which1 which2 =- [$msg|- In signature matching, cannot match definition for type- $q:tc1 because the $words:what does not match:- <dl>- <dt>actual: <dd>$which1- <dt>expected: <dd>$which2- </dl>- |]---- | To check that two type patterns match, and return the pairs of--- type variables that line up and thus need renaming.-matchTypats :: (?loc :: Loc, Monad m) =>- TyPat -> TyPat -> TC m ([TyVar R], [TyVar R])-matchTypats (TpVar tv1) (TpVar tv2)- = return ([tv1], [tv2])-matchTypats (TpApp tc1 tvs1) (TpApp tc2 tvs2)- | tc1 == tc2- = mconcat `liftM` zipWithM matchTypats tvs1 tvs2-matchTypats tp1 tp2- = terrexp- [$msg| In signature matching, cannot match type patterns: |]- (pprMsg tp1) (pprMsg tp2)---- | To flatten all the 'MdNil' and 'MdApp' constructors in a module--- into an ordinary list.-linearize :: Module -> [Module] -> [Module]-linearize MdNil = id-linearize (MdApp md1 md2) = linearize md1 . linearize md2-linearize md1 = (md1 :)--------- END Module Sealing-------- | Add the type of a value binding-addVal :: Monad m => Lid R -> Syntax.Type R -> TC m ()-addVal x t = do- let ?loc = mkBogus "<addVal>"- t' <- tcType t- bindVar x t'---- | Add an arbitrary declaration-addDecl :: Monad m => Decl R -> TC m ()-addDecl d = () <$ tcDecl d---- | Add a type constructor binding-addType :: Monad m => Lid R -> TyCon -> TC m ()-addType n tc = () <$ bindTycon n tc---- | Add a nested submodule-addMod :: Monad m => Uid R -> TC m a -> TC m ()-addMod u action = do- (_, md) <- steal $ enterModule u $ action- bindModule u md---- | Type check a program-tcProg :: Monad m => Prog R -> TC m (Type, Prog R)-tcProg [$prQ| $list:ds in $opt:e0 |] = do- (ds', md) <- steal $ tcDecls ds- (t, e0') <- case e0 of- Just e -> liftM (second Just) $ inModule md $ tcExpr e- Nothing -> return (tyUnit, Nothing)- return (t, [$prQ|+ $list:ds' in $opt:e0' |])---- | The initial type-checking state-env0 :: S-env0 = S e0 0 where- e0 :: E- e0 = genEmpty =+= (Con (uid "()") -:- tyUnit :: VE)---- | Find out the parameter type of an exception-getExnParam :: Type -> Maybe (Maybe Type)-getExnParam (TyApp tc _ _)- | tc == tcExn = Just Nothing-getExnParam (TyFun _ t1 (TyApp tc _ _))- | tc == tcExn = Just (Just t1)-getExnParam _ = Nothing---- | Reconstruct the declaration from a tycon binding, for printing-tyConToDec :: TyNames -> TyCon -> TyDec R-tyConToDec tn tc = case tc of- _ | tc == tcExn- -> tdAbs (lid "exn") [] [] maxBound- TyCon { tcName = n, tcNext = Just clauses }- -> tdSyn (jname n) [ (map (tyPatToStx tn) ps, typeToStx tn rhs)- | (ps, rhs) <- clauses ]- TyCon { tcName = n, tcCons = (ps, alts) }- | not (isEmpty alts)- -> tdDat (jname n) ps [ (u, fmap (typeToStx tn) mt)- | (u, mt) <- toList alts ]- TyCon { tcName = n }- ->- let tyvars = zipWith ($) tvalphabet (tcBounds tc)- in tdAbs (jname n)- (zipWith const tyvars (tcArity tc))- (tcArity tc)- (qRepresent- (denumberQDen- (map (qInterpret . qeVar) tyvars)- (tcQual tc)))--getVarInfo :: QLid R -> S -> Maybe Type-getVarInfo ql (S e _) = e =..= fmap Var ql--getTypeInfo :: QLid R -> S -> Maybe TyCon-getTypeInfo ql (S e _) = e =..= ql---- Find out about a data constructor. If it's an exception constructor,--- return 'Left' with its paramter, otherwise return the type construtor--- of the result type-getConInfo :: QUid R -> S -> Maybe (Either (Maybe Type) TyCon)-getConInfo qu (S e _) = do- t <- e =..= fmap Con qu- case getExnParam t of- Just mt -> Just (Left mt)- Nothing ->- let loop (TyFun _ _ t2) = loop t2- loop (TyQu _ _ t1) = loop t1- loop (TyApp tc _ _) = Just (Right tc)- loop _ = Nothing- in loop t---- Open the given module, if it exists.-staticsEnterScope :: Uid R -> S -> S-staticsEnterScope u s =- let e = sEnv s in- case e =..= u of- Just (_, e') -> s { sEnv = e =+= e' }- Nothing -> s+-- | The external interface to the type checker+module Statics (+ -- * Type checking state+ StaticsState, staticsState0, staticsState0',+ -- ** Initial state+ addSignature, addPrimType,++ -- * Type checking operations+ typeCheckDecls, typeCheckProg,++ -- * Renaming and typing info+ -- ** Renaming+ Statics.getRenamingInfo, RenamingInfo(..),+ -- ** Constraint solving+ getConstraint,+ -- ** Type checking+ getVarInfo, getTypeInfo, getConInfo,+ -- ** Printing nice type names+ addTyNameContext, makeTyNames, makeT2SContext, staticsEnterScope,+) where++import Util+import Util.MonadRef+import AST.Ident (Raw, Renamed, Id(..))+import qualified AST+import Syntax.PprClass (Doc, setTyNames)+import Type+import Statics.Env+import Statics.Error+import Statics.Constraint+import Statics.Rename+import Statics.Decl++import Prelude ()+import qualified Data.List as List++---+--- TYPE CHECKING STATE+---++-- | The state of the renamer and type checker, parameterized by+-- a reference type.+data StaticsState r+ = StaticsState {+ ssRen ∷ !RenameState,+ ssCon ∷ !(ConstraintState (TV r) r),+ ssEnv ∷ !(Γ (TV r))+ }+ deriving Show++-- | The initial state of the type checker, parameterized by the+-- initial renaming state.+staticsState0 ∷ RenameState → StaticsState r+staticsState0 rs+ = StaticsState {+ ssRen = rs,+ ssCon = constraintState0,+ ssEnv = mempty+ }++-- | The initial state of the type checker with no initial renaming+-- state.+staticsState0' ∷ StaticsState r+staticsState0' = staticsState0 renameState0++---+--- TYPE CHECKING OPERATIONS+---++-- | Type check a sequence of declarations.+typeCheckDecls ∷ (MonadAlmsError m, MonadRef r m) ⇒+ StaticsState r →+ [AST.Decl Raw] →+ m ([AST.Decl Renamed],+ [AST.SigItem R],+ StaticsState r)+typeCheckDecls ss ds = do+ (ds', rs) ← bailoutIfError $+ runRenamingM True bogus (ssRen ss) (renameDecls ds)+ ((ds'', γ', sig), cs) ← bailoutIfError . runConstraintT (ssCon ss) $ do+ tcDecls [] (ssEnv ss) ds' <* ensureSatisfiability+ let ss' = ss {+ ssRen = rs,+ ssCon = cs,+ ssEnv = γ'+ }+ return (ds'', sigItemToStx (makeTyNames ss') <$> sig, ss')++-- | Type check a program.+typeCheckProg ∷ (MonadAlmsError m, MonadRef r m) ⇒+ StaticsState r →+ AST.Prog Raw →+ m (AST.Prog Renamed, Maybe (AST.Type Renamed))+typeCheckProg ss p = do+ (p', _) ← bailoutIfError $+ runRenamingM True bogus (ssRen ss) (renameProg p)+ ((p'', mσ), _) ← bailoutIfError . runConstraintT (ssCon ss) $ do+ tcProg (ssEnv ss) p' <* ensureSatisfiability+ return (p'', typeToStx' <$> mσ)++---+--- ADDING INITIAL BINDINGS+---++-- | Bind the contents of a signature in the environment. This is used+-- for setting up some primitive types and values.+addSignature ∷ (MonadAlmsError m, MonadRef r m) ⇒+ StaticsState r →+ AST.SigExp Renamed →+ m (StaticsState r)+addSignature ss sigexp = do+ (sig, cs') ← runConstraintT (ssCon ss) (tcSigExp (ssEnv ss) sigexp)+ return ss {+ ssCon = cs',+ ssEnv = ssEnv ss =+= sigToEnv sig+ }++-- | Bind a primitive type constructor at top level.+addPrimType ∷ StaticsState r → TypId → TyCon → StaticsState r+addPrimType ss tid tc = ss { ssEnv = ssEnv ss =+= tid =:= tc }++---+--- INTERFACE FOR GETTING TYPE INFO+---++-- | Find out the renamed name of an identifier and where it was defined.+getRenamingInfo ∷ AST.Ident Raw → StaticsState r → [RenamingInfo]+getRenamingInfo = Statics.Rename.getRenamingInfo <$.> ssRen++-- | Find out the type of a variable+getVarInfo :: QVarId -> StaticsState r -> Maybe (AST.Type R)+getVarInfo vid ss = typeToStx (makeT2SContext ss) <$> ssEnv ss =..= vid++-- | Find out about a type+getTypeInfo :: QTypId -> StaticsState r -> Maybe TyCon+getTypeInfo tid ss = ssEnv ss =..= tid++-- Find out about a data constructor. If it's an exception constructor,+-- return 'Right' with its parameter, otherwise return the type construtor+-- of the result type+getConInfo :: QConId -> StaticsState r ->+ Maybe (Either TyCon (Maybe (AST.Type R)))+getConInfo cid ss = typeToStx (makeT2SContext ss) <$$$> ssEnv ss =..= cid++-- | Get a printable representation of the current constraint-solving+-- state.+getConstraint ∷ StaticsState r → Doc+getConstraint = pprConstraintState . ssCon++-- Open the given module, if it exists.+staticsEnterScope :: ModId -> StaticsState r -> StaticsState r+staticsEnterScope mid ss =+ case ssEnv ss =..= mid of+ Just (_, e') -> ss { ssEnv = ssEnv ss =+= e' }+ Nothing -> ss++---+--- CHOOSING BEST TYPE NAMES+---++-- | Given the type checker state, add it to the context of a document+-- for printing type names in that document.+addTyNameContext :: StaticsState r → Doc → Doc+addTyNameContext = setTyNames . makeTyNames++-- | Get the type name lookup gadget from the type checker state+makeTyNames :: StaticsState r → TyNames+makeTyNames ss+ = TyNames {+ tnLookup = getBestName ss,+ tnEnter = \mid → makeTyNames (staticsEnterScope mid ss)+ }++-- | Make the type-syntactifying context from the type checker state+makeT2SContext :: StaticsState r →+ T2SContext CurrentImpArrPrintingRule tv+makeT2SContext ss = t2sContext0 { t2sTyNames = makeTyNames ss }++-- | The status of a type name in an environment+data NameStatus+ -- | Bound to the expected type+ = Match+ -- | Not bound+ | NoMatch+ -- | Shadowed+ | Interfere+ deriving Eq++-- | In the given environment, what is the status of the given+-- type name?+getNameStatus :: StaticsState r → Int → QTypId → NameStatus+getNameStatus ss tag tid =+ case [ tid'+ | TyconAt _ tid' <- Statics.getRenamingInfo ql ss ] of+ tid':_ ->+ case getTypeInfo tid' ss of+ Just tc | tcId tc == tag -> Match+ | otherwise -> Interfere+ _ -> NoMatch+ _ -> NoMatch+ where ql = J (map (AST.renId bogus) (jpath tid))+ (AST.ident (AST.idName (jname tid)))++-- | Names known to the pretty-printer that should always be used+-- exactly like this so that things print nicely.+intrinsicNames ∷ [(Int, String)]+intrinsicNames = first tcId <$>+ [ (tcVariant, AST.tnVariant),+ (tcRecord, AST.tnRecord),+ (tcRowEnd, AST.tnRowEnd),+ (tcRowHole, AST.tnRowHole),+ (tcRowMap, AST.tnRowMap),+ (tcUn, AST.tnUn),+ (tcAf, AST.tnAf) ]++-- | Find the best name to refer to a type constructor.+-- The goal here is to get the shortest unambiguous name.+-- 1. If the first parameter is True, we want an accurate name, so+-- skip to step 3.+-- 2. If the unqualified name is bound to either the same type+-- or to nothing, then use the unqualified name.+-- 3. Try qualifiying the name, starting with the last segment+-- and adding one at a time, and if any of these match, then+-- use that.+-- 4. Otherwise, uglify the name, because it's probably gone+-- out of scope.+getBestName :: StaticsState r -> Int -> QTypId -> QTypId++getBestName ss tag qtid+ | Just str ← lookup tag intrinsicNames = qident str+ | otherwise =+ case tryQuals (jpath qtid) (jname qtid) of+ Just qtid' → qtid'+ Nothing+ | AST.isTrivial (idTag (jname qtid))+ , NoMatch ← getNameStatus ss tag qtid+ → qtid+ | otherwise → uglify+ where+ tryQuals mids tid = msum+ [ case getNameStatus ss tag (J mids' tid) of+ Match -> Just (J mids' tid)+ _ -> Nothing+ | mids' <- reverse (List.tails mids) ]+ uglify+ | '?':_ ← show qtid = qtid+ | otherwise = qtid { jpath = ident ('?':show tag) : jpath qtid }
+ src/Statics/Coercion.hs view
@@ -0,0 +1,134 @@+-- | Converts coercion expressions to dynamic checks.+module Statics.Coercion (+ coerceExpression,+) where++import Util+import Util.MonadRef+import qualified AST+import AST.Ident+import Data.Loc+import Meta.Quasi+import Error+import Type+import Statics.Constraint++import Prelude ()+import qualified Data.Map as M++-- | Location to use for constructed code+_loc :: Loc+_loc = mkBogus "<coercion>"++type R = AST.Renamed++-- | Coerce an expression from one type to another, if possible.+coerceExpression :: MonadConstraint tv r m ⇒+ AST.Expr R → Type tv → Type tv → m (AST.Expr R)+coerceExpression e σfrom σto = do+ σfrom' ← subst σfrom+ σto' ← subst σto+ prj ← evalStateT (build mempty σfrom' σto') 0 `catchAlms` handler+ return [ex|+ $prj ($str:neg, $str:pos) $e |]+ where+ neg = "context at " ++ show (getLoc e)+ pos = "value at " ++ show (getLoc e)+ mapMsg f exn = exn { exnMessage = f (exnMessage exn) }+ handler =+ throwAlmsList .+ map (mapMsg [msg| While constructing coercion (:>): <br> $1 |]) .+ mapHead (mapMsg+ [msg|+ $1+ <p>+ Could not construct coercion+ <dl>+ <dt>from type: <dd>$σfrom+ <dt>to type: <dd>$σto.+ </dl>+ <p>+ Hints:+ <ul>+ <li>+ Coercions may be constructed only between (possibly+ quantified) arrow types. All other types must be+ unifiable as subtypes.+ <li>+ Coercion construction may fail if either the type of+ the expression or the requested coercion type is+ incomplete due to type inference, so it may help to+ add a non-coercing type annotation to the term+ inside the coercion, like <q>(e : τfrom :> τto)</q>.+ </ul>+ |])++type RecMap tv r = M.Map (Type tv, Type tv) (VarId R, r Bool)++build :: (MonadConstraint tv r m, MonadState Integer m) ⇒+ RecMap tv r → Type tv → Type tv → m (AST.Expr R)++build μ σfrom σto+ | Just (x, used) ← M.lookup (σfrom, σto) μ+ = do+ writeRef used True+ return [ex| $vid:x |]++build μ σfrom@(TyMu _ σfrom') σto+ = remember μ σfrom σto $ \μ' →+ build μ' (openTy 0 [σfrom] σfrom') σto++build μ σfrom σto@(TyMu _ σto')+ = remember μ σfrom σto $ \μ' →+ build μ' σfrom (openTy 0 [σto] σto')++build μ (TyQu Forall tvs1 σfrom) (TyQu Forall tvs2 σto)+ | length tvs1 == length tvs2+ , all2 (⊑) (snd <$> tvs1) (snd <$> tvs2)+ = build μ σfrom σto++build μ (TyQu Exists tvs1 σfrom) (TyQu Exists tvs2 σto)+ | tvs1 == tvs2+ = build μ σfrom σto++build μ (TyApp tc1 [σf1, qf, σf2]) (TyApp tc2 [σt1, qt, σt2])+ | tc1 == tcFun, tc2 == tcFun+ = do+ dom ← build μ σt1 σf1+ cod ← build μ σf2 σt2+ let which = contractIdent $+ if qualifier qf ⊑ qualifier qt+ then "func"+ else "affunc"+ return [ex| $qvid:which $dom $cod |]++build _ σfrom σto+ = do+ σfrom <: σto+ return [ex| $qvid:anyId |]+ where anyId = contractIdent "any"++-- | Get the identifier for a known name from the contracts library.+contractIdent ∷ String → QVarId R+contractIdent = qident . ("INTERNALS.Contract." ++)++-- | Remember a coercion to use it recursively later.+remember ∷ (MonadConstraint tv r m, MonadState Integer m) ⇒+ RecMap tv r → Type tv → Type tv →+ (RecMap tv r → m (AST.Expr R)) →+ m (AST.Expr R)+remember μ σfrom σto k = do+ c ← freshVarId+ rused ← newRef False+ result ← k (M.insert (σfrom, σto) (c, rused) μ)+ used ← readRef rused+ return $ if used+ then [ex| let rec $vid:c = $result in $vid:c |]+ else result++-- | Get a fresh variable name to build a recursive coercion.+freshVarId :: MonadState Integer m ⇒ m (VarId R)+freshVarId = do+ n ← get+ put (n + 1)+ return (ident ("c" ++ show n))+
+ src/Statics/Constraint.hs view
@@ -0,0 +1,1587 @@+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+module Statics.Constraint (+ -- * The constraint solver interface+ MonadConstraint(..), generalize, generalizeList, generalizeEx,++ -- * An implementation of the interface+ ConstraintT,+ runConstraintT, mapConstraintT,+ ConstraintState, constraintState0, pprConstraintState,+ runConstraintIO,+) where++import Util+import Util.Trace+import Util.MonadRef+import qualified Syntax.Ppr as Ppr+import qualified Alt.Graph as Gr+import qualified Data.UnionFind as UF+import Type+import Statics.Error++import Prelude ()+import qualified Data.List as List+import qualified Data.Set as S+import qualified Data.Map as M+import qualified Data.Boolean.SatSolver as SAT+import Data.IORef (IORef)++---+--- A CONSTRAINT-SOLVING MONAD+---++class MonadSubst tv r m ⇒ MonadConstraint tv r m | m → tv r where+ -- | Subtype and equality constraints+ (<:), (=:) ∷ Type tv → Type tv → m ()+ -- | Subqualifier constraint+ (⊏:), (~:) ∷ (Qualifier q1 tv, Qualifier q2 tv) ⇒ q1 → q2 → m ()+ -- | Constrain by the given variance+ relate ∷ Variance → Type tv → Type tv → m ()+ --+ τ1 =: τ2 = τ1 <: τ2 >> τ2 <: τ1+ τ1 ~: τ2 = τ1 ⊏: τ2 >> τ2 ⊏: τ1+ relate variance τ1 τ2 = case variance of+ Covariant → τ1 <: τ2+ Contravariant → τ2 <: τ1+ Invariant → τ1 =: τ2+ QCovariant → τ1 ⊏: τ2+ QContravariant → τ2 ⊏: τ1+ QInvariant → τ1 ~: τ2+ Omnivariant → return ()+ --+ -- | Get the set of pinned type variables.+ getPinnedTVs ∷ m (S.Set tv)+ -- | Run a computation in the context of some "pinned down" type+ -- variables, which means that they won't be considered for+ -- elimination or generalization.+ withPinnedTVs ∷ Ftv a tv ⇒ a → m b → m b+ -- | Update the list of pinned type variables to reflect a substitution.+ -- PRECONDITION: τ is substituted.+ updatePinnedTVs ∷ tv → Type tv → m ()+ --+ -- | Figure out which variables to generalize in a piece of syntax.+ -- The 'Bool' indicates whether the syntax whose type is being+ -- generalized is a syntactic value. Returns a list of+ -- generalizable variables and their qualifier bounds.+ generalize' ∷ Bool → Rank → Type tv → m [(tv, QLit)]+ -- | Find 'QLit' bounds for a set of type variables. This assumes+ -- that these variables may safely be removed from the constraint+ -- if bounded as specified. In particular, all the variables must+ -- appear only on the left-hand side of the qualifier inequalities.+ getTVBounds ∷ [tv] → m [QLit]+ -- | Ensure that the current constraint is satisfiable. This is+ -- necessary after each REPL entry, because that's the commit point+ -- for the constraint, and the REPL becomes unusable if a particular+ -- type error hangs around in the constraint forever.+ ensureSatisfiability ∷ m ()++infix 5 <:, =:, ⊏:, ~:++--+-- Pass-through instances+--++instance (MonadConstraint tv s m, Monoid w) ⇒+ MonadConstraint tv s (WriterT w m) where+ (<:) = lift <$$> (<:)+ (=:) = lift <$$> (=:)+ (⊏:) = lift <$$> (⊏:)+ (~:) = lift <$$> (~:)+ getPinnedTVs = lift getPinnedTVs+ withPinnedTVs = mapWriterT <$> withPinnedTVs+ updatePinnedTVs= lift <$$> updatePinnedTVs+ generalize' = lift <$$$> generalize'+ getTVBounds = lift <$> getTVBounds+ ensureSatisfiability = lift ensureSatisfiability++instance MonadConstraint tv r m ⇒+ MonadConstraint tv r (StateT s m) where+ (<:) = lift <$$> (<:)+ (=:) = lift <$$> (=:)+ (⊏:) = lift <$$> (⊏:)+ (~:) = lift <$$> (~:)+ getPinnedTVs = lift getPinnedTVs+ withPinnedTVs = mapStateT <$> withPinnedTVs+ updatePinnedTVs= lift <$$> updatePinnedTVs+ generalize' = lift <$$$> generalize'+ getTVBounds = lift <$> getTVBounds+ ensureSatisfiability = lift ensureSatisfiability++instance MonadConstraint tv p m ⇒+ MonadConstraint tv p (ReaderT r m) where+ (<:) = lift <$$> (<:)+ (=:) = lift <$$> (=:)+ (⊏:) = lift <$$> (⊏:)+ (~:) = lift <$$> (~:)+ getPinnedTVs = lift getPinnedTVs+ withPinnedTVs = mapReaderT <$> withPinnedTVs+ updatePinnedTVs= lift <$$> updatePinnedTVs+ generalize' = lift <$$$> generalize'+ getTVBounds = lift <$> getTVBounds+ ensureSatisfiability = lift ensureSatisfiability++instance (MonadConstraint tv p m, Monoid w) ⇒+ MonadConstraint tv p (RWST r w s m) where+ (<:) = lift <$$> (<:)+ (=:) = lift <$$> (=:)+ (⊏:) = lift <$$> (⊏:)+ (~:) = lift <$$> (~:)+ getPinnedTVs = lift getPinnedTVs+ withPinnedTVs = mapRWST <$> withPinnedTVs+ updatePinnedTVs= lift <$$> updatePinnedTVs+ generalize' = lift <$$$> generalize'+ getTVBounds = lift <$> getTVBounds+ ensureSatisfiability = lift ensureSatisfiability++--+-- Some generic operations+--++-- | Generalize a type under a constraint and environment,+-- given whether the the value restriction is satisfied or not+generalize ∷ MonadConstraint tv r m ⇒+ Bool → Rank → Type tv → m (Type tv)+generalize value γrank ρ = do+ αqs ← generalize' value γrank ρ+ standardizeMus <$> closeQuant Forall αqs <$> subst ρ++-- | Generalize a list of types together.+generalizeList ∷ MonadConstraint tv r m ⇒+ Bool → Rank → [Type tv] → m [Type tv]+generalizeList value γrank ρs = do+ αqs ← generalize' value γrank (foldl tyTuple tyUnit ρs)+ mapM (standardizeMus <$> closeQuant Forall αqs <$$> subst) ρs++-- | Generalize the existential type variables in a type+generalizeEx ∷ MonadConstraint tv r m ⇒+ Rank → Type tv → m (Type tv)+generalizeEx γrank ρ0 = do+ ρ ← subst ρ0+ αs ← removeByRank γrank (filter (tvFlavorIs Existential) (ftvList ρ))+ αqs ← mapM addQual αs+ return (closeQuant Exists αqs ρ)+ where+ addQual α = case tvQual α of+ Just ql → return (α, ql)+ Nothing → typeBug "generalizeEx"+ "existential type variable with no rank"++-- | Remove type variables from a list if their rank indicates that+-- they're in the environment or if they're pinned+removeByRank ∷ MonadConstraint tv r m ⇒ Rank → [tv] → m [tv]+removeByRank γrank αs = do+ pinned ← getPinnedTVs+ let keep α = do+ rank ← getTVRank α+ return (rank > γrank && α `S.notMember` pinned)+ filterM keep αs++---+--- SUBTYPING CONSTRAINT SOLVER+---++--+-- The internal state+--++-- | The state of the constraint solver.+data CTState tv r+ = CTState {+ -- | Graph for subtype constraints on type variables and atomic+ -- type constructors+ csGraph ∷ !(Gr.Gr tv ()),+ -- | Reverse lookup for turning atoms into node numbers for the+ -- 'csGraph' graph+ csNodeMap ∷ !(Gr.NodeMap tv),+ -- | Maps type variables to same-size equivalence classes+ csEquivs ∷ !(ProxyMap tv r),+ -- | Types to relate by the subqualifier relation+ csQuals ∷ ![(Type tv, Type tv)],+ -- | Stack of pinned type variables+ csPinned ∷ ![S.Set tv]+ }++-- | Representation of type variable equivalence class+type TVProxy tv r = UF.Proxy r (S.Set tv)+-- | The map from type variables to equivalence classes+type ProxyMap tv r = M.Map tv (TVProxy tv r)++-- | Updater for 'csQuals' field+csQualsUpdate ∷ ([(Type tv, Type tv)] → [(Type tv, Type tv)]) →+ CTState tv r → CTState tv r+csQualsUpdate f cs = cs { csQuals = f (csQuals cs) }++-- | Updater for 'csEquivs' field+csEquivsUpdate ∷ (ProxyMap tv r → ProxyMap tv r) →+ CTState tv r → CTState tv r+csEquivsUpdate f cs = cs { csEquivs = f (csEquivs cs) }++-- | Updater for 'csPinned' field+csPinnedUpdate ∷ ([S.Set tv] → [S.Set tv]) →+ CTState tv r → CTState tv r+csPinnedUpdate f cs = cs { csPinned = f (csPinned cs) }++instance Tv tv ⇒ Show (CTState tv r) where+ showsPrec _ cs+ | null (Gr.edges (csGraph cs)) + , null (csQuals cs) + = id+ | otherwise+ = showString "CTState { csGraph = "+ . shows (Gr.ShowGraph (csGraph cs))+ . showString ", csQuals = "+ . shows (csQuals cs)+ . showString " }"++instance Tv tv ⇒ Ppr.Ppr (CTState tv r) where+ ppr cs = Ppr.ppr . M.fromList $+ [ ("graph", Ppr.fsep . Ppr.punctuate Ppr.comma $+ [ Ppr.pprPrec 10 α1+ Ppr.<> Ppr.text "<:"+ Ppr.<> Ppr.pprPrec 10 α2+ | (α1, α2) ← Gr.labNodeEdges (csGraph cs) ])+ , ("quals", Ppr.fsep . Ppr.punctuate Ppr.comma $+ [ Ppr.pprPrec 9 τ1+ Ppr.<> Ppr.char '⊑'+ Ppr.<> Ppr.pprPrec 9 τ2+ | (τ1, τ2) ← csQuals cs+ ])+ ]++--+-- The monad transformer+--++-- | Underlying 'ConstraintT' is a monad transformer that carries merely+-- the constraint-solving state.+newtype ConstraintT_ tv r m a+ = ConstraintT_ {+ unConstraintT_ ∷ StateT (CTState tv r) m a+ }+ deriving (Functor, Applicative, Monad, MonadAlmsError, MonadTrace)++-- | Map some higher-order operation through 'ConstraintT_'.+mapConstraintT_ ∷ (∀ s. m (a, s) → n (b, s)) →+ ConstraintT_ tv r m a → ConstraintT_ tv r n b+mapConstraintT_ f = ConstraintT_ . mapStateT f . unConstraintT_++-- | Constraint monad transformer carries constraint solver state.+-- 'SubstT' substitution state.+type ConstraintT tv r m = ConstraintT_ tv r (SubstT r m)++-- | Map some higher-order operation through 'ConstraintT'.+mapConstraintT ∷ (Functor m, Functor n) ⇒+ (∀ s. m (a, s) → n (b, s)) →+ ConstraintT tv r m a → ConstraintT tv r n b+mapConstraintT f = mapConstraintT_ (mapSubstT f')+ where+ f' action = unshift <$> f (shift <$> action)+ shift ((a, s), s') = (a, (s, s'))+ unshift (a, (s, s')) = ((a, s), s')++-- | Run the constraint solver.+runConstraintT ∷ (MonadAlmsError m, MonadRef r m) ⇒+ ConstraintState (TV r) r →+ ConstraintT (TV r) r m a →+ m (a, ConstraintState (TV r) r)+runConstraintT ecs m = do+ ((result, cs), ss) ← runSubstT+ (ecsSubst ecs)+ (runStateT (unConstraintT_ (resetEquivTVs >> m))+ (ecsInternal ecs))+ return (result, ExternalConstraintState cs ss)++-- | Run a constraint computation in the IO Monad+runConstraintIO ∷ ConstraintState (TV IORef) IORef →+ ConstraintT (TV IORef) IORef (AlmsErrorT IO) a →+ IO (Either [AlmsError]+ (a, ConstraintState (TV IORef) IORef))+runConstraintIO ecs m = runAlmsErrorT (runConstraintT ecs m)++-- | The external representation of the constraint solver's state+data ConstraintState tv r+ = ExternalConstraintState {+ ecsInternal ∷ !(CTState tv r),+ ecsSubst ∷ !SubstState+ }++-- | The initial constraint solver state+constraintState0 ∷ Tv tv ⇒ ConstraintState tv r+constraintState0+ = ExternalConstraintState {+ ecsInternal = CTState {+ csGraph = Gr.empty,+ csNodeMap = Gr.new,+ csEquivs = M.empty,+ csQuals = [],+ csPinned = []+ },+ ecsSubst = substState0+ }++instance Tv tv ⇒ Ppr.Ppr (ConstraintState tv r) where+ ppr = Ppr.ppr . ecsInternal++instance Tv tv ⇒ Show (ConstraintState tv r) where+ showsPrec = Ppr.showFromPpr++-- | Get a printable representations of the internal constraint-solving+-- state.+pprConstraintState ∷ Tv tv ⇒ ConstraintState tv r → Ppr.Doc+pprConstraintState = Ppr.ppr . ecsInternal++--+-- Instances+--++-- | Transformer instance+instance MonadTrans (ConstraintT_ tv r) where+ lift = ConstraintT_ . lift++-- | Pass through for reference operations+instance MonadSubst tv r m ⇒+ MonadRef r (ConstraintT_ tv r m) where+ newRef = lift <$> newRef+ readRef = lift <$> readRef+ writeRef = lift <$$> writeRef++-- | Pass through for unification operations+instance MonadSubst tv r m ⇒+ MonadSubst tv r (ConstraintT_ tv r m) where+ newTV_ (Universal, kind, bound, descr) = do+ α ← lift (newTV' (kind, descr))+ fvTy α ⊏: bound+ return α+ newTV_ attrs = lift (newTV' attrs)+ writeTV_ = lift <$$> writeTV_+ readTV_ = lift <$> readTV_+ getTVRank_ = lift <$> getTVRank_+ setTVRank_ = lift <$$> setTVRank_+ collectTVs = mapConstraintT_ (mapListen2 collectTVs)+ reportTVs = lift . reportTVs+ monitorChange = mapConstraintT_ (mapListen2 monitorChange)+ setChanged = lift setChanged++-- | 'ConstraintT' implements 'Graph'/'NodeMap' transformer operations+-- for accessing its graph and node map.+instance (Ord tv, Monad m) ⇒+ Gr.MonadNM tv () Gr.Gr (ConstraintT_ tv r m) where+ getNMState = ConstraintT_ (gets (csNodeMap &&& csGraph))+ getNodeMap = ConstraintT_ (gets csNodeMap)+ getGraph = ConstraintT_ (gets csGraph)+ putNMState (nm, g) = ConstraintT_ . modify $ \cs →+ cs { csNodeMap = nm, csGraph = g }+ putNodeMap nm = ConstraintT_ . modify $ \cs → cs { csNodeMap = nm }+ putGraph g = ConstraintT_ . modify $ \cs → cs { csGraph = g }++-- | Constraint solver implementation.+instance MonadSubst tv r m ⇒+ MonadConstraint tv r (ConstraintT_ tv r m) where+ τ <: τ' = do+ traceN 3 ("<:", τ, τ')+ runSeenT (subtypeTypes False τ τ')+ τ =: τ' = do+ traceN 3 ("=:", τ, τ')+ runSeenT (subtypeTypes True τ τ')+ τ ⊏: τ' = do+ traceN 3 ("⊏:", qualToType τ, qualToType τ')+ addQualConstraint τ τ'+ --+ getPinnedTVs = S.unions <$> ConstraintT_ (gets csPinned)+ --+ withPinnedTVs a m = do+ let αs = ftvSet a+ ConstraintT_ (modify (csPinnedUpdate (αs :)))+ result ← m+ ConstraintT_ (modify (csPinnedUpdate tail))+ return result+ --+ updatePinnedTVs α τ = do+ let βs = ftvSet τ+ update = snd . mapAccumR eachSet False+ eachSet False set+ | α `S.member` set = (True, βs `S.union` S.delete α set)+ eachSet done set = (done, set)+ ConstraintT_ (modify (csPinnedUpdate update))+ --+ generalize' = solveConstraint+ getTVBounds = solveBounds+ ensureSatisfiability = checkQualifiers++{-# INLINE gtraceN #-}+gtraceN ∷ (TraceMessage a, Tv tv, MonadTrace m) ⇒+ Int → a → ConstraintT_ tv r m ()+gtraceN =+ if debug then \n info →+ if n <= debugLevel then do+ trace info+ cs ← ConstraintT_ get+ let doc = Ppr.ppr cs+ unless (Ppr.isEmpty doc) $+ trace (Ppr.nest 4 doc)+ else return ()+ else \_ _ → return ()++-- | Monad transformer for tracking which type comparisons we've seen,+-- in order to implement recursive subtyping. A pair of types mapped+-- to @True@ means that they're known to be equal, whereas @False@+-- means that they're only known to be subtyped.+type SeenT tv r m = StateT (M.Map (Type tv, Type tv) Bool)+ (ConstraintT_ tv r m)++-- | Run a recursive subtyping computation.+runSeenT ∷ (Tv tv, MonadTrace m) ⇒ SeenT tv r m a → ConstraintT_ tv r m a+runSeenT m = do+ gtraceN 4 "runSeenT {"+ result ← evalStateT m M.empty+ gtraceN 4 "} runSeenT"+ return result++-- | Relate two types at either subtyping or equality, depending on+-- the value of the first parameter (@True@ means equality).+-- This eagerly solves as much as possible, adding to the constraint+-- only as necessary.+subtypeTypes ∷ MonadSubst tv r m ⇒+ Bool → Type tv → Type tv → SeenT tv r m ()+subtypeTypes unify = check where+ check τ1 τ2 = do+ lift $ gtraceN 4 ("subtypeTypes", unify, τ1, τ2)+ τ1' ← subst τ1+ τ2' ← subst τ2+ seen ← get+ unless (M.lookup (τ1', τ2') seen >= Just unify) $ do+ put (M.insert (τ1', τ2') unify seen)+ decomp τ1' τ2'+ --+ decomp τ1 τ2 = case (τ1, τ2) of+ (TyVar v1, TyVar v2)+ | v1 == v2 → return ()+ (TyVar (Free r1), TyVar (Free r2))+ | tvFlavorIs Universal r1, tvFlavorIs Universal r2 →+ if unify+ then unifyVar r1 (fvTy r2)+ else do+ lift (makeEquivTVs r1 r2)+ addEdge r1 r2+ (TyVar (Free r1), _)+ | tvFlavorIs Universal r1 →+ occursCheck r1 τ2 decomp $ \τ2'' → do+ τ2' ← if unify then return τ2'' else copyType τ2''+ unifyVar r1 τ2'+ unless unify (check τ2' τ2)+ (_, TyVar (Free r2))+ | tvFlavorIs Universal r2 → do+ occursCheck r2 τ1 (flip decomp) $ \τ1'' → do+ τ1' ← if unify then return τ1'' else copyType τ1''+ unifyVar r2 τ1'+ unless unify (check τ1 τ1')+ (TyQu Forall αs1 τ1', TyQu Forall αs2 τ2')+ | if unify+ then αs1 == αs2+ else length αs1 == length αs2+ && and (zipWith ((⊒)`on`snd) αs1 αs2) →+ check τ1' τ2'+ (TyQu Exists αs1 τ1', TyQu Exists αs2 τ2')+ | αs1 == αs2 →+ check τ1' τ2'+ (TyApp tc1 τs1, TyApp tc2 τs2)+ | tc1 == tc2 && tc1 /= tcRowMap && length τs1 == length τs2 →+ sequence_+ [ if unify+ then if isQVariance var+ then τ1' ~: τ2'+ else check τ1' τ2'+ else relateTypes var τ1' τ2'+ | var ← tcArity tc1+ | τ1' ← τs1+ | τ2' ← τs2 ]+ (TyRow n1 τ11 τ12, TyRow n2 τ21 τ22)+ | n1 == n2 → do+ check τ11 τ21+ check τ12 τ22+ | otherwise → do+ α ← newTVTy+ check (TyRow n1 τ11 α) τ22+ β ← newTVTy+ check τ12 (TyRow n2 τ21 β)+ check α β+ (TyMu _ τ1', _) →+ decomp (openTy 0 [τ1] τ1') τ2+ (_, TyMu _ τ2') →+ decomp τ1 (openTy 0 [τ2] τ2')+ _ | Just (τ1', τ2') ← matchReduce τ1 τ2 →+ check τ1' τ2'+ (TyApp tc1 [τ11, τ12], TyApp tc2 [τ21, τ22])+ | tc1 == tcRowMap && tc2 == tcRowMap → do+ check τ11 τ21+ check τ12 τ22+ _ | otherwise →+ tErrExp+ (if unify+ then [msg| Cannot unify: |]+ else [msg| Cannot subtype: |])+ (pprMsg τ1)+ (pprMsg τ2)+ --+ addEdge a1 a2 = do+ Gr.insNewMapNodeM a1+ Gr.insNewMapNodeM a2+ Gr.insMapEdgeM (a1, a2, ())+ lift (fvTy a1 ⊏: fvTy a2)++-- | Relate two types at the given variance.+relateTypes ∷ MonadSubst tv r m ⇒+ Variance → Type tv → Type tv → SeenT tv r m ()+relateTypes var = case var of+ Invariant → subtypeTypes True+ Covariant → subtypeTypes False+ Contravariant → flip (subtypeTypes False)+ QInvariant → (~:)+ QCovariant → (⊏:)+ QContravariant→ flip (⊏:)+ Omnivariant → \_ _ → return ()++-- | Copy a type while replacing all the type variables with fresh ones+-- of the same kind.+copyType ∷ MonadSubst tv r m ⇒ Type tv → m (Type tv)+copyType =+ foldTypeM (mkQuF (return <$$$> TyQu))+ (mkBvF (return <$$$> bvTy))+ fvar+ fcon+ (return <$$$> TyRow)+ (mkMuF (return <$$> TyMu))+ where+ fvar α | tvFlavorIs Universal α = newTVTy' (tvKind α)+ | otherwise = return (fvTy α)+ -- Nullary type constructors that are involved in the atomic subtype+ -- relation are converted to type variables:+ fcon tc τs+ = TyApp tc <$> sequence+ [ -- A Q-variant type constructor parameter becomes a single+ -- type variable:+ if isQVariance var+ then newTVTy' KdQual+ else return τ+ | τ ← τs+ | var ← tcArity tc ]++-- | Unify a type variable with a type, where the type must be locally+-- closed.+-- ASSUMPTIONS: @α@ has not been substituted and the occurs check has+-- already passed.+unifyVar ∷ MonadSubst tv r m ⇒ tv → Type tv → SeenT tv r m ()+unifyVar α τ0 = do+ lift $ gtraceN 4 ("unifyVar", α, τ0)+ τ ← subst τ0+ tassert (lcTy 0 τ)+ [msg|+ Cannot unify because a $τ is insufficiently polymorphic+ |]+ writeTV α τ+ lift (updatePinnedTVs α τ)+ (n, _) ← Gr.mkNodeM α+ gr ← Gr.getGraph+ case Gr.match n gr of+ (Nothing, _) → return ()+ (Just (pres, _, _, sucs), gr') → do+ Gr.putGraph gr'+ sequence_ $+ [ case Gr.lab gr' n' of+ Nothing → return ()+ Just a → subtypeTypes False (fvTy a) τ+ | (_, n') ← pres ]+ +++ [ case Gr.lab gr' n' of+ Nothing → return ()+ Just a → subtypeTypes False τ (fvTy a)+ | (_, n') ← sucs ]++--- OCCURS CHECK++-- | Performs the occurs check and returns a type suitable for unifying+-- with the given type variable, if possible. This does the subtyping+-- occurs check, which checks not in terms of type variables but in+-- terms of same-size equivalence classes of type variables.+-- Unification is possible if all occurrences of type variables+-- size-equivalent to @α@ appear guarded by a type constructor that+-- permits recursion, in which case we roll up @τ@ as a recursive type+-- and return that.+occursCheck ∷ MonadSubst tv r m ⇒+ tv → Type tv →+ (Type tv → Type tv → SeenT tv r m ()) →+ (Type tv → SeenT tv r m ()) →+ SeenT tv r m ()+occursCheck α τ0 kv kt = do+ lift (gtraceN 3 ("occursCheck", α, τ0))+ loop S.empty τ0+ where+ loop seen τ = do+ let (guarded, unguarded) = (M.keys***M.keys) . M.partition id $ ftvG τ+ apparentCycle ← lift $ anyA (checkEquivTVs α) unguarded+ if apparentCycle+ then case headReduceType τ of+ Next τ'@(TyVar (Free _)) → kv (fvTy α) τ'+ Next τ' | τ' ∉ seen → loop (S.insert τ' seen) τ'+ _ →+ -- | This type error has to throw because continuing will+ -- likely cause the type checker to diverge.+ typeError' [msg|+ Occurs check failed.+ Cannot construct an infinite type when unifying:+ <dl>+ <dt>type variable <dd>$α+ <dt>type <dd>$τ0+ </dl>+ |]+ else do+ recVars ← lift $ filterM (checkEquivTVs α) guarded+ unless (null recVars) $+ lift (gtraceN 3 ("occursCheck", "recvars", recVars))+ kt (foldr closeRec τ recVars)++-- | Records that two type variables have the same size.+makeEquivTVs ∷ MonadSubst tv r m ⇒ tv → tv → ConstraintT_ tv r m ()+makeEquivTVs α β = do+ pα ← getTVProxy α+ pβ ← getTVProxy β+ UF.coalesce_ (return <$$> S.union) pα pβ++-- | Checks whether two type variables have the same size.+checkEquivTVs ∷ MonadSubst tv r m ⇒ tv → tv → ConstraintT_ tv r m Bool+checkEquivTVs α β = do+ pα ← getTVProxy α+ pβ ← getTVProxy β+ UF.sameRepr pα pβ++-- | Clears all size-equivalence classes and rebuilds them based on the+-- current atomic subtyping constraint graph.+resetEquivTVs ∷ MonadSubst tv r m ⇒ ConstraintT_ tv r m ()+resetEquivTVs = do+ ConstraintT_ (modify (csEquivsUpdate (const M.empty)))+ g ← Gr.getGraph+ mapM_ (uncurry makeEquivTVs)+ [ (α, β) | (α, β) ← Gr.labNodeEdges g ]++-- | Helper to get the proxy the represents the size-equivalence class+-- of a type variable.+getTVProxy ∷ MonadSubst tv r m ⇒ tv → ConstraintT_ tv r m (TVProxy tv r)+getTVProxy α = do+ equivs ← ConstraintT_ (gets csEquivs)+ case M.lookup α equivs of+ Just pα → return pα+ Nothing → do+ pα ← UF.create (S.singleton α)+ ConstraintT_ (modify (csEquivsUpdate (M.insert α pα)))+ return pα++--- CONSTRAINT SOLVING++-- | Solve a constraint as much as possible, returning the type+-- variables to generalize and their qualifier bounds.+solveConstraint ∷ MonadSubst tv r m ⇒+ Bool → Rank → Type tv → ConstraintT_ tv r m [(tv, QLit)]+solveConstraint value γrank τ0 = do+ τ ← subst τ0+ let τftv = ftvV τ+ gtraceN 2 (TraceIn ("gen", "begin", value, γrank, τftv, τ))+ τftv ← coalesceSCCs τftv+ gtraceN 3 ("gen", "scc", τftv, τ)+ Gr.modifyGraph Gr.trcnr+ gtraceN 4 ("gen", "trc", τftv, τ)+ eliminateExistentials True (γrank, τftv)+ gtraceN 3 ("gen", "existentials 1", τftv, τ)+ untransitive+ gtraceN 3 ("gen", "untrans", τftv, τ)+ eliminateExistentials False (γrank, τftv)+ gtraceN 3 ("gen", "existentials 2", τftv, τ)+ τftv ← polarizedReduce τftv+ gtraceN 3 ("gen", "polarized", τftv, τ)+ eliminateExistentials False (γrank, τftv)+ gtraceN 3 ("gen", "existentials 3", τftv, τ)+ -- Guessing starts here+ τftv ← coalesceComponents value (γrank, τftv)+ gtraceN 3 ("gen", "components", τftv, τ)+ -- Guessing ends here+ qc ← ConstraintT_ $ gets csQuals >>= mapM subst+ cftv ← S.fromList . map snd <$> Gr.getsGraph Gr.labNodes+ αs ← S.fromDistinctAscList <$>+ filter (tvFlavorIs Universal) <$>+ (removeByRank γrank+ (S.toAscList $ (ftvSet qc `S.union` M.keysSet τftv) S.\\ cftv))+ (qc, αqs, τ) ← solveQualifiers value αs qc τ+ ConstraintT_ (modify (csQualsUpdate (const qc)))+ gtraceN 2 (TraceOut ("gen", "finished", αqs, τ))+ resetEquivTVs+ return αqs+ where+ --+ -- Eliminate existentially-quantified type variables from the+ -- constraint+ eliminateExistentials trans (γrank, τftv) = do+ extvs ← getExistentials (γrank, τftv)+ traceN 4 ("existentials:", extvs)+ mapM (eliminateNode trans) (S.toList extvs)+ -- Get the existential type variables+ getExistentials (γrank, τftv) = do+ lnodes ← Gr.getsGraph Gr.labNodes+ cftv ← removeByRank γrank [ α | (_, α) ← lnodes ]+ return (S.fromList cftv S.\\ M.keysSet τftv)+ -- Remove a node unless it is necessary to associate some of its+ -- neighbors -- in particular, a node with multiple predecessors+ -- but no successor (or dually, multiple successors but no+ -- predecessor) should not be removed.+ eliminateNode trans α = do+ (nm, g) ← Gr.getNMState+ let node = Gr.nmLab nm α+ case (Gr.pre g node, Gr.suc g node) of+ (_:_:_, []) → return ()+ ([], _:_:_) → return ()+ (pre, suc) → do+ β ← newTVTy' KdQual+ writeTV α β+ traceN 4 ("eliminateNode",+ catMaybes (map (Gr.lab g) pre),+ β,+ catMaybes (map (Gr.lab g) suc))+ Gr.putGraph $+ let g' = Gr.delNode node g in+ if trans+ then g'+ else foldr ($) g'+ [ Gr.insEdge (n1, n2, ())+ | n1 ← pre+ , n2 ← suc ]+ --+ -- Remove redundant edges:+ -- • Edges implied by transitivity+ untransitive = Gr.modifyGraph Gr.untransitive+ --+ -- Remove type variables based on polarity-related rules:+ -- • Coalesce positive type variables with a single predecessor+ -- and negative type variables with a single successor+ -- • Coalesce positive type variables that share all their+ -- predecessors and negative type variables that share all+ -- their successors.+ polarizedReduce = iterChanging $ \τftv → do+ nm ← Gr.getNodeMap+ foldM tryRemove τftv (findPolar nm τftv)+ where+ tryRemove τftv (n, α, var) = do+ let ln = (n, α)+ mτ ← readTV α+ g ← Gr.getGraph+ case (mτ, Gr.gelem n g) of+ (Left _, True) →+ case (var, Gr.pre g n, Gr.suc g n) of+ -- Should we consider QCo(ntra)variance here too?+ (Covariant, [pre], _)+ → snd <$> coalesce ln (Gr.labelNode g pre) τftv+ (Contravariant, _, [suc])+ → snd <$> coalesce ln (Gr.labelNode g suc) τftv+ (Covariant, pres, _)+ → siblings g τftv (ln, 1) pres (Gr.pre,Gr.suc)+ (Contravariant, _, sucs)+ → siblings g τftv (ln, -1) sucs (Gr.suc,Gr.pre)+ _ → return τftv+ _ → return τftv+ findPolar nm τftv = [ (Gr.nmLab nm α, α, var)+ | (α, var) ← M.toList τftv+ , var == 1 || var == -1 ]+ siblings g τftv (lnode@(n,_), var) pres (gpre, gsuc) = do+ lnodes ← liftM ordNub . runListT $ do+ pre ← ListT (return pres)+ sib ← ListT (return (gsuc g pre))+ guard $ sib /= n+ Just β ← return (Gr.lab g sib)+ guard $ M.lookup β τftv == Just var+ guard $ gpre g sib == pres+ return (sib, β)+ case lnodes of+ _:_ → do+ τftv' ← snd <$> coalesceList τftv (lnode:lnodes)+ return τftv'+ _ → return τftv+ --+ -- Coalesce the strongly-connected components to single atoms+ coalesceSCCs τftv = do+ foldM (liftM snd <$$> coalesceList) τftv =<< Gr.getsGraph Gr.labScc + -- Given a list of atoms, coalesce them to one atom+ coalesceList τftv0 (ln:lns) =+ foldM (\(ln1, state) ln2 → coalesce ln1 ln2 state) (ln, τftv0) lns+ coalesceList _ [] = typeBug "coalesceList" "Got []"+ -- Assign n2 to n1, updating the graph, type variables, and ftvs,+ -- and return whichever node survives+ -- PRECONDITION: α1 /= α2+ coalesce (n1, α1) (n2, α2) τftv = do+ τftv' ← assignTV α1 α2 τftv+ assignNode n1 n2+ return ((n2, α2), τftv')+ -- Update the graph to remove node n1, assigning all of its+ -- neighbors to n2+ assignNode n1 n2 = Gr.modifyGraph $ \g →+ Gr.insEdges [ (n', n2, ())+ | n' ← Gr.pre g n1, n' /= n1, n' /= n2 ] $+ Gr.insEdges [ (n2, n', ())+ | n' ← Gr.suc g n1, n' /= n1, n' /= n2 ] $+ Gr.delNode n1 g+ -- Update the type variables to assign β to α, updating the+ -- ftvs appropriately+ assignTV α β τftv = do+ writeTV α (fvTy β)+ updatePinnedTVs α (fvTy β)+ assignFtvMap α β τftv+ -- Given two type variables, where α ← β, update a map of free+ -- type variables to variance lists accordingly+ assignFtvMap α β vmap =+ case M.lookup α vmap of+ Just vs → return $ M.insertWith (+) β vs vmap'+ Nothing → return vmap+ where vmap' = M.delete α vmap+ -- Coalesce and remove fully-generalizable components+ coalesceComponents value (γrank, τftv) = do+ extvs ← getExistentials (γrank, τftv)+ τcands ← genCandidates value τftv γrank+ let candidates = extvs `S.union` τcands+ each τftv component@(_:_)+ | all (`S.member` candidates) (map snd component)+ = do+ ((node, _), τftv')+ ← coalesceList τftv component+ Gr.getGraph >>= Gr.putGraph . Gr.delNode node+ return τftv'+ each τftv _+ = return τftv+ foldM each τftv =<< Gr.getsGraph Gr.labComponents+ -- Find the generalization candidates, which are free in τ but+ -- not in γ (restricted further if not a value)+ genCandidates value τftv γrank =+ S.fromDistinctAscList <$>+ removeByRank γrank (map fst (M.toAscList (restrict τftv)))+ where+ restrict = if value+ then id+ else M.filter (`elem` [1, -1, 2, -2])++---+--- QUALIFIER CONSTRAINT SOLVING+---++{-++Syntactic metavariables:++ γ: any type variable+ α: generalization candidates+ β: type variables with Q-variance+ δ: generalization candidates with Q-variance+ q: qualifier literals+ _s: a collection of _++ qe ::= q | γs | q γs (qualifier expressions)++First rewrite as follows:++(DECOMPOSE)+ γs₁ \ γs₂ = γ₁ ... γⱼ+ βs = { γ ∈ γs₂ | γ is Q-variant }+ βsᵢ = if γᵢ is Q-variant then γs₂ else βs+ -----------------------------------------------------------------------+ q₁ γs₁ ⊑ q₂ γs₂ ---> q₁ \-\ q₂ ⊑ βs ⋀ γ₁ ⊑ q₁ βs₁ ⋀ ... ⋀ γⱼ ⊑ q₁ βsᵢ++(BOT-SAT)+ ---------------+ U ⊑ βs ---> ⊤++(TOP-SAT)+ -----------------+ γ ⊑ A βs ---> ⊤++(BOT-UNSAT)+ q ≠ U+ -----------------+ q ⊑ U ---> fail++(COMBINE-QLIT)+ --------------------------------------------+ γ ⊑ q ⋀ γ ⊑ q' ⋀ C; τ ---> γ ⊑ q⊓q' ⋀ C; τ++(COMBINE-LE)+ q ⊑ q' βs ⊆ βs'+ ---------------------------------------------------+ γ ⊑ q βs ⋀ γ ⊑ q' βs' ⋀ C; τ ---> γ ⊑ q βs ⋀ C; τ++Then we have a constraint where each inequality is in one of two forms:++ γ ⊑ q βs+ q ⊑ βs++Now we continue to rewrite and perform substitutions as well. Continue+to apply the above rules when they apply. These new rewrites apply to a+whole constraint and type together, not to single atomic constraints.++For a type variable γ and type τ, let V(γ,τ) be γ's variance in τ. We+also refer to the free type variables in only the lower or upper bounds+of a constraint C as lftv(C) and uftv(C), respectively.++These are non-lossy rewrites. Repeat them as much as possible,+continuing to apply the rewrites above when applicable:++(FORCE-U)+ -------------------------------+ β ⊑ U ⋀ C; τ ---> [U/β](C; τ)++(SUBST-NEG)+ δ ∉ lftv(C) V(δ,τ) ⊑ Q-+ ---------------------------------+ δ ⊑ qe ⋀ C; τ ---> [qe/δ](C; τ)++(SUBST-NEG-TOP)+ δ ∉ lftv(C) V(δ,τ) ⊑ Q-+ -------------------------+ C; τ ---> [A/δ](C; τ)++(SUBST-POS)+ δ ∉ uftv(C) V(δ,τ) ⊑ Q++ -----------------------------------------------------------+ qe₁ ⊑ δ ⋀ ... ⋀ qeⱼ ⊑ δ ⋀ C; τ ---> [qe₁⊔...⊔qeⱼ/δ](C; τ)++(SUBST-INV)+ δ ∉ uftv(C) V(δ,τ) = Q= δ' fresh+ --------------------------------------------------------------+ qe₀ ⊑ δ ⋀ ... ⋀ qeⱼ ⊑ δ ⋀ C; τ ---> [δ'⊔qe₀⊔...⊔qeⱼ/δ](C; τ)++Substitute for contravariant qualifier variables by adding these lossy+rewrites:++(SUBST-NEG-LOSSY)+ δ ∉ lftv(C) V(δ,τ) = Q-+ -----------------------------------------------+ δ ⊑ q₁ βs₁ ⋀ ... ⋀ δ ⊑ qⱼ βsⱼ ⋀ C; τ+ ---> [(q₁⊓...⊓qⱼ) (βs₁ ∩ ... ∩ βsⱼ)/δ](C; τ)++Run SAT as below for anything we missed. Then, add bounds:++(BOUND)+ α ∉ lftv(C) V(α,τ) ∈ { -, +, =, Q= } q = q₁⊓...⊓qⱼ+ ------------------------------------------------------+ α ⊑ q₁ βs₁ ⋀ ... ⋀ α ⊑ qⱼ βsⱼ ⋀ C; τ+ ---> [U/α]C; ∀α:q. τ+++We convert it to SAT as follows:++ Define:++ πa(Q) = A ⊑ Q+ πa(β) = 2 * tvId β + 1+ πa(q1 ⊔ q2) = πa(q1) ⋁ πa(q2)+ πa(q1 ⊓ q2) = πa(q1) ⋀ πa(q2)++ Then given the constraint++ q1 ⊑ q1' ⋀ ... ⋀ qk ⊑ qk'++ generate the formula:++ (πa(q1) ⇒ πa(q1'))+ ⋀ ... ⋀+ (πa(qk) ⇒ πa(qk'))++-}++-- | Represents the meet of several qualifier expressions, which happens+-- when some variable has multiple upper bounds. These are normalized+-- to implement COMBINE-QLIT and COMBINE-LE.+newtype QEMeet tv = QEMeet { unQEMeet ∷ [S.Set tv] }++instance Bounded (QEMeet tv) where+ minBound = QEMeet [S.empty]+ maxBound = QEMeet []++instance Tv tv ⇒ Ppr.Ppr (QEMeet tv) where+ ppr (QEMeet []) = Ppr.char 'A'+ ppr (QEMeet [qe]) = Ppr.ppr (QeU qe)+ ppr (QEMeet qem) =+ Ppr.prec Ppr.precCaret $+ Ppr.fsep (Ppr.punctuate (Ppr.text " ⋀")+ (Ppr.ppr <$> QeU <$> qem))++instance Tv tv ⇒ Show (QEMeet tv) where showsPrec = Ppr.showFromPpr++instance Ord tv ⇒ Ftv (QEMeet tv) tv where+ ftvTree = FTBranch . map FTSingle . S.toList . ftvSet+ ftvSet = S.unions . unQEMeet++instance Ord tv ⇒ Monoid (QEMeet tv) where+ mempty = maxBound+ mappend = foldr (qemInsert . QeU) <$.> unQEMeet++qemSingleton ∷ QExp tv → QEMeet tv+qemSingleton QeA = maxBound+qemSingleton (QeU αs) = QEMeet [αs]++qemInsert ∷ Ord tv ⇒ QExp tv → QEMeet tv → QEMeet tv+qemInsert qe (QEMeet qem) = QEMeet (loop qe qem) where+ loop QeA qem = qem+ loop (QeU αs) qem = loopU αs qem+ loopU αs [] = [αs]+ loopU αs (βs:qem)+ | αs `S.isSubsetOf` βs = loopU αs qem+ | βs `S.isSubsetOf` αs = βs:qem+ | otherwise = βs:loopU αs qem++-- | State of the qualifier constraint solver+data QCState tv+ = QCState {+ -- | Generalization candidates, which are type variables that+ -- appear in the qualifier constraint or type-to-be-generalized,+ -- but not in the shape constraint or environment+ sq_αs ∷ !(S.Set tv),+ -- | The current type to be generalized+ sq_τ ∷ !(Type tv),+ -- | Free type variables and variances in the type-to-be-generalized.+ sq_τftv ∷ !(VarMap tv),+ -- | Part of the qualifier constraint: joins of type variables+ -- lower-bounded by qualifier literals.+ sq_βlst ∷ ![(QLit, S.Set tv)],+ -- | Part of the qualifier constraint: type variables+ -- upper-bounded by (meets of) qualifier expressions.+ sq_vmap ∷ !(M.Map tv (QEMeet tv))+ }+ deriving Show++-- | The empty qualifier constraint+qcState0 ∷ QCState tv+qcState0 = QCState S.empty tyUnit M.empty mempty M.empty++instance Tv tv ⇒ Ppr.Ppr (QCState tv) where+ ppr sq = p . M.fromList $+ [ ("αs", p (sq_αs sq))+ , ("τ", p (sq_τ sq))+ , ("τftv", p (sq_τftv sq))+ , ("βlst", Ppr.fsep . Ppr.punctuate (Ppr.text " ⋀") $+ [ p ql Ppr.<> Ppr.char '⊑' Ppr.<>+ Ppr.hcat (Ppr.punctuate (Ppr.char '⊔')+ (p <$> S.toList tvs))+ | (ql, tvs) ← sq_βlst sq ])+ , ("vmap", Ppr.fsep . Ppr.punctuate (Ppr.text " ⋀") $+ [ p α Ppr.<> Ppr.char '⊑' Ppr.<> p qe+ | (α, qem) ← M.toList (sq_vmap sq)+ , qe ← unQEMeet qem ])+ ]+ where p x = Ppr.ppr x++---+--- MAIN QUALIFIER CONSTRAINT OPERATIONS+---++-- | Add a qualifier subtyping constraint+addQualConstraint ∷ (MonadSubst tv r m, Qualifier q1 tv, Qualifier q2 tv) ⇒+ q1 → q2 → ConstraintT_ tv r m ()+addQualConstraint q1 q2 = do+ q1' ← simplifyQual q1+ q2' ← simplifyQual q2+ tassert (q1' /= qlitexp Qa || q2' /= qlitexp Qu)+ [msg| Qualifier inequality unsatisfiable: Attempted to use an+ affine type where only an unlimited type is permitted. |]+ let qe1 = mapQExp (S.mapMonotonic Free) q1'+ qe2 = mapQExp (S.mapMonotonic Free) q2'+ unless (q1' ⊑ q2') $+ ConstraintT_ . modify . csQualsUpdate $+ ((qualToType qe1, qualToType qe2) :)++-- Find qualifier bounds for type variables that definitely have only+-- upper bounds.+solveBounds ∷ MonadSubst tv r m ⇒+ [tv] → ConstraintT_ tv r m [QLit]+solveBounds αs = do+ qc ← ConstraintT_ (gets csQuals)+ state ← decomposeQuals qc qcState0+ traceN 4 ("solveBounds", "decompose", state)+ let vmap = sq_vmap state+ ConstraintT_ . modify . csQualsUpdate . const $+ recomposeQuals state { sq_vmap = foldl' (flip M.delete) vmap αs }+ return [ case M.lookup α vmap of+ Just (QEMeet (_:_)) → Qu+ _ → Qa+ | α ← αs ]++-- Ensure that the qualifier constraint is satisfiable, but don't+-- make any approximating assumptions toward solving the constraint.+checkQualifiers ∷ MonadSubst tv r m ⇒ ConstraintT_ tv r m ()+checkQualifiers = do+ qc ← ConstraintT_ (gets csQuals)+ state ← decomposeQuals qc qcState0+ traceN 4 ("checkQualifiers", "decompose", state)+ runSat state False+ ConstraintT_ . modify . csQualsUpdate . const $ recomposeQuals state++-- | Solver for qualifier contraints.+-- Given a qualifier constraint, solve and produce type variable+-- bounds. Also return any remaining inequalities (which must be+-- satisfiable, but we haven't guessed how to satisfy them yet).+solveQualifiers+ ∷ MonadConstraint tv r m ⇒+ -- | Are we generalizing the type of a non-expansive term?+ Bool →+ -- | Generalization candidates+ S.Set tv →+ -- | The constraint as pairs of types in the subqualifier relation+ [(Type tv, Type tv)] →+ -- | The type to be generalized+ Type tv →+ m ([(Type tv, Type tv)], [(tv, QLit)], Type tv)+solveQualifiers value αs qc τ = do+ traceN 3 (TraceIn ("solveQ", "init", αs, qc))+ -- Decompose implements DECOMPOSE, TOP-SAT, BOT-SAT, and BOT-UNSAT.+ τftv ← ftvV <$> subst τ+ state ← decomposeQuals qc qcState0 {+ sq_αs = αs,+ sq_τftv = τftv,+ sq_τ = τ+ }+ traceN 4 ("solveQ", "decompose", state)+ -- Rewrite until it stops changing+ state ← iterChanging+ (stdizeType >=>+ forceU >=>+ substNeg False >=>!+ substPosInv >=>!+ substNeg True)+ state+ traceN 4 ("solveQ", "rewrites", state)+ -- Try the SAT solver, then recheck+ state ← runSat state True+ traceN 4 ("solveQ", "sat", state)+ runSat state False+ -- Finish by reconstructing the constraint and returning the bounds+ -- for the variables to quantify.+ state ← genVars state+ traceN 3 (TraceOut ("solveQ", "done", state))+ return (recomposeQuals state, getBounds state, τ)+ where+ --+ -- Standardize the qualifiers in the type+ stdizeType state = do+ τ ← subst τ+ let meet (QEMeet [αs])+ | S.null αs = Qu+ meet _ = Qa+ qm = meet <$> sq_vmap state+ τ' = standardizeQuals qm τ+ τftv = ftvV τ'+ traceN 5 ("stdizeType", τ, τ', qm)+ return state {+ sq_τ = τ',+ sq_τftv = τftv+ }+ --+ -- Substitute U for qualifier variables upper bounded by U (FORCE-U).+ forceU state =+ qSubsts "forceU" state $+ minBound <$+ M.filterWithKey+ (\β qem → case qem of+ QEMeet [γs] → qUnifiable state β && S.null γs+ _ → False)+ (sq_vmap state)+ --+ -- Replace Q- and 0-variant variables by a single upper bound, if they+ -- have only one (SUBST-NEG), or by A if they have none (SUBST-NEG-TOP).+ -- If 'doLossy', then we include SUBST-NEG-LOSSY as well, which uses+ -- approximate lower bounds for combining multiple upper bounds.+ substNeg doLossy state =+ qSubsts who state $ M.fromDistinctAscList $ do+ δ ← S.toAscList (sq_αs state)+ guard (qUnifiable state δ+ && M.lookup δ (sq_τftv state) ⊑ Just QContravariant)+ case M.lookup δ (sq_vmap state) of+ Nothing → return (δ, maxBound)+ Just (QEMeet []) → return (δ, maxBound)+ Just (QEMeet [qe]) → return (δ, QeU qe)+ Just (QEMeet qes)+ | doLossy → return (δ, bigMeet (QeU <$> qes))+ | otherwise → mzero+ where who = if doLossy then "substNeg/lossy" else "substNeg"+ --+ -- Replace Q+ and Q= variables with tight lower bounds.+ substPosInv state = do+ let add qe (S.toList → [β])+ | β `S.member` sq_αs state+ = M.insertWith (liftA2 (⊔)) β (Just qe)+ add _ βs+ = M.union (setToMap Nothing βs)+ -- For each (γ ⊑ meet) in the state, make γ ⊑ each qe in the meet+ add_vmap = M.foldrWithKey each <-> (sq_vmap state) where+ each γ (QEMeet qem) = foldr (add (qvarexp γ)) <-> qem+ -- for each (q ⊑ βs) in the state, make q ⊑ βs+ add_βlst = foldr each <-> sq_βlst state where+ each (q, βs) = add (qlitexp q) βs+ -- The lower bounds+ lbs = M.mapMaybe id . add_βlst . add_vmap+ $ setToMap (Just minBound)+ (S.filter (qUnifiable state) (sq_αs state))+ M.\\ sq_vmap state+ -- Positive variables with lower bounds+ pos = lbs M.\\ M.filter (/= QCovariant) (sq_τftv state)+ -- Invariant variables with lower bounds+ inv = lbs `M.intersection`+ M.filter (== QInvariant) (sq_τftv state)+ (δ's, inv) ← first S.fromDistinctAscList . unzip <$> sequence+ [ do+ δ' ← newTV' KdQual+ return (δ', (δ, S.insert δ' `mapQExp` qe))+ | (δ, qe) ← M.toAscList inv+ , qe /= minBound ]+ qSubsts "substPosInv"+ state {+ sq_αs = sq_αs state `S.union` δ's+ }+ (pos `M.union` M.fromDistinctAscList inv)+ --+ -- Find the variables to generalize+ genVars state = return state { sq_αs = αs' } where+ αs' = sq_αs state `S.intersection` kset+ kset = M.keysSet (keep (sq_τftv state))+ keep = if value then id else M.filter (`elem` [-2,-1,1,2])+ --+ -- Find the the bounds of variables to generalize+ getBounds state =+ map (id &&& getBound) (S.toList (sq_αs state)) where+ getBound α = maybe maxBound qeMeetQLit (M.lookup α (sq_vmap state))+ --+ -- The QLit lower bound of a QExp+ qeMeetQLit (QEMeet []) = maxBound+ qeMeetQLit _ = minBound++---+--- COMMON QUALIFIER CONSTRAINT HELPERS+---++-- Put a set of qualifier inequalities in decomposed form (given+-- possibly some in decomposed form already.+decomposeQuals ∷ MonadSubst tv r m ⇒+ [(Type tv, Type tv)] →+ QCState tv →+ m (QCState tv)+decomposeQuals qc0 state0 = do+ qc ← stdize qc0+ traceN 4 ("decomposeQuals", "stdize", qc)+ decompose state0 qc+ where+ --+ -- Given a list of qualifier inequalities on types, produce a list of+ -- inequalities on standard-form qualifiers, omitting trivial+ -- inequalities along the way.+ stdize qc = mapM each qc where+ each (τl, τh) = do+ qe1 ← simplifyQual τl+ qe2 ← simplifyQual τh+ return (qe1, qe2)+ --+ -- Given a list of inequalities on qualifiers, rewrite them into+ -- the two decomposed forms:+ --+ -- • γ ⊑ q βs+ --+ -- • q ⊑ βs+ --+ -- This implements DECOMPOSE, BOT-SAT, TOP-SAT, and BOT-UNSAT.+ decompose = foldM each where+ each state (_, QeA) = return state -- (TOP-SAT)+ each state (QeA, QeU γs2) = each' state (Qa, S.empty) γs2+ each state (QeU γs1, QeU γs2) = each' state (Qu, γs1) γs2+ each' state (q1, γs1) γs2 = do+ let γs' = γs1 S.\\ γs2+ βs' = S.filter flex γs2+ flex = (||) <$> qUnifiable state <*> (`S.notMember` sq_αs state)+ fβlst ← case q1 of+ -- (BOT-SAT)+ Qu → return id+ -- (BOT-UNSAT)+ _ | S.null βs' → do+ tErrExp_+ [msg| Qualifier inequality unsatisfiable. |]+ (pprMsg q1)+ (pprMsg (QeU γs2))+ return id+ | otherwise →+ return ((q1, βs') :)+ let fvmap = M.unionWith mappend (setToMapWith bound γs')+ bound γ+ | M.lookup γ (sq_τftv state) == Just Covariant+ , γ `S.member` sq_αs state+ = qemSingleton maxBound+ | qUnifiable state γ = qemSingleton (QeU γs2)+ | otherwise = qemSingleton (QeU βs')+ return state {+ sq_βlst = fβlst (sq_βlst state),+ sq_vmap = fvmap (sq_vmap state)+ }++-- | Turn the decomposed constraint back into a list of pairs of types.+recomposeQuals ∷ Ord tv ⇒ QCState tv → [(Type tv, Type tv)]+recomposeQuals state =+ [ (fvTy γ, clean βs)+ | (γ, QEMeet qem) ← M.toList (sq_vmap state)+ , γ `S.notMember` sq_αs state+ , βs ← qem ]+ +++ [ (qualToType ql, clean βs)+ | (ql, βs) ← sq_βlst state ]+ where+ clean βs = qualToType (βs S.\\ sq_αs state)++-- | Given a list of type variables and qualifiers, substitute for each,+-- updating the state as necessary.+qSubsts ∷ MonadConstraint tv r m ⇒+ String → QCState tv → M.Map tv (QExp tv) → m (QCState tv)+qSubsts who state γqes0+ | M.null γqes0 = return state+ | otherwise = do+ traceN 4 (who, γqes0, state)+ let sanitize _ [] []+ = typeBug "subst" $+ "Attempted impossible substitution: " ++ show γqes0+ sanitize _ acc []+ = unsafeSubsts state (M.fromDistinctAscList (reverse acc))+ sanitize seen acc ((γ, qe):rest)+ | S.member γ (S.union seen (ftvSet qe))+ = sanitize seen acc rest+ | otherwise+ = sanitize (seen `S.union` ftvSet qe) ((γ, qe):acc) rest+ sanitize S.empty [] (M.toAscList γqes0)+ where+ --+ -- This does the main work of substitution, and it has a funny+ -- precondition (which is enforced by 'subst', above), namely:+ -- the type variables will be substituted in increasing order, so the+ -- image of later variables must not contain earlier variables.+ --+ -- This is okay: { 1 ↦ 2 3, 2 ↦ 4 }+ -- This is not okay: { 1 ↦ 3 4, 2 ↦ 1 }+ unsafeSubsts state γqes = do+ sequence [ do+ let τ = qualToType (liftVQExp qe)+ writeTV γ τ+ updatePinnedTVs γ τ+ | (γ, qe) ← M.toList γqes ]+ let γset = M.keysSet γqes+ unchanged set = S.null (γset `S.intersection` set)+ (βlst, βlst') = List.partition (unchanged . snd) (sq_βlst state)+ (vmap, vmap') = M.partitionWithKey+ (curry (unchanged . ftvSet))+ (sq_vmap state)+ let ineqs =+ [ (qualToType ql, qualToType βs)+ | (ql, βs) ← βlst' ]+ +++ [ (fvTy γ, qualToType qe)+ | (γ, qem) ← M.toList vmap'+ , qe ← unQEMeet qem ]+ state ← decomposeQuals ineqs+ state {+ sq_αs = sq_αs state S.\\ γset,+ sq_τftv = M.foldrWithKey substQE (sq_τftv state) γqes,+ sq_βlst = βlst,+ sq_vmap = vmap+ }+ traceN 4 ("subst", γqes, state)+ return state++-- | Substitute and simplify a qualifier expression+simplifyQual ∷ (MonadSubst tv r m, Qualifier q tv) ⇒+ q → m (QExp tv)+simplifyQual q = do+ qe ← qualifier <$> subst (qualToType q)+ case qe of+ QeA → return QeA+ QeU γs → do+ (γs', qls) ← partitionJust tvQual <$> mapM fromTyVar (S.toAscList γs)+ case bigJoin qls of+ Qa → return QeA+ _ → return (QeU (S.fromDistinctAscList γs'))++---+--- SAT SOLVING FOR QUALIFIER CONSTRAINTS+---++--+-- As a last ditch effort, use a simple SAT solver to find a+-- decent literal-only substitution.+runSat ∷ MonadConstraint tv r m ⇒+ QCState tv → Bool → m (QCState tv)+runSat state doIt = do+ let sols = SAT.solve =<< SAT.assertTrue formula SAT.newSatSolver+ traceN 4 ("runSat", formula, sols)+ case sols of+ [] → do+ typeError_ [msg| Qualifier constraints unsatisfiable |]+ return state+ sat:_ | doIt+ → qSubsts "sat" state =<<+ M.fromDistinctAscList <$> sequence+ [ return (δ, qlitexp ql)+ -- warn $ "\nSAT: substituting " ++ show (QE ql slack) +++ -- " for type variable " ++ show δ+ | δ ← S.toAscList (sq_αs state)+ , qUnifiable state δ+ , let (ql, var) = decodeSatVar δ (sq_τftv state) sat+ , ql == Qa || var /= QInvariant ]+ _ → return state+ where+ formula = foldr (SAT.:&&:) SAT.Yes $+ [ (πa τftv q ==> πa τftv βs)+ | (q, βs) ← sq_βlst state ]+ +++ [ (πa τftv (Free α) ==> πa τftv αs)+ | (α, QEMeet qes) ← M.toList (sq_vmap state)+ , qUnifiable state α+ , αs ← qes ]+ p ==> q = SAT.Not p SAT.:||: q+ τftv = sq_τftv state++-- | To encode some qualifier as a SAT formula+class SATable a v where+ πa ∷ VarMap v → a → SAT.Boolean++instance SATable QLit v where+ πa _ Qa = SAT.Yes+ πa _ _ = SAT.No++instance Tv v ⇒ SATable (TyVar v) v where+ πa vm (Free β) = encodeSatVar β vm+ πa _ _ = SAT.No++instance Tv v ⇒ SATable (S.Set v) v where+ πa vm vs = S.fold ((SAT.:||:) . πa vm . Free) SAT.No vs++-- | Given a type variable and a SAT solution, return a bound+-- for that type variable as implied by the solution.+decodeSatVar ∷ Tv tv ⇒ tv → VarMap tv → SAT.SatSolver → (QLit, Variance)+decodeSatVar β vm solver = (q, var) where+ (maximize, var) = maximizeVariance β vm+ q = case (maximize, mba) of+ -- For minimizing variables, each component tells us whether that+ -- component may be omitted from the substitution, so we choose the+ -- smallest qualifier literal that includes the required components.+ (False, Just False) → Qa+ (False, _ ) → Qu+ -- For maximizing variables, each component tells us whether that+ -- component may be included in the substitution, so we choose the+ -- largest qualifier literal that omits the forbidden components.+ (True , Just False) → Qu+ (True , _ ) → Qa+ mba = SAT.lookupVar βa solver+ βa = tvUniqueID β++-- | Encode the 'q' component of type variable 'β'. We want to maximize+-- contravariant variables and minimize all the others. Since the+-- solver tries true before false, we use a positive literal to stand+-- for the 'q' component of a maximized variable and a negative+-- literal for a minimized variable.+encodeSatVar ∷ Tv tv ⇒ tv → VarMap tv → SAT.Boolean+encodeSatVar β vm+ | fst (maximizeVariance β vm) = SAT.Var z+ | otherwise = SAT.Not (SAT.Var z)+ where z = tvUniqueID β++maximizeVariance ∷ Ord tv ⇒ tv → VarMap tv → (Bool, Variance)+maximizeVariance γ vm = case M.findWithDefault 0 γ vm of+ v@QCovariant → (False, v)+ v@QInvariant → (False, v)+ v → (True, v)++instance Ppr.Ppr SAT.Boolean where pprPrec = Ppr.pprFromShow+instance Ppr.Ppr SAT.SatSolver where pprPrec = Ppr.pprFromShow++---+--- General qualifier-solving utility functions+---++-- | Is the given type variable unifiable as a qualifier variable?+-- Right now, this just means its kind is 'KdQual'.+qUnifiable ∷ Tv tv ⇒ QCState tv → tv → Bool+qUnifiable _ α = tvKindIs KdQual α++-- | Project a free type variable from a 'TyVar', or error if the+-- 'TyVar' is bounds.+fromTyVar ∷ MonadAlmsError m ⇒ TyVar tv → m tv+fromTyVar (Free α) = return α+fromTyVar _ = typeBug "solveQualifiers" "Got bound type variable"++-- | Update a type variable variance map as a result of substituting a+-- qualifier expression for a type variable.+substQE ∷ Ord tv ⇒ tv → QExp tv → VarMap tv → VarMap tv+substQE β qe vmap = case takeMap β vmap of+ (Just v, vmap') → M.unionWith (⊔) vmap' (setToMap v (ftvSet qe))+ _ → vmap++-- | Lookup a key in a map and remove the key from the map.+takeMap ∷ Ord k ⇒ k → M.Map k v → (Maybe v, M.Map k v)+takeMap = M.updateLookupWithKey (\_ _ → Nothing)++-- | Lift a 'S.Set' to a 'M.Map' with constant value+setToMap ∷ a → S.Set k → M.Map k a+setToMap = setToMapWith . const++-- | Lift a 'S.Set' to a 'M.Map' with values computed from keys.+setToMapWith ∷ (k → a) → S.Set k → M.Map k a+setToMapWith f = M.fromDistinctAscList . map (id &&& f) . S.toAscList++{-++OPTIMIZATIONS FROM SIMONET 2003++6.1 Collapsing Cycles++ This is the SCC phase++6.2 Polarities (implemented in buildGraph)++ Upper bounds on positive variables and lower bounds on negative+ variables are irrelevant, e.g.:++ f : ∀ α ≤ A. 1 → α × α+ f : ∀ α. 1 → α × α++ Or:++ let rec f = λx. f (f x) in f+ f : α → β [β ≤ α]+ f : ∀α. ∀β ≤ α. α → β+ f : ∀α. ∀β. α → β++6.3 Reducing Chains (implemented in polarizedReduce)++ A positive variable with a single predecessor can be fused with the+ predecessor; dually, a negative variable can be fused with a single+ successor.++ ∀ α ≤ A. α → 1+ A → 1++ ∀ α ≤ A. α × α → 1+ A × A → 1++ Currently this is implemented only for variables that occur only once.+ Why?++6.4 Polarized Garbage Collection++ ?++6.5 Minimization++ If two positive variables have all the same predecessors, the can be+ coalesced. Dually for negative variables with the same successors.++ ∀ α ≤ C. ∀ β ≤ C. α × β → 1+ A × B → 1++ ∀ α ≤ C. α × α → 1+ C × C → 1+ A × B → 1+-}+
+ src/Statics/Decl.hs view
@@ -0,0 +1,430 @@+-- | Type checking declarations+module Statics.Decl (+ tcProg, tcDecls, tcDecl, tcSigExp,+) where++import Util+import qualified AST+import qualified Data.Loc+import Meta.Quasi+import Type+import Statics.Constraint+import Statics.Env as Env+import Statics.Error+import Statics.Type+import Statics.Expr+import Statics.Sealing++import Prelude ()+import Data.IORef (IORef)+import qualified Data.List as L+import qualified Data.Map as M+import qualified Data.Set as S++-- | Type check a program+tcProg ∷ MonadConstraint tv r m ⇒+ Γ tv → AST.Prog R → m (AST.Prog R, Maybe (Type tv))+tcProg γ prog0 = withLocation prog0 $ case prog0 of+ [prQ| $list:ds in $opt:me |] → do+ (ds', γ', _) ← tcDecls [] γ ds+ meσ' ← mapM (tcExpr γ') me+ let me' = fst <$> meσ'+ return ([prQ| $list:ds' in $opt:me' |], snd <$> meσ')++-- | Type check a declaration.+tcDecl ∷ MonadConstraint tv r m ⇒+ [ModId] → Γ tv → AST.Decl R → m+ (AST.Decl R, Γ tv, Signature tv)+tcDecl μ γ d0 = withLocation d0 $ case d0 of+ [dc| let $π = $e |] → do+ (e', σs) ← tcExprPatt γ e π+ γ' ← γ !+! π -:*- σs+ return ([dc| let $π = $e' |], γ', zipWith SgVal (AST.dv π) σs)+ [dc| let rec $list:bns |] → do+ (bns', ns, σs) ← tcLetRecBindings γ bns+ γ' ← γ !+! ns -:*- σs+ return ([dc| let rec $list:bns' |], γ', zipWith SgVal ns σs)+ [dc| type $tid:lhs = type $qtid:rhs |] → do+ tc ← γ !.! rhs+ let sig = [SgTyp lhs tc { tcName = J (reverse μ) lhs }]+ return (d0, γ =+= sig, sig)+ [dc| abstype $list:at with $list:ds end |] → do+ (sigC, sigA) ← tcAbsTys μ γ at+ (ds', _, sig1) ← tcDecls μ (γ =+= sigC) ds+ let sig = sigA ++ replaceTyCons (getSigTyCons sigA) sig1+ γ' ← γ !+! sig+ return ([dc| abstype $list:at with $list:ds' end |], γ', sig)+ [dc| type $list:tds |] → do+ sig ← tcTyDecs μ γ tds+ return (d0, γ =+= sig, sig)+ [dc| module type $sid:n = $sigexp |] → do+ sig1 ← tcSigExp γ sigexp+ let sig = [SgSig n sig1]+ return (d0, γ =+= sig, sig)+ [dc| module $mid:n = $modexp |] → do+ (modexp', sig1) ← tcModExp (n:μ) γ modexp+ let sig = [SgMod n sig1]+ γ' ← γ !+! sig+ return ([dc| module $mid:n = $modexp' |], γ', sig)+ [dc| open $modexp |] → do+ (modexp', sig) ← tcModExp μ γ modexp+ γ' ← γ !+! sig+ return ([dc| open $modexp' |], γ', sig)+ [dc| local $list:ds0 with $list:ds1 end |] → do+ (ds0', γ', _) ← tcDecls (AST.ident "?LocalModule":μ) γ ds0+ (ds1', _, sig1) ← tcDecls μ γ' ds1+ γ'' ← γ !+! sig1+ return ([dc| local $list:ds0' with $list:ds1' end |], γ'', sig1)+ [dc| exception $cid:c of $opt:mt |] → do+ mσ ← toEmptyF <$$> mapM (tcType mempty γ) mt+ let sig = [SgExn c mσ]+ return (d0, γ =+= sig, sig)+ [dc| $anti:a |] → $(AST.antifail)++-- | Type check a sequence of declarations+tcDecls ∷ MonadConstraint tv r m ⇒+ [ModId] → Γ tv → [AST.Decl R] →+ m ([AST.Decl R], Γ tv, Signature tv)+tcDecls _ γ [] = return ([], γ, [])+tcDecls μ γ (d:ds) = do+ (d', γ', sig0) ← tcDecl μ γ d+ (ds', γ'', sig1) ← tcDecls μ γ' ds+ return (d':ds', γ'', sig0 ++ sig1)++-- | Type check a module expression+tcModExp ∷ MonadConstraint tv r m ⇒+ [ModId] → Γ tv → AST.ModExp R →+ m (AST.ModExp R, Signature tv)+tcModExp μ γ modexp0 = withLocation modexp0 $ case modexp0 of+ [meQ| struct $list:ds end |] → do+ (ds', _, sig) ← tcDecls μ γ ds+ return ([meQ| struct $list:ds' end |], sig)+ [meQ| $qmid:n $list:_ |] → do+ (sig, _) ← γ !.! n+ return (modexp0, sig)+ [meQ| $modexp : $sigexp |] → do+ (modexp', sig0) ← tcModExp μ γ modexp+ sig1 ← tcSigExp γ sigexp+ sig ← sealWith μ sig0 sig1+ return ([meQ| $modexp' : $sigexp |], sig)+ [meQ| $anti:a |] → $(AST.antifail)++-- | Type check a single signature item+tcSigItem ∷ MonadConstraint tv r m ⇒+ Γ tv → AST.SigItem R → m (Signature tv)+tcSigItem γ sigitem0 = withLocation sigitem0 $ case sigitem0 of+ [sgQ| val $vid:n : $t |] → do+ σ ← tcType mempty γ t+ return [SgVal n σ]+ [sgQ| type $list:tds |] → tcTyDecs [] γ tds+ [sgQ| type $tid:lhs = type $qtid:rhs |] → do+ tc ← γ !.! rhs+ return [SgTyp lhs tc { tcName = J [] lhs }]+ [sgQ| module $mid:n : $sigexp |] → do+ sig ← tcSigExp γ sigexp+ return [SgMod n sig]+ [sgQ| module type $sid:n = $sigexp |] → do+ sig ← tcSigExp γ sigexp+ return [SgSig n sig]+ [sgQ| include $sigexp |] → tcSigExp γ sigexp+ [sgQ| exception $cid:c of $opt:mt |] → do+ mσ ← toEmptyF <$$> mapM (tcType mempty γ) mt+ return [SgExn c mσ]+ [sgQ| $anti:a |] → $(AST.antifail)++-- | Type check a signature body+tcSigItems ∷ MonadConstraint tv r m ⇒+ Γ tv → [AST.SigItem R] → m (Signature tv)+tcSigItems _ [] = return []+tcSigItems γ (sg:sgs) = do+ sig0 ← tcSigItem γ sg+ γ' ← γ !+! sig0+ sig1 ← tcSigItems γ' sgs+ return (sig0 ++ sig1)++-- | Type check a signature expression+tcSigExp ∷ MonadConstraint tv r m ⇒+ Γ tv → AST.SigExp R → m (Signature tv)+tcSigExp γ sigexp0 = withLocation sigexp0 $ case sigexp0 of+ [seQ| sig $list:sgs end |] → tcSigItems γ sgs+ [seQ| $qsid:n $list:_ |] → fst <$> γ !.! n+ [seQ| $sigexp with type $list:αs $qtid:qc = $t |]+ → do+ sig ← tcSigExp γ sigexp+ let td = AST.tdSyn (jname qc) [(AST.tpVar <$> αs <*> pure 1, t)]+ [(_, tc)] ← tcTyDecs' [] γ [td]+ return (fibrate qc tc sig)+ [seQ| $anti:a |] → $(AST.antifail)++-- | Type check the type declarations of an abstype block+tcAbsTys ∷ MonadConstraint tv r m ⇒+ [ModId] → Γ tv → [AST.AbsTy R] →+ m (Signature tv, Signature tv)+tcAbsTys μ γ ats = do+ (arities, quals, tydecs) ← unzip3 <$> mapM unAbsTy ats+ ntcs0 ← tcTyDecs' μ γ tydecs+ ntcs1 ← sequence+ [ do+ qe ← indexQuals (AST.tdParams (view td)) qual+ let tc' = tc {+ tcArity = arity,+ tcQual = qe,+ tcCons = mempty,+ tcNext = Nothing+ }+ checkTyConMonotone (AST.tdParams (view td)) tc+ return (n, tc')+ | (n, tc) ← ntcs0+ | arity ← arities+ | qual ← quals+ | td ← tydecs ]+ return (uncurry SgTyp <$> ntcs0, uncurry SgTyp <$> ntcs1)+ where+ unAbsTy (AST.N _ (AST.AbsTy arity qual td)) = return (arity, qual, td)+ unAbsTy (AST.N _ (AST.AbsTyAnti a)) = $(AST.antifail)++-- | Type check a type declaration group+tcTyDecs ∷ MonadConstraint tv r m ⇒+ [ModId] → Γ tv → [AST.TyDec R] → m (Signature tv)+tcTyDecs = uncurry SgTyp <$$$$$> tcTyDecs'++-- | Type check a type declaration group+tcTyDecs' ∷ MonadConstraint tv r m ⇒+ [ModId] → Γ tv → [AST.TyDec R] → m [(TypId, TyCon)]+tcTyDecs' μ γ tds = do+ stub_sig ← forM tds $ \td → withLocation td $ case view td of+ AST.TdDat tid params _+ → allocStub tid (AST.tvqual <$> params)+ AST.TdSyn tid ((tps,_):_)+ → allocStub tid (Qa <$ tps)+ AST.TdAbs tid params variances guards qual+ → do+ qe ← indexQuals params qual+ ix ← tvUniqueID <$> newTV+ let tc = mkTC ix (J (reverse μ) tid)+ qe+ (zip3 variances+ (AST.tvqual <$> params)+ ((`elem` guards) <$> params))+ checkTyConMonotone params tc+ return (tid, tc)+ AST.TdSyn _ []+ → typeBug "tcTyDecs'" "Saw type synonym with 0 clauses."+ AST.TdAnti a+ → $(AST.antifail)+ real_sig ← iterChanging <-> stub_sig $ \sig →+ zipWithM (tcTyDec (γ =+= Env.fromList sig)) tds sig+ return (second (replaceTyCons (snd <$> real_sig)) <$> real_sig)+ where+ allocStub tid bounds = do+ ix ← tvUniqueID <$> newTV+ return (tid, mkTC ix (J (reverse μ) tid)+ ((Omnivariant,,False) <$> bounds) ∷ TyCon)+ --++checkTyConMonotone ∷ MonadAlmsError m ⇒ [AST.TyVar R] → TyCon → m ()+checkTyConMonotone params tc = do+ let ftv_qe = ftvSet (tcQual tc)+ bad_tvs = map ([msg| $2 (variance $1, at $3) |]+ <$> sel2 <*> sel3 <*> AST.getLoc. sel3) .+ filter (\tup → S.member (sel1 tup) ftv_qe) .+ filter (\tup → sel2 tup ⊑ Contravariant) $+ zip3 [ 0 .. ] (tcArity tc) params+ name = tcName tc+ unless (null bad_tvs) $+ typeError [msg| Type declaration for $q:name is inadmissable+ because it doesn’t satisfy the monotonicity condition for+ type constructors.+ All type variable parameters that appear in the qualifier of+ a type must be covariant or invariant, this is not satisfied+ by all parameters of $q:name:+ $ul:bad_tvs+ |]++tcTyDec ∷ MonadConstraint tv r m ⇒+ Γ tv → AST.TyDec R → (TypId, TyCon) → m (TypId, TyCon)+tcTyDec γ td (tid, tc) = withLocation td $ case view td of+ AST.TdDat _ params alts+ → do+ αs ← mapM (curry newTV' Skolem) params+ let δ = params -:*- αs+ mσs ← mapM (mapM (tcType δ γ) . snd) alts+ let mσs' = toEmptyF . closeTy 0 αs <$$> mσs+ arity = M.findWithDefault 0 <-> ftvV mσs <$> αs+ bounds = AST.tvqual <$> params+ guards = M.findWithDefault True <-> ftvG mσs <$> αs+ qual = case qualifierEnv [bounds] mσs' of+ QeA → QeA+ QeU set → QeU (S.mapMonotonic each set)+ where each (Bound _ j _) = j+ each (Free r) = elimEmpty r+ when (arity /= tcArity tc+ || bounds /= tcBounds tc+ || guards /= tcGuards tc+ || qual /= tcQual tc)+ setChanged+ return (tid, tc {+ tcArity = arity,+ tcBounds = bounds,+ tcGuards = guards,+ tcQual = qual,+ tcCons = map fst alts -:*- mσs'+ })+ AST.TdSyn _ cs@((tps0, _):_)+ → do+ let nparams = length tps0+ tassert (all ((== nparams) . length . fst) cs)+ [msg| In definition of type operator $q:tid, not all clauses+ have the same number of parameters. |]+ (cs', infos) ← unzip <$$> for cs $ \(tps, rhs) → do+ (tps', αss) ← unzip <$> mapM (tcTyPat γ) tps+ αss' ← mapM (mapM (const newTV . fst)) αss+ let (dot, nonDot)+ = L.partition (snd . fst)+ (zip (concat αss) (concat αss'))+ dot_αs = first fst <$> dot+ αs = fst . fst <$> nonDot+ αs' = snd <$> nonDot+ σ ← tcTypeRowDots (αs -:*- αs') dot_αs γ rhs+ qlss ← mapM getTVBounds αss'+ let σ' = toEmptyF (closeTy 0 (concat αss') σ)+ -- For each pattern, for each of its type variables,+ -- a triple of its variance, inclusion in the qualifer,+ -- and guardedness:+ kindses = tyPatKinds <$> tps'+ -- Bounds are computed by checking which type variables need to+ -- be bounded for the right-hand side to be well-formed, then+ -- checking which are similarly bounded on the left. For those+ -- that are not yet bounded on the left, if they are involved in+ -- the qualifier of the pattern then we can bound them by bounding+ -- the pattern, but otherwise it's an error.+ bounds ← sequence+ [ bigMeet <$> sequence+ [ if qll ⊑ qlr then return Qa+ else if inQExp then return Qu+ else do+ typeError_ $ uncurry+ [msg|+ Ill-formed type $1 declaration.+ <br>+ Type variable $α must be bounded by U (unlimited)+ for the type on the right-hand side of $2 to be+ well-formed, but it is not bounded by its appearance+ in the pattern, and because it does not contribute+ to the qualifier of the pattern, bounded the pattern+ cannot effectively bound $α.+ |] $+ if length cs == 1+ then ("synonym", "the declaration")+ else ("operator", "clause " ++ show i)+ return Qa+ | (_, inQExp, _, qll) ← kindsi+ | α ← αsi+ | qlr ← qlsi ]+ | i ← [1 ∷ Int .. ]+ | kindsi ← kindses+ | αsi ← αss+ | qlsi ← qlss ]+ -- The arity of each parameter is the join of the products+ -- of the arities of the type variables in the pattern and+ -- rhs type.+ let varmap = ftvV σ+ arity = [ bigJoin $+ zipWith (*)+ (sel1 <$> kindsi)+ (M.findWithDefault 0 <-> varmap <$> αsi')+ | kindsi ← kindses+ | αsi' ← αss' ]+ -- This is very permissive:+ guardmap = ftvG σ+ guards = [ all2 (||)+ (M.findWithDefault True <-> guardmap <$> αsi')+ (sel3 <$> kindsi)+ | kindsi ← kindses+ | αsi' ← αss' ]+ -- For each parameter, a list of which of its type+ -- variables are significant to the qualifier+ qinvolveds = [ map snd . filter fst $+ zip (sel2 <$> kindsi)+ αsi'+ | kindsi ← kindses+ | αsi' ← αss' ]+ qual = case qualifier σ of+ QeA → QeA+ QeU βs → bigJoin+ [ case L.findIndex (β `elem`) qinvolveds of+ Nothing → QeA+ Just ix+ | Qu:_ ← drop ix bounds → qlitexp Qu+ | otherwise → qvarexp ix+ | Free β ← S.toList βs ]+ return ((tps', σ'), (arity, bounds, guards, qual))+ let (arities, boundses, guardses, quals) = unzip4 infos+ arity = foldl1 (zipWith (⊔)) arities+ bounds = foldl1 (zipWith (⊓)) boundses+ guards = foldl1 (zipWith (&&)) guardses+ qual = bigJoin quals+ when (arity /= tcArity tc+ || bounds /= tcBounds tc+ || guards /= tcGuards tc+ || qual /= tcQual tc)+ setChanged+ traceN 1 ("bounds", bounds)+ return (tid, tc {+ tcArity = arity,+ tcBounds = bounds,+ tcGuards = guards,+ tcQual = qual,+ tcNext = Just cs'+ })+ AST.TdAbs _ _ _ _ _+ → return (tid, tc)+ AST.TdSyn _ []+ → typeBug "tcTyDec" "Saw type synonym with 0 clauses."+ AST.TdAnti a+ → $(AST.antifail)++-- | Convert a syntactic qualifier expression into an internal+-- qualifier expression over 'Int'.+indexQuals ∷ MonadAlmsError m ⇒+ [AST.TyVar R] → AST.QExp R → m (QExp Int)+indexQuals params = qInterpret resolver where+ resolver tv = case L.findIndex (== tv) params of+ Nothing → typeBug "indexQuals" "tv not found in type params"+ Just ix → return ix++-- | Given a functor, replace the contents with 'Empty', provided+-- there is no contents. If an 'Empty' value is actually required,+-- this is an error.+toEmptyF ∷ Functor f ⇒ f a → f Empty+toEmptyF = fmap toEmpty where+ toEmpty _ = throw (almsBug StaticsPhase "tcDecl" "saw free type variable")++---+--- MODULE SYSTEM+---++-- | Functional update on a signature+fibrate ∷ QTypId → TyCon → Signature tv → Signature tv+fibrate (J [] tid) tc sig = map eachItem sig where+ eachItem (SgTyp tid' _)+ | tid == tid' = SgTyp tid tc+ eachItem sigitem = sigitem+fibrate (J (mid:rest) tid) tc sig = map eachItem sig where+ eachItem (SgMod mid' sig')+ | mid == mid' = SgMod mid (fibrate (J rest tid) tc sig')+ eachItem sigitem = sigitem++---+--- TESTING+---++test_tcProg ∷ AST.Prog R →+ IO (Either [AlmsError]+ (Maybe (Type (TV IORef)),+ ConstraintState (TV IORef) IORef))+test_tcProg p =+ runConstraintIO+ constraintState0+ (subst =<< snd <$> tcProg test_g0 p)+
+ src/Statics/Decl.hs-boot view
@@ -0,0 +1,12 @@+{-# LANGUAGE+ UnicodeSyntax+ #-}+module Statics.Decl where++import qualified AST+import Statics.Constraint+import Statics.Env++tcDecl ∷ MonadConstraint tv r m ⇒+ [ModId] → Γ tv → AST.Decl R →+ m (AST.Decl R, Γ tv, Signature tv)
+ src/Statics/Env.hs view
@@ -0,0 +1,202 @@+{-# LANGUAGE TypeFamilies #-}+module Statics.Env (+ -- * Type variable environment+ Δ,+ -- * Main environment+ Γ(..), Γv, Γc, Γt, Γm, Γs, R,+ -- ** Operations+ bumpΓ, sigToEnv, sigItemToEnv, (!.!), (!..!), ExtendRank(..),+ -- * Testing+ test_g0,+ -- * Re-exports+ module Statics.Sig,+ module Env,+) where++import Util+import qualified AST+import Type+import Statics.Sig+import Statics.Error+import qualified Type.Rank as Rank+import qualified Syntax.Ppr as Ppr+import Env++import Prelude ()+import Data.Generics (Typeable, Data)+import qualified Data.Map as M++type R = AST.Renamed++-- | Mapping from type variable names to type variables+type Δ tv = Env (AST.TyVar R) tv++-- | Mapping variable names to type+type Γv tv = Env VarId (Type tv)+-- | Mapping data constructor names to type constructors or exception+-- parameter types+type Γc tv = Env ConId (Either TyCon (Maybe (Type Empty)))+-- | Mapping type names to type constructors+type Γt tv = Env TypId TyCon+-- | Mapping module names to their signatures and reflection as an environment+type Γm tv = Env ModId (Signature tv, Γ tv)+-- | Mapping signature names to signatures and reflection as an environment+type Γs tv = Env SigId (Signature tv, Γ tv)++-- | An environment+data Γ tv+ = Γ {+ rankΓ ∷ !Rank.Rank,+ varΓ ∷ !(Γv tv),+ conΓ ∷ !(Γc tv),+ typΓ ∷ !(Γt tv),+ modΓ ∷ !(Γm tv),+ sigΓ ∷ !(Γs tv)+ }+ deriving (Functor, Show, Typeable, Data)++instance Monoid (Γ tv) where+ mempty = Γ Rank.zero empty empty empty empty empty+ Γ rank a b c d e `mappend` Γ rank' a' b' c' d' e'+ = Γ (rank `max` rank') (a=+=a') (b=+=b') (c=+=c') (d=+=d') (e=+=e')++-- | Increment the rank of the environment+bumpΓ ∷ Γ tv → Γ tv+bumpΓ γ = γ { rankΓ = Rank.inc (rankΓ γ) }++-- | Reflect a signature as an environment+sigToEnv ∷ Signature tv → Γ tv+sigToEnv = foldMap sigItemToEnv++-- | Reflect a signature item as an environment+sigItemToEnv ∷ SigItem tv → Γ tv+sigItemToEnv (SgVal n τ) = mempty { varΓ = n =:= τ }+sigItemToEnv (SgTyp n tc) =+ mempty {+ typΓ = n =:= tc,+ conΓ = Left tc <$ tcCons tc+ }+sigItemToEnv (SgExn n mτ) = mempty { conΓ = n =:= Right mτ }+sigItemToEnv (SgMod n sig) = mempty { modΓ = n =:= (sig, sigToEnv sig) }+sigItemToEnv (SgSig n sig) = mempty { sigΓ = n =:= (sig, sigToEnv sig) }++---+--- INSTANCES+---++instance GenEmpty (Γ tv) where+ genEmpty = mempty++instance GenExtend (Γ tv) (Γ tv) where+ (=+=) = mappend+instance (v ~ VarId, tv ~ tv') ⇒+ GenExtend (Γ tv) (Env v (Type tv')) where -- Γv+ e =+= ev' = e { varΓ = varΓ e =+= ev' }+instance (c ~ ConId, tc ~ TyCon, mt ~ Maybe (Type Empty)) ⇒+ GenExtend (Γ tv) (Env c (Either tc mt)) where -- Γc+ e =+= ec' = e { conΓ = conΓ e =+= ec' }+instance t ~ TypId ⇒+ GenExtend (Γ tv) (Env t TyCon) where -- Γt+ e =+= et' = e { typΓ = typΓ e =+= et' }+instance (s ~ Signature tv, g ~ Γ tv) ⇒+ GenExtend (Γ tv) (Env ModId (s, g)) where -- Γm+ e =+= em' = e { modΓ = modΓ e =+= em' }+instance (s ~ Signature tv, g ~ Γ tv) ⇒+ GenExtend (Γ tv) (Env SigId (s, g)) where -- Γs+ e =+= es' = e { sigΓ = sigΓ e =+= es' }+instance tv ~ tv' ⇒ GenExtend (Γ tv) (Signature tv') where+ e =+= sig = e =+= sigToEnv sig++instance GenLookup (Γ tv) VarId (Type tv) where+ (=..=) = (=..=) . varΓ+instance GenLookup (Γ tv) ConId (Either TyCon (Maybe (Type Empty))) where+ (=..=) = (=..=) . conΓ+instance GenLookup (Γ tv) TypId TyCon where+ (=..=) = (=..=) . typΓ+instance GenLookup (Γ tv) ModId (Signature tv, Γ tv) where+ (=..=) = (=..=) . modΓ+instance GenLookup (Γ tv) SigId (Signature tv, Γ tv) where+ (=..=) = (=..=) . sigΓ+instance GenLookup (Γ tv) k v =>+ GenLookup (Γ tv) (Path ModId k) v where+ e =..= J [] k = e =..= k+ e =..= J (p:ps) k = do+ (_, e') <- e =..= p+ e' =..= J ps k++(!.!) ∷ (GenLookup e k v, Show k, MonadAlmsError m) ⇒ e → k → m v+e !.! k = case e =..= k of+ Just v → return v+ Nothing → typeBug "GenLookup" ("unbound identifier: " ++ show k)++(!..!) ∷ (GenLookup e k v, Show k) ⇒ e → k → v+e !..! k = case e =..= k of+ Just v → v+ Nothing → typeBugError "GenLookup" ("unbound identifier: " ++ show k)++infixl 6 !.!, !..!++-- | Extend the environment and update the ranks of the free type+-- variables of the added types.+class ExtendRank a tv | a → tv where+ (!+!) ∷ MonadSubst tv r m ⇒ Γ tv → a → m (Γ tv)++infixl 2 !+!++instance ExtendRank (Γ tv) tv where+ γ !+! γ' = do+ lowerRank (Rank.inc (rankΓ γ)) =<< subst (range (varΓ γ'))+ return (bumpΓ γ =+= γ')++instance ExtendRank (Γv tv) tv where+ γ !+! γv = γ !+! mempty { varΓ = γv }++instance ExtendRank (Signature tv) tv where+ γ !+! sig = γ !+! sigToEnv sig++instance (Ppr.Ppr k, Ppr.Ppr v) ⇒ Ppr.Ppr (Env k v) where+ ppr env = Ppr.braces . Ppr.fsep . Ppr.punctuate Ppr.comma $+ [ Ppr.ppr0 k Ppr.<> Ppr.colon Ppr.<+> Ppr.ppr0 v+ | (k, v) <- Env.toList env ]++instance Tv tv ⇒ Ppr.Ppr (Γ tv) where+ ppr γ = Ppr.char 'Γ' Ppr.<> Ppr.ppr (M.fromList+ [ ("rank", Ppr.ppr0 $ rankΓ γ)+ , ("typ", Ppr.ppr0 $ typΓ γ)+ , ("var", Ppr.ppr0 $ varΓ γ)+ , ("con", Ppr.ppr0 $ conΓ γ)+ , ("mod", Ppr.ppr0 $ snd <$> modΓ γ)+ , ("sig", Ppr.ppr0 $ snd <$> sigΓ γ)+ ])++test_g0 ∷ ∀ tv. Tv tv ⇒ Γ tv+test_g0 = mempty+ =+= AST.ident "->" =:= tcFun+ =+= AST.ident "unit" =:= tcUnit+ =+= AST.ident "()" =:= Left tcUnit+ =+= AST.ident "int" =:= tcInt+ =+= AST.ident "exn" =:= tcExn+ =+= AST.ident "Failure" =:= Right (Just tyString)+ =+= AST.ident "Match" =:= Right Nothing+ =+= AST.ident "U" =:= tcUn+ =+= AST.ident "A" =:= tcAf+ =+= AST.ident "\\/" =:= tcJoin+ =+= AST.ident "*" =:= tcTuple+ =+= AST.ident "rowend" =:= tcRowEnd+ =+= AST.ident "variant" =:= tcVariant+ =+= AST.ident "record" =:= tcRecord+ =+= AST.ident "nilRecord" =:= TyApp tcRecord [tyUn, tyRowEnd]+ =+= AST.ident "rowmap" =:= tcRowMap+ =+= AST.ident "rowhole" =:= tcRowHole+ =+= AST.ident "option" =:= tcOption+ =+= AST.ident "None" =:= Left tcOption+ =+= AST.ident "Some" =:= Left tcOption+ =+= AST.ident "idfun" =:= tcIdfun+ =+= AST.ident "Mono" =:= Left tcIdfun+ =+= AST.ident "Poly" =:= Left tcIdfun+ =+= AST.ident "ident" =:= tcIdent+ =+= AST.ident "const" =:= tcConst+ =+= AST.ident "cons" =:= tcConsTup+ =+= AST.ident "x" =:= tyInt+ =+= AST.ident "bot" =:= TyQu Forall [(Nope, Qa)] (bvTy 0 0 Nope)+ =+= AST.ident "botU" =:= TyQu Forall [(Nope, Qu)] (bvTy 0 0 Nope)
+ src/Statics/Error.hs view
@@ -0,0 +1,107 @@+-- | Type errors+module Statics.Error (+ -- * Basic error functions+ typeBug, typeBugError, typeError, typeError_, typeError', tassert,++ -- * Messages+ gotMessage, expMessage,+ -- ** Specialized message functions+ tErrGot, tErrGot_, tErrGot', tAssGot,+ tErrExp, tErrExp_, tErrExp', tAssExp,++ -- * Re-exports+ module Error,+) where++import Util+import Error+import Type++import Prelude ()++-- | Indicate a bug in the type checker.+typeBug ∷ MonadAlmsError m ⇒ String → String → m a+typeBug = throwAlms <$$> almsBug StaticsPhase++-- | Indicate a bug in the type checker, with no Alms error monad.+typeBugError ∷ String → String → a+typeBugError = throw <$$> almsBug StaticsPhase++-- | Indicate a type error.+typeError ∷ (MonadAlmsError m, Bogus a) ⇒ Message V → m a+typeError msg0 = do+ reportAlms (AlmsError StaticsPhase bogus msg0)+ return bogus++-- | Indicate a type error.+typeError_ ∷ MonadAlmsError m ⇒ Message V → m ()+typeError_ = typeError++-- | Indicate a type error from which we cannot recover.+typeError' ∷ MonadAlmsError m ⇒ Message V → m a+typeError' = throwAlms <$> AlmsError StaticsPhase bogus++-- | Assert some condition, indicating a type error if it doesn't hold.+tassert ∷ MonadAlmsError m ⇒ Bool → Message V → m ()+tassert True _ = return ()+tassert False m = typeError m++-- | Common message pattern: A got B where C expected+gotMessage ∷ Tv tv ⇒ String → Type tv → String → Message V+gotMessage who got expected =+ [msg| $words:who got $q:got where $words:expected expected. |]++-- | Error for 'gotMessage'+tErrGot ∷ (MonadAlmsError m, Bogus a, Tv tv) =>+ String -> Type tv -> String -> m a+tErrGot = typeError <$$$> gotMessage++-- | Error for 'gotMessage'+tErrGot_ ∷ (MonadAlmsError m, Tv tv) =>+ String -> Type tv -> String -> m ()+tErrGot_ = tErrGot++-- | Stopping error for 'gotMessage'+tErrGot' ∷ (MonadAlmsError m, Tv tv) =>+ String -> Type tv -> String -> m a+tErrGot' = typeError' <$$$> gotMessage+++-- | Assertion for 'gotMessage'+tAssGot ∷ (MonadAlmsError m, Tv tv) =>+ Bool -> String -> Type tv -> String -> m ()+tAssGot True = \_ _ _ → return ()+tAssGot False = tErrGot++-- | Common message pattern, actual vs. expected+expMessage ∷ Message V → Message V → Message V → Message V+expMessage =+ [msg|+ $msg:1+ <dl>+ <dt>actual: <dd>$msg:2+ <dt>expected: <dd>$msg:3+ </dl>+ |]++-- | Error for 'expMessage'+tErrExp ∷ (MonadAlmsError m, Bogus a) ⇒+ Message V → Message V → Message V → m a+tErrExp = typeError <$$$> expMessage++-- | Error for 'expMessage'+tErrExp_ ∷ MonadAlmsError m ⇒+ Message V → Message V → Message V → m ()+tErrExp_ = tErrExp++-- | Stopping error for 'expMessage'+tErrExp' ∷ (MonadAlmsError m) ⇒+ Message V → Message V → Message V → m a+tErrExp' = typeError' <$$$> expMessage++-- | Assertion for 'expMessage'+tAssExp ∷ MonadAlmsError m ⇒+ Bool → Message V → Message V → Message V → m ()+tAssExp True = \_ _ _ → return ()+tAssExp False = tErrExp+
+ src/Statics/Expr.hs view
@@ -0,0 +1,425 @@+-- | Type inference for expressions+module Statics.Expr (+ tcExpr, tcExprPatt, tcLetRecBindings,+) where++import Util+import Util.MonadRef+import qualified AST+import qualified Data.Loc+import Meta.Quasi+import Type+import Statics.Env+import Statics.Error+import Statics.Constraint+import Statics.Coercion+import Statics.InstGen+import Statics.Subsume+import Statics.Type+import Statics.Patt+import {-# SOURCE #-} Statics.Decl++import Prelude ()+import qualified Data.Map as M+import Data.IORef (IORef)++tcExpr ∷ MonadConstraint tv r m ⇒+ Γ tv → AST.Expr R → m (AST.Expr R, Type tv)+tcExpr γ e = withTVsOf mempty γ e $ \δ →+ infer (request Forall Exists) δ γ e Nothing++tcExprPatt ∷ MonadConstraint tv r m ⇒+ Γ tv → AST.Expr R → AST.Patt R →+ m (AST.Expr R, [Type tv])+tcExprPatt γ e π = withTVsOf mempty γ (e, π) $ \δ → do+ mσ1 ← extractPattAnnot δ γ π+ (e', σ1) ← infer (request Forall Exists) δ γ e mσ1+ (_, σs) ← tcPatt δ γ π (Just σ1) [ex|+! () |]+ mapM (⊏: Qu) σs+ return (e', σs)++infer ∷ MonadConstraint tv r m ⇒+ Request tv → Δ tv → Γ tv → AST.Expr R → Maybe (Type tv) →+ m (AST.Expr R, Type tv)+infer φ0 δ γ e0 mσ0 = do+ traceN 1 (TraceIn ("infer", φ0, e0, mσ0))+ mσ ← mapM subst mσ0+ let φ = maybe id prenexFlavors mσ φ0+ σ ← withLocation e0 $ case e0 of+ [ex| $qvid:n |] → do+ σ' ← maybeInstGen e0 φ γ =<< γ !.! n+ return ([ex| $qvid:n |], σ')+ --+ [ex| $int:_ |] → return (e0, tyInt)+ [ex| $char:_ |] → return (e0, tyChar)+ [ex| $flo:_ |] → return (e0, tyFloat)+ [ex| $str:_ |] → return (e0, tyString)+ --+ [ex| $qcid:c $opt:me |] → do+ -- Look up the type constructor and parameter type for the+ -- given data constructor+ tcexn ← γ !.! c+ (tc, mσ1) ← case tcexn of+ Left tc → (tc,) <$> tcCons tc !.! jname c+ Right mσ1 → return (tcExn, mσ1)+ -- Propagation: If an annotation has been passed downward, split+ -- it into type parameters for the type constructor. If splitting+ -- fails, then instantiate type variables with the right bounds+ -- and kinds.+ mσs ← splitCon mσ tc+ σs ← sequence+ [ maybe (newTVTy' (qli, variancei)) return mσi+ | mσi ← mσs+ | qli ← tcBounds tc+ | variancei ← tcArity tc ]+ -- Check whether a parameter is expected. If it isn't, then assert+ -- that none was given. If it is, then instantiate it using the+ -- propagated parameters, and propagate the instantated parameter+ -- type downward. Force the result to subsume the expected type.+ case mσ1 of+ Nothing → do+ tassert (isNothing me)+ [msg| In expression, nullary data constructor $q:c is+ applied to an argument. |]+ σ' ← maybeGen e0 φ γ (TyApp tc σs)+ return ([ex| $qcid:c |], σ')+ Just σ1E → do+ let σ1 = openTy 0 σs (elimEmptyF σ1E)+ case me of+ Just e → do+ (e', σ1') ← infer request δ γ e (Just σ1)+ σ1' ≤ σ1+ σ' ← maybeGen e0 φ γ (TyApp tc σs)+ return ([ex| $qcid:c $e' |], σ')+ Nothing → do+ σ' ← maybeGen e0 φ γ (tyArr σ1 (TyApp tc σs))+ return ([ex|+ λ x → $qcid:c x |], σ')+ --+ [ex| let $π = $e1 in $e2 |] → do+ mσ1 ← extractPattAnnot δ γ π+ ((e1', σs), αs) ← collectTVs $ do+ (e1', σ1) ← infer (request Forall Exists) δ γ e1 mσ1+ (_, σs) ← tcPatt δ γ π (Just σ1) e2+ return (e1', σs)+ γ' ← γ !+! π -:*- σs+ (e2', σ') ← infer (request φ γ αs) δ γ' e2 mσ+ return ([ex| let $π = $e1' in $e2' |], σ')+ [ex| match $e1 with $list:cas |] → do+ ((e1', σ1), αs) ← collectTVs (infer request δ γ e1 Nothing)+ (cas', σ') ← tcMatchCases (request φ γ αs) δ γ σ1 cas mσ+ return ([ex| match $e1' with $list:cas' |], σ')+ [ex| let rec $list:bs in $e2 |] → do+ (bs', ns, σs) ← tcLetRecBindingsΔ δ γ bs+ γ' ← γ !+! ns -:*- σs+ (e2', σ') ← infer φ δ γ' e2 mσ+ return ([ex| let rec $list:bs' in $e2' |], σ')+ [ex| let $decl:d in $e1 |] → do+ (d', γ', _) ← tcDecl [AST.ident "?LetModule"] γ d+ (e1', σ1) ← infer request δ γ' e1 mσ+ σ' ← maybeInstGen e0 φ γ σ1+ return ([ex| let $decl:d' in $e1' |], σ')+ --+ [ex| ($e1, $e2) |] → do+ [mσ1, mσ2] ← splitCon mσ tcTuple+ (e1', σ1) ← infer request δ γ e1 mσ1+ (e2', σ2) ← infer request δ γ e2 mσ2+ σ' ← maybeGen e0 φ γ (tyTuple σ1 σ2)+ return ([ex| ($e1', $e2') |], σ')+ --+ [ex| λ $π → $e |] → do+ [mσ1, _, mσ2] ← splitCon mσ tcFun+ ((σ1, σs), αs) ← collectTVs (tcPatt δ γ π mσ1 e)+ αs' ← filterM (isMonoType <$$> subst . fst)+ ((fvTy &&& tvDescr) <$> αs)+ γ' ← γ !+! π -:*- σs+ (e', σ2) ← infer (request Exists γ αs) δ γ' e mσ2+ for_ αs' $ \(α, descr) → do+ τ ← subst α+ tassert (isMonoType τ)+ [msg| Use $descr polymorphically |]+ let qe = arrowQualifier γ e0+ σ' ← maybeGen e0 φ γ (tyFun σ1 qe σ2)+ return ([ex| λ $π → $e' |], σ')+ --+ [ex| $_ $_ |] → do+ let (es, e1) = AST.unfoldExApp e0+ ((e0', σ), αs) ← collectTVs $ do+ (e1', σ1) ← infer request δ γ e1 Nothing+ (es', σ) ← inferApp δ γ σ1 es+ return (foldl' AST.exApp e1' es', σ)+ σ' ← maybeInstGen e0 (request φ γ αs) γ σ+ return (e0', σ')+ --+ [ex| `$uid:c $opt:me1 |] → do+ [mσRow] ← splitCon mσ tcVariant+ (mσ1, _) ← splitRow mσRow c+ σ2 ← newTVTy+ (me1', σ1) ← case me1 of+ Nothing → return (Nothing, tyUnit)+ Just e1 → first Just <$> infer request δ γ e1 mσ1+ σ' ← maybeGen e0 φ γ (TyApp tcVariant [TyRow c σ1 σ2])+ return ([ex| `$uid:c $opt:me1' |], σ')+ [ex| #$uid:c $e1 |] → do+ [mσRow] ← splitCon mσ tcVariant+ (_, mσ2) ← splitRow mσRow c+ (e1', σ2) ← infer request δ γ e1 (tyUnOp tcVariant <$> mσ2)+ σ1 ← newTVTy+ σ2' ← newTVTy+ tyUnOp tcVariant σ2' =: σ2+ σ' ← maybeGen e0 φ γ (tyUnOp tcVariant (TyRow c σ1 σ2'))+ return ([ex| #$uid:c $e1' |], σ')+ --+ [ex| { $list:flds | $e2 } |] → do+ (flds', e2', σ') ← inferRecordExp False e0 φ δ γ flds e2 mσ+ return ([ex| { $list:flds' | $e2' } |], σ')+ [ex| {+ $list:flds | $e2 +} |] → do+ (flds', e2', σ') ← inferRecordExp True e0 φ δ γ flds e2 mσ+ return ([ex| {+ $list:flds' | $e2' +} |], σ')+ --+ [ex| $e1 . $uid:u |] → do+ (([e1'], σ), αs) ← collectTVs $ do+ σField ← newTVTy+ σRow ← newTVTy+ let σSel = tyBinOp tcRecord tyAf (TyRow u σField σRow) `tyLol` σField+ inferApp δ γ σSel [e1]+ σ' ← maybeInstGen e0 (request φ γ αs) γ σ+ return ([ex| $e1' . $uid:u |], σ')+ --+ [ex| $e : $annot |] → do+ σ ← tcType δ γ annot+ (e', αs) ← collectTVs . withPinnedTVs σ $ do+ (e', σ') ← infer request δ γ e (Just σ)+ σ' ≤ σ+ return e'+ σ' ← maybeGen e0 (request φ γ αs) γ σ+ return ([ex| $e' : $annot |], σ')+ [ex| $e1 :> $annot |] → do+ σ ← tcType δ γ annot+ let φ' = prenexFlavors σ request+ (e1', σ1) ← infer (request φ') δ γ e1 Nothing+ (e', αs) ← collectTVs (coerceExpression e1' σ1 σ)+ σ' ← maybeGen e0 (request φ γ αs) γ σ+ return (e', σ')+ --+ [ex| $anti:a |] → $(AST.antifail)+ [ex| $antiL:a |] → $(AST.antifail)+ --+ traceN 1 (TraceOut ("infer", σ))+ return σ++-- | Infer the type of a record expression.+inferRecordExp ∷ MonadConstraint tv r m ⇒+ Bool → AST.Expr R →+ Request tv → Δ tv → Γ tv →+ [AST.Field R] → AST.Expr R → Maybe (Type tv) →+ m ([AST.Field R], AST.Expr R, Type tv)+inferRecordExp bqual e0 φ δ γ flds e2 mσ = do+ let qual = if bqual then tyAf else tyUn+ [_, mσRow] ← splitCon mσ tcRecord+ let eachFld mσRow' [fdQ| $uid:ui = $ei |] = do+ when bqual . tassert (AST.syntacticValue ei) $+ [msg|+ In an additive-record expression, all fields must be syntactic+ values:+ <dl>+ <dt>field: <dd>$1+ <dt>expression: <dd>$5:ei+ </dl>+ |] (AST.uidToLid ui)+ (mσi, mσRow'') ← splitRow mσRow' ui+ (ei', σi) ← infer request δ γ ei mσi+ tell ([[fdQ| $uid:ui = $ei' |]], Endo (TyRow ui σi))+ return mσRow''+ eachFld _ [fdQ| $antiF:a |] = $(AST.antifail)+ (mσ2, (flds', σs)) ← runWriterT (foldM eachFld mσRow flds)+ (e2', σ2) ← infer request δ γ e2 (tyBinOp tcRecord qual <$> mσ2)+ σRow ← newTVTy+ σ2 <: tyBinOp tcRecord qual σRow+ σ' ← maybeGen e0 φ γ+ (tyBinOp tcRecord qual (appEndo σs σRow))+ return (flds', e2', σ')++-- | Infer the type of an n-ary application expression+inferApp ∷ MonadConstraint tv r m ⇒+ Δ tv → Γ tv → Type tv → [AST.Expr R] →+ m ([AST.Expr R], Type tv)+inferApp δ γ ρ e1n = do+ traceN 2 (TraceIn ("inferApp", ρ, e1n))+ (σ1m, σ) ← funmatchN (length e1n) ρ+ refs ← replicateM (length σ1m) (newRef Nothing)+ withPinnedTVs ρ $+ subsumeN [ (σi, do+ (ei', σi') ← infer (request Exists) δ γ ei (Just σi)+ writeRef refi (Just ei')+ traceN 2 ("subsumeI", i, ei, σi', σi)+ if AST.isAnnotated ei+ then σi' <: σi+ else σi' ≤ σi)+ | i ← [ 0 ∷ Int .. ]+ | refi ← refs+ | σi ← σ1m+ | ei ← e1n ]+ e1m' ← for refs $+ readRef >=> maybe (typeBug "inferApp" "ref contained Nothing") return+ if length σ1m < length e1n+ then do+ ρ' ← instantiate σ+ first (e1m' ++) <$> inferApp δ γ ρ' (drop (length σ1m) e1n)+ else do+ traceN 2 (TraceOut ("inferApp", σ))+ return (e1m', σ)++-- | Type check a list of pattern match alternatives+tcMatchCases ∷ MonadConstraint tv r m ⇒+ Request tv → Δ tv → Γ tv →+ Type tv → [AST.CaseAlt R] → Maybe (Type tv) →+ m ([AST.CaseAlt R], Type tv)+tcMatchCases _ _ _ _ [] _ = ([],) <$> newTVTy+tcMatchCases φ δ γ σ ([caQ| #$uid:n $opt:mπi → $ei |]:cas) mσ = do+ traceN 3 ("tcMatchCases", φ, σ, "variant", n, mπi, ei)+ β ← newTVTy+ σ1 ← newTVTy+ σ2 ← newTVTy+ σ ≤≥ TyApp tcVariant [TyRow n σ1 σ2]+ (γ', αs) ← case mπi of+ Just πi → do+ ((_, σs), αs) ← collectTVs (tcPatt δ γ πi (Just σ1) ei)+ γ' ← γ !+! πi -:*- σs+ return (γ', αs)+ Nothing → do+ σ1 =: tyUnit+ return (γ, [])+ (ei', σi) ← infer (request φ γ αs) δ γ' ei mσ+ (cas', σk) ← if null cas+ then do+ σ2 ≤≥ tyNulOp tcRowEnd+ return ([], β)+ else tcMatchCases φ δ γ (TyApp tcVariant [σ2]) cas mσ+ if AST.isAnnotated ei+ then σi <: β+ else σi ≤ β+ σk <: β+ return ([caQ|+ `$uid:n $opt:mπi → $ei' |]:cas', β)+-- Should we do this case automatically like this?:+{-+tcMatchCases φ δ γ σ ([caQ| `$uid:n $opt:mπi → $ei |]:cas) mσ+ | maybe True (isPattTotal γ) mπi = do+ tcMatchCases φ δ γ σ ([caQ| #$uid:n $opt:mπi → $ei |]:cas) mσ+ -}+tcMatchCases φ δ γ σ ([caQ| $πi → $ei |]:cas) mσ = do+ traceN 3 ("tcMatchCases", φ, σ, πi, ei)+ β ← newTVTy+ ((_, σs), αs) ← collectTVs (tcPatt δ γ πi (Just σ) ei)+ γ' ← γ !+! πi -:*- σs+ (ei', σi) ← infer (request φ γ αs) δ γ' ei mσ+ (cas', σk) ← tcMatchCases φ δ γ σ cas mσ+ if AST.isAnnotated ei+ then σi <: β+ else σi ≤ β+ σk <: β+ return ([caQ|+ $πi → $ei' |]:cas', β)+tcMatchCases _ _ _ _ ([caQ| $antiC:a |]:_) _ = $(AST.antifail)++tcLetRecBindings ∷ MonadConstraint tv r m ⇒+ Γ tv → [AST.Binding R] →+ m ([AST.Binding R], [VarId], [Type tv])+tcLetRecBindings γ bs = withTVsOf mempty γ bs $ \δ → tcLetRecBindingsΔ δ γ bs++tcLetRecBindingsΔ ∷ MonadConstraint tv r m ⇒+ Δ tv → Γ tv → [AST.Binding R] →+ m ([AST.Binding R], [VarId], [Type tv])+tcLetRecBindingsΔ δ γ bs = do+ (ns, es) ← unzip <$> mapM unBinding bs+ let mannots = AST.getExprAnnot <$> es+ σs ← mapM (maybe newTVTy (tcType δ γ)) mannots+ γ' ← γ !+! ns -:*- σs+ (es', σs') ← unzip <$> sequence+ [ do+ tassert (AST.syntacticValue ei)+ [msg|+ In let rec, binding for $q:ni is not a syntactic value.+ |]+ σi ⊏: Qu+ infer request δ γ' ei (σi <$ mannoti)+ | ni ← ns+ | ei ← es+ | mannoti ← mannots+ | σi ← σs ]+ zipWithM (<:) σs' σs+ σs'' ← generalizeList True (rankΓ γ) σs'+ return (zipWith AST.bnBind ns es', ns, σs'')+ where+ unBinding [bnQ| $vid:x = $e |] = return (x, e)+ unBinding [bnQ| $antiB:a |] = $(AST.antifail)++---+--- MISCELLANEOUS HELPERS+---++-- | Determine which quantifiers may appear at the beginning of+-- a type scheme, given a list of quantifiers that may be presumed+-- to belong to an unsubstituted variable.+prenexFlavors ∷ Type tv → Request tv' → Request tv'+prenexFlavors σ φ =+ case σ of+ TyQu Exists _ (TyQu Forall _ _) → φ { rqEx = True, rqAll = True }+ TyQu Exists _ (TyVar _) → φ { rqEx = True }+ TyQu Exists _ _ → φ { rqEx = True, rqAll = False }+ TyQu Forall _ _ → φ { rqEx = False, rqAll = True }+ TyVar _ → φ+ _ → φ { rqEx = False, rqAll = False }++-- | To compute the qualifier expression for a function type.+arrowQualifier ∷ Ord tv ⇒ Γ tv → AST.Expr R → QExpV tv+arrowQualifier γ e =+ bigJoin [ qualifier (γ =..= n)+ | n ← M.keys (AST.fv e) ]++---+--- SUBSUMPTION OPERATIONS+---++-- | Given a function arity and a type, extracts a list of argument+-- types and a result type of at most the given arity.+funmatchN ∷ MonadConstraint tv r m ⇒+ Int → Type tv → m ([Type tv], Type tv)+funmatchN n0 σ0 = loop False n0 =<< subst σ0+ where+ loop _ 0 σ = return ([], σ)+ loop okay n σ = case σ of+ TyApp tc [σ1, _, σ'] | tc == tcFun+ → first (σ1:) <$> loop True (n - 1) σ'+ TyApp _ _ | Next σ' ← headReduceType σ+ → loop okay n σ'+ TyVar (Free α) | tvFlavorIs Universal α+ → do+ β1 ← newTVTy+ qe ← qvarexp . Free <$> newTV' KdQual+ β2 ← newTVTy+ σ =: tyFun β1 qe β2+ return ([β1], β2)+ TyMu _ σ1+ → loop okay n (openTy 0 [σ] σ1)+ _ | okay+ → return ([], σ)+ | otherwise+ → do+ tErrExp_+ [msg| In application expression, operator is not a function: |]+ [msg| $σ |]+ [msg| a function type |]+ βs ← replicateM n newTVTy+ β2 ← newTVTy+ return (βs, β2)++---+--- Testing++test_tcExpr ∷ AST.Expr R →+ IO (Either [AlmsError]+ (Type (TV IORef), ConstraintState (TV IORef) IORef))+test_tcExpr e =+ runConstraintIO+ constraintState0+ (subst =<< snd <$> tcExpr test_g0 e)+
+ src/Statics/InstGen.hs view
@@ -0,0 +1,277 @@+-- | Instantiation and generalization+module Statics.InstGen (+ -- * Instantiation operations+ instantiate, instantiateNeg, instAllEx, instAll, instEx,+ -- * Type-matching instantiation+ splitCon, splitRow,+ -- * Conditional generalization/instantiation+ Request(..), MkRequest(..),+ maybeGen, maybeInstGen, checkEscapingEx,+ -- * Instantiating type annotation variables+ withTVsOf,+) where++import Util+import qualified AST+import AST.TypeAnnotation+import qualified Syntax.Ppr as Ppr+import qualified Type.Rank as Rank+import Type+import Statics.Env+import Statics.Error+import Statics.Constraint++import Prelude ()+import qualified Data.Map as M++---+--- INSTANTIATION OPERATIONS+---++-- | To instantiate a prenex quantifier with fresh type variables.+instantiate ∷ MonadConstraint tv r m ⇒ Type tv → m (Type tv)+instantiate = instAllEx True True++-- | To instantiate a prenex quantifier with fresh type variables, in+-- a negative position+instantiateNeg ∷ MonadConstraint tv r m ⇒ Type tv → m (Type tv)+instantiateNeg = instAllEx False False++-- | Instantiate the outermost universal and existential quantifiers+-- at the given polarities.+instAllEx ∷ MonadConstraint tv r m ⇒ Bool → Bool → Type tv → m (Type tv)+instAllEx upos epos = subst >=> instEx epos >=> instAll upos++-- | Instantiate an outer universal quantifier.+-- PRECONDITION: σ is fully substituted.+instAll ∷ MonadConstraint tv r m ⇒ Bool → Type tv → m (Type tv)+instAll pos (TyQu Forall αqs σ) = do+ traceN 4 ("instAll/∀", pos, αqs, σ)+ instGeneric 0 (determineFlavor Forall pos) αqs σ+instAll pos (TyQu Exists αqs (TyQu Forall βqs σ)) = do+ traceN 4 ("instAll/∃∀", pos, αqs, βqs, σ)+ TyQu Exists αqs <$> instGeneric 1 (determineFlavor Forall pos) βqs σ+instAll _ σ = return σ++-- | Instantiate an outer existential quantifier.+-- PRECONDITION: σ is fully substituted.+instEx ∷ MonadConstraint tv r m ⇒ Bool → Type tv → m (Type tv)+instEx pos (TyQu Exists αqs σ) = do+ traceN 4 ("instEx", pos, αqs, σ)+ instGeneric 0 (determineFlavor Exists pos) αqs σ+instEx _ σ = return σ++-- | Instantiate type variables and use them to open a type, given+-- a flavor and list of qualifier literal bounds. Along with the+-- instantiated type, returns any new type variables.+-- PRECONDITION: σ is fully substituted.+instGeneric ∷ MonadConstraint tv r m ⇒+ Int → Flavor → [(a, QLit)] → Type tv →+ m (Type tv)+instGeneric k flav αqs σ = do+ αs ← zipWithM (newTV' <$$> (,flav,) . snd) αqs (inferKinds σ)+ return (openTy k (fvTy <$> αs) σ)++-- | What kind of type variable to create when instantiating+-- a given quantifier in a given polarity:+determineFlavor ∷ Quant → Bool → Flavor+determineFlavor Forall True = Universal+determineFlavor Forall False = Skolem+determineFlavor Exists True = Existential+determineFlavor Exists False = Universal++---+--- TYPE-MATCHING INSTANTIATION+---++-- | Given (maybe) a type, and a type constructor,+-- return a list of (maybe) parameter types and returns+-- a list of any new type variables. The output types are @Nothing@+-- iff the input type is @Nothign@. If the input type is a type+-- variable, it gets unified with the requested shape over fresh type+-- variables using the given type relation.+-- PRECONDITION: σ is fully substituted.+{-+Instantiates both ∀ and ∃ to univars:+ (λx.x) : A → A ⇒ (λ(x:A). (x:A)) : A → A+ (λx.x) : ∀α. α → α ⇒ (λ(x:β). (x:β)) : ∀α. α → α+ (λx.x) : ∀α. C α → C α ⇒ (λ(x:C β). (x:C β)) : ∀α. C α → C α+ (λx.x) : ∃α. α → α ⇒ (λ(x:β). (x:β)) : ∃α. α → α+ (λx.x) : ∃α. C α → C α ⇒ (λ(x:C β). (x:C β)) : ∃α. C α → C α+-}+splitCon ∷ MonadConstraint tv r m ⇒+ -- | Type to split+ Maybe (Type tv) →+ -- | Expected type+ TyCon →+ m ([Maybe (Type tv)])+splitCon Nothing tc = return (Nothing <$ tcArity tc)+splitCon (Just σ) tc = do+ traceN 4 ("splitCon", σ, tc)+ ρ ← instAllEx True False σ+ loop ρ+ where+ loop ρ = case ρ of+ TyApp tc' σs | tc == tc'+ → return (Just <$> σs)+ | Next ρ' ← headReduceType ρ+ → loop ρ'+ _ → return (Nothing <$ tcArity tc)++-- | Like 'splitCon', but for rows.+-- PRECONDITION: σ is fully substituted.+splitRow ∷ MonadConstraint tv r m ⇒+ -- | The type to split+ Maybe (Type tv) →+ -- | The row label that we're expecting+ RowLabel →+ m (Maybe (Type tv), Maybe (Type tv))+splitRow Nothing _ = return (Nothing, Nothing)+splitRow (Just σ) lab = do+ traceN 4 ("splitRow", σ, lab)+ ρ ← instAllEx True False σ+ loop ρ+ where+ loop ρ = case ρ of+ TyRow lab' τ1 τ2 | lab' == lab+ → return (Just τ1, Just τ2)+ | otherwise+ → do+ (mτ1, mτ2) ← loop τ2+ return (mτ1, TyRow lab' τ1 <$> mτ2)+ _ → return (Nothing, Nothing)++---+--- CONDITIONAL GENERALIZATION/INSTANTIATION+---++-- A system for specifying requested generalization/instantiation++-- | Used by 'infer' and helpers to specify a requested+-- generalization/instantiation state.+data Request tv+ = Request {+ -- | Request the type to have ∀ quantifiers generalized+ rqAll ∷ !Bool,+ -- | Request the type to have ∃ quantifiers generalized+ rqEx ∷ !Bool,+ -- | Require that the existential type variables among these+ -- be generalizable at the given ranks+ rqTVs ∷ [(tv, Rank.Rank)],+ -- | Rank to which to generalize+ rqRank ∷ !Rank.Rank+ }++instance Ppr.Ppr tv ⇒ Ppr.Ppr (Request tv) where+ ppr φ = (if rqAll φ then Ppr.char '∀' else mempty)+ Ppr.<>+ (if rqEx φ then Ppr.char '∃' else mempty)+ Ppr.<>+ (if null (rqTVs φ)+ then mempty+ else Ppr.ppr (rqTVs φ) Ppr.<>+ Ppr.char '/' Ppr.<> Ppr.ppr (rqRank φ))++-- | Defines a variadic function for building 'Request' states. Minimal+-- definition: 'addToRequest'+class MkRequest r tv | r → tv where+ -- | Variadic function that constructs a 'Request' state given some+ -- number of parameters to modify it, as shown by instances below.+ request ∷ r+ request = addToRequest Request {+ rqAll = False,+ rqEx = False,+ rqTVs = [],+ rqRank = Rank.infinity+ }+ addToRequest ∷ Request tv → r++instance MkRequest (Request tv) tv where+ addToRequest = id++instance MkRequest r tv ⇒ MkRequest (Request tv → r) tv where+ addToRequest _ r' = addToRequest r'++instance (Tv tv, MkRequest r tv) ⇒ MkRequest (Γ tv' → [tv] → r) tv where+ addToRequest r γ αs = addToRequest r {+ rqTVs = [(α, rank) | α ← αs, tvFlavorIs Existential α] ++ rqTVs r,+ rqRank = rank `min` rqRank r+ }+ where rank = rankΓ γ++instance MkRequest r tv ⇒ MkRequest (Rank.Rank → r) tv where+ addToRequest r rank = addToRequest r {+ rqRank = rank `min` rqRank r+ }++instance MkRequest r tv ⇒ MkRequest (Quant → r) tv where+ addToRequest r Forall = addToRequest r { rqAll = True }+ addToRequest r Exists = addToRequest r { rqEx = True }++-- 'maybeGen', 'maybeInst', and 'maybeInstGen' are the external+-- interface to conditional generalization.++-- | Generalize the requested flavors,·+maybeGen ∷ MonadConstraint tv r m ⇒+ AST.Expr R → Request tv → Γ tv → Type tv → m (Type tv)+maybeGen e0 φ γ σ = do+ let value = AST.syntacticValue e0+ traceN 4 ("maybeGen", value, φ, σ)+ checkEscapingEx φ+ (if rqAll φ then generalize value (Rank.inc (rankΓ γ)) else return)+ >=>+ (if rqEx φ then generalizeEx (rankΓ γ `min` rqRank φ) else return)+ >=>+ (if rqAll φ then generalize value (rankΓ γ) else return)+ $ σ++maybeInstGen ∷ MonadConstraint tv r m ⇒+ AST.Expr R → Request tv → Γ tv → Type tv → m (Type tv)+maybeInstGen e φ γ σ = do+ σ' ← case () of+ _ | AST.isAnnotated e → return σ+ | rqAll φ → return σ+ | rqEx φ → instAll True =<< subst σ+ | otherwise → instantiate σ+ maybeGen e φ γ σ'++-- | Check for escaping existential type variables+checkEscapingEx ∷ MonadConstraint tv r m ⇒ Request tv → m ()+checkEscapingEx φ = do+ αrs ← filterM escapes (rqTVs φ)+ tassert (null αrs) $+ case αrs of+ [(α,_)] → [msg| Existential type variable $α escapes its context. |]+ _ → [msg| Existential type variables escape their context: $ul:1 |]+ [ pprMsg α | (α, _) ← αrs ]+ where+ escapes (α, rank) = (rank >=) <$> getTVRank α++---+--- INSTANTIATING ANNOTATION TYPE VARIABLES+---++-- | Given the environments, a piece of syntax, and a continuation,+-- call the continuation with the type variable environment extended+-- with fresh type variables for any annotation type variables in the+-- piece of syntax.+withTVsOf ∷ (MonadConstraint tv r m, HasAnnotations a R) ⇒+ Δ tv → Γ tv → a → (Δ tv → m b) → m b+withTVsOf δ γ stx kont = do+ let (αs, κs) = unzip (tvsWithKinds γ stx)+ αs' ← zipWithM (\α κ → newTV' (AST.tvqual α, κ)) αs κs+ kont (δ =+= αs =:*= αs')++-- | Given an expression, get its type variables with their kinds+tvsWithKinds ∷ HasAnnotations a R ⇒+ Γ tv → a → [(AST.TyVar R, Kind)]+tvsWithKinds γ = M.toList . annotFtvMap var con cmb where+ var _ = KdType+ con n ix = case γ =..= n of+ Just tc+ | variance:_ ← drop ix (tcArity tc)+ , isQVariance variance+ → \_ → KdQual+ _ → id+ cmb KdQual KdQual = KdQual+ cmb _ _ = KdType
+ src/Statics/Patt.hs view
@@ -0,0 +1,209 @@+-- | Type inference for patterns+module Statics.Patt (+ tcPatt, extractPattAnnot, isPattTotal,+) where++import Util+import qualified AST+import qualified Data.Loc+import qualified Syntax.PprClass as Ppr+import Meta.Quasi+import Message.Quasi+import Type+import Statics.Constraint+import Statics.Env+import Statics.Error+import Statics.InstGen+import Statics.Subsume+import Statics.Type++import Prelude ()+import qualified Data.Map as M++-- | Type check a pattern.+tcPatt ∷ (MonadConstraint tv r m, AST.Fv stx R) ⇒+ -- | type variable environment+ Δ tv →+ -- | environment+ Γ tv →+ -- | pattern to check+ AST.Patt R →+ -- | expected type to match+ Maybe (Type tv) →+ -- | expression in scope of pattern (used to check variable+ -- occurrences)+ stx →+ m (Type tv, [Type tv])+tcPatt δ γ π0 mσ0 e0 = do+ traceN 1 (TraceIn ("inferPatt", δ, π0, mσ0))+ (σ, σs) ← evalRWST (loop π0 mσ0) 0 ()+ traceN 1 (TraceOut ("inferPatt", σ, σs))+ return (σ, σs)+ where+ -- Loop writes the types of bound parameters and reads the number+ -- of occurrences of any surrounding "as" patterns. The latter is so+ -- that if we check a pattern like “π as x”, occurrences of x count+ -- as occurrences of all the variables in π.+ loop π mσ = withLocation π $ case π of+ [pa| _ |] → do+ σ ← maybeFresh mσ [msg| unannotated wildcard pattern |]+ return σ+ [pa| $vid:n |] → do+ σ ← maybeFresh mσ [msg| unannotated parameter $q:n |]+ bind n σ+ return σ+ [pa| $qcid:c $opt:mπ |] → do+ tcexn ← γ !.! c+ (tc, mσ1) ← case tcexn of+ Left tc → (tc,) <$> tcCons tc !.! jname c+ Right mσ1 → return (tcExn, mσ1)+ mσs ← splitCon mσ tc+ σs ← mapM (flip maybeFresh [msg| |]) mσs+ case (mπ, mσ1) of+ (Just π1, Just σ1) → void $ loop π1 (Just (openTy 0 σs (elimEmptyF σ1)))+ (Nothing, Nothing) → return ()+ (Nothing, Just _ ) →+ typeError_ [msg|+ In pattern, unary data constructor $q:c is+ used with no argument.+ |]+ (Just _, Nothing) →+ typeError_ [msg|+ In pattern, nullary data constructor $q:c is+ applied to an argument.+ |]+ mσ ?≤ TyApp tc σs+ [pa| ($π1, $π2) |] → do+ [mσ1, mσ2] ← splitCon mσ tcTuple+ σ1 ← loop π1 mσ1+ σ2 ← loop π2 mσ2+ mσ ?≤ tyTuple σ1 σ2+ [pa| $str:_ |] → tcLitPatt tcString mσ+ [pa| $int:_ |] → tcLitPatt tcInt mσ+ [pa| $flo:_ |] → tcLitPatt tcFloat mσ+ [pa| $char:_ |] → tcLitPatt tcChar mσ+ [pa| $antiL:a |] → $(AST.antifail)+ [pa| $π1 as $vid:n |] → do+ σ ← local (+ occOf n) (loop π1 mσ)+ bind n σ+ return σ+ [pa| `$uid:lab $opt:mπ |] → do+ [mσRow] ← splitCon mσ tcVariant+ (mσ1, mσ2) ← splitRow mσRow lab+ let π1 = fromMaybe [pa|+ () |] mπ+ σ1 ← loop π1 mσ1+ σ2 ← maybeFresh mσ2 [msg| |]+ mσ ?≤ TyApp tcVariant [TyRow lab σ1 σ2]+ [pa| $π1 : $annot |] → do+ σ' ← tcType δ γ annot+ σ ← mσ ?≤ σ'+ loop π1 (Just σ')+ return σ+ [pa| { $uid:u = $π1 | $π2 } |] → do+ [_, mσRow] ← splitCon mσ tcRecord+ (mσ1, mσ2) ← splitRow mσRow u+ σ1 ← loop π1 mσ1+ σ2 ← loop π2 (tyRecord tyUn <$> mσ2)+ σ2' ← newTVTy+ tyRecord tyUn σ2' =: σ2+ mσ ?≤ tyRecord tyUn (TyRow u σ1 σ2')+ [pa| ! $_ |] →+ typeBug "tcPatt" "Encountered bang (!) pattern"+ [pa| $anti:a |] → $(AST.antifail)+ --+ occOf n = fromMaybe 0 (M.lookup (J [] n) (AST.fv e0))+ bind n τ = do+ as_occs ← ask+ τ ⊏: occOf n + as_occs+ tell [τ]+ --+ maybeFresh mσ message = case mσ of+ Nothing → newTVTy' (Ppr.ppr message)+ Just σ → do+ σ' ← subst σ+ case σ' of+ TyVar (Free α) → reportTVs [α]+ _ → return ()+ return σ'+ --+ Nothing ?≤ σ' = return σ'+ Just σ ?≤ σ' = do σ ≤ σ'; return σ++tcLitPatt ∷ MonadConstraint tv r m ⇒+ TyCon → Maybe (Type tv) → m (Type tv)+tcLitPatt tc mσ = do+ let σ' = tyNulOp tc+ maybe (return ()) (=: σ') mσ+ return σ'++isPattTotal ∷ Γ tv → AST.Patt R → Bool+isPattTotal γ = loop where+ loop [pa| _ |] = True+ loop [pa| $vid:_ |] = True+ loop [pa| $qcid:n $opt:mπ |] =+ maybe False oneCon (γ =..= n) && maybe True loop mπ+ where+ oneCon (Left tc) = numberOfKeys (tcCons tc) == 1+ oneCon (Right _) = False+ loop [pa| ($π1, $π2) |] = loop π1 && loop π2+ loop [pa| $lit:_ |] = False+ loop [pa| $π as $vid:_ |] = loop π+ loop [pa| `$uid:_ $opt:_ |] = False+ loop [pa| $π : $_ |] = loop π+ loop [pa| { $uid:_ = $π1 | $π2 } |]+ = loop π1 && loop π2+ loop [pa| ! $π |] = loop π+ loop [pa| $anti:a |] = $(AST.antierror)++-- | Extract and instantiate the annotations in a pattern as an annotation.+extractPattAnnot ∷ MonadConstraint tv r m ⇒+ Δ tv → Γ tv → AST.Patt R → m (Maybe (Type tv))+extractPattAnnot δ γ = loop where+ loop [pa| _ |] = return Nothing+ loop [pa| $vid:_ |] = return Nothing+ loop [pa| $qcid:_ $opt:_ |] = return Nothing+ loop [pa| ($π1, $π2) |] = do+ mσ1 ← loop π1+ mσ2 ← loop π2+ case (mσ1, mσ2) of+ (Just σ1, Just σ2) → return (Just (tyTuple σ1 σ2))+ (Nothing, Just σ2) → Just . flip tyTuple σ2 <$> newTVTy+ (Just σ1, Nothing) → Just . tyTuple σ1 <$> newTVTy+ (Nothing, Nothing) → return Nothing+ loop [pa| $lit:_ |] = return Nothing+ loop [pa| $π as $vid:_ |] = loop π+ loop [pa| `$uid:_ |] = return Nothing+ loop [pa| `$uid:uid $π |] = do+ mσ ← loop π+ case mσ of+ Just σ → Just . TyRow uid σ <$> newTVTy+ Nothing → return Nothing+ loop [pa| $_ : $annot |] = Just <$> tcType δ γ annot+ loop [pa| { $uid:uid = $π1 | $π2 } |]+ = do+ mσ1 ← loop π1+ mσ2 ← loop π2+ case (mσ1, mσ2) of+ (Just σ1, Just (TyApp _ [qual, σ2])) →+ return (Just (tyRecord qual (TyRow uid σ1 σ2)))+ (Nothing, Just (TyApp _ [qual, σ2])) → do+ σ1 ← newTVTy+ return (Just (tyRecord qual (TyRow uid σ1 σ2)))+ (Just σ1, _) → do+ qual ← newTVTy' KdQual+ σ2 ← newTVTy+ return (Just (tyRecord qual (TyRow uid σ1 σ2)))+ (Nothing, _) → return Nothing+ loop [pa| ! $π |] = loop π+ loop [pa| $anti:a |] = $(AST.antierror)++-- | Bind a pattern to a list of types.+instance GenNewEnv (AST.Patt R) [Type tv] VarId (Type tv) where+ π -:*- σs = AST.dv π -:*- σs++{-+test_tcPatt π e =+ runConstraintIO+ constraintState0+ (subst =<< tcPatt mempty test_g0 π Nothing e)+-}
+ src/Statics/Rename.hs view
@@ -0,0 +1,1072 @@+module Statics.Rename (+ -- * The renaming monad and runners+ Renaming, runRenaming, runRenamingM,+ renameMapM,+ -- * State between renaming steps+ RenameState, renameState0,+ -- ** Adding the basis+ addVal, addType, addMod,+ -- * Renamers+ renameProg, renameDecls, renameDecl, renameType, renameSigItem,+ -- * REPL query+ getRenamingInfo, RenamingInfo(..),+ renamingEnterScope,+) where++import Error++import Meta.Quasi+import AST hiding ((&))+import Data.Loc+import AST.TypeAnnotation+import qualified AST.Notable+import Util+import Syntax.Ppr (Ppr(..))++import Prelude ()+import qualified Data.Map as M+import qualified Data.Set as S++-- | The type to save the state of the renamer between calls+data RenameState = RenameState {+ savedEnv :: Env,+ savedCounter :: Renamed+} deriving Show++-- | The initial state+renameState0 :: RenameState+renameState0 = RenameState {+ savedEnv = mempty {+ datacons = M.singleton (ident "()") (ident "()", mkBogus "built-in", ())+ },+ savedCounter = renamed0+}++-- | Generate a renamer error.+renameErrorStop :: Message V -> R a+renameErrorStop msg0 = do+ throwAlms (AlmsError RenamerPhase bogus msg0)++-- | Generate a renamer error, but keep going.+renameError :: Bogus a => Message V -> R a+renameError msg0 = do+ reportAlms (AlmsError RenamerPhase bogus msg0)+ return bogus++renameBug :: String -> String -> R a+renameBug culprit msg0 = do+ throwAlms (almsBug RenamerPhase culprit msg0)++-- | The renaming monad: Reads a context, writes a module, and+-- keeps track of a renaming counter state.+newtype Renaming a = R {+ unR :: RWST Context Module RState (AlmsErrorT Identity) a+} deriving (Functor, MonadAlmsError)++-- | The threaded state of the renamer.+newtype RState = RState {+ -- | The gensym counter:+ rsCounter :: Renamed+}++instance Monad Renaming where+ return = R . return+ m >>= k = R (unR m >>= unR . k)+ fail = renameErrorStop . [msg| $words:1 |]++instance Applicative Renaming where+ pure = return+ (<*>) = ap++instance MonadWriter Module Renaming where+ listen = R . listen . unR+ tell = R . tell+ pass = R . pass . unR++instance MonadReader Env Renaming where+ ask = R (asks env)+ local f = R . local (\cxt -> cxt { env = f (env cxt) }) . unR++instance MonadError [AlmsError] Renaming where+ throwError = throwAlmsList+ catchError = catchAlms++-- | The renaming environment+data Env = Env {+ tycons :: !(EnvMap TypId [ConId Raw]),+ vars :: !(EnvMap VarId ()),+ datacons :: !(EnvMap ConId ()),+ modules :: !(EnvMap ModId (Module, Env)),+ sigs :: !(EnvMap SigId (Module, Env)),+ tyvars :: !(EnvMap Lid (QLit, Bool))+} deriving Show++type EnvMap f i = M.Map (f Raw) (f Renamed, Loc, i)++-- | A module item is one of 5 renaming entries, an empty module, r+-- a pair of modules. Note that while type variables are not actual+-- module items, they are exported from patterns, so it's useful to+-- have them here.+type Module = [ModItem]++data ModItem+ = MdTycon !Loc !(TypId Raw) !(TypId Renamed) ![ConId Raw]+ | MdVar !Loc !(VarId Raw) !(VarId Renamed)+ | MdDatacon !Loc !(ConId Raw) !(ConId Renamed)+ | MdModule !Loc !(ModId Raw) !(ModId Renamed) !Module+ | MdSig !Loc !(SigId Raw) !(SigId Renamed) !Module+ | MdTyvar !Loc !(TyVar Raw) !(TyVar Renamed)+ deriving Show++-- | The renaming context, which includes the environment (which is+-- persistant), and other information with is not+data Context = Context {+ env :: !Env,+ allocate :: !Bool,+ inExpr :: !Bool+}++-- | Run a renaming computation+runRenaming :: Bool -> Loc -> RenameState -> Renaming a ->+ Either [AlmsError] (a, RenameState)+runRenaming nonTrivial loc saved action = do+ runIdentity $+ runAlmsErrorT $ withLocation loc $ do+ (result, rstate, md) <-+ runRWST (unR action)+ Context {+ env = savedEnv saved,+ allocate = nonTrivial,+ inExpr = False+ }+ RState {+ rsCounter = savedCounter saved+ }+ let env' = savedEnv saved `mappend` envify md+ return (result, RenameState env' (rsCounter rstate))++-- | Run a renaming computation+runRenamingM :: MonadAlmsError m =>+ Bool -> Loc -> RenameState -> Renaming a ->+ m (a, RenameState)+runRenamingM = either throwAlmsList return <$$$$> runRenaming++-- | Alias+type R a = Renaming a++instance Monoid Env where+ mempty = Env M.empty M.empty M.empty M.empty M.empty M.empty+ mappend (Env a1 a2 a3 a4 a5 a6) (Env b1 b2 b3 b4 b5 b6) =+ Env (a1 & b1) (a2 & b2) (a3 & b3) (a4 & b4) (a5 & b5) (a6 & b6)+ where a & b = M.union b a++instance Bogus Env where bogus = mempty++-- | Open a module into an environment+envify :: Module -> Env+envify = foldMap envifyItem++envifyItem :: ModItem -> Env+envifyItem (MdTycon loc l l' dcs)+ = mempty { tycons = M.singleton l (l', loc, dcs) }+envifyItem (MdVar loc l l')+ = mempty { vars = M.singleton l (l', loc, ()) }+envifyItem (MdDatacon loc u u')+ = mempty { datacons = M.singleton u (u', loc, ()) }+envifyItem (MdModule loc u u' md)+ = mempty { modules = M.singleton u (u',loc,(md,envify md)) }+envifyItem (MdSig loc u u' md)+ = mempty { sigs = M.singleton u (u',loc,(md,envify md)) }+envifyItem (MdTyvar loc tv tv')+ = mempty { tyvars = M.singleton (tvname tv)+ (tvname tv',loc,(tvqual tv', True)) }++-- | Like 'asks', but in the 'R' monad+withContext :: (Context -> R a) -> R a+withContext = R . (ask >>=) . fmap unR++-- | Append a module to the current environment+inModule :: Module -> R a -> R a+inModule m = local (\e -> e `mappend` envify m)++-- | Run in the environment consisting of only the given module+onlyInModule :: Module -> R a -> R a+onlyInModule = local (const mempty) <$$> inModule++-- | Add the free annotation type variables in the given syntax+-- for the context of the action.+withAnnotationTVs :: HasAnnotations s Raw => s -> R a -> R a+withAnnotationTVs stx action = do+ skip <- R (asks inExpr)+ ((), md) <- steal $+ if skip+ then return ()+ else traverse_ bindTyvar (annotFtvSet stx)+ inModule md (R (local (\e -> e { inExpr = True }) (unR action)))++-- | Hide any annotation type variables that were in scope.+hideAnnotationTVs :: R a -> R a+hideAnnotationTVs = + R . local (\e -> e { inExpr = False }) . unR .+ local (\e -> e { tyvars = each <$> tyvars e })+ where each (a, b, (c, _)) = (a, b, (c, False))++-- | Temporarily stop allocating unique ids+don'tAllocate :: R a -> R a+don'tAllocate = R . local (\cxt -> cxt { allocate = False }) . unR++-- | Generate an unbound name error+unbound :: (Ppr a, Bogus b) => String -> a -> R b+unbound ns a =+ renameError [msg| $words:ns not in scope: $q:a |]++-- | Generate an error about a name declared twice+repeatedMsg :: Ppr a => String -> a -> String -> [Loc] -> Message V+repeatedMsg what a inwhat locs =+ [msg|+ $words:what $a+ repeated $words:times in $words:inwhat $words:at+ $ul:slocs+ |]+ where+ times = case length locs of+ 0 -> ""+ 1 -> ""+ 2 -> "twice"+ 3 -> "thrice"+ _ -> show (length locs) ++ " times"+ at = if length locs > 1 then "at:" else ""+ slocs = map [msg| $show:1 |] locs++-- | Generate an error about a name declared twice+repeated :: (Ppr a, Bogus b) => String -> a -> String -> [Loc] -> R b+repeated what a inwhat locs =+ renameError $ repeatedMsg what [msg| $q:a |] inwhat locs++-- | Generate an error about a name declared twice+repeatedTVs :: Bogus b => [TyVar i] -> String -> R b+repeatedTVs [] _ = renameBug "repatedTVs" "got empty list"+repeatedTVs tvs@(tv:_) inwhat =+ let quals = ordNub (tvqual <$> tvs)+ name = tvname tv+ bothQs = length quals > 1+ callIt = if bothQs then [msg| `$name / '$name |] else [msg| $tv |]+ msg0 = repeatedMsg "Type variable" callIt inwhat (getLoc <$> tvs)+ in renameError $+ if bothQs+ then [msg|+ $msg0+ <indent>+ (Type variables with the same name but different+ qualifiers may not appear in the same scope.)+ </indent>+ |]+ else msg0++-- | Are all keys of the list unique? If not, return the key and+-- list of two or more values with the same keys+unique :: Ord a => (b -> a) -> [b] -> Maybe (a, [b])+unique getKey = loop M.empty where+ loop _ [] = Nothing+ loop seen (x:xs) =+ let k = getKey x+ in case M.lookup k seen of+ Nothing -> loop (M.insert k x seen) xs+ Just x' -> Just (k, x' : x : filter ((== k) . getKey) xs)++-- | Grab the module produced by a computation, and+-- produce no module+steal :: R a -> R (a, Module)+steal = R . censor (const mempty) . listen . unR++-- | Get all the variable names, included qualified, bound in a module+getAllVariables :: Module -> [QVarId Renamed]+getAllVariables = S.toList . foldMap loop where+ loop (MdVar _ _ l') = S.singleton (J [] l')+ loop (MdModule _ _ u' md) = S.mapMonotonic (\(J us l) -> J (u':us) l)+ (foldMap loop md)+ loop _ = S.empty++-- | Look up something in an environment+envLookup :: (Ord k, Show k) =>+ (Env -> M.Map k k') ->+ Path (ModId Raw) k ->+ Env ->+ Either (Maybe (Path (ModId Renamed) (ModId Raw)))+ (Path (ModId Renamed) k')+envLookup prj = loop [] where+ loop ms' (J [] x) e = case M.lookup x (prj e) of+ Just x' -> Right (J (reverse ms') x')+ Nothing -> Left Nothing+ loop ms' (J (m:ms) x) e = case M.lookup m (modules e) of+ Just (m', _, (_, e')) -> loop (m':ms') (J ms x) e'+ Nothing -> Left (Just (J (reverse ms') m))++-- | Look up something in the environment+getGenericFull :: (Ord k, Show k, Bogus k') =>+ String -> (Env -> M.Map k k') ->+ Path (ModId Raw) k -> R (Path (ModId Renamed) k')+getGenericFull what prj qx = do+ e <- ask+ case envLookup prj qx e of+ Right qx' -> return qx'+ Left Nothing -> unbound what qx+ Left (Just m) -> unbound "Module" m++-- | Look up something in the environment+getGeneric :: (Ord (f Raw), Show (f Raw), Bogus i, Bogus (f Renamed)) =>+ String -> (Env -> EnvMap f i) ->+ Path (ModId Raw) (f Raw) -> R (Path (ModId Renamed) (f Renamed))+getGeneric = liftM (fmap (\(qx', _, _) -> qx')) <$$$> getGenericFull++-- | Look up a variable in the environment+getVar :: QVarId Raw -> R (QVarId Renamed)+getVar = getGeneric "Variable" vars++-- | Look up a data constructor in the environment+getDatacon :: QConId Raw -> R (QConId Renamed)+getDatacon = getGeneric "Data constructor" datacons++-- | Look up a type in the environment+getTycon :: QTypId Raw -> R (QTypId Renamed)+getTycon = getGeneric "Type constructor" tycons++-- | Look up a type with constructors in the environment+getTyconFull :: QTypId Raw -> R (QTypId Renamed, [ConId Raw])+getTyconFull qtid = do+ J ps (tid, _, cids) <- getGenericFull "Type name" tycons qtid+ return (J ps tid, cids)++-- | Look up a module in the environment+getModule :: QModId Raw -> R (QModId Renamed, Module, Env)+getModule = liftM pull . getGenericFull "Structure" modules+ where+ pull (J ps (qu, _, (m, e))) = (J ps qu, m, e)++-- | Look up a module in the environment+getSig :: QSigId Raw -> R (QSigId Renamed, Module, Env)+getSig = liftM pull . getGenericFull "Signature" sigs+ where+ pull (J ps (qu, _, (m, e))) = (J ps qu, m, e)++-- | Look up a type variable in the environment. This is complicated,+-- because there are several possibilities.+getTyvar :: TyVar Raw -> R (TyVar Renamed)+getTyvar tv@(TV name ql _) = do+ e <- asks tyvars+ case M.lookup name e of+ -- If the type variable isn't found in the block-structured type+ -- variable environment, that is an error.+ Nothing -> do+ renameError [msg| Type variable $tv is not in scope. |]+ --+ -- If the type variable *is* found in the bound type variable+ -- environment, we need to check if it's in the current scope or+ -- hidden, and if it's in the current scope, whether the qualifier+ -- matches. If the qualifier doesn't match or if it's hidden, that+ -- is an error.+ Just (name', loc', (ql', True))+ | ql == ql' -> return (TV name' ql' loc')+ | otherwise ->+ renameError $+ [msg|+ Type variable $tv is not in scope.+ <indent>+ (Type variable $1 was bound at $loc', but the same+ type variable name may not occur with different qualifiers+ in the same scope.)+ </indent>+ |] (TV name' ql' loc')+ --+ Just (_, loc', (_, False)) -> do+ renameError+ [msg|+ Type variable $tv is not in scope.+ <indent>+ (It was bound at $loc', but a nested declaration+ can neither see nor shadow type variables from its+ parent expression.)+ </indent>+ |]+getTyvar (TVAnti a) = $antifail++-- | Get a new name for a variable binding+bindGeneric :: (Ord ident, Show ident, Antible ident) =>+ (Renamed -> ident -> ident') ->+ (Loc -> ident -> ident' -> ModItem) ->+ ident -> R ident'+bindGeneric ren build x = do+ case prjAnti x of+ Just a -> $antifail+ Nothing -> return ()+ new <- newRenamed+ loc <- getLocation+ let x' = ren new x+ tell [build loc x x']+ return x'++-- | Allocate a new 'Renamed' token if we're in the right mode.+newRenamed :: R Renamed+newRenamed = R $ do+ doAlloc <- asks allocate+ if doAlloc+ then do+ rstate <- get+ put rstate { rsCounter = succ (rsCounter rstate) }+ return (rsCounter rstate)+ else do+ return trivialId++-- | Get a new name for a variable binding+bindVar :: VarId Raw -> R (VarId Renamed)+bindVar = bindGeneric renId MdVar++-- | Get a new name for a variable binding+bindTycon :: TypId Raw -> [ConId Raw] -> R (TypId Renamed)+bindTycon l0 dcs = bindGeneric renId build l0+ where build loc old new = MdTycon loc old new dcs++-- | Get a new name for a data constructor binding+bindDatacon :: ConId Raw -> R (ConId Renamed)+bindDatacon = bindGeneric renId MdDatacon++-- | Get a new name for a module, and bind it in the environment+bindModule :: ModId Raw -> Module -> R (ModId Renamed)+bindModule u0 md = bindGeneric renId build u0+ where build loc old new = MdModule loc old new md++-- | Get a new name for a signature, and bind it in the environment+bindSig :: SigId Raw -> Module -> R (SigId Renamed)+bindSig u0 md = bindGeneric renId build u0+ where build loc old new = MdSig loc old new md++-- | Add a type variable to the scope+bindTyvar :: TyVar Raw -> R (TyVar Renamed)+bindTyvar tv = do+ e <- asks tyvars+ case M.lookup (tvname tv) e of+ Nothing -> bindGeneric renId MdTyvar tv+ Just (name', loc', (ql', _)) ->+ if tvqual tv == ql'+ then+ renameError $+ [msg|+ Cannot shadow type variable $tv; it is already+ bound at $loc'.+ |]+ else+ renameError $+ [msg|+ Cannot introduce type variable $tv, because $1 is+ already bound at $loc'. The same type variable name cannot+ appear in the same scope with different qualifiers.+ |] (TV name' ql' loc')++-- | Map a function over a list, allowing the exports of each item+-- to be in scope for the rest+renameMapM :: (a -> R b) -> [a] -> R [b]+renameMapM _ [] = return []+renameMapM f (x:xs) = do+ (x', md) <- listen (f x)+ xs' <- inModule md $ renameMapM f xs+ return (x':xs')++-- | Rename a program+renameProg :: Prog Raw -> R (Prog Renamed)+renameProg [prQ| $list:ds in $opt:me1 |] = do+ (ds', md) <- listen $ renameDecls ds+ me1' <- inModule md $ traverse renameExpr me1+ return [prQ|+ $list:ds' in $opt:me1' |]++-- | Rename a list of declarations and return the environment+-- that they bind+renameDecls :: [Decl Raw] -> R [Decl Renamed]+renameDecls = renameMapM renameDecl++-- | Rename a declaration and return the environment that it binds+renameDecl :: Decl Raw -> R (Decl Renamed)+renameDecl d0 = withLocation d0 $ case d0 of+ [dc| let $x = $e |] -> do+ x' <- renamePatt x+ e' <- renameExpr e+ return [dc|+ let $x' = $e' |]+ [dc| let rec $list:bns |] -> do+ (bns', md) <- renameBindings bns+ tell md+ return [dc|+ let rec $list:bns' |]+ [dc| type $tid:lhs = type $qtid:rhs |] -> do+ (rhs', dcs) <- getTyconFull rhs+ lhs' <- bindTycon lhs dcs+ mapM_ bindDatacon dcs+ return [dc|+ type $tid:lhs' = type $qtid:rhs' |]+ [dc| type $list:tds |] -> do+ tds' <- renameTyDecs tds+ return [dc|+ type $list:tds' |]+ [dc| abstype $list:ats with $list:ds end |] -> do+ let bindEach [atQ| $anti:a |] = $antifail+ bindEach (N _ (AbsTy _ _ [tdQ| $anti:a |])) = $antifail+ bindEach (N note at) = withLocation note $ do+ let l = tdName (dataOf (atdecl at))+ bindTycon l []+ return (l, getLoc note)+ (llocs, mdT) <- listen $ mapM bindEach ats+ case unique fst llocs of+ Nothing -> return ()+ Just (l, locs) ->+ repeated "Type declaration for" l "abstype group" (snd <$> locs)+ (ats', mdD) <-+ steal $+ inModule mdT $+ forM ats $ \at -> withLocation at $ case dataOf at of+ AbsTy variances qe td -> do+ (Just qe', td') <- renameTyDec (Just qe) td+ return (absTy variances qe' td' <<@ at)+ AbsTyAnti a -> $antifail+ -- Don't tell mdD upward, since we're censoring the datacons+ ds' <- inModule (mdT `mappend` mdD) $ renameDecls ds+ return [dc|+ abstype $list:ats' with $list:ds' end |]+ [dc| module INTERNALS = $me1 |] ->+ R $ local (\context -> context { allocate = False }) $ unR $ do+ let u = ident "INTERNALS"+ (me1', md) <- steal $ renameModExp me1+ u' <- bindModule u md+ return [dc|+ module $mid:u' = $me1' |]+ [dc| module $mid:u = $me1 |] -> do+ (me1', md) <- steal $ renameModExp me1+ u' <- bindModule u md+ return [dc|+ module $mid:u' = $me1' |]+ [dc| module type $sid:u = $se1 |] -> do+ (se1', md) <- steal $ renameSigExp se1+ u' <- bindSig u md+ return [dc|+ module type $sid:u' = $se1' |]+ [dc| open $me1 |] -> do+ me1' <- renameModExp me1+ return [dc|+ open $me1' |]+ [dc| local $list:ds1 with $list:ds2 end |] -> do+ (ds1', md) <- steal $ renameDecls ds1+ ds2' <- inModule md $ renameDecls ds2+ return [dc| local $list:ds1' with $list:ds2' end |]+ [dc| exception $cid:u of $opt:mt |] -> do+ u' <- bindDatacon u+ mt' <- traverse renameType mt+ return [dc|+ exception $cid:u' of $opt:mt' |]+ [dc| $anti:a |] -> $antifail++renameTyDecs :: [TyDec Raw] -> R [TyDec Renamed]+renameTyDecs tds = withLocation tds $ do+ let bindEach [tdQ| $anti:a |] = $antifail+ bindEach (N note td) = withLocation note $ do+ bindTycon (tdName td) (tdMaybeCons td)+ return (tdName td, getLoc note)+ (llocs, md) <- listen $ mapM bindEach tds+ case unique fst llocs of+ Nothing -> return ()+ Just (l, locs) ->+ repeated "Type declaration for" l "type group" (snd <$> locs)+ inModule md $ mapM (liftM snd . renameTyDec Nothing) tds++tdMaybeCons :: TyDec' Raw -> [ConId Raw]+tdMaybeCons TdDat { tdAlts = alts } = fst <$> alts+tdMaybeCons _ = []++renameTyDec :: Maybe (QExp Raw) -> TyDec Raw ->+ R (Maybe (QExp Renamed), TyDec Renamed)+renameTyDec _ (N _ (TdAnti a)) = $antierror+renameTyDec mqe (N note (TdSyn l clauses)) = withLocation note $ do+ case mqe of+ Nothing -> return ()+ Just _ ->+ renameBug "renameTyDec" "can’t rename QExp in context of type synonym"+ J [] l' <- getTycon (J [] l)+ clauses' <- forM clauses $ \(ps, rhs) -> withLocation ps $ do+ (ps', md) <- steal $ renameTyPats ps+ rhs' <- inModule md $ renameType rhs+ return (ps', rhs')+ return (Nothing, tdSyn l' clauses' <<@ note)+renameTyDec mqe (N note td) = withLocation note $ do+ J [] l' <- getTycon (J [] (tdName td))+ let tvs = tdParams td+ case unique tvname tvs of+ Nothing -> return ()+ Just (_, tvs') -> repeatedTVs tvs' "type parameters"+ (tvs', mdTvs) <- steal $ mapM bindTyvar tvs+ inModule mdTvs $ do+ mqe' <- traverse renameQExp mqe+ td' <- case td of+ TdAbs _ _ variances gs qe -> do+ qe' <- renameQExp qe+ gs' <- ordNub <$> mapM getTyvar gs+ return (tdAbs l' tvs' variances gs' qe')+ TdSyn _ _ -> renameBug "renameTyDec" "unexpected TdSyn"+ TdDat _ _ cons -> do+ case unique fst cons of+ Nothing -> return ()+ Just (u, _) ->+ repeated "Data constructor" u "type declaration" []+ cons' <- forM cons $ \(u, mt) -> withLocation mt $ do+ -- XXX Why trivial?+ let u' = renTrivial u+ tell [MdDatacon (getLoc mt) u u']+ mt' <- traverse renameType mt+ return (u', mt')+ return (tdDat l' tvs' cons')+ TdAnti a -> $antifail+ return (mqe', td' <<@ note)++renameModExp :: ModExp Raw -> R (ModExp Renamed)+renameModExp me0 = withLocation me0 $ case me0 of+ [meQ| struct $list:ds end |] -> do+ ds' <- renameDecls ds+ return [meQ|+ struct $list:ds' end |]+ [meQ| $qmid:qu $list:_ |] -> do+ (qu', md, _) <- getModule qu+ let qls = getAllVariables md+ tell md+ return [meQ|+ $qmid:qu' $list:qls |]+ [meQ| $me1 : $se2 |] -> do+ (me1', md1) <- steal $ renameModExp me1+ (se2', md2) <- steal $ renameSigExp se2+ onlyInModule md1 $ sealWith md2+ return [meQ| $me1' : $se2' |]+ [meQ| $anti:a |] -> $antifail++renameSigExp :: SigExp Raw -> R (SigExp Renamed)+renameSigExp se0 = withLocation se0 $ case se0 of+ [seQ| sig $list:sgs end |] -> do+ (sgs', md) <- listen $ don'tAllocate $ renameMapM renameSigItem sgs+ onlyInModule mempty $ checkSigDuplicates md+ return [seQ|+ sig $list:sgs' end |]+ [seQ| $qsid:qu $list:_ |] -> do+ (qu', md, _) <- getSig qu+ let qls = getAllVariables md+ tell md+ return [seQ|+ $qsid:qu' $list:qls |]+ [seQ| $se1 with type $list:tvs $qtid:ql = $t |] -> do+ (se1', md) <- listen $ renameSigExp se1+ ql' <- onlyInModule md $ getTycon ql+ case unique id tvs of+ Nothing -> return ()+ Just (_, tvs') -> repeatedTVs tvs' "with-type"+ (tvs', mdtvs) <- steal $ mapM bindTyvar tvs+ t' <- inModule mdtvs $ renameType t+ return [seQ|+ $se1' with type $list:tvs' $qtid:ql' = $t' |]+ [seQ| $anti:a |] -> $antifail++checkSigDuplicates :: Module -> R ()+checkSigDuplicates md = case md of+ [] -> return ()+ md1:md2 -> do+ checkItem md1+ inModule [md1] $ checkSigDuplicates md2++ where+ checkItem item = case item of+ MdTycon loc l _ _ -> mustFail loc "Type" l $ getTycon (J [] l)+ MdVar loc l _ -> mustFail loc "Variable" l $ getVar (J [] l)+ MdDatacon loc u _ -> mustFail loc "Constructor" u $ getDatacon (J [] u)+ MdModule loc u _ _ -> mustFail loc "Structure" u $ getModule (J [] u)+ MdSig loc u _ _ -> mustFail loc "Signature" u $ getSig (J [] u)+ MdTyvar loc tv _ -> mustFail loc "Tyvar" tv $ getTyvar tv+ mustFail loc kind which check = do+ failed <- (False <$ check) `catchError` \_ -> return True+ unless failed $ do+ withLocation loc $+ repeated kind which "signature" []++sealWith :: Module -> R ()+sealWith = mapM_ (each Nothing) where+ each b moditem = case moditem of+ MdTycon _ l _ _ -> do+ (l', loc, cs') <- locate b "type constructor" tycons l+ tell [MdTycon loc l l' cs']+ MdVar _ l _ -> do+ (l', loc, _) <- locate b "variable" vars l+ tell [MdVar loc l l']+ MdDatacon _ u _ -> do+ (u', loc, _) <- locate b "data constructor" datacons u+ tell [MdDatacon loc u u']+ MdModule _ u _ md2 -> do+ (u', loc, (md1, _)) <- locate b "module" modules u+ ((), md1') <- steal $ onlyInModule md1 $ mapM_ (each b) md2+ tell [MdModule loc u u' md1']+ MdSig _ u _ md2 -> do+ (u', loc, (md1, _)) <- locate b "module type" sigs u+ ((), _ ) <- steal $ onlyInModule md2 $ mapM_ (each (Just (Left u))) md1+ ((), md1') <- steal $ onlyInModule md1 $ mapM_ (each (Just (Right u))) md2+ tell [MdSig loc u u' md1']+ MdTyvar _ _ _ ->+ renameBug "sealWith" "signature can’t declare type variable"+ locate b what prj name = do+ m <- asks prj+ case M.lookup name m of+ Just name' -> return name'+ Nothing -> renameError $+ case b of+ Nothing -> [msg|+ In signature matching, structure is missing+ $words:what $q:name,+ which is present in ascribed signature.+ |]+ Just (Left u) -> [msg|+ In exact signature matching (for nested signature $u)+ found unexpected $words:what $q:name.+ |]+ Just (Right u) -> [msg|+ In exact signature matching (for nested signature $u)+ missing expected $words:what $q:name.+ |]++-- | Rename a signature item and return the environment+-- that they bind+renameSigItem :: SigItem Raw -> R (SigItem Renamed)+renameSigItem sg0 = withLocation sg0 $ case sg0 of+ [sgQ| val $vid:l : $t |] -> do+ l' <- bindVar l+ t' <- renameType (closeType t)+ return [sgQ|+ val $vid:l' : $t' |]+ [sgQ| type $list:tds |] -> do+ tds' <- renameTyDecs tds+ return [sgQ|+ type $list:tds' |]+ [sgQ| type $tid:lhs = type $qtid:rhs |] -> do+ (rhs', dcs) <- getTyconFull rhs+ lhs' <- bindTycon lhs dcs+ mapM_ bindDatacon dcs+ return [sgQ|+ type $tid:lhs' = type $qtid:rhs' |]+ [sgQ| module $mid:u : $se1 |] -> do+ (se1', md) <- steal $ renameSigExp se1+ u' <- bindModule u md+ return [sgQ|+ module $mid:u' : $se1' |]+ [sgQ| module type $sid:u = $se1 |] -> do+ (se1', md) <- steal $ renameSigExp se1+ u' <- bindSig u md+ return [sgQ|+ module type $sid:u' = $se1' |]+ [sgQ| include $se1 |] -> do+ se1' <- renameSigExp se1+ return [sgQ|+ include $se1' |]+ [sgQ| exception $cid:u of $opt:mt |] -> do+ u' <- bindDatacon u+ mt' <- traverse renameType mt+ return [sgQ|+ exception $cid:u' of $opt:mt' |]+ [sgQ| $anti:a |] -> $antifail++-- | Rename an expression+renameExpr :: Expr Raw -> R (Expr Renamed)+renameExpr e00 = withAnnotationTVs e00 $ loop e00 where+ loop e0 = withLocation e0 $ case e0 of+ [ex| $qvid:ql |] -> do+ ql' <- getVar ql+ return [ex|+ $qvid:ql' |]+ [ex| $lit:lit |] -> do+ lit' <- renameLit lit+ return [ex|+ $lit:lit' |]+ [ex| $qcid:qu $opt:me |] -> do+ qu' <- getDatacon qu+ me' <- traverse loop me+ return [ex|+ $qcid:qu' $opt:me' |]+ [ex| `$uid:u $opt:me |] -> do+ let u' = renTrivial u+ me' <- traverse loop me+ return [ex|+ `$uid:u' $opt:me' |]+ [ex| #$uid:u $e |] -> do+ let u' = renTrivial u+ e' <- loop e+ return [ex|+ #$uid:u' $e' |]+ [ex| let $x = $e1 in $e2 |] -> do+ (x', md) <- steal $ renamePatt x+ e1' <- loop e1+ e2' <- inModule md $ loop e2+ return [ex| let $x' = $e1' in $e2' |]+ [ex| match $e1 with $list:cas |] -> do+ e1' <- loop e1+ cas' <- mapM renameCaseAlt cas+ return [ex|+ match $e1' with $list:cas' |]+ [ex| let rec $list:bns in $e |] -> do+ (bns', md) <- renameBindings bns+ e' <- inModule md $ loop e+ return [ex|+ let rec $list:bns' in $e' |]+ [ex| let $decl:d in $e |] -> do+ (d', md) <- steal . hideAnnotationTVs $ renameDecl d+ e' <- inModule md (loop e)+ return [ex|+ let $decl:d' in $e' |]+ [ex| ($e1, $e2) |] -> do+ e1' <- loop e1+ e2' <- loop e2+ return [ex|+ ($e1', $e2') |]+ [ex| fun $x -> $e |] -> do+ (x', md) <- steal $ renamePatt x+ e' <- inModule md $ loop e+ return [ex|+ fun $x' -> $e' |]+ [ex| $e1 $e2 |] -> do+ e1' <- loop e1+ e2' <- loop e2+ return [ex|+ $e1' $e2' |]+ [ex| { $list:flds | $e2 } |] -> do+ flds' <- mapM renameField flds+ e2' <- loop e2+ return [ex|+ { $list:flds' | $e2' } |]+ [ex| {+ $list:flds | $e2 +} |] -> do+ flds' <- mapM renameField flds+ e2' <- loop e2+ return [ex|+ {+ $list:flds' | $e2' +} |]+ [ex| $e1.$uid:u |] -> do+ let u' = renTrivial u+ e1' <- loop e1+ return [ex|+ $e1'.$uid:u' |]+ [ex| ( $e : $t) |] -> do+ e' <- loop e+ t' <- renameType t+ return [ex| ( $e' : $t' ) |]+ [ex| ( $e :> $t) |] -> do+ e' <- loop e+ t' <- renameType t+ return [ex| ( $e' :> $t' ) |]+ [ex| $anti:a |] -> $antifail++-- | Rename a literal (no-op, except fails on antiquotes)+renameLit :: Lit -> R Lit+renameLit lit0 = case lit0 of+ LtAnti a -> $antifail+ _ -> return lit0++-- | Rename a case alternative+renameCaseAlt :: CaseAlt Raw -> R (CaseAlt Renamed)+renameCaseAlt ca0 = withLocation ca0 $ case ca0 of+ [caQ| $x -> $e |] -> do+ (x', md) <- steal $ renamePatt x+ e' <- inModule md $ renameExpr e+ return [caQ|+ $x' -> $e' |]+ [caQ| #$uid:lab -> $e |] -> do+ let lab' = renTrivial lab+ e' <- renameExpr e+ return [caQ|+ #$uid:lab' -> $e' |]+ [caQ| #$uid:lab $x -> $e |] -> do+ let lab' = renTrivial lab+ (x', md) <- steal $ renamePatt x+ e' <- inModule md $ renameExpr e+ return [caQ|+ #$uid:lab' $x' -> $e' |]+ [caQ| $antiC:a |] -> $antifail++-- | Rename a set of let rec bindings+renameBindings :: [Binding Raw] -> R ([Binding Renamed], Module)+renameBindings bns = withAnnotationTVs bns $ withLocation bns $ do+ lxes <- forM bns $ \bn ->+ case bn of+ [bnQ| $vid:x = $e |] -> return (_loc, x, e)+ [bnQ| $antiB:a |] -> $antifail+ case unique (\(_,x,_) -> x) lxes of+ Nothing -> return ()+ Just (x, locs) ->+ repeated "Variable binding for" x "let-rec" (sel1 <$> locs)+ let bindEach rest (l,x,e) = withLocation l $ do+ x' <- bindVar x+ return ((l,x',e):rest)+ (lxes', md) <- steal $ foldM bindEach [] lxes+ bns' <- inModule md $+ forM (reverse lxes') $ \(l,x',e) -> withLocation l $ do+ let _loc = l+ e' <- renameExpr e+ return [bnQ|+ $vid:x' = $e' |]+ return (bns', md)++-- | Rename a record field+renameField :: Field Raw → R (Field Renamed)+renameField [fdQ| $uid:u = $e |] = do+ let u' = renTrivial u+ e' ← renameExpr e+ return [fdQ|+ $uid:u' = $e' |]+renameField [fdQ| $antiF:a |] = $antifail++-- | Rename a type+renameType :: Type Raw -> R (Type Renamed)+renameType t0 = withLocation t0 $ case t0 of+ [ty| ($list:ts) $qtid:ql |] -> do+ ql' <- getTycon ql+ ts' <- mapM renameType ts+ return [ty|+ ($list:ts') $qtid:ql' |]+ [ty| '$tv |] -> do+ tv' <- getTyvar tv+ return [ty|+ '$tv' |]+ [ty| $t1 -[$opt:mqe]> $t2 |] -> do+ t1' <- renameType t1+ mqe' <- traverse renameQExp mqe+ t2' <- renameType t2+ return [ty|+ $t1' -[$opt:mqe']> $t2' |]+ [ty| $quant:u '$tv. $t |] -> do+ (tv', md) <- steal $ bindTyvar tv+ t' <- inModule md $ renameType t+ return [ty|+ $quant:u '$tv'. $t' |]+ [ty| mu '$tv. $t |] -> do+ (tv', md) <- steal $ bindTyvar tv+ t' <- inModule md $ renameType t+ return [ty|+ mu '$tv'. $t' |]+ [ty| `$uid:u of $t1 | $t2 |] -> do+ let u' = renTrivial u+ t1' <- renameType t1+ t2' <- renameType t2+ return [ty| `$uid:u' of $t1' | $t2' |]+ [ty| $anti:a |] -> $antifail++-- | Rename a type pattern+renameTyPats :: [TyPat Raw] -> R [TyPat Renamed]+renameTyPats x00 = evalStateT (mapM loop x00) M.empty where+ loop :: TyPat Raw ->+ StateT (M.Map (Lid Raw) (TyVar Raw, Loc)) Renaming (TyPat Renamed)+ loop x0 = withLocation x0 $ case x0 of+ [tpQ| $antiP:a |] -> $antifail+ N note (TpVar tv var) -> do+ tv' <- tyvar (getLoc note) tv+ return (tpVar tv' var <<@ note)+ N note (TpRow tv var) -> do+ tv' <- tyvar (getLoc note) tv+ return (tpRow tv' var <<@ note)+ [tpQ| ($list:tps) $qtid:ql |] -> do+ ql' <- lift (withLocation _loc (getTycon ql))+ tps' <- mapM loop tps+ return [tpQ|+ ($list:tps') $qtid:ql' |]+ --+ tyvar :: Loc -> TyVar Raw ->+ StateT (M.Map (Lid Raw) (TyVar Raw, Loc)) Renaming (TyVar Renamed)+ tyvar loc1 tv = do+ seen <- get+ case M.lookup (tvname tv) seen of+ Just (tv', _) ->+ lift (repeatedTVs [tv,tv'] "type parameters")+ Nothing -> do+ put (M.insert (tvname tv) (tv, loc1) seen)+ lift (bindTyvar tv)++-- | Rename a qualifier expression+renameQExp :: QExp Raw -> R (QExp Renamed)+renameQExp qe0 = withLocation qe0 $ case qe0 of+ [qeQ| $qlit:qlit |] -> do+ return [qeQ|+ $qlit:qlit |]+ [qeQ| $qvar:tv |] -> do+ tv' <- getTyvar tv+ return [qeQ| $qvar:tv' |]+ [qeQ| $qe1 \/ $qe2 |] -> do+ qe1' <- renameQExp qe1+ qe2' <- renameQExp qe2+ return [qeQ| $qe1' \/ $qe2' |]+ [qeQ| $anti:a |] -> do+ $antifail++-- | Rename a pattern+renamePatt :: Patt Raw -> R (Patt Renamed)+renamePatt x00 = evalStateT (loop x00) M.empty where+ loop :: Patt Raw ->+ StateT (M.Map (VarId Raw) Loc)+ Renaming (Patt Renamed)+ loop x0 = withLocation x0 $ case x0 of+ [pa| _ |] ->+ return [pa|+ _ |]+ [pa| $vid:l |] -> do+ l' <- var _loc l+ return [pa|+ $vid:l' |]+ [pa| $qcid:qu $opt:mx |] -> do+ qu' <- lift $ getDatacon qu+ mx' <- traverse loop mx+ return [pa|+ $qcid:qu' $opt:mx' |]+ [pa| `$uid:qu $opt:mx |] -> do+ let qu' = renTrivial qu+ mx' <- traverse loop mx+ return [pa|+ `$uid:qu' $opt:mx' |]+ [pa| ($x1, $x2) |] -> do+ x1' <- loop x1+ x2' <- loop x2+ return [pa|+ ($x1', $x2') |]+ [pa| $lit:lit |] -> do+ lit' <- lift $ renameLit lit+ return [pa|+ $lit:lit' |]+ [pa| $x as $vid:l |] -> do+ x' <- loop x+ l' <- var _loc l+ return [pa|+ $x' as $vid:l' |]+ [pa| { $uid:u = $x | $y } |] -> do+ let u' = renTrivial u+ x' <- loop x+ y' <- loop y+ return [pa|! { $uid:u' = $x' | $y' } |]+ [pa| ! $x |] -> do+ x' <- loop x+ return [pa| ! $x' |]+ [pa| $x : $t |] -> do+ x' <- loop x+ t' <- lift $ renameType t+ return [pa| $x' : $t' |]+ [pa| $anti:a |] -> do+ $antifail+ --+ var loc1 vid = do+ seen <- get+ case M.lookup vid seen of+ Just loc2 -> lift (repeated "Variable" vid "pattern" [loc1, loc2])+ Nothing -> do+ put (M.insert vid loc1 seen)+ lift (withLocation loc1 (bindVar vid))++-- | Univerally-quantify all free type variables+closeType :: Type Raw -> Type Raw+closeType t = foldr tyAll t (annotFtvSet t)++addVal :: VarId Raw -> R (VarId Renamed)+addType :: TypId Raw -> Renamed -> [ConId Raw] -> R (TypId Renamed)+addMod :: ModId Raw -> R a -> R (ModId Renamed, a)++addVal = bindVar++addType l i dcs = do+ let l' = renId i l+ loc <- getLocation+ tell [MdTycon loc l l' dcs]+ return l'++addMod u body = do+ let u' = renTrivial u+ (a, md) <- steal body+ loc <- getLocation+ tell [MdModule loc u u' md]+ return (u', a)++-- | Result for 'getRenamingInfo'+data RenamingInfo+ = ModuleAt { renInfoLoc :: Loc, renInfoQModId :: QModId Renamed }+ | SigAt { renInfoLoc :: Loc, renInfoQSigId :: QSigId Renamed }+ | VariableAt { renInfoLoc :: Loc, renInfoQVarId :: QVarId Renamed }+ | TyconAt { renInfoLoc :: Loc, renInfoQTypId :: QTypId Renamed }+ | DataconAt { renInfoLoc :: Loc, renInfoQConId :: QConId Renamed }+ deriving Show++-- | For the REPL to find out where identifiers are bound and their+-- renamed name for looking up type info+getRenamingInfo :: Ident Raw -> RenameState -> [RenamingInfo]+getRenamingInfo name RenameState { savedEnv = e } =+ catMaybes $ case view name of+ Left ql -> [ look tycons (TypId <$> ql) TyconAt,+ look vars (VarId <$> ql) VariableAt ]+ Right qu -> [ look sigs (SigId <$> qu) SigAt,+ look modules (ModId <$> qu) ModuleAt,+ look datacons (ConId <$> qu) DataconAt ]+ where+ look prj qx build = case envLookup prj qx e of+ Left _ -> Nothing+ Right (J ps (x', loc, _)) -> Just (build loc (J ps x'))++-- Open the given module, if it exists.+renamingEnterScope :: ModId i -> RenameState -> RenameState+renamingEnterScope u r =+ let e = savedEnv r in+ case M.lookup (renTrivial u) (modules e) of+ Nothing -> r+ Just (_, _, (_, e'))+ -> r { savedEnv = e `mappend` e' }++-- | Test runner for renaming an expression+re :: Expr Raw -> Either [AlmsError] (Expr Renamed)+re e = fst <$> runRenaming True bogus renameState0 (renameExpr e)++-- | Test runner for renaming an declaration+rd :: Decl Raw -> Either [AlmsError] (Decl Renamed)+rd d = fst <$> runRenaming True bogus renameState0 (renameDecl d)++_loc :: Loc+_loc = initial "<interactive>"
+ src/Statics/Sealing.hs view
@@ -0,0 +1,418 @@+module Statics.Sealing (+ sealWith,+ replaceTyCons, getSigTyCons, getSigItemTyCons,+) where++import Util+import qualified AST+import Type+import Statics.Constraint+import Statics.Env as Env+import Statics.Error+import Statics.Subsume++import Prelude ()+import qualified Data.Map as M++-- | Perform generative signature matching+sealWith ∷ MonadConstraint tv r m ⇒+ [ModId] → Signature tv → Signature tv → m (Signature tv)+sealWith μ sig0 sig1 = do+ let sig1' = renameSig (makeNameMap sig0) μ sig1+ γ0 = sigToEnv sig0+ tcsubst ← matchSigTycons γ0 sig1'+ subsumeSig γ0 (applyTCSInTyCon tcsubst sig1')+ let tcs = getGenTycons sig1'+ tcs' ← for tcs $ \tc → do+ ix ← tvUniqueID <$> newTV+ return tc { tcId = ix }+ return (substTyCons tcs tcs' sig1')++-- | For mapping renamed names (from structures) into unrenamed names+-- (in signatures)+data NameMap+ = NameMap {+ nmVar ∷ Env VarId VarId,+ nmCon ∷ Env ConId ConId,+ nmTyp ∷ Env TypId TypId,+ nmMod ∷ Env ModId (ModId, NameMap),+ nmSig ∷ Env SigId SigId+ }++instance Monoid NameMap where+ mempty = NameMap empty empty empty empty empty+ mappend (NameMap a1 a2 a3 a4 a5) (NameMap b1 b2 b3 b4 b5) =+ NameMap (a1 =+= b1) (a2 =+= b2) (a3 =+= b3) (a4 =+= b4) (a5 =+= b5)++instance GenEmpty NameMap where+ genEmpty = mempty+instance GenExtend NameMap NameMap where+ (=+=) = mappend+instance GenLookup NameMap VarId VarId where+ e =..= k = nmVar e =..= k+instance GenLookup NameMap ConId ConId where+ e =..= k = nmCon e =..= k+instance GenLookup NameMap TypId TypId where+ e =..= k = nmTyp e =..= k+instance GenLookup NameMap ModId (ModId, NameMap) where+ e =..= k = nmMod e =..= k+instance GenLookup NameMap SigId SigId where+ e =..= k = nmSig e =..= k++-- | Given a signature, construct a 'NameMap' mapping trivially-renamed+-- versions of its names to the actual renamed version.+makeNameMap ∷ Signature tv → NameMap+makeNameMap = foldMap eachItem where+ eachItem (SgVal n _) = mempty { nmVar = unTag n =:= n }+ eachItem (SgTyp n tc) =+ mempty {+ nmTyp = unTag n =:= n,+ nmCon = Env.fromList ((unTag &&& id) <$> Env.domain (tcCons tc))+ }+ eachItem (SgExn n _) = mempty { nmCon = unTag n =:= n }+ eachItem (SgSig n _) = mempty { nmSig = unTag n =:= n }+ eachItem (SgMod n sig) = mempty { nmMod = unTag n =:= (n, makeNameMap sig) }+ --+ unTag ∷ AST.Id a ⇒ a R → a R+ unTag = AST.renId bogus++-- | Make the names in a signature match the names from the module it's+-- being applied to.+renameSig ∷ NameMap → [ModId] → Signature tv → Signature tv+renameSig nm μ = map eachItem where+ eachItem (SgVal n σ) = SgVal (nm !..! n) σ+ eachItem (SgTyp n tc) = SgTyp (nm !..! n) tc'+ where+ tc' = tc {+ tcName = J (reverse μ) (jname (tcName tc)),+ tcCons = Env.fromList (first (nm !..!) <$> Env.toList (tcCons tc))+ }+ eachItem (SgExn n mσ) = SgExn (nm !..! n) mσ+ eachItem (SgMod n sig) = SgMod n' sig'+ where+ (n', nm') = nm !..! n+ sig' = renameSig nm' (n':μ) sig+ eachItem (SgSig n sig) = SgSig (nm !..! n) sig++-- | Given a signature, find the tycon substitutions necessary to+-- unify it with the module in the environment.+matchSigTycons ∷ MonadConstraint tv r m ⇒+ Γ tv → Signature tv → m TyConSubst+matchSigTycons γ = execWriterT . eachSig [] where+ eachSig μ = mapM_ (eachItem μ)+ eachItem μ sigitem = case sigitem of+ SgVal _ _ → return ()+ SgTyp n tc → do+ tc' ← γ !.! J (reverse μ) n+ tell (makeTyConSubst [tc] [tc'])+ SgExn _ _ → return ()+ SgMod n sig → eachSig (n:μ) sig+ SgSig _ _ → return ()++-- | Check whether the given signature subsumes the signature+-- implicit in the environment.+subsumeSig ∷ MonadConstraint tv r m ⇒+ Γ tv → Signature tv → m ()+subsumeSig γ = eachSig where+ eachSig = mapM_ eachItem+ eachItem sg0 = case sg0 of+ SgVal n σ → do+ σ' ← γ !.! n+ σ' ≤ σ+ `addErrorContext`+ [msg| In signature matching, type mismatch for value binding $q:n. |]+ SgTyp n tc → do+ tc' ← γ !.! n+ case varietyOf tc of+ OperatorType → matchTyCons tc' tc+ DataType → matchTyCons tc' tc+ AbstractType → do+ let sigAss assertion thing getter =+ tAssExp assertion+ ([msg| In signature matching, cannot match the+ definition for type $q:1 because the+ $words:thing does not match: |] (tcName tc))+ (showMsg (getter tc'))+ (showMsg (getter tc))+ sigAss (length (tcArity tc') == length (tcArity tc))+ "number of type parameters" (length . tcArity)+ sigAss (all2 (⊑) (tcArity tc') (tcArity tc))+ "variance" tcArity+ sigAss (all2 (⊒) (tcBounds tc') (tcBounds tc))+ "parameter bounds" tcBounds+ sigAss (tcQual tc' ⊑ tcQual tc)+ "qualifier" tcQual+ SgExn n mσ → do+ emσ' ← γ !.! n+ case emσ' of+ Left _ → typeBug "subsumeSig" "Datacon where exn expected"+ Right mσ' → matchParamType mσ' mσ [msg| exception $q:n |]+ SgMod n sig → do+ (_, γ') ← γ !.! n+ subsumeSig γ' sig+ SgSig n sig → do+ (sig', _) ← γ !.! n+ matchSigs sig' sig++-- | Check that exception parameter types match, given the constructor+-- name, the actual type, and the expected type.+matchParamType ∷ MonadConstraint tv r m ⇒+ Maybe (Type Empty) → Maybe (Type Empty) →+ Message H →+ m ()+matchParamType mσ mσ' what = case (mσ, mσ') of+ (Nothing, Nothing)+ → return ()+ (Just σ, Just σ')+ → elimEmptyF σ =: elimEmptyF σ' `addErrorContext`+ [msg| In signature matching, type mismatch in parameter of $msg:what |]+ _ → tErrExp+ [msg| In signature matching, parameter of $msg:what does not match |]+ (maybe [msg| no parameter |] pprMsg mσ)+ (maybe [msg| no parameter |] pprMsg mσ')++-- | Check that two signatures match EXACTLY.+-- First signature is what we have, and second is what we want.+matchSigs ∷ MonadConstraint tv r m ⇒+ Signature tv → Signature tv → m ()+matchSigs = loop where+ loop [] [] = return ()+ loop (SgVal n1 σ1 : sgs1) (SgVal n2 σ2 : sgs2)+ | n1 == n2 = do+ σ1 =: σ2 `addErrorContext`+ [msg| In matching signatures, types do not match for+ value binding $q:n1. |]+ loop sgs1 sgs2+ loop (SgTyp n1 tc1 : sgs1) (SgTyp n2 tc2 : sgs2)+ | n1 == n2 = do+ matchTyCons tc2 tc1+ loop (substTyCon tc1 tc2 sgs1) sgs2+ loop (SgExn n1 mσ1 : sgs1) (SgExn n2 mσ2 : sgs2)+ | n1 == n2 = do+ matchParamType mσ2 mσ1 [msg| exception $q:n1 |]+ loop sgs1 sgs2+ loop (SgMod n1 sig1 : sgs1) (SgMod n2 sig2 : sgs2)+ | n1 == n2 = do+ matchSigs sig1 sig2+ loop sgs1 sgs2+ loop (SgSig n1 sig1 : sgs1) (SgSig n2 sig2 : sgs2)+ | n1 == n2 = do+ matchSigs sig1 sig2+ loop sgs1 sgs2+ loop [] (sg : _) = do+ (n, what) ← whatIs sg+ typeError [msg|+ In exact signature matching, missing expected $what $qmsg:n.+ |]+ loop (sg : _) [] = do+ (n, what) ← whatIs sg+ typeError [msg|+ In exact signature matching, found unexpected $what $qmsg:n.+ |]+ loop (sg1 : _) (sg2 : _) = do+ (n1, what1) ← whatIs sg1+ (n2, what2) ← whatIs sg2+ typeError [msg|+ In exact signature matching (for signatures as entries in+ signatures being matched), got signature items didn’t match:+ <dl>+ <dt>actual: <dd>$what1 $qmsg:n1+ <dt>expected: <dd>$what2 $qmsg:n2+ </dl>+ |]+ --+ whatIs (SgVal n _) = return (pprMsg n, "value")+ whatIs (SgTyp n _) = return (pprMsg n, "type")+ whatIs (SgExn n _) = return (pprMsg n, "exception")+ whatIs (SgMod n _) = return (pprMsg n, "module")+ whatIs (SgSig n _) = return (pprMsg n, "module type")++-- | Get a list of all the tycons that need a new index allocated+-- because they're generative.+getGenTycons ∷ Signature tv → [TyCon]+getGenTycons = execWriter . eachSig where+ eachSig = mapM_ eachItem+ eachItem sg0 = case sg0 of+ SgVal _ _ → return ()+ SgTyp _ tc → unless (varietyOf tc == OperatorType) (tell [tc])+ SgExn _ _ → return ()+ SgMod _ sig → eachSig sig+ SgSig _ _ → return ()++-- | Check that two type constructors match exactly.+matchTyCons ∷ MonadConstraint tv r m ⇒ TyCon → TyCon → m ()+matchTyCons tc1 tc2 = case (varietyOf tc1, varietyOf tc2) of+ (AbstractType, AbstractType) → do+ tcArity tc1 ==! tcArity tc2 $ "arity or variance"+ tcBounds tc1 ==! tcBounds tc2 $ "parameter bound"+ tcGuards tc1 ==! tcGuards tc2 $ "guarded parameters"+ tcQual tc1 ==! tcQual tc2 $ "qualifier"+ (DataType, DataType) → do+ tcArity tc1 ==! tcArity tc2 $ "number of parameters"+ let rhs1 = tcCons tc1+ rhs2 = tcCons tc2+ forM_ (Env.toList rhs1) $ \(k, mσ1) → do+ mσ2 ← rhs2 !.! k+ matchParamType mσ2 mσ1 [msg| constructor $q:k |]+ (OperatorType, _) | tyconExtEq tc1 tc2 → return ()+ (_, OperatorType) | tyconExtEq tc1 tc2 → return ()+ (OperatorType, OperatorType) → do+ let next1 = fromMaybe [] (tcNext tc1)+ next2 = fromMaybe [] (tcNext tc2)+ ncs1 = length next1+ ncs2 = length next1+ ncs1 ==! ncs2 $ "number of clauses"+ forM_ (zip3 next1 next2 [1 ∷ Int .. ]) $+ \((tp1, σ1), (tp2, σ2), ix) → do+ length tp1 ==! length tp2 $+ if ncs1 == 1+ then "number of type parameters"+ else "number of parameters else in clause " ++ show ix+ zipWithM_ matchTyPats tp1 tp2+ σ1 ==! σ2 $+ if ncs1 == 1+ then "type synonym right-hand sides"+ else "type operator right-hand sides in clause " ++ show ix+ (v1, v2) → v1 ==! v2 $ "kind of definition"+ where+ (a1 ==! a2) what =+ tAssExp (a1 == a2)+ [msg| In signature matching, cannot match definition for type+ $q:tc1 because the $words:what does not match: |]+ (pprMsg a1)+ (pprMsg a2)++-- | Extensional equality for type constructors.+-- This is probably too weak.+tyconExtEq ∷ TyCon → TyCon → Bool+tyconExtEq tc1 tc2 | tcBounds tc1 == tcBounds tc2 =+ let tvs = fvTy <$> [ 1 .. length (tcArity tc1) ]+ in TyApp tc1 tvs == TyApp tc2 tvs+tyconExtEq _ _ = False++-- | To check that two type patterns match, and return the pairs of+-- type variables that line up and thus need renaming.+matchTyPats ∷ MonadAlmsError m ⇒ TyPat → TyPat → m ()+matchTyPats (TpVar _) (TpVar _)+ = return ()+matchTyPats (TpRow _) (TpRow _)+ = return ()+matchTyPats (TpApp tc1 tvs1) (TpApp tc2 tvs2)+ | tc1 == tc2+ = zipWithM_ matchTyPats tvs1 tvs2+matchTyPats tp1 tp2+ = tErrExp+ [msg| In signature matching, cannot match type patterns: |]+ (pprMsg tp1)+ (pprMsg tp2)++---+--- TYPE CONSTRUCTOR SUBSTITUTION+---++-- | A substitution mapping type constructors to other type+-- constructors+type TyConSubst = M.Map Int TyCon++-- | Construct a tycon substitution from a list of tycons and a list+-- to map them to.+makeTyConSubst ∷ [TyCon] → [TyCon] → TyConSubst+makeTyConSubst tcs tcs' = M.fromList (zip (tcId <$> tcs) tcs')++class SubstTyCon a where+ applyTCS, applyTCSInTyCon ∷ TyConSubst → a → a+ applyTCSInTyCon = applyTCS++instance SubstTyCon a ⇒ SubstTyCon (Maybe a) where+ applyTCS = fmap . applyTCS+ applyTCSInTyCon = fmap . applyTCSInTyCon++instance SubstTyCon a ⇒ SubstTyCon [a] where+ applyTCS = fmap . applyTCS+ applyTCSInTyCon = fmap . applyTCSInTyCon++instance SubstTyCon v ⇒ SubstTyCon (Env k v) where+ applyTCS = fmap . applyTCS+ applyTCSInTyCon = fmap . applyTCSInTyCon++instance (SubstTyCon a, SubstTyCon b) ⇒ SubstTyCon (a, b) where+ applyTCS s = applyTCS s *** applyTCS s+ applyTCSInTyCon s = applyTCSInTyCon s *** applyTCSInTyCon s++instance (SubstTyCon a, SubstTyCon b, SubstTyCon c) ⇒+ SubstTyCon (a, b, c) where+ applyTCS s (a, b, c) = (applyTCS s a, applyTCS s b, applyTCS s c)+ applyTCSInTyCon s (a, b, c) =+ (applyTCSInTyCon s a, applyTCSInTyCon s b, applyTCSInTyCon s c)++instance (SubstTyCon a, SubstTyCon b) ⇒ SubstTyCon (Either a b) where+ applyTCS s = applyTCS s +++ applyTCS s+ applyTCSInTyCon s = applyTCSInTyCon s +++ applyTCSInTyCon s++instance SubstTyCon TyCon where+ applyTCS s tc+ | Just tc' ← M.lookup (tcId tc) s+ = applyTCSInTyCon s tc'+ | otherwise+ = applyTCSInTyCon s tc+ applyTCSInTyCon s tc+ = tc {+ tcNext = applyTCS s (tcNext tc),+ tcCons = applyTCS s (tcCons tc)+ }++instance SubstTyCon TyPat where+ applyTCS s tp0 = case tp0 of+ TpVar _ → tp0+ TpRow _ → tp0+ TpApp tc σs → TpApp (applyTCS s tc) (applyTCS s σs)++instance SubstTyCon (Type tv) where+ applyTCS s σ0 = case σ0 of+ TyVar _ → σ0+ TyQu qu αs σ → TyQu qu αs (applyTCS s σ)+ TyMu α σ → TyMu α (applyTCS s σ)+ TyRow lab σ1 σ2 → TyRow lab (applyTCS s σ1)+ (applyTCS s σ2)+ TyApp tc σs → TyApp (applyTCS s tc)+ (applyTCS s σs)++instance SubstTyCon (SigItem tv) where+ applyTCS s sg0 = case sg0 of+ SgVal n σ → SgVal n (applyTCS s σ)+ SgTyp n tc → SgTyp n (applyTCS s tc)+ SgExn n mσ → SgExn n (applyTCS s mσ)+ SgMod n sig → SgMod n (applyTCS s sig)+ SgSig n sig → SgSig n (applyTCS s sig)+ applyTCSInTyCon s sg0 = case sg0 of+ SgVal n σ → SgVal n (applyTCS s σ)+ SgTyp n tc → SgTyp n (applyTCSInTyCon s tc)+ SgExn n mσ → SgExn n (applyTCS s mσ)+ SgMod n sig → SgMod n (applyTCSInTyCon s sig)+ SgSig n sig → SgSig n (applyTCS s sig)++-- | Replace all the type constructors whose indices match the ones in the+-- list with the ones in the list.+replaceTyCons ∷ SubstTyCon a ⇒ [TyCon] → a → a+replaceTyCons tcs = substTyCons tcs tcs++-- Give a list of tycons to replace and a list of tycons to replace them+-- with, replaces them all recursively, including knot-tying+substTyCons ∷ SubstTyCon a ⇒ [TyCon] → [TyCon] → a → a+substTyCons tcs tcs' = applyTCS (makeTyConSubst tcs tcs')++-- | Replace all occurrences of the first tycon with the second+substTyCon ∷ SubstTyCon a ⇒ TyCon → TyCon → a → a+substTyCon tc tc' = substTyCons [tc] [tc']++-- | Get all the tycons that are bound in a signature+getSigTyCons ∷ Signature tv → [TyCon]+getSigTyCons = concatMap getSigItemTyCons++-- | Get all the tycons that are bound in a signature item+getSigItemTyCons ∷ SigItem tv → [TyCon]+getSigItemTyCons (SgVal _ _) = []+getSigItemTyCons (SgTyp _ tc) = [tc]+getSigItemTyCons (SgExn _ _) = []+getSigItemTyCons (SgMod _ sig) = getSigTyCons sig+getSigItemTyCons (SgSig _ sig) = getSigTyCons sig
+ src/Statics/Sig.hs view
@@ -0,0 +1,80 @@+module Statics.Sig (+ Signature, SigItem (..),+ sigToStx, sigToStx', sigItemToStx, sigItemToStx',+ abstractSig, abstractSigItem,+ VarId, ModId, SigId, QVarId, QModId, QSigId,+) where++import Util+import qualified AST+import Type+import qualified Syntax.Ppr as Ppr++import Prelude ()+import Data.Generics (Typeable, Data)++type R = AST.Renamed+type VarId = AST.VarId R+type ModId = AST.ModId R+type SigId = AST.SigId R+type QVarId = AST.QVarId R+type QModId = AST.QModId R+type QSigId = AST.QSigId R++data SigItem tv+ = SgVal !VarId !(Type tv)+ | SgTyp !TypId !TyCon+ | SgExn !ConId !(Maybe (Type Empty))+ | SgMod !ModId !(Signature tv)+ | SgSig !SigId !(Signature tv)+ deriving (Functor, Typeable, Data)++type Signature tv = [SigItem tv]++-- | Convert an internal signature to AST, with no type context+sigToStx' ∷ Tv tv ⇒ Signature tv → AST.SigExp R+sigToStx' = sigToStx tyNames0++-- | Convert an internal signature to AST+sigToStx ∷ Tv tv ⇒ TyNames → Signature tv → AST.SigExp R+sigToStx tn items = AST.seSig (sigItemToStx tn <$> items)++-- | Convert an internal signature item to an AST signature item,+-- with no type context.+sigItemToStx' ∷ Tv tv ⇒ SigItem tv → AST.SigItem R+sigItemToStx' = sigItemToStx tyNames0++-- | Convert an internal signature item to an AST signature item+-- TODO: Group mutually recursive types.+sigItemToStx ∷ Tv tv ⇒ TyNames → SigItem tv → AST.SigItem R+sigItemToStx tn si0 = case si0 of+ SgVal n τ → AST.sgVal n (typeToStx t2sc τ)+ SgTyp _ tc → AST.sgTyp [tyConToStx tn tc]+ SgExn n mτ → AST.sgExn n (typeToStx t2sc <$> mτ)+ SgMod n sig → AST.sgMod n (sigToStx (tnEnter tn n) sig)+ SgSig n sig → AST.sgSig n (sigToStx tn sig)+ where+ t2sc = t2sContext0 { t2sTyNames = tn }++-- | Abstract a signature by removing the representation information+-- of all type constructors+abstractSig ∷ Signature tv → Signature tv+abstractSig = map abstractSigItem++-- | Abstract a signature item by removing the representation information+-- of all type constructors+abstractSigItem ∷ SigItem tv → SigItem tv+abstractSigItem sg = case sg of+ SgVal n σ → SgVal n σ+ SgTyp n tc → SgTyp n (abstractTyCon tc)+ SgExn n mσ → SgExn n mσ+ SgMod n sig → SgMod n (abstractSig sig)+ SgSig n sig → SgSig n (abstractSig sig)++instance Tv tv ⇒ Ppr.Ppr (SigItem tv) where+ ppr item = Ppr.askTyNames $ \tn → Ppr.ppr (sigItemToStx tn item)+ pprList sig = Ppr.askTyNames $ \tn → Ppr.ppr (sigToStx tn sig)++instance Tv tv ⇒ Show (SigItem tv) where+ showsPrec = Ppr.showFromPpr+ showList = Ppr.showFromPpr 0
+ src/Statics/Subsume.hs view
@@ -0,0 +1,98 @@+-- | Subsumption+module Statics.Subsume (+ subsumeN, (≤), (≤≥), subsumeBy,+) where++import Util+import Statics.Constraint+import Statics.Error+import Statics.InstGen+import Type++import Prelude ()+import qualified Data.Set as S++-- | Given a list of type/U-action pairs, run all the U actions, but+-- in an order that does all U-actions not assocated with tyvars+-- before those associated with tyvars. Checks dynamically after each+-- action, since an action can turn a tyvar into a non-tyvar.+subsumeN ∷ MonadConstraint tv r m ⇒+ [(Type tv, m ())] → m ()+subsumeN [] = return ()+subsumeN σs0 = subsumeOneOf σs0 >>= subsumeN+ where+ subsumeOneOf [] = return []+ subsumeOneOf [(_, u1)] = [] <$ u1+ subsumeOneOf ((σ1, u1):σs) = do+ σ ← substHead σ1+ case σ of+ TyVar (Free α) | tvFlavorIs Universal α+ → ((σ, u1):) <$> subsumeOneOf σs+ _ → σs <$ u1++-- | Subsumption+(≤) ∷ MonadConstraint tv r m ⇒ Type tv → Type tv → m ()+σ1 ≤ σ2 = do+ traceN 2 ("≤", σ1, σ2)+ subsumeBy (<:) σ1 σ2+ `addErrorContext`+ [msg| When subsuming types (using instantiation and subtyping):+ <dl>+ <dt>actual: <dd>$5:σ1+ <dt>expected: <dd>$5:σ2+ </dl> |]++-- | Subsumption+(≤≥) ∷ MonadConstraint tv r m ⇒ Type tv → Type tv → m ()+σ1 ≤≥ σ2 = do+ traceN 2 ("≤≥", σ1, σ2)+ subsumeBy (=:) σ1 σ2+ `addErrorContext`+ [msg| When subsuming types (using instantiation and unification):+ <dl>+ <dt>actual: <dd>$5:σ1+ <dt>expected: <dd>$5:σ2+ </dl> |]++subsumeBy ∷ MonadConstraint tv r m ⇒+ (Type tv → Type tv → m ()) → Type tv → Type tv → m ()+subsumeBy (≤*) σ10 σ20 = do+ σ1 ← subst σ10+ σ2 ← subst σ20+ case (σ1, σ2) of+ (TyVar (Free α), _) | tvFlavorIs Universal α → do+ σ1 ≤* σ2+ (_, TyVar (Free α)) | tvFlavorIs Universal α → do+ σ1' ← instAll True σ1+ σ1' ≤* σ2+ _ → do+ ρ1 ← instantiate σ1+ (ρ2, αs2) ← collectTVs (instantiateNeg σ2)+ ρ1 ≤* ρ2+ -- Check for escaping skolems+ let (us1, _, ss1) = partitionFlavors αs2+ σ1' ← subst σ1+ σ2' ← subst σ2+ us1' ← mapM subst (fvTy <$> us1)+ let freeSkolems = S.filter (tvFlavorIs Skolem) (ftvSet (σ1', σ2', us1'))+ when (any (`S.member` freeSkolems) ss1) $ do+ traceN 3 (αs2, freeSkolems)+ tErrExp+ [msg|+ Cannot subsume types because a type is less+ polymorphic than expected:+ |]+ (pprMsg σ1')+ (pprMsg σ2')++-- | Given a list of type variables, partition it into a triple of lists+-- of 'Universal', 'Existential', and 'Skolem' flavored type variables.+partitionFlavors ∷ Tv tv ⇒+ [tv] → ([tv], [tv], [tv])+partitionFlavors = loop [] [] [] where+ loop us es ss [] = (us, es, ss)+ loop us es ss (α:αs) = case tvFlavor α of+ Universal → loop (α:us) es ss αs+ Existential → loop us (α:es) ss αs+ Skolem → loop us es (α:ss) αs+
+ src/Statics/Type.hs view
@@ -0,0 +1,203 @@+module Statics.Type (+ tcType, tcTypeRowDots, tcTyPat,+) where++import Util+import qualified AST+import Meta.Quasi+import Type+import Statics.Env+import Statics.Error+import Statics.Constraint++import Prelude ()+import qualified Data.Map as M++-- | Type check a type.+tcType ∷ MonadConstraint tv r m ⇒+ Δ tv → Γ tv → AST.Type R → m (Type tv)+tcType = tcTypeRowDots <-> []++-- | When checking row dots, there are three possible states we could be+-- in:+data DotState tv+ -- | We are not currently under an ellipsis, and the given type+ -- variables are available type variables bound under an ellipsis.+ = Available [tv]+ -- | We are under an ellipsis, but have not found out yet which+ -- variable it protects.+ | Unchosen [tv]+ -- | We are under an ellipsis that controls the given variable,+ -- with the remaining variables available for remaining ellipses.+ | Chosen tv [tv]++-- | Type check a type, resolving dots (maps over rows). Type variables+-- in the list of dots variables *must not* be bound in the type+-- variable environment.+tcTypeRowDots ∷ MonadConstraint tv r m ⇒+ Δ tv → [(AST.TyVar R, tv)] → Γ tv →+ AST.Type R → m (Type tv)+tcTypeRowDots δ0 dotTVs γ t00 =+ evalStateT (loop δ0 (iaeInit :: CurrentImpArrRule tv) t00)+ (Available dotTVs)+ where+ loop δ iae t0 = withLocation t0 $ case t0 of+ [ty| `$α |] → do+ fvTy <$> δ !.! α `catchAlms` handleDotTV α+ --+ [ty| $t1 -[$opt:mqe]> $t2 |] → do+ qe ← iaeInterpret (Free <$$> (δ !.!)) iae mqe+ τ1 ← loop δ (iaeLeft iae) t1+ τ2 ← loop δ (iaeRight iae qe τ1) t2+ return (tyFun τ1 qe τ2)+ --+ [ty| $t ... |] → do+ withDots $ loop δ iae t+ --+ [ty| ($list:ts) $qtid:n |] → do+ tc ← γ !.! n+ τs ← zipWithM (loop δ . iaeUnder iae) (tcArity tc) ts+ zipWithM_ (⊏:) τs (tcBounds tc)+ checkLength (length ts) (length (tcArity tc))+ return (TyApp tc τs)+ where+ checkLength actual expected =+ tAssExp (actual == expected)+ [msg| Type constructor $q:n got the wrong number of parameters: |]+ [msg| $actual |]+ [msg| $expected |]+ --+ [ty| $quant:qu `$_. $_ |] → do+ let (αs, t) = AST.unfoldTyQu qu t0+ qls = AST.tvqual <$> αs+ qu' ← tcQuant qu+ αs' ← mapM (curry newTV' Skolem) qls+ τ' ← loop (δ =+= αs =:*= αs') iae t+ return (closeQuant qu' (zip αs' qls) τ')+ --+ [ty| μ `$α. $t |] → do+ α' ← newTV+ τ' ← loop (δ =+= α =:= α') iae t+ checkGuarded α' τ'+ τ' ⊏: fvTy α'+ return (closeRec α' τ')+ where+ checkGuarded α' τ' = case M.lookup α' (ftvG τ') of+ Just False+ → typeError [msg|+ Recursive type is ill formed because the bound variable+ is unguarded:+ <dl>+ <dt>type: <dd>$t0+ <dt>variable: <dd>$α+ </dl>+ The type variable bound by μ must appear only under type+ constructors that are allowed to <q>guard</q> recursion,+ such as under an open variant.+ |]+ _ → return ()+ --+ [ty| `$uid:uid of $t1 | $t2 |] → do+ τ1 ← loop δ iae t1+ τ2 ← loop δ iae t2+ return (TyRow uid τ1 τ2)+ --+ [ty| $anti:a |] → $(AST.antifail)++withDots ∷ (MonadSubst tv r m,+ MonadState (DotState (AST.TyVar R, tv)) m) ⇒+ m (Type tv) → m (Type tv)+withDots checkT = do+ dotState ← get+ put . Unchosen =<< case dotState of+ Available [] → do+ typeError' [msg|+ Row dots (<q>...</q>) may only appear on the right-hand side+ of a type operator declaration that also has row dots on the+ left-hand side.+ |]+ Available βs → return βs+ Unchosen βs → return βs+ Chosen _ βs → return βs+ σ ← checkT+ dotState' ← get+ case dotState' of+ Available _ → availableBug+ Unchosen _ → unchosenError+ Chosen (_, β') _ → do+ put dotState+ return (TyApp tcRowMap [σ, fvTy β'])+ where+ availableBug = typeBug "withDots" "Saw Available inside dots"+ unchosenError = do+ typeError' [msg|+ Row dots (<q>...</q>) may only appear on the right-hand side+ of a type operator declaration, and must include in their+ parameter a type variable that appeared under row dots on the+ left-hand side.+ |]++-- | Given a type variable that was not bound in the type variable+-- environment (and the exceptions thrown to reflect that), check+-- if it's involved in row mapping (dots syntax) and if so, translate+-- it thusly.+handleDotTV ∷ (MonadSubst tv r m,+ MonadState (DotState (AST.TyVar R, tv)) m) ⇒+ AST.TyVar R → [AlmsError] → m (Type tv)+handleDotTV α es = do+ dotState ← get+ case dotState of+ Available βs+ | Just _ ← lookup α βs → do+ typeError' [msg|+ Type variable $α matches a row using dot notation (<q>...</q>)+ in the pattern of a type operator, but appears unprotected by+ dots on the right-hand side.+ |]+ Unchosen βs+ | Just α' ← lookup α βs → do+ put (Chosen (α, α') βs)+ return (TyApp tcRowHole [])+ Chosen (β, _) βs+ | α == β → return (TyApp tcRowHole [])+ | Just _ ← lookup α βs → do+ typeError' [msg|+ Type variable $α, which stands for a row,+ appears under row dots (<q>...</q>) that iterate+ a different row variable, $β.+ |]+ _ → throwAlmsList es++-- | Convert an AST quantifer to an internal quantifier+tcQuant ∷ MonadAlmsError m ⇒ AST.Quant → m Quant+tcQuant AST.Forall = return Forall+tcQuant AST.Exists = return Exists+tcQuant (AST.QuantAnti a) = $(AST.antifail)++-- | Type check a type pattern. Returns the internal pattern and a list+-- of type variables, each specifying whether it is a row variable.+tcTyPat ∷ MonadConstraint tv r m ⇒+ Γ tv → AST.TyPat R → m (TyPat, [(AST.TyVar R, Bool)])+tcTyPat γ = runWriterT . loop where+ loop tp0 = withLocation tp0 $ case tp0 of+ AST.N _ (AST.TpVar tv _) → do+ tell [(tv, False)]+ return (TpVar (Here (AST.idName tv)))+ AST.N _ (AST.TpRow tv _) → do+ tell [(tv, True)]+ return (TpRow (Here (AST.idName tv)))+ [tpQ| ($list:tps) $qtid:n |] → do+ tc ← γ !.! n+ tassert (isNothing (tcNext tc)) $+ [msg| In type operator pattern, the type constructor to+ be matched is also a type operator:+ <dl>+ <dt>In pattern: <dd> $tp0+ <dt>Type constructor: <dd> $1+ </dl>+ Type constructors in type patterns must be abstract types+ or concrete data types, not type synonyms or operators.+ |] (tcName tc)+ TpApp tc <$> mapM loop tps+ [tpQ| $antiP:a |] → $(AST.antifail)+
− src/Syntax.hs
@@ -1,140 +0,0 @@-{-# LANGUAGE- RankNTypes,- TemplateHaskell,- TypeFamilies,- TypeSynonymInstances #-}--------------------------------------------------------------------------------- |--- This module provides syntax and basic syntax operations for--- the implementation of the language from the paper "Stateful Contracts--- for Affine Types".-----------------------------------------------------------------------------------module Syntax (- -- * Identifiers- module Syntax.Anti,- module Syntax.POClass,- module Syntax.Notable,- module Syntax.Ident,- module Syntax.Kind,- module Syntax.Type,- module Syntax.Lit,- module Syntax.Patt,- module Syntax.Expr,- module Syntax.Decl,- module Syntax.SyntaxTable,-- -- * Unfold syntax to lists- unfoldExAbs, unfoldTyQu, unfoldTyMu,- unfoldExTApp, unfoldExApp, unfoldTyFun,- unfoldTupleExpr, unfoldTuplePatt, unfoldSeWith,-- -- * Miscellany- module Viewable-) where--import Syntax.Anti-import Syntax.POClass-import Syntax.Notable-import Syntax.Ident-import Syntax.Kind-import Syntax.Type-import Syntax.Lit-import Syntax.Patt-import Syntax.Expr-import Syntax.Decl-import Syntax.SyntaxTable--import Util-import Viewable--deriveAntibles syntaxTable---- These should be generated:-instance Antible (Prog i) where- injAnti _ = error "BUG! injAnti: Cannot inject into Prog"- prjAnti = const Nothing- dictOf = const noAntis--instance Antible (Ident i) where- injAnti = J [] . Var . injAnti- prjAnti (J [] (Var l)) = prjAnti l- prjAnti _ = Nothing- dictOf = const idAntis--instance Antible (QLid i) where- injAnti = J [] . injAnti- prjAnti (J [] i) = prjAnti i- prjAnti _ = Nothing- dictOf = const qlidAntis--instance Antible (QUid i) where- injAnti = J [] . injAnti- prjAnti (J [] i) = prjAnti i- prjAnti _ = Nothing- dictOf = const quidAntis---- Unfolding various sequences---- | Get the list of formal parameters and body of a--- lambda/typelambda expression-unfoldExAbs :: Expr i -> ([Either (Patt i, Type i) (TyVar i)], Expr i)-unfoldExAbs = unscanr each where- each e = case view e of- ExAbs x t e' -> Just (Left (x, t), e')- ExTAbs tv e' -> Just (Right tv, e')- _ -> Nothing---- | Get the list of formal parameters and body of a qualified type-unfoldTyQu :: Quant -> Type i -> ([TyVar i], Type i)-unfoldTyQu u = unscanr each where- each (N _ (TyQu u' x t)) | u == u' = Just (x, t)- each _ = Nothing---- | Get the list of mu-bound tvs of a recursive type-unfoldTyMu :: Type i -> ([TyVar i], Type i)-unfoldTyMu = unscanr each where- each (N _ (TyMu x t)) = Just (x, t)- each _ = Nothing---- | Get the list of actual parameters and body of a type application-unfoldExTApp :: Expr i -> ([Type i], Expr i)-unfoldExTApp = unscanl each where- each e = case view e of- ExTApp e' t -> Just (t, e')- _ -> Nothing---- | Get the list of actual parameters and body of a value application-unfoldExApp :: Expr i -> ([Expr i], Expr i)-unfoldExApp = unscanl each where- each e = case view e of- ExApp e1 e2 -> Just (e2, e1)- _ -> Nothing---- | Get the list of argument types and result type of a function type-unfoldTyFun :: Type i -> ([Type i], Type i)-unfoldTyFun = unscanr each where- each (N _ (TyFun _ ta tr)) = Just (ta, tr)- each _ = Nothing---- | Get the elements of a tuple as a list-unfoldTupleExpr :: Expr i -> ([Expr i], Expr i)-unfoldTupleExpr = unscanl each where- each e = case view e of- ExPair e1 e2 -> Just (e2, e1)- _ -> Nothing---- | Get the elements of a tuple pattere as a list-unfoldTuplePatt :: Patt i -> ([Patt i], Patt i)-unfoldTuplePatt = unscanl each where- each p = case view p of- PaPair p1 p2 -> Just (p2, p1)- _ -> Nothing---- | Get all the "with type" clauses on a signature expression-unfoldSeWith :: SigExp i -> ([(QLid i, [TyVar i], Type i)], SigExp i)-unfoldSeWith = unscanl each where- each p = case view p of- SeWith se ql tvs t -> Just ((ql, tvs, t), se)- _ -> Nothing
− src/Syntax/Anti.hs
@@ -1,378 +0,0 @@-{-# LANGUAGE- DeriveDataTypeable,- FlexibleContexts,- FlexibleInstances,- PatternGuards,- RankNTypes,- TemplateHaskell #-}-module Syntax.Anti (- -- * Representation of antiquotes- Anti(..),- -- ** Raising errors when encountering antiquotes- AntiFail(..), AntiError(..),- -- * Generic anti projection/injection- Antible(..), deriveAntibles,- -- * Generic location expansion- LocAst(..), deriveLocAsts,- -- * Antiquote expansion- -- ** Generic expander construction- expandAntibles, expandAntible, expandAntibleType,- -- * Syntax classes and antiquote tables- -- ** Antiquote tables- -- *** Types- AntiDict, PreTrans, Trans(..),- -- *** Constructors- (=:), (=:!), (=:<), (&),- -- ** Syntax classs- -- *** Types- SyntaxClass(..), SyntaxTable,- -- *** Constructors- (=::), ($:), (!:), (>:)-) where--import Loc as Loc-import Meta.THHelpers-import Syntax.Notable-import Util--import Data.Generics (Typeable, Data, extQ)-import Data.List (elemIndex)-import qualified Data.Map as M-import Language.Haskell.TH as TH------- Representation of antiquotes-----data Anti = Anti {- anType :: String,- anName :: String- }- deriving (Eq, Ord, Typeable, Data)--instance Show Anti where- show (Anti "" aid) = '$' : aid- show (Anti atag aid) = '$' : atag ++ ':' : aid--class AntiFail a where- antifail :: a--instance Monad m => AntiFail (String -> Anti -> m b) where- antifail who what = fail $- "BUG! " ++ who ++ ": encountered antiquote " ++ show what--instance AntiFail (Name -> TH.ExpQ) where- antifail a = do- loc <- TH.location- [| antifail $(stringE (show (fromTHLoc loc))) $(varE a) |]--instance AntiFail (TH.Q TH.Exp) where- antifail = antifail (mkName "a")--class AntiError a where- antierror :: a--instance AntiError (String -> Anti -> b) where- antierror who what = error $- "BUG! " ++ who ++ ": encountered antiquote " ++ show what--instance AntiError (Name -> TH.ExpQ) where- antierror a = do- loc <- TH.location- [| antierror $(stringE (show (fromTHLoc loc))) $(varE a) |]--instance AntiError (TH.Q TH.Exp) where- antierror = antierror (mkName "a")--class Antible a where- injAnti :: Anti -> a- prjAnti :: a -> Maybe Anti- dictOf :: a -> AntiDict-- injAntiList :: Anti -> [a]- prjAntiList :: [a] -> Maybe Anti- dictOfList :: [a] -> AntiDict-- injAntiList = return . injAnti- prjAntiList [a] = prjAnti a- prjAntiList _ = Nothing- dictOfList = const listAntis--instance Antible a => Antible [a] where- injAnti = injAntiList- prjAnti = prjAntiList- dictOf = dictOfList--instance Antible a => Antible (Maybe a) where- injAnti = return . injAnti- prjAnti = (prjAnti =<<)- dictOf = const optAntis--optAntis, listAntis :: AntiDict--listAntis - = "list" =: Nothing- & "nil" =: Just (\_ -> conS '[] [])- & "list1" =: Just (\v -> listS [varS (TH.mkName v) []])--optAntis- = "opt" =: Nothing- & "some" =:< 'Just- & "none" =: Just (\_ -> conS 'Nothing [])--------- Deriving antiquotes-------- Given the syntax table, we need to derive instances of Antible--- and antiquoters-deriveAntibles :: SyntaxTable -> TH.Q [TH.Dec]-deriveAntibles = concatMapM each where- each SyntaxClass { scDict = Nothing } = return []- each sc@SyntaxClass { scDict = Just dict } = do- TH.TyConI tc <- reify (scName sc)- tvs <- case tc of- TH.DataD _ _ tvs _ _ -> return tvs- TH.NewtypeD _ _ tvs _ _ -> return tvs- TH.TySynD _ tvs _ -> return tvs- _ -> fail "deriveAntibles requires type"- a <- TH.newName "a"- let wrapper p = case scWrap sc of- Nothing -> p- Just _ -> TH.conP 'N [TH.wildP, p]- [InstanceD context hd decs] <-- [d| instance Antible $(foldl TH.appT (TH.conT (scName sc))- (map typeOfTyVarBndr tvs)) where- injAnti = $(varE (maybe 'id id (scWrap sc)))- . $(conE (scAnti sc))- prjAnti stx = $(caseE [| stx |] [- match (wrapper (TH.conP (scAnti sc) [TH.varP a]))- (TH.normalB [| Just $(TH.varE a) |])- [],- match TH.wildP- (TH.normalB [| Nothing |])- []- ])- dictOf _ = $(varE dict)- injAntiList = return . injAnti- prjAntiList [b] = prjAnti b- prjAntiList _ = Nothing- dictOfList = const listAntis- |]- context' <- buildContext tvs (scCxt sc)- return [InstanceD (context' ++ context) hd decs]------- Location expanders-----class LocAst stx where- toLocAstQ :: ToSyntax ast => TH.Name -> stx -> TH.Q ast--deriveLocAst :: Name -> SyntaxClass -> TH.Q [TH.Dec]-deriveLocAst _ SyntaxClass { scWrap = Nothing } = return []-deriveLocAst build SyntaxClass { scName = name, scCxt = context } = do- info <- reify name- case info of- -- Located t i- TyConI (TySynD _ _ (AppT (AppT _ (ConT _)) _)) ->- thenNote ''LocNote- -- N (note i) (t i)- TyConI (TySynD _ _ (AppT (AppT _ (AppT (ConT note) _))- (AppT (ConT _) _))) ->- thenNote note- _ -> return []- where- --- thenNote note = do- info <- reify note- case info of- TyConI (DataD _ _ _ [con] _) -> thenCon con- TyConI (NewtypeD _ _ _ con _) -> thenCon con- _ -> runIO (print (name, info)) >> return []- --- thenCon (ForallC _ _ con) = thenCon con- thenCon (InfixC st1 dcon st2) = thenDCon dcon [snd st1, snd st2]- thenCon (NormalC dcon sts) = thenDCon dcon (map snd sts)- thenCon (RecC dcon vsts) = thenDCon dcon [t | (_,_,t) <- vsts]- --- thenDCon dcon ts- | Just ix <- elemIndex (ConT ''Loc.Loc) ts = do- i <- newName "i"- [InstanceD [] hd decls] <-- [d| instance LocAst ($(conT name) $(varT i)) where- toLocAstQ loc stx =- do- let _ignore = $(stringE (show name))- ast <- $(varE build) stx- case ast of- VarE _ -> return ast- _ -> varS $(stringE (show 'setLoc))- [return ast, varS loc []]- `whichS'`- do- let pat preAstQ =- conS $(stringE (show 'N))- [ conS $(stringE (show dcon))- $(listE [ if j == ix- then [| varS loc [] |]- else [| wildS |]- | j <- [0 .. length ts - 1] ])- , preAstQ ]- ast <- $(varE build) stx- case ast of- VarP v -> asP v (pat wildP)- ConP _ [_, preAst] -> pat (return preAst)- _ -> fail $- "BUG! toLocAstQ did not recognize " ++- "expanded code: " ++ show ast- |]- context' <- buildContext [PlainTV i] ((''Data, [0]) : context)- return [InstanceD context' hd decls]- | otherwise = return []--deriveLocAsts :: Name -> SyntaxTable -> TH.Q [TH.Dec]-deriveLocAsts name = concatMapM (deriveLocAst name)------- Antiquote expanders-----expandAntibles :: [Name] -> Name -> SyntaxTable -> ExpQ-expandAntibles params name = foldr each [| id |] where- each sc rest = [| $(expandAntible params name sc) . $rest |]--expandAntible :: [Name] -> Name -> SyntaxClass -> ExpQ-expandAntible params build SyntaxClass { scName = name, scWrap = wrap } = do- info <- reify name- case info of- TyConI (DataD _ _ [_] _ _) -> expandAntible1 params build wrap name- TyConI (NewtypeD _ _ [_] _ _) -> expandAntible1 params build wrap name- TyConI (TySynD _ [_] _) -> expandAntible1 params build wrap name- _ -> expandAntible0 build wrap name--expandAntible0 :: Name -> Maybe Name -> Name -> ExpQ-expandAntible0 build maybeWrap typeName =- [| $(expandAntibleType build maybeWrap [t| $_t |]) |]- where _t = conT typeName--expandAntible1 :: [Name] -> Name -> Maybe Name -> Name -> ExpQ-expandAntible1 params build maybeWrap typeName =- foldr (\a b -> [| $a . $b |]) [| id |]- [ expandAntibleType build maybeWrap [t| $_t $(conT _p) |]- | _p <- params ]- where _t = conT typeName--expandAntibleType :: Name -> Maybe Name -> TypeQ -> ExpQ-expandAntibleType build maybeWrap _t =- let main = case maybeWrap of- Nothing ->- [| \x -> expandAntiFun (x:: $_t) |]- Just wrap ->- [| \x -> expandWrappedAntiFun- $(varE build)- (mkName $(stringE (show wrap)))- (x:: $_t) |]- in- [| (`extQ` $main)- . (`extQ` (\x -> expandAntiFun (x:: Maybe $_t)))- . (`extQ` (\x -> expandAntiFun (x:: [$_t]))) |]--expandWrappedAntiFun :: (Antible (N note a), ToSyntax b) =>- (a -> Q b) -> Name -> N note a -> Maybe (Q b)-expandWrappedAntiFun build wrap stx =- Just $ case prjAnti stx of- Just (Anti tag name) -> case M.lookup tag (dictOf stx) of- Just (Trans trans) -> case trans of- Just f -> doWrap (f name)- Nothing -> varS name []- Nothing -> fail $- "Unrecognized antiquote tag: `" ++ tag ++ "'"- Nothing -> doWrap (build (dataOf stx))- where- doWrap preStx = varS wrap [preStx] `whichS` conS 'N [wildS, preStx]--expandAntiFun :: (Antible a, ToSyntax b) => a -> Maybe (Q b)-expandAntiFun stx = do- Anti tag name <- prjAnti stx- case M.lookup tag (dictOf stx) of- Just trans -> return $ case unTrans trans of- Just f -> f name- Nothing -> varS name []- Nothing -> fail $ "Unrecognized antiquote tag: `" ++ tag ++ "'"------- Antiquote and syntax table------- | A pat/exp-generic parser-type PreTrans = forall b. ToSyntax b => Maybe (String -> Q b)--- | A pat/exp-generic parser, wrapped-newtype Trans = Trans { unTrans :: PreTrans }--- | A dictionary mapping antiquote tags to parsers-type AntiDict = M.Map String Trans---- | A descriptor for a syntactic category, used for generating--- antiquotes-data SyntaxClass = SyntaxClass {- scName :: Name,- -- | The name of the constructor for antiquotes- scAnti :: Name,- -- | The safe injection from the underlying type to the main type- scWrap :: Maybe Name,- -- | The dictionary of splice tags- scDict :: Maybe Name,- -- | Type class context required for wrapping- scCxt :: [(Name, [Int])]-}--type SyntaxTable = [SyntaxClass]---- | Construct a single syntax class from the type name and antiquote--- constructor-(=::) :: TH.Name -> TH.Name -> SyntaxClass-name =:: anti = SyntaxClass {- scName = name,- scAnti = anti,- scWrap = Nothing,- scDict = Nothing,- scCxt = []-}---- | Extend a syntax class with the name of a function that lifts--- from pre-syntax to syntax-(!:) :: SyntaxClass -> TH.Name -> SyntaxClass-tab !: name = tab { scWrap = Just name }---- | Extend a syntax class with the name of an antiquote dictionary-($:) :: SyntaxClass -> TH.Name -> SyntaxClass-tab $: dict = tab { scDict = Just dict }---- | Extend a syntax class with a context-(>:) :: SyntaxClass -> (Name, [Int]) -> SyntaxClass-tab >: context = tab { scCxt = context : scCxt tab }--infixl 2 =::, !:, $:, >:---- | Append two antiquote dictionaries-(&) :: AntiDict -> AntiDict -> AntiDict-(&) = M.union--infixr 1 &---- | Construct a singleton antiquote dictionary from a key and--- generic parser-(=:) :: String -> PreTrans -> AntiDict-a =: b = M.singleton a (Trans b)---- | Create singleton dictionary with default (tagless) entry-(=:!) :: String -> PreTrans -> AntiDict-a =:! b = M.union ("" =: b) (a =: b)---- | Construct an antiquote dictionary for matching a--- simple constructor-(=:<) :: String -> TH.Name -> AntiDict-a =:< n = a =: Just (\v -> conS n [varS v []])--infix 2 =:, =:!, =:<-
+ src/Syntax/Construction.hs view
@@ -0,0 +1,267 @@+-- | Utilities for constructing syntax+module Syntax.Construction (+ -- * Generic tuple building+ ToTuple(..),+ -- * Optimizing expression constructors+ exLet', exLetVar', exAbs', exAbsVar',+ -- * Substitution+ substExpr,+) where++import Util+import AST+import Data.Loc+import Meta.Quasi++import Prelude ()+import Data.Map as M+import Data.Generics (Data, everywhere, mkT)++-- | Constructs a let expression, but with a special case:+--+-- @let x = e in x == e@+-- @let (x, y) = e in (x, y) == e@+-- @let x = v in e == [v/x]e@+--+-- This is always safe to do.+exLet' :: Tag i => Patt i -> Expr i -> Expr i -> Expr i+exLet' π e1 e2+ | π -==+ e2 = e1+ -- This case can cause code bloat:+ | [pa| $vid:x |] ← π+ , syntacticValue e1 = substExpr e1 (J [] x) e2+ | [pa| $vid:x |] ← π+ , qx ← J [] x+ , nextRedex qx e2+ , M.lookup qx (fv e2) == Just 1+ = substExpr e1 (J [] x) e2+ | otherwise = exLet π e1 e2++-- | Constructs a let expression whose pattern is a variable.+exLetVar' :: Tag i => VarId i -> Expr i -> Expr i -> Expr i+exLetVar' = exLet' . paVar++-- | Constructs a lambda expression, but with a special case:+--+-- @exAbs' x (exApp (exVar f) x) == exVar f@+-- @exAbs' (x,y) (exApp (exVar f) (x,y)) == exVar f@+--+-- This eta-contraction is always safe, because f has no effect+exAbs' :: Tag i => Patt i -> Expr i -> Expr i+exAbs' x e = case view e of+ ExApp e1 e2 -> case view e1 of+ ExVar (J p f) | x -==+ e2+ -> exVar (J p f)+ _ -> exAbs x e+ _ -> exAbs x e++-- | Construct an abstraction whose pattern is just a variable.+exAbsVar' :: Tag i => VarId i -> Expr i -> Expr i+exAbsVar' = exAbs' . paVar++-- | Does a pattern exactly match an expression? That is, is+-- @let p = e1 in e@ equivalent to @e1@? Note that we cannot+-- safely handle data constructors, because they may fail to match.+(-==+) :: Tag i => Patt i -> Expr i -> Bool+p -==+ e = case (dataOf p, dataOf e) of+ (PaVar l, ExVar (J [] l'))+ -> l == l'+ (PaCon (J [] (ConId (Uid _ "()"))) Nothing,+ ExCon (J [] (ConId (Uid _ "()"))) Nothing)+ -> True+ (PaPair p1 p2, ExPair e1 e2)+ -> p1 -==+ e1 && p2 -==+ e2+ _ -> False+infix 4 -==+++-- Does the given variable appear where the next redex would be+-- for the expression, if a substitution were made? This, along with+-- linearity (a separate check) makes it safe to substitute any expression+-- for it.+nextRedex ∷ Tag i ⇒ QVarId i → Expr i → Bool+nextRedex x = loop where+ e1 >*> b2 = loop e1+ || syntacticValue e1+ && x `M.notMember` fv e1+ && b2+ loop e = case e of+ [ex| $qvid:x' |] → x == x'+ [ex| $lit:_ |] → False+ [ex| $qcid:_ $opt:me |] → maybe False loop me+ [ex| let $vid:x' = $e1 in $e2 |]+ | J [] x' == x → loop e1+ | otherwise → e1 >*> loop e2+ [ex| let $_ = $e1 in $_ |] → loop e1+ [ex| match $e0 with $list:_ |]+ → loop e0+ [ex| let rec $list:bns in $e2 |]+ → x `M.notMember` fv bns+ && x ∉ qdv bns+ && loop e2+ [ex| let $decl:_ in $_ |] → False+ [ex| ($e1, $e2) |] → e1 >*> loop e2+ [ex| λ $_ → $_ |] → False+ [ex| $e1 $e2 |] → e1 >*> loop e2+ [ex| `$uid:_ $opt:me2 |] → maybe False loop me2+ [ex| #$uid:_ $e2 |] → loop e2+ [ex| { $list:flds | $e2 } |]+ → foldr (>*>) (loop e2)+ (fdexpr . view <$> flds)+ [ex| {+ $list:_ | $e2 +} |] → loop e2+ [ex| $e1.$uid:_ |] → loop e1+ [ex| $e1 : $_ |] → loop e1+ [ex| $e1 :> $_ |] → loop e1+ [ex| $anti:a |] → $antierror++-- Substitute an expression for a variable+substExpr ∷ Tag i ⇒ Expr i → QVarId i → Expr i → Expr i+substExpr e' x' = loop where+ fv_e' = [ x | J [] x ← M.keys (fv e') ]+ loop e = case e of+ [ex| $qvid:x |]+ | x == x' → e'+ | otherwise → e+ [ex| $lit:_ |] → e+ [ex| $qcid:c $opt:me |] → [ex| $qcid:c $opt:me' |]+ where me' = loop <$> me+ [ex| let $π = $e1 in $e2 |]+ | x' ∈ qdv π → [ex| let $π = $e1' in $e2 |]+ | otherwise → [ex| let $π' = $e1' in $e2' |]+ where e1' = loop e1+ (π', e2'0) = avoidCapture fv_e' x' π e2+ e2' = loop e2'0+ [ex| match $e0 with $list:cas |]+ → [ex| match $e0' with $list:cas' |]+ where e0' = loop e0+ cas' = substCaseAlt e' x' <$> cas+ [ex| let rec $list:bns in $e2 |]+ | x' ∈ (J [] <$> fs) → [ex| let rec $list:bns' in $e2 |]+ where fs = [ fi | [bnQ|! $vid:fi = $_ |] ← bns ]+ bns' = substBinding e' x' <$> bns+ [ex| let rec $list:bns in $e2 |]+ | otherwise → [ex| let rec $list:bns' in $e2' |]+ where+ (fs, es) = unzip [ (fi, ei) | [bnQ|! $vid:fi = $ei |] ← bns ]+ (fs', renamer) = avoidCapture' fv_e' x' fs (e2:es)+ bns' = reverse (fst (foldl' eachBn ([], fs') bns))+ e2' = loop (renamer e2)+ eachBn (acc, fi':rest) [bnQ| $vid:_ = $ei |]+ = ([bnQ| $vid:fi' = $ei' |]:acc, rest)+ where ei' = loop (renamer ei)+ eachBn (acc, rest) bn@[bnQ| $antiB:_ |]+ = (bn:acc, rest)+ eachBn _ _ =+ error "BUG in substExpr: Inconsistency in number of let rec bindings"+ [ex| let $decl:d in $e2 |] → [ex| let $decl:d in $e2' |]+ where e2' = loop e2 -- Doesn't handle d+ [ex| ($e1, $e2) |] → [ex| ($e1', $e2') |]+ where e1' = loop e1+ e2' = loop e2+ [ex| λ $π1 → $e2 |]+ | x' ∈ qdv π1 → e+ | otherwise → [ex| λ $π1' → $e2' |]+ where (π1', e2') = second loop+ $ avoidCapture fv_e' x' π1 e2+ [ex| $e1 $e2 |] → [ex| $e1' $e2' |]+ where e1' = loop e1+ e2' = loop e2+ [ex| `$uid:c $opt:me2 |] → [ex| `$uid:c $opt:me2' |]+ where me2' = loop <$> me2+ [ex| #$uid:c $e2 |] → [ex| #$uid:c $e2' |]+ where e2' = loop e2+ [ex| { $list:flds | $e2 } |]+ → [ex| { $list:flds' | $e2' } |]+ where flds' = substField e' x' <$> flds+ e2' = loop e2+ [ex| {+ $list:flds | $e2 +} |]+ → [ex| {+ $list:flds' | $e2' +} |]+ where flds' = substField e' x' <$> flds+ e2' = loop e2+ [ex| $e1.$uid:u |] → [ex| $e1'.$uid:u |]+ where e1' = loop e1+ [ex| $e1 : $annot |] → [ex| $e1' : $annot |]+ where e1' = loop e1+ [ex| $e1 :> $annot |] → [ex| $e1' : $annot |]+ where e1' = loop e1+ [ex| $anti:_ |] → e++substCaseAlt ∷ Tag i ⇒ Expr i → QVarId i → CaseAlt i → CaseAlt i+substCaseAlt e' x' ca = case ca of+ [caQ| $π1 → $e2 |]+ | x' ∈ qdv π1 → ca+ | otherwise → [caQ| $π1' → $e2' |]+ where (π1', e2') = second (substExpr e' x')+ $ avoidCapture [ x | J [] x ← M.keys (fv e') ]+ x' π1 e2+ [caQ| #$uid:c → $e2 |] → [caQ| #$uid:c → $e2' |]+ where e2' = substExpr e' x' e2+ [caQ| #$uid:c $π1 → $e2 |]+ | x' ∈ qdv π1 → ca+ | otherwise → [caQ| #$uid:c $π1' → $e2' |]+ where (π1', e2') = second (substExpr e' x')+ $ avoidCapture [ x | J [] x ← M.keys (fv e') ]+ x' π1 e2+ [caQ| $antiC:_ |] → ca++substBinding ∷ Tag i ⇒ Expr i → QVarId i → Binding i → Binding i+substBinding e' x' bn = case bn of+ [bnQ| $vid:f = $e2 |]+ | x' == J [] f → bn+ | otherwise → [bnQ| $vid:f' = $e2' |]+ where+ (f', e2') = second (substExpr e' x')+ $ avoidCapture [ x | J [] x ← M.keys (fv e') ]+ x' f e2+ [bnQ| $antiB:_ |] → bn++substField ∷ Tag i ⇒ Expr i → QVarId i → Field i → Field i+substField e' x' fld = case fld of+ [fdQ| $uid:u = $e2 |] → [fdQ| $uid:u = $e2' |]+ where e2' = substExpr e' x' e2+ [fdQ| $antiF:_ |] → fld++-- | Given a list of names not to capture, the variable being+-- substituted, a pattern, and an expression+-- in the scope of the pattern, rename the pattern and expression+-- together so that it's safe to substitute the names under the pattern.+avoidCapture ∷ (Data a, Dv a i, Tag i) ⇒+ [VarId i] → QVarId i → a → Expr i → (a, Expr i)+avoidCapture fv_e' x' π e = second ($ e) (avoidCapture' fv_e' x' π e)++-- | Given a list of names not to capture, the variable being+-- substituted, a pattern, and an expression+-- in the scope of the pattern, rename the pattern and expression+-- together so that it's safe to substitute the names under the pattern.+avoidCapture' ∷ (Data a, Dv a i, Fv b i, Tag i) ⇒+ [VarId i] → QVarId i → a → b → (a, Expr i → Expr i)+avoidCapture' fv_e' x' π e+ | x' ∈ qdv π || x' `M.notMember` fv e = (π, id)+ | otherwise = (π', r)+ where+ fv_e = [ idName x | J [] x ← M.keys (fv e) ]+ vs = dv π ∩ fv_e'+ vs' = ident <$> freshNames (Just . idName <$> vs)+ (fv_e ++ (idName <$> fv_e')) []+ π' = foldr2 (\v v' → renameGeneric v' v) π vs vs'+ r e' = foldr2 (\v v' → substExpr (exBVar v') (J [] v)) e' vs vs'++-- | Rename a variable+renameGeneric ∷ (Tag i, Data a) ⇒ VarId i → VarId i → a → a+renameGeneric x' x = everywhere (mkT each) where+ each y | x == y = x'+ each a = a++---+--- GENERIC TUPLING+---++class ToTuple a b c where+ (-*-) ∷ a → [b] → c++infixl 3 -*-++instance (Tag i, ToPatt a i, ToPatt b i) ⇒ ToTuple a b (Patt i) where+ π -*- πs = foldl' paPair (toPatt π) (toPatt <$> πs)++instance (Tag i, ToExpr a i, ToExpr b i) ⇒ ToTuple a b (Expr i) where+ π -*- πs = foldl' exPair (toExpr π) (toExpr <$> πs)
− src/Syntax/Decl.hs
@@ -1,331 +0,0 @@-{-# LANGUAGE- DeriveDataTypeable,- FlexibleInstances,- MultiParamTypeClasses,- StandaloneDeriving,- TemplateHaskell,- TypeFamilies,- TypeSynonymInstances #-}-module Syntax.Decl (- -- * Declarations- Decl'(..), Decl, DeclNote(..), newDecl,- -- ** Type declarations- TyDec'(..), TyDec, AbsTy'(..), AbsTy,- -- ** Modules- ModExp'(..), ModExp, newModExp,- -- ** Signature- SigExp'(..), SigExp, newSigExp,- SigItem'(..), SigItem, newSigItem,- -- ** Synthetic constructors- -- | These fill in the source location fields with a bogus location- dcLet, dcTyp, dcAbs, dcMod, dcSig, dcOpn, dcLoc, dcExn, dcAnti,- absTy, absTyAnti,- tdAbs, tdSyn, tdDat, tdAnti,- meStr, meName, meAsc, meAnti,- sgVal, sgTyp, sgMod, sgSig, sgInc, sgExn, sgAnti,- seSig, seName, seWith, seAnti,- prog,-- -- * Programs- Prog'(..), Prog,- prog2decls-) where--import Meta.DeriveNotable-import Syntax.Notable-import Syntax.Anti-import Syntax.Kind-import Syntax.Ident-import Syntax.Type-import Syntax.Patt-import Syntax.Expr--import Data.Generics (Typeable(..), Data(..))-import qualified Data.Set as S-import qualified Data.Map as M--type Decl i = N (DeclNote i) (Decl' i)-type ModExp i = N (DeclNote i) (ModExp' i)-type SigItem i = N (DeclNote i) (SigItem' i)-type SigExp i = N (DeclNote i) (SigExp' i)-type Prog i = Located Prog' i-type AbsTy i = Located AbsTy' i-type TyDec i = Located TyDec' i---- | A program is a sequence of declarations, maybe followed by an--- expression-data Prog' i = Prog [Decl i] (Maybe (Expr i))- deriving (Typeable, Data)---- | Declarations-data Decl' i- -- | Constant declaration- = DcLet (Patt i) (Maybe (Type i)) (Expr i)- -- | Type declaration- | DcTyp [TyDec i]- -- | Abstype block declaration- | DcAbs [AbsTy i] [Decl i]- -- | Module declaration- | DcMod (Uid i) (ModExp i)- -- | Signature declaration- | DcSig (Uid i) (SigExp i)- -- | Module open- | DcOpn (ModExp i)- -- | Local block- | DcLoc [Decl i] [Decl i]- -- | Exception declaration- | DcExn (Uid i) (Maybe (Type i))- -- | Antiquote- | DcAnti Anti- deriving (Typeable, Data)---- | A module expression-data ModExp' i- -- | A module literal- = MeStr [Decl i]- -- | A module variable- | MeName (QUid i) [QLid i]- -- | A signature ascription- | MeAsc (ModExp i) (SigExp i)- -- | An antiquote- | MeAnti Anti- deriving (Typeable, Data)---- | A signature item-data SigItem' i- -- | A value- = SgVal (Lid i) (Type i)- -- | A type- | SgTyp [TyDec i]- -- | A module- | SgMod (Uid i) (SigExp i)- -- | A signature- | SgSig (Uid i) (SigExp i)- -- | Signature inclusion- | SgInc (SigExp i)- -- | An exception- | SgExn (Uid i) (Maybe (Type i))- -- | An antiquote- | SgAnti Anti- deriving (Typeable, Data)---- | A module type expression-data SigExp' i- -- | A signature literal- = SeSig [SigItem i]- -- | A signature variable- | SeName (QUid i) [QLid i]- -- | Type-level fibration- | SeWith (SigExp i) (QLid i) [TyVar i] (Type i)- -- | An antiquote- | SeAnti Anti- deriving (Typeable, Data)---- | Affine language type declarations-data TyDec' i- -- | An abstract (empty) type- = TdAbs {- tdName :: Lid i,- tdParams :: [TyVar i],- -- | The variance of each parameter- tdVariances :: [Variance],- -- | Whether each parameter contributes to the qualifier- tdQual :: QExp i- }- -- | A type operator or synonym- | TdSyn {- tdName :: Lid i,- tdClauses :: [([TyPat i], Type i)]- }- -- | An algebraic datatype- | TdDat {- tdName :: Lid i,- tdParams :: [TyVar i],- tdAlts :: [(Uid i, Maybe (Type i))]- }- | TdAnti Anti- deriving (Typeable, Data)---- | An abstract type needs to specify variances and the qualifier-data AbsTy' i- = AbsTy {- atvariance :: [Variance],- atquals :: QExp i,- atdecl :: TyDec i- }- | AbsTyAnti Anti- deriving (Typeable, Data)--data DeclNote i- = DeclNote {- -- | source location- dloc_ :: !Loc,- -- | free variables- dfv_ :: FvMap i,- -- | defined variables- ddv_ :: S.Set (QLid i)- }- deriving (Typeable, Data)--instance Locatable (DeclNote i) where- getLoc = dloc_--instance Relocatable (DeclNote i) where- setLoc note loc = note { dloc_ = loc }--instance Notable (DeclNote i) where- newNote = DeclNote bogus M.empty S.empty--newDecl :: Id i => Decl' i -> Decl i-newDecl d0 = flip N d0 $ case d0 of- DcLet p1 t2 e3 ->- newNote {- dloc_ = getLoc (p1, t2, e3),- dfv_ = fv e3,- ddv_ = qdv p1- }- DcTyp tds ->- newNote {- dloc_ = getLoc tds- }- DcAbs at1 ds2 ->- newNote {- dloc_ = getLoc (at1, ds2),- dfv_ = fv ds2,- ddv_ = S.unions (map qdv ds2)- }- DcMod u1 me2 ->- newNote {- dloc_ = getLoc me2,- dfv_ = fv me2,- ddv_ = S.mapMonotonic (\(J p n) -> J (u1:p) n) (qdv me2)- }- DcSig _ se2 ->- newNote {- dloc_ = getLoc se2- }- DcOpn me1 ->- newNote {- dloc_ = getLoc me1,- dfv_ = fv me1,- ddv_ = qdv me1- }- DcLoc ds1 ds2 ->- newNote {- dloc_ = getLoc (ds1, ds2),- dfv_ = fv ds1 |+| (fv ds2 |--| qdv ds1),- ddv_ = qdv ds2- }- DcExn _ t2 ->- newNote {- dloc_ = getLoc t2- }- DcAnti a ->- newNote {- dfv_ = antierror "fv" a,- ddv_ = antierror "dv" a- }--newModExp :: Id i => ModExp' i -> ModExp i-newModExp me0 = flip N me0 $ case me0 of- MeStr ds ->- newNote {- dloc_ = getLoc ds,- dfv_ = fv ds,- ddv_ = qdv ds- }- MeName _ qls ->- newNote {- ddv_ = S.fromList qls- }- MeAsc me se ->- newNote {- dloc_ = getLoc (me, se),- dfv_ = fv me,- ddv_ = qdv se- }- MeAnti a ->- newNote {- dfv_ = antierror "fv" a,- ddv_ = antierror "dv" a- }--newSigItem :: Id i => SigItem' i -> SigItem i-newSigItem d0 = flip N d0 $ case d0 of- SgVal l1 t2 ->- newNote {- dloc_ = getLoc t2,- ddv_ = S.singleton (J [] l1)- }- SgTyp tds ->- newNote {- dloc_ = getLoc tds- }- SgMod u1 se2 ->- newNote {- dloc_ = getLoc se2,- ddv_ = S.mapMonotonic (\(J p n) -> J (u1:p) n) (qdv se2)- }- SgSig _ se2 ->- newNote {- dloc_ = getLoc se2- }- SgInc se1 ->- newNote {- dloc_ = getLoc se1,- ddv_ = qdv se1- }- SgExn _ t2 ->- newNote {- dloc_ = getLoc t2- }- SgAnti a ->- newNote {- dfv_ = antierror "fv" a,- ddv_ = antierror "dv" a- }--newSigExp :: Id i => SigExp' i -> SigExp i-newSigExp se0 = flip N se0 $ case se0 of- SeSig sis ->- newNote {- dloc_ = getLoc sis,- ddv_ = qdv sis- }- SeName _ qls ->- newNote {- ddv_ = S.fromList qls- }- SeWith se1 _ _ t3 ->- newNote {- dloc_ = getLoc (se1, t3),- ddv_ = qdv se1- }- SeAnti a ->- newNote {- dfv_ = antierror "fv" a,- ddv_ = antierror "dv" a- }--instance Id i => Fv (N (DeclNote i) a) i where fv = dfv_ . noteOf-instance Id i => Dv (N (DeclNote i) a) i where qdv = ddv_ . noteOf--deriveNotable 'newDecl (''Id, [0]) ''Decl-deriveNotable 'newModExp (''Id, [0]) ''ModExp-deriveNotable 'newSigItem (''Id, [0]) ''SigItem-deriveNotable 'newSigExp (''Id, [0]) ''SigExp-deriveNotable ''AbsTy-deriveNotable ''TyDec-deriveNotable ''Prog--------- Syntax Utils-------- | Turn a program into a sequence of declarations by replacing--- the final expression with a declaration of variable 'it'.-prog2decls :: Id i => Prog i -> [Decl i]-prog2decls (N _ (Prog ds (Just e)))- = ds ++ [dcLet (paVar (lid "it")) Nothing e]-prog2decls (N _ (Prog ds Nothing))- = ds
− src/Syntax/Decl.hs-boot
@@ -1,26 +0,0 @@--- vim: ft=haskell-{-# LANGUAGE- FlexibleInstances,- MultiParamTypeClasses,- TypeFamilies,- TypeSynonymInstances #-}-{-# OPTIONS_GHC -w #-}-module Syntax.Decl where--import Syntax.Notable-import Syntax.Ident (Id, Fv, Dv)--import Data.Data (Data, Typeable1)--data DeclNote i-data Decl' i-type Decl i = N (DeclNote i) (Decl' i)--instance Typeable1 DeclNote-instance Typeable1 Decl'-instance Id i => Data (DeclNote i)-instance Id i => Data (Decl' i)-instance Locatable (DeclNote i)-instance Notable (DeclNote i)-instance Id i => Fv (N (DeclNote i) a) i-instance Id i => Dv (N (DeclNote i) a) i
− src/Syntax/Expr.hs
@@ -1,325 +0,0 @@-{-# LANGUAGE- DeriveDataTypeable,- FlexibleInstances,- MultiParamTypeClasses,- TemplateHaskell,- TypeFamilies,- TypeSynonymInstances #-}-module Syntax.Expr (- -- * Expressions- Expr'(..), Expr, ExprNote(..), newExpr,- -- ** Letrec and case- Binding'(..), Binding, newBinding,- CaseAlt'(..), CaseAlt, newCaseAlt,-- -- * Two-level expression constructors- -- | These fill in the source location field based on the- -- subexpressions and perform the free variable analysis- exId, exLit, exCase, exLetRec, exLetDecl, exPair,- exAbs, exApp, exTAbs, exTApp, exPack, exCast, exAnti,- caClause, caAnti,- bnBind, bnAnti,- -- ** Synthetic expression constructors- exVar, exCon, exBVar, exBCon,- exStr, exInt, exFloat,- exLet, exSeq,- -- ** Optimizing expression constructors- exLet', exLetVar', exAbs', exAbsVar', exTAbs',-- -- * Expression accessors and updaters- syntacticValue-) where--import Syntax.Notable-import Syntax.Anti-import Syntax.Ident-import Syntax.Type-import Syntax.Lit-import Syntax.Patt-import {-# SOURCE #-} Syntax.Decl-import Viewable--import Meta.DeriveNotable--import Data.Generics (Typeable(..), Data(..))-import qualified Data.Map as M--type Expr i = N (ExprNote i) (Expr' i)-type Binding i = N (ExprNote i) (Binding' i)-type CaseAlt i = N (ExprNote i) (CaseAlt' i)---- | The underlying expression type, which we can pattern match without--- dealing with the common fields above.-data Expr' i- -- | variables and datacons- = ExId (Ident i)- -- | literals- | ExLit Lit- -- | case expressions (including desugared @if@ and @let@)- | ExCase (Expr i) [CaseAlt i]- -- | recursive let expressions- | ExLetRec [Binding i] (Expr i)- -- | nested declarations- | ExLetDecl (Decl i) (Expr i)- -- | pair construction- | ExPair (Expr i) (Expr i)- -- | lambda- | ExAbs (Patt i) (Type i) (Expr i)- -- | application- | ExApp (Expr i) (Expr i)- -- | type abstraction- | ExTAbs (TyVar i) (Expr i)- -- | type application- | ExTApp (Expr i) (Type i)- -- | existential construction- | ExPack (Maybe (Type i)) (Type i) (Expr i)- -- | dynamic promotion (True) or static type ascription (False)- | ExCast (Expr i) (Type i) Bool- -- | antiquotes- | ExAnti Anti- deriving (Typeable, Data)---- | Let-rec bindings require us to give types-data Binding' i- = BnBind {- bnvar :: Lid i,- bntype :: Type i,- bnexpr :: Expr i- }- | BnAnti Anti- deriving (Typeable, Data)--data CaseAlt' i- = CaClause {- capatt :: Patt i,- caexpr :: Expr i- }- | CaAnti Anti- deriving (Typeable, Data)---- | The annotation on every expression-data ExprNote i- = ExprNote {- -- | source location- eloc_ :: !Loc,- -- | free variables- efv_ :: FvMap i- }- deriving (Typeable, Data)--instance Locatable (ExprNote i) where- getLoc = eloc_--instance Relocatable (ExprNote i) where- setLoc note loc = note { eloc_ = loc }---- | Types with free variable analyses-instance Id i => Fv (N (ExprNote i) a) i where fv = efv_ . noteOf--instance Notable (ExprNote i) where- newNote = ExprNote {- eloc_ = bogus,- efv_ = M.empty- }--newExpr :: Id i => Expr' i -> Expr i-newExpr e0 = flip N e0 $ case e0 of- ExId i ->- newNote {- efv_ = case view i of- Left y -> M.singleton y 1- _ -> M.empty- }- ExLit _ -> newNote- ExCase e1 cas ->- newNote {- efv_ = fv e1 |*| fv (ADDITIVE cas),- eloc_ = getLoc (e1, cas)- }- ExLetRec bns e2 ->- newNote {- efv_ = let vs = map (J [] . bnvar . dataOf) bns- pot = fv e2 |+| fv bns- in foldl (|-|) pot vs,- eloc_ = getLoc (bns, e2)- }- ExLetDecl d1 e2 ->- newNote {- efv_ = fv d1 |*| (fv e2 |--| qdv d1),- eloc_ = getLoc (d1, e2)- }- ExPair e1 e2 ->- newNote {- efv_ = fv e1 |*| fv e2,- eloc_ = getLoc (e1, e2)- }- ExAbs p1 _ e3 ->- newNote {- efv_ = fv e3 |--| qdv p1,- eloc_ = getLoc (p1, e3)- }- ExApp e1 e2 ->- newNote {- efv_ = fv e1 |*| fv e2,- eloc_ = getLoc (e1, e2)- }- ExTAbs _ e2 ->- newNote {- efv_ = fv e2,- eloc_ = getLoc e2- }- ExTApp e1 t2 ->- newNote {- efv_ = fv e1,- eloc_ = getLoc (e1, t2)- }- ExPack mt1 t2 e3 ->- newNote {- efv_ = fv e3,- eloc_ = getLoc (mt1, t2, e3)- }- ExCast e1 t2 _ ->- newNote {- efv_ = fv e1,- eloc_ = getLoc (e1, t2)- }- ExAnti a ->- newNote {- efv_ = antierror "fv" a- }--newBinding :: Id i => Binding' i -> Binding i-newBinding b0 = flip N b0 $ case b0 of- BnBind x t e ->- newNote {- efv_ = fv e |-| J [] x,- eloc_ = getLoc (t, e)- }- BnAnti a ->- newNote {- efv_ = antierror "fv" a- }--newCaseAlt :: Id i => CaseAlt' i -> CaseAlt i-newCaseAlt ca0 = flip N ca0 $ case ca0 of- CaClause x e ->- newNote {- efv_ = fv e |--| qdv x,- eloc_ = getLoc (x, e)- }- CaAnti a ->- newNote {- efv_ = antierror "fv" a- }--deriveNotable 'newExpr (''Id, [0]) ''Expr-deriveNotable 'newCaseAlt (''Id, [0]) ''CaseAlt-deriveNotable 'newBinding (''Id, [0]) ''Binding--exVar :: Id i => QLid i -> Expr i-exVar = exId . fmap Var--exCon :: Id i => QUid i -> Expr i-exCon = exId . fmap Con--exBVar :: Id i => Lid i -> Expr i-exBVar = exId . J [] . Var--exBCon :: Id i => Uid i -> Expr i-exBCon = exId . J [] . Con--exStr :: Id i => String -> Expr i-exStr = exLit . LtStr--exInt :: Id i => Integer -> Expr i-exInt = exLit . LtInt--exFloat :: Id i => Double -> Expr i-exFloat = exLit . LtFloat--exLet :: Id i => Patt i -> Expr i -> Expr i -> Expr i-exLet x e1 e2 = exCase e1 [caClause x e2]--exSeq :: Id i => Expr i -> Expr i -> Expr i-exSeq e1 e2 = exCase e1 [caClause paWild e2]---- | Constructs a let expression, but with a special case:------ @let x = e in x == e@--- @let (x, y) = e in (x, y) == e@------ This is always safe to do.-exLet' :: Id i => Patt i -> Expr i -> Expr i -> Expr i-exLet' x e1 e2 = if (x -==+ e2) then e1 else exLet x e1 e2---- | Constructs a let expression whose pattern is a variable.-exLetVar' :: Id i => Lid i -> Expr i -> Expr i -> Expr i-exLetVar' = exLet' . paVar---- | Constructs a lambda expression, but with a special case:------ @exAbs' x t (exApp (exVar f) (exVar x)) == exVar f@------ This eta-contraction is always safe, because f has no effect-exAbs' :: Id i => Patt i -> Type i -> Expr i -> Expr i-exAbs' x t e = case view e of- ExApp e1 e2 -> case (dataOf x, view e1, view e2) of- (PaVar y, ExId (J p (Var f)), ExId (J [] (Var y'))) |- y == y' && J [] y /= J p f- -> exVar (J p f)- _ -> exAbs x t e- _ -> exAbs x t e---- | Construct an abstraction whose pattern is just a variable.-exAbsVar' :: Id i => Lid i -> Type i -> Expr i -> Expr i-exAbsVar' = exAbs' . paVar---- | Construct a type-lambda expression, but with a special case:------ @exTAbs' tv (exTApp (exVar f) tv) == exVar f@------ This should always be safe, because f has no effect-exTAbs' :: Id i => TyVar i -> Expr i -> Expr i-exTAbs' tv e = case view e of- ExTApp e1 t2 -> case (view e1, dataOf t2) of- (ExId (J p (Var f)), TyVar tv') |- tv == tv' -> exVar (J p f)- _ -> exTAbs tv e- _ -> exTAbs tv e---- | Does a pattern exactly match an expression? That is, is--- @let p = e1 in e@ equivalent to @e1@? Note that we cannot--- safely handle data constructors, because they may fail to match.-(-==+) :: Id i => Patt i -> Expr i -> Bool-p -==+ e = case (dataOf p, dataOf e) of- (PaVar l, ExId (J [] (Var l')))- -> l == l'- (PaCon (J [] (Uid _ "()")) Nothing,- ExId (J [] (Con (Uid _ "()"))))- -> True- (PaPair p1 p2, ExPair e1 e2)- -> p1 -==+ e1 && p2 -==+ e2- _ -> False-infix 4 -==+---- | Is the expression conservatively side-effect free?-syntacticValue :: Expr i -> Bool-syntacticValue e = case view e of- ExId _ -> True- ExLit _ -> True- ExPair e1 e2 -> syntacticValue e1 && syntacticValue e2- ExAbs _ _ _ -> True- ExApp e1 e2 -> syntacticConstructor e1 && syntacticValue e2- ExTAbs _ _ -> True- ExTApp e1 _ -> syntacticValue e1- ExAnti a -> antierror "syntacticValue" a- _ -> False--syntacticConstructor :: Expr i -> Bool-syntacticConstructor e = case view e of- ExId (J [] (Con _)) -> True- ExTApp e1 _ -> syntacticConstructor e1- ExApp e1 e2 -> syntacticConstructor e1 && syntacticValue e2- ExAnti a -> antierror "syntacticConstructor" a- _ -> False-
− src/Syntax/Ident.hs
@@ -1,265 +0,0 @@-{-# LANGUAGE- DeriveDataTypeable,- FlexibleInstances,- FunctionalDependencies,- GeneralizedNewtypeDeriving,- MultiParamTypeClasses,- ScopedTypeVariables,- TypeFamilies,- TypeSynonymInstances,- UndecidableInstances #-}-module Syntax.Ident (- -- * Identifier classes- Id(..), Raw(..), Renamed(..), renamed0,- -- ** Dirty tricks- trivialRename, trivialRename2,- -- * Identifiers - Path(..),- Lid(..), Uid(..), BIdent(..),- Ident, QLid, QUid,- TyVar(..), tvUn, tvAf, tvalphabet,- isOperator, lid, uid, qlid, quid,- -- * Free and defined vars- FvMap, Fv(..), Dv(..), ADDITIVE(..),- (|*|), (|+|), (|-|), (|--|)-) where--import Env (Path(..), (:>:)(..))-import Util-import Viewable-import Syntax.Anti-import Syntax.Kind (QLit(..))--import Data.Char (isAlpha, isDigit)-import Data.Generics (Typeable(..), Data(..), everywhere, mkT)-import qualified Data.Map as M-import qualified Data.Set as S-import qualified Unsafe.Coerce--class Data i => Id i where- -- The trivial identity tag, used when the identity tag is- -- insufficient to distinguish different thing- trivialId :: i- -- Check for triviality- isTrivial :: i -> Bool- -- Compare two identifiers, given a secondary criterion to use if- -- necessary- compareId :: i -> i -> Ordering -> Ordering--data Raw = Raw_- deriving (Data, Typeable, Show)--newtype Renamed = Ren_ Int- deriving (Data, Typeable, Enum, Eq, Ord)--instance Show Renamed where- showsPrec p (Ren_ z) = showsPrec p z--instance Id Raw where- trivialId = Raw_- isTrivial = const True- compareId _ _ = id--instance Id Renamed where- trivialId = Ren_ 0- isTrivial (Ren_ 0) = True- isTrivial (Ren_ _) = False- compareId (Ren_ 0) (Ren_ 0) next = next- compareId (Ren_ 0) _ _ = LT- compareId _ (Ren_ 0) _ = GT- compareId (Ren_ a) (Ren_ b) _ = a `compare` b--renamed0 :: Renamed-renamed0 = Ren_ 1---- | This is super dirty-trivialRename :: forall f i j. (Id i, Id j, Data (f i)) => f i -> f j-trivialRename = Unsafe.Coerce.unsafeCoerce . everywhere (mkT each) where- each :: i -> i- each _ = Unsafe.Coerce.unsafeCoerce (trivialId :: j)--trivialRename2 :: forall f g h i j.- (Id i, Id j, Data (f (g i) (h i))) =>- f (g i) (h i) -> f (g j) (h j)-trivialRename2 = Unsafe.Coerce.unsafeCoerce . everywhere (mkT each) where- each :: i -> i- each _ = Unsafe.Coerce.unsafeCoerce (trivialId :: j)---- IDENTIFIERS---- | lowercase identifiers (variables, tycons)-data Lid i- = Lid {- lidUnique :: !i,- unLid :: !String- }- | LidAnti Anti- deriving (Typeable, Data)--instance Id i => Eq (Lid i) where- a == b = compare a b == EQ--instance Id i => Ord (Lid i) where- Lid u1 s1 `compare` Lid u2 s2 = compareId u1 u2 (compare s1 s2)- LidAnti a `compare` _ = antierror "Lid#compare" a- _ `compare` LidAnti a = antierror "Lid#compare" a---- | uppercase identifiers (modules, datacons)-data Uid i- = Uid {- uidUnique :: !i,- unUid :: !String- }- | UidAnti Anti- deriving (Typeable, Data)--instance Id i => Eq (Uid i) where- a == b = compare a b == EQ--instance Id i => Ord (Uid i) where- Uid u1 s1 `compare` Uid u2 s2 = compareId u1 u2 (compare s1 s2)- UidAnti a `compare` _ = antierror "Uid#compare" a- _ `compare` UidAnti a = antierror "Uid#compare" a---- | bare (unqualified) identifers-data BIdent i = Var { unVar :: !(Lid i) }- | Con { unCon :: !(Uid i) }- deriving (Eq, Ord, Typeable, Data)---- | path-qualified uppercase identifiers-type QUid i = Path (Uid i) (Uid i)--- | path-qualified lowecase identifiers-type QLid i = Path (Uid i) (Lid i)--- | path-qualified identifiers-type Ident i = Path (Uid i) (BIdent i)---- | Type variables include qualifiers-data TyVar i- = TV {- tvname :: !(Lid i),- tvqual :: !QLit- }- | TVAnti Anti- deriving (Eq, Ord, Typeable, Data)--lid :: Id i => String -> Lid i-lid = Lid trivialId--uid :: Id i => String -> Uid i-uid = Uid trivialId--tvUn, tvAf :: Id i => String -> TyVar i-tvUn s = TV (lid s) Qu-tvAf s = TV (lid s) Qa--tvalphabet :: Id i => [QLit -> TyVar i]-tvalphabet = map (TV . lid) alphabet- where- alphabet = map return ['a' .. 'z'] ++- [ x ++ [y] | x <- alphabet, y <- ['a' .. 'z'] ]---- | Is the lowercase identifier an infix operator?-isOperator :: Lid i -> Bool-isOperator l = case show l of- '(':_ -> True- _ -> False---- | Sugar for generating AST for qualified lowercase identifers-qlid :: Id i => String -> QLid i-qlid s = case reverse (splitBy (=='.') s) of- [] -> J [] (lid "")- x:xs -> J (map uid (reverse xs)) (lid x)---- | Sugar for generating AST for qualified uppercase identifers-quid :: Id i => String -> QUid i-quid s = case reverse (splitBy (=='.') s) of- [] -> J [] (uid "")- x:xs -> J (map uid (reverse xs)) (uid x)--instance Show (Lid i) where- showsPrec _ (Lid _ s) =- case s of- '_':_ -> (s++)- c :_ | isAlpha c -> (s++)- c :_ | isDigit c -> (s++)- _ :_ | head s == '*' || last s == '*'- -> ("( "++) . (s++) . (" )"++)- _ -> ('(':) . (s++) . (')':)- {-- . let z = Unsafe.Coerce.unsafeCoerce i :: Renamed in- if z == Unsafe.Coerce.unsafeCoerce Raw_- then id- else showChar '[' . shows z . showChar ']'- -}- showsPrec p (LidAnti a) = showsPrec p a--instance Show (Uid i) where- showsPrec _ (Uid _ s) = (s++)- showsPrec p (UidAnti a) = showsPrec p a--instance Show (BIdent i) where- showsPrec p (Var x) = showsPrec p x- showsPrec p (Con k) = showsPrec p k--instance Show (TyVar i) where- showsPrec _ (TV x Qu) = showChar '\'' . shows x- showsPrec _ (TV x Qa) = showChar '`' . shows x- showsPrec _ (TVAnti a) = showChar '\'' . shows a--instance Viewable (Path (Uid i) (BIdent i)) where- type View (Ident i) = Either (QLid i) (QUid i)- view (J p (Var n)) = Left (J p n)- view (J p (Con n)) = Right (J p n)---- | Simple keys embed into path keyspace-instance (Ord p, (:>:) k k') =>- (:>:) (Path p k) k' where liftKey = J [] . liftKey--instance Id i => (:>:) (BIdent i) (Lid i) where liftKey = Var-instance Id i => (:>:) (BIdent i) (Uid i) where liftKey = Con--------- Identifier antiquotes------------- Free variables-------- | Our free variables function returns not merely a set,--- but a map from names to a count of maximum occurrences.-type FvMap i = M.Map (QLid i) Integer---- | The free variables analysis-class Id i => Fv a i | a -> i where- fv :: a -> FvMap i---- | The defined variables analysis-class Id i => Dv a i | a -> i where- qdv :: a -> S.Set (QLid i)- dv :: a -> S.Set (Lid i)-- qdv = S.mapMonotonic (J []) . dv- dv a = S.fromDistinctAscList [ v | J [] v <- S.toAscList (qdv a) ]--instance Fv a i => Fv [a] i where- fv = foldr (|+|) M.empty . map fv--instance Dv a i => Dv [a] i where- dv = S.unions . map dv--newtype ADDITIVE a = ADDITIVE [a]--instance Fv a i => Fv (ADDITIVE a) i where- fv (ADDITIVE a) = foldr (|+|) M.empty (map fv a)---- | Used by the free variables analysis-(|*|), (|+|) :: Id i => FvMap i -> FvMap i -> FvMap i-(|*|) = M.unionWith (+)-(|+|) = M.unionWith max--(|-|) :: Id i => FvMap i -> QLid i -> FvMap i-(|-|) = flip M.delete--(|--|) :: Id i => FvMap i -> S.Set (QLid i) -> FvMap i-(|--|) = S.fold M.delete
− src/Syntax/Ident.hs-boot
@@ -1,12 +0,0 @@-module Syntax.Ident where--import Data.Data (Data, Typeable1)--class Id i--data TyVar i--instance Typeable1 TyVar-instance Data i => Data (TyVar i)-instance Id i => Ord (TyVar i)-instance Id i => Eq (TyVar i)
+ src/Syntax/ImplicitThreading.hs view
@@ -0,0 +1,1141 @@+-- | Translation of bang patterns, which introduce implicit threading.+module Syntax.ImplicitThreading (+ threadDecls, threadDecl, threadProg,+) where++import Util+import AST+import Data.Loc+import Error+import Meta.Quasi+import Syntax.Construction+import qualified Syntax.Ppr as Ppr++import Prelude ()+import Data.Generics (Data, everywhere, mkT, extT)+import qualified Data.Map as M+import qualified Data.Set as S++type R = Raw+type ThreadTrans a = MonadAlmsError m ⇒ a → m a++threadProg ∷ ThreadTrans (Prog R)+threadDecls ∷ ThreadTrans [Decl R]+threadDecl ∷ ThreadTrans (Decl R)++threadProg [prQ| $list:ds in $opt:me |] = do+ ds' ← mapM threadDecl ds+ me' ← mapM threadExpr me+ return [prQ| $list:ds' in $opt:me' |]++threadDecls = mapM threadDecl++threadDecl d0 = withLocation d0 $ case d0 of+ [dc| let $π = $e |]+ → do+ withLocation π $+ bassert (not (patternHasBang π)) [msg|+ Implicit threading translation does not allow ! patterns to appear+ declaration let bindings.+ |]+ e' ← threadExpr e+ return [dc| let $π = $e' |]+ [dc| let rec $list:bns |]+ → do+ bns' ← mapM threadBinding bns+ return [dc| let rec $list:bns' |]+ [dc| type $list:_ |] → return d0+ [dc| type $tid:_ = type $qtid:_ |] → return d0+ [dc| abstype $list:abstys with $list:ds end |]+ → do+ ds' ← mapM threadDecl ds+ return [dc| abstype $list:abstys with $list:ds' end |]+ [dc| module $mid:mid = $modexp |]+ → do+ modexp' ← threadModExp modexp+ return [dc| module $mid:mid = $modexp' |]+ [dc| module type $sid:_ = $_ |] → return d0+ [dc| open $modexp |]+ → do+ modexp' ← threadModExp modexp+ return [dc| open $modexp' |]+ [dc| local $list:ds1 with $list:ds2 end |]+ → do+ ds1' ← mapM threadDecl ds1+ ds2' ← mapM threadDecl ds2+ return [dc| local $list:ds1' with $list:ds2' end |]+ [dc| exception $uid:_ of $opt:_ |] → return d0+ [dc| $anti:a |] → $antifail++threadModExp ∷ ThreadTrans (ModExp R)+threadModExp modexp0 = withLocation modexp0 $ case modexp0 of+ [meQ| struct $list:ds end |]+ → do+ ds' ← mapM threadDecl ds+ return [meQ| struct $list:ds' end |]+ [meQ| $qmid:_ $list:_ |] → return modexp0+ [meQ| $modexp : $sigexp |]+ → do+ modexp' ← threadModExp modexp+ return [meQ| $modexp' : $sigexp |]+ [meQ| $anti:a |] → $antifail++threadBinding ∷ ThreadTrans (Binding R)+threadBinding bn0 = withLocation bn0 $ case bn0 of+ [bnQ| $vid:x = $e |]+ → do+ e' ← threadExpr e+ return [bnQ| $vid:x = $e' |]+ [bnQ| $antiB:a |] → $antifail++threadCaseAlt ∷ ThreadTrans (CaseAlt R)+threadCaseAlt ca0 = case ca0 of+ [caQ| $π → $e |]+ | (π', xs@(_:_)) ← patternBangRename π+ → do+ e' ← beginTranslate xs e+ return [caQ| $π' → $e' |]+ | otherwise+ → do+ e' ← threadExpr e+ return [caQ| $π → $e' |]+ [caQ| #$uid:c $opt:mπ → $e |]+ | Just (π', xs@(_:_)) ← patternBangRename <$> mπ+ → do+ e' ← beginTranslate xs e+ return [caQ| #$uid:c $π' → $e' |]+ | otherwise+ → do+ e' ← threadExpr e+ return [caQ| #$uid:c $opt:mπ → $e' |]+ [caQ| $antiC:a |] → $antifail++threadField ∷ ThreadTrans (Field R)+threadField fd0 = case fd0 of+ [fdQ| $uid:u = $e |]+ → do+ e' ← threadExpr e+ return [fdQ| $uid:u = $e' |]+ [fdQ| $antiF:a |] → $antifail++threadExpr ∷ ThreadTrans (Expr R)+threadExpr e = case e of+ [ex| $qvid:_ |] → return e+ [ex| $lit:_ |] → return e+ [ex| $qcid:c $opt:me |]+ → do+ me' ← mapM threadExpr me+ return [ex| $qcid:c $opt:me' |]+ [ex| let $π = $e1 in $e2 |]+ | (π', xs@(_:_)) ← patternBangRename π+ → do+ e1' ← threadExpr e1+ e2' ← beginTranslate xs e2+ return [ex| let $π' = $e1' in $e2' |]+ | otherwise+ → do+ e1' ← threadExpr e1+ e2' ← threadExpr e2+ return [ex| let $π = $e1' in $e2' |]+ [ex| match $e0 with $list:cas |]+ → do+ e0' ← threadExpr e0+ cas' ← mapM threadCaseAlt cas+ return [ex| match $e0' with $list:cas' |]+ [ex| let rec $list:bns in $e1 |]+ → do+ bns' ← mapM threadBinding bns+ e1' ← threadExpr e1+ return [ex| let rec $list:bns' in $e1' |]+ [ex| let $decl:d in $e1 |]+ → do+ d' ← threadDecl d+ e1' ← threadExpr e1+ return [ex| let $decl:d' in $e1' |]+ [ex| ($e1, $e2) |]+ → do+ e1' ← threadExpr e1+ e2' ← threadExpr e2+ return [ex| ($e1', $e2') |]+ [ex| λ $π → $e2 |]+ | (π', xs@(_:_)) ← patternBangRename π+ → do+ e2' ← beginTranslate xs e2+ return [ex| λ $π' → $e2' |]+ | otherwise+ → do+ e2' ← threadExpr e2+ return [ex| λ $π → $e2' |]+ [ex| $e1 $e2 |]+ → do+ e1' ← threadExpr e1+ e2' ← threadExpr e2+ return [ex| $e1' $e2' |]+ [ex| `$uid:c $opt:me |]+ → do+ me' ← mapM threadExpr me+ return [ex| `$uid:c $opt:me' |]+ [ex| #$uid:c $e2 |]+ → do+ e2' ← threadExpr e2+ return [ex| #$uid:c $e2' |]+ [ex| { $list:flds | $e2 } |]+ → do+ flds' ← mapM threadField flds+ e2' ← threadExpr e2+ return [ex| { $list:flds' | $e2' } |]+ [ex| {+ $list:flds | $e2 +} |]+ → do+ flds' ← mapM threadField flds+ e2' ← threadExpr e2+ return [ex| {+ $list:flds' | $e2' +} |]+ [ex| $e1.$uid:u |]+ → do+ e1' ← threadExpr e1+ return [ex| $e1'.$uid:u |]+ [ex| $e1 : $annot |]+ → do+ e1' ← threadExpr e1+ return [ex| $e1' : $annot |]+ [ex| $e1 :> $annot |]+ → do+ e1' ← threadExpr e1+ return [ex| $e1' :> $annot |]+ [ex| $anti:_ |] → return e++-- Synthesized attributes+data Synth+ = S {+ code ∷ !(Expr R),+ typ ∷ ![[VarId R]],+ vars ∷ ![VarId R]+ }+ deriving Show++beginTranslate ∷ MonadAlmsError m ⇒ [VarId R] → Expr R → m (Expr R)+beginTranslate env0 e00 = do+ let e00_env = S.fromList env0+ e00' ← loop e00_env M.empty e00+ return $+ exLet' (r1 -*- vars e00') (code e00') $+ r1 -*- ren env0+ where+ loop env funs e = withLocation e $ case e of+ [ex| λ $π → $e1 |]+ → do+ let (π', new) = patternBangRename π+ e1_env = (env ∖ dv π) ∪ new+ e1' ← loop e1_env funs e1+ let latent = vars e1' ∖ ren new+ body = optExAbs latent $+ exLet' (r1 -*- vars e1') (code e1') $+ r1 -*- ren new ++ latent+ return S {+ vars = emptySet,+ typ = latent : typ e1',+ code = [ex| λ $π' → $body |]+ }+ --+ [ex| $e1 $e2 |]+ | Just dv_π2@(_:_) ← expr2pattVars env e2+ → do+ e1' ← loop env funs e1+ let (latent, cod_e1_typ) = splitType (typ e1')+ e_vars = toList (vars e1' ∪ ren dv_π2 ∪ latent)+ interference = ren dv_π2 ∩ latent+ e2' = ren e2+ bassert (null interference) $+ [msg|+ In implicit threading syntax expansion, the+ the operand of an application expression uses the+ some imperative variables that were also captured+ by the definition of the operator:+ <dl>+ <dt>operator: <dd>$5:e1+ <dt>operand: <dd>$5:e2+ <dt>variables: <dd>$interference+ </dl>+ |]+ return S {+ vars = e_vars,+ typ = cod_e1_typ,+ code = exLet' (r1 -*- vars e1') (code e1') $+ exLet' (r2 -*- ren dv_π2 ++ latent)+ (optExApp [ex| $vid:r1 $e2' |] latent) $+ r2 -*- e_vars+ }+ | otherwise+ → do+ e1' ← loop env funs e1+ e2' ← loop env funs e2+ assertNotFun e2' "operand of an application expression" e2+ let (latent, cod_e1_typ) = splitType (typ e1')+ e_vars = toList (vars e1' ∪ vars e2' ∪ latent)+ return S {+ vars = e_vars,+ typ = cod_e1_typ,+ code = exLet' (r1 -*- vars e1') (code e1') $+ exLet' (r2 -*- vars e2') (code e2') $+ exLet' (r -*- latent)+ (optExApp [ex| $vid:r1 $vid:r2 |] latent) $+ r -*- e_vars+ }+ --+ [ex| $vid:x |]+ | x ∈ env+ → return S {+ vars = [ren x],+ typ = [],+ code = exPair (ren e) exUnit+ }+ | otherwise+ → return S {+ vars = [],+ typ = M.findWithDefault [] x funs,+ code = e+ }+ [ex| $qvid:_ |]+ → return S {+ vars = [],+ typ = [],+ code = e+ }+ [ex| $qcid:_ |]+ → return S {+ vars = [],+ typ = [],+ code = e+ }+ [ex| $qcid:c1 $e2 |]+ → do+ e2' ← loop env funs e2+ assertNotFun e2' "argument of a data constructor" e2+ return S {+ vars = vars e2',+ typ = [],+ code = exLet' (r -*- vars e2') (code e2') $+ [ex| $qcid:c1 $vid:r |] -*- vars e2'+ }+ [ex| let $π = $e1 in $e2 |]+ | Just dv_π1@(_:_) ← expr2pattVars env e1+ → do+ let (π', new) = patternBangRename π+ hidden = dv_π1 ∖ (dv π ∖ new)+ e2_env = (env ∖ hidden ∖ dv π) ∪ new+ e1' = ren e1+ e2' ← loop e2_env funs e2+ let e_vars = ren dv_π1 ∪ (vars e2' ∖ ren new)+ e_vars' = [ if v ∈ ren new then exUnit else toExpr v+ | v ← e_vars ]+ body =+ censorVars (ren (dv_π1 ∖ dv π)) $+ exLet (r2 -*- vars e2') (code e2') $+ r2 -*- (toExpr <$> ren new) ++ e_vars'+ π'' = renOnly (env ∖ new) π'+ return S {+ vars = e_vars,+ typ = typ e2',+ code = [ex| let $π'' = $e1' in $body |]+ }+ | otherwise+ → do+ e1' ← loop env funs e1+ case typ e1' of+ _:_+ | [pa| $vid:x |] ← π+ → do+ let e2_env = env ∖ [x]+ e2_funs = M.insert x (typ e1') funs+ e2' ← loop e2_env e2_funs e2+ let e_vars = vars e1' ∪ vars e2'+ return S {+ vars = e_vars,+ typ = typ e2',+ code = (exLet (x -*- vars e1') (code e1') $+ exLet' (r2 -*- vars e2') (code e2') $+ r2 -*- e_vars)+ <<@ _loc+ }+ _ → do+ assertNotFun e1' "right-hand side of a let expression" e1+ let (π', new) = patternBangRename π+ e2_env = env ∪ new+ e2' ← loop e2_env funs e2+ let e_vars = vars e1' ∪ (vars e2' ∖ ren new)+ return S {+ vars = e_vars,+ typ = typ e2',+ code = (exLet' (r1 -*- vars e1') (code e1') $+ exLet' (r -*- (vars e2' ∖ ren new))+ (exLet π' (toExpr r1) $+ exLet' (r2 -*- vars e2') (code e2') $+ ((r2 -*- ren new ∷ Expr Raw)+ -*- (vars e2' ∖ ren new))) $+ (r -*- e_vars))+ <<@ _loc+ }+ [ex| $lit:_ |]+ → return S {+ vars = [],+ typ = [],+ code = e+ }+ --+ [ex| match $e0 with $list:cas |]+ → do+ (used, changed, rhs) ←+ case expr2pattVars env e0 of+ Just dv_π0@(_:_) →+ return (S.fromList dv_π0, [], ren e0)+ _ → do+ e0' ← loop env funs e0+ assertNotFun e0' "expression in match" e0+ return (emptySet, vars e0', code e0')+ let decompose [caQ|@=loc $πi → $ei |]+ = let (πi', newi) = patternBangRename πi+ in (dv πi, newi ∖ used, Left πi', ei, loc)+ decompose [caQ|@=loc #$uid:c → $ei |]+ = ([], [], Right (c, Nothing), ei, loc)+ decompose [caQ|@=loc #$uid:c $πi → $ei |]+ = let (πi', newi) = patternBangRename πi+ in (dv πi, newi ∖ used, Right (c, Just πi'), ei, loc)+ decompose [caQ|@=loc $antiC:a |] = $antierror+ let (dv_πs, news, eπs', es, locs)+ = unzip5 (decompose <$> cas)+ hides = ren ((used ∖) <$> dv_πs)+ ei_envs = zipWith (\dv_πi newi → (env ∖ dv_πi) ∪ used ∪ newi)+ dv_πs news+ synths ← zipWithM (loop <-> funs) ei_envs es+ let e_vars = foldl' (∪) (changed ∪ ren used)+ (zipWith (∖) (vars <$> synths) (ren news))+ e_typ = foldl' joinType [] (typ <$> synths)+ coerces = (`coerceType` e_typ) <$> typ <$> synths+ cas' = [ let body = censorVars (toList hidei) $+ exLet' (r -*- vars ei') (code ei') $+ coercei -*- e_vars+ in case renOnly used eπi' of+ Left πi'+ → [caQ|@=loc $πi' → $body |]+ Right (c, mπi')+ → [caQ|@=loc #$uid:c $opt:mπi' → $body |]+ | eπi' ← eπs'+ | hidei ← hides+ | ei' ← synths+ | coercei ← coerces+ | loc ← locs]+ return S {+ vars = e_vars,+ typ = e_typ,+ code = exLet' (r -*- changed) rhs $+ [ex| match $vid:r with $list:cas' |]+ }+ --+ [ex| let rec $list:bns in $e2 |]+ → do+ -- We infer the types of recursive functions by iterating to+ -- a fixpoint. Does this terminate? I believe it's monotone+ -- and in a finite domain, so it should.+ let bloop previous = do+ let env' = env ∖ (fst <$> previous)+ funs' = foldr (uncurry M.insert) funs previous+ (fτs, bns') ← unzip `liftM` mapM (binding env' funs') bns+ if (previous == fτs)+ then return (env', funs', bns')+ else bloop fτs+ (e2_env, e2_funs, bns') ← bloop []+ e2' ← loop e2_env e2_funs e2+ let e2_code = code e2'+ return S {+ vars = vars e2',+ typ = typ e2',+ code = [ex| let rec $list:bns' in $e2_code |]+ }+ [ex| let $decl:d in $e2 |]+ → do+ d' ← threadDecl d+ -- Note: decl bindings do not shadow bang variables+ e2' ← loop env funs e2+ let e2_code = code e2'+ return S {+ vars = vars e2',+ typ = typ e2',+ code = [ex| let $decl:d' in $e2_code |]+ }+ [ex| ($e1, $e2) |]+ → do+ e1' ← loop env funs e1+ e2' ← loop env funs e2+ assertNotFun e1' "tuple component" e1+ assertNotFun e2' "tuple component" e2+ let e_vars = vars e1' ∪ vars e2'+ return S {+ vars = e_vars,+ typ = [],+ code = exLet' (r1 -*- vars e1') (code e1') $+ exLet' (r2 -*- vars e2') (code e2') $+ [ex| ($vid:r1, $vid:r2) |] -*- e_vars+ }+ [ex| `$uid:_ |]+ → return S {+ vars = [],+ typ = [],+ code = e+ }+ [ex| `$uid:c1 $e2 |]+ → do+ e2' ← loop env funs e2+ assertNotFun e2' "argument of a variant constructor" e2+ return S {+ vars = vars e2',+ typ = [],+ code = exLet' (r -*- vars e2') (code e2') $+ [ex| `$uid:c1 $vid:r |] -*- vars e2'+ }+ [ex| #$uid:c1 $e2 |]+ → do+ e2' ← loop env funs e2+ assertNotFun e2' "argument of a variant embedding" e2+ return S {+ vars = vars e2',+ typ = [],+ code = exLet' (r -*- vars e2') (code e2') $+ [ex| #$uid:c1 $vid:r |] -*- vars e2'+ }+ [ex| { $list:flds1 | $e2 } |]+ → let eachField [] =+ withLocation e2 $ do+ e2' ← loop env funs e2+ assertNotFun e2' "record in extension expression" e2+ return e2'+ eachField ([fdQ|@=loci $uid:ui = $ei |]:flds) =+ withLocation loci $ do+ ei' ← loop env funs ei+ flds' ← eachField flds+ assertNotFun ei' "field of record" ei+ let each_vars = vars ei' ∪ vars flds'+ return S {+ vars = each_vars,+ typ = [],+ code = exLet' (r1 -*- vars ei') (code ei') $+ exLet' (r2 -*- vars flds') (code flds') $+ [ex| { $uid:ui = $vid:r1 | $vid:r2 } |]+ -*- each_vars+ }+ eachField ([fdQ|! $antiF:a |]:_) = $antifail+ in eachField flds1+ [ex| {+ $list:flds1 | $e2 +} |]+ → do+ sequence_+ [ withLocation loci $ do+ ei' ← loop env funs ei+ assertNotFun ei' "field of record" ei+ assertNoCapture ei' "Additive-record field"+ | [fdQ|@=loci $uid:_ = $ei |] ← flds1 ]+ e2' ← loop env funs e2+ assertNotFun e2' "record in extension expression" e2+ assertNoCapture e2' "Additive-record in extension expression"+ return S {+ vars = [],+ typ = [],+ code = e+ }+ [ex| $e1.$uid:u |]+ → do+ e1' ← loop env funs e1+ assertNotFun e1' "record in selector expression" e1+ return S {+ vars = vars e1',+ typ = [],+ code = exLet' (r1 -*- vars e1') (code e1') $+ [ex| $vid:r1.$uid:u |] -*- vars e1'+ }+ [ex| $e1 : $annot |]+ → do+ e1' ← loop env funs e1+ return S {+ vars = vars e1',+ typ = typ e1',+ code = exLet' (r -*- vars e1') (code e1') $+ [ex| $vid:r : $annot |] -*- vars e1'+ }+ [ex| $e1 :> $annot |]+ → do+ e1' ← loop env funs e1+ return S {+ vars = vars e1',+ typ = typ e1',+ code = exLet' (r -*- vars e1') (code e1') $+ [ex| $vid:r :> $annot |] -*- vars e1'+ }+ [ex| $anti:a |]+ → $antifail+ --+ binding env funs bn = withLocation bn $ case bn of+ [bnQ| $vid:f = $e |] → do+ let env_e = env ∖ [f]+ e' ← loop env_e funs e+ bassert (null (vars e')) $+ [msg|+ In implicit threading syntax expansion, imperative variables+ may not be used on the right-hand side of a let rec binding+ unless they occur in the body of a function.+ <dl>+ <dt>In binding: <dd> $f+ <dt>Used variables: <dd> $1+ </dl>+ |]+ (vars e')+ let e_code = code e'+ return ((f, typ e'), [bnQ| $vid:f = $e_code |])+ [bnQ| $antiB:a |] → $antifail+++-- Find the least-upper bound of two variable/effect types.+joinType ∷ [[VarId R]] → [[VarId R]] → [[VarId R]]+joinType (vs1:rest1) (vs2:rest2) = (vs1 ∪ vs2) : joinType rest1 rest2+joinType [] τ2 = τ2+joinType τ1 [] = τ1++-- | Coerce a value whose variable/effect type is the first argument+-- to have the effect of the second. Assumes that the second subsumes+-- the first. Assumes that the value is named @r@.+coerceType ∷ [[VarId R]] → [[VarId R]] → Expr R+coerceType _ [] = toExpr r+coerceType reste restg+ | reste == restg = toExpr r+coerceType [] (gots:restg) =+ exAbsVar' r1 $+ optExAbs gots $+ exLetVar' r (exApp (toExpr r) (toExpr r1)) $+ coerceType [] restg -*- gots+coerceType (exps:reste) (gots:restg) =+ exAbsVar' r1 $+ optExAbs gots $+ exLet' (r -*- exps)+ (optExApp (exApp (toExpr r) (toExpr r1)) exps) $+ coerceType reste restg -*- gots++-- | Shadow some variables with @()@.+censorVars ∷ [VarId R] → Expr R → Expr R+censorVars [] = id+censorVars (v:vs) = exLet' (v -*- vs) (exUnit -*- exUnit <$ vs)++-- Given an expression and a list, apply the expression to the+-- tuple of the list only if the list is non-empty.+optExApp ∷ (Tag i, ToExpr a i) ⇒ Expr i → [a] → Expr i+optExApp e0 [] = e0+optExApp e0 (e1:es) = exApp e0 (e1 -*- es)++-- Given an expression and a list, abstract to a tuple pattern+-- of the list only if the list is non-empty.+optExAbs ∷ (Tag i, ToPatt a i) ⇒ [a] → Expr i → Expr i+optExAbs [] e0 = e0+optExAbs (π1:πs) e0 = exAbs' (π1 -*- πs) e0++-- Split a type into the latent effect and the codomain+splitType ∷ [[a]] → ([a], [[a]])+splitType [] = ([], [])+splitType (v:vs) = (v, vs)++-- | Given a pattern, rename any !-ed variables, remove the ! itself,+-- and return the list of renamed variables.+patternBangRename ∷ Patt R → (Patt R, [VarId R])+patternBangRename = runWriter . loop False+ where+ loop doIt π0 = case π0 of+ [pa| $vid:x |]+ | doIt → do+ tell [x]+ let x' = ren x+ return [pa| $vid:x' |]+ | otherwise → return π0+ [pa| _ |] → return π0+ [pa| $qcid:c $opt:mπ |] → do+ mπ' ← mapM (loop doIt) mπ+ return [pa| $qcid:c $opt:mπ' |]+ [pa| ($π1, $π2) |] → do+ π1' ← loop doIt π1+ π2' ← loop doIt π2+ return [pa| ($π1', $π2') |]+ [pa| $lit:_ |] → return π0+ [pa| $π as $vid:x |] → do+ π' ← loop doIt π+ return [pa| $π' as $vid:x |]+ [pa| `$uid:c $opt:mπ |] → do+ mπ' ← mapM (loop doIt) mπ+ return [pa| `$uid:c $opt:mπ' |]+ [pa| $π : $annot |] → do+ π' ← loop doIt π+ return [pa| $π' : $annot |]+ [pa| {$uid:u = $π1 | $π2} |] → do+ π1' ← loop doIt π1+ π2' ← loop doIt π2+ return [pa| { $uid:u = $π1' | $π2' } |]+ [pa| ! $π |] → loop True π+ [pa| $anti:a |] → $antifail++patternHasBang ∷ Patt i → Bool+patternHasBang π0 = case π0 of+ [pa| $vid:_ |] → False+ [pa| _ |] → False+ [pa| $qcid:_ $opt:mπ |] → maybe False patternHasBang mπ+ [pa| ($π1, $π2) |] → patternHasBang π1 || patternHasBang π2+ [pa| $lit:_ |] → False+ [pa| $π as $vid:_ |] → patternHasBang π+ [pa| `$uid:_ $opt:mπ |] → maybe False patternHasBang mπ+ [pa| $π : $_ |] → patternHasBang π+ [pa| {$uid:_ = $π1 | $π2} |] → patternHasBang π1 || patternHasBang π2+ [pa| ! $_ |] → True+ [pa| $anti:a |] → $antierror++ren :: Data a => a → a+ren = everywhere (mkT eachRaw `extT` eachRen) where+ eachRaw ∷ VarId Raw → VarId Raw+ eachRen ∷ VarId Renamed → VarId Renamed+ eachRaw = each; eachRen = each+ each ∷ Tag i ⇒ VarId i → VarId i+ each (VarId (LidAnti a)) = VarId (LidAnti a)+ each (VarId (Lid i s)) = VarId (Lid i (s ++ "!"))++renOnly :: ∀ a i. (Data a, Tag i) ⇒ S.Set (VarId i) → a → a+renOnly set = everywhere (mkT each) where+ each ∷ VarId i → VarId i+ each vid | vid `S.member` set = ren vid+ | otherwise = vid++{-+---- The first order, one variable case:++ (x is the variable name, y is the fresh state name)++ fun !(x:t) -> e === fun y:t -> [[ e ]]+ let !x = e1 in e2 === let y = e1 in [[ e ]]++ [[ e1 x ]] = let (r, y) = [[ e1 ]] in+ r y+ [[ e1 e2 ]] = let (r1, y) = [[ e1 ]] in+ let (r2, y) = [[ e2 ]] in+ (r1 r2, y)+ [[ x ]] = (y, ())+ [[ v ]] = (v, y)+ [[ match e with+ | p1 -> e1+ | ...+ | pk -> ek ]]+ = let (r, y) = [[ e ]] in+ match r with+ | p1 -> [[ e1 ]]+ | ...+ | pk -> [[ ek ]]+ [[ c e ]] = let (r, y) = [[ e ]] in+ (c r, y)++-- The first order pattern case (2):++ (p! is a renaming of p)++ fun !(p:t) -> e === fun p!:t -> + let (r1, e.vars) = e.code+ in (r1, p!)+ where e.env = dv p in+ let !p = e1 in e2 === let p! = e1 in+ let (r1, e.vars) = e.code+ in (r1, p!)+ where e.env = dv p in++ e ::= e1 p2 | dv p2 `subseteq` dv e.env && dv p2 != empty++ e1.env = e.env+ e.vars = e1.vars `union` dv p2!+ e.code = let (r1, e1.vars) = e1.code in+ let (r2, p2!) = r1 p2! in+ (r2, e.vars)++ e ::= e1 e2++ e1.env = e2.env = e.env+ e.vars = e1.vars `union` e2.vars+ e.code = let (r1, e1.vars) = e1.code in+ let (r2, e2.vars) = e2.code in+ (r1 r2, e.vars)++ e ::= x | x `member` dv p++ e.vars = x!+ e.code = (x!, ())++ e ::= v++ e.vars = fv v `intersect` env+ e.code = let e.vars = e.vars! in+ (v, [ () | _ <- e.vars ])++ e ::= match p0 with+ | p1 -> e1+ | ...+ | pk -> ek+ | dv p0 `subseteq` dv e.env && dv p0 != empty++ if p1 is a bang pattern+ then e1.env = e.env `union` dv p1+ else e1.env = e.env - (dv p1 - dv p0)+ ...+ if pk is a bang pattern+ then ek.env = e.env `union` dv pk+ else ek.env = e.env - (dv pk - dv p0)++ e.vars = e.env `intersection` (e1.vars `union` ... `union` ek.vars)+ e.code = match p0! with+ | p1[p0!/p0] -> let (p0 - p1)! = ((), ..., ()) in+ let (r2, e1.vars) = e1.code in (r2, e.vars)+ | ...+ (if pk is not a bang pattern then)+ | pk[p0!/p0] -> let (p0 - pk)! = ((), ..., ()) in+ let (r2, e1.vars) = e1.code in (r2, e.vars)+ (else)+ | pk! -> let (p0 - pk)! = ((), ..., ()) in+ let (r2, e1.vars) = e1.code in (r2, e.vars)++ e ::= match e0 with+ | p1 -> e1+ | ...+ | pk -> ek++ e0.env = e.env+ e1.env = e.env - dv p1+ ...+ ek.env = e.env - dv pk++ e.vars = e.env `intersection`+ (e0.vars `union` e1.vars `union` ... `union` ek.vars)+ e.code = let (r1, e0.vars) = e0.code in+ match r1 with+ | p1 -> let (r2, e1.vars) = e1.code in (r2, e.vars)+ | ...+ | pk -> let (r2, ek.vars) = ek.code in (r2, e.vars)++ e ::= let rec f1 = v1+ and ...+ and fk = vk+ in e1++ captured = { x `in` (fv v1 `union` ... `union` fv vk)+ | x! `in` e.env }++ e1.env = e.env - { f1, ..., fk }+ e.vars = e1.vars `union` captured!+ e.code = let captured = captured! in+ let captured! = ((), ..., ()) in+ let rec f1 = v1+ and ...+ and fk = vk+ in let (r1, e1.vars) = e1.code+ in (r1, e.vars)++ e ::= let !p1 = e1 in e2++ e1.env = e.env+ e2.env = e.env `union` dv p1+ e.vars = e1.vars `union` (e2.vars `intersection` e.env)+ e.code = let (p1!, e1.vars) = e1.code in+ let (r2, e2.vars) = e2.code in+ ((r2, p1!), e.vars)+ [assuming no shadowing]++-- The pattern and function case (3):++ Types:+ τ ∷= 1 → τ / [VarId]+ | 1++ Inherited attributes:+ - env ∷ S.Set VarId+ - funs ∷ S.Map VarId τ -- τ is renamed++ Synthesized attributes:+ - vars ∷ [VarId] -- renamed+ - type ∷ τ -- renamed+ - code ∷ Expr++ Notation+ • e! is e renamed+ • [xs/ys]e is the substitution of xs for ys in e+ • [!xs]e = [!xs/xs]e+ • {vs} means include this only if vs is non-empty++ π → e1 ==> [!e1.env]π →+ let (r1, e1.vars) = e1.code+ in (r1, !e1.env)+ where e1.env = bangvars(π)+ e1.funs = ∅++ let π = e1 in e2 ==> let [!e.env]π = e1 in+ let (r1, e2.vars) = e2.code+ in (r1, !e2.env)+ where e2.env = bangvars π+ e2.funs = ∅++ e ::= λ π → e1++ new = bangvars(π)+ latent = e1.vars \ !new++ e1.env = (e.env \ dv π) ∪ new+ e.vars = ∅+ e.type = 1 → e1.type / latent++ e.code = λ [!new]π {latent} →+ let (r, e1.vars) = e1.code in+ (r, {!new}, {latent})++ e ::= e1 π2++ [ dv π2 nonempty ⊆ e.env ]++ latent = latent(e1.type)++ [ !(dv π2) ∩ latent ≠ ∅ ] ERROR!++ e.vars = e1.vars ∪ !(dv π2) ∪ latent+ e.type = cod(e1.type)+ e.code = let (r1, e1.vars) = e1.code in+ let (r, !(dv π2), {latent}) = r1 !π2 {latent} in+ (r, e.vars)++ e ::= e1 e2++ [ e2.type ≠ 1 ]++ ERROR!++ latent = latent(e1.type)++ e.vars = e1.vars ∪ e2.vars ∪ latent+ e.type = cod(e1.type)+ e.code = let (r1, e1.vars) = e1.code in+ let (r2, e2.vars) = e2.code in+ let (r, {latent}) = r1 r2 {latent} in+ (r, e.vars)++ e ::= x++ [ x ∈ e.env ]++ e.vars = !x+ e.type = 1+ e.code = (!x, ())++ [ otherwise ]++ e.vars = ∅+ e.type = e.funs(x) || 1+ e.code = x++ e ::= c1 e2++ [ e2.type ≠ 1 ]++ ERROR!++ [ otherwise ]++ e.vars = e2.vars+ e.type = 1+ e.code = let (r, e2.vars) = e2 in+ (c1 r, e.vars)++ e ::= let π = π1 in e2++ [ dv π1 nonempty ⊆ e.env ]++ new = bangvars(π)+ hidden = dv π1 \ (dv π \ new)++ e2.env = (e.env \ hidden \ dv π) ∪ new+ e.vars = !(dv π1) ∪ (e2.vars \ !new)+ e.type = e2.type+ e.code = let [!new][!π1]π = !π1 in+ let !(dv π1 \ dv π) = () ... () in+ let (r2, e2.vars) = e2.code in+ ((r2, !new), [()/!new]e.vars)++ e ::= let x = e1 in e2++ [ e1.type ≠ 1 ]++ e2.env = e.env \ x+ e2.funs = e.funs[x ↦ e1.type]+ e.vars = e1.vars ∪ e2.vars+ e.type = e2.type+ e.code = let (x, e1.vars) = e1 in+ let (r2, e2.vars) = e2 in+ (r2, e.vars)++ e ::= let π = e1 in e2++ [ e1.type ≠ 1 ]++ ERROR!++ [ otherwise ]++ new = bangvars(π)++ e2.env = e.env ∪ new+ e.vars = e1.vars ∪ (e2.vars \ !new)+ e.type = e2.type++ e.code = let (r1, e1.vars) = e1.code in+ let (r, e2.vars \ !new) =+ let [!new]π = r1 in+ let (r2, e2.vars) = e2.code in+ ((r2, !new), e2.vars \ !new) in+ (r, e.vars)++ e ::= match e0 with+ | π1 → e1+ ⋮+ | πk → ek++ {+ [ e0 = π0 ⋀ dv π0 nonempty ⊆ e.env ]++ used = dv π0+ changed = ∅+ rhs = !π0++ [ e0.type ≠ 1 ]++ ERROR++ [ otherwise ]++ used = ∅+ changed = e0.vars+ rhs = e0.code+ }++ newᵢ = bangvars(πᵢ) \ used+ hideᵢ = !(used \ dv πᵢ)+ eᵢ.env = (e.env \ dv πᵢ) ∪ used ∪ newᵢ++ e.vars = !used ∪ changed ∪ (e1.vars \ !new1) ∪ ... ∪ (ek.vars \ !newk)+ e.type = e1.type ⊔ ... ⊔ ek.type+ coerceᵢ= eᵢ.type ⇝ e.type++ e.code = let (r, changed) = rhs in+ match r with+ | [!used][!new]π1 →+ let hide1 = () ... () in+ let (r, e1.vars) = e1.code in+ (coerce1 r, e.vars)+ ⋮+ | [!used][!new]πk →+ let hidek = () ... () in+ let (r, ek.vars) = ek.code in+ (coercek r, e.vars)++-}++r, r1, r2 :: VarId R+r = ident "r.!"+r1 = ident "r1.!"+r2 = ident "r2.!"++-- | Transform an expression into a pattern, if possible, using only+-- the specified variables, and return the set of variables used.+expr2pattVars ∷ S.Set (VarId R) → Expr R → Maybe [VarId R]+expr2pattVars vs0 e0 = evalStateT (loop e0) vs0+ where+ loop e = case e of+ [ex| $vid:x |] → do+ possible ← get+ if x `S.member` possible+ then do+ put (S.delete x possible)+ return [x]+ else mzero+ [ex| $lit:_ |] → return []+ [ex| $qcid:_ $opt:me |] → concatMapM loop me+ [ex| ($e1, $e2) |] → mappend <$> loop e1 <*> loop e2+ [ex| `$uid:_ $opt:me |] → concatMapM loop me+ [ex| $e1 : $_ |] → loop e1+ [ex| $qvid:_ |] → mzero+ [ex| let $_ = $_ in $_ |] → mzero+ [ex| match $_ with $list:_ |] → mzero+ [ex| let rec $list:_ in $_ |] → mzero+ [ex| let $decl:_ in $_ |] → mzero+ [ex| λ $_ → $_ |] → mzero+ [ex| $_ $_ |] → mzero+ [ex| #$uid:_ $_ |] → mzero+ [ex| { $list:flds | $e2 } |] → mappend <$> concatMapM loopField flds+ <*> loop e2+ [ex| {+ $list:_ | $_ +} |] → mzero+ [ex| $_.$uid:_ |] → mzero+ [ex| $anti:_ |] → mzero+ [ex| $_ :> $_ |] → mzero+ --+ loopField [fdQ| $uid:_ = $ei |] = loop ei+ loopField [fdQ| $antiF:_ |] = mzero++---+--- Producing errors+---++-- | Indicate a bug in the bang translator.+bangBug ∷ MonadAlmsError m ⇒ String → String → m a+bangBug = throwAlms <$$> almsBug ParserPhase++-- | Indicate a bug in the bang translator, with no Alms error monad.+bangBugError ∷ String → String → a+bangBugError = throw <$$> almsBug ParserPhase++-- | Indicate a bang translation error.+bangError ∷ (MonadAlmsError m, Bogus a) ⇒ Message V → m a+bangError msg0 = do+ reportAlms (AlmsError ParserPhase bogus msg0)+ return bogus++-- | Indicate a bang error.+bangError_ ∷ MonadAlmsError m ⇒ Message V → m ()+bangError_ = bangError++-- | Indicate a bang error from which we cannot recover.+bangError' ∷ MonadAlmsError m ⇒ Message V → m a+bangError' = throwAlms <$> AlmsError ParserPhase bogus++-- | Assert some condition, indicating a bang translation error if+-- it doesn't hold.+bassert ∷ MonadAlmsError m ⇒ Bool → Message V → m ()+bassert True _ = return ()+bassert False m = bangError m++-- | Assert that the type of the given synthesized attribute is trivial,+-- indicating that the term it belongs to hasn't captured any bang+-- vars. Also takes a description of the role of the term and the+-- term itself.+assertNotFun ∷ (MonadAlmsError m, Ppr.Ppr a, Ppr.Ppr b) ⇒ + Synth → a → b → m ()+assertNotFun e' =+ bassert (all null (typ e')) <$$>+ [msg|+ In implicit threading syntax expansion, the $2 cannot be a+ function that captures some imperative variables.+ <dl>+ <dt>culprit: <dd>$5:3+ <dt>captured: <dd>$1+ </dl>+ |]+ (fromOpt [] (typ e'))++assertNoCapture ∷ (MonadAlmsError m, Ppr.Ppr a) ⇒+ Synth → a → m ()+assertNoCapture e' =+ bassert (null (vars e')) <$>+ [msg|+ $2 may not capture implicitly threaded variables:+ <dl>+ <dt>captures: <dd>$1+ </dl>+ |]+ (vars e')
− src/Syntax/Kind.hs
@@ -1,263 +0,0 @@-{-# LANGUAGE- DeriveDataTypeable,- GeneralizedNewtypeDeriving,- TemplateHaskell,- TypeFamilies #-}-module Syntax.Kind (- -- * Qualifiers, qualifiers sets, and variance- QLit(..), QExp'(..),- QExp, qeLit, qeVar, qeDisj, qeConj, qeAnti,- QDen,- Variance(..),- -- ** Qualifier operations- qConstBound, elimQLit,- qDenToLit, qDenOfTyVar, qDenFtv,- qInterpretM, qInterpret, qInterpretCanonical, qRepresent,- qSubst,- numberQDenM, numberQDen, numberQDenMap, denumberQDen-) where--import Meta.DeriveNotable-import PDNF (PDNF)-import qualified PDNF-import Syntax.Anti-import Syntax.Notable-import Syntax.POClass-import {-# SOURCE #-} Syntax.Ident-import Util--import Control.Monad.Identity (runIdentity)-import Data.List (elemIndex)-import Data.Generics (Typeable, Data)-import qualified Data.Map as M-import qualified Data.Set as S---- QUALIFIERS, VARIANCES---- | Usage qualifier literals-data QLit- -- | affine- = Qa- -- | unlimited- | Qu- deriving (Eq, Typeable, Data)---- | The syntactic version of qualifier expressions, which are--- positive logical formulae over literals and type variables-data QExp' i- = QeLit QLit- | QeVar (TyVar i)- | QeDisj [QExp i]- | QeConj [QExp i]- | QeAnti Anti- deriving (Typeable, Data)--type QExp i = Located QExp' i--deriveNotable ['QeDisj, 'QeConj] ''QExp---- | Synthetic constructor to avoid constructing nullary or unary--- disjunctions-qeDisj :: [QExp i] -> QExp i-qeDisj [] = newN (QeLit Qu)-qeDisj [qe] = qe-qeDisj qes = newN (QeDisj qes)---- | Synthetic constructor to avoid constructing nullary or unary--- conjunctions-qeConj :: [QExp i] -> QExp i-qeConj [] = newN (QeLit Qa)-qeConj [qe] = qe-qeConj qes = newN (QeConj qes)---- | The meaning of qualifier expressions-newtype QDen a = QDen { unQDen :: PDNF a }- deriving (Eq, Ord, PO, Bounded, Typeable, Data, Show)---- | Tycon parameter variance (like sign analysis)-data Variance- -- | Z- = Invariant- -- | non-negative- | Covariant- -- | non-positive- | Contravariant- -- | { 0 } - | Omnivariant- deriving (Eq, Ord, Typeable, Data)--------- Operations------qConstBound :: Ord a => QDen a -> QLit-qConstBound (QDen qden) =- if PDNF.isUnsat qden then Qu else Qa--elimQLit :: a -> a -> QLit -> a-elimQLit u _ Qu = u-elimQLit _ a Qa = a---- | Find the meaning of a qualifier expression-qInterpretM :: (Monad m, Id i) => QExp i -> m (QDen (TyVar i))-qInterpretM (N note qe0) = case qe0 of- QeLit Qu -> return minBound- QeLit Qa -> return maxBound- QeVar v -> return (QDen (PDNF.variable v))- QeDisj es -> bigVee `liftM` mapM qInterpretM es- QeConj es -> bigWedge `liftM` mapM qInterpretM es- QeAnti a -> antifail ("Syntax.Kind.qInterpret: " ++ show (getLoc note)) a---- | Find the meaning of a qualifier expression-qInterpret :: Id i => QExp i -> QDen (TyVar i)-qInterpret = runIdentity . qInterpretM---- | Convert a canonical representation back to a denotation.--- (Unsafe if the representation is not actually canonical)-qInterpretCanonical :: Id i => QExp i -> QDen (TyVar i)-qInterpretCanonical (N _ (QeDisj clauses)) = QDen $- PDNF.fromListsUnsafe $- [ [ v ] | N _ (QeVar v) <- clauses ] ++- [ [ v | N _ (QeVar v) <- clause ] | N _ (QeConj clause) <- clauses ]-qInterpretCanonical e = qInterpret e---- | Return the canonical representation of the meaning of a--- qualifier expression-qRepresent :: Id i => QDen (TyVar i) -> QExp i-qRepresent (QDen pdnf)- | PDNF.isUnsat pdnf = newN (QeLit Qu)- | PDNF.isValid pdnf = newN (QeLit Qa)- | otherwise =- qeDisj (map (qeConj . map qeVar)- (PDNF.toLists pdnf))--qDenToLit :: Ord a => QDen a -> Maybe QLit-qDenToLit (QDen pdnf)- | PDNF.isUnsat pdnf = Just Qu- | PDNF.isValid pdnf = Just Qa- | otherwise = Nothing--qDenOfTyVar :: Ord a => a -> QDen a-qDenOfTyVar = QDen . PDNF.variable--qDenFtv :: Ord a => QDen a -> S.Set a-qDenFtv (QDen pdnf) = PDNF.support pdnf--qSubst :: Ord tv => tv -> QDen tv -> QDen tv -> QDen tv-qSubst v (QDen pdnf1) (QDen pdnf2) = QDen (PDNF.replace v pdnf1 pdnf2)--numberQDenM :: (Ord tv, Monad m) =>- (tv -> m (QDen Int)) ->- [tv] -> QDen tv -> m (QDen Int)-numberQDenM unbound tvs (QDen pdnf) =- liftM QDen $ PDNF.mapReplaceM pdnf $ \tv ->- case tv `elemIndex` tvs of- Nothing -> liftM unQDen $ unbound tv- Just n -> return (PDNF.variable n)--numberQDen :: Ord tv => [tv] -> QDen tv -> QDen Int-numberQDen = runIdentity <$$> numberQDenM (const (return minBound))--numberQDenMap :: Ord tv =>- (tv -> QLit) ->- M.Map tv Int ->- QDen tv -> QDen Int-numberQDenMap lit m = runIdentity . numberQDenM get [] where- get tv = case M.lookup tv m of- Just i -> return (QDen (PDNF.variable i))- Nothing -> return (elimQLit minBound maxBound (lit tv))---- | Given a qualifier set of indices into a list of qualifier--- expressions, build the qualifier set over the qexps.--- Assumes that the list is long enough for all indices.-denumberQDen :: Ord tv => [QDen tv] -> QDen Int -> QDen tv-denumberQDen qds (QDen pdnf) = QDen $- PDNF.mapReplace pdnf $ \ix -> unQDen (qds !! ix)--instance Show QLit where- showsPrec _ Qa = ('A':)- showsPrec _ Qu = ('U':)--instance Show Variance where- showsPrec _ Invariant = ('=':)- showsPrec _ Covariant = ('+':)- showsPrec _ Contravariant = ('-':)- showsPrec _ Omnivariant = ('*':)--instance Bounded QLit where- minBound = Qu- maxBound = Qa--instance Bounded (QExp' a) where- minBound = QeLit minBound- maxBound = QeLit maxBound--instance Bounded Variance where- minBound = Omnivariant- maxBound = Invariant--instance (Ord a, Num a) => Num (QDen a) where- fromInteger = QDen . PDNF.variable . fromInteger- (+) = error "QDen.signum: not implemented"- (*) = error "QDen.signum: not implemented"- abs = error "QDen.signum: not implemented"- signum = error "QDen.signum: not implemented"---- | The variance lattice:------ @--- (In)--- =--- (Co) + - (Contra)--- *--- (Omni)--- @-instance PO Variance where- Covariant \/ Covariant = Covariant- Contravariant \/ Contravariant = Contravariant- v \/ Omnivariant = v- Omnivariant \/ v = v- _ \/ _ = Invariant-- Covariant /\ Covariant = Covariant- Contravariant /\ Contravariant = Contravariant- v /\ Invariant = v- Invariant /\ v = v- _ /\ _ = Omnivariant---- | The qualifier lattice--- @--- Qa--- |--- Qu--- @-instance PO QLit where- Qu \/ Qu = Qu- _ \/ _ = Qa- Qa /\ Qa = Qa- _ /\ _ = Qu--instance Ord QLit where- (<=) = (<:)---- | Variance has a bit more structure still -- it does sign analysis:-instance Num Variance where- Covariant * Covariant = Covariant- Covariant * Contravariant = Contravariant- Contravariant * Covariant = Contravariant- Contravariant * Contravariant = Covariant- Omnivariant * _ = Omnivariant- _ * Omnivariant = Omnivariant- _ * _ = Invariant-- (+) = (\/)- negate = (* Contravariant)- abs x = x * x- signum = id-- x - y = x + negate y-- fromInteger n | n > 0 = Covariant- | n < 0 = Contravariant- | otherwise = Omnivariant-
+ src/Syntax/Lexer.hs view
@@ -0,0 +1,351 @@+-- | Lexer setup for parsec+module Syntax.Lexer (+ -- * Class for saving pre-whitespace position+ T.TokenEnd(..),+ -- * Identifier tokens+ isUpperIdentifier, lid, uid,+ llabel, ulabel,++ -- * Operators+ opP,+ cons, semis, bang, star,+ pragma,+ lolli, arrow, funbraces, plusbraces,+ lambda, forall, exists, mu,+ qualbox,+ qualU, qualA, qjoin, qjoinArr, ellipsis,+ variantInj, variantEmb,+ sigilU, sigilA,+ markCovariant, markContravariant, markInvariant, markOmnivariant,+ markQVariant,++ -- * Token parsers from Parsec+ identifier, reserved, operator, reservedOp, charLiteral,+ stringLiteral, natural, integer, integerOrFloat, float,+ naturalOrFloat, decimal, hexadecimal, octal, symbol, lexeme,+ whiteSpace, parens, braces, angles, brackets, squares, semi, comma,+ colon, dot, semiSep, semiSep1, commaSep, commaSep1+) where++import Syntax.Prec+import Util+import Alt.Parsec+import qualified Alt.Token as T++import Prelude ()+import Data.Char+import qualified Data.List as List++tok :: T.TokenEnd st => T.TokenParser st+tok = T.makeTokenParser T.LanguageDef {+ T.commentStart = "(*",+ T.commentEnd = "*)",+ T.commentLine = "--",+ T.nestedComments = True,+ T.identStart = noλμ $ upper <|> lower <|> oneOf "_",+ T.identLetter = alphaNum <|> oneOf "_'′₀₁₂₃₄₅₆₇₈₉⁰¹²³⁴⁵⁶⁷⁸⁹ᵢⱼₐₑₒₓⁱⁿ",+ T.opStart = satisfy isOpStart <|> plusNoBrace,+ T.opLetter = satisfy isOpLetter <|> plusNoBrace,+ T.reservedNames = ["fun", "λ",+ "if", "then", "else",+ "match", "with", "as", "_",+ "try",+ "local", "open", "exception",+ "let", "rec", "and", "in",+ "interface", "abstype", "end",+ "module", "struct",+ "sig", "val", "include",+ "all", "ex", "mu", "μ", "of",+ "type", "qualifier" ],+ T.reservedOpNames = ["|", "=", ":", ":>", "->", "→", "⊸",+ "∀", "∃", "⋁", "\\/", "...", "…", "::", "∷" ],+ T.caseSensitive = True+ }+ -- 'λ' is not an identifier character, so that we can use it as+ -- a reserved operator. Otherwise, we'd need a space after it.+ where noλμ p = notFollowedBy (char 'λ' <|> char 'μ') *> p+ plusNoBrace = char '+' <* notFollowedBy (char '}')++isOpStart, isOpLetter :: Char -> Bool+isOpStart c+ | isAscii c = c `elem` "!$%&*-/<=>?@^|~"+ | otherwise = case generalCategory c of+ ConnectorPunctuation -> True+ DashPunctuation -> True+ OtherPunctuation -> True+ MathSymbol -> True+ CurrencySymbol -> True+ OtherSymbol -> True+ ModifierSymbol -> True+ OpenPunctuation -> True+ ClosePunctuation -> True+ _ -> False+isOpLetter c+ | isAscii c = c `elem` "!$%&*-/<=>?@^|~.:"+ | otherwise = case generalCategory c of+ ConnectorPunctuation -> True+ DashPunctuation -> True+ OtherPunctuation -> True+ MathSymbol -> True+ CurrencySymbol -> True+ OtherSymbol -> True+ ModifierSymbol -> True+ OpenPunctuation -> True+ ClosePunctuation -> True+ -- InitialQuote+ -- FinalQuote+ _ -> False++identifier :: T.TokenEnd st => CharParser st String+identifier = T.identifier tok+reserved :: T.TokenEnd st => String -> CharParser st ()+reserved = T.reserved tok+operator :: T.TokenEnd st => CharParser st String+operator = T.operator tok+reservedOp :: T.TokenEnd st => String -> CharParser st ()+reservedOp = T.reservedOp tok+charLiteral :: T.TokenEnd st => CharParser st Char+charLiteral = T.charLiteral tok+stringLiteral :: T.TokenEnd st => CharParser st String+stringLiteral = T.stringLiteral tok+natural :: T.TokenEnd st => CharParser st Integer+natural = T.natural tok+integer :: T.TokenEnd st => CharParser st Integer+integer = lexeme $ try $ do+ sign <- choice [+ char '+' >> return id,+ char '-' >> return negate,+ return id+ ]+ nat <- natural+ return (sign nat)+integerOrFloat :: T.TokenEnd st => CharParser st (Either Integer Double)+integerOrFloat = lexeme $ try $ do+ sign <- choice [+ char '+' >> return id,+ char '-' >> return (either (Left . negate) (Right . negate)),+ return id+ ]+ nof <- naturalOrFloat+ return (sign nof)+ +float :: T.TokenEnd st => CharParser st Double+float = T.float tok+naturalOrFloat :: T.TokenEnd st => CharParser st (Either Integer Double)+naturalOrFloat = T.naturalOrFloat tok+decimal :: T.TokenEnd st => CharParser st Integer+decimal = T.decimal tok+hexadecimal :: T.TokenEnd st => CharParser st Integer+hexadecimal = T.hexadecimal tok+octal :: T.TokenEnd st => CharParser st Integer+octal = T.octal tok+symbol :: T.TokenEnd st => String -> CharParser st String+symbol = T.symbol tok+lexeme :: T.TokenEnd st => CharParser st a -> CharParser st a+lexeme = T.lexeme tok+whiteSpace :: T.TokenEnd st => CharParser st ()+whiteSpace = T.whiteSpace tok+parens :: T.TokenEnd st => CharParser st a -> CharParser st a+parens = T.parens tok+braces :: T.TokenEnd st => CharParser st a -> CharParser st a+braces = T.braces tok+angles :: T.TokenEnd st => CharParser st a -> CharParser st a+angles = T.angles tok+brackets :: T.TokenEnd st => CharParser st a -> CharParser st a+brackets = T.brackets tok+squares :: T.TokenEnd st => CharParser st a -> CharParser st a+squares = T.squares tok+semi :: T.TokenEnd st => CharParser st String+semi = T.semi tok+comma :: T.TokenEnd st => CharParser st String+comma = T.comma tok+colon :: T.TokenEnd st => CharParser st String+colon = T.reservedOp tok ":" >> return ":"+dot :: T.TokenEnd st => CharParser st String+dot = T.dot tok+semiSep :: T.TokenEnd st => CharParser st a -> CharParser st [a]+semiSep = T.semiSep tok+semiSep1 :: T.TokenEnd st => CharParser st a -> CharParser st [a]+semiSep1 = T.semiSep1 tok+commaSep :: T.TokenEnd st => CharParser st a -> CharParser st [a]+commaSep = T.commaSep tok+commaSep1 :: T.TokenEnd st => CharParser st a -> CharParser st [a]+commaSep1 = T.commaSep1 tok++-- | Parse a pragma or a prefix thereof+pragma :: T.TokenEnd st ⇒ String → CharParser st ()+pragma name = try $ do+ char '#'+ s ← lid+ guard (s `List.isPrefixOf` name)++-- | @!@, which has special meaning in let patterns+bang :: T.TokenEnd st => CharParser st String+bang = symbol "!"++-- | The @-o@ type operator, which violates our other lexer rules+lolli :: T.TokenEnd st => CharParser st ()+lolli = reserved "-o" <|> reservedOp "⊸"++-- | The @->@ type operator+arrow :: T.TokenEnd st => CharParser st ()+arrow = reservedOp "->" <|> reservedOp "→"++-- | The left part of the $-_>$ operator+funbraceLeft :: T.TokenEnd st => CharParser st ()+funbraceLeft = () <$ symbol "-"++-- | The right part of the $-_>$ operator+funbraceRight :: T.TokenEnd st => CharParser st ()+funbraceRight = () <$ symbol ">"++-- | The left part of the $-[_]>$ operator+oldFunbraceLeft :: T.TokenEnd st => CharParser st ()+oldFunbraceLeft = () <$ try (symbol "-[")++-- | The right part of the $-[_]>$ operator+oldFunbraceRight :: T.TokenEnd st => CharParser st ()+oldFunbraceRight = () <$ try (symbol "]>")++funbraces :: T.TokenEnd st => CharParser st a -> CharParser st a+funbraces = liftM2 (<|>) (between oldFunbraceLeft oldFunbraceRight)+ (between funbraceLeft funbraceRight)++-- | Curly braces with + symbols+plusbraces :: T.TokenEnd st => CharParser st a -> CharParser st a+plusbraces = between (try (symbol "{+")) (try (symbol "+}"))++-- | The left part of the $|[_]$ annotation+qualboxLeft :: T.TokenEnd st => CharParser st ()+qualboxLeft = () <$ try (symbol "|[")++-- | The right part of the $|[_]$ annotation+qualboxRight :: T.TokenEnd st => CharParser st ()+qualboxRight = () <$ symbol "]"++qualbox :: T.TokenEnd st => CharParser st a -> CharParser st a+qualbox = between qualboxLeft qualboxRight++-- | The function keyword+lambda :: T.TokenEnd st => CharParser st ()+lambda = reserved "fun" <|> reservedOp "λ"++-- | The universal quantifier keyword+forall :: T.TokenEnd st => CharParser st ()+forall = reserved "all" <|> reservedOp "∀"++-- | The existential quantifier keyword+exists :: T.TokenEnd st => CharParser st ()+exists = reserved "ex" <|> reservedOp "∃"++-- | The recursive type binder+mu :: T.TokenEnd st => CharParser st ()+mu = reserved "mu" <|> reservedOp "μ"++-- | The list constructor+cons :: T.TokenEnd st => CharParser st ()+cons = reservedOp "::" <|> reservedOp "∷"++-- | @;@, @;;@, ...+semis :: T.TokenEnd st => CharParser st String+semis = lexeme (many1 (char ';'))++-- | @*@, which gets special treatment for unicode+star :: T.TokenEnd st => CharParser st String+star = symbol "*" <|> symbol "×"++-- | Qualifier @U@ (not reserved)+qualU :: T.TokenEnd st => CharParser st ()+qualU = reserved "U"+-- | Qualifier @A@ (not reserved)+qualA :: T.TokenEnd st => CharParser st ()+qualA = reserved "A"++-- | Infix operator for qualifier disjunction+qjoin :: T.TokenEnd st => CharParser st String+qjoin = "\\/" <$ (reservedOp "\\/" <|> reservedOp "⋁")++-- | Infix operator for qualifier disjunction in type arrows+qjoinArr :: T.TokenEnd st => CharParser st ()+qjoinArr = reservedOp "," <|> reservedOp "\\/" <|> reservedOp "⋁"++-- | Postfix ellipsis type operator+ellipsis :: T.TokenEnd st => CharParser st ()+ellipsis = () <$ (reservedOp "..." <|> reservedOp "…")++-- | Marker for open variant injection+variantInj :: T.TokenEnd st => CharParser st ()+variantInj = () <$ symbol "`"++-- | Marker for open variant embedding+variantEmb :: T.TokenEnd st => CharParser st ()+variantEmb = () <$ symbol "#"++-- | Marker for unlimited type variables+sigilU :: T.TokenEnd st => CharParser st ()+sigilU = () <$ symbol "'"++-- | Marker for affine type variables+sigilA :: T.TokenEnd st => CharParser st ()+sigilA = () <$ symbol "`"++markCovariant, markContravariant, markInvariant, markOmnivariant,+ markQVariant :: T.TokenEnd st => CharParser st ()++markCovariant = () <$ symbol "+"+markContravariant = () <$ symbol "-"+markInvariant = () <$ symbol "="+markOmnivariant = () <$ symbol "0"+markQVariant = () <$ symbol "Q"++-- | Is the string an uppercase identifier? (Special case: @true@ and+-- @false@ are consider uppercase.)+isUpperIdentifier :: String -> Bool+isUpperIdentifier "true" = True+isUpperIdentifier "false" = True+isUpperIdentifier "()" = True+isUpperIdentifier "[]" = True+isUpperIdentifier "::" = True+isUpperIdentifier (c:_) = isUpper c+isUpperIdentifier _ = False++-- | Lex a lowercase identifer+lid :: T.TokenEnd st => CharParser st String+lid = try $ do+ s <- identifier+ if isUpperIdentifier s+ then pzero <?> "lowercase identifier"+ else return s++-- | Lex an uppercase identifer+uid :: T.TokenEnd st => CharParser st String+uid = try $ do+ s <- identifier <|> symbol "()" <|> symbol "[]"+ if isUpperIdentifier s+ then return s+ else pzero <?> "uppercase identifier"++-- | Lex a record label+llabel :: T.TokenEnd st => CharParser st String+llabel = try $ do+ c:s <- identifier+ if isLower c+ then return (toUpper c : s)+ else pzero <?> "record field label"++-- | Lex a variant label+ulabel :: T.TokenEnd st => CharParser st String+ulabel = try $ do+ s@(c:_) <- identifier+ if isUpper c+ then return s+ else pzero <?> "variant constructor label"++-- | Accept an operator having the specified precedence+opP :: T.TokenEnd st => Prec -> CharParser st String+opP p = try $ do+ op <- operator+ if precOp op == p+ then return op+ else pzero+
− src/Syntax/Lit.hs
@@ -1,18 +0,0 @@-{-# LANGUAGE- DeriveDataTypeable,- TemplateHaskell #-}-module Syntax.Lit (- Lit(..)-) where--import Syntax.Anti--import Data.Generics (Typeable, Data)---- | Literals-data Lit- = LtInt Integer- | LtStr String- | LtFloat Double- | LtAnti Anti- deriving (Eq, Typeable, Data)
− src/Syntax/Notable.hs
@@ -1,60 +0,0 @@-{-# LANGUAGE- DeriveDataTypeable,- FlexibleContexts,- GeneralizedNewtypeDeriving,- DeriveFunctor,- TypeFamilies #-}-module Syntax.Notable (- Notable(..), N(..), Located,- LocNote(..), module Loc-) where--import Loc-import Viewable--import Data.Data--class Notable note where- newNote :: note- newN :: a -> N note a- newN = N newNote- locN :: Relocatable note => Loc -> a -> N note a- locN loc a = newN a `setLoc` loc--data N note a- = N {- noteOf :: !note,- dataOf :: !a- }- deriving (Typeable, Data, Functor)--instance Eq a => Eq (N note a) where- a == b = dataOf a == dataOf b--instance Ord a => Ord (N note a) where- a `compare` b = dataOf a `compare` dataOf b--instance (Notable note, Bounded a) => Bounded (N note a) where- minBound = newN minBound- maxBound = newN maxBound--instance Locatable note => Locatable (N note a) where- getLoc (N note _) = getLoc note--instance Relocatable note => Relocatable (N note a) where- setLoc (N note val) loc = N (setLoc note loc) val--instance Viewable (N note a) where- type View (N note a) = a- view = dataOf--newtype LocNote i = LocNote { unLocNote :: Loc }- deriving (Eq, Ord, Data, Typeable, Locatable, Relocatable)--instance Show (LocNote i) where- showsPrec p = showsPrec p . unLocNote--type Located f i = N (LocNote i) (f i)--instance Notable (LocNote i) where- newNote = LocNote bogus
− src/Syntax/POClass.hs
@@ -1,87 +0,0 @@-module Syntax.POClass (- -- * Partial orders- PO(..), bigVee, bigVeeM, bigWedge, bigWedgeM,-) where--import Util--import Control.Monad.Error-import qualified Data.Set as S---- | Partial orders.--- Minimal complete definition is one of:------ * 'ifMJ'------ * '\/', '/\' (only if it's a lattice)------ * '\/?', '/\?' (partial join and meet)-class Eq a => PO a where- -- | Takes a boolean parameter, and does join if true- -- and meet if false. This sometimes allows us to exploit duality- -- to define both at once.- ifMJ :: (Error e, MonadError e m) => Bool -> a -> a -> m a- ifMJ True x y = return (x \/ y)- ifMJ False x y = return (x /\ y)-- -- | Partial join returns in a monad, in case join DNE- (\/?) :: (Error e, MonadError e m) => a -> a -> m a- (\/?) = ifMJ True-- -- | Partial meet returns in a monad, in case meet DNE- (/\?) :: (Error e, MonadError e m) => a -> a -> m a- (/\?) = ifMJ False-- -- | Total join- (\/) :: a -> a -> a- -- | Total meet- (/\) :: a -> a -> a- x \/ y = either error id (x \/? y)- x /\ y = either error id (x /\? y)-- -- | The order relation (derived)- (<:) :: a -> a -> Bool- x <: y = either (const False :: String -> Bool) ((==) x) (x /\? y)- || either (const False :: String -> Bool) ((==) y) (x \/? y)-- -- | The complement of the order relation (derived)- (/<:) :: a -> a -> Bool- (/<:) = not <$$> (<:)--infixl 7 /\, /\?-infixl 6 \/, \/?-infix 4 <:--bigVee :: (Bounded a, PO a) => [a] -> a-bigVee = foldr (\/) minBound--bigVeeM :: (Error e, MonadError e m, Bounded a, PO a) => [a] -> m a-bigVeeM = foldrM (\/?) minBound--bigWedge :: (Bounded a, PO a) => [a] -> a-bigWedge = foldr (/\) maxBound--bigWedgeM :: (Error e, MonadError e m, Bounded a, PO a) => [a] -> m a-bigWedgeM = foldrM (/\?) maxBound--instance Ord a => PO (S.Set a) where- (\/) = S.union- (/\) = S.intersection--instance PO a => PO (Maybe a) where- Just a \/? Just b = liftM Just (a \/? b)- Nothing \/? b = return b- a \/? Nothing = return a-- Just a /\? Just b = liftM Just (a /\? b)- Nothing /\? _ = return Nothing- _ /\? Nothing = return Nothing-- Just a <: Just b = a <: b- Nothing <: _ = True- _ <: Nothing = False--instance (PO a, PO b) => PO (a, b) where- ifMJ d (a, b) (a', b') = liftM2 (,) (ifMJ d a a') (ifMJ d b b')- (a, b) <: (a', b') = a <: a' && b <: b'-
+ src/Syntax/Parser.hs view
@@ -0,0 +1,1376 @@+-- | Parser+module Syntax.Parser (+ -- * The parsing monad+ P, parse,+ -- ** Errors+ ParseError,+ -- ** Quasiquote parsing+ parseQuasi,+ -- ** File and REPL command parsing+ parseFile,+ REPLCommand(..), parseCommand,+ -- ** Parsers+ parseProg, parseRepl, parseDecls, parseDecl, parseModExp,+ parseTyDec, parseAbsTy, parseType, parseTyPat,+ parseQExp, parseExpr, parsePatt,+ parseCaseAlt, parseBinding, parseField,+ parseSigExp, parseSigItem,+ -- ** For parsing with row dots+ withDots,+ -- * Convenience parsers (quick and dirty)+ pp, pds, pd, pme, ptd, pt, ptp, pqe, pe, px+) where++import Util hiding (before, lift)+import Paths+import AST+import Syntax.Prec+import Syntax.Lexer as Lexer+import Error (AlmsError(..), Phase(ParserPhase))+import qualified Message.AST as Msg+import Alt.Parsec hiding (parse)++import Prelude ()+import qualified Data.Map as M+import qualified Data.List as L+import qualified Language.Haskell.TH as TH+import qualified Text.ParserCombinators.Parsec.Error as PE+import System.IO.Unsafe (unsafePerformIO)++data St = St {+ stAnti :: !Bool,+ stPos :: !SourcePos,+ stDots :: !Bool+ }++instance TokenEnd St where+ saveTokenEnd = do+ pos <- getPosition+ updateState $ \st -> st { stPos = pos }++-- | A 'Parsec' character parser, with abstract state+type P a = CharParser St a++state0 :: St+state0 = St {+ stAnti = False,+ stPos = toSourcePos bogus,+ stDots = False+ }++-- | Run a parser, given the source file name, on a given string+parse :: P a -> SourceName -> String -> Either ParseError a+parse p = runParser p state0++-- | Run a parser on the given string in quasiquote mode+parseQuasi :: String ->+ (String -> String -> Maybe TH.Name -> P a) ->+ TH.Q a+parseQuasi str p = do+ loc <- fromTHLoc <$> TH.location+ let parser = do+ setPosition (toSourcePos loc)+ iflag <- (++) <$> option "" (string "+")+ <*> option "" (string "'")+ lflag <- choice [+ do char '@'+ choice [ char '=' >> identp_no_ws >>! Just,+ char '!' >> return Nothing ],+ char '!' >> return Nothing,+ return (Just "_loc")+ ]+ p (file loc) iflag (fmap TH.mkName lflag)+ either (fail . show) return $+ runParser parser state0 { stAnti = True } "<quasi>" str++-- | Given a file name and source, parse it+parseFile :: Tag i => String -> String -> Either AlmsError (Prog i)+parseFile = (almsParseError +++ id) <$$> parse parseProg++almsParseError :: ParseError -> AlmsError+almsParseError e =+ AlmsError ParserPhase (fromSourcePos (errorPos e)) message+ where+ message =+ Msg.Stack Msg.Broken [+ flow ";" messages,+ (if null messages then id else Msg.Indent)+ (Msg.Table (unlist ++ explist))+ ]+ unlist = case unexpects of+ [] -> []+ s:_ -> [("unexpected:", Msg.Words s)]+ explist = case expects of+ [] -> []+ _ -> [("expected:", flow "," expects)]+ messages = [ s | PE.Message s <- PE.errorMessages e, not $ null s ]+ unexpects = [ s | PE.UnExpect s <- PE.errorMessages e, not $ null s ]+ ++ [ s | PE.SysUnExpect s <- PE.errorMessages e, not $ null s ]+ expects = [ s | PE.Expect s <- PE.errorMessages e, not $ null s ]+ flow c = Msg.Flow . map Msg.Words . punct c . L.nub+ punct _ [] = []+ punct _ [s] = [s]+ punct c (s:ss) = (s++c) : punct c ss++-- | REPL-level commands+data REPLCommand+ = GetInfoCmd [Ident Raw]+ | GetPrecCmd [String]+ | GetConstraintCmd+ | QuitCmd+ | DeclsCmd [Decl Raw]+ | ParseError AlmsError++-- | Parse a line typed into the REPL+parseCommand :: Int -> String -> String -> REPLCommand+parseCommand row line syntax =+ case parsePragma line of+ Just cmd -> cmd+ _ -> case parseInteractive row syntax of+ Right ast -> DeclsCmd ast+ Left err -> ParseError (almsParseError err)++-- | Parse a #-style REPL command+parsePragma :: String -> Maybe REPLCommand+parsePragma = (const Nothing ||| Just) . runParser parser state0 "-"+ where+ parser = finish $+ GetInfoCmd <$+ pragma "info" <*>+ many1 (identp+ <|> J [] . Var . ident <$> (operator <|> qjoin))+ <|> GetPrecCmd <$+ pragma "precedence" <*>+ many1 (operator <|> qjoin)+ <|> GetConstraintCmd <$+ pragma "constraints"+ <|> QuitCmd <$+ pragma "quit"++-- | Parse a declaration or expression in the REPL+parseInteractive :: Tag i => Int -> String -> Either ParseError [Decl i]+parseInteractive line src = parse p "-" src where+ p = do+ pos <- getPosition+ setPosition (pos `setSourceLine` line)+ optional whiteSpace+ r <- replp+ eof+ return r++-- | Get the ending position of the last token, before trailing whitespace+getEndPosition :: P SourcePos+getEndPosition = stPos <$> getState++-- | Parse something and return the span of its location+withLoc :: P a -> P (a, Loc)+withLoc p = do+ before <- getPosition+ a <- p+ after <- getEndPosition+ return (a, fromSourcePosSpan before after)++addLoc :: Relocatable a => P a -> P a+addLoc = uncurry (<<@) <$$> withLoc++class Nameable a where+ (@@) :: String -> a -> a++infixr 0 @@++instance Relocatable a => Nameable (P a) where+ s @@ p = addLoc p <?> s++instance Nameable r => Nameable (a -> r) where+ s @@ p = \x -> s @@ p x++punit :: P ()+punit = pure ()++delimList :: P pre -> (P [a] -> P [a]) -> P sep -> P a -> P [a]+delimList before around delim each =+ choice [+ before >> choice [+ around (each `sepBy` delim),+ each >>! \x -> [x]+ ],+ return []+ ]++chainl1last :: P a -> P (a -> a -> a) -> P a -> P a+chainl1last each sep final = start where+ start = each >>= loop+ loop a = option a $ do+ build <- sep+ choice+ [ each >>= loop . build a,+ final >>= return . build a ]++chainr1last :: P a -> P (a -> a -> a) -> P a -> P a+chainr1last each sep final = start where+ start = do+ a <- each+ builder <- loop+ return (builder a)+ loop = option id $ do+ build <- sep+ choice+ [ do+ b <- each+ builder <- loop+ return (\a -> a `build` builder b),+ do+ b <- final+ return (\a -> a `build` b) ]++foldlp :: (a -> b -> a) -> P a -> P b -> P a+foldlp make start follow = foldl make <$> start <*> many follow++-- Antiquote+antip :: AntiDict -> P Anti+antip dict = antilabels . lexeme . try $ do+ char '$' <?> ""+ (s1, s2) <- (,) <$> option "" (try (option "" identp_no_ws <* char ':'))+ <*> identp_no_ws+ assertAnti+ case M.lookup s1 dict of+ Just _ -> return (Anti s1 s2)+ Nothing -> unexpected $ "antiquote tag: `" ++ s1 ++ "'"+ where+ antilabels p = do+ st <- getState+ if (stAnti st)+ then labels p [ "antiquote `" ++ key ++ "'"+ | key <- M.keys dict, key /= "" ]+ else p++identp_no_ws :: P String+identp_no_ws = do+ c <- lower <|> char '_'+ cs <- many (alphaNum <|> oneOf "_'")+ return (c:cs)++-- Fail if we should not recognize antiquotes+assertAnti :: P ()+assertAnti = do+ st <- getState+ unless (stAnti st) (unexpected "antiquote")++-- | Parse an antiquote and inject into syntax+antiblep :: forall a. Antible a => P a+antiblep = antip (dictOf (undefined::a)) >>! injAnti++antioptp :: Antible a => P a -> P (Maybe a)+antioptp = antioptaroundp id++antioptaroundp :: Antible a =>+ (P (Maybe a) -> P (Maybe a)) ->+ P a -> P (Maybe a)+antioptaroundp wrap p = wrap present <|> pure Nothing+ where present = antiblep+ <|> Just <$> antiblep+ <|> Just <$> p++antilist1p :: Antible a => P b -> P a -> P [a]+antilist1p sep p = antiblep+ <|> sepBy1 (antiblep <|> p) sep++antilistp :: Antible a => P b -> P a -> P [a]+antilistp = option [] <$$> antilist1p++-- | Accept or don't accept row type dots.+withDots :: Bool -> P a -> P a+withDots b p = do+ saved <- getState+ setState saved { stDots = b }+ result <- p+ state <- getState+ setState state { stDots = stDots saved }+ return result++-- | Assert that we are accepting dots.+assertDots :: P ()+assertDots = do+ state <- getState+ if stDots state+ then return ()+ else pzero++-- Just uppercase identifiers+uidp :: Tag i => P (Uid i)+uidp = ident <$> Lexer.uid+ <|> antiblep+ <?> "uppercase identifier"++-- Just lowercase identifiers+lidp :: Tag i => P (Lid i)+lidp = ident <$> Lexer.lid+ <|> antiblep+ <?> "lowercase identifier"++-- Just uppercase row labels+ulabelp :: Tag i => P (Uid i)+ulabelp = ident <$> Lexer.ulabel+ <|> antiblep+ <?> "variant constructor label"++-- Just lowercase row labels+llabelp :: Tag i => P (Uid i)+llabelp = ident <$> Lexer.llabel+ <|> antiblep+ <?> "record field label"++-- Infix operator at the given precdence+oplevelp :: Tag i => Prec -> P (Lid i)+oplevelp p = ident <$> opP p+ <?> "infix operator"++-- Just parenthesized operators+operatorp :: Tag i => P (Lid i)+operatorp = ident <$> try (parens (operator <|> semis))+ <?> "operator name"++-- Lowercase identifiers or naturals+-- - tycon declarations+lidnatp :: Tag i => P (Lid i)+lidnatp = ident <$> (Lexer.lid <|> show <$> natural)+ <|> operatorp+ <|> antiblep+ <?> "type name"++-- Type identifiers (unqualified)+typidp :: Tag i => P (TypId i)+typidp = antiblep+ <|> TypId <$> (lidnatp <|> operatorp)+ <?> "type constructor"++-- Infix type identifiers+typopp :: Tag i => Prec → P (TypId i)+typopp p = TypId <$> oplevelp p+ <?> "infix type operator"++-- Variable bindings+varidp :: Tag i => P (VarId i)+varidp = antiblep+ <|> VarId <$> (lidp <|> operatorp)+ <?> "variable name"++-- Infix variable occurrences+varopp :: Tag i => Prec → P (VarId i)+varopp p = VarId <$> oplevelp p+ <?> "infix operator"++-- Data constructor names+conidp :: Tag i => P (ConId i)+conidp = antiblep+ <|> ConId <$> uidp+ <|> ConId (ident "::") <$ parens cons+ <?> "data constructor"++-- Module names+modidp :: Tag i => P (ModId i)+modidp = antiblep+ <|> ModId <$> uidp+ <?> "module name"++-- Module type names+sigidp :: Tag i => P (SigId i)+sigidp = antiblep+ <|> SigId <$> uidp+ <?> "module type (signature) name"++-- Add a path before something+pathp :: (Tag i, Antible b) => P ([ModId i] -> b) -> P b+pathp p = (antiblep <|>) . try $ do+ path <- many $ try $ modidp <* dot+ make <- p+ return (make path)++-- Qualified type identifiers+qtypidp :: Tag i => P (QTypId i)+qtypidp = pathp (flip J <$> typidp)+ <|> qident tnAf <$ qualA+ <|> qident tnUn <$ qualU+ <?> "(qualified) type constructor"++-- Qualified variable occurrences+qvaridp :: Tag i => P (QVarId i)+qvaridp = pathp (flip J <$> varidp)+ <?> "(qualified) variable name"++-- Qualified data constructor names+qconidp :: Tag i => P (QConId i)+qconidp = pathp (flip J <$> conidp)+ <?> "(qualified) data constructor"++-- Qualified module names+qmodidp :: Tag i => P (QModId i)+qmodidp = pathp (flip J <$> modidp)+ <?> "(qualified) module name"++-- Qualified module type names+qsigidp :: Tag i => P (QSigId i)+qsigidp = pathp (flip J <$> sigidp)+ <?> "(qualified) module type name"++-- Identifiers+identp :: Tag i => P (Ident i)+identp = pathp (flip J <$> (Var . unTypId <$> typidp <|> Con <$> uidp))+ <?> "identifier"++-- Type variables+tyvarp :: Tag i => P (TyVar i)+tyvarp = try $ "type variable" @@+ sigilU *> tv Qu+ <|> sigilA *> tv Qa+ where tv q = antiblep <|> TV <$> lidp <*> pure q <*> pure bogus++-- open variant injection constructor+varinjp ∷ Tag i ⇒ P (Uid i)+varinjp = try (variantInj *> ulabelp)+ <?> "open variant constructor"++-- open variant embedding constructor+varembp ∷ Tag i ⇒ P (Uid i)+varembp = try (variantEmb *> ulabelp)+ <?> "open variant constructor"++quantp :: P Quant+quantp = Forall <$ forall+ <|> Exists <$ exists+ <|> antiblep+ <?> "quantifier"++typep :: Tag i => P (Type i)+typep = typepP precStart++typepP :: Tag i => Int -> P (Type i)+typepP p = "type" @@ case () of+ _ | p == precStart+ -> tyrowp1 <|> next+ | p == precDot+ -> do+ tc <- tyQu <$> quantp+ <|> tyMu <$ mu+ tvs <- many tyvarp+ dot+ t <- typepP p+ return (foldr tc t tvs)+ <|> next+ | p == precArr+ -> chainr1last+ next+ (choice+ [ tyArr <$ arrow,+ tyLol <$ lolli,+ funbraces (flip tyFun <$> (antiblep <|> Just <$> qExpp)),+ tybinopp (Right precArr) ])+ (typepP precStart)+ | p == precTySemi+ -> chainr1last next+ (tyAppN <$> (semis <|> qjoin))+ (typepP precStart)+ | Just (Left _) <- fixities p+ -> chainl1last next+ (tybinopp (Left p))+ (typepP precStart)+ | Just (Right _) <- fixities p+ -> chainr1last next+ (tybinopp (Right p))+ (typepP precStart)+ | p == precApp -- this case ensures termination+ -> tyarg >>= tyapp'+ | p < precApp+ -> next+ | otherwise+ -> typepP precStart+ where+ tyarg :: Tag i => P [Type i]+ tyarg = parens (antiblep <|> commaSep1 (typepP precMin))+ <|> (:[]) <$> tyatom+ --+ tyatom :: Tag i => P (Type i)+ tyatom = tyVar <$> tyvarp+ <|> tyApp <$> qtypidp <*> pure []+ <|> antiblep+ <|> varianttyp+ <|> recordtyp+ <|> parens (typepP precMin)+ <|> do+ ops <- many1 $ addLoc $+ typopp (Right precBang) >>! tyApp . J []+ arg <- tyatom+ return (foldr (\op t -> op [t]) arg ops)+ --+ tyapp' :: Tag i => [Type i] -> P (Type i)+ tyapp' [t] = option t $+ do+ tc <- qtypidp+ tyapp' [tyApp tc [t]]+ <|>+ do+ assertDots+ ellipsis+ tyapp' [tyRowDots t]+ tyapp' ts = do+ tc <- qtypidp+ tyapp' [tyApp tc ts]+ --+ next = typepP (p + 1)++-- A variant type+varianttyp ∷ Tag i ⇒ P (Type i)+varianttyp = AST.tyVariant <$> brackets tyrowp++-- A non-empty type row, in variant style+tyrowp1 ∷ Tag i ⇒ P (Type i)+tyrowp1 = AST.tyRow <$> varinjp+ <*> option AST.tyUnit+ (reserved "of" *> typepP precStart)+ <*> option AST.tyRowEnd+ (reservedOp "|" *> tyrowp)++-- A possibly empty type row, in variant style+tyrowp ∷ Tag i ⇒ P (Type i)+tyrowp = "row type" @@+ antiblep+ <|> tyrowp1+ <|> extensionp+ <|> AST.tyRowEnd <$ whiteSpace++-- A record type+recordtyp ∷ Tag i ⇒ P (Type i)+recordtyp = AST.tyRecordAdditive <$>+ plusbraces (recrowp <|> pure AST.tyRowEnd)+ <|> AST.tyRecordMultiplicative <$>+ braces (recrowp <|> pure AST.tyRowEnd)++-- A type row in record style+recrowp ∷ Tag i ⇒ P (Type i)+recrowp = antiblep+ <|> do+ labs ← commaSep1 llabelp+ colon+ t ← typepP precStart+ rest ← option AST.tyRowEnd $+ comma *> recrowp+ <|> reservedOp "|" *> extensionp+ return (foldr (AST.tyRow <-> t) rest labs)+ <|> extensionp++-- A row extension variable or dot form+extensionp ∷ Tag i ⇒ P (Type i)+extensionp = try (tyRowDots <$> withDots False (typepP precApp) <* ellipsis)+ <|> AST.tyVar <$> tyvarp ++tybinopp :: Tag i => Prec -> P (Type i -> Type i -> Type i)+tybinopp p = try $ do+ op <- typopp p+ when (idName op == "-") pzero+ return (\t1 t2 -> tyApp (J [] op) [t1, t2])++progp :: Tag i => P (Prog i)+progp = choice [+ do ds <- declsp+ when (null ds) pzero+ e <- antioptaroundp (reserved "in" `between` punit) exprp+ return (prog ds e),+ antioptp exprp >>! prog []+ ]++replp :: Tag i => P [Decl i]+replp = choice [+ try $ do+ ds <- declsp+ when (null ds) pzero+ eof+ return ds,+ exprp >>! (prog2decls . prog [] . Just)+ ]++declsp :: Tag i => P [Decl i]+declsp = antiblep <|> loop+ where loop =+ choice [+ do+ d <- declp+ ds <- loop+ return (d : ds),+ (<?> "#load") $ do+ pragma "load"+ name <- stringLiteral+ rel <- sourceName `liftM` getPosition+ let mcontents = unsafePerformIO $ do+ mfile <- findAlmsLibRel name rel+ traverse readFile mfile+ contents <- case mcontents of+ Just contents -> return contents+ Nothing -> fail $ "Could not load: " ++ name+ ds <- case parse parseProg name contents of+ Left e -> fail (show e)+ Right p -> return (prog2decls p)+ ds' <- loop+ return (ds ++ ds'),+ return []+ ]++declp :: Tag i => P (Decl i)+declp = "declaration" @@ choice [+ do+ tid ← try $+ reserved "type" *> typidp <* reservedOp "=" <* reserved "type"+ rhs ← qtypidp+ return (dcAli tid rhs),+ do+ reserved "type"+ tyDecsp >>! dcTyp,+ letp,+ do+ reserved "open"+ modexpp >>! dcOpn,+ do+ reserved "module"+ choice [+ do+ reserved "type"+ n <- sigidp+ reservedOp "="+ s <- sigexpp+ return (dcSig n s),+ do+ n <- modidp+ asc <- option id $ do+ colon+ sigexpp >>! flip meAsc+ reservedOp "="+ b <- modexpp >>! asc+ return (dcMod n b)+ ],+ do+ reserved "local"+ ds0 <- declsp+ reserved "with"+ ds1 <- declsp+ reserved "end"+ return (dcLoc ds0 ds1),+ do+ reserved "abstype"+ at <- absTysp+ reserved "with"+ ds <- declsp+ reserved "end"+ return (dcAbs at ds),+ do+ reserved "exception"+ n <- conidp+ t <- antioptaroundp (reserved "of" `between` punit) typep+ return (dcExn n t),+ antiblep+ ]++modexpp :: Tag i => P (ModExp i)+modexpp = "structure" @@ foldlp meAsc body ascription where+ body = choice [+ meStr <$> between (reserved "struct") (reserved "end") declsp,+ meName <$> qmodidp+ <*> antilistp comma qvaridp,+ antiblep+ ]+ ascription = colon *> sigexpp++sigexpp :: Tag i => P (SigExp i)+sigexpp = "signature" @@ do+ se <- choice [+ seSig <$> between (reserved "sig") (reserved "end")+ (antiblep <|> many sigitemp),+ seName <$> qsigidp+ <*> antilistp comma qvaridp,+ antiblep+ ]+ specs <- many $ do+ reserved "with"+ reserved "type"+ flip sepBy1 (reserved "and") $ "signature specialization" @@ do+ (tvs, tc) <- tyAppp (antiblep <|>) tyvarp (J []) qtypidp+ reservedOp "="+ t <- typep+ return (\sig -> seWith sig tc tvs t)+ return (foldl (flip ($)) se (concat specs))++sigitemp :: Tag i => P (SigItem i)+sigitemp = "signature item" @@ choice [+ do+ reserved "val"+ n <- varidp+ colon+ t <- typep+ return (sgVal n t),+ do+ tid ← try $+ reserved "type" *> typidp <* reservedOp "=" <* reserved "type"+ rhs ← qtypidp+ return (sgAli tid rhs),+ do+ reserved "type"+ sgTyp <$> tyDecsp,+ do+ reserved "module"+ choice [+ do+ reserved "type"+ n <- sigidp+ reservedOp "="+ s <- sigexpp+ return (sgSig n s),+ do+ n <- modidp+ colon+ s <- sigexpp+ return (sgMod n s)+ ],+ do+ reserved "include"+ sgInc <$> sigexpp,+ do+ reserved "exception"+ n <- conidp+ t <- antioptaroundp (reserved "of" `between` punit) typep+ return (sgExn n t),+ antiblep+ ]++tyDecsp :: Tag i => P [TyDec i]+tyDecsp = antilist1p (reserved "and") tyDecp++tyDecp :: Tag i => P (TyDec i)+tyDecp = "type declaration" @@ addLoc $ choice+ [ antiblep+ , do+ optional (reservedOp "|")+ tp <- typatp+ (name, ps) <- checkHead tp+ case checkTVs ps of+ -- Could be a data type, a synonym, or an abstract type+ Just (True, tvs, arity) ->+ reservedOp "=" *>+ (tdDat name tvs <$> altsp+ <|> tryTySyn name ps)+ <|> finishTyAbs name tvs arity+ -- Must be a synonym or an abstract type+ Just (_, tvs, arity) ->+ reservedOp "=" *> tryTySyn name ps+ <|> finishTyAbs name tvs arity+ -- Must be a type function+ Nothing ->+ reservedOp "=" *> tryTySyn name ps+ ]+ where+ -- Try to parse the right-hand side of a type synonym+ tryTySyn name ps = do+ t <- withDots True typep+ alts <- many $ do+ reservedOp "|"+ tp <- typatp+ (name', ps') <- checkHead tp+ unless (name == name') $+ unexpected $+ "non-matching type operators ‘" ++ show name' +++ "’ and ‘" ++ show name ++ "’ in type pattern"+ reservedOp "="+ ti <- withDots True typep+ return (ps', ti)+ return (tdSyn name ((ps,t):alts))+ --+ finishTyAbs name tvs arity = do+ let guardsp = option [] $ reserved "rec" *> commaSep1 tyvarp+ guards1 ← guardsp+ qual ← qualsp+ guards2 ← guardsp+ return (tdAbs name tvs arity (guards1 ++ guards2) qual)+ --+ -- A type declaration needs to give an unqualified name for the type+ -- being defined. This checks that and splits into the name and the+ -- parameter patterns.+ checkHead tp = case dataOf tp of+ TpApp (J [] name) ps -> return (name, ps)+ TpApp _ _ -> unexpected "qualified identifier"+ TpVar _ _ -> unexpected "type variable"+ TpRow _ _ -> unexpected "row type"+ TpAnti _ -> unexpected "antiquote"+ --+ -- Look at the parameters and determine what kind of type declaration+ -- this might be. Returns @Just (allInv, tvs, vars)@ if all the+ -- parameters are type variables, where @allInv@ tells whether all the+ -- variances are 'Invariant', and @tvs@ and @vars@ are the lists of+ -- type variables and variances. Otherwise, we're defining a type+ -- function and it returns @Nothing@.+ checkTVs [] = return (True, [], [])+ checkTVs (N _ (TpVar tv var):rest) = do+ (b, tvs, vars) <- checkTVs rest+ return (b && var == Invariant, tv:tvs, var:vars)+ checkTVs _ = Nothing++-- | Generic parser for things in the shape of type constructor+-- applications.+tyAppp :: Tag i =>+ -- | Wrapper for parsing the parameter(s) of a normal suffix+ -- type application+ (P [a] -> P [a]) ->+ -- | Parser for a type parameter+ P a ->+ -- | Injection to lift a type operator+ (TypId i -> b) ->+ -- | Parser for postfix constructor+ P b ->+ P ([a], b)+tyAppp wrap param oper suffix = choice [+ -- prefix operator+ do+ l <- typopp (Right precBang)+ p1 <- param+ return ([p1], oper l),+ -- infix operator+ try $ do+ p1 <- param+ n <- choice [ semis, operator ]+ when (n == "-" || precOp n == Right precBang) pzero+ p2 <- param+ return ([p1, p2], oper (ident n)),+ -- normal postfix application+ do+ ps <- wrap (delimList punit parens comma param)+ name <- suffix+ return (ps, name)+ ]++-- | Left-hand side of a type declaration, which looks like a+-- type constructor applied to parameters+tyProtp :: Tag i => P ([(Variance, TyVar i)], TypId i)+tyProtp = tyAppp id paramVp id typidp++-- | A type pattern+typatp :: Tag i => P (TyPat i)+typatp = typatpP precStart++typatpP :: Tag i => Int -> P (TyPat i)+typatpP p = "type pattern" @@ case () of+ _ | p == precTySemi+ -> chainr1last (typatpP (p + 1))+ (tpBinOp . J [] . ident <$> semis)+ (typatpP precStart)+ | Just e <- fixities p -> case e of+ Left _ ->+ chainl1last (typatpP (p + 1))+ (tpBinOp . J [] <$> typopp (Left p))+ (typatpP precStart)+ Right _ ->+ chainr1last (typatpP (p + 1))+ (tpBinOp . J [] <$> typopp (Right p))+ (typatpP precStart)+ | p == precApp -- this case ensures termination+ -> tparg >>= tpapp'+ | p < precApp+ -> typatpP (p + 1)+ | otherwise+ -> typatpP precStart+ where+ tpBinOp ql tp1 tp2 = tpApp ql [tp1, tp2]+ --+ tparg = parens (antiblep <|> commaSep1 (typatpP precMin))+ <|> (:[]) <$> tpatom+ --+ tpatom = tpvar+ <|> tpApp <$> qtypidp <*> pure []+ <|> antiblep+ <|> tpApp (qident tnUn) [] <$ qualU+ <|> tpApp (qident tnAf) [] <$ qualA+ <|> tpvariant+ <|> tprecord+ <|> parens (typatpP precMin)+ <|> do+ ops <- many1 $ addLoc $+ typopp (Right precBang) >>! tpApp . J []+ arg <- tpatom+ return (foldr (\op t -> op [t]) arg ops)+ tpapp' [t] = option t $ do+ tc <- qtypidp+ tpapp' [tpApp tc [t]]+ tpapp' ts = do+ tc <- qtypidp+ tpapp' [tpApp tc ts]+ --+ tpvar = do+ (v,tv) <- paramVp+ con <- option tpVar (tpRow <$ ellipsis)+ return (con tv v)+ --+ tpvariant = brackets $+ tpApp (qident tnVariant) . (:[]) <$> (antiblep <|> tpvar)+ tprecord = braces $+ tpApp (qident tnRecord) . (:[]) <$> (antiblep <|> tpvar)++-- | A let or let rec declaration+letp :: Tag i => P (Decl i)+letp = do+ reserved "let"+ choice [+ do+ reserved "rec"+ dcLetRec <$> antilist1p (reserved "and") bindingp,+ do+ f <- varidp+ args <- buildargsp+ annot <- buildannotp+ reservedOp "="+ e <- args . annot <$> exprp+ return (dcLet (paVar f) e),+ dcLet <$> pattp+ <* reservedOp "="+ <*> exprp+ ]++-- An abstype group+absTysp :: Tag i => P [AbsTy i]+absTysp = antilist1p (reserved "and") $ absTyp++-- A single abstype+absTyp :: Tag i => P (AbsTy i)+absTyp = addLoc $ antiblep <|> do+ ((arity, tvs), name) <- tyProtp >>! first unzip+ quals <- qualsp+ reservedOp "="+ alts <- altsp+ return (absTy arity quals (tdDat name tvs alts))++-- A type declaration parameter, consisting of a variance and a tyvar+paramVp :: Tag i => P (Variance, TyVar i)+paramVp = try $ (,) <$> variancep <*> tyvarp++-- A variance mark+variancep :: P Variance+variancep = do+ qvariance ← option Invariant (QInvariant <$ markQVariant)+ sign ← option Invariant $ choice+ [ Covariant <$ markCovariant+ , Contravariant <$ markContravariant+ , Omnivariant <$ markOmnivariant+ , Invariant <$ markInvariant ]+ return (qvariance ⊓ sign)+ <?> "variance marker"++-- A qualifier annotation for a type declaration+qualsp :: Tag i => P (QExp i)+qualsp = option minBound $+ (reserved "qualifier" <|> reservedOp ":") *> qExpp++-- A qualifier expression+qExpp :: Tag i => P (QExp i)+qExpp = "qualifier expression" @@ qexp where+ qexp = addLoc $+ chainl1 qatom (addLoc $ qeJoin <$ (void comma <|> qjoinArr))+ qatom = addLoc $+ qeLit Qu <$ qualU+ <|> qeLit Qa <$ qualA+ <|> clean <$> tyvarp+ <|> qeLid <$> lidp+ <|> antiblep+ <|> parens qexp+ qeLid = qeVar . (TV <-> Qa <-> bogus)+ clean (TV _ Qu _) = minBound+ clean tv = qeVar tv++altsp :: Tag i => P [(ConId i, Maybe (Type i))]+altsp = sepBy1 altp (reservedOp "|")++altp :: Tag i => P (ConId i, Maybe (Type i))+altp = do+ k <- try $ conidp <* try (dot *> pzero <|> punit)+ t <- optionMaybe $ do+ reserved "of"+ typep+ return (k, t)++exprp :: Tag i => P (Expr i)+exprp = exprpP precStart++exprpP :: Tag i => Int -> P (Expr i)+exprpP p = mark $ case () of+ _ | p == precStart → choice+ [ do reserved "let"+ choice+ [ exLetRec <$ reserved "rec"+ <*> antilist1p (reserved "and") bindingp+ <* reserved "in"+ <*> exprp+ , exLet <$> (paVar <$> varidp)+ <*> (buildargsp <*>+ (buildannotp <* reservedOp "=" <*> exprp))+ <* reserved "in"+ <*> exprp+ , exLet <$> pattp+ <* reservedOp "="+ <*> exprp+ <* reserved "in"+ <*> exprp+ , reserved "let" *> unexpected "let"+ , exLetDecl <$> declp+ <* reserved "in"+ <*> exprp ],+ do reserved "if"+ ec <- exprp+ clt <- addLoc $ do+ reserved "then"+ caClause (paCon idTrueValue Nothing)+ <$> exprp+ clf <- addLoc $ do+ reserved "else"+ caClause (paCon idFalseValue Nothing)+ <$> exprp+ return (exCase ec [clt, clf]),+ do reserved "match"+ e1 <- exprp+ reserved "with"+ choice [+ exCase e1 <$> antiblep,+ do+ optional (reservedOp "|")+ clauses <- flip sepBy1 (reservedOp "|") casealtp+ return (exCase e1 clauses) ],+ do reserved "try"+ e1 <- exprp+ reserved "with"+ optional (reservedOp "|")+ clauses <- sepBy1 <-> reservedOp "|" $ addLoc $ do+ caClause . paCon (qident "Left") . Just+ <$> pattp+ <* arrow+ <*> exprp+ let tryQ = qident $+ "INTERNALS.Exn.tryfun"+ return $+ exCase (exApp (exVar tryQ)+ (exAbs paWild e1)) $+ caClause (paCon (qident "Right")+ (Just (paVar (ident "x"))))+ (exVar (qident "x"))+ :+ clauses +++ [caClause+ (paCon (qident "Left")+ (Just (paVar (ident "e"))))+ (exApp (exVar (qident "INTERNALS.Exn.raise"))+ (exVar (qident "e")))+ ],+ lambda *> buildargsp <* arrow <*> exprp,+ next ]+ | p == precExSemi → do+ e1 <- next+ choice+ [ do semi+ e2 <- exprp+ return (exSeq e1 e2),+ return e1 ]+ | p == precCast → do+ e1 <- next+ anns <- many $ do+ b <- False <$ colon+ <|> True <$ reservedOp ":>"+ t2 <- typep+ return (t2, b)+ return (foldl (uncurry . exCast) e1 anns)+ | p == precTySemi →+ next+ | p == precApp →+ choice [+ exCon <$> qconidp <*> antioptp next,+ exInj <$> varinjp <*> antioptp next,+ exEmb <$> varembp <*> next,+ chainl1 next (addLoc (return exApp))+ ]+ | p == precSel → do+ foldl' exSel <$> next <*> many (dot *> llabelp)+ | p == precBang → do+ ops <- many $ addLoc $ exBVar <$> varopp (Right precBang)+ arg <- next+ return (foldr exApp arg ops)+ | p == precCom →+ foldl1 exPair <$> commaSep1 next+ | p > precMax → choice+ [+ exVar <$> qvaridp,+ exCon <$> qconidp <*> pure Nothing,+ exLit <$> litp,+ antiblep,+ brackets (listexp <|> pure exNil),+ parens (exprpP precMin <|> pure exUnit),+ recordp+ ]+ | p == precCaret+ -> chainr1last next+ (opappp (Right p) <|> opconsp exCon exPair)+ exprp+ | Just (Left _) <- fixities p ->+ chainl1last next (opappp (Left p)) exprp+ | Just (Right _) <- fixities p ->+ chainr1last next (opappp (Right p)) exprp+ | otherwise → next+ where+ next = exprpP (p + 1)+ mark = ("expression" @@)++-- | The body of a list.+listexp ∷ Tag i ⇒ P (Expr i)+listexp = foldr exCons exNil <$> commaSep1 exprp++-- | Parse a record expression+recordp :: Tag i ⇒ P (Expr i)+recordp = plusbraces (recordbodyp True <|> pure exNilRecord)+ <|> braces (recordbodyp False <|> pure exNilRecord)++-- | Parse a record expression body+recordbodyp :: Tag i => Bool → P (Expr i)+recordbodyp additive = "record field" @@ do+ fields ← antilist1p comma fieldp+ end ← reservedOp "|" *> exprp+ <|> pure exNilRecord+ return (exRec additive fields end)++-- | Parse a record field+fieldp :: Tag i ⇒ P (Field i)+fieldp = "record field" @@ antiblep <|> do+ lab ← llabelp+ e ← option (exBVar (VarId (uidToLid lab))) $+ buildargsp <*> (buildannotp <* reservedOp "=" <*> exprp)+ return (fdField lab e)++-- Parse a match clause+casealtp :: Tag i => P (CaseAlt i)+casealtp = "match clause" @@ antiblep <|>+ caClause <$> pattp <* arrow <*> exprp+ <|> caPrj <$> varembp <*> antioptp pattp <* arrow <*> exprp++-- Parse a single let rec binding+bindingp :: Tag i => P (Binding i)+bindingp = "let rec binding" @@ antiblep <|>+ bnBind <$> varidp+ <*> (buildargsp+ <*> (buildannotp+ <* reservedOp "="+ <*> exprp))++-- Parse an infix operator at given precedence+opappp :: Tag i => Prec -> P (Expr i -> Expr i -> Expr i)+opappp p = do+ op <- addLoc (exBVar <$> varopp p)+ return (\e1 e2 -> op `exApp` e1 `exApp` e2)++-- Parse list cons+opconsp :: Tag i => (QConId i -> Maybe a -> a) → (a -> a -> a) →+ P (a -> a -> a)+opconsp con pair = cons *> return (con idConsList . Just <$$> pair)++-- Parse some number of argument patterns and return the function+-- that adds them to a body expression to build a lambda.+buildargsp :: Tag i => P (Expr i -> Expr i)+buildargsp = (foldr exAbs <->) <$> many (pattpP (precApp + 1))++-- Parse an optional type annotation and return the function that+-- adds it as an ascription on an expression.+buildannotp :: Tag i => P (Expr i -> Expr i)+buildannotp = do+ mt <- antioptaroundp (colon *>) typep+ return $ case mt of+ Nothing → id+ Just t → \e → exCast e t False++-- A pattern+pattp :: Tag i => P (Patt i)+pattp = pattpP precStart++pattpP ∷ Tag i ⇒ Int → P (Patt i)+pattpP p = mark $ case () of+ _ | p == precCast →+ foldl paAnn <$> next <*> many (colon *> typep)+ | p == precEq → do+ x <- next+ choice+ [ do+ reserved "as"+ y <- varidp+ return (paAs x y),+ return x+ ]+ | p == precApp →+ choice [+ paCon <$> qconidp <*> antioptp next,+ paInj <$> varinjp <*> antioptp next,+ next+ ]+ | p == precBang →+ option id (paBang <$ bang) <*> next+ | p == precCom →+ foldl1 paPair <$> commaSep1 next+ | p == precCaret →+ chainr1last next (opconsp paCon paPair) pattp+ | p > precMax → choice+ [+ paWild <$ reserved "_",+ paVar <$> varidp,+ paCon <$> qconidp <*> pure Nothing,+ paInj <$> varinjp <*> pure Nothing,+ paLit <$> litp,+ antiblep,+ brackets (listpap <|> pure paNil),+ braces recordpap,+ parens (pattpP precMin <|> pure paUnit)+ ]+ | otherwise → next+ where+ next = pattpP (p + 1)+ mark = ("pattern" @@)++-- | The body of a list.+listpap ∷ Tag i ⇒ P (Patt i)+listpap = foldr paCons paNil <$> commaSep1 pattp++recordpap ∷ Tag i ⇒ P (Patt i)+recordpap = do+ flds ← commaSep1 $ do+ lab ← llabelp+ π ← option (paVar (VarId (uidToLid lab))) (reservedOp "=" *> pattp)+ return (lab, π)+ ext ← option paWild (reservedOp "|" *> pattp)+ return (foldr (uncurry paRec) ext flds)++litp :: P Lit+litp = (<?> "literal") $ choice [+ integerOrFloat >>! either LtInt LtFloat,+ charLiteral >>! LtChar,+ stringLiteral >>! LtStr,+ antiblep+ ]++finish :: P a -> P a+finish p = do+ optional whiteSpace+ r <- p+ eof+ return r++-- | Parse a program+parseProg :: Tag i => P (Prog i)+-- | Parse a REPL line+parseRepl :: Tag i => P [Decl i]+-- | Parse a sequence of declarations+parseDecls :: Tag i => P [Decl i]+-- | Parse a declaration+parseDecl :: Tag i => P (Decl i)+-- | Parse a module expression+parseModExp :: Tag i => P (ModExp i)+-- | Parse a type declaration+parseTyDec :: Tag i => P (TyDec i)+-- | Parse a abstype declaration+parseAbsTy :: Tag i => P (AbsTy i)+-- | Parse a type+parseType :: Tag i => P (Type i)+-- | Parse a type pattern+parseTyPat :: Tag i => P (TyPat i)+-- | Parse a qualifier expression+parseQExp :: Tag i => P (QExp i)+-- | Parse an expression+parseExpr :: Tag i => P (Expr i)+-- | Parse a pattern+parsePatt :: Tag i => P (Patt i)+-- | Parse a case alternative+parseCaseAlt :: Tag i => P (CaseAlt i)+-- | Parse a let rec binding+parseBinding :: Tag i => P (Binding i)+-- | Parse a record field+parseField :: Tag i => P (Field i)+-- | Parse a signature+parseSigExp :: Tag i => P (SigExp i)+-- | Parse a signature item+parseSigItem :: Tag i => P (SigItem i)++parseProg = finish progp+parseRepl = finish replp+parseDecls = finish declsp+parseDecl = finish declp+parseModExp = finish modexpp+parseTyDec = finish tyDecp+parseAbsTy = finish absTyp+parseType = finish typep+parseTyPat = finish typatp+parseQExp = finish qExpp+parseExpr = finish exprp+parsePatt = finish pattp+parseCaseAlt = finish casealtp+parseBinding = finish bindingp+parseField = finish fieldp+parseSigExp = finish sigexpp+parseSigItem = finish sigitemp++-- Convenience functions for quick-and-dirty parsing:++-- | Parse a program+pp :: String -> Prog Renamed+pp = makeQaD parseProg++-- | Parse a sequence of declarations+pds :: String -> [Decl Renamed]+pds = makeQaD parseDecls++-- | Parse a declaration+pd :: String -> Decl Renamed+pd = makeQaD parseDecl++pme :: String -> ModExp Renamed+pme = makeQaD parseModExp++-- | Parse a type declaration+ptd :: Tag i => String -> TyDec i+ptd = makeQaD parseTyDec++-- | Parse a type+pt :: String -> Type Renamed+pt = makeQaD parseType++-- | Parse a type pattern+ptp :: String -> TyPat Renamed+ptp = makeQaD parseTyPat++-- | Parse a qualifier expression+pqe :: String -> QExp Renamed+pqe = makeQaD parseQExp++-- | Parse an expression+pe :: String -> Expr Renamed+pe = makeQaD parseExpr++-- | Parse a pattern+px :: String -> Patt Renamed+px = makeQaD parsePatt++{-+deriving instance Show (Expr' i)+deriving instance Show (CaseAlt' i)+deriving instance Show (Decl' i)+deriving instance Show (Binding' i)+deriving instance Show (AbsTy' i)+deriving instance Show (ModExp' i)+deriving instance Show (SigExp' i)+deriving instance Show (TyDec' i)+deriving instance Show (TyPat' i)+deriving instance Show (SigItem' i)+deriving instance Show (Patt' i)+deriving instance Show (Type' i)+deriving instance Show (QExp' i)+deriving instance Show (Prog' i)+deriving instance Show Lit+instance Show a ⇒ Show (N i a) where showsPrec = showsPrec <$.> view+-}++makeQaD :: P a -> String -> a+makeQaD parser =+ either (error . show) id . runParser parser state0 "<string>"+
− src/Syntax/Patt.hs
@@ -1,121 +0,0 @@-{-# LANGUAGE- DeriveDataTypeable,- FlexibleInstances,- MultiParamTypeClasses,- NoMonomorphismRestriction,- TemplateHaskell,- TypeFamilies,- TypeSynonymInstances #-}-module Syntax.Patt (- Patt'(..), Patt, PattNote(..), newPatt,- paWild, paVar, paCon, paPair, paLit, paAs, paPack, paAnti,- dtv-) where--import Meta.DeriveNotable-import Syntax.Notable-import Syntax.Anti-import Syntax.Ident-import Syntax.Lit--import qualified Data.Set as S-import Data.Generics (Typeable, Data)--type Patt i = N (PattNote i) (Patt' i)---- | Patterns-data Patt' i- -- | wildcard- = PaWild- -- | variable pattern- | PaVar (Lid i)- -- | datacon, possibly with parameter, possibly an exception- | PaCon (QUid i) (Maybe (Patt i))- -- | pair pattern- | PaPair (Patt i) (Patt i)- -- | literal pattern- | PaLit Lit- -- | bind an identifer and a pattern (@as@)- | PaAs (Patt i) (Lid i)- -- | existential opening- | PaPack (TyVar i) (Patt i)- -- | antiquote- | PaAnti Anti- deriving (Typeable, Data)--data PattNote i- = PattNote {- -- | source location- ploc_ :: !Loc,- -- | defined variables- pdv_ :: S.Set (Lid i),- -- | defined type variables- pdtv_ :: S.Set (TyVar i)- }- deriving (Typeable, Data)--instance Locatable (PattNote i) where- getLoc = ploc_--instance Relocatable (PattNote i) where- setLoc note loc = note { ploc_ = loc }--instance Notable (PattNote i) where- newNote = PattNote bogus S.empty S.empty--newPatt :: Id i => Patt' i -> Patt i-newPatt p0 = flip N p0 $ case p0 of- PaWild ->- newNote {- pdv_ = S.empty,- pdtv_ = S.empty- }- PaVar x ->- newNote {- pdv_ = S.singleton x,- pdtv_ = S.empty- }- PaCon _ Nothing ->- newNote {- pdv_ = S.empty,- pdtv_ = S.empty- }- PaCon _ (Just x) ->- newNote {- pdv_ = dv x,- pdtv_ = dtv x- }- PaPair x y ->- newNote {- pdv_ = dv x `S.union` dv y,- pdtv_ = dtv x `S.union` dtv y- }- PaLit _ ->- newNote {- pdv_ = S.empty,- pdtv_ = S.empty- }- PaAs x y ->- newNote {- pdv_ = S.insert y (dv x),- pdtv_ = dtv x- }- PaPack tv x ->- newNote {- pdv_ = dv x,- pdtv_ = S.insert tv (dtv x)- }- PaAnti a ->- newNote {- pdv_ = antierror "dv" a,- pdtv_ = antierror "dtv" a- }--instance Id i => Dv (N (PattNote i) a) i where- dv = pdv_ . noteOf--dtv :: Id i => Patt i -> S.Set (TyVar i)-dtv = pdtv_ . noteOf--deriveNotable 'newPatt (''Id, [0]) ''Patt-
+ src/Syntax/Ppr.hs view
@@ -0,0 +1,638 @@+-- | Pretty-printing+module Syntax.Ppr (+ pprTyApp,+ -- * Re-exports+ module Syntax.PprClass,+ module Syntax.Prec+) where++import Meta.Quasi+import Syntax.PprClass+import Syntax.Prec+import AST+import Util++import qualified Syntax.Strings as Strings+import Data.Loc++import Prelude ()+import Data.List (sortBy)++instance IsInfix (Type i) where+ isInfix [ty| ($_, $_) $lid:n |] = isOperator n+ isInfix [ty| $_ -[$_]> $_ |] = True+ isInfix _ = False++-- | For printing infix expressions. Given a splitter function that+-- splits expressions into a left operand, operator name, and right+-- operand (if possible), and an expression to print, pretty-prints+-- the expression, but only if there is one level of infix to be+-- done.+pprInfix :: Ppr a =>+ (a -> Maybe (a, String, Maybe a)) ->+ a -> Maybe Doc+pprInfix inspect x0+ | Just (x1, op, Nothing) <- inspect x0+ , precOp op == Right precBang+ = let rloop x'+ | Just (x1', op', Nothing) <- inspect x'+ , precOp op == Right precBang+ = first (op':) (rloop x1')+ | otherwise+ = ([], x')+ (ops, x) = first (op:) (rloop x1)+ in Just $+ fsep (mapTail (nest 2) $ map text ops)+ <> pprPrec precBang x+ | Just (_, op, Just _) <- inspect x0+ , isOperator (ident op :: Lid Raw)+ , p <- precOp op+ , p /= Right precBang+ = Just $+ prec (id|||id $ p) $+ fcat $ mapTail (nest 2) $ loop p mempty x0+ | otherwise+ = Nothing+ where+ loop p suf x+ | Just (x1, op, Just x2) <- inspect x+ , precOp op == p+ = case precOp op of+ Left _ -> loop p (oper op) x1 ++ [ppr1 x2 <> suf]+ Right _ -> ppr1 x1 <> oper op : loop p suf x2+ loop _ suf x = [ ppr x <> suf ]+ oper s = case s of+ '@':_ -> text s+ "\\/" -> text Strings.join+ ';':_ -> text s <> space+ _ -> space <> text s <> space++instance Ppr (Type i) where+ ppr [ty| $t1 -> $t2 |]+ = prec precArr $+ sep [ ppr1 t1, text Strings.uArrow <+> pprRight t2 ]+ ppr [ty| $t1 -[$q]> $t2 |]+ = prec precArr $+ sep [ ppr1 t1,+ text Strings.arrowPre <> ppr0 q <>+ text Strings.arrowPost <+> pprRight t2 ]+ ppr [ty| U |] = char 'U'+ ppr [ty| A |] = char 'A'+ ppr [ty| [ $t ] |]+ = atPrec precStart $+ pprVariantRow (lbrack <+>) t (<+> rbrack)+ ppr [ty| {+ $t +} |] = pprRecordType "{+" t "+}"+ ppr [ty| { $t } |] = pprRecordType "{" t "}"+ ppr [ty| $t ... |] = prec precApp $ sep [ ppr t, text Strings.ellipsis ]+ ppr [ty| $t $qtid:n |]+ | show n == tnRowHole+ = brackets $ ppr0 t+ ppr t@[ty| ($list:ts) $qtid:n |]+ | Just doc <- pprInfix unfoldType t+ = doc+ | null ts = ppr n+ | otherwise = prec precApp $ sep [ ppr ts, ppr n ]+ ppr [ty| '$x |] = ppr x+ ppr [ty| $quant:qu '$x. $t |]+ = prec precDot $+ ppr qu <+>+ fsep (map ppr1 tvs) <>+ char '.'+ >+> ppr body+ where (tvs, body) = unfoldTyQu qu [ty| $quant:qu '$x. $t |]+ ppr [ty| mu '$x. $t |]+ = prec precDot $+ text Strings.mu <+>+ ppr1 x <>+ char '.'+ >+> ppr t+ ppr t@[ty| `$uid:_ of $_ | $_ |]+ = pprVariantRow id t id+ ppr [ty| $anti:a |] = ppr a++unfoldType :: Type i -> Maybe (Type i, String, Maybe (Type i))+unfoldType [ty| ($t1, $t2) $name:n |] = Just (t1, n, Just t2)+unfoldType [ty| $t1 $name:n |] = Just (t1, n, Nothing)+unfoldType _ = Nothing++pprVariantRow ∷ (Doc → Doc) → Type i → (Doc → Doc) → Doc+pprVariantRow pre t post =+ case items' ++ end' of+ [] → pre (post mempty)+ docs → prec precStart .+ sep .+ mapHead pre .+ mapLast post .+ mapTail (char '|' <+>) $+ docs+ where+ (items, end) = unfoldTyRow t+ items' = [ char '`' <> ppr ni <+>+ case ti of+ [ty| unit |] → mempty+ [ty| INTERNALS.PrimTypes.unit |] → mempty+ _ → text "of" <+> ppr1 ti+ | (ni, ti) ← sortBy (compare`on`show.fst) items ]+ end' = case end of+ [ty| $qtid:n |] | show n == tnRowEnd+ → []+ _ → [ppr1 end]++pprRecordType ∷ String → Type i → String → Doc+pprRecordType lb t rb = case items' ++ end' of+ [] → text lb <> text rb+ docs → atPrec precStart .+ fsep .+ mapHead (text lb <+>) .+ mapTail (nest 2) .+ mapLast (<+> text rb) $+ docs+ where+ (uitems, end) = unfoldTyRow t+ items = first uidToLid <$> uitems+ items' = punctuate comma+ [ ppr ni <> colon <+> ppr1 ti+ | (ni, ti) ← sortBy (compare`on`show.fst) items ]+ end' = case end of+ [ty| $qtid:n |] | show n == tnRowEnd+ → []+ _ → [(if null items' then mempty else char '|')+ <+> ppr1 end]++instance Ppr (TyPat i) where+ ppr tp0 = case tp0 of+ _ | Just doc <- pprInfix unfoldTyPat tp0+ -> doc+ N _ (TpVar tv var) -> pprParamV var tv+ N _ (TpRow tv var) -> pprParamV var tv <+> text Strings.ellipsis+ [tpQ| [ $tp ] |] -> lbrack <+> ppr0 tp <+> rbrack+ [tpQ| { $tp } |] -> lbrace <+> ppr0 tp <+> rbrace+ [tpQ| $qtid:ql |] -> ppr ql+ [tpQ| ($list:tps) $qtid:ql |]+ -> prec precApp $ sep [ppr tps, ppr ql]+ [tpQ| $antiP:a |] -> ppr a++unfoldTyPat :: TyPat i -> Maybe (TyPat i, String, Maybe (TyPat i))+unfoldTyPat [tpQ| ($t1, $t2) $name:n |] = Just (t1, n, Just t2)+unfoldTyPat [tpQ| $t1 $name:n |] = Just (t1, n, Nothing)+unfoldTyPat _ = Nothing++instance Ppr (QExp i) where+ ppr [qeQ| $qlit:qu |] = ppr qu+ ppr [qeQ| $qvar:v |] = ifPrec (> 0)+ (ppr v)+ (ppr (tvname v))+ ppr [qeQ| $qe1, $qe2 |] = ifPrec (> 0)+ (ppr qe1 <+> text Strings.join <+> ppr qe2)+ (ppr qe1 <> comma <> ppr qe2)+ ppr [qeQ| $anti:a |] = ppr a++instance Ppr (Prog i) where+ ppr [prQ| $list:ms |] = vcat (map ppr0 ms)+ ppr [prQ| $expr:e |] = ppr e+ ppr [prQ| $list:ms in $e |] = vcat (map ppr0 ms) $+$+ (text "in" >+> ppr e)++instance Ppr (Decl i) where+ ppr [dc| let $lid:x = $e |] =+ prec precDot $+ pprLet (text "let" <+> ppr x) e False+ ppr [dc| let $x = $e |] =+ prec precDot $+ text "let" <+> ppr x <+> equals+ >+> ppr e+ ppr [dc| let rec $list:bs |] =+ prec precDot $+ text "let" <+>+ vcat (zipWith pprBinding ("rec" : repeat "and") bs)+ ppr [dc| type $tid:lhs = type $qtid:rhs |] =+ text "type" <+> ppr lhs <+> equals <+> text "type" <+> ppr rhs+ ppr [dc| type $list:tds |] = pprTyDecs tds+ ppr [dc| abstype $list:ats0 with $list:ds end |] =+ case ats0 of+ [] ->+ vcat [+ text "abstype with",+ nest 2 $ vcat (map ppr ds),+ text "end"+ ]+ at:ats ->+ vcat [+ vcat (text "abstype" <+> pprAbsTy at :+ [ nest 4 $ text "and" <+> pprAbsTy ati | ati <- ats ])+ <+> text "with",+ nest 2 $ vcat (map ppr ds),+ text "end"+ ]+ ppr [dc| open $b |] = pprModExp (text "open" <+>) b+ ppr [dc| module $uid:n : $s = $b |] = pprModExp add1 b where+ add1 body = pprSigExp add2 s <+> equals <+> body+ add2 body = text "module" <+> ppr n <+> colon <+> body+ ppr [dc| module $uid:n = $b |] = pprModExp add b where+ add body = text "module" <+> ppr n <+> equals <+> body+ ppr [dc| module type $uid:n = $s |] = pprSigExp add s where+ add body = text "module type" <+> ppr n <+> equals <+> body+ ppr [dc| local $list:d0 with $list:d1 end |] =+ vcat [+ text "local",+ nest 2 (vcat (map ppr d0)),+ text "with",+ nest 2 (vcat (map ppr d1)),+ text "end"+ ]+ ppr [dc| exception $uid:n of $opt:mt |] =+ pprExcDec n mt+ ppr [dc| $anti:a |] = ppr a++pprTyDecs :: [TyDec i] -> Doc+pprTyDecs tds =+ vcat $+ mapHead (text "type" <+>) $+ mapTail ((nest 1) . (text "and" <+>)) $+ map ppr tds++pprExcDec :: Uid i -> Maybe (Type i) -> Doc+pprExcDec u Nothing =+ text "exception" <+> ppr u+pprExcDec u (Just t) =+ text "exception" <+> ppr u <+> text "of" <+> ppr t++instance Ppr (TyDec i) where+ ppr td = case view td of+ TdAbs n ps vs gs qs -> pprProtoV n vs ps+ >?> pprQuals qs+ >?> pprGuards gs+ TdSyn n [(ps,t)] -> pprProto n ps >+> equals <+> ppr t+ TdSyn n cs -> vcat [ char '|' <+> each ci | ci <- cs ]+ where+ each (ps, rhs) = pprProto n ps+ >+> equals <+> ppr rhs+ TdDat n ps alts -> pprProtoV n (repeat Invariant) ps+ >?> pprAlternatives alts+ TdAnti a -> ppr a++pprAbsTy :: AbsTy i -> Doc+pprAbsTy at = case view at of+ AbsTy variances qual (N _ (TdDat name params alts)) ->+ pprProtoV name variances params+ >?> pprQuals qual+ >?> pprAlternatives alts+ AbsTy _ _ td -> ppr td -- shouldn't happen (yet)+ AbsTyAnti a -> ppr a++pprProto :: TypId i -> [TyPat i] -> Doc+pprProto n ps = ppr (tpApp (J [] n) ps)++pprProtoV :: TypId i -> [Variance] -> [TyVar i] -> Doc+pprProtoV n vs tvs = pprProto n (zipWith tpVar tvs vs)++pprParamV :: Variance -> TyVar i -> Doc+pprParamV Invariant tv = ppr tv+pprParamV v tv = ppr v <> ppr tv++pprGuards :: [TyVar i] -> Doc+pprGuards [] = mempty+pprGuards tvs = text "rec" <+> fsep (punctuate comma (ppr <$> tvs))++pprQuals :: QExp i -> Doc+pprQuals [qeQ| U |] = mempty+pprQuals qs = text ":" <+> pprPrec precApp qs++pprAlternatives :: [(ConId i, Maybe (Type i))] -> Doc+pprAlternatives [] = equals+pprAlternatives (a:as) = sep $+ equals <+> alt a : [ char '|' <+> alt a' | a' <- as ]+ where+ alt (u, Nothing) = ppr u+ alt (u, Just t) = ppr u <+> text "of" <+> pprPrec precDot t++pprModExp :: (Doc -> Doc) -> ModExp i -> Doc+pprModExp add modexp = case modexp of+ [meQ| $qmid:n |] -> add (ppr n)+ [meQ| $qmid:n $list:qls |] ->+ add (ppr n) <+>+ pprStyleList listStyleBrack qls+ [meQ| struct $list:ds end |] ->+ add (text "struct")+ $$ nest 2 (vcat (map ppr0 ds))+ $$ text "end"+ [meQ| $me1 : $se2 |] ->+ pprSigExp (pprModExp add me1 <+> colon <+>) se2+ [meQ| $anti:a |] -> add (ppr a)++instance Ppr (SigExp i) where+ ppr = pprSigExp id++pprSigExp :: (Doc -> Doc) -> SigExp i -> Doc+pprSigExp add se0 = body >+> withs where+ (wts, se1) = unfoldSeWith se0+ body = case se1 of+ [seQ| $qsid:n |] -> add (ppr n)+ [seQ| $qsid:n $list:qls |] ->+ add (ppr n) <+>+ pprStyleList listStyleBrack qls+ [seQ| sig $list:sgs end |] ->+ add (text "sig")+ $$ nest 2 (vcat (map ppr0 sgs))+ $$ text "end"+ [seQ| $_ with type $list:_ $qtid:_ = $_ |] ->+ error "BUG! can't happen in pprSigExp"+ [seQ| $anti:a |] -> add (ppr a)+ withs =+ atPrec 0 $ sep $+ mapHead (text "with type" <+>) $+ mapTail ((nest 6) . (text "and" <+>)) $+ [ pprTyApp tc tvs <+> equals <+> ppr t+ | (tc, tvs, t) <- wts ]++instance Ppr (SigItem i) where+ ppr sg0 = case sg0 of+ [sgQ| val $lid:n : $t |] ->+ text "val" <+> ppr n >+> colon <+> ppr t+ [sgQ| type $list:tds |] ->+ pprTyDecs tds+ [sgQ| type $tid:lhs = type $qtid:rhs |] ->+ text "type" <+> ppr lhs <+> equals <+> text "type" <+> ppr rhs+ [sgQ| module $uid:u : $s |] ->+ pprSigExp add s where+ add body = text "module" <+> ppr u <+> colon <+> body+ [sgQ| module type $uid:u = $s |] ->+ pprSigExp add s where+ add body = text "module type" <+> ppr u <+> equals <+> body+ [sgQ| include $s |] ->+ pprSigExp (text "include" <+>) s+ [sgQ| exception $uid:u of $opt:mt |] ->+ pprExcDec u mt+ [sgQ| $anti:a |] ->+ ppr a++instance Ppr (Expr i) where+ ppr e0 = case e0 of+ _ | Just doc <- pprInfix unfoldExpr e0+ -> doc+ | Just es <- unfoldExList e0+ -> pprStyleList listStyleBrack es+ [ex| { } |] -> braces mempty -- Must come before ExVar case+ [ex| $e1 :: $e2 |] -> prec precCaret $+ ppr1 e1 <+> text Strings.cons <+> ppr e2+ [ex| $qvid:x |] -> ppr x+ [ex| $lit:lt |] -> ppr lt+ [ex| $qcid:x |] -> ppr x+ [ex| $qcid:x $e |] -> prec precApp (sep [ ppr x, ppr1 e ])+ [ex| `$uid:x |] -> char '`' <> ppr x+ [ex| `$uid:x $e |] -> prec precApp (sep [ char '`' <> ppr x, ppr1 e ])+ [ex| #$uid:x $e |] -> prec precApp (sep [ char '#' <> ppr x, ppr1 e ])+ [ex| if $ec then $et else $ef |] ->+ prec precDot $+ sep [ text "if" <+> ppr ec,+ nest 2 $ text "then" <+> ppr0 et,+ nest 2 $ text "else" <+> ppr ef ]+ [ex| $_; $_ |] ->+ prec precExSemi $+ sep (unfold e0)+ where unfold [ex| $e1; $e2 |] = ppr1 e1 <> semi : unfold e2+ unfold e = [ ppr0 e ]+ [ex| let $lid:x = $e1 in $e2 |] ->+ prec precDot $+ hangLet (pprLet (text "let" <+> ppr x) e1 True) e2+ [ex| let $x = $e1 in $e2 |] ->+ prec precDot $+ hangLet (text "let" <+> ppr x <+> equals+ >+> ppr e1 <+> text "in")+ e2+ [ex| match $e1 with $list:clauses |] ->+ prec precDot $+ vcat (sep [ text "match",+ nest 2 $ ppr0 e1,+ text "with" ] : map ppr clauses)+ [ex| let rec $list:bs in $e2 |] ->+ prec precDot $+ text "let" <+>+ vcat (zipWith pprBinding ("rec" : repeat "and") bs) $$+ nest 1 (text "in" <+> ppr e2)+ [ex| let $decl:d in $e2 |] ->+ prec precDot $+ hangLet+ (text "let" <+> ppr0 d <+> text "in")+ e2+ [ex| ($e1, $e2) |] ->+ prec precCom $+ sep [ ppr e1 <> comma, ppr1 e2 ]+ [ex| λ $_ → $_ |] ->+ prec precDot $+ hang+ (text Strings.fun <+>+ fsep (pprPrec1 precApp <$> args) <+>+ text Strings.arrow)+ 2+ (ppr body)+ where (args, body) = unfoldExAbs e0+ [ex| $e1 $e2 |]+ -> prec precApp $+ sep [ ppr e1, ppr1 e2 ]+ [ex| ( $e : $t1 :> $t2 ) |] ->+ prec precCast $+ atPrec (precCast + 2) $+ sep [ ppr e,+ colon <+> ppr t1,+ text ":>" <+> ppr t2 ]+ [ex| { $list:flds | $e2 } |] ->+ pprRecord "{" flds e2 "}"+ [ex| {+ $list:flds | $e2 +} |] ->+ pprRecord "{+" flds e2 "+}"+ [ex| $e . $uid:sel |] ->+ prec precSel $+ pprPrec precSel e <> char '.' <> ppr (uidToLid sel)+ [ex| ( $e : $t1 ) |] ->+ prec precCast $+ atPrec (precCast + 2) $+ sep [ ppr e,+ colon <+> ppr t1 ]+ [ex| ( $e :> $t1 ) |] ->+ prec precCast $+ atPrec (precCast + 2) $+ sep [ ppr e,+ text ":>" <+> ppr t1 ]+ [ex| $anti:a |] -> ppr a+ where+ unfoldExpr [ex| ($name:x $e1) $e2 |] = Just (e1, x, Just e2)+ unfoldExpr [ex| $name:x $e1 |] = Just (e1, x, Nothing)+ unfoldExpr _ = Nothing++unfoldExList ∷ Expr i → Maybe [Expr i]+unfoldExList [ex| [] |] = Just []+unfoldExList [ex| [ ] |] = Just []+unfoldExList [ex| $e1 ∷ $e2 |] = (e1 :) <$> unfoldExList e2+unfoldExList _ = Nothing++pprRecord ∷ String → [Field i] → Expr i → String → Doc+pprRecord bl flds e2 br =+ atPrec precStart $+ text bl <+>+ fsep (punctuate comma (ppr <$> flds)+ ++ case e2 of+ [ex|! { } |] → []+ _ → [char '|' <+> ppr e2])+ <+> text br++instance Ppr (Field i) where+ ppr [fdQ| $uid:u = $e |] = pprLet (ppr (uidToLid u)) e False+ ppr [fdQ| $antiF:a |] = ppr a++pprBinding :: String -> Binding i -> Doc+pprBinding kw [bnQ| $lid:x = $e |] = pprLet (text kw <+> ppr x) e True+pprBinding kw [bnQ| $antiB:a |] = text kw <+> ppr a++instance Ppr (CaseAlt i) where+ ppr [caQ| $xi -> $ei |] =+ hang (char '|' <+> ppr xi <+> text Strings.arrow)+ 4+ (ppr ei)+ ppr [caQ| #$uid:lab $opt:mxi -> $ei |] =+ hang (text "| #" <> ppr lab+ <+> maybe mempty (pprPrec (precApp + 1)) mxi+ <+> text Strings.arrow)+ 4+ (ppr ei)+ ppr [caQ| $antiC:a |] = char '|' <+> ppr a++-- | Print a let expression, indenting the body only if the body is+-- not another let expression.+hangLet ∷ Doc → Expr i → Doc+hangLet doc e2 = hang doc (if (isLet e2) then 0 else 2) (ppr e2)+ where+ isLet [ex| $_; $_ |] = False+ isLet [ex| let $_ = $_ in $_ |] = True+ isLet [ex| let rec $list:_ in $_ |] = True+ isLet _ = False++-- | Print the binding and rhs of a let+pprLet :: Doc -> Expr i -> Bool -> Doc+pprLet doc e1 withIn =+ doc <+>+ nest 2 (fsep (pprPrec1 precApp <$> args)) <+>+ maybe mempty (nest 2 . (colon <+>) . ppr0) mannot <+> equals+ >+> ppr rhs <+> if withIn then text "in" else mempty+ where+ (args, rhs, mannot) = resugarLet e1++-- | Given the rhs of a let expression, pull out the arguments and+-- any result-type annotation.+resugarLet ∷ Expr i → ([Patt i], Expr i, Maybe (Type i))+resugarLet e =+ let (args, rhs0) = unfoldExAbs e+ in case rhs0 of+ [ex| $e' : $t |] → (args, e', Just t)+ _ → (args, rhs0, Nothing)++instance Ppr (Patt i) where+ ppr π0 | Just πs ← unfoldPaList π0+ = pprStyleList listStyleBrack πs+ ppr [pa| _ |] = text "_"+ ppr [pa| $lid:l |] = ppr l+ ppr [pa| $x :: $y |] = prec precCaret $+ ppr1 x <+> text Strings.cons <+> ppr y+ ppr [pa| $qcid:qu |] = ppr qu+ ppr [pa| $qcid:qu $x |] = prec precApp $+ ppr qu <+> ppr1 x+ ppr [pa| ($x, $y) |] = prec precCom $+ ppr x <> comma <+> ppr1 y+ ppr [pa| $lit:lt |] = ppr lt+ ppr [pa| $x as $lid:l |] = prec precDot $+ ppr1 x <+> text "as" <+> ppr l+ ppr [pa| `$uid:u |] = char '`' <> ppr u+ ppr [pa| `$uid:u $x |] = prec precApp $+ char '`' <> ppr u <+> ppr1 x+ ppr π0@[pa| { $uid:_ = $_ | $_ } |]+ =+ atPrec precStart $+ char '{' <+>+ fsep (punctuate comma+ [ ppr (uidToLid ui) <+> equals <+> ppr πi+ | (ui, πi) ← flds ]+ ++ case π2 of+ [pa|! _ |] → []+ _ → [char '|' <+> ppr π2])+ <+> char '}'+ where (flds, π2) = unfoldPaRec π0+ ppr [pa| ! $x |] = prec precBang $+ char '!' <> ppr1 x+ ppr [pa| $x : $t |] = prec precCast $+ hang (ppr x)+ 2+ (colon <+> ppr0 t)+ ppr [pa| $anti:a |] = ppr a++unfoldPaList ∷ Patt i → Maybe [Patt i]+unfoldPaList [pa| [] |] = Just []+unfoldPaList [pa| [ ] |] = Just []+unfoldPaList [pa| $π1 ∷ $π2 |] = (π1 :) <$> unfoldPaList π2+unfoldPaList _ = Nothing++instance Ppr Lit where+ ppr (LtInt i) = integer i+ ppr (LtChar c) = text (show c)+ ppr (LtFloat f) = double f+ ppr (LtStr s) = text (show s)+ ppr (LtAnti a) = ppr a++--+-- Helper for pretty-printing type-like things -- doesn't require+-- underlying types, but does need to see the operator name.+--++data PprTyAppHelper i a+ = PTAHBranch (QTypId i) [a]+ | PTAHLeaf a++instance Ppr a => Ppr (PprTyAppHelper i a) where+ ppr (PTAHLeaf a) = ppr a+ ppr _ = error "BUG! in PprTyAppHelper.ppr"++unfoldPTAH :: PprTyAppHelper i a ->+ Maybe (PprTyAppHelper i a, String, Maybe (PprTyAppHelper i a))+unfoldPTAH (PTAHBranch (J [] l) [a, b])+ = Just (PTAHLeaf a, unLid (unTypId l), Just (PTAHLeaf b))+unfoldPTAH (PTAHBranch (J [] l) [a])+ = Just (PTAHLeaf a, unLid (unTypId l), Nothing)+unfoldPTAH _+ = Nothing++pprTyApp :: Ppr a => QTypId i -> [a] -> Doc+pprTyApp ql ts+ | Just doc <- pprInfix unfoldPTAH (PTAHBranch ql ts)+ = doc+pprTyApp ql [] = ppr ql+pprTyApp ql ts = prec precApp $ sep [ ppr ts, ppr ql ]++--+-- Instances+--++instance Show (Prog i) where showsPrec = showFromPpr+instance Show (Decl i) where showsPrec = showFromPpr+instance Show (TyDec i) where showsPrec = showFromPpr+instance Show (Expr i) where showsPrec = showFromPpr+instance Show (Patt i) where showsPrec = showFromPpr+instance Show Lit where showsPrec = showFromPpr+instance Show (Type i) where showsPrec = showFromPpr+instance Show (TyPat i) where showsPrec = showFromPpr+instance Show (QExp i) where showsPrec = showFromPpr+instance Show (SigItem i)where showsPrec = showFromPpr++instance Ppr Loc where pprPrec = pprFromShow+instance Ppr QLit where pprPrec = pprFromShow+instance Ppr Variance where pprPrec = pprFromShow+instance Ppr Quant where pprPrec = pprFromShow+instance Ppr (Lid i) where pprPrec = pprFromShow+instance Ppr (Uid i) where pprPrec = pprFromShow+instance Ppr (TypId i) where pprPrec = pprFromShow+instance Ppr (VarId i) where pprPrec = pprFromShow+instance Ppr (ConId i) where pprPrec = pprFromShow+instance Ppr (ModId i) where pprPrec = pprFromShow+instance Ppr (SigId i) where pprPrec = pprFromShow+instance Ppr (BIdent i)where pprPrec = pprFromShow+instance Ppr (TyVar i) where pprPrec = pprFromShow+instance Ppr Anti where pprPrec = pprFromShow+instance (Show p, Show k) => Ppr (Path p k) where pprPrec = pprFromShow+
+ src/Syntax/PprClass.hs view
@@ -0,0 +1,394 @@+module Syntax.PprClass (+ -- * Documents+ Doc,+ -- * Pretty-printing class+ Ppr(..), IsInfix(..), ListStyle(..), listStyleBrack,+ -- ** Helpers+ ppr0, ppr1, pprPrec1, pprDepth,+ -- ** Context operations+ prec, prec0, mapPrec, prec1, descend, atPrec, atDepth,+ askPrec, ifPrec, askDepth, ifDepth,+ trimList, trimCat,+ -- *** For type name shortening+ TyNames(..), tyNames0,+ setTyNames, askTyNames, enterTyNames, lookupTyNames,+ -- * Pretty-printing combinators+ (>+>), (>?>), ifEmpty,+ vcat, sep, cat, fsep, fcat,+ -- * Renderers+ render, renderS, printDoc, printPpr, hPrintDoc, hPrintPpr,+ -- ** Instantiations of several context-sensitive functions+ -- with the zero context+ isEmpty, renderStyle, fullRender,+ -- ** Instance helpers+ showFromPpr, pprFromShow,+ -- * Alternate printing of 'Maybe'+ MAYBE(..),+ -- * Re-exports+ module Alt.PrettyPrint+) where++import Alt.PrettyPrint hiding ( Doc(..),+ render, isEmpty, renderStyle, fullRender,+ vcat, sep, cat, fsep, fcat )+import qualified Alt.PrettyPrint as P++import Data.Perhaps+import Syntax.Prec+import qualified Syntax.Strings as Strings+import AST.Ident (QTypId, ModId, Renamed)++import System.IO (Handle, stdout, hPutChar, hPutStr)+import qualified Data.Map as M+import qualified Data.Set as S++-- | Context for pretty-printing.+data PprContext+ = PprContext {+ pcPrec :: !Int,+ pcDepth :: !Int,+ pcTyName :: !TyNames+ }++data TyNames =+ TyNames {+ tnLookup :: Int -> QTypId Renamed -> QTypId Renamed,+ tnEnter :: ModId Renamed -> TyNames+ }++-- | Default context+pprContext0 :: PprContext+pprContext0 = PprContext {+ pcPrec = 0,+ pcDepth = -1,+ pcTyName = tyNames0+}++tyNames0 :: TyNames+tyNames0 = TyNames {+ tnLookup = const id,+ tnEnter = const tyNames0+}++type Doc = P.Doc PprContext++data ListStyle + = ListStyle {+ listStyleBegin, listStyleEnd, listStylePunct :: Doc,+ listStyleDelimitEmpty, listStyleDelimitSingleton :: Bool,+ listStyleJoiner :: [Doc] -> Doc+ }++-- | Class for pretty-printing at different types+--+-- Minimal complete definition is one of:+--+-- * 'pprPrec'+--+-- * 'ppr'+class Ppr p where+ -- | Print current precedence+ ppr :: p -> Doc+ -- | Print at the specified enclosing precedence+ pprPrec :: Int -> p -> Doc+ -- | Print a list in the default style+ pprList :: [p] -> Doc+ -- | Print a list in the specified style+ pprStyleList :: ListStyle -> [p] -> Doc+ -- | Style for printing lists+ listStyle :: [p] -> ListStyle+ --+ --+ ppr = asksD pcPrec . flip pprPrec+ pprPrec p = prec p . ppr+ pprList xs = pprStyleList (listStyle xs) xs+ --+ pprStyleList st [] =+ if listStyleDelimitEmpty st+ then listStyleBegin st <> listStyleEnd st+ else mempty+ pprStyleList st [x] =+ if listStyleDelimitSingleton st+ then listStyleBegin st <> ppr0 x <> listStyleEnd st+ else ppr x+ pprStyleList st xs =+ listStyleBegin st <>+ listStyleJoiner st (punctuate (listStylePunct st) (map ppr0 xs))+ <> listStyleEnd st+ --+ listStyle _ = ListStyle {+ listStyleBegin = lparen,+ listStyleEnd = rparen,+ listStylePunct = comma,+ listStyleDelimitEmpty = False,+ listStyleDelimitSingleton = False,+ listStyleJoiner = fsep+ }++-- | Style for printing square-bracketed lists.+listStyleBrack ∷ ListStyle+listStyleBrack = ListStyle {+ listStyleBegin = lbrack,+ listStyleEnd = rbrack,+ listStylePunct = comma,+ listStyleDelimitEmpty = True,+ listStyleDelimitSingleton = True,+ listStyleJoiner = fsep+}++-- | Print at top level.+ppr0 :: Ppr p => p -> Doc+ppr0 = atPrec 0 . ppr++-- | Print at next level.+ppr1 :: Ppr p => p -> Doc+ppr1 = prec1 . ppr++-- | Print at one more than the given level.+pprPrec1 :: Ppr p => Int -> p -> Doc+pprPrec1 = pprPrec . succ++-- | Print to the given depth.+pprDepth :: Ppr p => Int -> p -> Doc+pprDepth d = atDepth d . ppr++-- | Enter the given precedence level, drawing parentheses if necessary,+-- and count it as a descent in depth as well.+prec :: Int -> Doc -> Doc+prec p doc = asksD pcPrec $ \p' ->+ if p' > p+ then descend $ parens (atPrec p doc)+ else atPrec p doc++-- | Enter the given precedence level, drawing parentheses if necessary,+-- and count it as a descent in depth as well. If we enter+-- parentheses, reset the precedence to 0 at most.+prec0 :: Int -> Doc -> Doc+prec0 p doc = asksD pcPrec $ \p' ->+ if p' > p+ then descend $ parens (atPrec (p `min` 0) doc)+ else atPrec p doc++-- | Adjust the precedence with the given function.+mapPrec :: (Int -> Int) -> Doc -> Doc+mapPrec f doc = askPrec (\p -> prec (f p) doc)++-- | Go to the next (tigher) precedence level.+prec1 :: Doc -> Doc+prec1 = mapD (\e -> e { pcPrec = pcPrec e + 1 })++-- | Descend a level, elliding if the level counter runs out+descend :: Doc -> Doc+descend doc = askD $ \e ->+ case pcDepth e of+ -1 -> doc+ 0 -> text Strings.ellipsis+ k -> localD e { pcDepth = k - 1 } doc++-- | Set the precedence, but check or draw parentheses+atPrec :: Int -> Doc -> Doc+atPrec p = mapD (\e -> e { pcPrec = p })++-- | Set the precedence, but check or draw parentheses+atDepth :: Int -> Doc -> Doc+atDepth k = mapD (\e -> e { pcDepth = k })++-- | Find out the precedence+askPrec :: (Int -> Doc) -> Doc+askPrec = asksD pcPrec++-- | A conditional: uses the second argument if the current precedence+-- satisfies the predicate, otherwise the second+ifPrec :: (Int -> Bool) -> Doc -> Doc -> Doc+ifPrec predicate true false =+ askPrec $ \p → if predicate p then true else false++-- | Find out the depth+askDepth :: (Int -> Doc) -> Doc+askDepth = asksD pcDepth++-- | A conditional: uses the second argument if the current depth+-- satisfies the predicate, otherwise the second+ifDepth :: (Int -> Bool) -> Doc -> Doc -> Doc+ifDepth predicate true false =+ askDepth $ \p → if predicate p then true else false++-- | Change the type name lookup function+setTyNames :: TyNames -> Doc -> Doc+setTyNames f = mapD (\e -> e { pcTyName = f })++-- | Retrieve the type name lookup function+askTyNames :: (TyNames -> Doc) -> Doc+askTyNames = asksD pcTyName++-- | Render a document with a module opened+enterTyNames :: ModId Renamed -> Doc -> Doc+enterTyNames u doc = askTyNames $ \tn ->+ setTyNames (tnEnter tn u) doc++-- | Look up a type name in the rendering context+lookupTyNames :: Int -> QTypId Renamed -> (QTypId Renamed -> Doc) -> Doc+lookupTyNames tag ql kont = askTyNames $ \tn ->+ kont (tnLookup tn tag ql)++-- | Trim a list to (about) the given number of elements, with+-- "..." in the middle.+trimList :: Int -> [Doc] -> [Doc]+trimList (-1) ds = ds+trimList n2 ds = if k <= 2 * n+ then ds+ else take n ds ++ text "... " : drop (k - n) ds+ where+ n = (n2 + 1) `div` 2+ k = length ds++-- | Lift a concatenation function to respect depth.+trimCat :: ([Doc] -> Doc) -> [Doc] -> Doc+trimCat xcat docs = asksD pcDepth $ \d -> case d of+ -1 -> xcat docs+ _ -> atDepth ((d + 1) `div` 2) (xcat (trimList d docs))++vcat, sep, cat, fsep, fcat :: [Doc] -> Doc+vcat = trimCat P.vcat+sep = trimCat P.sep+cat = trimCat P.cat+fsep = trimCat P.fsep+fcat = trimCat P.fcat++newtype MAYBE a = MAYBE (Maybe a) deriving (Eq, Ord)++instance Ppr a => Ppr (MAYBE a) where+ ppr (MAYBE Nothing) = text "nothing"+ ppr (MAYBE (Just a)) = ppr a++instance Ppr a => Ppr (Maybe a) where+ ppr Nothing = mempty+ ppr (Just a) = ppr a++instance Ppr a => Ppr (Perhaps a) where+ ppr Nope = mempty+ ppr (Here a) = ppr a++instance (Ppr a, Ppr b) => Ppr (Either a b) where+ ppr (Left a) = prec precApp (text "Left" <+> ppr a)+ ppr (Right a) = prec precApp (text "Right" <+> ppr a)++instance Ppr a => Ppr [a] where+ ppr = pprList++instance (Ppr a, Ppr b) => Ppr (a, b) where+ ppr (a, b) = parens (sep (punctuate comma [ppr0 a, ppr0 b]))++instance (Ppr a, Ppr b, Ppr c) => Ppr (a, b, c) where+ ppr (a,b,c) =+ parens (sep (punctuate comma [ppr0 a, ppr0 b, ppr0 c]))++instance (Ppr a, Ppr b, Ppr c, Ppr d) => Ppr (a, b, c, d) where+ ppr (a,b,c,d) =+ parens (sep (punctuate comma [ppr0 a, ppr0 b, ppr0 c, ppr0 d]))++instance (Ppr k, Ppr v) => Ppr (M.Map k v) where+ ppr m = braces . fsep . punctuate comma $+ [ ppr0 k <> colon <+> ppr0 v+ | (k, v) <- M.toList m ]++instance Ppr a => Ppr (S.Set a) where+ ppr = braces . fsep . punctuate comma . map ppr0 . S.toList++-- | Class to check if a particular thing will print infix. Adds+-- an operation to print at the given precedence only if the given+-- thing is infix. (We use this for printing arrows without too+-- many parens.)+class Ppr a => IsInfix a where+ isInfix :: a -> Bool+ pprRight :: a -> Doc+ pprRight a =+ if isInfix a+ then ppr a+ else ppr0 a++instance Ppr Bool where pprPrec = pprFromShow+instance Ppr Int where ppr = int+instance Ppr Integer where ppr = integer+instance Ppr Double where ppr = double++instance Ppr Char where+ pprPrec = pprFromShow+ pprStyleList _ = text++instance Ppr (P.Doc PprContext) where ppr = id+instance Show (P.Doc PprContext) where showsPrec = showFromPpr++-- Render a document in the preferred style, given a string continuation+renderS :: Doc -> ShowS+renderS doc rest = fullRenderIn pprContext0 PageMode 80 1.1 each rest doc+ where each (Chr c) s' = c:s'+ each (Str s) s' = s++s'+ each (PStr s) s' = s++s'++-- Render a document in the preferred style+render :: Doc -> String+render doc = renderS doc ""++-- Is the document empty (in 'pprContext0')?+isEmpty :: Doc -> Bool+isEmpty = isEmptyIn pprContext0++-- Render in the given style (in 'pprContext0')+renderStyle :: Style -> Doc -> String+renderStyle = renderStyleIn pprContext0++-- Render with the given parameters (in 'pprContext0')+fullRender :: Mode -> Int -> Float ->+ (TextDetails -> a -> a) -> a ->+ Doc -> a+fullRender = fullRenderIn pprContext0++-- Render and display a document in the preferred style+printDoc :: Doc -> IO ()+printDoc = hPrintDoc stdout++-- Pretty-print, render and display in the preferred style+printPpr :: Ppr a => a -> IO ()+printPpr = hPrintPpr stdout++-- Render and display a document in the preferred style+hPrintDoc :: Handle -> Doc -> IO ()+hPrintDoc h = fullRenderIn pprContext0 PageMode 80 1.1 each (putChar '\n')+ where each (Chr c) io = hPutChar h c >> io+ each (Str s) io = hPutStr h s >> io+ each (PStr s) io = hPutStr h s >> io++hPrintPpr :: Ppr a => Handle -> a -> IO ()+hPrintPpr h = hPrintDoc h . ppr++showFromPpr :: Ppr a => Int -> a -> ShowS+showFromPpr p t = renderS (pprPrec p t)++pprFromShow :: Show a => Int -> a -> Doc+pprFromShow p t = text (showsPrec p t "")++--+-- Some indentation operations+--++liftEmpty :: (Doc -> Doc -> Doc) -> Doc -> Doc -> Doc+liftEmpty joiner d1 d2 = askD f where+ f e | isEmptyIn e d1 = d2+ | isEmptyIn e d2 = d1+ | otherwise = joiner d1 d2++ifEmpty :: Doc -> Doc -> Doc -> Doc+ifEmpty dc dt df = askD $ \e ->+ if isEmptyIn e dc+ then dt+ else df++(>+>) :: Doc -> Doc -> Doc+(>+>) = flip hang 2++(>?>) :: Doc -> Doc -> Doc+(>?>) = liftEmpty (>+>)++infixr 5 >+>, >?>+
+ src/Syntax/Prec.hs view
@@ -0,0 +1,80 @@+-- | Operator precdences+--+-- We use operator precedences from Ocaml. The precence and+-- associativity of an operator is determined by its first character.+module Syntax.Prec (+ Prec, precOp, fixities,+ -- * Precedences for reserved operators needed by the parser+ precMin, precStart, precMax, precCast,+ precCom, precDot, precExSemi, precTySemi, precEq, precCaret, precArr,+ precPlus, precStar, precAt, precApp, precBang, precSel,+) where++import Data.Char++-- | Precedence and associativity, e.g. @Right 4@ is right-associative+-- at level 4. Higher precedences bind tighter, with application+-- at precedence 9.+type Prec = Either Int Int++precOp :: String -> Prec+precOp ('*':'*':_) = Right precAt+precOp ('→':_) = Right precArr+precOp ('-':'>':_) = Right precArr+precOp ('-':'o':_) = Right precArr+precOp "-[]>" = Right precArr+precOp (';':_) = Right precTySemi+precOp "⋁" = Right precTySemi+precOp "\\/" = Right precTySemi+precOp "!=" = Left precEq+precOp (c:cs)+ | c `elem` "=<>|&$" = Left precEq+ | c `elem` "*×/%" = Left precStar+ | c `elem` "+-" = Left precPlus+ | c `elem` "^:∷" = Right precCaret+ | c `elem` "@" = Right precAt+ | c `elem` "!~?" = Right precBang+ | otherwise = case generalCategory c of+ CurrencySymbol -> Left precEq+ MathSymbol -> Left precStar+ DashPunctuation -> Left precPlus+ OtherSymbol -> Left precPlus+ ConnectorPunctuation -> Right precCaret+ OtherPunctuation -> Right precAt+ _ -> precOp cs+precOp "" = Left precApp++precMin, precStart, precMax, precCast,+ precCom, precDot, precExSemi, precTySemi, precEq, precCaret, precArr,+ precPlus, precStar, precAt, precApp, precSel, precBang :: Int+precMin = -1+precCom = -1 -- ,+precStart = 0 -- includes "|" for row types+precDot = 1 -- in, else, of, .+precExSemi= 1 -- ; (expressions only)+precCast = 2 -- :>+precArr = 3 -- ->+precEq = 4 -- != = < > | & $ as+precCaret = 5 -- ^ : (infixr)+precPlus = 6 -- - ++precStar = 7 -- % / *+precTySemi= 8 -- ; "\\/" "⋁" (types only)+precAt = 9 -- @ ** (infixr)+precApp = 10 -- f x+precSel = 11 -- record selection+precBang = 12 -- ! ~ ? (prefix)+precMax = 12++{-# INLINE fixities #-}+-- To find out the fixity of a precedence level+fixities :: Int -> Maybe Prec+fixities n+ | n == precArr = Just $ Right precArr+ | n == precEq = Just $ Left precEq+ | n == precCaret = Just $ Right precCaret+ | n == precPlus = Just $ Left precPlus+ | n == precStar = Just $ Left precStar+ | n == precTySemi = Just $ Right precTySemi+ | n == precAt = Just $ Right precAt+ | n == precBang = Just $ Right precBang+ | otherwise = Nothing
+ src/Syntax/Strings.hs view
@@ -0,0 +1,146 @@+-- | Hard-coded strings that depend on whether we're doing unicode.+module Syntax.Strings where++{-# INLINE digits #-}+-- | Subscript numerals for type variables+digits ∷ [Char]++{-# INLINE tvNames #-}+-- | Names to give to type variables+tvNames ∷ [Char]++{-# INLINE fun #-}+{-# INLINE arrow #-}+-- | Term keywords+fun, arrow ∷ String++{-# INLINE all #-}+{-# INLINE ex #-}+{-# INLINE mu #-}+-- | Quantifiers+all, ex, mu ∷ String++{-# INLINE cons #-}+{-# INLINE product #-}+{-# INLINE uArrow #-}+{-# INLINE aArrow #-}+{-# INLINE arrowPre #-}+{-# INLINE arrowPost #-}+{-# INLINE join #-}+-- | Infix type constructors+cons, product, uArrow, aArrow, arrowPre, arrowPost, join ∷ String++{-# INLINE affine #-}+{-# INLINE unlimited #-}+{-# INLINE covariant #-}+{-# INLINE contravariant #-}+{-# INLINE invariant #-}+{-# INLINE omnivariant #-}+{-# INLINE qcovariant #-}+{-# INLINE qcontravariant #-}+{-# INLINE qinvariant #-}+-- | Sigils+affine, unlimited,+ covariant, contravariant, invariant, omnivariant,+ qcovariant, qcontravariant, qinvariant ∷ String++{-# INLINE ellipsis #-}+ellipsis ∷ String++#ifdef UNICODE+digits = unicodeDigits+tvNames = [ 'a' .. 'z' ]+all = "∀"+ex = "∃"+mu = "μ"+cons = "∷"+product = "×"+uArrow = "→"+aArrow = "-A>"+arrowPre = "-"+arrowPost = ">"+join = "⋁"+affine = "`"+unlimited = "\'"+covariant = "+"+contravariant = "-"+invariant = ""+omnivariant = "0"+qcovariant = "Q+"+qcontravariant = "Q-"+qinvariant = "Q"+ellipsis = "..."+fun = "λ"+arrow = "→"+#else+digits = asciiDigits+tvNames = [ 'a' .. 'z' ]+all = "all"+ex = "ex"+mu = "mu"+cons = "::"+product = "*"+uArrow = "->"+aArrow = "-A>"+arrowPre = "-"+arrowPost = ">"+join = "\\/"+affine = "`"+unlimited = "\'"+covariant = "+"+contravariant = "-"+invariant = ""+omnivariant = "0"+qcovariant = "Q+"+qcontravariant = "Q-"+qinvariant = "Q"+ellipsis = "..."+fun = "fun"+arrow = "->"+#endif++{-# INLINE unicodeDigits #-}+{-# INLINE asciiDigits #-}+unicodeDigits, asciiDigits ∷ [Char]+unicodeDigits = "₀₁₂₃₄₅₆₇₈₉"+asciiDigits = "0123456789"++normalizeChar ∷ Char → Char+normalizeChar '₀' = '0'+normalizeChar '₁' = '1'+normalizeChar '₂' = '2'+normalizeChar '₃' = '3'+normalizeChar '₄' = '4'+normalizeChar '₅' = '5'+normalizeChar '₆' = '6'+normalizeChar '₇' = '7'+normalizeChar '₈' = '8'+normalizeChar '₉' = '9'+normalizeChar '′' = '\''+normalizeChar 'α' = 'a'+normalizeChar 'β' = 'b'+normalizeChar 'ψ' = 'c'+normalizeChar 'δ' = 'd'+normalizeChar 'ε' = 'e'+normalizeChar 'φ' = 'f'+normalizeChar 'γ' = 'g'+normalizeChar 'η' = 'h'+normalizeChar 'ι' = 'i'+normalizeChar 'ξ' = 'j'+normalizeChar 'κ' = 'k'+normalizeChar 'λ' = 'l'+normalizeChar 'μ' = 'm'+normalizeChar 'ν' = 'n'+normalizeChar 'ο' = 'o'+normalizeChar 'π' = 'p'+normalizeChar 'ρ' = 'r'+normalizeChar 'σ' = 's'+normalizeChar 'τ' = 't'+normalizeChar 'θ' = 'u'+normalizeChar 'ω' = 'v'+normalizeChar 'ς' = 'w'+normalizeChar 'χ' = 'x'+normalizeChar 'υ' = 'y'+normalizeChar 'ζ' = 'z'+normalizeChar c = c+
− src/Syntax/SyntaxTable.hs
@@ -1,133 +0,0 @@-{-# LANGUAGE- RankNTypes,- TemplateHaskell #-}-module Syntax.SyntaxTable where--import Meta.THHelpers-import Syntax.Anti-import Syntax.Notable-import Syntax.Ident-import Syntax.Kind-import Syntax.Type-import Syntax.Lit-import Syntax.Patt-import Syntax.Expr-import Syntax.Decl--import qualified Data.Map as M-import qualified Language.Haskell.TH as TH--litAntis, pattAntis,- exprAntis, bindingAntis, caseAltAntis,- typeAntis, tyPatAntis, quantAntis, qExpAntis, tyVarAntis,- declAntis, tyDecAntis, absTyAntis, modExpAntis,- sigExpAntis, sigItemAntis,- lidAntis, uidAntis, qlidAntis, quidAntis, idAntis, noAntis- :: AntiDict--litAntis- = "lit" =: Nothing- & "str" =:< 'LtStr- & "int" =:< 'LtInt- & "flo" =:< 'LtFloat- & "float" =:< 'LtFloat- & "antiL" =:< 'LtAnti-pattAntis- = "patt" =:! Nothing- & "anti" =:< 'PaAnti-exprAntis- = "expr" =:! Nothing- & "anti" =:< 'ExAnti-bindingAntis- = "bind" =:! Nothing- & "antiB" =:< 'BnAnti-caseAltAntis- = "case" =: Nothing- & "antiC" =:< 'CaAnti-typeAntis- = "type" =:! Nothing- & "anti" =:< 'TyAnti-tyPatAntis- = "typat" =:! Nothing- & "antiP" =:< 'TpAnti-quantAntis- = "quant" =: Nothing- & "antiQ" =:< 'QuantAnti-qExpAntis- = "qexp" =:! Nothing- & "qlit" =:< 'QeLit- & "qvar" =:< 'QeVar- & "qdisj" =:< 'QeDisj- & "qconj" =:< 'QeConj- & "anti" =:< 'QeAnti-tyVarAntis- = "tyvar" =:! Nothing- & "anti" =:< 'TVAnti-declAntis- = "decl" =:! Nothing- & "anti" =:< 'DcAnti-tyDecAntis- = "tydec" =:! Nothing- & "anti" =:< 'TdAnti-absTyAntis- = "absty" =:! Nothing- & "anti" =:< 'AbsTyAnti-modExpAntis- = "mod" =:! Nothing- & "anti" =:< 'MeAnti-sigExpAntis- = "sig" =:! Nothing- & "anti" =:< 'SeAnti-sigItemAntis- = "sgitem" =:! Nothing- & "anti" =:< 'SgAnti-lidAntis- = "lid" =: Nothing- & "name" =: Just (\v -> varS 'lid [varS v []]- `whichS` conS 'Lid [wildS, varS v []])- & "antiLid"=:< 'LidAnti-uidAntis- = "uid" =: Nothing- & "uname" =: Just (\v -> varS 'uid [varS v []]- `whichS` conS 'Uid [wildS, varS v []])- & "antiUid"=:< 'LidAnti-qlidAntis- = "qlid" =: Nothing- & "qname" =: appFun 'qlid -- error in pattern context-quidAntis- = "quid" =: Nothing- & "quname" =: appFun 'quid -- error in pattern context-idAntis- = "id" =: Nothing-noAntis- = M.empty--appFun :: ToSyntax b => TH.Name -> Maybe (String -> TH.Q b)-appFun n = Just (\v -> varS n [varS v []])--syntaxTable :: SyntaxTable-syntaxTable =- [ ''Prog =:: 'Prog !: 'newN >: (''Id, [0])- , ''Lit =:: 'LtAnti $: 'litAntis- , ''Patt =:: 'PaAnti $: 'pattAntis !: 'newPatt >: (''Id, [0])- , ''Expr =:: 'ExAnti $: 'exprAntis !: 'newExpr >: (''Id, [0])- , ''Binding =:: 'BnAnti $: 'bindingAntis !: 'newBinding >: (''Id, [0])- , ''CaseAlt =:: 'CaAnti $: 'caseAltAntis !: 'newCaseAlt >: (''Id, [0])- , ''Type =:: 'TyAnti $: 'typeAntis !: 'newN- , ''TyPat =:: 'TpAnti $: 'tyPatAntis !: 'newN- , ''Quant =:: 'QuantAnti $: 'quantAntis- , ''QExp =:: 'QeAnti $: 'qExpAntis !: 'newN- , ''TyVar =:: 'TVAnti $: 'tyVarAntis- , ''Decl =:: 'DcAnti $: 'declAntis !: 'newDecl >: (''Id, [0])- , ''TyDec =:: 'TdAnti $: 'tyDecAntis !: 'newN- , ''AbsTy =:: 'AbsTyAnti $: 'absTyAntis !: 'newN- , ''ModExp =:: 'MeAnti $: 'modExpAntis !: 'newModExp >: (''Id, [0])- , ''SigExp =:: 'SeAnti $: 'sigExpAntis !: 'newSigExp >: (''Id, [0])- , ''SigItem =:: 'SgAnti $: 'sigItemAntis !: 'newSigItem >: (''Id, [0])- , ''Lid =:: 'LidAnti $: 'lidAntis- , ''Uid =:: 'UidAnti $: 'uidAntis- , ''QLid =:: '()- , ''QUid =:: '()- , ''Ident =:: '()- ]-
− src/Syntax/Type.hs
@@ -1,136 +0,0 @@-{-# LANGUAGE- DeriveDataTypeable,- FlexibleInstances,- ParallelListComp,- TemplateHaskell,- TypeFamilies #-}-module Syntax.Type (- -- * Types- Quant(..), Type'(..), Type, TyPat'(..), TyPat,- -- ** Constructors- tyApp, tyVar, tyFun, tyQu, tyMu, tyAnti,- tpVar, tpApp, tpAnti,-- -- * Built-in types- tyNulOp, tyUnOp, tyBinOp,- tyUnit, tyTuple, tyUn, tyAf,- -- ** Convenience constructors- tyArr, tyLol,- tyAll, tyEx,-- -- * Miscellany- dumpType-) where--import Meta.DeriveNotable-import Syntax.Notable-import Syntax.Anti-import Syntax.Kind-import Syntax.Ident--import Data.Generics (Typeable, Data)---- | Type quantifers-data Quant = Forall | Exists | QuantAnti Anti- deriving (Typeable, Data, Eq, Ord)--type Type i = Located Type' i-type TyPat i = Located TyPat' i---- | Types are parameterized by [@i@], the type of information--- associated with each tycon-data Type' i- = TyApp (QLid i) [Type i]- | TyVar (TyVar i)- | TyFun (Maybe (QExp i)) (Type i) (Type i)- | TyQu Quant (TyVar i) (Type i)- | TyMu (TyVar i) (Type i)- | TyAnti Anti- deriving (Typeable, Data)---- | Type patterns for defining type operators-data TyPat' i- -- | type variables- = TpVar (TyVar i) Variance- -- | type constructor applications- | TpApp (QLid i) [TyPat i]- -- | antiquotes- | TpAnti Anti- deriving (Typeable, Data)--deriveNotable ''Type-deriveNotable ''TyPat---- | Convenience constructors for qualified types-tyAll, tyEx :: TyVar i -> Type i -> Type i-tyAll = tyQu Forall-tyEx = tyQu Exists--instance Show Quant where- show Forall = "all"- show Exists = "ex"- show (QuantAnti a) = show a--------- Built-in types--------- Convenience constructors--tyNulOp :: Id i => String -> Type i-tyNulOp s = tyApp (qlid s) []--tyUnOp :: Id i => String -> Type i -> Type i-tyUnOp s a = tyApp (qlid s) [a]--tyBinOp :: Id i => String -> Type i -> Type i -> Type i-tyBinOp s a b = tyApp (qlid s) [a, b]--tyUnit :: Id i => Type i-tyUnit = tyNulOp "unit"--tyTuple :: Id i => Type i -> Type i -> Type i-tyTuple = tyBinOp "*"--tyUn :: Id i => Type i-tyUn = tyNulOp "U"--tyAf :: Id i => Type i-tyAf = tyNulOp "A"--tyArr :: Type i -> Type i -> Type i-tyArr = tyFun Nothing--tyLol :: Type i -> Type i -> Type i-tyLol = tyFun (Just maxBound)--infixr 8 `tyArr`, `tyLol`---- | Noisy type printer for debugging-dumpType :: Id i => Int -> Type i -> IO ()-dumpType i (N _ t0) = do- putStr (replicate i ' ')- case t0 of- TyApp n ps -> do- putStrLn $ show n ++ " {"- mapM_ (dumpType (i + 2)) ps- putStrLn (replicate i ' ' ++ "}")- TyFun mq dom cod -> do- putStrLn $ case mq of- Just q -> "-[" ++ maybe "ANTI" show (qInterpretM q) ++ "]> {"- Nothing -> "-> {"- dumpType (i + 2) dom- dumpType (i + 2) cod- putStrLn (replicate i ' ' ++ "}")- TyVar tv -> print tv- TyQu u a t -> do- print $ show u ++ " " ++ show a ++ ". {"- dumpType (i + 2) t- putStrLn (replicate i ' ' ++ "}")- TyMu a t -> do- print $ "mu " ++ show a ++ ". {"- dumpType (i + 2) t- putStrLn (replicate i ' ' ++ "}")- TyAnti a -> do- print a-
− src/Token.hs
@@ -1,494 +0,0 @@-{-# LANGUAGE RankNTypes #-}-{-# OPTIONS_GHC -fno-warn-name-shadowing #-}-{-- This is a modified version of the Parsec module whose copyright is- below, which supports figuring out where a token has ended *before*- ensuing whitespace.-- In particular, it defines a type class for functionally updating the- state with a SourcePos, and then lexeme always stashes the position- there before discarding whitespace.--}--------------------------------------------------------------------------------- |--- Module : Text.ParserCombinators.Parsec.Token--- Copyright : (c) Daan Leijen 1999-2001--- License : BSD-style (see the file libraries/parsec/LICENSE)------ Maintainer : daan@cs.uu.nl--- Stability : provisional--- Portability : non-portable (uses existentially quantified data constructors)------ A helper module to parse lexical elements (tokens).-----------------------------------------------------------------------------------module Token- ( TokenEnd (..)- , LanguageDef (..)- , TokenParser (..)- , makeTokenParser- ) where--import Data.Char (isAlpha,toLower,toUpper,isSpace,digitToInt)-import Data.List (nub,sort)-import Text.ParserCombinators.Parsec--class TokenEnd st where- saveTokenEnd :: CharParser st ()--instance TokenEnd () where- saveTokenEnd = return ()---------------------------------------------------------------- Language Definition-------------------------------------------------------------data LanguageDef st- = LanguageDef- { commentStart :: String- , commentEnd :: String- , commentLine :: String- , nestedComments :: Bool- , identStart :: CharParser st Char- , identLetter :: CharParser st Char- , opStart :: CharParser st Char- , opLetter :: CharParser st Char- , reservedNames :: [String]- , reservedOpNames:: [String]- , caseSensitive :: Bool- }---------------------------------------------------------------- A first class module: TokenParser-------------------------------------------------------------data TokenParser st- = TokenParser{ identifier :: CharParser st String- , reserved :: String -> CharParser st ()- , operator :: CharParser st String- , reservedOp :: String -> CharParser st ()-- , charLiteral :: CharParser st Char- , stringLiteral :: CharParser st String- , natural :: CharParser st Integer- , integer :: CharParser st Integer- , float :: CharParser st Double- , naturalOrFloat :: CharParser st (Either Integer Double)- , decimal :: CharParser st Integer- , hexadecimal :: CharParser st Integer- , octal :: CharParser st Integer-- , symbol :: String -> CharParser st String- , lexeme :: forall a. CharParser st a -> CharParser st a- , whiteSpace :: CharParser st ()-- , parens :: forall a. CharParser st a -> CharParser st a- , braces :: forall a. CharParser st a -> CharParser st a- , angles :: forall a. CharParser st a -> CharParser st a- , brackets :: forall a. CharParser st a -> CharParser st a- -- "squares" is deprecated- , squares :: forall a. CharParser st a -> CharParser st a-- , semi :: CharParser st String- , comma :: CharParser st String- , colon :: CharParser st String- , dot :: CharParser st String- , semiSep :: forall a . CharParser st a -> CharParser st [a]- , semiSep1 :: forall a . CharParser st a -> CharParser st [a]- , commaSep :: forall a . CharParser st a -> CharParser st [a]- , commaSep1 :: forall a . CharParser st a -> CharParser st [a]- }---------------------------------------------------------------- Given a LanguageDef, create a token parser.-------------------------------------------------------------makeTokenParser :: TokenEnd st => LanguageDef st -> TokenParser st-makeTokenParser languageDef- = TokenParser{ identifier = identifier- , reserved = reserved- , operator = operator- , reservedOp = reservedOp-- , charLiteral = charLiteral- , stringLiteral = stringLiteral- , natural = natural- , integer = integer- , float = float- , naturalOrFloat = naturalOrFloat- , decimal = decimal- , hexadecimal = hexadecimal- , octal = octal-- , symbol = symbol- , lexeme = lexeme- , whiteSpace = whiteSpace-- , parens = parens- , braces = braces- , angles = angles- , brackets = brackets- , squares = brackets- , semi = semi- , comma = comma- , colon = colon- , dot = dot- , semiSep = semiSep- , semiSep1 = semiSep1- , commaSep = commaSep- , commaSep1 = commaSep1- }- where-- ------------------------------------------------------------ -- Bracketing- ------------------------------------------------------------ parens p = between (symbol "(") (symbol ")") p- braces p = between (symbol "{") (symbol "}") p- angles p = between (symbol "<") (symbol ">") p- brackets p = between (symbol "[") (symbol "]") p-- semi = symbol ";"- comma = symbol ","- dot = symbol "."- colon = symbol ":"-- commaSep p = sepBy p comma- semiSep p = sepBy p semi-- commaSep1 p = sepBy1 p comma- semiSep1 p = sepBy1 p semi--- ------------------------------------------------------------ -- Chars & Strings- ------------------------------------------------------------ -- charLiteral :: CharParser st Char- charLiteral = lexeme (between (char '\'')- (char '\'' <?> "end of character")- characterChar )- <?> "character"-- characterChar = charLetter <|> charEscape- <?> "literal character"-- charEscape = do{ char '\\'; escapeCode }- charLetter = satisfy (\c -> (c /= '\'') && (c /= '\\') && (c > '\026'))---- -- stringLiteral :: CharParser st String- stringLiteral = lexeme (- do{ str <- between (char '"')- (char '"' <?> "end of string")- (many stringChar)- ; return (foldr (maybe id (:)) "" str)- }- <?> "literal string")-- -- stringChar :: CharParser st (Maybe Char)- stringChar = do{ c <- stringLetter; return (Just c) }- <|> stringEscape- <?> "string character"-- stringLetter = satisfy (\c -> (c /= '"') && (c /= '\\') && (c > '\026'))-- stringEscape = do{ char '\\'- ; do{ escapeGap ; return Nothing }- <|> do{ escapeEmpty; return Nothing }- <|> do{ esc <- escapeCode; return (Just esc) }- }-- escapeEmpty = char '&'- escapeGap = do{ many1 space- ; char '\\' <?> "end of string gap"- }---- -- escape codes- escapeCode = charEsc <|> charNum <|> charAscii <|> charControl- <?> "escape code"-- -- charControl :: CharParser st Char- charControl = do{ char '^'- ; code <- upper- ; return (toEnum (fromEnum code - fromEnum 'A'))- }-- -- charNum :: CharParser st Char- charNum = do{ code <- decimal- <|> do{ char 'o'; number 8 octDigit }- <|> do{ char 'x'; number 16 hexDigit }- ; return (toEnum (fromInteger code))- }-- charEsc = choice (map parseEsc escMap)- where- parseEsc (c,code) = do{ char c; return code }-- charAscii = choice (map parseAscii asciiMap)- where- parseAscii (asc,code) = try (do{ string asc; return code })--- -- escape code tables- escMap = zip ("abfnrtv\\\"\'") ("\a\b\f\n\r\t\v\\\"\'")- asciiMap = zip (ascii3codes ++ ascii2codes) (ascii3 ++ ascii2)-- ascii2codes = ["BS","HT","LF","VT","FF","CR","SO","SI","EM",- "FS","GS","RS","US","SP"]- ascii3codes = ["NUL","SOH","STX","ETX","EOT","ENQ","ACK","BEL",- "DLE","DC1","DC2","DC3","DC4","NAK","SYN","ETB",- "CAN","SUB","ESC","DEL"]-- ascii2 = ['\BS','\HT','\LF','\VT','\FF','\CR','\SO','\SI',- '\EM','\FS','\GS','\RS','\US','\SP']- ascii3 = ['\NUL','\SOH','\STX','\ETX','\EOT','\ENQ','\ACK',- '\BEL','\DLE','\DC1','\DC2','\DC3','\DC4','\NAK',- '\SYN','\ETB','\CAN','\SUB','\ESC','\DEL']--- ------------------------------------------------------------ -- Numbers- ------------------------------------------------------------ -- naturalOrFloat :: CharParser st (Either Integer Double)- naturalOrFloat = lexeme (natFloat) <?> "number"-- float = lexeme floating <?> "float"- integer = lexeme int <?> "integer"- natural = lexeme nat <?> "natural"--- -- floats- floating = do{ n <- decimal- ; fractExponent n- }--- natFloat = do{ char '0'- ; zeroNumFloat- }- <|> decimalFloat-- zeroNumFloat = do{ n <- hexadecimal <|> octal- ; return (Left n)- }- <|> decimalFloat- <|> fractFloat 0- <|> return (Left 0)-- decimalFloat = do{ n <- decimal- ; option (Left n)- (fractFloat n)- }-- fractFloat n = do{ f <- fractExponent n- ; return (Right f)- }-- fractExponent n = do{ fract <- fraction- ; expo <- option 1.0 exponent'- ; return ((fromInteger n + fract)*expo)- }- <|>- do{ expo <- exponent'- ; return ((fromInteger n)*expo)- }-- fraction = do{ char '.'- ; digits <- many1 digit <?> "fraction"- ; return (foldr op 0.0 digits)- }- <?> "fraction"- where- op d f = (f + fromIntegral (digitToInt d))/10.0-- exponent' = do{ oneOf "eE"- ; f <- sign- ; e <- decimal <?> "exponent"- ; return (power (f e))- }- <?> "exponent"- where- power e | e < 0 = 1.0/power(-e)- | otherwise = fromInteger (10^e)--- -- integers and naturals- int = do{ f <- lexeme sign- ; n <- nat- ; return (f n)- }-- -- sign :: CharParser st (Integer -> Integer)- sign = (char '-' >> return negate)- <|> (char '+' >> return id)- <|> return id-- nat = zeroNumber <|> decimal-- zeroNumber = do{ char '0'- ; hexadecimal <|> octal <|> decimal <|> return 0- }- <?> ""-- decimal = number 10 digit- hexadecimal = do{ oneOf "xX"; number 16 hexDigit }- octal = do{ oneOf "oO"; number 8 octDigit }-- -- number :: Integer -> CharParser st Char -> CharParser st Integer- number base baseDigit- = do{ digits <- many1 baseDigit- ; let n = foldl (\x d -> base*x + toInteger (digitToInt d)) 0 digits- ; seq n (return n)- }-- ------------------------------------------------------------ -- Operators & reserved ops- ------------------------------------------------------------ reservedOp name =- lexeme $ try $- do{ string name- ; notFollowedBy (opLetter languageDef) <?> ("end of " ++ show name)- }-- operator =- lexeme $ try $- do{ name <- oper- ; if (isReservedOp name)- then unexpected ("reserved operator " ++ show name)- else return name- }-- oper =- do{ c <- (opStart languageDef)- ; cs <- many (opLetter languageDef)- ; return (c:cs)- }- <?> "operator"-- isReservedOp name =- isReserved (sort (reservedOpNames languageDef)) name--- ------------------------------------------------------------ -- Identifiers & Reserved words- ------------------------------------------------------------ reserved name =- lexeme $ try $- do{ caseString name- ; notFollowedBy (identLetter languageDef) <?> ("end of " ++ show name)- }-- caseString name- | caseSensitive languageDef = string name- | otherwise = do{ walk name; return name }- where- walk [] = return ()- walk (c:cs) = do{ caseChar c <?> msg; walk cs }-- caseChar c | isAlpha c = char (toLower c) <|> char (toUpper c)- | otherwise = char c-- msg = show name--- identifier =- lexeme $ try $- do{ name <- ident- ; if (isReservedName name)- then unexpected ("reserved word " ++ show name)- else return name- }--- ident- = do{ c <- identStart languageDef- ; cs <- many (identLetter languageDef)- ; return (c:cs)- }- <?> "identifier"-- isReservedName name- = isReserved theReservedNames caseName- where- caseName | caseSensitive languageDef = name- | otherwise = map toLower name--- isReserved names name- = scan names- where- scan [] = False- scan (r:rs) = case (compare r name) of- LT -> scan rs- EQ -> True- GT -> False-- theReservedNames- | caseSensitive languageDef = sortedNames- | otherwise = map (map toLower) sortedNames- where- sortedNames = sort (reservedNames languageDef)---- ------------------------------------------------------------ -- White space & symbols- ------------------------------------------------------------ symbol name- = lexeme (string name)-- lexeme p- = do- x <- p- saveTokenEnd- whiteSpace- return x--- --whiteSpace- whiteSpace- | noLine && noMulti = skipMany (simpleSpace <?> "")- | noLine = skipMany (simpleSpace <|> multiLineComment <?> "")- | noMulti = skipMany (simpleSpace <|> oneLineComment <?> "")- | otherwise = skipMany (simpleSpace <|> oneLineComment <|> multiLineComment <?> "")- where- noLine = null (commentLine languageDef)- noMulti = null (commentStart languageDef)--- simpleSpace =- skipMany1 (satisfy isSpace)-- oneLineComment =- do{ try (string (commentLine languageDef))- ; skipMany (satisfy (/= '\n'))- ; return ()- }-- multiLineComment =- do { try (string (commentStart languageDef))- ; inComment- }-- inComment- | nestedComments languageDef = inCommentMulti- | otherwise = inCommentSingle-- inCommentMulti- = do{ try (string (commentEnd languageDef)) ; return () }- <|> do{ multiLineComment ; inCommentMulti }- <|> do{ skipMany1 (noneOf startEnd) ; inCommentMulti }- <|> do{ oneOf startEnd ; inCommentMulti }- <?> "end of comment"- where- startEnd = nub (commentEnd languageDef ++ commentStart languageDef)-- inCommentSingle- = do{ try (string (commentEnd languageDef)); return () }- <|> do{ skipMany1 (noneOf startEnd) ; inCommentSingle }- <|> do{ oneOf startEnd ; inCommentSingle }- <?> "end of comment"- where- startEnd = nub (commentEnd languageDef ++ commentStart languageDef)-
src/Type.hs view
@@ -1,1068 +1,23 @@ -- | The internal representation of types, created by the type checker--- from the syntactic types in 'Syntax.Type'.-{-# LANGUAGE- CPP,- DeriveDataTypeable,- DeriveFunctor,- ViewPatterns,- FlexibleInstances,- ParallelListComp,- PatternGuards,- ScopedTypeVariables,- TypeFamilies #-}-module Type (- -- * Representation of types- Type(..), TyCon(..), TyVarR, TyPat(..), tyApp,- -- * Type reduction- ReductionState(..),- -- ** Head reduction- isHeadNormalType, headReduceType,- headNormalizeTypeK, headNormalizeTypeM,- headNormalizeType,- -- ** Deep reduction- isNormalType, normalizeTypeK, normalizeType,- -- ** Freshness- Ftv(..), freshTyVar, freshTyVars,- fastFreshTyVar, fastFreshTyVars,- -- ** Substitutions- tysubst, tysubsts, tyrename,- -- * Miscellaneous type operations- castableType, typeToStx, typeToStx', tyPatToStx, tyPatToStx',- tyPatToType, qualifier,- -- ** Type varieties- TypeVariety(..), isAbstractTyCon, varietyOf,- -- * Built-in types- -- ** Type constructors- mkTC,- tcBot, tcUnit, tcInt, tcFloat, tcString, tcExn, tcTuple, tcUn, tcAf,- -- ** Types- tyNulOp, tyUnOp, tyBinOp,- tyArr, tyLol,- tyAll, tyEx,- -- *** Convenience- tyBot, tyUnit, tyInt, tyFloat, tyString, tyExn, tyUn, tyAf, tyTop,- tyIdent, tyConst,- tyTuple,- (.*.), (.->.), (.-*.),- -- * Views- vtAppTc, isBotType,- -- ** Unfolds- vtFuns, vtQus,- -- * Implicit arrow annotations- CurrentImpArrRule, ImpArrRule(..),- -- * Re-exports- module Syntax.Ident,- module Syntax.Kind,- module Syntax.POClass,- Stx.Quant(..),- -- * Debugging and testing- dumpType,- tcSend, tcRecv, tcSelect, tcFollow, tcSemi, tcDual,- tySend, tyRecv, tyDual, tySelect, tyFollow, tySemi, (.:.),-) where--import qualified Env-import Ppr-import Syntax.Ident-import Syntax.Kind-import Syntax.POClass-import qualified Syntax as Stx-import Util-import Viewable--import qualified Control.Monad.Writer as CMW-import Data.Char (isDigit)-import Data.Generics (Typeable, Data, everything, mkQ)-import qualified Data.Map as M-import qualified Data.Set as S---- | All tyvars are renamed by this point-type TyVarR = TyVar Renamed---- | The internal representation of a type-data Type- -- | A type variable- = TyVar TyVarR- -- | The application of a type constructor (possibly nullary); the- -- third field caches the next head-reduction step if the type- -- is not head-normal -- note that substitution invalidates this- -- cache. Use 'tyApp' to construct a type application that- -- (re)initializes the cache.- | TyApp TyCon [Type] (ReductionState Type)- -- | An arrow type, including qualifier expression- | TyFun (QDen TyVarR) Type Type- -- | A quantified (all or ex) type- | TyQu Stx.Quant TyVarR Type- -- | A recursive (mu) type- | TyMu TyVarR Type- deriving (Typeable, Data)---- | Information about a type constructor-data TyCon- = TyCon {- -- | Unique ID- tcId :: Int,- -- | Printable name- tcName :: (QLid Renamed),- -- | Variances for parameters, and correct length- tcArity :: [Variance],- -- | Bounds for parameters (may be infinite)- tcBounds :: [QLit],- -- | Qualifier as a function of parameters- tcQual :: (QDen Int),- -- | For pattern-matchable types, the data constructors- tcCons :: ([TyVarR], Env.Env (Uid Renamed) (Maybe Type)),- -- | For type operators, the next head reduction- tcNext :: Maybe [([TyPat], Type)]- }- deriving (Typeable, Data)---- | A type pattern, for defining type operators-data TyPat- -- | A type variable, matching any type and binding- = TpVar TyVarR- -- | A type application node, matching the given constructor- -- and its parameters- | TpApp TyCon [TyPat]- deriving (Typeable, Data)--instance Eq TyCon where- tc == tc' = tcId tc == tcId tc'--instance Ord TyCon where- compare tc tc' = compare (tcName tc) (tcName tc')--instance Ppr Type where- ppr t = askTyNames (\tn -> ppr (typeToStx tn t))-instance Ppr TyPat where- ppr t = askTyNames (\tn -> ppr (tyPatToStx tn t))--instance Show Type where showsPrec = showFromPpr-instance Show TyPat where showsPrec = showFromPpr---- | The different varieties of type definitions-data TypeVariety- -- | Type operators and synonyms- = OperatorType- -- | Datatype- | DataType- -- | Abstract type- | AbstractType- deriving (Eq, Ord, Typeable, Data)--instance Show TypeVariety where- showsPrec _ OperatorType = showString "a type operator"- showsPrec _ DataType = showString "a datatype"- showsPrec _ AbstractType = showString "abstract"---- | What variety of type definition do we have?-varietyOf :: TyCon -> TypeVariety-varietyOf TyCon { tcNext = Just _ } = OperatorType-varietyOf TyCon { tcCons = (_, e) } =- if Env.isEmpty e then AbstractType else DataType---- | Find the qualifier of a type-qualifier :: Type -> QDen TyVarR-qualifier (TyApp tc ts _) = denumberQDen (map qualifier ts) (tcQual tc)-qualifier (TyFun q _ _) = q-qualifier (TyVar tv)- | tvqual tv <: Qu = minBound- | otherwise = qInterpret (qeVar tv)-qualifier (TyQu _ tv t) = qSubst tv minBound (qualifier t)-qualifier (TyMu tv t) = qSubst tv minBound (qualifier t)---- | Is the given type constructor abstract?-isAbstractTyCon :: TyCon -> Bool-isAbstractTyCon = (== AbstractType) . varietyOf--------- Free type variables, freshness, and substitution-------- | Class for getting free type variables (from types, expressions,--- lists thereof, pairs thereof, etc.)-class Ftv a where- ftvVs :: a -> M.Map TyVarR Variance- ftv :: a -> S.Set TyVarR- ftv = M.keysSet . ftvVs- alltv :: a -> S.Set TyVarR- maxtv :: a -> Renamed--instance Ftv Type where- ftv (TyApp _ ts _) = S.unions (map ftv ts)- ftv (TyVar tv) = S.singleton tv- ftv (TyFun q t1 t2) = S.unions [ftv t1, ftv t2, ftv q]- ftv (TyQu _ tv t) = S.delete tv (ftv t)- ftv (TyMu tv t) = S.delete tv (ftv t)- --- ftvVs (TyApp tc ts _) = M.unionsWith (+)- [ M.map (* var) m- | var <- tcArity tc- | m <- map ftvVs ts ]- ftvVs (TyFun q t1 t2) = M.unionsWith (+)- [ ftvVs q- , M.map negate (ftvVs t1)- , ftvVs t2 ]- ftvVs (TyVar tv) = M.singleton tv 1- ftvVs (TyQu _ tv t) = M.delete tv (ftvVs t)- ftvVs (TyMu tv t) = M.delete tv (ftvVs t)- --- alltv (TyApp _ ts _) = alltv ts- alltv (TyVar tv) = alltv tv- alltv (TyFun q t1 t2) = alltv q `S.union` alltv t1 `S.union` alltv t2- alltv (TyQu _ tv t) = tv `S.insert` alltv t- alltv (TyMu tv t) = tv `S.insert` alltv t- --- maxtv (TyApp _ ts _) = maxtv ts- maxtv (TyVar tv) = maxtv tv- maxtv (TyFun q t1 t2) = maxtv q `max` maxtv t1 `max` maxtv t2- maxtv (TyQu _ tv t) = maxtv tv `max` maxtv t- maxtv (TyMu tv t) = maxtv tv `max` maxtv t--instance (Data a, Ord a, Ftv a) => Ftv (QDen a) where- ftv = everything S.union (mkQ S.empty (ftv :: a -> S.Set TyVarR))- ftvVs = everything M.union- (mkQ M.empty (ftvVs :: a -> M.Map TyVarR Variance))- alltv = everything S.union (mkQ S.empty (alltv :: a -> S.Set TyVarR))- maxtv = everything max (mkQ trivialId (maxtv :: a -> Renamed))--instance Ftv a => Ftv [a] where- ftv = S.unions . map ftv- ftvVs = M.unionsWith (+) . map ftvVs- alltv = S.unions . map alltv- maxtv [] = trivialId- maxtv xs = maximum (map maxtv xs)--instance (i ~ Renamed) => Ftv (TyVar i) where- ftv = S.singleton- ftvVs tv = M.singleton tv 1- alltv = S.singleton- maxtv = lidUnique . tvname--instance Ftv () where- ftv _ = S.empty- ftvVs _ = M.empty- alltv _ = S.empty- maxtv _ = maximum []--instance Ftv a => Ftv (Maybe a) where- ftv = maybe (ftv ()) ftv- ftvVs = maybe (ftvVs ()) ftvVs- alltv = maybe (alltv ()) alltv- maxtv = maybe (maxtv ()) maxtv--instance (Ftv a, Ftv b) => Ftv (a, b) where- ftv (a, b) = ftv a `S.union` ftv b- ftvVs (a, b) = M.unionWith (+) (ftvVs a) (ftvVs b)- alltv (a, b) = alltv a `S.union` alltv b- maxtv (a, b) = maxtv a `max` maxtv b--instance (Ftv a, Ftv b, Ftv c) => Ftv (a, b, c) where- ftv (a, b, c) = ftv (a, (b, c))- ftvVs (a, b, c) = ftvVs (a, (b, c))- alltv (a, b, c) = alltv (a, (b, c))- maxtv (a, b, c) = maxtv (a, (b, c))--instance (Ftv a, Ftv b, Ftv c, Ftv d) => Ftv (a, b, c, d) where- ftv (a, b, c, d) = ftv ((a, b), (c, d))- ftvVs (a, b, c, d) = ftvVs ((a, b), (c, d))- alltv (a, b, c, d) = alltv ((a, b), (c, d))- maxtv (a, b, c, d) = maxtv ((a, b), (c, d))---- Rename a type variable, if necessary, to make its unique tag higher--- than the one given-fastFreshTyVar :: TyVarR -> Renamed -> TyVarR-fastFreshTyVar tv@(TV (Lid i n) q) imax =- if i > imax- then tv- else TV (Lid (succ imax) n) q-fastFreshTyVar (TVAnti a) _ = Stx.antierror "Type.fastFreshTyVar" a-fastFreshTyVar (TV (LidAnti a) _) _ = Stx.antierror "Type.fastFreshTyVar" a---- Rename a list of type variables, if necessary, to make each unique tag--- higher than the one given and mutually unique-fastFreshTyVars :: [TyVarR] -> Renamed -> [TyVarR]-fastFreshTyVars [] _ = []-fastFreshTyVars (tv:tvs) imax =- let tv' = fastFreshTyVar tv imax in- tv' : fastFreshTyVars tvs (imax `max` maxtv tv')---- | Given a type variable, rename it (if necessary) to make it--- fresh for a set of type variables.-freshTyVar :: TyVarR -> S.Set TyVarR -> TyVarR-freshTyVar (TV l q) set = TV l' q where- l' = if unLid l `S.member` names- then lid (loop count)- else l- names = S.map (unLid . tvname) set- loop n =- let tv' = prefix ++ show n- in if tv' `S.member` names- then loop (n + 1)- else tv'- suffix = reverse . takeWhile isDigit . reverse . unLid $ l- prefix = reverse . dropWhile isDigit . reverse . unLid $ l- count = case reads suffix of- ((n, ""):_) -> n- _ -> 1::Integer-freshTyVar (TVAnti a) _ = Stx.antierror "Type.freshTyVar" a---- | Given a list of type variables, rename them (if necessary) to make--- each of them fresh for both the set of type variables and each--- other.-freshTyVars :: [TyVarR] -> S.Set TyVarR -> [TyVarR]-freshTyVars [] _ = []-freshTyVars (tv:tvs) set = tv' : freshTyVars tvs (S.insert tv' set)- where tv' = freshTyVar tv (set `S.union` S.fromList tvs)---- | Type substitution-tysubst :: TyVarR -> Type -> Type -> Type-tysubst a t = loop where- loop (TyVar a')- | a' == a = t- | otherwise = TyVar a'- loop (TyFun q t1 t2)- = TyFun (qSubst a (qualifier t) q) (loop t1) (loop t2)- loop (TyApp tc ts _)- = tyApp tc (map loop ts)- loop (TyQu u a' t')- | a' == a = TyQu u a' t'- | a'' <- fastFreshTyVar a' imax- = TyQu u a'' (loop (tysubst a' (TyVar a'') t'))- loop (TyMu a' t')- | a' == a = TyMu a' t'- | a'' <- fastFreshTyVar a' imax- = TyMu a'' (loop (tysubst a' (TyVar a'') t'))- imax = maxtv (a, t)---- | Given a list of type variables and types, perform all the--- substitutions, avoiding capture between them.-tysubsts :: [TyVarR] -> [Type] -> Type -> Type-tysubsts ps ts t =- let ps' = fastFreshTyVars ps (maxtv (t:ts))- substs tvs ts0 t0 = foldr2 tysubst t0 tvs ts0 in- substs ps' ts .- substs ps (map TyVar ps') $- t---- | Rename a type variable-tyrename :: TyVarR -> TyVarR -> Type -> Type-tyrename tv = tysubst tv . TyVar--------- Type reduction-------- | As we head-reduce a type, it can be in one of four states:-data ReductionState t- -- | The type is head-normal -- that is, its head constructor is- -- not a type synonym/operator- = Done- -- | The type has a next head-reduction step- | Next t- -- | The type may reduce further in the future, but right now it- -- has a pattern match that depends on the value of a type variable- | Blocked- -- | The type's head constructor is a synonym/operator, but it- -- can never take a step, due to a failed pattern match- | Stuck- deriving (Eq, Ord, Show, Functor, Typeable, Data)---- | Helper type for 'tyApp'-type MatchResult t = Either (ReductionState t) ([TyVarR], [Type])---- | Creates a type application, initializing the head-reduction cache-tyApp :: TyCon -> [Type] -> Type-tyApp tc0 ts0 = TyApp tc0 ts0 $ maybe Done clauses (tcNext tc0) where- clauses [] = Stuck- clauses ((tps, rhs):rest) = case patts tps ts0 of- Right (xs, us) -> Next (tysubsts xs us rhs)- Left Stuck -> clauses rest- Left rs -> fmap (tyApp tc0) rs-- patts :: [TyPat] -> [Type] -> MatchResult [Type]- patts [] [] = Right ([], [])- patts (tp:tps) (t:ts) = case patt tp t of- Right (xs, us) -> case patts tps ts of- Right (xs', us') -> Right (xs ++ xs', us ++ us')- Left rs -> Left (fmap (t:) rs)- Left Blocked -> Left (either (fmap (t:))- (const Blocked)- (patts tps ts))- Left rs -> Left (fmap (:ts) rs)- patts _ _ = Left Stuck-- patt :: TyPat -> Type -> MatchResult Type- patt (TpVar tv) t = Right ([tv], [t])- patt (TpApp tc tps) t = case t of- TyApp tc' ts next- | tc == tc' -> (fmap (tyApp tc') +++ id) (patts tps ts)- | Done <- next -> Left Stuck- | otherwise -> Left next- TyMu tv t1 -> Left (Next (tysubst tv (TyMu tv t1) t1))- TyVar _ -> Left Blocked- _ -> Left Stuck---- | Takes one head reduction step. Returns 'Nothing' if the type is--- already head-normal.-headReduceType :: Type -> ReductionState Type-headReduceType (TyApp _ _ next) = next-headReduceType _ = Done---- | Is the type head-normal? A type is head-normal unless its--- top-level constructor is a type operator which can currently--- take a step.-isHeadNormalType :: Type -> Bool-isHeadNormalType t = case headReduceType t of- Next _ -> False- _ -> True---- | Head reduces a type until it is head-normal, given some amount of fuel-headNormalizeTypeF :: Type -> Fuel (ReductionState (), Type) Type-headNormalizeTypeF t = case headReduceType t of- Done -> pure t- Next t' -> burnFuel (Next (), t') *> headNormalizeTypeF t'- Blocked -> bailOut (Blocked, t)- Stuck -> bailOut (Stuck, t)---- | Head reduces a type until it is head-normal or we run out of steps-headNormalizeTypeK :: Int -> Type -> (ReductionState (), Type)-headNormalizeTypeK fuel t = case evalFuel (headNormalizeTypeF t) fuel of- Right t' -> (Done, t')- Left (rs, t') -> (rs, t')--headNormalizeTypeM :: Monad m => Int -> Type -> m Type-headNormalizeTypeM limit t = case headNormalizeTypeK limit t of- (Next (), t') -> fail $- "Gave up reducing type `" ++ show t' ++- "' after " ++ show limit ++ " steps"- (_, t') -> return t'---- | Head reduces a type until it is head-normal-headNormalizeType :: Type -> Type-headNormalizeType = snd . headNormalizeTypeK (-1)---- | Is the type in normal form?-isNormalType :: Type -> Bool-isNormalType t = case t of- TyVar _ -> True- TyFun _ t1 t2 -> isNormalType t1 && isNormalType t2- TyApp _ ts _ -> isHeadNormalType t && all isNormalType ts- TyQu _ _ t1 -> isNormalType t1- TyMu _ t1 -> isNormalType t1---- | Reduces a type until it is normal, given some amount of fuel-normalizeTypeF :: Type -> Fuel (ReductionState (), Type) Type-normalizeTypeF t0 = do- t <- headNormalizeTypeF t0- case t of- TyVar _ -> pure t- TyFun q t1 t2 -> do- t1' <- normalizeTypeF t1 `mapError` fmap (flip (TyFun q) t2)- t2' <- normalizeTypeF t2 `mapError` fmap (TyFun q t1')- return (TyFun q t1' t2')- TyApp tc ts0 _ -> do- let loop [] = return []- loop (t1:ts) = do- t' <- normalizeTypeF t1 `mapError` fmap (:ts)- ts' <- loop ts `mapError` fmap (t':)- return (t':ts')- tyApp tc <$> (loop ts0 `mapError` fmap (tyApp tc))- TyQu qu tv t1 -> do- t1' <- normalizeTypeF t1 `mapError` fmap (TyQu qu tv)- return (TyQu qu tv t1')- TyMu tv t1 -> do- t1' <- normalizeTypeF t1 `mapError` fmap (TyMu tv)- return (TyMu tv t1')--normalizeTypeK :: Int -> Type -> (ReductionState (), Type)-normalizeTypeK fuel t = case evalFuel (normalizeTypeF t) fuel of- Right t' -> (Done, t')- Left (rs, t') -> (rs, t')---- | Reduces a type until it is normal-normalizeType :: Type -> (ReductionState (), Type)-normalizeType = normalizeTypeK (-1)--{---- | Performs one reduction step. The order of evaluation is--- different than used by 'normalizeType', but note that type--- reduction is not guaranteed to be confluent-reduceType :: Type -> Maybe Type-reduceType t = case t of- TyVar _ -> Nothing- TyFun q t1 t2 -> TyFun q <$> reduceType t1 <*> pure t2- <|> TyFun q <$> pure t1 <*> reduceType t2- TyApp tc ts _ -> headReduceType t- <|> tyApp tc <$> reduceTypeList ts- TyQu qu tv t1 -> TyQu qu tv <$> reduceType t1- TyMu tv t1 -> TyMu tv <$> reduceType t1---- | Takes the first reduction step found in a list of types, or--- returns 'Nothing' if they're all normal-reduceTypeList :: [Type] -> Maybe [Type]-reduceTypeList [] = Nothing-reduceTypeList (t:ts) = (:) <$> reduceType t <*> pure ts- <|> (:) <$> pure t <*> reduceTypeList ts--}--------- The Fuel monad-------- | The Fuel monad enables counting computation steps, and--- fails if it runs out of fuel-newtype Fuel r a- = Fuel {- -- | Run a 'Fuel' computation, getting back the- -- answer and remaining fuel- runFuel :: Int -> Either r (a, Int)- }- deriving Functor---- | Run a 'Fuel' computation, getting back the answer only-evalFuel :: Fuel r a -> Int -> Either r a-evalFuel = fmap fst <$$> runFuel---- | Use up one unit of fuel-burnFuel :: r -> Fuel r ()-burnFuel r = Fuel $ \fuel ->- if fuel == 0- then Left r- else Right ((), fuel - 1)---- | Give up on a fuel computation-bailOut :: r -> Fuel r a-bailOut = Fuel . const . Left--{---- | Catch a failed fuel computation, and potentially add more fuel-reFuel :: Fuel r a -> (r -> (Int, Fuel r a)) -> Fuel r a-reFuel f k = Fuel $ \fuel -> case runFuel f fuel of- Left r -> let (fuel', f') = k r in runFuel f' fuel'- Right (fuel', a) -> Right (fuel', a)--}---- | Given a fuel computation with a given failure result, map--- the failure result-mapError :: Fuel r a -> (r -> s) -> Fuel s a-mapError f h = Fuel $ \fuel -> case runFuel f fuel of- Left r -> Left (h r)- Right a -> Right a--instance Applicative (Fuel r) where- pure a = Fuel $ \fuel -> Right (a, fuel)- f <*> g = Fuel $ \fuel -> case runFuel f fuel of- Right (f', fuel') -> case runFuel g fuel' of- Right (g', fuel'') -> Right (f' g', fuel'')- Left r -> Left r- Left r -> Left r--instance Monad (Fuel r) where- return a = Fuel $ \fuel -> Right (a, fuel)- m >>= k = Fuel $ \fuel -> case runFuel m fuel of- Right (m', fuel') -> runFuel (k m') fuel'- Left r -> Left r--------- Built-in type constructors------class ExtTC r where- extTC :: TyCon -> r--instance ExtTC TyCon where- extTC = id-instance ExtTC r => ExtTC (QLid Renamed -> r) where- extTC tc x = extTC (tc { tcName = x })-instance (v ~ Variance, ExtTC r) => ExtTC ([(QLit, v)] -> r) where- extTC tc x = extTC (tc { tcArity = map snd x, tcBounds = map fst x })-instance ExtTC r => ExtTC (QDen Int -> r) where- extTC tc x = extTC (tc { tcQual = x })-instance (v ~ TyVarR, a ~ Type, i ~ Renamed, ExtTC r) =>- ExtTC (([v], Env.Env (Uid i) (Maybe a)) -> r) where- extTC tc x = extTC (tc { tcCons = x })-instance ExtTC r => ExtTC ([([TyPat], Type)] -> r) where- extTC tc x = extTC (tc { tcNext = Just x })-instance ExtTC r => ExtTC (Maybe [([TyPat], Type)] -> r) where- extTC tc x = extTC (tc { tcNext = x })--mkTC :: ExtTC r => Int -> QLid Renamed -> r-mkTC i ql = extTC TyCon {- tcId = i,- tcName = ql,- tcArity = [],- tcBounds = [],- tcQual = minBound,- tcCons = ([], Env.empty),- tcNext = Nothing-}--internalTC :: ExtTC r => Int -> String -> r-internalTC i s = extTC TyCon {- tcId = i,- tcName = J [] (Lid (Ren_ i) s),- tcArity = [],- tcBounds = [],- tcQual = minBound,- tcCons = ([], Env.empty),- tcNext = Nothing-}--tcBot, tcUnit, tcInt, tcFloat, tcString,- tcExn, tcUn, tcAf, tcTuple, tcIdent, tcConst :: TyCon--tcBot = internalTC (-1) "any"-tcUnit = internalTC (-2) "unit" ([], Env.fromList [(uid "()", Nothing)])-tcInt = internalTC (-3) "int"-tcFloat = internalTC (-4) "float"-tcString = internalTC (-5) "string"-tcExn = internalTC (-6) "exn" (maxBound :: QDen Int)-tcUn = internalTC (-7) "U"-tcAf = internalTC (-8) "A" (maxBound :: QDen Int)-tcTuple = internalTC (-9) "*" (0 \/ 1 :: QDen Int) [(Qa, 1), (Qa, 1)]-tcIdent = internalTC (-10) "id" (0 :: QDen Int) [(Qa, 1)]- [([TpVar (tvAf "a")], TyVar (tvAf "a"))]-tcConst = internalTC (-11) "const" (0 :: QDen Int) [(Qa, Invariant)]- [([TpVar (tvAf "a")], tyUnit)]--------- Convenience type constructors-------- | Make a type from a nullary type constructor-tyNulOp :: TyCon -> Type-tyNulOp tc = tyApp tc []---- | Make a type from a unary type constructor-tyUnOp :: TyCon -> Type -> Type-tyUnOp tc t1 = tyApp tc [t1]---- | Make a type from a binary type constructor-tyBinOp :: TyCon -> Type -> Type -> Type-tyBinOp tc t1 t2 = tyApp tc [t1, t2]---- | Constructor for unlimited arrow types-tyArr :: Type -> Type -> Type-tyArr = TyFun minBound---- | Constructor for affine arrow types-tyLol :: Type -> Type -> Type-tyLol = TyFun maxBound---- | Construct a universal type-tyAll :: TyVarR -> Type -> Type-tyAll = TyQu Stx.Forall---- | Construct a existential type-tyEx :: TyVarR -> Type -> Type-tyEx = TyQu Stx.Exists---- | Preconstructed types-tyBot, tyUnit, tyInt, tyFloat, tyString, tyExn, tyUn, tyAf :: Type-tyIdent, tyConst :: Type -> Type-tyTuple :: Type -> Type -> Type-tyTop :: QLit -> Type--tyBot = tyNulOp tcBot-tyUnit = tyNulOp tcUnit-tyInt = tyNulOp tcInt-tyFloat = tyNulOp tcFloat-tyString = tyNulOp tcString-tyExn = tyNulOp tcExn-tyUn = tyNulOp tcUn-tyAf = tyNulOp tcAf-tyTop = elimQLit tyUn tyAf-tyTuple = tyBinOp tcTuple-tyIdent = tyUnOp tcIdent-tyConst = tyUnOp tcConst--(.*.), (.->.), (.-*.) :: Type -> Type -> Type-(.*.) = tyTuple-(.->.) = tyArr-(.-*.) = tyLol--infixr 6 .->., .-*., `tyArr`, `tyLol`-infixl 7 .*., `tyTuple`-infixr 8 .:., `tySemi`--------- Miscellany-------- | Represent a type value as a pre-syntactic type, for printing-typeToStx' :: Type -> Stx.Type Renamed-typeToStx' = typeToStx tyNames0---- | Represent a type value as a syntactic type, for printing; renames--- so that scope is apparent, since internal renaming may result in--- different identifiers that print the same-typeToStx :: TyNames -> Type -> Stx.Type Renamed-typeToStx tns = typeToStxRule tns (iaeInit :: CurrentImpArrPrintingRule)--#ifdef ANNOTATION_RULE-type CurrentImpArrRule = ANNOTATION_RULE-#else-type CurrentImpArrRule = Rule4-#endif--#ifdef ANNOTATION_PRINTING_RULE-type CurrentImpArrPrintingRule = ANNOTATION_PRINTING_RULE-#else-type CurrentImpArrPrintingRule = CurrentImpArrRule-#endif--class ImpArrRule a where- iaeInit :: a- iaeLeft :: a -> a- iaeRight :: a -> QDen (TyVar Renamed) -> Type -> a- iaeImplied :: a -> QDen (TyVar Renamed)- iaeInterpret :: Monad m =>- a -> Maybe (QExp Renamed) -> m (QDen (TyVar Renamed))- iaeRepresent :: a -> QDen (TyVar Renamed) -> Maybe (QExp Renamed)- iaeUnder :: a -> Variance -> a- --- iaeLeft _ = iaeInit- iaeRight iae _ _ = iae- iaeImplied _ = minBound- iaeInterpret iae = maybe (return (iaeImplied iae)) qInterpretM- iaeRepresent iae actual- | actual == iaeImplied iae = Nothing- | otherwise = Just (qRepresent actual)- iaeUnder _ _ = iaeInit---- | Turns annotated arrows into implicit arrows where possible-typeToStxRule :: ImpArrRule iae => TyNames -> iae -> Type -> Stx.Type Renamed-typeToStxRule f iae0 = loop (S.empty, M.empty) iae0 where- loop ren iae t0 = case t0 of- TyVar tv -> Stx.tyVar (maybe tv id (M.lookup tv (snd ren)))- TyFun q t1 t2 -> Stx.tyFun (iaeRepresent iae q)- (loop ren (iaeLeft iae) t1)- (loop ren (iaeRight iae q t1) t2)- TyApp tc ts _ -> Stx.tyApp- (bestName f tc)- (zipWith (loop ren . iaeUnder iae) (tcArity tc) ts)- TyQu qu tv t1 -> Stx.tyQu qu tv' (loop ren' iae t1)- where (tv', ren') = fresh tv ren- TyMu tv t1 -> Stx.tyMu tv' (loop ren' iae t1)- where (tv', ren') = fresh tv ren- fresh tv (seen, remap) =- let tv' = if S.member (unLid (tvname tv)) seen- then freshTyVar tv $- M.keysSet remap `S.union`- S.fromList (M.elems remap)- else tv- in (tv', (S.insert (unLid (tvname tv')) seen,- M.insert tv tv' remap))---- | Print all arrow annotations explicitly-data Rule0 = Rule0--instance ImpArrRule Rule0 where- iaeInit = Rule0- iaeRepresent _ actual = Just (qRepresent actual)---- | Annotation ‘U’ is implicit for unlabeled arrows.-data Rule1 = Rule1--instance ImpArrRule Rule1 where- iaeInit = Rule1--newtype Rule2 = Rule2 { unRule2 :: QDen (TyVar Renamed) }---- | Implicit annotation is lub of qualifiers of prior curried--- arguments. Explicit annotations have no effect on subsequent--- arrows.-instance ImpArrRule Rule2 where- iaeInit = Rule2 minBound- iaeRight iae _ t = Rule2 (unRule2 iae \/ qualifier t)- iaeImplied = unRule2---- | Like 'Rule2', but explicit annotations reset the qualifier to--- themselves for subsequent arrows.-newtype Rule3 = Rule3 { unRule3 :: QDen (TyVar Renamed) }--instance ImpArrRule Rule3 where- iaeInit = Rule3 minBound- iaeRight iae actual t- | unRule3 iae == actual = Rule3 (unRule3 iae \/ qualifier t)- | otherwise = Rule3 (actual \/ qualifier t)- iaeImplied = unRule3---- | Like 'Rule3', but we arrow the implicit qualifer into covariant--- type constructors.-newtype Rule4 = Rule4 { unRule4 :: QDen (TyVar Renamed) }--instance ImpArrRule Rule4 where- iaeInit = Rule4 minBound- iaeRight iae actual t- | unRule4 iae == actual = Rule4 (unRule4 iae \/ qualifier t)- | otherwise = Rule4 (actual \/ qualifier t)- iaeImplied = unRule4- iaeUnder iae Covariant = iae- iaeUnder _ _ = iaeInit---- | Like 'Rule4', but we carry the implicit quantifier into ALL type--- constructors and only use it when we arrive at an arrow in a--- positive position wrt the surrounding arrow.-data Rule5- = Rule5 {- unRule5 :: !(QDen (TyVar Renamed)),- r4Var :: !Variance- }--instance ImpArrRule Rule5 where- iaeInit = Rule5 minBound 1- iaeRight iae actual t- | unRule5 iae == actual = Rule5 (unRule5 iae \/ qualifier t) 1- | otherwise = Rule5 (actual \/ qualifier t) 1- iaeImplied iae- | r4Var iae == 1 = unRule5 iae- | otherwise = minBound- iaeUnder iae var = Rule5 (unRule5 iae) (var * r4Var iae)--tyPatToStx' :: TyPat -> Stx.TyPat Renamed-tyPatToStx' = tyPatToStx tyNames0---- | Represent a type pattern as a syntactic type pattern, for printing-tyPatToStx :: TyNames -> TyPat -> Stx.TyPat Renamed-tyPatToStx f tp0 = case tp0 of- TpVar tv -> Stx.tpVar tv Invariant- TpApp tc tps -> Stx.tpApp (bestName f tc) (map (tyPatToStx f) tps)- where---- | Look up the best printing name for a type.-bestName :: TyNames -> TyCon -> QLid Renamed-bestName tn = tnLookup tn <$> tcId <*> tcName---- | Convert a type pattern to a type; useful for quqlifier and variance--- analysis-tyPatToType :: TyPat -> Type-tyPatToType (TpVar tv) = TyVar tv-tyPatToType (TpApp tc tps) = tyApp tc (map tyPatToType tps)--castableType :: Type -> Bool-castableType t = case headNormalizeType t of- TyVar _ -> False- TyFun _ _ _ -> True- TyApp _ _ _ -> False- TyQu _ _ t1 -> castableType t1- TyMu _ t1 -> castableType t1--{---- Example types and reduction--hgo t = loop 0 where- loop 100 = putStrLn "gave up after 100 steps"- loop i = case headNormalizeTypeK i t of- (Next (), t) -> do print t; loop (i + 1)- (rs, _) -> print rs--go t = loop 0 where- loop 100 = putStrLn "gave up after 100 steps"- loop i = case normalizeTypeK i t of- (Next (), t) -> do print t; loop (i + 1)- (rs, _) -> print rs--a = tyApp tcDual- [tyApp tcSemi- [tyApp tcRecv [tyApp tcInt []],- tyApp tcSemi- [tyApp tcSend [tyApp tcString []],- tyUnit]]]--b = tyApp tcIdent- [tyApp tcSemi- [tyApp tcIdent [tyApp tcRecv [tyApp tcInt []]],- tyApp tcIdent- [tyApp tcSemi- [tyApp tcSend [tyApp tcString []],- tyUnit]]]]--c = tyApp tcIdent [tyApp tcDual [b]]--d = tyApp tcDual [c]--e = tyApp tcDual- [tyApp tcIdent- [tyApp tcSemi- [tyApp tcIdent [tyUnit],- tyApp tcIdent- [tyApp tcSemi- [tyApp tcSend [tyApp tcString []],- tyUnit]]]]]--f = tyApp tcDual- [tyApp tcIdent- [tyApp tcSemi- [tyApp tcIdent [TyVar (TV (Lid "c") Qu)],- tyApp tcIdent- [tyApp tcSemi- [tyApp tcSend [tyApp tcString []],- tyUnit]]]]]--g = tyApp tcInfiniteLoop [tyUnit] where--tcInfiniteLoop :: TyCon--tcInfiniteLoop = internalTC (-100) "loop"- [([TpVar (TV (Lid "a") Qu)],- tyApp tcInfiniteLoop [TyVar (TV (Lid "a") Qu)])]--}--instance Viewable Type where- type View Type = Type- view t = case headNormalizeTypeM 1000 t of- Just t' -> t'- Nothing -> error "view: gave up reducting type after 1000 steps"---- | Normalize a type enough to see if it's an application of--- the given construtor-vtAppTc :: TyCon -> Type -> Type-vtAppTc tc t = case headNormalizeType t of- t'@(TyApp tc' _ _) | tc == tc' -> t'- _ -> t---- | Normalize a type enough to see if it's bottom-isBotType :: Type -> Bool-isBotType t = case view t of- TyApp tc _ _ -> tc == tcBot- _ -> False---- | Unfold the arguments of a function type, normalizing as--- necessary-vtFuns :: Type -> ([Type], Type)-vtFuns t = case view t of- TyFun _ ta tr -> first (ta:) (vtFuns tr)- _ -> ([], t)---- | Unfold the parameters of a quantified type, normalizing as--- necessary-vtQus :: Stx.Quant -> Type -> ([TyVarR], Type)-vtQus u t = case view t of- TyQu u' x t' | u == u' -> first (x:) (vtQus u t')- _ -> ([], t)---- For session types:--tcSend, tcRecv, tcSelect, tcFollow, tcSemi, tcDual :: TyCon--tcSend = internalTC (-31) "send" [(Qa, 1)]-tcRecv = internalTC (-32) "recv" [(Qa, -1)]-tcSelect = internalTC (-33) "select" [(Qu, 1), (Qu, 1)]-tcFollow = internalTC (-34) "follow" [(Qu, 1), (Qu, 1)]-tcSemi = internalTC (-35) ";" [(Qu, -1), (Qu, 1)]-tcDual = internalTC (-36) "dual" [(Qu, -1)]- [ ([TpApp tcSemi [TpApp tcSend [pa], pb]],- (tyApp tcSemi [tyApp tcRecv [ta], dual tb]))- , ([TpApp tcSemi [TpApp tcRecv [pa], pb]],- (tyApp tcSemi [tyApp tcSend [ta], dual tb]))- , ([TpApp tcSelect [pa, pb]], (tyApp tcFollow [dual ta, dual tb]))- , ([TpApp tcFollow [pa, pb]], (tyApp tcSelect [dual ta, dual tb]))- , ([TpApp tcUnit []], (tyApp tcUnit []))- ]- where a = tvAf "a"- b = tvAf "b"- pa = TpVar a- pb = TpVar b- ta = TyVar a- tb = TyVar b- dual t = tyApp tcDual [t]--tySend, tyRecv, tyDual :: Type -> Type-tySelect, tyFollow, tySemi :: Type -> Type -> Type-(.:.) :: Type -> Type -> Type--tySend = tyUnOp tcSend-tyRecv = tyUnOp tcRecv-tySelect = tyBinOp tcSelect-tyFollow = tyBinOp tcFollow-tySemi = tyBinOp tcSemi-tyDual = tyUnOp tcDual-(.:.) = tySemi---- | Noisy type printer for debugging (includes type tags that aren't--- normally pretty-printed)-dumpType :: Type -> String-dumpType = CMW.execWriter . loop 0 where- loop i t0 = do- CMW.tell (replicate i ' ')- case t0 of- TyApp tc ts _ -> do- CMW.tell $- show (tcName tc) ++ "[" ++- show (lidUnique (jname (tcName tc))) ++ "] {\n"- mapM_ (loop (i + 2)) ts- CMW.tell (replicate i ' ' ++ "}\n")- TyFun q dom cod -> do- CMW.tell $ "-[" ++ show q ++ "]> {\n"- loop (i + 2) dom- loop (i + 2) cod- CMW.tell (replicate i ' ' ++ "}\n")- TyVar tv -> CMW.tell $ show tv- TyQu u a t -> do- CMW.tell $ show u ++ " " ++ show a ++ ". {\n"- loop (i + 2) t- CMW.tell (replicate i ' ' ++ "}\n")- TyMu a t -> do- CMW.tell $ "mu " ++ show a ++ ". {\n"- loop (i + 2) t- CMW.tell (replicate i ' ' ++ "}\n")--instance Ppr TyCon where- ppr tc = atPrec 0 $- case tcNext tc of- Just [(tps,t)] -> pprTyApp (tcName tc) (ps (map snd tvs))- >?> qe (map fst tvs)- >?> char '=' <+> ppr t- where- tvs = [ case tp of- TpVar tv -> (tv, ppr tv)- _ -> let tv = TV (lid (show i)) qlit- tv' = case qlit of- Qa -> ppr tv <> char '=' <>- mapPrec (max precEq) (ppr tp)- Qu -> ppr tp- in (tv, tv')- | tp <- tps- | qlit <- tcBounds tc- | i <- [ 1 :: Integer .. ] ]- --- Just next -> pprTyApp (tcName tc) (ps tvs)- >?> (qe tvs <+> text "with"- $$ vcat (map alt next))- where- tvs = [ TV (lid (show i)) qlit- | qlit <- tcBounds tc- | i <- [ 1 .. ] :: [Int] ]- alt (tps,t) = char '|' <+> pprPrec precApp tps- <+> ppr (jname (tcName tc))- >?> char '=' <+> ppr t- --- Nothing -> pprTyApp (tcName tc) (ps tvs)- >?> qe tvs- >?> alts- where- tvs = case fst (tcCons tc) of- [] -> [ mk qlit | qlit <- tcBounds tc | mk <- tvalphabet ]- tvs' -> tvs'- alts = sep $- mapHead (text "=" <+>) $- mapTail (text "|" <+>) $- map alt (Env.toList (snd (tcCons tc)))- alt (u, Nothing) = ppr u- alt (u, Just t) = ppr u <+> text "of" <+> ppr t- where- qe :: [TyVarR] -> Doc- qe tvs = case qDenToLit (tcQual tc) of- Just Qu -> empty- _ -> colon <+>- ppr (qRepresent- (denumberQDen- (map qDenOfTyVar tvs) (tcQual tc)))- ps :: Ppr a => [a] -> [Doc]- ps tvs = [ ppr var <> pprPrec (precApp + 1) tv- | tv <- tvs- | var <- tcArity tc ]--instance Show TyCon where showsPrec = showFromPpr+-- from the syntactic types in 'AST.Type'.+module Type (+ module Type.Analyses,+ module Type.ArrowAnnotations,+ module Type.Internal,+ module Type.Ppr,+ module Type.Recursive,+ module Type.Reduce,+ module Type.Subst,+ module Type.Syntax,+ module Type.TyVar,+) where++import Type.Analyses+import Type.ArrowAnnotations+import Type.Internal+import Type.Ppr+import Type.Recursive (standardizeMus)+import Type.Reduce+import Type.Subst+import Type.Syntax+import Type.TyVar
+ src/Type/Analyses.hs view
@@ -0,0 +1,78 @@+module Type.Analyses (+ inferKinds,+ isMonoType,+ tyPatToType,+ tyPatKinds,+) where++import Util+import Type.Internal+import Type.TyVar++import Prelude ()+import qualified Data.Set as S++-- | Find the kinds of the rib 0 type variables in an opened type, where+-- the given 'Int' is the width of the rib.+inferKinds ∷ Ord tv ⇒ Type tv → [Kind]+inferKinds = varianceToKind <$$> loop 0 where+ loop k (TyQu _ _ σ) = loop (k + 1) σ+ loop k (TyVar (Bound i j _))+ | i == k = replicate j 0 ++ 1 : repeat 0+ | otherwise = repeat 0+ loop _ (TyVar (Free _)) = repeat 0+ loop k (TyApp tc σs) =+ foldr (zipWith (+)) (repeat 0)+ [ let σ' = if isQVariance var+ then qualToType σ+ else σ+ in (* var) <$> loop k σ'+ | var ← tcArity tc+ | σ ← σs ]+ loop k (TyRow _ σ1 σ2) = zipWith (+) (loop k σ1) (loop k σ2)+ loop k (TyMu _ σ) = loop (k + 1) σ++-- | Is the given type monomorphic (quantifer free)?+isMonoType ∷ Ord tv ⇒ Type tv → Bool+isMonoType = foldType (\_ ns k → k (() <$ ns) (\_ → False))+ (\_ _ _ → False)+ (\_ → True)+ (\_ → and)+ (\_ → (&&))+ (\_ k → k () id)++-- | Convert a type pattern to a type.+tyPatToType ∷ TyPat → Type Int+tyPatToType tp0 = evalState (loop tp0) [0..]+ where+ loop (TpVar _) = fvTy <$> next+ loop (TpRow _) = tyBinOp tcRowMap (tyNulOp tcRowHole) . fvTy <$> next+ loop (TpApp tc tps) = TyApp tc <$> mapM loop tps+ next = do+ i:rest ← get+ put rest+ return i++-- | Find out the variances, qualifier-involvement, guardedness and+-- 'QLit' bounds of the type variables in a type pattern.+tyPatKinds ∷ TyPat → [(Variance, Bool, Bool, QLit)]+tyPatKinds = loop 1 True False Qa where+ loop !variance !involved !guarded !bound tp0 = case tp0 of+ TpVar _ → [(variance, involved, guarded, bound)]+ TpRow _ → [(variance, involved, guarded, bound)]+ TpApp tc tps →+ concat+ [ loop (vi * variance)+ (involved && S.member i ftv_qe)+ (guarded || gi)+ (if bound == Qu && involved+ then Qu+ else bi)+ tpi+ | i ← [ 0 .. ]+ | vi ← tcArity tc+ | gi ← tcGuards tc+ | bi ← tcBounds tc+ | tpi ← tps ]+ where ftv_qe = ftvSet (tcQual tc)+
+ src/Type/ArrowAnnotations.hs view
@@ -0,0 +1,143 @@+-- | Rules for interpreting arrow qualifier annotations.+module Type.ArrowAnnotations (+ -- * Between internal and external qualifier expressions+ qInterpret, qRepresent,+ -- * Arrow annotation rules+ ImpArrRule(..), CurrentImpArrRule, CurrentImpArrPrintingRule,+) where++import Util+import Meta.Quasi+import qualified AST+import Type.Internal++import Prelude ()+import qualified Data.Set as S++type R = AST.Renamed++-- | The rule for parsing arrows+#ifdef ANNOTATION_RULE+type CurrentImpArrRule = ANNOTATION_RULE+#else+type CurrentImpArrRule = Rule3+#endif++-- | The rule for printing arrows+#ifdef ANNOTATION_PRINTING_RULE+type CurrentImpArrPrintingRule = ANNOTATION_PRINTING_RULE+#else+type CurrentImpArrPrintingRule = CurrentImpArrRule+#endif++-- | Interpret an explicit external qualifier as an internal one+qInterpret ∷ (Ord tv, Monad m) ⇒+ (AST.TyVar R → m tv) →+ AST.QExp R → m (QExp tv)+qInterpret resolve = loop where+ loop [qeQ| $qlit:ql |] = return (qlitexp ql)+ loop [qeQ| `$tv |] = qvarexp `liftM` resolve tv+ loop [qeQ| $qe1 ⋁ $qe2 |] = (⊔) `liftM` loop qe1 `ap` loop qe2+ loop [qeQ| $anti:a |] = $(AST.antifail)++-- | Represent an internal qualifier as an explicit external one+qRepresent ∷ (tv → AST.TyVar R) →+ QExp tv → AST.QExp R+qRepresent _ QeA = [qeQ|+! A |]+qRepresent rename (QeU tvs)+ | S.null tvs = [qeQ|+! U |]+ | otherwise =+ foldr1 AST.qeJoin (AST.qeVar . rename <$> S.toList tvs)++-- | Interface to rules for implicit annotation of arrows+class ImpArrRule rule where+ -- | The initial labeling state+ iaeInit ∷ rule tv+ -- | Update the state to the left of an arrow+ iaeLeft ∷ rule tv → rule tv+ -- | Update the state to the right of an arrow with the given+ -- qualifier+ iaeRight ∷ Ord tv ⇒ rule tv → QExpV tv → Type tv → rule tv+ -- | The implied qualifier at a particular point+ iaeImplied ∷ rule tv → QExpV tv+ -- | Interpret the given implicit qualifier into an explicit qualifier+ -- at the given point+ iaeInterpret ∷ (Ord tv, Monad m) ⇒+ (AST.TyVar R → m (TyVar tv)) →+ rule tv → Maybe (AST.QExp R) → m (QExpV tv)+ -- | Represent the given explicit qualifier as an implicit one+ iaeRepresent ∷ Eq tv ⇒+ (TyVar tv → AST.TyVar R) →+ rule tv → QExpV tv → Maybe (AST.QExp R)+ -- | Update the state under the given variance+ iaeUnder ∷ rule tv → Variance → rule tv+ --+ iaeLeft _ = iaeInit+ iaeRight iae _ _ = iae+ iaeImplied _ = minBound+ iaeInterpret resolve iae+ = maybe (return (iaeImplied iae)) (qInterpret resolve)+ iaeRepresent rename iae actual+ | actual == iaeImplied iae = Nothing+ | otherwise = Just (qRepresent rename actual)+ iaeUnder _ _ = iaeInit++-- | Print all arrow annotations explicitly+data Rule0 tv = Rule0++instance ImpArrRule Rule0 where+ iaeInit = Rule0+ iaeRepresent rename _ actual = Just (qRepresent rename actual)++-- | Annotation ‘U’ is implicit for unlabeled arrows.+data Rule1 tv = Rule1++instance ImpArrRule Rule1 where+ iaeInit = Rule1++newtype Rule2 tv = Rule2 { unRule2 ∷ QExpV tv }++-- | Implicit annotation is lub of qualifiers of prior curried+-- arguments. Explicit annotations have no effect on subsequent+-- arrows.+instance ImpArrRule Rule2 where+ iaeInit = Rule2 minBound+ iaeRight iae _ t = Rule2 (unRule2 iae ⊔ qualifier t)+ iaeImplied = unRule2++-- | Like 'Rule2', but explicit annotations reset the qualifier to+-- themselves for subsequent arrows.+newtype Rule3 tv = Rule3 { unRule3 ∷ QExpV tv }++instance ImpArrRule Rule3 where+ iaeInit = Rule3 minBound+ iaeRight _ actual t = Rule3 (actual ⊔ qualifier t)+ iaeImplied = unRule3++-- | Like 'Rule3', but we arrow the implicit qualifer into covariant+-- type constructors.+newtype Rule4 tv = Rule4 { unRule4 ∷ QExpV tv }++instance ImpArrRule Rule4 where+ iaeInit = Rule4 minBound+ iaeRight _ actual t = Rule4 (actual ⊔ qualifier t)+ iaeImplied = unRule4+ iaeUnder iae Covariant = iae+ iaeUnder _ _ = iaeInit++-- | Like 'Rule4', but we carry the implicit quantifier into ALL type+-- constructors and only use it when we arrive at an arrow in a+-- positive position wrt the surrounding arrow.+data Rule5 tv+ = Rule5 {+ unRule5 ∷ !(QExpV tv),+ r4Var ∷ !Variance+ }++instance ImpArrRule Rule5 where+ iaeInit = Rule5 minBound 1+ iaeRight _ actual t = Rule5 (actual ⊔ qualifier t) 1+ iaeImplied iae+ | r4Var iae == 1 = unRule5 iae+ | otherwise = minBound+ iaeUnder iae var = Rule5 (unRule5 iae) (var * r4Var iae)
+ src/Type/Internal.hs view
@@ -0,0 +1,847 @@+{-# LANGUAGE TypeFamilies #-}+-- | The internal representation of types, created by the type checker+-- from the syntactic types in 'AST.Type'.+module Type.Internal (+ -- * Data definitions+ -- ** Types+ Quant(..), TyVar(..), Type(..), TyCon(..),+ -- ** Qualifiers+ QLit(..), QExp(..), QExpV,+ -- ** Type patterns+ TyPat(..),+ -- ** Kind re-exports+ Variance(..), Lattice(..), BoundedLattice(..), isQVariance,+ -- ** Names+ Name, TypId, QTypId, ConId, QConId, RowLabel, RecLabel,++ -- * Qualifiers+ Qualifier(..), qlitexp, qvarexp, extractQual, liftVQExp, mapQExp,++ -- * Type constructors+ abstractTyCon, mkTC,+ -- ** Built-in+ tcUnit, tcInt, tcChar, tcFloat, tcString, tcExn, tcTuple, tcFun,+ tcUn, tcAf, tcJoin, tcRowEnd, tcRecord, tcVariant, tcRowMap,+ tcRowDots, tcRowHole,+ -- ** Convenient constructors and projections+ fvTy, bvTy, fromFreeTV,+ -- ** Pre-constructed types+ tyNulOp, tyUnOp, tyBinOp,+ tyFun, tyArr, tyLol, tyTuple, tyQLit,+ tyAf, tyUn, tyUnit, tyInt, tyChar, tyFloat, tyString, tyExn,+ tyRecord, tyRowEnd, tyRowMap, tyRowHole,+ (.->.), (.-*.), (.*.),+ -- *** For testing+ tcCycle, tcConst, tcIdent, tcConsTup, tcOption, tcIdfun,+ tcSessOne, tcSessSend, tcSessRecv, tcSessSemi, tcSessDual,++ -- * Standard forms+ standardizeType, standardizeQuals,++ -- * Unfolds and folds+ -- ** Type folding+ foldType, foldTypeM, foldTypeEnv, mkBvF, mkQuF, mkMuF,+ -- ** Unfolds+ unfoldQu, unfoldRow, unfoldMu,+ -- ** Row operations+ foldRow, sortRow,++ -- * Locally nameless+ openTy, openTyN, closeTy, lcTy, lcTyK,+ closeRec, closeQuant,++ -- * Varieties+ TyConVariety(..), varietyOf,++ module Data.Empty,+) where++import Util+import Util.MonadRef+import Data.Empty+import Data.Lattice+import Error+import qualified Env+import qualified AST+import AST ( QLit(..), Variance(..), isQVariance )++import Prelude ()+import Control.Monad.ST+import Data.Generics (Typeable, Data)+import Data.STRef (STRef)+import qualified Data.List as List+import qualified Data.Map as M+import qualified Data.Set as S++---+--- DATA TYPES+---++-- | Everything should be renamed by now+type R = AST.Renamed+type TypId = AST.TypId R+type QTypId = AST.QTypId R+type ConId = AST.ConId R+type QConId = AST.QConId R+type RowLabel = AST.Uid R+type RecLabel = AST.Lid R++-- | Optional names that don't affect α equivalence+type Name = Perhaps String++-- | Locally-nameless–style type variable occurrences in internal types+data TyVar tv+ -- | A free type variable+ = Free !tv+ -- | A bound type variable+ | Bound !Int !Int !Name+ deriving (Eq, Ord, Functor, Typeable, Data)++-- | Quantifiers+data Quant+ -- | Universal quantifier+ = Forall+ -- | Existential quantifier+ | Exists+ deriving (Eq, Ord, Typeable, Data)++-- | The internal representation of a type+data Type tv+ -- | A free type variable+ = TyVar !(TyVar tv)+ -- | A quantified (all or ex) type+ | TyQu !Quant ![(Name, QLit)] !(Type tv)+ -- | A recursive (mu) type+ | TyMu !Name !(Type tv)+ -- | A row type+ | TyRow !RowLabel !(Type tv) !(Type tv)+ -- | The application of a type constructor (possibly nullary).+ | TyApp !TyCon ![Type tv]+ deriving (Functor, Typeable, Data)++-- | Internal qualifier expressions+data QExp tv+ -- | The type qualifier expression+ = QeA+ -- | The join of a set of type variables+ | QeU !(S.Set tv)+ deriving (Eq, Typeable, Data)++-- | Qualifier expressions containing bound variables+type QExpV tv = QExp (TyVar tv)++-- | Information about a type constructor+data TyCon+ = TyCon {+ -- | Unique ID+ tcId ∷ !Int,+ -- | Printable name+ tcName ∷ !QTypId,+ -- | Variances for parameters, and correct length+ tcArity ∷ ![Variance],+ -- | Bounds for parameters+ tcBounds ∷ ![QLit],+ -- | Guards recursive types+ tcGuards ∷ ![Bool],+ -- | Qualifier as a function of parameters+ tcQual ∷ !(QExp Int),+ -- | For pattern-matchable types, the data constructors,+ -- where type parameters are bound at level 0+ tcCons ∷ !(Env.Env ConId (Maybe (Type Empty))),+ -- | For type operators, the next head reduction+ tcNext ∷ !(Maybe [([TyPat], Type Empty)])+ }+ deriving (Typeable, Data)++-- | A type pattern, for defining type operators+data TyPat+ -- | A type variable, matching any type and binding+ = TpVar !Name+ -- | A type application node, matching the given constructor+ -- and its parameters+ | TpApp !TyCon ![TyPat]+ -- | A row type pattern+ | TpRow !Name+ deriving (Typeable, Data)++instance Eq TyCon where+ tc == tc' = tcId tc == tcId tc'++instance Ord TyCon where+ compare tc tc' = compare (tcName tc) (tcName tc')++---+--- Abstracting type constructors+---++-- | Remove the representation from a type constructor+abstractTyCon ∷ TyCon → TyCon+abstractTyCon tc = tc { tcCons = mempty, tcNext = Nothing }++---+--- Built-in types+---++class ExtTC r where+ extTC ∷ TyCon → r++instance ExtTC TyCon where+ extTC = id++instance ExtTC r ⇒ ExtTC (QTypId → r) where+ extTC tc x = extTC (tc { tcName = x })++instance (v ~ Variance, ql ~ QLit, ExtTC r) ⇒+ ExtTC ([(v, ql, Bool)] → r) where+ extTC tc x = extTC tc {+ tcArity = sel1 <$> x,+ tcBounds = sel2 <$> x,+ tcGuards = sel3 <$> x+ }++instance (tv ~ Int, ExtTC r) ⇒ ExtTC (QExp tv → r) where+ extTC tc x = extTC (tc { tcQual = x })++instance (a ~ Type Empty, ExtTC r) ⇒+ ExtTC (Env.Env ConId (Maybe a) → r) where+ extTC tc x = extTC (tc { tcCons = x })++instance (t ~ Type Empty, ExtTC r) ⇒+ ExtTC ([([TyPat], t)] → r) where+ extTC tc x = extTC (tc { tcNext = Just x })++mkTC ∷ ExtTC r ⇒ Int → AST.QTypId R → r+mkTC i ql+ = extTC TyCon {+ tcId = i,+ tcName = ql,+ tcArity = [],+ tcBounds = [],+ tcGuards = [],+ tcQual = minBound,+ tcCons = Env.empty,+ tcNext = Nothing+ }++internalTC ∷ ExtTC r ⇒ Int → String → r+internalTC i s = mkTC i (AST.J [] (AST.identT (AST.Ren_ i) s))++tcUnit, tcInt, tcChar, tcFloat, tcString,+ tcExn, tcUn, tcAf, tcJoin, tcTuple, tcFun,+ tcRowEnd, tcRecord, tcVariant, tcRowMap, tcRowDots, tcRowHole ∷ TyCon++tcFun = internalTC (-1) "->" (qvarexp 1)+ [(Contravariant, Qa, False),+ (QCovariant, Qa, False),+ (Covariant, Qa, False)]+tcUnit = internalTC (-2) "unit"+ (Env.fromList [(AST.ident "()" ∷ ConId, Nothing)])+tcInt = internalTC (-3) "int"+tcChar = internalTC (-4) "char"+tcFloat = internalTC (-5) "float"+tcString = internalTC (-6) "string"+tcExn = internalTC (-7) "exn" QeA+tcUn = internalTC (-8) "U"+tcAf = internalTC (-9) "A" QeA+tcJoin = internalTC (-10) "\\/" (qvarexp 0 ⊔ qvarexp 1)+ [(Covariant, Qa, False),+ (Covariant, Qa, False)]+tcTuple = internalTC (-11) "*" (qvarexp 0 ⊔ qvarexp 1)+ [(Covariant, Qa, False),+ (Covariant, Qa, False)]+tcRowEnd = internalTC (-12) "rowend"+tcVariant = internalTC (-13) "variant" (qvarexp 0)+ [(Covariant, Qa, False)]+tcRecord = internalTC (-14) "record" (qvarexp 1)+ [(QCovariant, Qa, False),+ (Covariant, Qa, False)]+tcRowMap = internalTC (-15) "rowmap#" (qvarexp 0 ⊔ qvarexp 1)+ [(Covariant, Qa, False),+ (Invariant, Qa, False)]+tcRowDots = internalTC (-16) "rowdots#" (qvarexp 0)+ [(Covariant, Qa, True)]+tcRowHole = internalTC (-17) "rowhole#" (qvarexp 0)+ [(Covariant, Qa, True)]++-- Types for testing++tcCycle, tcConst, tcIdent, tcConsTup, tcOption, tcIdfun ∷ TyCon+tcCycle = internalTC (-51) "cycle" [(Invariant, Qa, True)]+tcConst = internalTC (-52) "const" [(Omnivariant, Qa, False)]+ [([TpVar Nope], tyUnit)]+tcIdent = internalTC (-53) "ident" (qvarexp 0)+ [(Covariant, Qa, False)]+ [([TpVar Nope], TyVar (Bound 0 0 Nope))]+tcConsTup = internalTC (-54) "cons" (qvarexp 0 ⊔ qvarexp 1)+ [(Covariant, Qa, False),+ (Covariant, Qa, False)]+ [([TpVar Nope, TpApp tcTuple [TpVar Nope, TpVar Nope]],+ TyApp tcTuple [TyApp tcConsTup [TyVar (Bound 0 0 Nope),+ TyVar (Bound 0 1 Nope)],+ TyVar (Bound 0 2 Nope)]),+ ([TpVar Nope, TpVar Nope],+ TyApp tcTuple [TyVar (Bound 0 0 Nope),+ TyVar (Bound 0 1 Nope)])]+tcOption = internalTC (-55) "option" (qvarexp 0)+ [(Covariant, Qa, False)]+ (Env.fromList [(AST.ident "None" ∷ ConId, Nothing),+ (AST.ident "Some", Just (bvTy 0 0 Nope))])+tcIdfun = internalTC (-55) "idfun" [(Invariant, Qa, False)]+ (Env.fromList [(AST.ident "Mono" ∷ ConId,+ Just (bvTy 0 0 Nope .->. bvTy 0 0 Nope)),+ (AST.ident "Poly",+ Just (TyQu Forall [(Nope, Qa)]+ (bvTy 0 0 Nope .->. bvTy 0 0 Nope)))])++tcSessOne, tcSessSend, tcSessRecv, tcSessSemi, tcSessDual ∷ TyCon+tcSessOne = internalTC (-56) "1"+tcSessSend = internalTC (-57) "!" [(-1, Qa, False)]+tcSessRecv = internalTC (-58) "?" [(1, Qa, False)]+tcSessSemi = internalTC (-59) ";" [(1, Qu, False), (1, Qu, True)]+tcSessDual = internalTC (-60) "dual" [(-1, Qu, False)]+ [([TpApp tcSessOne []],+ TyApp tcSessOne []),+ ([TpApp tcSessSemi [TpApp tcSessSend [TpVar Nope], TpVar Nope]],+ TyApp tcSessSemi [TyApp tcSessRecv [TyVar (Bound 0 0 Nope)],+ TyApp tcSessDual [TyVar (Bound 0 1 Nope)]]),+ ([TpApp tcSessSemi [TpApp tcSessRecv [TpVar Nope], TpVar Nope]],+ TyApp tcSessSemi [TyApp tcSessSend [TyVar (Bound 0 0 Nope)],+ TyApp tcSessDual [TyVar (Bound 0 1 Nope)]])]++---+--- Convenience constructors+---++-- | Make a free type variable into a type+fvTy ∷ tv → Type tv+fvTy = TyVar . Free++-- | Make a bound type variable type+bvTy ∷ Optional f ⇒ Int → Int → f String → Type tv+bvTy i j n = TyVar (Bound i j (foldOpt Nope Here n))++-- | Project a free type variable from a 'TyVar'+fromFreeTV ∷ TyVar tv → tv+fromFreeTV (Free r) = r+fromFreeTV _ = throw $+ almsBug StaticsPhase "fromFreeTV" "Got bound type variable"++-- | Make a type from a nullary type constructor+tyNulOp ∷ TyCon → Type tv+tyNulOp tc = TyApp tc []++-- | Make a type from a unary type constructor+tyUnOp ∷ TyCon → Type tv → Type tv+tyUnOp tc t1 = TyApp tc [t1]++-- | Make a type from a binary type constructor+tyBinOp ∷ TyCon → Type tv → Type tv → Type tv+tyBinOp tc t1 t2 = TyApp tc [t1, t2]++-- | A function type+tyFun ∷ Qualifier qe tv ⇒ Type tv → qe → Type tv → Type tv+tyFun t1 qe t2 = TyApp tcFun [t1, qualToType qe, t2]++-- | Constructor for unlimited arrow types+tyArr ∷ Type tv → Type tv → Type tv+tyArr = tyFun <-> Qu++-- | Constructor for affine arrow types+tyLol ∷ Type tv → Type tv → Type tv+tyLol = tyFun <-> Qa++-- | Type from a 'QLit'+tyQLit ∷ QLit → Type tv+tyQLit Qa = tyAf+tyQLit Qu = tyUn++-- | Binary types+tyTuple, tyRowMap, tyRecord ∷ Type tv → Type tv → Type tv++tyTuple = tyBinOp tcTuple+tyRowMap = tyBinOp tcRowMap+tyRecord = tyBinOp tcRecord++-- | Nullary types+tyAf, tyUn, tyUnit, tyInt, tyChar, tyFloat, tyString, tyExn,+ tyRowEnd, tyRowHole ∷ Type tv++tyAf = tyNulOp tcAf+tyUn = tyNulOp tcUn+tyUnit = tyNulOp tcUnit+tyInt = tyNulOp tcInt+tyChar = tyNulOp tcChar+tyFloat = tyNulOp tcFloat+tyString = tyNulOp tcString+tyExn = tyNulOp tcExn+tyRowEnd = tyNulOp tcRowEnd+tyRowHole= tyNulOp tcRowHole++(.*.), (.->.), (.-*.) ∷ Type tv → Type tv → Type tv+(.*.) = tyTuple+(.->.) = tyArr+(.-*.) = tyLol++infixr 6 .->., .-*., `tyArr`, `tyLol`+infixl 7 .*., `tyTuple`++---+--- Qualifiers+---++instance Ord tv ⇒ Lattice (QExp tv) where+ QeA ⊔ _ = QeA+ _ ⊔ QeA = QeA+ QeU tvs ⊔ QeU tvs' = QeU (tvs `S.union` tvs')+ --+ QeA ⊓ qe' = qe'+ qe ⊓ QeA = qe+ QeU tvs ⊓ QeU tvs' = QeU (tvs `S.intersection` tvs')+ --+ _ ⊑ QeA = True+ QeA ⊑ _ = False+ QeU tvs ⊑ QeU tvs' = tvs `S.isSubsetOf` tvs'++instance Bounded (QExp tv) where+ minBound = QeU S.empty+ maxBound = QeA++class Qualifier q tv | q → tv where+ qualToType ∷ q → Type tv+ qualifierEnv ∷ Ord tv ⇒ [[QLit]] → q → QExpV tv+ qualifier ∷ Ord tv ⇒ q → QExpV tv+ qualifierEnv = const qualifier+ qualifier = qualifierEnv []++instance Qualifier q tv ⇒ Qualifier (Maybe q) tv where+ qualToType = maybe tyUn qualToType+ qualifierEnv = maybe minBound . qualifierEnv++instance (Ord tv, Qualifier q tv) ⇒ Qualifier [q] tv where+ qualToType = qualToType . qualifier+ qualifierEnv = bigJoin <$$> map . qualifierEnv++instance Qualifier QLit tv where+ qualToType Qa = tyAf+ qualToType Qu = tyUn+ qualifier Qa = QeA+ qualifier Qu = QeU S.empty++instance Qualifier AST.Occurrence tv where+ qualToType = qualToType . AST.occToQLit+ qualifier = qualifier . AST.occToQLit++instance Ord tv ⇒ Qualifier (Type tv) tv where+ qualToType = qualToType . qualifier+ qualifierEnv env0 = foldTypeEnv (Left <$$> env0)+ fquant fbvar ffvar fcon frow frec+ where+ fquant ∷ Quant → [(Name, QLit)] →+ ([Either QLit QLit] → (QExpV tv → QExpV tv) → a) → a+ frec ∷ Name → (Either QLit QLit → (QExpV tv → QExpV tv) → a) → a+ fquant Forall αs k = k (Right Qu <$ αs) bumpQExp+ fquant Exists αs k = k (Right . snd <$> αs) bumpQExp+ fbvar _ _ (Just (Right ql)) = qlitexp ql+ fbvar _ _ (Just (Left Qu)) = qlitexp Qu+ fbvar (i,j) n _ = qvarexp (Bound i j n)+ ffvar = qvarexp . Free+ fcon tc qes = extractQual (tcQual tc) qes+ frow _ qe1 qe2 = qe1 ⊔ qe2+ frec _ k = k (Right Qu) bumpQExp+ --+ bumpQExp QeA = QeA+ bumpQExp (QeU tvs) = QeU (S.map (bumpVar (-1)) tvs)+ bumpVar _ (Free r) = Free r+ bumpVar k (Bound i j n)= Bound (i + k) j n++instance Qualifier (QExpV tv) tv where+ qualToType QeA = TyApp tcAf []+ qualToType (QeU tvs)+ | S.null tvs = TyApp tcUn []+ | otherwise = foldr1 (\t1 t2 → TyApp tcJoin [t1, t2])+ (TyVar <$> S.toList tvs)+ qualifier = id++instance Qualifier (S.Set tv) tv where+ qualifier αs = QeU (S.mapMonotonic Free αs)+ qualToType αs = qualToType (QeU (S.mapMonotonic Free αs))++-- | Make a qualifier expression from a single literal+qlitexp ∷ QLit → QExp tv+qlitexp Qa = QeA+qlitexp Qu = QeU S.empty++-- | Make a qualifier expression from a single type variable+qvarexp ∷ tv → QExp tv+qvarexp = QeU . S.singleton++-- | Build a qualifier from a list of qualifiers using an+-- integer-numbered qualifier.+extractQual ∷ Ord tv ⇒ QExp Int → [QExp tv] → QExp tv+extractQual QeA _ = QeA+extractQual (QeU zs) qes = bigJoin (fst <$> filter ((`elem` zs) . snd)+ (zip qes [0 ..]))++-- | Lift a free-variable q-expression to a 'QExpV'+liftVQExp ∷ QExp tv → QExpV tv+liftVQExp QeA = QeA+liftVQExp (QeU αs) = QeU (S.mapMonotonic Free αs)++-- | Modify the set of a 'QeU' 'QExp"+mapQExp ∷ (S.Set tv → S.Set tv') → QExp tv → QExp tv'+mapQExp _ QeA = QeA+mapQExp f (QeU αs) = QeU (f αs)++---+--- Folds and unfolds+---++foldTypeEnv+ ∷ Ord tv ⇒+ -- | Initial environment+ [[s]] →+ -- | For quantifiers+ (∀a. Quant → [(Name, QLit)] → ([s] → (r → r) → a) → a) →+ -- | For bound variables+ ((Int, Int) → Name → Maybe s → r) →+ -- | For free variables+ (tv → r) →+ -- | For constructor applications+ (TyCon → [r] → r) →+ -- | For row type labels+ (RowLabel → r → r → r) →+ -- | For recursive types+ (∀a. Name → (s → (r → r) → a) → a) →+ -- | Type to fold+ Type tv →+ r+foldTypeEnv env0 fquant fbvar ffvar fcon frow frec σ0 =+ runReader (loop σ0) env0+ where+ loop (TyQu q αs σ) =+ fquant q αs $ \ss f → f `liftM` local (ss:) (loop σ)+ loop (TyVar (Bound i j n)) = do+ env ← ask+ return (fbvar (i, j) n (look i j env))+ loop (TyVar (Free v)) = return (ffvar v)+ loop (TyApp tc ts) =+ fcon tc <$> sequence+ [ if isQVariance v+ then loop (qualToType t)+ else loop t+ | t ← ts+ | v ← tcArity tc ]+ loop (TyRow n t1 t2) =+ frow n `liftM` loop t1 `ap` loop t2+ loop (TyMu n t) =+ frec n (\s f → f `liftM` local ([s]:) (loop t))+ --+ look i j env+ | rib:_ ← drop i env+ , elt:_ ← drop j rib = Just elt+ look _ _ _ = Nothing++foldType ∷ Ord tv ⇒+ -- | For quantifiers+ (∀a. Quant → [(Name, QLit)] → ([s] → (r → r) → a) → a) →+ -- | For bound variables+ ((Int, Int) → Name → Maybe s → r) →+ -- | For free variables+ (tv → r) →+ -- | For constructor applications+ (TyCon → [r] → r) →+ -- | For row type labels+ (RowLabel → r → r → r) →+ -- | For recursive types+ (∀a. Name → (s → (r → r) → a) → a) →+ -- | Type to fold+ Type tv →+ r+foldType = foldTypeEnv []++-- | Helper for constructing bound variable case for 'foldType'+mkBvF ∷ (Int → Int → Name → r) →+ (Int, Int) → Name → a → r+mkBvF f (i, j) pn _ = f i j pn++-- | Helper for constructing quantifier case for 'foldType'+mkQuF+ ∷ (Quant → [(Name, QLit)] → r → s) →+ (∀a. Quant → [(Name, QLit)] → ([(Int, Int)] → (r → s) → a) → a)+mkQuF f q αs k = k [ (0, j) | j ← [0 .. length αs - 1] ] (f q αs)++-- | Helper for constructing recursive case for 'foldType'+mkMuF ∷ (Name → r → s) →+ (∀a. Name → ((Int, Int) → (r → s) → a) → a)+mkMuF f pn k = k (0, 0) (f pn)++foldTypeM ∷ (Monad m, Ord tv) ⇒+ -- | For quantifiers+ (∀a. Quant → [(Name, QLit)] → ([s] → (r → m r) → a) → a) →+ -- | For bound variables+ ((Int, Int) → Name → Maybe s → m r) →+ -- | For free variables+ (tv → m r) →+ -- | For constructor applications+ (TyCon → [r] → m r) →+ -- | For row type labels+ (RowLabel → r → r → m r) →+ -- | For recursive types+ (∀a. Name → (s → (r → m r) → a) → a) →+ -- | Type to fold+ Type tv →+ m r+foldTypeM fquant fbvar ffvar fapp frow frec =+ foldType (\qu ns k → fquant qu ns (\s k' → k s (>>= k')))+ fbvar+ ffvar+ (\tc mrs → sequence mrs >>= fapp tc)+ (\lab mr1 mr2 → mr1 >>= \r1 → mr2 >>= frow lab r1)+ (\n k → frec n (\s k' → k s (>>= k')))++--+-- Other unfolds+--++-- To strip off as many of the specified quantifier as possible,+-- building a qualifier bound environment for the layers.+unfoldQu ∷ Quant → Type tv → ([[QLit]], Type tv)+unfoldQu u0 = first reverse . loop where+ loop (TyQu u tvs t)+ | u0 == u || lcTyK 0 t = first (map snd tvs:) (loop t)+ loop t = ([], t)++-- To find the labels and fields of a row type, and the extension,+-- in standard order+unfoldRow ∷ Type tv → ([(RowLabel, Type tv)], Type tv)+unfoldRow = first (List.sortBy (compare <$> fst <$.> fst)) . loop where+ loop (TyRow n t1 t2) = first ((n, t1):) (loop t2)+ loop t = ([], t)++-- Unfold leading μ (recursive type) binders.+unfoldMu ∷ Type tv → ([Name], Type tv)+unfoldMu (TyMu pn t) = first (pn:) (unfoldMu t)+unfoldMu t = ([], t)++---+--- Row operations+---++-- Construct a row from a list of label/type pairs and a tail type.+foldRow ∷ [(RowLabel, Type a)] → Type a → Type a+foldRow = flip (foldr (uncurry TyRow))++-- Sort a row by its labels+sortRow ∷ Type a → Type a+sortRow = uncurry foldRow . unfoldRow++---+--- Type standardization+---++-- | @standardize@ puts a type in standard form.+-- A type is in standard form if three conditions are met:+-- +-- * All bound type variables actually appear in their scope. That+-- is, ‘∀ α β γ. α → γ’ is not standard, but ‘∀ α γ. α → γ’ is.+--+-- * The same quantifier never nests directly inside itself. That is,+-- ‘∀ α β. ∀ γ. C α β γ’ is not standard, but ‘∀ α β γ. C α β γ’ is.+--+-- * The bound type variables of each quantifier are listed in the+-- order that they appear in its scope. That is,+-- ‘∀ α β γ. C α γ β’ is not standard, but ‘∀ α β γ. C α β γ’ is.+--+-- * Type variables bound by μ appear in their scope, and there are+-- never multiple, immediately nested μs.+--+-- Type standardization is necessary as a post-pass after parsing,+-- because it's difficult to parse into standard form directly.+standardizeType ∷ Ord tv ⇒ Type tv → Type tv+standardizeType = standardizeQuals M.empty++-- | Used in the definition of 'standardizeQuals' below.+type StdizeEnv s = [[(Int, STRef s [((Int, Int), (Name, QLit))], Bool, QLit)]]++-- | Standardize a type while cleaning up qualifiers.+standardizeQuals ∷ ∀tv. Ord tv ⇒ M.Map tv QLit → Type tv → Type tv+standardizeQuals qm t00 = runST (loop 0 [] t00) where+ loop ∷ ∀s. Int → StdizeEnv s → Type tv → ST s (Type tv)+ loop depth g t0 = case t0 of+ TyQu u _ _ → do+ rn ← newRef []+ let (qls, t) = unfoldQu u t0+ i = length qls+ g' = (depth + i, rn, False,) <$$> qls+ t' ← loop (depth + i) (g' ++ g) t+ nl ← readRef rn+ return $ case nl of+ [] → openTyN i (-1) [] t'+ _ → TyQu u [ n | (_,n) ← nl ] (openTyN (i - 1) (i - 1) [] t')+ TyApp tc ts → TyApp tc <$> sequence+ [ if isQVariance v+ then doQual depth g t+ else loop depth g t+ | t ← ts+ | v ← tcArity tc ]+ TyVar v → TyVar . fst <$> doVar depth g (const True) v+ TyRow _ _ _ → do+ let (row, ext) = unfoldRow t0+ row' ← sequence+ [ (ni,) <$> loop depth g ti+ | (ni, ti) ← row ]+ ext' ← loop depth g ext+ return (foldRow row' ext')+ TyMu pn _ → do+ rn ← newRef []+ let (pns, t) = unfoldMu t0+ i = length pns+ g' = (depth + i, rn, True,) <$$> replicate i [Qa]+ t' ← loop (depth + i) (g' ++ g) t+ nl ← readRef rn+ return $+ if null nl+ then openTyN i (-1) [] t'+ else TyMu pn (openTyN (i - 1) (i - 1) [] t')+ --+ doVar ∷ ∀s. Int → StdizeEnv s →+ (QLit → Bool) → TyVar tv → ST s (TyVar tv, Bool)+ doVar depth g keep v0 = case v0 of+ Bound i j n+ | rib:_ ← drop i g+ , (olddepth, r, rec, ql):_ ← drop j rib+ → do+ s ← readRef r+ if rec+ then do+ case List.findIndex ((== (depth - i)) . fst . fst) s of+ Just _ → return ()+ Nothing → writeRef r (s ++ [((depth - i, 0), (n, ql))])+ return (Bound (depth - olddepth) 0 n, True)+ else do+ j' ← case List.findIndex ((== (depth - i, j)) . fst) s of+ Just j' → return j'+ Nothing → do+ when (keep ql) $+ writeRef r (s ++ [((depth - i, j), (n, ql))])+ return (length s)+ return (Bound (depth - olddepth) j' n, keep ql)+ | otherwise → return (v0, True)+ Free r → return (Free r,+ keep (M.findWithDefault maxBound r qm))+ --+ doQual ∷ ∀s. Ord tv ⇒ Int → StdizeEnv s → Type tv → ST s (Type tv)+ doQual depth g t =+ qualToType <$> case qualifier t of+ QeA → return QeA+ QeU tvs → do+ tvbs' ← mapM (doVar depth g (== Qa)) (S.toList tvs)+ return (QeU (S.fromList (fst <$> filter snd tvbs')))++---+--- Locally-nameless operations+---++-- | @openTy k τs τ@ substitutes @τs@ for the bound type variables at+-- rib level @k@. DeBruijn indices higher than @k@ are adjusted downward,+-- since opening a type peels off a quantifier.+openTy ∷ Int → [Type a] → Type a → Type a+openTy = openTyN 1++-- | Generalization of 'openTy': the first argument specifies how much+-- to adjust indices that exceed @k@.+openTyN ∷ Int → Int → [Type a] → Type a → Type a+openTyN n k vs σ0 = case σ0 of+ TyQu u e σ → TyQu u e (next σ)+ TyVar v → openTV_N n k vs v+ TyApp name σs → TyApp name (map this σs)+ TyRow name σ1 σ2 → TyRow name (this σ1) (this σ2)+ TyMu name σ → TyMu name (next σ)+ where+ this = openTyN n k vs+ next = openTyN n (k + 1) vs++openTV_N ∷ Int → Int → [Type a] → TyVar a → Type a+openTV_N n k vs (Bound i j name)+ | i > k = TyVar (Bound (i - n) j name)+ | i == k, Just σ ← listNth j vs+ = σ+ | otherwise = TyVar (Bound i j name)+openTV_N _ _ _ (Free v) = TyVar (Free v)++-- | @closeTy k αs τ@ finds the free variables @αs@ and replaces them+-- with bound variables at rib level @k@. The position of each type+-- variable in @αs@ gives the index of each bound variable into the+-- new rib.+closeTy ∷ Eq a ⇒ Int → [a] → Type a → Type a+closeTy k vs σ0 = case σ0 of+ TyQu u e σ → TyQu u e (next σ)+ TyVar (Bound i j n)+ | i >= k → TyVar (Bound (i + 1) j n)+ | otherwise → TyVar (Bound i j n)+ TyVar (Free v)+ | Just j ← List.findIndex (== v) vs+ → TyVar (Bound k j Nope)+ | otherwise → TyVar (Free v)+ TyApp n σs → TyApp n (map this σs)+ TyRow n σ1 σ2 → TyRow n (this σ1) (this σ2)+ TyMu n σ → TyMu n (next σ)+ where+ this = closeTy k vs+ next = closeTy (k + 1) vs++-- | Build a recursive type by closing and binding the given variable+closeRec ∷ Ord tv ⇒ tv → Type tv → Type tv+closeRec α σ = standardizeType (TyMu Nope (closeTy 0 [α] σ))++-- | Add the given quantifier while binding the given list of variables+closeQuant ∷ Ord tv ⇒ Quant → [(tv, QLit)] → Type tv → Type tv+closeQuant qu αqs ρ = standardizeType (TyQu qu nqs (closeTy 0 αs ρ))+ where+ αs = fst <$> αqs+ nqs = zip (repeat Nope) (snd <$> αqs)++-- | Is the given type locally closed to level k? A type is locally closed+-- if none of its bound variables point to quantifiers "outside" the+-- type.+--+-- ASSUMPTION: No bound variables are lurking behind an apparent free+-- variable, because @lcTy@ doesn't attempt to dereference free+-- variables. This should be an invariant, because it would come+-- about only as a result of a capturing substitution.+lcTy ∷ Int → Type a → Bool+lcTy = loop where+ loop k (TyQu _ _ t) = loop (k + 1) t+ loop k (TyVar (Bound i _ _)) = k > i+ loop _ (TyVar (Free _)) = True+ loop k (TyApp _ ts) = all (loop k) ts+ loop k (TyRow _ t1 t2) = loop k t1 && loop k t2+ loop k (TyMu _ t) = loop (k + 1) t++-- | Are there no bound vars of level k?+lcTyK ∷ Int → Type tv → Bool+lcTyK = loop where+ loop k (TyQu _ _ t) = loop (k + 1) t+ loop k (TyVar (Bound i _ _)) = k /= i+ loop _ (TyVar (Free _)) = True+ loop k (TyApp _ ts) = all (loop k) ts+ loop k (TyRow _ t1 t2) = loop k t1 && loop k t2+ loop k (TyMu _ t) = loop (k + 1) t++---+--- TyCon Varieties+---++data TyConVariety+ = AbstractType+ | DataType+ | OperatorType+ deriving (Eq, Ord)++-- | Find out the variety of a type constructor+varietyOf ∷ TyCon → TyConVariety+varietyOf tc+ | isJust (tcNext tc) = OperatorType+ | Env.isEmpty (tcCons tc) = AbstractType+ | otherwise = DataType+
+ src/Type/Ppr.hs view
@@ -0,0 +1,108 @@+-- | Pretty printing of internal types+module Type.Ppr ( TyConInfo(..) ) where++import Util+import qualified AST+import Type.Internal+import Type.Syntax+import Type.TyVar+import Type.ArrowAnnotations+import Syntax.Ppr++import Prelude ()+import qualified Data.Set as S++instance Tv tv ⇒ Ppr (Type tv) where+ ppr τ = askTyNames $ \tn → ppr (typeToStx t2sContext0 { t2sTyNames = tn } τ)++instance Ppr TyPat where+ ppr tp = askTyNames $ \tn → ppr (fst (tyPatToStx tn [] Qa tp))++instance Ppr TyCon where+ ppr tc = askTyNames $ \tn → ppr (tyConToStx tn tc)++instance Tv tv ⇒ Ppr (QExp tv) where+ ppr QeA = char 'A'+ ppr (QeU αset) = case S.toList αset of+ [] → char 'U'+ [α] → ppr α+ αs → prec precTySemi $+ fcat (punctuate (char '⋁') (ppr0 <$> αs))++instance Ppr TyConVariety where+ ppr AbstractType = text "abstract type"+ ppr DataType = text "data type"+ ppr OperatorType = text "type synonym or operator"++instance Tv tv ⇒ Show (Type tv) where showsPrec = showFromPpr+instance Show TyPat where showsPrec = showFromPpr+instance Show TyCon where showsPrec = showFromPpr+instance Tv tv ⇒ Show (QExp tv) where showsPrec = showFromPpr+instance Show TyConVariety where showsPrec = showFromPpr++-- | For verbose printing of 'TyCon's+newtype TyConInfo = TyConInfo TyCon++instance Ppr TyConInfo where+ ppr (TyConInfo tc) | tc == tcExn = text "exn"+ ppr (TyConInfo tc) = askTyNames $ \tn → atPrec 0 $+ case view (tyConToStx tn tc) of+ AST.TdSyn { AST.tdClauses = [(tps, t)] } →+ pprTyApp (tcName tc) (ps (snd <$> tvs))+ >?> ge (fst <$> tvs)+ >?> qe (fst <$> tvs)+ >?> char '=' <+> ppr t+ where+ tvs = [ case view tp of+ AST.TpVar tv _ → (tv, ppr tv)+ _ →+ let tv = AST.TV (AST.ident (show i)) qlit bogus+ tv' = case qlit of+ Qa → ppr tv <> char '=' <>+ mapPrec (max precEq) (ppr tp)+ Qu → ppr tp+ in (tv, tv')+ | tp ← tps+ | qlit ← tcBounds tc+ | i ← [ 1 ∷ Int .. ] ]+ AST.TdSyn { AST.tdClauses = next } →+ pprTyApp (tcName tc) (ps tvs)+ >?> ge tvs+ >?> (qe tvs <+> text "with"+ $$ vcat (map alt next))+ where+ tvs = [ AST.TV (AST.ident (show i)) qlit bogus+ | qlit ← tcBounds tc+ | i ← [ 1 .. ] ∷ [Int] ]+ alt (tps,t) = char '|' <+> pprPrec precApp tps+ <+> ppr (AST.jname (tcName tc))+ >?> char '=' <+> ppr t+ AST.TdAbs { AST.tdParams = tvs } →+ pprTyApp (tcName tc) (ps tvs)+ >?> ge tvs+ >?> qe tvs+ AST.TdDat { AST.tdParams = tvs, AST.tdAlts = altsList } →+ pprTyApp (tcName tc) (ps tvs)+ >?> ge tvs+ >?> qe tvs+ >?> alts+ where+ alts = sep $+ mapHead (text "=" <+>) $+ mapTail (text "|" <+>) $+ map alt altsList+ alt (u, Nothing) = ppr u+ alt (u, Just t) = ppr u <+> text "of" <+> ppr t+ AST.TdAnti a → AST.antierror "ppr (TyConInfo)" a+ where+ qe tvs = case tcQual tc of+ QeU αs | S.null αs+ → mempty+ qe' → colon <+> pprPrec precApp (qRepresent (tvs !!) qe')+ ps tvs = [ ppr var <> pprPrec (precApp + 1) tv+ | tv ← tvs+ | var ← tcArity tc ]+ ge tvs = case map snd . filter fst $ zip (tcGuards tc) tvs of+ [] → mempty+ tvs' → text "rec" <+> fsep (punctuate comma (ppr <$> tvs'))+
+ src/Type/Rank.hs view
@@ -0,0 +1,30 @@+module Type.Rank (+ Rank, zero, infinity, inc+) where++import Syntax.PprClass as Ppr++import Data.Generics (Typeable, Data)++data Rank+ = Finite !Int+ | Infinity+ deriving (Eq, Ord, Typeable, Data)++instance Show Rank where+ show (Finite n) = show n+ show Infinity = "∞"++instance Ppr Rank where ppr = Ppr.text . show++instance Bounded Rank where+ minBound = Finite 0+ maxBound = Infinity++zero, infinity ∷ Rank+zero = minBound+infinity = maxBound++inc ∷ Rank → Rank+inc (Finite n) = Finite (n + 1)+inc Infinity = Infinity
+ src/Type/Recursive.hs view
@@ -0,0 +1,136 @@+-- | Facilities for proper handling of equirecursive types+module Type.Recursive (+ -- * Equirecursive type standardization+ standardizeMus,++ -- * Non-equirecursive comparison+ NoRec(..),+) where++import Util+import Util.MonadRef+import Type.Internal++import Prelude ()+import qualified Data.Map as M+import qualified Data.Set as S+import Control.Monad.ST (runST)++-- | Put all recursion in standard form.+-- PRECONDITION: The type is in 'standardize' standard form and all+-- type variables are substituted+standardizeMus ∷ Ord tv ⇒ Type tv → Type tv+standardizeMus σ00 = runST $ do+ counter ← newRef (0 ∷ Int)+ let loop g0 σ0 = do+ case M.lookup σ0 g0 of+ Just (i, used') → do+ writeRef used' True+ return (fvTy i)+ Nothing → do+ i ← gensym+ used ← newRef False+ let g = M.insert σ0 (i, used) g0+ σ0' ← case σ0 of+ TyQu qu qls σ → do+ is ← mapM (const gensym) qls+ σ' ← loop g (openTy 0 (map fvTy is) σ)+ return (TyQu qu qls (closeTy 0 is σ'))+ TyApp tc σs → TyApp tc `liftM` mapM (loop g) σs+ TyVar _ → return σ0+ TyRow n σ1 σ2 → TyRow n `liftM` loop g σ1 `ap` loop g σ2+ TyMu _ σ1 → loop g0 (openTy 0 [σ0] σ1)+ wasUsed ← readRef used+ return $ if wasUsed+ then TyMu Nope (closeTy 0 [i] σ0')+ else σ0'+ gensym = do+ i ← readRef counter+ writeRef counter (i + 1)+ return (Right i)+ clean = either id (error "BUG! (standardizeMus)")+ σ00' ← loop M.empty (Left <$> σ00)+ return (clean <$> σ00')+++-- | Newtype for defining 'Eq' and 'Ord' on types treating 'TyMu' as a+-- normal type constructor without unfolding. We build the correct+-- equirecursive operations on top of this.+newtype NoRec tv = NoRec (Type tv)++instance Ord tv ⇒ Eq (Type tv) where+ σ1 == σ2 = compare σ1 σ2 == EQ++instance Ord tv ⇒ Ord (Type tv) where+ compare σ10 σ20 = evalState (loop σ10 σ20) S.empty where+ compareM a b = return (compare a b)+ loop σ1 σ2 = do+ seen ← get+ if (S.member (NoRec σ1, NoRec σ2) seen ||+ S.member (NoRec σ2, NoRec σ1) seen)+ then return EQ+ else do+ put (S.insert (NoRec σ1, NoRec σ2) seen)+ case (σ1, σ2) of+ (TyMu _ σ1', _)+ → loop (openTy 0 [σ1] σ1') σ2+ (_, TyMu _ σ2')+ → loop σ1 (openTy 0 [σ2] σ2')+ (TyVar v1, TyVar v2)+ → compareM v1 v2+ (TyQu qu1 qls1 σ1', TyQu qu2 qls2 σ2')+ → compareM qu1 qu2 `thenCmpM`+ compareM qls1 qls2 `thenCmpM`+ loop σ1' σ2'+ (TyRow n1 σ1f σ1r, TyRow n2 σ2f σ2r)+ → compareM n1 n2 `thenCmpM`+ loop σ1f σ2f `thenCmpM`+ loop σ1r σ2r+ (TyApp n1 σs1, TyApp n2 σs2)+ → compareM n1 n2 `thenCmpM`+ compareM (length σs1) (length σs2)+ `thenCmpM`+ foldl' thenCmpM (return EQ) (zipWith loop σs1 σs2)+ (TyVar _, _)+ → return LT+ (_, TyVar _)+ → return GT+ (TyQu _ _ _, _)+ → return LT+ (_, TyQu _ _ _)+ → return GT+ (TyApp _ _, _)+ → return LT+ (_, TyApp _ _)+ → return GT++instance Ord tv ⇒ Eq (NoRec tv) where+ σ1 == σ2 = compare σ1 σ2 == EQ++instance Ord tv ⇒ Ord (NoRec tv) where+ NoRec σ10 `compare` NoRec σ20 = loop σ10 σ20 where+ loop (TyVar r1) (TyVar r2)+ = compare r1 r2+ loop (TyQu qu1 qls1 σ1) (TyQu qu2 qls2 σ2)+ = compare qu1 qu2 `mappend`+ compare qls1 qls2 `mappend`+ loop σ1 σ2+ loop (TyMu _ σ1) (TyMu _ σ2)+ = loop σ1 σ2+ loop (TyRow l1 t1 t1') (TyRow l2 t2 t2')+ = compare l1 l2 `mappend`+ loop t1 t2 `mappend`+ loop t1' t2'+ loop (TyApp tc1 σs1) (TyApp tc2 σs2)+ = compare tc1 tc2 `mappend`+ mconcat (zipWith loop σs1 σs2)+ loop (TyVar _) _ = LT+ loop _ (TyVar _) = GT+ loop (TyQu _ _ _) _ = LT+ loop _ (TyQu _ _ _) = GT+ loop (TyMu _ _) _ = LT+ loop _ (TyMu _ _) = GT+ loop (TyRow _ _ _) _ = LT+ loop _ (TyRow _ _ _) = GT++
+ src/Type/Reduce.hs view
@@ -0,0 +1,155 @@+{-# LANGUAGE TypeFamilies #-}+module Type.Reduce (+ matchReduce,+ headNormalizeTypeK, headNormalizeType,+ headReduceType, ReductionState(..),+ majorReductionSequence, reductionSequence, reductionSequence'+) where++import Util+import Error+import Type.Internal+import Type.TyVar (Tv)+import Type.Ppr ()++import Prelude ()+import Data.Generics (Typeable, Data)+import qualified Data.List as List++instance Tv tv ⇒ Viewable (Type tv) where+ type View (Type tv) = Type tv+ view = headNormalizeTypeK 1000++-- | Reduce a type to head normal form+headNormalizeType ∷ Ord tv ⇒ Type tv → Type tv+headNormalizeType = last . reductionSequence++-- | Allow @k0@ steps to reduce a type to head normal form, or call+-- 'error'+headNormalizeTypeK ∷ Tv tv ⇒ Int → Type tv → Type tv+headNormalizeTypeK k0 σ0 = loop k0 (reductionSequence σ0) where+ loop _ [] = throw $+ almsBug StaticsPhase "headNormalizeTypeK"+ "got empty reduction sequence"+ loop _ [σ] = σ+ loop 0 (σ:_) = throw $+ AlmsError StaticsPhase bogus+ [msg|+ Reduction of type $q:σ0 has not converged after $k0+ steps; stopped at $q:σ.+ |]+ loop k (_:σs) = loop (k - 1) σs++-- | Given two types, try to reduce them to a pair with a common+-- head constructor. We assume that the two types given don't+-- match in the head already.+matchReduce ∷ Ord tv ⇒ Type tv → Type tv → Maybe (Type tv, Type tv)+matchReduce σ1 σ2 =+ List.find isCandidate+ (safeTail (allPairsBFS (majorReductionSequence σ1)+ (majorReductionSequence σ2)))+ where+ isCandidate (TyApp tc _, TyApp tc' _) = tc == tc'+ isCandidate _ = True+ safeTail [] = []+ safeTail (_:σs) = σs++-- | Returns all pairs of a pair of lists, breadth first+allPairsBFS ∷ [a] → [b] → [(a, b)]+allPairsBFS xs0 ys0 = loop [(xs0, ys0)] where+ loop [] = []+ loop xsys = [ (x, y) | (x:_, y:_) ← xsys ]+ ++ loop (take 1 [ (xs, ys) | (xs, _:ys) ← xsys ]+ ++ [ (xs, ys) | (_:xs, ys) ← xsys ])++-- | A major reduction sequence is a reduction sequence filtered+-- to show only changes in the head constructor.+majorReductionSequence ∷ Ord tv ⇒ Type tv → [Type tv]+majorReductionSequence = clean . reductionSequence where+ clean [] = []+ clean (σ:σs) = σ : cleanWith σ σs+ cleanWith σ@(TyApp tc _) ((TyApp tc' _) : σs)+ | tc == tc' = cleanWith σ σs+ cleanWith _ σs = clean σs++-- | The reduction sequence of a type+reductionSequence ∷ Ord tv ⇒ Type tv → [Type tv]+reductionSequence σ = (σ:) $ case headReduceType σ of+ Next σ' → reductionSequence σ'+ _ → []++-- | The reduction sequence of a type along with a final status+-- indicator+reductionSequence' ∷ Ord tv ⇒ Type tv → ([Type tv], ReductionState ())+reductionSequence' σ = first (σ:) $ case headReduceType σ of+ Next σ' → reductionSequence' σ'+ rs → ([], () <$ rs)++-- | The state of a type reduction+data ReductionState t+ -- | The type is head-normal -- that is, its head constructor is+ -- not a type synonym/operator+ = Done+ -- | The type has a next head-reduction step+ | Next t+ -- | The type may reduce further in the future, but right now it+ -- has a pattern match that depends on the value of a type variable+ | Blocked+ -- | The type's head constructor is a synonym/operator, but it+ -- can never take a step, due to a failed pattern match+ | Stuck+ deriving (Eq, Ord, Show, Functor, Typeable, Data)++-- | Perform one head reduction step.+headReduceType ∷ Ord tv ⇒ Type tv → ReductionState (Type tv)+headReduceType σ0 = case σ0 of+ TyQu _ _ _ → Done+ TyVar _ → Done+ TyRow _ _ _ → Done+ TyMu _ σ → Next $ openTy 0 [σ0] σ+ TyApp tc [σ1, σ2] | tc == tcRowMap+ → applyRowMap σ1 σ2+ TyApp tc σs → maybe Done (clauses tc σs) (tcNext tc)+ where+ --+ clauses _ _ [] = Stuck+ clauses tc σs ((tps, rhs):rest) = case patts tps σs of+ Right σs' → Next $ openTy 0 σs' (elimEmptyF rhs)+ Left Stuck → clauses tc σs rest+ Left rs → TyApp tc <$> rs+ --+ patts [] [] = Right []+ patts (tp:tps) (σ:σs) = case patt tp σ of+ Right σs' → case patts tps σs of+ Right σss' → Right (σs' ++ σss')+ Left rs → Left ((σ:) <$> rs)+ Left Blocked → Left $ either ((σ:) <$>) (const Blocked) (patts tps σs)+ Left rs → Left $ (:σs) <$> rs+ patts _ _ = Left Stuck+ --+ patt (TpVar _) σ = Right [σ]+ patt (TpApp tc tps) σ = case σ of+ TyApp tc' σs+ | tc == tc' → ((TyApp tc' <$>) +++ id) (patts tps σs)+ TyVar _ → Left Blocked+ _ → case headReduceType σ of+ Done → Left Stuck+ rs → Left rs+ patt (TpRow _) σ = Right [σ]++applyRowMap ∷ Ord tv ⇒ Type tv → Type tv → ReductionState (Type tv)+applyRowMap σcxt σarg = case σarg of+ TyRow lab σ1 σ2+ → Next $ TyRow lab (plugHole σcxt σ1) (tyRowMap σcxt σ2)+ TyApp tc [] | tc == tcRowEnd+ → Next tyRowEnd+ _ → tyRowMap σcxt <$> headReduceType σarg++plugHole ∷ Ord tv ⇒ Type tv → Type tv → Type tv+plugHole σcxt σ' = foldType (mkQuF TyQu) (mkBvF bvTy) fvTy fcon+ TyRow (mkMuF TyMu) σcxt+ where+ fcon tc σs =+ if tc == tcRowHole+ then σ'+ else TyApp tc σs
+ src/Type/Subst.hs view
@@ -0,0 +1,453 @@+-- | Representation of type variables and substitution+module Type.Subst (+ -- * Substitution monads+ MonadSubst(..),+ -- ** New type variables+ newTV', newTVTy', newTV, newTVTy,+ -- ** Reading and writing type variables+ readTV, writeTV, rewriteTV, rootTV, derefTV,+ -- ** Rank management+ Rank, lowerRank, lowerTVRank, getTVRank,+ -- ** Change tracking+ whileChanging, iterChanging, (>=>!), collectTVs_,++ -- * A 'MonadSubst' implementation+ SubstT, TV, SubstState, substState0,+ -- ** Running+ runSubstT, runEitherSubstT,+ Subst, runSubst,+ mapSubstT,++ -- * Substitution+ Substitutable(..),++ module Util.Trace,+) where++import Util+import Util.MonadRef+import Util.Trace+import Error+import Syntax.PprClass as Ppr+import Syntax.Prec (precEq)+import qualified AST+import qualified Type.Rank as Rank+import Type.Rank (Rank)+import Type.Internal+import Type.TyVar+import Type.Ppr ()++import Prelude ()+import Control.Monad.ST (runST)++---+--- A SUBSTITUTION MONAD INTERFACE+---++-- | A class supporting substitutable type variables+class (Functor m, Applicative m, Tv tv,+ MonadRef r m, MonadTrace m, MonadAlmsError m) ⇒+ MonadSubst tv r m | m → tv r where+ -- | Create a new type variable.+ newTV_ ∷ (Flavor, Kind, QLit, Doc) → m tv+ -- | Write a type variable. (Not for client use.)+ writeTV_ ∷ tv → Type tv → m ()+ -- | Read a type variable.+ readTV_ ∷ tv → m (Maybe (Type tv))+ -- | Get the rank of a type variable. (Not for client use.)+ getTVRank_ ∷ tv → m (Maybe Rank)+ -- | Set the rank of a type variable. (Not for client use.)+ setTVRank_ ∷ Rank → tv → m ()+ --+ -- | Get all the type variables allocated while running the+ -- action (except for any masked out by 'collectTV' already)+ collectTVs ∷ m a → m (a, [tv])+ -- | Report a type variable as "new" to any upstream collectors+ reportTVs ∷ [tv] → m ()+ --+ -- | Monitor an action for changes to variables+ monitorChange ∷ m a → m (a, Bool)+ -- | Indicate that a variable has changed+ setChanged ∷ m ()++-- | Class for constructing new type variables with a variety of+-- attributes.+class NewTV a where+ newTVArg ∷ a → (Flavor, Kind, QLit, Doc) → (Flavor, Kind, QLit, Doc)+ newTV' ∷ MonadSubst tv r m ⇒ a → m tv+ newTV' a = newTV_ (newTVArg a (Universal, KdType, maxBound, mempty))+ newTVTy' ∷ MonadSubst tv r m ⇒ a → m (Type tv)+ newTVTy' = fvTy <$$> newTV'++instance (NewTV a, NewTV b, NewTV c, NewTV d) ⇒ NewTV (a, b, c, d) where+ newTVArg (a, b, c, d) = newTVArg a . newTVArg b . newTVArg c . newTVArg d+instance (NewTV a, NewTV b, NewTV c) ⇒ NewTV (a, b, c) where+ newTVArg (a, b, c) = newTVArg a . newTVArg b . newTVArg c+instance (NewTV a, NewTV b) ⇒ NewTV (a, b) where+ newTVArg (a, b) = newTVArg a . newTVArg b+instance AST.Tag i ⇒ NewTV (AST.TyVar i) where+ newTVArg tv = newTVArg (AST.tvqual tv, ppr (AST.tvqual tv))+instance NewTV Flavor where newTVArg = upd1+instance NewTV Kind where newTVArg = upd2+instance NewTV Variance where newTVArg = upd2 . varianceToKind+instance NewTV QLit where newTVArg = upd3+instance NewTV Doc where newTVArg = upd4+instance NewTV String where newTVArg = upd4 . text+instance NewTV () where newTVArg = const id++substBug ∷ MonadSubst tv r m ⇒ String → String → m a+substBug = throwAlms <$$> almsBug StaticsPhase++-- Allocate a new, empty (unifiable) type variable+newTV ∷ MonadSubst tv r m ⇒ m tv+newTV = newTV' ()++-- | Allocate a new type variable and wrap it in a type+newTVTy ∷ MonadSubst tv r m ⇒ m (Type tv)+newTVTy = fvTy <$> newTV++-- | Get the canonical representative (root) of a tree of type+-- variables, and any non-tv type stored at the root, if it+-- exists. Performs path compression.+rootTV ∷ MonadSubst tv r m ⇒ tv → m (tv, Maybe (Type tv))+rootTV α = do+ mτ ← readTV_ α+ case mτ of+ Just (TyVar (Free α')) → do+ (α'', mτ') ← rootTV α'+ when (α'' /= α') $ writeTV_ α (fvTy α'')+ return (α'', mτ')+ Just τ → return (α, Just τ)+ Nothing → return (α, Nothing)++-- | Follow a type variable to the end of the chain, whatever that is.+derefTV ∷ MonadSubst tv r m ⇒ tv → m (Type tv)+derefTV = liftM (uncurry (fromMaybe . fvTy)) . rootTV++-- | Read a type variable+readTV ∷ MonadSubst tv r m ⇒ tv → m (Either tv (Type tv))+readTV = uncurry (flip maybe Right . Left) <$$> rootTV++-- | Write a type into an empty type variable.+writeTV ∷ MonadSubst tv r m ⇒ tv → Type tv → m ()+writeTV α τ = do+ setChanged+ (α', mτα) ← rootTV α+ traceN 2 ("writeTV", α', τ)+ case mτα of+ Nothing → do+ Just rank ← getTVRank_ α'+ lowerRank rank τ+ writeTV_ α' τ+ Just _ → substBug "writeTV" "Tried to overwrite type variable."++-- | Write a type into a type variable, even if it's not empty.+rewriteTV ∷ MonadSubst tv r m ⇒ tv → Type tv → m ()+rewriteTV α τ = do+ setChanged+ (α', mτα) ← rootTV α+ traceN 2 ("rewriteTV", (α', mτα), τ)+ writeTV_ α' τ++-- | Lower the rank of a type variable+lowerTVRank ∷ MonadSubst tv r m ⇒ Rank → tv → m ()+lowerTVRank r tv = do+ r0 ← getTVRank tv+ when (r < r0) (setTVRank_ r tv)++-- | Find out the rank of a type variable.+getTVRank ∷ MonadSubst tv r m ⇒ tv → m Rank+getTVRank = fromMaybe Rank.infinity <$$> getTVRank_++-- | Lower the rank of all the type variables in a given type+lowerRank ∷ (MonadSubst tv r m, Ftv a tv) ⇒+ Rank → a → m ()+lowerRank rank τ = mapM_ (lowerTVRank rank) (ftvList τ)++-- | Collect type variables, discarding the result.+collectTVs_ ∷ MonadSubst tv r m ⇒ m a → m [tv]+collectTVs_ = snd <$$> collectTVs++-- | Iterate a computation until it stops changing+whileChanging ∷ MonadSubst tv r m ⇒ m a → m a+whileChanging m = do+ (r, b) ← monitorChange m+ if b+ then whileChanging m+ else return r++-- | Iterate a Kleisli arrow until it stops changing.+iterChanging ∷ MonadSubst tv r m ⇒ (a → m a) → a → m a+iterChanging f z = do+ (z', b) ← monitorChange (f z)+ if b+ then iterChanging f z'+ else return z'++-- | Compose two Kleisli arrows, running the second only if the first+-- had no effect.+(>=>!) ∷ MonadSubst tv r m ⇒ (a → m a) → (a → m a) → a → m a+(>=>!) m n z = do+ (z', changed) ← monitorChange (m z)+ if changed+ then return z'+ else n z++infixr 1 >=>!++---+--- A REPRESENTATION OF FREE TYPE VARIABLES+---++-- | A free type variable+data TV r+ = UnsafeReadRef r ⇒ TV {+ tvId ∷ !Int,+ tvKind_ ∷ !Kind,+ tvDescr_ ∷ !Doc,+ tvRep ∷ !(TVRep r)+ }++-- | The flavor-dependent representation of a free type variable+data TVRep r+ = UniFl !(r (Either Rank (Type (TV r))))+ | ExiFl !QLit !(r Rank)+ | SkoFl !QLit++instance Eq (TV r) where+ tv1 == tv2 = tvId tv1 == tvId tv2++instance Ftv (TV r) (TV r) where+ ftvTree = FTSingle++instance Ord (TV r) where+ tv1 `compare` tv2 = tvId tv1 `compare` tvId tv2++instance Ppr (TV s) where+ ppr tv = case (debug, unsafeReadTV tv) of+ (True, Just t) →+ if debugLevel > 4+ then int (tvId tv) <> char '=' <> pprPrec precEq t+ else ppr t+ _ → text (uglyTvName tv)++instance Show (TV s) where+ showsPrec = showFromPpr++instance Tv (TV r) where+ tvUniqueID = tvId+ tvKind = tvKind_+ tvDescr = tvDescr_+ tvFlavor TV { tvRep = UniFl _ } = Universal+ tvFlavor TV { tvRep = ExiFl _ _ } = Existential+ tvFlavor TV { tvRep = SkoFl _ } = Skolem+ tvQual TV { tvRep = UniFl _ } = Nothing+ tvQual TV { tvRep = ExiFl q _ } = Just q+ tvQual TV { tvRep = SkoFl q } = Just q+ unsafeReadTV TV { tvRep = UniFl r } =+ (const Nothing ||| Just) (unsafeReadRef r)+ unsafeReadTV _ = Nothing++---+--- A MonadSubst IMPLEMENTATION+---++-- | Monad transformer implementing 'MonadSubst'.+newtype SubstT s m a+ = SubstT {+ unSubstT ∷ RWST () ([TV s], Any) SubstState m a+ }+ deriving (Monad, MonadTrans)++-- | The threaded state.+data SubstState+ = SubstState {+ stsGensym ∷ !Int,+ stsTrace ∷ !Int+ }++instance Monad m ⇒ Functor (SubstT s m) where+ fmap f m = m >>= return . f++instance Monad m ⇒ Applicative (SubstT s m) where+ pure = return+ (<*>) = ap++instance Monad m ⇒ MonadTrace (SubstT s m) where+ getTraceIndent = SubstT (gets stsTrace)+ putTraceIndent n = SubstT (modify (\sts → sts { stsTrace = n }))++instance MonadAlmsError m ⇒ MonadAlmsError (SubstT s m) where+ getLocation = lift getLocation+ catchAlms m h = SubstT (catchAlms (unSubstT m) (unSubstT . h))+ withLocation_ loc = SubstT . withLocation_ loc . unSubstT+ bailoutAlms_ = lift bailoutAlms_+ reportAlms_ = lift <$> reportAlms_+ mapAlmsErrors f = SubstT . mapAlmsErrors f . unSubstT++instance MonadAlmsError m ⇒ MonadError [AlmsError] (SubstT s m) where+ throwError = throwAlmsList+ catchError = catchAlms++instance MonadRef r m ⇒ MonadRef r (SubstT r m) where+ newRef = lift <$> newRef+ readRef = lift <$> readRef+ writeRef = lift <$$> writeRef+ modifyRef = lift <$$> modifyRef++instance (MonadRef r m, MonadAlmsError m) ⇒+ MonadSubst (TV r) r (SubstT r m) where+ newTV_ (flavor, kind, bound, descr) = do+ when (flavor == Universal && bound /= maxBound) $+ substBug "newTV_" "Universal tyvars cannot have non-A bound"+ sts ← SubstT get+ let i = stsGensym sts+ SubstT $ put sts { stsGensym = succ i }+ traceN 2 ("new", flavor, kind, i)+ α ← TV i kind descr <$> case flavor of+ Universal → UniFl <$> newRef (Left Rank.infinity)+ Existential → ExiFl bound <$> newRef Rank.infinity+ Skolem → return $ SkoFl bound+ SubstT $ tell ([α], mempty)+ return α+ writeTV_ TV { tvRep = UniFl r } t = writeRef r (Right t)+ writeTV_ TV { tvRep = ExiFl _ _ } _ = substBug "writeTV_" "got existential"+ writeTV_ TV { tvRep = SkoFl _ } _ = substBug "writeTV_" "got skolem"+ readTV_ TV { tvRep = UniFl r } = (const Nothing ||| Just) <$> readRef r+ readTV_ _ = return Nothing+ --+ getTVRank_ TV { tvRep = UniFl r } = (Just ||| const Nothing ) <$> readRef r+ getTVRank_ TV { tvRep = ExiFl _ r } = Just <$> readRef r+ getTVRank_ TV { tvRep = SkoFl _ } = return Nothing+ setTVRank_ rank TV { tvRep = UniFl r } = writeRef r (Left rank)+ setTVRank_ rank TV { tvRep = ExiFl _ r } = writeRef r rank+ setTVRank_ _ TV { tvRep = SkoFl _ } = return ()+ --+ collectTVs action = do+ rαs ← (SubstT . censor (upd1 []) . listens sel1 . unSubstT) action+ traceN 2 ("collectTV", snd rαs)+ return rαs+ reportTVs αs = SubstT (tell (αs, mempty))+ --+ monitorChange = SubstT . listens (getAny . sel2) . unSubstT+ setChanged = SubstT $ tell ([], Any True)++--+-- Pass-through instances+--++instance (MonadSubst tv r m, Monoid w) ⇒ MonadSubst tv r (WriterT w m) where+ newTV_ = lift <$> newTV_+ writeTV_ = lift <$$> writeTV_+ readTV_ = lift <$> readTV_+ getTVRank_ = lift <$> getTVRank_+ setTVRank_ = lift <$$> setTVRank_+ collectTVs = mapWriterT (mapListen2 collectTVs)+ reportTVs = lift <$> reportTVs+ monitorChange = mapWriterT (mapListen2 monitorChange)+ setChanged = lift setChanged++instance MonadSubst tv r m ⇒ MonadSubst tv r (StateT s m) where+ newTV_ = lift <$> newTV_+ writeTV_ = lift <$$> writeTV_+ readTV_ = lift <$> readTV_+ getTVRank_ = lift <$> getTVRank_+ setTVRank_ = lift <$$> setTVRank_+ collectTVs = mapStateT (mapListen2 collectTVs)+ reportTVs = lift <$> reportTVs+ monitorChange = mapStateT (mapListen2 monitorChange)+ setChanged = lift setChanged++instance MonadSubst tv r m ⇒ MonadSubst tv r (ReaderT r' m) where+ newTV_ = lift <$> newTV_+ writeTV_ = lift <$$> writeTV_+ readTV_ = lift <$> readTV_+ getTVRank_ = lift <$> getTVRank_+ setTVRank_ = lift <$$> setTVRank_+ collectTVs = mapReaderT collectTVs+ reportTVs = lift <$> reportTVs+ monitorChange = mapReaderT monitorChange+ setChanged = lift setChanged++instance (MonadSubst tv r m, Monoid w) ⇒ MonadSubst tv r (RWST r' w s m) where+ newTV_ = lift <$> newTV_+ writeTV_ = lift <$$> writeTV_+ readTV_ = lift <$> readTV_+ getTVRank_ = lift <$> getTVRank_+ setTVRank_ = lift <$$> setTVRank_+ collectTVs = mapRWST (mapListen3 collectTVs)+ reportTVs = lift <$> reportTVs+ monitorChange = mapRWST (mapListen3 monitorChange)+ setChanged = lift setChanged++--+-- Running+--++-- | Run in the substitution monad+runSubstT ∷ Monad m ⇒ SubstState → SubstT r m a → m (a, SubstState)+runSubstT state0 (SubstT m) = do+ (result, state, _) ← runRWST m () state0 { stsTrace = 0 }+ return (result, state)++substState0 ∷ SubstState+substState0 = SubstState 0 0++-- | Run a substitution computation, but not inheriting exception+-- handling+runEitherSubstT ∷ Monad m ⇒+ SubstState → SubstT r (AlmsErrorT m) a →+ m (Either [AlmsError] (a, SubstState))+runEitherSubstT = runAlmsErrorT <$$> runSubstT++-- | The type of a generic substitution computation+type Subst a = ∀ s m. (MonadRef s m, MonadAlmsError m) ⇒ SubstT s m a++-- | Run a substitution computation in a pure context+runSubst ∷ SubstState → Subst a → Either [AlmsError] (a, SubstState)+runSubst st0 m = runST (runEitherSubstT st0 m)++-- | For lifting through 'SubstT'+mapSubstT ∷ (Functor t1, Functor t2) ⇒+ (∀s. t1 (a, s) → t2 (b, s)) →+ SubstT r t1 a → SubstT r t2 b+mapSubstT f = SubstT . mapRWST f' . unSubstT where+ f' action = fromPair <$> f (toPair <$> action)+ toPair (a, s, w) = (a, (s, w))+ fromPair (a, (s, w)) = (a, s, w)++---+--- SUBSTITUTION+---++class Monad m ⇒ Substitutable a m where+ -- | Fully dereference all the values, deeply.+ subst ∷ a → m a+ -- | Fully dereference a sequence of TV indirections, with path+ -- compression, at the root of a type (or each type of a+ -- collection).+ substHead ∷ a → m a++instance Substitutable a m ⇒ Substitutable [a] m where+ subst = mapM subst+ substHead = mapM substHead++instance Substitutable a m ⇒ Substitutable (Maybe a) m where+ subst = mapM subst+ substHead = mapM substHead++instance (Substitutable a m, Substitutable b m) ⇒+ Substitutable (a, b) m where+ subst (a, b) = liftM2 (,) (subst a) (subst b)+ substHead (a, b) = liftM2 (,) (substHead a) (substHead b)++instance MonadSubst tv r m ⇒ Substitutable (Type tv) m where+ subst = foldTypeM (mkQuF (return <$$$> TyQu))+ (mkBvF (return <$$$> bvTy))+ ((>>= either (return . fvTy) subst) . readTV)+ (return <$$> TyApp)+ (return <$$$> TyRow)+ (mkMuF (return <$$> TyMu))+ substHead (TyVar (Free r)) = derefTV r+ substHead σ = return σ+
+ src/Type/Syntax.hs view
@@ -0,0 +1,212 @@+-- | For converting internal types back to syntactic types+module Type.Syntax (+ -- * Types to syntax+ typeToStx, typeToStx',+ T2SContext(..), t2sContext0, TyNames(..), tyNames0,+ -- * Patterns to syntax+ tyPatToStx, tyPatToStx', tyPatsToStx,+ -- * Type constructors to type declarations+ tyConToStx, tyConToStx',+) where++import Util+import Util.Trace+import qualified Env+import Type.Internal+import Type.ArrowAnnotations+import Type.TyVar+import qualified AST+import Syntax.PprClass (TyNames(..), tyNames0)++import Prelude ()+import qualified Data.Set as S++type R = AST.Renamed++-- | Context for printing types and type patterns+data T2SContext rule tv+ = T2SContext {+ t2sTyNames ∷ TyNames,+ t2sArrRule ∷ rule tv,+ t2sTvEnv ∷ [[AST.TyVar R]]+ }++-- | The default initial printing context+t2sContext0 ∷ T2SContext CurrentImpArrPrintingRule tv+t2sContext0+ = T2SContext {+ t2sTyNames = tyNames0,+ t2sArrRule = iaeInit,+ t2sTvEnv = []+ }++-- | Represent a type value as a pre-syntactic type, for printing+typeToStx' ∷ Tv tv ⇒ Type tv → AST.Type R+typeToStx' = typeToStx t2sContext0++-- | Turns annotated arrows into implicit arrows where possible+typeToStx ∷ (Tv tv, ImpArrRule rule) ⇒+ T2SContext rule tv → Type tv → AST.Type R+typeToStx cxt0 σ0 = runReader (loop σ0) cxt0 where+ loop (TyVar (Free r)) | debug, Just σ ← unsafeReadTV r =+ do+ δ ← asks t2sTvEnv+ t ← loop σ+ return (AST.tyApp (AST.qident "@=")+ [AST.tyVar (getTV δ (Free r)), t])+ {-+ else throw $+ almsBug (OtherError "unknown")+ "typeToStx"+ ("Saw unsubstituted type variable: " ++ show r)+ -}+ loop (TyVar tv0) = do+ δ ← asks t2sTvEnv+ return (AST.tyVar (getTV δ tv0))+ loop (TyQu quant αs σ) =+ withFresh αs $ \αs' → do+ σ' ← loop σ+ return (foldr (AST.tyQu (quantToStx quant)) σ' αs')+ loop (TyMu n σ) =+ withFresh [(n, Qa)] $ \αs' → do+ σ' ← loop σ+ return (foldr AST.tyMu σ' αs')+ loop (TyRow lab σ1 σ2) =+ AST.tyRow lab <$> loop σ1 <*> loop σ2+ loop (TyApp tc [σ1, qe, σ2]) | tc == tcFun = do+ cxt ← ask+ qe' ← represent qe+ let cxt1 = cxt { t2sArrRule = iaeLeft (t2sArrRule cxt) }+ cxt2 = cxt { t2sArrRule = iaeRight (t2sArrRule cxt)+ (qualifierCxt cxt qe)+ σ1 }+ t1' ← local (\_ → cxt1) (loop σ1)+ t2' ← local (\_ → cxt2) (loop σ2)+ return (AST.tyFun t1' qe' t2')+ loop (TyApp tc σs) = do+ AST.tyApp <$> bestName t2sTyNames tc <*> sequence+ [ local (\cxt → cxt { t2sArrRule = iaeUnder (t2sArrRule cxt) variance })+ (loop σ)+ | σ ← σs+ | variance ← tcArity tc ]+ --+ withFresh αs k = do+ δ ← asks t2sTvEnv+ let names = fst <$> αs+ seen = AST.unLid . AST.tvname <$> concat δ+ names' = AST.freshNames names seen AST.tvalphabet+ αs' = zipWith3 AST.TV (AST.ident <$> names')+ (snd <$> αs)+ (repeat AST.bogus)+ local (\cxt → cxt { t2sTvEnv = αs' : δ }) (k αs')+ --+ getTV _ (Free tv)+ = AST.TV (AST.ident (uglyTvName tv)) (fromMaybe Qa (tvQual tv)) AST.bogus+ getTV δ (Bound i j n)+ | rib:_ ← drop i δ, tv:_ ← drop j rib+ = tv+ | otherwise+ = AST.tvAf ('?' : fromPerhaps "" n)+ --+ represent qe = do+ cxt ← ask+ return (iaeRepresent (getTV (t2sTvEnv cxt))+ (t2sArrRule cxt)+ (qualifierCxt cxt qe))+ --+ qualifierCxt cxt = qualifierEnv (AST.tvqual <$$> t2sTvEnv cxt)++-- | Represent a type value as a pre-syntactic type, for printing+tyPatToStx' ∷ TyPat → (AST.TyPat R, [AST.TyVar R])+tyPatToStx' = tyPatToStx tyNames0 [] Qa++-- | Turn an internal type pattern into a syntactic type pattern+tyPatToStx ∷ TyNames → [(AST.TyVar R, Variance)] → QLit → TyPat →+ (AST.TyPat R, [AST.TyVar R])+tyPatToStx tn0 tvs0 ql0 tp0 =+ evalRWS (loop ql0 tp0) tn0 (extendTyPatNames tvs0)+ where+ loop ql (TpVar _) = fresh ql AST.tpVar+ loop ql (TpApp tc tps) = AST.tpApp+ <$> bestName id tc+ <*> sequence+ [ let qli = bi ⊓ if S.member i ftv_qe+ then ql else Qa+ in loop qli tpi+ | i ← [ 0 .. ]+ | tpi ← tps+ | bi ← tcBounds tc ]+ where ftv_qe = ftvSet (tcQual tc)+ loop ql (TpRow _) = fresh ql AST.tpRow+ --+ fresh ql mk = do+ (tv, variance):tvs ← get+ put tvs+ let tv' = tv { AST.tvqual = ql }+ tell [tv']+ return (mk tv' variance)++-- | Turn a list of internal type pattern into a list of syntactic type+-- patterns+tyPatsToStx ∷ TyNames → [(AST.TyVar R, Variance)] → [QLit] → [TyPat] →+ ([AST.TyPat R], [AST.TyVar R])+tyPatsToStx tn0 tvs0 qls0 tps0 =+ loop (extendTyPatNames tvs0) (qls0 ++ repeat Qa) tps0+ where+ loop tvs (ql:qls) (tp:tps) =+ let (tp', tvs') = tyPatToStx tn0 tvs ql tp+ (tps', tvss') = loop (drop (length tvs') tvs) qls tps+ in (tp':tps', tvs'++tvss')+ loop _ _ _ = ([], [])++extendTyPatNames ∷ [(AST.TyVar R, Variance)] →+ [(AST.TyVar R, Variance)]+extendTyPatNames tvs0 =+ tvs0 ++ [ (AST.tvAf name, maxBound)+ | name ← AST.tvalphabet+ , name `notElem` map (AST.unLid . AST.tvname . fst) tvs0 ]++-- | Externalize a quantifier+quantToStx ∷ Quant → AST.Quant+quantToStx Forall = AST.Forall+quantToStx Exists = AST.Exists++-- | Look up the best printing name for a type.+bestName ∷ MonadReader r m ⇒ (r → TyNames) → TyCon → m QTypId+bestName getter tc = do+ tn ← asks getter+ return (tnLookup tn (tcId tc) (tcName tc))++tyConToStx' ∷ TyCon → AST.TyDec R+tyConToStx' = tyConToStx tyNames0++tyConToStx ∷ TyNames → TyCon → AST.TyDec R+tyConToStx tn tc =+ let+ n = AST.jname (tcName tc)+ tvs = zipWith3 AST.TV (AST.ident <$> AST.tvalphabet)+ (tcBounds tc)+ (repeat AST.bogus)+ doType envTvs = typeToStx t2sContext0 { t2sTyNames = tn, t2sTvEnv = [envTvs] }+ in+ case tc of+ _ | tc == tcExn+ → AST.tdAbs (AST.ident "exn") [] [] [] maxBound+ TyCon { tcNext = Just clauses }+ → AST.tdSyn n+ [ second (`doType` rhs) (tyPatsToStx tn [] (tcBounds tc) ps)+ | (ps, rhs) ← clauses ]+ TyCon { tcCons = alts }+ | not (Env.isEmpty alts)+ → AST.tdDat n tvs+ (second (doType tvs <$>) <$> Env.toList alts)+ TyCon { tcArity = arity, tcQual = qual, tcGuards = guards }+ → AST.tdAbs n tvs arity (fst <$> filter snd (zip tvs guards)) $+ case qual of+ QeA → AST.qeLit Qa+ QeU ixs →+ case fst <$> filter ((`S.member` ixs) . snd) (zip tvs [0..]) of+ [] → AST.qeLit Qu+ tvs' → foldr1 AST.qeJoin (AST.qeVar <$> tvs')++
+ src/Type/TyVar.hs view
@@ -0,0 +1,239 @@+module Type.TyVar (+ -- * Type variable observations+ Tv(..), Kind(..), Flavor(..),+ tvFlavorIs, tvKindIs, uglyTvName,+ -- * Miscellany+ varianceToKind,+ -- * Free type variables+ Ftv(..), VarMap,+ FtvTree(..), foldFtvTree,+) where++import Util+import qualified AST+import Syntax.PprClass+import Type.Internal++import Prelude ()+import Data.Generics (Typeable, Data)+import qualified Data.Map as M+import qualified Data.Set as S++---+--- TYPE VARIABLES+---++-- | Internal kinds for type variables+data Kind+ -- | The kind of normal types+ = KdType+ -- | The kind of qualifier variables+ | KdQual+ deriving (Eq, Typeable, Data)++instance Ppr Kind where+ ppr KdType = char '*'+ ppr KdQual = char 'Q'+instance Show Kind where showsPrec = showFromPpr++-- | Get the kind associated with type variables that appear at a+-- particular variance.+varianceToKind ∷ Variance → Kind+varianceToKind var = if isQVariance var then KdQual else KdType++-- | Flavors of type variables+data Flavor+ -- | unification variables+ = Universal+ -- | existential skolems+ | Existential+ -- | universal skolems+ | Skolem+ deriving (Eq, Typeable, Data)++instance Ppr Flavor where ppr = char . flavorSigil+instance Show Flavor where showsPrec = showFromPpr++-- | Type variable observations+class (Ftv tv tv, Show tv, Ppr tv) ⇒ Tv tv where+ -- | The unique identity of a type variable+ tvUniqueID ∷ tv → Int+ -- | The internal kind of a type variable+ tvKind ∷ tv → Kind+ -- | The internal flavor of a type variable+ tvFlavor ∷ tv → Flavor+ -- | Possibly a qualifier bound+ tvQual ∷ tv → Maybe QLit+ -- | A description+ tvDescr ∷ tv → Doc+ -- | Read the contents of a type variable (not pure)+ unsafeReadTV ∷ tv → Maybe (Type tv)++instance Tv Empty where+ tvUniqueID = elimEmpty+ tvKind = elimEmpty+ tvFlavor = elimEmpty+ tvQual = elimEmpty+ tvDescr = elimEmpty+ unsafeReadTV = elimEmpty++instance Ftv Empty Empty where ftvTree = elimEmpty+instance Ppr Empty where ppr = elimEmpty++instance Tv Int where+ tvUniqueID = id+ tvKind _ = KdType+ tvFlavor _ = Skolem+ tvQual _ = Nothing+ tvDescr = ppr+ unsafeReadTV = const Nothing++instance Ftv Int Int where ftvTree = FTSingle++-- | Check the flavor of a type variable+tvFlavorIs ∷ Tv tv ⇒ Flavor → tv → Bool+tvFlavorIs flavor v = tvFlavor v == flavor++-- | Check the kind of a type variable+tvKindIs ∷ Tv tv ⇒ Kind → tv → Bool+tvKindIs kind v = tvKind v == kind++-- | When all else fails, we can print a type variable like this+uglyTvName ∷ Tv tv ⇒ tv → String+uglyTvName tv = flavorSigil (tvFlavor tv) : (AST.tvalphabet !! tvUniqueID tv)++-- | A character denoting a flavor+flavorSigil ∷ Flavor → Char+flavorSigil Universal = '_'+flavorSigil Existential = '#'+flavorSigil Skolem = '$'++---+--- FREE TYPE VARIABLES+---++{-+ We're going to construct a framework for generic functions to compute+ the free type variables of a type. It may seem a bit over-engineered,+ but it turns out to be handy, The idea is to write a generic function+ that builds an 'FtvTree', which contains all the free type variables+ in the relevant piece of syntax, along with variance and recursive+ guard information.+-}++-- | A tree of free type variables, with variance and recursive guard+-- information+data FtvTree v+ -- | A single free type variable+ = FTSingle v+ -- | Updates the incoming variance to give the variance in+ -- the subtree+ | FTVariance VarianceEndo (FtvTree v)+ -- | Indicates that the subtree is guarded by a type constructor+ -- that allows recursion+ | FTGuard (FtvTree v)+ -- | A forest of 'FtvTree's+ | FTBranch [FtvTree v]+ deriving (Functor, Show)++-- | Type for providing a 'Show' instance for @Variance -> Variance@+-- functions which allows deriving 'Show' for 'FtvTree'.+newtype VarianceEndo+ = VarianceEndo { applyVarianceEndo ∷ Variance → Variance }++instance Show VarianceEndo where+ show ve = show (applyVarianceEndo ve 1)++instance Monoid (FtvTree v) where+ mempty = FTBranch []+ mappend a b = FTBranch [a, b]+ mconcat = FTBranch++-- | A fold for 'FtvTree's. It's necessary to specify how to+-- add a free type variable and its variance to the result, and the+-- initial result. Note that this fold gives no information about+-- the shape of the tree, but it uses the tree structure to determine+-- the variance of each type variable.+foldFtvTree ∷ (v → Variance → Bool → r → r) → r → FtvTree v → r+foldFtvTree fsingle = loop Covariant False where+ loop var gua acc tree = case tree of+ FTSingle v → fsingle v var gua acc+ FTVariance vf t → loop (applyVarianceEndo vf var) gua acc t+ FTGuard t → loop var True acc t+ FTBranch ts → foldr (flip (loop var gua)) acc ts++-- | Map from variables to variances+type VarMap v = M.Map v Variance++class Ord tv ⇒ Ftv a tv | a → tv where+ -- | To compute the 'FtvTree' for a piece of syntax. Because+ -- everything is parametric in the representation of ftvs, it needs+ -- to be told how to dereference an apparently free type variable.+ -- The dereferencing function should return @Nothing@ if the type+ -- variable is actually free, and @Just τ@ if a type @τ@ has been+ -- substituted for it.+ --+ -- This is the only method that doesn't have a default+ -- implementation, so it must be defined explicitly.+ ftvTree ∷ a → FtvTree tv+ -- | To fold over the free type variables in a piece of syntax.+ ftvFold ∷ (tv → Variance → Bool → r → r) → r → a → r+ -- | To get a map from free type variables to their variances.+ ftvV ∷ a → VarMap tv+ -- | To get a map from free type variables to their guardedness+ ftvG ∷ a → M.Map tv Bool+ -- | To get a map from free type variables to a list of all their+ -- occurrences' variances.+ ftvSet ∷ a → S.Set tv+ -- | To get a list of the free type variables in a type (with no repeats).+ ftvList ∷ a → [tv]+ --+ --+ ftvFold fsingle zero a+ = foldFtvTree fsingle zero $ ftvTree a+ ftvV = ftvFold (const <$$> M.insertWith (+)) M.empty+ ftvG = ftvFold (const <$> M.insertWith (&&)) M.empty+ ftvSet = ftvFold (\v _ _ → S.insert v) S.empty+ ftvList = S.toAscList . ftvSet++instance Ord tv ⇒ Ftv (Type tv) tv where+ ftvTree = foldType+ (mkQuF (\_ _ → id))+ (mkBvF (\_ _ _ → mempty))+ FTSingle+ (\tc trees → FTBranch+ [ FTVariance (VarianceEndo (* var)) $+ if guarded then FTGuard tree else tree+ | tree ← trees+ | var ← tcArity tc+ | guarded ← tcGuards tc ])+ (\_ σ1 σ2 → FTBranch [FTGuard σ1, σ2])+ (mkMuF (\_ → id))++instance Ord tv ⇒ Ftv (QExp tv) tv where+ ftvTree QeA = FTBranch []+ ftvTree (QeU αs) = FTBranch (FTSingle <$> S.toList αs)+ ftvSet QeA = S.empty+ ftvSet (QeU αs) = αs++instance Ftv a tv ⇒ Ftv [a] tv where+ ftvTree = foldMap ftvTree++instance Ftv a tv ⇒ Ftv (M.Map k a) tv where+ ftvTree = ftvTree . M.elems++instance (Ftv a tv, Ftv b tv) ⇒ Ftv (a, b) tv where+ ftvTree (a, b) = ftvTree a `mappend` ftvTree b++instance (Ftv a tv, Ftv b tv, Ftv c tv) ⇒ Ftv (a, b, c) tv where+ ftvTree (a, b, c) = mconcat [ftvTree a, ftvTree b, ftvTree c]++instance (Ftv a tv, Ftv b tv, Ftv c tv, Ftv d tv) ⇒ Ftv (a, b, c, d) tv where+ ftvTree (a, b, c, d) = mconcat [ftvTree a, ftvTree b, ftvTree c, ftvTree d]++instance Ftv a tv ⇒ Ftv (Maybe a) tv where+ ftvTree = maybe mempty ftvTree++instance (Ftv a tv, Ftv b tv) ⇒ Ftv (Either a b) tv where+ ftvTree = either ftvTree ftvTree+
− src/TypeRel.hs
@@ -1,1051 +0,0 @@-{-# LANGUAGE- FlexibleContexts,- GeneralizedNewtypeDeriving,- ParallelListComp,- PatternGuards,- RankNTypes,- RelaxedPolyRec #-}-module TypeRel (- -- * Type operations- -- ** Equality and subtyping- AType(..), subtype, jointype,- -- ** Queries and conversions- qualConst, abstractTyCon,- -- ** Tycon substitutions- TyConSubst, makeTyConSubst,- applyTyConSubst, applyTyConSubstInTyCon,- replaceTyCon, replaceTyCons,- substTyCons, substTyCon,- -- * Tests- tests,-) where--import Env-import ErrorST-import Ppr ()-import Type-import Util-import Viewable--import qualified Control.Monad.Reader as CMR-import Control.Monad.Error-import Data.Generics (Data, everywhere, mkT, extT)-import Data.Monoid-import qualified Data.Map as M-import qualified Data.Set as S--import qualified Test.HUnit as T---- | Remove the concrete portions of a type constructor.-abstractTyCon :: TyCon -> TyCon-abstractTyCon tc = tc { tcCons = ([], empty), tcNext = Nothing }---- | A substitution mapping type constructors to other type--- constructors-newtype TyConSubst = TyConSubst { unTyConSubst :: M.Map Int TyCon }- deriving Monoid---- | Construct a tycon substitution from a list of tycons and a list--- to map them to.-makeTyConSubst :: [TyCon] -> [TyCon] -> TyConSubst-makeTyConSubst tcs tcs' =- TyConSubst (M.fromList [ (tcId tc, tc') | tc <- tcs | tc' <- tcs' ])---- | Apply a tycon substitution to any SYB data.-applyTyConSubst :: Data a => TyConSubst -> a -> a-applyTyConSubst subst = loop where- loop :: Data a => a -> a- loop = everywhere (mkT tycon `extT` tyapp)- --- tycon :: TyCon -> TyCon- tycon tc- | Just tc' <- M.lookup (tcId tc) (unTyConSubst subst)- = applyTyConSubstInTyCon subst tc'- | otherwise = tc- --- tyapp :: Type -> Type- tyapp (TyApp tc ts _) = tyApp tc ts- tyapp t = t---- | Apply a tycon substitution "inside" the right-hand side of--- a tycon, but don't replace the tycon itself.-applyTyConSubstInTyCon :: TyConSubst -> TyCon -> TyCon-applyTyConSubstInTyCon subst tc =- tc {- tcNext = applyTyConSubst subst (tcNext tc),- tcCons = applyTyConSubst subst (tcCons tc)- }---- | Given a list of type constructors and something traversable,--- find all constructors with the same identity as the given type one, and--- replace them. We can use this for type abstraction by redacting--- data constructor or synonym expansions. It also replaces within--- the list of type constructors themselves, which ties the knot for--- recursive type constructors.-replaceTyCons :: Data a => [TyCon] -> a -> a-replaceTyCons tcs0 = substTyCons tcs0 tcs0--replaceTyCon :: Data a => TyCon -> a -> a-replaceTyCon tc = replaceTyCons [tc]---- Give a list of tycons to replace and a list of tycons to replace them--- with, replaces them all recursively, including knot-tying-substTyCons :: Data a => [TyCon] -> [TyCon] -> a -> a-substTyCons tcs tcs' = applyTyConSubst (makeTyConSubst tcs tcs')---- | Replace all occurrences of the first tycon with the second-substTyCon :: Data a => TyCon -> TyCon -> a -> a-substTyCon tc tc' = substTyCons [tc] [tc']---- | The constant bound on the qualifier of a type-qualConst :: Type -> QLit-qualConst = qConstBound . qualifier---- | A fresh type for defining alpha equality up to mu.-newtype AType = AType { unAType :: Type }---- | On AType, we define simple alpha equality, up to mu and operator--- reduction, which we then use--- to keep track of where we've been when we define type equality--- that understands mu and reduction.-instance Eq AType where- te1 == te2 = compare te1 te2 == EQ--instance Ord AType where- te1 `compare` te2 = unAType te1 =?= unAType te2- where- (=?=) :: Type -> Type -> Ordering- TyApp tc ts _ =?= TyApp tc' ts' _- = tc `compare` tc'- `thenCmp` map AType ts `compare` map AType ts'- TyVar x =?= TyVar x'- = x `compare` x'- TyFun q t1 t2 =?= TyFun q' t1' t2'- = q `compare` q'- `thenCmp` t1 =?= t1'- `thenCmp` t2 =?= t2'- TyQu u x t =?= TyQu u' x' t'- = u `compare` u'- `thenCmp` tvqual x `compare` tvqual x'- `thenCmp` tysubst x a t =?= tysubst x' a t'- where a = TyVar (fastFreshTyVar x (maxtv (t, t')))- TyMu x t =?= TyMu x' t'- = tvqual x `compare` tvqual x'- `thenCmp` tysubst x a t =?= tysubst x' a t'- where a = TyVar (fastFreshTyVar x (maxtv (t, t')))- TyApp _ _ _ =?= _ = LT- _ =?= TyApp _ _ _ = GT- TyVar _ =?= _ = LT- _ =?= TyVar _ = GT- TyFun _ _ _ =?= _ = LT- _ =?= TyFun _ _ _ = GT- TyQu _ _ _ =?= _ = LT- _ =?= TyQu _ _ _ = GT--type UT s t a = CMR.ReaderT (TCS s t) (ST t String) a---- | An environment mapping mu-bound type variables to their--- definition for unrolling ('Left') or forall-bound variables--- to a pair of lower and upper bounds, for instantiation ('Right')-type UEnv t = M.Map TyVarR (UVar t)-type UVar t = (Int, STRef t (Type, Type))--data TCS s t = TCS {- -- | Pairs of types previously seen, and thus considered related- -- if seen again.- tcsSeen :: STRef t (M.Map (AType, AType) s),- -- | A supply of fresh type variables- tcsSupply :: STRef t [QLit -> TyVarR],- -- | The number of instantiated foralls we are currently under- tcsLevel :: Int,- -- | The environment for the left side of the relation- tcsEnv1 :: UEnv t,- -- | The environment for the right side of the relation- tcsEnv2 :: UEnv t-}--data Field s t = Field {- get :: TCS s t -> UEnv t,- update :: TCS s t -> UEnv t -> TCS s t-}--env1, env2 :: Field s t-env1 = Field tcsEnv1 (\tcs e -> tcs { tcsEnv1 = e })-env2 = Field tcsEnv2 (\tcs e -> tcs { tcsEnv2 = e })--runUT :: forall s a m. MonadError String m =>- (forall t. UT s t a) -> S.Set TyVarR -> m a-runUT m set =- runST $ do- seen <- newTransSTRef M.empty- supply <- newSTRef [ f | f <- tvalphabet- , f Qu `S.notMember` set- , f Qa `S.notMember` set ]- CMR.runReaderT m TCS {- tcsSeen = seen,- tcsSupply = supply,- tcsLevel = 1,- tcsEnv1 = M.empty,- tcsEnv2 = M.empty- }--getVar :: TyVarR -> Field s t -> UT s t (Maybe (UVar t))-getVar tv field = CMR.asks (M.lookup tv . get field)---- | To add some unification variables to the scope, run the body,--- and return a map containing their lower and upper bounds.--- Unification variables are assumed to be fresh with respect to--- existing variables. In particular, the initial set of unification--- variables precedes any other bindings, and all subsequent foralls--- are renamed using fresh type variables.-withUVars :: [TyVarR] -> Field s t -> UT s t a -> UT s t (a, [Type])-withUVars tvs field body = do- level <- CMR.asks tcsLevel- refs <- lift $ sequence- [ do ref <- newTransSTRef (tyBot, tyTop (tvqual tv))- return (tv, (level, ref))- | tv <- tvs ]- res <- CMR.local- (\st -> update field st (M.fromList refs `M.union` get field st))- body- typs <- sequence- [ do- (lower, upper) <- lift $ readSTRef ref- if lower <: upper- then return $- -- This is a heuristic -- we prefer to return something- -- with information, meaning not top or bottom, but if- -- the choice is between top and bottom, we go with bottom- if isBotType lower- then if upper == tyUn || upper == tyAf then lower else upper- else lower- else throwError $- "Unification cannot solve:\n" ++- show lower ++ " <: " ++ show upper- | (_, (_, ref)) <- refs ]- return (res, typs)---- | Bump up the quantification nesting level-incU :: UT s t a -> UT s t a-incU = CMR.local (\st -> st { tcsLevel = tcsLevel st + 1 })---- | Try to assert an upper bound on a unification variable.-upperBoundUVar :: STRef t (Type, Type) -> Type -> UT s t ()-upperBoundUVar ref t = do- (lower, upper) <- lift $ readSTRef ref- unless (upper <: t) $ do- upper' <- t /\? upper- lift $ writeSTRef ref (lower, upper')----- | Try to assert a lower bound on a unification variable.-lowerBoundUVar :: STRef t (Type, Type) -> Type -> UT s t ()-lowerBoundUVar ref t = do- (lower, upper) <- lift $ readSTRef ref- unless (t <: lower) $ do- lower' <- t \/? lower- lift $ writeSTRef ref (lower', upper)---- | Get maps of the left and right uvars-getUVars :: UT s t (TyVarR -> Maybe (Int, STRef t (Type, Type)),- TyVarR -> Maybe (Int, STRef t (Type, Type)))-getUVars = do- st <- CMR.ask- return (flip M.lookup (tcsEnv1 st), flip M.lookup (tcsEnv2 st))---- | Check if two types have been seen before. If so, return the--- previously stored answer. If not, temporarily store the given--- answer, then run a block, and finally replace the stored answer--- with the result of the block.-chkU :: Type -> Type -> s -> UT s t s -> UT s t s-chkU t1 t2 s body = do- st <- CMR.ask- let key = (AType t2, AType t1)- ref = tcsSeen st- seen <- lift $ readSTRef ref- case M.lookup key seen of- Just s' -> return s'- Nothing -> do- lift $ modifySTRef ref (M.insert key s)- res <- body- lift $ modifySTRef ref (M.insert key res)- return res---- | Flip the left and right sides of the relation in the given block.-flipU :: UT s t a -> UT s t a-flipU body = CMR.local flipSt body where- flipSt (TCS seen level supply e1 e2) =- TCS seen level supply e2 e1---- | Get a fresh type variable from the supply.-freshU :: QLit -> UT s t TyVarR-freshU qlit = do- ref <- CMR.ask >>! tcsSupply- f:supply <- lift $ readSTRef ref- lift $ writeSTRef ref supply- return (f qlit)---- | Print a debug message--- pM :: Show b => b -> UT s t ()--- pM = lift . unsafeIOToST . print--- pM = const $ return ()--subtype :: MonadError String m =>- Int -> [TyVarR] -> Type -> [TyVarR] -> Type ->- m ([Type], [Type])-subtype limit uvars1 t1i uvars2 t2i =- runUT start (S.fromList uvars1 `S.union`- S.fromList uvars2 `S.union`- alltv (t1i, t2i))- where- start :: UT () t ([Type], [Type])- start = liftM (first snd) $- withUVars uvars2 env2 $- withUVars uvars1 env1 $- cmp t1i t2i- --- cmp :: Type -> Type -> UT () t ()- cmp t u = chkU t u () $ case (t, u) of- -- Handle top- (_ , TyApp tcu _ _)- | tcu == tcUn && qualConst t <: Qu- -> return ()- (_ , TyApp tcu _ _)- | tcu == tcAf- -> return ()- -- Handle bottom- (TyApp tct _ _, _)- | tct == tcBot- -> return ()- -- Variables- (TyVar vt, TyVar vu) -> do- mt' <- getVar vt env1- mu' <- getVar vu env2- case (mt', mu') of- (Just (_, t'), Nothing) -> upperBoundUVar t' u- (Nothing, Just (_, u')) -> lowerBoundUVar u' t- (Just (lt, t'), Just (lu, u'))- | lt > lu -> upperBoundUVar t' u- | lt < lu -> lowerBoundUVar u' t- _ -> unless (vt == vu) $ giveUp t u- (TyVar vt, _) -> do- mt' <- getVar vt env1- case mt' of- Just (_, t') -> upperBoundUVar t' u- Nothing -> giveUp t u- (_, TyVar vu) -> do- mu' <- getVar vu env2- case mu' of- Just (_, u') -> lowerBoundUVar u' t- Nothing -> giveUp t u- -- Type applications- (TyApp tct ts _, TyApp tcu us _)- | tct == tcu,- isHeadNormalType t, isHeadNormalType u ->- cmpList (tcArity tct) ts us- (TyApp tct ts _, TyApp tcu us _)- | tct == tcu ->- cmpList (tcArity tct) ts us `catchError` \_ -> do- t' <- hn t- u' <- hn u- cmp t' u'- (TyApp _ _ _, _)- | not (isHeadNormalType t)- -> (`cmp` u) =<< hn t- (_, TyApp _ _ _)- | not (isHeadNormalType u)- -> (t `cmp`) =<< hn u- -- Arrows- (TyFun qt t1 t2, TyFun qu u1 u2) -> do- subkind qt qu $ giveUp t u- revCmp t1 u1- cmp t2 u2- -- Quantifiers- (TyQu Forall tvt t1, _) -> do- tv' <- freshU (tvqual tvt)- incU $- withUVars [tv'] env1 $- cmp (tysubst tvt (TyVar tv') t1) u- return ()- (_, TyQu Exists tvu u1) -> do- tv' <- freshU (tvqual tvu)- incU $- withUVars [tv'] env2 $- cmp t (tysubst tvu (TyVar tv') u1)- return ()- (_, TyQu Forall tvu u1) -> do- tv' <- freshU (tvqual tvu)- cmp t (tysubst tvu (TyVar tv') u1)- (TyQu Exists tvt t1, _) -> do- tv' <- freshU (tvqual tvt)- cmp (tysubst tvt (TyVar tv') t1) u- -- Recursion- (TyMu tvt t1, _) -> cmp (tysubst tvt t t1) u- (_, TyMu tvu u1) -> cmp t (tysubst tvu u u1)- -- Failure- _ -> giveUp t u- --- giveUp t u = - throwError $- "Got type `" ++ show t ++ "' where type `" ++- show u ++ "' expected"- --- revCmp u t = flipU (cmp t u)- --- hn t = headNormalizeTypeM limit t- --- cmpList arity ts us =- sequence_- [ case var of- 1 -> cmp tj uj- -1 -> revCmp tj uj- _ -> do cmp tj uj; revCmp tj uj- | var <- arity- | tj <- ts- | uj <- us ]- --- -- XXX This is woefully insufficient- subkind qd1 qd2 orElse =- if qd1 <: qd2 then return () else do- (m1, m2) <- getUVars- case (view $ qRepresent qd1, view $ qRepresent qd2) of- (QeVar tv1, QeVar tv2)- | Just (_, ref) <- m1 tv1, Nothing <- m2 tv2- -> upperBoundUVar ref (TyVar tv2)- | Nothing <- m1 tv1, Just (_, ref) <- m2 tv2- -> lowerBoundUVar ref (TyVar tv1)- (QeVar tv1, QeLit qlit)- | Just (_, ref) <- m1 tv1- -> upperBoundUVar ref (tyTop qlit)- (QeLit qlit, QeVar tv2)- | Just (_, ref) <- m2 tv2- -> lowerBoundUVar ref (tyTop qlit)- _ -> orElse--jointype :: MonadError String m => Int -> Bool -> Type -> Type -> m Type-jointype limit b t1i t2i =- liftM clean $ runUT (cmp (b, True) t1i t2i) (alltv (t1i, t2i))- where- cmp, revCmp :: (Bool, Bool) -> Type -> Type -> UT Type t Type- cmp m t u = do- let (direction, _) = m- tv <- freshU (qualConst t \/ qualConst u)- catchTop m t u $- chkU t u (TyVar tv) $- TyMu tv `liftM`- case (t, u) of- -- Handle top and bottom- _ | Just t' <- points direction t u -> return t'- | Just t' <- points direction u t -> return t'- -- Type applications- (TyApp tct ts _, TyApp tcu us _)- | tct == tcu,- isHeadNormalType t, isHeadNormalType u ->- tyApp tct `liftM`- cmpList (tcArity tct) (direction, True) ts us- (TyApp tct ts _, TyApp tcu us _)- | tct == tcu- -> liftM (tyApp tct)- (cmpList (tcArity tct) (direction, False) ts us)- `catchError` \_ -> do- t' <- hn t- u' <- hn u- cmp m t' u'- (TyApp _ _ _, _)- | not (isHeadNormalType t) -> do- t' <- hn t- cmp m t' u- (_, TyApp _ _ _)- | not (isHeadNormalType u) -> do- u' <- hn u- cmp m t u'- -- Variables- (TyVar vt, TyVar ut)- | vt == ut ->- return t- -- Arrows- (TyFun qt t1 t2, TyFun qu u1 u2) -> do- q' <- ifMJ direction qt qu- t1' <- revCmp m t1 u1- t2' <- cmp m t2 u2- return (TyFun q' t1' t2')- -- Quantifiers- (TyQu qt tvt t1, TyQu qu tvu u1)- | qt == qu -> do- q' <- ifMJ direction (tvqual tvt) (tvqual tvu)- tv' <- freshU q'- liftM (TyQu qt tv') $- cmp m (tysubst tvt (TyVar tv') t1)- (tysubst tvu (TyVar tv') u1)- -- Recursion- (TyMu tvt t1, _) ->- cmp m (tysubst tvt t t1) u- (_, TyMu tvu u1) ->- cmp m t (tysubst tvu u u1)- -- Failure- _ ->- throwError $- "Could not " ++ (if direction then "join" else "meet") ++- " types `" ++ show t ++- "' and `" ++ show u ++ "'"- --- hn t = headNormalizeTypeM limit t- --- cmpList arity m ts us =- sequence- [ case var of- 1 -> cmp m tj uj- -1 -> revCmp m tj uj- _ -> if tj == uj- then return tj- else throwError $- "Could not unify types `" ++ show tj ++- "' and `" ++ show uj ++ "'"- | var <- arity- | tj <- ts- | uj <- us ]- --- points True t u@(TyApp tc _ _)- | tc == tcAf = Just u- | tc == tcUn, qualConst t <: Qu = Just u- | tc == tcBot = Just t- points False t u@(TyApp tc _ _)- | tc == tcAf = Just t- | tc == tcUn, qualConst t <: Qu = Just t- | tc == tcBot = Just u- points _ _ _ = Nothing- --- revCmp (direction, lossy) t u = cmp (not direction, lossy) t u- --- catchTop (True, True) t u body = body- `catchError` \_ -> return (tyTop (qualConst t \/ qualConst u))- {-- catchTop (False, True) _ _ body = body- `catchError` \_ -> return tyBot- -}- catchTop _ _ _ body = body- --- clean :: Type -> Type- clean (TyApp tc ts _) = tyApp tc (map clean ts)- clean (TyVar a) = TyVar a- clean (TyFun q t1 t2) = TyFun q (clean t1) (clean t2)- clean (TyQu u a t) = TyQu u a (clean t)- clean (TyMu a t)- | a `S.member` ftv t = TyMu a (clean t)- | otherwise = clean t---- | Helper to force 'Either' to the right type-runEither :: (String -> r) -> (a -> r) -> Either String a -> r-runEither = either---- | The Type partial order-instance Eq Type where- t1 == t2 = t1 <: t2 && t2 <: t1--instance PO Type where- t1 <: t2 = runEither (const False) (const True)- (subtype 100 [] t1 [] t2)- ifMJ b t1 t2 = runEither (throwError . strMsg) return- (jointype 100 b t1 t2)--subtypeTests, joinTests, uvarsTests :: T.Test--subtypeTests = T.test- [ tyUnit <:! tyUnit- , tyUnit !<: tyInt- , tyInt <:! tyInt- , tyInt .->. tyInt <:! tyInt .->. tyInt- , tyInt .->. tyInt <:! tyInt .-*. tyInt- , tyInt .-*. tyInt <:! tyInt .-*. tyInt- , tyInt .-*. tyInt !<: tyInt .->. tyInt- , tyUnit .->. tyInt !<: tyInt .->. tyInt- , (tyInt .-*. tyInt) .->. tyInt .->. tyInt <:!- (tyInt .->. tyInt) .->. tyInt .-*. tyInt - , tyInt .->. tyInt <:! tyUn- , tyInt .->. tyInt <:! tyAf- , tyInt .-*. tyInt !<: tyUn- , tyInt .-*. tyInt <:! tyAf- , tyUn <:! tyAf- , tyAf !<: tyUn- , tyRecv tyInt <:! tyRecv tyInt- , tyRecv tyInt !<: tyRecv tyUnit- , tyRecv tyInt !<: tySend tyInt- , tyRecv (tyInt .-*. tyInt) <:! tyRecv (tyInt .->. tyInt)- , tyRecv (tyInt .->. tyInt) !<: tyRecv (tyInt .-*. tyInt)- , tySend (tyInt .-*. tyInt) !<: tySend (tyInt .->. tyInt)- , tySend (tyInt .->. tyInt) <:! tySend (tyInt .-*. tyInt)- , tyIdent tyInt <:! tyIdent tyInt- , tyIdent tyInt !<: tyIdent tyUnit- , tyInt <:! tyIdent tyInt- , tyIdent tyInt <:! tyInt- , tyInt !<: tyIdent tyUnit- , tyIdent tyInt !<: tyUnit- , tyConst tyInt <:! tyConst tyInt- , tyConst tyInt <:! tyConst tyUnit- , tyConst tyInt <:! tyUnit- , tyUnit <:! tyConst tyInt- , tyUnit .->. tyInt <:! tyIdent (tyConst (tySend tyInt) .-*. tyInt)- , tyInt .->. tyInt !<: tyIdent (tyConst (tySend tyInt) .-*. tyInt)- , tyDual (tyRecv tyInt .:. tySend tyUnit .:. tyUnit) <:!- tyDual (tyRecv tyInt .:. tySend tyUnit .:. tyUnit)- , tyDual (tyRecv tyInt .:. tySend tyUnit .:. tyUnit) <:!- tySend tyInt .:. tyDual (tySend tyUnit .:. tyUnit) - , tyDual (tyRecv tyInt .:. tySend tyUnit .:. tyUnit) <:!- tySend tyInt .:. tyRecv tyUnit .:. tyUnit - , tyBot <:! tyInt .->. tyInt- , tyInt .->. tyInt !<: tyBot- , TyVar a <:! TyVar a- , TyVar a !<: TyVar b- , tyAll a (tyInt .->. TyVar a) <:! tyAll b (tyInt .->. TyVar b)- , tyAll a (tyInt .->. TyVar a) <:! tyAll b (tyInt .->. TyVar a)- , tyAll c (TyVar c .->. tyInt) <:! tyAll a (TyVar a .-*. tyInt)- , tyAll a (TyVar a .->. tyInt) !<: tyAll c (TyVar c .-*. tyInt)- , tyAll a (tyAll b (TyVar a .*. TyVar b)) <:!- tyAll b (tyAll a (TyVar b .*. TyVar a))- , tyAll a (tyAll b (TyVar a .*. TyVar b)) <:!- tyAll b (tyAll a (TyVar a .*. TyVar b))- , tyAll a (tyAll a (TyVar a .*. TyVar b)) !<:- tyAll b (tyAll a (TyVar a .*. TyVar b))- , tyAll a (tyAll a (TyVar a .*. TyVar b)) <:!- tyAll a (tyAll a (TyVar a .*. TyVar b))- , TyMu a (tyInt .->. TyVar a) <:!- TyMu b (tyInt .->. TyVar b)- , TyMu a (tyInt .->. TyVar a) <:!- TyMu b (tyInt .->. tyInt .->. TyVar b)- , TyMu a (tyInt .->. TyVar a) <:!- TyMu b (tyInt .->. tyInt .-*. TyVar b)- , TyMu a (tyInt .->. TyVar a) !<:- TyMu b (tyInt .->. tyUnit .-*. TyVar b)- , TyMu a (TyVar a .*. tyInt .*. tyInt) <:!- TyMu a (TyVar a .*. tyInt .*. tyInt) .*. tyInt - , TyMu a (TyVar a .*. tyInt .*. tyUnit) <:!- TyMu a (TyVar a .*. tyUnit .*. tyInt) .*. tyUnit - , tyAll c (TyMu a (TyVar a .*. tyInt .*. TyVar c)) <:!- tyAll d (TyMu a (TyVar a .*. TyVar d .*. tyInt) .*. TyVar d)- , tyAll c (TyMu a (TyVar a .*. tyInt .*. TyVar c)) !<:- tyAll d (TyMu a (TyVar d .*. TyVar a .*. tyInt) .*. TyVar d)- , TyMu a (tyAll c ((tyInt .-*. TyVar c) .->. TyVar a)) !<:- TyMu b (tyAll d ((tyInt .->. TyVar d) .->. TyVar c))- , TyMu a (tyAll c (tyInt .-*. TyVar c) .->. TyVar a) <:!- TyMu b (tyAll d (tyInt .->. TyVar d) .->. TyVar b)- , TyMu a (tyAll c (TyVar a .-*. TyVar c) .->. TyVar a) <:!- TyMu b (tyAll d (TyVar b .->. TyVar d) .->. TyVar b)- , tyAll a (TyVar a .*. tyInt) .->. TyVar a <:!- tyAll b (TyVar b .*. tyInt) .->. TyVar a - , tyAll a (TyVar a .*. tyInt) .->. TyVar a !<:- tyAll b (TyVar b .*. tyInt) .->. TyVar b - -- Universal instantiation tests- , tyAll a (TyVar a .->. TyVar a) <:! tyInt .->. tyInt- , tyAll a (TyVar a .->. TyVar a) !<: tyInt .->. tyUnit- , tyInt .->. tyInt !<: tyAll a (TyVar a .->. TyVar a)- , tyAll a (TyVar a .->. tyInt) <:! tyInt .->. tyInt- , tyAll a (tyInt .->. tyInt) <:! tyInt .->. tyInt- , tyInt .->. tyAll a (TyVar a .->. TyVar a) <:!- tyInt .->. tyInt .->. tyInt- , TyMu a (TyVar a .*. (tyAll a (TyVar a .->. TyVar a))) <:!- TyMu a (TyVar a .*. (tyInt .->. tyInt))- , TyMu a (TyVar a .*. (tyAll a (tyInt .->. TyVar a))) <:!- TyMu a (TyVar a .*. (tyInt .->. tyInt))- , TyMu b (TyVar b .*. (tyAll a (TyVar a .->. TyVar a))) <:!- TyMu a (TyVar a .*. (tyInt .->. tyInt))- , TyMu b (TyVar b .*. (tyAll a (tyInt .->. TyVar a))) <:!- TyMu a (TyVar a .*. (tyInt .->. tyInt))- , TyMu a (tyAll b (TyVar b .->. TyVar a)) <:!- TyMu a (tyInt .->. TyVar a)- , tyAll a (TyVar a .*. tyInt) <:! TyMu a (TyVar a .*. tyInt)- , tyAll a (TyVar a .*. TyVar a) !<: TyMu a (TyVar a .*. tyInt)- , tyAll a (TyMu b (TyVar a .->. TyVar b)) <:!- TyMu b (tyInt .->. TyVar b)- , tyAll a (TyMu a (tyInt .->. TyVar a)) !<:- TyMu b (tyInt .->. tyInt)- , tyAll a (tyInt .->. TyVar a) .->. tyInt !<:- (tyInt .->. tyInt) .->. tyInt- , (tyInt .->. tyInt) .->. tyInt <:!- tyAll a (tyInt .->. TyVar a) .->. tyInt- , tyAll a (tyInt .->. TyVar a) !<: tyInt .->. tyInt .-*. tyInt- -- This is now true, but should it be?:- , TyMu a (tyAll c (tyInt .->. tyAll d (TyVar c .->. TyVar a))) <:!- tyAll c (tyInt .->.- TyMu a (tyAll d (TyVar c .->.- tyAll c (tyInt .->. TyVar a))))- -- This is now true, but should it be?:- , tyAll c (tyInt .->.- TyMu a (tyAll d (TyVar c .->.- tyAll c (tyInt .->. TyVar a)))) <:!- TyMu a (tyAll c (tyInt .->. tyAll d (TyVar c .->. TyVar a)))- , tyInt <:! tyEx a (TyVar a)- , tyInt <:! tyEx a tyInt- , tyInt .*. tyInt <:! tyEx a (TyVar a .*. tyInt)- , tyInt .*. tyInt <:! tyEx a (tyInt .*. TyVar a)- , tyInt .*. tyInt <:! tyEx a (TyVar a .*. TyVar a)- , tyInt .*. tyInt <:! tyEx a (tyEx b (TyVar a .*. TyVar a))- , tyInt .*. tyInt <:! tyEx a (tyEx b (TyVar b .*. TyVar a))- , tyUn .->. tyUn !<: TyVar a .->. TyVar a- -- These are potentially sketchy, but useful:- , tyInt <:! tyAll a tyInt- , tyInt !<: tyAll a (TyVar a)- , tyEx a tyInt <:! tyInt- , tyEx a (TyVar a) !<: tyInt- , tyEx a (TyVar a) !<: TyVar a- ]- where- t1 <:! t2 = T.assertBool (show t1 ++ " <: " ++ show t2) (t1 <: t2)- t1 !<: t2 = T.assertBool (show t1 ++ " /<: " ++ show t2) (t1 /<: t2)- infix 4 <:!, !<:- a = tvUn "a"; b = tvUn "b"; c = tvAf "c"; d = tvAf "d"--joinTests = T.test- [ tyUnit \/! tyUnit ==! tyUnit- , tyUnit /\! tyUnit ==! tyUnit- , tyInt /\! tyInt ==! tyInt- , tyUnit \/! tyInt ==! tyUn- , tyUnit !/\ tyInt- , tyInt .->. tyInt \/! tyInt .->. tyInt ==! tyInt .->. tyInt- , tyInt .->. tyInt \/! tyInt .-*. tyInt ==! tyInt .-*. tyInt- , tyInt .-*. tyInt \/! tyInt .-*. tyInt ==! tyInt .-*. tyInt- , tyInt .-*. tyInt \/! tyInt .->. tyInt ==! tyInt .-*. tyInt- , tyInt .->. tyInt /\! tyInt .->. tyInt ==! tyInt .->. tyInt- , tyInt .->. tyInt /\! tyInt .-*. tyInt ==! tyInt .->. tyInt- , tyInt .-*. tyInt /\! tyInt .-*. tyInt ==! tyInt .-*. tyInt- , tyInt .-*. tyInt /\! tyInt .->. tyInt ==! tyInt .->. tyInt- , tyInt .->. tyInt \/! tyInt .->. tyUnit ==! tyInt .->. tyUn- , tyInt .->. tyInt \/! tyUnit .->. tyInt ==! tyUn- , tyInt .-*. tyInt \/! tyUnit .->. tyInt ==! tyAf- , tyInt .->. tyInt !/\ tyInt .->. tyUnit- , tyInt .->. tyInt /\! tyUnit .->. tyInt ==! tyUn .->. tyInt- , tyInt .-*. tyInt /\! tyUnit .->. tyInt ==! tyUn .->. tyInt- , (tyInt .-*. tyInt) .-*. tyInt /\! tyUnit .->. tyInt- ==! tyAf .->. tyInt- , tyInt .->. tyInt \/! tyUn ==! tyUn- , tyInt .->. tyInt \/! tyAf ==! tyAf- , tyInt .-*. tyInt \/! tyUn ==! tyAf- , tyInt .-*. tyInt \/! tyAf ==! tyAf- , tyInt .->. tyInt /\! tyUn ==! tyInt .->. tyInt- , tyInt .->. tyInt /\! tyAf ==! tyInt .->. tyInt- , tyInt .-*. tyInt !/\ tyUn -- could do better- , tyInt .-*. tyInt /\! tyAf ==! tyInt .-*. tyInt- , tyRecv tyInt \/! tyRecv tyInt ==! tyRecv tyInt- , tySend tyInt \/! tySend tyUnit ==! tySend tyUn- , tyRecv tyInt \/! tySend tyInt ==! tyUn- , tyRecv (tyInt .-*. tyInt) \/!- tyRecv (tyInt .->. tyInt) ==!- tyRecv (tyInt .->. tyInt)- , tyRecv (tyInt .->. tyInt) \/!- tyRecv (tyInt .-*. tyInt) ==!- tyRecv (tyInt .->. tyInt)- , tySend (tyInt .-*. tyInt) \/!- tySend (tyInt .->. tyInt) ==!- tySend (tyInt .-*. tyInt)- , tySend (tyInt .->. tyInt) \/!- tySend (tyInt .-*. tyInt) ==!- tySend (tyInt .-*. tyInt)- , tyRecv (tyInt .-*. tyInt) /\!- tyRecv (tyInt .->. tyInt) ==!- tyRecv (tyInt .-*. tyInt)- , tyRecv (tyInt .->. tyInt) /\!- tyRecv (tyInt .-*. tyInt) ==!- tyRecv (tyInt .-*. tyInt)- , tySend (tyInt .-*. tyInt) /\!- tySend (tyInt .->. tyInt) ==!- tySend (tyInt .->. tyInt)- , tySend (tyInt .->. tyInt) /\!- tySend (tyInt .-*. tyInt) ==!- tySend (tyInt .->. tyInt)- , tyIdent tyInt \/! tyIdent tyInt ==! tyIdent tyInt- , tyIdent tyInt \/! tyIdent tyUnit ==! tyUn- , tyInt \/! tyIdent tyInt ==! tyInt- , tyInt \/! tyIdent tyUnit ==! tyUn- , tyIdent tyInt /\! tyIdent tyInt ==! tyIdent tyInt- , tyIdent tyInt !/\ tyIdent tyUnit- , tyInt /\! tyIdent tyInt ==! tyInt- , tyInt !/\ tyIdent tyUnit- , tyIdent (tyIdent tyInt) \/! tyIdent tyInt ==! tyIdent tyInt- , tyIdent (tyConst tyInt) \/! tyIdent (tyConst tyUnit) ==! tyIdent tyUnit- , tyConst tyInt \/! tyConst tyInt ==! tyConst tyInt- , tyConst tyInt \/! tyConst tyUnit ==! tyUnit- , tyConst tyInt /\! tyConst tyInt ==! tyConst tyInt- , tyConst tyInt /\! tyConst tyUnit ==! tyUnit- , tyUnit .->. tyInt \/! tyIdent (tyConst (tySend tyInt) .-*. tyInt)- ==! tyUnit .-*. tyInt- , tyInt .->. tyInt \/! tyIdent (tyConst (tySend tyInt) .-*. tyInt)- ==! tyAf- , tyUnit .->. tyInt /\! tyIdent (tyConst (tySend tyInt) .-*. tyInt)- ==! tyUnit .->. tyInt- , tyInt .->. tyInt /\! tyIdent (tyConst (tySend tyInt) .-*. tyInt)- ==! tyUn .->. tyInt- , tyDual (tyRecv tyInt .:. tySend tyUnit .:. tyUnit) \/!- tyDual (tyRecv tyInt .:. tySend tyUnit .:. tyUnit) ==!- tyDual (tyRecv tyInt .:. tySend tyUnit .:. tyUnit)- , tyDual (tyRecv tyInt .:. tySend tyUnit .:. tyUnit) \/!- tySend tyInt .:. tyDual (tySend tyUnit .:. tyUnit) ==!- tySend tyInt .:. tyDual (tySend tyUnit .:. tyUnit) - , tyDual (tyRecv tyInt .:. tySend tyUnit .:. tyUnit) \/!- tySend tyInt .:. tyRecv tyUnit .:. tyUnit ==!- tySend tyInt .:. tyRecv tyUnit .:. tyUnit - , tyDual (tyRecv tyInt .:. tySend tyUnit .:. tyUnit) /\!- tyDual (tyRecv tyInt .:. tySend tyUnit .:. tyUnit) ==!- tyDual (tyRecv tyInt .:. tySend tyUnit .:. tyUnit)- , tyDual (tyRecv tyInt .:. tySend tyUnit .:. tyUnit) /\!- tySend tyInt .:. tyDual (tySend tyUnit .:. tyUnit) ==!- tySend tyInt .:. tyDual (tySend tyUnit .:. tyUnit) - , tyDual (tyRecv tyInt .:. tySend tyUnit .:. tyUnit) /\!- tySend tyInt .:. tyRecv tyUnit .:. tyUnit ==!- tySend tyInt .:. tyRecv tyUnit .:. tyUnit - , tyBot \/! tyInt .->. tyInt ==! tyInt .->. tyInt- , tyInt .->. tyInt /\! tyBot ==! tyAll b (TyVar b)- , TyVar a \/! TyVar a ==! TyVar a- , TyVar a \/! TyVar b ==! tyUn- , TyVar a \/! TyVar c ==! tyAf- , TyVar a /\! TyVar a ==! TyVar a- , TyVar a !/\ TyVar b- , TyVar a !/\ TyVar c- , tyAll a (tyInt .->. TyVar a) \/! tyAll b (tyInt .->. TyVar b)- ==! tyAll a (tyInt .->. TyVar a)- , tyAll a (tyInt .->. TyVar a) \/! tyAll b (tyInt .->. TyVar a)- ==! tyAll a (tyInt .->. tyUn)- , tyAll c (TyVar c .->. tyInt) \/! tyAll a (TyVar a .-*. tyInt)- ==! tyAll d (TyVar d .-*. tyInt)- , tyAll a (tyInt .->. TyVar a) /\! tyAll b (tyInt .->. TyVar b)- ==! tyAll a (tyInt .->. TyVar a)- , tyAll a (tyInt .->. TyVar a) !/\ tyAll b (tyInt .->. TyVar a)- , tyAll c (TyVar c .->. tyInt) /\!- tyAll a (TyVar a .-*. tyInt) ==!- tyAll b (TyVar b .->. tyInt)- , tyAll a (tyAll b (TyVar a .*. TyVar b)) \/!- tyAll b (tyAll a (TyVar b .*. TyVar a)) ==!- tyAll b (tyAll a (TyVar b .*. TyVar a))- , tyAll a (tyAll b (TyVar a .*. TyVar b)) \/!- tyAll b (tyAll a (TyVar a .*. TyVar b)) ==!- tyAll b (tyAll a (tyUn .*. tyUn))- , tyAll c (tyAll c (TyVar c .*. TyVar d)) \/!- tyAll d (tyAll c (TyVar c .*. TyVar d)) ==!- tyAll d (tyAll d (TyVar d .*. tyAf))- , tyAll a (tyAll a (TyVar a .*. TyVar b)) \/!- tyAll a (tyAll a (TyVar a .*. TyVar b)) ==!- tyAll a (tyAll a (TyVar a .*. TyVar b))- , tyAll a (tyAll b (TyVar a .*. TyVar b)) /\!- tyAll b (tyAll a (TyVar b .*. TyVar a)) ==!- tyAll b (tyAll a (TyVar b .*. TyVar a))- , tyAll a (tyAll b (TyVar a .*. TyVar b)) !/\- tyAll b (tyAll a (TyVar a .*. TyVar b))- , tyAll c (tyAll c (TyVar c .*. TyVar d)) !/\- tyAll d (tyAll c (TyVar c .*. TyVar d))- , tyAll a (tyAll a (TyVar a .*. TyVar b)) /\!- tyAll a (tyAll a (TyVar a .*. TyVar b)) ==!- tyAll a (tyAll a (TyVar a .*. TyVar b))- , TyMu a (tyInt .->. TyVar a) \/!- TyMu b (tyInt .->. TyVar b) ==!- TyMu b (tyInt .->. TyVar b)- , TyMu a (tyInt .->. TyVar a) /\!- TyMu b (tyInt .->. TyVar b) ==!- TyMu b (tyInt .->. TyVar b)- , TyMu a (tyInt .->. TyVar a) \/!- TyMu b (tyInt .->. tyInt .->. TyVar b) ==!- TyMu a (tyInt .->. TyVar a)- , TyMu a (tyInt .->. TyVar a) /\!- TyMu b (tyInt .->. tyInt .->. TyVar b) ==!- TyMu a (tyInt .->. TyVar a)- , TyMu a (tyInt .->. TyVar a) \/!- TyMu b (tyInt .->. tyInt .-*. TyVar b) ==!- TyMu b (tyInt .->. tyInt .-*. TyVar b)- , TyMu a (tyInt .->. TyVar a) /\!- TyMu b (tyInt .->. tyInt .-*. TyVar b) ==!- TyMu b (tyInt .->. TyVar b)- , TyMu a (tyInt .->. TyVar a) \/!- TyMu b (tyInt .->. tyUnit .-*. TyVar b) ==!- tyInt .->. tyAf- , TyMu a (tyInt .->. TyVar a) /\!- TyMu b (tyInt .->. tyUnit .-*. TyVar b) ==!- TyMu a (tyInt .->. tyUn .->. TyVar a)- , TyMu a (TyVar a .*. tyInt .*. tyInt) \/!- TyMu a (TyVar a .*. tyInt .*. tyInt) .*. tyInt ==!- TyMu a (TyVar a .*. tyInt)- , TyMu a (TyVar a .*. tyInt .*. tyInt) /\!- TyMu a (TyVar a .*. tyInt .*. tyInt) .*. tyInt ==!- TyMu a (TyVar a .*. tyInt)- , TyMu a (TyVar a .*. tyInt .*. tyUnit) \/!- TyMu a (TyVar a .*. tyUnit .*. tyInt) .*. tyUnit ==!- TyMu b (TyVar b .*. tyInt .*. tyUnit)- , TyMu a (TyVar a .*. tyInt .*. tyUnit) /\!- TyMu a (TyVar a .*. tyUnit .*. tyInt) .*. tyUnit ==!- TyMu b (TyVar b .*. tyInt .*. tyUnit)- , tyAll c (TyMu a (TyVar a .*. tyInt .*. TyVar c)) \/!- tyAll d (TyMu a (TyVar a .*. TyVar d .*. tyInt) .*. TyVar d) ==!- tyAll c (TyMu b (TyVar b .*. tyInt .*. TyVar c))- , tyAll c (TyMu a (TyVar a .*. tyInt .*. TyVar c)) /\!- tyAll d (TyMu a (TyVar a .*. TyVar d .*. tyInt) .*. TyVar d) ==!- tyAll c (TyMu b (TyVar b .*. tyInt .*. TyVar c))- , tyAll c (TyMu a (TyVar a .*. tyInt .*. TyVar c)) \/!- tyAll d (TyMu a (TyVar d .*. TyVar a .*. tyInt) .*. TyVar d) ==!- tyAll c (tyAf .*. tyAf .*. tyInt .*. TyVar c)- , tyAll c (TyMu a (TyVar a .*. tyInt .*. TyVar c)) !/\- tyAll d (TyMu a (TyVar d .*. TyVar a .*. tyInt) .*. TyVar d)- , TyMu a (tyAll c (tyInt .-*. TyVar c) .->. TyVar a) \/!- TyMu b (tyAll d (tyInt .->. TyVar d) .->. TyVar c) ==!- tyAll d (tyInt .->. TyVar d) .->. tyAf- , TyMu a (tyAll c (tyInt .-*. TyVar c) .->. TyVar a) !/\- TyMu b (tyAll d (tyInt .->. TyVar d) .->. TyVar c)- , TyMu a (tyAll c (tyInt .-*. TyVar c) .->. TyVar a) \/!- TyMu b (tyAll d (tyInt .->. TyVar d) .->. TyVar b) ==!- TyMu b (tyAll c (tyInt .->. TyVar c) .->. TyVar b)- , TyMu a (tyAll c (tyInt .-*. TyVar c) .->. TyVar a) /\!- TyMu b (tyAll d (tyInt .->. TyVar d) .->. TyVar b) ==!- TyMu b (tyAll c (tyInt .-*. TyVar c) .->. TyVar b)- , TyMu a (tyAll c (TyVar a .-*. TyVar c) .->. TyVar a) \/!- TyMu b (tyAll d (TyVar b .->. TyVar d) .->. TyVar b) ==!- TyMu b (tyAll d (TyVar b .->. TyVar d) .->. TyVar b)- , TyMu a (tyAll c (TyVar a .-*. TyVar c) .->. TyVar a) /\!- TyMu b (tyAll d (TyVar b .->. TyVar d) .->. TyVar b) ==!- TyMu b (tyAll d (TyVar b .-*. TyVar d) .->. TyVar b)- , tyAll a (TyVar a .*. tyInt) .->. TyVar a \/!- tyAll b (TyVar b .*. tyInt) .->. TyVar a ==!- tyAll b (TyVar b .*. tyInt) .->. TyVar a - , tyAll a (TyVar a .*. tyInt) .->. TyVar a /\!- tyAll b (TyVar b .*. tyInt) .->. TyVar a ==!- tyAll b (TyVar b .*. tyInt) .->. TyVar a - , tyAll a (TyVar a .*. tyInt) .->. TyVar a \/!- tyAll b (TyVar b .*. tyInt) .->. TyVar b ==!- tyAll b (TyVar b .*. tyInt) .->. tyUn- , tyAll a (TyVar a .*. tyInt) .->. TyVar a !/\- tyAll b (TyVar b .*. tyInt) .->. TyVar b - , tyBot \/! TyVar b ==! TyVar b- , tyIdent tyBot \/! TyVar b ==! TyVar b- ]- where- t1 \/! t2 = Left (t1, t2)- t1 /\! t2 = Right (t1, t2)- Left (t1, t2) ==! t =- tassertSuccess (show t1 ++ " \\/ " ++ show t2 ++ " = " ++ show t)- t (t1 \/? t2)- Right (t1, t2) ==! t =- tassertSuccess (show t1 ++ " /\\ " ++ show t2 ++ " = " ++ show t)- t (t1 /\? t2)- t1 !/\ t2 =- tassertFailure (show t1 ++ " /\\ " ++ show t2 ++ " DNE")- (t1 /\? t2)- infix 2 ==!- infix 4 \/!, /\!, !/\- a = tvUn "a"; b = tvUn "b"; c = tvAf "c"; d = tvAf "d"--uvarsTests = T.test- [ tyInt !<: tyUnit- , tyInt <:! tyInt ==! (noU, noU, noA, noA)- , TyVar a <:! tyInt ==! (tyInt, noU, noA, noA)- , TyVar c <:! tyInt ==! (noU, noU, tyInt, noA)- , tyInt !<: TyVar a- , TyVar a .*. TyVar a <:! tyInt .*. tyInt- ==! (tyInt, noU, noA, noA)- , TyVar a .*. TyVar a !<: tyInt .*. tyUnit- , TyVar a .*. TyVar a <:! (tyInt .->. tyInt) .*. (tyInt .-*. tyInt)- ==! (tyInt .->. tyInt, noU, noA, noA)- , TyVar a .*. TyVar a <:! (tyUnit .->. tyInt) .*. (tyInt .-*. tyInt)- ==! (tyUn .->. tyInt, noU, noA, noA)- , TyVar a .->. tyInt <:! tyInt .->. tyInt- ==! (tyInt, noU, noA, noA)- , TyVar a .->. TyVar a <:! tyInt .->. tyInt- ==! (tyInt, noU, noA, noA)- , TyVar a .->. TyVar a !<: tyFloat .->. tyInt- , TyVar a .->. TyVar a !<: (tyInt .->. tyInt) .-*. (tyInt .-*. tyInt)- , TyVar c .->. TyVar c <:! (tyInt .->. tyInt) .-*. (tyInt .-*. tyInt)- ==! (noU, noU, tyInt .->. tyInt, noA)- , TyVar c .->. TyVar c !<: (tyInt .-*. tyInt) .-*. (tyInt .->. tyInt)- , TyVar c .-*. TyVar c !<: (tyInt .->. tyInt) .->. (tyInt .-*. tyInt)- , TyVar a .*. TyVar a <:! tyDual (tyRecv tyInt .:. tyUnit) .*.- (tySend tyInt .:. tyUnit)- ==! (tySend tyInt .:. tyUnit, noU, noA, noA)- , TyVar a .*. TyVar a !<: tyDual (tyRecv tyInt .:. tyUnit) .*.- (tySend tyInt .:. tyInt)- , TyVar a .*. tyAll a (TyVar a .->. tyInt) <:!- tyInt .*. tyAll b (TyVar b .->. tyInt)- ==! (tyInt, noU, noA, noA)- , TyVar a .*. tyAll a (TyVar a .->. tyInt) <:!- tyInt .*. tyAll b (tyInt .->. tyInt)- ==! (tyInt, noU, noA, noA)- , tyAll a (TyVar a .->. tyInt) <:!- tyAll a (tyInt .->. tyInt)- ==! (noU, noU, noA, noA)- , TyVar a <:! tyInt .->. TyMu a (tyInt .->. TyVar a)- ==! (TyMu b (tyInt .->. TyVar b), noU, noA, noA)- , TyVar a .->. TyVar b <:! tyInt .->. TyMu a (tyInt .->. TyVar a)- ==! (tyInt, TyMu b (tyInt .->. TyVar b), noA, noA)- , TyVar a .->. TyVar b <:! TyMu a (tyInt .->. TyVar a)- ==! (tyInt, TyMu b (tyInt .->. TyVar b), noA, noA)- , TyVar a >:! tyInt- ==! (tyInt, noU, noA, noA)- , TyVar a .-*. TyVar a >:! tyInt .->. tyInt- ==! (tyInt, noU, noA, noA)- , TyVar a .->. TyVar a !>: tyInt .-*. tyInt- , TyVar a .-*. TyVar a >:! tyUn .->. tyInt- ==! (tyInt, noU, noA, noA)- , TyFun (qInterpret (qeVar c)) tyInt tyInt <:! tyInt .-*. tyInt- ==! (noU, noU, noA, noA)- , TyFun (qInterpret (qeVar c)) tyInt tyInt <:! tyInt .->. tyInt- ==! (noU, noU, noA, noA)- , (TyVar c .->. TyVar d .-*. TyVar d) .*. TyVar d .*. tyRecv (TyVar c)- <:!- (TyVar e .->. TyVar f .-*. TyVar f) .*. TyVar f .*. tyRecv (TyVar e)- ==! (noU, noU, TyVar e, TyVar f)- , tyConst (TyVar a) <:! tyConst (tyInt)- ==! (tyInt, noU, noA, noA) -- suboptimal- , tyConst (TyVar a .*. tyUnit) <:! tyConst (tyInt .*. tyInt)- ==! (noU, noU, noA, noA)- , tyRecv (TyVar c) .*. tyRecv (TyVar c) >:!- tyRecv (TyVar e) .*. tyAll f (tyRecv (TyVar f))- ==! (noU, noU, TyVar e, noA)- , tyRecv (TyVar c) .*. tyRecv (TyVar c) >:!- tyRecv (TyVar e) .*. tyRecv (TyVar e)- ==! (noU, noU, TyVar e, noA)- , tyRecv (TyVar c) .*. tyRecv (TyVar c) !>:- tyRecv (TyVar e) .*. tyRecv (TyVar f)- , tassertFailure "'<c `supertype` '<d = ERROR"- (subtype 100 [c] (TyVar c) [d] (TyVar d))- , tyFollow (TyVar a) (TyVar b) >:!- tyFollow tyUnit (tyRecv tyInt .:.- TyMu e (tyFollow tyUnit (tyRecv tyInt .:.- TyVar e)))- ==! (tyUnit, (tyRecv tyInt .:.- TyMu e (tyFollow tyUnit (tyRecv tyInt .:.- TyVar e))), noA, noA)- , tyFollow (TyVar a) (TyVar b) >:!- TyMu e (tyFollow tyUnit (tyRecv tyInt .:. TyVar e))- ==! (tyUnit, (tyRecv tyInt .:.- TyMu e (tyFollow tyUnit (tyRecv tyInt .:.- TyVar e))), noA, noA)- ]- where- t1 <:! t2 = Left (t1, t2)- t1 >:! t2 = Right (t1, t2)- Left (t1, t2) ==! (ta, tb, tc, td) =- tassertSuccess (show t1 ++ " `subtype` " ++ show t2)- ([ta, tb, tc, td], [])- (subtype 100 set t1 [] t2)- Right (t1, t2) ==! (ta, tb, tc, td) =- tassertSuccess (show t1 ++ " `supertype` " ++ show t2)- ([], [ta, tb, tc, td])- (subtype 100 [] t2 set t1)- t1 !<: t2 =- tassertFailure (show t1 ++ " `subtype` " ++ show t2 ++ " = ERROR")- (subtype 100 set t1 [] t2)- t1 !>: t2 =- tassertFailure (show t1 ++ " `supertype` " ++ show t2 ++ " = ERROR")- (subtype 100 [] t2 set t1)- infix 2 ==!- infix 4 <:!, !<:, >:!, !>:- noU = tyBot; noA = tyBot- set = [a, b, c, d]- a = tvUn "a"; b = tvUn "b"; c = tvAf "c"; d = tvAf "d"- e = tvAf "e"; f = tvAf "f"--tassertSuccess :: (Eq a, Show a) =>- String -> a -> Either String a -> T.Assertion-tassertSuccess msg = T.assertEqual msg . Right--tassertFailure :: String -> Either String a -> T.Assertion-tassertFailure msg = either (\_ -> return ()) (\_ -> T.assertFailure msg)--tests :: IO ()-tests = do- T.runTestTT subtypeTests- T.runTestTT joinTests- T.runTestTT uvarsTests- return ()
src/Util.hs view
@@ -1,26 +1,32 @@ -- | Utility functions-{-# LANGUAGE- CPP,- FlexibleContexts- #-} module Util (- -- * List combinators- -- ** Shallow mapping- mapCons, mapHead, mapTail,- -- ** Two-list versions+ -- * Extra collection operations+ -- ** Shallow mapping of 'Traversable's+ mapHead, mapTail, mapInit, mapLast,+ -- ** 'Foldable'/'Applicative' operations+ allA, anyA,+ -- ** 2-way 'Foldable' operations foldl2, foldr2, all2, any2,- -- ** Monadic version- foldrM, anyM, allM, anyM2, allM2,- concatMapM,- -- ** Applicative versions- mapA,- -- ** Unfold with an accumulator+ allA2, anyA2,+ -- ** Extra zips+ zip4, unzip4, zip5, unzip5,+ -- ** List operations+ mapCons, foldM1,+ lookupWithIndex, listNth, ordNub, partitionJust,+ -- *** Unfold with an accumulator unscanr, unscanl,- -- ** Map in CPS+ -- *** Map in CPS mapCont, mapCont_,- -- ** Monad generalization of map and sequence- GSequence(..), + -- * Extra monadic operations+ whenM, unlessM, concatMapM, before,++ -- * Maps for state-like monads+ mapListen2, mapListen3,++ -- * 'Maybe' and 'Either' operations+ fromOptA, unEither,+ -- * More convenience -- ** Maybe functions (?:),@@ -31,100 +37,261 @@ -- ** Monomorphic @ord@ and @chr@ char2integer, integer2char, -- ** For defining 'Ord'- thenCmp,- -- ** Versions of fmap+ thenCmp, thenCmpM,+ -- ** Versions of fmap and compose (>>!),- (<$$>), (<$$$>), (<$$$$>), (<$$$$$>),+ (<$$>), (<$$$>), (<$$$$>), (<$$$$$>), (<$$$$$$>),+ (<$.>), (<$$.>), (<$$$.>), (<$$$$.>),+ (<->), (<-->), (<--->), (<---->), (<----->), + -- * Generic set operations+ SetLike(..), SetLike2(..),+ -- * Re-exports- module Data.Maybe, module Control.Arrow,+ module Control.Applicative, module Control.Monad,- module Control.Applicative+ module Control.Monad.Error,+ module Control.Monad.Identity,+ module Control.Monad.List,+ module Control.Monad.RWS.Strict,+ module Control.Monad.Reader,+ module Control.Monad.State.Strict,+ module Control.Monad.Trans,+ module Control.Monad.Writer.Strict,+ module Data.Foldable,+ module Data.Function,+ module Data.Maybe,+ module Data.Monoid,+ module Data.Traversable,+ module Data.Tuple.All,+ module Data.OptionalClass,+ module Data.Perhaps,+ module Util.Bogus,+ module Util.Viewable,+ module Prelude, ) where +import Prelude hiding ( (=<<), Functor(..), Maybe(..), Monad(..), all,+ and, any, concat, concatMap, elem, foldl, foldl1,+ foldr, foldr1, mapM, mapM_, maximum, maybe,+ minimum, notElem, or, product, sequence, sequence_,+ sum )++import Control.Arrow ( Arrow(..), ArrowChoice(..), (>>>), (<<<) )+import Control.Applicative hiding ( empty )+import Control.Monad hiding ( forM, forM_, mapM_, mapM, msum,+ sequence, sequence_ )++import Control.Monad.Error ( MonadError(..), ErrorT(..), mapErrorT,+ Error(..) )+import Control.Monad.Identity ( Identity(..) )+import Control.Monad.List ( ListT(..), mapListT )+import Control.Monad.RWS.Strict ( RWST(..), runRWST, execRWST, evalRWST,+ mapRWST, evalRWS )+import Control.Monad.Reader ( MonadReader(..), ReaderT(..), mapReaderT,+ asks, runReader )+import Control.Monad.State.Strict ( MonadState(..), StateT(..), evalStateT,+ execStateT, evalState, gets, modify,+ mapStateT )+import Control.Monad.Trans ( MonadTrans(..), MonadIO(..) )+import Control.Monad.Writer.Strict ( MonadWriter(..), WriterT(..),+ runWriter, execWriterT, execWriter,+ mapWriterT, censor, listens )+ import Data.Char (chr, ord) import Data.Maybe-import Control.Arrow hiding (loop, (<+>))-import Control.Monad-import Control.Applicative (Applicative(..), (<$>), (<$), (<**>))+import Data.Monoid+import Data.Foldable+import Data.Function ( on )+import Data.Traversable+import Data.Tuple.All -#if PARSEC_VERSION == 2+import Data.OptionalClass+import Data.Perhaps+import Util.Bogus+import Util.Viewable -import Text.ParserCombinators.Parsec (GenParser)--- | Parsec parsers are Applicatives, which lets us write slightly--- more pleasant, non-monadic-looking parsers-instance Applicative (GenParser a b) where- pure = return- (<*>) = ap-#endif+import qualified Data.Set as S+import qualified Data.List as L --- | Right-associative monadic fold-foldrM :: Monad m => (a -> b -> m a) -> a -> [b] -> m a-foldrM _ z [] = return z-foldrM f z (b:bs) = foldrM f z bs >>= flip f b+mapHead, mapTail, mapInit, mapLast ∷ Traversable t ⇒ (a → a) → t a → t a --- | Like 'Prelude.any' with a monadic predicate-anyM :: Monad m => (a -> m Bool) -> [a] -> m Bool-anyM p (x:xs) = do- b <- p x- if b- then return True- else anyM p xs-anyM _ _ = return False+mapHead f = snd . mapAccumL each True where+ each True x = (False, f x)+ each _ x = (False, x) --- | Like 'Prelude.all' with a monadic predicate-allM :: Monad m => (a -> m Bool) -> [a] -> m Bool-allM p = liftM not . anyM (liftM not . p)+mapTail f = snd . mapAccumL each True where+ each True x = (False, x)+ each _ x = (False, f x) --- | Two-list, monadic 'any'-anyM2 :: Monad m => (a -> b -> m Bool) -> [a] -> [b] -> m Bool-anyM2 p as bs = anyM (uncurry p) (zip as bs)+mapInit f = snd . mapAccumR each True where+ each True x = (False, x)+ each _ x = (False, f x) --- | Two-list, monadic 'all'-allM2 :: Monad m => (a -> b -> m Bool) -> [a] -> [b] -> m Bool-allM2 p as bs = allM (uncurry p) (zip as bs)+mapLast f = snd . mapAccumR each True where+ each True x = (False, f x)+ each _ x = (False, x) -concatMapM :: Monad m => (a -> m [b]) -> [a] -> m [b]-concatMapM f xs = concat `liftM` mapM f xs+-- | 'all' with an applicative predicate+allA ∷ (Applicative f, Foldable t) ⇒ (a → f Bool) → t a → f Bool+allA p xs = and <$> traverse p (toList xs) --- | Map an applicative over a list-mapA :: Applicative t => (a -> t b) -> [a] -> t [b]-mapA _ [] = pure []-mapA f (x:xs) = (:) <$> f x <*> mapA f xs+-- | 'any' with an applicative predicate+anyA ∷ (Applicative f, Foldable t) ⇒ (a → f Bool) → t a → f Bool+anyA p xs = or <$> traverse p (toList xs) +-- | Left-associative fold over two lists+foldl2 ∷ (Foldable t1, Foldable t2) ⇒+ (c → a → b → c) → c → t1 a → t2 b → c+foldl2 f z xs ys = foldl (uncurry . f) z (zip (toList xs) (toList ys))++-- | Right-associative fold over two lists+foldr2 ∷ (Foldable t1, Foldable t2) ⇒+ (a → b → c → c) → c → t1 a → t2 b → c+foldr2 f z xs ys = foldr (uncurry f) z (zip (toList xs) (toList ys))++-- | Two-list 'all'+all2 :: (Foldable f1, Foldable f2) ⇒+ (a -> b -> Bool) -> f1 a -> f2 b -> Bool+all2 p xs ys = and (zipWith p (toList xs) (toList ys))++-- | Two-list 'any'+any2 :: (Foldable f1, Foldable f2) ⇒+ (a -> b -> Bool) -> f1 a -> f2 b -> Bool+any2 p xs ys = or (zipWith p (toList xs) (toList ys))++-- | 'all' for two 'Foldable's with an applicative predicate+allA2 ∷ (Applicative f, Foldable t1, Foldable t2) ⇒+ (a → b → f Bool) → t1 a → t2 b → f Bool+allA2 p xs ys = allA id (zipWith p (toList xs) (toList ys))++-- | 'all' for two 'Foldable's with an applicative predicate+anyA2 ∷ (Applicative f, Foldable t1, Foldable t2) ⇒+ (a → b → f Bool) → t1 a → t2 b → f Bool+anyA2 p xs ys = anyA id (zipWith p (toList xs) (toList ys))++-- | Zip four lists+zip4 ∷ [a] → [b] → [c] → [d] → [(a, b, c, d)]+zip4 (a:as) (b:bs) (c:cs) (d:ds) = (a, b, c, d) : zip4 as bs cs ds+zip4 _ _ _ _ = []++-- | Zip five lists+zip5 ∷ [a] → [b] → [c] → [d] → [e] → [(a, b, c, d, e)]+zip5 (a:as) (b:bs) (c:cs) (d:ds) (e:es) = (a, b, c, d, e) : zip5 as bs cs ds es+zip5 _ _ _ _ _ = []++-- | Unzip four lists+unzip4 ∷ [(a, b, c, d)] → ([a], [b], [c], [d])+unzip4 = foldr (\(a,b,c,d) ~(as,bs,cs,ds) → (a:as,b:bs,c:cs,d:ds))+ ([],[],[],[])++-- | Unzip four lists+unzip5 ∷ [(a, b, c, d, e)] → ([a], [b], [c], [d], [e])+unzip5 = foldr (\(a,b,c,d,e) ~(as,bs,cs,ds,es) → (a:as,b:bs,c:cs,d:ds,e:es))+ ([],[],[],[],[])+ -- | Apply one function to the head of a list and another to the -- tail mapCons :: (a -> b) -> ([a] -> [b]) -> [a] -> [b] mapCons _ _ [] = [] mapCons fh ft (x:xs) = fh x : ft xs --- | Map a function over only the first element of a list-mapHead :: (a -> a) -> [a] -> [a]-mapHead f = mapCons f id+-- | Fold over a non-empty 'Foldable' in a monad+foldM1 ∷ (Foldable t, Monad m) ⇒ (a → a → m a) → t a → m a+foldM1 f xs0 = loop (toList xs0) where+ loop [] = fail "foldM1: empty"+ loop (x:xs) = foldM f x xs --- | Map a function over all but the first element of a list-mapTail :: (a -> a) -> [a] -> [a]-mapTail = mapCons id . map+-- | Like 'Data.List.lookup', but returns the index into the list as+-- well.+lookupWithIndex ∷ Eq a ⇒ a → [(a, b)] → Maybe (b, Int)+lookupWithIndex k = loop 0 where+ loop _ [] = Nothing+ loop !ix ((k',v):rest)+ | k == k' = Just (v, ix)+ | otherwise = loop (ix + 1) rest --- | Left-associative fold over two lists-foldl2 :: (c -> a -> b -> c) -> c -> [a] -> [b] -> c-foldl2 f z (x:xs) (y:ys) = foldl2 f (f z x y) xs ys-foldl2 _ z _ _ = z+-- | Safe version of '(Data.List.!!)'+listNth ∷ Int → [a] → Maybe a+listNth i = foldr (const . Just) Nothing . drop i --- | Right-associative fold over two lists-foldr2 :: (a -> b -> c -> c) -> c -> [a] -> [b] -> c-foldr2 f z (x:xs) (y:ys) = f x y (foldr2 f z xs ys)-foldr2 _ z _ _ = z+-- | Like nub, but O(n log n) instead of O(n^2)+ordNub ∷ Ord a ⇒ [a] → [a]+ordNub = loop S.empty where+ loop seen (x:xs)+ | x `S.member` seen = loop seen xs+ | otherwise = x : loop (S.insert x seen) xs+ loop _ [] = [] --- | Two-list 'all'-all2 :: (a -> b -> Bool) -> [a] -> [b] -> Bool-all2 p xs ys = and (zipWith p xs ys)+-- | Partition a list into the portions where the function returns+-- 'Just' and the portions where it returns 'Nothing'+partitionJust ∷ (a → Maybe b) → [a] → ([a], [b])+partitionJust f = foldr each ([], []) where+ each x (xs, ys) = case f x of+ Nothing → (x:xs, ys)+ Just y → (xs, y:ys) --- | Two-list 'any'-any2 :: (a -> b -> Bool) -> [a] -> [b] -> Bool-any2 p xs ys = or (zipWith p xs ys)+-- | Unfold a list, left-to-right, returning the final state+unscanr :: (b -> Maybe (a, b)) -> b -> ([a], b)+unscanr f b = case f b of+ Just (a, b') -> (a : fst rest, snd rest) where rest = unscanr f b'+ Nothing -> ([], b) +-- | Unfold a list, right-to-left, returning the final state+unscanl :: (b -> Maybe (a, b)) -> b -> ([a], b)+unscanl f = loop [] where+ loop acc b = case f b of+ Just (a, b') -> loop (a : acc) b'+ Nothing -> (acc, b)++-- | CPS version of 'map'+mapCont :: (a -> (b -> r) -> r) -> [a] -> ([b] -> r) -> r+mapCont _ [] k = k []+mapCont f (x:xs) k = f x $ \x' ->+ mapCont f xs $ \xs' ->+ k (x' : xs')++-- | CPS version of 'map_'+mapCont_ :: (a -> r -> r) -> [a] -> r -> r+mapCont_ _ [] k = k+mapCont_ f (x:xs) k = f x $ mapCont_ f xs $ k++whenM ∷ Monad m ⇒ m Bool → m () → m ()+whenM test branch = test >>= flip when branch++unlessM ∷ Monad m ⇒ m Bool → m () → m ()+unlessM test branch = test >>= flip unless branch++-- | Map and concatenate in a monad.+concatMapM ∷ (Foldable t, Monad m, Monoid b) ⇒ (a → m b) → t a → m b+concatMapM f = foldr (liftM2 mappend . f) (return mempty)++before ∷ Monad m ⇒ m a → (a → m b) → m a+before m k = do+ a ← m+ k a+ return a++infixl 8 `before`++mapListen2 ∷ Monad m ⇒ (a → m ((b, s), w)) → a → m ((b, w), s)+mapListen3 ∷ Monad m ⇒ (a → m ((b, s1, s2), w)) → a → m ((b, w), s1, s2)++mapListen2 mapper action = do+ ((b, s), w) ← mapper action+ return ((b, w), s)++mapListen3 mapper action = do+ ((b, s1, s2), w) ← mapper action+ return ((b, w), s1, s2)++fromOptA ∷ (Applicative f, Optional t) ⇒ f a → t a → f a+fromOptA def = foldOpt def pure++unEither ∷ Either a a → a+unEither = either id id+ -- | The ASCII value of a character char2integer :: Char -> Integer char2integer = fromIntegral . ord@@ -140,9 +307,8 @@ in ys : splitBy p (drop 1 zs) -- | Maybe cons, maybe not-(?:) :: Maybe a -> [a] -> [a]-Nothing ?: xs = xs-Just x ?: xs = x : xs+(?:) :: Optional t ⇒ t a -> [a] -> [a]+(?:) = foldOpt id (:) infixr 5 ?: @@ -152,45 +318,20 @@ isRight (Right _) = True isRight _ = False --- | Unfold a list, left-to-right, returning the final state-unscanr :: (b -> Maybe (a, b)) -> b -> ([a], b)-unscanr f b = case f b of- Just (a, b') -> (a : fst rest, snd rest) where rest = unscanr f b'- Nothing -> ([], b)---- | Unfold a list, right-to-left, returning the final state-unscanl :: (b -> Maybe (a, b)) -> b -> ([a], b)-unscanl f = loop [] where- loop acc b = case f b of- Just (a, b') -> loop (a : acc) b'- Nothing -> (acc, b)- -- | To combine two 'Ordering's in lexigraphic order thenCmp :: Ordering -> Ordering -> Ordering thenCmp EQ k2 = k2 thenCmp k1 _ = k1-infixr 4 `thenCmp` --- | 2nd order fmap-(<$$>) :: (Functor f, Functor g) => (a -> b) -> f (g a) -> f (g b)-(<$$>) = (<$>) . (<$>)---- | 3rd order fmap-(<$$$>) :: (Functor f, Functor g, Functor h) =>- (a -> b) -> f (g (h a)) -> f (g (h b))-(<$$$>) = (<$$>) . (<$>)---- | 4th order fmap-(<$$$$>) :: (Functor f, Functor g, Functor h, Functor j) =>- (a -> b) -> f (g (h (j a))) -> f (g (h (j b)))-(<$$$$>) = (<$$$>) . (<$>)---- | 5th order fmap-(<$$$$$>) :: (Functor f, Functor g, Functor h, Functor j, Functor k) =>- (a -> b) -> f (g (h (j (k a)))) -> f (g (h (j (k b))))-(<$$$$$>) = (<$$$$>) . (<$>)+-- | To combine two actions producing 'Ordering's in lexigraphic order+thenCmpM ∷ Monad m ⇒ m Ordering → m Ordering → m Ordering+thenCmpM m1 m2 = do+ ordering ← m1+ case ordering of+ EQ → m2+ _ → return ordering -infixl 4 <$$>, <$$$>, <$$$$>, <$$$$$>+infixr 4 `thenCmp`, `thenCmpM` -- | @flip fmap@ (>>!) :: Functor f => f a -> (a -> b) -> f b@@ -198,38 +339,133 @@ infixl 1 >>! --- | CPS version of 'map'-mapCont :: (a -> (b -> r) -> r) -> [a] -> ([b] -> r) -> r-mapCont _ [] k = k []-mapCont f (x:xs) k = f x $ \x' ->- mapCont f xs $ \xs' ->- k (x' : xs')+(<$$>) ∷ (Functor f, Functor g) ⇒ + (b → c) → g (f b) → g (f c)+(<$$>) = fmap . fmap --- | CPS version of 'map_'-mapCont_ :: (a -> r -> r) -> [a] -> r -> r-mapCont_ _ [] k = k-mapCont_ f (x:xs) k = f x $ mapCont_ f xs $ k+(<$$$>) ∷ (Functor f, Functor g, Functor h) ⇒+ (b → c) → h (g (f b)) →+ h (g (f c))+(<$$$>) = fmap . fmap . fmap --- | Generalize 'map' and 'sequence' to a few other monads-class GSequence m where- gsequence :: Monad m' => m (m' a) -> m' (m a)- gsequence_ :: Monad m' => m (m' a) -> m' ()- gsequence_ m = gsequence m >> return ()- gmapM :: (Monad m, Monad m') => (a -> m' b) -> m a -> m' (m b)- gmapM f = gsequence . liftM f- gmapM_ :: (Monad m, Monad m') => (a -> m' b) -> m a -> m' ()- gmapM_ f = gsequence_ . liftM f- gforM :: (Monad m, Monad m') => m a -> (a -> m' b) -> m' (m b)- gforM = flip gmapM- gforM_ :: (Monad m, Monad m') => m a -> (a -> m' b) -> m' ()- gforM_ = flip gmapM_+(<$$$$>) ∷ (Functor f, Functor g, Functor h, Functor i) ⇒+ (b → c) → i (h (g (f b))) →+ i (h (g (f c)))+(<$$$$>) = fmap . fmap . fmap . fmap -instance GSequence [] where- gsequence = sequence- gsequence_ = sequence_- gmapM = mapM- gmapM_ = mapM_+(<$$$$$>) ∷ (Functor f, Functor g, Functor h, Functor i, Functor j) ⇒+ (b → c) → j (i (h (g (f b)))) →+ j (i (h (g (f c))))+(<$$$$$>) = fmap . fmap . fmap . fmap . fmap -instance GSequence Maybe where- gsequence = maybe (return Nothing) (liftM return)- gsequence_ = maybe (return ()) (>> return ())+(<$$$$$$>) ∷ (Functor f, Functor g, Functor h,+ Functor i, Functor j, Functor k) ⇒+ (b → c) → k (j (i (h (g (f b))))) →+ k (j (i (h (g (f c)))))+(<$$$$$$>) = fmap . fmap . fmap . fmap . fmap . fmap++infixl 4 <$$>, <$$$>, <$$$$>, <$$$$$>, <$$$$$$>++(<$.>) ∷ (Arrow (⇝), Functor f) ⇒+ f (b ⇝ c) → (a ⇝ b) →+ f (a ⇝ c)+f <$.> g = (g >>>) <$> f++(<$$.>) ∷ (Arrow (⇝), Functor f, Functor g) ⇒+ g (f (b ⇝ c)) → (a ⇝ b) →+ g (f (a ⇝ c))+f <$$.> g = (g >>>) <$$> f++(<$$$.>) ∷ (Arrow (⇝), Functor f, Functor g, Functor h) ⇒+ h (g (f (b ⇝ c))) → (a ⇝ b) →+ h (g (f (a ⇝ c)))+f <$$$.> g = (g >>>) <$$$> f++(<$$$$.>) ∷ (Arrow (⇝), Functor f, Functor g, Functor h, Functor i) ⇒+ i (h (g (f (b ⇝ c)))) → (a ⇝ b) →+ i (h (g (f (a ⇝ c))))+f <$$$$.> g = (g >>>) <$$$$> f++infixl 4 <$.>, <$$.>, <$$$.>, <$$$$.>++(<->) ∷ Functor f ⇒ + f (a → b) → a → f b+f <-> x = ($ x) <$> f++(<-->) ∷ (Functor f, Functor g) ⇒+ f (g (a → b)) → a → f (g b)+f <--> x = (<-> x) <$> f++(<--->) ∷ (Functor f, Functor g, Functor h) ⇒+ f (g (h (a → b))) → a → f (g (h b))+f <---> x = (<--> x) <$> f++(<---->) ∷ (Functor f, Functor g, Functor h, Functor i) ⇒+ f (g (h (i (a → b)))) → a → f (g (h (i b)))+f <----> x = (<---> x) <$> f++(<----->) ∷ (Functor f, Functor g, Functor h, Functor i, Functor j) ⇒+ f (g (h (i (j (a → b))))) → a → f (g (h (i (j b))))+f <-----> x = (<----> x) <$> f++infixl 4 <->, <-->, <--->, <---->, <----->++class (Eq a, Foldable t) ⇒ SetLike t a where+ isEmptySet ∷ t a → Bool+ (∈), (∉) ∷ a → t a → Bool+ emptySet ∷ t a+ singleton ∷ a → t a+ --+ isEmptySet = null . toList+ a ∈ set = a `elem` toList set+ a ∉ set = not (a ∈ set)++class (SetLike t a, SetLike t' a) ⇒ SetLike2 t t' a where+ (⊆), (⊇), (/⊆), (/⊇), (/∩)+ ∷ t a → t' a → Bool+ (∪), (∩), (∖) ∷ t a → t' a → t a+ --+ set1 ⊆ set2 = all (∈ set2) set1+ set1 ⊇ set2 = all (∈ set1) set2+ set1 /⊆ set2 = not (set1 /⊆ set2)+ set1 /⊇ set2 = not (set1 /⊇ set2)+ set1 /∩ set2 = not (any (∈ set2) set1)++infix 4 ∈, ∉, ⊆, ⊇, /⊆, /⊇, /∩+infixl 6 ∪, ∖+infixl 7 ∩++instance Eq a ⇒ SetLike [] a where+ emptySet = []+ singleton a = [a]++instance Eq a ⇒ SetLike2 [] [] a where+ (∪) = L.union+ (∩) = L.intersect+ (∖) = (L.\\)++instance Ord a ⇒ SetLike2 [] S.Set a where+ (∪) = L.union <$.> toList+ (∩) = L.intersect <$.> toList+ (∖) = (L.\\) <$.> toList++instance Ord a ⇒ SetLike S.Set a where+ isEmptySet = S.null+ (∈) = S.member+ emptySet = S.empty+ singleton = S.singleton++instance Ord a ⇒ SetLike2 S.Set S.Set a where+ (⊆) = S.isSubsetOf+ set1 /∩ set2 = isEmptySet (set1 ∩ set2)+ (∪) = S.union+ (∩) = S.intersection+ (∖) = (S.\\)++instance Ord a ⇒ SetLike2 S.Set [] a where+ (⊆) = (⊆) <$.> S.fromList+ set1 ⊇ list2 = all (∈ set1) list2+ set1 /∩ list2 = all (∉ set1) list2+ (∪) = foldr S.insert+ (∩) = (∩) <$.> S.fromList+ (∖) = foldr S.delete
+ src/Util/Bogus.hs view
@@ -0,0 +1,41 @@+-- | Interface for producing bogus results, usually when an error+-- has occurred but we want to keep going to try to find more errors.+module Util.Bogus (+ Bogus(..), IsBogus(..),+) where++-- | A bogus value.+class Bogus a where+ bogus ∷ a++-- | Test for bogosity.+class Bogus a ⇒ IsBogus a where+ isBogus ∷ a → Bool++instance Bogus () where+ bogus = ()++instance Bogus (Maybe a) where+ bogus = Nothing++instance Bogus [a] where+ bogus = []++instance Bogus a ⇒ Bogus (Either a b) where+ bogus = Left bogus++instance IsBogus a ⇒ IsBogus (Either a b) where+ isBogus = either isBogus (const False)++instance (Bogus a, Bogus b) ⇒ Bogus (a, b) where+ bogus = (bogus, bogus)++instance (IsBogus a, IsBogus b) ⇒ IsBogus (a, b) where+ isBogus (a, b) = isBogus a && isBogus b++instance (Bogus a, Bogus b, Bogus c) ⇒ Bogus (a, b, c) where+ bogus = (bogus, bogus, bogus)++instance (IsBogus a, IsBogus b, IsBogus c) ⇒ IsBogus (a, b, c) where+ isBogus (a, b, c) = isBogus a && isBogus b && isBogus c+
+ src/Util/Eq1.hs view
@@ -0,0 +1,26 @@+{- Equality type classes for unary and binary type constructors. -}+module Util.Eq1 (+ Eq1(..), EQ1(..),+) where++import Data.IORef+import Data.STRef+import Control.Concurrent.STM.TVar++-- | Like 'Eq', but for unary type constructors.+class Eq1 t where+ eq1 ∷ t a → t a → Bool+ ne1 ∷ t a → t a → Bool+ x `ne1` y = not (x `eq1` y)++infix 4 `eq1`, `ne1`++instance Eq1 IORef where eq1 = (==)+instance Eq1 (STRef s) where eq1 = (==)+instance Eq1 TVar where eq1 = (==)++-- | Injection for using 'Eq': If @t@ is 'Eq1' then @EQ1 t a@ is 'Eq'+newtype EQ1 t a = EQ1 (t a)+instance Eq1 t ⇒ Eq1 (EQ1 t) where EQ1 x `eq1` EQ1 y = x `eq1` y+instance Eq1 t ⇒ Eq (EQ1 t a) where EQ1 x == EQ1 y = x `eq1` y+
+ src/Util/MonadRef.hs view
@@ -0,0 +1,122 @@+module Util.MonadRef (+ MonadRef(..),+ UnsafeReadRef(..),+) where++import Control.Monad.ST+import Control.Monad.STM++import Data.IORef+import Data.STRef+import Control.Concurrent.STM.TVar++import Control.Monad.Cont+import Control.Monad.Error+import Control.Monad.List+import Control.Monad.RWS.Strict as Strict+import Control.Monad.RWS.Lazy as Lazy+import Control.Monad.Reader+import Control.Monad.State.Strict as Strict+import Control.Monad.State.Lazy as Lazy+import Control.Monad.Writer.Strict as Strict+import Control.Monad.Writer.Lazy as Lazy++import System.IO.Unsafe++import Util.Eq1++-- | A class for monads with mutable references. Provides generic+-- operations for creating, reading, writing, and modifying+-- references.+class (UnsafeReadRef p, Monad m, Eq1 p) ⇒ MonadRef p m | m → p where+ newRef ∷ a → m (p a)+ readRef ∷ p a → m a+ writeRef ∷ p a → a → m ()+ modifyRef ∷ (a → a) → p a → m ()+ modifyRef f r = do+ a ← readRef r+ writeRef r (f a)++class UnsafeReadRef p where+ unsafeReadRef ∷ p a → a++---+--- Other MonadRef instances+---++instance MonadRef IORef IO where+ newRef = newIORef+ readRef = readIORef+ writeRef = writeIORef++instance UnsafeReadRef IORef where+ unsafeReadRef = unsafePerformIO . readRef++instance MonadRef (STRef s) (ST s) where+ newRef = newSTRef+ readRef = readSTRef+ writeRef = writeSTRef++instance UnsafeReadRef (STRef s) where+ unsafeReadRef = unsafePerformIO . unsafeSTToIO . readRef++instance MonadRef TVar STM where+ newRef = newTVar+ readRef = readTVar+ writeRef = writeTVar++instance UnsafeReadRef TVar where+ unsafeReadRef = unsafePerformIO . atomically . readRef++instance MonadRef p m ⇒ MonadRef p (ContT r m) where+ newRef a = lift $ newRef a+ readRef r = lift $ readRef r+ writeRef r a = lift $ writeRef r a++instance (Show e, Error e, MonadRef p m) ⇒ MonadRef p (ErrorT e m) where+ newRef a = lift $ newRef a+ readRef r = lift $ readRef r+ writeRef r a = lift $ writeRef r a++instance MonadRef p m ⇒ MonadRef p (ListT m) where+ newRef a = lift $ newRef a+ readRef r = lift $ readRef r+ writeRef r a = lift $ writeRef r a++instance (Monoid w, MonadRef p m) ⇒+ MonadRef p (Strict.RWST r w s m) where+ newRef a = lift $ newRef a+ readRef r = lift $ readRef r+ writeRef r a = lift $ writeRef r a++instance (Monoid w, MonadRef p m) ⇒+ MonadRef p (Lazy.RWST r w s m) where+ newRef a = lift $ newRef a+ readRef r = lift $ readRef r+ writeRef r a = lift $ writeRef r a++instance (MonadRef p m) ⇒ MonadRef p (ReaderT r m) where+ newRef a = lift $ newRef a+ readRef r = lift $ readRef r+ writeRef r a = lift $ writeRef r a++instance (MonadRef p m) ⇒ MonadRef p (Strict.StateT s m) where+ newRef a = lift $ newRef a+ readRef r = lift $ readRef r+ writeRef r a = lift $ writeRef r a++instance (MonadRef p m) ⇒ MonadRef p (Lazy.StateT s m) where+ newRef a = lift $ newRef a+ readRef r = lift $ readRef r+ writeRef r a = lift $ writeRef r a++instance (Monoid w, MonadRef p m) ⇒ MonadRef p (Strict.WriterT w m) where+ newRef a = lift $ newRef a+ readRef r = lift $ readRef r+ writeRef r a = lift $ writeRef r a++instance (Monoid w, MonadRef p m) ⇒ MonadRef p (Lazy.WriterT w m) where+ newRef a = lift $ newRef a+ readRef r = lift $ readRef r+ writeRef r a = lift $ writeRef r a+
+ src/Util/Trace.hs view
@@ -0,0 +1,268 @@+module Util.Trace (+ TraceIndent, MonadTrace(..),+ traceN, trace, traceLow,+ debugLevel, debug,+ --+ TraceT(..), runTraceT, mapTraceT,+ --+ TraceMessage(..),+ TracePpr(..), TraceNesting(..),+) where++import Util+import Syntax.PprClass as Ppr++import Prelude ()+import Data.IORef+import System.IO.Unsafe (unsafePerformIO)++{-# INLINE debugLevel #-}+debugLevel ∷ Int+debugLevel = 0++{-# INLINE debug #-}+debug ∷ Bool+debug = debugLevel > 0++type TraceIndent = Int++class Monad m ⇒ MonadTrace m where+ getTraceIndent ∷ m Int+ putTraceIndent ∷ Int → m ()+ modifyTraceIndent ∷ (Int → Int) → m ()+ modifyTraceIndent f = getTraceIndent >>= putTraceIndent . f+ putTraceString ∷ String → m ()+ putTraceString s = unsafePerformIO (putStr s) `seq` return ()++class TraceMessage a where+ pprTrace ∷ a → Doc+ pprTraceIndent ∷ a → Ordering+ pprTraceIndent = const EQ++{-# INLINE traceN #-}+traceN ∷ (TraceMessage a, MonadTrace m) ⇒ Int → a → m ()+traceN =+ if debug+ then \level →+ if debugLevel >= level+ then traceLow+ else \_ → return ()+ else \_ _ → return ()++{-# INLINE trace #-}+trace ∷ (TraceMessage a, MonadTrace m) ⇒ a → m ()+trace =+ if debug+ then traceLow+ else \_ → return ()++{-# INLINE traceLow #-}+traceLow ∷ (TraceMessage a, MonadTrace m) ⇒ a → m ()+traceLow a = do+ n0 ← getTraceIndent+ (n, brace) ← case pprTraceIndent a of+ LT → putTraceIndent (n0 - 2) >> return (n0 - 2, (char '}' Ppr.<+>))+ EQ → return (n0, id)+ GT → putTraceIndent (n0 + 2) >> return (n0, (Ppr.<+> char '{'))+ let doc = nest n (brace (pprTrace a))+ putTraceString (show doc ++ "\n")++---+--- MonadTrace instances+---++instance Monad m ⇒ MonadTrace (TraceT m) where+ putTraceIndent = TraceT . put+ getTraceIndent = TraceT get+ modifyTraceIndent = TraceT . modify++instance MonadTrace m ⇒ MonadTrace (ReaderT r m) where+ putTraceIndent = lift . putTraceIndent+ getTraceIndent = lift getTraceIndent+ modifyTraceIndent = lift . modifyTraceIndent++instance (MonadTrace m, Monoid w) ⇒ MonadTrace (WriterT w m) where+ putTraceIndent = lift . putTraceIndent+ getTraceIndent = lift getTraceIndent+ modifyTraceIndent = lift . modifyTraceIndent++instance MonadTrace m ⇒ MonadTrace (StateT s m) where+ putTraceIndent = lift . putTraceIndent+ getTraceIndent = lift getTraceIndent+ modifyTraceIndent = lift . modifyTraceIndent++instance (MonadTrace m, Monoid w) ⇒ MonadTrace (RWST r w s m) where+ putTraceIndent = lift . putTraceIndent+ getTraceIndent = lift getTraceIndent+ modifyTraceIndent = lift . modifyTraceIndent++instance MonadTrace m ⇒ MonadTrace (ListT m) where+ putTraceIndent = lift . putTraceIndent+ getTraceIndent = lift getTraceIndent+ modifyTraceIndent = lift . modifyTraceIndent++---+--- A transformer+---++newtype TraceT m a = TraceT { unTraceT ∷ StateT TraceIndent m a }+ deriving (Functor, Applicative, Monad, MonadTrans)++runTraceT ∷ Monad m ⇒ TraceT m a → m a+runTraceT = flip evalStateT 0 . unTraceT++mapTraceT ∷ Monad m ⇒+ (m a → m b) → TraceT m a → TraceT m b+mapTraceT f = TraceT . mapStateT f' . unTraceT where+ f' ma = do+ (a, indent) ← ma+ b ← f (return a)+ return (b, indent)++instance MonadReader r m ⇒ MonadReader r (TraceT m) where+ ask = lift ask+ local = mapTraceT . local++instance MonadWriter w m ⇒ MonadWriter w (TraceT m) where+ tell = lift . tell+ listen = mapTraceT listen+ pass = mapTraceT pass++instance MonadState s m ⇒ MonadState s (TraceT m) where+ get = lift get+ put = lift . put++instance MonadIO m ⇒ MonadIO (TraceT m) where+ liftIO = lift . liftIO++---+--- An instance for IO+---++{-# NOINLINE ioTraceIndent #-}+ioTraceIndent ∷ IORef TraceIndent+ioTraceIndent = unsafePerformIO (newIORef 0)++instance MonadTrace IO where+ getTraceIndent = readIORef ioTraceIndent+ putTraceIndent = writeIORef ioTraceIndent+ modifyTraceIndent = modifyIORef ioTraceIndent+ putTraceString = putStr++---+--- TraceMessage instances+---++newtype TracePpr a = TracePpr { unTracePpr ∷ a }++instance Ppr a ⇒ TraceMessage (TracePpr a) where+ pprTrace = ppr . unTracePpr++instance TraceMessage Doc where pprTrace = id++data TraceNesting a+ = TraceIn { unTraceNesting ∷ !a }+ | TraceOut { unTraceNesting ∷ !a }++instance TraceMessage String where+ pprTrace = Ppr.text . snd . pprDecomposeString+ pprTraceIndent = fst . pprDecomposeString++pprDecomposeString ∷ String → (Ordering, String)+pprDecomposeString ('}':s) = (LT, dropWhile (== ' ') s)+pprDecomposeString s = case reverse s of+ '{':s' → (GT, reverse (dropWhile (== ' ') s'))+ _ → (EQ, s)++instance TraceMessage a ⇒ TraceMessage (TraceNesting a) where+ pprTrace = pprTrace . unTraceNesting+ pprTraceIndent (TraceIn _) = GT+ pprTraceIndent (TraceOut _) = LT++instance (Ppr a, Ppr z)+ ⇒ TraceMessage (a,z) where+ pprTrace (a,z) = ppr a <> char '(' <> ppr z <> char ')'++instance (Ppr a, Ppr b, Ppr z)+ ⇒ TraceMessage (a,b,z) where+ pprTrace (a,b,z) =+ hang+ (ppr a <> char '(' <> p b)+ 4+ (fsep+ [+ ppr z <> char ')'])++instance (Ppr a, Ppr b, Ppr c, Ppr z)+ ⇒ TraceMessage (a,b,c,z) where+ pprTrace (a,b,c,z) =+ hang+ (ppr a <> char '(' <> p b)+ 4+ (fsep+ [p c,+ ppr z <> char ')'])++instance (Ppr a, Ppr b, Ppr c, Ppr d, Ppr z)+ ⇒ TraceMessage (a,b,c,d,z) where+ pprTrace (a,b,c,d,z) =+ hang+ (ppr a <> char '(' <> p b)+ 4+ (fsep+ [p c, p d,+ ppr z <> char ')'])++instance (Ppr a, Ppr b, Ppr c, Ppr d, Ppr e, Ppr z)+ ⇒ TraceMessage (a,b,c,d,e,z) where+ pprTrace (a,b,c,d,e,z) =+ hang+ (ppr a <> char '(' <> p b)+ 4+ (fsep+ [p c, p d, p e,+ ppr z <> char ')'])++instance (Ppr a, Ppr b, Ppr c, Ppr d, Ppr e, Ppr f, Ppr z)+ ⇒ TraceMessage (a,b,c,d,e,f,z) where+ pprTrace (a,b,c,d,e,f,z) =+ hang+ (ppr a <> char '(' <> p b)+ 4+ (fsep+ [p c, p d, p e, p f,+ ppr z <> char ')'])++instance (Ppr a, Ppr b, Ppr c, Ppr d, Ppr e, Ppr f, Ppr g, Ppr z)+ ⇒ TraceMessage (a,b,c,d,e,f,g,z) where+ pprTrace (a,b,c,d,e,f,g,z) =+ hang+ (ppr a <> char '(' <> p b)+ 4+ (fsep+ [p c, p d, p e, p f, p g,+ ppr z <> char ')'])++instance (Ppr a, Ppr b, Ppr c, Ppr d, Ppr e, Ppr f, Ppr g, Ppr h, Ppr z)+ ⇒ TraceMessage (a,b,c,d,e,f,g,h,z) where+ pprTrace (a,b,c,d,e,f,g,h,z) =+ hang+ (ppr a <> char '(' <> p b)+ 4+ (fsep+ [p c, p d, p e, p f, p g, p h,+ ppr z <> char ')'])++instance (Ppr a, Ppr b, Ppr c, Ppr d, Ppr e, Ppr f, Ppr g, Ppr h, Ppr i, Ppr z)+ ⇒ TraceMessage (a, b, c, d, e, f, g, h, i, z) where+ pprTrace (a,b,c,d,e,f,g,h,i,z) =+ hang+ (ppr a <> char '(' <> p b)+ 4+ (fsep+ [p c, p d, p e, p f, p g, p h, p i,+ ppr z <> char ')'])++-- Very common helper+p :: Ppr a => a -> Doc+p x = ppr x <> char ';'
+ src/Util/UndoIO.hs view
@@ -0,0 +1,77 @@+-- | An extension of the IO monad with an undo facility+module Util.UndoIO (+ -- * The 'UndoIO' monad+ UndoIO(..),+ -- ** Running+ runUndoIO, runUndoIO',+ -- ** Operation+ addUndo+) where++import Prelude hiding (catch)+import Util.MonadRef+import Control.Applicative+import Control.Exception+import Control.Monad.Error+import Control.Monad+import Control.Monad.Trans+import Data.IORef++-- | A layer on top of the IO monad with an undo facility.+newtype UndoIO a+ = UndoIO {+ unUndoIO ∷ IORef [IO ()] → IO a+ }+ deriving Functor++instance Applicative UndoIO where+ pure = return+ (<*>) = ap++instance Monad UndoIO where+ return = UndoIO . const . return+ m >>= k = UndoIO $ \undo → do+ a ← unUndoIO m undo+ unUndoIO (k a) undo++instance MonadIO UndoIO where+ liftIO = UndoIO . const++-- | Run an 'UndoIO' computation, running the undo list actions+-- if it raises an exception.+runUndoIO ∷ UndoIO a → IO a+runUndoIO action = do+ undo ← newRef []+ unUndoIO action undo `catch` \e → do+ sequence_ =<< readRef undo+ throwIO (e ∷ SomeException)++-- | Run an 'UndoIO' computation, without checking for an escaping+-- exception.+runUndoIO' ∷ UndoIO a → IO a+runUndoIO' action = unUndoIO action =<< newRef []++---+--- OPERATIONS+---++-- | Add an action to the front of the undo list+addUndo ∷ IO () → UndoIO ()+addUndo action = UndoIO (modifyRef (action :))++instance MonadRef IORef UndoIO where+ newRef = UndoIO . const . newRef+ readRef = UndoIO . const . readRef+ writeRef r a = modifyRef (const a) r+ modifyRef f r = UndoIO $ \undo → do+ old ← readRef r+ writeRef r (f old)+ modifyRef (writeRef r old :) undo++instance MonadError SomeException UndoIO where+ throwError = liftIO . throwIO+ catchError action handler = UndoIO $ \undo → do+ undo' ← newRef []+ unUndoIO action undo' `catch` \exn → do+ sequence_ =<< readRef undo'+ unUndoIO (handler exn) undo
+ src/Util/Viewable.hs view
@@ -0,0 +1,58 @@+{-# LANGUAGE TypeFamilies #-}+-- | Quick and dirty views+module Util.Viewable where++import Control.Arrow++import Data.Perhaps++-- | A viewable type has an associated type at which we view it, and+-- an operation to view it at that type.+--+-- Instances map view over lists, options, sums, and products+class Viewable a where+ type View a+ view :: a -> View a++-- | Wrapper type to hide from 'Viewable'. The view of+-- @HIDE a@ is @a@, rather than @View a@.+newtype HIDDEN a = HIDE { unHIDE :: a }++instance Viewable (HIDDEN a) where+ type View (HIDDEN a) = a+ view (HIDE a) = a++instance Viewable a => Viewable [a] where+ type View [a] = [View a]+ view = fmap view++instance Viewable a => Viewable (Maybe a) where+ type View (Maybe a) = Maybe (View a)+ view = fmap view++instance Viewable a => Viewable (Perhaps a) where+ type View (Perhaps a) = Perhaps (View a)+ view = fmap view++instance (Viewable a, Viewable b) => Viewable (Either a b) where+ type View (Either a b) = Either (View a) (View b)+ view = view +++ view++instance (Viewable a, Viewable b) => Viewable (a, b) where+ type View (a, b) = (View a, View b)+ view = view *** view++instance (Viewable a, Viewable b, Viewable c) =>+ Viewable (a, b, c) where+ type View (a, b, c) = (View a, View b, View c)+ view (a, b, c) = (view a, view b, view c)++instance (Viewable a, Viewable b, Viewable c, Viewable d) =>+ Viewable (a, b, c, d) where+ type View (a, b, c, d) = (View a, View b, View c, View d)+ view (a, b, c, d) = (view a, view b, view c, view d)++instance (Viewable a, Viewable b, Viewable c, Viewable d, Viewable e) =>+ Viewable (a, b, c, d, e) where+ type View (a, b, c, d, e) = (View a, View b, View c, View d, View e)+ view (a, b, c, d, e) = (view a, view b, view c, view d, view e)
src/Value.hs view
@@ -1,13 +1,4 @@ -- | The representation and embedding of values-{-# LANGUAGE- DeriveDataTypeable,- ExistentialQuantification,- FlexibleInstances,- MultiParamTypeClasses,- PatternGuards,- RankNTypes,- ScopedTypeVariables- #-} module Value ( -- * Value and function representation Valuable(..), FunName(..), Value(..),@@ -18,6 +9,8 @@ Vinj(..), VExn(..), -- *** Exception IDs ExnId(..),+ -- ** Records+ VRecord(..), -- * Utilities for algebraic data types enumTypeDecl,@@ -29,17 +22,18 @@ import Data.Generics import Util-import Syntax (Uid(..), Type, Renamed, uid)-import Ppr (Doc, text, Ppr(..), hang, sep, char, (<>), (<+>),+import AST (Type, Renamed, Id(..), Uid, ConId, uidToLid)+import Syntax.Ppr (Doc, text, Ppr(..), hang, sep, char, (<>), (<+>), prec, prec1, ppr1, atPrec, precCom, precApp)+import qualified Syntax.Ppr as Ppr import qualified Control.Exception as Exn +import qualified Control.Monad as C.M+import Prelude () import Foreign.C.Types (CInt) import Data.Word (Word32, Word16) -import Control.Monad.State as M.S- -- | The kind of identifiers used type R = Renamed @@ -90,23 +84,20 @@ -- by 'Show' for printing 'String's differently than other -- lists.) vpprList :: [a] -> Doc- vpprList [] = text "nil"- vpprList (x:xs) = prec precApp $ prec1 $- hang (text "cons" <+> vppr x)- 1- (vpprList xs)+ vpprList =+ Ppr.brackets . atPrec 0 . Ppr.fsep . Ppr.punctuate Ppr.comma . map vppr -- | Inject a list. As with the above, this lets us special-case -- lists at some types (e.g. we inject Haskell 'String' as object -- language @string@ rather than @char list@) vinjList :: [a] -> Value- vinjList [] = VaCon (uid "Nil") Nothing- vinjList (x:xs) = VaCon (uid "Cons") (Just (vinj (x, xs)))+ vinjList [] = VaCon (ident "[]") Nothing+ vinjList (x:xs) = VaCon (ident "::") (Just (vinj (x, xs))) -- | Project a list. (Same deal.) vprjListM :: Monad m => Value -> m [a]- vprjListM (VaCon (Uid _ "Nil") Nothing) = return []- vprjListM (VaCon (Uid _ "Cons") (Just v)) = do+ vprjListM (VaCon (idName -> "[]") Nothing) = return []+ vprjListM (VaCon (idName -> "::") (Just v)) = do (x, xs) <- vprjM v return (x:xs) vprjListM _ = fail "vprjM: not a list"@@ -129,7 +120,10 @@ -- | A function = VaFun FunName (Value -> IO Value) -- | A datacon, potentially applied- | VaCon (Uid R) (Maybe Value)+ | VaCon (ConId R) (Maybe Value)+ -- | An open variant injection or embedding. The 'Int' gives the+ -- number of embeddings of the label+ | VaLab Int (Uid R) Value -- | Any other embeddable Haskell type | forall a. Valuable a => VaDyn a deriving Typeable@@ -198,27 +192,37 @@ instance Valuable () where veq = (==)- vinj () = VaCon (uid "()") Nothing- vprjM (VaCon (Uid _ "()") _) = return ()- vprjM _ = fail "vprjM: not a unit"+ vinj () = VaCon (ident "()") Nothing+ vprjM (VaCon (idName -> "()") _) = return ()+ vprjM _ = fail "vprjM: not a unit" instance Valuable Bool where veq = (==)- vinj True = VaCon (uid "true") Nothing- vinj False = VaCon (uid "false") Nothing- vprjM (VaCon (Uid _ "true") _) = return True- vprjM (VaCon (Uid _ "false") _) = return False- vprjM _ = fail "vprjM: not a bool"+ vinj True = VaCon (ident "true") Nothing+ vinj False = VaCon (ident "false") Nothing+ vprjM (VaCon (idName -> "true") _) = return True+ vprjM (VaCon (idName -> "false") _) = return False+ vprjM _ = fail "vprjM: not a bool" instance Valuable Value where vinj v = v veq (VaCon c v) (VaCon d w) = c == d && v == w+ veq (VaLab n c v) (VaLab m d w)+ = n == m && c == d && v == w veq (VaDyn a) b = veqDyn a b veq _ _ = False+ vppr v | Just vs ← vprjM v = vppr (vs ∷ [Value]) vppr (VaFun n _) = ppr n vppr (VaCon c Nothing) = ppr c vppr (VaCon c (Just v)) = prec precApp $ ppr c <+> ppr1 v+ vppr (VaLab 0 c v)+ | v == vinj () = char '`' <> ppr c+ | otherwise = prec precApp $+ char '`' <> ppr c <+> ppr1 v+ vppr (VaLab z c v) = prec precApp $+ char '#' <> ppr c <+>+ ppr1 (VaLab (z - 1) c v) vppr (VaDyn v) = vppr v -- for value debugging: {-@@ -253,22 +257,22 @@ veq (Right b) (Right b') = veq b b' veq (Left _) (Right _) = False veq (Right _) (Left _) = False- vinj (Left v) = VaCon (uid "Left") (Just (vinj v))- vinj (Right v) = VaCon (uid "Right") (Just (vinj v))- vprjM (VaCon (Uid _ "Left") (Just v)) = liftM Left (vprjM v)- vprjM (VaCon (Uid _ "Right") (Just v)) = liftM Right (vprjM v)- vprjM _ = fail "vprjM: not a sum"+ vinj (Left v) = VaCon (ident "Left") (Just (vinj v))+ vinj (Right v) = VaCon (ident "Right") (Just (vinj v))+ vprjM (VaCon (idName -> "Left") (Just v)) = liftM Left (vprjM v)+ vprjM (VaCon (idName -> "Right") (Just v)) = liftM Right (vprjM v)+ vprjM _ = fail "vprjM: not a sum" instance Valuable a => Valuable (Maybe a) where veq (Just a) (Just a') = veq a a' veq Nothing Nothing = True veq (Just _) Nothing = False veq Nothing (Just _) = False- vinj (Just v) = VaCon (uid "Some") (Just (vinj v))- vinj Nothing = VaCon (uid "None") Nothing- vprjM (VaCon (Uid _ "Some") (Just v)) = liftM Just (vprjM v)- vprjM (VaCon (Uid _ "None") Nothing) = return Nothing- vprjM _ = fail "vprjM: not an option"+ vinj (Just v) = VaCon (ident "Some") (Just (vinj v))+ vinj Nothing = VaCon (ident "None") Nothing+ vprjM (VaCon (idName -> "Some") (Just v)) = liftM Just (vprjM v)+ vprjM (VaCon (idName -> "None") Nothing) = return Nothing+ vprjM _ = fail "vprjM: not an option" -- | Type for injection of arbitrary Haskell values with -- minimal functionality@@ -301,7 +305,7 @@ -- | Exception identity, generated dynamically data ExnId i = ExnId {- eiName :: Uid i,+ eiName :: ConId i, eiParam :: Maybe (Type i) } deriving (Typeable, Data)@@ -309,6 +313,39 @@ instance Eq (ExnId Renamed) where ei == ei' = eiName ei == eiName ei' +--+-- Representation of records+--++data VRecord+ = AdditiveRecord [(Uid Renamed, (IO Value, Doc))]+ | MultiplicativeRecord [(Uid Renamed, Value)]+ deriving Typeable++instance Valuable VRecord where+ veq (MultiplicativeRecord kvs0) (MultiplicativeRecord kvs0') =+ loop (sortFst kvs0) (sortFst kvs0')+ where+ sortFst = List.sortBy (compare`on`fst)+ loop [] [] = True+ loop ((k,v):kvs) ((k',v'):kvs') = k == k' && veq v v' && loop kvs kvs'+ loop _ _ = False+ veq _ _ = False+ vppr record =+ case record of+ AdditiveRecord kvs → finish "{+" ((fst &&& snd . snd) <$> kvs) "+}"+ MultiplicativeRecord kvs → finish "{" (second vppr <$> kvs) "}"+ where+ finish lb [] rb = text lb <> text rb+ finish lb kvs rb =+ text lb <+> Ppr.fsep (Ppr.punctuate (char ',')+ [ ppr (show (uidToLid k)) <+> char '=' <+> ppr v+ | (k, v) ← kvs ])+ <+> text rb++instance Ppr VRecord where ppr = vppr+instance Show VRecord where showsPrec = Ppr.showFromPpr+ -- nasty syb stuff isString :: Data a => a -> Bool@@ -335,7 +372,7 @@ c:cs -> Char.toLower c : cs _ -> error "(BUG!) bad type name in enumTypeDecl" -newtype Const a b = Const { unConst :: a }+newtype CONST a b = CONST { unCONST :: a } -- | Use SYB to attempt to inject a value of a Haskell data type into -- an object language value matching the type declaration generated@@ -356,21 +393,21 @@ AlgConstr _ | Just s <- cast datum -> vinj (s :: String)- | otherwise -> c (unConst (gfoldl k z datum))+ | otherwise -> c (unCONST (gfoldl k z datum)) where r = toConstr datum- k (Const Nothing) x = Const (Just (vinjData x))- k (Const (Just v)) x = Const (Just (vinj (v, vinjData x)))- z = const (Const Nothing)+ k (CONST Nothing) x = CONST (Just (vinjData x))+ k (CONST (Just v)) x = CONST (Just (vinj (v, vinjData x)))+ z = const (CONST Nothing) c f = case (showConstr r, f) of (s, Just f') | isTuple s -> f'- _ -> VaCon (uid (showConstr r)) f+ _ -> VaCon (ident (showConstr r)) f -- | The partial inverse of 'vinjData' vprjDataM :: forall a m. (Data a, Monad m) => Value -> m a vprjDataM = generic- `ext1RT` (\x -> vprjM x >>= sequence . liftM vprjDataM)+ `ext1RT` (\x -> vprjM x >>= C.M.sequence . liftM vprjDataM) `ext1RT` (\x -> vprjM x >>= maybe (return Nothing) (liftM return) . liftM vprjDataM) `extRT` (vprjM :: Value -> m Int)@@ -384,29 +421,29 @@ `extRT` (vprjM :: Value -> m Bool) `extRT` (vprjM :: Value -> m Char) where- generic (VaCon (Uid _ u) mfields0) = case readConstr ty u of+ generic (VaCon (idName -> u) mfields0) = case readConstr ty u of Nothing -> fail $ "(BUG) Couldn't find constructor: " ++ u ++ " in " ++ show ty- Just c -> M.S.evalStateT (gunfold k z c) mfields0+ Just c -> evalStateT (gunfold k z c) mfields0 where k consmaker = do- mfields <- M.S.get+ mfields <- get fields <- case mfields of Just fields -> return fields Nothing -> fail "(BUG) ran out of fields" field <- case vprjM fields of Just (fields', field) -> do- M.S.put (Just fields')+ put (Just fields') return field Nothing -> do- M.S.put Nothing+ put Nothing return fields make <- consmaker- mrest <- M.S.get+ mrest <- get field' <- case mrest of Just rest -> do- M.S.put Nothing+ put Nothing return (vinj (rest, field)) Nothing -> return field@@ -415,7 +452,7 @@ z = return generic v@(VaDyn _) = case dataTypeRep ty of AlgRep (c:_) | t <- showConstr c, isTuple t- -> generic (VaCon (uid t) (Just v))+ -> generic (VaCon (ident t) (Just v)) IntRep | Just i <- vprjM v, Just d <- cast (i :: Integer) -> return d
− src/Viewable.hs
@@ -1,52 +0,0 @@--- | Quick and dirty views-{-# LANGUAGE TypeFamilies #-}-module Viewable where--import Util---- | A viewable type has an associated type at which we view it, and--- an operation to view it at that type.------ Instances map view over lists, options, sums, and products-class Viewable a where- type View a- view :: a -> View a---- | Wrapper type to hide from 'Viewable'. The view of--- @HIDE a@ is @a@, rather than @View a@.-newtype HIDDEN a = HIDE { unHIDE :: a }--instance Viewable (HIDDEN a) where- type View (HIDDEN a) = a- view (HIDE a) = a--instance Viewable a => Viewable [a] where- type View [a] = [View a]- view = fmap view--instance Viewable a => Viewable (Maybe a) where- type View (Maybe a) = Maybe (View a)- view = fmap view--instance (Viewable a, Viewable b) => Viewable (Either a b) where- type View (Either a b) = Either (View a) (View b)- view = view +++ view--instance (Viewable a, Viewable b) => Viewable (a, b) where- type View (a, b) = (View a, View b)- view = view *** view--instance (Viewable a, Viewable b, Viewable c) =>- Viewable (a, b, c) where- type View (a, b, c) = (View a, View b, View c)- view (a, b, c) = (view a, view b, view c)--instance (Viewable a, Viewable b, Viewable c, Viewable d) =>- Viewable (a, b, c, d) where- type View (a, b, c, d) = (View a, View b, View c, View d)- view (a, b, c, d) = (view a, view b, view c, view d)--instance (Viewable a, Viewable b, Viewable c, Viewable d, Viewable e) =>- Viewable (a, b, c, d, e) where- type View (a, b, c, d, e) = (View a, View b, View c, View d, View e)- view (a, b, c, d, e) = (view a, view b, view c, view d, view e)
+ src/extensions.txt view
@@ -0,0 +1,24 @@+BangPatterns+CPP+DeriveDataTypeable+DeriveFunctor+EmptyDataDecls+ExistentialQuantification+FlexibleContexts+FlexibleInstances+FunctionalDependencies+GeneralizedNewtypeDeriving+MultiParamTypeClasses+ParallelListComp+PatternGuards+QuasiQuotes+RankNTypes+ScopedTypeVariables+StandaloneDeriving+TemplateHaskell+TupleSections+TypeOperators+TypeSynonymInstances+UndecidableInstances+UnicodeSyntax+ViewPatterns