Contact: fumanchu@aminus.org

Log in as guest/geniusql to create tickets

Changeset 131

Show
Ignore:
Timestamp:
08/12/07 01:55:15
Author:
fumanchu
Message:

All test now pass in ast branch. Reintroduced the old 'bind_late' as 'irreducible'.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/ast/geniusql/adapters.py

    r130 r131  
    530530            if value is None: 
    531531                return 'NULL' 
     532            if not isinstance(value, typerefs.fixedpoint.FixedPoint): 
     533                value = typerefs.fixedpoint.FixedPoint(value) 
    532534            return "'" + str(value) + "'" 
    533535         
  • branches/ast/geniusql/astwalk.py

    r130 r131  
    1 """AST visitors, including rewriters and decompilers. 
     1"""AST visitors, including rewriters and deparsers. 
    22 
    33This work, including the source code, documentation 
     
    134134    optimization, because the order of eval is (x * 4) * 5. Rewritten 
    135135    as lambda x: 4 * 5 * x, the "4 * 5" can be replaced with "20". 
     136     
     137    irreducible: a list of constants (globals, freevars, or attributes) 
     138        which should not be reduced. For example, datetime.date.today 
     139        would usually be called and the result stored in the AST (since 
     140        it takes no arguments, and therefore has no free variables). 
     141        If you want the today function to be stored directly in the AST 
     142        (so it can be called later), include it in this "irreducible" list. 
     143        This does not control the conversion of globals and free variables 
     144        into constants--that happens regardless. It only controls the 
     145        reduction of complex expressions into simpler ones. 
     146     
     147    env: a dict of objects which will be used to make Consts out of 
     148        globals and builtins. This is auto-populated with items in 
     149        __builtin__ and any globals which were present at the time 
     150        the function was created, so you usually don't have to add 
     151        anything. However, it can be a handy way for frameworks to 
     152        provide globals without forcing every caller to import them. 
    136153    """ 
    137154     
    138     def __init__(self, func, env=None, reduce=True): 
     155    def __init__(self, func, env=None, reduce=True, irreducible=None): 
    139156        codewalk.Visitor.__init__(self, func) 
    140157         
    141158        self.reduce = reduce 
    142159         
    143         # self.env will be used to make Consts out of globals and builtins. 
    144160        if env is None: 
    145161            self.env = {} 
     
    158174        if fc.co_flags & codewalk.CO_VARARGS: 
    159175            self.ast.star_args = self.ast.args.pop() 
     176         
     177        if irreducible is None: 
     178            irreducible = [] 
     179        self.irreducible = irreducible 
    160180     
    161181    def walk(self): 
     182        """Walk self and set self.ast.root.""" 
    162183        self.stack = [] 
    163184        self.targets = {} 
     
    169190        if self.verbose: 
    170191            self.debug("stack:", self.stack) 
     192     
     193    def _may_reduce(self, *terms): 
     194        """Return True if all terms are ast.Const and not marked irreducible.""" 
     195        for term in terms: 
     196            if not isinstance(term, ast.Const): 
     197                return False 
     198            if term.value in self.irreducible: 
     199                return False 
     200            if getattr(term.value, "irreducible", False): 
     201                return False 
     202        return True 
    171203     
    172204    def visit_instruction(self, op, lo=None, hi=None): 
     
    195227            while terms: 
    196228                term, oper = terms.pop() 
    197                 if self.reduce and (isinstance(term, ast.Const) and 
    198                                     isinstance(clause, ast.Const)): 
     229                if self.reduce and self._may_reduce(term, clause): 
    199230                    op = ast_to_op[oper] 
    200231                    clause = ast.Const(op(term.value, clause.value)) 
     
    245276        func = self.stack[-1] 
    246277         
    247         if self.reduce and isinstance(func, ast.Const): 
     278        if self.reduce and self._may_reduce(func): 
    248279            if func.value is getattr and not isinstance(args[0], ast.Const): 
    249280                self.stack[-1] = ast.Getattr(args[0], args[1].value) 
     
    252283                # If all args/kwargs are also Const, 
    253284                # reduce to a single Const. 
    254                 argvals = [] 
    255                 for a in args: 
    256                     if isinstance(a, ast.Const): 
    257                         argvals.append(a.value) 
    258                     else: 
    259                         argvals = None 
    260                         break 
    261                 if argvals is not None: 
    262                     kwargvals = {} 
    263                     for k in kwargs: 
    264                         if isinstance(k.expr, ast.Const): 
    265                             kwargvals[k.name] = k.expr.value 
    266                         else: 
    267                             kwargvals = None 
    268                             break 
    269                     if kwargvals is not None: 
     285                argvals = [a.value for a in args if self._may_reduce(a)] 
     286                if len(argvals) == len(args): 
     287                    kwargvals = dict([(k.name, k.expr.value) for k, v in kwargs 
     288                                      if self._may_reduce(k.expr)]) 
     289                    if len(kwargvals) == len(kwargs): 
    270290                        retval = func.value(*tuple(argvals), **kwargvals) 
    271291                        self.stack[-1] = ast.Const(retval) 
     
    279299        term1, term2 = self.stack[-2:] 
    280300        op = cmp_op[lo + (hi << 8)] 
    281         if self.reduce and (isinstance(term1, ast.Const) and 
    282                             isinstance(term2, ast.Const)): 
     301        if self.reduce and self._may_reduce(term1, term2): 
    283302            oper = codewalk.comparisons[op] 
    284303            self.stack[-2:] = [ast.Const(oper(term1.value, term2.value))] 
     
    314333        term = self.co_names[lo + (hi << 8)] 
    315334        obj = self.stack[-1] 
    316         if self.reduce and isinstance(obj, ast.Const): 
     335        if self.reduce and self._may_reduce(obj): 
    317336            self.stack[-1] = ast.Const(getattr(obj.value, term)) 
    318337        else: 
     
    331350            value = self._func.func_closure[lo + (hi << 8)] 
    332351            self.stack.append(ast.Const(codewalk.deref_cell(value))) 
    333         else: 
    334             name = self.co_freevars[lo + (hi << 8)] 
    335             self.stack.append(ast.Name(name)) 
     352            return 
     353         
     354        name = self.co_freevars[lo + (hi << 8)] 
     355        self.stack.append(ast.Name(name)) 
    336356     
    337357    def visit_LOAD_FAST(self, lo, hi): 
     
    347367                raise KeyError("'%s' is not present in supplied globals." % name) 
    348368            self.stack.append(ast.Const(self.env[name])) 
    349         else: 
    350             self.stack.append(ast.Name(name)) 
     369            return 
     370         
     371        self.stack.append(ast.Name(name)) 
    351372     
    352373    def visit_POP_TOP(self): 
     
    363384    def visit_SLICE_PLUS_0(self): 
    364385        obj = self.stack[-1] 
    365         if self.reduce and isinstance(obj, ast.Const): 
     386        if self.reduce and self._may_reduce(obj): 
    366387            self.stack[-1] = ast.Const(obj.value[:]) 
    367388        else: 
     
    370391    def visit_SLICE_PLUS_1(self): 
    371392        obj, arg = self.stack[-2:] 
    372         if self.reduce and (isinstance(obj, ast.Const) and 
    373                             isinstance(arg, ast.Const)): 
     393        if self.reduce and self._may_reduce(obj, arg): 
    374394            self.stack[-2:] = [ast.Const(obj.value[arg.value:])] 
    375395        else: 
     
    378398    def visit_SLICE_PLUS_2(self): 
    379399        obj, arg = self.stack[-2:] 
    380         if self.reduce and (isinstance(obj, ast.Const) and 
    381                             isinstance(arg, ast.Const)): 
     400        if self.reduce and self._may_reduce(obj, arg): 
    382401            self.stack[-2:] = ast.Const(obj.value[:arg.value]) 
    383402        else: 
     
    386405    def visit_SLICE_PLUS_3(self): 
    387406        obj, arg1, arg2 = self.stack[-3:] 
    388         if self.reduce and (isinstance(obj, ast.Const) and 
    389                             isinstance(arg1, ast.Const) and 
    390                             isinstance(arg2, ast.Const)): 
     407        if self.reduce and self._may_reduce(obj, arg1, arg2): 
    391408            self.stack[-3:] = ast.Const(obj.value[arg1.value:arg2.value]) 
    392409        else: 
     
    398415        self.stack[-3:] = [] 
    399416        x.items.append((k, v)) 
    400 ##     
    401 ##    def visit_UNARY_CONVERT(self): 
    402 ##        term = self.stack.pop() 
    403 ##        self.stack.append("`(" + term + ")`") 
    404417     
    405418    def visit_UNARY_INVERT(self): 
    406419        term = self.stack[-1] 
    407         if self.reduce and isinstance(term, ast.Const): 
     420        if self.reduce and self._may_reduce(term): 
    408421            self.stack[-1] = ast.Const(~term.value) 
    409422        else: 
     
    412425    def visit_UNARY_NEGATIVE(self): 
    413426        term = self.stack[-1] 
    414         if self.reduce and isinstance(term, ast.Const): 
     427        if self.reduce and self._may_reduce(term): 
    415428            self.stack[-1] = ast.Const(-term.value) 
    416429        else: 
     
    419432    def visit_UNARY_NOT(self): 
    420433        term = self.stack[-1] 
    421         if self.reduce and isinstance(term, ast.Const): 
     434        if self.reduce and self._may_reduce(term): 
    422435            self.stack[-1] = ast.Const(not term.value) 
    423436        else: 
     
    426439    def visit_UNARY_POSITIVE(self): 
    427440        term = self.stack[-1] 
    428         if self.reduce and isinstance(term, ast.Const): 
     441        if self.reduce and self._may_reduce(term): 
    429442            self.stack[-1] = ast.Const(+term.value) 
    430443        else: 
     
    433446    def visit_BINARY_SUBSCR(self): 
    434447        op1, op2 = self.stack[-2:] 
    435         if self.reduce and (isinstance(op1, ast.Const) and 
    436                             isinstance(op2, ast.Const)): 
     448        if self.reduce and self._may_reduce(op1, op2): 
    437449            self.stack[-2:] = [ast.Const(op1.value[op2.value])] 
    438450        else: 
    439             self.stack[-2:] = [ast.Subscript(op1, 'OP_APPLY', op2)] 
     451            self.stack[-2:] = [ast.Subscript(op1, 'OP_APPLY', [op2])] 
    440452     
    441453    def binary_op(self, op): 
    442454        op1, op2 = self.stack[-2:] 
    443         if self.reduce and (isinstance(op1, ast.Const) and 
    444                             isinstance(op2, ast.Const)): 
     455        if self.reduce and self._may_reduce(op1, op2): 
    445456            self.stack[-2:] = [ast.Const(ast_to_op[op](op1.value, op2.value))] 
    446457        else: 
     
    450461    def bit_op(self, op): 
    451462        op1, op2 = self.stack[-2:] 
    452         if self.reduce and (isinstance(op1, ast.Const) and 
    453                             isinstance(op2, ast.Const)): 
     463        if self.reduce and self._may_reduce(op1, op2): 
    454464            self.stack[-2:] = [ast.Const(ast_to_op[op](op1.value, op2.value))] 
    455465        else: 
     
    497507     
    498508    def visit_Dict(self, *terms): 
    499         return "{%s}" % ", ".join([self.walk(term) for term in terms]) 
     509        return "{%s}" % ", ".join(["%s: %s" % (self.walk(terms[i]), 
     510                                               self.walk(terms[i + 1])) 
     511                                   for i in xrange(0, len(terms), 2)]) 
    500512     
    501513    def visit_Tuple(self, *terms): 
     
    578590     
    579591    def visit_Subscript(self, expr, flags, subs): 
    580         expr = self.walk(expr) 
    581         return "%s[%r]" % (expr, subs) 
     592        return "%s[%s]" % (self.walk(expr), self.walk(subs)) 
    582593     
    583594    def visit_Invert(self, expr): 
  • branches/ast/geniusql/deparse.py

    r130 r131  
    11import datetime 
     2import sys 
     3import traceback 
    24from types import FunctionType, NoneType 
    35from geniusql import logic, astwalk 
     
    124126    # SQL binary operators; a map from values in astwalk.binary_operators 
    125127    # to their SQL equivalents. The default map is isomorphic. 
    126     sql_bin_op = dict([(v, v) for v in astwalk.codewalk.binary_repr.itervalues()]) 
     128    sql_bin_op = dict([(k, k) for k in astwalk.repr_to_op]) 
    127129     
    128130    none_expr = SQLExpression("NULL", "expr0", None, NoneType) 
     
    173175        # Grab the completed SQL from a cache, if available 
    174176        try: 
    175             sql, imp = ast_to_sql_cache[(rootrepr, tablenames)] 
     177            sql, imp = ast_to_sql_cache[(self.typeset, rootrepr, tablenames)] 
    176178        except KeyError: 
    177179            pass 
     
    197199         
    198200        # Cache the result 
    199         ast_to_sql_cache[(rootrepr, tablenames)] = (result.sql, self.imperfect) 
     201        ast_to_sql_cache[(self.typeset, rootrepr, tablenames)] = (result.sql, self.imperfect) 
    200202         
    201203        return result.sql 
     
    236238                # Use TRUE for the term, so all records are returned. 
    237239                term = self.expr_true 
    238 ##                # Blurg. SQL Server is *so* picky. 
    239 ##                if term == self.comp_true: 
    240 ##                    term = self.expr_true 
    241 ##                elif term == self.comp_false: 
    242 ##                    term = self.expr_false 
     240            else: 
     241                # Blurg. SQL Server is *so* picky. 
     242                if term == self.comp_true: 
     243                    term = self.expr_true 
     244                elif term == self.comp_false: 
     245                    term = self.expr_false 
    243246            newterms.append("(%s)" % term.sql) 
    244247        clause = self.get_expr(" AND ".join(newterms), bool) 
     
    258261                # Use TRUE for the term, so all records are returned. 
    259262                term = self.expr_true 
    260 ##                # Blurg. SQL Server is *so* picky. 
    261 ##                if term == self.comp_true: 
    262 ##                    term = self.expr_true 
    263 ##                elif term == self.comp_false: 
    264 ##                    term = self.expr_false 
     263            else: 
     264                # Blurg. SQL Server is *so* picky. 
     265                if term == self.comp_true: 
     266                    term = self.expr_true 
     267                elif term == self.comp_false: 
     268                    term = self.expr_false 
    265269            newterms.append("(%s)" % term.sql) 
    266270        clause = self.get_expr(" OR ".join(newterms), bool) 
     
    389393                try: 
    390394                    sql = op1.adapter.compare_op(op1, op, self.sql_cmp_op[op], op2) 
    391                 except TypeError: 
     395                except TypeError, exc: 
     396                    if self.verbose: 
     397                        self.debug("".join(traceback.format_exception(*sys.exc_info()))) 
    392398                    rop = reverseop[op] 
    393399                    try: 
    394400                        sql = op1.adapter.compare_op(op2, rop, self.sql_cmp_op[rop], op1) 
    395                     except TypeError: 
     401                    except TypeError, exc: 
     402                        if self.verbose: 
     403                            self.debug("".join(traceback.format_exception(*sys.exc_info()))) 
    396404                        raise CannotRepresent( 
    397405                            "No comparison function %r between %r and %r." % 
     
    415423                             (subs, expr)) 
    416424         
    417         name = subs[0] 
    418 ##        # name, since formed in visit_Const, may have extraneous quotes. 
    419 ##        name = name.sql.strip("'\"") 
     425        name = subs[0].value 
    420426         
    421427        value = self.expr.kwargs[name] 
  • branches/ast/geniusql/logicfuncs.py

    r130 r131  
    6464    """Late-bound datetime.datetime.now(). Taint this when early binding.""" 
    6565    return _datetime.datetime.now() 
    66 now.bind_late = True 
     66now.irreducible = True 
    6767 
    6868def utcnow(): 
    6969    """Late-bound datetime.datetime.utcnow(). Taint this when early binding.""" 
    7070    return _datetime.datetime.utcnow() 
    71 utcnow.bind_late = True 
     71utcnow.irreducible = True 
    7272 
    7373def today(): 
    7474    """Late-bound datetime.date.today(). Taint this when early binding.""" 
    7575    return _datetime.date.today() 
    76 today.bind_late = True 
     76today.irreducible = True 
    7777 
    7878def iscurrentweek(value): 
     
    8282    else: 
    8383        return False 
    84 iscurrentweek.bind_late = True 
     84iscurrentweek.irreducible = True 
    8585 
    8686def count(values): 
  • branches/ast/geniusql/select.py

    r130 r131  
    245245                            # Get the key for the table. 
    246246                            colkey = '%s_%s' % (table.schema.key_for(table), colkey) 
    247                             colname = '%s_%s' % (alias, col.name) 
     247                            colname = '%s_%s' % (table.name, col.name) 
    248248                            colqname = self.db.quote(colname) 
    249249                            selname = '%s.%s AS %s' % (alias, col.qname, colqname) 
     
    308308            append("FROM") 
    309309            append(self.fromclause) 
    310         if self.whereclause: 
    311             append("WHERE") 
    312             append(self.whereclause) 
     310            if self.whereclause: 
     311                append("WHERE") 
     312                append(self.whereclause) 
    313313        if self._groupby and len(self._groupby) < len(self.input_list): 
    314314            append("GROUP BY") 
  • branches/ast/geniusql/test/test_logic.py

    r130 r131  
    1717        e = logic.Expression(lambda x: icontains(x.Status, 'c')) 
    1818        self.assertEqual(repr(e), lx + "icontains(x.Status, 'c'))") 
    19         co_code = e.func.func_code.co_code 
    20         co_code = logic.codewalk.named_opcodes(map(ord, co_code)) 
    21 ##        if sys.version_info >= (2, 5): 
    22 ##            # Python 2.5 stopped including args in co_names, 
    23 ##            # so the indices into co_names changed. 
    24 ##            self.assertEqual(co_code, 
    25 ##                             ['LOAD_CONST', 2, 0, 
    26 ##                              'LOAD_FAST', 0, 0, 
    27 ##                              'LOAD_ATTR', 2, 0, 
    28 ##                              'LOAD_CONST', 0, 0, 
    29 ##                              'CALL_FUNCTION', 2, 0, 
    30 ##                              'RETURN_VALUE']) 
    31 ##        else: 
    32 ##            self.assertEqual(co_code, 
    33 ##                             ['LOAD_CONST', 2, 0, 
    34 ##                              'LOAD_FAST', 0, 0, 
    35 ##                              'LOAD_ATTR', 2, 0, 
    36 ##                              'LOAD_CONST', 1, 0, 
    37 ##                              'CALL_FUNCTION', 2, 0, 
    38 ##                              'RETURN_VALUE']) 
    3919         
    4020        # 4/28/04: This one failed in endue.html.nav, 
     
    240220        f = logic.comparison('Name', 2, 'Harry') 
    241221        g = logic.Expression(lambda x: x.Name == 'Harry') 
    242         self.assertEqual(f.func.func_code, g.func.func_code) 
     222        self.assertEqual(f.func.func_code.co_code, g.func.func_code.co_code) 
    243223         
    244224        f = logic.comparison('Size', 4, 300) 
    245225        g = logic.Expression(lambda x: x.Size > 300) 
    246         self.assertEqual(f.func.func_code, g.func.func_code) 
     226        self.assertEqual(f.func.func_code.co_code, g.func.func_code.co_code) 
    247227         
    248228        f = logic.comparison(u'ID', 2, u'30003') 
    249229        g = logic.Expression(lambda x: x.ID == u'30003') 
    250         self.assertEqual(f.func.func_code, g.func.func_code) 
     230        self.assertEqual(f.func.func_code.co_code, g.func.func_code.co_code) 
    251231 
    252232