Esempio n. 1
0
def quote(obj, depth=1):
    assert depth > 0

    if isinstance(obj, rootops.quote):
        depth += 1

    elif isinstance(obj, rootops.escape):
        extra = obj.__operands__.get('extra', [])
        escapelevel = 1 + len(extra)
        if escapelevel > depth:
            raise CompileError("invalid quote escape")
        
        elif escapelevel == depth:
            if obj.__operands__.hasField('splice'):
                raise CompileError("Can't splice here")

            elif obj.__operands__.hasField("localmodule"):
                return topy(localModuleQuote())
            
            else:
                assertResult(obj[0], "insert into quote")
                return topy(obj[0])

    if isinstance(type(obj), OperatorType):
        # {{{ generate code to build the operator
        cls = obj.__class__
        if cls.__module__ == '%s.rootops' % logixModuleName:
            classx = ast.Getattr(logixglobal('rootops'), cls.__name__)
        else:
            optoken = obj.__class__.__syntax__.token
            classx = compileGetOp(obj)

        operands = macros.gensym("operands")
        return ast.Stmt([ast.Assign([compilePlace(operands)],
                                    quotedArgs(obj.__operands__, depth)),
                         ast.CallFunc(classx, [],
                                      ast.Getattr(topy(operands), "elems"),
                                      ast.Getattr(topy(operands), "fields"))])
        # }}}

    elif isinstance(obj, flist):
        # {{{ generate code to build the flist
        return quotedArgs(obj, depth)
        # }}}

    elif isinstance(obj, Symbol):
        # {{{ generate code to build the symbol
        return ast.CallFunc(logixglobal('Symbol'), [ast.Const(obj.asStr())])
        # }}}

    elif isinstance(obj, (tuple, list, dict)):
        # Q: Is this ok?
        assert 0, "didn't expect one of those to be quoted"

    else:
        return topy(obj)
Esempio n. 2
0
def quotedArgs(operands, depth):
    """
    Generate code from an flist of operand expressions, possibly containing splices.
    
    Returns an expression that constructs an flist.
    """

    parts = []
    for x in operands.elems:
        if isinstance(x, rootops.escape):
            extra = x.__operands__.get('extra', [])
            escapelevel = 1 + len(extra)
            if escapelevel > depth:
                raise CompileError("invalid quote escape")
            escape = escapelevel == depth
        else:
            escape = False
            
        if escape:
            if x.__operands__.hasField("splice"):
                assertResult(x[0], "insert into quote")
                parts.append( ('s', topy(x[0])) )  # 's' == splice
            
            elif x.__operands__.hasField("localmodule"):
                parts.append( ('v',topy(localModuleQuote())) )
                     
            else:
                assertResult(x[0], "insert into quote")
                parts.append( ('v', topy(x[0])) )  # 'v' == plain value
            
        else:
            parts.append( ('v', quote(x, depth)) )  # 'v' == plain value

    # {{{ expr = reduce parts to a single expression
    # If there is just a single splice, then that is the expression
    # otherwise generate:  val = ??; val.extend(??); val.extend(??)...
    def frontSection(parts):
        vals = list(itools.takewhile(lambda (tag, exp): tag == 'v', parts))
        if len(vals) == 0:
            return parts[0][1], parts[1:]
        else:
            return ast.List([v[1] for v in vals]), parts[len(vals):]
        
    if len(parts) == 0:
        expr = ast.List([])
    else:
        first, rest = frontSection(parts)
        if len(rest) == 0:
            expr = first
        else:
            # Generate:
            #     val = ...; if not hasattr(val, 'extend'): val = list(val)
            val = macros.gensym("val")
            statements = [
                ast.Assign([compilePlace(val)], first),
                ast.If([(ast.CallFunc(GlobalName('isinstance'),
                                      [topy(val), logixglobal("flist")]),
                         ast.Assign([compilePlace(val)],
                                    ast.CallFunc(ast.Getattr(topy(val), "copy"),
                                                 [])))],
                       #else
                       ast.Assign([compilePlace(val)],
                                  ast.CallFunc(GlobalName('list'), [topy(val)])))]

            while len(rest) > 0:
                ex, rest = frontSection(rest)

                statements.append(ast.Discard(ast.CallFunc(ast.Getattr(topy(val),
                                                                       "extend"),
                                                           [ex])))
            statements.append(topy(val))

            expr = ast.Stmt(statements)
    # }}}

    for v in operands.fields.values():
        assertResult(v, "use as operand")
        
    keywords = ast.Dict([(ast.Const(n), quote(v, depth))
                         for n, v in operands.items()])

    if isinstance(expr, ast.List):
        return ast.CallFunc(ast.Getattr(logixglobal("flist"), 'new'),
                            [expr, keywords])
    else:
        return ast.Add([expr, ast.CallFunc(ast.Getattr(logixglobal("flist"), 'new'),
                                           [ast.List([]), keywords])])
