~ubuntu-branches/ubuntu/maverick/sugar-calculate-activity/maverick-201007230209

« back to all changes in this revision

Viewing changes to eqnparser.py

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2009-10-25 19:24:50 UTC
  • mfrom: (1.1.4 upstream) (0.4.4 sid)
  • Revision ID: james.westby@ubuntu.com-20091025192450-aprz7n98niflonce
Tags: 30-3
* Update python-sugar.mk to replace superfluous COPYING files with
  symlinks.
* Drop COPYING removal (python-sugar.mk replaces with symlink now).
* Fix python-sugar.mk to include both simple and versioned activity
  packages in DEB_PYTHON_SUGAR_PACKAGES by default. This fixes
  sugar-calculate-activity virtually empty binary package, and closes:
  bug#552332, thanks to Sascha Silbe.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- coding: UTF-8 -*-
2
 
# eqnparser.py, generic equation parser by Reinier Heeres <reinier@heeres.eu>
3
 
#
4
 
# This program is free software; you can redistribute it and/or modify
5
 
# it under the terms of the GNU General Public License as published by
6
 
# the Free Software Foundation; either version 2 of the License, or
7
 
# (at your option) any later version.
8
 
#
9
 
# This program is distributed in the hope that it will be useful,
10
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
# GNU General Public License for more details.
13
 
#
14
 
# You should have received a copy of the GNU General Public License
15
 
# along with this program; if not, write to the Free Software
16
 
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
 
#
18
 
# Change log:
19
 
#    2007-07-03: rwh, first version
20
 
 
21
 
import logging
22
 
_logger = logging.getLogger('EqnParser')
23
 
 
24
 
import types
25
 
from mathlib import MathLib
26
 
from plotlib import PlotLib
27
 
from eqnparserhelp import EqnParserHelp
28
 
 
29
 
from rational import Rational
30
 
 
31
 
from gettext import gettext as _
32
 
 
33
 
_generic_error = _('Parse error')
34
 
 
35
 
class Equation:
36
 
    def __init__(self, eqn):
37
 
        self.equation = eqn
38
 
 
39
 
class ParserState:
40
 
    OK = 1
41
 
    PARSE_ERROR = 2
42
 
 
43
 
    def __init__(self, str):
44
 
        self.str = str
45
 
        self.strlen = len(str)
46
 
        if self.strlen > 0:
47
 
            self.char = str[0]
48
 
        else:
49
 
            self.char = None
50
 
        self.ofs = 0
51
 
        self.level = -1
52
 
        self.result_type = EqnParser.TYPE_UNKNOWN
53
 
        self.error_code = self.OK
54
 
        self.error_msg = ""
55
 
        self.error_range = (0, 0)
56
 
 
57
 
    def state_string(self):
58
 
        return _('level: %d, ofs %d') % (self.level, self.ofs)
59
 
 
60
 
    def more(self):
61
 
        return self.error_code == self.OK and self.ofs < self.strlen
62
 
 
63
 
    def next(self):
64
 
        self.ofs += 1
65
 
        if self.ofs < self.strlen:
66
 
            self.char = self.str[self.ofs]
67
 
        else:
68
 
            self.char = None
69
 
        return self.char
70
 
 
71
 
    def prev(self):
72
 
        self.ofs -= 1
73
 
        if self.ofs < self.strlen and self.ofs >= 0:
74
 
            self.char = self.str[self.ofs]
75
 
        else:
76
 
            self.char = None
77
 
        return self.char
78
 
 
79
 
    def set_ofs(self, o):
80
 
        self.ofs = o
81
 
        self.char = self.str[o]
82
 
 
83
 
    def inc_level(self):
84
 
        self.level += 1
85
 
 
86
 
    def dec_level(self):
87
 
        self.level -= 1
88
 
 
89
 
    def set_type(self, t):
90
 
        if self.result_type == EqnParser.TYPE_UNKNOWN or t is EqnParser.TYPE_SYMBOLIC:
91
 
            self.result_type = t
92
 
            return True
93
 
        elif self.result_type != t:
