BNFC-2.5.0: src/formats/c-sharp/CSharpUtils.hs
{-
BNF Converter: Utility Functions for C#
Copyright (C) 2006 Author: Johan Broberg
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{-
**************************************************************
BNF Converter Module
Description : This module provides utility functions for the
C# format.
Author : Johan Broberg (johan@pontemonti.com)
License : GPL (GNU General Public License)
Created : 23 November, 2006
Modified : 21 January, 2007 by Johan Broberg
**************************************************************
-}
module CSharpUtils where
import CF
import Control.Monad.ST
-- Control.Monad.State
import Data.Char (toLower)
import Data.Maybe
import Data.List
import OOAbstract hiding (basetypes)
type Namespace = String
--The visit-function name of a basic type
visitFunName :: String -> String
visitFunName v =
if "integer_" `isPrefixOf` v then "Integer"
else if "char_" `isPrefixOf` v then "Char"
else if "string_" `isPrefixOf` v then "String"
else if "double_" `isPrefixOf` v then "Double"
else if "ident_" `isPrefixOf` v then "Ident"
else "Ident" --User-defined type
isUserDefined :: String -> Bool
isUserDefined v = v `notElem` (map classVar (map fst basetypes))
basetypes = [
("Integer","int"),
("Char", "char"),
("Double", "double"),
("String", "string"),
("Ident", "string")
]
typename :: String -> String
typename name
| name == "Char" = "char"
| name == "Double" = "double"
| name == "Ident" = "string"
| name == "Integer" = "int"
| name == "String" = "string"
| otherwise = name
-- Creates a variable name.
-- To make sure that no reserved keyword is generated, an underscore is added at the end. Not very pretty, but effective.
varname :: String -> String
varname name = (map toLower name) ++ "_"
-- Given a variable name (in an abstract syntax class), returns ".ToString()" if the name doesn't match one of the basetypes.
toString :: String -> String
toString v = if isUserDefined v then ".ToString()" else ""
-- Prepends namespace ".Absyn." to typ unless it is one of the basetypes
identifier :: Namespace -> String -> String
identifier namespace typ
| typ `elem` (map snd basetypes) = typ
| otherwise = namespace ++ ".Absyn." ++ typ
-- Removes empty lines, and removes the line-break at the end.
-- This can be useful if you want to use unlines "inside" unlines and don't want a whole lot of "useless" line-breaks.
unlinesInline :: [String] -> String
unlinesInline xs = concat $ intersperse "\n" $ filter (\x -> x /= "") xs
unlinesInlineMap :: (a -> String) -> [a] -> String
unlinesInlineMap fun xs = unlinesInline $ intersperse " " $ filter (\x -> x /= "") $ map fun xs
--Helper function that escapes characters in strings
escapeChars :: String -> String
escapeChars [] = []
escapeChars ('\\':xs) = '\\' : ('\\' : (escapeChars xs))
escapeChars ('\"':xs) = '\\' : ('\"' : (escapeChars xs))
escapeChars (x:xs) = x : (escapeChars xs)
isAlsoCategory :: Fun -> Cat -> Bool
isAlsoCategory f c = f == c
flattenSignatures :: CAbs -> [(Cat, CSharpAbsRule)]
flattenSignatures cabs = [(c,r) | (c,rs) <- signatures cabs, r <- map cabsrule2csharpabsrule rs]
type VariableName = String
type PropertyName = String
-- Just like CAbsRule in OOAbstract, except this also has PropertyName.
-- (valcat,(constr,args)), True = is class (not basic), class variable stored
type CSharpAbsRule = (Fun,[(Cat,Bool,VariableName,PropertyName)])
cabsrule2csharpabsrule :: CAbsRule -> CSharpAbsRule
cabsrule2csharpabsrule (f, cabsrule) = (f, addPropertyNames cabsrule)
-- This generates names for properties. It's done the same way as generation of variable names in OOAbstract->cf2cabs
-- A property name uses the same casing as its category, but has an underscore at the end
addPropertyNames :: [(Cat, Bool, String)] -> [(Cat, Bool, VariableName, PropertyName)]
addPropertyNames cs = [(c,b,v,p) | ((c,b,v),p) <- zip cs (properties [] (map propertyName [c | (c,_,_) <- cs]))]
--- creating new names is quadratic, but parameter lists are short
--- this should conform with Michael's naming
where
properties seen vv = case vv of
[] -> vv
v:vs -> case length (filter (==v) seen) of
0 | elem v vs -> (v ++ "1"): properties (v:seen) vs
0 -> v : properties (v:seen) vs
n -> (v ++ show (n+1)) : properties (v:seen) vs
propertyName :: Cat -> PropertyName
propertyName c = c ++ "_"
-- Given a rule's definition, it goes through and nicely the properties by type.
-- Does the same thing as numVars in NamedVariables, except the varName part
numProps :: [(String, Int)] -> [Either String b] -> [Either String b]
numProps _env [] = []
numProps env ((Right f) : fs) = (Right f) : (numProps env fs)
numProps env ((Left f) : fs) =
case lookup f' env of
Nothing -> (Left f') : (numProps ((f',1):env) fs)
Just n -> (Left $ f' ++ (show $ n + 1)) : (numProps ((f',n+1):env) fs)
where
f' = propertyName (normCat (identCat f))