0

I have an AST representing a haskell program and a bitvector/bool list representing the presence of strictness annotations on Patterns in order.For example, 1000 represents a program with 4 Pats where the first one is a BangPat. Is there any way that I can turn on and off the annotations in the AST according to the list?

-- EDIT: further clarify what I want editBang to do

Based on user5042's answer: Simple.hs :=

main = do
  case args of
    [] -> error "blah"
    [!x] -> putStrLn "one"
    (!x : xs) -> putStrLn "many"

And I want editBang "Simple.hs" [True, True, True, True] to produce

main = do
  case args of
    [] -> error "blah"
    [!x] -> putStrLn "one"
    (!(!x : !xs)) -> putStrLn "many"

Given that above are the only 4 places that ! can appear

rem
  • 893
  • 4
  • 18
  • Answer updated with working example. – ErikR Aug 02 '15 at 22:32
  • Note that `!xs` is not allowed. You've got your work cut out for you since bangs are allowed in many locations that you are not considering, e.g. `![]` and `![!x]`, but they are not allowed at top-level definitions, e.g. `!main = ...` is not allowed even though `main` is a pattern. Next time be more explicit about what you want. – ErikR Aug 03 '15 at 03:19

1 Answers1

3

As a first step, here's how to use transformBi:

import Data.Data
import Control.Monad
import Data.Generics.Uniplate.Data
import Language.Haskell.Exts
import Text.Show.Pretty (ppShow)

changeNames x = transformBi change x
  where change (Ident str) = Ident ("foo_" ++ str)
        change x           = x

test2 = do
  content <- readFile "Simple.hs"
  case parseModule content of
    ParseFailed _ e -> error e
    ParseOk a       -> do
      let a' = changeNames a
      putStrLn $ ppShow a'

The changeNames function finds all occurrences of a Ident s and replaces it with Ident ("foo_"++s) in the source tree.

There is a monadic version called transformBiM which allows the replacement function to be monadic which would allow you to consume elements from your list of Bools as you found bang patterns.

Here is a complete working example:

import Control.Monad
import Data.Generics.Uniplate.Data
import Language.Haskell.Exts
import Text.Show.Pretty (ppShow)
import Control.Monad.State.Strict

parseHaskell path = do
  content <- readFile path
  let mode = ParseMode path Haskell2010 [EnableExtension BangPatterns] False False Nothing
  case parseModuleWithMode mode content of
    ParseFailed _ e -> error $ path ++ ": " ++ e
    ParseOk a       -> return a

changeBangs bools x = runState (transformBiM go x) bools
  where go pp@(PBangPat p) = do
           (b:bs) <- get
           put bs
           if b
             then return p
             else return pp
        go x = return x

test = do
  a <- parseHaskell "Simple.hs"
  putStrLn $ unlines . map ("before: " ++) . lines $ ppShow a
  let a' = changeBangs [True,False] a
  putStrLn $ unlines . map ("after : " ++) . lines $ ppShow a'

You might also look into using rewriteBiM.

The file Simple.hs:

main = do
  case args of
    [] -> error "blah"
    [!x] -> putStrLn "one"
    (!x : xs) -> putStrLn "many"
ErikR
  • 51,541
  • 9
  • 73
  • 124
  • Thank you very much, I wasn't expecting a full answer like this. Will accept as soon as I get it working. – rem Aug 02 '15 at 23:43