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
23import Control.Monad.Identity
24import Control.Monad.State.Strict
25import Control.Monad.Trans
27import Data.Array.Unboxed
28import Data.Bits ( (.|.), (.&.), xor )
38data EvalState = EvalState
39 { eval_stack :: ![ CapParam ]
40 , eval_expression :: !CapExpression
41 , eval_params :: ![ CapParam ]
44type EvalT m a = StateT EvalState m a
45type Eval a = EvalT Identity a
47{-# SPECIALIZE pop :: EvalT IO CapParam #-}
48pop :: Monad m => EvalT m CapParam
51 let v : stack' = eval_stack s
52 s' = s { eval_stack = stack' }
56{-# SPECIALIZE read_param :: Word -> EvalT IO CapParam #-}
57read_param :: Monad m => Word -> EvalT m CapParam
59 EvalState _ _ !params <- get
60 return $! genericIndex params pn
62{-# SPECIALIZE push :: CapParam -> EvalT IO () #-}
63push :: Monad m => CapParam -> EvalT m ()
66 let s' = s { eval_stack = v : eval_stack s }
69apply_param_ops :: CapExpression -> [CapParam] -> [CapParam]
70apply_param_ops cap params = foldl apply_param_op params (param_ops cap)
72apply_param_op :: [CapParam] -> ParamOp -> [CapParam]
73apply_param_op params IncFirstTwo = map (+ 1) params
75cap_expression_required_bytes :: CapExpression -> [CapParam] -> Word
76cap_expression_required_bytes cap params =
77 let params' = apply_param_ops cap params
78 s_0 = EvalState [] cap params'
79 in fst $! runIdentity $! runStateT ( cap_ops_required_bytes $! cap_ops cap ) s_0
81cap_ops_required_bytes :: CapOps -> Eval Word
82cap_ops_required_bytes ops = do
83 counts <- mapM cap_op_required_bytes ops
86cap_op_required_bytes :: CapOp -> Eval Word
87cap_op_required_bytes (Bytes _ _ c) = return $ toEnum c
88cap_op_required_bytes DecOut = do
90 return $ toEnum $ length $ show p
91cap_op_required_bytes CharOut = do
94cap_op_required_bytes (PushParam pn) = do
95 read_param pn >>= push
97cap_op_required_bytes (PushValue v) = do
100cap_op_required_bytes (Conditional expr parts) = do
101 c_expr <- cap_ops_required_bytes expr
102 c_parts <- cond_parts_required_bytes parts
103 return $ c_expr + c_parts
105 cond_parts_required_bytes [] = return 0
106 cond_parts_required_bytes ( (true_ops, false_ops) : false_parts ) = do
108 -- Usually the %? expr part pushes a value onto the stack, and %t pops it from the
109 -- stack, testing if it is nonzero (true). If it is zero (false), control
110 -- passes to the %e (else) part.
113 then cap_ops_required_bytes true_ops
115 c_false <- cap_ops_required_bytes false_ops
116 c_remain <- cond_parts_required_bytes false_parts
117 return $ c_false + c_remain
119cap_op_required_bytes BitwiseOr = do
124cap_op_required_bytes BitwiseAnd = do
129cap_op_required_bytes BitwiseXOr = do
134cap_op_required_bytes ArithPlus = do
139cap_op_required_bytes ArithMinus = do
144cap_op_required_bytes CompareEq = do
147 push $ if v_0 == v_1 then 1 else 0
149cap_op_required_bytes CompareLt = do
152 push $ if v_0 < v_1 then 1 else 0
154cap_op_required_bytes CompareGt = do
157 push $ if v_0 > v_1 then 1 else 0
160serialize_cap_expression :: CapExpression -> [CapParam] -> OutputBuffer -> IO OutputBuffer
161serialize_cap_expression cap params out_ptr = do
162 let params' = apply_param_ops cap params
163 s_0 = EvalState [] cap params'
164 (!out_ptr', _) <- runStateT ( serialize_cap_ops out_ptr (cap_ops cap) ) s_0
167serialize_cap_ops :: OutputBuffer -> CapOps -> EvalT IO OutputBuffer
168serialize_cap_ops out_ptr ops = foldM serialize_cap_op out_ptr ops
170serialize_cap_op :: OutputBuffer -> CapOp -> EvalT IO OutputBuffer
171serialize_cap_op !out_ptr ( Bytes !offset !byte_count !next_offset ) = do
172 EvalState _ !cap _ <- get
173 let ( !start_ptr, _ ) = cap_bytes cap
174 !src_ptr = start_ptr `plusPtr` offset
175 !out_ptr' = out_ptr `plusPtr` next_offset
176 liftIO $! memcpy out_ptr src_ptr byte_count
178serialize_cap_op out_ptr DecOut = do
181 out_bytes = string_to_bytes out_str
182 serialize_bytes out_bytes out_ptr
183serialize_cap_op out_ptr CharOut = do
185 -- XXX Truncate the character value to a single byte?
186 let !out_byte = W8# (and# p 0xFF##)
187 !out_ptr' = out_ptr `plusPtr` 1
188 liftIO $ poke out_ptr out_byte
190serialize_cap_op out_ptr (PushParam pn) = do
191 read_param pn >>= push
193serialize_cap_op out_ptr (PushValue v) = do
196serialize_cap_op out_ptr (Conditional expr parts) = do
197 out_ptr' <- serialize_cap_ops out_ptr expr
198 out_ptr'' <- serialize_cond_parts out_ptr' parts
201 serialize_cond_parts ptr [] = return ptr
202 serialize_cond_parts ptr ( (true_ops, false_ops) : false_parts ) = do
204 -- Usually the %? expr part pushes a value onto the stack, and %t pops it from the
205 -- stack, testing if it is nonzero (true). If it is zero (false), control
206 -- passes to the %e (else) part.
209 then serialize_cap_ops ptr true_ops
211 ptr' <- serialize_cap_ops ptr false_ops
212 serialize_cond_parts ptr' false_parts
215serialize_cap_op out_ptr BitwiseOr = do
220serialize_cap_op out_ptr BitwiseAnd = do
225serialize_cap_op out_ptr BitwiseXOr = do
230serialize_cap_op out_ptr ArithPlus = do
235serialize_cap_op out_ptr ArithMinus = do
240serialize_cap_op out_ptr CompareEq = do
243 push $ if v_0 == v_1 then 1 else 0
245serialize_cap_op out_ptr CompareLt = do
248 push $ if v_0 < v_1 then 1 else 0
250serialize_cap_op out_ptr CompareGt = do
253 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