packages feed

asil-1.2: src/SymbolTables.ag

--
-- Extract static symbol tables from the ABC code
--
-- Of interest are:
-- String/Int/Word32/Double constant pools
-- Name/Nameset constant pool
-- Namespace constant pool
-- Method-info
-- Class-info

MODULE {SymbolTables} {symInfoAbc, symInfoSwf} {}

INCLUDE "ByteCodeAst.ag"

imports
{
import Data.ByteString.Lazy(ByteString,unpack)
import ByteCode
import Data.Monoid
import Data.Word
import qualified Data.Set as Set
import Data.Set(Set)
import qualified Data.Map as Map
import Data.Map(Map)
import Codec.Binary.UTF8.String
import Env
import ProgInfo
}


WRAPPER SwfFile
WRAPPER AbcFile

{
-- | Extracts symbol tables from an Abc module
symInfoAbc :: AbcFile -> SymbolTables
symInfoAbc abc = tables_Syn_AbcFile syn where
  inh = Inh_AbcFile {}
  sem = sem_AbcFile abc
  syn = wrap_AbcFile sem inh

-- | Extracts all symbol tables from a flash file
symInfoSwf :: SwfFile -> [SymbolTables]
symInfoSwf swf = allTables_Syn_SwfFile syn where
  inh = Inh_SwfFile {}
  sem = sem_SwfFile swf
  syn = wrap_SwfFile sem inh
}


--
-- Collect them together
--

ATTR AbcFile [ | | tables : SymbolTables ]
SEM AbcFile | File
  loc.tables = SymbolTables @loc.intPool @loc.uintPool @loc.doublePool @loc.stringPool @loc.namePool
                  @loc.spacesPool @loc.setsPool @methods.gathSigs @loc.classInfos

ATTR OnlySwfAbc [ | | allTables USE {++} {[]} : {[SymbolTables]} ]
SEM AbcFile | File  loc.allTables = [@loc.tables]

--
-- String/Int/Word32/Double pool
--

ATTR PoolInfo [ | | gathStringPool : StringPool  gathIntPool : IntPool  gathUIntPool : UIntPool  gathDoublePool : DoublePool ]
SEM PoolInfo | Info
  lhs.gathStringPool = listEnv $ zip [1..] @strings.values
  lhs.gathIntPool    = listEnv $ zip [1..] @integers.values
  lhs.gathUIntPool   = listEnv $ zip [1..] @uintegers.values
  lhs.gathDoublePool = listEnv $ zip [1..] @doubles.values

ATTR  PoolStrings [ | | values USE {++} {[]} : {[String]} ]
SEM PoolStrings | Cons  +values = ((decode $ unpack @hd) :)

ATTR  PoolInts [ | | values USE {++} {[]} : {[Word32]} ]
SEM PoolInts | Cons  +values = (@hd :)

ATTR  PoolUInts [ | | values USE {++} {[]} : {[Word32]} ]
SEM PoolUInts | Cons  +values = (@hd :)

ATTR  PoolDoubles [ | | values USE {++} {[]} : {[Double]} ]
SEM PoolDoubles | Cons  +values = (@hd :)

SEM AbcFile | File
  loc.intPool    = singleEnv 0 0 `mappend` @constantPool.gathIntPool
  loc.uintPool   = singleEnv 0 0 `mappend` @constantPool.gathUIntPool
  loc.doublePool = singleEnv 0 0 `mappend` @constantPool.gathDoublePool
  loc.stringPool = singleEnv 0 "" `mappend` @constantPool.gathStringPool

--
-- Name pool
--

ATTR PoolInfo [ | | gathNamePool : NamePool ]
SEM PoolInfo | Info
  lhs.gathNamePool = listEnv $ zip [1..] @multinames.names

ATTR  MultinameInfos [ | | names USE {++} {[]} : {[Name]} ]
SEM MultinameInfos | Cons +names = (@hd.name :)

ATTR MultinameInfo [ | | name : Name ]
SEM MultinameInfo
  | QName QNameA            lhs.name = Name (QualNs $ Ref @namespace) (Just $ Ref @name)
  | RTQName RTQNameA        lhs.name = Name QualLate (Just $ Ref @name)
  | RTQNameL RTQNameLA      lhs.name = Name QualLate Nothing
  | Multiname MultinameA    lhs.name = Name (QualNss $ Ref @set) (Just $ Ref @name)
  | MultinameL MultinameLA  lhs.name = Name (QualNss $ Ref @set) Nothing
  | Generic                 lhs.name = Name QualOther Nothing

SEM AbcFile | File
  loc.namePool = singleEnv 0 (Name (QualNs $ Ref 0) (Just $ Ref 0)) `mappend` @constantPool.gathNamePool

