Пример #1
0
 def __init__(self, *expressions, **kwargs):
     super(Debug, self).__init__()
     self.expr = Plus()
     for e in expressions:
         if not isinstance(e, Expression):
             e = Literal(e)
         self.expr.append(e)
     if kwargs.get('nl', True):
         self.expr.append(Literal('\n'))
Пример #2
0
def expr(obj):
    from js2esi.node.expression import Expression
    from js2esi.node.literal import Literal
    if obj is None:
        return None
    if isinstance(obj, Expression):
        return obj
    return Literal(obj)
Пример #3
0
 def __js__(self, ctxt):
     # TODO: i think this can be made into a single "printv()" call...
     #      however, it should inspect the number & size of the output
     #      to see if it should resort to the repetetive invocation...
     # note: the reason to call __js__() instead of js() is that js()
     #       will inject an artificial 'Block' into the node hierarchy.
     from js2esi.node.expression import FunctionCall
     from js2esi.node.literal import Literal
     if len(self.statements) == 1 and not self.raw:
         return Block(
             FunctionCall(self.vars and 'printv' or 'print',
                          self.statements[0])).__js__(ctxt)
     sts = [
         FunctionCall(self.raw and 'printraw' or 'print', e)
         for e in self.statements
     ]
     if self.vars:
         sts.insert(0, FunctionCall('printraw', Literal('<esi:vars>')))
         sts.append(FunctionCall('printraw', Literal('</esi:vars>')))
     return Block(*sts).__js__(ctxt)
Пример #4
0
 def outdent():
     return IfDebug(
         Assign(
             'node_indent',
             Function('substr', Var('node_indent'), Literal(0),
                      Literal(-2))))
Пример #5
0
 def indent():
     return IfDebug(
         Assign('node_indent', Plus(Var('node_indent'), Literal('  '))))
Пример #6
0
 def __init__(self):
     super(DebugBlock, self).__init__()
     self.init = Block(Assign('node_debug', ''), Assign('node_indent', ''))
     self.term = Function('set_response_code', Literal(444),
                          Var('node_debug'))
Пример #7
0
    def optimize(self, level=7):
        '''
        Optimize this node node (and all of it\'s children). The ``level``
        parameter indicates how aggressively to optimize the tree - with the
        trade-off being time-to-finish. Currently, the following levels exist:
          3+: collapse all literals, e.g. 3+4 becomes 7
          5+: resolve inline functions
          6+: (TODO) inline hardcoded variable values (but keep declarations)
          7+: (TODO) examine all functions for inline-ability, but keep
              definitions around (in case this script gets included via "eval")
          8:  (TODO) remove auto-inlined functions and unused variables
          9:  (TODO) rename functions and variables to be shorter
        '''
        from js2esi.node import util
        from js2esi.node.function import FunctionDefinition
        from js2esi.node.expression import FunctionCall, Operator, Not
        from js2esi.node.literal import Literal

        ret = self

        if level < 5:
            # un-inline all inline functions
            for fdef in util.allchildren(ret, FunctionDefinition):
                fdef.inline = False
        else:
            inlines = {}
            for fdef in util.allchildren(ret, FunctionDefinition,
                                         lambda f: f.inline):
                inlines[fdef.name] = fdef
            # tbd: see below for comments on better ways of detecting recursively
            #      inlined functions... instead of states, i could use a stack of
            #      inlining functions.
            # TODO: this process seems *much* more processor intensive that it needs to
            #      be... need to review exactly why this is necessary...
            # process:
            #   - first iteratively resolve inlines within inlined function definitions
            #     (this is to create completely self-contained inlined function defs)
            #     note that this loop is so that at each step, inlining only happens
            #     for function calls to function definitions that do not, in turn, also
            #     inline. this is for two reasons: a) prevent recursive loops, and b)
            #     keep the inlining process simple since i don't need to worry about
            #     recursive inlining.
            #   - then resolve inlines everywhere else
            count = 0
            changed = True
            while changed:
                count += 1
                changed = False
                if count > 1000:
                    raise StructureError(
                        'resolving inlined functions appears to have entered an infinite loop'
                    )
                for fdef in inlines.values():
                    # print >>sys.stderr,'check-inline:',fdef
                    for fcall in util.allchildren(
                            fdef, FunctionCall, lambda fc: fc.name in inlines):
                        ok2inline = True
                        subfdef = inlines[fcall.name]
                        for subfcall in util.allchildren(
                                subfdef, FunctionCall,
                                lambda fc: fc.name in inlines):
                            ok2inline = False
                            # print >>sys.stderr,'!ok2inline: %s => %s' % (fdef.name, subfdef.name)
                            break
                        if not ok2inline:
                            continue
                        subfdef.inlineInto(fcall)
                        changed = True
                if changed:
                    ret = _resolveProxies(ret)
                    # TODO: do i need to rebuild the inlines dictionary?...
            # check that all inlined functions are self-contained...
            for fdef in inlines.values():
                for fcall in util.allchildren(fdef, FunctionCall,
                                              lambda fc: fc.name in inlines):
                    raise StructureError(
                        'recursive inlined function %s() detected' %
                        (fdef.name, ))
            while True:
                # tbd: do i need an infinite loop check?
                changed = False
                for call in util.allchildren(ret, FunctionCall,
                                             lambda fc: fc.name in inlines):
                    inlines[call.name].inlineInto(call)
                    changed = True
                    ret = _resolveProxies(ret)
                    break
                if not changed:
                    break

        if level >= 3:
            # collapse literals
            # tbd: instead of just limiting the loops to 1000, should
            #      i detect thrashing?... ie.:
            #        initial state A.
            #        first loop: state A changes to state B.
            #        second loop: state B changes to state A.
            #        and we are now in an infinite loop...
            #      instead of limiting this to 1000 loops, should i
            #      detect equivalent states?...
            count = 0
            changed = True
            while changed:
                count += 1
                if count > 1000:
                    raise StructureError(
                        'collapsing literals appears to have entered an infinite loop'
                    )
                changed = False
                for op in util.allchildren(ret, Operator):
                    if isinstance(op, Not):
                        # TODO: !(Literal(boolean)) can be optimized...
                        continue
                    # TODO: handle other operators, such as bitwise?...
                    # TODO: better strategy: do a "try" with python... if it succeeds,
                    #      use that, otherwise just leave it as is... note that then
                    #      i could combine types, for example ('-' * 6) ==> '------'
                    handlers = {
                        '+': lambda a, b: a + b,
                        '-': lambda a, b: a - b,
                        '*': lambda a, b: a * b,
                        '/': lambda a, b: a / b,
                        '%': lambda a, b: a % b,
                    }
                    if op.op not in handlers:
                        continue
                    lits = None
                    for arg in op.args:
                        if not isinstance(arg, Literal):
                            lits = None
                            break
                        if lits is None:
                            lits = arg.type
                        else:
                            if lits != arg.type:
                                lits = None
                                break
                    if lits is None:
                        continue
                    # tbd: i should really use map/reduce here...
                    val = op.args[0].value
                    for arg in op.args[1:]:
                        val = handlers[op.op](val, arg.value)
                    op._proxy = Literal(
                        str(val)[-2:] == '.0' and int(val) or val)
                    changed = True

                ret = _resolveProxies(ret)

        return ret
Пример #8
0
 def __js__(self, ctxt):
     ctxt.write(ctxt.indent + 'require(')
     Literal(self.src).js(ctxt)
     if self.force:
         ctxt.write(', force=true')
     ctxt.write(');\n')