packages feed

haskell-awk-1.1: src/System/Console/Hawk.hs

--   Copyright 2013 Mario Pastorelli (pastorelli.mario@gmail.com) Samuel Gélineau (gelisam@gmail.com)
--
--   Licensed under the Apache License, Version 2.0 (the "License");
--   you may not use this file except in compliance with the License.
--   You may obtain a copy of the License at
--
--       http://www.apache.org/licenses/LICENSE-2.0
--
--   Unless required by applicable law or agreed to in writing, software
--   distributed under the License is distributed on an "AS IS" BASIS,
--   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--   See the License for the specific language governing permissions and
--   limitations under the License.

-- | Hawk as seen from the outside world: parsing command-line arguments,
--   evaluating user expressions.
module System.Console.Hawk
  ( processArgs
  ) where


import Language.Haskell.Interpreter
import Text.Printf (printf)

import Control.Monad.Trans.Uncertain
import System.Console.Hawk.Args
import System.Console.Hawk.Args.Spec
import System.Console.Hawk.Help
import System.Console.Hawk.Interpreter
import System.Console.Hawk.Runtime.Base
import System.Console.Hawk.Version


-- | Same as if the given arguments were passed to Hawk on the command-line.
processArgs :: [String] -> IO ()
processArgs args = do
    r <- runWarningsIO $ parseArgs args
    case r of
      Left err -> failHelp err
      Right spec -> processSpec spec

-- | A variant of `processArgs` which accepts a structured specification
--   instead of a sequence of strings.
processSpec :: HawkSpec -> IO ()
processSpec Help          = help
processSpec Version       = putStrLn versionString
processSpec (Eval  e   o) = applyExpr (wrapExpr "const" e) noInput o
processSpec (Apply e i o) = applyExpr e                    i       o
processSpec (Map   e i o) = applyExpr (wrapExpr "map"   e) i       o

wrapExpr :: String -> ExprSpec -> ExprSpec
wrapExpr f e = e'
  where
    u = userExpression e
    u' = printf "%s (%s)" (prel f) u
    e' = e { userExpression = u' }

applyExpr :: ExprSpec -> InputSpec -> OutputSpec -> IO ()
applyExpr e i o = do
    let contextDir = userContextDirectory e
    let expr = userExpression e
    
    processRuntime <- runUncertainIO $ runHawkInterpreter $ do
      applyContext contextDir
      interpret' $ processTable' $ tableExpr expr
    runHawkIO $ processRuntime hawkRuntime
  where
    interpret' expr = do
      interpret expr (as :: HawkRuntime -> HawkIO ())
    
    hawkRuntime = HawkRuntime i o
    
    processTable' :: String -> String
    processTable' = printf "(%s) (%s) (%s)" (prel "flip")
                                            (runtime "processTable")
    
    -- turn the user expr into an expression manipulating [[B.ByteString]]
    tableExpr :: String -> String
    tableExpr = (`compose` fromTable)
      where
        fromTable = case inputFormat i of
            RawStream            -> head' `compose` head'
            Records _ RawRecord  -> map' head'
            Records _ (Fields _) -> prel "id"
    
    compose :: String -> String -> String
    compose f g = printf "(%s) %s (%s)" f (prel ".") g
    
    head' :: String
    head' = prel "head"
    
    map' :: String -> String
    map' = printf "(%s) (%s)" (prel "map")

-- we cannot use any unqualified symbols in the user expression,
-- because we don't know which modules the user prelude will import.
qualify :: String -> String -> String
qualify moduleName = printf "%s.%s" moduleName

prel, runtime :: String -> String
prel = qualify "Prelude"
runtime = qualify "System.Console.Hawk.Runtime"