Package libxyz :: Package parser :: Module flat
[hide private]
[frames] | no frames]

Source Code for Module libxyz.parser.flat

  1  #-*- coding: utf8 -* 
  2  # 
  3  # Max E. Kuznecov ~syhpoon <syhpoon@syhpoon.name> 2008 
  4  # 
  5  # This file is part of XYZCommander. 
  6  # XYZCommander is free software: you can redistribute it and/or modify 
  7  # it under the terms of the GNU Lesser Public License as published by 
  8  # the Free Software Foundation, either version 3 of the License, or 
  9  # (at your option) any later version. 
 10  # XYZCommander is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 13  # GNU Lesser Public License for more details. 
 14  # You should have received a copy of the GNU Lesser Public License 
 15  # along with XYZCommander. If not, see <http://www.gnu.org/licenses/>. 
 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   
25 -class FlatParser(BaseParser):
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
52 - def __init__(self, opt=None):
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 # Finish assembling value 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
146 - def _process_state_variable(self, word):
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
159 - def _process_state_assign(self, word):
160 if word != self.assignchar: 161 self.error(msg=(word, self.assignchar), 162 etype=self.error_unexpected) 163 else: 164 self._state = self.STATE_VALUE 165 self._lexer.escaping_on()
166 167 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 168
169 - def _process_state_value(self, word):
170 self._current_list.append(word) 171 self._state = self.STATE_LIST_VALUE
172 173 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 174
175 - def _process_state_list_value(self, word):
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" % str(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
204 - def _process_state_delim(self, word):
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
217 - def _cleanup(self):
218 self._parsed = 0 219 self._state = self.STATE_VARIABLE 220 self._varname = None 221 self._result = ParsedData()
222 223 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 224
225 - def _check_complete(self):
226 if self._state not in (self.STATE_VARIABLE, self.STATE_DELIM): 227 self.error(_(u"Unterminated expression"))
228