packages feed

BNFC-2.4.2.1: formats/OOAbstract.hs

{-
    BNF Converter: Datastructure for object-oriented abstract syntax generators
    Copyright (C) 2006  Author:  Aarne Ranta

    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 defines a data structure that is
                    used for generating abstract syntax in cpp_stl.
                    It should be used in other STL modules as well,
                    and could be used for object-oriented languages
                    in general, to avoid duplicated work.

    Author        : Aarne Ranta (aarne@cs.chalmers.se)

    License       : GPL (GNU General Public License)

    Created       : 29 August, 2006            

    Modified      : 29 August, 2006 / Aarne Ranta
	            
   
   ************************************************************** 
-}

module OOAbstract where

import CF
import Utils((+++),(++++))
import NamedVariables
import Data.List
import Data.Char(toLower)

-- A datastructure more appropriate than CF

data CAbs = CAbs {
  tokentypes :: [Cat],               -- user non-position token types
  listtypes  :: [(Cat,Bool)],        -- list types used, whether of classes
  absclasses :: [Cat],               -- grammar-def cats, normalized names
  conclasses :: [Fun],               -- constructors, except list ones
  signatures :: [(Cat,[CAbsRule])],  -- rules for each class, incl. pos tokens
  postokens  :: [Cat],               -- position token types
  defineds   :: [Fun]                -- defined (non-)constructors  
  }

-- (valcat,(constr,args)), True = is class (not basic), class variable stored
type CAbsRule = (Fun,[(Cat,Bool,String)]) 

-- all those names that denote classes in C++
allClasses :: CAbs -> [Cat]
allClasses ca = 
  absclasses ca ++ conclasses ca ++ map fst (listtypes ca) ++ postokens ca 

-- all those names that denote non-class types in C++
allNonClasses :: CAbs -> [Cat]
allNonClasses ca = 
  map fst basetypes ++ tokentypes ca

cf2cabs :: CF -> CAbs
cf2cabs cf@((pragmas,_),_) = CAbs {
  tokentypes = toks,
  listtypes  = [(c, snd (status (drop 4 c))) | -- remove "List" from "ListC"
                  c <- map (normCat . identCat) lists],
  absclasses = nub $ map normCat cats,
  conclasses = [f | Just f <- map testRule (rulesOfCF cf)],
  signatures = posdata ++ map normSig (cf2data cf), 
  postokens  = pos,
  defineds   = defs
  }
 where
  (pos,base) = partition (isPositionCat cf) $ fst (unzip (tokenPragmas cf))
  (lists,cats) = partition isList $ allCats cf
  toks = map normCat base
  testRule (f, (c, r))
   | isList c  = Nothing
   | f == "_"  = Nothing
   | otherwise = Just f
  normSig (c,fcs) = 
    (identCat c,[(f, classVars (map (status . identCat) cs)) | (f,cs) <- fcs])
  posdata = 
    [("Visitable",  -- to give superclass
     [(c,[("String",False,"string_"),("Integer",False,"integer_")])]) | c<-pos]
  status cat = (cat, notElem cat (map fst basetypes ++ toks))
  defs = [f | FunDef f _ _ <- pragmas]

  classVars :: [(Cat,Bool)] -> [(Cat,Bool,String)]
  classVars cs = 
    [(c,b,s) | ((c,b),s) <- zip cs (vars [] (map (classVar . fst) cs))]
  --- creating new names is quadratic, but parameter lists are short
  --- this should conform with Michael's naming
  vars seen vv = case vv of
    []   -> vv
    v:vs -> case length (filter (==v) seen) of
      0 | elem v vs -> (v ++ "1"): vars (v:seen) vs
      0             -> v         : vars (v:seen) vs
      n             -> (v ++ show (n+1)) : vars (v:seen) vs

basetypes = [
  ("Integer","int"),
  ("Char",   "char"),
  ("Double", "double"),
  ("String", "std::string"),
  ("Ident",  "std::string")
  ]

isBaseType :: CAbs -> Cat -> Bool
isBaseType cf c = elem c $ tokentypes cf ++ map fst basetypes

classVar :: Cat -> String
classVar c = map toLower c ++ "_"

pointerIf :: Bool -> String -> String
pointerIf b v = if b then "*" ++ v else v