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
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)
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
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
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)
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))
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()])])
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
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
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)
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)
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
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")
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)
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)
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)
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
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')])])
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
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)
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)
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))
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)
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))
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)
def call_stmt(func, args, lineno): return ast.CallFunc(ast.Name(func, lineno=lineno), args, lineno=lineno)
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
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):
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])])
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