def _compile_call(self, text, attribute_handlers=None): import compiler import types from compiler import ast, misc, pycodegen raise NotImplementedError('Incomplete') # TODO Make this work? def _generate(node): if node.type == node.TERM: return ast.Compare(ast.Const(node.value), [('in', ast.Name('text'))]) elif node.type == node.AND: return ast.And([_generate(node.left), _generate(node.right)]) elif node.type == node.OR: return ast.Or([_generate(node.left), _generate(node.right)]) elif node.type == node.NOT: return ast.Not(_generate(node.left)) elif node.type == node.ATTR: raise NotImplementedError qast = ast.Expression( ast.Lambda(['self', 'text', 'attribute_handlers'], [ast.Name('None')], 0, _generate(self))) misc.set_filename('<%s compiled query>' % self.__class__.__name__, qast) gen = pycodegen.ExpressionCodeGenerator(qast) self.__call__ = types.MethodType(eval(gen.getCode()), self, Query) return self.__call__(text)
def __init__(self, source, filename=None, lineno=-1, lookup='lenient'): """Create the code object, either from a string, or from an AST node. :param source: either a string containing the source code, or an AST node :param filename: the (preferably absolute) name of the file containing the code :param lineno: the number of the line on which the code was found :param lookup: the lookup class that defines how variables are looked up in the context. Can be either `LenientLookup` (the default), `StrictLookup`, or a custom lookup class """ if isinstance(source, basestring): self.source = source node = _parse(source, mode=self.mode) else: assert isinstance(source, ast.Node) self.source = '?' if self.mode == 'eval': node = ast.Expression(source) else: node = ast.Module(None, source) self.code = _compile(node, self.source, mode=self.mode, filename=filename, lineno=lineno) if lookup is None: lookup = LenientLookup elif isinstance(lookup, basestring): lookup = {'lenient': LenientLookup, 'strict': StrictLookup}[lookup] self._globals = lookup.globals()
def _compileAstMethod(self, name, expr): """ Produce a callable of a single argument with name C{name} that returns the value of the given AST. @param name: The name of the callable. @param expr: The AST to compile. """ f = self.function(name, expr) e = ast.Expression(f) e.filename = self.name c = ExpressionCodeGenerator(e).getCode() return FunctionType(c.co_consts[-1], globals())
def eval(self, frame): # fall-back for unknown expression nodes try: expr = ast.Expression(self.__obj__) expr.filename = '<eval>' self.__obj__.filename = '<eval>' co = pycodegen.ExpressionCodeGenerator(expr).getCode() result = frame.eval(co) except passthroughex: raise except: raise Failure(self) self.result = result self.explanation = self.explanation or frame.repr(self.result)
def compile(src, filename, mode='exec', showTree=False, importlogix=True, module=None): global lineno lineno = 0 global modulename modulename = module implogix = ast.Import([(logixModuleName, 'logix')]) prepend = importlogix and [implogix] or None if len(src) == 0: src = [None] try: if mode == "exec": statements = block(src, False, prepend) tree = ast.Module(None, statements) gen = pycodegen.ModuleCodeGenerator else: assert len(src) == 1 stmt = src[0] if mode == "single": statements = block([stmt], False, prepend=prepend) tree = ast.Module(None, statements) gen = pycodegen.InteractiveCodeGenerator elif mode == "eval": statements = block([stmt], True, prepend) tree = ast.Expression(statements) gen = pycodegen.ExpressionCodeGenerator else: raise ValueError("compile() 3rd arg must be 'exec' or " "'eval' or 'single'") except CompileError, exc: offset = None raise SyntaxError(str(exc), (filename, lineno, offset, None))