Beispiel #1
0
def compileDeflang(self, name, parentx, body):
    assert isinstance(name, Symbol)

    if parentx:
        assertResult(parentx, "derive language from")
        parent = topy(parentx)
    else:
        parent = logixglobal('langlang')

    funcname = "#lang:%s" % name

    body = len(body) > 0 and block(body, False).nodes or []

    funcbody = ast.Stmt(
        body
        + [ast.CallFunc(ast.Getattr(ast.Getattr(ast.Name(str(name)),
                                                '__impl__'),
                                    'addDeflangLocals'),
                        [ast.CallFunc(ast.Name('locals'), [])])])
    
    res = ast.Stmt([
        ast.Assign([compilePlace(Symbol(name))],
                   ast.CallFunc(logixglobal('defLanguage'),
                                [ast.Const(str(name)),
                                 parent,
                                 ast.CallFunc(GlobalName("globals"), [])])),
        astFunction(funcname, tuple(), tuple(), 0, None, funcbody),
        ast.CallFunc(ast.Name(funcname), []),
        ast.AssName(funcname, 'OP_DELETE')])
    
    lineno = getmeta(self, 'lineno')
    for n in res.nodes:
        n.lineno = lineno
    res.lineno = lineno
    return res
Beispiel #2
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)
Beispiel #3
0
def compileSetlang(self, langx, temp=False):
    assertResult(langx, "set language to")
    if temp:
        # a top-level setlang - set to a temporary language
        res = ast.CallFunc(logixglobal('tmpLanguage'),
                           [topy(langx), GlobalName('__name__'),
                            ast.CallFunc(GlobalName("globals"), [], None, None)])
    else:
        res = topy(langx)
    res.lineno = getmeta(self, 'lineno')
    return res
Beispiel #4
0
def compileSetlang(doc):
    langx = doc[0]
    assertResult(langx, "set language to")
    if doc.get('temp'):
        # a top-level setlang - set to a temporary language
        res = ast.CallFunc(logixglobal('tmpLanguage'),
                           [topy(langx), GlobalName('__name__'),
                            ast.CallFunc(GlobalName("globals"), [])])
    else:
        res = topy(langx)

    if hasattr(doc, 'lineno'):
        res.lineno = doc.lineno
    return res
Beispiel #5
0
 def apply(self, ruleName, codeName='', *exprs):
     """
     Create a call to self.apply(ruleName, *args).
     """
     args = [self.compilePythonExpr(codeName, arg) for arg in exprs]
     if ruleName == "super":
         return ast.CallFunc(ast.Getattr(ast.Name("self"),
                                         "superApply"),
                             [ast.Const(codeName)] + args,
                             None, None)
     return ast.CallFunc(ast.Getattr(ast.Name("self"),
                                     "apply"),
                         [ast.Const(ruleName)] + args,
                     None, None)
Beispiel #6
0
    def file_input(self, nodelist):
        # Add a "from IO_MODULE import IO_CLASS" statement to the
        # beginning of the module.
        doc = None  # self.get_docstring(nodelist, symbol.file_input)

        if sys.hexversion >= 0x02050000:
            io_imp = ast.From(IO_MODULE, [(IO_CLASS, None)], 0)
            markup_imp = ast.From(MARKUP_MODULE, [(MARKUP_CLASS, None)], 0)
        else:
            io_imp = ast.From(IO_MODULE, [(IO_CLASS, None)])
            markup_imp = ast.From(MARKUP_MODULE, [(MARKUP_CLASS, None)])

        markup_assign = ast.Assign(
            [ast.AssName(MARKUP_MANGLED_CLASS, OP_ASSIGN)],
            ast.Name(MARKUP_CLASS))

        # Add an IO_INSTANCE binding for module level expressions (like
        # doc strings).  This instance will not be returned.
        io_instance = ast.CallFunc(ast.Name(IO_CLASS), [])
        io_assign_name = ast.AssName(IO_INSTANCE, OP_ASSIGN)
        io_assign = ast.Assign([io_assign_name], io_instance)

        stmts = [io_imp, io_assign, markup_imp, markup_assign]

        for node in nodelist:
            if node[0] != token.ENDMARKER and node[0] != token.NEWLINE:
                self.com_append_stmt(stmts, node)

        return ast.Module(doc, ast.Stmt(stmts))