94
 
            _logger.debug('Type error')
95
 
            return False
96
 
        else:
97
 
            return True
98
 
 
99
 
    def set_error(self, c, msg=None, range=None):
100
 
        self.error_code = c
101
 
        if msg is not None:
102
 
            self.error_msg = msg
103
 
        if range is not None:
104
 
            _logger.debug('Setting range: %r', range)
105
 
            self.error_range = range
106
 
        else:
107
 
            _logger.debug('Setting offset: %d', self.ofs)
108
 
            self.error_range = (self.ofs, self.ofs + 1)
109
 
 
110
 
    def get_error(self):
111
 
        return self.error_code
112
 
 
113
 
    def set_error_range(self, r):
114
 
        self.error_range = r
115
 
 
116
 
    def format_error(self):
117
 
        msg = _("Error at %d") % (self.error_range[0])
118
 
        if self.error_msg is not None and len(self.error_msg) > 0:
119
 
            msg += ": %s" % (self.error_msg)
120
 
        return msg
121
 
 
122
 
    def copy_error(self, ps):
123
 
        """Copy error state from recursively created ParserState object"""
124
 
        self.error_code = ps.error_code
125
 
        self.error_msg = ps.error_msg
126
 
        self.error_range = (ps.error_range[0] + ps.ofs, ps.error_range[1] + ps.ofs)
127
 
 
128
 
class EqnParser:
129
 
    OP_INVALID = -1
130
 
    OP_PRE = 1
131
 
    OP_POST = 2
132
 
    OP_DIADIC = 3
133
 
    OP_ASSIGN = 4
134
 
 
135
 
    INVALID_OP = ('err', OP_INVALID, 0, lambda x: False)
136
 
 
137
 
    NAME_CHARS = u'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789 '
138
 
    DIGITS = u'0123456789'
139
 
    SPACE_CHARS = u'\t \r\n'
140
 
 
141
 
# These will be filled from register_operator
142
 
    OP_START_CHARS = u""
143
 
    OP_CHARS = u""
144
 
 
145
 
    TYPE_UNKNOWN = 1
146
 
    TYPE_INT = 2
147
 
    TYPE_FLOAT = 3
148
 
    TYPE_BOOL = 4
149
 
    TYPE_SYMBOLIC = 5
150
 
 
151
 
    def __init__(self, ml=None):
152
 
        if ml is None:
153
 
            self.ml = MathLib()
154
 
        else:
155
 
            self.ml = ml
156
 
 
157
 
        self.ps = None
158
 
 
159
 
        self.pl = PlotLib(self)
160
 
 
161
 
        self.variables = {}
162
 
        self.parse_var = {}     # Whether or not to parse this variable recursively
163
 
        self.functions = {}
164
 
        self.operators = []
165
 
 
166
 
        self.cached_diadic_ops = None
167
 
        self.cached_pre_ops = None
168
 
        self.cached_post_ops = None
169
 
 
170
 
        self.register_function('exp', lambda x: self.ml.exp(x[0]), {"nargs": 1})
171
 
        self.register_function('ln', lambda x: self.ml.ln(x[0]), {"nargs": 1})
172
 
        self.register_function('log', lambda x: self.ml.log10(x[0]), {"nargs": 1})
173
 
        self.register_function('log10', lambda x: self.ml.log10(x[0]), {"nargs": 1})
174
 
        self.register_function('pow', lambda x: self.ml.pow(x[0], x[1]), {"nargs": 2})
175
 
 
176
 
        self.register_function('sqrt', lambda x: self.ml.sqrt(x[0]), {"nargs": 1})
177
 
 
178
 
        self.register_function('sin', lambda x: self.ml.sin(x[0]), {"nargs": 1})
179
 
        self.register_function('cos', lambda x: self.ml.cos(x[0]), {"nargs": 1})
180
 
        self.register_function('tan', lambda x: self.ml.tan(x[0]), {"nargs": 1})
181
 
 
182
 
        self.register_function('asin', lambda x: self.ml.asin(x[0]), {"nargs": 1})
