import "Prelude" import "StringBuilder" as StringBuilder import "Coercion" // JSValue and printing data JSValue = JSObject [JSEntry] | JSArray [JSValue] | JSString String | JSNumber String | JSBoolean Boolean | JSNull data JSEntry = JSEntry String JSValue instance Show JSValue where sb <+ JSObject entries = printWithSeparator (sb << "{") "," entries << "}" sb <+ JSArray elements = printWithSeparator (sb << "[") "," elements << "]" sb <+ JSString str = sb <+ str sb <+ JSNumber str = sb << str sb <+ JSBoolean v = sb << if v then "true" else "false" sb <+ JSNull = sb << "null" instance Show JSEntry where sb <+ JSEntry key value = sb <+ key << ":" <+ value // JSCompatible class JSCompatible a where toJSValue :: a -> JSValue toJSONString :: a -> String printJSON :: StringBuilder.T -> a -> StringBuilder.T printJSON sb v = sb <+ toJSValue v toJSONString v = runProc (StringBuilder.toString (printJSON StringBuilder.new v)) instance JSCompatible JSValue where toJSValue = id printJSON = (<+) instance JSCompatible Integer where toJSValue = JSNumber . coerce instance JSCompatible Long where toJSValue = JSNumber . coerce instance JSCompatible Float where toJSValue = JSNumber . coerce instance JSCompatible Double where toJSValue = JSNumber . coerce instance JSCompatible String where toJSValue = JSString instance JSCompatible Boolean where toJSValue = JSBoolean instance (JSCompatible a) => JSCompatible (Maybe a) where toJSValue (Just v) = toJSValue v toJSValue Nothing = JSNull instance (JSCompatible a) => JSCompatible [a] where toJSValue = JSArray . map toJSValue (:::) :: JSCompatible a => String -> a -> JSEntry key ::: value = JSEntry key (toJSValue value)