Beispiel #7
0
    def flist(obj):
        for x in obj: assertResult(x, 'use in flist')

        return ast.CallFunc(ast.Getattr(logixglobal('flist'), 'new'),
                            [ast.List(map(topy, obj.elems)),
                             ast.Dict([(ast.Const(n), topy(v))
                                       for n,v in obj.items()])])
Beispiel #8
0
def compileGetops(doc):
    fromlang = doc[0]
    targetlang = doc.get("lang")
    ops = [op.strip() for op in doc[1:]]
    
    if targetlang is None:
        raise CompileError("No target language for getops"
                           "(getops in non-exec parse?)")

    assertResult(fromlang, "get operators from")

    lineno = getattr(doc, 'lineno', None)

    lastdot = targetlang.rfind('.')
    if lastdot == -1:
        def targetlangexpr():
            return GlobalName(targetlang)
    else:
        assert 0, ("PROBE: Why are we getting ops into an imported language?")
        langname = targetlang[lastdot+1:]
        langmod = targetlang[:lastdot]
        def targetlangexpr():
            return ast.Getattr(ast.Subscript(logixglobal('lmodules'),
                                             'OP_APPLY',
                                             [ast.Const(langmod)]),
                               langname)

    if len(ops) == 0:
        # get all operators
        res = ast.CallFunc(ast.Getattr(ast.Getattr(targetlangexpr(), '__impl__'),
                                       'addAllOperators'),
                           [topy(fromlang)])
        
    else:
        stmts = [ast.CallFunc(ast.Getattr(ast.Getattr(targetlangexpr(), '__impl__'),
                                          'addOp'),
                              [ast.CallFunc(ast.Getattr(ast.Getattr(topy(fromlang),
                                                                    "__impl__"),
                                                        "getOp"),
                                            [ast.Const(op), ast.Const(False)])])
                 for op in ops]

        for s in stmts: s.lineno = lineno
        res = ast.Stmt(stmts)

    res.lineno = lineno
    return res
Beispiel #9
0
 def visitName(self, node):
     # If the name refers to a local inside a lambda, list comprehension, or
     # generator expression, leave it alone
     if node.name not in flatten(self.locals):
         # Otherwise, translate the name ref into a context lookup
         func_args = [ast.Name('data'), ast.Const(node.name)]
         node = ast.CallFunc(ast.Name('_lookup_name'), func_args)
     return node
Beispiel #10
0
 def exactly(self, expr):
     """
     Create a call to self.exactly(expr).
     """
     return ast.CallFunc(ast.Getattr(ast.Name("self"),
                                     "exactly"),
                         [ast.Const(expr)],
                         None, None)
Beispiel #11
0
 def visitPower(self, node, *args):
     walk(node.left, self)
     walk(node.right, self)
     cnode = ast.CallFunc(ast.Name('pow'), [node.left, node.right], None,
                          None)
     node.left = cnode
     # Little hack: instead of trying to turn node into a CallFunc, we just do pow(left, right)**1
     node.right = ast.Const(1)
Beispiel #12
0
 def atom_string(self, nodelist):
     k = ''
     for node in nodelist:
         k = k + eval(node[1])
     n = ast.Const(k)
     if self.__template_type and self.__template_type[-1] == "html":
         # change "foo" to _q_htmltext("foo")
         n = ast.CallFunc(ast.Name(MARKUP_MANGLED_CLASS), [n])
     return n
Beispiel #13
0
def p_power(p):
    """power : atom
             | atom trailer"""
    if len(p) == 2:
        p[0] = p[1]
    else:
        if p[2][0] == "CALL":
            p[0] = ast.CallFunc(p[1], p[2][1], None, None)
        else:
            raise AssertionError("not implemented")
Beispiel #14
0
 def listpattern(self, exprs):
     """
     Create a call to self.listpattern(lambda: exprs).
     """
     f = ast.Lambda([], [], 0, exprs)
     f.filename = self.name
     return ast.CallFunc(ast.Getattr(ast.Name("self"),
                                     "listpattern"),
                         [f],
                         None, None)
Beispiel #15
0
 def many1(self, expr):
     """
     Create a call to self.many((lambda: expr), expr).
     """
     f = ast.Lambda([], [], 0, expr)
     f.filename = self.name
     return ast.CallFunc(ast.Getattr(ast.Name("self"),
                                     "many"),
                         [f, expr],
                         None, None)