183
 
        self.register_function('acos', lambda x: self.ml.acos(x[0]), {"nargs": 1})
184
 
        self.register_function('atan', lambda x: self.ml.atan(x[0]), {"nargs": 1})
185
 
 
186
 
        self.register_function('sinh', lambda x: self.ml.sinh(x[0]), {"nargs": 1})
187
 
        self.register_function('cosh', lambda x: self.ml.cosh(x[0]), {"nargs": 1})
188
 
        self.register_function('tanh', lambda x: self.ml.tanh(x[0]), {"nargs": 1})
189
 
 
190
 
        self.register_function('asinh', lambda x: self.ml.asinh(x[0]), {"nargs": 1})
191
 
        self.register_function('acosh', lambda x: self.ml.acosh(x[0]), {"nargs": 1})
192
 
        self.register_function('atanh', lambda x: self.ml.atanh(x[0]), {"nargs": 1})
193
 
 
194
 
        self.register_function('round', lambda x: self.ml.round(x[0]), {"nargs": 1})
195
 
        self.register_function('floor', lambda x: self.ml.floor(x[0]), {"nargs": 1})
196
 
        self.register_function('ceil', lambda x: self.ml.ceil(x[0]), {"nargs": 1})
197
 
 
198
 
        self.register_function('rand', lambda x: self.ml.rand_float(), {"nargs": 0})
199
 
        self.register_function('randint', lambda x: self.ml.rand_int(), {"nargs": 0})
200
 
 
201
 
        self.register_function('mod', lambda x: self.ml.mod(x[0], x[1]), {"nargs": 2})
202
 
 
203
 
        self.register_function('factorize', lambda x: self.ml.factorize(x[0]), {"nargs": 1})
204
 
 
205
 
        self.register_function('plot', lambda x: self.pl.plot(x[0], x[1]), {"nargs": 2, 'parse_options': False})
206
 
 
207
 
        self.register_function('help', lambda x: EqnParserHelp.help(x[0]), {"nargs": 1, 'parse_options': False})
208
 
 
209
 
        self.register_function('functions', lambda x: self.functions_string(), {"nargs": 0})
210
 
        self.register_function('variables', lambda x: self.variables_string(), {"nargs": 0})
211
 
        self.register_function('operators', lambda x: self.operators_string(), {"nargs": 0})
212
 
 
213
 
        self.register_operator('+', self.OP_DIADIC, 0, lambda x: self.ml.add(x[0], x[1]))
214
 
        self.register_operator('+', self.OP_PRE, 2, lambda x: x[0])
215
 
        self.register_operator('-', self.OP_DIADIC, 0, lambda x: self.ml.sub(x[0], x[1]))
216
 
        self.register_operator('-', self.OP_PRE, 2, lambda x: self.ml.negate(x[0]))
217
 
        self.register_operator('*', self.OP_DIADIC, 1, lambda x: self.ml.mul(x[0], x[1]))
218
 
        self.register_operator(u'⨯', self.OP_DIADIC, 1, lambda x: self.ml.mul(x[0], x[1]))
219
 
        self.register_operator(u'×', self.OP_DIADIC, 1, lambda x: self.ml.mul(x[0], x[1]))
220
 
        self.register_operator('/', self.OP_DIADIC, 1, lambda x: self.div_operator(x[0], x[1]))
221
 
        self.register_operator(u'÷', self.OP_DIADIC, 1, lambda x: self.div_operator(x[0], x[1]))
222
 
 
223
 
        self.register_operator('^', self.OP_DIADIC, 2, lambda x: self.ml.pow(x[0], x[1]))
224
 
        self.register_operator('**', self.OP_DIADIC, 2, lambda x: self.ml.pow(x[0], x[1]))
225
 
 
226
 
        self.register_operator('!', self.OP_POST, 0, lambda x: self.ml.factorial(x[0]))
227
 
 
228
 
        self.register_operator('&', self.OP_DIADIC, 0, lambda x: x[0] and x[1])
229
 
        self.register_function('and', lambda x: x[0] and x[1], {"nargs": 2})
