diff options
Diffstat (limited to 'ext/librethinkdbxx/test/yaml_to_cxx.py')
-rw-r--r-- | ext/librethinkdbxx/test/yaml_to_cxx.py | 467 |
1 files changed, 0 insertions, 467 deletions
diff --git a/ext/librethinkdbxx/test/yaml_to_cxx.py b/ext/librethinkdbxx/test/yaml_to_cxx.py deleted file mode 100644 index bf6e4bfe..00000000 --- a/ext/librethinkdbxx/test/yaml_to_cxx.py +++ /dev/null @@ -1,467 +0,0 @@ -from sys import argv, stderr, float_info -import sys -from upstream.parsePolyglot import parseYAML -from os import walk -from os.path import join -from re import sub, match, split, DOTALL -from collections import namedtuple -import ast - -verbosity = 1 - -try: - NameConstant = ast.NameConstant -except: - NameConstant = lambda a: a - -class Discard(Exception): - pass - -class Unhandled(Exception): - pass - -failed = False - -Ctx = namedtuple('Ctx', ['vars', 'context', 'type']) - -def convert(python, prec, file, type): - try: - expr = ast.parse(python, filename=file, mode='eval').body - cxx = to_cxx(expr, prec, Ctx(vars=[], type=type, context=None)) - return sub('" \\+ "', '', cxx) - except (Unhandled, AssertionError): - print("While translating: " + python, file=stderr) - raise - except SyntaxError as e: - raise Unhandled("syntax error: " + str(e) + ": " + repr(python)) - -def py_str(py): - def maybe_unstr(s): - if '(' in s: - return s - else: - return repr(s) - if type(py) is dict: - return '{' + ', '.join([repr(k) + ': ' + maybe_str(py[k]) for k in py]) + '}' - if not isinstance(py, "".__class__): - return repr(py) - return py - -def rename(id): - return { - 'R::default': 'R::default_', - 'default': 'default_', - 'R::do': 'R::do_', - 'do': 'do_', - 'union': 'union_', - 'False': 'false', - 'True': 'true', - 'xrange': 'R::range', - 'None': 'R::Nil()', - 'null': 'R::Nil()', - 'delete': 'delete_', - 'float': 'double', - 'int_cmp': 'int', - 'float_cmp': 'double', - 'range': 'R::range', - 'list': '', - 'R::union': 'R::union_' - }.get(id, id) - -def to_cxx_str(expr): - if type(expr) is ast.Str: - return string(expr.s) - if type(expr) is ast.Num: - return string(str(expr.n)) - if 'frozenset' in ast.dump(expr): - raise Discard("frozenset not supported") - if type(expr) is ast.Name: - raise Discard("dict with non-string key") - raise Unhandled("not string expr: " + ast.dump(expr)) - -def is_null(expr): - return (type(expr) is ast.Name and expr.id in ['None', 'null'] - or type(expr) is NameConstant and expr.value == None) - -def is_bool(expr): - return (type(expr) is ast.Name and expr.id in ['true', 'false', 'True', 'False'] - or type(expr) is NameConstant and expr.value in [True, False]) - -def to_cxx_expr(expr, prec, ctx): - if ctx.type == 'query': - if type(expr) in [ast.Str, ast.Num] or is_null(expr) or is_bool(expr): - return "R::expr(" + to_cxx(expr, 17, ctx) + ")" - return to_cxx(expr, prec, ctx) - -def to_cxx(expr, prec, ctx, parentType=None): - context = ctx.context - ctx = Ctx(vars=ctx.vars, type=ctx.type, context=None) - try: - t = type(expr) - if t == ast.Num: - if abs(expr.n) > 4503599627370496: - f = repr(expr.n) - if "e" in f: - return f - else: - return f + ".0" - else: - return repr(expr.n) - elif t == ast.Call: - #assert not expr.kwargs - #assert not expr.starargs - return to_cxx(expr.func, 2, ctx_set(ctx, context='function')) + to_args(expr.func, expr.args, expr.keywords, ctx) - elif t == ast.Attribute: - if type(expr.value) is ast.Name: - if expr.value.id == 'r': - if expr.attr == 'error' and context != 'function': - return "R::error()" - if expr.attr == 'binary': - if ctx.type == 'query': - return 'R::binary' - else: - return 'R::Binary' - return rename("R::" + expr.attr) - elif expr.value.id == 'datetime': - if expr.attr == 'fromtimestamp': - return "R::Time" - elif expr.attr == 'now': - return "R::Time::now" - if expr.attr == 'RqlTzinfo': - return 'R::Time::parse_utc_offset' - if expr.attr in ['encode', 'close']: - raise Discard(expr.attr + " not supported") - return to_cxx_expr(expr.value, 2, ctx) + "." + rename(expr.attr) - elif t == ast.Name: - if expr.id in ['frozenset']: - raise Discard("frozenset not supported") - elif expr.id in ctx.vars: - if ctx.type == 'query': - return parens(prec, 3, "*" + expr.id) - else: - return expr.id - elif (expr.id == 'range' or expr.id == 'xrange') and ctx.type != 'query': - return 'array_range' - elif expr.id == 'nil' and ctx.type == 'query': - return 'R::expr(nil)' - return rename(expr.id) - elif t == NameConstant: - if expr.value == True: - return "true" - elif expr.value == False: - return "false" - elif expr.value == None: - return "R::Nil()" - else: - raise Unhandled("constant: " + repr(expr.value)) - elif t == ast.Subscript: - st = type(expr.slice) - if st == ast.Index: - return to_cxx(expr.value, 2, ctx) + "[" + to_cxx(expr.slice.value, 17, ctx) + "]" - if st == ast.Slice: - assert not expr.slice.step - if not expr.slice.upper: - return to_cxx(expr.value, 2, ctx) + ".slice(" + to_cxx(expr.slice.lower, 17, ctx) + ")" - if not expr.slice.lower: - return to_cxx(expr.value, 2, ctx) + ".limit(" + to_cxx(expr.slice.upper, 17, ctx) + ")" - return to_cxx(expr.value, 2, ctx) + ".slice(" + to_cxx(expr.slice.lower, 17, ctx) + ", " + to_cxx(expr.slice.upper, 17, ctx) + ")" - else: - raise Unhandled("slice type: " + repr(st)) - elif t == ast.Dict: - if ctx.type == 'query': - return "R::object(" + ', '.join([to_cxx(k, 17, ctx) + ", " + to_cxx(v, 17, ctx) for k, v in zip(expr.keys, expr.values)]) + ")" - else: - return "R::Object{" + ', '.join(["{" + to_cxx_str(k) + ", " + to_cxx(v, 17, ctx) + "}" for k, v in zip(expr.keys, expr.values)]) + "}" - elif t == ast.Str: - return string(expr.s, ctx) - elif t == ast.List: - if ctx.type == 'query': - return "R::array(" + ', '.join([to_cxx(el, 17, ctx) for el in expr.elts]) + ")" - else: - if parentType == ast.List: - return "{ R::Array{" + ', '.join([to_cxx(el, 17, ctx, t) for el in expr.elts]) + "} }" - else: - return "R::Array{" + ', '.join([to_cxx(el, 17, ctx, t) for el in expr.elts]) + "}" - elif t == ast.Lambda: - assert not expr.args.vararg - assert not expr.args.kwarg - ctx = ctx_set(ctx, vars = ctx.vars + [arg.arg for arg in expr.args.args]) - return "[=](" + ', '.join(['R::Var ' + arg.arg for arg in expr.args.args]) + "){ return " + to_cxx_expr(expr.body, 17, ctx_set(ctx, type='query')) + "; }" - elif t == ast.BinOp: - if type(expr.op) is ast.Mult and type(expr.left) is ast.Str: - return "repeat(" + to_cxx(expr.left, 17, ctx) + ", " + to_cxx(expr.right, 17, ctx) + ")" - ll = type(expr.left) is ast.List or type(expr.left) is ast.ListComp - rl = type(expr.right) is ast.List or type(expr.right) is ast.ListComp - op, op_prec = convert_op(expr.op) - if type(expr.op) is ast.Add and ll and rl: - return "append(" + to_cxx_expr(expr.left, op_prec, ctx) + ", " + to_cxx(expr.right, op_prec, ctx) + ")" - if op_prec: - return parens(prec, op_prec, to_cxx_expr(expr.left, op_prec, ctx) + " " + op + " " + to_cxx(expr.right, op_prec, ctx)) - else: - return op + "(" + to_cxx(expr.left, 17, ctx) + ", " + to_cxx(expr.right, 17, ctx) + ")" - elif t == ast.ListComp: - assert len(expr.generators) == 1 - assert type(expr.generators[0]) == ast.comprehension - assert type(expr.generators[0].target) == ast.Name - assert expr.generators[0].ifs == [] - seq = to_cxx(expr.generators[0].iter, 2, ctx) - if ctx.type == 'query': - var = expr.generators[0].target.id - body = to_cxx(expr.elt, 17, ctx_set(ctx, vars = ctx.vars + [var])) - return seq + ".map([=](R::Var " + var + "){ return " + body + "; })" - else: - var = expr.generators[0].target.id - body = to_cxx(expr.elt, 17, ctx_set(ctx, vars = ctx.vars + [var])) - # assume int - return "array_map([=](int " + var + "){ return " + body + "; }, " + seq + ")" - elif t == ast.Compare: - assert len(expr.ops) == 1 - assert len(expr.comparators) == 1 - op, op_prec = convert_op(expr.ops[0]) - return parens(prec, op_prec, to_cxx_expr(expr.left, op_prec, ctx) + op + to_cxx(expr.comparators[0], op_prec, ctx)) - elif t == ast.UnaryOp: - op, op_prec = convert_op(expr.op) - return parens(prec, op_prec, op + to_cxx(expr.operand, op_prec, ctx)) - elif t == ast.Bytes: - return string(expr.s, ctx) - elif t == ast.Tuple: - if ctx.type == 'query': - return "R::array(" + ', '.join([to_cxx(el, 17, ctx) for el in expr.elts]) + ")" - else: - return "R::Array{" + ', '.join([to_cxx(el, 17, ctx) for el in expr.elts]) + "}" - else: - raise Unhandled('ast type: ' + repr(t) + ', fields: ' + str(expr._fields)) - except Unhandled: - print("While translating: " + ast.dump(expr), file=stderr) - raise - -def ctx_set(ctx, context=None, vars=None, type=None): - if context is None: - context = ctx.context - if vars is None: - vars = ctx.vars - if type is None: - type = ctx.type - return Ctx(vars=vars, type=type, context=context) - -def convert_op(op): - t = type(op) - if t == ast.Add: - return '+', 6 - if t == ast.Sub: - return '-', 6 - if t == ast.Mod: - return '%', 5 - if t == ast.Mult: - return '*', 5 - if t == ast.Div: - return '/', 5 - if t == ast.Pow: - return 'pow', 0 - if t == ast.Eq: - return '==', 9 - if t == ast.NotEq: - return '!=', 9 - if t == ast.Lt: - return '<', 8 - if t == ast.Gt: - return '>', 8 - if t == ast.GtE: - return '>=', 8 - if t == ast.LtE: - return '<=', 8 - if t == ast.USub: - return '-', 3 - if t == ast.BitAnd: - return '&&', 13 - if t == ast.BitOr: - return '||', 14 - if t == ast.Invert: - return '!', 3 - else: - raise Unhandled('op type: ' + repr(t)) - -def to_args(func, args, optargs, ctx): - it = func - while type(it) is ast.Attribute: - it = it.value - if type(it) is ast.Call: - ctx = ctx_set(ctx, type='query') - break - if type(it) is ast.Name and it.id == 'r': - ctx = ctx_set(ctx, type='query') - ret = "(" - ret = ret + ', '.join([to_cxx(arg, 17, ctx) for arg in args]) - o = list(optargs) - if o: - out = [] - for f in o: - out.append("{" + string(f.arg) + ", R::expr(" + to_cxx(f.value, 17, ctx) + ")}") - if args: - ret = ret + ", " - ret = ret + "R::OptArgs{" + ', '.join(out) + "}" - return ret + ")" - -def string(s, ctx=None): - was_hex = False - wrap = ctx and ctx.type == 'string' - if type(s) is str: - s = s.encode('utf8') - if type(s) is bytes: - def string_escape(c): - nonlocal wrap - nonlocal was_hex - if c == 0: - wrap = True - if c < 32 or c > 127 or (was_hex and chr(c) in "0123456789abcdefABCDEF"): - was_hex = True - return '\\x' + ('0' + hex(c)[2:])[-2:] - was_hex = False - if c == 34: - return '\\"' - if c == 92: - return '\\\\' - else: - return chr(c) - else: - raise Unhandled("string type: " + repr(type(s))) - e = '"' + ''.join([string_escape(c) for c in s]) + '"' - if wrap: - return "std::string(" + e + ", " + str(len(s)) + ")" - return e - -def parens(prec, in_prec, cxx): - if in_prec >= prec: - return "(" + cxx + ")" - else: - return cxx - -print("// auto-generated by yaml_to_cxx.py from " + argv[1]) -print("#include \"testlib.h\"") - -indent = 0 - -def p(s): - print((indent * " ") + s); - -def enter(s = ""): - if s: - p(s) - global indent - indent = indent + 1 - -def exit(s = ""): - global indent - indent = indent - 1 - if s: - p(s) - -def get(o, ks, d): - try: - for k in ks: - if k in o: - return o[k] - except: - pass - return d - -def python_tests(tests): - for test in tests: - runopts = get(test, ['runopts'], None) - try: - ot = py_str(get(test['ot'], ['py', 'cd'], test['ot'])) - except: - try: - ot = py_str(test['py']['ot']) - except: - ot = None - if 'def' in test: - py = get(test['def'], ['py', 'cd'], test['def']) - if py and type(py) is not dict: - yield py_str(py), None, 'def', runopts - py = get(test, ['py', 'cd'], None) - if py: - if isinstance(py, "".__class__): - yield py, ot, 'query', runopts - elif type(py) is dict and 'cd' in py: - yield py_str(py['cd']), ot, 'query', runopts - else: - for t in py: - yield py_str(t), ot, 'query', runopts - -def maybe_discard(py, ot): - if ot is None: - return - if match(".*Expected .* argument", ot): - raise Discard("argument checks not supported") - if match(".*argument .* must", ot): - raise Discard("argument checks not supported") - if match(".*infix bitwise", ot): - raise Discard("infix bitwise not supported") - if match(".*Object keys must be strings", ot): - raise Discard("string object keys tests not supported") - if match(".*Got .* argument", ot): - raise Discard("argument checks not supported") - if match(".*AttributeError.*", ot): - raise Discard("attribute checks not supported, will cause a compiler error") - -data = parseYAML(open(argv[1]).read()) - -name = sub('/', '_', argv[1].split('.')[0]) - -enter("void %s() {" % name) - -p("enter_section(\"%s: %s\");" % (name, data['desc'].replace('"', '\\"'))) - -if 'table_variable_name' in data: - for var in split(" |, ", data['table_variable_name']): - p("temp_table %s_table;" % var) - p("R::Term %s = %s_table.table();" % (var, var)) - -defined = [] -for py, ot, tp, runopts in python_tests(data["tests"]): - try: - maybe_discard(py, ot) - assignment = match("\\A(\\w+) *= *([^=].*)\\Z", py, DOTALL) - if runopts: - args = ", R::optargs(" + ', '.join(['"' + k + '", ' + convert(py_str(runopts[k]), 17, name, 'value') for k in runopts]) + ")" - else: - args = '' - if assignment: - var = assignment.group(1) - if var == 'float_max': - p('auto float_max = ' + repr(float_info.max) + ";") - elif var == 'float_min': - p('auto float_min = ' + repr(float_info.min) + ";") - else: - if tp == 'def' and var not in ['bad_insert', 'trows']: - val = convert(assignment.group(2), 15, name, 'string') - post = "" - else: - val = convert(assignment.group(2), 15, name, 'query') - post = ".run(*conn" + args + ")" - if var in defined: - dvar = var - else: - defined.append(var); - dvar = "auto " + var - p("TEST_DO(" + dvar + " = (" + val + post + "));") - elif ot: - p("TEST_EQ(maybe_run(%s, *conn%s), (%s));" % (convert(py, 2, name, 'query'), args, convert(ot, 17, name, 'datum'))) - else: - p("TEST_DO(maybe_run(%s, *conn%s));" % (convert(py, 2, name, 'query'), args)) - except Discard as exc: - if verbosity >= 1: - print("Discarding %s (%s): %s" % (repr(py), repr(ot), str(exc)), file=stderr) - pass - except Unhandled as e: - failed = True - print(argv[1] + ": could not translate: " + str(e), file=stderr) - -p("section_cleanup();") -p("exit_section();") - -exit("}") - -if failed: - sys.exit(1) |