1-- | Pretty printer for the Objective-C 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.List ((\\))
18import qualified Control.Arrow as A
20import Data.Maybe (fromMaybe)
21import Data.Monoid ((<>))
22import Data.Text (Text)
23import qualified Data.Text as T
25import Language.PureScript.AST (SourceSpan(..))
26import Language.PureScript.CoreImp.AST
27import Language.PureScript.Comments
28import Language.PureScript.Crash
29import Language.PureScript.Names (Ident)
30import Language.PureScript.Pretty.Common
31import Language.PureScript.PSString (PSString, decodeString, mkString, prettyPrintString)
32import CodeGen.Cpp.Common
34import qualified Language.PureScript.Constants as C
36-- TODO (Christoph): Get rid of T.unpack / pack
38literals :: (Emit gen) => Pattern PrinterState AST gen
39literals = mkPattern' match'
41 match' :: (Emit gen) => AST -> StateT PrinterState Maybe gen
42 match' cpp = (addMapping' (getSourceSpan cpp) <>) <$> match cpp
44 match :: (Emit gen) => AST -> StateT PrinterState Maybe gen
45 match (NumericLiteral _ n) = return $ emit $ T.pack $ either show show n
46 match (StringLiteral _ s) = return $ emit $ prettyPrintString s
47 match (BooleanLiteral _ True) = return $ emit "true"
48 match (BooleanLiteral _ False) = return $ emit "false"
49 -- match (ArrayLiteral _ []) = return $ emit "std::initializer_list<boxed>{}"
50 match (ArrayLiteral _ xs) = mconcat <$> sequence
51 [ return $ emit "as_array { "
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 "as_dict {\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 $ prettyPrintString 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 ", " (("const boxed& " <>) <$> 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.dataSemiring || dictMod == C.dataRing || dictMod == C.dataEuclideanRing
106 , Just t <- unboxType dict
107 = mconcat <$> sequence
108 [ return $ emit $ unbox t x
109 , return $ emit $ renderOp fn
110 , return $ emit $ unbox t y
112 match (App _ val args) = mconcat <$> sequence
113 [ prettyPrintCpp' val
115 , intercalate (emit ", ") <$> forM args prettyPrintCpp'
118 match (Function _ (Just name) [] ret@(Block _ [Return _ (Function {})])) = mconcat <$> sequence
119 [ return $ emit "auto "
121 , return $ emit "() -> boxed "
122 , prettyPrintCpp' ret
124 match (Function _ (Just name) [] (Block _ [Return _ ret])) = mconcat <$> sequence
125 [ return $ emit "auto "
127 , return $ emit "() -> boxed "
128 , return $ emit "{\n"
130 indentString <- currentIndent
131 return $ indentString <> emit dispatchOnceBegin
134 , return $ emit ";\n"
136 indentString <- currentIndent
137 return $ indentString <> emit dispatchOnceEnd
138 , return $ emit "\n}"
140 -- match (Function _ (Just name) [] ret) = mconcat <$> sequence
141 match (Function _ (Just name) [] (Block ss sts)) | Return _ ret <- last sts = mconcat <$> sequence
142 [ return $ emit "auto "
144 , return $ emit "() -> boxed {\n"
146 prettyStatements $ init sts
149 indentString <- currentIndent
150 return $ indentString <> emit dispatchOnceBegin
153 , return $ emit ";\n"
155 indentString <- currentIndent
156 return $ indentString <> emit dispatchOnceEnd
157 , return $ emit "\n}"
159 match (Function _ name args ret) = mconcat <$> sequence
160 [ return $ emit $ if name == (Just tcoLoop) then "[&]" else "[=]"
162 , return $ emit $ intercalate ", " (("const boxed& " <>) <$> args)
163 , return $ emit ") -> boxed "
164 , prettyPrintCpp' ret
166 match (Indexer _ prop@(Var _ name) val) = mconcat <$> sequence
167 [ prettyPrintCpp' val
169 , prettyPrintCpp' prop
172 match (Indexer _ (ArrayLiteral _ [name]) val) = mconcat <$> sequence
173 [ prettyPrintCpp' val
175 , prettyPrintCpp' name
178 match (Indexer _ (NumericLiteral _ (Left index)) val) = mconcat <$> sequence
179 [ prettyPrintCpp' val
181 , return . emit . T.pack $ show index
184 match (Indexer _ prop val) = mconcat <$> sequence
185 [ prettyPrintCpp' val
187 , prettyPrintCpp' prop
190 match (InstanceOf _ val ty) = mconcat <$> sequence
191 [ return . emit $ unbox dictType val
192 , return $ emit ".count("
194 , return $ emit ") == 1"
196 match (While _ cond sts) = mconcat <$> sequence
197 [ return $ emit "while ("
198 , prettyPrintCpp' cond
200 , prettyPrintCpp' sts
202 match (For _ ident start end sts) = mconcat <$> sequence
203 [ return $ emit $ "for (boxed " <> ident <> " = "
204 , prettyPrintCpp' start
205 , return $ emit $ "; " <> ident <> " < "
206 , prettyPrintCpp' end
207 , return $ emit $ "; " <> ident <> "++) "
208 , prettyPrintCpp' sts
210 match (ForIn _ ident obj sts) = mconcat <$> sequence
211 [ return $ emit $ "for (boxed " <> ident <> " in "
212 , prettyPrintCpp' obj
214 , prettyPrintCpp' sts
216 match (IfElse _ (Binary _ EqualTo cond (BooleanLiteral Nothing True)) thens elses) = mconcat <$> sequence
217 [ return $ emit "if ("
218 , return $ emit $ unbox "bool" cond
220 , prettyPrintCpp' thens
221 , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintCpp') elses
223 match (IfElse _ (Binary _ EqualTo cond (BooleanLiteral Nothing False)) thens elses) = mconcat <$> sequence
224 [ return $ emit "if (!("
225 , return $ emit $ unbox "bool" cond
226 , return $ emit ")) "
227 , prettyPrintCpp' thens
228 , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintCpp') elses
230 match (IfElse _ (Binary _ EqualTo x@Var{} y@(NumericLiteral _ n)) thens elses) = mconcat <$> sequence
231 [ return $ emit "if ("
232 , return $ emit $ unbox t x
233 , return $ emit $ " == "
236 , prettyPrintCpp' thens
237 , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintCpp') elses
240 t | Left _ <- n = "int64_t"
241 | Right _ <- n = "double"
243 match (IfElse _ cond thens elses) = mconcat <$> sequence
244 [ return $ emit "if ("
245 , prettyPrintCpp' cond
247 , prettyPrintCpp' thens
248 , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintCpp') elses
250 match (Return _ value) = mconcat <$> sequence
251 [ return $ emit "return "
252 , prettyPrintCpp' value
254 match (ReturnNoResult _) = return $ emit "return nullptr"
255 -- match (Throw _ _) = return mempty
256 match (Throw _ value) = mconcat <$> sequence
257 [ return $ emit "throw "
258 , return $ emit "std::runtime_error(\"PatternMatchFailure: \""
259 , prettyPrintCpp' value
262 match (Comment _ com cpp) = mconcat <$> sequence
264 , mconcat <$> forM com comment
265 , prettyPrintCpp' cpp
269 comment :: (Emit gen) => Comment -> StateT PrinterState Maybe gen
270 comment (LineComment com) = fmap mconcat $ sequence $
272 , return $ emit "//" <> emit com <> emit "\n"
274 comment (BlockComment com) = fmap mconcat $ sequence $
276 , return $ emit "/**\n"
278 map asLine (T.lines com) ++
280 , return $ emit " */\n"
284 asLine :: (Emit gen) => Text -> StateT PrinterState Maybe gen
287 return $ i <> emit " * " <> (emit . removeComments) s <> emit "\n"
289 removeComments :: Text -> Text
291 case T.stripPrefix "*/" t of
292 Just rest -> removeComments rest
293 Nothing -> case T.uncons t of
294 Just (x, xs) -> x `T.cons` removeComments xs
297unary' :: (Emit gen) => UnaryOperator -> (AST -> Text) -> Operator PrinterState AST gen
298unary' op mkStr = Wrap match (const)
300 match :: (Emit gen) => Pattern PrinterState AST (gen, AST)
301 match = mkPattern match'
303 match' (Unary _ op' val) | op' == op = Just (emit $ mkStr val, val)
306unary :: (Emit gen) => UnaryOperator -> Text -> Operator PrinterState AST gen
307unary op str = unary' op (\v -> str <> "(" <> prettyPrintCpp1 v <> ")")
309negateOperator :: (Emit gen) => Operator PrinterState AST gen
310negateOperator = unary' Negate (\v -> if isNegate v then "- " else "-")
312 isNegate (Unary _ Negate _) = True
315binary :: (Emit gen) => BinaryOperator -> Text -> Operator PrinterState AST gen
316binary op str = AssocL match (\v1 v2 -> v1 <> emit (" " <> str <> " ") <> v2)
318 match :: Pattern PrinterState AST (AST, AST)
319 match = mkPattern match'
321 match' (Binary _ op' v1 v2) | op' == op = Just (v1, v2)
324prettyStatements :: (Emit gen) => [AST] -> StateT PrinterState Maybe gen
325prettyStatements sts = do
326 cpps <- forM sts prettyPrintCpp'
327 indentString <- currentIndent
328 return $ intercalate (emit "\n") $ map ((<> emit ";") . (indentString <>)) cpps
330-- | Generate a pretty-printed string representing a collection of Objective-C expressions at the same indentation level
331prettyPrintCppWithSourceMaps :: [AST] -> (Text, [SMap])
332prettyPrintCppWithSourceMaps cpp =
333 let StrPos (_, s, mp) = (fromMaybe (internalError "Incomplete pattern") . flip evalStateT (PrinterState 0) . prettyStatements) cpp
336prettyPrintCpp :: [AST] -> Text
337prettyPrintCpp = maybe (internalError "Incomplete pattern") runPlainString . flip evalStateT (PrinterState 0) . prettyStatements
339-- | Generate an indented, pretty-printed string representing a Objective-C expression
340prettyPrintCpp' :: (Emit gen) => AST -> StateT PrinterState Maybe gen
341prettyPrintCpp' = A.runKleisli $ runPattern matchValue
343 matchValue :: (Emit gen) => Pattern PrinterState AST gen
344 matchValue = buildPrettyPrinter operators (literals <+> fmap parensPos matchValue)
345 operators :: (Emit gen) => OperatorTable PrinterState AST gen
347 OperatorTable [ [ unary New "box" ]
349 , unary BitwiseNot "~"
352 , [ binary Multiply "*"
354 , binary Modulus "%" ]
356 , binary Subtract "-" ]
357 , [ binary ShiftLeft "<<"
358 , binary ShiftRight ">>"
359 , binary ZeroFillShiftRight ">>>" ]
360 , [ binary LessThan "<"
361 , binary LessThanOrEqualTo "<="
362 , binary GreaterThan ">"
363 , binary GreaterThanOrEqualTo ">=" ]
364 , [ binary EqualTo "=="
365 , binary NotEqualTo "!=" ]
366 , [ binary BitwiseAnd "&" ]
367 , [ binary BitwiseXor "^" ]
368 , [ binary BitwiseOr "|" ]
369 , [ binary And "&&" ]
373prettyPrintCpp1 :: AST -> Text
374prettyPrintCpp1 = maybe (internalError "Incomplete pattern") runPlainString . flip evalStateT (PrinterState 0) . prettyPrintCpp'
376unbox :: Text -> AST -> Text
377unbox _ v@(NumericLiteral{}) = prettyPrintCpp1 v
378unbox _ v@(BooleanLiteral{}) = prettyPrintCpp1 v
379unbox _ v@(StringLiteral{}) = prettyPrintCpp1 v
380unbox t v = "unbox<" <> t <> ">(" <> prettyPrintCpp1 v <> ")"
382unboxType :: Text -> Maybe Text
384 | t == C.semiringInt ||
387 | t == C.semiringNumber ||
389 t == C.euclideanRingNumber
391 | otherwise = Nothing
393renderOp :: Text -> Text
395 | op == C.add = " + "
396 | op == C.sub = " - "
397 | op == C.mul = " * "
398 | op == C.div = " / "
399 | otherwise = error $ "Unknown operator " <> T.unpack op
401interfaceSource :: Text -> [Ident] -> [Ident] -> Text
402interfaceSource mn exports foreigns =
403 "// Generated by purecc compiler\n\n" <>
404 "#ifndef " <> mn <> "_H\n" <>
405 "#define " <> mn <> "_H\n\n" <>
406 "#include \"purescript.h\"\n" <>
408 "namespace " <> mn <> " {\n\n" <>
409 "using namespace purescript;\n\n" <>
410 (T.concat $ (\export -> "auto " <> identToCpp export <> "() -> boxed;\n") <$> (exports \\ foreigns)) <>
412 (if null foreigns then "" else ("// Foreign values\n\nauto " <> foreignDict <> "() -> " <> dictType <> "&;\n\n")) <>
413 (T.concat $ (\foreign' -> "inline auto " <>
414 identToCpp foreign' <>
415 "() -> const boxed& { " <>
417 foreignDict <> "().at(\"" <> identToCpp foreign' <> "\"); " <>
419 " };\n") <$> foreigns) <>
421 "} // end namespace " <> mn <>
423 "#endif // " <> mn <> "_H\n\n"
425implHeaderSource :: Text -> [Text] -> Text -> Text
426implHeaderSource mn imports interfaceImport =
427 T.concat imports <> "\n"<>
428 interfaceImport <> "\n\n" <>
429 "namespace " <> mn <> " {\n\n"
431implFooterSource :: Text -> [Ident] -> Text
432implFooterSource mn foreigns =
434 (if null foreigns then "" else ("auto " <> foreignDict <> "() -> " <> dictType <> "& {\n" <>
435 " static dict_t _dict_;\n" <>
436 " return _dict_;\n" <>
438 "} // end namespace " <> mn <>
440 if mn == "Main" then mainSource else "\n"
444 \int main(int argc, const char * argv[]) {\n\
445 \ Main::main()(nullptr);\n\
454foreignDict = "_foreign_"
456dispatchOnceBegin :: Text
457dispatchOnceBegin = "static const boxed _value_ = "
459dispatchOnceEnd :: Text
460dispatchOnceEnd = "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