@@ -25,94 +25,171 @@ import Data.List
25import Data.Maybe (fromMaybe)
25import Data.Maybe (fromMaybe)
26import qualified Control.Arrow as A
26import qualified Control.Arrow as A
27import Control.Arrow ((***), (<+>), first, second)
27import Control.Arrow ((***), (<+>), first, second)
28+import Control.Applicative
29+import Control.Monad.State
31+newtype PrinterState = PrinterState { indent :: Int } deriving (Show, Eq, Ord)
36+withIndent :: StateT PrinterState Maybe String -> StateT PrinterState Maybe String
39+ modify $ \s -> s { indent = indent s + blockIndent }
41+ modify $ \s -> s { indent = indent s - blockIndent }
44+currentIndent :: StateT PrinterState Maybe String
47+ return $ replicate (indent current) ' '
29−literals :: Pattern JS String
49+literals :: Pattern PrinterState JS String
30−literals = Pattern $ A.Kleisli match
50+literals = mkPattern' match
52+ match :: JS -> StateT PrinterState Maybe String
32− match (JSNumericLiteral n) = Just $ either show show n
53+ match (JSNumericLiteral n) = return $ either show show n
33− match (JSStringLiteral s) = Just $ show s
54+ match (JSStringLiteral s) = return $ show s
34− match (JSBooleanLiteral True) = Just "true"
55+ match (JSBooleanLiteral True) = return "true"
35− match (JSBooleanLiteral False) = Just "false"
56+ match (JSBooleanLiteral False) = return "false"
36− match (JSArrayLiteral xs) = Just $ "[" ++ intercalate ", " (map prettyPrintJS xs) ++ "]"
57+ match (JSArrayLiteral xs) = fmap concat $ sequence
59+ , fmap (intercalate ", ") $ forM xs prettyPrintJS'
62+ match (JSObjectLiteral ps) = fmap concat $ sequence
37− match (JSObjectLiteral ps) = Just $ "{ " ++ intercalate ", " (map (\(key, value) -> key ++ ": " ++ prettyPrintJS value) ps) ++ " }"
65+ jss <- forM ps $ \(key, value) -> fmap ((key ++ ": ") ++) . prettyPrintJS' $ value
38− match (JSBlock sts) = Just $ "{ " ++ intercalate "; " (map prettyPrintJS sts) ++ " }"
66+ indentString <- currentIndent
67+ return $ intercalate ", \n" $ map (indentString ++) jss
72+ match (JSBlock sts) = fmap concat $ sequence
75+ jss <- forM sts prettyPrintJS'
76+ indentString <- currentIndent
77+ return $ intercalate "\n" $ map (++ "; ") $ map (indentString ++) jss
39− match (JSVar ident) = Just (identToJs ident)
82+ match (JSVar ident) = return (identToJs ident)
40− match (JSVariableIntroduction ident value) = Just $ "var " ++ identToJs ident ++ maybe "" ((" = " ++) . prettyPrintJS) value
83+ match (JSVariableIntroduction ident value) = fmap concat $ sequence
85+ , return $ identToJs ident
86+ , maybe (return "") (fmap (" = " ++) . prettyPrintJS') value
41− match (JSAssignment target value) = Just $ targetToJs target ++ " = " ++ prettyPrintJS value
88+ match (JSAssignment target value) = fmap concat $ sequence
89+ [ return $ targetToJs target
91+ , prettyPrintJS' value
42− match (JSWhile cond sts) = Just $ "while ("
93+ match (JSWhile cond sts) = fmap concat $ sequence
43− ++ prettyPrintJS cond ++ ") "
95+ , prettyPrintJS' cond
44− ++ prettyPrintJS sts
97+ , prettyPrintJS' sts
45− match (JSFor ident start end sts) = Just $ "for ("
99+ match (JSFor ident start end sts) = fmap concat $ sequence
100+ [ return $ "for (" ++ identToJs ident ++ " = "
46− ++ identToJs ident ++ " = " ++ prettyPrintJS start ++ "; "
101+ , prettyPrintJS' start
102+ , return $ "; " ++ identToJs ident ++ " < "
47− ++ identToJs ident ++ " < " ++ prettyPrintJS end ++ "; "
103+ , prettyPrintJS' end
48− ++ identToJs ident ++ "++) "
104+ , return $ "; " ++ identToJs ident ++ "++) "
49− ++ prettyPrintJS sts
105+ , prettyPrintJS' sts
50− match (JSIfElse cond thens elses) = Just $ "if ("
107+ match (JSIfElse cond thens elses) = fmap concat $ sequence
51− ++ prettyPrintJS cond ++ ") "
109+ , prettyPrintJS' cond
52− ++ prettyPrintJS thens
111+ , prettyPrintJS' thens
53− ++ maybe "" ((" else " ++) . prettyPrintJS) elses
112+ , maybe (return "") (fmap (" else " ++) . prettyPrintJS') elses
114+ match (JSReturn value) = fmap concat $ sequence
54− match (JSReturn value) = Just $ "return " ++ prettyPrintJS value
116+ , prettyPrintJS' value
118+ match (JSThrow value) = fmap concat $ sequence
55− match (JSThrow value) = Just $ "throw " ++ prettyPrintJS value
120+ , prettyPrintJS' value
56− match _ = Nothing
122+ match _ = mzero
58targetToJs :: JSAssignment -> String
124targetToJs :: JSAssignment -> String
59targetToJs (JSAssignVariable ident) = identToJs ident
125targetToJs (JSAssignVariable ident) = identToJs ident
60targetToJs (JSAssignProperty prop target) = targetToJs target ++ "." ++ prop
126targetToJs (JSAssignProperty prop target) = targetToJs target ++ "." ++ prop
62−conditional :: Pattern JS ((JS, JS), JS)
128+conditional :: Pattern PrinterState JS ((JS, JS), JS)
63−conditional = Pattern $ A.Kleisli match
129+conditional = mkPattern match
65 match (JSConditional cond th el) = Just ((th, el), cond)
131 match (JSConditional cond th el) = Just ((th, el), cond)
66 match _ = Nothing
132 match _ = Nothing
68−accessor :: Pattern JS (String, JS)
134+accessor :: Pattern PrinterState JS (String, JS)
69−accessor = Pattern $ A.Kleisli match
135+accessor = mkPattern match
71 match (JSAccessor prop val) = Just (prop, val)
137 match (JSAccessor prop val) = Just (prop, val)
72 match _ = Nothing
138 match _ = Nothing
74−indexer :: Pattern JS (String, JS)
140+indexer :: Pattern PrinterState JS (String, JS)
75−indexer = Pattern $ A.Kleisli match
141+indexer = mkPattern' match
77− match (JSIndexer index val) = Just (prettyPrintJS index, val)
143+ match (JSIndexer index val) = (,) <$> prettyPrintJS' index <*> pure val
78− match _ = Nothing
144+ match _ = mzero
80−lam :: Pattern JS ((Maybe Ident, [Ident]), JS)
146+lam :: Pattern PrinterState JS ((Maybe Ident, [Ident]), JS)
81−lam = Pattern $ A.Kleisli match
147+lam = mkPattern match
83 match (JSFunction name args ret) = Just ((name, args), ret)
149 match (JSFunction name args ret) = Just ((name, args), ret)
84 match _ = Nothing
150 match _ = Nothing
86−app :: Pattern JS (String, JS)
152+app :: Pattern PrinterState JS (String, JS)
87−app = Pattern $ A.Kleisli match
153+app = mkPattern' match
89− match (JSApp val args) = Just (intercalate "," (map prettyPrintJS args), val)
155+ match (JSApp val args) = do
156+ jss <- mapM prettyPrintJS' args
157+ return (intercalate ", " jss, val)
90− match _ = Nothing
158+ match _ = mzero
92−unary :: UnaryOperator -> String -> Operator JS String
160+unary :: UnaryOperator -> String -> Operator PrinterState JS String
93unary op str = Wrap pattern (++)
161unary op str = Wrap pattern (++)
95− pattern :: Pattern JS (String, JS)
163+ pattern :: Pattern PrinterState JS (String, JS)
96− pattern = Pattern $ A.Kleisli match
164+ pattern = mkPattern match
98 match (JSUnary op' val) | op' == op = Just (str, val)
166 match (JSUnary op' val) | op' == op = Just (str, val)
99 match _ = Nothing
167 match _ = Nothing
101−binary :: BinaryOperator -> String -> Operator JS String
169+binary :: BinaryOperator -> String -> Operator PrinterState JS String
102binary op str = AssocR pattern (\v1 v2 -> v1 ++ " " ++ str ++ " " ++ v2)
170binary op str = AssocR pattern (\v1 v2 -> v1 ++ " " ++ str ++ " " ++ v2)
104− pattern :: Pattern JS (JS, JS)
172+ pattern :: Pattern PrinterState JS (JS, JS)
105− pattern = Pattern $ A.Kleisli match
173+ pattern = mkPattern match
107 match (JSBinary op' v1 v2) | op' == op = Just (v1, v2)
175 match (JSBinary op' v1 v2) | op' == op = Just (v1, v2)
108 match _ = Nothing
176 match _ = Nothing
178+prettyPrintJS1 :: JS -> String
179+prettyPrintJS1 = fromMaybe (error "Incomplete pattern") . flip evalStateT (PrinterState 0) . prettyPrintJS'
110−prettyPrintJS :: JS -> String
181+prettyPrintJS :: [JS] -> String
111−prettyPrintJS = fromMaybe (error "Incomplete pattern") . pattern matchValue
182+prettyPrintJS sts = fromMaybe (error "Incomplete pattern") . flip evalStateT (PrinterState 0) $ do
183+ jss <- forM sts prettyPrintJS'
184+ indentString <- currentIndent
185+ return $ intercalate "\n" $ map (++ "; ") $ map (indentString ++) jss
187+prettyPrintJS' :: JS -> StateT PrinterState Maybe String
188+prettyPrintJS' = A.runKleisli $ runPattern matchValue
113− matchValue :: Pattern JS String
190+ matchValue :: Pattern PrinterState JS String
114 matchValue = buildPrettyPrinter operators (literals <+> fmap parens matchValue)
191 matchValue = buildPrettyPrinter operators (literals <+> fmap parens matchValue)
115− operators :: OperatorTable JS String
192+ operators :: OperatorTable PrinterState JS String
116 operators =
193 operators =
117 OperatorTable [ [ Wrap accessor $ \prop val -> val ++ "." ++ prop ]
194 OperatorTable [ [ Wrap accessor $ \prop val -> val ++ "." ++ prop ]
118 , [ Wrap indexer $ \index val -> val ++ "[" ++ index ++ "]" ]
195 , [ Wrap indexer $ \index val -> val ++ "[" ++ index ++ "]" ]
@@ -121,7 +198,7 @@ prettyPrintJS = fromMaybe (error "Incomplete pattern") . pattern matchValue
121 ++ maybe "" identToJs name
198 ++ maybe "" identToJs name
122 ++ "(" ++ intercalate ", " (map identToJs args) ++ ") "
199 ++ "(" ++ intercalate ", " (map identToJs args) ++ ") "
124− , [ Wrap conditional $ \(th, el) cond -> cond ++ " ? " ++ prettyPrintJS th ++ " : " ++ prettyPrintJS el ]
201+ , [ Wrap conditional $ \(th, el) cond -> cond ++ " ? " ++ prettyPrintJS1 th ++ " : " ++ prettyPrintJS1 el ]
125 , [ binary LessThan "<" ]
202 , [ binary LessThan "<" ]
126 , [ binary LessThanOrEqualTo "<=" ]
203 , [ binary LessThanOrEqualTo "<=" ]
127 , [ binary GreaterThan ">" ]
204 , [ binary GreaterThan ">" ]