1-- Compiler Toolkit: general purpose attribute management 2-- 3-- Author : Manuel M. T. Chakravarty 4-- Created: 14 February 95 5-- 6-- Version $Revision: 1.4 $ from $Date: 2005/06/22 16:01:03 $ 7-- 8-- Copyright (c) [1995..1999] Manuel M. T. Chakravarty 9-- 10-- This file is free software; you can redistribute it and/or modify 11-- it under the terms of the GNU General Public License as published by 12-- the Free Software Foundation; either version 2 of the License, or 13-- (at your option) any later version. 14-- 15-- This file is distributed in the hope that it will be useful, 16-- but WITHOUT ANY WARRANTY; without even the implied warranty of 17-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18-- GNU General Public License for more details. 19-- 20--- DESCRIPTION --------------------------------------------------------------- 21-- 22-- This module provides an abstract notion of attributes (in the sense of 23-- compiler construction). The collection of attributes that is attached to a 24-- single node of the structure tree is referenced via an attributes 25-- identifier. This is basically a reference into so-called attribute tables, 26-- which manage attributes of one type and may use different representations. 27-- There is also a position attribute managed via the attribute identifier 28-- without needing a further table (it is already fixed on construction of 29-- the structure tree). 30-- 31-- The `Attributed' class is based on a suggestion from Roman Lechtchinsky. 32-- 33--- DOCU ---------------------------------------------------------------------- 34-- 35-- language: Haskell 98 36-- 37-- * Attribute identifiers are generated during parsing and whenever new 38-- structure tree elements, possibly due to transformations, are generated. 39-- 40-- * New attributes can be added by simply providing a new attribute table 41-- indexed by the attribute identifiers. Thus, adding or discarding an 42-- attribute does not involve any change in the structure tree. 43-- 44-- * Consecutive sequences of names are used as attribute identifiers to 45-- facilitate the use of arrays for attributes that are fixed; speeds up 46-- read access. (See also TODO.) 47-- 48-- * Each attribute table can simultaneously provide melted (updatable) and 49-- frozen (non-updatable) attributes. It also allows to dynamically grow the 50-- table, i.e., cover a wider range of attribute identifiers. 51-- 52-- * There is a variant merely providing a position, which is used for 53-- internal identifiers and such. 54-- 55-- * `StdAttr' provides standard undefined and don't care variants for 56-- attribute values. 57-- 58--- TODO ---------------------------------------------------------------------- 59-- 60-- * When there are sparse attribute tables that we want to freeze (and they 61-- will occur sooner or later), then introduce a third variant of tables 62-- realized via hash table---depending on the type of attribute table, we 63-- may even allow them to be soft. 64-- 65-- NOTE: Currently, if assertions are switched on, on freezing a table, its 66-- density is calculate and, if it is below 33%, an internal error is 67-- raised (only if there are more than 1000 entries in the table). 68-- 69-- * check whether it would increase the performance significantly if we use 70-- a mixed finite map/array representation for soft tables (all attributes 71-- defined before the last `soften' could be held in the array, changing 72-- an attribute just means to update it in the FM; i.e., the FM entries take 73-- precedence over the array entries) 74-- 75 76module Attributes (-- attribute management 77 -- 78 Attrs, newAttrsOnlyPos, newAttrs, 79 Attributed(attrsOf), eqOfAttrsOf, posOfAttrsOf, 80 -- 81 -- attributes and attribute tables 82 -- 83 Attr(undef, isUndef, dontCare, isDontCare), 84 AttrTable, newAttrTable, getAttr, setAttr, updAttr, 85 copyAttr, freezeAttrTable, softenAttrTable, 86 StdAttr(..), getStdAttr, getStdAttrDft, isDontCareStdAttr, 87 isUndefStdAttr, setStdAttr, updStdAttr, 88 getGenAttr, setGenAttr, updGenAttr) 89where 90 91import Data.Array 92import Control.Exception (assert) 93import Position (Position, Pos(posOf), nopos, isNopos, dontCarePos, 94 isDontCarePos) 95import Errors (interr) 96import UNames (NameSupply, Name, 97 rootSupply, splitSupply, names) 98import Map (Map) 99import qualified Map as Map (fromList, toList, insert, 100 findWithDefault, empty) 101import Binary (Binary(..), putByte, getByte) 102 103 104-- attribute management data structures and operations 105-- --------------------------------------------------- 106 107-- abstract data structure used in the structure tree to represent the 108-- attribute identifier and the position (EXPORTED) 109-- 110data Attrs = OnlyPos Position -- only pos (for internal stuff only) 111 | Attrs Position Name -- pos and unique name 112 113-- get the position associated with an attribute identifier (EXPORTED) 114-- 115instance Pos Attrs where 116 posOf (OnlyPos pos ) = pos 117 posOf (Attrs pos _) = pos 118 119-- equality of attributes is used to define the equality of objects (EXPORTED) 120-- 121instance Eq Attrs where 122 (Attrs _ id1) == (Attrs _ id2) = id1 == id2 123 _ == _ = 124 interr "Attributes: Attempt to compare `OnlyPos' attributes!" 125 126-- attribute ordering is also lifted to objects (EXPORTED) 127-- 128instance Ord Attrs where 129 (Attrs _ id1) <= (Attrs _ id2) = id1 <= id2 130 _ <= _ = 131 interr "Attributes: Attempt to compare `OnlyPos' attributes!" 132 133-- a class for convenient access to the attributes of an attributed object 134-- (EXPORTED) 135-- 136class Attributed a where 137 attrsOf :: a -> Attrs 138 139-- equality induced by attribution (EXPORTED) 140-- 141eqOfAttrsOf :: Attributed a => a -> a -> Bool 142eqOfAttrsOf obj1 obj2 = (attrsOf obj1) == (attrsOf obj2) 143 144-- position induced by attribution (EXPORTED) 145-- 146posOfAttrsOf :: Attributed a => a -> Position 147posOfAttrsOf = posOf . attrsOf 148 149 150-- attribute identifier creation 151-- ----------------------------- 152 153-- Given only a source position, create a new attribute identifier (EXPORTED) 154-- 155newAttrsOnlyPos :: Position -> Attrs 156newAttrsOnlyPos pos = OnlyPos pos 157 158-- Given a source position and a unique name, create a new attribute 159-- identifier (EXPORTED) 160-- 161newAttrs :: Position -> Name -> Attrs 162newAttrs pos name = Attrs pos name 163 164 165-- attribute tables and operations on them 166-- --------------------------------------- 167 168-- the type class `Attr' determines which types may be used as attributes 169-- (EXPORTED) 170-- 171-- * such types have to provide values representing an undefined and a don't 172-- care state, together with two functions to test for these values 173-- 174-- * an attribute in an attribute table is initially set to `undef' (before 175-- some value is assigned to it) 176-- 177-- * an attribute with value `dontCare' participated in an already detected 178-- error, it's value may not be used for further computations in order to 179-- avoid error avalanches 180-- 181class Attr a where 182 undef :: a 183 isUndef :: a -> Bool 184 dontCare :: a 185 isDontCare :: a -> Bool 186 undef = interr "Attributes: Undefined `undef' method in `Attr' class!" 187 isUndef = interr "Attributes: Undefined `isUndef' method in `Attr' \ 188 \class!" 189 dontCare = interr "Attributes: Undefined `dontCare' method in `Attr' \ 190 \class!" 191 isDontCare = interr "Attributes: Undefined `isDontCare' method in `Attr' \ 192 \class!" 193 194-- attribute tables map attribute identifiers to attribute values 195-- (EXPORTED ABSTRACT) 196-- 197-- * the attributes within a table can be soft or frozen, the former may by be 198-- updated, but the latter can not be changed 199-- 200-- * the attributes in a frozen table are stored in an array for fast 201-- lookup; consequently, the attribute identifiers must be *dense* 202-- 203-- * the table description string is used to emit better error messages (for 204-- internal errors) 205-- 206data Attr a => 207 AttrTable a = -- for all attribute identifiers not contained in the 208 -- finite map the value is `undef' 209 -- 210 SoftTable (Map Name a) -- updated attr.s 211 String -- desc of the table 212 213 -- the array contains `undef' attributes for the undefined 214 -- attributes; for all attribute identifiers outside the 215 -- bounds, the value is also `undef'; 216 -- 217 | FrozenTable (Array Name a) -- attribute values 218 String -- desc of the table 219 220 221 222-- create an attribute table, where all attributes are `undef' (EXPORTED) 223-- 224-- the description string is used to identify the table in error messages 225-- (internal errors); a table is initially soft 226-- 227newAttrTable :: Attr a => String -> AttrTable a 228newAttrTable desc = SoftTable Map.empty desc 229 230-- get the value of an attribute from the given attribute table (EXPORTED) 231-- 232getAttr :: Attr a => AttrTable a -> Attrs -> a 233getAttr at (OnlyPos pos ) = onlyPosErr "getAttr" at pos 234getAttr at (Attrs _ aid) = 235 case at of 236 (SoftTable fm _) -> Map.findWithDefault undef aid fm 237 (FrozenTable arr _) -> let (lbd, ubd) = bounds arr 238 in 239 if (aid < lbd || aid > ubd) then undef else arr!aid 240 241-- set the value of an, up to now, undefined attribute from the given 242-- attribute table (EXPORTED) 243-- 244setAttr :: Attr a => AttrTable a -> Attrs -> a -> AttrTable a 245setAttr at (OnlyPos pos ) av = onlyPosErr "setAttr" at pos 246setAttr at (Attrs pos aid) av = 247 case at of 248 (SoftTable fm desc) -> assert (isUndef (Map.findWithDefault undef aid fm)) $ 249 SoftTable (Map.insert aid av fm) desc 250 (FrozenTable arr _) -> interr frozenErr 251 where 252 frozenErr = "Attributes.setAttr: Tried to write frozen attribute in\n" 253 ++ errLoc at pos 254 255-- update the value of an attribute from the given attribute table (EXPORTED) 256-- 257updAttr :: Attr a => AttrTable a -> Attrs -> a -> AttrTable a 258updAttr at (OnlyPos pos ) av = onlyPosErr "updAttr" at pos 259updAttr at (Attrs pos aid) av = 260 case at of 261 (SoftTable fm desc) -> SoftTable (Map.insert aid av fm) desc 262 (FrozenTable arr _) -> interr $ "Attributes.updAttr: Tried to\ 263 \ update frozen attribute in\n" 264 ++ errLoc at pos 265 266-- copy the value of an attribute to another one (EXPORTED) 267-- 268-- * undefined attributes are not copied, to avoid filling the table 269-- 270copyAttr :: Attr a => AttrTable a -> Attrs -> Attrs -> AttrTable a 271copyAttr at ats ats' 272 | isUndef av = assert (isUndef (getAttr at ats')) 273 at 274 | otherwise = updAttr at ats' av 275 where 276 av = getAttr at ats 277 278-- auxiliary functions for error messages 279-- 280onlyPosErr :: Attr a => String -> AttrTable a -> Position -> b 281onlyPosErr fctName at pos = 282 interr $ "Attributes." ++ fctName ++ ": No attribute identifier in\n" 283 ++ errLoc at pos 284-- 285errLoc :: Attr a => AttrTable a -> Position -> String 286errLoc at pos = " table `" ++ tableDesc at ++ "' for construct at\n\ 287 \ position " ++ show pos ++ "!" 288 where 289 tableDesc (SoftTable _ desc) = desc 290 tableDesc (FrozenTable _ desc) = desc 291 292-- freeze a soft table; afterwards no more changes are possible until the 293-- table is softened again (EXPORTED) 294-- 295freezeAttrTable :: Attr a => AttrTable a -> AttrTable a 296freezeAttrTable (SoftTable fm desc) = 297 let contents = Map.toList fm 298 keys = map fst contents 299 lbd = minimum keys 300 ubd = maximum keys 301 in 302 assert (length keys < 1000 || (length . range) (lbd, ubd) > 3 * length keys) 303 (FrozenTable (array (lbd, ubd) contents) desc) 304freezeAttrTable (FrozenTable arr desc) = 305 interr ("Attributes.freezeAttrTable: Attempt to freeze the already frozen\n\ 306 \ table `" ++ desc ++ "'!") 307 308-- soften a frozen table; afterwards changes are possible until the 309-- table is frozen again (EXPORTED) 310-- 311softenAttrTable :: Attr a => AttrTable a -> AttrTable a 312softenAttrTable (SoftTable fm desc) = 313 interr ("Attributes.softenAttrTable: Attempt to soften the already \ 314 \softened\n table `" ++ desc ++ "'!") 315softenAttrTable (FrozenTable arr desc) = 316 SoftTable (Map.fromList . assocs $ arr) desc 317 318 319-- standard attributes 320-- ------------------- 321 322-- standard attribute variants (EXPORTED) 323-- 324data StdAttr a = UndefStdAttr 325 | DontCareStdAttr 326 | JustStdAttr a 327 328instance Attr (StdAttr a) where 329 undef = UndefStdAttr 330 331 isUndef UndefStdAttr = True 332 isUndef _ = False 333 334 dontCare = DontCareStdAttr 335 336 isDontCare DontCareStdAttr = True 337 isDontCare _ = False 338 339-- get an attribute value from a standard attribute table (EXPORTED) 340-- 341-- * if the attribute can be "don't care", this should be checked before 342-- calling this function (using `isDontCareStdAttr') 343-- 344getStdAttr :: AttrTable (StdAttr a) -> Attrs -> a 345getStdAttr atab at = getStdAttrDft atab at err 346 where 347 err = interr $ "Attributes.getStdAttr: Don't care in\n" 348 ++ errLoc atab (posOf at) 349 350-- get an attribute value from a standard attribute table, where a default is 351-- substituted if the table is don't care (EXPORTED) 352-- 353getStdAttrDft :: AttrTable (StdAttr a) -> Attrs -> a -> a 354getStdAttrDft atab at dft = 355 case getAttr atab at of 356 DontCareStdAttr -> dft 357 JustStdAttr av -> av 358 UndefStdAttr -> interr $ "Attributes.getStdAttrDft: Undefined in\n" 359 ++ errLoc atab (posOf at) 360 361-- check if the attribue value is marked as "don't care" (EXPORTED) 362-- 363isDontCareStdAttr :: AttrTable (StdAttr a) -> Attrs -> Bool 364isDontCareStdAttr atab at = isDontCare (getAttr atab at) 365 366-- check if the attribue value is still undefined (EXPORTED) 367-- 368-- * we also regard "don't care" attributes as undefined 369-- 370isUndefStdAttr :: AttrTable (StdAttr a) -> Attrs -> Bool 371isUndefStdAttr atab at = isUndef (getAttr atab at) 372 373-- set an attribute value in a standard attribute table (EXPORTED) 374-- 375setStdAttr :: AttrTable (StdAttr a) -> Attrs -> a -> AttrTable (StdAttr a) 376setStdAttr atab at av = setAttr atab at (JustStdAttr av) 377 378-- update an attribute value in a standard attribute table (EXPORTED) 379-- 380updStdAttr :: AttrTable (StdAttr a) -> Attrs -> a -> AttrTable (StdAttr a) 381updStdAttr atab at av = updAttr atab at (JustStdAttr av) 382 383 384-- generic attribute table access (EXPORTED) 385-- ------------------------------ 386 387getGenAttr :: (Attr a, Attributed obj) => AttrTable a -> obj -> a 388getGenAttr atab at = getAttr atab (attrsOf at) 389 390setGenAttr :: (Attr a, Attributed obj) 391 => AttrTable a -> obj -> a -> AttrTable a 392setGenAttr atab at av = setAttr atab (attrsOf at) av 393 394updGenAttr :: (Attr a, Attributed obj) 395 => AttrTable a -> obj -> a -> AttrTable a 396updGenAttr atab at av = updAttr atab (attrsOf at) av 397 398 399{-! for Attrs derive : GhcBinary !-} 400{-! for AttrTable derive : GhcBinary !-} 401{-* Generated by DrIFT : Look, but Don't Touch. *-} 402instance Binary Attrs where 403 put_ bh (OnlyPos aa) = do 404 putByte bh 0 405 put_ bh aa 406 put_ bh (Attrs ab ac) = do 407 putByte bh 1 408 put_ bh ab 409 put_ bh ac 410 get bh = do 411 h <- getByte bh 412 case h of 413 0 -> do 414 aa <- get bh 415 return (OnlyPos aa) 416 1 -> do 417 ab <- get bh 418 ac <- get bh 419 return (Attrs ab ac) 420 421instance (Binary a, Attr a) => Binary (AttrTable a) where 422 put_ bh (SoftTable aa ab) = do 423 putByte bh 0 424 put_ bh aa 425 put_ bh ab 426 put_ bh (FrozenTable ac ad) = do 427 putByte bh 1 428 put_ bh ac 429 put_ bh ad 430 get bh = do 431 h <- getByte bh 432 case h of 433 0 -> do 434 aa <- get bh 435 ab <- get bh 436 return (SoftTable aa ab) 437 1 -> do 438 ac <- get bh 439 ad <- get bh 440 return (FrozenTable ac ad) 441