Beispiel #16
0
    def pred(self, expr):
        """
        Create a call to self.pred(lambda: expr).
        """

        f = ast.Lambda([], [], 0, expr)
        f.filename = self.name
        return ast.CallFunc(ast.Getattr(ast.Name("self"),
                                        "pred"),
                            [f],
                            None, None)
Beispiel #17
0
def compileGetops(self, fromlang, *ops, **kw):
    targetlang = kw.get("lang")
    if targetlang is None:
        raise CompileError("No target language for getops"
                           "(getops in non-exec parse?)")

    assertResult(fromlang, "get operators from")

    lineno = getmeta(self, 'lineno')

    lastdot = targetlang.rfind('.')
    if lastdot == -1:
        targetlangexpr = GlobalName(targetlang)
    else:
        assert 0, ("PROBE: Why are we getting ops into an imported language?")
        langname = targetlang[lastdot+1:]
        langmod = targetlang[:lastdot]
        targetlangexpr = ast.Getattr(ast.Subscript(logixglobal('lmodules'),
                                                   'OP_APPLY',
                                                   [ast.Const(langmod)]),
                               langname)

    if len(ops) == 0:
        # get all operators
        res = ast.CallFunc(ast.Getattr(ast.Getattr(targetlangexpr, '__impl__'),
                                       'addAllOperators'),
                           [topy(fromlang)])
        
    else:
        stmts = [ast.CallFunc(ast.Getattr(ast.Getattr(targetlangexpr, '__impl__'),
                                          'addOp'),
                              [compileGetOp(op)])
                 for op in ops]

        for s in stmts: s.lineno = lineno
        res = ast.Stmt(stmts)

    res.lineno = lineno
    return res
Beispiel #18
0
    def compilePythonExpr(self, name, expr):
        """
        Compile an embedded Python expression.

        @param name: The current rule name.
        @param expr: The Python expression to compile.
        """
        c = python_compile(expr, "<grammar rule %s>" % (name,), "eval")
        return ast.Stmt([
                ast.CallFunc(ast.Name('eval'),
                             [ast.Const(c),
                              ast.Getattr(ast.Name("self"), "globals"),
                              ast.Name('__locals')])])
Beispiel #19
0
def wrap_node(n):
    """
    Replaces literal lists and dictionaries, and list comprehensions,
    with calls to the appropriate Ren'Py constructors.
    """

    if isinstance(n, (ast.List, ast.ListComp)):
        n = ast.CallFunc(
            node=ast.Name('__renpy__list__'),
            args=[n],
            star_args=None,
            dstar_args=None,
        )

    elif isinstance(n, ast.Dict):
        n = ast.CallFunc(
            node=ast.Name('__renpy__dict__'),
            args=[n],
            star_args=None,
            dstar_args=None,
        )

    return n
Beispiel #20
0
 def _or(self, exprs):
     """
     Create a call to
     self._or([lambda: expr1, lambda: expr2, ... , lambda: exprN]).
     """
     fs = []
     for expr in exprs:
         f = ast.Lambda([], [], 0, expr)
         f.filename = self.name
         fs.append(f)
     return ast.CallFunc(ast.Getattr(ast.Name("self"),
                                     "_or"),
                         [ast.List(fs)],
                         None, None)
Beispiel #21
0
 def _do_CallExpression(self, node):
     target = self.transform(node.Target)
     args = []
     star_args = dstar_args = None
     for arg in node.Args:
         name = str(arg.Name)
         expr = self.transform(arg.Expression)
         if name == '*':
             star_args = expr
         elif name == '**':
             dstar_args = expr
         elif name is not None:
             args.append(ast.Keyword(name, expr))
         else:
             args.append(expr)
     return ast.CallFunc(target, args, star_args, dstar_args)
Beispiel #22
0
def compileFunctionCall(pyfunc, argxs, kwxs, starArg=None, dstarArg=None):
    # `pyfunc` is already an ast, other args need translating
    for a in itools.chain(argxs, kwxs.values()):
        assertResult(a, 'pass')

    if starArg:
        assertResult(starArg, "pass")

    if dstarArg:
        assertResult(dstarArg, "pass")

    argsc = map(topy, argxs)
    keywords = [ast.Keyword(str(n), topy(v)) for n,v in kwxs.items()]

    return ast.CallFunc(pyfunc, argsc + keywords,
                        starArg and topy(starArg),
                        dstarArg and topy (dstarArg))
