From 3f93c2ddeee06d182fccacb2a35311d00ed83226 Mon Sep 17 00:00:00 2001 From: Mark Probst Date: Thu, 13 Jul 2017 10:47:49 -0700 Subject: [PATCH 1/3] Nested types, first draft for CSharp --- src/Main.purs | 78 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 12 deletions(-) diff --git a/src/Main.purs b/src/Main.purs index 51dd39f834..6cbedd42b2 100644 --- a/src/Main.purs +++ b/src/Main.purs @@ -2,29 +2,83 @@ module Main where import Prelude -import Data.Argonaut.Core (Json, foldJsonObject) +import Control.Monad.Eff (Eff) +import Control.Monad.Eff.Console (CONSOLE) +import Control.Monad.Eff.Console as C +import Data.Argonaut.Core (JArray, JBoolean, JNull, JString, Json, JObject, foldJson, foldJsonObject) import Data.Argonaut.Parser (jsonParser) +import Data.Array (length, toUnfoldable, (:), concat, (!!), foldMap) import Data.Either (Either) -import Data.Foldable (foldMap) -import Data.StrMap as StrMap +import Data.Maybe (fromJust) +import Data.StrMap (StrMap, fromFoldable, keys, values, foldMap, toUnfoldable) as StrMap +import Data.Tuple (uncurry, Tuple(..), fst, snd) +import Partial.Unsafe (unsafePartial) -data CSharpType = Class { name :: String, properties :: Array String } +data CSharpClass = CSClass { name :: String, properties :: StrMap.StrMap CSharpType } +data CSharpType + = CSClassType CSharpClass + | CSArray CSharpType + | CSObject + | CSBool + | CSDouble + | CSString -jsonToCSharpType :: Json -> CSharpType -jsonToCSharpType j = Class { name: "MyValue", properties } - where properties = foldJsonObject [] StrMap.keys j +gatherCSharpClassesFromJson :: String -> Json -> Tuple CSharpType (Array CSharpClass) +gatherCSharpClassesFromJson name json = foldJson + (const $ Tuple CSObject []) + (\b -> Tuple CSBool []) + (\x -> Tuple CSDouble []) + (\s -> Tuple CSString []) + (case _ of + [] -> Tuple (CSArray CSObject) [] + a -> + let Tuple et classes = gatherCSharpClassesFromJson (singularize name) (unsafePartial $ fromJust $ a !! 0) in + Tuple (CSArray et) classes) + (\o -> + let Tuple props classes = mapProperties o + c = CSClass { name: name, properties: props } in + Tuple (CSClassType c) (c : classes)) + json + +mapStrMap :: forall a b. (String -> a -> b) -> StrMap.StrMap a -> Array b +mapStrMap f sm = map (uncurry f) (StrMap.toUnfoldable sm) + +singularize :: String -> String +singularize s = "OneOf" <> s + +mapProperties :: StrMap.StrMap Json -> Tuple (StrMap.StrMap CSharpType) (Array CSharpClass) +mapProperties sm = Tuple propMap classes + where mapper (Tuple n j) = let Tuple t classes = gatherCSharpClassesFromJson n j + in Tuple (Tuple n t) classes + results = map mapper (StrMap.toUnfoldable sm) + propMap = StrMap.fromFoldable $ map fst results + classes = concat $ map snd results renderCSharpType :: CSharpType -> String -renderCSharpType (Class { name, properties }) = "class " <> name <> """ +renderCSharpType (CSArray a) = (renderCSharpType a) <> "[]" +renderCSharpType (CSClassType (CSClass { name, properties })) = name +renderCSharpType CSObject = "object" +renderCSharpType CSBool = "bool" +renderCSharpType CSDouble = "double" +renderCSharpType CSString = "string" + +renderCSharpClass :: CSharpClass -> String +renderCSharpClass (CSClass { name, properties }) = + "class " <> name <> """ {""" <> - foldMap (\n -> "\n" <> nameToProperty n) properties + StrMap.foldMap (\n -> \t -> "\n" <> nameToProperty n t) properties <> """ } """ - where nameToProperty name = " public string " <> name <> " { get; set; }" + where nameToProperty name csType = " public " <> (renderCSharpType csType) <> " " <> name <> " { get; set; }" + +renderCSharpClasses :: Array CSharpClass -> String +renderCSharpClasses classes = + foldMap (\c -> (renderCSharpClass c) <> "\n\n") classes jsonToCSharp :: String -> Either String String jsonToCSharp json = jsonParser json - <#> jsonToCSharpType - <#> renderCSharpType \ No newline at end of file + <#> gatherCSharpClassesFromJson "TopLevel" + <#> snd + <#> renderCSharpClasses From d7e13d7eec42c76713aa508d3195f4dc3eecd531 Mon Sep 17 00:00:00 2001 From: Mark Probst Date: Thu, 13 Jul 2017 17:50:25 -0700 Subject: [PATCH 2/3] Don't gather classes in separate array --- app/src/App.js | 6 +++--- src/Main.purs | 53 +++++++++++++++++++++++++++----------------------- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/app/src/App.js b/app/src/App.js index ca79ef7256..706f37c4a9 100644 --- a/app/src/App.js +++ b/app/src/App.js @@ -12,9 +12,9 @@ import Main from "../../output/Main"; let json = `{ "name": "David", - "age": 31 -} -`; + "age": 31, + "addresses": [{"street": "222 Clayton St"}] +}`; class App extends Component { constructor(props) { diff --git a/src/Main.purs b/src/Main.purs index 6cbedd42b2..53a4bf13c3 100644 --- a/src/Main.purs +++ b/src/Main.purs @@ -7,7 +7,7 @@ import Control.Monad.Eff.Console (CONSOLE) import Control.Monad.Eff.Console as C import Data.Argonaut.Core (JArray, JBoolean, JNull, JString, Json, JObject, foldJson, foldJsonObject) import Data.Argonaut.Parser (jsonParser) -import Data.Array (length, toUnfoldable, (:), concat, (!!), foldMap) +import Data.Array (length, toUnfoldable, (:), concat, (!!), foldMap, concatMap) import Data.Either (Either) import Data.Maybe (fromJust) import Data.StrMap (StrMap, fromFoldable, keys, values, foldMap, toUnfoldable) as StrMap @@ -23,36 +23,41 @@ data CSharpType | CSDouble | CSString -gatherCSharpClassesFromJson :: String -> Json -> Tuple CSharpType (Array CSharpClass) -gatherCSharpClassesFromJson name json = foldJson - (const $ Tuple CSObject []) - (\b -> Tuple CSBool []) - (\x -> Tuple CSDouble []) - (\s -> Tuple CSString []) +makeCSharpTypeFromJson :: String -> Json -> CSharpType +makeCSharpTypeFromJson name json = foldJson + (const $ CSObject) + (\b -> CSBool) + (\x -> CSDouble) + (\s -> CSString) (case _ of - [] -> Tuple (CSArray CSObject) [] + [] -> CSArray CSObject a -> - let Tuple et classes = gatherCSharpClassesFromJson (singularize name) (unsafePartial $ fromJust $ a !! 0) in - Tuple (CSArray et) classes) + let elementType = makeCSharpTypeFromJson (singularize name) (unsafePartial $ fromJust $ a !! 0) in + CSArray elementType) (\o -> - let Tuple props classes = mapProperties o - c = CSClass { name: name, properties: props } in - Tuple (CSClassType c) (c : classes)) + let props = mapProperties o in + CSClassType (CSClass { name: name, properties: props })) json -mapStrMap :: forall a b. (String -> a -> b) -> StrMap.StrMap a -> Array b -mapStrMap f sm = map (uncurry f) (StrMap.toUnfoldable sm) +mapProperties :: StrMap.StrMap Json -> StrMap.StrMap CSharpType +mapProperties sm = StrMap.fromFoldable results + where mapper (Tuple n j) = Tuple n (makeCSharpTypeFromJson n j) + results = map mapper (unfold sm) singularize :: String -> String singularize s = "OneOf" <> s -mapProperties :: StrMap.StrMap Json -> Tuple (StrMap.StrMap CSharpType) (Array CSharpClass) -mapProperties sm = Tuple propMap classes - where mapper (Tuple n j) = let Tuple t classes = gatherCSharpClassesFromJson n j - in Tuple (Tuple n t) classes - results = map mapper (StrMap.toUnfoldable sm) - propMap = StrMap.fromFoldable $ map fst results - classes = concat $ map snd results +-- This is a travesty. Try putting this function definition +-- in the where clause below. +unfold :: forall a. StrMap.StrMap a -> Array (Tuple String a) +unfold sm = StrMap.toUnfoldable sm + +gatherClassesFromType :: CSharpType -> Array CSharpClass +gatherClassesFromType (CSClassType c) = + let CSClass { name, properties } = c in + c : (concatMap gatherClassesFromType (StrMap.values properties)) +gatherClassesFromType (CSArray t) = gatherClassesFromType t +gatherClassesFromType _ = [] renderCSharpType :: CSharpType -> String renderCSharpType (CSArray a) = (renderCSharpType a) <> "[]" @@ -79,6 +84,6 @@ renderCSharpClasses classes = jsonToCSharp :: String -> Either String String jsonToCSharp json = jsonParser json - <#> gatherCSharpClassesFromJson "TopLevel" - <#> snd + <#> makeCSharpTypeFromJson "TopLevel" + <#> gatherClassesFromType <#> renderCSharpClasses From aad6db9294a0fb281ab73652c700d367e32535e0 Mon Sep 17 00:00:00 2001 From: Mark Probst Date: Thu, 13 Jul 2017 18:06:33 -0700 Subject: [PATCH 3/3] More backend-agnostic IR --- src/Main.purs | 86 +++++++++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 40 deletions(-) diff --git a/src/Main.purs b/src/Main.purs index 53a4bf13c3..81083e9d74 100644 --- a/src/Main.purs +++ b/src/Main.purs @@ -14,34 +14,37 @@ import Data.StrMap (StrMap, fromFoldable, keys, values, foldMap, toUnfoldable) a import Data.Tuple (uncurry, Tuple(..), fst, snd) import Partial.Unsafe (unsafePartial) -data CSharpClass = CSClass { name :: String, properties :: StrMap.StrMap CSharpType } -data CSharpType - = CSClassType CSharpClass - | CSArray CSharpType - | CSObject - | CSBool - | CSDouble - | CSString +data IRClassData = IRClassData { name :: String, properties :: StrMap.StrMap IRType } +data IRType + = IRNothing + | IRNull + | IRInteger + | IRDouble + | IRBool + | IRString + | IRArray IRType + | IRClass IRClassData + | IRUnion (Array IRType) -makeCSharpTypeFromJson :: String -> Json -> CSharpType -makeCSharpTypeFromJson name json = foldJson - (const $ CSObject) - (\b -> CSBool) - (\x -> CSDouble) - (\s -> CSString) +makeTypeFromJson :: String -> Json -> IRType +makeTypeFromJson name json = foldJson + (const $ IRNull) + (\b -> IRBool) + (\x -> IRDouble) + (\s -> IRString) (case _ of - [] -> CSArray CSObject + [] -> IRArray IRNothing a -> - let elementType = makeCSharpTypeFromJson (singularize name) (unsafePartial $ fromJust $ a !! 0) in - CSArray elementType) + let elementType = makeTypeFromJson (singularize name) (unsafePartial $ fromJust $ a !! 0) in + IRArray elementType) (\o -> let props = mapProperties o in - CSClassType (CSClass { name: name, properties: props })) + IRClass (IRClassData { name: name, properties: props })) json -mapProperties :: StrMap.StrMap Json -> StrMap.StrMap CSharpType +mapProperties :: StrMap.StrMap Json -> StrMap.StrMap IRType mapProperties sm = StrMap.fromFoldable results - where mapper (Tuple n j) = Tuple n (makeCSharpTypeFromJson n j) + where mapper (Tuple n j) = Tuple n (makeTypeFromJson n j) results = map mapper (unfold sm) singularize :: String -> String @@ -52,38 +55,41 @@ singularize s = "OneOf" <> s unfold :: forall a. StrMap.StrMap a -> Array (Tuple String a) unfold sm = StrMap.toUnfoldable sm -gatherClassesFromType :: CSharpType -> Array CSharpClass -gatherClassesFromType (CSClassType c) = - let CSClass { name, properties } = c in - c : (concatMap gatherClassesFromType (StrMap.values properties)) -gatherClassesFromType (CSArray t) = gatherClassesFromType t +gatherClassesFromType :: IRType -> Array IRClassData +gatherClassesFromType (IRClass classData) = + let IRClassData { name, properties } = classData in + classData : (concatMap gatherClassesFromType (StrMap.values properties)) +gatherClassesFromType (IRArray t) = gatherClassesFromType t gatherClassesFromType _ = [] -renderCSharpType :: CSharpType -> String -renderCSharpType (CSArray a) = (renderCSharpType a) <> "[]" -renderCSharpType (CSClassType (CSClass { name, properties })) = name -renderCSharpType CSObject = "object" -renderCSharpType CSBool = "bool" -renderCSharpType CSDouble = "double" -renderCSharpType CSString = "string" +renderTypeToCSharp :: IRType -> String +renderTypeToCSharp IRNothing = "object" +renderTypeToCSharp IRNull = "object" +renderTypeToCSharp IRInteger = "int" +renderTypeToCSharp IRDouble = "double" +renderTypeToCSharp IRBool = "bool" +renderTypeToCSharp IRString = "string" +renderTypeToCSharp (IRArray a) = (renderTypeToCSharp a) <> "[]" +renderTypeToCSharp (IRClass (IRClassData { name, properties })) = name +renderTypeToCSharp (IRUnion _) = "FIXME" -renderCSharpClass :: CSharpClass -> String -renderCSharpClass (CSClass { name, properties }) = +renderClassToCSharp :: IRClassData -> String +renderClassToCSharp (IRClassData { name, properties }) = "class " <> name <> """ {""" <> StrMap.foldMap (\n -> \t -> "\n" <> nameToProperty n t) properties <> """ } """ - where nameToProperty name csType = " public " <> (renderCSharpType csType) <> " " <> name <> " { get; set; }" + where nameToProperty name irType = " public " <> (renderTypeToCSharp irType) <> " " <> name <> " { get; set; }" -renderCSharpClasses :: Array CSharpClass -> String -renderCSharpClasses classes = - foldMap (\c -> (renderCSharpClass c) <> "\n\n") classes +renderClassesToCSharp :: Array IRClassData -> String +renderClassesToCSharp classes = + foldMap (\c -> (renderClassToCSharp c) <> "\n\n") classes jsonToCSharp :: String -> Either String String jsonToCSharp json = jsonParser json - <#> makeCSharpTypeFromJson "TopLevel" + <#> makeTypeFromJson "TopLevel" <#> gatherClassesFromType - <#> renderCSharpClasses + <#> renderClassesToCSharp