Skip to content

Commit 6ea964a

Browse files
committed
Make Printer a Monoid instead of Monad
1 parent 12a2219 commit 6ea964a

File tree

4 files changed

+146
-117
lines changed

4 files changed

+146
-117
lines changed

src/Fay.hs

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import Fay.Compiler
2727
import Fay.Compiler.Misc (ioWarn, printSrcSpanInfo)
2828
import Fay.Compiler.Packages
2929
import Fay.Compiler.Prelude
30+
import Fay.Compiler.Print
3031
import Fay.Compiler.Typecheck
3132
import Fay.Config
3233
import qualified Fay.Exts as F
@@ -128,30 +129,21 @@ compileToModule :: FilePath
128129
-> Config -> String -> (F.Module -> Compile [JsStmt]) -> String
129130
-> IO (Either CompileError (String,Maybe [Mapping],CompileState))
130131
compileToModule filepath config raw with hscode = do
131-
result <- compileViaStr filepath config printState with hscode
132+
result <- compileViaStr filepath config with hscode
132133
return $ case result of
133134
Left err -> Left err
134-
Right (ps,state,_) ->
135-
Right ( generateWrapped (concat . reverse $ psOutput ps)
136-
(stateModuleName state)
137-
, if null (psMappings ps) then Nothing else Just (psMappings ps)
135+
Right (printer,state@CompileState{ stateModuleName = (ModuleName _ modulename) },_) ->
136+
Right ((concat . reverse . pwOutput $ pw)
137+
, if null (pwMappings pw) then Nothing else Just (pwMappings pw)
138138
, state
139139
)
140-
where
141-
generateWrapped jscode (ModuleName _ modulename) =
142-
unlines $ filter (not . null)
143-
[if configExportRuntime config then raw else ""
144-
,jscode
145-
,if not (configLibrary config)
146-
then unlines [";"
147-
,"Fay$$_(" ++ modulename ++ ".main,true);"
148-
]
149-
else ""
150-
]
151-
printState = defaultPrintState
152-
{ psPretty = configPrettyPrint config
153-
, psLine = length (lines raw) + 3
154-
}
140+
where
141+
pw = execPrinter (runtime <> printer <> main) pr
142+
runtime = whenP (configExportRuntime config) $
143+
write raw
144+
main = whenP (not $ configLibrary config) $
145+
write $ "Fay$$_(" ++ modulename ++ ".main, true);\n"
146+
pr = defaultPrintReader { prPretty = configPrettyPrint config }
155147

156148
-- | Convert a Haskell filename to a JS filename.
157149
toJsName :: String -> String

src/Fay/Compiler.hs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ import Fay.Types
4444

4545
import Control.Monad.Error
4646
import Control.Monad.RWS
47-
import Control.Monad.State
47+
4848
import qualified Data.Set as S
4949
import Language.Haskell.Exts.Annotated hiding (name)
5050
import Language.Haskell.Names
@@ -57,16 +57,15 @@ compileViaStr
5757

5858
:: FilePath
5959
-> Config
60-
-> PrintState
6160
-> (F.Module -> Compile [JsStmt])
6261
-> String
63-
-> IO (Either CompileError (PrintState,CompileState,CompileWriter))
64-
compileViaStr filepath cfg printState with from = do
62+
-> IO (Either CompileError (Printer,CompileState,CompileWriter))
63+
compileViaStr filepath cfg with from = do
6564
rs <- defaultCompileReader cfg
6665
runTopCompile rs
6766
defaultCompileState
6867
(parseResult (throwError . uncurry ParseError)
69-
(fmap (\x -> execState (runPrinter (printJS x)) printState) . with)
68+
(fmap printJS . with)
7069
(parseFay filepath from))
7170

7271
-- | Compile the top-level Fay module.

src/Fay/Compiler/Print.hs

Lines changed: 68 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import Fay.Compiler.PrimOp
2222
import qualified Fay.Exts.NoAnnotation as N
2323
import Fay.Types
2424

25-
import Control.Monad.State
2625
import Data.Aeson.Encode
2726
import qualified Data.ByteString.Lazy.UTF8 as UTF8
2827
import Language.Haskell.Exts.Annotated hiding (alt, name, op, sym)
@@ -33,11 +32,11 @@ import SourceMap.Types
3332

3433
-- | Print the JS to a flat string.
3534
printJSString :: Printable a => a -> String
36-
printJSString x = concat . reverse . psOutput $ execState (runPrinter (printJS x)) defaultPrintState
35+
printJSString x = concat . reverse . pwOutput $ execPrinter (printJS x) defaultPrintReader
3736

3837
-- | Print the JS to a pretty string.
3938
printJSPretty :: Printable a => a -> String
40-
printJSPretty x = concat . reverse . psOutput $ execState (runPrinter (printJS x)) defaultPrintState { psPretty = True }
39+
printJSPretty x = concat . reverse . pwOutput $ execPrinter (printJS x) defaultPrintReader { prPretty = True }
4140

4241
-- | Print literals. These need some special encoding for
4342
-- JS-format literals. Could use the Text.JSON library.
@@ -88,7 +87,7 @@ instance Printable N.Name where
8887

8988
-- | Print a list of statements.
9089
instance Printable [JsStmt] where
91-
printJS = mapM_ printJS
90+
printJS = mconcat . map printJS
9291

9392
-- | Print a single statement.
9493
instance Printable JsStmt where
@@ -102,9 +101,9 @@ instance Printable JsStmt where
102101
name +> " = " +> expr +> ";" +> newline
103102
printJS (JsSetProp name prop expr) =
104103
name +> "." +> prop +> " = " +> expr +> ";" +> newline
105-
printJS (JsSetQName msrcloc name expr) = do
106-
maybe (return ()) mapping msrcloc
107-
name +> " = " +> expr +> ";" +> newline
104+
printJS (JsSetQName msrcloc name expr) =
105+
maybe mempty mapping msrcloc
106+
<> (name +> " = " +> expr +> ";" +> newline)
108107
printJS (JsSetConstructor name expr) =
109108
printCons name +> " = " +> expr +> ";" +> newline +>
110109
-- The unqualifiedness here is bad.
@@ -117,9 +116,11 @@ instance Printable JsStmt where
117116
"if (" +> exp +> ") {" +> newline +>
118117
indented (printJS thens) +>
119118
"}" +>
120-
(unless (null elses) $ " else {" +>
121-
indented (printJS elses) +>
122-
"}") +> newline
119+
(if (null elses)
120+
then mempty
121+
else " else {" +>
122+
indented (printJS elses) +>
123+
"}") +> newline
123124
printJS (JsEarlyReturn exp) =
124125
"return " +> exp +> ";" +> newline
125126
printJS (JsThrow exp) =
@@ -137,7 +138,7 @@ instance Printable ModulePath where
137138

138139
-- | Print an expression.
139140
instance Printable JsExp where
140-
printJS (JsSeq es) = "(" +> intercalateM "," (map printJS es) +> ")"
141+
printJS (JsSeq es) = "(" +> mintercalate "," (map printJS es) +> ")"
141142
printJS (JsRawExp e) = write e
142143
printJS (JsName name) = printJS name
143144
printJS (JsThrowExp exp) =
@@ -151,7 +152,7 @@ instance Printable JsExp where
151152
printJS (JsParen exp) =
152153
"(" +> exp +> ")"
153154
printJS (JsList exps) =
154-
"[" +> intercalateM "," (map printJS exps) +> printJS "]"
155+
"[" +> mintercalate "," (map printJS exps) +> "]"
155156
printJS (JsNew name args) =
156157
"new " +> JsApp (JsName name) args
157158
printJS (JsIndex i exp) =
@@ -176,28 +177,26 @@ instance Printable JsExp where
176177
printJS (JsInstanceOf exp classname) =
177178
exp +> " instanceof " +> classname
178179
printJS (JsObj assoc) =
179-
"{" +> intercalateM "," (map cons assoc) +> "}"
180+
"{" +> mintercalate "," (map cons assoc) +> "}"
180181
where cons (key,value) = "\"" +> key +> "\": " +> value
181182
printJS (JsLitObj assoc) =
182-
"{" +> intercalateM "," (map cons assoc) +> "}"
183-
where
184-
cons :: (N.Name, JsExp) -> Printer ()
185-
cons (key,value) = "\"" +> key +> "\": " +> value
183+
"{" +> mintercalate "," (map cons assoc) +> "}"
184+
where cons (key,value) = "\"" +> key +> "\": " +> value
186185
printJS (JsFun nm params stmts ret) =
187186
"function"
188-
+> maybe (return ()) ((" " +>) . printJS . ident) nm
187+
+> maybe mempty ((" " +>) . printJS . ident) nm
189188
+> "("
190-
+> intercalateM "," (map printJS params)
189+
+> mintercalate "," (map printJS params)
191190
+> "){" +> newline
192191
+> indented (stmts +>
193192
case ret of
194193
Just ret' -> "return " +> ret' +> ";" +> newline
195-
Nothing -> return ())
194+
Nothing -> mempty)
196195
+> "}"
197196
printJS (JsApp op args) =
198197
(if isFunc op then JsParen op else op)
199198
+> "("
200-
+> (intercalateM "," (map printJS args))
199+
+> mintercalate "," (map printJS args)
201200
+> ")"
202201
where isFunc JsFun{..} = True; isFunc _ = False
203202
printJS (JsNegApp args) =
@@ -230,27 +229,27 @@ instance Printable JsName where
230229
JsModuleName (ModuleName _ m) -> write m
231230

