def topy(obj): """The main compiler function - convert a source object to an ast node""" # {{{ ln = line number from metadata (also set global \lineno) ln = getmeta(obj, 'lineno') if ln: global lineno lineno = ln # }}} customcompile = getattr(obj, 'pycompile', None) if customcompile: node = customcompile(*opargs(obj), **opfields(obj)) elif isinstance(type(obj), OperatorType): node = compileOperator(obj) else: typ = type(obj).__name__ method = (getattr(objtopy, typ, None) or getattr(objtopy, "_" + typ, None)) compilefunc = method and method.im_func if compilefunc: node = compilefunc(obj) else: raise CompileError("Cannot compile %s (of type %s)" % (obj, typ)) if ln: node.lineno = ln return node
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 stm(x): if hasResult(x): dis = ast.Discard(topy(x)) dis.lineno = getmeta(x, 'lineno') return dis else: return topy(x)
def block(lst, withResult, prepend=None): if len(lst) == 0: if withResult: return ast.Const(None) else: return ast.Pass() def stm(x): if hasResult(x): dis = ast.Discard(topy(x)) dis.lineno = getmeta(x, 'lineno') return dis else: return topy(x) if withResult: stms = [stm(s) for s in lst[:-1]] last = lst[-1] lastpy = topy(last) if hasResult(last): # Insert a pass so pycodegen emits a SET_LINENO p = ast.Pass() p.lineno = getmeta(last, 'lineno') statements = stms + [p, lastpy] else: statements = stms + [lastpy, ast.Const(None)] else: statements = [stm(s) for s in lst] if prepend: return ast.Stmt(prepend + statements) else: return ast.Stmt(statements)
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 _if(self, test, body, elifs=None, _else=None): assertResult(test, "use as if test") if elifs: for el in elifs: assertResult(el['test'], "use as elif test") tests = [(test, body)] + [(el['test'], el['body']) for el in elifs] else: tests = [(test, body)] pytests = [] for t,b in tests: pyt = topy(t) pyt.lineno = getmeta(t, 'lineno') pytests.append( (pyt, block(b, True)) ) # HACK: For line numbers. Workaround for a test with no metadata # (e.g. just a symbol), but this doesn't work for elifs if pytests[0][0].lineno is None: pytests[0][0].lineno = getmeta(self, 'lineno') if _else: _else = block(_else, True) return ast.If(pytests, _else or ast.Const(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 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