230
 
        self.register_operator('|', self.OP_DIADIC, 0, lambda x: x[0] or x[1])
231
 
        self.register_function('or', lambda x: x[0] or x[1], {"nargs": 2})
232
 
        self.register_operator('!', self.OP_PRE, 0, lambda x: not x[0])
233
 
        self.register_function('not', lambda x: not x[0], {"nargs": 1})
234
 
 
235
 
#        self.register_operator('^', self.OP_PRE, 0, lambda x: not x[0])
236
 
        self.register_function('xor', lambda x: (x[0] and not x[1]) or (x[1] and not x[0]), {"nargs": 2})
237
 
 
238
 
        self.register_operator('=', self.OP_DIADIC, 0, lambda x: x[0] == x[1])
239
 
        self.register_operator('!=', self.OP_DIADIC, 0, lambda x: x[0] != x[1])
240
 
        self.register_operator('<', self.OP_DIADIC, 0, lambda x: x[0] < x[1])
241
 
        self.register_operator('>', self.OP_DIADIC, 0, lambda x: x[0] > x[1])
242
 
 
243
 
        self.register_operator('<<', self.OP_DIADIC, 0, lambda x: self.ml.shift_left(x[0], x[1]))
244
 
        self.register_operator('>>', self.OP_DIADIC, 0, lambda x: self.ml.shift_right(x[0], x[1]))
245
 
 
246
 
        self.register_operator('%', self.OP_DIADIC, 2, lambda x: self.ml.mod(x[0], x[1]))
247
 
 
248
 
        self.set_var('help',
249
 
            _("Use help(test) for help about 'test', or help(index) for the index"),
250
 
            parse=False)
251
 
 
252
 
    def register_function(self, name, f, opts):
253
 
        self.functions[name] = (f, opts)
254
 
        self.functions[_(name)] = (f, opts)
255
 
 
256
 
    def register_operator(self, op, type, presedence, f):
257
 
        self.operators.append((op, type, presedence, f))
258
 
 
259
 
        if op[0] not in self.OP_START_CHARS:
260
 
            self.OP_START_CHARS += op[0]
261
 
        for c in op:
262
 
            if c not in self.OP_CHARS:
263
 
                self.OP_CHARS += c
264
 
 
265
 
    def get_diadic_operators(self):
266
 
        if self.cached_diadic_ops == None:
267
 
            self.cached_diadic_ops = []
268
 
            for (op, type, presedence, f) in self.operators:
269
 
                if type == self.OP_DIADIC:
270
 
                    self.cached_diadic_ops.append(op)
271
 
        return self.cached_diadic_ops
272
 
 
273
 
    def get_pre_operators(self):
274
 
        if self.cached_pre_ops == None:
275
 
            self.cached_pre_ops = []
276
 
            for (op, type, presedence, f) in self.operators:
277
 
                if type == self.OP_PRE:
278
 
                    self.cached_pre_ops.append(op)
279
 
        return self.cached_pre_ops
280
 
 
281
 
    def get_post_operators(self):
282
 
        if self.cached_post_ops == None:
283
 
            self.cached_post_ops = []
284
 
            for (op, type, presedence, f) in self.operators:
285
 
                if type == self.OP_POST:
286
 
                    self.cached_post_ops.append(op)
287
 
        return self.cached_post_ops
288
 
 
289
 
    def reset_variable_level(self, level):
290
 
        return
291
 
#        for i in self.variables.keys():
292
 
#            self.variables[i].highest_level = level
293
 
 
294
 
    def set_var(self, name, val, parse=True):
295
 
        if type(val) is types.FloatType:
296
 
            self.variables[name] = self.ml.d(val)
297
 
        else:
298
 
            self.variables[name] = val
299
 
            self.parse_var[name] = parse
300
 
 
301
 
    def get_var(self, name):
302
 
        if name in self.variables:
303
 
            return self.variables[name]
304
 
        else:
305
 
            return None
306
 
 
307
 
    def lookup_var(self, name, ps):
308
 
        c = self.ml.get_constant(name)
309
 
        if c is not None:
