module PureScript.ToString (toString, moduleNameToString) where import Data.Array as Array import Data.Map as Map import Data.Maybe as Maybe import Data.Set as Set import Data.String as String import Data.String.CodePoints as CodePoints import Data.String.NonEmpty (NonEmptyString) import Data.String.NonEmpty as NonEmptyString import Data.Tuple as Tuple import Prelude as Prelude import PureScript.Data as Data toString :: Data.Module -> String toString pModule@(Data.Module { definitionList }) = let importedModuleQualifiedNameDict :: ModuleQualifiedNameDict importedModuleQualifiedNameDict = importedModuleSetToQualifiedNameDict (collectInportModule pModule) in String.joinWith "\n\n" ( Array.concat [ [ Prelude.append "-- generated by definy. Do not edit!\n" (moduleNameCode pModule) , String.joinWith "\n" ( Prelude.map ( \(Tuple.Tuple moduleName qualifiedName) -> String.joinWith "" [ "import " , NonEmptyString.toString (moduleNameToString moduleName) , " as " , NonEmptyString.toString qualifiedName ] ) (dictToTupleArray importedModuleQualifiedNameDict) ) ] , Prelude.map (definitionToString importedModuleQualifiedNameDict) definitionList , [ "" ] ] ) newtype ModuleQualifiedNameDict = ModuleQualifiedNameDict (Map.Map Data.ModuleName NonEmptyString) dictToTupleArray :: ModuleQualifiedNameDict -> Array (Tuple.Tuple Data.ModuleName NonEmptyString) dictToTupleArray (ModuleQualifiedNameDict map) = Map.toUnfoldable map dicGetQualifiedName :: Data.ModuleName -> ModuleQualifiedNameDict -> Maybe.Maybe NonEmptyString dicGetQualifiedName moduleName (ModuleQualifiedNameDict map) = Map.lookup moduleName map importedModuleSetToQualifiedNameDict :: Set.Set Data.ModuleName -> ModuleQualifiedNameDict importedModuleSetToQualifiedNameDict moduleNameSet = ModuleQualifiedNameDict ( Map.fromFoldable ( Array.mapWithIndex ( \i moduleName -> Tuple.Tuple moduleName ( NonEmptyString.cons (String.codePointFromChar 'M') (Prelude.show i) ) ) ((Set.toUnfoldable moduleNameSet) :: Array Data.ModuleName) ) ) moduleNameCode :: Data.Module -> String moduleNameCode (Data.Module { name, definitionList }) = String.joinWith "" [ "module " , NonEmptyString.toString (moduleNameToString name) , " (" , String.joinWith ", " (collectExportDefinition definitionList) , ") where" ] moduleNameToString :: Data.ModuleName -> NonEmptyString moduleNameToString (Data.ModuleName stringList) = NonEmptyString.join1With "." stringList collectInportModule :: Data.Module -> Set.Set Data.ModuleName collectInportModule (Data.Module { name, definitionList }) = Set.delete name ( Set.unions (Prelude.map collectInportModuleInDefinition definitionList) ) collectInportModuleInDefinition :: Data.Definition -> Set.Set Data.ModuleName collectInportModuleInDefinition (Data.Definition { typeData, exprData }) = Set.union (collectInportModuleInType typeData) (collectInportModuleInExprData exprData) collectInportModuleInType :: Data.TypeData -> Set.Set Data.ModuleName collectInportModuleInType = case _ of Data.TypeData { moduleName } -> Set.singleton moduleName Data.SymbolLiteral _ -> Set.empty Data.TypeWithArgument { function, argument } -> Set.union (collectInportModuleInType function) (collectInportModuleInType argument) collectInportModuleInExprData :: Data.ExprData -> Set.Set Data.ModuleName collectInportModuleInExprData = case _ of Data.Call { function, argument } -> Set.union (collectInportModuleInExprData function) (collectInportModuleInExprData argument) Data.Variable { moduleName } -> Set.singleton moduleName Data.StringLiteral _ -> Set.empty Data.CharLiteral _ -> Set.empty Data.ArrayLiteral list -> Set.unions (Prelude.map collectInportModuleInExprData list) Data.TypeAnnotation { expr, pType } -> Set.union (collectInportModuleInExprData expr) (collectInportModuleInType pType) Data.Tag { moduleName } -> Set.singleton moduleName collectExportDefinition :: Array Data.Definition -> Array String collectExportDefinition list = Array.mapMaybe ( case _ of Data.Definition { isExport: true, name } -> Maybe.Just (NonEmptyString.toString name) Data.Definition _ -> Maybe.Nothing ) list definitionToString :: ModuleQualifiedNameDict -> Data.Definition -> String definitionToString importedModuleQualifiedNameDict (Data.Definition { name, document, typeData, exprData }) = String.joinWith "" [ documentToString document , NonEmptyString.toString name , " :: " , typeToString importedModuleQualifiedNameDict typeData , "\n" , NonEmptyString.toString name , " = " , exprDataToString importedModuleQualifiedNameDict exprData ] typeToString :: ModuleQualifiedNameDict -> Data.TypeData -> String typeToString importedModuleQualifiedNameDict pType = case pType of Data.TypeData { moduleName, name } -> String.joinWith "" [ moduleNameToStringSelfEmpty importedModuleQualifiedNameDict moduleName , NonEmptyString.toString name ] Data.SymbolLiteral str -> stringToStringLiteral str Data.TypeWithArgument { function, argument } -> String.joinWith "" [ "(" , typeToString importedModuleQualifiedNameDict function , ") (" , typeToString importedModuleQualifiedNameDict argument , ")" ] exprDataToString :: ModuleQualifiedNameDict -> Data.ExprData -> String exprDataToString importedModuleQualifiedNameDict = case _ of Data.Call { function, argument } -> String.joinWith "" [ "(" , exprDataToString importedModuleQualifiedNameDict function , ") (" , exprDataToString importedModuleQualifiedNameDict argument , ")" ] Data.Variable { moduleName, name } -> Prelude.append (moduleNameToStringSelfEmpty importedModuleQualifiedNameDict moduleName) (NonEmptyString.toString name) Data.StringLiteral value -> stringToStringLiteral value Data.CharLiteral value -> String.joinWith "" [ "'" , case value of '\n' -> "\\n" '\'' -> "\\'" '\\' -> "\\\\" _ -> String.singleton (CodePoints.codePointFromChar value) , "'" ] Data.ArrayLiteral list -> String.joinWith "" [ "[ " , String.joinWith ", " (Prelude.map (exprDataToString importedModuleQualifiedNameDict) list) , " ]" ] Data.TypeAnnotation { expr, pType } -> String.joinWith "" [ exprDataToString importedModuleQualifiedNameDict expr , " :: " , typeToString importedModuleQualifiedNameDict pType ] Data.Tag { moduleName, name } -> Prelude.append (moduleNameToStringSelfEmpty importedModuleQualifiedNameDict moduleName) (NonEmptyString.toString name) stringToStringLiteral :: String -> String stringToStringLiteral value = String.joinWith "" [ "\"" , String.replaceAll (String.Pattern "\n") (String.Replacement "\\n") ( String.replaceAll (String.Pattern "\"") (String.Replacement "\\\"") ( String.replaceAll (String.Pattern "\\") (String.Replacement "\\\\") value ) ) , "\"" ] moduleNameToStringSelfEmpty :: ModuleQualifiedNameDict -> Data.ModuleName -> String moduleNameToStringSelfEmpty importedModuleQualifiedNameDict moduleName = case dicGetQualifiedName moduleName importedModuleQualifiedNameDict of Maybe.Just qualifiedName -> NonEmptyString.toString (NonEmptyString.appendString qualifiedName ".") Maybe.Nothing -> "" documentToString :: String -> String documentToString document = let documentTrimmed = String.trim document in if String.null documentTrimmed then "" else Prelude.append ( String.joinWith "\n" ( Prelude.map ( \line -> Prelude.append "-- |" ( if String.null line then "" else (Prelude.append " " line) ) ) (String.split (String.Pattern "\n") documentTrimmed) ) ) "\n"