haste-compiler 0.4.2 → 0.4.2.1
raw patch · 10 files changed
+254/−89 lines, 10 filesdep +network-uridep ~networkdep ~websockets
Dependencies added: network-uri
Dependency ranges changed: network, websockets
Files
- haste-compiler.cabal +11/−2
- lib/rts.js +23/−16
- libraries/haste-lib/src/Haste/Binary.hs +126/−2
- src/Data/JSTarget.hs +1/−1
- src/Data/JSTarget/AST.hs +49/−34
- src/Data/JSTarget/Traversal.hs +1/−1
- src/Haste/Module.hs +21/−12
- src/Haste/Monad.hs +8/−8
- src/Haste/Version.hs +1/−1
- src/Main.hs +13/−12
haste-compiler.cabal view
@@ -1,5 +1,5 @@ Name: haste-compiler-Version: 0.4.2+Version: 0.4.2.1 License: BSD3 License-File: LICENSE Synopsis: Haskell To ECMAScript compiler@@ -62,6 +62,7 @@ bzlib, transformers, network,+ network-uri, HTTP, shellmate >= 0.1.5, ghc-paths,@@ -235,7 +236,6 @@ binary, data-binary-ieee754, bytestring >= 0.9.2.1,- websockets >= 0.8, utf8-string, -- For Haste.Compiler shellmate >= 0.1.5,@@ -246,4 +246,13 @@ ghc-paths, ghc, directory+ -- websockets-0.9 is broken on Windows+ if os(windows)+ Build-Depends:+ websockets >= 0.8 && < 0.9,+ network < 2.6,+ network-uri < 2.6+ else+ Build-Depends:+ websockets >= 0.8 Default-Language: Haskell98
lib/rts.js view
@@ -69,21 +69,24 @@ function E(t) { if(t instanceof T) { if(t.f instanceof F) {- return t.f = t.f.f();- } else {- return t.f;+ var f = t.f.f;+ t.f = 0;+ t.f = f(); }+ return t.f; } else { return t; } } /* Bounce- Bonuce on a trampoline for as long as we get a function back.+ Bounce on a trampoline for as long as we get a function back. */ function B(f) { while(f instanceof F) {- f = f.f();+ var fun = f.f;+ f = 0;+ f = fun(); } return f; }@@ -117,12 +120,16 @@ // 32 bit integer multiplication, with correct overflow behavior // note that |0 or >>>0 needs to be applied to the result, for int and word // respectively.-function imul(a, b) {- // ignore high a * high a as the result will always be truncated- var lows = (a & 0xffff) * (b & 0xffff); // low a * low b- var aB = (a & 0xffff) * (b & 0xffff0000); // low a * high b- var bA = (a & 0xffff0000) * (b & 0xffff); // low b * high a- return lows + aB + bA; // sum will not exceed 52 bits, so it's safe+if(Math.imul) {+ var imul = Math.imul;+} else {+ var imul = function(a, b) {+ // ignore high a * high a as the result will always be truncated+ var lows = (a & 0xffff) * (b & 0xffff); // low a * low b+ var aB = (a & 0xffff) * (b & 0xffff0000); // low a * high b+ var bA = (a & 0xffff0000) * (b & 0xffff); // low b * high a+ return lows + aB + bA; // sum will not exceed 52 bits, so it's safe+ } } function addC(a, b) {@@ -254,11 +261,11 @@ function localeEncoding() { var le = newByteArr(5);- le['b']['i8'] = 'U'.charCodeAt(0);- le['b']['i8'] = 'T'.charCodeAt(0);- le['b']['i8'] = 'F'.charCodeAt(0);- le['b']['i8'] = '-'.charCodeAt(0);- le['b']['i8'] = '8'.charCodeAt(0);+ le['v']['i8'][0] = 'U'.charCodeAt(0);+ le['v']['i8'][1] = 'T'.charCodeAt(0);+ le['v']['i8'][2] = 'F'.charCodeAt(0);+ le['v']['i8'][3] = '-'.charCodeAt(0);+ le['v']['i8'][4] = '8'.charCodeAt(0); return le; }
libraries/haste-lib/src/Haste/Binary.hs view
@@ -1,7 +1,9 @@ {-# LANGUAGE MagicHash, CPP, MultiParamTypeClasses, OverloadedStrings, TypeSynonymInstances , FlexibleInstances, OverlappingInstances,- GeneralizedNewtypeDeriving #-}+ GeneralizedNewtypeDeriving, BangPatterns, TypeOperators, KindSignatures, DefaultSignatures, FlexibleInstances, TypeSynonymInstances, FlexibleContexts, ScopedTypeVariables #-} -- | Handling of Javascript-native binary blobs.+--+-- Generics borrowed from the binary package by Lennart Kolmodin (released under BSD3) module Haste.Binary ( module Haste.Binary.Put, module Haste.Binary.Get,@@ -20,6 +22,8 @@ import Haste.Binary.Put import Haste.Binary.Get import Control.Applicative+import GHC.Generics+import Data.Bits class Monad m => MonadBlob m where -- | Retrieve the raw data from a blob.@@ -43,7 +47,7 @@ #else mkBlobData = undefined #endif- + convertBlob :: Blob -> Opaque (Unpacked -> IO ()) -> IO () convertBlob = ffi "(function(b,cb){var r=new FileReader();r.onload=function(){B(A(cb,[new DataView(r.result),0]));};r.readAsArrayBuffer(b);})"@@ -65,6 +69,17 @@ get :: Get a put :: a -> Put + default put :: (Generic a, GBinary (Rep a)) => a -> Put+ put = gput . from++ default get :: (Generic a, GBinary (Rep a)) => Get a+ get = to `fmap` gget++-- | Generic version+class GBinary f where+ gput :: f t -> Put+ gget :: Get (f t)+ instance Binary Word8 where put = putWord8 get = getWord8@@ -160,3 +175,112 @@ decode :: Binary a => BlobData -> Either String a decode = runGet get+++-- Type without constructors+instance GBinary V1 where+ gput _ = return ()+ gget = return undefined++-- Constructor without arguments+instance GBinary U1 where+ gput U1 = return ()+ gget = return U1++-- Product: constructor with parameters+instance (GBinary a, GBinary b) => GBinary (a :*: b) where+ gput (x :*: y) = gput x >> gput y+ gget = (:*:) <$> gget <*> gget++-- Metadata (constructor name, etc)+instance GBinary a => GBinary (M1 i c a) where+ gput = gput . unM1+ gget = M1 <$> gget++-- Constants, additional parameters, and rank-1 recursion+instance Binary a => GBinary (K1 i a) where+ gput = put . unK1+ gget = K1 <$> get++-- Borrowed from the cereal package.++-- The following GBinary instance for sums has support for serializing+-- types with up to 2^64-1 constructors. It will use the minimal+-- number of bytes needed to encode the constructor. For example when+-- a type has 2^8 constructors or less it will use a single byte to+-- encode the constructor. If it has 2^16 constructors or less it will+-- use two bytes, and so on till 2^64-1.+--+-- NB: changed to 2^32-1 constructors++#define GUARD(WORD) (size - 1) <= fromIntegral (maxBound :: WORD)+#define PUTSUM(WORD) GUARD(WORD) = putSum (0 :: WORD) (fromIntegral size)+#define GETSUM(WORD) GUARD(WORD) = (get :: Get WORD) >>= checkGetSum (fromIntegral size)++instance ( GSum a, GSum b+ , GBinary a, GBinary b+ , SumSize a, SumSize b) => GBinary (a :+: b) where+ gput | PUTSUM(Word8) | PUTSUM(Word16) | PUTSUM(Word32) -- | PUTSUM(Word64)+ | otherwise = sizeError "encode" size+ where+ size = unTagged (sumSize :: Tagged (a :+: b) Word32)+ {-# INLINE gput #-}++ gget | GETSUM(Word8) | GETSUM(Word16) | GETSUM(Word32) -- | GETSUM(Word64)+ | otherwise = sizeError "decode" size+ where+ size = unTagged (sumSize :: Tagged (a :+: b) Word32)+ {-# INLINE gget #-}++sizeError :: Show size => String -> size -> error+sizeError s size =+ error $ "Can't " ++ s ++ " a type with " ++ show size ++ " constructors"++------------------------------------------------------------------------++checkGetSum :: (Ord word, Num word, Bits word, GSum f)+ => word -> word -> Get (f a)+checkGetSum size code | code < size = getSum code size+ | otherwise = fail "Unknown encoding for constructor"+{-# INLINE checkGetSum #-}++class GSum f where+ getSum :: (Ord word, Num word, Bits word) => word -> word -> Get (f a)+ putSum :: (Num w, Bits w, Binary w) => w -> w -> f a -> Put++instance (GSum a, GSum b, GBinary a, GBinary b) => GSum (a :+: b) where+ getSum !code !size | code < sizeL = L1 <$> getSum code sizeL+ | otherwise = R1 <$> getSum (code - sizeL) sizeR+ where+ sizeL = size `shiftR` 1+ sizeR = size - sizeL+ {-# INLINE getSum #-}++ putSum !code !size s = case s of+ L1 x -> putSum code sizeL x+ R1 x -> putSum (code + sizeL) sizeR x+ where+ sizeL = size `shiftR` 1+ sizeR = size - sizeL+ {-# INLINE putSum #-}++instance GBinary a => GSum (C1 c a) where+ getSum _ _ = gget+ {-# INLINE getSum #-}++ putSum !code _ x = put code *> gput x+ {-# INLINE putSum #-}++------------------------------------------------------------------------++class SumSize f where+ sumSize :: Tagged f Word32++newtype Tagged (s :: * -> *) b = Tagged {unTagged :: b}++instance (SumSize a, SumSize b) => SumSize (a :+: b) where+ sumSize = Tagged $ unTagged (sumSize :: Tagged a Word32) ++ unTagged (sumSize :: Tagged b Word32)++instance SumSize (C1 c a) where+ sumSize = Tagged 1
src/Data/JSTarget.hs view
@@ -4,7 +4,7 @@ PPOpts (..), pretty, runPP, prettyProg, def, Arity, Comment, Shared, Name (..), Var (..), LHS, Call, Lit, Exp, Stm, Alt, AST (..), Module (..),- foreignModule, moduleOf, pkgOf, blackHole, blackHoleVar+ foreignModule, moduleOf, pkgOf, blackHole, blackHoleVar, merge ) where import Data.JSTarget.AST import Data.JSTarget.Op as Op
src/Data/JSTarget/AST.hs view
@@ -1,7 +1,11 @@-{-# LANGUAGE GADTs, GeneralizedNewtypeDeriving, FlexibleInstances #-}+{-# LANGUAGE GADTs, GeneralizedNewtypeDeriving, FlexibleInstances, CPP #-} module Data.JSTarget.AST where import qualified Data.Set as S+#if __GLASGOW_HASKELL__ >= 708+import qualified Data.Map.Strict as M+#else import qualified Data.Map as M+#endif import System.IO.Unsafe import System.Random (randomIO) import Data.IORef@@ -16,7 +20,7 @@ -- | Shared statements. newtype Shared a = Shared Lbl deriving (Eq, Show) -data Name = Name String (Maybe (String, String)) deriving (Eq, Ord, Show)+data Name = Name !String !(Maybe (String, String)) deriving (Eq, Ord, Show) class HasModule a where moduleOf :: a -> Maybe String@@ -34,8 +38,8 @@ -- | Representation of variables. data Var where- Foreign :: String -> Var- Internal :: Name -> Comment -> Var+ Foreign :: !String -> Var+ Internal :: !Name -> !Comment -> Var deriving (Show) instance Eq Var where@@ -53,8 +57,8 @@ -- but for some primops we need to assign array elements as well. -- LhsExp is never reorderable. data LHS where- NewVar :: Reorderable -> Var -> LHS- LhsExp :: Exp -> LHS+ NewVar :: !Reorderable -> !Var -> LHS+ LhsExp :: !Exp -> LHS deriving (Eq, Show) -- | Distinguish between normal, optimized and method calls.@@ -63,48 +67,48 @@ -- only be set to False when there is absolutely no possibility whatsoever -- that the called function will tailcall. data Call where- Normal :: Bool -> Call- Fast :: Bool -> Call- Method :: String -> Call+ Normal :: !Bool -> Call+ Fast :: !Bool -> Call+ Method :: !String -> Call deriving (Eq, Show) -- | Literals; nothing fancy to see here. data Lit where- LNum :: Double -> Lit- LStr :: String -> Lit- LBool :: Bool -> Lit- LInt :: Integer -> Lit+ LNum :: !Double -> Lit+ LStr :: !String -> Lit+ LBool :: !Bool -> Lit+ LInt :: !Integer -> Lit LNull :: Lit deriving (Eq, Show) -- | Expressions. Completely predictable. data Exp where- Var :: Var -> Exp- Lit :: Lit -> Exp- Not :: Exp -> Exp- BinOp :: BinOp -> Exp -> Exp -> Exp- Fun :: Maybe Name -> [Var] -> Stm -> Exp- Call :: Arity -> Call -> Exp -> [Exp] -> Exp- Index :: Exp -> Exp -> Exp- Arr :: [Exp] -> Exp- AssignEx :: Exp -> Exp -> Exp- IfEx :: Exp -> Exp -> Exp -> Exp- Eval :: Exp -> Exp- Thunk :: Stm -> Exp+ Var :: !Var -> Exp+ Lit :: !Lit -> Exp+ Not :: !Exp -> Exp+ BinOp :: !BinOp -> Exp -> !Exp -> Exp+ Fun :: !(Maybe Name) -> ![Var] -> !Stm -> Exp+ Call :: !Arity -> !Call -> !Exp -> ![Exp] -> Exp+ Index :: !Exp -> !Exp -> Exp+ Arr :: ![Exp] -> Exp+ AssignEx :: !Exp -> !Exp -> Exp+ IfEx :: !Exp -> !Exp -> !Exp -> Exp+ Eval :: !Exp -> Exp+ Thunk :: !Stm -> Exp deriving (Eq, Show) -- | Statements. The only mildly interesting thing here are the Case and Jump -- constructors, which allow explicit sharing of continuations. data Stm where- Case :: Exp -> Stm -> [Alt] -> Shared Stm -> Stm- Forever :: Stm -> Stm- Assign :: LHS -> Exp -> Stm -> Stm- Return :: Exp -> Stm+ Case :: !Exp -> !Stm -> ![Alt] -> !(Shared Stm) -> Stm+ Forever :: !Stm -> Stm+ Assign :: !LHS -> !Exp -> !Stm -> Stm+ Return :: !Exp -> Stm Cont :: Stm- Jump :: Shared Stm -> Stm+ Jump :: !(Shared Stm) -> Stm NullRet :: Stm- Tailcall :: Exp -> Stm- ThunkRet :: Exp -> Stm -- Return from a Thunk+ Tailcall :: !Exp -> Stm+ ThunkRet :: !Exp -> Stm -- Return from a Thunk deriving (Eq, Show) -- | Case alternatives - an expression to match and a branch.@@ -120,6 +124,17 @@ modDefs :: !(M.Map Name (AST Exp)) } +-- | Merge two modules. The module and package IDs of the second argument are+-- used, and the second argument will take precedence for symbols which exist+-- in both.+merge :: Module -> Module -> Module+merge m1 m2 = Module {+ modPackageId = modPackageId m2,+ modName = modName m2,+ modDeps = M.union (modDeps m1) (modDeps m2),+ modDefs = M.union (modDefs m1) (modDefs m2)+ }+ -- | Imaginary module for foreign code that may need one. foreignModule :: Module foreignModule = Module {@@ -141,8 +156,8 @@ -- | An AST with local jumps. data AST a = AST {- astCode :: a,- astJumps :: JumpTable+ astCode :: !a,+ astJumps :: !JumpTable } deriving (Show, Eq) instance Functor AST where
src/Data/JSTarget/Traversal.hs view
@@ -7,7 +7,7 @@ import Data.Map as M ((!), insert) -- | AST nodes we'd like to fold and map over.-data ASTNode = Exp Exp | Stm Stm | Label Lbl+data ASTNode = Exp !Exp | Stm !Stm | Label !Lbl newtype TravM a = T (JumpTable -> (JumpTable, a)) instance Monad TravM where
src/Haste/Module.hs view
@@ -8,12 +8,12 @@ import Data.Binary -- | The file extension to use for modules.-jsmodExt :: String-jsmodExt = "jsmod"+jsmodExt :: Bool -> String+jsmodExt boot = if boot then "jsmod-boot" else "jsmod" -moduleFilePath :: FilePath -> String -> String -> FilePath-moduleFilePath basepath pkgid modname =- flip addExtension jsmodExt $+moduleFilePath :: FilePath -> String -> String -> Bool -> FilePath+moduleFilePath basepath pkgid modname boot =+ flip addExtension (jsmodExt boot) $ basepath </> pkgid </> (moduleNameSlashes $ mkModuleName modname) -- | Write a module to file, with the extension specified in `fileExt`.@@ -21,19 +21,28 @@ -- basepath/Foo/Bar.jsmod -- If any directory in the path where the module is to be written doesn't -- exist, it gets created.-writeModule :: FilePath -> Module -> IO ()-writeModule basepath m@(Module pkgid modname _ _) =+writeModule :: FilePath -> Module -> Bool -> IO ()+writeModule basepath m@(Module pkgid modname _ _) boot = fromRight "writeModule" . shell $ do mkdir True (takeDirectory path) liftIO $ B.writeFile path (encode m) where- path = moduleFilePath basepath pkgid modname+ path = moduleFilePath basepath pkgid modname boot -- | Read a module from file. If the module is not found at the specified path,--- libpath/path is tried instead. Panics if the module is found on neither--- path.+-- libpath/path is tried instead. Returns Nothing is the module is not found+-- on either path. readModule :: FilePath -> String -> String -> IO (Maybe Module) readModule basepath pkgid modname = fromRight "readModule" . shell $ do+ mm <- readMod basepath pkgid modname False+ mmboot <- readMod basepath pkgid modname True+ case (mm, mmboot) of+ (Just m, Nothing) -> return $ Just m+ (Just m, Just mboot) -> return . Just $ merge mboot m+ _ -> return Nothing++readMod :: FilePath -> String -> String -> Bool -> Shell (Maybe Module)+readMod basepath pkgid modname boot = do x <- isFile path let path' = if x then path else syspath isF <- isFile path'@@ -41,8 +50,8 @@ then Just . decode <$> liftIO (B.readFile path') else return Nothing where- path = moduleFilePath "." pkgid modname- syspath = moduleFilePath basepath pkgid modname+ path = moduleFilePath "." pkgid modname boot+ syspath = moduleFilePath basepath pkgid modname boot fromRight :: String -> IO (Either String b) -> IO b fromRight from m = do
src/Haste/Monad.hs view
@@ -12,19 +12,19 @@ deps :: !(S.Set Name), locals :: !(S.Set Name), continuation :: !(AST Stm -> AST Stm),- bindStack :: [Var],- modName :: String,- config :: cfg+ bindStack :: ![Var],+ modName :: !String,+ config :: !cfg } -initialState :: GenState cfg-initialState = GenState {+initialState :: cfg -> GenState cfg+initialState cfg = GenState { deps = S.empty, locals = S.empty, continuation = id, bindStack = [],- modName = undefined,- config = undefined+ modName = "",+ config = cfg } newtype JSGen cfg a =@@ -65,7 +65,7 @@ -> JSGen cfg a -- ^ The code generation computation. -> (a, S.Set J.Name, S.Set J.Name, AST Stm -> AST Stm) genJS cfg myModName (JSGen gen) =- case runState gen initialState {modName = myModName, config = cfg} of+ case runState gen (initialState cfg) {modName = myModName} of (a, GenState dependencies loc cont _ _ _) -> (a, dependencies, loc, cont)
src/Haste/Version.hs view
@@ -9,7 +9,7 @@ import Haste.Environment (hasteSysDir, ghcBinary) hasteVersion :: Version-hasteVersion = Version [0, 4, 2] []+hasteVersion = Version [0, 4, 2, 1] [] ghcVersion :: String ghcVersion = unsafePerformIO $ do
src/Main.hs view
@@ -233,22 +233,23 @@ -- | Compile a module into a .jsmod intermediate file. compile :: (GhcMonad m) => Config -> DynFlags -> ModSummary -> m () compile cfg dynflags modSummary = do- case ms_hsc_src modSummary of- HsBootFile -> liftIO $ logStr cfg $ "Skipping boot " ++ myName- _ -> do- (pgm, name) <- prepare dynflags modSummary+ let boot = case ms_hsc_src modSummary of+ HsBootFile -> True+ _ -> False+ (pgm, name) <- prepare dynflags modSummary #if __GLASGOW_HASKELL__ >= 706- let pkgid = showPpr dynflags $ modulePackageId $ ms_mod modSummary- cfg' = cfg {showOutputable = showPpr dynflags}+ let pkgid = showPpr dynflags $ modulePackageId $ ms_mod modSummary+ cfg' = cfg {showOutputable = showPpr dynflags} #else- let pkgid = showPpr $ modulePackageId $ ms_mod modSummary- cfg' = cfg {showOutputable = showPpr}+ let pkgid = showPpr $ modulePackageId $ ms_mod modSummary+ cfg' = cfg {showOutputable = showPpr} #endif- theCode = generate cfg' pkgid name pgm- liftIO $ logStr cfg $ "Compiling " ++ myName ++ " into " ++ targetpath- liftIO $ writeModule targetpath theCode+ theCode = generate cfg' pkgid name pgm+ liftIO $ logStr cfg $ "Compiling " ++ myName boot ++ " into " ++ targetpath+ liftIO $ writeModule targetpath theCode boot where- myName = moduleNameString $ moduleName $ ms_mod modSummary+ myName False = moduleNameString $ moduleName $ ms_mod modSummary+ myName True = myName False ++ " [boot]" targetpath = targetLibPath cfg -- | Fill in linkage info, such as whether to link at all and what the program