310
 
            return c
311
 
 
312
 
        if name in self.variables.keys():
313
 
#            if self.variables[name].highest_level > 0 and self.variables[name].highest_level != ps.level:
314
 
#                _logger.error('EqnParser.lookup_var(): recursion detected')
315
 
#                return None
316
 
#            self.variables[name].highest_level = level
317
 
            if (type(self.variables[name]) is types.UnicodeType or type(self.variables[name]) is types.StringType) \
318
 
                and self.parse_var[name]:
319
 
                return self.parse(self.variables[name], reset=False)
320
 
            else:
321
 
                return self.variables[name]
322
 
        else:
323
 
            _logger.debug('variable %s not defined', name)
324
 
            ps.set_type(self.TYPE_SYMBOLIC)
325
 
            return None
326
 
 
327
 
    def get_vars(self):
328
 
        list = []
329
 
        for name in self.variables:
330
 
            list.append((name, self.variables[name]))
331
 
        return list
332
 
 
333
 
    def get_var_names(self, start=None):
334
 
        names = self.variables.keys()
335
 
        names.sort()
336
 
 
337
 
        if start is None:
338
 
            return names
339
 
 
340
 
        retnames = []
341
 
        for name in names:
342
 
            if name[:len(start)] == start:
343
 
                retnames.append(name)
344
 
        return retnames
345
 
 
346
 
    def get_function_names(self):
347
 
        names = self.functions.keys()
348
 
        names.sort()
349
 
        return names
350
 
 
351
 
    def eval_func(self, func, args, level):
352
 
        if func not in self.functions:
353
 
            _logger.error(_("Function '%s' not defined"), func)
354
 
            self.ps.set_error(ParserState.PARSE_ERROR, msg=_("Function '%s' not defined") % (func))
355
 
            return None
356
 
 
357
 
        (f, opts) = self.functions[func]
358
 
        if len(args) != opts['nargs']:
359
 
            _logger.error(_('Invalid number of arguments (%d instead of %d)'), len(args), opts['nargs'])
360
 
            self.ps.set_error(ParserState.PARSE_ERROR, msg=_('function takes %d args') % (opts['nargs']))
361
 
            return None
362
 
 
363
 
        if 'parse_options' in opts and opts['parse_options'] == False:
364
 
            pargs = args
365
 
        else:
366
 
            pargs = []
367
 
            for i in range(len(args)):
368
 
                pargs.append(self.parse(args[i], reset=False))
369
 
                if pargs[i] is None:
370
 
                    _logger.error(_('Unable to parse argument %d: \'%s\''), i, args[i])
371
 
                    self.ps.set_error(ParserState.PARSE_ERROR, msg=_('Unable to parse argument %d: \'%s\'') % (i, args[i]))
372
 
                    return None
373
 
 
374
 
        try:
375
 
            res = f(pargs)
376
 
 
377
 
# Maybe we should map exceptions to more obvious error messages
378
 
        except Exception, inst:
379
 
            res = None
380
 
            self.ps.set_error(ParserState.PARSE_ERROR, msg=_("Function error: %s") % (str(inst)))
381
 
 
382
 
        _logger.debug('Function \'%s\' returned %s', func, self.ml.format_number(res))
383
 
        return res
384
 
 
385
 
    def parse_number(self, ps):
386
 
        startofs = ps.ofs
387
 
 
388
 
# integer part
389
 
        while ps.more() and ps.char in self.DIGITS:
390
 
            ps.next()
391
 
 
392
 
# part after dot
393
 
        if ps.char == '.' or ps.char == self.ml.fraction_sep:
394
 
            ps.next()
395
 
            while ps.more() and ps.char in self.DIGITS:
396
 
                ps.next()
397
 
 
398
 
# exponent
399
 
        if ps.char is not None and ps.char in u'eE':
400
 
            ps.next()
401
 
            if ps.char is not None and ps.char in u'+-':
402
 
                ps.next()
403
 
            while ps.more() and ps.char in self.DIGITS:
404
 
                ps.next()
