aboutsummaryrefslogtreecommitdiffstats
path: root/style-generator/src/MyElm/Stringify.elm
diff options
context:
space:
mode:
Diffstat (limited to 'style-generator/src/MyElm/Stringify.elm')
-rw-r--r--style-generator/src/MyElm/Stringify.elm282
1 files changed, 282 insertions, 0 deletions
diff --git a/style-generator/src/MyElm/Stringify.elm b/style-generator/src/MyElm/Stringify.elm
new file mode 100644
index 0000000..da2793c
--- /dev/null
+++ b/style-generator/src/MyElm/Stringify.elm
@@ -0,0 +1,282 @@
+module MyElm.Stringify exposing (arg2string, declaration2string, expose2string, expression2string, module2string, needsBrackets, qualifiedName2string, type2str, type2string)
+
+import MyElm.Types exposing (..)
+
+
+
+-- indentation
+
+
+indented : String -> String
+indented s =
+ s
+ |> String.split "\n"
+ |> String.join "\n "
+ |> String.append " "
+
+
+listLike : String -> String -> String -> List String -> String
+listLike before sep after l =
+ let
+ shouldBeMultiline =
+ List.any (\ln -> List.length (String.split "\n" ln) > 1) l || List.foldl (\ln s -> s + String.length ln) 0 l > 100
+ in
+ if shouldBeMultiline then
+ "\n" ++ indented (before ++ " " ++ String.join ("\n" ++ sep) l ++ "\n" ++ after)
+
+ else if after == "" && before == "" then
+ String.join sep l
+
+ else
+ before ++ " " ++ String.join sep l ++ " " ++ after
+
+
+bodyIndent : String -> String
+bodyIndent str =
+ if List.length (String.split "\n" str) > 1 then
+ str
+
+ else
+ "\n " ++ str
+
+
+expose2string : Exposing -> String
+expose2string expose =
+ case expose of
+ ValueExposed val ->
+ val
+
+ TypeExposed tp ->
+ tp
+
+ TypeAndConstructors tp ->
+ tp ++ "(..)"
+
+
+module2string : Module -> String
+module2string (Module { name, exposes, doc, imports, declarations }) =
+ let
+ header =
+ "module " ++ name ++ " exposing (" ++ String.join ", " (List.map expose2string exposes) ++ ")\n\n"
+
+ docstr =
+ case doc of
+ Just d ->
+ "{-|" ++ d ++ "-}\n\n"
+
+ Nothing ->
+ ""
+
+ imps =
+ String.join "\n" imports
+ ++ (if List.length imports > 0 then
+ "\n\n\n"
+
+ else
+ ""
+ )
+
+ decs =
+ String.join "" <| List.map declaration2string declarations
+ in
+ header ++ docstr ++ imps ++ decs
+
+
+type2str : Bool -> Type -> String
+type2str needsBr tp =
+ case tp of
+ NamedType qualifiedName typeList ->
+ if List.length typeList > 0 then
+ if needsBr then
+ "(" ++ qualifiedName2string qualifiedName ++ " " ++ String.join " " (List.map (type2str True) typeList) ++ ")"
+
+ else
+ qualifiedName2string qualifiedName ++ " " ++ String.join " " (List.map (type2str True) typeList)
+
+ else
+ qualifiedName2string qualifiedName
+
+ RecordType branches ->
+ "{ " ++ String.join ", " (List.map (\( name, typ ) -> name ++ " = " ++ type2str False typ) branches) ++ " }"
+
+ FunctionType typeList ->
+ let
+ a =
+ String.join " -> " (List.map (type2str False) typeList)
+ in
+ if needsBr then
+ "(" ++ a ++ ")"
+
+ else
+ a
+
+ TupleType typeList ->
+ "( " ++ String.join ", " (List.map (type2str False) typeList) ++ " )"
+
+ TypeVariable name ->
+ name
+
+
+type2string =
+ type2str False
+
+
+declaration2string : Declaration -> String
+declaration2string declaration =
+ case declaration of
+ CustomType name variables variants ->
+ "type " ++ String.join " " (name :: variables) ++ "\n = " ++ String.join "\n | " (List.map (\( nm, args ) -> String.join " " (nm :: List.map (type2str True) args)) variants) ++ "\n\n\n"
+
+ TypeAlias name variables aliased ->
+ "type alias " ++ String.join " " (name :: variables) ++ "\n =" ++ type2string aliased ++ "\n\n\n"
+
+ Comment str ->
+ "{-|" ++ str ++ "}"
+
+ ValueDeclaration name anno argList expression ->
+ let
+ decl =
+ name ++ " " ++ String.join " " (List.map arg2string argList) ++ " =" ++ bodyIndent (expression2string expression) ++ "\n\n\n"
+ in
+ case anno of
+ [] ->
+ decl
+
+ signature ->
+ name ++ " : " ++ String.join " -> " (List.map type2string signature) ++ "\n" ++ decl
+
+
+arg2string : Argument -> String
+arg2string argument =
+ case argument of
+ Argument a ->
+ a
+
+
+qualifiedName2string : QualifiedName -> String
+qualifiedName2string qualifiedName =
+ let
+ identifierToStr id =
+ case id of
+ Constructor _ s ->
+ s
+
+ ValueOrType s ->
+ s
+ in
+ case qualifiedName of
+ Local ident ->
+ identifierToStr ident
+
+ FullyQualified modPath ident ->
+ String.join "." modPath ++ "." ++ identifierToStr ident
+
+ Aliased _ alias_ ident ->
+ alias_ ++ "." ++ identifierToStr ident
+
+ Bare _ ident ->
+ identifierToStr ident
+
+
+bracketify : Expression -> String
+bracketify arg =
+ if needsBrackets arg then
+ "(" ++ expression2string arg ++ ")"
+
+ else
+ expression2string arg
+
+
+isOperator : String -> Bool
+isOperator op =
+ case op of
+ "++" ->
+ True
+
+ "-" ->
+ True
+
+ "+" ->
+ True
+
+ "*" ->
+ True
+
+ "/" ->
+ True
+
+ "//" ->
+ True
+
+ "^" ->
+ True
+
+ "|>" ->
+ True
+
+ "<|" ->
+ True
+
+ _ ->
+ False
+
+
+expression2string : Expression -> String
+expression2string expression =
+ case expression of
+ Call name args ->
+ let
+ nameStr =
+ qualifiedName2string name
+ in
+ if isOperator nameStr then
+ case args of
+ a :: b :: rest ->
+ case nameStr of
+ "|>" ->
+ listLike "" " |> " "" [ expression2string a, String.join " " (List.map expression2string (b :: rest)) ]
+
+ _ ->
+ expression2string a ++ " " ++ nameStr ++ " " ++ String.join " " (List.map expression2string (b :: rest))
+
+ _ ->
+ "(" ++ nameStr ++ ") " ++ String.join " " (List.map bracketify args)
+
+ else
+ String.join " "
+ (nameStr
+ :: List.map
+ (\arg ->
+ if needsBrackets arg then
+ "(" ++ expression2string arg ++ ")"
+
+ else
+ expression2string arg
+ )
+ args
+ )
+
+ Literal lit ->
+ lit
+
+ ListExpr expressions ->
+ listLike "[" ", " "]" (List.map expression2string expressions)
+
+ Tuple expressions ->
+ listLike "(" ", " ")" (List.map expression2string expressions)
+
+ Record branches ->
+ listLike "{" ", " "}" (List.map (\( name, branch ) -> name ++ " = " ++ expression2string branch) branches)
+
+
+needsBrackets : Expression -> Bool
+needsBrackets expression =
+ case expression of
+ Call _ [] ->
+ False
+
+ Call _ _ ->
+ True
+
+ _ ->
+ False