def expandComprehension(self, key, value, coll, filtr, exp, collector): if key is None: key = t.IgnorePattern(None) validateFor(self, scope(exp), scope(coll)) validateFor(self, scope(key).add(scope(value)), scope(coll)) fTemp = self.mktemp("validFlag") kTemp = self.mktemp("key") vTemp = self.mktemp("value") skip = self.mktemp("skip") value = t.SeqExpr( [t.Def(key, None, kTemp), t.Def(value, None, vTemp), exp]) if filtr: value = t.If(filtr, value, t.MethodCallExpr(skip, "run", [])) obj = t.Object( "For-loop body", t.IgnorePattern(None), t.Script(None, None, [], [ t.Method(None, "run", [ t.FinalPattern(kTemp, None), t.FinalPattern(vTemp, None), t.FinalPattern(skip, None) ], None, t.SeqExpr([mcall("__validateFor", "run", fTemp), value])) ], [])) return t.SeqExpr([ t.Def(t.VarPattern(fTemp, None), None, t.NounExpr("true")), t.Finally(t.MethodCallExpr(t.NounExpr(collector), "run", [coll, obj]), t.Assign(fTemp, t.NounExpr("false"))) ])
def expandOr(left, right, success, failure, leftmap, rightmap): broken = mcall("__booleanFlow", "broken") def partialFail(failed): return t.SeqExpr( [t.Def(t.BindingPattern(n), None, broken) for n in failed] + [success]) rightOnly = [t.NounExpr(n) for n in rightmap - leftmap] leftOnly = [t.NounExpr(n) for n in leftmap - rightmap] return t.If(left, partialFail(rightOnly), t.If(right, partialFail(leftOnly), failure))
def expandLogical(self, left, right, fn): leftmap = scope(left).outNames() rightmap = scope(right).outNames() both = [t.NounExpr(n) for n in leftmap | rightmap] result = self.mktemp("ok") success = t.MethodCallExpr(t.NounExpr("__makeList"), "run", [TRUE] + [t.BindingExpr(n) for n in both]) failure = t.MethodCallExpr(t.NounExpr("__booleanFlow"), "failureList", [t.LiteralExpr(len(both))]) return t.SeqExpr([ t.Def( t.ListPattern([t.FinalPattern(result, None)] + [t.BindingPattern(n) for n in both], None), None, fn(left, right, success, failure, leftmap, rightmap)), result ])
def expandFor(self, key, value, coll, block, catcher): if key.tag.name == "null": key = t.IgnorePattern(None) validateFor(self, scope(key).add(scope(value)), scope(coll)) fTemp = self.mktemp("validFlag") kTemp = self.mktemp("key") vTemp = self.mktemp("value") obj = t.Object( "For-loop body", t.IgnorePattern(None), t.Script(None, None, [], [ t.Method( None, "run", [t.FinalPattern(kTemp, None), t.FinalPattern(vTemp, None)], None, t.SeqExpr([ mcall("__validateFor", "run", fTemp), t.Escape( t.FinalPattern(t.NounExpr("__continue"), None), t.SeqExpr([ t.Def(key, None, kTemp), t.Def(value, None, vTemp), block, t.NounExpr("null") ]), None) ])) ], [])) return t.Escape( t.FinalPattern(t.NounExpr("__break"), None), t.SeqExpr([ t.Def(t.VarPattern(fTemp, None), None, t.NounExpr("true")), t.Finally( t.MethodCallExpr(t.NounExpr("__loop"), "run", [coll, obj]), t.Assign(fTemp, t.NounExpr("false"))), t.NounExpr("null") ]), catcher)
def getBinding(self, n, default=_absent): if n in self.outers: return Binding(t.FinalPattern(t.NounExpr(n), None), '_m_outerScope["%s"]' % n, None, OUTER) else: if default is _absent: raise CompileError("No global named " + repr(n)) else: return default
def reifyNoun(self, base, o): k = (base, o) if k in self.cache: return self.cache[k] self.id += 1 noun = "%s__%s" % (base, self.id) while noun in self.nouns: self.id += 1 noun = "%s__%s" % (base, self.id) self.nouns.add(noun) n = t.NounExpr(noun) self.cache[k] = n return n
def expandDef(self, patt, optEj, rval, nouns): pattScope = scope(patt) defPatts = pattScope.defNames varPatts = pattScope.varNames rvalScope = scope(rval) if optEj: rvalScope = scope(optEj).add(rvalScope) rvalUsed = rvalScope.namesUsed() if len(varPatts & rvalUsed) != 0: err("Circular 'var' definition not allowed", self) if len(pattScope.namesUsed() & rvalScope.outNames()) != 0: err("Pattern may not use var defined on the right", self) conflicts = defPatts & rvalUsed if len(conflicts) == 0: return t.Def(patt, optEj, rval) else: promises = [] resolves = [] renamings = {} for oldNameStr in conflicts.getKeys(): newName = self.mktemp(oldNameStr) newNameR = self.mktemp(oldNameStr + "R") renamings[oldNameStr] = newName # def [newName, newNameR] := Ref.promise() pair = [ t.FinalPattern(newName, None), t.FinalPattern(newNameR, None) ] promises.append( t.Def(t.ListPattern(pair, None), None, mcall("Ref", "promise"))) resolves.append( t.MethodCallExpr(newNameR, "resolve", [t.NounExpr(oldNameStr)])) resName = self.mktemp("value") resolves.append(resName) cr = CycleRenamer([rval]) cr.renamings = renamings rval = cr.apply("transform")[0] resPatt = t.FinalPattern(resName, None) resDef = t.Def(resPatt, None, t.Def(patt, optEj, rval)) return t.SeqExpr(promises + [resDef] + resolves)
def expandMatchBind(self, spec, patt): pattScope = scope(patt) specScope = scope(spec) conflicts = pattScope.outNames() & specScope.namesUsed() if conflicts: err( "Use on left isn't really in scope of matchbind pattern: %s" % (', '.join(conflicts)), self) sp = self.mktemp("sp") ejector = self.mktemp("fail") result = self.mktemp("ok") problem = self.mktemp("problem") broken = self.mktemp("b") patternNouns = [t.NounExpr(n) for n in pattScope.outNames()] return t.SeqExpr([ t.Def(t.FinalPattern(sp, None), None, spec), t.Def( t.ListPattern([t.FinalPattern(result, None)] + [t.BindingPattern(n) for n in patternNouns], None), None, t.Escape( t.FinalPattern(ejector, None), t.SeqExpr([ t.Def(patt, ejector, sp), mcall("__makeList", "run", TRUE, *[t.BindingExpr(n) for n in patternNouns]) ]), t.Catch( t.FinalPattern(problem, None), t.SeqExpr([ t.Def(slotpatt(broken), None, mcall("Ref", "broken", problem)), mcall("__makeList", "run", FALSE, *([t.BindingExpr(broken)] * len(patternNouns))) ])))), result ])
def slotpatt(n): return t.ViaPattern(t.NounExpr("__slotToBinding"), t.BindingPattern(n))
def mcall(noun, verb, *expr): return t.MethodCallExpr(t.NounExpr(noun), verb, expr)
from ometa.grammar import TreeTransformerGrammar from ometa.runtime import TreeTransformerBase, ParseError from terml.nodes import Tag, Term, termMaker as t ### XXX TODO: Create TemporaryExprs for variables generated by ### expansion. Replace all temps with nouns in a single pass at the ### end. TRUE = t.NounExpr('true') #Term(Tag('true'), None, None, None) FALSE = t.NounExpr('false') #Term(Tag('false'), None, None, None) class ScopeSet(object): def __init__(self, bits=()): self.contents = list(bits)[:] def __sub__(self, other): bits = self.contents[:] for bit in other: if bit in bits: bits[bits.index(bit)] = bits[-1] del bits[-1] return ScopeSet(bits) def __and__(self, other): if len(self) > len(other): big = self.contents small = list(other) else: small = self.contents big = list(other) bits = []