# -*- encoding: utf-8 -*- from copy import deepcopy import utils class PythonRenderer(object): @staticmethod def comment(s): return "# %s" % s @staticmethod def assign(*p): return "%s = %s" % p @staticmethod def bool(b): if b: return "True" return "False" @staticmethod def inc(*p): return "%s += 1" % p @staticmethod def dec(*p): return "%s -= 1" % p @staticmethod def oneline_if(*p): return "if %s: %s" % p @staticmethod def swap(x, y): return "%(x)s, %(y)s = %(y)s, %(x)s" % locals() @staticmethod def unorderd_decoder(n, name, r0name, r1name): return [ "n = %d" % n, "%s = 0" % r0name, "while %s >= n and n > 0:" % name, " %s -= n" % name, " n -= 1", " %s += 1" % r0name, "%s = %s + %s" % (r1name, name, r0name)] @staticmethod def multiline_if(cond, then_lines, else_lines): return ( ["if %s:" % cond] + utils.indent(then_lines) + ["else:"] + utils.indent(else_lines)) @staticmethod def mix(x, y): return "not(%s ^ %s)" % (x, y) @staticmethod def get_encoder(rule, context={}): global Renderer Renderer = PythonRenderer args = sorted(list(set(rule.args))) lines = ["def encode("] lines += utils.indent(["%s=0, # %s %s" % (v, typ, com) for (typ, v, com) in args]) lines += ["):"] lines += utils.indent( rule.encoder(context) + ["return %s" % rule.node_name]) return "\n".join(lines) @staticmethod def get_decoder(rule, context={}): global Renderer Renderer = PythonRenderer result = ["def decode(input_value):"] result += [" %s = %s;" % (rule.node_name, "input_value")] result += utils.indent(rule.decoder(context)) result += [" result = {}"] args = sorted(list(set(rule.args))) result += [' result["%s"] = locals().get("%s")' % (a[1], a[1]) for a in args] result += [" return result"] return "\n".join(result) class CppRenderer(object): @staticmethod def comment(s): return "// %s" % s @staticmethod def assign(*p): return "%s = %s;" % p @staticmethod def bool(b): if b: return "true" return "false" @staticmethod def inc(*p): return "%s++;" % p @staticmethod def dec(*p): return "%s--;" % p @staticmethod def oneline_if(*p): return "if(%s) %s" % p @staticmethod def swap(x, y): return "std::swap(%s, %s);" % (x, y) @staticmethod def unorderd_decoder(n, name, r0name, r1name): return [ "n = %d;" % n, "%s = 0;" % r0name, "while(%s >= n && n > 0){" % name, " %s -= n;" % name, " n--;", " %s++;" % r0name, "}", "%s = %s + %s;" % (r1name, name, r0name)] @staticmethod def multiline_if(cond, then_lines, else_lines): return ( ["if(%s){" % cond] + utils.indent(then_lines) + ["}else{ /* %s */" % cond] + utils.indent(else_lines) + ["} /* %s */" % cond]) @staticmethod def mix(x, y): return "!(%s ^ %s)" % (x, y) @staticmethod def take_decoder(arg_name, node_name, resource_name): lines = [ "for(int i=0; ; i++){", " if(!resource_%(resource_name)s[i]){ // is vacant", " if(!%(node_name)s){", " %(arg_name)s = i;", " break;", " }", " %(node_name)s--;", " }", "}", "resource_%(resource_name)s[%(arg_name)s] = true;"] return [line % locals() for line in lines] @staticmethod def take_encoder(arg_name, node_name, resource_name): lines = [ "%(node_name)s = %(arg_name)s;", "for(int i=0; i < %(arg_name)s; i++){", " if(resource_%(resource_name)s[i]){", " %(node_name)s--;", " }", "}", "resource_%(resource_name)s[%(arg_name)s] = true;"] return [line % locals() for line in lines] @staticmethod def get_encoder(rule, context={}): global Renderer Renderer = CppRenderer args = sorted(list(set(rule.args))) result = ["int encode("] result += [ ",\n".join(utils.indent(["%s %s /* %s */" % p for p in args]))] result += ["){"] result += [" vector resource_X(5); // FIXME"] vars = sorted(list(set(rule.vars))) result += utils.indent(["%s %s;" % p for p in vars]) result += utils.indent( rule.encoder(context) + ["return %s;" % rule.node_name]) result += ["}\n\n"] return "\n".join(result) @staticmethod def get_decoder(rule, context={}): global Renderer Renderer = CppRenderer result = [ "void decode(int input_value,"] args = sorted(list(set(rule.args))) result += [ ",\n".join(utils.indent(["%s &%s /* %s */" % p for p in args]))] result += [ "){"] result += [" vector resource_X(5); // FIXME"] vars = sorted(list(set(rule.vars))) result += [ "\n".join(utils.indent(["%s %s;" % p for p in vars]))] result += [ " %s = %s;" % (rule.node_name, "input_value")] result += [ "\n".join(utils.indent(rule.decoder(context)))] result += [ "}\n\n"] return "\n".join(result) @staticmethod def get_test(rule, context={}): global Renderer Renderer = CppRenderer result = [ '#include "debugprint/debugprint.hpp" // FIXME', "#include", "#include", "#include", "#include", "using namespace std;", "#define UNDEF 12345", Renderer.get_encoder(rule, deepcopy(context)), Renderer.get_decoder(rule, deepcopy(context))] result += ["int main(){"] args = sorted(list(set(rule.args))) body = ["%s %s = 0; /* %s */" % p for p in args] n = rule.size(deepcopy(context)) body += ["for(size_t i=0; i<%d; i++){" % n] body += utils.indent( ["%s = UNDEF; // undefined" % " = ".join(p[1] for p in args)] + ["decode(i, %s);" % ", ".join(p[1] for p in args)] + ["int result = encode(%s);" % ", ".join(p[1] for p in args)] + ["// std::cout << (i == result); // faster test"] + ["if(1){// detailed debug print"] + utils.indent( ['std::cout << "@" << i << "(" << result << "): ";'] + ['std::cout << %s << ", ";' % (a[1], ) for a in args] + ["std::cout << std::endl;"]) + ["}"] + ['if(!(%s < %s || %s == UNDEF)){std::cout << "%s" << "=" << %s << std::endl; return 255;}' % (a[1], a[2][4:-1], a[1], a[1], a[1]) for a in args if a[0] == "int"] + ["if (i != result){ // fastest test", ' std::cout << "ERROR@" << i << "(result:" << result << ")" << std::endl;', ' return 255;', '}'] ) body += [ "}"] result += utils.indent(body) result += [ "}"] return "\n".join(result) Renderer = PythonRenderer class Choice(object): @staticmethod def encoder(self, context={}): suffix = context.get("suffix", "") name = self.node_name + suffix arg = self.arg_name + suffix return [Renderer.comment(self), Renderer.assign(name, arg)] @staticmethod def decoder(self, context={}): suffix = context.get("suffix", "") name = self.node_name + suffix arg = self.arg_name + suffix return [Renderer.comment(self), Renderer.assign(arg, name)] class Take(object): @staticmethod def encoder(self, context={}): suffix = context.get("suffix", "") name = self.node_name + suffix arg = self.arg_name + suffix result = [Renderer.comment(self)] result += Renderer.take_encoder(arg, name, self.res.name) context[self.res.name].append(arg) return result @staticmethod def decoder(self, context={}): suffix = context.get("suffix", "") name = self.node_name + suffix arg = self.arg_name + suffix result = [Renderer.comment(self)] result += Renderer.take_decoder(arg, name, self.res.name) context[self.res.name].append(arg) return result class Unordered(object): @staticmethod def encoder(self, context={}): suffix = context.get("suffix", "") c0 = deepcopy(context) c0["suffix"] = suffix + "_0" c1 = deepcopy(context) c1["suffix"] = suffix + "_1" result = [Renderer.comment(self)] result += self.rule.encoder(c0) + self.rule.encoder(c1) name = self.get_node_name(context) r0name = self.rule.get_node_name(c0) r1name = self.rule.get_node_name(c1) result += [ Renderer.oneline_if( "%(r0name)s > %(r1name)s" % locals(), Renderer.swap(r0name, r1name))] n = self.rule.size(deepcopy(context)) if self.is_repeatable(): result += [ Renderer.assign( name, "%(n)d * %(x)s - %(x)s * (%(x)s - 1) / 2 + %(y)s - %(x)s" % dict(x=r0name, y=r1name, n=n))] else: result += [ Renderer.assign( name, "%(n)d * %(x)s - %(x)s * (%(x)s + 1) / 2 + %(y)s - %(x)s" % dict(x=r0name, y=r1name, n=n))] return result @staticmethod def decoder(self, context={}): suffix = context.get("suffix", "") c0 = deepcopy(context) c0["suffix"] = suffix + "_0" c1 = deepcopy(context) c1["suffix"] = suffix + "_1" result = [Renderer.comment(self)] name = self.get_node_name(context) r0name = self.rule.get_node_name(c0) r1name = self.rule.get_node_name(c1) n = self.rule.size(deepcopy(context)) if self.is_repeatable(): result += Renderer.unorderd_decoder(n, name, r0name, r1name) else: result += Renderer.unorderd_decoder(n - 1, name, r0name, r1name) result += self.rule.decoder(c0) result += self.rule.decoder(c1) return result class Or(object): @staticmethod def encoder(self, context={}): suffix = context.get("suffix", "") arg = self.arg_name + suffix name = self.get_node_name(context) self.r1.size(deepcopy(context)) n = self.r2.size(deepcopy(context)) if self.unorder_info: orig_flag = self.unorder_info cond = Renderer.mix(orig_flag + "_0", orig_flag + "_1") else: cond = arg result = [Renderer.comment(self)] result += Renderer.multiline_if( cond, self.r2.encoder(deepcopy(context)) + [Renderer.assign(name, self.r2.get_node_name(context))], self.r1.encoder(deepcopy(context)) + [Renderer.assign(name, "%s + %s" % (self.r1.get_node_name(context), n))]) return result @staticmethod def decoder(self, context={}): suffix = context.get("suffix", "") arg = self.arg_name + suffix name = self.get_node_name(context) self.r1.size(deepcopy(context)) n = self.r2.size(deepcopy(context)) result = [Renderer.comment(self)] if self.unorder_info: orig_flag = self.unorder_info result += [Renderer.assign("%s_0" % (orig_flag,), Renderer.bool(False))] result += Renderer.multiline_if( "%s < %d" % (name, n), [Renderer.assign(arg, Renderer.bool(True))] + [Renderer.assign(self.r2.get_node_name(context), name)] + self.r2.decoder(deepcopy(context)), [Renderer.assign(arg, Renderer.bool(False))] + [Renderer.assign(self.r1.get_node_name(context), "%s - %d" % (name, n))] + self.r1.decoder(deepcopy(context))) if self.unorder_info: orig_flag = self.unorder_info result += [Renderer.assign(arg, Renderer.mix(arg, orig_flag + "_0"))] return result class And(object): @staticmethod def encoder(self, context={}): size_context = deepcopy(context) self.r1.size(size_context) n = self.r2.size(size_context) result = [Renderer.comment(self)] r1name = self.r1.get_node_name(context) r2name = self.r2.get_node_name(context) if self.unorder_info: oname = self.unorder_info # 正規化のコードを入れる result += Renderer.multiline_if( "%s_1" % oname, [Renderer.assign(v, v + "_0") for typ, v, com in self.r1.args], [Renderer.assign(v, v + "_1") for typ, v, com in self.r1.args]) result += self.r1.encoder(context) if self.unorder_info: # 正規化のコードを入れる result += Renderer.multiline_if( "%s_1" % oname, [Renderer.assign(v, v + "_1") for typ, v, com in self.r2.args], [Renderer.assign(v, v + "_0") for typ, v, com in self.r2.args]) result += self.r2.encoder(context) result += [ Renderer.assign( self.get_node_name(context), "%s * %s + %s" % (r1name, n, r2name))] return result @staticmethod def decoder(self, context={}): size_context = deepcopy(context) self.r1.size(size_context) n = self.r2.size(size_context) name = self.get_node_name(context) result = [Renderer.comment(self)] result += [ Renderer.assign( self.r1.get_node_name(context), "%s / %s" % (name, n)), Renderer.assign( self.r2.get_node_name(context), "%s %% %s" % (name, n))] result += self.r1.decoder(context) # 正規化戻しのコードを入れる(foo_? = foo) if self.unorder_info: oname = self.unorder_info r1arg = self.r1.arg_name r2arg = self.r2.arg_name result += [Renderer.assign(v + "_0", v) for typ, v, com in self.r1.args] result += self.r2.decoder(context) # 正規化戻しのコードを入れる(foo_? = foo) if self.unorder_info: result += [Renderer.assign(v + "_1", v) for typ, v, com in self.r2.args] return result