232231
-- | Print a constructor name given a QName.
233-
printCons :: N.QName -> Printer ()
232+
printCons :: N.QName -> Printer
234233
printCons (UnQual _ n) = printConsName n
235234
printCons (Qual _ (ModuleName _ m) n) = printJS m +> "." +> printConsName n
236235
printCons (Special {}) = error "qname2String Special"
237236

238237
-- | Print an unqualified name.
239-
printConsUnQual :: N.QName -> Printer ()
238+
printConsUnQual :: N.QName -> Printer
240239
printConsUnQual (UnQual _ x) = printJS x
241240
printConsUnQual (Qual _ _ n) = printJS n
242241
printConsUnQual (Special {}) = error "printConsUnqual Special"
243242

244243
-- | Print a constructor name given a Name. Helper for printCons.
245-
printConsName :: N.Name -> Printer ()
246-
printConsName n = write "_" >> printJS n
244+
printConsName :: N.Name -> Printer
245+
printConsName = (write "_" <>) . printJS
247246

248247
-- | Just write out strings.
249248
instance Printable String where
250249
printJS = write
251250

252251
-- | A printer is a printable.
253-
instance Printable (Printer ()) where
252+
instance Printable Printer where
254253
printJS = id
255254

256255
--------------------------------------------------------------------------------
@@ -299,63 +298,55 @@ normalizeName = concatMap encodeChar
299298

