packages feed

SableCC2Hs-0.0.0.2: src/SableCC/AstDefinition.hs

----------------------------------------------------------------------------
-- |
-- Module      :  SableCC.AstDefinition
-- Copyright   :  (c) Fontaine 2011
-- License     :  BSD3
--
-- Maintainer  :  fontaine@cs.uni-duesseldorf.de
-- Stability   :  experimental
-- Portability :  GHC-only
--
--
-- The data type AstDefinition stores the structure of an Abstract Syntax Tree,
-- as it is modelled by the SableCC parser generator.
-- It also stores the SabelCC generated reduce actions for AST generation.
--
-----------------------------------------------------------------------------

{-
prototype of a Haskell backend for LR-parser-tables generated by SableCC
-}
{-# LANGUAGE GeneralizedNewtypeDeriving, RecordWildCards #-}
module SableCC.AstDefinition
where
import qualified SableCC.XML.ParserDefinitionRaw as Raw
import SableCC.XML.ParserDefinitionRaw hiding (Action)
import SableCC.ParserTypes hiding (Action)

import Data.Array as Array
import Data.List as List
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe

data AstDefinition = AstDefinition {
   productions :: [Prod]
  ,reductionTable :: Array ReductionID Action
  }

data Action = Action {
   actionRule :: Rule
  ,actionExpression :: ActionExpression
  }

data ActionExpression
  = Var String
  | EmptyList
  | SingletonList ActionExpression
  | AppendNode ActionExpression ActionExpression
  | AppendList ActionExpression ActionExpression
  | NewNode Prod Alt [ActionExpression]
  | FromNode ActionExpression
  | FromList ActionExpression
  | NodeResult ActionExpression
  | ListResult ActionExpression
  | ResultNothing
  deriving (Show)

-- | Translate the raw parser definition that is read from the XML file
-- to more highlevel representation.
-- This function also compiles the imperative reduce actions to a functional style.
makeAstDefinition :: Raw.Parser -> AstDefinition
makeAstDefinition rawParser = AstDefinition {..}
  where
    productions = Raw.parser_prods rawParser
    reductionTable = mkArray ReductionID $ map makeAction $ Raw.parser_rules rawParser

    mkArray :: Ix i => (Int -> i) -> [e] -> Array i e
    mkArray iType elems = listArray (iType 0, iType $ length elems -1 ) elems

    makeAction :: Rule -> Action
    makeAction rule = Action {..}
      where
        actionRule = rule
        actionExpression = runInterpreter [] $ rule_actions rule

    enameTable :: Map String (Prod,Alt)
    enameTable = Map.fromList $ do
         prod <- parser_prods rawParser
         alt <- prod_alt prod
         return (alt_ename alt,(prod,alt))

    runInterpreter :: [(String, ActionExpression)] -> [Raw.Action] -> ActionExpression
    runInterpreter env (h:r@(_:_)) = runInterpreter ((innerAction env h): env) r
    runInterpreter env [ret] = returnAction env ret

    innerAction :: [(String, ActionExpression)] -> Raw.Action -> (String, ActionExpression)
    innerAction env action = case action of
      Pop (ActionArgs {..}) -> (action_result, Var action_result)
      MakeList (ActionArgs {..}) -> (action_result, EmptyList)
      FetchList (ActionArgs {..}) | action_index == 0 -> (action_result, FromList $ valueOf action_arg_from)
      FetchList {} -> error "interpretAction : FETCHLIST expection Index == 0"
      FetchNode (ActionArgs {..}) | action_index == 0-> (action_result, FromNode $ valueOf action_arg_from)
      FetchNode (ActionArgs {..}) -> error "interpretAction :FETCHNODE expection Index == 0"
      AddList (ActionArgs {..}) -> (action_tolist, smartAppendList (valueOf action_tolist) (valueOf action_fromlist))
      AddNode (ActionArgs {..}) -> (action_tolist, smartAppendNode (valueOf action_tolist) (valueOf action_node))
      MakeNode (ActionArgs {..}) -> (action_result, NewNode prod alt $ makeChildren action_args)
        where
          (prod,alt) = case Map.lookup action_etype enameTable of
             Nothing -> error $ "cannot find " ++ action_etype ++ " in enameTable"
             Just res -> res

      other                      -> error $ "innerAction " ++ show other
      where
        valueOf = valueOfEnv env
        makeChildren = map toArg
          where
            toArg a = case a of
              ActionArgNull -> ResultNothing
              ActionArgList s -> valueOf s
              ActionArg s -> valueOf s

    smartAppendList :: ActionExpression -> ActionExpression -> ActionExpression
    smartAppendList EmptyList l = l
    smartAppendList a b = AppendList a b

    smartAppendNode :: ActionExpression -> ActionExpression -> ActionExpression
    smartAppendNode EmptyList l = SingletonList l
    smartAppendNode a b = AppendNode a b

    returnAction :: [(String, ActionExpression)] -> Raw.Action -> ActionExpression
    returnAction env action = case action of
      ReturnNode (ActionArgs {..})-> NodeResult $ valueOfEnv env action_node
      ReturnList (ActionArgs {..})-> ListResult $ valueOfEnv env action_list
      other                      -> error $ "returnAction " ++ show other

    valueOfEnv :: [(String, ActionExpression)] -> String -> ActionExpression
    valueOfEnv env ident = case List.lookup ident env of
          Nothing -> error $ "interpretAction, variable not in scope : " ++ ident
          Just a -> a