-- Copyright (c) Microsoft. All rights reserved. -- Licensed under the MIT license. See LICENSE file in the project root for full license information. {-# LANGUAGE QuasiQuotes, OverloadedStrings #-} {-# OPTIONS_GHC -fno-warn-orphans #-} {-| Copyright : (c) Microsoft License : MIT Maintainer : adamsap@microsoft.com Stability : provisional Portability : portable Helper functions for creating common structures useful in code generation. These functions often operate on 'Text' objects. -} module Language.Bond.Codegen.Util ( commonHeader , commaSep , newlineSep , commaLineSep , newlineSepEnd , newlineBeginSep , doubleLineSep , doubleLineSepEnd , uniqueName , uniqueNames , indent , newLine , slashForward ) where import Data.Int (Int64) import Data.Word import Prelude import Data.Text.Lazy (Text, justifyRight) import Text.Shakespeare.Text import Paths_bond (version) import Data.Version (showVersion) import Language.Bond.Util instance ToText Word16 where toText = toText . show instance ToText Double where toText = toText . show instance ToText Integer where toText = toText . show indent :: Int64 -> Text indent n = justifyRight (4 * n) ' ' "" commaLine :: Int64 -> Text commaLine n = [lt|, #{indent n}|] newLine :: Int64 -> Text newLine n = [lt| #{indent n}|] doubleLine :: Int64 -> Text doubleLine n = [lt| #{indent n}|] -- | Separates elements of a list with a comma. commaSep :: (a -> Text) -> [a] -> Text commaSep = sepBy ", " newlineSep, commaLineSep, newlineSepEnd, newlineBeginSep, doubleLineSep, doubleLineSepEnd :: Int64 -> (a -> Text) -> [a] -> Text -- | Separates elements of a list with new lines. Starts new lines at the -- specified indentation level. newlineSep = sepBy . newLine -- | Separates elements of a list with comma followed by a new line. Starts -- new lines at the specified indentation level. commaLineSep = sepBy . commaLine -- | Separates elements of a list with new lines, ending with a new line. -- Starts new lines at the specified indentation level. newlineSepEnd = sepEndBy . newLine -- | Separates elements of a list with new lines, beginning with a new line. -- Starts new lines at the specified indentation level. newlineBeginSep = sepBeginBy . newLine -- | Separates elements of a list with two new lines. Starts new lines at -- the specified indentation level. doubleLineSep = sepBy . doubleLine -- | Separates elements of a list with two new lines, ending with two new -- lines. Starts new lines at the specified indentation level. doubleLineSepEnd = sepEndBy . doubleLine -- | Returns common header for generated files using specified single-line -- comment lead character(s) and a file name. commonHeader :: ToText a => a -> a -> a -> Text commonHeader c input output = [lt| #{c}------------------------------------------------------------------------------ #{c} This code was generated by a tool. #{c} #{c} Tool : Bond Compiler #{showVersion version} #{c} Input filename: #{input} #{c} Output filename: #{output} #{c} #{c} Changes to this file may cause incorrect behavior and will be lost when #{c} the code is regenerated. #{c} #{c}------------------------------------------------------------------------------ |] -- | Given an intended name and a list of already taken names, returns a -- unique name. Assumes that it's legal to append digits to the end of the -- intended name. uniqueName :: String -> [String] -> String uniqueName baseName taken = go baseName (0::Integer) where go name counter | not (name `elem` taken) = name | otherwise = go newName (counter + 1) where newName = baseName ++ (show counter) -- | Given a list of names with duplicates and a list of reserved names, -- create a list of unique names using the uniqueName function. uniqueNames :: [String] -> [String] -> [String] uniqueNames names reservedInit = reverse $ go names [] reservedInit where go [] acc _ = acc go (name:remaining) acc reservedAcc = go remaining (newName:acc) (newName:reservedAcc) where newName = uniqueName name reservedAcc -- | Converts all file path slashes to forward slashes. slashForward :: String -> String slashForward path = map replace path where replace '\\' = '/' replace c = c