Bug 463982 - Drop configure support for cairo-mac widget toolkit, r=ted
[wine-gecko.git] / config / Expression.py
blobf26a8f5cba8434786dbc661ddd3b9cd88b5c2326
1 # ***** BEGIN LICENSE BLOCK *****
2 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 # The contents of this file are subject to the Mozilla Public License Version
5 # 1.1 (the "License"); you may not use this file except in compliance with
6 # the License. You may obtain a copy of the License at
7 # http://www.mozilla.org/MPL/
9 # Software distributed under the License is distributed on an "AS IS" basis,
10 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 # for the specific language governing rights and limitations under the
12 # License.
14 # The Original Code is Mozilla build system.
16 # The Initial Developer of the Original Code is
17 # Mozilla Foundation.
18 # Portions created by the Initial Developer are Copyright (C) 2007
19 # the Initial Developer. All Rights Reserved.
21 # Contributor(s):
22 # Axel Hecht <axel@pike.org>
24 # Alternatively, the contents of this file may be used under the terms of
25 # either the GNU General Public License Version 2 or later (the "GPL"), or
26 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 # in which case the provisions of the GPL or the LGPL are applicable instead
28 # of those above. If you wish to allow use of your version of this file only
29 # under the terms of either the GPL or the LGPL, and not to allow others to
30 # use your version of this file under the terms of the MPL, indicate your
31 # decision by deleting the provisions above and replace them with the notice
32 # and other provisions required by the GPL or the LGPL. If you do not delete
33 # the provisions above, a recipient may use your version of this file under
34 # the terms of any one of the MPL, the GPL or the LGPL.
36 # ***** END LICENSE BLOCK *****
38 """
39 Parses and evaluates simple statements for Preprocessor:
41 Expression currently supports the following grammar, whitespace is ignored:
43 expression :
44 unary ( ( '==' | '!=' ) unary ) ? ;
45 unary :
46 '!'? value ;
47 value :
48 [0-9]+ # integer
49 | \w+ # string identifier or value;
50 """
52 import re
54 class Expression:
55 def __init__(self, expression_string):
56 """
57 Create a new expression with this string.
58 The expression will already be parsed into an Abstract Syntax Tree.
59 """
60 self.content = expression_string
61 self.offset = 0
62 self.__ignore_whitespace()
63 self.e = self.__get_equality()
64 if self.content:
65 raise Expression.ParseError, self
67 def __get_equality(self):
68 """
69 Production: unary ( ( '==' | '!=' ) unary ) ?
70 """
71 if not len(self.content):
72 return None
73 rv = Expression.__AST("equality")
74 # unary
75 rv.append(self.__get_unary())
76 self.__ignore_whitespace()
77 if not re.match('[=!]=', self.content):
78 # no equality needed, short cut to our prime unary
79 return rv[0]
80 # append operator
81 rv.append(Expression.__ASTLeaf('op', self.content[:2]))
82 self.__strip(2)
83 self.__ignore_whitespace()
84 rv.append(self.__get_unary())
85 self.__ignore_whitespace()
86 return rv
88 def __get_unary(self):
89 """
90 Production: '!'? value
91 """
92 # eat whitespace right away, too
93 not_ws = re.match('!\s*', self.content)
94 if not not_ws:
95 return self.__get_value()
96 rv = Expression.__AST('not')
97 self.__strip(not_ws.end())
98 rv.append(self.__get_value())
99 self.__ignore_whitespace()
100 return rv
102 def __get_value(self):
104 Production: ( [0-9]+ | \w+)
105 Note that the order is important, and the expression is kind-of
106 ambiguous as \w includes 0-9. One could make it unambiguous by
107 removing 0-9 from the first char of a string literal.
109 rv = None
110 word_len = re.match('[0-9]*', self.content).end()
111 if word_len:
112 rv = Expression.__ASTLeaf('int', int(self.content[:word_len]))
113 else:
114 word_len = re.match('\w*', self.content).end()
115 if word_len:
116 rv = Expression.__ASTLeaf('string', self.content[:word_len])
117 else:
118 raise Expression.ParseError, self
119 self.__strip(word_len)
120 self.__ignore_whitespace()
121 return rv
123 def __ignore_whitespace(self):
124 ws_len = re.match('\s*', self.content).end()
125 self.__strip(ws_len)
126 return
128 def __strip(self, length):
130 Remove a given amount of chars from the input and update
131 the offset.
133 self.content = self.content[length:]
134 self.offset += length
136 def evaluate(self, context):
138 Evaluate the expression with the given context
141 # Helper function to evaluate __get_equality results
142 def eval_equality(tok):
143 left = opmap[tok[0].type](tok[0])
144 right = opmap[tok[2].type](tok[2])
145 rv = left == right
146 if tok[1].value == '!=':
147 rv = not rv
148 return rv
149 # Mapping from token types to evaluator functions
150 # Apart from (non-)equality, all these can be simple lambda forms.
151 opmap = {
152 'equality': eval_equality,
153 'not': lambda tok: not opmap[tok[0].type](tok[0]),
154 'string': lambda tok: context[tok.value],
155 'int': lambda tok: tok.value}
157 return opmap[self.e.type](self.e);
159 class __AST(list):
161 Internal class implementing Abstract Syntax Tree nodes
163 def __init__(self, type):
164 self.type = type
165 super(self.__class__, self).__init__(self)
167 class __ASTLeaf:
169 Internal class implementing Abstract Syntax Tree leafs
171 def __init__(self, type, value):
172 self.value = value
173 self.type = type
174 def __str__(self):
175 return self.value.__str__()
176 def __repr__(self):
177 return self.value.__repr__()
179 class ParseError(StandardError):
181 Error raised when parsing fails.
182 It has two members, offset and content, which give the offset of the
183 error and the offending content.
185 def __init__(self, expression):
186 self.offset = expression.offset
187 self.content = expression.content[:3]
188 def __str__(self):
189 return 'Unexpected content at offset %i, "%s"'%(self.offset, self.content)
191 class Context(dict):
193 This class holds variable values by subclassing dict, and while it
194 truthfully reports True and False on
196 name in context
198 it returns the variable name itself on
200 context["name"]
202 to reflect the ambiguity between string literals and preprocessor
203 variables.
205 def __getitem__(self, key):
206 if key in self:
207 return super(self.__class__, self).__getitem__(key)
208 return key