@@ -1,22 +1,19 @@
1+{-# LANGUAGE BangPatterns #-}
12{-# LANGUAGE FlexibleContexts #-}
23{-# LANGUAGE NoMonomorphismRestriction #-}
34{-# LANGUAGE NamedFieldPuns #-}
45module Data.Terminfo.Parse ( module Data.Terminfo.Parse
5− , Text.Parsec.ParseError
6+ , Text.ParserCombinators.Parsec.ParseError
67 )
78 where
89
910import Control.Monad ( liftM )
10−import Control.Monad.ST.Strict
1111
1212import Data.Array.Unboxed
13−import Data.Array.ST
1413import Data.Monoid
1514import Data.Word
1615
17−import Numeric
18−
19−import Text.Parsec
16+import Text.ParserCombinators.Parsec
2017
2118type BytesLength = Word8
2219type BytesOffset = Word8
@@ -46,6 +43,7 @@ data CapOp =
4643 , conditional_parts :: [(CapOps, CapOps)]
4744 }
4845 | BitwiseOr
46+ | CompareEq
4947 | LiteralInt Int
5048 deriving ( Show )
5149
@@ -55,15 +53,15 @@ data ParamOp =
5553 deriving ( Show )
5654
5755parse_cap_expression :: String -> Either ParseError CapExpression
58−parse_cap_expression cap_string = runST $ do
59− v <- runParserT cap_expression_parser
56+parse_cap_expression cap_string =
57+ let v = runParser cap_expression_parser
6058 initial_build_state
6159 "terminfo cap"
6260 cap_string
63− case v of
64− Left error -> return $ Left error
61+ in case v of
62+ Left e -> Left e
6563 Right build_results ->
66− return $ Right $ CapExpression
64+ Right $ CapExpression
6765 { cap_ops = out_cap_ops build_results
6866 -- The cap bytes are the lower 8 bits of the input string's characters.
6967 -- \todo Verify the input string actually contains an 8bit byte per character.
@@ -74,21 +72,27 @@ parse_cap_expression cap_string = runST $ do
7472 , param_ops = out_param_ops build_results
7573 }
7674
75+type CapParser a = GenParser Char BuildState a
76+
77+cap_expression_parser :: CapParser BuildResults
7778cap_expression_parser = do
7879 rs <- many $ param_escape_parser <|> bytes_op_parser
7980 return $ mconcat rs
8081
82+param_escape_parser :: CapParser BuildResults
8183param_escape_parser = do
8284 char '%'
8385 inc_offset 1
8486 literal_percent_parser <|> param_op_parser
8587
88+literal_percent_parser :: CapParser BuildResults
8689literal_percent_parser = do
8790 char '%'
8891 start_offset <- getState >>= return . next_offset
8992 inc_offset 1
9093 return $ BuildResults 0 [Bytes (start_offset, 1)] []
9194
95+param_op_parser :: CapParser BuildResults
9296param_op_parser
9397 = increment_op_parser
9498 <|> push_op_parser
@@ -96,23 +100,28 @@ param_op_parser
96100 <|> conditional_op_parser
97101 <|> bitwise_op_parser
98102 <|> literal_int_op_parser
103+ <|> compare_op_parser
99104
105+increment_op_parser :: CapParser BuildResults
100106increment_op_parser = do
101107 char 'i'
102108 inc_offset 1
103109 return $ BuildResults 0 [] [ IncFirstTwo ]
104110
111+push_op_parser :: CapParser BuildResults
105112push_op_parser = do
106113 char 'p'
107114 param_n <- digit >>= return . (\d -> read [d])
108115 inc_offset 2
109116 return $ BuildResults param_n [ PushParam $ param_n - 1 ] []
110117
118+dec_out_parser :: CapParser BuildResults
111119dec_out_parser = do
112120 char 'd'
113121 inc_offset 1
114122 return $ BuildResults 0 [ DecOut ] []
115123
124+conditional_op_parser :: CapParser BuildResults
116125conditional_op_parser = do
117126 char '?'
118127 inc_offset 1
@@ -122,7 +131,9 @@ conditional_op_parser = do
122131 true_part <- many_expr $ choice [ try $ lookAhead conditional_end_parser
123132 , conditional_false_parser
124133 ]
125− false_part <- many_expr $ lookAhead conditional_end_parser
134+ false_part <- many_expr $ choice [ try $ lookAhead conditional_end_parser
135+ , conditional_true_parser
136+ ]
126137 return ( true_part, false_part )
127138 )
128139 conditional_end_parser
@@ -140,9 +151,9 @@ conditional_op_parser = do
140151
141152 let true_param_ops = mconcat $ map out_param_ops true_parts
142153 false_param_ops = mconcat $ map out_param_ops false_parts
143− param_ops = mconcat [cond_param_ops, true_param_ops, false_param_ops]
154+ p_ops = mconcat [cond_param_ops, true_param_ops, false_param_ops]
144155
145− return $ BuildResults n'' [ Conditional cond cond_parts ] param_ops
156+ return $ BuildResults n'' [ Conditional cond cond_parts ] p_ops
146157
147158 where
148159 many_p p end = choice
@@ -153,26 +164,32 @@ conditional_op_parser = do
153164 ]
154165 many_expr end = liftM mconcat $ many_p ( param_escape_parser <|> bytes_op_parser ) end
155166
167+conditional_true_parser :: CapParser ()
156168conditional_true_parser = do
157169 string "%t"
158170 inc_offset 2
159171
172+conditional_false_parser :: CapParser ()
160173conditional_false_parser = do
161174 string "%e"
162175 inc_offset 2
163176
177+conditional_end_parser :: CapParser ()
164178conditional_end_parser = do
165179 string "%;"
166180 inc_offset 2
167181
182+bitwise_op_parser :: CapParser BuildResults
168183bitwise_op_parser = do
169184 bitwise_or_parser
170185
186+bitwise_or_parser :: CapParser BuildResults
171187bitwise_or_parser = do
172188 char '|'
173189 inc_offset 1
174190 return $ BuildResults 0 [ BitwiseOr ] [ ]
175191
192+literal_int_op_parser :: CapParser BuildResults
176193literal_int_op_parser = do
177194 char '{'
178195 inc_offset 1
@@ -183,19 +200,33 @@ literal_int_op_parser = do
183200 inc_offset 1
184201 return $ BuildResults 0 [ LiteralInt n ] [ ]
185202
203+compare_op_parser :: CapParser BuildResults
204+compare_op_parser = do
205+ char '='
206+ inc_offset 1
207+ return $ BuildResults 0 [ CompareEq ] [ ]
208+
209+bytes_op_parser :: CapParser BuildResults
186210bytes_op_parser = do
187211 bytes <- many1 $ satisfy (/= '%')
188212 start_offset <- getState >>= return . next_offset
189− let !count = toEnum $ length bytes
190− modifyState $ \s -> s { next_offset = start_offset + count }
191− return $ BuildResults 0 [Bytes (start_offset, count)] []
213+ let !c = toEnum $ length bytes
214+ !s <- getState
215+ let s' = s { next_offset = start_offset + c }
216+ setState s'
217+ return $ BuildResults 0 [Bytes (start_offset, c)] []
192218
193219data BuildState = BuildState
194220 { next_offset :: Word8
195221 }
196222
197−inc_offset n = modifyState $ \s -> s { next_offset = next_offset s + n }
223+inc_offset :: Word8 -> CapParser ()
224+inc_offset n = do
225+ s <- getState
226+ let s' = s { next_offset = next_offset s + n }
227+ setState s'
198228
229+initial_build_state :: BuildState
199230initial_build_state = BuildState 0
200231
201232data BuildResults = BuildResults