class DefineLanguage_IdRewriter(pattern.PatternTransformer): def __init__(self, definelanguage): assert isinstance(definelanguage, tlform.DefineLanguage) super().__init__() self.definelanguage = definelanguage self.symgen = SymGen() def run(self): ntdefs = [] for nt, ntdef in self.definelanguage.nts.items(): npats = [] for pat in ntdef.patterns: npat = self.transform(pat) npat.copyattributesfrom(pat) npats.append(npat) ntdefs.append(tlform.DefineLanguage.NtDefinition(ntdef.nt, npats)) return tlform.DefineLanguage(self.definelanguage.name, ntdefs) def transformBuiltInPat(self, node): assert isinstance(node, pattern.BuiltInPat) nsym = self.symgen.get(node.prefix+'_') return pattern.BuiltInPat(node.kind, node.prefix, nsym).copyattributesfrom(node) def transformNt(self, node): assert isinstance(node, pattern.Nt) nsym = self.symgen.get(node.prefix+'_') return pattern.Nt(node.prefix, nsym).copyattributesfrom(node)
def __init__(self, module, context): assert isinstance(module, tlform.Module) assert isinstance(context, CompilationContext) self.module = module self.context = context self.symgen = SymGen() self.modulebuilder = rpy.BlockBuilder() self.main_procedurecalls = []
def __init__(self, variables, idof, context): self.idof = idof self.path = [] self.context = context self.variables = variables self.symgen = SymGen() # stores annotations that will be injected into term-template after # visiting all the children. self.annotations = { term.TermAttribute.MatchRead: {}, term.TermAttribute.InArg: {}, term.TermAttribute.ForEach: {}, }
def __init__(self, module, context, debug_dump_ntgraph=False): assert isinstance(module, tlform.Module) assert isinstance(context, CompilationContext) self.module = module self.context = context self.symgen = SymGen() self.debug_dump_ntgraph = debug_dump_ntgraph # store reference to definelanguage structure for use by redex-match form self.definelanguages = {} self.definelanguageclosures = {} self.reductionrelations = {} self.metafunctions = {}
def transformTermLiteral(self, node): assert isinstance(node, term.TermLiteral) funcname = self.context.get_function_for_term_template(node) match, parameters, matchreads = self._gen_inputs(node) symgen = SymGen() fb = rpy.BlockBuilder() tmp0 = rpy.gen_pyid_temporaries(1, symgen) if node.kind == term.TermLiteralKind.Variable: fb.AssignTo(tmp0).New('Variable', rpy.PyString(node.value)) if node.kind == term.TermLiteralKind.Integer: fb.AssignTo(tmp0).New('Integer', rpy.PyInt(int(node.value))) if node.kind == term.TermLiteralKind.Float: fb.AssignTo(tmp0).New('Float', rpy.PyFloat(float(node.value))) if node.kind == term.TermLiteralKind.Hole: fb.AssignTo(tmp0).New('Hole') if node.kind == term.TermLiteralKind.String: fb.AssignTo(tmp0).New('String', rpy.PyString(node.value)) if node.kind == term.TermLiteralKind.Boolean: fb.AssignTo(tmp0).New('Boolean', rpy.PyString(node.value)) fb.Return(tmp0) self.modulebuilder.SingleLineComment(repr(node)) self.modulebuilder.Function(funcname).WithParameters(match).Block(fb) return node
def _visitApplyReductionRelationAssertEqual(self, form): assert isinstance(form, tlform.ApplyReductionRelationAssertEqual) def gen_terms(termtemplates, fb, symgen): processed = [] for expectedterm in termtemplates: TermCodegen(self.modulebuilder, self.context).transform(expectedterm) expectedtermfunc = self.context.get_function_for_term_template( expectedterm) tmpi, tmpj = rpy.gen_pyid_temporaries(2, symgen) fb.AssignTo(tmpi).New('Match') fb.AssignTo(tmpj).FunctionCall(expectedtermfunc, tmpi) processed.append(tmpj) tmpi = rpy.gen_pyid_temporaries(1, symgen) fb.AssignTo(tmpi).PyList(*processed) return tmpi nameof_reductionrelation = self.context.get_reduction_relation( form.reductionrelationname) fb = rpy.BlockBuilder() symgen = SymGen() tmp0 = rpy.gen_pyid_temporaries(1, symgen) expectedterms = gen_terms(form.expected_termtemplates, fb, symgen) terms = self._genreductionrelation(fb, symgen, nameof_reductionrelation, form.term) fb.AssignTo(tmp0).FunctionCall(TermHelperFuncs.AssertTermListsEqual, terms, expectedterms) nameof_function = self.symgen.get('applyreductionrelationassertequal') self.modulebuilder.Function(nameof_function).Block(fb) self.main_procedurecalls.append(nameof_function)
def __init__(self): self.__variables_mentioned = {} self.__isa_functions = {} self.__pattern_code = {} self.__term_template_funcs = {} self._litterms = {} self.__toplevel_patterns = {} self.__reductionrelations = {} self.__metafuctions = {} self.__redexmatches = {} self.symgen = SymGen()
def transformMetafunctionApplication(self, node): assert isinstance(node, term.MetafunctionApplication) nameof_function = self.context.get_function_for_term_template(node) nodematch, nodeparameters, nodematchreads = self._gen_inputs(node) assert len(nodematchreads) == 0 self.transform(node.termtemplate) ttmatch, ttparameters, _ = self._gen_inputs(node.termtemplate) func_tocall = self.context.get_function_for_term_template( node.termtemplate) metafunctionfunc = self.context.get_metafunction(node.metafunctionname) symgen = SymGen() tmp0, tmp1 = rpy.gen_pyid_temporaries(2, symgen) fb = rpy.BlockBuilder() fb.AssignTo(tmp0).FunctionCall(func_tocall, ttmatch, *ttparameters) fb.AssignTo(tmp1).FunctionCall(metafunctionfunc, tmp0) fb.Return(tmp1) self.modulebuilder.Function(nameof_function).WithParameters( nodematch, *nodeparameters).Block(fb) return node
def _visitRedexMatch(self, form, callself=True): assert isinstance(form, tlform.RedexMatch) assert False if self.context.get_toplevel_function_for_pattern( form.languagename, repr(form.pat)) is None: PatternCodegen(self.modulebuilder, form.pat, self.context, form.languagename, self.symgen).run() TermCodegen(self.modulebuilder, self.context).transform(form.termstr) termfunc = self.context.get_function_for_term_template(form.termstr) matchfunc = self.context.get_toplevel_function_for_pattern( form.languagename, repr(form.pat)) symgen = SymGen() matches, match, term = rpy.gen_pyid_for('matches', 'match', 'term') tmp0 = rpy.gen_pyid_temporaries(1, symgen) fb = rpy.BlockBuilder() fb.AssignTo(tmp0).New('Match') fb.AssignTo(term).FunctionCall(termfunc, tmp0) fb.AssignTo(matches).FunctionCall(matchfunc, term) fb.Print(matches) fb.Return(matches) # call redex-match itself. nameof_this_func = self.symgen.get('redexmatch') self.context.add_redexmatch_for(form, nameof_this_func) self.modulebuilder.Function(nameof_this_func).Block(fb) if callself: tmp0 = rpy.gen_pyid_temporaries(1, self.symgen) self.modulebuilder.AssignTo(tmp0).FunctionCall(nameof_this_func)
def run(self): self.modulebuilder.IncludeFromPythonSource('runtime/term.py') self.modulebuilder.IncludeFromPythonSource('runtime/parser.py') self.modulebuilder.IncludeFromPythonSource('runtime/fresh.py') self.modulebuilder.IncludeFromPythonSource('runtime/match.py') # parse all term literals. # ~~ 26.07.2020 disable lit terms for now, need to implement # nt caching acceleration technique first. """ tmp0, tmp1 = rpy.gen_pyid_temporaries(2, self.symgen) for trm, sym1 in self.context._litterms.items(): sym1 = rpy.gen_pyid_for(sym1) self.modulebuilder.AssignTo(tmp0).New('Parser', rpy.PyString(repr(trm))) self.modulebuilder.AssignTo(sym1).MethodCall(tmp0, 'parse') """ # variable-not-otherwise-mentioned of given define language for ident, variables in self.context.get_variables_mentioned_all(): ident = rpy.gen_pyid_for(ident) variables = map(lambda v: rpy.PyString(v), variables) self.modulebuilder.AssignTo(ident).PySet(*variables) for form in self.module.tlforms: self._visit(form) # generate main fb = rpy.BlockBuilder() symgen = SymGen() ## emit some dummy Terms to aid RPython with type inference. tmp0, tmp1, tmp2, tmp3, tmp4 = rpy.gen_pyid_temporaries(5, symgen) fb.AssignTo(tmp0).New('Integer', rpy.PyInt(0)) fb.AssignTo(tmp1).New('Float', rpy.PyFloat(0.0)) fb.AssignTo(tmp2).New('String', rpy.PyString("\"hello world!\"")) fb.AssignTo(tmp3).New('Boolean', rpy.PyString("#f")) fb.AssignTo(tmp4).New('Variable', rpy.PyString("x")) for procedure in self.main_procedurecalls: tmpi = rpy.gen_pyid_temporaries(1, symgen) fb.AssignTo(tmpi).FunctionCall(procedure) fb.Return(rpy.PyInt(0)) self.modulebuilder.Function('entrypoint').WithParameters( rpy.PyId('argv')).Block(fb) #required entry procedure for Rpython. fb = rpy.BlockBuilder() fb.Return(rpy.PyTuple(rpy.PyId('entrypoint'), rpy.PyNone())) self.modulebuilder.Function('target').WithParameters( rpy.PyVarArg('args')).Block(fb) # if __name__ == '__main__': entrypoint() # for python2.7 compatibility. ifb = rpy.BlockBuilder() tmp = rpy.gen_pyid_temporaries(1, self.symgen) ifb.AssignTo(tmp).FunctionCall('entrypoint', rpy.PyList()) self.modulebuilder.If.Equal(rpy.PyId('__name__'), rpy.PyString('__main__')).ThenBlock(ifb) return rpy.Module(self.modulebuilder.build())
def _visitRedexMatchAssertEqual(self, form): def gen_matches(expectedmatches, fb, symgen): processedmatches = [] for m in expectedmatches: tmp0 = rpy.gen_pyid_temporaries(1, symgen) fb.AssignTo(tmp0).New('Match') processedmatches.append(tmp0) for sym, termx in m.bindings: tmp1, tmp2, tmp3, tmp4 = rpy.gen_pyid_temporaries( 4, symgen) TermCodegen(self.modulebuilder, self.context).transform(termx) termfunc = self.context.get_function_for_term_template( termx) fb.AssignTo(tmp1).New('Match') fb.AssignTo(tmp2).FunctionCall(termfunc, tmp1) fb.AssignTo(tmp3).MethodCall(tmp0, MatchMethodTable.AddKey, rpy.PyString(sym)) fb.AssignTo(tmp4).MethodCall(tmp0, MatchMethodTable.AddToBinding, rpy.PyString(sym), tmp2) tmpi = rpy.gen_pyid_temporaries(1, symgen) fb.AssignTo(tmpi).PyList(*processedmatches) return tmpi assert isinstance(form, tlform.RedexMatchAssertEqual) if self.context.get_toplevel_function_for_pattern( form.languagename, repr(form.pat)) is None: PatternCodegen(self.modulebuilder, form.pat, self.context, form.languagename, self.symgen).run() TermCodegen(self.modulebuilder, self.context).transform(form.termtemplate) matchfunc = self.context.get_toplevel_function_for_pattern( form.languagename, repr(form.pat)) termfunc = self.context.get_function_for_term_template( form.termtemplate) symgen = SymGen() matches, match, term = rpy.gen_pyid_for('matches', 'match', 'term') fb = rpy.BlockBuilder() expectedmatches = gen_matches(form.expectedmatches, fb, symgen) tmp0, tmp1, tmp2 = rpy.gen_pyid_temporaries(3, symgen) fb.AssignTo(tmp0).New('Match') fb.AssignTo(term).FunctionCall(termfunc, tmp0) fb.AssignTo(matches).FunctionCall(matchfunc, term) fb.AssignTo(tmp1).FunctionCall('assert_compare_match_lists', matches, expectedmatches) fb.AssignTo(tmp2).FunctionCall(MatchHelperFuncs.PrintMatchList, matches) fb.Return(matches) nameof_this_func = self.symgen.get('redexmatchassertequal') self.context.add_redexmatch_for(form, nameof_this_func) self.modulebuilder.Function(nameof_this_func).Block(fb) self.main_procedurecalls.append(nameof_this_func)
def _visitDefineReductionRelation(self, form): assert isinstance(form, tlform.DefineReductionRelation) # def reduction_relation_name(term): # outterms = [] # {for each case} # tmpi = rc(term) # outterms = outterms + tmp{i} # return outterms if form.domain != None: if self.context.get_toplevel_function_for_pattern( form.languagename, repr(form.domain)) is None: PatternCodegen(self.modulebuilder, form.domain, self.context, form.languagename, self.symgen).run() nameof_domaincheck = None if form.domain != None: nameof_domaincheck = self.context.get_toplevel_function_for_pattern( form.languagename, repr(form.domain)) rcfuncs = [] for rc in form.reductioncases: rcfunc = self._codegenReductionCase(rc, form.languagename, form.name, nameof_domaincheck) rcfuncs.append(rcfunc) terms, term = rpy.gen_pyid_for('terms', 'term') symgen = SymGen() fb = rpy.BlockBuilder() if nameof_domaincheck != None: tmp0 = rpy.gen_pyid_temporaries(1, symgen) ifb = rpy.BlockBuilder() tmpa = rpy.gen_pyid_temporaries(1, symgen) ifb.AssignTo(tmpa).MethodCall(term, TermMethodTable.ToString) ifb.RaiseException('reduction-relation not defined for %s', tmpa) fb.AssignTo(tmp0).FunctionCall(nameof_domaincheck, term) fb.If.LengthOf(tmp0).Equal(rpy.PyInt(0)).ThenBlock(ifb) fb.AssignTo(terms).PyList() for rcfunc in rcfuncs: tmpi = rpy.gen_pyid_temporaries(1, symgen) fb.AssignTo(tmpi).FunctionCall(rcfunc, term) fb.AssignTo(terms).Add(terms, tmpi) fb.Return(terms) nameof_function = '{}_{}'.format(form.languagename, form.name) self.context.add_reduction_relation(form.name, nameof_function) self.modulebuilder.Function(nameof_function).WithParameters( term).Block(fb) return form
def _visitApplyReductionRelation(self, form): assert isinstance(form, tlform.ApplyReductionRelation) nameof_reductionrelation = self.context.get_reduction_relation( form.reductionrelationname) assert nameof_reductionrelation != None fb = rpy.BlockBuilder() symgen = SymGen() self._genreductionrelation(fb, symgen, nameof_reductionrelation, form.term) tmp1 = rpy.gen_pyid_temporaries(1, symgen) nameof_function = self.symgen.get('applyreductionrelation') self.modulebuilder.Function(nameof_function).Block(fb) self.modulebuilder.AssignTo(tmp1).FunctionCall(nameof_function)
def gen_procedure_for_lit(self, lit, consumeprocedure, exactvalue): if self.context.get_function_for_pattern(self.languagename, repr(lit)) is not None: return lit nameof_this_func = 'lang_{}_consume_lit{}'.format(self.languagename, self.symgen.get()) self.context.add_function_for_pattern(self.languagename, repr(lit), nameof_this_func) symgen = SymGen() term, match, head, tail = rpy.gen_pyid_for('term', 'match', 'head', 'tail') tmp0 = rpy.gen_pyid_temporaries(1, symgen) fb = rpy.BlockBuilder() fb.AssignTo(tmp0).FunctionCall(consumeprocedure, term, match, head, tail, exactvalue) fb.Return(tmp0) self.modulebuilder.SingleLineComment('#{}'.format(repr(lit))) self.modulebuilder.Function(nameof_this_func).WithParameters(term, match, head, tail).Block(fb) return lit
def _visitTermLetAssertEqual(self, form): assert isinstance(form, tlform.TermLetAssertEqual) template = form.template TermCodegen(self.modulebuilder, self.context).transform(template) templatetermfunc = self.context.get_function_for_term_template( template) TermCodegen(self.modulebuilder, self.context).transform(form.expected) expectedtermfunc = self.context.get_function_for_term_template( form.expected) fb = rpy.BlockBuilder() symgen = SymGen() expected, match = rpy.gen_pyid_for('expected', 'match') tmp0 = rpy.gen_pyid_temporaries(1, symgen) fb.AssignTo(tmp0).New('Match') fb.AssignTo(expected).FunctionCall(expectedtermfunc, tmp0) fb.AssignTo(match).New('Match') for variable, term in form.variableassignments.items(): tmp1, tmp2, tmp3, tmp4 = rpy.gen_pyid_temporaries(4, symgen) TermCodegen(self.modulebuilder, self.context).transform(term) termfunc = self.context.get_function_for_term_template(term) fb.AssignTo(tmp1).New('Match') fb.AssignTo(tmp2).FunctionCall(termfunc, tmp1) fb.AssignTo(tmp3).MethodCall(match, MatchMethodTable.AddKey, rpy.PyString(variable)) fb.AssignTo(tmp4).MethodCall(match, MatchMethodTable.AddToBinding, rpy.PyString(variable), tmp2) tmp0, tmp1, tmp2 = rpy.gen_pyid_temporaries(3, symgen) fb.AssignTo(tmp0).FunctionCall(templatetermfunc, match) fb.AssignTo(tmp1).FunctionCall('asserttermsequal', tmp0, expected) fb.AssignTo(tmp2).FunctionCall(TermHelperFuncs.PrintTerm, tmp0) nameof_this_func = self.symgen.get('asserttermequal') self.modulebuilder.Function(nameof_this_func).Block(fb) self.main_procedurecalls.append(nameof_this_func)
def _visitReadFromStdinAndApplyReductionRelation(self, form): assert isinstance(form, tlform.ReadFromStdinAndApplyReductionRelation) reduction_relation_func = self.context.get_reduction_relation( form.reductionrelationname) symgen = SymGen() term = rpy.gen_pyid_for('term') tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7 = rpy.gen_pyid_temporaries( 8, symgen) forb = rpy.BlockBuilder() forb.AssignTo(tmp3).FunctionCall(reduction_relation_func, term) forb.AssignTo(tmp2).Add(tmp2, tmp3) wh = rpy.BlockBuilder() wh.AssignTo(tmp2).PyList() wh.For(term).In(tmp1).Block(forb) wh.AssignTo(tmp1).PyId(tmp2) wh.AssignTo(tmp4).FunctionCall(TermHelperFuncs.PrintTermList, tmp1) fb = rpy.BlockBuilder() fb.AssignTo(tmp0).FunctionCall(ReadFromStdinAndParse) if form.metafunctionname != None: mfname = self.context.get_metafunction(form.metafunctionname) fb.AssignTo(tmp5).New('Variable', rpy.PyString(form.metafunctionname)) fb.AssignTo(tmp6).New('Sequence', rpy.PyList(tmp5, tmp0)) fb.AssignTo(tmp0).FunctionCall(mfname, tmp6) fb.AssignTo(tmp1).PyList(tmp0) fb.AssignTo(tmp4).FunctionCall(TermHelperFuncs.PrintTermList, tmp1) fb.While.LengthOf(tmp1).NotEqual(rpy.PyInt(0)).Block(wh) nameof_this_func = self.symgen.get('readfromstdinandeval') self.modulebuilder.Function(nameof_this_func).Block(fb) self.main_procedurecalls.append(nameof_this_func) return form
def run(self): if self.context.get_function_for_pattern(self.languagename, repr(self.pattern)) is None: self.transform(self.pattern) if self.context.get_toplevel_function_for_pattern(self.languagename, repr(self.pattern)) is None: nameof_this_func = 'lang_{}_{}_toplevel'.format(self.languagename, self.symgen.get('pat')) self.context.add_toplevel_function_for_pattern(self.languagename, repr(self.pattern), nameof_this_func) assignable_symbols = self.pattern.getattribute(pattern.PatternAttribute.PatternVariables) symgen = SymGen() func2call = self.context.get_function_for_pattern(self.languagename, repr(self.pattern)) term, match, matches, ret = rpy.gen_pyid_for('term', 'match', 'matches', 'ret') m, h, t = rpy.gen_pyid_for('m', 'h', 't') tmp0, tmp1 = rpy.gen_pyid_temporaries(2, symgen) forb = rpy.BlockBuilder() try: symstoremove = self.pattern.getattribute(pattern.PatternAttribute.PatternVariablesToRemove) for sym in symstoremove: tmpi = rpy.gen_pyid_temporaries(1, symgen) forb.AssignTo(tmpi).MethodCall(m, MatchMethodTable.RemoveKey, rpy.PyString(sym)) except: pass forb.AssignTo(tmp0).MethodCall(ret, 'append', m) fb = rpy.BlockBuilder() fb.AssignTo(match).New('Match', self._assignable_symbols_to_rpylist(assignable_symbols)) fb.AssignTo(matches).FunctionCall(func2call, term, match, rpy.PyInt(0), rpy.PyInt(1)) fb.AssignTo(ret).PyList() fb.For(m, h, t).In(matches).Block(forb) fb.Return(ret) self.modulebuilder.SingleLineComment('toplevel {}'.format(repr(self.pattern))) self.modulebuilder.Function(nameof_this_func).WithParameters(term).Block(fb) return self.pattern
def transformPyCall(self, pycall): assert isinstance(pycall, term.PyCall) # codegen nested terms for t in pycall.termargs: self.transform(t) match, parameters, matchreads = self._gen_inputs(pycall) assert len(matchreads) == 0 and len( parameters) == 0 # expecting only match parameter for pycalls. # First generate nested terms and then call python function with them as arguments symgen = SymGen() pycallarguments = [ ] # will be calling python function with these arguments. fb = rpy.BlockBuilder() for t in pycall.termargs: tmpi = rpy.gen_pyid_temporaries(1, symgen) funcname = self.context.get_function_for_term_template(t) tmatch, tparameters, _ = self._gen_inputs(t) assert len(tparameters) == 0 tmpi = rpy.gen_pyid_temporaries(1, symgen) pycallarguments.append(tmpi) fb.AssignTo(tmpi).FunctionCall(funcname, tmatch, *tparameters) funcname = self.context.get_function_for_term_template(pycall) tmpi = rpy.gen_pyid_temporaries(1, symgen) fb.AssignTo(tmpi).FunctionCall(pycall.functionname, *pycallarguments) fb.Return(tmpi) self.modulebuilder.SingleLineComment(repr(pycall)) self.modulebuilder.Function(funcname).WithParameters( match, *parameters).Block(fb) return pycall
def _visitParseAssertEqual(self, form): assert isinstance(form, tlform.ParseAssertEqual) TermCodegen(self.modulebuilder, self.context).transform(form.expected_termtemplate) termfunc = self.context.get_function_for_term_template( form.expected_termtemplate) symgen = SymGen() argterm = rpy.gen_pyid_for('argterm') tmp0, tmp1, tmp2, tmp3, tmp4, tmp5 = rpy.gen_pyid_temporaries( 6, symgen) fb = rpy.BlockBuilder() fb.AssignTo(tmp0).New('Parser', rpy.PyString(form.string2parse)) fb.AssignTo(tmp1).MethodCall(tmp0, 'parse') fb.AssignTo(tmp2).New('Match') fb.AssignTo(tmp3).FunctionCall(termfunc, tmp2) fb.AssignTo(tmp4).FunctionCall('asserttermsequal', tmp1, tmp3) fb.AssignTo(tmp5).FunctionCall(TermHelperFuncs.PrintTerm, tmp1) nameof_this_func = self.symgen.get('parseassertequal') self.modulebuilder.Function(nameof_this_func).Block(fb) self.main_procedurecalls.append(nameof_this_func)
def _gen_match_function_for_primitive(self, functionname, isafunction, patstr, sym=None): # tmp0 = asafunction(term) # if tmp0 == True: # tmp1 = match.addtobinding(sym, term) # this is optional of sym != None; useful for holes. # head = head + 1 # return [(match, head, tail)] # return [] symgen = SymGen() term, match, head, tail = rpy.gen_pyid_for('term', 'match', 'head', 'tail') tmp0, tmp1 = rpy.gen_pyid_temporaries(2, symgen) ifb1 = rpy.BlockBuilder() if sym is not None: ifb1.AssignTo(tmp0).MethodCall(match, MatchMethodTable.AddToBinding, rpy.PyString(sym), term) ifb1.AssignTo(head).Add(head, rpy.PyInt(1)) ifb1.Return(rpy.PyList( rpy.PyTuple(match, head, tail) )) fb = rpy.BlockBuilder() fb.AssignTo(tmp0).FunctionCall(isafunction, term) fb.If.Equal(tmp0, rpy.PyBoolean(True)).ThenBlock(ifb1) fb.Return(rpy.PyList()) self.modulebuilder.SingleLineComment(patstr) self.modulebuilder.Function(functionname).WithParameters(term, match, head, tail).Block(fb)
def __init__(self, pattern): self.pattern = pattern self.symgen = SymGen() self.symstoremove = []
class Pattern_ConstraintCheckInserter(pattern.PatternTransformer): def __init__(self, pattern): self.pattern = pattern self.symgen = SymGen() self.symstoremove = [] def run(self): pat, _ = self.transform(self.pattern) pat.addattribute(pattern.PatternAttribute.PatternVariablesToRemove, self.symstoremove) return pat def _merge_variable_maps(self, m1, m2): m1k = set(list(m1.keys())) m2k = set(list(m2.keys())) intersection = m1k.intersection(m2k) nmap, syms2check = {}, [] for k in intersection: syms2check.append((m1[k], m2[k])) nmap[k] = m2[k] for k in m1k: if k not in intersection: nmap[k] = m1[k] for k in m2k: nmap[k] = m2[k] return nmap, syms2check def transformInHole(self, node): assert isinstance(node, pattern.InHole) npat1, syms1 = self.transform(node.pat1) npat2, syms2 = self.transform(node.pat2) constraintchecks = [] syms, syms2check = self._merge_variable_maps(syms1, syms2) for sym1, sym2 in syms2check: constraintchecks.append(pattern.CheckConstraint(sym1, sym2)) return pattern.InHole(npat1, npat2, constraintchecks).copyattributesfrom(node), syms def transformPatSequence(self, node): assert isinstance(node, pattern.PatSequence) if len(node.seq) == 0: return node, {} nseq = [] npat, syms = self.transform(node.seq[0]) nseq.append(npat) for pat in node.seq[1:]: npat, nsyms = self.transform(pat) nseq.append(npat) syms, syms2check = self._merge_variable_maps(syms, nsyms) for sym1, sym2 in syms2check: nseq.append(pattern.CheckConstraint(sym1, sym2)) return pattern.PatSequence(nseq).copyattributesfrom(node), syms def transformRepeat(self, node): assert isinstance(node, pattern.Repeat) pat, syms = self.transform(node.pat) return pattern.Repeat(pat, node.matchmode).copyattributesfrom(node), syms def transformNt(self, node): assert isinstance(node, pattern.Nt) # First time we see desired symbol we do not rename it - we will keep it in the end. nsym = self.symgen.get('{}#'.format(node.sym)) if nsym == '{}#0'.format(node.sym): nsym = node.sym else: self.symstoremove.append(nsym) return pattern.Nt(node.prefix, nsym).copyattributesfrom(node), { node.sym: nsym } def transformBuiltInPat(self, node): assert isinstance(node, pattern.BuiltInPat) # First time we see desired symbol we do not rename it - we will keep it in the end. # Also we never bind holes. if node.kind != pattern.BuiltInPatKind.Hole: nsym = self.symgen.get('{}#'.format(node.sym)) if nsym == '{}#0'.format(node.sym): nsym = node.sym else: self.symstoremove.append(nsym) return pattern.BuiltInPat(node.kind, node.prefix, nsym).copyattributesfrom(node), { node.sym: nsym } return node, {} def transformLit(self, pat): return pat, {} def transformCheckConstraint(self, node): return node, {}
def _codegenReductionCase(self, rc, languagename, reductionrelationname, nameof_domaincheck=None): assert isinstance(rc, tlform.DefineReductionRelation.ReductionCase) if self.context.get_toplevel_function_for_pattern( languagename, repr(rc.pattern)) is None: PatternCodegen(self.modulebuilder, rc.pattern, self.context, languagename, self.symgen).run() TermCodegen(self.modulebuilder, self.context).transform(rc.termtemplate) nameof_matchfn = self.context.get_toplevel_function_for_pattern( languagename, repr(rc.pattern)) nameof_termfn = self.context.get_function_for_term_template( rc.termtemplate) nameof_rc = self.symgen.get('{}_{}_case'.format( languagename, reductionrelationname)) symgen = SymGen() # terms = [] # matches = match(term) # if len(matches) != 0: # for match in matches: # tmp0 = gen_term(match) # tmp2 = match_domain(tmp0) # if len(tmp2) == 0: # raise Exception('reduction-relation {}: term reduced from {} to {} via rule {} and is outside domain') # tmp1 = terms.append(tmp0) # return terms terms, term, matches, match = rpy.gen_pyid_for('terms', 'term', 'matches', 'match') tmp0, tmp1, tmp2 = rpy.gen_pyid_temporaries(3, symgen) forb = rpy.BlockBuilder() forb.AssignTo(tmp0).FunctionCall(nameof_termfn, match) if nameof_domaincheck is not None: ifb = rpy.BlockBuilder() tmpa, tmpb = rpy.gen_pyid_temporaries(2, symgen) ifb.AssignTo(tmpa).MethodCall(term, TermMethodTable.ToString) ifb.AssignTo(tmpb).MethodCall(tmp0, TermMethodTable.ToString) ifb.RaiseException('reduction-relation \\"{}\\": term reduced from %s to %s via rule \\"{}\\" is outside domain' \ .format(reductionrelationname, rc.name), tmpa, tmpb) forb.AssignTo(tmp2).FunctionCall(nameof_domaincheck, tmp0) forb.If.LengthOf(tmp2).Equal(rpy.PyInt(0)).ThenBlock(ifb) forb.AssignTo(tmp1).MethodCall(terms, 'append', tmp0) ifb = rpy.BlockBuilder() ifb.For(match).In(matches).Block(forb) fb = rpy.BlockBuilder() fb.AssignTo(terms).PyList() fb.AssignTo(matches).FunctionCall(nameof_matchfn, term) fb.If.LengthOf(matches).NotEqual(rpy.PyInt(0)).ThenBlock(ifb) fb.Return(terms) self.modulebuilder.Function(nameof_rc).WithParameters(term).Block(fb) return nameof_rc
class Term_EllipsisDepthChecker(term.TermTransformer): def __init__(self, variables, idof, context): self.idof = idof self.path = [] self.context = context self.variables = variables self.symgen = SymGen() # stores annotations that will be injected into term-template after # visiting all the children. self.annotations = { term.TermAttribute.MatchRead: {}, term.TermAttribute.InArg: {}, term.TermAttribute.ForEach: {}, } def add_annotation_to(self, node, attribute, value): attributedict = self.annotations[attribute] if node not in attributedict: attributedict[node] = [] attributedict[node].append(value) def complete_annotation(self, oldnode, newnode): if isinstance(oldnode, term.Repeat): attributedict = self.annotations[term.TermAttribute.ForEach] contents = attributedict.get(oldnode, []) return newnode.addattribute(term.TermAttribute.ForEach, contents) attributedict = self.annotations[term.TermAttribute.MatchRead] contents = attributedict.get(oldnode, []) newnode.addattribute(term.TermAttribute.MatchRead, contents) attributedict = self.annotations[term.TermAttribute.InArg] contents = attributedict.get(oldnode, []) return newnode.addattribute(term.TermAttribute.InArg, contents) def contains_nonzero_foreach_annotations(self, node): assert isinstance(node, term.Repeat) attributedict = self.annotations[term.TermAttribute.ForEach] contents = attributedict.get(node, []) return len(contents) != 0 def transform(self, element): assert isinstance(element, term.Term) method_name = 'transform' + element.__class__.__name__ method_ref = getattr(self, method_name) self.path.append(element) result = method_ref(element) assert isinstance(result, term.Term) self.path.pop() return result def transformTermLiteral(self, literal): assert isinstance(literal, term.TermLiteral) #self.context.add_lit_term(literal) return literal def transformPyCall(self, pycall): assert isinstance(pycall, term.PyCall) terms = [] for t in pycall.termargs: transformer = Term_EllipsisDepthChecker(self.variables, '', self.context) terms.append(transformer.transform(t)) return self.complete_annotation( pycall, term.PyCall(pycall.mode, pycall.functionname, terms)) def transformRepeat(self, repeat): assert isinstance(repeat, term.Repeat) nrepeat = term.Repeat(self.transform( repeat.term)).copyattributesfrom(repeat) if not self.contains_nonzero_foreach_annotations(repeat): raise Exception('too many ellipses in template {}'.format( repr(nrepeat))) return self.complete_annotation(repeat, nrepeat) def transformTermSequence(self, termsequence): ntermsequence = super().transformTermSequence(termsequence) return self.complete_annotation(termsequence, ntermsequence) def transformInHole(self, inhole): ninhole = super().transformInHole(inhole) return self.complete_annotation(inhole, ninhole) def transformUnresolvedSym(self, node): assert isinstance(node, term.UnresolvedSym) if node.sym not in self.variables: t = term.TermLiteral(term.TermLiteralKind.Variable, node.sym) #self.context.add_lit_term(t) return t expecteddepth = self.variables[node.sym] actualdepth = 0 param = self.symgen.get(node.sym) # definitely a pattern variable now, topmost entry on the stack is this node. for t in reversed(self.path): if isinstance(t, term.UnresolvedSym): if expecteddepth == 0: self.add_annotation_to(t, term.TermAttribute.MatchRead, (node.sym, param)) break self.add_annotation_to(t, term.TermAttribute.InArg, param) if isinstance(t, term.TermSequence) or isinstance(t, term.InHole): if expecteddepth == actualdepth: self.add_annotation_to(t, term.TermAttribute.MatchRead, (node.sym, param)) break else: self.add_annotation_to(t, term.TermAttribute.InArg, param) if isinstance(t, term.Repeat): actualdepth += 1 self.add_annotation_to(t, term.TermAttribute.ForEach, (param, actualdepth)) if actualdepth != expecteddepth: raise Exception( 'inconsistent ellipsis depth for pattern variable {}: expected {} actual {}' .format(node.sym, expecteddepth, actualdepth)) return self.complete_annotation(node, term.PatternVariable(node.sym))
def transformRepeat(self, repeat): assert isinstance(repeat, pattern.Repeat) if self.context.get_function_for_pattern(self.languagename, repr(repeat)) is None: match_fn = 'match_{}_term_{}'.format(self.languagename, self.symgen.get()) self.context.add_function_for_pattern(self.languagename, repr(repeat), match_fn) # codegen enclosed pattern self.transform(repeat.pat) functionname = self.context.get_function_for_pattern(self.languagename, repr(repeat.pat)) # retrieve all bindable elements assignable_symbols = repeat.getattribute(pattern.PatternAttribute.PatternVariables) symgen = SymGen() term, match, head, tail = rpy.gen_pyid_for('term', 'match', 'head', 'tail') if repeat.matchmode == pattern.RepeatMatchMode.Deterministic: tmp0, tmp1, tmp2, tmp3, tmp4 = rpy.gen_pyid_temporaries(5, symgen) # tmp0 = match.increasedepth(...) # while True: # if head == tail: # break # tmp1 = term.get[head] # tmp2 = match_term(tmp1, match, head, tail) # if len(tmp2) == 0: # break # if len(tmp2) != 1: # raise Exception # tmp3 = tmp2[0] # match = tmp3[0] # head = tmp3[1] # tmp4 = match.decreasedepth(...) # return (match, head, tail) # tmp0 = match.increasedepth(...) # outmatches = [] # matches = [(tmp0, head, tail)] # while len(matches) != 0: # nmatches = [] # for m, h, t in matches: # if h == t: # tmp1 = (m,h,t) # tmp1 = completedmatches.append() # continue # tmp2 = term.get[h] # tmp3 = match_term(tmp2, m, h, t) # if len(tmp3) == 0: # completedmatches.append((m,h,t)) # continue # nmatches = nmatches + tmp3 # matches = nmatches # for match in outmatches: # tmp4 = match.decreasedepth(...) # return outmatches matches, nmatches, outmatches = rpy.gen_pyid_for('matches', 'nmatches', 'outmatches') m, h, t = rpy.gen_pyid_for('m', 'h', 't') ifb1 = rpy.BlockBuilder() ifb1.AssignTo(tmp1).PyTuple(m, h, t) ifb1.AssignTo(tmp1).MethodCall(outmatches, 'append', tmp1) ifb1.Continue ifb2 = rpy.BlockBuilder() ifb2.AssignTo(tmp4).PyTuple(m, h, t) ifb2.AssignTo(tmp4).MethodCall(outmatches, 'append', tmp4) ifb2.Continue forb1 = rpy.BlockBuilder() forb1.If.Equal(h, t).ThenBlock(ifb1) forb1.AssignTo(tmp2).MethodCall(term, TermMethodTable.Get, h) forb1.AssignTo(tmp3).FunctionCall(functionname, tmp2, m, h, t) forb1.If.LengthOf(tmp3).Equal(rpy.PyInt(0)).ThenBlock(ifb2) forb1.AssignTo(nmatches).Add(nmatches, tmp3) whb = rpy.BlockBuilder() whb.AssignTo(nmatches).PyList() whb.For(m,h,t).In(matches).Block(forb1) whb.AssignTo(matches).PyId(nmatches) if len(assignable_symbols) != 0: forb2 = rpy.BlockBuilder() for bindable in assignable_symbols: forb2.AssignTo(tmp4).MethodCall(m, MatchMethodTable.DecreaseDepth, rpy.PyString(bindable)) fb = rpy.BlockBuilder() for bindable in assignable_symbols: fb.AssignTo(tmp0).MethodCall(match, MatchMethodTable.IncreaseDepth, rpy.PyString(bindable)) fb.AssignTo(outmatches).PyList() fb.AssignTo(matches).PyList( rpy.PyTuple(match, head, tail) ) fb.While.LengthOf(matches).NotEqual(rpy.PyInt(0)).Block(whb) if len(assignable_symbols) != 0: fb.For(m,h,t).In(outmatches).Block(forb2) fb.Return(outmatches) self.modulebuilder.SingleLineComment('{} deterministic'.format(repr(repeat))) self.modulebuilder.Function(match_fn).WithParameters(term, match, head, tail).Block(fb) if repeat.matchmode == pattern.RepeatMatchMode.NonDetermininstic: matches, queue = rpy.gen_pyid_for('matches', 'queue') m, h, t = rpy.gen_pyid_for('m', 'h', 't') tmp0, tmp1, tmp2, tmp3, tmp4 = rpy.gen_pyid_temporaries(5, symgen) # tmp0 = match.increasedepth(...) # tmp1 = (match, head, tail) # matches = [ tmp1 ] # queue = [ tmp1 ] # while len(queue) != 0: # m, h, t = queue.pop(0) # if h == t: # continue # m = m.copy() # tmp2 = term.get[h] # tmp3 = match_term(tmp2, m, h, t) # matches = matches + tmp3 # queue = queue + tmp3 # for m, h, t in matches: # tmp4 = m.decreasedepth(...) # return matches ifb = rpy.BlockBuilder() ifb.Continue wb = rpy.BlockBuilder() wb.AssignTo(m, h, t).MethodCall(queue, 'pop', rpy.PyInt(0)) wb.If.Equal(h, t).ThenBlock(ifb) wb.AssignTo(m).MethodCall(m, MatchMethodTable.DeepCopy) wb.AssignTo(tmp2).MethodCall(term, TermMethodTable.Get, h) wb.AssignTo(tmp3).FunctionCall(functionname, tmp2, m, h, t) wb.AssignTo(matches).Add(matches, tmp3) wb.AssignTo(queue).Add(queue, tmp3) if len(assignable_symbols) != 0: forb = rpy.BlockBuilder() for bindable in assignable_symbols: forb.AssignTo(tmp4).MethodCall(m, MatchMethodTable.DecreaseDepth, rpy.PyString(bindable)) fb = rpy.BlockBuilder() for bindable in assignable_symbols: fb.AssignTo(tmp0).MethodCall(match, MatchMethodTable.IncreaseDepth, rpy.PyString(bindable)) fb.AssignTo(tmp1).PyTuple(match, head, tail) fb.AssignTo(matches).PyList(tmp1) fb.AssignTo(queue).PyList(tmp1) fb.While.LengthOf(queue).NotEqual(rpy.PyInt(0)).Block(wb) if len(assignable_symbols) != 0: fb.For(m, h, t).In(matches).Block(forb) fb.Return(matches) self.modulebuilder.SingleLineComment('{} non-deterministic'.format(repr(repeat))) self.modulebuilder.Function(match_fn).WithParameters(term, match, head, tail).Block(fb)
def _visitDefineMetafunction(self, form): assert isinstance(form, tlform.DefineMetafunction) #def mf(argterm): # tmp0 = domaincheck(argterm) # if len(tmp0) == 0: # raise Exception('mfname: term is not in my domain') # { foreach reductioncase # tmp{i} = mfcase(term) # if len(tmp{i}) == 1: # tmp{j} = tmp{i}[0] # tmp{k} = codomaincheck(tmp{j}) # if len(tmp{k}) == 0: # raise Exception('mfname: term not in my codomain') # return tmp{j} # } # raise Exception('no metafuncion cases matched for term') mfname = form.contract.name nameof_function = self.symgen.get('metafunction') self.context.add_metafunction(mfname, nameof_function) if self.context.get_toplevel_function_for_pattern( form.languagename, repr(form.contract.domain)) is None: PatternCodegen(self.modulebuilder, form.contract.domain, self.context, form.languagename, self.symgen).run() domainmatchfunc = self.context.get_toplevel_function_for_pattern( form.languagename, repr(form.contract.domain)) if self.context.get_toplevel_function_for_pattern( form.languagename, repr(form.contract.codomain)) is None: PatternCodegen(self.modulebuilder, form.contract.codomain, self.context, form.languagename, self.symgen).run() codomainmatchfunc = self.context.get_toplevel_function_for_pattern( form.languagename, repr(form.contract.codomain)) symgen = SymGen() argterm = rpy.gen_pyid_for('argterm') tmp0, tmp1, tmp2 = rpy.gen_pyid_temporaries(3, symgen) tmpa = rpy.gen_pyid_temporaries(1, symgen) ifbd = rpy.BlockBuilder() ifbd.AssignTo(tmpa).MethodCall(argterm, TermMethodTable.ToString) ifbd.RaiseException( 'meta-function {}: term %s not in my domain'.format(mfname), tmpa) fb = rpy.BlockBuilder() fb.AssignTo(tmp0).FunctionCall(domainmatchfunc, argterm) fb.If.LengthOf(tmp0).Equal(rpy.PyInt(0)).ThenBlock(ifbd) for i, mfcase in enumerate(form.cases): tmpi, tmpj, tmpk = rpy.gen_pyid_temporaries(3, symgen) mfcasefunc = self._codegenMetafunctionCase(form, mfcase, i, nameof_function) tmpa = rpy.gen_pyid_temporaries(1, symgen) ifbi1 = rpy.BlockBuilder() ifbi1.AssignTo(tmpa).MethodCall(tmpj, TermMethodTable.ToString) ifbi1.RaiseException( 'meta-function {}: term %s not in my codomain'.format(mfname), tmpa) ifbi2 = rpy.BlockBuilder() ifbi2.AssignTo(tmpj).ArrayGet(tmpi, rpy.PyInt(0)) ifbi2.AssignTo(tmpk).FunctionCall(codomainmatchfunc, tmpj) ifbi2.If.LengthOf(tmpk).Equal(rpy.PyInt(0)).ThenBlock(ifbi1) ifbi2.Return(tmpj) fb.AssignTo(tmpi).FunctionCall(mfcasefunc, argterm) fb.If.LengthOf(tmpi).Equal(rpy.PyInt(1)).ThenBlock(ifbi2) fb.RaiseException( 'meta-function \\"{}\\": no clauses matches'.format(mfname)) self.modulebuilder.Function(nameof_function).WithParameters( argterm).Block(fb) return nameof_function
def transformBuiltInPat(self, pat): assert isinstance(pat, pattern.BuiltInPat) if pat.kind == pattern.BuiltInPatKind.Any: if self.context.get_function_for_pattern(self.languagename, repr(pat)) is None: nameof_this_func = 'match_lang_{}_builtin_{}'.format(self.languagename, self.symgen.get()) self.context.add_function_for_pattern(self.languagename, repr(pat), nameof_this_func) # tmp0 = match.addtobinding(sym, term) # head = head + 1 # return [(match, head, tail)] symgen = SymGen() term, match, head, tail = rpy.gen_pyid_for('term', 'match', 'head', 'tail') tmp0 = rpy.gen_pyid_temporaries(1, symgen) fb = rpy.BlockBuilder() fb.AssignTo(tmp0).MethodCall(match, MatchMethodTable.AddToBinding, rpy.PyString(pat.sym), term) fb.AssignTo(head).Add(head, rpy.PyInt(1)) fb.Return(rpy.PyList( rpy.PyTuple(match, head, tail) )) self.modulebuilder.SingleLineComment(repr(pat)) self.modulebuilder.Function(nameof_this_func).WithParameters(term, match, head, tail).Block(fb) return pat elif pat.kind == pattern.BuiltInPatKind.VariableNotOtherwiseDefined: # generate isa function for variable-not-otherwise-mentioned here because we need to reference # compile-time generated language-specific array 'langname_variable_mentioned' if self.context.get_isa_function_name(self.languagename, pat.prefix) is None: nameof_this_func = 'lang_{}_isa_builtin_variable_not_othewise_mentioned'.format(self.languagename) self.context.add_isa_function_name(self.languagename, pat.prefix, nameof_this_func) symgen = SymGen() var, _ = self.context.get_variables_mentioned(self.languagename) var = rpy.gen_pyid_for(var) term = rpy.gen_pyid_for('term') tmp0, tmp1 = rpy.gen_pyid_temporaries(2, symgen) fb = rpy.BlockBuilder() fb.AssignTo(tmp0).FunctionCall(TermHelperFuncs.TermIsVariableNotOtherwiseMentioned, term, var) fb.Return(tmp0) self.modulebuilder.SingleLineComment('#Is this term {}?'.format(pat.prefix)) self.modulebuilder.Function(nameof_this_func).WithParameters(term).Block(fb) """ # tmp0 = term.kind() # if tmp0 == TermKind.Variable: # tmp1 = term.value() # if tmp1 not in var: # return True # return False # This one is different from other built-in isa funcs because we do set membership test here. ifb2 = rpy.BlockBuilder() ifb2.Return(rpy.PyBoolean(True)) ifb1 = rpy.BlockBuilder() ifb1.AssignTo(tmp1).MethodCall(term, TermMethodTable.Value) ifb1.If.NotContains(tmp1).In(var).ThenBlock(ifb2) fb = rpy.BlockBuilder() fb.If.IsInstance(term, 'Variable').ThenBlock(ifb1) fb.Return(rpy.PyBoolean(False)) self.modulebuilder.SingleLineComment('#Is this term {}?'.format(pat.prefix)) self.modulebuilder.Function(nameof_this_func).WithParameters(term).Block(fb) """ ##----- generate actual match function if self.context.get_function_for_pattern(self.languagename, repr(pat)) is None: nameof_this_func = 'match_lang_{}_builtin_{}'.format(self.languagename, self.symgen.get()) self.context.add_function_for_pattern(self.languagename, repr(pat), nameof_this_func) isafunc = self.context.get_isa_function_name(self.languagename, pat.prefix) self._gen_match_function_for_primitive(nameof_this_func, isafunc, repr(pat), sym=pat.sym) return pat else: if self.context.get_function_for_pattern(self.languagename, repr(pat)) is None: pat_isA_tab = { pattern.BuiltInPatKind.Number: TermHelperFuncs.TermIsNumber, pattern.BuiltInPatKind.Integer: TermHelperFuncs.TermIsInteger, pattern.BuiltInPatKind.Natural: TermHelperFuncs.TermIsNatural, pattern.BuiltInPatKind.Float: TermHelperFuncs.TermIsFloat, pattern.BuiltInPatKind.String: TermHelperFuncs.TermIsString, pattern.BuiltInPatKind.Boolean: TermHelperFuncs.TermIsBoolean, pattern.BuiltInPatKind.Hole: TermHelperFuncs.TermIsHole, } try: term_func = pat_isA_tab[pat.kind] nameof_this_func = 'match_lang_{}_builtin_{}'.format(self.languagename, self.symgen.get()) self.context.add_function_for_pattern(self.languagename, repr(pat), nameof_this_func) if pat.kind == pattern.BuiltInPatKind.Hole: # 'hole' key is not present in the final Match object. self._gen_match_function_for_primitive(nameof_this_func, term_func, repr(pat)) else: self._gen_match_function_for_primitive(nameof_this_func, term_func, repr(pat), sym=pat.sym) except KeyError: assert False, 'unsupported pattern' + pat.kind return pat
def transformInHole(self, pat): assert isinstance(pat, pattern.InHole) if not self.context.get_function_for_pattern(self.languagename, repr(pat)): functionname = 'lang_{}_builtin_inhole_{}'.format(self.languagename, self.symgen.get()) self.context.add_function_for_pattern(self.languagename, repr(pat), functionname) # 1. Look up all the terms that match pat2. Store (term, [match]) pairs. # 2. For each matching term, # 1. Replace term with hole # 2. Try match pat1. If match is successful, copy term recursively starting from hole, # and add appropriate binding into matches associated with the term. # 3. Replace hole with term to restore the whole term to it's original state. pat1, pat2 = pat.pat1, pat.pat2 self.transform(pat1) self.transform(pat2) matchpat1 = self.context.get_function_for_pattern(self.languagename, repr(pat1)) matchpat2 = self.context.get_function_for_pattern(self.languagename, repr(pat2)) assignable_syms1 = pat1.getattribute(pattern.PatternAttribute.PatternVariables) assignable_syms2 = pat2.getattribute(pattern.PatternAttribute.PatternVariables) assignable_syms_all = assignable_syms1.union(assignable_syms2) # def inhole(term, match, head, tail, path): # matches = [] # inpat2match = Match(...) # pat2matches = pat2matchfunc(term, inpat2match, 0, 1) # if len(pat2matches) != 0: # inpat1match = Match(...) # tmp0 = path + [term] # tmp1 = copy_path_and_replace_last(tmp0, hole) # pat1matches = pat1matchfunc(tmp1, inpat1match, 0, 1) # if len(pat1matches) != 0: # tmp11 = head + 1 # for m1, h1, t1 in pat1matches: # for m2, h2, t2 in pat2matches: # tmp2 = combine_matches(m1, m2) # tmp{i} = match.copy() # tmp{j} = tmp2.getbinding(...) ; same for inpat2match # tmp{k} = tmp{i}.addtobinding(..., tmp{j}) ; same for inpat2match # tmp3 = matches.append((tmp{i}, tmp11, tail)) # tmp4 = term.kind() # if tmp4 == Term.Sequence: # tmp5 = path.append(term) # tmp6 = term.length() # for tmp10 in range(tmp6): # tmp7 = term.get(tmp10) # tmp8 = inhole(tmp7, match, head, tail, path) # matches = matches + tmp8 # tmp9 = path.pop() # return matches symgen = SymGen() lookupfuncname = 'lang_{}_inhole_{}_impl'.format(self.languagename, self.symgen.get()) matches, hole = rpy.gen_pyid_for('matches', '{}_hole'.format(self.languagename)) term, match, head, tail, path = rpy.gen_pyid_for('term', 'match', 'head', 'tail', 'path') m1, h1, t1 = rpy.gen_pyid_for('m1', 'h1', 't1') m2, h2, t2 = rpy.gen_pyid_for('m2', 'h2', 't2') pat1matches, inpat1match = rpy.gen_pyid_for('pat1matches', 'inpat1match') pat2matches, inpat2match = rpy.gen_pyid_for('pat2matches', 'inpat2match') tmp0, tmp1, tmp2, tmp3, tmp4 = rpy.gen_pyid_temporaries(5, symgen) tmp5, tmp6, tmp7, tmp8, tmp9 = rpy.gen_pyid_temporaries(5, symgen) tmp10, tmp11, tmp12 = rpy.gen_pyid_temporaries(3, symgen) tmpm = rpy.gen_pyid_temporaries(1, symgen) forb2 = rpy.BlockBuilder() forb2.AssignTo(tmp2).FunctionCall(MatchHelperFuncs.CombineMatches, m1, m2) forb2.AssignTo(tmpm).MethodCall(match, MatchMethodTable.DeepCopy) for sym in assignable_syms_all: tmpi, tmpj = rpy.gen_pyid_temporaries(2, symgen) forb2.AssignTo(tmpi).MethodCall(tmp2, MatchMethodTable.GetBinding, rpy.PyString(sym)) forb2.AssignTo(tmpj).MethodCall(tmpm, MatchMethodTable.AddToBinding, rpy.PyString(sym), tmpi) forb2.AssignTo(tmp3).MethodCall(matches, 'append', rpy.PyTuple(tmpm, tmp11, tail)) forb1 = rpy.BlockBuilder() forb1.For(m2, h2, t2).In(pat2matches).Block(forb2) ifb0 = rpy.BlockBuilder() ifb0.AssignTo(tmp11).Add(head, rpy.PyInt(1)) ifb0.AssignTo(tmp2).FunctionCall(MatchHelperFuncs.CartesianProductAndCombineWith, pat1matches, pat2matches, match, tmp11, tail) ifb0.AssignTo(matches).Add(matches, tmp2) #ifb0.For(m1, h1, t1).In(pat1matches).Block(forb1) ifb1 = rpy.BlockBuilder() ifb1.AssignTo(inpat1match).New('Match', self._assignable_symbols_to_rpylist(assignable_syms1)) ifb1.AssignTo(tmp0).Add(path, rpy.PyList(term)) ifb1.AssignTo(tmp1).FunctionCall(TermHelperFuncs.CopyPathAndReplaceLast, tmp0, hole) ifb1.AssignTo(pat1matches).FunctionCall(matchpat1, tmp1, inpat1match, rpy.PyInt(0), rpy.PyInt(1)) ifb1.If.LengthOf(pat1matches).NotEqual(rpy.PyInt(0)).ThenBlock(ifb0) # --------------- forb1 = rpy.BlockBuilder() forb1.AssignTo(tmp7).MethodCall(term, TermMethodTable.Get, tmp10) forb1.AssignTo(tmp8).FunctionCall(lookupfuncname, tmp7, match, head, tail, path) forb1.AssignTo(matches).Add(matches, tmp8) ifb3 = rpy.BlockBuilder() ifb3.AssignTo(tmp5).MethodCall(path, 'append', term) ifb3.AssignTo(tmp6).MethodCall(term, TermMethodTable.Length) ifb3.For(tmp10).InRange(tmp6).Block(forb1) ifb3.AssignTo(tmp9).MethodCall(path, 'pop') # ---------------- fb = rpy.BlockBuilder() fb.AssignTo(matches).PyList() fb.AssignTo(inpat2match).New('Match', self._assignable_symbols_to_rpylist(assignable_syms2)) fb.AssignTo(pat2matches).FunctionCall(matchpat2, term, inpat2match, rpy.PyInt(0), rpy.PyInt(1)) fb.If.LengthOf(pat2matches).NotEqual(rpy.PyInt(0)).ThenBlock(ifb1) #fb.AssignTo(tmp4).MethodCall(term, TermMethodTable.Kind) fb.If.IsInstance(term, 'Sequence').ThenBlock(ifb3) fb.Return(matches) self.modulebuilder.SingleLineComment('{}'.format(repr(pat))) self.modulebuilder.Function(lookupfuncname).WithParameters(term, match, head, tail, path).Block(fb) #-------- this produces top-level function with empty list representing the path. # We do constraint checking here also. symgen = SymGen() m, h, t = rpy.gen_pyid_for('m', 'h', 't') fb = rpy.BlockBuilder() fb.AssignTo(tmp0).FunctionCall(lookupfuncname, term, match, head, tail, rpy.PyList()) if pat.constraintchecks != None: fb.AssignTo(matches).PyList() forb = rpy.BlockBuilder() for chck in pat.constraintchecks: tmpi = rpy.gen_pyid_temporaries(1, symgen) ifb = rpy.BlockBuilder() ifb.Continue forb.AssignTo(tmpi).MethodCall(m, MatchMethodTable.CompareKeys, rpy.PyString(chck.sym1), rpy.PyString(chck.sym2)) forb.If.NotEqual(tmpi, rpy.PyBoolean(True)).ThenBlock(ifb) tmp = rpy.gen_pyid_temporaries(1, symgen) forb.AssignTo(tmp).MethodCall(matches, 'append', rpy.PyTuple(m, h, t)) fb.For(m, h, t).In(tmp0).Block(forb) fb.Return(matches) else: fb.Return(tmp0) self.modulebuilder.Function(functionname).WithParameters(term, match, head, tail).Block(fb)
def transformPatSequence(self, seq): assert isinstance(seq, pattern.PatSequence) if self.context.get_function_for_pattern(self.languagename, repr(seq)) is None: match_fn = 'language_{}_match_term_{}'.format(self.languagename, self.symgen.get()) self.context.add_function_for_pattern(self.languagename, repr(seq), match_fn) # generate code for all elements of the sequence. for pat in seq: if not isinstance(pat, pattern.CheckConstraint): self.transform(pat) # symgen for the function symgen = SymGen() term, match, head, tail = rpy.gen_pyid_for('term', 'match', 'head', 'tail') m, h, t = rpy.gen_pyid_for('m', 'h', 't') subhead, subtail = rpy.gen_pyid_for('subhead', 'subtail') fb = rpy.BlockBuilder() # ensure term is actually a sequence. # # tmp{i} = term.kind() # if tmp{i} != TermKind.Sequence: # return [] tmpi = rpy.gen_pyid_temporaries(1, symgen) ifb = rpy.BlockBuilder() ifb.Return(rpy.PyList()) fb.If.NotIsInstance(term, 'Sequence').ThenBlock(ifb) # 'enter' the term # subhead = 0 # subtail = term.length() fb.AssignTo(subhead).PyInt(0) fb.AssignTo(subtail).MethodCall(term, TermMethodTable.Length) # ensure number of terms in the sequence is at least equal to number of non Repeat patterns. # if num_required is zero, condition is always false. # tmp{i} = subtail - subhead # if tmp{i} < num_required: # return [] num_required = seq.get_number_of_nonoptional_matches_between(0, len(seq)) tmpi = rpy.gen_pyid_temporaries(1, symgen) ifb = rpy.BlockBuilder() ifb.Return(rpy.PyList()) fb.AssignTo(tmpi).Subtract(subtail, subhead) fb.If.LessThan(tmpi, rpy.PyInt(num_required)).ThenBlock(ifb) # stick initial match object into array - simplifies codegen. previousmatches = rpy.gen_pyid_for('matches') fb.AssignTo(previousmatches).PyList( rpy.PyTuple(match, subhead, subtail) ) for i, pat in enumerate(seq): matches = rpy.gen_pyid_temporary_with_sym('matches', symgen) if isinstance(pat, pattern.Repeat) : # matches{i} = [] # get temporary with symbol # for m,h,t in matches{i-1}: # tmp{i} = matchfn(term, m, h, t) # matches{i} = matches{i} + tmp{i} functionname = self.context.get_function_for_pattern(self.languagename, repr(pat)) tmpi, tmpj = rpy.gen_pyid_temporaries(2, symgen) forb = rpy.BlockBuilder() forb.AssignTo(tmpi).FunctionCall(functionname, term, m, h, t) forb.AssignTo(matches).Add(matches, tmpi) fb.AssignTo(matches).PyList() fb.For(m, h, t).In(previousmatches).Block(forb) # ensure number of terms in the sequence is at least equal to number of non Repeat patterns after # this repeat pattern. # # matches{i} = [] # for m, h, t in matches{i-1}: # tmp{i} = t - h # if tmp{i} >= num_required: # tmp{j} = matches{i}.append((m, h, t)) # if len(matches{i}) == 0: # return matches{i} num_required = seq.get_number_of_nonoptional_matches_between(i, len(seq)) if num_required > 0: previousmatches = matches matches = rpy.gen_pyid_temporary_with_sym('matches', symgen) tmpi, tmpj = rpy.gen_pyid_temporaries(2, symgen) ifb1 = rpy.BlockBuilder() ifb1.AssignTo(tmpj).MethodCall(matches, 'append', rpy.PyTuple(m, h, t)) forb = rpy.BlockBuilder() forb.AssignTo(tmpi).Subtract(t, h) forb.If.GreaterEqual(tmpi, rpy.PyInt(num_required)).ThenBlock(ifb1) ifb2 = rpy.BlockBuilder() ifb2.Return(matches) fb.AssignTo(matches).PyList() fb.For(m, h, t).In(previousmatches).Block(forb) fb.If.LengthOf(matches).Equal(rpy.PyInt(0)).ThenBlock(ifb2) elif isinstance(pat, pattern.CheckConstraint): # matches{i} = [] # for m, h, t in matches{i-1}: # tmp{i} = m.CompareKeys(sym1, sym2) # if tmp{i} == True: # tmp{j} = matches{i}.append( (m, h, t) ) # if len(matches{i}) == 0: # return matches{i} tmpi, tmpj, tmpk = rpy.gen_pyid_temporaries(3, symgen) ifb1 = rpy.BlockBuilder() ifb1.AssignTo(tmpj).MethodCall(matches, 'append', rpy.PyTuple(m, h, t)) forb = rpy.BlockBuilder() forb.AssignTo(tmpi).MethodCall(m, MatchMethodTable.CompareKeys, rpy.PyString(pat.sym1), rpy.PyString(pat.sym2)) forb.If.Equal(tmpi, rpy.PyBoolean(True)).ThenBlock(ifb1) ifb2 = rpy.BlockBuilder() ifb2.Return(matches) fb.AssignTo(matches).PyList() fb.For(m, h, t).In(previousmatches).Block(forb) fb.If.LengthOf(matches).Equal(rpy.PyInt(0)).ThenBlock(ifb2) else: # matches{i} = [] # for m, h, t in matches{i-1}: # tmp{j} = term.get(h) # tmp{i} = func(tmp{j}, m, h, t) # matches{i} = matches{i} + tmp{i} # if len(matches{i}) == 0: # return matches{i} function = self.context.get_function_for_pattern(self.languagename, repr(pat)) tmpi, tmpj = rpy.gen_pyid_temporaries(2, symgen) forb = rpy.BlockBuilder() forb.AssignTo(tmpj).MethodCall(term, TermMethodTable.Get, h) forb.AssignTo(tmpi).FunctionCall(function, tmpj, m, h, t) forb.AssignTo(matches).Add(matches, tmpi) ifb1 = rpy.BlockBuilder() ifb1.Return(matches) fb.AssignTo(matches).PyList() fb.For(m, h, t).In(previousmatches).Block(forb) fb.If.LengthOf(matches).Equal(rpy.PyInt(0)).ThenBlock(ifb1) previousmatches = matches # exit term # # matches{i} = [] # for m, h, t in matches{i-1}: # if h == t: # tmp{k} = head + 1 # tmp{i} = (m, head, tail) # tmp{j} = matches{i}.append(tmp{i}) # return matches{i} tmpi, tmpj, tmpk = rpy.gen_pyid_temporaries(3, symgen) matches = rpy.gen_pyid_temporary_with_sym('matches', symgen) ifb = rpy.BlockBuilder() ifb.AssignTo(tmpk).Add(head, rpy.PyInt(1)) ifb.AssignTo(tmpi).PyTuple(m, tmpk, tail) ifb.AssignTo(tmpj).MethodCall(matches, 'append', tmpi) forb = rpy.BlockBuilder() forb.If.Equal(h, t).ThenBlock(ifb) fb.AssignTo(matches).PyList() fb.For(m, h, t).In(previousmatches).Block(forb) fb.Return(matches) self.modulebuilder.SingleLineComment(repr(seq)) self.modulebuilder.Function(match_fn).WithParameters(term, match, head, tail).Block(fb)
class CompilationContext: def __init__(self): self.__variables_mentioned = {} self.__isa_functions = {} self.__pattern_code = {} self.__term_template_funcs = {} self._litterms = {} self.__toplevel_patterns = {} self.__reductionrelations = {} self.__metafuctions = {} self.__redexmatches = {} self.symgen = SymGen() def add_variables_mentioned(self, languagename, variables): assert languagename not in self.__variables_mentioned self.__variables_mentioned[languagename] = ( '{}_variables_mentioned'.format(languagename), variables) def get_variables_mentioned(self, languagename): assert languagename in self.__variables_mentioned return self.__variables_mentioned[languagename] def get_variables_mentioned_all(self): return self.__variables_mentioned.values() def add_lit_term(self, term): self._litterms[term] = self.symgen.get('literal_term_') def add_isa_function_name(self, languagename, patrepr, functionname): k = (languagename, patrepr) assert k not in self.__isa_functions self.__isa_functions[k] = functionname def get_isa_function_name(self, languagename, patrepr): k = (languagename, patrepr) if k in self.__isa_functions: return self.__isa_functions[k] return None def get_sym_for_lit_term(self, term): return self._litterms[term] def add_function_for_pattern(self, languagename, patrepr, functionname): k = (languagename, patrepr) assert k not in self.__pattern_code, 'function for {}-{} is present'.format( languagename, patrepr) self.__pattern_code[k] = functionname def get_function_for_pattern(self, languagename, patrepr): k = (languagename, patrepr) if k in self.__pattern_code: return self.__pattern_code[k] return None # generated and returns procedurename, boolean for given pattern. If boolean is True - the code for # pattern has already been generated. def get_function_for_pattern_2(self, languagename, patrepr): k = (languagename, patrepr) if k in self.__pattern_code: return self.__pattern_code[k], True self.__pattern_code[k] = self.symgen.get('pattern_match') return self.__pattern_code[k], False def add_toplevel_function_for_pattern(self, languagename, patrepr, functionname): k = (languagename, patrepr) assert k not in self.__toplevel_patterns, 'function for {}-{} is present'.format( languagename, patrepr) self.__toplevel_patterns[k] = functionname def get_toplevel_function_for_pattern(self, languagename, patrepr): k = (languagename, patrepr) if k in self.__toplevel_patterns: return self.__toplevel_patterns[k] return None def get_function_for_term_template(self, term_template): assert isinstance(term_template, term.Term) if term_template not in self.__term_template_funcs: name = self.symgen.get('gen_term') self.__term_template_funcs[term_template] = name return self.__term_template_funcs[term_template] def add_reduction_relation(self, reductionrelationname, function): k = reductionrelationname assert k not in self.__reductionrelations self.__reductionrelations[k] = function def get_reduction_relation(self, reductionrelationname): k = reductionrelationname if k in self.__reductionrelations: return self.__reductionrelations[k] return None def add_metafunction(self, mfname, function): k = mfname assert k not in self.__metafuctions self.__metafuctions[k] = function def get_metafunction(self, mfname): k = mfname if k in self.__metafuctions: return self.__metafuctions[k] return None def get_redexmatch_for(self, form): return self.__redexmatches[form] def add_redexmatch_for(self, form, name): self.__redexmatches[form] = name