From 014a4bb756f7ef71ccb4a2ee2e386ff81a6c4929 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Thu, 7 Jul 2005 12:49:52 +0000 Subject: [PATCH] [pymbolic @ Arch-1:inform@tiker.net--iam-2005%pymbolic--mainline--1.0--patch-22] Made compiler usable. --- src/__init__.py | 37 +++++++++++++++++++++--------------- src/compiler.py | 28 +++++++++++++-------------- src/mapper/__init__.py | 11 +++++++++-- src/mapper/evaluator.py | 3 +++ src/mapper/hash_generator.py | 5 +++++ src/mapper/stringifier.py | 5 +++++ src/mapper/substitutor.py | 16 +++++++++++++--- src/parser.py | 13 ++++++++++++- src/primitives.py | 33 ++++++++++++++++++++++++++++++++ 9 files changed, 116 insertions(+), 35 deletions(-) diff --git a/src/__init__.py b/src/__init__.py index 7213b27..197c9aa 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -1,27 +1,34 @@ import parser import compiler -import mapper.evaluator -import mapper.stringifier -import mapper.dependency -import mapper.substitutor -import mapper.differentiator +import pymbolic.mapper.evaluator +import pymbolic.mapper.stringifier +import pymbolic.mapper.dependency +import pymbolic.mapper.substitutor +import pymbolic.mapper.differentiator +import pymbolic.primitives -parse = parser.parse -evaluate = mapper.evaluator.evaluate -compile = compiler.compile -stringify = mapper.stringifier.stringify -is_constant = mapper.dependency.is_constant -get_dependencies = mapper.dependency.get_dependencies -substitute = mapper.substitutor.substitute -differentiate = mapper.differentiator.differentiate +var = pymbolic.primitives.Variable +const = pymbolic.primitives.Constant + +parse = pymbolic.parser.parse +evaluate = pymbolic.mapper.evaluator.evaluate +compile = pymbolic.compiler.compile +stringify = pymbolic.mapper.stringifier.stringify +is_constant = pymbolic.mapper.dependency.is_constant +get_dependencies = pymbolic.mapper.dependency.get_dependencies +substitute = pymbolic.mapper.substitutor.substitute +differentiate = pymbolic.mapper.differentiator.differentiate if __name__ == "__main__": import math - ex = parse("0 + 4.3e3j * alpha * cos(x+pi)") + 5 + ex = parse("0 + 4.3e3j * alpha * math.cos(x+math.pi)") + 5 print ex - print evaluate(ex, {"alpha":5, "cos":math.cos, "x":-math.pi, "pi":math.pi}) + print evaluate(ex, {"alpha":5, "math":math, "x":-math.pi}) + compiled = compile(substitute(ex, {var("alpha"): const(5)})) + print compiled(-math.pi) + print hash(ex) print is_constant(ex) print substitute(ex, {"alpha": ex}) diff --git a/src/compiler.py b/src/compiler.py index 9a930da..465323f 100644 --- a/src/compiler.py +++ b/src/compiler.py @@ -1,3 +1,7 @@ +import sets +import math + +import pymbolic import pymbolic.mapper.stringifier import pymbolic.mapper.dependency @@ -7,31 +11,27 @@ import pymbolic.mapper.dependency class CompiledExpression: """This class is necessary to make compiled expressions picklable.""" - def __init__(self, expression, variables = []): + def __init__(self, expression, context = {"math": math}, variables = []): self._Expression = expression - self._VariableSubstitutions = variable_substitutions.copy() + self._Context = context self._Variables = variables[:] self.__compile__() def __compile__(self): - used_variables = get_dependencies(self.Expression) - mentioned_variables sets.Set(self._Variables) - used_variables -= mentioned_variables + used_variables = pymbolic.get_dependencies(self._Expression) + used_variables -= sets.Set(self._Variables) + used_variables -= sets.Set(pymbolic.var(key) for key in self._Context.keys()) used_variables = list(used_variables) used_variables.sort() all_variables = self._Variables + used_variables - AAA FIXME sort order on Variables and Subscripts - - pythonified = mapper.stringifier.stringify(self.Expression) - if len(self.Variables) == 0 and len(used_variables) != 0: - variable_str = ",".join(used_variables) - else: - variable_str = ",".join(self.Variables) - self.__call__ = eval("lambda %s:%s" % (variable_str, pythonified)) + expr_s = "lambda %s:%s" % (",".join(str(v) for v in all_variables), + str(self._Expression)) + print expr_s + self.__call__ = eval(expr_s, self._Context) def __getinitargs__(self): - return self._Expression, self._VariableSubstitutions, self._Variables + return self._Expression, self._Context, self._Variables def __getstate__(self): return None diff --git a/src/mapper/__init__.py b/src/mapper/__init__.py index 65d485f..9c78539 100644 --- a/src/mapper/__init__.py +++ b/src/mapper/__init__.py @@ -8,8 +8,11 @@ class CombineMapper: for child in expr.parameters]) def map_subscript(self, expr): - return expr.__class__(expr.aggregate.invoke_mapper(self), - expr.index.invoke_mapper(self)) + return self.combine([expr.aggregate.invoke_mapper(self), + expr.index.invoke_mapper(self)]) + + def map_lookup(self, expr): + return expr.aggregate.invoke_mapper(self) def map_negation(self, expr): return expr.child.invoke_mapper(self) @@ -53,6 +56,10 @@ class IdentityMapper: return expr.__class__(expr.aggregate.invoke_mapper(self), expr.index.invoke_mapper(self)) + def map_lookup(self, expr): + return expr.__class__(expr.aggregate.invoke_mapper(self), + expr.name) + def map_negation(self, expr): return expr.__class__(expr.child.invoke_mapper(self)) diff --git a/src/mapper/evaluator.py b/src/mapper/evaluator.py index 13c59ab..c180d21 100644 --- a/src/mapper/evaluator.py +++ b/src/mapper/evaluator.py @@ -16,6 +16,9 @@ class EvaluationMapper: def map_subscript(self, expr): return expr.aggregate.invoke_mapper(self)[expr.index.invoke_mapper(self)] + def map_lookup(self, expr): + return getattr(expr.aggregate.invoke_mapper(self), expr.name) + def map_negation(self, expr): return -expr.child.invoke_mapper(self) diff --git a/src/mapper/hash_generator.py b/src/mapper/hash_generator.py index f7d1494..db2735f 100644 --- a/src/mapper/hash_generator.py +++ b/src/mapper/hash_generator.py @@ -13,6 +13,11 @@ class HashMapper: ^ hash(expr.aggregate) \ ^ hash(expr.index) + def map_lookup(self, expr): + return 0x183 \ + ^ hash(expr.aggregate) \ + ^ hash(expr.name) + def map_negation(self, expr): return ~ hash(expr.child) diff --git a/src/mapper/stringifier.py b/src/mapper/stringifier.py index 0df6794..673c59a 100644 --- a/src/mapper/stringifier.py +++ b/src/mapper/stringifier.py @@ -15,6 +15,11 @@ class StringifyMapper: (expr.aggregate.invoke_mapper(self), expr.index.invoke_mapper(self)) + def map_lookup(self, expr): + return "%s.%s" % \ + (expr.aggregate.invoke_mapper(self), + expr.name) + def map_negation(self, expr): return "-%s" % expr.child.invoke_mapper(self) diff --git a/src/mapper/substitutor.py b/src/mapper/substitutor.py index 2b0afc6..8f26d47 100644 --- a/src/mapper/substitutor.py +++ b/src/mapper/substitutor.py @@ -1,9 +1,9 @@ -import mapper +import pymbolic.mapper -class SubstitutionMapper(mapper.IdentityMapper): +class SubstitutionMapper(pymbolic.mapper.IdentityMapper): def __init__(self, variable_assignments): self.Assignments = variable_assignments @@ -13,7 +13,17 @@ class SubstitutionMapper(mapper.IdentityMapper): except KeyError: return expr - map_subscript = map_variable + def map_subscript(self, expr): + try: + return self.Assignments[expr] + except KeyError: + return pymbolic.mapper.IdentityMapper.map_subscript(self, expr) + + def map_lookup(self, expr): + try: + return self.Assignments[expr] + except KeyError: + return pymbolic.mapper.IdentityMapper.map_lookup(self, expr) diff --git a/src/parser.py b/src/parser.py index 163e00d..9e4a0d0 100644 --- a/src/parser.py +++ b/src/parser.py @@ -16,6 +16,7 @@ _closebracket = intern("closebracket") _identifier = intern("identifier") _whitespace = intern("whitespace") _comma = intern("comma") +_dot = intern("dot") _LEX_TABLE = [ (_imaginary, (_float, pytools.lex.RE("j"))), @@ -35,6 +36,7 @@ _LEX_TABLE = [ (_identifier, pytools.lex.RE(r"[a-zA-Z_]+")), (_whitespace, pytools.lex.RE("[ \n\t]*")), (_comma, pytools.lex.RE(",")), + (_dot, pytools.lex.RE(".")), ] _PREC_PLUS = 10 @@ -74,6 +76,7 @@ def parse(expr_str): pstate.advance() result = parse_expression(pstate) pstate.expect(_closepar) + pstate.advance() return result left_exp = parse_terminal(pstate) @@ -96,16 +99,24 @@ def parse(expr_str): left_exp = primitives.Call(left_exp, tuple(parse_expr_list(pstate))) pstate.expect(_closepar) + pstate.advance() did_something = True elif next_tag is _openbracket and _PREC_CALL >= min_precedence: pstate.advance() pstate.expect_not_end() left_exp = primitives.Subscript(left_exp, parse_expression(pstate)) pstate.expect(_closebracket) + pstate.advance() + did_something = True + elif next_tag is _dot and _PREC_CALL >= min_precedence: + pstate.advance() + pstate.expect(_identifier) + left_exp = primitives.ElementLookup(left_exp, pstate.next_str()) + pstate.advance() did_something = True elif next_tag is _plus and _PREC_PLUS >= min_precedence: pstate.advance() - left_exp = parse_expression(pstate, _PREC_PLUS) + left_exp += parse_expression(pstate, _PREC_PLUS) did_something = True elif next_tag is _minus and _PREC_PLUS >= min_precedence: pstate.advance() diff --git a/src/primitives.py b/src/primitives.py index d2cce49..6e7fea6 100644 --- a/src/primitives.py +++ b/src/primitives.py @@ -120,6 +120,12 @@ class Constant(Expression): return self._Value value = property(_value) + def __lt__(self, other): + if isinstance(other, Variable): + return self._Value.__lt__(other._Value) + else: + return NotImplemented + def __eq__(self, other): return isinstance(other, Constant) and self._Value == other._Value @@ -233,6 +239,12 @@ class Variable(Expression): return self._Name name = property(_name) + def __lt__(self, other): + if isinstance(other, Variable): + return self._Name.__lt__(other._Name) + else: + return NotImplemented + def __eq__(self, other): return isinstance(other, Variable) and self._Name == other._Name @@ -284,6 +296,27 @@ class Subscript(Expression): def invoke_mapper(self, mapper): return mapper.map_subscript(self) +class ElementLookup(Expression): + def __init__(self, aggregate, name): + self._Aggregate = aggregate + self._Name = name + + def _aggregate(self): + return self._Aggregate + aggregate = property(_aggregate) + + def _name(self): + return self._Name + name = property(_name) + + def __eq__(self, other): + return isinstance(other, Subscript) \ + and (self._Aggregate == other._Aggregate) \ + and (self._Name == other._Name) + + def invoke_mapper(self, mapper): + return mapper.map_lookup(self) + class Negation(Expression): def __init__(self, child): self._Child = child -- GitLab