Beispiel #23
0
 def visitAugAssign(self, node):
     if isinstance(node.node, ast.Name) and (
             not self.locals or node.node.name not in flatten(self.locals)):
         name = node.node.name
         node.node = ast.Subscript(ast.Name('data'), 'OP_APPLY',
                                   [ast.Const(name)])
         node.expr = self.visit(node.expr)
         return ast.If(
             [(ast.Compare(ast.Const(name),
                           [('in', ast.Name('data'))]), ast.Stmt([node]))],
             ast.Stmt([
                 ast.Raise(
                     ast.CallFunc(ast.Name('UndefinedError'),
                                  [ast.Const(name)]), None, None)
             ]))
     else:
         return ASTTransformer.visitAugAssign(self, node)
Beispiel #24
0
def compileFunctionCall(pyfunc, argxs, kwxs, starArg, dstarArg):
    try:
        for a in itools.chain(argxs, kwxs.values()):
            assertResult(a, 'pass')
    except:
        pass

    if starArg:
        assertResult(starArg, "pass")

    if dstarArg:
        assertResult(dstarArg, "pass")

    argsc = map(topy, argxs)
    keywords = [ast.Keyword(n, topy(v)) for n,v in kwxs.items()]

    return ast.CallFunc(pyfunc, argsc + keywords,
                        starArg and topy(starArg),
                        dstarArg and topy (dstarArg))
Beispiel #25
0
 def CALL_FUNCTION(decompiler, argc, star=None, star2=None):
     pop = decompiler.stack.pop
     kwarg, posarg = divmod(argc, 256)
     args = []
     for i in range(kwarg):
         arg = pop()
         key = pop().value
         args.append(ast.Keyword(key, arg))
     for i in range(posarg): args.append(pop())
     args.reverse()
     tos = pop()
     if isinstance(tos, ast.GenExpr):
         assert len(args) == 1 and star is None and star2 is None
         genexpr = tos
         qual = genexpr.code.quals[0]
         assert isinstance(qual.iter, ast.Name)
         assert qual.iter.name in ('.0', '[outmost-iterable]')
         qual.iter = args[0]
         return genexpr
     else: return ast.CallFunc(tos, args, star, star2)
Beispiel #26
0
def call_stmt(func, args, lineno):
    return ast.CallFunc(ast.Name(func, lineno=lineno),
                        args, lineno=lineno)
Beispiel #27
0
def compileDefop(doc):
    binding = doc['binding']
    ruledef = doc['ruledef']
    smartspace = doc.get('smartspace')
    assoc = doc.get('assoc', 'left')
    imp = doc.get('imp')
    lang = doc.get('lang')

    if lang is None:
        raise CompileError("invalid defop")

    assertResult(ruledef, "use in defop")
    assertResult(binding, "use in defop")

    lineno = getattr(doc, "lineno", None)

    # {{{ token = extract from ruledef
    def islit(x): return x[0][0] == 'LiteralRule'

    if islit(ruledef):
        token = ruledef[1]
    elif ruledef[0][0] == 'SequenceRule':
        rules = ruledef[1:]
        if len(rules) > 1 and islit(rules[0]):
            token = rules[0][1]
        elif len(rules) > 1 and islit(rules[1]):
            token = rules[1][1]
        else:
            raise CompileError("invalid ruledef")
    else:
        raise CompileError("invalid ruledef")

    # }}}

    if imp:
        if imp['kind'] == 'm':
            impkind = 'macro'
            
        elif imp['kind'] == 'f':
            impkind = 'func'

        else:
            assert 0, "invalid implementation kind: %s" % imp.kind

        impfuncname = 'operator[%s]' % token

        # {{{ impfunc = 
        argflags, argnames, argdefaults = funcArgs(imp.get('args'))
        impfunc = astFunction(impfuncname,
                              argnames,
                              argdefaults,
                              argflags,
                              None, #docstring
                              ast.Return(block(imp['body'], True)))
        impfunc.lineno = lineno
        # }}}

        impArgs = [ast.Const(impkind), ast.Name(impfuncname)]
    else:
        impArgs = []

    lastdot = lang.rfind('.')
    if lastdot == -1:
        langexpr = GlobalName(lang)
    else:
        assert 0, "PROBE: Why are we adding an op to an imported language?"
        langname = lang[lastdot+1:]
        langmod = lang[:lastdot]
        langexpr = ast.Getattr(ast.Subscript(logixglobal('lmodules'),
                                             'OP_APPLY',
                                             [ast.Const(langmod)]),
                               langname)

    # If unmarshallable objects get into the code-object, you get a
    # blanket error message, so check these before they go in.
    assert isinstance(token, str)
    assert isinstance(smartspace, str) or smartspace == None
    assert isinstance(assoc, str)

    newOpCall = ast.CallFunc(
        ast.Getattr(ast.Getattr(langexpr, '__impl__'), 'newOp'),
        [ast.Const(token),
         topy(binding),
         topy(ruledef),
         ast.Const(smartspace),
         ast.Const(assoc)]
        + impArgs)

    if impArgs != []:
        return ast.Stmt([impfunc, newOpCall])
    else:
        return newOpCall
