@@ -1,13 +1,16 @@
1+{-# LANGUAGE ScopedTypeVariables #-}
12{-# LANGUAGE BangPatterns #-}
23{-# LANGUAGE FlexibleContexts #-}
34{-# LANGUAGE NoMonomorphismRestriction #-}
45{-# LANGUAGE NamedFieldPuns #-}
6+{-# OPTIONS_GHC -funbox-strict-fields -O #-}
57module Data.Terminfo.Parse ( module Data.Terminfo.Parse
68 , Text.ParserCombinators.Parsec.ParseError
79 )
810 where
911
1012import Control.Monad ( liftM )
13+import Control.Parallel.Strategies
1114
1215import Data.Array.Unboxed
1316import Data.Monoid
@@ -20,33 +23,44 @@ type BytesOffset = Word8
2023type CapBytes = UArray Word8 Word8
2124
2225data CapExpression = CapExpression
23− { cap_ops :: CapOps
24− , cap_bytes :: CapBytes
25− , source_string :: String
26− , param_count :: Word
27− , param_ops :: ParamOps
26+ { cap_ops :: !CapOps
27+ , cap_bytes :: !CapBytes
28+ , source_string :: !String
29+ , param_count :: !Word
30+ , param_ops :: !ParamOps
2831 }
2932
33+instance NFData CapExpression where
34+ rnf (CapExpression ops !_bytes !_str !_c !_p_ops)
35+ = rnf ops
36+
3037type CapParam = Word
3138
3239type CapOps = [CapOp]
3340data CapOp =
34− Bytes (BytesOffset, BytesLength)
35− | DecOut
41+ Bytes !BytesOffset !BytesLength
42+ | DecOut | CharOut
3643 -- This stores a 0-based index to the parameter. However the operation that implies this op is
3744 -- 1-based
38− | PushParam !Word
45+ | PushParam !Word | PushValue !Word
3946 -- The conditional parts are the sequence of (%t expression, %e expression) pairs.
4047 -- The %e expression may be NOP
4148 | Conditional
42− { conditional_expr :: CapOps
43− , conditional_parts :: [(CapOps, CapOps)]
49+ { conditional_expr :: !CapOps
50+ , conditional_parts :: ![(CapOps, CapOps)]
4451 }
45− | BitwiseOr
46− | CompareEq
47− | LiteralInt Int
52+ | BitwiseOr | BitwiseXOr | BitwiseAnd
53+ | ArithPlus
54+ | CompareEq | CompareLt | CompareGt
4855 deriving ( Show )
4956
57+instance NFData CapOp where
58+ rnf (Bytes offset c) = rnf offset >| rnf c
59+ rnf (PushParam !_pn) = ()
60+ rnf (PushValue !_v) = ()
61+ rnf (Conditional c_expr c_parts) = rnf c_expr >| rnf c_parts
62+ rnf _ = ()
63+
5064type ParamOps = [ParamOp]
5165data ParamOp =
5266 IncFirstTwo
@@ -61,16 +75,18 @@ parse_cap_expression cap_string =
6175 in case v of
6276 Left e -> Left e
6377 Right build_results ->
64− Right $ CapExpression
65− { cap_ops = out_cap_ops build_results
66− -- The cap bytes are the lower 8 bits of the input string's characters.
67− -- \todo Verify the input string actually contains an 8bit byte per character.
68− , cap_bytes = listArray (0, toEnum $ length cap_string - 1)
69− $ map (toEnum . fromEnum) cap_string
70− , source_string = cap_string
71− , param_count = out_param_count build_results
72− , param_ops = out_param_ops build_results
73− }
78+ Right $! ( CapExpression
79+ { cap_ops = out_cap_ops build_results
80+ -- The cap bytes are the lower 8 bits of the input string's characters.
81+ -- \todo Verify the input string actually contains an 8bit byte per character.
82+ , cap_bytes = listArray (0, toEnum $ length cap_string - 1)
83+ $ map (toEnum . fromEnum) cap_string
84+ , source_string = cap_string
85+ , param_count = out_param_count build_results
86+ , param_ops = out_param_ops build_results
87+ }
88+ `using` rnf
89+ )
7490
7591type CapParser a = GenParser Char BuildState a
7692
@@ -90,17 +106,20 @@ literal_percent_parser = do
90106 char '%'
91107 start_offset <- getState >>= return . next_offset
92108 inc_offset 1
93− return $ BuildResults 0 [Bytes (start_offset, 1)] []
109+ return $ BuildResults 0 [Bytes start_offset 1] []
94110
95111param_op_parser :: CapParser BuildResults
96112param_op_parser
97113 = increment_op_parser
98114 <|> push_op_parser
99115 <|> dec_out_parser
116+ <|> char_out_parser
100117 <|> conditional_op_parser
101118 <|> bitwise_op_parser
119+ <|> arith_op_parser
102120 <|> literal_int_op_parser
103121 <|> compare_op_parser
122+ <|> char_const_parser
104123
105124increment_op_parser :: CapParser BuildResults
106125increment_op_parser = do
@@ -121,6 +140,12 @@ dec_out_parser = do
121140 inc_offset 1
122141 return $ BuildResults 0 [ DecOut ] []
123142
143+char_out_parser :: CapParser BuildResults
144+char_out_parser = do
145+ char 'c'
146+ inc_offset 1
147+ return $ BuildResults 0 [ CharOut ] []
148+
124149conditional_op_parser :: CapParser BuildResults
125150conditional_op_parser = do
126151 char '?'
@@ -156,11 +181,11 @@ conditional_op_parser = do
156181 return $ BuildResults n'' [ Conditional cond cond_parts ] p_ops
157182
158183 where
159− many_p p end = choice
184+ many_p !p !end = choice
160185 [ try end >> return []
161− , do v <- p
162− vs <- many_p p end
163− return $ v : vs
186+ , do !v <- p
187+ !vs <- many_p p end
188+ return $! v : vs
164189 ]
165190 many_expr end = liftM mconcat $ many_p ( param_escape_parser <|> bytes_op_parser ) end
166191
@@ -180,8 +205,10 @@ conditional_end_parser = do
180205 inc_offset 2
181206
182207bitwise_op_parser :: CapParser BuildResults
183−bitwise_op_parser = do
184− bitwise_or_parser
208+bitwise_op_parser
209+ = bitwise_or_parser
210+ <|> bitwise_and_parser
211+ <|> bitwise_xor_parser
185212
186213bitwise_or_parser :: CapParser BuildResults
187214bitwise_or_parser = do
@@ -189,22 +216,53 @@ bitwise_or_parser = do
189216 inc_offset 1
190217 return $ BuildResults 0 [ BitwiseOr ] [ ]
191218
219+bitwise_and_parser :: CapParser BuildResults
220+bitwise_and_parser = do
221+ char '&'
222+ inc_offset 1
223+ return $ BuildResults 0 [ BitwiseAnd ] [ ]
224+
225+bitwise_xor_parser :: CapParser BuildResults
226+bitwise_xor_parser = do
227+ char '^'
228+ inc_offset 1
229+ return $ BuildResults 0 [ BitwiseXOr ] [ ]
230+
231+arith_op_parser :: CapParser BuildResults
232+arith_op_parser = do
233+ char '+'
234+ inc_offset 1
235+ return $ BuildResults 0 [ ArithPlus ] [ ]
236+
192237literal_int_op_parser :: CapParser BuildResults
193238literal_int_op_parser = do
194239 char '{'
195240 inc_offset 1
196241 n_str <- many1 digit
197242 inc_offset $ toEnum $ length n_str
198− let n = read n_str
243+ let n :: Word = read n_str
199244 char '}'
200245 inc_offset 1
201− return $ BuildResults 0 [ LiteralInt n ] [ ]
246+ return $ BuildResults 0 [ PushValue n ] [ ]
202247
203248compare_op_parser :: CapParser BuildResults
204−compare_op_parser = do
205− char '='
206− inc_offset 1
207− return $ BuildResults 0 [ CompareEq ] [ ]
249+compare_op_parser
250+ = compare_eq_op
251+ <|> compare_lt_op
252+ <|> compare_gt_op
253+ where
254+ compare_eq_op = do
255+ char '='
256+ inc_offset 1
257+ return $ BuildResults 0 [ CompareEq ] [ ]
258+ compare_lt_op = do
259+ char '<'
260+ inc_offset 1
261+ return $ BuildResults 0 [ CompareLt ] [ ]
262+ compare_gt_op = do
263+ char '>'
264+ inc_offset 1
265+ return $ BuildResults 0 [ CompareGt ] [ ]
208266
209267bytes_op_parser :: CapParser BuildResults
210268bytes_op_parser = do
@@ -214,7 +272,15 @@ bytes_op_parser = do
214272 !s <- getState
215273 let s' = s { next_offset = start_offset + c }
216274 setState s'
217− return $ BuildResults 0 [Bytes (start_offset, c)] []
275+ return $ BuildResults 0 [Bytes start_offset c] []
276+
277+char_const_parser :: CapParser BuildResults
278+char_const_parser = do
279+ char '\''
280+ char_value <- liftM (toEnum . fromEnum) anyChar
281+ char '\''
282+ inc_offset 3
283+ return $ BuildResults 0 [ PushValue char_value ] [ ]
218284
219285data BuildState = BuildState
220286 { next_offset :: Word8
@@ -230,9 +296,9 @@ initial_build_state :: BuildState
230296initial_build_state = BuildState 0
231297
232298data BuildResults = BuildResults
233− { out_param_count :: Word
234− , out_cap_ops :: CapOps
235− , out_param_ops :: ParamOps
299+ { out_param_count :: !Word
300+ , out_cap_ops :: !CapOps
301+ , out_param_ops :: !ParamOps
236302 }
237303
238304instance Monoid BuildResults where