1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 from libxyz.parser import Lexer
18 from libxyz.parser import BaseParser
19 from libxyz.parser import ParsedData
20
21 from libxyz.exceptions import XYZValueError
22 from libxyz.exceptions import ParseError
23 from libxyz.exceptions import LexerError
24
26 """
27 FlatParser is simple linear parser.
28
29 Format:
30
31 var1 <assign> val1 <delimiter>
32 var2 <assign> val2 <delimiter>
33 ...
34 """
35
36 STATE_VARIABLE = 0
37 STATE_ASSIGN = 1
38 STATE_VALUE = 2
39 STATE_LIST_VALUE = 3
40 STATE_DELIM = 4
41
42 DEFAULT_OPT = {
43 u"comment": u"#",
44 u"assignchar": u":",
45 u"delimiter": u"\n",
46 u"validvars": (),
47 u"value_validator": None,
48 u"count": 0,
49 u"list_separator": u",",
50 }
51
53 """
54 @param opt: Options
55 @type opt: dict
56
57 Available options:
58 - comment: Comment character.
59 Everything else ignored until EOL.
60 Type: I{string (single char)}
61 - assignchar: Variable-value split character.
62 Type: I{string (single char)}
63 - delimiter: Character to use as delimiter between statements.
64 Type: I{string (single char)}
65 - validvars: List of variables valid within block.
66 Type: I{sequence}
67 - value_validator: Value validator
68 Type: A function that takes two args:
69 variable and value and validates them.
70 In case value is invalid, XYZValueError must be raised.
71 Otherwise function must return required value, possibly modified.
72 - count: How many blocks to parse. If count <= 0 - will parse
73 all available.
74 Type: integer
75 - list_separator: Character to separate elements in list
76 Type: I{string (single char)}
77 Default: ,
78 """
79
80 super(FlatParser, self).__init__()
81
82 self._parsed = 0
83 self._result = ParsedData()
84 self._current_list = []
85 self._lexer = None
86 self._state = self.STATE_VARIABLE
87
88 self.opt = opt or self.DEFAULT_OPT
89 self.set_opt(self.DEFAULT_OPT, self.opt)
90
91 self._parse_table = {
92 self.STATE_VARIABLE: self._process_state_variable,
93 self.STATE_ASSIGN: self._process_state_assign,
94 self.STATE_VALUE: self._process_state_value,
95 self.STATE_LIST_VALUE: self._process_state_list_value,
96 self.STATE_DELIM: self._process_state_delim,
97 }
98
99
100
101 - def parse(self, source, default_data=None):
102 """
103 Begin parsing
104 @param default_data: Dictionary with default values.
105 """
106
107 self._cleanup()
108
109 if default_data and isinstance(default_data, dict):
110 self._result = default_data.copy()
111
112 _tokens = (
113 self.assignchar,
114 self.delimiter,
115 self.list_separator
116 )
117
118 self._lexer = Lexer(source, _tokens, self.comment, macro=None)
119
120 try:
121 while True:
122 _res = self._lexer.lexer()
123
124 if _res is None:
125 break
126 else:
127 _lex, _val = _res
128
129 if _val == u"\n" and self._state not in \
130 (self.STATE_DELIM, self.STATE_LIST_VALUE):
131 continue
132 self._parse_table[self._state](_val)
133 except LexerError, e:
134 self.error(str(e))
135
136
137 if self._state == self.STATE_LIST_VALUE:
138 self._process_state_list_value(None)
139
140 self._check_complete()
141
142 return self._result
143
144
145
147 if self.count > 0 and self.count == self._parsed:
148 self._lexer.done()
149 return
150
151 if self.validvars and word not in self.validvars:
152 self.error(_(u"Unknown variable %s") % word)
153 else:
154 self._varname = word
155 self._state = self.STATE_ASSIGN
156
157
158
166
167
168
172
173
174
176 if word == self.list_separator:
177 self._state = self.STATE_VALUE
178 return
179
180 if len(self._current_list) == 1:
181 _value = self._current_list[0]
182 else:
183 _value = tuple(self._current_list)
184
185 if self.value_validator:
186 try:
187 _value = self.value_validator(self._varname, _value)
188 except XYZValueError, e:
189 self.error(_(u"Invalid value: %s") % unicode(e))
190
191 self._result[self._varname] = _value
192 self._parsed += 1
193 self._varname = None
194
195 self._current_list = []
196 self._lexer.escaping_off()
197 self._state = self.STATE_DELIM
198
199 if word is not None:
200 self._lexer.unget(word)
201
202
203
205 if self.count > 0 and self.count == self._parsed:
206 self._lexer.done()
207 return
208
209 if word != self.delimiter:
210 self.error(msg=(word, self.delimiter),
211 etype=self.error_unexpected)
212 else:
213 self._state = self.STATE_VARIABLE
214
215
216
222
223
224
228