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 _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 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 _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 transformLit(self, lit): assert isinstance(lit, pattern.Lit) if lit.kind == pattern.LitKind.Variable: return self.gen_procedure_for_lit(lit, TermHelperFuncs.ConsumeVariable, rpy.PyString(lit.lit)) if lit.kind == pattern.LitKind.Integer: return self.gen_procedure_for_lit(lit, TermHelperFuncs.ConsumeInteger, rpy.PyInt(int(lit.lit))) if lit.kind == pattern.LitKind.Float: return self.gen_procedure_for_lit(lit, TermHelperFuncs.ConsumeFloat, rpy.PyFloat(float(lit.lit))) if lit.kind == pattern.LitKind.String: return self.gen_procedure_for_lit(lit, TermHelperFuncs.ConsumeString, rpy.PyString(lit.lit)) if lit.kind == pattern.LitKind.Boolean: return self.gen_procedure_for_lit(lit, TermHelperFuncs.ConsumeBoolean, rpy.PyString(lit.lit)) assert False, 'unknown literal kind ' + str(lit.kind)
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_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 _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 _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 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 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
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
##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) ifb2 = rpy.BlockBuilder() ifb2.AssignTo(tmpa).MethodCall(argterm, TermMethodTable.ToString) ifb2.RaiseException('meta-function {}: clause {} produced multiple terms when matching term %s' \ .format(metafunction.contract.name, caseid), tmpa) fb = rpy.BlockBuilder() fb.AssignTo(tmp0).FunctionCall(matchfunc, argterm) fb.AssignTo(tmp1).PyList() fb.For(tmp2).In(tmp0).Block(forb) fb.If.LengthOf(tmp1).Equal(rpy.PyInt(0)).ThenBlock(ifb1) fb.AssignTo(tmp5).FunctionCall(TermHelperFuncs.AreTermsEqualPairwise, tmp1) fb.If.NotEqual(tmp5, rpy.PyBoolean(True)).ThenBlock(ifb2) fb.AssignTo(tmp6).ArrayGet(tmp1, rpy.PyInt(0)) fb.Return(rpy.PyList(tmp6)) nameof_function = self.symgen.get('{}_case'.format(mfname)) self.modulebuilder.Function(nameof_function).WithParameters( argterm).Block(fb) return nameof_function def _visitDefineMetafunction(self, form): assert isinstance(form, tlform.DefineMetafunction) #def mf(argterm): # tmp0 = domaincheck(argterm)