--
-- Namesets Pool
--

ATTR PoolInfo [ | | gathNamesetsPool : NamesetsPool ]
SEM PoolInfo | Info
  lhs.gathNamesetsPool = listEnv $ zip [1..] @namesets.sets

ATTR  SetInfos [ | | sets USE {++} {[]} : {[Nameset]} ]
SEM SetInfos | Cons +sets = (@hd.set :)

ATTR SetInfo [ | | set : Nameset ]
SEM SetInfo | Info  lhs.set = Nameset (map Ref @names.names)

ATTR NamespaceNames [ | | names : SELF ]

SEM AbcFile | File
  loc.setsPool = singleEnv 0 (Nameset []) `mappend` @constantPool.gathNamesetsPool

--
-- Namespace Pool
--

ATTR PoolInfo [ | | gathNamespacePool : NamespacePool ]
SEM PoolInfo | Info
  lhs.gathNamespacePool = listEnv $ zip [1..] @namespaces.spaces

ATTR  NamespaceInfos [ | | spaces USE {++} {[]} : {[Namespace]} ]
SEM NamespaceInfos | Cons +spaces = (@hd.name :)

ATTR NamespaceInfo [ | | name : Namespace ]
SEM NamespaceInfo | Info  lhs.name = Namespace $ Ref @name

SEM AbcFile | File
  loc.spacesPool = singleEnv 0 (Namespace $ Ref 0) `mappend` @constantPool.gathNamespacePool


--
-- MethodInfo
--

ATTR MethodInfos [ sigIndex : Word32 | | gathSigs : Sigs ]
SEM AbcFile | File
  methods.sigIndex = 0

SEM MethodInfos
  | Cons  tl.sigIndex = 1 + @lhs.sigIndex
          lhs.gathSigs = singleEnv @lhs.sigIndex @hd.gathSig `mappend` @tl.gathSigs
  | Nil   lhs.gathSigs = mempty

ATTR MethodInfo [ | | gathSig : Sig ]
SEM MethodInfo | Info
  loc.mbNamesL  = map (Just . Ref) @names.names
  loc.paramSigs = zipWith SigParam (@loc.mbNamesL ++ repeat Nothing) (map Ref @params.types)
  lhs.gathSig   = Sig (if @name /= 0 then Just $ Ref @name else Nothing) (Ref @return) @loc.paramSigs

ATTR ParamNames [ | | names : SELF ]
ATTR ParamTypes [ | | types : SELF ]


--
-- ClassInfo
--

SEM AbcFile | File
  loc.classInfos = mapEnv (\n c -> c { clStaTraits = Map.findWithDefault [] n @classes.gathTraits }) @instances.gathInsts

ATTR InstanceInfos ClassInfos [ index : Word32 | | ]
SEM AbcFile | File
  instances.index = 0
  classes.index   = 0

SEM InstanceInfos | Cons  tl.index = 1 + @lhs.index
SEM ClassInfos    | Cons  tl.index = 1 + @lhs.index

-- collect instance infos
ATTR InstanceInfos [ | | gathInsts : ClassDescrs ]
SEM InstanceInfos
  | Nil  lhs.gathInsts = mempty
  | Cons lhs.gathInsts = singleEnv @lhs.index @hd.classInfo `mappend` @tl.gathInsts

ATTR InstanceInfo [ | | classInfo : ClassDescr ]
SEM InstanceInfo | Info
  lhs.classInfo = ClassDescr (Ref @name) (if @super /= 0 then Just $ Ref @super else Nothing) (map Ref @interfaces.itfs) @traits.gathInfos []

ATTR Interfaces [ | | itfs : SELF ]

-- collect class infos
ATTR ClassInfos [ | | gathTraits : {Map Word32 TraitDescrs} ]

SEM ClassInfos
  | Nil  lhs.gathTraits = mempty
  | Cons lhs.gathTraits = Map.insert @lhs.index @hd.gathInfos @tl.gathTraits

-- collect traits
ATTR ClassInfo Traits [ | | gathInfos : TraitDescrs ]

SEM Traits
  | Nil   lhs.gathInfos = []
  | Cons  lhs.gathInfos = @hd.traitInfo : @tl.gathInfos

ATTR Trait [ | | traitInfo : TraitDescr ]
SEM Trait | Trait
  lhs.traitInfo = TraitDescr (Ref @name) @data.body

ATTR TraitData [ | | body : TraitBody ]
SEM TraitData
  | Slot Const                      lhs.body = TraitField $ Ref @tp
  | Method Getter Setter Function   lhs.body = TraitMethod $ Ref @method
  | Class                           lhs.body = TraitClass $ Ref @class