Esempio n. 3
0
def quotedDoc(doc, depth):
    """
    Generate code to build a Doc like `doc` with quote-escapes
    replaced by runtime values.
    """

    # Each element of contentParts is either:
    #  an AST - meaning a spliced value - the resulting content
    #           should be `extend`ed by that value
    #  a list of ASTs - a list of regular elements, the resulting
    #                   content should be `extend`ed by an ast.List
    #                   with these elements
    # {{{ contentParts = 
    contentParts = [[]]

    for x in doc.content():
        if isDoc(x, rootops.escape):
            escapelevel = 1 + len(x.get('extra', []))
            if escapelevel > depth:
                raise CompileError("more quote escapes than quotes")
            escape = escapelevel == depth
        else:
            escape = False
            
        if escape:
            if x.hasProperty("splice"):
                assertResult(x[0], "insert into quote")
                contentParts.append(topy(x[0]))
                contentParts.append([])
            elif x.hasProperty("localmodule"):
                contentParts[-1].append(topy(localModuleQuote()))
            else:
                assertResult(x[0], "insert into quote")
                contentParts[-1].append(topy(x[0]))
            
        else:
            contentParts[-1].append(quote(x, depth))
    # }}}

    # These properties are added to the result doc *after*
    # any spliced in docs, so they overwrite any spliced properties
    for v in doc.propertyValues():
        assertResult(v, "use as operand")
    properties = ast.Dict([(compileSymbol(n), quote(v, depth))
                           for n, v in doc.properties()])
        
    # assert isinstance(contentParts[0], list)

    if contentParts == [[]]:
        return ast.CallFunc(logixglobal("Doc"),
                            [compileSymbol(doc.tag),
                             properties])
    else:
        if len(contentParts[0]) > 0:
            docArg = ast.List(contentParts[0])
            rest = contentParts[1:]
        elif len(contentParts) > 0:
            docArg = contentParts[1]
            rest = contentParts[2:]
        
        if len(rest) == 0:
            return ast.CallFunc(logixglobal("Doc"),
                                [compileSymbol(doc.tag),
                                 docArg,
                                 properties])
        else:
            val = macros.gensym("val")
            stmts = [ast.Assign([compilePlace(val)],
                                ast.CallFunc(logixglobal("Doc"),
                                             [compileSymbol(doc.tag),
                                              docArg]))]
            for part in rest:
                if isinstance(part, list):
                    if len(part) == 0:
                        continue
                    ext = ast.List(part)
                else:
                    ext = part
                stmts.append(ast.Discard(ast.CallFunc(ast.Getattr(topy(val),
                                                                  "extend"),
                                                      [ext])))
        
            stmts.append(ast.Discard(ast.CallFunc(ast.Getattr(topy(val),
                                                              "extend"),
                                                  [properties])))
            stmts.append(topy(val))
            return ast.Stmt(stmts)