405
 
 
406
 
        _logger.debug('parse_number(): %d - %d: %s', startofs, ps.ofs, ps.str[startofs:ps.ofs])
407
 
        n = self.ml.parse_number(ps.str[startofs:ps.ofs])
408
 
        return n
409
 
 
410
 
    def valid_operator(self, opstr, left_val):
411
 
        for op_tuple in self.operators:
412
 
            (op, type, presedence, f) = op_tuple
413
 
            if op == opstr:
414
 
                if type == self.OP_DIADIC and left_val is not None:
415
 
                    return op_tuple
416
 
                elif type == self.OP_POST and left_val is not None:
417
 
                    return op_tuple
418
 
                elif type == self.OP_PRE and left_val is None:
419
 
                    return op_tuple
420
 
        return None
421
 
 
422
 
    def parse_operator(self, ps, left_val):
423
 
        startofs = ps.ofs
424
 
        op = None
425
 
        while ps.more() and ps.char in self.OP_CHARS:
426
 
            ps.next()
427
 
            op2 = self.valid_operator(ps.str[startofs:ps.ofs], left_val)
428
 
            if op2 is not None:
429
 
                op = op2
430
 
            elif op is not None:
431
 
                ps.prev()
432
 
                break
433
 
 
434
 
        if op is not None:
435
 
            _logger.debug('parse_operator(): %d - %d: %s', startofs, ps.ofs, ps.str[startofs:ps.ofs])
436
 
            return op
437
 
        else:
438
 
            return self.INVALID_OP
439
 
 
440
 
    def parse_func_args(self, ps):
441
 
        startofs = ps.ofs
442
 
        args = []
443
 
        pcount = 1
444
 
        while ps.more() and pcount > 0:
445
 
            if ps.char == ',' and pcount == 1:
446
 
                args.append(ps.str[startofs:ps.ofs])
447
 
                startofs = ps.ofs + 1
448
 
            elif ps.char == '(':
449
 
                pcount += 1
450
 
            elif ps.char == ')':
451
 
                pcount -= 1
452
 
                if pcount == 0 and (ps.ofs - startofs) > 0:
453
 
                    args.append(ps.str[startofs:ps.ofs])
454
 
            ps.next()
455
 
        _logger.debug('parse_func_args(): %d - %d: %r', startofs, ps.ofs, args)
456
 
        return args
457
 
 
458
 
    def parse_var_func(self, ps):
459
 
        startofs = ps.ofs
460
 
        while ps.more() and ps.char in self.NAME_CHARS:
461
 
            ps.next()
462
 
        name = ps.str[startofs:ps.ofs]
463
 
        name.strip(self.SPACE_CHARS)
464
 
        name.rstrip(self.SPACE_CHARS)
465
 
 
466
 
# handle function
467
 
        if ps.char == '(':
468
 
            ps.next()
469
 
            _logger.debug('parse_var_func(): function %d - %d: %s', startofs, ps.ofs, name)
470
 
            args = self.parse_func_args(ps)
471
 
            ret = self.eval_func(name, args, ps.level)
472
 
            if ret is None:
473
 
                ps.set_error_range((startofs, ps.ofs))
474
 
            return ret
475
 
 
476
 
# handle var
477
 
        else:
478
 
            _logger.debug('parse_var_func(): variable %d - %d: %s', startofs, ps.ofs, name)
479
 
            res = self.lookup_var(name, ps)
480
 
            if res is None:
481
 
                ps.set_error(ParserState.PARSE_ERROR, msg=_("Variable '%s' not defined") % (name), range=(startofs, ps.ofs))
482
 
            return res
483
 
 
484
 
    def _parse(self, ps, presedence=None):
485
 
        if presedence is None:
486
 
            ps.inc_level()
487
 
        _logger.debug('_parse(): %s, presedence: %r', ps.state_string(), presedence)
488
 
 
489
 
        op = None
490
 
        left_val = None
491
 
        right_val = None
492
 
 
493
 
        while ps.more():
494
 
#            _logger.debug('Looking at %r, ofs %d in %r', ps.char, ps.ofs, ps.str)
495
 
 
496
 
