purescript 0.1.0 → 0.1.1
raw patch · 57 files changed
+2819/−2811 lines, 57 files
Files
- purescript.cabal +34/−18
- src/Language/PureScript.hs +26/−0
- src/Language/PureScript/CodeGen.hs +18/−0
- src/Language/PureScript/CodeGen/Externs.hs +35/−0
- src/Language/PureScript/CodeGen/JS.hs +232/−0
- src/Language/PureScript/CodeGen/Monad.hs +31/−0
- src/Language/PureScript/Declarations.hs +39/−0
- src/Language/PureScript/Kinds.hs +25/−0
- src/Language/PureScript/Names.hs +26/−0
- src/Language/PureScript/Parser.hs +22/−0
- src/Language/PureScript/Parser/Common.hs +181/−0
- src/Language/PureScript/Parser/Declarations.hs +100/−0
- src/Language/PureScript/Parser/Kinds.hs +41/−0
- src/Language/PureScript/Parser/State.hs +27/−0
- src/Language/PureScript/Parser/Types.hs +91/−0
- src/Language/PureScript/Parser/Values.hs +292/−0
- src/Language/PureScript/Pretty.hs +22/−0
- src/Language/PureScript/Pretty/Common.hs +80/−0
- src/Language/PureScript/Pretty/Kinds.hs +50/−0
- src/Language/PureScript/Pretty/Types.hs +95/−0
- src/Language/PureScript/Pretty/Values.hs +185/−0
- src/Language/PureScript/TypeChecker.hs +96/−0
- src/Language/PureScript/TypeChecker/Kinds.hs +182/−0
- src/Language/PureScript/TypeChecker/Monad.hs +67/−0
- src/Language/PureScript/TypeChecker/Synonyms.hs +56/−0
- src/Language/PureScript/TypeChecker/Types.hs +624/−0
- src/Language/PureScript/Types.hs +43/−0
- src/Language/PureScript/Values.hs +97/−0
- src/Main.hs +1/−1
- src/PureScript.hs +0/−26
- src/PureScript/CodeGen.hs +0/−21
- src/PureScript/CodeGen/Common.hs +0/−80
- src/PureScript/CodeGen/Common/Gen.hs +0/−31
- src/PureScript/CodeGen/Externs.hs +0/−36
- src/PureScript/CodeGen/JS.hs +0/−232
- src/PureScript/CodeGen/Pretty/Kinds.hs +0/−50
- src/PureScript/CodeGen/Pretty/Types.hs +0/−95
- src/PureScript/CodeGen/Pretty/Values.hs +0/−185
- src/PureScript/Declarations.hs +0/−39
- src/PureScript/Kinds.hs +0/−25
- src/PureScript/Names.hs +0/−26
- src/PureScript/Parser.hs +0/−22
- src/PureScript/Parser/Common.hs +0/−181
- src/PureScript/Parser/Declarations.hs +0/−100
- src/PureScript/Parser/Kinds.hs +0/−41
- src/PureScript/Parser/State.hs +0/−27
- src/PureScript/Parser/Types.hs +0/−91
- src/PureScript/Parser/Values.hs +0/−292
- src/PureScript/Pretty.hs +0/−22
- src/PureScript/TypeChecker.hs +0/−96
- src/PureScript/TypeChecker/Kinds.hs +0/−183
- src/PureScript/TypeChecker/Monad.hs +0/−67
- src/PureScript/TypeChecker/Synonyms.hs +0/−56
- src/PureScript/TypeChecker/Types.hs +0/−626
- src/PureScript/Types.hs +0/−43
- src/PureScript/Values.hs +0/−97
- tests/Main.hs +1/−2
purescript.cabal view
@@ -1,5 +1,5 @@ name: purescript-version: 0.1.0+version: 0.1.1 cabal-version: >=1.8 build-type: Simple license: MIT@@ -11,28 +11,45 @@ description: A small compile-to-JS language with extensible records and type-safe blocks author: Phil Freeman <paf31@cantab.net> data-dir: ""- +category: Language+ library build-depends: base >=4 && <5, syb -any, cmdtheline -any, containers -any, mtl -any, transformers -any, parsec -any, utf8-string -any- exposed-modules: PureScript.CodeGen.Pretty.Values- PureScript.CodeGen.Pretty.Types PureScript PureScript.Declarations- PureScript.Names PureScript.TypeChecker.Synonyms- PureScript.CodeGen.Externs PureScript.CodeGen.JS- PureScript.CodeGen.Common.Gen PureScript.CodeGen.Common Main- PureScript.CodeGen PureScript.Kinds PureScript.Parser- PureScript.TypeChecker PureScript.Types PureScript.Values- PureScript.Parser.Common PureScript.Parser.Declarations- PureScript.Parser.Types PureScript.Parser.Values- PureScript.TypeChecker.Kinds PureScript.TypeChecker.Monad- PureScript.TypeChecker.Types PureScript.Parser.State- PureScript.Parser.Kinds PureScript.CodeGen.Pretty.Kinds+ exposed-modules: Main+ Language.PureScript+ Language.PureScript.Declarations+ Language.PureScript.Names+ Language.PureScript.Types+ Language.PureScript.Values+ Language.PureScript.Kinds+ Language.PureScript.Pretty+ Language.PureScript.Pretty.Common+ Language.PureScript.Pretty.Values+ Language.PureScript.Pretty.Types+ Language.PureScript.Pretty.Kinds+ Language.PureScript.CodeGen+ Language.PureScript.CodeGen.Externs+ Language.PureScript.CodeGen.JS+ Language.PureScript.CodeGen.Monad+ Language.PureScript.Parser+ Language.PureScript.Parser.Common+ Language.PureScript.Parser.Declarations+ Language.PureScript.Parser.Types+ Language.PureScript.Parser.Values+ Language.PureScript.Parser.State+ Language.PureScript.Parser.Kinds+ Language.PureScript.TypeChecker+ Language.PureScript.TypeChecker.Kinds+ Language.PureScript.TypeChecker.Monad+ Language.PureScript.TypeChecker.Types+ Language.PureScript.TypeChecker.Synonyms exposed: True buildable: True hs-source-dirs: src- other-modules: PureScript.Pretty- + other-modules:+ executable psc build-depends: base >=4 && <5, cmdtheline -any, containers -any, mtl -any, transformers -any, parsec -any, utf8-string -any,@@ -40,8 +57,7 @@ main-is: Main.hs buildable: True hs-source-dirs: src- other-modules: PureScript.Pretty- + test-suite tests build-depends: base >=4 && <5, syb -any, directory -any, filepath -any, containers -any, mtl -any, transformers -any,
+ src/Language/PureScript.hs view
@@ -0,0 +1,26 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++module Language.PureScript (module P) where++import Language.PureScript.Values as P+import Language.PureScript.Types as P+import Language.PureScript.Kinds as P+import Language.PureScript.Declarations as P+import Language.PureScript.Names as P+import Language.PureScript.Parser as P+import Language.PureScript.CodeGen as P+import Language.PureScript.TypeChecker as P+import Language.PureScript.Pretty as P+
+ src/Language/PureScript/CodeGen.hs view
@@ -0,0 +1,18 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.CodeGen+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++module Language.PureScript.CodeGen (module C) where++import Language.PureScript.CodeGen.JS as C+import Language.PureScript.CodeGen.Externs as C
+ src/Language/PureScript/CodeGen/Externs.hs view
@@ -0,0 +1,35 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.CodeGen.Externs+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++module Language.PureScript.CodeGen.Externs (+ externToPs+) where++import Data.List (intercalate)+import qualified Data.Map as M+import Language.PureScript.Declarations+import Language.PureScript.TypeChecker.Monad+import Language.PureScript.Pretty++externToPs :: Environment -> Declaration -> Maybe String+externToPs env (ValueDeclaration name _) = do+ (ty, _) <- M.lookup name $ names env+ return $ "extern " ++ show name ++ " :: " ++ prettyPrintPolyType ty+externToPs env (ExternDeclaration name ty) =+ return $ "extern " ++ show name ++ " :: " ++ prettyPrintPolyType ty+externToPs env (ExternDataDeclaration name kind) =+ return $ "extern data " ++ name ++ " :: " ++ prettyPrintKind kind+externToPs env (TypeSynonymDeclaration name args ty) =+ return $ "type " ++ name ++ " " ++ unwords args ++ " = " ++ prettyPrintType ty+externToPs _ _ = Nothing
+ src/Language/PureScript/CodeGen/JS.hs view
@@ -0,0 +1,232 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.CodeGen.JS+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++module Language.PureScript.CodeGen.JS (+ declToJs+) where++import Data.Char+import Data.Maybe (fromMaybe)+import Data.List (intercalate)+import qualified Control.Arrow as A+import Control.Arrow ((<+>))+import Control.Monad (forM)+import Control.Applicative++import Language.PureScript.Types+import Language.PureScript.Values+import Language.PureScript.Names+import Language.PureScript.Declarations+import Language.PureScript.Pretty.Common+import Language.PureScript.CodeGen.Monad++declToJs :: Declaration -> Maybe String+declToJs (ValueDeclaration ident (Abs args ret)) = Just $ "function " ++ identToJs ident ++ "(" ++ intercalate "," (map identToJs args) ++ ") { return " ++ valueToJs ret ++ "; }"+declToJs (ValueDeclaration ident val) = Just $ "var " ++ identToJs ident ++ " = " ++ valueToJs val ++ ";"+declToJs (DataDeclaration _ _ ctors) =+ Just $ flip concatMap ctors $ \(ctor, maybeTy) ->+ case maybeTy of+ Nothing -> "var " ++ ctor ++ " = { ctor: '" ++ ctor ++ "' };"+ Just _ -> "var " ++ ctor ++ " = function (value) { return { ctor: '" ++ ctor ++ "', value: value }; };"+declToJs _ = Nothing++literals :: Pattern Value String+literals = Pattern $ A.Kleisli match+ where+ match (NumericLiteral n) = Just $ either show show n+ match (StringLiteral s) = Just $ show s+ match (BooleanLiteral True) = Just "true"+ match (BooleanLiteral False) = Just "false"+ match (ArrayLiteral xs) = Just $ "[" ++ intercalate "," (map valueToJs xs) ++ "]"+ match (ObjectLiteral ps) = Just $ "{" ++ intercalate "," (map objectPropertyToJs ps) ++ "}"+ match (ObjectUpdate o ps) = Just $ "Object.extend("+ ++ valueToJs o ++ ", { "+ ++ intercalate ", " (map objectPropertyToJs ps) ++ " }"+ match (Constructor name) = Just name+ match (Block sts) = Just $ "(function () {" ++ intercalate ";" (map statementToJs sts) ++ "})()"+ match (Case value binders) = Just $ "(" ++ runGen (bindersToJs binders) ++ ")(" ++ valueToJs value ++ ")"+ where+ bindersToJs :: [(Binder, Value)] -> Gen String+ bindersToJs binders = do+ valName <- fresh+ jss <- forM binders $ \(binder, result) -> do+ let js = valueToJs result+ binderToJs valName ("return " ++ js ++ ";") binder+ return $ "function (" ++ valName ++ ") {" ++ concat jss ++ "throw \"Failed pattern match\"; }"+ match (Var ident) = Just (identToJs ident)+ match _ = Nothing++ifThenElse :: Pattern Value ((Value, Value), Value)+ifThenElse = Pattern $ A.Kleisli match+ where+ match (IfThenElse cond th el) = Just ((th, el), cond)+ match _ = Nothing++accessor :: Pattern Value (String, Value)+accessor = Pattern $ A.Kleisli match+ where+ match (Accessor prop val) = Just (prop, val)+ match _ = Nothing++indexer :: Pattern Value (String, Value)+indexer = Pattern $ A.Kleisli match+ where+ match (Indexer index val) = Just (valueToJs index, val)+ match _ = Nothing++app :: Pattern Value (String, Value)+app = Pattern $ A.Kleisli match+ where+ match (App val args) = Just (intercalate "," (map valueToJs args), val)+ match _ = Nothing++lam :: Pattern Value ([String], Value)+lam = Pattern $ A.Kleisli match+ where+ match (Abs args val) = Just (map identToJs args, val)+ match _ = Nothing++unary :: UnaryOperator -> String -> Operator Value String+unary op str = Wrap pattern (++)+ where+ pattern :: Pattern Value (String, Value)+ pattern = Pattern $ A.Kleisli match+ where+ match (Unary op' val) | op' == op = Just (str, val)+ match _ = Nothing++binary :: BinaryOperator -> String -> Operator Value String+binary op str = AssocR pattern (\v1 v2 -> v1 ++ " " ++ str ++ " " ++ v2)+ where+ pattern :: Pattern Value (Value, Value)+ pattern = Pattern $ A.Kleisli match+ where+ match (Binary op' v1 v2) | op' == op = Just (v1, v2)+ match _ = Nothing++valueToJs :: Value -> String+valueToJs = fromMaybe (error "Incomplete pattern") . pattern matchValue+ where+ matchValue :: Pattern Value String+ matchValue = buildPrettyPrinter operators (literals <+> fmap parens matchValue)+ operators :: OperatorTable Value String+ operators =+ OperatorTable [ [ Wrap accessor $ \prop val -> val ++ "." ++ prop ]+ , [ Wrap indexer $ \index val -> val ++ "[" ++ index ++ "]" ]+ , [ Wrap app $ \args val -> val ++ "(" ++ args ++ ")" ]+ , [ Split lam $ \args val -> "function (" ++ intercalate "," args ++ ") { return " ++ valueToJs val ++ "; }" ]+ , [ Wrap ifThenElse $ \(th, el) cond -> cond ++ " ? " ++ valueToJs th ++ " : " ++ valueToJs el ]+ , [ binary LessThan "<" ]+ , [ binary LessThanOrEqualTo "<=" ]+ , [ binary GreaterThan ">" ]+ , [ binary GreaterThanOrEqualTo ">=" ]+ , [ unary Not "!" ]+ , [ unary BitwiseNot "~" ]+ , [ unary Negate "-" ]+ , [ binary Multiply "*" ]+ , [ binary Divide "/" ]+ , [ binary Modulus "%" ]+ , [ binary Concat "+" ]+ , [ binary Add "+" ]+ , [ binary Subtract "-" ]+ , [ binary ShiftLeft "<<" ]+ , [ binary ShiftRight ">>" ]+ , [ binary ZeroFillShiftRight ">>>" ]+ , [ binary EqualTo "===" ]+ , [ binary NotEqualTo "!==" ]+ , [ binary BitwiseAnd "&" ]+ , [ binary BitwiseXor "^" ]+ , [ binary BitwiseOr "|" ]+ , [ binary And "&&" ]+ , [ binary Or "||" ]+ ]++binderToJs :: String -> String -> Binder -> Gen String+binderToJs varName done NullBinder = return done+binderToJs varName done (StringBinder str) =+ return $ "if (" ++ varName ++ " === \"" ++ str ++ "\") {" ++ done ++ " }"+binderToJs varName done (NumberBinder num) =+ return $ "if (" ++ varName ++ " === " ++ either show show num ++ ") {" ++ done ++ " }"+binderToJs varName done (BooleanBinder True) =+ return $ "if (" ++ varName ++ ") {" ++ done ++ " }"+binderToJs varName done (BooleanBinder False) =+ return $ "if (!" ++ varName ++ ") {" ++ done ++ " }"+binderToJs varName done (VarBinder ident) =+ return $ "var " ++ identToJs ident ++ " = " ++ varName ++ "; " ++ done+binderToJs varName done (NullaryBinder ctor) =+ return $ "if (" ++ varName ++ ".ctor === \"" ++ ctor ++ "\") { " ++ done ++ " }"+binderToJs varName done (UnaryBinder ctor b) = do+ value <- fresh+ js <- binderToJs value done b+ return $ "if (" ++ varName ++ ".ctor === \"" ++ ctor ++ "\") { " ++ "var " ++ value ++ " = " ++ varName ++ ".value; " ++ js ++ " }"+binderToJs varName done (ObjectBinder bs) = go done bs+ where+ go done [] = return done+ go done ((prop, binder):bs) = do+ propVar <- fresh+ done' <- go done bs+ js <- binderToJs propVar done' binder+ return $ "var " ++ propVar ++ " = " ++ varName ++ "." ++ prop ++ ";" ++ js+binderToJs varName done (ArrayBinder bs rest) = do+ js <- go done rest 0 bs+ return $ "if (" ++ varName ++ ".length " ++ cmp ++ " " ++ show (length bs) ++ ") { " ++ js ++ " }"+ where+ cmp = maybe "===" (const ">=") rest+ go done Nothing _ [] = return done+ go done (Just binder) index [] = do+ restVar <- fresh+ js <- binderToJs restVar done binder+ return $ "var " ++ restVar ++ " = " ++ varName ++ ".slice(" ++ show index ++ "); " ++ js+ go done rest index (binder:bs) = do+ elVar <- fresh+ done' <- go done rest (index + 1) bs+ js <- binderToJs elVar done' binder+ return $ "var " ++ elVar ++ " = " ++ varName ++ "[" ++ show index ++ "]; " ++ js+binderToJs varName done (NamedBinder ident binder) = do+ js <- binderToJs varName done binder+ return $ "var " ++ identToJs ident ++ " = " ++ varName ++ "; " ++ js+binderToJs varName done (GuardedBinder cond binder) = binderToJs varName done' binder+ where+ done' = "if (" ++ valueToJs cond ++ ") { " ++ done ++ "}"++objectPropertyToJs :: (String, Value) -> String+objectPropertyToJs (key, value) = key ++ ": " ++ valueToJs value++statementToJs :: Statement -> String+statementToJs (VariableIntroduction ident value) = "var " ++ identToJs ident ++ " = " ++ valueToJs value+statementToJs (Assignment target value) = identToJs target ++ " = " ++ valueToJs value+statementToJs (While cond sts) = "while ("+ ++ valueToJs cond ++ ") {"+ ++ intercalate ";" (map statementToJs sts) ++ "}"+statementToJs (For ident start end sts) = "for (" +++ identToJs ident ++ " = " ++ valueToJs start ++ ";"+ ++ identToJs ident ++ " < " ++ valueToJs end ++ ";"+ ++ identToJs ident ++ "++) {"+ ++ intercalate ";" (map statementToJs sts) ++ "}"+statementToJs (ForEach ident arr sts) = valueToJs arr+ ++ ".forEach(function(" ++ identToJs ident ++ ") {"+ ++ intercalate ";" (map statementToJs sts) ++ "})"+statementToJs (If ifst) = ifStatementToJs ifst+statementToJs (Return value) = "return " ++ valueToJs value++ifStatementToJs :: IfStatement -> String+ifStatementToJs (IfStatement cond thens elst) =+ "if ("+ ++ valueToJs cond ++ ") {"+ ++ intercalate ";" (map statementToJs thens) ++ "}"+ ++ maybe "" elseStatementToJs elst++elseStatementToJs :: ElseStatement -> String+elseStatementToJs (Else sts) = " else {" ++ intercalate ";" (map statementToJs sts) ++ "}"+elseStatementToJs (ElseIf ifst) = " else " ++ ifStatementToJs ifst
+ src/Language/PureScript/CodeGen/Monad.hs view
@@ -0,0 +1,31 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.CodeGen.Monad+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++{-# LANGUAGE GeneralizedNewtypeDeriving #-}++module Language.PureScript.CodeGen.Monad where++import Control.Monad.State+import Control.Applicative++newtype Gen a = Gen { unGen :: State Int a } deriving (Functor, Applicative, Monad, MonadState Int)++runGen :: Gen a -> a+runGen = flip evalState 0 . unGen++fresh :: Gen String+fresh = do+ n <- get+ modify (+ 1)+ return $ '_' : show n
+ src/Language/PureScript/Declarations.hs view
@@ -0,0 +1,39 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.Declarations+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++{-# LANGUAGE DeriveDataTypeable #-}++module Language.PureScript.Declarations where++import Language.PureScript.Values+import Language.PureScript.Types+import Language.PureScript.Names+import Language.PureScript.Kinds++import qualified Data.Data as D++type Precedence = Integer++data Associativity = Infixl | Infixr deriving (Show, D.Data, D.Typeable)++data Fixity = Fixity Associativity Precedence deriving (Show, D.Data, D.Typeable)++data Declaration+ = DataDeclaration String [String] [(String, Maybe Type)]+ | TypeSynonymDeclaration String [String] Type+ | TypeDeclaration Ident PolyType+ | ValueDeclaration Ident Value+ | ExternDeclaration Ident PolyType+ | ExternDataDeclaration String Kind+ | FixityDeclaration Fixity String deriving (Show, D.Data, D.Typeable)
+ src/Language/PureScript/Kinds.hs view
@@ -0,0 +1,25 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.Kinds+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++{-# LANGUAGE DeriveDataTypeable #-}++module Language.PureScript.Kinds where++import Data.Data++data Kind+ = KUnknown Int+ | Star+ | Row+ | FunKind Kind Kind deriving (Show, Eq, Data, Typeable)
+ src/Language/PureScript/Names.hs view
@@ -0,0 +1,26 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.Names+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++{-# LANGUAGE DeriveDataTypeable #-}++module Language.PureScript.Names where++import Data.Data++data Ident = Ident String | Op String deriving (Eq, Ord, Data, Typeable)++instance Show Ident where+ show (Ident s) = s+ show (Op op) = '(':op ++ ")"+
+ src/Language/PureScript/Parser.hs view
@@ -0,0 +1,22 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.Parser+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++module Language.PureScript.Parser (module P) where++import Language.PureScript.Parser.Common as P+import Language.PureScript.Parser.Types as P+import Language.PureScript.Parser.Values as P+import Language.PureScript.Parser.State as P+import Language.PureScript.Parser.Kinds as P+import Language.PureScript.Parser.Declarations as P
+ src/Language/PureScript/Parser/Common.hs view
@@ -0,0 +1,181 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.Parser.Common+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++{-# LANGUAGE FlexibleContexts #-}++module Language.PureScript.Parser.Common where++import Data.Char (isSpace)+import Control.Applicative+import Control.Monad+import Control.Monad.State+import Language.PureScript.Parser.State+import qualified Data.Map as M+import qualified Text.Parsec as P+import qualified Text.Parsec.Pos as P+import qualified Text.Parsec.Token as PT++import Language.PureScript.Names++reservedNames :: [String]+reservedNames = [ "case"+ , "of"+ , "data"+ , "type"+ , "var"+ , "val"+ , "while"+ , "for"+ , "foreach"+ , "if"+ , "then"+ , "else"+ , "return"+ , "true"+ , "false"+ , "extern"+ , "forall"+ , "do"+ , "until"+ , "in"+ , "break"+ , "catch"+ , "continue"+ , "debugger"+ , "default"+ , "delete"+ , "finally"+ , "function"+ , "instanceof"+ , "new"+ , "switch"+ , "this"+ , "throw"+ , "try"+ , "typeof"+ , "void"+ , "with"+ , "Number"+ , "String"+ , "Boolean"+ , "infixl"+ , "infixr" ]++reservedOpNames :: [String]+reservedOpNames = [ "!", "~", "-", "<=", ">=", "<", ">", "*", "/", "%", "++", "+", "<<", ">>>", ">>"+ , "==", "!=", "&", "^", "|", "&&", "||", "->" ]++identStart :: P.Parsec String u Char+identStart = P.lower <|> P.oneOf "_$"++properNameStart :: P.Parsec String u Char+properNameStart = P.upper++identLetter :: P.Parsec String u Char+identLetter = P.alphaNum <|> P.oneOf "_'"++opStart :: P.Parsec String u Char+opStart = P.oneOf "!#$%&*+/<=>?@^|-~"++opLetter :: P.Parsec String u Char+opLetter = P.oneOf ":#$%&*+./<=>?@^|"++langDef = PT.LanguageDef+ { PT.reservedNames = reservedNames+ , PT.reservedOpNames = reservedOpNames+ , PT.commentStart = "{-"+ , PT.commentEnd = "-}"+ , PT.commentLine = "--"+ , PT.nestedComments = True+ , PT.identStart = identStart+ , PT.identLetter = identLetter+ , PT.opStart = opStart+ , PT.opLetter = opLetter+ , PT.caseSensitive = True+ }++tokenParser = PT.makeTokenParser langDef++lexeme = PT.lexeme tokenParser+identifier = PT.identifier tokenParser+reserved = PT.reserved tokenParser+reservedOp = PT.reservedOp tokenParser+operator = PT.operator tokenParser+stringLiteral = PT.stringLiteral tokenParser+whiteSpace = PT.whiteSpace tokenParser+parens = PT.parens tokenParser+braces = PT.braces tokenParser+angles = PT.angles tokenParser+squares = PT.squares tokenParser+semi = PT.semi tokenParser+comma = PT.comma tokenParser+colon = PT.colon tokenParser+dot = PT.dot tokenParser+semiSep = PT.semiSep tokenParser+semiSep1 = PT.semiSep1 tokenParser+commaSep = PT.commaSep tokenParser+commaSep1 = PT.commaSep1 tokenParser+natural = PT.natural tokenParser++tick :: P.Parsec String u Char+tick = lexeme $ P.char '`'++properName :: P.Parsec String u String+properName = lexeme $ P.try ((:) <$> P.upper <*> many (PT.identLetter langDef) P.<?> "name")++integerOrFloat :: P.Parsec String u (Either Integer Double)+integerOrFloat = (Left <$> P.try (PT.natural tokenParser) <|>+ Right <$> P.try (PT.float tokenParser)) P.<?> "number"++augment :: P.Stream s m t => P.ParsecT s u m a -> P.ParsecT s u m b -> (a -> b -> a) -> P.ParsecT s u m a+augment p q f = flip (maybe id $ flip f) <$> p <*> P.optionMaybe q++fold :: P.Stream s m t => P.ParsecT s u m a -> P.ParsecT s u m b -> (a -> b -> a) -> P.ParsecT s u m a+fold first more combine = do+ a <- first+ bs <- P.many more+ return $ foldl combine a bs++buildPostfixParser :: P.Stream s m t => [P.ParsecT s u m (a -> a)] -> P.ParsecT s u m a -> P.ParsecT s u m a+buildPostfixParser f x = fold x (P.choice (map P.try f)) (flip ($))++parseIdent :: P.Parsec String u Ident+parseIdent = (Ident <$> identifier) <|> (Op <$> parens operator)++parseIdentInfix :: P.Parsec String u Ident+parseIdentInfix = (Ident <$> P.between tick tick identifier) <|> (Op <$> operator)++mark :: P.Parsec String ParseState a -> P.Parsec String ParseState a+mark p = do+ current <- indentationLevel <$> P.getState+ pos <- P.sourceColumn <$> P.getPosition+ P.modifyState $ \st -> st { indentationLevel = pos }+ a <- p+ P.modifyState $ \st -> st { indentationLevel = current }+ return a++checkIndentation :: (P.Column -> P.Column -> Bool) -> P.Parsec String ParseState ()+checkIndentation rel = do+ col <- P.sourceColumn <$> P.getPosition+ current <- indentationLevel <$> P.getState+ guard (col `rel` current)++indented :: P.Parsec String ParseState ()+indented = checkIndentation (>) P.<?> "indentation"++same :: P.Parsec String ParseState ()+same = checkIndentation (==) P.<?> "no indentation"++runIndentParser :: P.Parsec String ParseState a -> String -> Either P.ParseError a+runIndentParser p = P.runParser p (ParseState 0 M.empty) ""
+ src/Language/PureScript/Parser/Declarations.hs view
@@ -0,0 +1,100 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.Parser.Declarations+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++module Language.PureScript.Parser.Declarations (+ parseDeclaration,+ parseDeclarations+) where++import Data.Char+import Data.List+import Data.Maybe+import Data.Function+import Control.Applicative+import Control.Arrow (Arrow(..))+import Control.Monad.State+import qualified Data.Map as M+import qualified Text.Parsec as P+import qualified Text.Parsec.Pos as P++import Language.PureScript.Values+import Language.PureScript.Types+import Language.PureScript.Parser.State+import Language.PureScript.Parser.Common+import Language.PureScript.Declarations+import Language.PureScript.Parser.Values+import Language.PureScript.Parser.Types+import Language.PureScript.Parser.Kinds++parseDataDeclaration :: P.Parsec String ParseState Declaration+parseDataDeclaration = do+ reserved "data"+ name <- indented *> properName+ tyArgs <- many (indented *> identifier)+ lexeme $ indented *> P.char '='+ ctors <- P.sepBy1 ((,) <$> (indented *> properName) <*> P.optionMaybe parseType) (lexeme $ indented *> P.char '|')+ return $ DataDeclaration name tyArgs ctors++parseTypeDeclaration :: P.Parsec String ParseState Declaration+parseTypeDeclaration =+ TypeDeclaration <$> parseIdent+ <*> (lexeme (indented *> P.string "::") *> parsePolyType)++parseTypeSynonymDeclaration :: P.Parsec String ParseState Declaration+parseTypeSynonymDeclaration =+ TypeSynonymDeclaration <$> (reserved "type" *> indented *> properName)+ <*> many (indented *> identifier)+ <*> (lexeme (indented *> P.char '=') *> parseType)++parseValueDeclaration :: P.Parsec String ParseState Declaration+parseValueDeclaration =+ ValueDeclaration <$> parseIdent+ <*> (lexeme (indented *> P.char '=') *> parseValue)++parseExternDeclaration :: P.Parsec String ParseState Declaration+parseExternDeclaration = reserved "extern" *> indented *>+ (ExternDataDeclaration <$> (reserved "data" *> indented *> properName)+ <*> (lexeme (indented *> P.string "::") *> parseKind)+ <|> ExternDeclaration <$> parseIdent+ <*> (lexeme (indented *> P.string "::") *> parsePolyType))++parseAssociativity :: P.Parsec String ParseState Associativity+parseAssociativity =+ (reserved "infixl" >> return Infixl) <|>+ (reserved "infixr" >> return Infixr)++parseFixity :: P.Parsec String ParseState Fixity+parseFixity = Fixity <$> parseAssociativity <*> (indented *> natural)++parseFixityDeclaration :: P.Parsec String ParseState Declaration+parseFixityDeclaration = do+ fixity <- parseFixity+ indented+ name <- operator+ current <- fixities <$> P.getState+ when (name `M.member` current) (P.unexpected $ "redefined fixity for " ++ show name)+ P.modifyState $ \st -> st { fixities = M.insert name fixity current }+ return $ FixityDeclaration fixity name++parseDeclaration :: P.Parsec String ParseState Declaration+parseDeclaration = P.choice (map P.try+ [ parseDataDeclaration+ , parseTypeDeclaration+ , parseTypeSynonymDeclaration+ , parseValueDeclaration+ , parseExternDeclaration+ , parseFixityDeclaration ]) P.<?> "declaration"++parseDeclarations :: P.Parsec String ParseState [Declaration]+parseDeclarations = whiteSpace *> mark (same *> P.many parseDeclaration) <* P.eof
+ src/Language/PureScript/Parser/Kinds.hs view
@@ -0,0 +1,41 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.Parser.Kinds+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++module Language.PureScript.Parser.Kinds (+ parseKind+) where++import Language.PureScript.Kinds+import Language.PureScript.Parser.State+import Language.PureScript.Parser.Common+import Control.Applicative+import qualified Text.Parsec as P+import qualified Text.Parsec.Expr as P++parseStar :: P.Parsec String ParseState Kind+parseStar = const Star <$> lexeme (P.char '*')++parseRow :: P.Parsec String ParseState Kind+parseRow = const Row <$> lexeme (P.char '#')++parseTypeAtom :: P.Parsec String ParseState Kind+parseTypeAtom = indented *> P.choice (map P.try+ [ parseStar+ , parseRow+ , parens parseKind ])++parseKind :: P.Parsec String ParseState Kind+parseKind = P.buildExpressionParser operators parseTypeAtom P.<?> "kind"+ where+ operators = [ [ P.Infix (lexeme (P.try (P.string "->")) >> return FunKind) P.AssocRight ] ]
+ src/Language/PureScript/Parser/State.hs view
@@ -0,0 +1,27 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.Parser.State+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++module Language.PureScript.Parser.State where++import Language.PureScript.Names+import Language.PureScript.Declarations++import qualified Text.Parsec as P+import qualified Data.Map as M++data ParseState = ParseState+ { indentationLevel :: P.Column+ , fixities :: M.Map String Fixity } deriving Show++
+ src/Language/PureScript/Parser/Types.hs view
@@ -0,0 +1,91 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.Parser.Types+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++module Language.PureScript.Parser.Types (+ parseType,+ parsePolyType,+ parseRow+) where++import Language.PureScript.Types+import Language.PureScript.Parser.State+import Language.PureScript.Parser.Common+import Control.Applicative+import qualified Text.Parsec as P+import qualified Text.Parsec.Expr as P+import Control.Arrow (Arrow(..))++parseNumber :: P.Parsec String ParseState Type+parseNumber = const Number <$> reserved "Number"++parseString :: P.Parsec String ParseState Type+parseString = const String <$> reserved "String"++parseBoolean :: P.Parsec String ParseState Type+parseBoolean = const Boolean <$> reserved "Boolean"++parseArray :: P.Parsec String ParseState Type+parseArray = squares $ Array <$> parseType++parseObject :: P.Parsec String ParseState Type+parseObject = braces $ Object <$> parseRow++parseFunction :: P.Parsec String ParseState Type+parseFunction = do+ args <- lexeme $ parens $ commaSep parseType+ lexeme $ P.string "->"+ resultType <- parseType+ return $ Function args resultType++parseTypeVariable :: P.Parsec String ParseState Type+parseTypeVariable = TypeVar <$> identifier++parseTypeConstructor :: P.Parsec String ParseState Type+parseTypeConstructor = TypeConstructor <$> properName++parseTypeAtom :: P.Parsec String ParseState Type+parseTypeAtom = indented *> P.choice (map P.try+ [ parseNumber+ , parseString+ , parseBoolean+ , parseArray+ , parseObject+ , parseFunction+ , parseTypeVariable+ , parseTypeConstructor+ , parens parseType ])++parsePolyType :: P.Parsec String ParseState PolyType+parsePolyType = (PolyType <$> P.option [] (indented *> reserved "forall" *> many (indented *> identifier) <* indented <* dot)+ <*> parseType) P.<?> "polymorphic type"++parseType :: P.Parsec String ParseState Type+parseType = (P.buildExpressionParser operators . buildPostfixParser postfixTable $ parseTypeAtom) P.<?> "type"+ where+ postfixTable :: [P.Parsec String ParseState (Type -> Type)]+ postfixTable = [ flip TypeApp <$> (indented *> parseTypeAtom) ]+ operators = [ [ P.Infix (lexeme (P.try (P.string "->")) >> return (\t1 t2 -> Function [t1] t2)) P.AssocRight ] ]++parseNameAndType :: P.Parsec String ParseState (String, Type)+parseNameAndType = (,) <$> (indented *> identifier <* indented <* lexeme (P.string "::")) <*> parseType++parseRowEnding :: P.Parsec String ParseState Row+parseRowEnding = P.option REmpty (RowVar <$> (lexeme (indented *> P.char '|') *> indented *> identifier))++parseRow :: P.Parsec String ParseState Row+parseRow = (fromList <$> (parseNameAndType `P.sepBy` (indented *> semi)) <*> parseRowEnding) P.<?> "row"+ where+ fromList :: [(String, Type)] -> Row -> Row+ fromList [] r = r+ fromList ((name, t):ts) r = RCons name t (fromList ts r)
+ src/Language/PureScript/Parser/Values.hs view
@@ -0,0 +1,292 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.Parser.Values+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++module Language.PureScript.Parser.Values (+ parseValue,+ parseBinder+) where++import Language.PureScript.Values+import Language.PureScript.Names+import Language.PureScript.Declarations+import Language.PureScript.Parser.State+import Data.Function (on)+import Data.List+import Data.Functor.Identity+import qualified Data.Map as M+import qualified Language.PureScript.Parser.Common as C+import Control.Applicative+import qualified Text.Parsec as P+import Text.Parsec.Expr+import Control.Monad+import Control.Arrow (Arrow(..))+import Language.PureScript.Parser.Types+import Language.PureScript.Types++booleanLiteral :: P.Parsec String ParseState Bool+booleanLiteral = (C.reserved "true" >> return True) P.<|> (C.reserved "false" >> return False)++parseNumericLiteral :: P.Parsec String ParseState Value+parseNumericLiteral = NumericLiteral <$> C.integerOrFloat++parseStringLiteral :: P.Parsec String ParseState Value+parseStringLiteral = StringLiteral <$> C.stringLiteral++parseBooleanLiteral :: P.Parsec String ParseState Value+parseBooleanLiteral = BooleanLiteral <$> booleanLiteral++parseArrayLiteral :: P.Parsec String ParseState Value+parseArrayLiteral = ArrayLiteral <$> C.squares (parseValue `P.sepBy` (C.indented *> C.comma))++parseObjectLiteral :: P.Parsec String ParseState Value+parseObjectLiteral = ObjectLiteral <$> C.braces (parseIdentifierAndValue `P.sepBy` (C.indented *> C.comma))++parseIdentifierAndValue :: P.Parsec String ParseState (String, Value)+parseIdentifierAndValue = (,) <$> (C.indented *> C.identifier <* C.indented <* C.colon)+ <*> (C.indented *> parseValue)++parseAbs :: P.Parsec String ParseState Value+parseAbs = do+ C.lexeme $ P.char '\\'+ args <- (C.indented *> C.parseIdent) `P.sepBy` (C.indented *> C.comma)+ C.lexeme $ C.indented *> P.string "->"+ value <- parseValue+ return $ Abs args value++parseApp :: P.Parsec String ParseState Value+parseApp = App <$> parseValue+ <*> (C.indented *> C.parens (parseValue `P.sepBy` (C.indented *> C.comma)))++parseVar :: P.Parsec String ParseState Value+parseVar = Var <$> C.parseIdent++parseConstructor :: P.Parsec String ParseState Value+parseConstructor = Constructor <$> C.properName++parseCase :: P.Parsec String ParseState Value+parseCase = Case <$> P.between (C.reserved "case") (C.indented *> C.reserved "of") parseValue+ <*> (C.indented *> C.mark (P.many (C.same *> C.mark parseCaseAlternative)))++parseCaseAlternative :: P.Parsec String ParseState (Binder, Value)+parseCaseAlternative = (,) <$> (parseGuardedBinder <* C.lexeme (P.string "->"))+ <*> parseValue+ P.<?> "case alternative"++parseIfThenElse :: P.Parsec String ParseState Value+parseIfThenElse = IfThenElse <$> (C.reserved "if" *> C.indented *> parseValue)+ <*> (C.indented *> C.reserved "then" *> C.indented *> parseValue)+ <*> (C.indented *> C.reserved "else" *> C.indented *> parseValue)++parseBlock :: P.Parsec String ParseState Value+parseBlock = Block <$> (C.reserved "do" *> parseManyStatements)++parseManyStatements :: P.Parsec String ParseState [Statement]+parseManyStatements = C.indented *> C.mark (P.many (C.same *> C.mark parseStatement)) P.<?> "block"++parseValueAtom :: P.Parsec String ParseState Value+parseValueAtom = C.indented *> P.choice (map P.try+ [ parseNumericLiteral+ , parseStringLiteral+ , parseBooleanLiteral+ , parseArrayLiteral+ , parseObjectLiteral+ , parseAbs+ , parseVar+ , parseConstructor+ , parseBlock+ , parseCase+ , parseIfThenElse+ , C.parens parseValue ])++parsePropertyUpdate :: P.Parsec String ParseState (String, Value)+parsePropertyUpdate = do+ name <- C.lexeme C.identifier+ C.lexeme $ C.indented *> P.char '='+ value <- C.indented *> parseValue+ return (name, value)++parseValue :: P.Parsec String ParseState Value+parseValue = do+ customOps <- fixities <$> P.getState+ (buildExpressionParser (operators customOps)+ . C.buildPostfixParser postfixTable2+ $ indexersAndAccessors) P.<?> "expression"+ where+ indexersAndAccessors = C.buildPostfixParser postfixTable1 parseValueAtom+ postfixTable1 = [ Accessor <$> (C.indented *> C.dot *> C.indented *> C.identifier)+ , Indexer <$> (C.indented *> C.squares parseValue)+ , flip ObjectUpdate <$> (C.indented *> C.braces ((C.indented *> parsePropertyUpdate) `P.sepBy1` (C.indented *> C.comma))) ]+ postfixTable2 = [ C.indented *> indexersAndAccessors >>= \t2 -> return (\t1 -> App t1 [t2])+ , flip App <$> (C.indented *> C.parens (parseValue `P.sepBy` (C.indented *> C.comma)))+ , flip TypedValue <$> (P.try (C.lexeme (C.indented *> P.string "::")) *> parsePolyType) ]+ operators user =+ [ [ Prefix $ C.lexeme (P.try $ C.indented *> C.reservedOp "!") >> return (Unary Not)+ , Prefix $ C.lexeme (P.try $ C.indented *> C.reservedOp "~") >> return (Unary BitwiseNot)+ , Prefix $ C.lexeme (P.try $ C.indented *> C.reservedOp "-") >> return (Unary Negate)+ , Prefix $ C.lexeme (P.try $ C.indented *> C.reservedOp "+") >> return id ]+ ] ++ customOperatorTable user +++ [ [ Infix (C.lexeme (P.try (C.indented *> C.parseIdentInfix P.<?> "operator") >>= \ident -> return $ \t1 t2 -> App (App (Var ident) [t1]) [t2])) AssocLeft ]+ , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "<=") >> return (Binary LessThanOrEqualTo)) AssocRight+ , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp ">=") >> return (Binary GreaterThanOrEqualTo)) AssocRight ]+ , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "<") >> return (Binary LessThan)) AssocRight+ , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp ">") >> return (Binary GreaterThan)) AssocRight ]+ , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "*") >> return (Binary Multiply)) AssocRight+ , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "/") >> return (Binary Divide)) AssocRight+ , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "%") >> return (Binary Modulus)) AssocRight ]+ , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "++") >> return (Binary Concat)) AssocRight+ , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "+") >> return (Binary Add)) AssocRight+ , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "-") >> return (Binary Subtract)) AssocRight ]+ , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "<<") >> return (Binary ShiftLeft)) AssocRight+ , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp ">>>") >> return (Binary ZeroFillShiftRight)) AssocRight+ , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp ">>") >> return (Binary ShiftRight)) AssocRight ]+ , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "==") >> return (Binary EqualTo)) AssocRight+ , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "!=") >> return (Binary NotEqualTo)) AssocRight ]+ , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "&") >> return (Binary BitwiseAnd)) AssocRight ]+ , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "^") >> return (Binary BitwiseXor)) AssocRight ]+ , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "|") >> return (Binary BitwiseOr)) AssocRight ]+ , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "&&") >> return (Binary And)) AssocRight ]+ , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "||") >> return (Binary Or)) AssocRight ]+ ]++customOperatorTable :: M.Map String Fixity -> OperatorTable String ParseState Identity Value+customOperatorTable fixities =+ let+ ops = map (\(name, Fixity a p) -> (name, (a, p))) . M.toList $ fixities+ sorted = sortBy (compare `on` (snd . snd)) ops+ levels = groupBy ((==) `on` (snd . snd)) sorted+ in+ map (map $ \(name, (a, _)) ->+ flip Infix (toAssoc a) $+ C.lexeme $ P.try $ do+ C.indented+ C.reservedOp name P.<?> "operator"+ return $ \t1 t2 -> App (App (Var (Op name)) [t1]) [t2])+ levels+++toAssoc :: Associativity -> Assoc+toAssoc Infixl = AssocLeft+toAssoc Infixr = AssocRight++parseVariableIntroduction :: P.Parsec String ParseState Statement+parseVariableIntroduction = do+ C.reserved "var"+ name <- C.indented *> C.parseIdent+ C.lexeme $ C.indented *> P.char '='+ value <- parseValue+ return $ VariableIntroduction name value++parseAssignment :: P.Parsec String ParseState Statement+parseAssignment = do+ tgt <- C.parseIdent+ C.lexeme $ C.indented *> P.char '='+ value <- parseValue+ return $ Assignment tgt value++parseWhile :: P.Parsec String ParseState Statement+parseWhile = While <$> (C.reserved "while" *> C.indented *> parseValue <* C.indented <* C.colon)+ <*> parseManyStatements++parseFor :: P.Parsec String ParseState Statement+parseFor = For <$> (C.reserved "for" *> C.indented *> C.parseIdent)+ <*> (C.indented *> C.lexeme (P.string "<-") *> parseValue)+ <*> (C.indented *> C.reserved "until" *> parseValue <* C.colon)+ <*> parseManyStatements++parseForEach :: P.Parsec String ParseState Statement+parseForEach = ForEach <$> (C.reserved "foreach" *> C.indented *> C.parseIdent)+ <*> (C.indented *> C.reserved "in" *> parseValue <* C.colon)+ <*> parseManyStatements++parseIf :: P.Parsec String ParseState Statement+parseIf = If <$> parseIfStatement++parseIfStatement :: P.Parsec String ParseState IfStatement+parseIfStatement =+ IfStatement <$> (C.reserved "if" *> C.indented *> parseValue <* C.indented <* C.colon)+ <*> parseManyStatements+ <*> P.optionMaybe (C.same *> parseElseStatement)++parseElseStatement :: P.Parsec String ParseState ElseStatement+parseElseStatement = C.reserved "else" >> (ElseIf <$> (C.indented *> parseIfStatement)+ <|> Else <$> (C.indented *> C.colon *> parseManyStatements))++parseReturn :: P.Parsec String ParseState Statement+parseReturn = Return <$> (C.reserved "return" *> parseValue)++parseStatement :: P.Parsec String ParseState Statement+parseStatement = P.choice (map P.try+ [ parseVariableIntroduction+ , parseAssignment+ , parseWhile+ , parseFor+ , parseForEach+ , parseIf+ , parseReturn ]) P.<?> "statement"++parseStringBinder :: P.Parsec String ParseState Binder+parseStringBinder = StringBinder <$> C.stringLiteral++parseBooleanBinder :: P.Parsec String ParseState Binder+parseBooleanBinder = BooleanBinder <$> booleanLiteral++parseNumberBinder :: P.Parsec String ParseState Binder+parseNumberBinder = NumberBinder <$> C.integerOrFloat++parseVarBinder :: P.Parsec String ParseState Binder+parseVarBinder = VarBinder <$> C.parseIdent++parseNullaryBinder :: P.Parsec String ParseState Binder+parseNullaryBinder = NullaryBinder <$> C.lexeme C.properName++parseUnaryBinder :: P.Parsec String ParseState Binder+parseUnaryBinder = UnaryBinder <$> C.lexeme C.properName <*> (C.indented *> parseBinder)++parseObjectBinder :: P.Parsec String ParseState Binder+parseObjectBinder = ObjectBinder <$> C.braces ((C.indented *> parseIdentifierAndBinder) `P.sepBy` (C.indented *> C.comma))++parseArrayBinder :: P.Parsec String ParseState Binder+parseArrayBinder = C.squares $ ArrayBinder <$> ((C.indented *> parseBinder) `P.sepBy` (C.indented *> C.comma))+ <*> P.optionMaybe (C.indented *> C.colon *> C.indented *> parseBinder)++parseNamedBinder :: P.Parsec String ParseState Binder+parseNamedBinder = NamedBinder <$> (C.parseIdent <* C.indented <* C.lexeme (P.char '@'))+ <*> (C.indented *> parseBinder)++parseNullBinder :: P.Parsec String ParseState Binder+parseNullBinder = C.lexeme (P.char '_') *> P.notFollowedBy C.identLetter *> return NullBinder++parseIdentifierAndBinder :: P.Parsec String ParseState (String, Binder)+parseIdentifierAndBinder = do+ name <- C.lexeme C.identifier+ C.lexeme $ C.indented *> P.char '='+ binder <- C.indented *> parseBinder+ return (name, binder)++parseBinder :: P.Parsec String ParseState Binder+parseBinder = P.choice (map P.try+ [ parseNullBinder+ , parseStringBinder+ , parseBooleanBinder+ , parseNumberBinder+ , parseNamedBinder+ , parseVarBinder+ , parseUnaryBinder+ , parseNullaryBinder+ , parseObjectBinder+ , parseArrayBinder+ , C.parens parseBinder ]) P.<?> "binder"++parseGuardedBinder :: P.Parsec String ParseState Binder+parseGuardedBinder = flip ($) <$> parseBinder <*> P.option id (GuardedBinder <$> (C.indented *> C.lexeme (P.char '|') *> C.indented *> parseValue))
+ src/Language/PureScript/Pretty.hs view
@@ -0,0 +1,22 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.Pretty+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++module Language.PureScript.Pretty (module P) where++import Language.PureScript.Pretty.Kinds as P+import Language.PureScript.Pretty.Values as P+import Language.PureScript.Pretty.Types as P+++
+ src/Language/PureScript/Pretty/Common.hs view
@@ -0,0 +1,80 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.Pretty.Common+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++{-# LANGUAGE GeneralizedNewtypeDeriving, GADTs #-}++module Language.PureScript.Pretty.Common where++import Data.Char+import Data.Maybe (fromMaybe)+import Data.List (nub, intersperse, intercalate)+import Data.Function (fix)+import Control.Monad.State+import Control.Applicative (Applicative(..), Alternative(..))+import qualified Control.Category as C+import Control.Category ((>>>))+import qualified Control.Arrow as A+import Control.Arrow ((***), (<+>))++import Language.PureScript.Names+import Language.PureScript.Values+import Language.PureScript.Types+import Language.PureScript.Declarations++identToJs :: Ident -> String+identToJs (Ident name) = name+identToJs (Op op) = concatMap opCharToString op+ where+ opCharToString :: Char -> String+ opCharToString = (:) '$'. show . ord++newtype Pattern a b = Pattern { runPattern :: A.Kleisli Maybe a b } deriving (C.Category, A.Arrow, A.ArrowZero, A.ArrowPlus)++instance Functor (Pattern a) where+ fmap f (Pattern p) = Pattern $ A.Kleisli $ fmap f . A.runKleisli p++pattern :: Pattern a b -> a -> Maybe b+pattern = A.runKleisli . runPattern++parens :: String -> String+parens s = ('(':s) ++ ")"++chainl :: Pattern a (a, a) -> (r -> r -> r) -> Pattern a r -> Pattern a r+chainl split f p = fix $ \c -> split >>> ((c <+> p) *** p) >>> A.arr (uncurry f)++chainr :: Pattern a (a, a) -> (r -> r -> r) -> Pattern a r -> Pattern a r+chainr split f p = fix $ \c -> split >>> (p *** (c <+> p)) >>> A.arr (uncurry f)++wrap :: Pattern a (s, a) -> (s -> r -> r) -> Pattern a r -> Pattern a r+wrap split f p = fix $ \c -> split >>> (C.id *** (c <+> p)) >>> A.arr (uncurry f)++split :: Pattern a (s, t) -> (s -> t -> r) -> Pattern a r -> Pattern a r+split s f p = s >>> A.arr (uncurry f)++data OperatorTable a r = OperatorTable { runOperatorTable :: [ [Operator a r] ] }++data Operator a r where+ AssocL :: Pattern a (a, a) -> (r -> r -> r) -> Operator a r+ AssocR :: Pattern a (a, a) -> (r -> r -> r) -> Operator a r+ Wrap :: Pattern a (s, a) -> (s -> r -> r) -> Operator a r+ Split :: Pattern a (s, t) -> (s -> t -> r) -> Operator a r++buildPrettyPrinter :: OperatorTable a r -> Pattern a r -> Pattern a r+buildPrettyPrinter table p = foldl (\p' ops -> foldl1 (<+>) (flip map ops $ \op ->+ case op of+ AssocL pat g -> chainl pat g p'+ AssocR pat g -> chainr pat g p'+ Wrap pat g -> wrap pat g p'+ Split pat g -> split pat g p'+ ) <+> p') p $ runOperatorTable table
+ src/Language/PureScript/Pretty/Kinds.hs view
@@ -0,0 +1,50 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.Pretty.Kinds+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++module Language.PureScript.Pretty.Kinds (+ prettyPrintKind+) where++import Data.Maybe (fromMaybe)+import Data.List (intersperse, intercalate)+import qualified Control.Arrow as A+import Control.Arrow ((<+>))+import qualified Data.Map as M+import Control.Applicative++import Language.PureScript.Kinds+import Language.PureScript.Pretty.Common++typeLiterals :: Pattern Kind String+typeLiterals = Pattern $ A.Kleisli match+ where+ match Star = Just "*"+ match Row = Just "#"+ match (KUnknown u) = Just $ 'u' : show u+ match _ = Nothing++funKind :: Pattern Kind (Kind, Kind)+funKind = Pattern $ A.Kleisli match+ where+ match (FunKind arg ret) = Just (arg, ret)+ match _ = Nothing++prettyPrintKind :: Kind -> String+prettyPrintKind = fromMaybe (error "Incomplete pattern") . pattern matchKind+ where+ matchKind :: Pattern Kind String+ matchKind = buildPrettyPrinter operators (typeLiterals <+> fmap parens matchKind)+ operators :: OperatorTable Kind String+ operators =+ OperatorTable [ [ AssocR funKind $ \arg ret -> arg ++ " -> " ++ ret ] ]
+ src/Language/PureScript/Pretty/Types.hs view
@@ -0,0 +1,95 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.Pretty.Types+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++module Language.PureScript.Pretty.Types (+ prettyPrintType,+ prettyPrintRow,+ prettyPrintPolyType+) where++import Data.Maybe (fromMaybe)+import Data.List (intersperse, intercalate)+import qualified Control.Arrow as A+import Control.Arrow ((<+>))+import qualified Data.Map as M+import Control.Applicative++import Language.PureScript.Values+import Language.PureScript.Types+import Language.PureScript.Names+import Language.PureScript.Declarations+import Language.PureScript.TypeChecker.Monad+import Language.PureScript.Pretty.Common++typeLiterals :: Pattern Type String+typeLiterals = Pattern $ A.Kleisli match+ where+ match Number = Just "Number"+ match String = Just "String"+ match Boolean = Just "Boolean"+ match (Array ty) = Just $ "[" ++ prettyPrintType ty ++ "]"+ match (Object row) = Just $ "{ " ++ prettyPrintRow row ++ " }"+ match (TypeVar var) = Just var+ match (TypeConstructor ctor) = Just ctor+ match (TUnknown u) = Just $ 'u' : show u+ match (SaturatedTypeSynonym name args) = Just $ name ++ "<" ++ intercalate "," (map prettyPrintType args) ++ ">"+ match _ = Nothing++prettyPrintRow :: Row -> String+prettyPrintRow = (\(tys, tail) -> intercalate "; " (map (uncurry nameAndTypeToPs) tys) ++ tailToPs tail) . toList []+ where+ nameAndTypeToPs :: String -> Type -> String+ nameAndTypeToPs name ty = name ++ " :: " ++ prettyPrintType ty+ tailToPs :: Row -> String+ tailToPs REmpty = ""+ tailToPs (RUnknown u) = " | " ++ show u+ tailToPs (RowVar var) = " | " ++ var+ toList :: [(String, Type)] -> Row -> ([(String, Type)], Row)+ toList tys (RCons name ty row) = toList ((name, ty):tys) row+ toList tys r = (tys, r)++typeApp :: Pattern Type (Type, Type)+typeApp = Pattern $ A.Kleisli match+ where+ match (TypeApp f x) = Just (f, x)+ match _ = Nothing++singleArgumentFunction :: Pattern Type (Type, Type)+singleArgumentFunction = Pattern $ A.Kleisli match+ where+ match (Function [arg] ret) = Just (arg, ret)+ match _ = Nothing++function :: Pattern Type ([Type], Type)+function = Pattern $ A.Kleisli match+ where+ match (Function args ret) = Just (args, ret)+ match _ = Nothing++prettyPrintType :: Type -> String+prettyPrintType = fromMaybe (error "Incomplete pattern") . pattern matchType+ where+ matchType :: Pattern Type String+ matchType = buildPrettyPrinter operators (typeLiterals <+> fmap parens matchType)+ operators :: OperatorTable Type String+ operators =+ OperatorTable [ [ AssocL typeApp $ \f x -> f ++ " " ++ x ]+ , [ AssocR singleArgumentFunction $ \arg ret -> arg ++ " -> " ++ ret+ , Wrap function $ \args ret -> "(" ++ intercalate ", " (map prettyPrintType args) ++ ") -> " ++ ret+ ]+ ]++prettyPrintPolyType :: PolyType -> String+prettyPrintPolyType (PolyType [] ty) = prettyPrintType ty+prettyPrintPolyType (PolyType idents ty) = "forall " ++ unwords idents ++ ". " ++ prettyPrintType ty
+ src/Language/PureScript/Pretty/Values.hs view
@@ -0,0 +1,185 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.Pretty.Values+-- Copyright : Kinds.hs(c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++module Language.PureScript.Pretty.Values (+ prettyPrintValue,+ prettyPrintBinder+) where++import Data.Char+import Data.Maybe (fromMaybe)+import Data.List (intercalate)+import qualified Control.Arrow as A+import Control.Arrow ((<+>))+import Control.Applicative++import Language.PureScript.Types+import Language.PureScript.Values+import Language.PureScript.Names+import Language.PureScript.Pretty.Common++literals :: Pattern Value String+literals = Pattern $ A.Kleisli match+ where+ match (NumericLiteral n) = Just $ either show show n+ match (StringLiteral s) = Just $ show s+ match (BooleanLiteral True) = Just "true"+ match (BooleanLiteral False) = Just "false"+ match (ArrayLiteral xs) = Just $ "[" ++ intercalate ", " (map prettyPrintValue xs) ++ "]"+ match (ObjectLiteral ps) = Just $ "{" ++ intercalate ", " (map (uncurry prettyPrintObjectProperty) ps) ++ "}"+ match (Constructor name) = Just name+ match (Block sts) = Just $ "do { " ++ intercalate " ; " (map prettyPrintStatement sts) ++ " }"+ match (Case value binders) = Just $ "case " ++ prettyPrintValue value ++ " of { " ++ intercalate " ; " (map (uncurry prettyPrintCaseAlternative) binders) ++ " }"+ match (Var ident) = Just $ show ident+ match _ = Nothing++prettyPrintCaseAlternative :: Binder -> Value -> String+prettyPrintCaseAlternative binder val = prettyPrintBinder binder ++ " -> " ++ prettyPrintValue val++ifThenElse :: Pattern Value ((Value, Value), Value)+ifThenElse = Pattern $ A.Kleisli match+ where+ match (IfThenElse cond th el) = Just ((th, el), cond)+ match _ = Nothing++accessor :: Pattern Value (String, Value)+accessor = Pattern $ A.Kleisli match+ where+ match (Accessor prop val) = Just (prop, val)+ match _ = Nothing++indexer :: Pattern Value (String, Value)+indexer = Pattern $ A.Kleisli match+ where+ match (Indexer index val) = Just (prettyPrintValue index, val)+ match _ = Nothing++objectUpdate :: Pattern Value ([String], Value)+objectUpdate = Pattern $ A.Kleisli match+ where+ match (ObjectUpdate o ps) = Just (flip map ps $ \(key, val) -> key ++ " = " ++ prettyPrintValue val, o)+ match _ = Nothing++app :: Pattern Value (String, Value)+app = Pattern $ A.Kleisli match+ where+ match (App val args) = Just (intercalate "," (map prettyPrintValue args), val)+ match _ = Nothing++lam :: Pattern Value ([String], Value)+lam = Pattern $ A.Kleisli match+ where+ match (Abs args val) = Just (map show args, val)+ match _ = Nothing++unary :: UnaryOperator -> String -> Operator Value String+unary op str = Wrap pattern (++)+ where+ pattern :: Pattern Value (String, Value)+ pattern = Pattern $ A.Kleisli match+ where+ match (Unary op' val) | op' == op = Just (str, val)+ match _ = Nothing++binary :: BinaryOperator -> String -> Operator Value String+binary op str = AssocR pattern (\v1 v2 -> v1 ++ " " ++ str ++ " " ++ v2)+ where+ pattern :: Pattern Value (Value, Value)+ pattern = Pattern $ A.Kleisli match+ where+ match (Binary op' v1 v2) | op' == op = Just (v1, v2)+ match _ = Nothing++prettyPrintValue :: Value -> String+prettyPrintValue = fromMaybe (error "Incomplete pattern") . pattern matchValue+ where+ matchValue :: Pattern Value String+ matchValue = buildPrettyPrinter operators (literals <+> fmap parens matchValue)+ operators :: OperatorTable Value String+ operators =+ OperatorTable [ [ Wrap accessor $ \prop val -> val ++ "." ++ prop ]+ , [ Wrap indexer $ \index val -> val ++ "[" ++ index ++ "]" ]+ , [ Wrap objectUpdate $ \ps val -> val ++ "{ " ++ intercalate ", " ps ++ " }" ]+ , [ Wrap app $ \args val -> val ++ "(" ++ args ++ ")" ]+ , [ Split lam $ \args val -> "function (" ++ intercalate "," args ++ ") { return " ++ prettyPrintValue val ++ "; }" ]+ , [ Wrap ifThenElse $ \(th, el) cond -> cond ++ " ? " ++ prettyPrintValue th ++ " : " ++ prettyPrintValue el ]+ , [ binary LessThan "<" ]+ , [ binary LessThanOrEqualTo "<=" ]+ , [ binary GreaterThan ">" ]+ , [ binary GreaterThanOrEqualTo ">=" ]+ , [ unary Not "!" ]+ , [ unary BitwiseNot "~" ]+ , [ unary Negate "-" ]+ , [ binary Multiply "*" ]+ , [ binary Divide "/" ]+ , [ binary Modulus "%" ]+ , [ binary Concat "++" ]+ , [ binary Add "+" ]+ , [ binary Subtract "-" ]+ , [ binary ShiftLeft "<<" ]+ , [ binary ShiftRight ">>" ]+ , [ binary ZeroFillShiftRight ">>>" ]+ , [ binary EqualTo "==" ]+ , [ binary NotEqualTo "!=" ]+ , [ binary BitwiseAnd "&" ]+ , [ binary BitwiseXor "^" ]+ , [ binary BitwiseOr "|" ]+ , [ binary And "&&" ]+ , [ binary Or "||" ]+ ]++prettyPrintBinder :: Binder -> String+prettyPrintBinder NullBinder = "_"+prettyPrintBinder (StringBinder str) = show str+prettyPrintBinder (NumberBinder num) = either show show num+prettyPrintBinder (BooleanBinder True) = "true"+prettyPrintBinder (BooleanBinder False) = "false"+prettyPrintBinder (VarBinder ident) = show ident+prettyPrintBinder (NullaryBinder ctor) = ctor+prettyPrintBinder (UnaryBinder ctor b) = ctor ++ prettyPrintBinder b+prettyPrintBinder (ObjectBinder bs) = "{ " ++ intercalate ", " (map (uncurry prettyPrintObjectPropertyBinder) bs) ++ " }"+prettyPrintBinder (ArrayBinder bs rest) = "[ " ++ intercalate ", " (map prettyPrintBinder bs) ++ maybe "" (("; " ++) . prettyPrintBinder) rest ++ " ]"+prettyPrintBinder (NamedBinder ident binder) = show ident ++ "@" ++ prettyPrintBinder binder+prettyPrintBinder (GuardedBinder cond binder) = prettyPrintBinder binder ++ " | " ++ prettyPrintValue cond++prettyPrintObjectPropertyBinder :: String -> Binder -> String+prettyPrintObjectPropertyBinder key binder = key ++ ": " ++ prettyPrintBinder binder++prettyPrintObjectProperty :: String -> Value -> String+prettyPrintObjectProperty key value = key ++ ": " ++ prettyPrintValue value++prettyPrintStatement :: Statement -> String+prettyPrintStatement (VariableIntroduction ident value) = "var " ++ show ident ++ " = " ++ prettyPrintValue value+prettyPrintStatement (Assignment target value) = show target ++ " = " ++ prettyPrintValue value+prettyPrintStatement (While cond sts) = "while " ++ prettyPrintValue cond ++ ": {" ++ intercalate ";" (map prettyPrintStatement sts) ++ " }"+prettyPrintStatement (For ident start end sts) = "for " ++ show ident+ ++ " <- " ++ prettyPrintValue start+ ++ " until " ++ prettyPrintValue end ++ ": {"+ ++ intercalate "; " (map prettyPrintStatement sts) ++ " }"+prettyPrintStatement (ForEach ident arr sts) = "foreach " ++ show ident+ ++ " in " ++ prettyPrintValue arr ++ ": {"+ ++ intercalate "; " (map prettyPrintStatement sts) ++ " }"+prettyPrintStatement (If ifst) = prettyPrintIfStatement ifst+prettyPrintStatement (Return value) = "return " ++ prettyPrintValue value++prettyPrintIfStatement :: IfStatement -> String+prettyPrintIfStatement (IfStatement cond thens elst) =+ "if "+ ++ prettyPrintValue cond ++ ": {"+ ++ intercalate "; " (map prettyPrintStatement thens) ++ " }"+ ++ maybe "" prettyPrintElseStatement elst++prettyPrintElseStatement :: ElseStatement -> String+prettyPrintElseStatement (Else sts) = "else: {" ++ intercalate "; " (map prettyPrintStatement sts) ++ " }"+prettyPrintElseStatement (ElseIf ifst) = "else " ++ prettyPrintIfStatement ifst
+ src/Language/PureScript/TypeChecker.hs view
@@ -0,0 +1,96 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.TypeChecker+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++{-# LANGUAGE FlexibleInstances #-}++module Language.PureScript.TypeChecker (+ module T,+ typeCheckAll+) where++import Language.PureScript.TypeChecker.Monad as T+import Language.PureScript.TypeChecker.Kinds as T+import Language.PureScript.TypeChecker.Types as T+import Language.PureScript.TypeChecker.Synonyms as T++import Data.List+import Data.Maybe+import Data.Function+import qualified Data.Map as M++import Language.PureScript.Values+import Language.PureScript.Types+import Language.PureScript.Names+import Language.PureScript.Kinds+import Language.PureScript.Declarations++import Control.Monad (forM_)+import Control.Monad.State+import Control.Monad.Error++typeCheckAll :: [Declaration] -> Check ()+typeCheckAll [] = return ()+typeCheckAll (DataDeclaration name args dctors : rest) = do+ rethrow (("Error in type constructor " ++ name ++ ": ") ++) $ do+ env <- getEnv+ guardWith (name ++ " is already defined") $ not $ M.member name (types env)+ ctorKind <- kindsOf (Just name) args (mapMaybe snd dctors)+ putEnv $ env { types = M.insert name (ctorKind, Data) (types env) }+ forM_ dctors $ \(dctor, maybeTy) ->+ rethrow (("Error in data constructor " ++ name ++ ": ") ++) $ do+ env' <- getEnv+ guardWith (dctor ++ " is already defined") $ not $ M.member dctor (dataConstructors env')+ let retTy = foldl TypeApp (TypeConstructor name) (map TypeVar args)+ let dctorTy = maybe retTy (\ty -> Function [ty] retTy) maybeTy+ let polyType = PolyType args dctorTy+ putEnv $ env' { dataConstructors = M.insert dctor polyType (dataConstructors env') }+ typeCheckAll rest+typeCheckAll (TypeSynonymDeclaration name args ty : rest) = do+ rethrow (("Error in type synonym " ++ name ++ ": ") ++) $ do+ env <- getEnv+ guardWith (name ++ " is already defined") $ not $ M.member name (types env)+ kind <- kindsOf (Just name) args [ty]+ putEnv $ env { types = M.insert name (kind, TypeSynonym) (types env)+ , typeSynonyms = M.insert name (args, ty) (typeSynonyms env) }+ typeCheckAll rest+typeCheckAll (TypeDeclaration name ty : ValueDeclaration name' val : rest) | name == name' =+ typeCheckAll (ValueDeclaration name (TypedValue val ty) : rest)+typeCheckAll (TypeDeclaration name _ : _) = throwError $ "Orphan type declaration for " ++ show name+typeCheckAll (ValueDeclaration name val : rest) = do+ rethrow (("Error in declaration " ++ show name ++ ": ") ++) $ do+ env <- getEnv+ case M.lookup name (names env) of+ Just ty -> throwError $ show name ++ " is already defined"+ Nothing -> do+ ty <- typeOf name val+ putEnv (env { names = M.insert name (ty, Value) (names env) })+ typeCheckAll rest+typeCheckAll (ExternDataDeclaration name kind : rest) = do+ env <- getEnv+ guardWith (name ++ " is already defined") $ not $ M.member name (types env)+ putEnv $ env { types = M.insert name (kind, TypeSynonym) (types env) }+ typeCheckAll rest+typeCheckAll (ExternDeclaration name ty : rest) = do+ rethrow (("Error in extern declaration " ++ show name ++ ": ") ++) $ do+ env <- getEnv+ kind <- kindOf ty+ guardWith "Expected kind *" $ kind == Star+ case M.lookup name (names env) of+ Just _ -> throwError $ show name ++ " is already defined"+ Nothing -> putEnv (env { names = M.insert name (ty, Extern) (names env) })+ typeCheckAll rest+typeCheckAll (FixityDeclaration _ name : rest) = do+ typeCheckAll rest+ env <- getEnv+ guardWith ("Fixity declaration with no binding: " ++ name) $ M.member (Op name) $ names env
+ src/Language/PureScript/TypeChecker/Kinds.hs view
@@ -0,0 +1,182 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.TypeChecker.Kinds+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++{-# LANGUAGE DeriveDataTypeable #-}++module Language.PureScript.TypeChecker.Kinds (+ KindConstraint(..),+ KindSolution(..),+ kindsOf,+ kindOf+) where++import Data.List+import Data.Maybe (fromMaybe)+import Data.Function+import Data.Data++import Language.PureScript.Types+import Language.PureScript.Kinds+import Language.PureScript.Declarations+import Language.PureScript.TypeChecker.Monad+import Language.PureScript.Pretty++import Control.Monad.State+import Control.Monad.Error++import Control.Applicative+import Control.Arrow (Kleisli(..), (***))+import qualified Control.Category as C++import qualified Data.Map as M++data KindConstraintOrigin+ = DataDeclOrigin+ | TypeOrigin Type+ | RowOrigin Row deriving (Show, Data, Typeable)++prettyPrintKindConstraintOrigin :: KindConstraintOrigin -> String+prettyPrintKindConstraintOrigin (DataDeclOrigin) = "data declaration"+prettyPrintKindConstraintOrigin (TypeOrigin ty) = prettyPrintType ty+prettyPrintKindConstraintOrigin (RowOrigin row) = prettyPrintRow row++data KindConstraint = KindConstraint Int Kind KindConstraintOrigin deriving (Show, Data, Typeable)++newtype KindSolution = KindSolution { runKindSolution :: Int -> Kind }++emptyKindSolution :: KindSolution+emptyKindSolution = KindSolution KUnknown++kindOf :: PolyType -> Check Kind+kindOf (PolyType idents ty) = do+ ns <- replicateM (length idents) fresh+ (cs, n, m) <- kindConstraints (M.fromList (zip idents ns)) ty+ solution <- solveKindConstraints cs emptyKindSolution+ return $ starIfUnknown $ runKindSolution solution n++kindsOf :: Maybe String -> [String] -> [Type] -> Check Kind+kindsOf name args ts = do+ tyCon <- fresh+ nargs <- replicateM (length args) fresh+ (cs, ns, m) <- kindConstraintsAll (maybe id (`M.insert` tyCon) name $ M.fromList (zip args nargs)) ts+ let extraConstraints =+ KindConstraint tyCon (foldr (FunKind . KUnknown) Star nargs) DataDeclOrigin+ : zipWith (\n arg -> KindConstraint n Star (TypeOrigin arg)) ns ts+ solution <- solveKindConstraints (extraConstraints ++ cs) emptyKindSolution+ return $ starIfUnknown $ runKindSolution solution tyCon++starIfUnknown :: Kind -> Kind+starIfUnknown (KUnknown _) = Star+starIfUnknown (FunKind k1 k2) = FunKind (starIfUnknown k1) (starIfUnknown k2)+starIfUnknown k = k++kindConstraintsAll :: M.Map String Int -> [Type] -> Check ([KindConstraint], [Int], M.Map String Int)+kindConstraintsAll m [] = return ([], [], m)+kindConstraintsAll m (t:ts) = do+ (cs, n1, m') <- kindConstraints m t+ (cs', ns, m'') <- kindConstraintsAll m' ts+ return (KindConstraint n1 Star (TypeOrigin t) : cs ++ cs', n1:ns, m'')++kindConstraints :: M.Map String Int -> Type -> Check ([KindConstraint], Int, M.Map String Int)+kindConstraints m a@(Array t) = do+ me <- fresh+ (cs, n1, m') <- kindConstraints m t+ return (KindConstraint n1 Star (TypeOrigin t) : KindConstraint me Star (TypeOrigin a) : cs, me, m')+kindConstraints m o@(Object row) = do+ me <- fresh+ (cs, r, m') <- kindConstraintsForRow m row+ return (KindConstraint me Star (TypeOrigin o) : KindConstraint r Row (RowOrigin row) : cs, me, m')+kindConstraints m f@(Function args ret) = do+ me <- fresh+ (cs, ns, m') <- kindConstraintsAll m args+ (cs', retN, m'') <- kindConstraints m' ret+ return (KindConstraint retN Star (TypeOrigin ret) : KindConstraint me Star (TypeOrigin f) : zipWith (\n arg -> KindConstraint n Star (TypeOrigin arg)) ns args ++ cs ++ cs', me, m'')+kindConstraints m (TypeVar v) =+ case M.lookup v m of+ Just u -> return ([], u, m)+ Nothing -> throwError $ "Unbound type variable " ++ v+kindConstraints m c@(TypeConstructor v) = do+ env <- getEnv+ me <- fresh+ case M.lookup v m of+ Nothing -> case M.lookup v (types env) of+ Nothing -> throwError $ "Unknown type constructor '" ++ v ++ "'"+ Just (kind, _) -> return ([KindConstraint me kind (TypeOrigin c)], me, m)+ Just u -> return ([KindConstraint me (KUnknown u) (TypeOrigin c)], me, m)+kindConstraints m a@(TypeApp t1 t2) = do+ me <- fresh+ (cs1, n1, m1) <- kindConstraints m t1+ (cs2, n2, m2) <- kindConstraints m1 t2+ return (KindConstraint n1 (FunKind (KUnknown n2) (KUnknown me)) (TypeOrigin a) : cs1 ++ cs2, me, m2)+kindConstraints m t = do+ me <- fresh+ return ([KindConstraint me Star (TypeOrigin t)], me, m)++kindConstraintsForRow :: M.Map String Int -> Row -> Check ([KindConstraint], Int, M.Map String Int)+kindConstraintsForRow m r@(RowVar v) = do+ me <- case M.lookup v m of+ Just u -> return u+ Nothing -> fresh+ return ([KindConstraint me Row (RowOrigin r)], me, M.insert v me m)+kindConstraintsForRow m r@REmpty = do+ me <- fresh+ return ([KindConstraint me Row (RowOrigin r)], me, m)+kindConstraintsForRow m r@(RCons _ ty row) = do+ me <- fresh+ (cs1, n1, m1) <- kindConstraints m ty+ (cs2, n2, m2) <- kindConstraintsForRow m1 row+ return (KindConstraint me Row (RowOrigin r) : KindConstraint n1 Star (TypeOrigin ty) : KindConstraint n2 Row (RowOrigin r) : cs1 ++ cs2, me, m2)++solveKindConstraints :: [KindConstraint] -> KindSolution -> Check KindSolution+solveKindConstraints [] s = return s+solveKindConstraints all@(KindConstraint n k t : cs) s = do+ (cs', s') <- rethrow (\err -> "Error in " ++ prettyPrintKindConstraintOrigin t ++ ": " ++ err) $ do+ guardWith "Occurs check failed" $ not $ kindOccursCheck False n k+ let s' = KindSolution $ replaceUnknownKind n k . runKindSolution s+ cs' <- fmap concat $ mapM (substituteKindConstraint n k) cs+ return (cs', s')+ solveKindConstraints cs' s'++substituteKindConstraint :: Int -> Kind -> KindConstraint -> Check [KindConstraint]+substituteKindConstraint n k (KindConstraint m l t)+ | n == m = unifyKinds t k l+ | otherwise = return [KindConstraint m (replaceUnknownKind n k l) t]++replaceUnknownKind :: Int -> Kind -> Kind -> Kind+replaceUnknownKind n k = f+ where+ f (KUnknown m) | m == n = k+ f (FunKind k1 k2) = FunKind (f k2) (f k2)+ f other = other++unifyKinds :: KindConstraintOrigin -> Kind -> Kind -> Check [KindConstraint]+unifyKinds _ (KUnknown u1) (KUnknown u2) | u1 == u2 = return []+unifyKinds t (KUnknown u) k = do+ guardWith "Occurs check failed" $ not $ kindOccursCheck False u k+ return [KindConstraint u k t]+unifyKinds t k (KUnknown u) = do+ guardWith "Occurs check failed" $ not $ kindOccursCheck False u k+ return [KindConstraint u k t]+unifyKinds _ Star Star = return []+unifyKinds _ Row Row = return []+unifyKinds t (FunKind k1 k2) (FunKind k3 k4) = do+ cs1 <- unifyKinds t k1 k3+ cs2 <- unifyKinds t k2 k4+ return $ cs1 ++ cs2+unifyKinds _ k1 k2 = throwError $ "Cannot unify " ++ prettyPrintKind k1 ++ " with " ++ prettyPrintKind k2 ++ "."++kindOccursCheck :: Bool -> Int -> Kind -> Bool+kindOccursCheck b u (KUnknown u') | u == u' = b+kindOccursCheck _ u (FunKind k1 k2) = kindOccursCheck True u k1 || kindOccursCheck True u k2+kindOccursCheck _ _ _ = False
+ src/Language/PureScript/TypeChecker/Monad.hs view
@@ -0,0 +1,67 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.TypeChecker.Monad+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++{-# LANGUAGE GeneralizedNewtypeDeriving, FlexibleInstances #-}++module Language.PureScript.TypeChecker.Monad where++import Language.PureScript.Types+import Language.PureScript.Kinds+import Language.PureScript.Names++import Control.Applicative+import Control.Monad.State+import Control.Monad.Error++import Control.Arrow ((***), first, second)++import qualified Data.Map as M++data NameKind = Value | Extern deriving Show++data TypeDeclarationKind = Data | ExternData | TypeSynonym deriving Show++data Environment = Environment+ { names :: M.Map Ident (PolyType, NameKind)+ , types :: M.Map String (Kind, TypeDeclarationKind)+ , dataConstructors :: M.Map String PolyType+ , typeSynonyms :: M.Map String ([String], Type)+ }++emptyEnvironment :: Environment+emptyEnvironment = Environment M.empty M.empty M.empty M.empty++newtype Check a = Check { unCheck :: StateT (Environment, Int) (Either String) a } deriving (Functor, Monad, Applicative, MonadPlus, MonadState (Environment, Int), MonadError String)++getEnv :: Check Environment+getEnv = fmap fst get++putEnv :: Environment -> Check ()+putEnv env = fmap (first (const env)) get >>= put++fresh :: Check Int+fresh = do+ (env, n) <- get+ put (env, n + 1)+ return n++check :: Check a -> Either String (a, Environment)+check = fmap (second fst) . flip runStateT (emptyEnvironment, 0) . unCheck++guardWith :: (MonadError e m) => e -> Bool -> m ()+guardWith _ True = return ()+guardWith e False = throwError e++rethrow :: (MonadError e m) => (e -> e) -> m a -> m a+rethrow f = flip catchError $ \e -> throwError (f e)
+ src/Language/PureScript/TypeChecker/Synonyms.hs view
@@ -0,0 +1,56 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.TypeChecker.Synonyms+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++{-# LANGUAGE Rank2Types #-}++module Language.PureScript.TypeChecker.Synonyms (+ saturateTypeSynonym,+ saturateAllTypeSynonyms+) where++import Language.PureScript.Types+import Language.PureScript.Declarations++import Data.Maybe (fromMaybe)+import Data.Data+import Data.Generics+import Control.Arrow+import Control.Monad.Writer+import Control.Monad.Error+import qualified Data.Map as M++buildTypeSubstitution :: String -> Int -> Type -> Either String (Maybe Type)+buildTypeSubstitution name n = go n []+ where+ go :: Int -> [Type] -> Type -> Either String (Maybe Type)+ go 0 args (TypeConstructor ctor) | name == ctor = return (Just $ SaturatedTypeSynonym ctor args)+ go n _ (TypeConstructor ctor) | n > 0 && name == ctor = throwError $ "Partially applied type synonym " ++ name+ go n args (TypeApp f arg) = go (n - 1) (arg:args) f+ go _ _ _ = return Nothing++everywhereM' :: (Monad m, Data d) => (forall d. (Data d) => d -> m d) -> d -> m d+everywhereM' f x = do+ y <- f x+ gmapM (everywhereM' f) y++saturateTypeSynonym :: (Data d) => String -> Int -> d -> Either String d+saturateTypeSynonym name n = everywhereM' (mkM replace)+ where+ replace t = fmap (fromMaybe t) $ buildTypeSubstitution name n t++saturateAllTypeSynonyms :: (Data d) => [(String, Int)] -> d -> Either String d+saturateAllTypeSynonyms syns d = foldM (\d (name, n) -> saturateTypeSynonym name n d) d syns+++
+ src/Language/PureScript/TypeChecker/Types.hs view
@@ -0,0 +1,624 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.TypeChecker.Types+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++{-# LANGUAGE DeriveDataTypeable #-}++module Language.PureScript.TypeChecker.Types (+ TypeConstraint(..),+ TypeSolution(..),+ typeOf+) where++import Debug.Trace++import Data.List+import Data.Function+import qualified Data.Data as D+import Data.Generics (everywhere, everywhereM, everything, mkT, mkM, mkQ, extM, extQ)++import Language.PureScript.Values+import Language.PureScript.Types+import Language.PureScript.Kinds+import Language.PureScript.Names+import Language.PureScript.TypeChecker.Monad+import Language.PureScript.TypeChecker.Kinds+import Language.PureScript.TypeChecker.Synonyms+import Language.PureScript.Pretty++import Control.Monad.State+import Control.Monad.Error++import Control.Applicative+import Control.Arrow (Kleisli(..), (***), (&&&), first)+import qualified Control.Category as C++import qualified Data.Map as M++data TypeConstraintOrigin+ = ValueOrigin Value+ | BinderOrigin Binder+ | AssignmentTargetOrigin Ident deriving (Show, D.Data, D.Typeable)++prettyPrintOrigin :: TypeConstraintOrigin -> String+prettyPrintOrigin (ValueOrigin val) = prettyPrintValue val+prettyPrintOrigin (BinderOrigin binder) = prettyPrintBinder binder+prettyPrintOrigin (AssignmentTargetOrigin ident) = show ident++data TypeConstraint+ = TypeConstraint Int Type TypeConstraintOrigin+ | RowConstraint Int Row TypeConstraintOrigin deriving (Show, D.Data, D.Typeable)++newtype TypeSolution = TypeSolution { runTypeSolution :: (Int -> Type, Int -> Row) }++emptyTypeSolution :: TypeSolution+emptyTypeSolution = TypeSolution (TUnknown, RUnknown)++isFunction :: Value -> Bool+isFunction (Abs _ _) = True+isFunction (TypedValue untyped _) = isFunction untyped+isFunction _ = False++allConstraints :: Ident -> Value -> Check ([TypeConstraint], Int)+allConstraints name val | isFunction val = do+ me <- fresh+ (cs, n) <- typeConstraints (M.singleton name me) val+ return (TypeConstraint me (TUnknown n) (ValueOrigin val): cs, n)+allConstraints _ val = typeConstraints M.empty val++typeOf :: Ident -> Value -> Check PolyType+typeOf name val = do+ (cs, n) <- allConstraints name val+ desugared <- replaceAllTypeSynonyms cs+ solution <- solveTypeConstraints desugared emptyTypeSolution+ let ty = fst (runTypeSolution solution) n+ allUnknownsBecameQuantified desugared solution ty+ return $ varIfUnknown $ desaturateAllTypeSynonyms $ setifyAll ty++allUnknownsBecameQuantified :: [TypeConstraint] -> TypeSolution -> Type -> Check ()+allUnknownsBecameQuantified cs solution ty = do+ let+ typesMentioned = findUnknownTypes ty+ unknownTypes = nub $ flip concatMap cs $ \c -> case c of+ TypeConstraint u t _ -> u : findUnknownTypes t+ RowConstraint _ r _ -> findUnknownTypes r+ unsolvedTypes = filter (\n -> TUnknown n == fst (runTypeSolution solution) n) unknownTypes+ guardWith "Unsolved type variable" $ null $ unsolvedTypes \\ typesMentioned+ let+ rowsMentioned = findUnknownRows ty+ unknownRows = nub $ flip concatMap cs $ \c -> case c of+ TypeConstraint _ t _ -> findUnknownRows t+ RowConstraint u r _ -> u : findUnknownRows r+ unsolvedRows = filter (\n -> RUnknown n == snd (runTypeSolution solution) n) unknownRows+ guardWith "Unsolved row variable" $ null $ unsolvedRows \\ rowsMentioned++setify :: Row -> Row+setify = rowFromList . first (M.toList . M.fromList) . rowToList++setifyAll :: (D.Data d) => d -> d+setifyAll = everywhere (mkT setify)++findUnknownTypes :: (D.Data d) => d -> [Int]+findUnknownTypes = everything (++) (mkQ [] f)+ where+ f :: Type -> [Int]+ f (TUnknown n) = [n]+ f _ = []++findTypeVars :: (D.Data d) => d -> [String]+findTypeVars = everything (++) (mkQ [] f)+ where+ f :: Type -> [String]+ f (TypeVar v) = [v]+ f _ = []++findUnknownRows :: (D.Data d) => d -> [Int]+findUnknownRows = everything (++) (mkQ [] f)+ where+ f :: Row -> [Int]+ f (RUnknown n) = [n]+ f _ = []++varIfUnknown :: Type -> PolyType+varIfUnknown ty =+ let+ (ty', m) = flip runState M.empty $ everywhereM (flip extM g $ mkM f) ty+ in+ PolyType (sort $ nub $ M.elems m ++ findTypeVars ty) ty'+ where+ f :: Type -> State (M.Map Int String) Type+ f (TUnknown n) = do+ m <- get+ case M.lookup n m of+ Nothing -> do+ let name = 't' : show (M.size m)+ put $ M.insert n name m+ return $ TypeVar name+ Just name -> return $ TypeVar name+ f t = return t+ g :: Row -> State (M.Map Int String) Row+ g (RUnknown n) = do+ m <- get+ case M.lookup n m of+ Nothing -> do+ let name = 'r' : show (M.size m)+ put $ M.insert n name m+ return $ RowVar name+ Just name -> return $ RowVar name+ g r = return r++replaceTypeVars :: M.Map String Type -> Type -> Type+replaceTypeVars m = everywhere (mkT replace)+ where+ replace (TypeVar v) = case M.lookup v m of+ Just ty -> ty+ _ -> TypeVar v+ replace t = t++replaceVarsWithUnknowns :: [String] -> Type -> Check Type+replaceVarsWithUnknowns idents = flip evalStateT M.empty . everywhereM (flip extM f $ mkM g)+ where+ f :: Type -> StateT (M.Map String Int) Check Type+ f (TypeVar var) | var `elem` idents = do+ m <- get+ n <- lift fresh+ case M.lookup var m of+ Nothing -> do+ put (M.insert var n m)+ return $ TUnknown n+ Just u -> return $ TUnknown u+ f t = return t+ g :: Row -> StateT (M.Map String Int) Check Row+ g (RowVar var) | var `elem` idents = do+ m <- get+ n <- lift fresh+ case M.lookup var m of+ Nothing -> do+ put (M.insert var n m)+ return $ RUnknown n+ Just u -> return $ RUnknown u+ g r = return r++replaceAllTypeSynonyms :: (D.Data d) => d -> Check d+replaceAllTypeSynonyms d = do+ env <- getEnv+ let syns = map (\(name, (args, _)) -> (name, length args)) . M.toList $ typeSynonyms env+ either throwError return $ saturateAllTypeSynonyms syns d++desaturateAllTypeSynonyms :: (D.Data d) => d -> d+desaturateAllTypeSynonyms = everywhere (mkT replace)+ where+ replace (SaturatedTypeSynonym name args) = foldl TypeApp (TypeConstructor name) args+ replace t = t++replaceType :: (D.Data d) => Int -> Type -> d -> d+replaceType n t = everywhere (mkT go)+ where+ go (TUnknown m) | m == n = t+ go t = t++replaceRow :: (D.Data d) => Int -> Row -> d -> d+replaceRow n r = everywhere (mkT go)+ where+ go (RUnknown m) | m == n = r+ go r = r++typeOccursCheck :: Int -> Type -> Check ()+typeOccursCheck u (TUnknown _) = return ()+typeOccursCheck u t = when (occursCheck u t) $ throwError $ "Occurs check failed: " ++ show u ++ " = " ++ prettyPrintType t++rowOccursCheck :: Int -> Row -> Check ()+rowOccursCheck u (RUnknown _) = return ()+rowOccursCheck u r = when (occursCheck u r) $ throwError $ "Occurs check failed: " ++ show u ++ " = " ++ prettyPrintRow r++occursCheck :: (D.Data d) => Int -> d -> Bool+occursCheck u = everything (||) $ flip extQ g $ mkQ False f+ where+ f (TUnknown u') | u' == u = True+ f _ = False+ g (RUnknown u') | u' == u = True+ g _ = False++typesToRow :: [(String, Type)] -> Row+typesToRow [] = REmpty+typesToRow ((name, ty):tys) = RCons name ty (typesToRow tys)++rowToList :: Row -> ([(String, Type)], Row)+rowToList (RCons name ty row) = let (tys, rest) = rowToList row+ in ((name, ty):tys, rest)+rowToList r = ([], r)++rowFromList :: ([(String, Type)], Row) -> Row+rowFromList ([], r) = r+rowFromList ((name, t):ts, r) = RCons name t (rowFromList (ts, r))++ensureNoDuplicateProperties :: [(String, Value)] -> Check ()+ensureNoDuplicateProperties ps = guardWith "Duplicate property names" $ length (nub . map fst $ ps) == length ps++typeConstraints :: M.Map Ident Int -> Value -> Check ([TypeConstraint], Int)+typeConstraints _ v@(NumericLiteral _) = do+ me <- fresh+ return ([TypeConstraint me Number (ValueOrigin v)], me)+typeConstraints _ v@(StringLiteral _) = do+ me <- fresh+ return ([TypeConstraint me String (ValueOrigin v)], me)+typeConstraints _ v@(BooleanLiteral _) = do+ me <- fresh+ return ([TypeConstraint me Boolean (ValueOrigin v)], me)+typeConstraints m v@(ArrayLiteral vals) = do+ all <- mapM (typeConstraints m) vals+ let (cs, ns) = (concatMap fst &&& map snd) all+ me <- fresh+ return (cs ++ zipWith (\n el -> TypeConstraint me (Array $ TUnknown n) (ValueOrigin el)) ns vals, me)+typeConstraints m u@(Unary op val) = do+ (cs, n1) <- typeConstraints m val+ me <- fresh+ return (cs ++ unaryOperatorConstraints u op n1 me, me)+typeConstraints m b@(Binary op left right) = do+ (cs1, n1) <- typeConstraints m left+ (cs2, n2) <- typeConstraints m right+ me <- fresh+ return (cs1 ++ cs2 ++ binaryOperatorConstraints b op n1 n2 me, me)+typeConstraints m v@(ObjectLiteral ps) = do+ ensureNoDuplicateProperties ps+ all <- mapM (typeConstraints m . snd) ps+ let (cs, ns) = (concatMap fst &&& map snd) all+ me <- fresh+ let tys = zipWith (\(name, _) u -> (name, TUnknown u)) ps ns+ return (TypeConstraint me (Object (typesToRow tys)) (ValueOrigin v) : cs, me)+typeConstraints m v@(ObjectUpdate o ps) = do+ ensureNoDuplicateProperties ps+ (cs1, n1) <- typeConstraints m o+ all <- mapM (typeConstraints m . snd) ps+ let (cs2, ns) = (concatMap fst &&& map snd) all+ row <- fresh+ let tys = zipWith (\(name, _) u -> (name, TUnknown u)) ps ns+ return (TypeConstraint n1 (Object (rowFromList (tys, RUnknown row))) (ValueOrigin v) : cs1 ++ cs2, n1)+typeConstraints m v@(Indexer index val) = do+ (cs1, n1) <- typeConstraints m index+ (cs2, n2) <- typeConstraints m val+ me <- fresh+ return (TypeConstraint n1 Number (ValueOrigin index) : TypeConstraint n2 (Array (TUnknown me)) (ValueOrigin v) : cs1 ++ cs2, me)+typeConstraints m v@(Accessor prop val) = do+ (cs, n1) <- typeConstraints m val+ me <- fresh+ rest <- fresh+ return (TypeConstraint n1 (Object (RCons prop (TUnknown me) (RUnknown rest))) (ValueOrigin v) : cs, me)+typeConstraints m v@(Abs args ret) = do+ ns <- replicateM (length args) fresh+ let m' = m `M.union` M.fromList (zip args ns)+ (cs, n') <- typeConstraints m' ret+ me <- fresh+ return (TypeConstraint me (Function (map TUnknown ns) (TUnknown n')) (ValueOrigin v) : cs, me)+typeConstraints m v@(App f xs) = do+ (cs1, n1) <- typeConstraints m f+ all <- mapM (typeConstraints m) xs+ let (cs2, ns) = (concatMap fst &&& map snd) all+ me <- fresh+ return (TypeConstraint n1 (Function (map TUnknown ns) (TUnknown me)) (ValueOrigin v) : cs1 ++ cs2, me)+typeConstraints m v@(Var var) =+ case M.lookup var m of+ Nothing -> do+ env <- getEnv+ case M.lookup var (names env) of+ Nothing -> throwError $ show var ++ " is undefined"+ Just (PolyType idents ty, _) -> do+ me <- fresh+ replaced <- replaceVarsWithUnknowns idents ty+ return ([TypeConstraint me replaced (ValueOrigin v)], me)+ Just u -> do+ me <- fresh+ return ([TypeConstraint u (TUnknown me) (ValueOrigin v)], me)+typeConstraints m (Block ss) = do+ ret <- fresh+ (cs, allCodePathsReturn, _) <- typeConstraintsForBlock m M.empty ret ss+ guardWith "Block is missing a return statement" allCodePathsReturn+ return (cs, ret)+typeConstraints m v@(Constructor c) = do+ env <- getEnv+ case M.lookup c (dataConstructors env) of+ Nothing -> throwError $ "Constructor " ++ c ++ " is undefined"+ Just (PolyType idents ty) -> do+ me <- fresh+ replaced <- replaceVarsWithUnknowns idents ty+ return ([TypeConstraint me replaced (ValueOrigin v)], me)+typeConstraints m (Case val binders) = do+ (cs1, n1) <- typeConstraints m val+ ret <- fresh+ cs2 <- typeConstraintsForBinders m n1 ret binders+ return (cs1 ++ cs2, ret)+typeConstraints m v@(IfThenElse cond th el) = do+ (cs1, n1) <- typeConstraints m cond+ (cs2, n2) <- typeConstraints m th+ (cs3, n3) <- typeConstraints m el+ return (TypeConstraint n1 Boolean (ValueOrigin cond) : TypeConstraint n2 (TUnknown n3) (ValueOrigin v) : cs1 ++ cs2 ++ cs3, n2)+typeConstraints m v@(TypedValue val poly@(PolyType idents ty)) = do+ kind <- kindOf poly+ guardWith ("Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star+ (cs, n1) <- typeConstraints m val+ return (TypeConstraint n1 ty (ValueOrigin v) : cs, n1)++unaryOperatorConstraints :: Value -> UnaryOperator -> Int -> Int -> [TypeConstraint]+unaryOperatorConstraints v Negate val result = [TypeConstraint val Number (ValueOrigin v), TypeConstraint result Number (ValueOrigin v)]+unaryOperatorConstraints v Not val result = [TypeConstraint val Boolean (ValueOrigin v), TypeConstraint result Boolean (ValueOrigin v)]+unaryOperatorConstraints v BitwiseNot val result = [TypeConstraint val Number (ValueOrigin v), TypeConstraint result Number (ValueOrigin v)]++binaryOperatorConstraints :: Value -> BinaryOperator -> Int -> Int -> Int -> [TypeConstraint]+binaryOperatorConstraints v Add = symBinOpConstraints v Number+binaryOperatorConstraints v Subtract = symBinOpConstraints v Number+binaryOperatorConstraints v Multiply = symBinOpConstraints v Number+binaryOperatorConstraints v Divide = symBinOpConstraints v Number+binaryOperatorConstraints v Modulus = symBinOpConstraints v Number+binaryOperatorConstraints v LessThan = asymBinOpConstraints v Number Boolean+binaryOperatorConstraints v LessThanOrEqualTo = asymBinOpConstraints v Number Boolean+binaryOperatorConstraints v GreaterThan = asymBinOpConstraints v Number Boolean+binaryOperatorConstraints v GreaterThanOrEqualTo = asymBinOpConstraints v Number Boolean+binaryOperatorConstraints v BitwiseAnd = symBinOpConstraints v Number+binaryOperatorConstraints v BitwiseOr = symBinOpConstraints v Number+binaryOperatorConstraints v BitwiseXor = symBinOpConstraints v Number+binaryOperatorConstraints v ShiftLeft = symBinOpConstraints v Number+binaryOperatorConstraints v ShiftRight = symBinOpConstraints v Number+binaryOperatorConstraints v ZeroFillShiftRight = symBinOpConstraints v Number+binaryOperatorConstraints v EqualTo = equalityBinOpConstraints v+binaryOperatorConstraints v NotEqualTo = equalityBinOpConstraints v+binaryOperatorConstraints v And = symBinOpConstraints v Boolean+binaryOperatorConstraints v Or = symBinOpConstraints v Boolean+binaryOperatorConstraints v Concat = symBinOpConstraints v String++equalityBinOpConstraints :: Value -> Int -> Int -> Int -> [TypeConstraint]+equalityBinOpConstraints v left right result = [TypeConstraint left (TUnknown right) (ValueOrigin v), TypeConstraint result Boolean (ValueOrigin v)]++symBinOpConstraints :: Value -> Type -> Int -> Int -> Int -> [TypeConstraint]+symBinOpConstraints v ty = asymBinOpConstraints v ty ty++asymBinOpConstraints :: Value -> Type -> Type -> Int -> Int -> Int -> [TypeConstraint]+asymBinOpConstraints v ty res left right result = [TypeConstraint left ty (ValueOrigin v), TypeConstraint right ty (ValueOrigin v), TypeConstraint result res (ValueOrigin v)]++typeConstraintsForBinder :: Int -> Binder -> Check ([TypeConstraint], M.Map Ident Int)+typeConstraintsForBinder _ NullBinder = return ([], M.empty)+typeConstraintsForBinder val b@(StringBinder _) = constantBinder b val String+typeConstraintsForBinder val b@(NumberBinder _) = constantBinder b val Number+typeConstraintsForBinder val b@(BooleanBinder _) = constantBinder b val Boolean+typeConstraintsForBinder val b@(VarBinder name) = do+ me <- fresh+ return ([TypeConstraint me (TUnknown val) (BinderOrigin b)], M.singleton name me)+typeConstraintsForBinder val b@(NullaryBinder ctor) = do+ env <- getEnv+ case M.lookup ctor (dataConstructors env) of+ Just (PolyType args ret) -> do+ ret' <- replaceVarsWithUnknowns args ret+ return ([TypeConstraint val ret' (BinderOrigin b)], M.empty)+ _ -> throwError $ "Constructor " ++ ctor ++ " is not defined"+typeConstraintsForBinder val b@(UnaryBinder ctor binder) = do+ env <- getEnv+ case M.lookup ctor (dataConstructors env) of+ Just (PolyType idents f@(Function [_] _)) -> do+ obj <- fresh+ (Function [ty] ret) <- replaceVarsWithUnknowns idents f+ (cs, m1) <- typeConstraintsForBinder obj binder+ return (TypeConstraint val ret (BinderOrigin b) : TypeConstraint obj ty (BinderOrigin b) : cs, m1)+ Just _ -> throwError $ ctor ++ " is not a unary constructor"+ _ -> throwError $ "Constructor " ++ ctor ++ " is not defined"+typeConstraintsForBinder val b@(ObjectBinder props) = do+ row <- fresh+ rest <- fresh+ (cs, m1) <- typeConstraintsForProperties row (RUnknown rest) props+ return (TypeConstraint val (Object (RUnknown row)) (BinderOrigin b) : cs, m1)+ where+ typeConstraintsForProperties :: Int -> Row -> [(String, Binder)] -> Check ([TypeConstraint], M.Map Ident Int)+ typeConstraintsForProperties nrow row [] = return ([RowConstraint nrow row (BinderOrigin b)], M.empty)+ typeConstraintsForProperties nrow row ((name, binder):binders) = do+ propTy <- fresh+ (cs1, m1) <- typeConstraintsForBinder propTy binder+ (cs2, m2) <- typeConstraintsForProperties nrow (RCons name (TUnknown propTy) row) binders+ return (cs1 ++ cs2, m1 `M.union` m2)+typeConstraintsForBinder val b@(ArrayBinder binders rest) = do+ el <- fresh+ all <- mapM (typeConstraintsForBinder el) binders+ let (cs1, m1) = (concatMap fst &&& M.unions . map snd) all+ let arrayConstraint = TypeConstraint val (Array (TUnknown el)) (BinderOrigin b)+ case rest of+ Nothing -> return (arrayConstraint : cs1, m1)+ Just binder -> do+ (cs2, m2) <- typeConstraintsForBinder val binder+ return (arrayConstraint : cs1 ++ cs2, m1 `M.union` m2)+typeConstraintsForBinder val b@(NamedBinder name binder) = do+ me <- fresh+ (cs, m) <- typeConstraintsForBinder val binder+ return (TypeConstraint me (TUnknown val) (BinderOrigin b) : cs, M.insert name me m)+typeConstraintsForBinder val b@(GuardedBinder cond binder) = do+ (cs1, m) <- typeConstraintsForBinder val binder+ (cs2, n) <- typeConstraints m cond+ return (TypeConstraint n Boolean (ValueOrigin cond) : cs1 ++ cs2, m)++constantBinder :: Binder -> Int -> Type -> Check ([TypeConstraint], M.Map Ident Int)+constantBinder b val ty = return ([TypeConstraint val ty (BinderOrigin b)], M.empty)++typeConstraintsForBinders :: M.Map Ident Int -> Int -> Int -> [(Binder, Value)] -> Check [TypeConstraint]+typeConstraintsForBinders _ _ _ [] = return []+typeConstraintsForBinders m nval ret ((binder, val):bs) = do+ (cs1, m1) <- typeConstraintsForBinder nval binder+ (cs2, n2) <- typeConstraints (m `M.union` m1) val+ cs3 <- typeConstraintsForBinders m nval ret bs+ return (TypeConstraint n2 (TUnknown ret) (BinderOrigin binder) : cs1 ++ cs2 ++ cs3)++assignVariable :: Ident -> M.Map Ident Int -> Check ()+assignVariable name m =+ case M.lookup name m of+ Nothing -> return ()+ Just _ -> throwError $ "Variable with name " ++ show name ++ " already exists."++typeConstraintsForStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> Statement -> Check ([TypeConstraint], Bool, M.Map Ident Int)+typeConstraintsForStatement m mass ret (VariableIntroduction name val) = do+ assignVariable name (m `M.union` mass)+ (cs1, n1) <- typeConstraints m val+ return (cs1, False, M.insert name n1 mass)+typeConstraintsForStatement m mass ret (Assignment ident val) = do+ (cs1, n1) <- typeConstraints m val+ case M.lookup ident mass of+ Nothing -> throwError $ "No local variable with name " ++ show ident+ Just ty ->+ return (TypeConstraint n1 (TUnknown ty) (AssignmentTargetOrigin ident) : cs1, False, mass)+typeConstraintsForStatement m mass ret (While val inner) = do+ (cs1, n1) <- typeConstraints m val+ (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret inner+ return (TypeConstraint n1 Boolean (ValueOrigin val) : cs1 ++ cs2, allCodePathsReturn, mass)+typeConstraintsForStatement m mass ret (If ifst) = do+ (cs, allCodePathsReturn) <- typeConstraintsForIfStatement m mass ret ifst+ return (cs, allCodePathsReturn, mass)+typeConstraintsForStatement m mass ret (For ident start end inner) = do+ assignVariable ident (m `M.union` mass)+ (cs1, n1) <- typeConstraints (m `M.union` mass) start+ (cs2, n2) <- typeConstraints (m `M.union` mass) end+ let mass1 = M.insert ident n1 mass+ (cs3, allCodePathsReturn, _) <- typeConstraintsForBlock (m `M.union` mass1) mass1 ret inner+ return (TypeConstraint n1 Number (ValueOrigin start) : TypeConstraint n2 Number (ValueOrigin end) : cs1 ++ cs2 ++ cs3, allCodePathsReturn, mass)+typeConstraintsForStatement m mass ret (ForEach ident vals inner) = do+ assignVariable ident (m `M.union` mass)+ val <- fresh+ (cs1, n1) <- typeConstraints (m `M.union` mass) vals+ let mass1 = M.insert ident val mass+ (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock (m `M.union` mass1) mass1 ret inner+ guardWith "Cannot return from within a foreach block" $ not allCodePathsReturn+ return (TypeConstraint n1 (Array (TUnknown val)) (ValueOrigin vals) : cs1 ++ cs2, False, mass)+typeConstraintsForStatement m mass ret (Return val) = do+ (cs1, n1) <- typeConstraints (m `M.union` mass) val+ return (TypeConstraint n1 (TUnknown ret) (ValueOrigin val) : cs1, True, mass)++typeConstraintsForIfStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> IfStatement -> Check ([TypeConstraint], Bool)+typeConstraintsForIfStatement m mass ret (IfStatement val thens Nothing) = do+ (cs1, n1) <- typeConstraints m val+ (cs2, _, _) <- typeConstraintsForBlock m mass ret thens+ return (TypeConstraint n1 Boolean (ValueOrigin val) : cs1 ++ cs2, False)+typeConstraintsForIfStatement m mass ret (IfStatement val thens (Just elses)) = do+ (cs1, n1) <- typeConstraints m val+ (cs2, allCodePathsReturn1, _) <- typeConstraintsForBlock m mass ret thens+ (cs3, allCodePathsReturn2) <- typeConstraintsForElseStatement m mass ret elses+ return (TypeConstraint n1 Boolean (ValueOrigin val) : cs1 ++ cs2 ++ cs3, allCodePathsReturn1 && allCodePathsReturn2)++typeConstraintsForElseStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> ElseStatement -> Check ([TypeConstraint], Bool)+typeConstraintsForElseStatement m mass ret (Else elses) = do+ (cs, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret elses+ return (cs, allCodePathsReturn)+typeConstraintsForElseStatement m mass ret (ElseIf ifst) = do+ (cs, allCodePathsReturn) <- typeConstraintsForIfStatement m mass ret ifst+ return (cs, allCodePathsReturn)++typeConstraintsForBlock :: M.Map Ident Int -> M.Map Ident Int -> Int -> [Statement] -> Check ([TypeConstraint], Bool, M.Map Ident Int)+typeConstraintsForBlock _ mass _ [] = return ([], False, mass)+typeConstraintsForBlock m mass ret (s:ss) = do+ (cs1, b1, mass1) <- typeConstraintsForStatement (m `M.union` mass) mass ret s+ case (b1, ss) of+ (True, []) -> return (cs1, True, mass1)+ (True, _) -> throwError "Unreachable code"+ (False, ss) -> do+ (cs2, b2, mass2) <- typeConstraintsForBlock m mass1 ret ss+ return (cs1 ++ cs2, b2, mass2)++solveTypeConstraints :: [TypeConstraint] -> TypeSolution -> Check TypeSolution+solveTypeConstraints [] s = return s+solveTypeConstraints all@(TypeConstraint n t o:cs) s = do+ (cs', s') <- rethrow (\err -> "Error in " ++ prettyPrintOrigin o ++ ": " ++ err) $ do+ typeOccursCheck n t+ let s' = let (f, g) = runTypeSolution s+ in TypeSolution (replaceType n t . f, replaceType n t . g)+ cs' <- fmap concat $ mapM (substituteTypeInConstraint n t) cs+ return (cs', s')+ solveTypeConstraints cs' s'+solveTypeConstraints (RowConstraint n r o:cs) s = do+ (cs', s') <- rethrow (\err -> "Error in " ++ prettyPrintOrigin o ++ ": " ++ err) $ do+ rowOccursCheck n r+ let s' = let (f, g) = runTypeSolution s+ in TypeSolution (replaceRow n r . f, replaceRow n r . g)+ cs' <- fmap concat $ mapM (substituteRowInConstraint n r) cs+ return (cs', s')+ solveTypeConstraints cs' s'++substituteTypeInConstraint :: Int -> Type -> TypeConstraint -> Check [TypeConstraint]+substituteTypeInConstraint n s (TypeConstraint m t v)+ | n == m = unifyTypes v s t+ | otherwise = return [TypeConstraint m (replaceType n s t) v]+substituteTypeInConstraint n s (RowConstraint m r v)+ = return [RowConstraint m (replaceType n s r) v]++substituteRowInConstraint :: Int -> Row -> TypeConstraint -> Check [TypeConstraint]+substituteRowInConstraint n r (TypeConstraint m t v)+ = return [TypeConstraint m (replaceRow n r t) v]+substituteRowInConstraint n r (RowConstraint m r1 v)+ | m == n = unifyRows v r r1+ | otherwise = return [RowConstraint m (replaceRow n r r1) v]++unifyTypes :: TypeConstraintOrigin -> Type -> Type -> Check [TypeConstraint]+unifyTypes _ (TUnknown u1) (TUnknown u2) | u1 == u2 = return []+unifyTypes o (TUnknown u) t = do+ typeOccursCheck u t+ return [TypeConstraint u t o]+unifyTypes o t (TUnknown u) = do+ typeOccursCheck u t+ return [TypeConstraint u t o]+unifyTypes o (SaturatedTypeSynonym name1 args1) (SaturatedTypeSynonym name2 args2) | name1 == name2 =+ fmap concat $ zipWithM (unifyTypes o) args1 args2+unifyTypes o (SaturatedTypeSynonym name args) ty = do+ env <- getEnv+ case M.lookup name (typeSynonyms env) of+ Just (synArgs, body) -> do+ let m = M.fromList $ zip synArgs args+ let replaced = replaceTypeVars m body+ unifyTypes o replaced ty+ Nothing -> error "Type synonym was not defined"+unifyTypes o ty s@(SaturatedTypeSynonym _ _) = unifyTypes o s ty+unifyTypes _ Number Number = return []+unifyTypes _ String String = return []+unifyTypes _ Boolean Boolean = return []+unifyTypes o (Array s) (Array t) = unifyTypes o s t+unifyTypes o (Object row1) (Object row2) = unifyRows o row1 row2+unifyTypes o (Function args1 ret1) (Function args2 ret2) = do+ guardWith "Function applied to incorrect number of args" $ length args1 == length args2+ cs1 <- fmap concat $ zipWithM (unifyTypes o) args1 args2+ cs2 <- unifyTypes o ret1 ret2+ return $ cs1 ++ cs2+unifyTypes _ (TypeVar v1) (TypeVar v2) | v1 == v2 = return []+unifyTypes _ (TypeConstructor c1) (TypeConstructor c2) | c1 == c2 = return []+unifyTypes o (TypeApp t1 t2) (TypeApp t3 t4) = do+ cs1 <- unifyTypes o t1 t3+ cs2 <- unifyTypes o t2 t4+ return $ cs1 ++ cs2+unifyTypes _ t1 t2 = throwError $ "Cannot unify " ++ prettyPrintType t1 ++ " with " ++ prettyPrintType t2 ++ "."++unifyRows :: TypeConstraintOrigin -> Row -> Row -> Check [TypeConstraint]+unifyRows o r1 r2 =+ let+ (s1, r1') = rowToList r1+ (s2, r2') = rowToList r2+ int = [ (t1, t2) | (name, t1) <- s1, (name', t2) <- s2, name == name' ]+ sd1 = [ (name, t1) | (name, t1) <- s1, name `notElem` map fst s2 ]+ sd2 = [ (name, t2) | (name, t2) <- s2, name `notElem` map fst s1 ]+ in do+ cs1 <- fmap concat $ mapM (uncurry $ unifyTypes o) int+ cs2 <- unifyRows' o sd1 r1' sd2 r2'+ return $ cs1 ++ cs2+ where+ unifyRows' :: TypeConstraintOrigin -> [(String, Type)] -> Row -> [(String, Type)] -> Row -> Check [TypeConstraint]+ unifyRows' o [] (RUnknown u) sd r = do+ rowOccursCheck u r+ return [RowConstraint u (rowFromList (sd, r)) o]+ unifyRows' o sd r [] (RUnknown u) = do+ rowOccursCheck u r+ return [RowConstraint u (rowFromList (sd, r)) o]+ unifyRows' o ns@((name, ty):row) r others (RUnknown u) | not (occursCheck u (ty, row)) = do+ u' <- fresh+ cs <- unifyRows' o row r others (RUnknown u')+ return (RowConstraint u (RCons name ty (RUnknown u')) o : cs)+ unifyRows' _ [] REmpty [] REmpty = return []+ unifyRows' _ [] (RowVar v1) [] (RowVar v2) | v1 == v2 = return []+ unifyRows' _ sd1 r1 sd2 r2 = throwError $ "Cannot unify " ++ prettyPrintRow (rowFromList (sd1, r1)) ++ " with " ++ prettyPrintRow (rowFromList (sd2, r2)) ++ "."
+ src/Language/PureScript/Types.hs view
@@ -0,0 +1,43 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.Types+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++{-# LANGUAGE DeriveDataTypeable #-}++module Language.PureScript.Types where++import Data.Data++data Type+ = TUnknown Int+ | Number+ | String+ | Boolean+ | Array Type+ | Object Row+ | Function [Type] Type+ | TypeVar String+ | TypeConstructor String+ | TypeApp Type Type+ | SaturatedTypeSynonym String [Type] deriving (Show, Eq, Data, Typeable)++data PolyType = PolyType [String] Type deriving (Show, Eq, Data, Typeable)++data Row+ = RUnknown Int+ | RowVar String+ | REmpty+ | RCons String Type Row deriving (Show, Eq, Data, Typeable)++monoType :: Type -> PolyType+monoType = PolyType []
+ src/Language/PureScript/Values.hs view
@@ -0,0 +1,97 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.Values+-- Copyright : (c) Phil Freeman 2013+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++{-# LANGUAGE DeriveDataTypeable #-}++module Language.PureScript.Values where++import Language.PureScript.Types+import Language.PureScript.Names++import Data.Data++data UnaryOperator+ = Negate+ | Not+ | BitwiseNot deriving (Show, Eq, Data, Typeable)++data BinaryOperator+ = Add+ | Subtract+ | Multiply+ | Divide+ | Modulus+ | EqualTo+ | NotEqualTo+ | LessThan+ | LessThanOrEqualTo+ | GreaterThan+ | GreaterThanOrEqualTo+ | And+ | Or+ | BitwiseAnd+ | BitwiseOr+ | BitwiseXor+ | ShiftLeft+ | ShiftRight+ | ZeroFillShiftRight+ | Concat deriving (Show, Eq, Data, Typeable)++data Value+ = NumericLiteral (Either Integer Double)+ | StringLiteral String+ | BooleanLiteral Bool+ | Unary UnaryOperator Value+ | Binary BinaryOperator Value Value+ | ArrayLiteral [Value]+ | Indexer Value Value+ | ObjectLiteral [(String, Value)]+ | Accessor String Value+ | ObjectUpdate Value [(String, Value)]+ | Abs [Ident] Value+ | App Value [Value]+ | Var Ident+ | IfThenElse Value Value Value+ | Block [Statement]+ | Constructor String+ | Case Value [(Binder, Value)]+ | TypedValue Value PolyType deriving (Show, Data, Typeable)++data Statement+ = VariableIntroduction Ident Value+ | Assignment Ident Value+ | While Value [Statement]+ | For Ident Value Value [Statement]+ | ForEach Ident Value [Statement]+ | If IfStatement+ | Return Value deriving (Show, Data, Typeable)++data IfStatement = IfStatement Value [Statement] (Maybe ElseStatement) deriving (Show, Data, Typeable)++data ElseStatement+ = Else [Statement]+ | ElseIf IfStatement deriving (Show, Data, Typeable)++data Binder+ = NullBinder+ | BooleanBinder Bool+ | StringBinder String+ | NumberBinder (Either Integer Double)+ | VarBinder Ident+ | NullaryBinder String+ | UnaryBinder String Binder+ | ObjectBinder [(String, Binder)]+ | ArrayBinder [Binder] (Maybe Binder)+ | NamedBinder Ident Binder+ | GuardedBinder Value Binder deriving (Show, Data, Typeable)
src/Main.hs view
@@ -14,7 +14,7 @@ module Main where -import PureScript+import Language.PureScript import Data.Maybe (mapMaybe) import Data.List (intercalate) import System.Console.CmdTheLine
− src/PureScript.hs
@@ -1,26 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------module PureScript (module P) where--import PureScript.Values as P-import PureScript.Types as P-import PureScript.Kinds as P-import PureScript.Declarations as P-import PureScript.Names as P-import PureScript.Parser as P-import PureScript.CodeGen as P-import PureScript.TypeChecker as P-import PureScript.Pretty as P-
− src/PureScript/CodeGen.hs
@@ -1,21 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.CodeGen--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------module PureScript.CodeGen (- module PureScript.CodeGen.JS,- module PureScript.CodeGen.Externs-) where--import PureScript.CodeGen.JS-import PureScript.CodeGen.Externs
− src/PureScript/CodeGen/Common.hs
@@ -1,80 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.CodeGen.Common--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------{-# LANGUAGE GeneralizedNewtypeDeriving, GADTs #-}--module PureScript.CodeGen.Common where--import Data.Char-import Data.Maybe (fromMaybe)-import Data.List (nub, intersperse, intercalate)-import Data.Function (fix)-import Control.Monad.State-import Control.Applicative (Applicative(..), Alternative(..))-import qualified Control.Category as C-import Control.Category ((>>>))-import qualified Control.Arrow as A-import Control.Arrow ((***), (<+>))--import PureScript.Names-import PureScript.Values-import PureScript.Types-import PureScript.Declarations--identToJs :: Ident -> String-identToJs (Ident name) = name-identToJs (Op op) = concatMap opCharToString op- where- opCharToString :: Char -> String- opCharToString = (:) '$'. show . ord--newtype Pattern a b = Pattern { runPattern :: A.Kleisli Maybe a b } deriving (C.Category, A.Arrow, A.ArrowZero, A.ArrowPlus)--instance Functor (Pattern a) where- fmap f (Pattern p) = Pattern $ A.Kleisli $ fmap f . A.runKleisli p--pattern :: Pattern a b -> a -> Maybe b-pattern = A.runKleisli . runPattern--parens :: String -> String-parens s = ('(':s) ++ ")"--chainl :: Pattern a (a, a) -> (r -> r -> r) -> Pattern a r -> Pattern a r-chainl split f p = fix $ \c -> split >>> ((c <+> p) *** p) >>> A.arr (uncurry f)--chainr :: Pattern a (a, a) -> (r -> r -> r) -> Pattern a r -> Pattern a r-chainr split f p = fix $ \c -> split >>> (p *** (c <+> p)) >>> A.arr (uncurry f)--wrap :: Pattern a (s, a) -> (s -> r -> r) -> Pattern a r -> Pattern a r-wrap split f p = fix $ \c -> split >>> (C.id *** (c <+> p)) >>> A.arr (uncurry f)--split :: Pattern a (s, t) -> (s -> t -> r) -> Pattern a r -> Pattern a r-split s f p = s >>> A.arr (uncurry f)--data OperatorTable a r = OperatorTable { runOperatorTable :: [ [Operator a r] ] }--data Operator a r where- AssocL :: Pattern a (a, a) -> (r -> r -> r) -> Operator a r- AssocR :: Pattern a (a, a) -> (r -> r -> r) -> Operator a r- Wrap :: Pattern a (s, a) -> (s -> r -> r) -> Operator a r- Split :: Pattern a (s, t) -> (s -> t -> r) -> Operator a r--buildPrettyPrinter :: OperatorTable a r -> Pattern a r -> Pattern a r-buildPrettyPrinter table p = foldl (\p' ops -> foldl1 (<+>) (flip map ops $ \op ->- case op of- AssocL pat g -> chainl pat g p'- AssocR pat g -> chainr pat g p'- Wrap pat g -> wrap pat g p'- Split pat g -> split pat g p'- ) <+> p') p $ runOperatorTable table
− src/PureScript/CodeGen/Common/Gen.hs
@@ -1,31 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.CodeGen.Common.Gen--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------{-# LANGUAGE GeneralizedNewtypeDeriving #-}--module PureScript.CodeGen.Common.Gen where--import Control.Monad.State-import Control.Applicative--newtype Gen a = Gen { unGen :: State Int a } deriving (Functor, Applicative, Monad, MonadState Int)--runGen :: Gen a -> a-runGen = flip evalState 0 . unGen--fresh :: Gen String-fresh = do- n <- get- modify (+ 1)- return $ '_' : show n
− src/PureScript/CodeGen/Externs.hs
@@ -1,36 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.CodeGen.Externs--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------module PureScript.CodeGen.Externs (- externToPs-) where--import Data.List (intercalate)-import qualified Data.Map as M-import PureScript.Declarations-import PureScript.TypeChecker.Monad-import PureScript.CodeGen.Pretty.Types-import PureScript.CodeGen.Pretty.Kinds--externToPs :: Environment -> Declaration -> Maybe String-externToPs env (ValueDeclaration name _) = do- (ty, _) <- M.lookup name $ names env- return $ "extern " ++ show name ++ " :: " ++ prettyPrintPolyType ty-externToPs env (ExternDeclaration name ty) =- return $ "extern " ++ show name ++ " :: " ++ prettyPrintPolyType ty-externToPs env (ExternDataDeclaration name kind) =- return $ "extern data " ++ name ++ " :: " ++ prettyPrintKind kind-externToPs env (TypeSynonymDeclaration name args ty) =- return $ "type " ++ name ++ " " ++ unwords args ++ " = " ++ prettyPrintType ty-externToPs _ _ = Nothing
− src/PureScript/CodeGen/JS.hs
@@ -1,232 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.CodeGen.JS--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------module PureScript.CodeGen.JS (- declToJs-) where--import Data.Char-import Data.Maybe (fromMaybe)-import Data.List (intercalate)-import qualified Control.Arrow as A-import Control.Arrow ((<+>))-import Control.Monad (forM)-import Control.Applicative--import PureScript.Types-import PureScript.Values-import PureScript.Names-import PureScript.Declarations-import PureScript.CodeGen.Common-import PureScript.CodeGen.Common.Gen--declToJs :: Declaration -> Maybe String-declToJs (ValueDeclaration ident (Abs args ret)) = Just $ "function " ++ identToJs ident ++ "(" ++ intercalate "," (map identToJs args) ++ ") { return " ++ valueToJs ret ++ "; }"-declToJs (ValueDeclaration ident val) = Just $ "var " ++ identToJs ident ++ " = " ++ valueToJs val ++ ";"-declToJs (DataDeclaration _ _ ctors) =- Just $ flip concatMap ctors $ \(ctor, maybeTy) ->- case maybeTy of- Nothing -> "var " ++ ctor ++ " = { ctor: '" ++ ctor ++ "' };"- Just _ -> "var " ++ ctor ++ " = function (value) { return { ctor: '" ++ ctor ++ "', value: value }; };"-declToJs _ = Nothing--literals :: Pattern Value String-literals = Pattern $ A.Kleisli match- where- match (NumericLiteral n) = Just $ either show show n- match (StringLiteral s) = Just $ show s- match (BooleanLiteral True) = Just "true"- match (BooleanLiteral False) = Just "false"- match (ArrayLiteral xs) = Just $ "[" ++ intercalate "," (map valueToJs xs) ++ "]"- match (ObjectLiteral ps) = Just $ "{" ++ intercalate "," (map objectPropertyToJs ps) ++ "}"- match (ObjectUpdate o ps) = Just $ "Object.extend("- ++ valueToJs o ++ ", { "- ++ intercalate ", " (map objectPropertyToJs ps) ++ " }"- match (Constructor name) = Just name- match (Block sts) = Just $ "(function () {" ++ intercalate ";" (map statementToJs sts) ++ "})()"- match (Case value binders) = Just $ "(" ++ runGen (bindersToJs binders) ++ ")(" ++ valueToJs value ++ ")"- where- bindersToJs :: [(Binder, Value)] -> Gen String- bindersToJs binders = do- valName <- fresh- jss <- forM binders $ \(binder, result) -> do- let js = valueToJs result- binderToJs valName ("return " ++ js ++ ";") binder- return $ "function (" ++ valName ++ ") {" ++ concat jss ++ "throw \"Failed pattern match\"; }"- match (Var ident) = Just (identToJs ident)- match _ = Nothing--ifThenElse :: Pattern Value ((Value, Value), Value)-ifThenElse = Pattern $ A.Kleisli match- where- match (IfThenElse cond th el) = Just ((th, el), cond)- match _ = Nothing--accessor :: Pattern Value (String, Value)-accessor = Pattern $ A.Kleisli match- where- match (Accessor prop val) = Just (prop, val)- match _ = Nothing--indexer :: Pattern Value (String, Value)-indexer = Pattern $ A.Kleisli match- where- match (Indexer index val) = Just (valueToJs index, val)- match _ = Nothing--app :: Pattern Value (String, Value)-app = Pattern $ A.Kleisli match- where- match (App val args) = Just (intercalate "," (map valueToJs args), val)- match _ = Nothing--lam :: Pattern Value ([String], Value)-lam = Pattern $ A.Kleisli match- where- match (Abs args val) = Just (map identToJs args, val)- match _ = Nothing--unary :: UnaryOperator -> String -> Operator Value String-unary op str = Wrap pattern (++)- where- pattern :: Pattern Value (String, Value)- pattern = Pattern $ A.Kleisli match- where- match (Unary op' val) | op' == op = Just (str, val)- match _ = Nothing--binary :: BinaryOperator -> String -> Operator Value String-binary op str = AssocR pattern (\v1 v2 -> v1 ++ " " ++ str ++ " " ++ v2)- where- pattern :: Pattern Value (Value, Value)- pattern = Pattern $ A.Kleisli match- where- match (Binary op' v1 v2) | op' == op = Just (v1, v2)- match _ = Nothing--valueToJs :: Value -> String-valueToJs = fromMaybe (error "Incomplete pattern") . pattern matchValue- where- matchValue :: Pattern Value String- matchValue = buildPrettyPrinter operators (literals <+> fmap parens matchValue)- operators :: OperatorTable Value String- operators =- OperatorTable [ [ Wrap accessor $ \prop val -> val ++ "." ++ prop ]- , [ Wrap indexer $ \index val -> val ++ "[" ++ index ++ "]" ]- , [ Wrap app $ \args val -> val ++ "(" ++ args ++ ")" ]- , [ Split lam $ \args val -> "function (" ++ intercalate "," args ++ ") { return " ++ valueToJs val ++ "; }" ]- , [ Wrap ifThenElse $ \(th, el) cond -> cond ++ " ? " ++ valueToJs th ++ " : " ++ valueToJs el ]- , [ binary LessThan "<" ]- , [ binary LessThanOrEqualTo "<=" ]- , [ binary GreaterThan ">" ]- , [ binary GreaterThanOrEqualTo ">=" ]- , [ unary Not "!" ]- , [ unary BitwiseNot "~" ]- , [ unary Negate "-" ]- , [ binary Multiply "*" ]- , [ binary Divide "/" ]- , [ binary Modulus "%" ]- , [ binary Concat "+" ]- , [ binary Add "+" ]- , [ binary Subtract "-" ]- , [ binary ShiftLeft "<<" ]- , [ binary ShiftRight ">>" ]- , [ binary ZeroFillShiftRight ">>>" ]- , [ binary EqualTo "===" ]- , [ binary NotEqualTo "!==" ]- , [ binary BitwiseAnd "&" ]- , [ binary BitwiseXor "^" ]- , [ binary BitwiseOr "|" ]- , [ binary And "&&" ]- , [ binary Or "||" ]- ]--binderToJs :: String -> String -> Binder -> Gen String-binderToJs varName done NullBinder = return done-binderToJs varName done (StringBinder str) =- return $ "if (" ++ varName ++ " === \"" ++ str ++ "\") {" ++ done ++ " }"-binderToJs varName done (NumberBinder num) =- return $ "if (" ++ varName ++ " === " ++ either show show num ++ ") {" ++ done ++ " }"-binderToJs varName done (BooleanBinder True) =- return $ "if (" ++ varName ++ ") {" ++ done ++ " }"-binderToJs varName done (BooleanBinder False) =- return $ "if (!" ++ varName ++ ") {" ++ done ++ " }"-binderToJs varName done (VarBinder ident) =- return $ "var " ++ identToJs ident ++ " = " ++ varName ++ "; " ++ done-binderToJs varName done (NullaryBinder ctor) =- return $ "if (" ++ varName ++ ".ctor === \"" ++ ctor ++ "\") { " ++ done ++ " }"-binderToJs varName done (UnaryBinder ctor b) = do- value <- fresh- js <- binderToJs value done b- return $ "if (" ++ varName ++ ".ctor === \"" ++ ctor ++ "\") { " ++ "var " ++ value ++ " = " ++ varName ++ ".value; " ++ js ++ " }"-binderToJs varName done (ObjectBinder bs) = go done bs- where- go done [] = return done- go done ((prop, binder):bs) = do- propVar <- fresh- done' <- go done bs- js <- binderToJs propVar done' binder- return $ "var " ++ propVar ++ " = " ++ varName ++ "." ++ prop ++ ";" ++ js-binderToJs varName done (ArrayBinder bs rest) = do- js <- go done rest 0 bs- return $ "if (" ++ varName ++ ".length " ++ cmp ++ " " ++ show (length bs) ++ ") { " ++ js ++ " }"- where- cmp = maybe "===" (const ">=") rest- go done Nothing _ [] = return done- go done (Just binder) index [] = do- restVar <- fresh- js <- binderToJs restVar done binder- return $ "var " ++ restVar ++ " = " ++ varName ++ ".slice(" ++ show index ++ "); " ++ js- go done rest index (binder:bs) = do- elVar <- fresh- done' <- go done rest (index + 1) bs- js <- binderToJs elVar done' binder- return $ "var " ++ elVar ++ " = " ++ varName ++ "[" ++ show index ++ "]; " ++ js-binderToJs varName done (NamedBinder ident binder) = do- js <- binderToJs varName done binder- return $ "var " ++ identToJs ident ++ " = " ++ varName ++ "; " ++ js-binderToJs varName done (GuardedBinder cond binder) = binderToJs varName done' binder- where- done' = "if (" ++ valueToJs cond ++ ") { " ++ done ++ "}"--objectPropertyToJs :: (String, Value) -> String-objectPropertyToJs (key, value) = key ++ ": " ++ valueToJs value--statementToJs :: Statement -> String-statementToJs (VariableIntroduction ident value) = "var " ++ identToJs ident ++ " = " ++ valueToJs value-statementToJs (Assignment target value) = identToJs target ++ " = " ++ valueToJs value-statementToJs (While cond sts) = "while ("- ++ valueToJs cond ++ ") {"- ++ intercalate ";" (map statementToJs sts) ++ "}"-statementToJs (For ident start end sts) = "for (" ++- identToJs ident ++ " = " ++ valueToJs start ++ ";"- ++ identToJs ident ++ " < " ++ valueToJs end ++ ";"- ++ identToJs ident ++ "++) {"- ++ intercalate ";" (map statementToJs sts) ++ "}"-statementToJs (ForEach ident arr sts) = valueToJs arr- ++ ".forEach(function(" ++ identToJs ident ++ ") {"- ++ intercalate ";" (map statementToJs sts) ++ "})"-statementToJs (If ifst) = ifStatementToJs ifst-statementToJs (Return value) = "return " ++ valueToJs value--ifStatementToJs :: IfStatement -> String-ifStatementToJs (IfStatement cond thens elst) =- "if ("- ++ valueToJs cond ++ ") {"- ++ intercalate ";" (map statementToJs thens) ++ "}"- ++ maybe "" elseStatementToJs elst--elseStatementToJs :: ElseStatement -> String-elseStatementToJs (Else sts) = " else {" ++ intercalate ";" (map statementToJs sts) ++ "}"-elseStatementToJs (ElseIf ifst) = " else " ++ ifStatementToJs ifst
− src/PureScript/CodeGen/Pretty/Kinds.hs
@@ -1,50 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.CodeGen.Pretty.Kinds--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------module PureScript.CodeGen.Pretty.Kinds (- prettyPrintKind-) where--import Data.Maybe (fromMaybe)-import Data.List (intersperse, intercalate)-import qualified Control.Arrow as A-import Control.Arrow ((<+>))-import qualified Data.Map as M-import Control.Applicative--import PureScript.Kinds-import PureScript.CodeGen.Common--typeLiterals :: Pattern Kind String-typeLiterals = Pattern $ A.Kleisli match- where- match Star = Just "*"- match Row = Just "#"- match (KUnknown u) = Just $ 'u' : show u- match _ = Nothing--funKind :: Pattern Kind (Kind, Kind)-funKind = Pattern $ A.Kleisli match- where- match (FunKind arg ret) = Just (arg, ret)- match _ = Nothing--prettyPrintKind :: Kind -> String-prettyPrintKind = fromMaybe (error "Incomplete pattern") . pattern matchKind- where- matchKind :: Pattern Kind String- matchKind = buildPrettyPrinter operators (typeLiterals <+> fmap parens matchKind)- operators :: OperatorTable Kind String- operators =- OperatorTable [ [ AssocR funKind $ \arg ret -> arg ++ " -> " ++ ret ] ]
− src/PureScript/CodeGen/Pretty/Types.hs
@@ -1,95 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.CodeGen.Pretty.Types--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------module PureScript.CodeGen.Pretty.Types (- prettyPrintType,- prettyPrintRow,- prettyPrintPolyType-) where--import Data.Maybe (fromMaybe)-import Data.List (intersperse, intercalate)-import qualified Control.Arrow as A-import Control.Arrow ((<+>))-import qualified Data.Map as M-import Control.Applicative--import PureScript.Values-import PureScript.Types-import PureScript.Names-import PureScript.Declarations-import PureScript.TypeChecker.Monad-import PureScript.CodeGen.Common--typeLiterals :: Pattern Type String-typeLiterals = Pattern $ A.Kleisli match- where- match Number = Just "Number"- match String = Just "String"- match Boolean = Just "Boolean"- match (Array ty) = Just $ "[" ++ prettyPrintType ty ++ "]"- match (Object row) = Just $ "{ " ++ prettyPrintRow row ++ " }"- match (TypeVar var) = Just var- match (TypeConstructor ctor) = Just ctor- match (TUnknown u) = Just $ 'u' : show u- match (SaturatedTypeSynonym name args) = Just $ name ++ "<" ++ intercalate "," (map prettyPrintType args) ++ ">"- match _ = Nothing--prettyPrintRow :: Row -> String-prettyPrintRow = (\(tys, tail) -> intercalate "; " (map (uncurry nameAndTypeToPs) tys) ++ tailToPs tail) . toList []- where- nameAndTypeToPs :: String -> Type -> String- nameAndTypeToPs name ty = name ++ " :: " ++ prettyPrintType ty- tailToPs :: Row -> String- tailToPs REmpty = ""- tailToPs (RUnknown u) = " | " ++ show u- tailToPs (RowVar var) = " | " ++ var- toList :: [(String, Type)] -> Row -> ([(String, Type)], Row)- toList tys (RCons name ty row) = toList ((name, ty):tys) row- toList tys r = (tys, r)--typeApp :: Pattern Type (Type, Type)-typeApp = Pattern $ A.Kleisli match- where- match (TypeApp f x) = Just (f, x)- match _ = Nothing--singleArgumentFunction :: Pattern Type (Type, Type)-singleArgumentFunction = Pattern $ A.Kleisli match- where- match (Function [arg] ret) = Just (arg, ret)- match _ = Nothing--function :: Pattern Type ([Type], Type)-function = Pattern $ A.Kleisli match- where- match (Function args ret) = Just (args, ret)- match _ = Nothing--prettyPrintType :: Type -> String-prettyPrintType = fromMaybe (error "Incomplete pattern") . pattern matchType- where- matchType :: Pattern Type String- matchType = buildPrettyPrinter operators (typeLiterals <+> fmap parens matchType)- operators :: OperatorTable Type String- operators =- OperatorTable [ [ AssocL typeApp $ \f x -> f ++ " " ++ x ]- , [ AssocR singleArgumentFunction $ \arg ret -> arg ++ " -> " ++ ret- , Wrap function $ \args ret -> "(" ++ intercalate ", " (map prettyPrintType args) ++ ") -> " ++ ret- ]- ]--prettyPrintPolyType :: PolyType -> String-prettyPrintPolyType (PolyType [] ty) = prettyPrintType ty-prettyPrintPolyType (PolyType idents ty) = "forall " ++ unwords idents ++ ". " ++ prettyPrintType ty
− src/PureScript/CodeGen/Pretty/Values.hs
@@ -1,185 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.CodeGen.Pretty.Values--- Copyright : Kinds.hs(c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------module PureScript.CodeGen.Pretty.Values (- prettyPrintValue,- prettyPrintBinder-) where--import Data.Char-import Data.Maybe (fromMaybe)-import Data.List (intercalate)-import qualified Control.Arrow as A-import Control.Arrow ((<+>))-import Control.Applicative--import PureScript.Types-import PureScript.Values-import PureScript.Names-import PureScript.CodeGen.Common--literals :: Pattern Value String-literals = Pattern $ A.Kleisli match- where- match (NumericLiteral n) = Just $ either show show n- match (StringLiteral s) = Just $ show s- match (BooleanLiteral True) = Just "true"- match (BooleanLiteral False) = Just "false"- match (ArrayLiteral xs) = Just $ "[" ++ intercalate ", " (map prettyPrintValue xs) ++ "]"- match (ObjectLiteral ps) = Just $ "{" ++ intercalate ", " (map (uncurry prettyPrintObjectProperty) ps) ++ "}"- match (Constructor name) = Just name- match (Block sts) = Just $ "do { " ++ intercalate " ; " (map prettyPrintStatement sts) ++ " }"- match (Case value binders) = Just $ "case " ++ prettyPrintValue value ++ " of { " ++ intercalate " ; " (map (uncurry prettyPrintCaseAlternative) binders) ++ " }"- match (Var ident) = Just $ show ident- match _ = Nothing--prettyPrintCaseAlternative :: Binder -> Value -> String-prettyPrintCaseAlternative binder val = prettyPrintBinder binder ++ " -> " ++ prettyPrintValue val--ifThenElse :: Pattern Value ((Value, Value), Value)-ifThenElse = Pattern $ A.Kleisli match- where- match (IfThenElse cond th el) = Just ((th, el), cond)- match _ = Nothing--accessor :: Pattern Value (String, Value)-accessor = Pattern $ A.Kleisli match- where- match (Accessor prop val) = Just (prop, val)- match _ = Nothing--indexer :: Pattern Value (String, Value)-indexer = Pattern $ A.Kleisli match- where- match (Indexer index val) = Just (prettyPrintValue index, val)- match _ = Nothing--objectUpdate :: Pattern Value ([String], Value)-objectUpdate = Pattern $ A.Kleisli match- where- match (ObjectUpdate o ps) = Just (flip map ps $ \(key, val) -> key ++ " = " ++ prettyPrintValue val, o)- match _ = Nothing--app :: Pattern Value (String, Value)-app = Pattern $ A.Kleisli match- where- match (App val args) = Just (intercalate "," (map prettyPrintValue args), val)- match _ = Nothing--lam :: Pattern Value ([String], Value)-lam = Pattern $ A.Kleisli match- where- match (Abs args val) = Just (map show args, val)- match _ = Nothing--unary :: UnaryOperator -> String -> Operator Value String-unary op str = Wrap pattern (++)- where- pattern :: Pattern Value (String, Value)- pattern = Pattern $ A.Kleisli match- where- match (Unary op' val) | op' == op = Just (str, val)- match _ = Nothing--binary :: BinaryOperator -> String -> Operator Value String-binary op str = AssocR pattern (\v1 v2 -> v1 ++ " " ++ str ++ " " ++ v2)- where- pattern :: Pattern Value (Value, Value)- pattern = Pattern $ A.Kleisli match- where- match (Binary op' v1 v2) | op' == op = Just (v1, v2)- match _ = Nothing--prettyPrintValue :: Value -> String-prettyPrintValue = fromMaybe (error "Incomplete pattern") . pattern matchValue- where- matchValue :: Pattern Value String- matchValue = buildPrettyPrinter operators (literals <+> fmap parens matchValue)- operators :: OperatorTable Value String- operators =- OperatorTable [ [ Wrap accessor $ \prop val -> val ++ "." ++ prop ]- , [ Wrap indexer $ \index val -> val ++ "[" ++ index ++ "]" ]- , [ Wrap objectUpdate $ \ps val -> val ++ "{ " ++ intercalate ", " ps ++ " }" ]- , [ Wrap app $ \args val -> val ++ "(" ++ args ++ ")" ]- , [ Split lam $ \args val -> "function (" ++ intercalate "," args ++ ") { return " ++ prettyPrintValue val ++ "; }" ]- , [ Wrap ifThenElse $ \(th, el) cond -> cond ++ " ? " ++ prettyPrintValue th ++ " : " ++ prettyPrintValue el ]- , [ binary LessThan "<" ]- , [ binary LessThanOrEqualTo "<=" ]- , [ binary GreaterThan ">" ]- , [ binary GreaterThanOrEqualTo ">=" ]- , [ unary Not "!" ]- , [ unary BitwiseNot "~" ]- , [ unary Negate "-" ]- , [ binary Multiply "*" ]- , [ binary Divide "/" ]- , [ binary Modulus "%" ]- , [ binary Concat "++" ]- , [ binary Add "+" ]- , [ binary Subtract "-" ]- , [ binary ShiftLeft "<<" ]- , [ binary ShiftRight ">>" ]- , [ binary ZeroFillShiftRight ">>>" ]- , [ binary EqualTo "==" ]- , [ binary NotEqualTo "!=" ]- , [ binary BitwiseAnd "&" ]- , [ binary BitwiseXor "^" ]- , [ binary BitwiseOr "|" ]- , [ binary And "&&" ]- , [ binary Or "||" ]- ]--prettyPrintBinder :: Binder -> String-prettyPrintBinder NullBinder = "_"-prettyPrintBinder (StringBinder str) = show str-prettyPrintBinder (NumberBinder num) = either show show num-prettyPrintBinder (BooleanBinder True) = "true"-prettyPrintBinder (BooleanBinder False) = "false"-prettyPrintBinder (VarBinder ident) = show ident-prettyPrintBinder (NullaryBinder ctor) = ctor-prettyPrintBinder (UnaryBinder ctor b) = ctor ++ prettyPrintBinder b-prettyPrintBinder (ObjectBinder bs) = "{ " ++ intercalate ", " (map (uncurry prettyPrintObjectPropertyBinder) bs) ++ " }"-prettyPrintBinder (ArrayBinder bs rest) = "[ " ++ intercalate ", " (map prettyPrintBinder bs) ++ maybe "" (("; " ++) . prettyPrintBinder) rest ++ " ]"-prettyPrintBinder (NamedBinder ident binder) = show ident ++ "@" ++ prettyPrintBinder binder-prettyPrintBinder (GuardedBinder cond binder) = prettyPrintBinder binder ++ " | " ++ prettyPrintValue cond--prettyPrintObjectPropertyBinder :: String -> Binder -> String-prettyPrintObjectPropertyBinder key binder = key ++ ": " ++ prettyPrintBinder binder--prettyPrintObjectProperty :: String -> Value -> String-prettyPrintObjectProperty key value = key ++ ": " ++ prettyPrintValue value--prettyPrintStatement :: Statement -> String-prettyPrintStatement (VariableIntroduction ident value) = "var " ++ show ident ++ " = " ++ prettyPrintValue value-prettyPrintStatement (Assignment target value) = show target ++ " = " ++ prettyPrintValue value-prettyPrintStatement (While cond sts) = "while " ++ prettyPrintValue cond ++ ": {" ++ intercalate ";" (map prettyPrintStatement sts) ++ " }"-prettyPrintStatement (For ident start end sts) = "for " ++ show ident- ++ " <- " ++ prettyPrintValue start- ++ " until " ++ prettyPrintValue end ++ ": {"- ++ intercalate "; " (map prettyPrintStatement sts) ++ " }"-prettyPrintStatement (ForEach ident arr sts) = "foreach " ++ show ident- ++ " in " ++ prettyPrintValue arr ++ ": {"- ++ intercalate "; " (map prettyPrintStatement sts) ++ " }"-prettyPrintStatement (If ifst) = prettyPrintIfStatement ifst-prettyPrintStatement (Return value) = "return " ++ prettyPrintValue value--prettyPrintIfStatement :: IfStatement -> String-prettyPrintIfStatement (IfStatement cond thens elst) =- "if "- ++ prettyPrintValue cond ++ ": {"- ++ intercalate "; " (map prettyPrintStatement thens) ++ " }"- ++ maybe "" prettyPrintElseStatement elst--prettyPrintElseStatement :: ElseStatement -> String-prettyPrintElseStatement (Else sts) = "else: {" ++ intercalate "; " (map prettyPrintStatement sts) ++ " }"-prettyPrintElseStatement (ElseIf ifst) = "else " ++ prettyPrintIfStatement ifst
− src/PureScript/Declarations.hs
@@ -1,39 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.Declarations--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------{-# LANGUAGE DeriveDataTypeable #-}--module PureScript.Declarations where--import PureScript.Values-import PureScript.Types-import PureScript.Names-import PureScript.Kinds--import qualified Data.Data as D--type Precedence = Integer--data Associativity = Infixl | Infixr deriving (Show, D.Data, D.Typeable)--data Fixity = Fixity Associativity Precedence deriving (Show, D.Data, D.Typeable)--data Declaration- = DataDeclaration String [String] [(String, Maybe Type)]- | TypeSynonymDeclaration String [String] Type- | TypeDeclaration Ident PolyType- | ValueDeclaration Ident Value- | ExternDeclaration Ident PolyType- | ExternDataDeclaration String Kind- | FixityDeclaration Fixity String deriving (Show, D.Data, D.Typeable)
− src/PureScript/Kinds.hs
@@ -1,25 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.Kinds--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------{-# LANGUAGE DeriveDataTypeable #-}--module PureScript.Kinds where--import Data.Data--data Kind- = KUnknown Int- | Star- | Row- | FunKind Kind Kind deriving (Show, Eq, Data, Typeable)
− src/PureScript/Names.hs
@@ -1,26 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.Names--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------{-# LANGUAGE DeriveDataTypeable #-}--module PureScript.Names where--import Data.Data--data Ident = Ident String | Op String deriving (Eq, Ord, Data, Typeable)--instance Show Ident where- show (Ident s) = s- show (Op op) = '(':op ++ ")"-
− src/PureScript/Parser.hs
@@ -1,22 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.Parser--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------module PureScript.Parser (module P) where--import PureScript.Parser.Common as P-import PureScript.Parser.Types as P-import PureScript.Parser.Values as P-import PureScript.Parser.State as P-import PureScript.Parser.Kinds as P-import PureScript.Parser.Declarations as P
− src/PureScript/Parser/Common.hs
@@ -1,181 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.Parser.Common--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------{-# LANGUAGE FlexibleContexts #-}--module PureScript.Parser.Common where--import Data.Char (isSpace)-import Control.Applicative-import Control.Monad-import Control.Monad.State-import PureScript.Parser.State-import qualified Data.Map as M-import qualified Text.Parsec as P-import qualified Text.Parsec.Pos as P-import qualified Text.Parsec.Token as PT--import PureScript.Names--reservedNames :: [String]-reservedNames = [ "case"- , "of"- , "data"- , "type"- , "var"- , "val"- , "while"- , "for"- , "foreach"- , "if"- , "then"- , "else"- , "return"- , "true"- , "false"- , "extern"- , "forall"- , "do"- , "until"- , "in"- , "break"- , "catch"- , "continue"- , "debugger"- , "default"- , "delete"- , "finally"- , "function"- , "instanceof"- , "new"- , "switch"- , "this"- , "throw"- , "try"- , "typeof"- , "void"- , "with"- , "Number"- , "String"- , "Boolean"- , "infixl"- , "infixr" ]--reservedOpNames :: [String]-reservedOpNames = [ "!", "~", "-", "<=", ">=", "<", ">", "*", "/", "%", "++", "+", "<<", ">>>", ">>"- , "==", "!=", "&", "^", "|", "&&", "||", "->" ]--identStart :: P.Parsec String u Char-identStart = P.lower <|> P.oneOf "_$"--properNameStart :: P.Parsec String u Char-properNameStart = P.upper--identLetter :: P.Parsec String u Char-identLetter = P.alphaNum <|> P.oneOf "_'"--opStart :: P.Parsec String u Char-opStart = P.oneOf "!#$%&*+/<=>?@^|-~"--opLetter :: P.Parsec String u Char-opLetter = P.oneOf ":#$%&*+./<=>?@^|"--langDef = PT.LanguageDef- { PT.reservedNames = reservedNames- , PT.reservedOpNames = reservedOpNames- , PT.commentStart = "{-"- , PT.commentEnd = "-}"- , PT.commentLine = "--"- , PT.nestedComments = True- , PT.identStart = identStart- , PT.identLetter = identLetter- , PT.opStart = opStart- , PT.opLetter = opLetter- , PT.caseSensitive = True- }--tokenParser = PT.makeTokenParser langDef--lexeme = PT.lexeme tokenParser-identifier = PT.identifier tokenParser-reserved = PT.reserved tokenParser-reservedOp = PT.reservedOp tokenParser-operator = PT.operator tokenParser-stringLiteral = PT.stringLiteral tokenParser-whiteSpace = PT.whiteSpace tokenParser-parens = PT.parens tokenParser-braces = PT.braces tokenParser-angles = PT.angles tokenParser-squares = PT.squares tokenParser-semi = PT.semi tokenParser-comma = PT.comma tokenParser-colon = PT.colon tokenParser-dot = PT.dot tokenParser-semiSep = PT.semiSep tokenParser-semiSep1 = PT.semiSep1 tokenParser-commaSep = PT.commaSep tokenParser-commaSep1 = PT.commaSep1 tokenParser-natural = PT.natural tokenParser--tick :: P.Parsec String u Char-tick = lexeme $ P.char '`'--properName :: P.Parsec String u String-properName = lexeme $ P.try ((:) <$> P.upper <*> many (PT.identLetter langDef) P.<?> "name")--integerOrFloat :: P.Parsec String u (Either Integer Double)-integerOrFloat = (Left <$> P.try (PT.natural tokenParser) <|>- Right <$> P.try (PT.float tokenParser)) P.<?> "number"--augment :: P.Stream s m t => P.ParsecT s u m a -> P.ParsecT s u m b -> (a -> b -> a) -> P.ParsecT s u m a-augment p q f = flip (maybe id $ flip f) <$> p <*> P.optionMaybe q--fold :: P.Stream s m t => P.ParsecT s u m a -> P.ParsecT s u m b -> (a -> b -> a) -> P.ParsecT s u m a-fold first more combine = do- a <- first- bs <- P.many more- return $ foldl combine a bs--buildPostfixParser :: P.Stream s m t => [P.ParsecT s u m (a -> a)] -> P.ParsecT s u m a -> P.ParsecT s u m a-buildPostfixParser f x = fold x (P.choice (map P.try f)) (flip ($))--parseIdent :: P.Parsec String u Ident-parseIdent = (Ident <$> identifier) <|> (Op <$> parens operator)--parseIdentInfix :: P.Parsec String u Ident-parseIdentInfix = (Ident <$> P.between tick tick identifier) <|> (Op <$> operator)--mark :: P.Parsec String ParseState a -> P.Parsec String ParseState a-mark p = do- current <- indentationLevel <$> P.getState- pos <- P.sourceColumn <$> P.getPosition- P.modifyState $ \st -> st { indentationLevel = pos }- a <- p- P.modifyState $ \st -> st { indentationLevel = current }- return a--checkIndentation :: (P.Column -> P.Column -> Bool) -> P.Parsec String ParseState ()-checkIndentation rel = do- col <- P.sourceColumn <$> P.getPosition- current <- indentationLevel <$> P.getState- guard (col `rel` current)--indented :: P.Parsec String ParseState ()-indented = checkIndentation (>) P.<?> "indentation"--same :: P.Parsec String ParseState ()-same = checkIndentation (==) P.<?> "no indentation"--runIndentParser :: P.Parsec String ParseState a -> String -> Either P.ParseError a-runIndentParser p = P.runParser p (ParseState 0 M.empty) ""
− src/PureScript/Parser/Declarations.hs
@@ -1,100 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.Parser.Declarations--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------module PureScript.Parser.Declarations (- parseDeclaration,- parseDeclarations-) where--import Data.Char-import Data.List-import Data.Maybe-import Data.Function-import Control.Applicative-import Control.Arrow (Arrow(..))-import Control.Monad.State-import qualified Data.Map as M-import qualified Text.Parsec as P-import qualified Text.Parsec.Pos as P--import PureScript.Values-import PureScript.Types-import PureScript.Parser.State-import PureScript.Parser.Common-import PureScript.Declarations-import PureScript.Parser.Values-import PureScript.Parser.Types-import PureScript.Parser.Kinds--parseDataDeclaration :: P.Parsec String ParseState Declaration-parseDataDeclaration = do- reserved "data"- name <- indented *> properName- tyArgs <- many (indented *> identifier)- lexeme $ indented *> P.char '='- ctors <- P.sepBy1 ((,) <$> (indented *> properName) <*> P.optionMaybe parseType) (lexeme $ indented *> P.char '|')- return $ DataDeclaration name tyArgs ctors--parseTypeDeclaration :: P.Parsec String ParseState Declaration-parseTypeDeclaration =- TypeDeclaration <$> parseIdent- <*> (lexeme (indented *> P.string "::") *> parsePolyType)--parseTypeSynonymDeclaration :: P.Parsec String ParseState Declaration-parseTypeSynonymDeclaration =- TypeSynonymDeclaration <$> (reserved "type" *> indented *> properName)- <*> many (indented *> identifier)- <*> (lexeme (indented *> P.char '=') *> parseType)--parseValueDeclaration :: P.Parsec String ParseState Declaration-parseValueDeclaration =- ValueDeclaration <$> parseIdent- <*> (lexeme (indented *> P.char '=') *> parseValue)--parseExternDeclaration :: P.Parsec String ParseState Declaration-parseExternDeclaration = reserved "extern" *> indented *>- (ExternDataDeclaration <$> (reserved "data" *> indented *> properName)- <*> (lexeme (indented *> P.string "::") *> parseKind)- <|> ExternDeclaration <$> parseIdent- <*> (lexeme (indented *> P.string "::") *> parsePolyType))--parseAssociativity :: P.Parsec String ParseState Associativity-parseAssociativity =- (reserved "infixl" >> return Infixl) <|>- (reserved "infixr" >> return Infixr)--parseFixity :: P.Parsec String ParseState Fixity-parseFixity = Fixity <$> parseAssociativity <*> (indented *> natural)--parseFixityDeclaration :: P.Parsec String ParseState Declaration-parseFixityDeclaration = do- fixity <- parseFixity- indented- name <- operator- current <- fixities <$> P.getState- when (name `M.member` current) (P.unexpected $ "redefined fixity for " ++ show name)- P.modifyState $ \st -> st { fixities = M.insert name fixity current }- return $ FixityDeclaration fixity name--parseDeclaration :: P.Parsec String ParseState Declaration-parseDeclaration = P.choice (map P.try- [ parseDataDeclaration- , parseTypeDeclaration- , parseTypeSynonymDeclaration- , parseValueDeclaration- , parseExternDeclaration- , parseFixityDeclaration ]) P.<?> "declaration"--parseDeclarations :: P.Parsec String ParseState [Declaration]-parseDeclarations = whiteSpace *> mark (same *> P.many parseDeclaration) <* P.eof
− src/PureScript/Parser/Kinds.hs
@@ -1,41 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.Parser.Kinds--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------module PureScript.Parser.Kinds (- parseKind-) where--import PureScript.Kinds-import PureScript.Parser.State-import PureScript.Parser.Common-import Control.Applicative-import qualified Text.Parsec as P-import qualified Text.Parsec.Expr as P--parseStar :: P.Parsec String ParseState Kind-parseStar = const Star <$> lexeme (P.char '*')--parseRow :: P.Parsec String ParseState Kind-parseRow = const Row <$> lexeme (P.char '#')--parseTypeAtom :: P.Parsec String ParseState Kind-parseTypeAtom = indented *> P.choice (map P.try- [ parseStar- , parseRow- , parens parseKind ])--parseKind :: P.Parsec String ParseState Kind-parseKind = P.buildExpressionParser operators parseTypeAtom P.<?> "kind"- where- operators = [ [ P.Infix (lexeme (P.try (P.string "->")) >> return FunKind) P.AssocRight ] ]
− src/PureScript/Parser/State.hs
@@ -1,27 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.Parser.State--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------module PureScript.Parser.State where--import PureScript.Names-import PureScript.Declarations--import qualified Text.Parsec as P-import qualified Data.Map as M--data ParseState = ParseState- { indentationLevel :: P.Column- , fixities :: M.Map String Fixity } deriving Show--
− src/PureScript/Parser/Types.hs
@@ -1,91 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.Parser.Types--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------module PureScript.Parser.Types (- parseType,- parsePolyType,- parseRow-) where--import PureScript.Types-import PureScript.Parser.State-import PureScript.Parser.Common-import Control.Applicative-import qualified Text.Parsec as P-import qualified Text.Parsec.Expr as P-import Control.Arrow (Arrow(..))--parseNumber :: P.Parsec String ParseState Type-parseNumber = const Number <$> reserved "Number"--parseString :: P.Parsec String ParseState Type-parseString = const String <$> reserved "String"--parseBoolean :: P.Parsec String ParseState Type-parseBoolean = const Boolean <$> reserved "Boolean"--parseArray :: P.Parsec String ParseState Type-parseArray = squares $ Array <$> parseType--parseObject :: P.Parsec String ParseState Type-parseObject = braces $ Object <$> parseRow--parseFunction :: P.Parsec String ParseState Type-parseFunction = do- args <- lexeme $ parens $ commaSep parseType- lexeme $ P.string "->"- resultType <- parseType- return $ Function args resultType--parseTypeVariable :: P.Parsec String ParseState Type-parseTypeVariable = TypeVar <$> identifier--parseTypeConstructor :: P.Parsec String ParseState Type-parseTypeConstructor = TypeConstructor <$> properName--parseTypeAtom :: P.Parsec String ParseState Type-parseTypeAtom = indented *> P.choice (map P.try- [ parseNumber- , parseString- , parseBoolean- , parseArray- , parseObject- , parseFunction- , parseTypeVariable- , parseTypeConstructor- , parens parseType ])--parsePolyType :: P.Parsec String ParseState PolyType-parsePolyType = (PolyType <$> P.option [] (indented *> reserved "forall" *> many (indented *> identifier) <* indented <* dot)- <*> parseType) P.<?> "polymorphic type"--parseType :: P.Parsec String ParseState Type-parseType = (P.buildExpressionParser operators . buildPostfixParser postfixTable $ parseTypeAtom) P.<?> "type"- where- postfixTable :: [P.Parsec String ParseState (Type -> Type)]- postfixTable = [ flip TypeApp <$> (indented *> parseTypeAtom) ]- operators = [ [ P.Infix (lexeme (P.try (P.string "->")) >> return (\t1 t2 -> Function [t1] t2)) P.AssocRight ] ]--parseNameAndType :: P.Parsec String ParseState (String, Type)-parseNameAndType = (,) <$> (indented *> identifier <* indented <* lexeme (P.string "::")) <*> parseType--parseRowEnding :: P.Parsec String ParseState Row-parseRowEnding = P.option REmpty (RowVar <$> (lexeme (indented *> P.char '|') *> indented *> identifier))--parseRow :: P.Parsec String ParseState Row-parseRow = (fromList <$> (parseNameAndType `P.sepBy` (indented *> semi)) <*> parseRowEnding) P.<?> "row"- where- fromList :: [(String, Type)] -> Row -> Row- fromList [] r = r- fromList ((name, t):ts) r = RCons name t (fromList ts r)
− src/PureScript/Parser/Values.hs
@@ -1,292 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.Parser.Values--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------module PureScript.Parser.Values (- parseValue,- parseBinder-) where--import PureScript.Values-import PureScript.Names-import PureScript.Declarations-import PureScript.Parser.State-import Data.Function (on)-import Data.List-import Data.Functor.Identity-import qualified Data.Map as M-import qualified PureScript.Parser.Common as C-import Control.Applicative-import qualified Text.Parsec as P-import Text.Parsec.Expr-import Control.Monad-import Control.Arrow (Arrow(..))-import PureScript.Parser.Types-import PureScript.Types--booleanLiteral :: P.Parsec String ParseState Bool-booleanLiteral = (C.reserved "true" >> return True) P.<|> (C.reserved "false" >> return False)--parseNumericLiteral :: P.Parsec String ParseState Value-parseNumericLiteral = NumericLiteral <$> C.integerOrFloat--parseStringLiteral :: P.Parsec String ParseState Value-parseStringLiteral = StringLiteral <$> C.stringLiteral--parseBooleanLiteral :: P.Parsec String ParseState Value-parseBooleanLiteral = BooleanLiteral <$> booleanLiteral--parseArrayLiteral :: P.Parsec String ParseState Value-parseArrayLiteral = ArrayLiteral <$> C.squares (parseValue `P.sepBy` (C.indented *> C.comma))--parseObjectLiteral :: P.Parsec String ParseState Value-parseObjectLiteral = ObjectLiteral <$> C.braces (parseIdentifierAndValue `P.sepBy` (C.indented *> C.comma))--parseIdentifierAndValue :: P.Parsec String ParseState (String, Value)-parseIdentifierAndValue = (,) <$> (C.indented *> C.identifier <* C.indented <* C.colon)- <*> (C.indented *> parseValue)--parseAbs :: P.Parsec String ParseState Value-parseAbs = do- C.lexeme $ P.char '\\'- args <- (C.indented *> C.parseIdent) `P.sepBy` (C.indented *> C.comma)- C.lexeme $ C.indented *> P.string "->"- value <- parseValue- return $ Abs args value--parseApp :: P.Parsec String ParseState Value-parseApp = App <$> parseValue- <*> (C.indented *> C.parens (parseValue `P.sepBy` (C.indented *> C.comma)))--parseVar :: P.Parsec String ParseState Value-parseVar = Var <$> C.parseIdent--parseConstructor :: P.Parsec String ParseState Value-parseConstructor = Constructor <$> C.properName--parseCase :: P.Parsec String ParseState Value-parseCase = Case <$> P.between (C.reserved "case") (C.indented *> C.reserved "of") parseValue- <*> (C.indented *> C.mark (P.many (C.same *> C.mark parseCaseAlternative)))--parseCaseAlternative :: P.Parsec String ParseState (Binder, Value)-parseCaseAlternative = (,) <$> (parseGuardedBinder <* C.lexeme (P.string "->"))- <*> parseValue- P.<?> "case alternative"--parseIfThenElse :: P.Parsec String ParseState Value-parseIfThenElse = IfThenElse <$> (C.reserved "if" *> C.indented *> parseValue)- <*> (C.indented *> C.reserved "then" *> C.indented *> parseValue)- <*> (C.indented *> C.reserved "else" *> C.indented *> parseValue)--parseBlock :: P.Parsec String ParseState Value-parseBlock = Block <$> (C.reserved "do" *> parseManyStatements)--parseManyStatements :: P.Parsec String ParseState [Statement]-parseManyStatements = C.indented *> C.mark (P.many (C.same *> C.mark parseStatement)) P.<?> "block"--parseValueAtom :: P.Parsec String ParseState Value-parseValueAtom = C.indented *> P.choice (map P.try- [ parseNumericLiteral- , parseStringLiteral- , parseBooleanLiteral- , parseArrayLiteral- , parseObjectLiteral- , parseAbs- , parseVar- , parseConstructor- , parseBlock- , parseCase- , parseIfThenElse- , C.parens parseValue ])--parsePropertyUpdate :: P.Parsec String ParseState (String, Value)-parsePropertyUpdate = do- name <- C.lexeme C.identifier- C.lexeme $ C.indented *> P.char '='- value <- C.indented *> parseValue- return (name, value)--parseValue :: P.Parsec String ParseState Value-parseValue = do- customOps <- fixities <$> P.getState- (buildExpressionParser (operators customOps)- . C.buildPostfixParser postfixTable2- $ indexersAndAccessors) P.<?> "expression"- where- indexersAndAccessors = C.buildPostfixParser postfixTable1 parseValueAtom- postfixTable1 = [ Accessor <$> (C.indented *> C.dot *> C.indented *> C.identifier)- , Indexer <$> (C.indented *> C.squares parseValue)- , flip ObjectUpdate <$> (C.indented *> C.braces ((C.indented *> parsePropertyUpdate) `P.sepBy1` (C.indented *> C.comma))) ]- postfixTable2 = [ C.indented *> indexersAndAccessors >>= \t2 -> return (\t1 -> App t1 [t2])- , flip App <$> (C.indented *> C.parens (parseValue `P.sepBy` (C.indented *> C.comma)))- , flip TypedValue <$> (P.try (C.lexeme (C.indented *> P.string "::")) *> parsePolyType) ]- operators user =- [ [ Prefix $ C.lexeme (P.try $ C.indented *> C.reservedOp "!") >> return (Unary Not)- , Prefix $ C.lexeme (P.try $ C.indented *> C.reservedOp "~") >> return (Unary BitwiseNot)- , Prefix $ C.lexeme (P.try $ C.indented *> C.reservedOp "-") >> return (Unary Negate)- , Prefix $ C.lexeme (P.try $ C.indented *> C.reservedOp "+") >> return id ]- ] ++ customOperatorTable user ++- [ [ Infix (C.lexeme (P.try (C.indented *> C.parseIdentInfix P.<?> "operator") >>= \ident -> return $ \t1 t2 -> App (App (Var ident) [t1]) [t2])) AssocLeft ]- , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "<=") >> return (Binary LessThanOrEqualTo)) AssocRight- , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp ">=") >> return (Binary GreaterThanOrEqualTo)) AssocRight ]- , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "<") >> return (Binary LessThan)) AssocRight- , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp ">") >> return (Binary GreaterThan)) AssocRight ]- , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "*") >> return (Binary Multiply)) AssocRight- , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "/") >> return (Binary Divide)) AssocRight- , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "%") >> return (Binary Modulus)) AssocRight ]- , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "++") >> return (Binary Concat)) AssocRight- , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "+") >> return (Binary Add)) AssocRight- , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "-") >> return (Binary Subtract)) AssocRight ]- , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "<<") >> return (Binary ShiftLeft)) AssocRight- , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp ">>>") >> return (Binary ZeroFillShiftRight)) AssocRight- , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp ">>") >> return (Binary ShiftRight)) AssocRight ]- , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "==") >> return (Binary EqualTo)) AssocRight- , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "!=") >> return (Binary NotEqualTo)) AssocRight ]- , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "&") >> return (Binary BitwiseAnd)) AssocRight ]- , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "^") >> return (Binary BitwiseXor)) AssocRight ]- , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "|") >> return (Binary BitwiseOr)) AssocRight ]- , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "&&") >> return (Binary And)) AssocRight ]- , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "||") >> return (Binary Or)) AssocRight ]- ]--customOperatorTable :: M.Map String Fixity -> OperatorTable String ParseState Identity Value-customOperatorTable fixities =- let- ops = map (\(name, Fixity a p) -> (name, (a, p))) . M.toList $ fixities- sorted = sortBy (compare `on` (snd . snd)) ops- levels = groupBy ((==) `on` (snd . snd)) sorted- in- map (map $ \(name, (a, _)) ->- flip Infix (toAssoc a) $- C.lexeme $ P.try $ do- C.indented- C.reservedOp name P.<?> "operator"- return $ \t1 t2 -> App (App (Var (Op name)) [t1]) [t2])- levels---toAssoc :: Associativity -> Assoc-toAssoc Infixl = AssocLeft-toAssoc Infixr = AssocRight--parseVariableIntroduction :: P.Parsec String ParseState Statement-parseVariableIntroduction = do- C.reserved "var"- name <- C.indented *> C.parseIdent- C.lexeme $ C.indented *> P.char '='- value <- parseValue- return $ VariableIntroduction name value--parseAssignment :: P.Parsec String ParseState Statement-parseAssignment = do- tgt <- C.parseIdent- C.lexeme $ C.indented *> P.char '='- value <- parseValue- return $ Assignment tgt value--parseWhile :: P.Parsec String ParseState Statement-parseWhile = While <$> (C.reserved "while" *> C.indented *> parseValue <* C.indented <* C.colon)- <*> parseManyStatements--parseFor :: P.Parsec String ParseState Statement-parseFor = For <$> (C.reserved "for" *> C.indented *> C.parseIdent)- <*> (C.indented *> C.lexeme (P.string "<-") *> parseValue)- <*> (C.indented *> C.reserved "until" *> parseValue <* C.colon)- <*> parseManyStatements--parseForEach :: P.Parsec String ParseState Statement-parseForEach = ForEach <$> (C.reserved "foreach" *> C.indented *> C.parseIdent)- <*> (C.indented *> C.reserved "in" *> parseValue <* C.colon)- <*> parseManyStatements--parseIf :: P.Parsec String ParseState Statement-parseIf = If <$> parseIfStatement--parseIfStatement :: P.Parsec String ParseState IfStatement-parseIfStatement =- IfStatement <$> (C.reserved "if" *> C.indented *> parseValue <* C.indented <* C.colon)- <*> parseManyStatements- <*> P.optionMaybe (C.same *> parseElseStatement)--parseElseStatement :: P.Parsec String ParseState ElseStatement-parseElseStatement = C.reserved "else" >> (ElseIf <$> (C.indented *> parseIfStatement)- <|> Else <$> (C.indented *> C.colon *> parseManyStatements))--parseReturn :: P.Parsec String ParseState Statement-parseReturn = Return <$> (C.reserved "return" *> parseValue)--parseStatement :: P.Parsec String ParseState Statement-parseStatement = P.choice (map P.try- [ parseVariableIntroduction- , parseAssignment- , parseWhile- , parseFor- , parseForEach- , parseIf- , parseReturn ]) P.<?> "statement"--parseStringBinder :: P.Parsec String ParseState Binder-parseStringBinder = StringBinder <$> C.stringLiteral--parseBooleanBinder :: P.Parsec String ParseState Binder-parseBooleanBinder = BooleanBinder <$> booleanLiteral--parseNumberBinder :: P.Parsec String ParseState Binder-parseNumberBinder = NumberBinder <$> C.integerOrFloat--parseVarBinder :: P.Parsec String ParseState Binder-parseVarBinder = VarBinder <$> C.parseIdent--parseNullaryBinder :: P.Parsec String ParseState Binder-parseNullaryBinder = NullaryBinder <$> C.lexeme C.properName--parseUnaryBinder :: P.Parsec String ParseState Binder-parseUnaryBinder = UnaryBinder <$> C.lexeme C.properName <*> (C.indented *> parseBinder)--parseObjectBinder :: P.Parsec String ParseState Binder-parseObjectBinder = ObjectBinder <$> C.braces ((C.indented *> parseIdentifierAndBinder) `P.sepBy` (C.indented *> C.comma))--parseArrayBinder :: P.Parsec String ParseState Binder-parseArrayBinder = C.squares $ ArrayBinder <$> ((C.indented *> parseBinder) `P.sepBy` (C.indented *> C.comma))- <*> P.optionMaybe (C.indented *> C.colon *> C.indented *> parseBinder)--parseNamedBinder :: P.Parsec String ParseState Binder-parseNamedBinder = NamedBinder <$> (C.parseIdent <* C.indented <* C.lexeme (P.char '@'))- <*> (C.indented *> parseBinder)--parseNullBinder :: P.Parsec String ParseState Binder-parseNullBinder = C.lexeme (P.char '_') *> P.notFollowedBy C.identLetter *> return NullBinder--parseIdentifierAndBinder :: P.Parsec String ParseState (String, Binder)-parseIdentifierAndBinder = do- name <- C.lexeme C.identifier- C.lexeme $ C.indented *> P.char '='- binder <- C.indented *> parseBinder- return (name, binder)--parseBinder :: P.Parsec String ParseState Binder-parseBinder = P.choice (map P.try- [ parseNullBinder- , parseStringBinder- , parseBooleanBinder- , parseNumberBinder- , parseNamedBinder- , parseVarBinder- , parseUnaryBinder- , parseNullaryBinder- , parseObjectBinder- , parseArrayBinder- , C.parens parseBinder ]) P.<?> "binder"--parseGuardedBinder :: P.Parsec String ParseState Binder-parseGuardedBinder = flip ($) <$> parseBinder <*> P.option id (GuardedBinder <$> (C.indented *> C.lexeme (P.char '|') *> C.indented *> parseValue))
− src/PureScript/Pretty.hs
@@ -1,22 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.Pretty--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------module PureScript.Pretty (module P) where--import PureScript.CodeGen.Pretty.Kinds as P-import PureScript.CodeGen.Pretty.Values as P-import PureScript.CodeGen.Pretty.Types as P---
− src/PureScript/TypeChecker.hs
@@ -1,96 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.TypeChecker--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------{-# LANGUAGE FlexibleInstances #-}--module PureScript.TypeChecker (-module T,- typeCheckAll-) where--import PureScript.TypeChecker.Monad as T-import PureScript.TypeChecker.Kinds as T-import PureScript.TypeChecker.Types as T-import PureScript.TypeChecker.Synonyms as T--import Data.List-import Data.Maybe-import Data.Function-import qualified Data.Map as M--import PureScript.Values-import PureScript.Types-import PureScript.Names-import PureScript.Kinds-import PureScript.Declarations--import Control.Monad (forM_)-import Control.Monad.State-import Control.Monad.Error--typeCheckAll :: [Declaration] -> Check ()-typeCheckAll [] = return ()-typeCheckAll (DataDeclaration name args dctors : rest) = do- rethrow (("Error in type constructor " ++ name ++ ": ") ++) $ do- env <- getEnv- guardWith (name ++ " is already defined") $ not $ M.member name (types env)- ctorKind <- kindsOf (Just name) args (mapMaybe snd dctors)- putEnv $ env { types = M.insert name (ctorKind, Data) (types env) }- forM_ dctors $ \(dctor, maybeTy) ->- rethrow (("Error in data constructor " ++ name ++ ": ") ++) $ do- env' <- getEnv- guardWith (dctor ++ " is already defined") $ not $ M.member dctor (dataConstructors env')- let retTy = foldl TypeApp (TypeConstructor name) (map TypeVar args)- let dctorTy = maybe retTy (\ty -> Function [ty] retTy) maybeTy- let polyType = PolyType args dctorTy- putEnv $ env' { dataConstructors = M.insert dctor polyType (dataConstructors env') }- typeCheckAll rest-typeCheckAll (TypeSynonymDeclaration name args ty : rest) = do- rethrow (("Error in type synonym " ++ name ++ ": ") ++) $ do- env <- getEnv- guardWith (name ++ " is already defined") $ not $ M.member name (types env)- kind <- kindsOf (Just name) args [ty]- putEnv $ env { types = M.insert name (kind, TypeSynonym) (types env)- , typeSynonyms = M.insert name (args, ty) (typeSynonyms env) }- typeCheckAll rest-typeCheckAll (TypeDeclaration name ty : ValueDeclaration name' val : rest) | name == name' =- typeCheckAll (ValueDeclaration name (TypedValue val ty) : rest)-typeCheckAll (TypeDeclaration name _ : _) = throwError $ "Orphan type declaration for " ++ show name-typeCheckAll (ValueDeclaration name val : rest) = do- rethrow (("Error in declaration " ++ show name ++ ": ") ++) $ do- env <- getEnv- case M.lookup name (names env) of- Just ty -> throwError $ show name ++ " is already defined"- Nothing -> do- ty <- typeOf name val- putEnv (env { names = M.insert name (ty, Value) (names env) })- typeCheckAll rest-typeCheckAll (ExternDataDeclaration name kind : rest) = do- env <- getEnv- guardWith (name ++ " is already defined") $ not $ M.member name (types env)- putEnv $ env { types = M.insert name (kind, TypeSynonym) (types env) }- typeCheckAll rest-typeCheckAll (ExternDeclaration name ty : rest) = do- rethrow (("Error in extern declaration " ++ show name ++ ": ") ++) $ do- env <- getEnv- kind <- kindOf ty- guardWith "Expected kind *" $ kind == Star- case M.lookup name (names env) of- Just _ -> throwError $ show name ++ " is already defined"- Nothing -> putEnv (env { names = M.insert name (ty, Extern) (names env) })- typeCheckAll rest-typeCheckAll (FixityDeclaration _ name : rest) = do- typeCheckAll rest- env <- getEnv- guardWith ("Fixity declaration with no binding: " ++ name) $ M.member (Op name) $ names env
− src/PureScript/TypeChecker/Kinds.hs
@@ -1,183 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.TypeChecker.Kinds--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------{-# LANGUAGE DeriveDataTypeable #-}--module PureScript.TypeChecker.Kinds (- KindConstraint(..),- KindSolution(..),- kindsOf,- kindOf-) where--import Data.List-import Data.Maybe (fromMaybe)-import Data.Function-import Data.Data--import PureScript.Types-import PureScript.Kinds-import PureScript.Declarations-import PureScript.TypeChecker.Monad-import PureScript.CodeGen.Pretty.Kinds-import PureScript.CodeGen.Pretty.Types--import Control.Monad.State-import Control.Monad.Error--import Control.Applicative-import Control.Arrow (Kleisli(..), (***))-import qualified Control.Category as C--import qualified Data.Map as M--data KindConstraintOrigin- = DataDeclOrigin- | TypeOrigin Type- | RowOrigin Row deriving (Show, Data, Typeable)--prettyPrintKindConstraintOrigin :: KindConstraintOrigin -> String-prettyPrintKindConstraintOrigin (DataDeclOrigin) = "data declaration"-prettyPrintKindConstraintOrigin (TypeOrigin ty) = prettyPrintType ty-prettyPrintKindConstraintOrigin (RowOrigin row) = prettyPrintRow row--data KindConstraint = KindConstraint Int Kind KindConstraintOrigin deriving (Show, Data, Typeable)--newtype KindSolution = KindSolution { runKindSolution :: Int -> Kind }--emptyKindSolution :: KindSolution-emptyKindSolution = KindSolution KUnknown--kindOf :: PolyType -> Check Kind-kindOf (PolyType idents ty) = do- ns <- replicateM (length idents) fresh- (cs, n, m) <- kindConstraints (M.fromList (zip idents ns)) ty- solution <- solveKindConstraints cs emptyKindSolution- return $ starIfUnknown $ runKindSolution solution n--kindsOf :: Maybe String -> [String] -> [Type] -> Check Kind-kindsOf name args ts = do- tyCon <- fresh- nargs <- replicateM (length args) fresh- (cs, ns, m) <- kindConstraintsAll (maybe id (`M.insert` tyCon) name $ M.fromList (zip args nargs)) ts- let extraConstraints =- KindConstraint tyCon (foldr (FunKind . KUnknown) Star nargs) DataDeclOrigin- : zipWith (\n arg -> KindConstraint n Star (TypeOrigin arg)) ns ts- solution <- solveKindConstraints (extraConstraints ++ cs) emptyKindSolution- return $ starIfUnknown $ runKindSolution solution tyCon--starIfUnknown :: Kind -> Kind-starIfUnknown (KUnknown _) = Star-starIfUnknown (FunKind k1 k2) = FunKind (starIfUnknown k1) (starIfUnknown k2)-starIfUnknown k = k--kindConstraintsAll :: M.Map String Int -> [Type] -> Check ([KindConstraint], [Int], M.Map String Int)-kindConstraintsAll m [] = return ([], [], m)-kindConstraintsAll m (t:ts) = do- (cs, n1, m') <- kindConstraints m t- (cs', ns, m'') <- kindConstraintsAll m' ts- return (KindConstraint n1 Star (TypeOrigin t) : cs ++ cs', n1:ns, m'')--kindConstraints :: M.Map String Int -> Type -> Check ([KindConstraint], Int, M.Map String Int)-kindConstraints m a@(Array t) = do- me <- fresh- (cs, n1, m') <- kindConstraints m t- return (KindConstraint n1 Star (TypeOrigin t) : KindConstraint me Star (TypeOrigin a) : cs, me, m')-kindConstraints m o@(Object row) = do- me <- fresh- (cs, r, m') <- kindConstraintsForRow m row- return (KindConstraint me Star (TypeOrigin o) : KindConstraint r Row (RowOrigin row) : cs, me, m')-kindConstraints m f@(Function args ret) = do- me <- fresh- (cs, ns, m') <- kindConstraintsAll m args- (cs', retN, m'') <- kindConstraints m' ret- return (KindConstraint retN Star (TypeOrigin ret) : KindConstraint me Star (TypeOrigin f) : zipWith (\n arg -> KindConstraint n Star (TypeOrigin arg)) ns args ++ cs ++ cs', me, m'')-kindConstraints m (TypeVar v) =- case M.lookup v m of- Just u -> return ([], u, m)- Nothing -> throwError $ "Unbound type variable " ++ v-kindConstraints m c@(TypeConstructor v) = do- env <- getEnv- me <- fresh- case M.lookup v m of- Nothing -> case M.lookup v (types env) of- Nothing -> throwError $ "Unknown type constructor '" ++ v ++ "'"- Just (kind, _) -> return ([KindConstraint me kind (TypeOrigin c)], me, m)- Just u -> return ([KindConstraint me (KUnknown u) (TypeOrigin c)], me, m)-kindConstraints m a@(TypeApp t1 t2) = do- me <- fresh- (cs1, n1, m1) <- kindConstraints m t1- (cs2, n2, m2) <- kindConstraints m1 t2- return (KindConstraint n1 (FunKind (KUnknown n2) (KUnknown me)) (TypeOrigin a) : cs1 ++ cs2, me, m2)-kindConstraints m t = do- me <- fresh- return ([KindConstraint me Star (TypeOrigin t)], me, m)--kindConstraintsForRow :: M.Map String Int -> Row -> Check ([KindConstraint], Int, M.Map String Int)-kindConstraintsForRow m r@(RowVar v) = do- me <- case M.lookup v m of- Just u -> return u- Nothing -> fresh- return ([KindConstraint me Row (RowOrigin r)], me, M.insert v me m)-kindConstraintsForRow m r@REmpty = do- me <- fresh- return ([KindConstraint me Row (RowOrigin r)], me, m)-kindConstraintsForRow m r@(RCons _ ty row) = do- me <- fresh- (cs1, n1, m1) <- kindConstraints m ty- (cs2, n2, m2) <- kindConstraintsForRow m1 row- return (KindConstraint me Row (RowOrigin r) : KindConstraint n1 Star (TypeOrigin ty) : KindConstraint n2 Row (RowOrigin r) : cs1 ++ cs2, me, m2)--solveKindConstraints :: [KindConstraint] -> KindSolution -> Check KindSolution-solveKindConstraints [] s = return s-solveKindConstraints all@(KindConstraint n k t : cs) s = do- (cs', s') <- rethrow (\err -> "Error in " ++ prettyPrintKindConstraintOrigin t ++ ": " ++ err) $ do- guardWith "Occurs check failed" $ not $ kindOccursCheck False n k- let s' = KindSolution $ replaceUnknownKind n k . runKindSolution s- cs' <- fmap concat $ mapM (substituteKindConstraint n k) cs- return (cs', s')- solveKindConstraints cs' s'--substituteKindConstraint :: Int -> Kind -> KindConstraint -> Check [KindConstraint]-substituteKindConstraint n k (KindConstraint m l t)- | n == m = unifyKinds t k l- | otherwise = return [KindConstraint m (replaceUnknownKind n k l) t]--replaceUnknownKind :: Int -> Kind -> Kind -> Kind-replaceUnknownKind n k = f- where- f (KUnknown m) | m == n = k- f (FunKind k1 k2) = FunKind (f k2) (f k2)- f other = other--unifyKinds :: KindConstraintOrigin -> Kind -> Kind -> Check [KindConstraint]-unifyKinds _ (KUnknown u1) (KUnknown u2) | u1 == u2 = return []-unifyKinds t (KUnknown u) k = do- guardWith "Occurs check failed" $ not $ kindOccursCheck False u k- return [KindConstraint u k t]-unifyKinds t k (KUnknown u) = do- guardWith "Occurs check failed" $ not $ kindOccursCheck False u k- return [KindConstraint u k t]-unifyKinds _ Star Star = return []-unifyKinds _ Row Row = return []-unifyKinds t (FunKind k1 k2) (FunKind k3 k4) = do- cs1 <- unifyKinds t k1 k3- cs2 <- unifyKinds t k2 k4- return $ cs1 ++ cs2-unifyKinds _ k1 k2 = throwError $ "Cannot unify " ++ prettyPrintKind k1 ++ " with " ++ prettyPrintKind k2 ++ "."--kindOccursCheck :: Bool -> Int -> Kind -> Bool-kindOccursCheck b u (KUnknown u') | u == u' = b-kindOccursCheck _ u (FunKind k1 k2) = kindOccursCheck True u k1 || kindOccursCheck True u k2-kindOccursCheck _ _ _ = False
− src/PureScript/TypeChecker/Monad.hs
@@ -1,67 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.TypeChecker.Monad--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------{-# LANGUAGE GeneralizedNewtypeDeriving, FlexibleInstances #-}--module PureScript.TypeChecker.Monad where--import PureScript.Types-import PureScript.Kinds-import PureScript.Names--import Control.Applicative-import Control.Monad.State-import Control.Monad.Error--import Control.Arrow ((***), first, second)--import qualified Data.Map as M--data NameKind = Value | Extern deriving Show--data TypeDeclarationKind = Data | ExternData | TypeSynonym deriving Show--data Environment = Environment- { names :: M.Map Ident (PolyType, NameKind)- , types :: M.Map String (Kind, TypeDeclarationKind)- , dataConstructors :: M.Map String PolyType- , typeSynonyms :: M.Map String ([String], Type)- }--emptyEnvironment :: Environment-emptyEnvironment = Environment M.empty M.empty M.empty M.empty--newtype Check a = Check { unCheck :: StateT (Environment, Int) (Either String) a } deriving (Functor, Monad, Applicative, MonadPlus, MonadState (Environment, Int), MonadError String)--getEnv :: Check Environment-getEnv = fmap fst get--putEnv :: Environment -> Check ()-putEnv env = fmap (first (const env)) get >>= put--fresh :: Check Int-fresh = do- (env, n) <- get- put (env, n + 1)- return n--check :: Check a -> Either String (a, Environment)-check = fmap (second fst) . flip runStateT (emptyEnvironment, 0) . unCheck--guardWith :: (MonadError e m) => e -> Bool -> m ()-guardWith _ True = return ()-guardWith e False = throwError e--rethrow :: (MonadError e m) => (e -> e) -> m a -> m a-rethrow f = flip catchError $ \e -> throwError (f e)
− src/PureScript/TypeChecker/Synonyms.hs
@@ -1,56 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.TypeChecker.Synonyms--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------{-# LANGUAGE Rank2Types #-}--module PureScript.TypeChecker.Synonyms (- saturateTypeSynonym,- saturateAllTypeSynonyms-) where--import PureScript.Types-import PureScript.Declarations--import Data.Maybe (fromMaybe)-import Data.Data-import Data.Generics-import Control.Arrow-import Control.Monad.Writer-import Control.Monad.Error-import qualified Data.Map as M--buildTypeSubstitution :: String -> Int -> Type -> Either String (Maybe Type)-buildTypeSubstitution name n = go n []- where- go :: Int -> [Type] -> Type -> Either String (Maybe Type)- go 0 args (TypeConstructor ctor) | name == ctor = return (Just $ SaturatedTypeSynonym ctor args)- go n _ (TypeConstructor ctor) | n > 0 && name == ctor = throwError $ "Partially applied type synonym " ++ name- go n args (TypeApp f arg) = go (n - 1) (arg:args) f- go _ _ _ = return Nothing--everywhereM' :: (Monad m, Data d) => (forall d. (Data d) => d -> m d) -> d -> m d-everywhereM' f x = do- y <- f x- gmapM (everywhereM' f) y--saturateTypeSynonym :: (Data d) => String -> Int -> d -> Either String d-saturateTypeSynonym name n = everywhereM' (mkM replace)- where- replace t = fmap (fromMaybe t) $ buildTypeSubstitution name n t--saturateAllTypeSynonyms :: (Data d) => [(String, Int)] -> d -> Either String d-saturateAllTypeSynonyms syns d = foldM (\d (name, n) -> saturateTypeSynonym name n d) d syns---
− src/PureScript/TypeChecker/Types.hs
@@ -1,626 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.TypeChecker.Types--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------{-# LANGUAGE DeriveDataTypeable #-}--module PureScript.TypeChecker.Types (- TypeConstraint(..),- TypeSolution(..),- typeOf-) where--import Debug.Trace--import Data.List-import Data.Function-import qualified Data.Data as D-import Data.Generics (everywhere, everywhereM, everything, mkT, mkM, mkQ, extM, extQ)--import PureScript.Values-import PureScript.Types-import PureScript.Kinds-import PureScript.Names-import PureScript.TypeChecker.Monad-import PureScript.TypeChecker.Kinds-import PureScript.TypeChecker.Synonyms-import PureScript.CodeGen.Pretty.Types-import PureScript.CodeGen.Pretty.Kinds-import PureScript.CodeGen.Pretty.Values--import Control.Monad.State-import Control.Monad.Error--import Control.Applicative-import Control.Arrow (Kleisli(..), (***), (&&&), first)-import qualified Control.Category as C--import qualified Data.Map as M--data TypeConstraintOrigin- = ValueOrigin Value- | BinderOrigin Binder- | AssignmentTargetOrigin Ident deriving (Show, D.Data, D.Typeable)--prettyPrintOrigin :: TypeConstraintOrigin -> String-prettyPrintOrigin (ValueOrigin val) = prettyPrintValue val-prettyPrintOrigin (BinderOrigin binder) = prettyPrintBinder binder-prettyPrintOrigin (AssignmentTargetOrigin ident) = show ident--data TypeConstraint- = TypeConstraint Int Type TypeConstraintOrigin- | RowConstraint Int Row TypeConstraintOrigin deriving (Show, D.Data, D.Typeable)--newtype TypeSolution = TypeSolution { runTypeSolution :: (Int -> Type, Int -> Row) }--emptyTypeSolution :: TypeSolution-emptyTypeSolution = TypeSolution (TUnknown, RUnknown)--isFunction :: Value -> Bool-isFunction (Abs _ _) = True-isFunction (TypedValue untyped _) = isFunction untyped-isFunction _ = False--allConstraints :: Ident -> Value -> Check ([TypeConstraint], Int)-allConstraints name val | isFunction val = do- me <- fresh- (cs, n) <- typeConstraints (M.singleton name me) val- return (TypeConstraint me (TUnknown n) (ValueOrigin val): cs, n)-allConstraints _ val = typeConstraints M.empty val--typeOf :: Ident -> Value -> Check PolyType-typeOf name val = do- (cs, n) <- allConstraints name val- desugared <- replaceAllTypeSynonyms cs- solution <- solveTypeConstraints desugared emptyTypeSolution- let ty = fst (runTypeSolution solution) n- allUnknownsBecameQuantified desugared solution ty- return $ varIfUnknown $ desaturateAllTypeSynonyms $ setifyAll ty--allUnknownsBecameQuantified :: [TypeConstraint] -> TypeSolution -> Type -> Check ()-allUnknownsBecameQuantified cs solution ty = do- let- typesMentioned = findUnknownTypes ty- unknownTypes = nub $ flip concatMap cs $ \c -> case c of- TypeConstraint u t _ -> u : findUnknownTypes t- RowConstraint _ r _ -> findUnknownTypes r- unsolvedTypes = filter (\n -> TUnknown n == fst (runTypeSolution solution) n) unknownTypes- guardWith "Unsolved type variable" $ null $ unsolvedTypes \\ typesMentioned- let- rowsMentioned = findUnknownRows ty- unknownRows = nub $ flip concatMap cs $ \c -> case c of- TypeConstraint _ t _ -> findUnknownRows t- RowConstraint u r _ -> u : findUnknownRows r- unsolvedRows = filter (\n -> RUnknown n == snd (runTypeSolution solution) n) unknownRows- guardWith "Unsolved row variable" $ null $ unsolvedRows \\ rowsMentioned--setify :: Row -> Row-setify = rowFromList . first (M.toList . M.fromList) . rowToList--setifyAll :: (D.Data d) => d -> d-setifyAll = everywhere (mkT setify)--findUnknownTypes :: (D.Data d) => d -> [Int]-findUnknownTypes = everything (++) (mkQ [] f)- where- f :: Type -> [Int]- f (TUnknown n) = [n]- f _ = []--findTypeVars :: (D.Data d) => d -> [String]-findTypeVars = everything (++) (mkQ [] f)- where- f :: Type -> [String]- f (TypeVar v) = [v]- f _ = []--findUnknownRows :: (D.Data d) => d -> [Int]-findUnknownRows = everything (++) (mkQ [] f)- where- f :: Row -> [Int]- f (RUnknown n) = [n]- f _ = []--varIfUnknown :: Type -> PolyType-varIfUnknown ty =- let- (ty', m) = flip runState M.empty $ everywhereM (flip extM g $ mkM f) ty- in- PolyType (sort $ nub $ M.elems m ++ findTypeVars ty) ty'- where- f :: Type -> State (M.Map Int String) Type- f (TUnknown n) = do- m <- get- case M.lookup n m of- Nothing -> do- let name = 't' : show (M.size m)- put $ M.insert n name m- return $ TypeVar name- Just name -> return $ TypeVar name- f t = return t- g :: Row -> State (M.Map Int String) Row- g (RUnknown n) = do- m <- get- case M.lookup n m of- Nothing -> do- let name = 'r' : show (M.size m)- put $ M.insert n name m- return $ RowVar name- Just name -> return $ RowVar name- g r = return r--replaceTypeVars :: M.Map String Type -> Type -> Type-replaceTypeVars m = everywhere (mkT replace)- where- replace (TypeVar v) = case M.lookup v m of- Just ty -> ty- _ -> TypeVar v- replace t = t--replaceVarsWithUnknowns :: [String] -> Type -> Check Type-replaceVarsWithUnknowns idents = flip evalStateT M.empty . everywhereM (flip extM f $ mkM g)- where- f :: Type -> StateT (M.Map String Int) Check Type- f (TypeVar var) | var `elem` idents = do- m <- get- n <- lift fresh- case M.lookup var m of- Nothing -> do- put (M.insert var n m)- return $ TUnknown n- Just u -> return $ TUnknown u- f t = return t- g :: Row -> StateT (M.Map String Int) Check Row- g (RowVar var) | var `elem` idents = do- m <- get- n <- lift fresh- case M.lookup var m of- Nothing -> do- put (M.insert var n m)- return $ RUnknown n- Just u -> return $ RUnknown u- g r = return r--replaceAllTypeSynonyms :: (D.Data d) => d -> Check d-replaceAllTypeSynonyms d = do- env <- getEnv- let syns = map (\(name, (args, _)) -> (name, length args)) . M.toList $ typeSynonyms env- either throwError return $ saturateAllTypeSynonyms syns d--desaturateAllTypeSynonyms :: (D.Data d) => d -> d-desaturateAllTypeSynonyms = everywhere (mkT replace)- where- replace (SaturatedTypeSynonym name args) = foldl TypeApp (TypeConstructor name) args- replace t = t--replaceType :: (D.Data d) => Int -> Type -> d -> d-replaceType n t = everywhere (mkT go)- where- go (TUnknown m) | m == n = t- go t = t--replaceRow :: (D.Data d) => Int -> Row -> d -> d-replaceRow n r = everywhere (mkT go)- where- go (RUnknown m) | m == n = r- go r = r--typeOccursCheck :: Int -> Type -> Check ()-typeOccursCheck u (TUnknown _) = return ()-typeOccursCheck u t = when (occursCheck u t) $ throwError $ "Occurs check failed: " ++ show u ++ " = " ++ prettyPrintType t--rowOccursCheck :: Int -> Row -> Check ()-rowOccursCheck u (RUnknown _) = return ()-rowOccursCheck u r = when (occursCheck u r) $ throwError $ "Occurs check failed: " ++ show u ++ " = " ++ prettyPrintRow r--occursCheck :: (D.Data d) => Int -> d -> Bool-occursCheck u = everything (||) $ flip extQ g $ mkQ False f- where- f (TUnknown u') | u' == u = True- f _ = False- g (RUnknown u') | u' == u = True- g _ = False--typesToRow :: [(String, Type)] -> Row-typesToRow [] = REmpty-typesToRow ((name, ty):tys) = RCons name ty (typesToRow tys)--rowToList :: Row -> ([(String, Type)], Row)-rowToList (RCons name ty row) = let (tys, rest) = rowToList row- in ((name, ty):tys, rest)-rowToList r = ([], r)--rowFromList :: ([(String, Type)], Row) -> Row-rowFromList ([], r) = r-rowFromList ((name, t):ts, r) = RCons name t (rowFromList (ts, r))--ensureNoDuplicateProperties :: [(String, Value)] -> Check ()-ensureNoDuplicateProperties ps = guardWith "Duplicate property names" $ length (nub . map fst $ ps) == length ps--typeConstraints :: M.Map Ident Int -> Value -> Check ([TypeConstraint], Int)-typeConstraints _ v@(NumericLiteral _) = do- me <- fresh- return ([TypeConstraint me Number (ValueOrigin v)], me)-typeConstraints _ v@(StringLiteral _) = do- me <- fresh- return ([TypeConstraint me String (ValueOrigin v)], me)-typeConstraints _ v@(BooleanLiteral _) = do- me <- fresh- return ([TypeConstraint me Boolean (ValueOrigin v)], me)-typeConstraints m v@(ArrayLiteral vals) = do- all <- mapM (typeConstraints m) vals- let (cs, ns) = (concatMap fst &&& map snd) all- me <- fresh- return (cs ++ zipWith (\n el -> TypeConstraint me (Array $ TUnknown n) (ValueOrigin el)) ns vals, me)-typeConstraints m u@(Unary op val) = do- (cs, n1) <- typeConstraints m val- me <- fresh- return (cs ++ unaryOperatorConstraints u op n1 me, me)-typeConstraints m b@(Binary op left right) = do- (cs1, n1) <- typeConstraints m left- (cs2, n2) <- typeConstraints m right- me <- fresh- return (cs1 ++ cs2 ++ binaryOperatorConstraints b op n1 n2 me, me)-typeConstraints m v@(ObjectLiteral ps) = do- ensureNoDuplicateProperties ps- all <- mapM (typeConstraints m . snd) ps- let (cs, ns) = (concatMap fst &&& map snd) all- me <- fresh- let tys = zipWith (\(name, _) u -> (name, TUnknown u)) ps ns- return (TypeConstraint me (Object (typesToRow tys)) (ValueOrigin v) : cs, me)-typeConstraints m v@(ObjectUpdate o ps) = do- ensureNoDuplicateProperties ps- (cs1, n1) <- typeConstraints m o- all <- mapM (typeConstraints m . snd) ps- let (cs2, ns) = (concatMap fst &&& map snd) all- row <- fresh- let tys = zipWith (\(name, _) u -> (name, TUnknown u)) ps ns- return (TypeConstraint n1 (Object (rowFromList (tys, RUnknown row))) (ValueOrigin v) : cs1 ++ cs2, n1)-typeConstraints m v@(Indexer index val) = do- (cs1, n1) <- typeConstraints m index- (cs2, n2) <- typeConstraints m val- me <- fresh- return (TypeConstraint n1 Number (ValueOrigin index) : TypeConstraint n2 (Array (TUnknown me)) (ValueOrigin v) : cs1 ++ cs2, me)-typeConstraints m v@(Accessor prop val) = do- (cs, n1) <- typeConstraints m val- me <- fresh- rest <- fresh- return (TypeConstraint n1 (Object (RCons prop (TUnknown me) (RUnknown rest))) (ValueOrigin v) : cs, me)-typeConstraints m v@(Abs args ret) = do- ns <- replicateM (length args) fresh- let m' = m `M.union` M.fromList (zip args ns)- (cs, n') <- typeConstraints m' ret- me <- fresh- return (TypeConstraint me (Function (map TUnknown ns) (TUnknown n')) (ValueOrigin v) : cs, me)-typeConstraints m v@(App f xs) = do- (cs1, n1) <- typeConstraints m f- all <- mapM (typeConstraints m) xs- let (cs2, ns) = (concatMap fst &&& map snd) all- me <- fresh- return (TypeConstraint n1 (Function (map TUnknown ns) (TUnknown me)) (ValueOrigin v) : cs1 ++ cs2, me)-typeConstraints m v@(Var var) =- case M.lookup var m of- Nothing -> do- env <- getEnv- case M.lookup var (names env) of- Nothing -> throwError $ show var ++ " is undefined"- Just (PolyType idents ty, _) -> do- me <- fresh- replaced <- replaceVarsWithUnknowns idents ty- return ([TypeConstraint me replaced (ValueOrigin v)], me)- Just u -> do- me <- fresh- return ([TypeConstraint u (TUnknown me) (ValueOrigin v)], me)-typeConstraints m (Block ss) = do- ret <- fresh- (cs, allCodePathsReturn, _) <- typeConstraintsForBlock m M.empty ret ss- guardWith "Block is missing a return statement" allCodePathsReturn- return (cs, ret)-typeConstraints m v@(Constructor c) = do- env <- getEnv- case M.lookup c (dataConstructors env) of- Nothing -> throwError $ "Constructor " ++ c ++ " is undefined"- Just (PolyType idents ty) -> do- me <- fresh- replaced <- replaceVarsWithUnknowns idents ty- return ([TypeConstraint me replaced (ValueOrigin v)], me)-typeConstraints m (Case val binders) = do- (cs1, n1) <- typeConstraints m val- ret <- fresh- cs2 <- typeConstraintsForBinders m n1 ret binders- return (cs1 ++ cs2, ret)-typeConstraints m v@(IfThenElse cond th el) = do- (cs1, n1) <- typeConstraints m cond- (cs2, n2) <- typeConstraints m th- (cs3, n3) <- typeConstraints m el- return (TypeConstraint n1 Boolean (ValueOrigin cond) : TypeConstraint n2 (TUnknown n3) (ValueOrigin v) : cs1 ++ cs2 ++ cs3, n2)-typeConstraints m v@(TypedValue val poly@(PolyType idents ty)) = do- kind <- kindOf poly- guardWith ("Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star- (cs, n1) <- typeConstraints m val- return (TypeConstraint n1 ty (ValueOrigin v) : cs, n1)--unaryOperatorConstraints :: Value -> UnaryOperator -> Int -> Int -> [TypeConstraint]-unaryOperatorConstraints v Negate val result = [TypeConstraint val Number (ValueOrigin v), TypeConstraint result Number (ValueOrigin v)]-unaryOperatorConstraints v Not val result = [TypeConstraint val Boolean (ValueOrigin v), TypeConstraint result Boolean (ValueOrigin v)]-unaryOperatorConstraints v BitwiseNot val result = [TypeConstraint val Number (ValueOrigin v), TypeConstraint result Number (ValueOrigin v)]--binaryOperatorConstraints :: Value -> BinaryOperator -> Int -> Int -> Int -> [TypeConstraint]-binaryOperatorConstraints v Add = symBinOpConstraints v Number-binaryOperatorConstraints v Subtract = symBinOpConstraints v Number-binaryOperatorConstraints v Multiply = symBinOpConstraints v Number-binaryOperatorConstraints v Divide = symBinOpConstraints v Number-binaryOperatorConstraints v Modulus = symBinOpConstraints v Number-binaryOperatorConstraints v LessThan = asymBinOpConstraints v Number Boolean-binaryOperatorConstraints v LessThanOrEqualTo = asymBinOpConstraints v Number Boolean-binaryOperatorConstraints v GreaterThan = asymBinOpConstraints v Number Boolean-binaryOperatorConstraints v GreaterThanOrEqualTo = asymBinOpConstraints v Number Boolean-binaryOperatorConstraints v BitwiseAnd = symBinOpConstraints v Number-binaryOperatorConstraints v BitwiseOr = symBinOpConstraints v Number-binaryOperatorConstraints v BitwiseXor = symBinOpConstraints v Number-binaryOperatorConstraints v ShiftLeft = symBinOpConstraints v Number-binaryOperatorConstraints v ShiftRight = symBinOpConstraints v Number-binaryOperatorConstraints v ZeroFillShiftRight = symBinOpConstraints v Number-binaryOperatorConstraints v EqualTo = equalityBinOpConstraints v-binaryOperatorConstraints v NotEqualTo = equalityBinOpConstraints v-binaryOperatorConstraints v And = symBinOpConstraints v Boolean-binaryOperatorConstraints v Or = symBinOpConstraints v Boolean-binaryOperatorConstraints v Concat = symBinOpConstraints v String--equalityBinOpConstraints :: Value -> Int -> Int -> Int -> [TypeConstraint]-equalityBinOpConstraints v left right result = [TypeConstraint left (TUnknown right) (ValueOrigin v), TypeConstraint result Boolean (ValueOrigin v)]--symBinOpConstraints :: Value -> Type -> Int -> Int -> Int -> [TypeConstraint]-symBinOpConstraints v ty = asymBinOpConstraints v ty ty--asymBinOpConstraints :: Value -> Type -> Type -> Int -> Int -> Int -> [TypeConstraint]-asymBinOpConstraints v ty res left right result = [TypeConstraint left ty (ValueOrigin v), TypeConstraint right ty (ValueOrigin v), TypeConstraint result res (ValueOrigin v)]--typeConstraintsForBinder :: Int -> Binder -> Check ([TypeConstraint], M.Map Ident Int)-typeConstraintsForBinder _ NullBinder = return ([], M.empty)-typeConstraintsForBinder val b@(StringBinder _) = constantBinder b val String-typeConstraintsForBinder val b@(NumberBinder _) = constantBinder b val Number-typeConstraintsForBinder val b@(BooleanBinder _) = constantBinder b val Boolean-typeConstraintsForBinder val b@(VarBinder name) = do- me <- fresh- return ([TypeConstraint me (TUnknown val) (BinderOrigin b)], M.singleton name me)-typeConstraintsForBinder val b@(NullaryBinder ctor) = do- env <- getEnv- case M.lookup ctor (dataConstructors env) of- Just (PolyType args ret) -> do- ret' <- replaceVarsWithUnknowns args ret- return ([TypeConstraint val ret' (BinderOrigin b)], M.empty)- _ -> throwError $ "Constructor " ++ ctor ++ " is not defined"-typeConstraintsForBinder val b@(UnaryBinder ctor binder) = do- env <- getEnv- case M.lookup ctor (dataConstructors env) of- Just (PolyType idents f@(Function [_] _)) -> do- obj <- fresh- (Function [ty] ret) <- replaceVarsWithUnknowns idents f- (cs, m1) <- typeConstraintsForBinder obj binder- return (TypeConstraint val ret (BinderOrigin b) : TypeConstraint obj ty (BinderOrigin b) : cs, m1)- Just _ -> throwError $ ctor ++ " is not a unary constructor"- _ -> throwError $ "Constructor " ++ ctor ++ " is not defined"-typeConstraintsForBinder val b@(ObjectBinder props) = do- row <- fresh- rest <- fresh- (cs, m1) <- typeConstraintsForProperties row (RUnknown rest) props- return (TypeConstraint val (Object (RUnknown row)) (BinderOrigin b) : cs, m1)- where- typeConstraintsForProperties :: Int -> Row -> [(String, Binder)] -> Check ([TypeConstraint], M.Map Ident Int)- typeConstraintsForProperties nrow row [] = return ([RowConstraint nrow row (BinderOrigin b)], M.empty)- typeConstraintsForProperties nrow row ((name, binder):binders) = do- propTy <- fresh- (cs1, m1) <- typeConstraintsForBinder propTy binder- (cs2, m2) <- typeConstraintsForProperties nrow (RCons name (TUnknown propTy) row) binders- return (cs1 ++ cs2, m1 `M.union` m2)-typeConstraintsForBinder val b@(ArrayBinder binders rest) = do- el <- fresh- all <- mapM (typeConstraintsForBinder el) binders- let (cs1, m1) = (concatMap fst &&& M.unions . map snd) all- let arrayConstraint = TypeConstraint val (Array (TUnknown el)) (BinderOrigin b)- case rest of- Nothing -> return (arrayConstraint : cs1, m1)- Just binder -> do- (cs2, m2) <- typeConstraintsForBinder val binder- return (arrayConstraint : cs1 ++ cs2, m1 `M.union` m2)-typeConstraintsForBinder val b@(NamedBinder name binder) = do- me <- fresh- (cs, m) <- typeConstraintsForBinder val binder- return (TypeConstraint me (TUnknown val) (BinderOrigin b) : cs, M.insert name me m)-typeConstraintsForBinder val b@(GuardedBinder cond binder) = do- (cs1, m) <- typeConstraintsForBinder val binder- (cs2, n) <- typeConstraints m cond- return (TypeConstraint n Boolean (ValueOrigin cond) : cs1 ++ cs2, m)--constantBinder :: Binder -> Int -> Type -> Check ([TypeConstraint], M.Map Ident Int)-constantBinder b val ty = return ([TypeConstraint val ty (BinderOrigin b)], M.empty)--typeConstraintsForBinders :: M.Map Ident Int -> Int -> Int -> [(Binder, Value)] -> Check [TypeConstraint]-typeConstraintsForBinders _ _ _ [] = return []-typeConstraintsForBinders m nval ret ((binder, val):bs) = do- (cs1, m1) <- typeConstraintsForBinder nval binder- (cs2, n2) <- typeConstraints (m `M.union` m1) val- cs3 <- typeConstraintsForBinders m nval ret bs- return (TypeConstraint n2 (TUnknown ret) (BinderOrigin binder) : cs1 ++ cs2 ++ cs3)--assignVariable :: Ident -> M.Map Ident Int -> Check ()-assignVariable name m =- case M.lookup name m of- Nothing -> return ()- Just _ -> throwError $ "Variable with name " ++ show name ++ " already exists."--typeConstraintsForStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> Statement -> Check ([TypeConstraint], Bool, M.Map Ident Int)-typeConstraintsForStatement m mass ret (VariableIntroduction name val) = do- assignVariable name (m `M.union` mass)- (cs1, n1) <- typeConstraints m val- return (cs1, False, M.insert name n1 mass)-typeConstraintsForStatement m mass ret (Assignment ident val) = do- (cs1, n1) <- typeConstraints m val- case M.lookup ident mass of- Nothing -> throwError $ "No local variable with name " ++ show ident- Just ty ->- return (TypeConstraint n1 (TUnknown ty) (AssignmentTargetOrigin ident) : cs1, False, mass)-typeConstraintsForStatement m mass ret (While val inner) = do- (cs1, n1) <- typeConstraints m val- (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret inner- return (TypeConstraint n1 Boolean (ValueOrigin val) : cs1 ++ cs2, allCodePathsReturn, mass)-typeConstraintsForStatement m mass ret (If ifst) = do- (cs, allCodePathsReturn) <- typeConstraintsForIfStatement m mass ret ifst- return (cs, allCodePathsReturn, mass)-typeConstraintsForStatement m mass ret (For ident start end inner) = do- assignVariable ident (m `M.union` mass)- (cs1, n1) <- typeConstraints (m `M.union` mass) start- (cs2, n2) <- typeConstraints (m `M.union` mass) end- let mass1 = M.insert ident n1 mass- (cs3, allCodePathsReturn, _) <- typeConstraintsForBlock (m `M.union` mass1) mass1 ret inner- return (TypeConstraint n1 Number (ValueOrigin start) : TypeConstraint n2 Number (ValueOrigin end) : cs1 ++ cs2 ++ cs3, allCodePathsReturn, mass)-typeConstraintsForStatement m mass ret (ForEach ident vals inner) = do- assignVariable ident (m `M.union` mass)- val <- fresh- (cs1, n1) <- typeConstraints (m `M.union` mass) vals- let mass1 = M.insert ident val mass- (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock (m `M.union` mass1) mass1 ret inner- guardWith "Cannot return from within a foreach block" $ not allCodePathsReturn- return (TypeConstraint n1 (Array (TUnknown val)) (ValueOrigin vals) : cs1 ++ cs2, False, mass)-typeConstraintsForStatement m mass ret (Return val) = do- (cs1, n1) <- typeConstraints (m `M.union` mass) val- return (TypeConstraint n1 (TUnknown ret) (ValueOrigin val) : cs1, True, mass)--typeConstraintsForIfStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> IfStatement -> Check ([TypeConstraint], Bool)-typeConstraintsForIfStatement m mass ret (IfStatement val thens Nothing) = do- (cs1, n1) <- typeConstraints m val- (cs2, _, _) <- typeConstraintsForBlock m mass ret thens- return (TypeConstraint n1 Boolean (ValueOrigin val) : cs1 ++ cs2, False)-typeConstraintsForIfStatement m mass ret (IfStatement val thens (Just elses)) = do- (cs1, n1) <- typeConstraints m val- (cs2, allCodePathsReturn1, _) <- typeConstraintsForBlock m mass ret thens- (cs3, allCodePathsReturn2) <- typeConstraintsForElseStatement m mass ret elses- return (TypeConstraint n1 Boolean (ValueOrigin val) : cs1 ++ cs2 ++ cs3, allCodePathsReturn1 && allCodePathsReturn2)--typeConstraintsForElseStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> ElseStatement -> Check ([TypeConstraint], Bool)-typeConstraintsForElseStatement m mass ret (Else elses) = do- (cs, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret elses- return (cs, allCodePathsReturn)-typeConstraintsForElseStatement m mass ret (ElseIf ifst) = do- (cs, allCodePathsReturn) <- typeConstraintsForIfStatement m mass ret ifst- return (cs, allCodePathsReturn)--typeConstraintsForBlock :: M.Map Ident Int -> M.Map Ident Int -> Int -> [Statement] -> Check ([TypeConstraint], Bool, M.Map Ident Int)-typeConstraintsForBlock _ mass _ [] = return ([], False, mass)-typeConstraintsForBlock m mass ret (s:ss) = do- (cs1, b1, mass1) <- typeConstraintsForStatement (m `M.union` mass) mass ret s- case (b1, ss) of- (True, []) -> return (cs1, True, mass1)- (True, _) -> throwError "Unreachable code"- (False, ss) -> do- (cs2, b2, mass2) <- typeConstraintsForBlock m mass1 ret ss- return (cs1 ++ cs2, b2, mass2)--solveTypeConstraints :: [TypeConstraint] -> TypeSolution -> Check TypeSolution-solveTypeConstraints [] s = return s-solveTypeConstraints all@(TypeConstraint n t o:cs) s = do- (cs', s') <- rethrow (\err -> "Error in " ++ prettyPrintOrigin o ++ ": " ++ err) $ do- typeOccursCheck n t- let s' = let (f, g) = runTypeSolution s- in TypeSolution (replaceType n t . f, replaceType n t . g)- cs' <- fmap concat $ mapM (substituteTypeInConstraint n t) cs- return (cs', s')- solveTypeConstraints cs' s'-solveTypeConstraints (RowConstraint n r o:cs) s = do- (cs', s') <- rethrow (\err -> "Error in " ++ prettyPrintOrigin o ++ ": " ++ err) $ do- rowOccursCheck n r- let s' = let (f, g) = runTypeSolution s- in TypeSolution (replaceRow n r . f, replaceRow n r . g)- cs' <- fmap concat $ mapM (substituteRowInConstraint n r) cs- return (cs', s')- solveTypeConstraints cs' s'--substituteTypeInConstraint :: Int -> Type -> TypeConstraint -> Check [TypeConstraint]-substituteTypeInConstraint n s (TypeConstraint m t v)- | n == m = unifyTypes v s t- | otherwise = return [TypeConstraint m (replaceType n s t) v]-substituteTypeInConstraint n s (RowConstraint m r v)- = return [RowConstraint m (replaceType n s r) v]--substituteRowInConstraint :: Int -> Row -> TypeConstraint -> Check [TypeConstraint]-substituteRowInConstraint n r (TypeConstraint m t v)- = return [TypeConstraint m (replaceRow n r t) v]-substituteRowInConstraint n r (RowConstraint m r1 v)- | m == n = unifyRows v r r1- | otherwise = return [RowConstraint m (replaceRow n r r1) v]--unifyTypes :: TypeConstraintOrigin -> Type -> Type -> Check [TypeConstraint]-unifyTypes _ (TUnknown u1) (TUnknown u2) | u1 == u2 = return []-unifyTypes o (TUnknown u) t = do- typeOccursCheck u t- return [TypeConstraint u t o]-unifyTypes o t (TUnknown u) = do- typeOccursCheck u t- return [TypeConstraint u t o]-unifyTypes o (SaturatedTypeSynonym name1 args1) (SaturatedTypeSynonym name2 args2) | name1 == name2 =- fmap concat $ zipWithM (unifyTypes o) args1 args2-unifyTypes o (SaturatedTypeSynonym name args) ty = do- env <- getEnv- case M.lookup name (typeSynonyms env) of- Just (synArgs, body) -> do- let m = M.fromList $ zip synArgs args- let replaced = replaceTypeVars m body- unifyTypes o replaced ty- Nothing -> error "Type synonym was not defined"-unifyTypes o ty s@(SaturatedTypeSynonym _ _) = unifyTypes o s ty-unifyTypes _ Number Number = return []-unifyTypes _ String String = return []-unifyTypes _ Boolean Boolean = return []-unifyTypes o (Array s) (Array t) = unifyTypes o s t-unifyTypes o (Object row1) (Object row2) = unifyRows o row1 row2-unifyTypes o (Function args1 ret1) (Function args2 ret2) = do- guardWith "Function applied to incorrect number of args" $ length args1 == length args2- cs1 <- fmap concat $ zipWithM (unifyTypes o) args1 args2- cs2 <- unifyTypes o ret1 ret2- return $ cs1 ++ cs2-unifyTypes _ (TypeVar v1) (TypeVar v2) | v1 == v2 = return []-unifyTypes _ (TypeConstructor c1) (TypeConstructor c2) | c1 == c2 = return []-unifyTypes o (TypeApp t1 t2) (TypeApp t3 t4) = do- cs1 <- unifyTypes o t1 t3- cs2 <- unifyTypes o t2 t4- return $ cs1 ++ cs2-unifyTypes _ t1 t2 = throwError $ "Cannot unify " ++ prettyPrintType t1 ++ " with " ++ prettyPrintType t2 ++ "."--unifyRows :: TypeConstraintOrigin -> Row -> Row -> Check [TypeConstraint]-unifyRows o r1 r2 =- let- (s1, r1') = rowToList r1- (s2, r2') = rowToList r2- int = [ (t1, t2) | (name, t1) <- s1, (name', t2) <- s2, name == name' ]- sd1 = [ (name, t1) | (name, t1) <- s1, name `notElem` map fst s2 ]- sd2 = [ (name, t2) | (name, t2) <- s2, name `notElem` map fst s1 ]- in do- cs1 <- fmap concat $ mapM (uncurry $ unifyTypes o) int- cs2 <- unifyRows' o sd1 r1' sd2 r2'- return $ cs1 ++ cs2- where- unifyRows' :: TypeConstraintOrigin -> [(String, Type)] -> Row -> [(String, Type)] -> Row -> Check [TypeConstraint]- unifyRows' o [] (RUnknown u) sd r = do- rowOccursCheck u r- return [RowConstraint u (rowFromList (sd, r)) o]- unifyRows' o sd r [] (RUnknown u) = do- rowOccursCheck u r- return [RowConstraint u (rowFromList (sd, r)) o]- unifyRows' o ns@((name, ty):row) r others (RUnknown u) | not (occursCheck u (ty, row)) = do- u' <- fresh- cs <- unifyRows' o row r others (RUnknown u')- return (RowConstraint u (RCons name ty (RUnknown u')) o : cs)- unifyRows' _ [] REmpty [] REmpty = return []- unifyRows' _ [] (RowVar v1) [] (RowVar v2) | v1 == v2 = return []- unifyRows' _ sd1 r1 sd2 r2 = throwError $ "Cannot unify " ++ prettyPrintRow (rowFromList (sd1, r1)) ++ " with " ++ prettyPrintRow (rowFromList (sd2, r2)) ++ "."
− src/PureScript/Types.hs
@@ -1,43 +0,0 @@------------------------------------------------------------------------------------ Module : Purescript.Types--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------{-# LANGUAGE DeriveDataTypeable #-}--module PureScript.Types where--import Data.Data--data Type- = TUnknown Int- | Number- | String- | Boolean- | Array Type- | Object Row- | Function [Type] Type- | TypeVar String- | TypeConstructor String- | TypeApp Type Type- | SaturatedTypeSynonym String [Type] deriving (Show, Eq, Data, Typeable)--data PolyType = PolyType [String] Type deriving (Show, Eq, Data, Typeable)--data Row- = RUnknown Int- | RowVar String- | REmpty- | RCons String Type Row deriving (Show, Eq, Data, Typeable)--monoType :: Type -> PolyType-monoType = PolyType []
− src/PureScript/Values.hs
@@ -1,97 +0,0 @@------------------------------------------------------------------------------------ Module : PureScript.Values--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |-----------------------------------------------------------------------------------{-# LANGUAGE DeriveDataTypeable #-}--module PureScript.Values where--import PureScript.Types-import PureScript.Names--import Data.Data--data UnaryOperator- = Negate- | Not- | BitwiseNot deriving (Show, Eq, Data, Typeable)--data BinaryOperator- = Add- | Subtract- | Multiply- | Divide- | Modulus- | EqualTo- | NotEqualTo- | LessThan- | LessThanOrEqualTo- | GreaterThan- | GreaterThanOrEqualTo- | And- | Or- | BitwiseAnd- | BitwiseOr- | BitwiseXor- | ShiftLeft- | ShiftRight- | ZeroFillShiftRight- | Concat deriving (Show, Eq, Data, Typeable)--data Value- = NumericLiteral (Either Integer Double)- | StringLiteral String- | BooleanLiteral Bool- | Unary UnaryOperator Value- | Binary BinaryOperator Value Value- | ArrayLiteral [Value]- | Indexer Value Value- | ObjectLiteral [(String, Value)]- | Accessor String Value- | ObjectUpdate Value [(String, Value)]- | Abs [Ident] Value- | App Value [Value]- | Var Ident- | IfThenElse Value Value Value- | Block [Statement]- | Constructor String- | Case Value [(Binder, Value)]- | TypedValue Value PolyType deriving (Show, Data, Typeable)--data Statement- = VariableIntroduction Ident Value- | Assignment Ident Value- | While Value [Statement]- | For Ident Value Value [Statement]- | ForEach Ident Value [Statement]- | If IfStatement- | Return Value deriving (Show, Data, Typeable)--data IfStatement = IfStatement Value [Statement] (Maybe ElseStatement) deriving (Show, Data, Typeable)--data ElseStatement- = Else [Statement]- | ElseIf IfStatement deriving (Show, Data, Typeable)--data Binder- = NullBinder- | BooleanBinder Bool- | StringBinder String- | NumberBinder (Either Integer Double)- | VarBinder Ident- | NullaryBinder String- | UnaryBinder String Binder- | ObjectBinder [(String, Binder)]- | ArrayBinder [Binder] (Maybe Binder)- | NamedBinder Ident Binder- | GuardedBinder Value Binder deriving (Show, Data, Typeable)
tests/Main.hs view
@@ -14,8 +14,7 @@ module Main (main) where -import PureScript-import PureScript.CodeGen.Pretty.Types+import Language.PureScript import Data.List (isSuffixOf) import Control.Applicative