@@ -1,22 +1,19 @@
1+{-# LANGUAGE BangPatterns #-}
1{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE NoMonomorphismRestriction #-}
3{-# LANGUAGE NoMonomorphismRestriction #-}
3{-# LANGUAGE NamedFieldPuns #-}
4{-# LANGUAGE NamedFieldPuns #-}
4module Data.Terminfo.Parse ( module Data.Terminfo.Parse
5module Data.Terminfo.Parse ( module Data.Terminfo.Parse
5− , Text.Parsec.ParseError
6+ , Text.ParserCombinators.Parsec.ParseError
9import Control.Monad ( liftM )
10import Control.Monad ( liftM )
10−import Control.Monad.ST.Strict
12import Data.Array.Unboxed
12import Data.Array.Unboxed
14import Data.Monoid
13import Data.Monoid
15import Data.Word
14import Data.Word
19−import Text.Parsec
16+import Text.ParserCombinators.Parsec
21type BytesLength = Word8
18type BytesLength = Word8
22type BytesOffset = Word8
19type BytesOffset = Word8
@@ -46,6 +43,7 @@ data CapOp =
46 , conditional_parts :: [(CapOps, CapOps)]
43 , conditional_parts :: [(CapOps, CapOps)]
48 | BitwiseOr
45 | BitwiseOr
49 | LiteralInt Int
47 | LiteralInt Int
50 deriving ( Show )
48 deriving ( Show )
@@ -55,15 +53,15 @@ data ParamOp =
55 deriving ( Show )
53 deriving ( Show )
57parse_cap_expression :: String -> Either ParseError CapExpression
55parse_cap_expression :: String -> Either ParseError CapExpression
58−parse_cap_expression cap_string = runST $ do
56+parse_cap_expression cap_string =
59− v <- runParserT cap_expression_parser
57+ let v = runParser cap_expression_parser
60 initial_build_state
58 initial_build_state
61 "terminfo cap"
59 "terminfo cap"
62 cap_string
60 cap_string
63− case v of
61+ in case v of
64− Left error -> return $ Left error
62+ Left e -> Left e
65 Right build_results ->
63 Right build_results ->
66− return $ Right $ CapExpression
64+ Right $ CapExpression
67 { cap_ops = out_cap_ops build_results
65 { cap_ops = out_cap_ops build_results
68 -- The cap bytes are the lower 8 bits of the input string's characters.
66 -- The cap bytes are the lower 8 bits of the input string's characters.
69 -- \todo Verify the input string actually contains an 8bit byte per character.
67 -- \todo Verify the input string actually contains an 8bit byte per character.
@@ -74,21 +72,27 @@ parse_cap_expression cap_string = runST $ do
74 , param_ops = out_param_ops build_results
72 , param_ops = out_param_ops build_results
75+type CapParser a = GenParser Char BuildState a
77+cap_expression_parser :: CapParser BuildResults
77cap_expression_parser = do
78cap_expression_parser = do
78 rs <- many $ param_escape_parser <|> bytes_op_parser
79 rs <- many $ param_escape_parser <|> bytes_op_parser
79 return $ mconcat rs
80 return $ mconcat rs
82+param_escape_parser :: CapParser BuildResults
81param_escape_parser = do
83param_escape_parser = do
83 inc_offset 1
85 inc_offset 1
84 literal_percent_parser <|> param_op_parser
86 literal_percent_parser <|> param_op_parser
88+literal_percent_parser :: CapParser BuildResults
86literal_percent_parser = do
89literal_percent_parser = do
88 start_offset <- getState >>= return . next_offset
91 start_offset <- getState >>= return . next_offset
89 inc_offset 1
92 inc_offset 1
90 return $ BuildResults 0 [Bytes (start_offset, 1)] []
93 return $ BuildResults 0 [Bytes (start_offset, 1)] []
95+param_op_parser :: CapParser BuildResults
92param_op_parser
96param_op_parser
93 = increment_op_parser
97 = increment_op_parser
94 <|> push_op_parser
98 <|> push_op_parser
@@ -96,23 +100,28 @@ param_op_parser
96 <|> conditional_op_parser
100 <|> conditional_op_parser
97 <|> bitwise_op_parser
101 <|> bitwise_op_parser
98 <|> literal_int_op_parser
102 <|> literal_int_op_parser
103+ <|> compare_op_parser
105+increment_op_parser :: CapParser BuildResults
100increment_op_parser = do
106increment_op_parser = do
102 inc_offset 1
108 inc_offset 1
103 return $ BuildResults 0 [] [ IncFirstTwo ]
109 return $ BuildResults 0 [] [ IncFirstTwo ]
111+push_op_parser :: CapParser BuildResults
105push_op_parser = do
112push_op_parser = do
107 param_n <- digit >>= return . (\d -> read [d])
114 param_n <- digit >>= return . (\d -> read [d])
108 inc_offset 2
115 inc_offset 2
109 return $ BuildResults param_n [ PushParam $ param_n - 1 ] []
116 return $ BuildResults param_n [ PushParam $ param_n - 1 ] []
118+dec_out_parser :: CapParser BuildResults
111dec_out_parser = do
119dec_out_parser = do
113 inc_offset 1
121 inc_offset 1
114 return $ BuildResults 0 [ DecOut ] []
122 return $ BuildResults 0 [ DecOut ] []
124+conditional_op_parser :: CapParser BuildResults
116conditional_op_parser = do
125conditional_op_parser = do
118 inc_offset 1
127 inc_offset 1
@@ -122,7 +131,9 @@ conditional_op_parser = do
122 true_part <- many_expr $ choice [ try $ lookAhead conditional_end_parser
131 true_part <- many_expr $ choice [ try $ lookAhead conditional_end_parser
123 , conditional_false_parser
132 , conditional_false_parser
125− false_part <- many_expr $ lookAhead conditional_end_parser
134+ false_part <- many_expr $ choice [ try $ lookAhead conditional_end_parser
135+ , conditional_true_parser
126 return ( true_part, false_part )
137 return ( true_part, false_part )
128 conditional_end_parser
139 conditional_end_parser
@@ -140,9 +151,9 @@ conditional_op_parser = do
141 let true_param_ops = mconcat $ map out_param_ops true_parts
152 let true_param_ops = mconcat $ map out_param_ops true_parts
142 false_param_ops = mconcat $ map out_param_ops false_parts
153 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]
145− return $ BuildResults n'' [ Conditional cond cond_parts ] param_ops
156+ return $ BuildResults n'' [ Conditional cond cond_parts ] p_ops
148 many_p p end = choice
159 many_p p end = choice
@@ -153,26 +164,32 @@ conditional_op_parser = do
154 many_expr end = liftM mconcat $ many_p ( param_escape_parser <|> bytes_op_parser ) end
165 many_expr end = liftM mconcat $ many_p ( param_escape_parser <|> bytes_op_parser ) end
167+conditional_true_parser :: CapParser ()
156conditional_true_parser = do
168conditional_true_parser = do
157 string "%t"
169 string "%t"
158 inc_offset 2
170 inc_offset 2
172+conditional_false_parser :: CapParser ()
160conditional_false_parser = do
173conditional_false_parser = do
161 string "%e"
174 string "%e"
162 inc_offset 2
175 inc_offset 2
177+conditional_end_parser :: CapParser ()
164conditional_end_parser = do
178conditional_end_parser = do
165 string "%;"
179 string "%;"
166 inc_offset 2
180 inc_offset 2
182+bitwise_op_parser :: CapParser BuildResults
168bitwise_op_parser = do
183bitwise_op_parser = do
169 bitwise_or_parser
184 bitwise_or_parser
186+bitwise_or_parser :: CapParser BuildResults
171bitwise_or_parser = do
187bitwise_or_parser = do
173 inc_offset 1
189 inc_offset 1
174 return $ BuildResults 0 [ BitwiseOr ] [ ]
190 return $ BuildResults 0 [ BitwiseOr ] [ ]
192+literal_int_op_parser :: CapParser BuildResults
176literal_int_op_parser = do
193literal_int_op_parser = do
178 inc_offset 1
195 inc_offset 1
@@ -183,19 +200,33 @@ literal_int_op_parser = do
183 inc_offset 1
200 inc_offset 1
184 return $ BuildResults 0 [ LiteralInt n ] [ ]
201 return $ BuildResults 0 [ LiteralInt n ] [ ]
203+compare_op_parser :: CapParser BuildResults
204+compare_op_parser = do
207+ return $ BuildResults 0 [ CompareEq ] [ ]
209+bytes_op_parser :: CapParser BuildResults
186bytes_op_parser = do
210bytes_op_parser = do
187 bytes <- many1 $ satisfy (/= '%')
211 bytes <- many1 $ satisfy (/= '%')
188 start_offset <- getState >>= return . next_offset
212 start_offset <- getState >>= return . next_offset
189− let !count = toEnum $ length bytes
213+ let !c = toEnum $ length bytes
190− modifyState $ \s -> s { next_offset = start_offset + count }
215+ let s' = s { next_offset = start_offset + c }
191− return $ BuildResults 0 [Bytes (start_offset, count)] []
217+ return $ BuildResults 0 [Bytes (start_offset, c)] []
193data BuildState = BuildState
219data BuildState = BuildState
194 { next_offset :: Word8
220 { next_offset :: Word8
223+inc_offset :: Word8 -> CapParser ()
197−inc_offset n = modifyState $ \s -> s { next_offset = next_offset s + n }
226+ let s' = s { next_offset = next_offset s + n }
229+initial_build_state :: BuildState
199initial_build_state = BuildState 0
230initial_build_state = BuildState 0
201data BuildResults = BuildResults
232data BuildResults = BuildResults