# Skip spaces
497
 
            if ps.char in self.SPACE_CHARS:
498
 
                ps.next()
499
 
 
500
 
# Left parenthesis: parse sub-expression
501
 
            elif ps.char == '(':
502
 
                if not (left_val is None or left_val is not None and op is not None):
503
 
                    _logger.error('Parse error (left parenthesis)')
504
 
                    ps.set_error(ParserState.PARSE_ERROR, msg=_("Left parenthesis unexpected"))
505
 
                    return None
506
 
 
507
 
                ps.next()
508
 
                left_val = self._parse(ps)
509
 
 
510
 
# Right parenthesis: return from parsing sub-expression
511
 
# -If we are looking ahead because of operator presedence return value
512
 
# -Else move to next character, decrease level and return value
513
 
            elif ps.char == ')':
514
 
                if presedence is not None:
515
 
                    if left_val is None:
516
 
                        _logger.error(_('Parse error (right parenthesis)'))
517
 
                        ps.set_error(ParserState.PARSE_ERROR, msg=_("Right parenthesis unexpected"))
518
 
                        return None
519
 
                    else:
520
 
                        _logger.debug('returning %s', self.ml.format_number(left_val))
521
 
                        return left_val
522
 
 
523
 
                if ps.level > 0:
524
 
                    ps.next()
525
 
                    ps.dec_level()
526
 
                    if left_val is None:
527
 
                        _logger.error(_('Parse error (right parenthesis, no left_val)'))
528
 
                        ps.set_error(ParserState.PARSE_ERROR, msg=_("Right parenthesis unexpected"))
529
 
                        return None
530
 
                    else:
531
 
                        _logger.debug('returning %s', self.ml.format_number(left_val))
532
 
                        return left_val
533
 
                else:
534
 
                    _logger.error(_('Parse error (right parenthesis, no level to close)'))
535
 
                    ps.set_error(ParserState.PARSE_ERROR, msg=_("Right parenthesis unexpected"))
536
 
                    return None
537
 
 
538
 
# Parse number
539
 
            elif ps.char == '.' or ps.char in self.DIGITS:
540
 
                if right_val is not None or left_val is not None:
541
 
                    _logger.error(_('Number not expected'))
542
 
                    ps.set_error(ParserState.PARSE_ERROR, msg=_("Number not expected"))
543
 
                    return None
544
 
 
545
 
                left_val = self.parse_number(ps)
546
 
 
547
 
# Parse operator
548
 
            elif ps.char in self.OP_START_CHARS:
549
 
                if op is not None:
550
 
                    ps.set_error(ParserState.PARSE_ERROR, msg=_("Operator not expected"))
551
 
                    return None
552
 
 
553
 
                startofs = ps.ofs
554
 
                op = self.parse_operator(ps, left_val)
555
 
                (opstr, otype, opres, of) = op
556
 
 
557
 
# Diadic operators
558
 
                if otype == self.OP_DIADIC:
559
 
                    if presedence is not None and opres <= presedence:
560
 
                        ps.set_ofs(startofs)
561
 
                        _logger.debug('returning %s (by presedence, %d)', self.ml.format_number(left_val), ps.ofs)
562
 
                        return left_val
563
 
                    else:
564
 
                        right_val = self._parse(ps, presedence=opres)
565
 
                        if right_val is None and self.ps.get_error() == ParserState.OK:
566
 
                            _logger.error(_('Parse error: number or variable expected'))
567
 
                            ps.set_error(ParserState.PARSE_ERROR, msg=_("Number or variable expected"))
568
 
                            return None
569
 
                        elif right_val is None:
570
 
                            return None
571
 
 
572
 
                        res = of([left_val, right_val])
573
 
                        _logger.debug('OP: %s (%r), %s (%r) ==> %s (%r)', self.ml.format_number(left_val), left_val, self.ml.format_number(right_val), right_val, self.ml.format_number(res), res)
574
 
                        left_val = res
575
 
                        right_val = None
576
 
                    op = None
577
 
 
578
 
