1-- | Pretty printer for the AST
2module CodeGen.Cpp.Printer
5 , prettyPrintCppWithSourceMaps
13import Control.Arrow ((<+>))
14import Control.Monad (forM, mzero)
15import Control.Monad.State (StateT, evalStateT)
16import Control.PatternArrows
17import Data.Char (isAscii)
18import Data.List ((\\))
19import qualified Control.Arrow as A
21import Data.Maybe (fromMaybe)
22import Data.Monoid ((<>))
23import Data.Text (Text)
24import qualified Data.Text as T
26import Language.PureScript.AST (SourceSpan(..))
27import Language.PureScript.CoreImp.AST
28import Language.PureScript.Comments
29import Language.PureScript.Crash
30import Language.PureScript.Names (Ident, runIdent)
31import Language.PureScript.Pretty.Common
32import Language.PureScript.PSString (PSString, decodeString, mkString)
33import CodeGen.Cpp.Common
35import qualified Language.PureScript.Constants as C
37-- TODO (Christoph): Get rid of T.unpack / pack
39literals :: (Emit gen) => Pattern PrinterState AST gen
40literals = mkPattern' match'
42 match' :: (Emit gen) => AST -> StateT PrinterState Maybe gen
43 match' cpp = (addMapping' (getSourceSpan cpp) <>) <$> match cpp
45 match :: (Emit gen) => AST -> StateT PrinterState Maybe gen
46 match (NumericLiteral _ n) = return $ emit $ T.pack $ either show show n
47 match (StringLiteral _ s) = return $ emit $ stringLiteral s
48 match (BooleanLiteral _ True) = return $ emit "true"
49 match (BooleanLiteral _ False) = return $ emit "false"
50 match (ArrayLiteral _ xs) = mconcat <$> sequence
51 [ return . emit $ arrayType <> "{"
52 , intercalate (emit ", ") <$> forM xs prettyPrintCpp'
55 -- match (ObjectLiteral _ []) = return $ emit "std::initializer_list<std::pair<const string, boxed>>{}"
56 match (ObjectLiteral _ ps) = mconcat <$> sequence
57 [ return . emit $ dictType <> "{\n"
59 cpps <- forM ps $ \(key, value) -> do
60 value' <- prettyPrintCpp' value
61 return $ emit "{ " <> objectPropertyToString key <> value' <> emit " }"
62 indentString <- currentIndent
63 return $ intercalate (emit ",\n") $ map (indentString <>) cpps
69 objectPropertyToString :: (Emit gen) => PSString -> gen
70 objectPropertyToString s = emit $ stringLiteral s <> ", "
71 match (Block _ sts) = mconcat <$> sequence
73 , withIndent $ prettyStatements sts
78 match (Var _ ident) = return $ emit ident
79 match (VariableIntroduction _ ident value) = mconcat <$> sequence
80 [ return $ emit $ "boxed " <> ident
81 , maybe (return mempty) (fmap (emit " = " <>) . prettyPrintCpp') value
83 match (Assignment _ target@(Var _ var) value@(Function _ Nothing args body)) = mconcat <$> sequence
84 [ prettyPrintCpp' target
86 , return $ emit "[=, &"
87 , prettyPrintCpp' target
90 , return $ emit $ intercalate ", " (renderArg <$> args)
91 , return $ emit ") -> boxed "
92 , prettyPrintCpp' body
94 match (Assignment _ target value) = mconcat <$> sequence
95 [ prettyPrintCpp' target
97 , prettyPrintCpp' value
99 match (App _ val []) = mconcat <$> sequence
100 [ prettyPrintCpp' val
103 match (App ss (App _ (App _ (Indexer _ (Var _ fn) (Var _ fnMod)) [Indexer _ (Var _ dict) (Var _ dictMod)]) [x]) [y])
105 , dictMod == C.dataEq || dictMod == C.dataSemiring || dictMod == C.dataRing || dictMod == C.dataEuclideanRing
106 , Just op <- renderOp fn
107 , Just t <- unboxType dict
108 = mconcat <$> sequence
109 [ return $ emit $ unbox' t x
111 , return $ emit $ unbox' t y
113 match (App _ (App _ (Indexer _ (Var _ fn) (Var _ fnMod)) [Indexer _ (Var _ dict) (Var _ dictMod)]) [n])
115 , dictMod == C.dataRing
117 , Just t <- unboxType dict
118 = mconcat <$> sequence
120 , return $ emit $ unbox' t n
122 match (App _ val args) = mconcat <$> sequence
123 [ prettyPrintCpp' val
125 , intercalate (emit ", ") <$> forM args prettyPrintCpp'
128 match (Function _ (Just name) [] ret@(Block _ [Return _ (Function {})])) = mconcat <$> sequence
129 [ return $ emit "auto "
131 , return $ emit "() -> boxed "
132 , prettyPrintCpp' ret
134 match (Function _ (Just name) [] (Block _ [Return _ ret])) = mconcat <$> sequence
135 [ return $ emit "auto "
137 , return $ emit "() -> boxed "
138 , return $ emit "{\n"
140 indentString <- currentIndent
141 return $ indentString <> emit dispatchOnceBegin
144 , return $ emit ";\n"
146 indentString <- currentIndent
147 return $ indentString <> emit dispatchOnceEnd
148 , return $ emit "\n}"
150 -- match (Function _ (Just name) [] ret) = mconcat <$> sequence
151 match (Function _ (Just name) [] (Block ss sts)) | Return _ ret <- last sts = mconcat <$> sequence
152 [ return $ emit "auto "
154 , return $ emit "() -> boxed {\n"
156 prettyStatements $ init sts
159 indentString <- currentIndent
160 return $ indentString <> emit dispatchOnceBegin
163 , return $ emit ";\n"
165 indentString <- currentIndent
166 return $ indentString <> emit dispatchOnceEnd
167 , return $ emit "\n}"
169 match (Function _ name args ret) = mconcat <$> sequence
170 [ return $ emit $ if name == (Just tcoLoop) then "[&]" else "[=]"
172 , return $ emit $ intercalate ", " (renderArg <$> args)
173 , return $ emit ") -> boxed "
174 , prettyPrintCpp' ret
176 match (Indexer _ prop@(Var _ name) val) = mconcat <$> sequence
177 [ prettyPrintCpp' val
179 , prettyPrintCpp' prop
182 match (Indexer _ prop val) = mconcat <$> sequence
183 [ prettyPrintCpp' val
185 , prettyPrintCpp' prop
188 match (InstanceOf _ val ty) = mconcat <$> sequence
189 [ return . emit $ unbox' dictType val
190 , return $ emit ".contains("
194 match (While _ cond sts) = mconcat <$> sequence
195 [ return $ emit "while ("
196 , prettyPrintCpp' cond
198 , prettyPrintCpp' sts
200 match (For _ ident start end sts) = mconcat <$> sequence
201 [ return $ emit $ "for (boxed " <> ident <> " = "
202 , prettyPrintCpp' start
203 , return $ emit $ "; " <> ident <> " < "
204 , prettyPrintCpp' end
205 , return $ emit $ "; " <> ident <> "++) "
206 , prettyPrintCpp' sts
208 match (ForIn _ ident obj sts) = mconcat <$> sequence
209 [ return $ emit $ "for (boxed " <> ident <> " in "
210 , prettyPrintCpp' obj
212 , prettyPrintCpp' sts
214 match (IfElse _ (Binary _ EqualTo cond (BooleanLiteral Nothing True)) thens elses) = mconcat <$> sequence
215 [ return $ emit "if ("
216 , return $ emit $ unbox' "bool" cond
218 , prettyPrintCpp' thens
219 , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintCpp') elses
221 match (IfElse _ (Binary _ EqualTo cond (BooleanLiteral Nothing False)) thens elses) = mconcat <$> sequence
222 [ return $ emit "if (!("
223 , return $ emit $ unbox' "bool" cond
224 , return $ emit ")) "
225 , prettyPrintCpp' thens
226 , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintCpp') elses
228 match (IfElse _ (Binary _ EqualTo x y@(NumericLiteral _ n)) thens elses) = mconcat <$> sequence
229 [ return $ emit "if ("
230 , return $ emit $ unbox' t x
231 , return $ emit $ " == "
234 , prettyPrintCpp' thens
235 , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintCpp') elses
238 t | Left _ <- n = int
239 | Right _ <- n = float
240 match (IfElse _ (Binary _ EqualTo a b@StringLiteral{}) thens elses) = mconcat <$> sequence
241 [ return $ emit "if ("
242 , return $ emit $ unbox' string a
243 , return $ emit $ " == "
246 , prettyPrintCpp' thens
247 , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintCpp') elses
249 match (IfElse _ cond thens elses) = mconcat <$> sequence
250 [ return $ emit "if ("
251 , prettyPrintCpp' cond
253 , prettyPrintCpp' thens
254 , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintCpp') elses
256 match (Return _ value) = mconcat <$> sequence
257 [ return $ emit "return "
258 , prettyPrintCpp' value
260 match (ReturnNoResult _) = return $ emit "return nullptr"
261 -- match (Throw _ _) = return mempty
262 match (Throw _ value) = mconcat <$> sequence
263 [ return $ emit "throw "
264 , return $ emit "std::runtime_error(\"PatternMatchFailure: \""
265 , prettyPrintCpp' value
268 match (Comment _ com cpp) = mconcat <$> sequence
270 , mconcat <$> forM com comment
271 , prettyPrintCpp' cpp
275 comment :: (Emit gen) => Comment -> StateT PrinterState Maybe gen
276 comment (LineComment com) = fmap mconcat $ sequence $
278 , return $ emit "//" <> emit com <> emit "\n"
280 comment (BlockComment com) = fmap mconcat $ sequence $
282 , return $ emit "/**\n"
284 map asLine (T.lines com) ++
286 , return $ emit " */\n"
290 asLine :: (Emit gen) => Text -> StateT PrinterState Maybe gen
293 return $ i <> emit " * " <> (emit . removeComments) s <> emit "\n"
295 removeComments :: Text -> Text
297 case T.stripPrefix "*/" t of
298 Just rest -> removeComments rest
299 Nothing -> case T.uncons t of
300 Just (x, xs) -> x `T.cons` removeComments xs
303unary' :: (Emit gen) => UnaryOperator -> (AST -> Text) -> Operator PrinterState AST gen
304unary' op mkStr = Wrap match (const)
306 match :: (Emit gen) => Pattern PrinterState AST (gen, AST)
307 match = mkPattern match'
309 match' (Unary _ op' val) | op' == op = Just (emit $ mkStr val, val)
312unary :: (Emit gen) => UnaryOperator -> Text -> Operator PrinterState AST gen
313unary op str = unary' op (\v -> str <> "(" <> prettyPrintCpp1 v <> ")")
315negateOperator :: (Emit gen) => Operator PrinterState AST gen
316negateOperator = unary' Negate (\v -> if isNegate v then "- " else "-")
318 isNegate (Unary _ Negate _) = True
321binary :: (Emit gen) => BinaryOperator -> Text -> Operator PrinterState AST gen
322binary op str = AssocL match (\v1 v2 -> v1 <> emit (" " <> str <> " ") <> v2)
324 match :: Pattern PrinterState AST (AST, AST)
325 match = mkPattern match'
327 match' (Binary _ op' v1 v2) | op' == op = Just (v1, v2)
330prettyStatements :: (Emit gen) => [AST] -> StateT PrinterState Maybe gen
331prettyStatements sts = do
332 cpps <- forM sts prettyPrintCpp'
333 indentString <- currentIndent
334 return $ intercalate (emit "\n") $ map ((<> emit ";") . (indentString <>)) cpps
336-- | Generate a pretty-printed string representing a collection of Objective-C expressions at the same indentation level
337prettyPrintCppWithSourceMaps :: [AST] -> (Text, [SMap])
338prettyPrintCppWithSourceMaps cpp =
339 let StrPos (_, s, mp) = (fromMaybe (internalError "Incomplete pattern") . flip evalStateT (PrinterState 0) . prettyStatements) cpp
342prettyPrintCpp :: [AST] -> Text
343prettyPrintCpp = maybe (internalError "Incomplete pattern") runPlainString . flip evalStateT (PrinterState 0) . prettyStatements
345-- | Generate an indented, pretty-printed string representing a Objective-C expression
346prettyPrintCpp' :: (Emit gen) => AST -> StateT PrinterState Maybe gen
347prettyPrintCpp' = A.runKleisli $ runPattern matchValue
349 matchValue :: (Emit gen) => Pattern PrinterState AST gen
350 matchValue = buildPrettyPrinter operators (literals <+> fmap parensPos matchValue)
351 operators :: (Emit gen) => OperatorTable PrinterState AST gen
353 OperatorTable [ [ unary New "box" ]
355 , unary BitwiseNot "~"
358 , [ binary Multiply "*"
360 , binary Modulus "%" ]
362 , binary Subtract "-" ]
363 , [ binary ShiftLeft "<<"
364 , binary ShiftRight ">>"
365 , binary ZeroFillShiftRight ">>>" ]
366 , [ binary LessThan "<"
367 , binary LessThanOrEqualTo "<="
368 , binary GreaterThan ">"
369 , binary GreaterThanOrEqualTo ">=" ]
370 , [ binary EqualTo "=="
371 , binary NotEqualTo "!=" ]
372 , [ binary BitwiseAnd "&" ]
373 , [ binary BitwiseXor "^" ]
374 , [ binary BitwiseOr "|" ]
375 , [ binary And "&&" ]
379prettyPrintCpp1 :: AST -> Text
380prettyPrintCpp1 = maybe (internalError "Incomplete pattern") runPlainString . flip evalStateT (PrinterState 0) . prettyPrintCpp'
382stringLiteral :: PSString -> Text
383stringLiteral pss | Just s <- decodeString pss =
386 else ("u8")) <> stringLiteral' s
388 stringLiteral' :: Text -> Text
389 stringLiteral' s = "\"" <> T.concatMap encodeChar s <> "\""
390 encodeChar :: Char -> Text
391 encodeChar '\0' = "\\0"
392 encodeChar '\b' = "\\b"
393 encodeChar '\t' = "\\t"
394 encodeChar '\n' = "\\n"
395 encodeChar '\v' = "\\v"
396 encodeChar '\f' = "\\f"
397 encodeChar '\r' = "\\r"
398 encodeChar '"' = "\\\""
399 encodeChar '\\' = "\\\\"
400 encodeChar c = T.singleton $ c
401stringLiteral _ = "\"\\uFFFD\""
403unbox' :: Text -> AST -> Text
404unbox' _ v@(NumericLiteral{}) = prettyPrintCpp1 v
405unbox' _ v@(BooleanLiteral{}) = prettyPrintCpp1 v
406unbox' _ v@(StringLiteral{}) = prettyPrintCpp1 v
407unbox' t v = unbox t <> "(" <> prettyPrintCpp1 v <> ")"
409unboxType :: Text -> Maybe Text
412 t == C.semiringInt ||
415 | t == C.semiringNumber ||
417 t == C.euclideanRingNumber
419 | otherwise = Nothing
421renderOp :: Text -> Maybe Text
423 | op == C.eq = Just " == "
424 | op == C.notEq = Just " != "
425 | op == C.add = Just " + "
426 | op == C.sub = Just " - "
427 | op == C.mul = Just " * "
428 | op == C.div = Just " / "
429 | otherwise = Nothing
431interfaceSource :: Text -> [Ident] -> [Ident] -> Text
432interfaceSource mn exports foreigns =
433 "// Generated by pscpp compiler\n\n" <>
434 "#ifndef " <> mn <> "_H\n" <>
435 "#define " <> mn <> "_H\n\n" <>
436 "#include \"purescript.h\"\n" <>
438 "namespace " <> mn <> " {\n\n" <>
439 "using namespace purescript;\n\n" <>
440 (T.concat $ (\export -> "auto " <> identToCpp export <> "() -> boxed;\n") <$> (exports \\ foreigns)) <>
442 (if null foreigns then "" else ("// Foreign values\n\nauto " <> foreignDict <> "() -> " <> dictType <> "&;\n\n")) <>
443 (T.concat $ (\foreign' -> "inline auto " <>
444 identToCpp foreign' <>
445 "() -> " <> varDecl <> " { " <>
447 foreignDict <> "()[" <>
448 (stringLiteral . mkString $ runIdent foreign') <> "]; " <>
450 " };\n") <$> foreigns) <>
452 "} // end namespace " <> mn <>
454 "#endif // " <> mn <> "_H\n\n"
456implHeaderSource :: Text -> [Text] -> Text -> Text
457implHeaderSource mn imports interfaceImport =
458 T.concat imports <> "\n"<>
459 interfaceImport <> "\n\n" <>
460 "namespace " <> mn <> " {\n\n"
462implFooterSource :: Text -> [Ident] -> Text
463implFooterSource mn foreigns =
465 (if null foreigns then "" else ("auto " <> foreignDict <> "() -> " <> dictType <> "& {\n" <>
466 " static " <> dictType <> " $dict$;\n" <>
467 " return $dict$;\n" <>
469 "} // end namespace " <> mn <>
471 if mn == "Main" then mainSource else "\n"
475 \int main(int argc, const char * argv[]) {\n\
482varDecl = "const boxed&"
484renderArg :: Text -> Text
486 | arg == unusedName = varDecl
487 | otherwise = varDecl <> " " <> arg
490foreignDict = "foreign"
492dispatchOnceBegin :: Text
493dispatchOnceBegin = "static const boxed $value$ = "
495dispatchOnceEnd :: Text
496dispatchOnceEnd = "return $value$;"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list