300299

301300
-- | Print the given printer indented.
302-
indented :: Printer a -> Printer ()
303-
indented p = do
304-
PrintState{..} <- get
305-
if psPretty
306-
then do modify $ \s -> s { psIndentLevel = psIndentLevel + 1 }
307-
void p
308-
modify $ \s -> s { psIndentLevel = psIndentLevel }
309-
else void p
301+
indented :: Printer -> Printer
302+
indented p = askP $ \PrintReader{..} ->
303+
if prPretty
304+
then addToIndentLevel 1 <> p <> addToIndentLevel (-1)
305+
else p
306+
where addToIndentLevel d = modifyP (\s@PrintState{..} -> s { psIndentLevel = psIndentLevel + d } )
310307

311308
-- | Output a newline.
312-
newline :: Printer ()
313-
newline = do
314-
PrintState{..} <- get
315-
when psPretty $ do
316-
write "\n"
317-
modify $ \s -> s { psNewline = True }
309+
newline :: Printer
310+
newline = askP $ \PrintReader{..} ->
311+
whenP prPretty $ write "\n" <> (modifyP $ \s -> s { psNewline = True })
312+
318313

319314
-- | Write out a string, updating the current position information.
320-
write :: String -> Printer ()
321-
write x = do
322-
PrintState{..} <- get
323-
let out = if psNewline then replicate (2*psIndentLevel) ' ' ++ x else x
324-
modify $ \s -> s { psOutput = out : psOutput
325-
, psLine = psLine + additionalLines
326-
, psColumn = if additionalLines > 0
327-
then length (concat (take 1 (reverse srclines)))
328-
else psColumn + length x
329-
, psNewline = False
330-
}
331-
return (error "Nothing to return for writer string.")
332-
333-
where srclines = lines x
315+
write :: String -> Printer
316+
write x = p <> q
317+
where p = getP $ \PrintState{..} ->
318+
let out = if psNewline
319+
then replicate (2*psIndentLevel) ' ' ++ x
320+
else x
321+
in tellP mempty { pwOutput = [out] }
322+
q = modifyP $ \s@PrintState{..} ->
323+
s { psLine = psLine + additionalLines
324+
, psColumn = if additionalLines > 0
325+
then length (concat (take 1 (reverse srclines)))
326+
else psColumn + length x
327+
, psNewline = False
328+
}
329+
srclines = lines x
334330
additionalLines = length (filter (=='\n') x)
335331

