def _codegenNtDefinition(self, languagename, ntdef): assert isinstance(ntdef, tlform.DefineLanguage.NtDefinition) for pat in ntdef.patterns: if self.context.get_toplevel_function_for_pattern( languagename, repr(pat)) is None: PatternCodegen(self.modulebuilder, pat, self.context, languagename, self.symgen).run() nameof_this_func = 'lang_{}_isa_nt_{}'.format(languagename, ntdef.nt.prefix) term, match, matches = rpy.gen_pyid_for('term', 'match', 'matches') # for each pattern in ntdefinition # match = Match(...) # matches = matchpat(term, match, 0, 1) # if len(matches) != 0: # return True fb = rpy.BlockBuilder() for pat in ntdef.patterns: func2call = self.context.get_toplevel_function_for_pattern( languagename, repr(pat)) ifb = rpy.BlockBuilder() ifb.Return(rpy.PyBoolean(True)) fb.AssignTo(matches).FunctionCall(func2call, term) fb.If.LengthOf(matches).NotEqual(rpy.PyInt(0)).ThenBlock(ifb) fb.Return(rpy.PyBoolean(False)) self.modulebuilder.Function(nameof_this_func).WithParameters( term).Block(fb)
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 _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 _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 _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 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 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 __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 _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 _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 _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 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 _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 _gen_inconsistent_ellipsis_match_counts(self, foreach, bb, symgen): # store in the set and assert length of the set is 1 assert isinstance(bb, rpy.BlockBuilder) tmps = [] for ident, _ in foreach: idnt = rpy.gen_pyid_for(ident) tmpi = rpy.gen_pyid_temporaries(1, symgen) tmps.append(tmpi) bb.AssignTo(tmpi).MethodCall(idnt, TermMethodTable.Length) ifb = rpy.BlockBuilder() ifb.RaiseException('inconsistent ellipsis match counts') lengths = rpy.gen_pyid_for('lengths') bb.AssignTo(lengths).PySet(*tmps) bb.If.LengthOf(lengths).NotEqual(rpy.PyInt(1)).ThenBlock(ifb)
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 transformPatternVariable(self, node): funcname = self.context.get_function_for_term_template(node) match, parameters, matchreads = self._gen_inputs(node) bb = rpy.BlockBuilder() if len(parameters) == 0: # must be of ellipsis depth 0 assert len(matchreads) == 1 ident, sym = matchreads[0] bb.AssignTo(ident).MethodCall(match, MatchMethodTable.GetBinding, sym) bb.Return(ident) else: assert len(parameters) == 1 bb.Return(parameters[0]) self.modulebuilder.SingleLineComment(repr(node)) self.modulebuilder.Function(funcname).WithParameters( match, *parameters).Block(bb) return node
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 transformInHole(self, inhole): assert isinstance(inhole, term.InHole) # T1 = call inhole.term1 # T2 = call inhole.term2 # plug(T1, T2) self.transform(inhole.term1) self.transform(inhole.term2) funcname = self.context.get_function_for_term_template(inhole) match, parameters, matchreads = self._gen_inputs(inhole) #FIXME not sure about this. assert len(matchreads) == 0 fb = rpy.BlockBuilder() plugholeargs = [] t1 = rpy.gen_pyid_for('t1') t1func = self.context.get_function_for_term_template(inhole.term1) t1match, t1parameters, _ = self._gen_inputs(inhole.term1) fb.AssignTo(t1).FunctionCall(t1func, t1match, *t1parameters) plugholeargs.append(t1) t2 = rpy.gen_pyid_for('t2') t2func = self.context.get_function_for_term_template(inhole.term2) t2match, t2parameters, _ = self._gen_inputs(inhole.term2) fb.AssignTo(t2).FunctionCall(t2func, t2match, *t2parameters) plugholeargs.append(t2) ret = rpy.gen_pyid_for('ret') fb.AssignTo(ret).FunctionCall('plughole', *plugholeargs) fb.Return(ret) self.modulebuilder.SingleLineComment(repr(inhole)) self.modulebuilder.Function(funcname).WithParameters( match, *parameters).Block(fb) return inhole
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 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)
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
PatternCodegen(self.modulebuilder, case.patternsequence, self.context, metafunction.languagename, self.symgen).run() TermCodegen(self.modulebuilder, self.context).transform(case.termtemplate) matchfunc = self.context.get_toplevel_function_for_pattern( metafunction.languagename, repr(case.patternsequence)) termfunc = self.context.get_function_for_term_template( case.termtemplate) symgen = SymGen() argterm = rpy.gen_pyid_for('argterm') tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6 = rpy.gen_pyid_temporaries( 7, symgen) ifb1 = rpy.BlockBuilder() ifb1.Return(tmp1) ifbx = rpy.BlockBuilder() ifbx.Continue forb = rpy.BlockBuilder() forb.AssignTo(tmp3).FunctionCall(termfunc, tmp2) ##FIXME temporary hack to simulate side-conditions in metafunctions. ##You'd use hand-written python function that returns None upon side-condition ## failure. Python functions are not allowed to return None otherwise. forb.If.IsNone(tmp3).ThenBlock(ifbx) forb.AssignTo(tmp4).MethodCall(tmp1, 'append', tmp3) tmpa = rpy.gen_pyid_temporaries(1, symgen)
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
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 transformTermSequence(self, termsequence): assert isinstance(termsequence, term.TermSequence) seqfuncname = self.context.get_function_for_term_template(termsequence) symgen = SymGen() match, parameters, matchreads = self._gen_inputs(termsequence) lst = rpy.gen_pyid_for('lst') fb = rpy.BlockBuilder() fb.AssignTo(lst).PyList() for var, sym in matchreads: fb.AssignTo(var).MethodCall(match, MatchMethodTable.GetBinding, sym) terms2codegen = [ ] # we will generate all nested terms after doing this sequence first. for t in termsequence.seq: if isinstance(t, term.Repeat): # for i in range(len(term)): # tmp{i} = term{i}.get{i} # tmp{j} = term{j}.get{i} # ... # tmp{x} = gen_term(tmp{i}, tmp{j} ...) # seq.append(tmp{x}) terms2codegen.append( t.term ) ## FIXME it was term2codegen.append(t) before. Why did it work? foreach = t.getattribute(term.TermAttribute.ForEach) self._gen_inconsistent_ellipsis_match_counts( foreach, fb, symgen) forb = rpy.BlockBuilder() tmpi = rpy.gen_pyid_temporaries(1, symgen) targuments = [] for param, _ in foreach: tmpj, param = rpy.gen_pyid_temporaries( 1, symgen), rpy.gen_pyid_for(param) targuments.append(tmpj) forb.AssignTo(tmpj).MethodCall(param, TermMethodTable.Get, tmpi) tfunctionname = self.context.get_function_for_term_template( t.term) tmpx, tmpy, tmpz = rpy.gen_pyid_temporaries(3, symgen) forb.AssignTo(tmpx).FunctionCall(tfunctionname, match, *targuments) forb.AssignTo(tmpy).MethodCall(lst, 'append', tmpx) fb.AssignTo(tmpz).MethodCall(rpy.gen_pyid_for(foreach[0][0]), TermMethodTable.Length) fb.For(tmpi).InRange(tmpz).Block(forb) if isinstance(t, term.PatternVariable) or \ isinstance(t, term.TermSequence) or \ isinstance(t, term.TermLiteral) or \ isinstance(t, term.InHole) or \ isinstance(t, term.MetafunctionApplication): terms2codegen.append(t) tmatch, tparameters, _ = self._gen_inputs(t) func_tocall = self.context.get_function_for_term_template(t) tmp0, tmp1 = rpy.gen_pyid_temporaries(2, symgen) fb.AssignTo(tmp0).FunctionCall(func_tocall, tmatch, *tparameters) fb.AssignTo(tmp1).MethodCall(lst, 'append', tmp0) if isinstance(t, term.PyCall): terms2codegen.append(t) funcname = self.context.get_function_for_term_template(t) tmatch, tparameters, _ = self._gen_inputs(t) assert len(tparameters) == 0 if t.mode == term.PyCallInsertionMode.Append: tmp0, tmp1 = rpy.gen_pyid_temporaries(2, symgen) fb.AssignTo(tmp0).FunctionCall(funcname, tmatch, *tparameters) fb.AssignTo(tmp1).MethodCall(lst, 'append', tmp0) else: # tmp0 = genterm(...) # tmp1 = tmp0.kind() # if tmp1 != TermKind.Sequence: # raise Exception(...) # tmp4 = tmp0.length() # for tmp5 in range(tmp4): # tmp2 = tmp0.get(tmp5) # tmp3 = lst.append(tmp2) tmp0, tmp1, tmp2, tmp3, tmp4, tmp5 = rpy.gen_pyid_temporaries( 6, symgen) ifb = rpy.BlockBuilder() ifb.RaiseException('term is not Sequence!') forb = rpy.BlockBuilder() forb.AssignTo(tmp2).MethodCall(tmp0, TermMethodTable.Get, tmp5) forb.AssignTo(tmp3).MethodCall(lst, 'append', tmp2) fb.AssignTo(tmp0).FunctionCall(funcname, tmatch, *tparameters) fb.If.NotIsInstance(tmp0, 'Sequence').ThenBlock(ifb) fb.AssignTo(tmp4).MethodCall(tmp0, TermMethodTable.Length) fb.For(tmp5).InRange(tmp4).Block(forb) tmpi = rpy.gen_pyid_temporaries(1, symgen) fb.AssignTo(tmpi).New('Sequence', lst) fb.Return(tmpi) self.modulebuilder.SingleLineComment(repr(termsequence)) self.modulebuilder.Function(seqfuncname).WithParameters( match, *parameters).Block(fb) for t in terms2codegen: self.transform(t) return termsequence