Package lepl :: Package contrib :: Module matchers
[hide private]
[frames] | no frames]

Source Code for Module lepl.contrib.matchers

  1   
  2  # The contents of this file are subject to the Mozilla Public License 
  3  # (MPL) Version 1.1 (the "License"); you may not use this file except 
  4  # in compliance with the License. You may obtain a copy of the License 
  5  # at http://www.mozilla.org/MPL/ 
  6  # 
  7  # Software distributed under the License is distributed on an "AS IS" 
  8  # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 
  9  # the License for the specific language governing rights and 
 10  # limitations under the License. 
 11  # 
 12  # The Original Code is LEPL (http://www.acooke.org/lepl) 
 13  # The Initial Developer of the Original Code is Andrew Cooke. 
 14  # Portions created by the Initial Developer are Copyright (C) 2009-2010 
 15  # Andrew Cooke (andrew@acooke.org). All Rights Reserved. 
 16  # 
 17  # Contributor(s): 
 18  # - "mereandor" / mereandor at gmail dot com (Roman) 
 19  # Portions created by the Contributors are Copyright (C) 2009 
 20  # The Contributors.  All Rights Reserved. 
 21  # 
 22  # Alternatively, the contents of this file may be used under the terms 
 23  # of the LGPL license (the GNU Lesser General Public License, 
 24  # http://www.gnu.org/licenses/lgpl.html), in which case the provisions 
 25  # of the LGPL License are applicable instead of those above. 
 26  # 
 27  # If you wish to allow use of your version of this file only under the 
 28  # terms of the LGPL License and not to allow others to use your version 
 29  # of this file under the MPL, indicate your decision by deleting the 
 30  # provisions above and replace them with the notice and other provisions 
 31  # required by the LGPL License.  If you do not delete the provisions 
 32  # above, a recipient may use your version of this file under either the 
 33  # MPL or the LGPL License. 
 34   
 35  ''' 
 36  Contributed matchers. 
 37  ''' 
 38   
 39  from copy import copy 
 40   
 41  from lepl.matchers.derived import Optional 
 42  from lepl.matchers.combine import And, Or, BaseSearch 
 43  from lepl.matchers.matcher import is_child 
 44  from lepl.matchers.transform import Transform 
 45  from lepl.matchers.operators import _BaseSeparator 
 46   
 47   
 48  # (c) 2009 "mereandor" / mereandor at gmail dot com (Roman), Andrew Cooke 
 49   
 50  # pylint: disable-msg=R0903 
51 -class SmartSeparator2(_BaseSeparator):
52 ''' 53 A substitute `Separator` with different semantics for optional matchers. 54 This identifies optional matchers by type (whether they subclass 55 `BaseSearch`) and then constructs a replacement that adds space only 56 when both matchers are used. 57 58 See also `SmartSeparator1`, which is more general but less efficient. 59 ''' 60
61 - def _replacements(self, separator):
62 ''' 63 Provide alternative definitions of '&` and `[]`. 64 ''' 65 66 def non_optional_copy(matcher): 67 ''' 68 Check whether a matcher is optional and, if so, make it not so. 69 ''' 70 # both of the "copy" calls below make me nervous - it's not the 71 # way the rest of lepl works - but i don't have any specific 72 # criticism, or a good alternative. 73 required, optional = matcher, False 74 if isinstance(matcher, Transform): 75 temp, optional = non_optional_copy(matcher.matcher) 76 if optional: 77 required = copy(matcher) 78 required.matcher = temp 79 elif is_child(matcher, BaseSearch, fail=False): 80 # this introspection only works because Repeat sets named 81 # (ie kargs) arguments. 82 optional = (matcher.start == 0) 83 if optional: 84 required = copy(matcher) 85 required.start = 1 86 if required.stop == 1: 87 required = required.first 88 return required, optional
89 90 # pylint: disable-msg=W0141 91 def and_(matcher_a, matcher_b): 92 ''' 93 Combine two matchers. 94 ''' 95 (requireda, optionala) = non_optional_copy(matcher_a) 96 (requiredb, optionalb) = non_optional_copy(matcher_b) 97 98 if not (optionala or optionalb): 99 return And(matcher_a, separator, matcher_b) 100 else: 101 matcher = Or( 102 *filter((lambda x: x is not None), [ 103 And(Optional(And(requireda, separator)), requiredb) 104 if optionala else None, 105 And(requireda, Optional(And(separator, requiredb))) 106 if optionalb else None])) 107 if optionala and optionalb: 108 # making this explicit allows chaining (we can detect it 109 # when called again in a tree of "ands") 110 matcher = Optional(matcher) 111 return matcher
112 return (and_, self._repeat(separator)) 113