332+
336333
-- | Generate a mapping from the Haskell location to the current point in the output.
337-
mapping :: SrcSpan -> Printer ()
338-
mapping SrcSpan{..} = do
339-
modify $ \s -> s { psMappings = m s : psMappings s }
340-
return ()
341-
342-
where m ps = Mapping { mapGenerated = Pos (fromIntegral (psLine ps))
343-
(fromIntegral (psColumn ps))
344-
, mapOriginal = Just (Pos (fromIntegral srcSpanStartLine)
345-
(fromIntegral srcSpanStartColumn - 1))
346-
, mapSourceFile = Just srcSpanFilename
347-
, mapName = Nothing
348-
}
349-
350-
-- | Intercalate monadic action.
351-
intercalateM :: String -> [Printer a] -> Printer ()
352-
intercalateM _ [] = return ()
353-
intercalateM _ [x] = void x
354-
intercalateM str (x:xs) = do
355-
void x
356-
write str
357-
intercalateM str xs
334+
mapping :: SrcSpan -> Printer
335+
mapping SrcSpan{..} =
336+
getP $ \PrintState{..} ->
337+
let m = Mapping { mapGenerated = Pos (fromIntegral (psLine))
338+
(fromIntegral (psColumn))
339+
, mapOriginal = Just (Pos (fromIntegral srcSpanStartLine)
340+
(fromIntegral srcSpanStartColumn - 1))
341+
, mapSourceFile = Just srcSpanFilename
342+
, mapName = Nothing
343+
}
344+
in tellP $ mempty { pwMappings = [m] }
345+
346+
-- | Intercalate monoids.
347+
mintercalate :: String -> [Printer] -> Printer
348+
mintercalate str xs = mconcat $ intersperse (write str) xs
358349

359350
-- | Concatenate two printables.
360-
(+>) :: (Printable a, Printable b) => a -> b -> Printer ()
361-
pa +> pb = printJS pa >> printJS pb
351+
(+>) :: (Printable a, Printable b) => a -> b -> Printer
352+
pa +> pb = printJS pa <> printJS pb

0 commit comments

Comments
 (0)