@@ -1,43 +1,37 @@
1−{-# LANGUAGE MagicHash #-}
2{-# LANGUAGE BangPatterns #-}
1{-# LANGUAGE BangPatterns #-}
3−{-# LANGUAGE RecordWildCards #-}
4−{-# LANGUAGE FlexibleContexts #-}
5{-# LANGUAGE NoMonomorphismRestriction #-}
2{-# LANGUAGE NoMonomorphismRestriction #-}
6−{-# LANGUAGE NamedFieldPuns #-}
7{-# OPTIONS_GHC -funbox-strict-fields #-}
3{-# OPTIONS_GHC -funbox-strict-fields #-}
8{- Evaluates the paramaterized terminfo string capability with the given parameters.
4{- Evaluates the paramaterized terminfo string capability with the given parameters.
10 - todo: This can be greatly simplified.
6 - todo: This can be greatly simplified.
12−module Data.Terminfo.Eval ( cap_expression_required_bytes
8+module Data.Terminfo.Eval (write_cap_expr)
13− , serialize_cap_expression
17−import Data.ByteString.Internal ( memcpy )
11+import Blaze.ByteString.Builder.Word
12+import Blaze.ByteString.Builder
18import Data.Terminfo.Parse
13import Data.Terminfo.Parse
20import Control.Monad.Identity
15import Control.Monad.Identity
21import Control.Monad.State.Strict
16import Control.Monad.State.Strict
17+import Control.Monad.Writer
23−import Data.Bits ( (.|.), (.&.), xor )
19+import Data.Bits ((.|.), (.&.), xor)
24import Data.List
20import Data.List
26−import GHC.Prim
23+import qualified Data.Vector.Unboxed as Vector
29-- | capability evaluator state
25-- | capability evaluator state
30data EvalState = EvalState
26data EvalState = EvalState
31− { eval_stack :: ![ CapParam ]
27+ { eval_stack :: ![CapParam]
32 , eval_expression :: !CapExpression
28 , eval_expression :: !CapExpression
33− , eval_params :: ![ CapParam ]
29+ , eval_params :: ![CapParam]
36−type EvalT m a = StateT EvalState m a
32+type Eval a = StateT EvalState (Writer Write) a
37−type Eval a = EvalT Identity a
39−{-# SPECIALIZE pop :: EvalT IO CapParam #-}
40−pop :: Monad m => EvalT m CapParam
34+pop :: Eval CapParam
43 let v : stack' = eval_stack s
37 let v : stack' = eval_stack s
@@ -45,14 +39,12 @@ pop = do
48−{-# SPECIALIZE read_param :: Word -> EvalT IO CapParam #-}
42+read_param :: Word -> Eval CapParam
49−read_param :: Monad m => Word -> EvalT m CapParam
50read_param pn = do
43read_param pn = do
51 !params <- get >>= return . eval_params
44 !params <- get >>= return . eval_params
52 return $! genericIndex params pn
45 return $! genericIndex params pn
54−{-# SPECIALIZE push :: CapParam -> EvalT IO () #-}
47+push :: CapParam -> Eval ()
55−push :: Monad m => CapParam -> EvalT m ()
56push !v = do
48push !v = do
58 let s' = s { eval_stack = v : eval_stack s }
50 let s' = s { eval_stack = v : eval_stack s }
@@ -64,184 +56,77 @@ apply_param_ops cap params = foldl apply_param_op params (param_ops cap)
64apply_param_op :: [CapParam] -> ParamOp -> [CapParam]
56apply_param_op :: [CapParam] -> ParamOp -> [CapParam]
65apply_param_op params IncFirstTwo = map (+ 1) params
57apply_param_op params IncFirstTwo = map (+ 1) params
67−cap_expression_required_bytes :: CapExpression -> [CapParam] -> Int
59+write_cap_expr :: CapExpression -> [CapParam] -> Write
68−cap_expression_required_bytes cap params =
60+write_cap_expr cap params =
69 let params' = apply_param_ops cap params
61 let params' = apply_param_ops cap params
70 s_0 = EvalState [] cap params'
62 s_0 = EvalState [] cap params'
71− in fromEnum $! fst $! runIdentity $! runStateT ( cap_ops_required_bytes $! cap_ops cap ) s_0
63+ in snd $ runWriter (runStateT (write_cap_ops (cap_ops cap)) s_0)
73−cap_ops_required_bytes :: CapOps -> Eval Word
65+write_cap_ops :: CapOps -> Eval ()
74−cap_ops_required_bytes ops = do
66+write_cap_ops ops = mapM_ write_cap_op ops
75− counts <- mapM cap_op_required_bytes ops
78−cap_op_required_bytes :: CapOp -> Eval Word
68+write_cap_op :: CapOp -> Eval ()
79−cap_op_required_bytes (Bytes _ _ c) = return $ toEnum c
69+write_cap_op (Bytes !offset !count) = do
80−cap_op_required_bytes DecOut = do
82− return $ toEnum $ length $ show p
83−cap_op_required_bytes CharOut = do
86−cap_op_required_bytes (PushParam pn) = do
87− read_param pn >>= push
89−cap_op_required_bytes (PushValue v) = do
92−cap_op_required_bytes (Conditional expr parts) = do
93− c_expr <- cap_ops_required_bytes expr
94− c_parts <- cond_parts_required_bytes parts
95− return $ c_expr + c_parts
97− cond_parts_required_bytes [] = return 0
98− cond_parts_required_bytes ( (true_ops, false_ops) : false_parts ) = do
100− -- Usually the %? expr part pushes a value onto the stack, and %t pops it from the
101− -- stack, testing if it is nonzero (true). If it is zero (false), control
102− -- passes to the %e (else) part.
104− c_total <- if v /= 0
105− then cap_ops_required_bytes true_ops
107− c_false <- cap_ops_required_bytes false_ops
108− c_remain <- cond_parts_required_bytes false_parts
109− return $ c_false + c_remain
111−cap_op_required_bytes BitwiseOr = do
116−cap_op_required_bytes BitwiseAnd = do
121−cap_op_required_bytes BitwiseXOr = do
124− push $ v_0 `xor` v_1
126−cap_op_required_bytes ArithPlus = do
131−cap_op_required_bytes ArithMinus = do
136−cap_op_required_bytes CompareEq = do
139− push $ if v_0 == v_1 then 1 else 0
141−cap_op_required_bytes CompareLt = do
144− push $ if v_0 < v_1 then 1 else 0
146−cap_op_required_bytes CompareGt = do
149− push $ if v_0 > v_1 then 1 else 0
152−serialize_cap_expression :: CapExpression -> [CapParam] -> OutputBuffer -> IO OutputBuffer
153−serialize_cap_expression cap params out_ptr = do
154− let params' = apply_param_ops cap params
155− s_0 = EvalState [] cap params'
156− (!out_ptr', _) <- runStateT ( serialize_cap_ops out_ptr (cap_ops cap) ) s_0
159−serialize_cap_ops :: OutputBuffer -> CapOps -> EvalT IO OutputBuffer
160−serialize_cap_ops out_ptr ops = foldM serialize_cap_op out_ptr ops
162−serialize_cap_op :: OutputBuffer -> CapOp -> EvalT IO OutputBuffer
163−serialize_cap_op !out_ptr (Bytes !offset !byte_count !next_offset) = do
164 !cap <- get >>= return . eval_expression
70 !cap <- get >>= return . eval_expression
165− let ( !start_ptr, _ ) = cap_bytes cap
71+ let bytes = Vector.take count $ Vector.drop offset (cap_bytes cap)
166− !src_ptr = start_ptr `plusPtr` offset
72+ Vector.forM_ bytes $ tell.writeWord8
167− !out_ptr' = out_ptr `plusPtr` next_offset
73+write_cap_op DecOut = do
168− liftIO $! memcpy out_ptr src_ptr (fromIntegral byte_count)
170−serialize_cap_op out_ptr DecOut = do
172 let out_str = show p
75 let out_str = show p
173− out_bytes = string_to_bytes out_str
76+ forM_ out_str $ tell.writeWord8.toEnum.fromEnum
174− serialize_bytes out_bytes out_ptr
77+write_cap_op CharOut = do
175−serialize_cap_op out_ptr CharOut = do
78+ pop >>= tell.writeWord8.toEnum.fromEnum
177− -- XXX Truncate the character value to a single byte?
178− let !out_byte = W8# (and# p 0xFF##)
179− !out_ptr' = out_ptr `plusPtr` 1
180− liftIO $ poke out_ptr out_byte
182−serialize_cap_op out_ptr (PushParam pn) = do
79+write_cap_op (PushParam pn) = do
183 read_param pn >>= push
80 read_param pn >>= push
185−serialize_cap_op out_ptr (PushValue v) = do
81+write_cap_op (PushValue v) = do
188−serialize_cap_op out_ptr (Conditional expr parts) = do
83+write_cap_op (Conditional expr parts) = do
189− out_ptr' <- serialize_cap_ops out_ptr expr
84+ write_cap_ops expr
190− out_ptr'' <- serialize_cond_parts out_ptr' parts
85+ write_contitional_parts parts
193− serialize_cond_parts ptr [] = return ptr
87+ write_contitional_parts [] = return ()
194− serialize_cond_parts ptr ( (true_ops, false_ops) : false_parts ) = do
88+ write_contitional_parts ((true_ops, false_ops) : false_parts) = do
195 -- (man 5 terminfo)
89 -- (man 5 terminfo)
196 -- Usually the %? expr part pushes a value onto the stack, and %t pops it from the
90 -- Usually the %? expr part pushes a value onto the stack, and %t pops it from the
197 -- stack, testing if it is nonzero (true). If it is zero (false), control
91 -- stack, testing if it is nonzero (true). If it is zero (false), control
198 -- passes to the %e (else) part.
92 -- passes to the %e (else) part.
200− ptr'' <- if v /= 0
94+ if v /= 0
201− then serialize_cap_ops ptr true_ops
95+ then write_cap_ops true_ops
203− ptr' <- serialize_cap_ops ptr false_ops
97+ write_cap_ops false_ops
204− serialize_cond_parts ptr' false_parts
98+ write_contitional_parts false_parts
206−
100+write_cap_op BitwiseOr = do
207−serialize_cap_op out_ptr BitwiseOr = do
208 v_0 <- pop
101 v_0 <- pop
209 v_1 <- pop
102 v_1 <- pop
210 push $ v_0 .|. v_1
103 push $ v_0 .|. v_1
212−serialize_cap_op out_ptr BitwiseAnd = do
104+write_cap_op BitwiseAnd = do
213 v_0 <- pop
105 v_0 <- pop
214 v_1 <- pop
106 v_1 <- pop
215 push $ v_0 .&. v_1
107 push $ v_0 .&. v_1
217−serialize_cap_op out_ptr BitwiseXOr = do
108+write_cap_op BitwiseXOr = do
218 v_1 <- pop
109 v_1 <- pop
219 v_0 <- pop
110 v_0 <- pop
220 push $ v_0 `xor` v_1
111 push $ v_0 `xor` v_1
221− return out_ptr
112+write_cap_op ArithPlus = do
222−serialize_cap_op out_ptr ArithPlus = do
223 v_1 <- pop
113 v_1 <- pop
224 v_0 <- pop
114 v_0 <- pop
225 push $ v_0 + v_1
115 push $ v_0 + v_1
227−serialize_cap_op out_ptr ArithMinus = do
116+write_cap_op ArithMinus = do
228 v_1 <- pop
117 v_1 <- pop
229 v_0 <- pop
118 v_0 <- pop
230 push $ v_0 - v_1
119 push $ v_0 - v_1
231− return out_ptr
120+write_cap_op CompareEq = do
232−serialize_cap_op out_ptr CompareEq = do
233 v_1 <- pop
121 v_1 <- pop
234 v_0 <- pop
122 v_0 <- pop
235 push $ if v_0 == v_1 then 1 else 0
123 push $ if v_0 == v_1 then 1 else 0
236− return out_ptr
124+write_cap_op CompareLt = do
237−serialize_cap_op out_ptr CompareLt = do
238 v_1 <- pop
125 v_1 <- pop
239 v_0 <- pop
126 v_0 <- pop
240 push $ if v_0 < v_1 then 1 else 0
127 push $ if v_0 < v_1 then 1 else 0
241− return out_ptr
128+write_cap_op CompareGt = do
242−serialize_cap_op out_ptr CompareGt = do
243 v_1 <- pop
129 v_1 <- pop
244 v_0 <- pop
130 v_0 <- pop
245 push $ if v_0 > v_1 then 1 else 0
131 push $ if v_0 > v_1 then 1 else 0