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.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)
31import Language.PureScript.Pretty.Common
32import Language.PureScript.PSString (PSString, decodeString, mkString, prettyPrintString)
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)
48 | Just s' <- decodeString s = return $ emit $
51 else "u8" <> stringLiteral s'
52 match (StringLiteral _ s)
53 | Just s' <- decodeString s = return $ emit $ "u8" <> stringLiteral s'
54 match (StringLiteral _ s) = error $ "Bad character in string literal " ++ show s
55 match (BooleanLiteral _ True) = return $ emit "true"
56 match (BooleanLiteral _ False) = return $ emit "false"
57 -- match (ArrayLiteral _ []) = return $ emit "std::initializer_list<boxed>{}"
58 match (ArrayLiteral _ xs) = mconcat <$> sequence
59 [ return $ emit "as_array { "
60 , intercalate (emit ", ") <$> forM xs prettyPrintCpp'
63 -- match (ObjectLiteral _ []) = return $ emit "std::initializer_list<std::pair<const string, boxed>>{}"
64 match (ObjectLiteral _ ps) = mconcat <$> sequence
65 [ return $ emit "as_dict {\n"
67 cpps <- forM ps $ \(key, value) -> do
68 value' <- prettyPrintCpp' value
69 return $ emit "{ " <> objectPropertyToString key <> value' <> emit " }"
70 indentString <- currentIndent
71 return $ intercalate (emit ",\n") $ map (indentString <>) cpps
77 objectPropertyToString :: (Emit gen) => PSString -> gen
78 objectPropertyToString s = emit $ prettyPrintString s <> ", "
79 match (Block _ sts) = mconcat <$> sequence
81 , withIndent $ prettyStatements sts
86 match (Var _ ident) = return $ emit ident
87 match (VariableIntroduction _ ident value) = mconcat <$> sequence
88 [ return $ emit $ "boxed " <> ident
89 , maybe (return mempty) (fmap (emit " = " <>) . prettyPrintCpp') value
91 match (Assignment _ target@(Var _ var) value@(Function _ Nothing args body)) = mconcat <$> sequence
92 [ prettyPrintCpp' target
94 , return $ emit "[=, &"
95 , prettyPrintCpp' target
98 , return $ emit $ intercalate ", " (("const boxed& " <>) <$> args)
99 , return $ emit ") -> boxed "
100 , prettyPrintCpp' body
102 match (Assignment _ target value) = mconcat <$> sequence
103 [ prettyPrintCpp' target
104 , return $ emit " = "
105 , prettyPrintCpp' value
107 match (App _ val []) = mconcat <$> sequence
108 [ prettyPrintCpp' val
111 match (App ss (App _ (App _ (Indexer _ (Var _ fn) (Var _ fnMod)) [Indexer _ (Var _ dict) (Var _ dictMod)]) [x]) [y])
113 , dictMod == C.dataSemiring || dictMod == C.dataRing || dictMod == C.dataEuclideanRing
114 , Just t <- unboxType dict
115 = mconcat <$> sequence
116 [ return $ emit $ unbox t x
117 , return $ emit $ renderOp fn
118 , return $ emit $ unbox t y
120 match (App _ val args) = mconcat <$> sequence
121 [ prettyPrintCpp' val
123 , intercalate (emit ", ") <$> forM args prettyPrintCpp'
126 match (Function _ (Just name) [] ret@(Block _ [Return _ (Function {})])) = mconcat <$> sequence
127 [ return $ emit "auto "
129 , return $ emit "() -> boxed "
130 , prettyPrintCpp' ret
132 match (Function _ (Just name) [] (Block _ [Return _ ret])) = mconcat <$> sequence
133 [ return $ emit "auto "
135 , return $ emit "() -> boxed "
136 , return $ emit "{\n"
138 indentString <- currentIndent
139 return $ indentString <> emit dispatchOnceBegin
142 , return $ emit ";\n"
144 indentString <- currentIndent
145 return $ indentString <> emit dispatchOnceEnd
146 , return $ emit "\n}"
148 -- match (Function _ (Just name) [] ret) = mconcat <$> sequence
149 match (Function _ (Just name) [] (Block ss sts)) | Return _ ret <- last sts = mconcat <$> sequence
150 [ return $ emit "auto "
152 , return $ emit "() -> boxed {\n"
154 prettyStatements $ init sts
157 indentString <- currentIndent
158 return $ indentString <> emit dispatchOnceBegin
161 , return $ emit ";\n"
163 indentString <- currentIndent
164 return $ indentString <> emit dispatchOnceEnd
165 , return $ emit "\n}"
167 match (Function _ name args ret) = mconcat <$> sequence
168 [ return $ emit $ if name == (Just tcoLoop) then "[&]" else "[=]"
170 , return $ emit $ intercalate ", " (("const boxed& " <>) <$> args)
171 , return $ emit ") -> boxed "
172 , prettyPrintCpp' ret
174 match (Indexer _ prop@(Var _ name) val) = mconcat <$> sequence
175 [ prettyPrintCpp' val
177 , prettyPrintCpp' prop
180 match (Indexer _ (ArrayLiteral _ [name]) val) = mconcat <$> sequence
181 [ prettyPrintCpp' val
183 , prettyPrintCpp' name
186 match (Indexer _ (NumericLiteral _ (Left index)) val) = mconcat <$> sequence
187 [ prettyPrintCpp' val
189 , return . emit . T.pack $ show index
192 match (Indexer _ prop val) = mconcat <$> sequence
193 [ prettyPrintCpp' val
195 , prettyPrintCpp' prop
198 match (InstanceOf _ val ty) = mconcat <$> sequence
199 [ return . emit $ unbox dictType val
200 , return $ emit ".count("
202 , return $ emit ") == 1"
204 match (While _ cond sts) = mconcat <$> sequence
205 [ return $ emit "while ("
206 , prettyPrintCpp' cond
208 , prettyPrintCpp' sts
210 match (For _ ident start end sts) = mconcat <$> sequence
211 [ return $ emit $ "for (boxed " <> ident <> " = "
212 , prettyPrintCpp' start
213 , return $ emit $ "; " <> ident <> " < "
214 , prettyPrintCpp' end
215 , return $ emit $ "; " <> ident <> "++) "
216 , prettyPrintCpp' sts
218 match (ForIn _ ident obj sts) = mconcat <$> sequence
219 [ return $ emit $ "for (boxed " <> ident <> " in "
220 , prettyPrintCpp' obj
222 , prettyPrintCpp' sts
224 match (IfElse _ (Binary _ EqualTo cond (BooleanLiteral Nothing True)) thens elses) = mconcat <$> sequence
225 [ return $ emit "if ("
226 , return $ emit $ unbox "bool" cond
228 , prettyPrintCpp' thens
229 , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintCpp') elses
231 match (IfElse _ (Binary _ EqualTo cond (BooleanLiteral Nothing False)) thens elses) = mconcat <$> sequence
232 [ return $ emit "if (!("
233 , return $ emit $ unbox "bool" cond
234 , return $ emit ")) "
235 , prettyPrintCpp' thens
236 , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintCpp') elses
238 match (IfElse _ (Binary _ EqualTo x@Var{} y@(NumericLiteral _ n)) thens elses) = mconcat <$> sequence
239 [ return $ emit "if ("
240 , return $ emit $ unbox t x
241 , return $ emit $ " == "
244 , prettyPrintCpp' thens
245 , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintCpp') elses
248 t | Left _ <- n = "int"
249 | Right _ <- n = "double"
251 match (IfElse _ cond thens elses) = mconcat <$> sequence
252 [ return $ emit "if ("
253 , prettyPrintCpp' cond
255 , prettyPrintCpp' thens
256 , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintCpp') elses
258 match (Return _ value) = mconcat <$> sequence
259 [ return $ emit "return "
260 , prettyPrintCpp' value
262 match (ReturnNoResult _) = return $ emit "return nullptr"
263 -- match (Throw _ _) = return mempty
264 match (Throw _ value) = mconcat <$> sequence
265 [ return $ emit "throw "
266 , return $ emit "std::runtime_error(\"PatternMatchFailure: \""
267 , prettyPrintCpp' value
270 match (Comment _ com cpp) = mconcat <$> sequence
272 , mconcat <$> forM com comment
273 , prettyPrintCpp' cpp
277 comment :: (Emit gen) => Comment -> StateT PrinterState Maybe gen
278 comment (LineComment com) = fmap mconcat $ sequence $
280 , return $ emit "//" <> emit com <> emit "\n"
282 comment (BlockComment com) = fmap mconcat $ sequence $
284 , return $ emit "/**\n"
286 map asLine (T.lines com) ++
288 , return $ emit " */\n"
292 asLine :: (Emit gen) => Text -> StateT PrinterState Maybe gen
295 return $ i <> emit " * " <> (emit . removeComments) s <> emit "\n"
297 removeComments :: Text -> Text
299 case T.stripPrefix "*/" t of
300 Just rest -> removeComments rest
301 Nothing -> case T.uncons t of
302 Just (x, xs) -> x `T.cons` removeComments xs
305unary' :: (Emit gen) => UnaryOperator -> (AST -> Text) -> Operator PrinterState AST gen
306unary' op mkStr = Wrap match (const)
308 match :: (Emit gen) => Pattern PrinterState AST (gen, AST)
309 match = mkPattern match'
311 match' (Unary _ op' val) | op' == op = Just (emit $ mkStr val, val)
314unary :: (Emit gen) => UnaryOperator -> Text -> Operator PrinterState AST gen
315unary op str = unary' op (\v -> str <> "(" <> prettyPrintCpp1 v <> ")")
317negateOperator :: (Emit gen) => Operator PrinterState AST gen
318negateOperator = unary' Negate (\v -> if isNegate v then "- " else "-")
320 isNegate (Unary _ Negate _) = True
323binary :: (Emit gen) => BinaryOperator -> Text -> Operator PrinterState AST gen
324binary op str = AssocL match (\v1 v2 -> v1 <> emit (" " <> str <> " ") <> v2)
326 match :: Pattern PrinterState AST (AST, AST)
327 match = mkPattern match'
329 match' (Binary _ op' v1 v2) | op' == op = Just (v1, v2)
332prettyStatements :: (Emit gen) => [AST] -> StateT PrinterState Maybe gen
333prettyStatements sts = do
334 cpps <- forM sts prettyPrintCpp'
335 indentString <- currentIndent
336 return $ intercalate (emit "\n") $ map ((<> emit ";") . (indentString <>)) cpps
338-- | Generate a pretty-printed string representing a collection of Objective-C expressions at the same indentation level
339prettyPrintCppWithSourceMaps :: [AST] -> (Text, [SMap])
340prettyPrintCppWithSourceMaps cpp =
341 let StrPos (_, s, mp) = (fromMaybe (internalError "Incomplete pattern") . flip evalStateT (PrinterState 0) . prettyStatements) cpp
344prettyPrintCpp :: [AST] -> Text
345prettyPrintCpp = maybe (internalError "Incomplete pattern") runPlainString . flip evalStateT (PrinterState 0) . prettyStatements
347-- | Generate an indented, pretty-printed string representing a Objective-C expression
348prettyPrintCpp' :: (Emit gen) => AST -> StateT PrinterState Maybe gen
349prettyPrintCpp' = A.runKleisli $ runPattern matchValue
351 matchValue :: (Emit gen) => Pattern PrinterState AST gen
352 matchValue = buildPrettyPrinter operators (literals <+> fmap parensPos matchValue)
353 operators :: (Emit gen) => OperatorTable PrinterState AST gen
355 OperatorTable [ [ unary New "box" ]
357 , unary BitwiseNot "~"
360 , [ binary Multiply "*"
362 , binary Modulus "%" ]
364 , binary Subtract "-" ]
365 , [ binary ShiftLeft "<<"
366 , binary ShiftRight ">>"
367 , binary ZeroFillShiftRight ">>>" ]
368 , [ binary LessThan "<"
369 , binary LessThanOrEqualTo "<="
370 , binary GreaterThan ">"
371 , binary GreaterThanOrEqualTo ">=" ]
372 , [ binary EqualTo "=="
373 , binary NotEqualTo "!=" ]
374 , [ binary BitwiseAnd "&" ]
375 , [ binary BitwiseXor "^" ]
376 , [ binary BitwiseOr "|" ]
377 , [ binary And "&&" ]
381prettyPrintCpp1 :: AST -> Text
382prettyPrintCpp1 = maybe (internalError "Incomplete pattern") runPlainString . flip evalStateT (PrinterState 0) . prettyPrintCpp'
384stringLiteral :: Text -> Text
385stringLiteral s = "\"" <> s <> "\""
387unbox :: Text -> AST -> Text
388unbox _ v@(NumericLiteral{}) = prettyPrintCpp1 v
389unbox _ v@(BooleanLiteral{}) = prettyPrintCpp1 v
390unbox _ v@(StringLiteral{}) = prettyPrintCpp1 v
391unbox t v = "unbox<" <> t <> ">(" <> prettyPrintCpp1 v <> ")"
393unboxType :: Text -> Maybe Text
395 | t == C.semiringInt ||
398 | t == C.semiringNumber ||
400 t == C.euclideanRingNumber
402 | otherwise = Nothing
404renderOp :: Text -> Text
406 | op == C.add = " + "
407 | op == C.sub = " - "
408 | op == C.mul = " * "
409 | op == C.div = " / "
410 | otherwise = error $ "Unknown operator " <> T.unpack op
412interfaceSource :: Text -> [Ident] -> [Ident] -> Text
413interfaceSource mn exports foreigns =
414 "// Generated by purecc compiler\n\n" <>
415 "#ifndef " <> mn <> "_H\n" <>
416 "#define " <> mn <> "_H\n\n" <>
417 "#include \"purescript.h\"\n" <>
419 "namespace " <> mn <> " {\n\n" <>
420 "using namespace purescript;\n\n" <>
421 (T.concat $ (\export -> "auto " <> identToCpp export <> "() -> boxed;\n") <$> (exports \\ foreigns)) <>
423 (if null foreigns then "" else ("// Foreign values\n\nauto " <> foreignDict <> "() -> " <> dictType <> "&;\n\n")) <>
424 (T.concat $ (\foreign' -> "inline auto " <>
425 identToCpp foreign' <>
426 "() -> const boxed& { " <>
428 foreignDict <> "().at(\"" <> identToCpp foreign' <> "\"); " <>
430 " };\n") <$> foreigns) <>
432 "} // end namespace " <> mn <>
434 "#endif // " <> mn <> "_H\n\n"
436implHeaderSource :: Text -> [Text] -> Text -> Text
437implHeaderSource mn imports interfaceImport =
438 T.concat imports <> "\n"<>
439 interfaceImport <> "\n\n" <>
440 "namespace " <> mn <> " {\n\n"
442implFooterSource :: Text -> [Ident] -> Text
443implFooterSource mn foreigns =
445 (if null foreigns then "" else ("auto " <> foreignDict <> "() -> " <> dictType <> "& {\n" <>
446 " static dict_t _dict_;\n" <>
447 " return _dict_;\n" <>
449 "} // end namespace " <> mn <>
451 if mn == "Main" then mainSource else "\n"
455 \int main(int argc, const char * argv[]) {\n\
456 \ Main::main()(nullptr);\n\
465foreignDict = "_foreign_"
467dispatchOnceBegin :: Text
468dispatchOnceBegin = "static const boxed _value_ = "
470dispatchOnceEnd :: Text
471dispatchOnceEnd = "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