Beispiel #28
0
        if as != None and not isinstance(as, Symbol):
            raise CompileError("invalid 'as' clause in input")
        return ast.Import([('.'.join(module), as and str(as))])
    # }}}

    # {{{ def limport(self, module, as):
    def limport(self, module, as=None):
        if as != None:
            if not isinstance(as, Symbol):
                raise CompileError("invalid 'as' clause in input")
        else:
            as = module[-1]
        fname = '.'.join(module)
        return ast.Assign([ast.AssName(str(as), 'OP_ASSIGN')],
                          ast.CallFunc(logixglobal('imp'),
                                       [ast.Const(fname),
                                        ast.CallFunc(GlobalName('globals'), [])]))
    # }}}

    # {{{ def dot(self, expr, field):
    def dot(self, expr, field):
        "."
        assertResult(expr, "get attribute from")
        if isinstance(field, Symbol):
            return ast.Getattr(topy(expr), str(field))
        else:
            raise CompileError("object field must be a symbol (got %s)" % field)
    # }}}

    # {{{ def comma(*elems):
    def comma(self, *elems):
Beispiel #29
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])])
Beispiel #30
0
def compileDefop(self, binding, ruledef, smartspace=None, assoc='left',
                 imp=None, lang=None):

    if lang is None:
        raise CompileError("invalid defop")

    assertResult(ruledef, "use in defop")
    assertResult(binding, "use in defop")

    lineno = getmeta(self, 'lineno')

    # {{{ token = extract from ruledef
    def islit(x): return x[0][0] == 'LiteralRule'

    if islit(ruledef):
        token = ruledef[1]
    elif ruledef[0][0] == 'SequenceRule':
        rules = ruledef[1:]
        if len(rules) > 1 and islit(rules[0]):
            token = rules[0][1]
        elif len(rules) > 1 and islit(rules[1]):
            token = rules[1][1]
        else:
            raise CompileError("invalid ruledef")
    else:
        raise CompileError("invalid ruledef")
    # }}}

    if imp:
        if imp['kind'] == 'm':
            funcname = 'macro'
            
        elif imp['kind'] == 'f':
            funcname = 'func'

        else:
            assert 0, "invalid implementation kind: %s" % imp.kind

        impfuncname = 'operator[%s]' % token

        # {{{ impfunc = 
        argflags, argnames, argdefaults = funcArgs(imp.get('args'))
        impfunc = astFunction(impfuncname,
                              argnames,
                              argdefaults,
                              argflags,
                              None, #docstring
                              ast.Return(block(imp['body'], True)))
        impfunc.lineno = lineno
        # }}}
    else:
        funcname = None
        impfuncname = "None"
        impfunc = None

    lastdot = lang.rfind('.')
    if lastdot == -1:
        langexpr = GlobalName(lang)
    else:
        assert 0, "PROBE: Why are we adding an op to an imported language?"
        langname = lang[lastdot+1:]
        langmod = lang[:lastdot]
        langexpr = ast.Getattr(ast.Subscript(logixglobal('lmodules'),
                                             'OP_APPLY',
                                             [ast.Const(langmod)]),
                               langname)

    newOpCall = ast.CallFunc(
        ast.Getattr(ast.Getattr(langexpr, '__impl__'), 'newOp'),
        [ast.Const(token),
         topy(binding),
         topy(ruledef),
         ast.Const(smartspace),
         ast.Const(assoc),
         ast.Const(funcname),
         ast.Name(impfuncname)
         ])

    if impfunc:
        return ast.Stmt([impfunc, newOpCall])
    else:
        return newOpCall