# Operator that goes after value
579
 
                elif otype == self.OP_POST:
580
 
                    res = of([left_val])
581
 
                    _logger.debug('OP POST: %s ==> %s', self.ml.format_number(left_val), self.ml.format_number(res))
582
 
                    left_val = res
583
 
                    op = None
584
 
 
585
 
# Operator that goes before value
586
 
                elif otype == self.OP_PRE:
587
 
                    right_val = self._parse(ps, presedence=opres)
588
 
                    if right_val is None:
589
 
                        return None
590
 
                    left_val = of([right_val])
591
 
                    _logger.debug('OP PRE: %s ==> %s', self.ml.format_number(right_val), self.ml.format_number(left_val))
592
 
                    op = None
593
 
 
594
 
                elif otype == self.OP_INVALID:
595
 
                    _logger.debug('Invalid operator')
596
 
                    ps.set_error(ParserState.PARSE_ERROR, msg=_("Invalid operator"), range=(startofs, ps.ofs))
597
 
                    return None
598
 
 
599
 
# Parse variable or function
600
 
            else:
601
 
                if left_val is not None:
602
 
                    _logger.debug('Operator expected: %r', self.OP_START_CHARS)
603
 
                    ps.set_error(ParserState.PARSE_ERROR, msg=_("Operator expected"))
604
 
                    return None
605
 
 
606
 
                left_val = self.parse_var_func(ps)
607
 
 
608
 
        if not ps.more() and ps.level > 0:
609
 
            _logger.debug('Parse error: \')\' expected')
610
 
            ps.set_error(ParserState.PARSE_ERROR, msg=_("Right parenthesis unexpected"))
611
 
            return None
612
 
        elif op is None and left_val is not None:
613
 
            _logger.debug('returning %s', self.ml.format_number(left_val))
614
 
            return left_val
615
 
        else:
616
 
            _logger.error(_('_parse(): returning None'))
617
 
# Should be set somewhere already
618
 
#            ps.set_error(ParserState.PARSE_ERROR)
619
 
            return None
620
 
 
621
 
    def get_error_offset(self):
622
 
        return self.ps.error_range[0]
623
 
 
624
 
    def get_error_range(self):
625
 
        return self.ps.error_range
626
 
 
627
 
    def parse(self, eqn, reset=True):
628
 
        """Construct ParserState object and call _parse"""
629
 
 
630
 
        # Parse everything in unicode
631
 
        if type(eqn) is types.StringType:
632
 
            eqn = unicode(eqn)
633
 
 
634
 
        _logger.debug('parse(): %r', eqn)
635
 
        self.reset_variable_level(0)
636
 
 
637
 
        if reset:
638
 
            self.ps = None
639
 
 
640
 
        oldps = self.ps
641
 
        self.ps = ParserState(eqn)
642
 
        ret = self._parse(self.ps)
643
 
        if oldps is not None:
644
 
            oldps.copy_error(self.ps)
645
 
            self.ps = oldps
646
 
 
647
 
        return ret
648
 
 
649
 
    def functions_string(self):
650
 
        ret = ""
651
 
        for key in self.functions.keys():
652
 
            ret += key + " "
653
 
        return ret
654
 
 
655
 
    def variables_string(self):
656
 
        ret = ""
657
 
        for key in self.variables.keys():
658
 
            ret += key + " "
659
 
        return ret
660
 
 
661
 
    def operators_string(self):
662
 
        ret = ""
663
 
        for (op, type, p, f) in self.operators:
664
 
            ret += op + " "
665
 
        return ret
666
 
 
667
 
    def div_operator(self, a, b):
668
 
        if b == 0 or b == 0.0:
669
 
            return _('Undefined')
670
 
        if isinstance(a, Rational) or isinstance(b, Rational):
671
 
            return a / b
672
 
        elif self.ml.is_int(a) and float(self.ml.abs(a)) < 1e12 and \
673
 
                self.ml.is_int(b) and float(self.ml.abs(b)) < 1e12:
674
 
            return Rational(a, b)
675
 
        else:
676
 
            return self.ml.div(a, b)