1{-# LANGUAGE MagicHash #-}
2{-# LANGUAGE BangPatterns #-}
3{-# LANGUAGE ScopedTypeVariables #-}
4{-# LANGUAGE RecordWildCards #-}
5{-# LANGUAGE FlexibleContexts #-}
6{-# LANGUAGE NoMonomorphismRestriction #-}
7{-# LANGUAGE NamedFieldPuns #-}
8{-# OPTIONS_GHC -funbox-strict-fields #-}
9{- Evaluates the paramaterized terminfo string capability with the given parameters.
11 - todo: This can be greatly simplified.
13module Data.Terminfo.Eval ( cap_expression_required_bytes
14 , serialize_cap_expression
18import Data.ByteString.Internal ( memcpy )
19import Data.Marshalling
20import Data.Terminfo.Parse
22import Control.Monad.Identity
23import Control.Monad.State.Strict
25import Data.Bits ( (.|.), (.&.), xor )
31data EvalState = EvalState
32 { eval_stack :: ![ CapParam ]
33 , eval_expression :: !CapExpression
34 , eval_params :: ![ CapParam ]
37type EvalT m a = StateT EvalState m a
38type Eval a = EvalT Identity a
40{-# SPECIALIZE pop :: EvalT IO CapParam #-}
41pop :: Monad m => EvalT m CapParam
44 let v : stack' = eval_stack s
45 s' = s { eval_stack = stack' }
49{-# SPECIALIZE read_param :: Word -> EvalT IO CapParam #-}
50read_param :: Monad m => Word -> EvalT m CapParam
52 !params <- get >>= return . eval_params
53 return $! genericIndex params pn
55{-# SPECIALIZE push :: CapParam -> EvalT IO () #-}
56push :: Monad m => CapParam -> EvalT m ()
59 let s' = s { eval_stack = v : eval_stack s }
62apply_param_ops :: CapExpression -> [CapParam] -> [CapParam]
63apply_param_ops cap params = foldl apply_param_op params (param_ops cap)
65apply_param_op :: [CapParam] -> ParamOp -> [CapParam]
66apply_param_op params IncFirstTwo = map (+ 1) params
68cap_expression_required_bytes :: CapExpression -> [CapParam] -> Word
69cap_expression_required_bytes cap params =
70 let params' = apply_param_ops cap params
71 s_0 = EvalState [] cap params'
72 in fst $! runIdentity $! runStateT ( cap_ops_required_bytes $! cap_ops cap ) s_0
74cap_ops_required_bytes :: CapOps -> Eval Word
75cap_ops_required_bytes ops = do
76 counts <- mapM cap_op_required_bytes ops
79cap_op_required_bytes :: CapOp -> Eval Word
80cap_op_required_bytes (Bytes _ _ c) = return $ toEnum c
81cap_op_required_bytes DecOut = do
83 return $ toEnum $ length $ show p
84cap_op_required_bytes CharOut = do
87cap_op_required_bytes (PushParam pn) = do
88 read_param pn >>= push
90cap_op_required_bytes (PushValue v) = do
93cap_op_required_bytes (Conditional expr parts) = do
94 c_expr <- cap_ops_required_bytes expr
95 c_parts <- cond_parts_required_bytes parts
96 return $ c_expr + c_parts
98 cond_parts_required_bytes [] = return 0
99 cond_parts_required_bytes ( (true_ops, false_ops) : false_parts ) = do
101 -- Usually the %? expr part pushes a value onto the stack, and %t pops it from the
102 -- stack, testing if it is nonzero (true). If it is zero (false), control
103 -- passes to the %e (else) part.
106 then cap_ops_required_bytes true_ops
108 c_false <- cap_ops_required_bytes false_ops
109 c_remain <- cond_parts_required_bytes false_parts
110 return $ c_false + c_remain
112cap_op_required_bytes BitwiseOr = do
117cap_op_required_bytes BitwiseAnd = do
122cap_op_required_bytes BitwiseXOr = do
127cap_op_required_bytes ArithPlus = do
132cap_op_required_bytes ArithMinus = do
137cap_op_required_bytes CompareEq = do
140 push $ if v_0 == v_1 then 1 else 0
142cap_op_required_bytes CompareLt = do
145 push $ if v_0 < v_1 then 1 else 0
147cap_op_required_bytes CompareGt = do
150 push $ if v_0 > v_1 then 1 else 0
153serialize_cap_expression :: CapExpression -> [CapParam] -> OutputBuffer -> IO OutputBuffer
154serialize_cap_expression cap params out_ptr = do
155 let params' = apply_param_ops cap params
156 s_0 = EvalState [] cap params'
157 (!out_ptr', _) <- runStateT ( serialize_cap_ops out_ptr (cap_ops cap) ) s_0
160serialize_cap_ops :: OutputBuffer -> CapOps -> EvalT IO OutputBuffer
161serialize_cap_ops out_ptr ops = foldM serialize_cap_op out_ptr ops
163serialize_cap_op :: OutputBuffer -> CapOp -> EvalT IO OutputBuffer
164serialize_cap_op !out_ptr ( Bytes !offset !byte_count !next_offset ) = do
165 !cap <- get >>= return . eval_expression
166 let ( !start_ptr, _ ) = cap_bytes cap
167 !src_ptr = start_ptr `plusPtr` offset
168 !out_ptr' = out_ptr `plusPtr` next_offset
169 liftIO $! memcpy out_ptr src_ptr byte_count
171serialize_cap_op out_ptr DecOut = do
174 out_bytes = string_to_bytes out_str
175 serialize_bytes out_bytes out_ptr
176serialize_cap_op out_ptr CharOut = do
178 -- XXX Truncate the character value to a single byte?
179 let !out_byte = W8# (and# p 0xFF##)
180 !out_ptr' = out_ptr `plusPtr` 1
181 liftIO $ poke out_ptr out_byte
183serialize_cap_op out_ptr (PushParam pn) = do
184 read_param pn >>= push
186serialize_cap_op out_ptr (PushValue v) = do
189serialize_cap_op out_ptr (Conditional expr parts) = do
190 out_ptr' <- serialize_cap_ops out_ptr expr
191 out_ptr'' <- serialize_cond_parts out_ptr' parts
194 serialize_cond_parts ptr [] = return ptr
195 serialize_cond_parts ptr ( (true_ops, false_ops) : false_parts ) = do
197 -- Usually the %? expr part pushes a value onto the stack, and %t pops it from the
198 -- stack, testing if it is nonzero (true). If it is zero (false), control
199 -- passes to the %e (else) part.
202 then serialize_cap_ops ptr true_ops
204 ptr' <- serialize_cap_ops ptr false_ops
205 serialize_cond_parts ptr' false_parts
208serialize_cap_op out_ptr BitwiseOr = do
213serialize_cap_op out_ptr BitwiseAnd = do
218serialize_cap_op out_ptr BitwiseXOr = do
223serialize_cap_op out_ptr ArithPlus = do
228serialize_cap_op out_ptr ArithMinus = do
233serialize_cap_op out_ptr CompareEq = do
236 push $ if v_0 == v_1 then 1 else 0
238serialize_cap_op out_ptr CompareLt = do
241 push $ if v_0 < v_1 then 1 else 0
243serialize_cap_op out_ptr CompareGt = do
246 push $ if v_0 > v_1 then 1 else 0
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list