Пример #1
0
    def visit_Compare(self, node):
        if self._language in {"dart", "kotlin", "nim", "python"}:
            return node

        if isinstance(node.ops[0], ast.In):
            left = node.left
            right = node.comparators[0]
            left_type = get_id(get_inferred_type(left))
            right_type = get_id(get_inferred_type(right))
            if left_type == "str" and right_type == "str":
                if self._language == "julia":
                    ret = ast.parse("findfirst(a, b) != Nothing").body[0].value
                    ret.left.args[0] = left
                    ret.left.args[1] = right
                elif self._language == "go":
                    # To be rewritten to strings.Contains via plugins
                    ret = ast.parse("StringsContains(a, b)").body[0].value
                    ret.args[0] = right
                    ret.args[1] = left
                elif self._language == "cpp":
                    ret = ast.parse("a.find(b) != string.npos").body[0].value
                    ret.left.func.value = right
                    ret.left.args[0] = left
                else:
                    # rust and c++23
                    ret = ast.parse("a.contains(b)").body[0].value
                    ret.func.value = right
                    ret.args[0] = left
                ret.lineno = node.lineno
                ast.fix_missing_locations(ret)
                return ret

        return node
Пример #2
0
    def _visit_AssignOne(self, node, target):
        if isinstance(target, ast.Tuple):
            elts = [self.visit(e) for e in target.elts]
            value = self.visit(node.value)
            return "{0} = {1}".format(", ".join(elts), value)

        if isinstance(node.scopes[-1], ast.If):
            outer_if = node.scopes[-1]
            target_id = self.visit(target)
            if target_id in outer_if.common_vars:
                value = self.visit(node.value)
                return "{0} = {1}".format(target_id, value)

        if isinstance(target, ast.Subscript) or isinstance(
                target, ast.Attribute):
            target = self.visit(target)
            value = self.visit(node.value)
            if value == None:
                value = "None"
            return "{0} = {1}".format(target, value)

        definition = node.scopes.parent_scopes.find(get_id(target))
        if definition is None:
            definition = node.scopes.find(get_id(target))
        if isinstance(target, ast.Name) and defined_before(definition, node):
            target_str = self.visit(target)
            value = self.visit(node.value)
            return f"{target_str} = {value};"
        else:
            target = self.visit(target)
            value = self.visit(node.value)
            return f"{target} = {value}"
Пример #3
0
    def _visit_AssignOne(self, node, target) -> str:
        kw = "var" if is_mutable(node.scopes, get_id(target)) else "let"

        if isinstance(target, ast.Tuple):
            elts = [self.visit(e) for e in target.elts]
            elts_str = ", ".join(elts)
            value = self.visit(node.value)
            return f"{kw} ({elts_str}) = {value}"

        if isinstance(node.scopes[-1], ast.If):
            outer_if = node.scopes[-1]
            target_id = self.visit(target)
            if target_id in outer_if.common_vars:
                value = self.visit(node.value)
                return f"{kw} {target_id} = {value}"

        if isinstance(target, ast.Subscript) or isinstance(
                target, ast.Attribute):
            target = self.visit(target)
            value = self.visit(node.value)
            return f"{target} = {value}"

        definition = node.scopes.parent_scopes.find(get_id(target))
        if definition is None:
            definition = node.scopes.find(get_id(target))
        if isinstance(target, ast.Name) and defined_before(definition, node):
            target = self.visit(target)
            value = self.visit(node.value)
            return f"{target} = {value}"
        else:
            target = self.visit(target)
            value = self.visit(node.value)

            return f"{kw} {target} = {value}"
Пример #4
0
 def visit_Call(self, node):
     needs_assign = False
     fname = node.func
     if isinstance(fname, ast.Attribute):
         if is_list(node.func.value) and fname.attr == "append":
             needs_assign = True
         value_id = get_id(fname.value)
         if value_id not in IGNORED_MODULE_SET:
             if value_id:
                 node0 = ast.Name(id=get_id(fname.value),
                                  lineno=node.lineno)
             else:
                 node0 = fname.value
             node.args = [node0] + node.args
             node.func = ast.Name(id=fname.attr,
                                  lineno=node.lineno,
                                  ctx=fname.ctx)
     if needs_assign:
         ret = ast.Assign(
             targets=[ast.Name(id=fname.value.id, lineno=node.lineno)],
             value=node,
             lineno=node.lineno,
             scopes=node.scopes,
         )
         return ret
     return node
Пример #5
0
 def _typename_from_type_node(self, node) -> Union[List, str, None]:
     if isinstance(node, ast.Name):
         return self._map_type(
             get_id(node), getattr(node, "lifetime", LifeTime.UNKNOWN)
         )
     elif isinstance(node, ast.ClassDef):
         return get_id(node)
     elif isinstance(node, ast.Tuple):
         return [self._typename_from_type_node(e) for e in node.elts]
     elif isinstance(node, ast.Attribute):
         node_id = get_id(node)
         if node_id.startswith("typing."):
             node_id = node_id.split(".")[1]
         return node_id
     elif isinstance(node, ast.Subscript):
         # Store a tuple like (List, int) or (Dict, (str, int)) for container types
         # in node.container_type
         # And return a target specific type
         slice_value = self._slice_value(node)
         (value_type, index_type) = tuple(
             map(self._typename_from_type_node, (node.value, slice_value))
         )
         value_type = self._map_container_type(value_type)
         node.container_type = (value_type, index_type)
         return self._combine_value_index(value_type, index_type)
     return self._default_type
Пример #6
0
 def visit_Call(self, node):
     if get_id(node.func) == "print":
         if len(node.args) == 1:
             anno = getattr(node.args[0], "annotation", None)
             if get_id(anno) == "bool":
                 if self._language == "go":
                     return self._do_go_rewrite(node)
                 else:
                     return self._do_other_rewrite(node)
     return node
Пример #7
0
    def visit_Name(self, node):
        if node.id == "True" or node.id == "False":
            return CLikeTranspiler().visit(node)

        var = node.scopes.find(node.id)
        if not var:
            return get_id(node)
        if defined_before(var, node):
            return get_id(node)
        else:
            return self.visit(var.assigned_from.value)
Пример #8
0
 def visit_BinOp(self, node):
     self.generic_visit(node)
     if isinstance(node.op, ast.Div):
         left_type = get_id(get_inferred_type(node.left))
         right_type = get_id(get_inferred_type(node.right))
         if set([left_type, right_type]) == {"int"}:
             # This attribute should technically be on node.op
             # But python seems to use the same AST node for other
             # division operations?
             node.use_integer_div = True
     return node
Пример #9
0
 def visit_Set(self, node):
     self.generic_visit(node)
     if len(node.elts) > 0:
         elements = [self.visit(e) for e in node.elts]
         elt_types = set([get_id(get_inferred_type(e)) for e in elements])
         if len(elt_types) == 1:
             elt_type = get_id(elements[0].annotation)
             self._annotate(node, f"Set[{elt_type}]")
     else:
         if not hasattr(node, "annotation"):
             node.annotation = ast.Name(id="Set")
     return node
Пример #10
0
 def visit_Call(self, node):
     fname = get_id(node.func)
     fndef = node.scopes.find(fname)
     if fndef and hasattr(fndef, "args"):
         for fnarg, node_arg in zip(fndef.args.args, node.args):
             if hasattr(fndef, "mutable_vars") and fnarg.arg in fndef.mutable_vars:
                 self.increase_use_count(get_id(node_arg))
     if hasattr(node.func, "attr"):
         if node.func.attr == "append":
             self.increase_use_count(get_id(node.func.value))
     self.generic_visit(node)
     return node
Пример #11
0
 def visit_If(self, node):
     body_vars = {get_id(v): v for v in node.scopes[-1].body_vars}
     orelse_vars = {get_id(v): v for v in node.scopes[-1].orelse_vars}
     node.common_vars = set(body_vars.keys()).intersection(set(orelse_vars.keys()))
     types = [self._typename_from_annotation(body_vars[v]) for v in node.common_vars]
     common_vars = "\n".join(
         [f"var {v} {t}" for v, t in zip(node.common_vars, types)]
     )
     if common_vars:
         return common_vars + "\n" + super().visit_If(node)
     else:
         return super().visit_If(node)
Пример #12
0
    def _visit_AssignOne(self, node, target):
        if isinstance(target, ast.Tuple):
            elts = [self.visit(e) for e in target.elts]
            value = self.visit(node.value)
            return "var {0} = {1}".format(", ".join(elts), value)

        if isinstance(node.scopes[-1], ast.If):
            outer_if = node.scopes[-1]
            target_id = self.visit(target)
            if target_id in outer_if.common_vars:
                value = self.visit(node.value)
                return "{0} = {1}".format(target_id, value)

        if isinstance(target, ast.Subscript) or isinstance(
                target, ast.Attribute):
            target = self.visit(target)
            value = self.visit(node.value)
            if value == None:
                value = "None"
            return "{0} = {1}".format(target, value)

        typename = self._typename_from_annotation(target)
        needs_cast = self._needs_cast(target, node.value)
        target_str = self.visit(target)
        value = self.visit(node.value)
        if needs_cast:
            left_annotation = target.annotation
            right_annotation = getattr(node.value, "annotation", None)
            if right_annotation is None:
                right_annotation = ast.Name(
                    id=get_inferred_go_type(node.value))
            value = self._assign_cast(value, typename, left_annotation,
                                      right_annotation)

        definition = node.scopes.parent_scopes.find(get_id(target))
        if definition is None:
            definition = node.scopes.find(get_id(target))
        if isinstance(target, ast.Name) and defined_before(definition, node):
            return f"{target_str} = {value}"
        else:
            if typename is not None:
                # Dummy assign to silence the compiler on unused vars
                maybe_tail = ""
                if target_str.startswith("_") and target_str != "_":
                    maybe_tail = f"\n_ = {target_str}"
                if target_str == "_":
                    return f"{target_str} = {value}"
                return f"var {target_str} {typename} = {value}{maybe_tail}"

            if is_global(node):
                return f"var {target_str} = {value}"
            return f"{target_str} := {value}"
Пример #13
0
def get_inferred_rust_type(node):
    if hasattr(node, "rust_annotation"):
        return node.rust_annotation
    if isinstance(node, ast.Name):
        if not hasattr(node, "scopes"):
            return None
        definition = node.scopes.find(get_id(node))
        # Prevent infinite recursion
        if definition != node:
            return get_inferred_rust_type(definition)
    python_type = get_inferred_type(node)
    ret = map_type(get_id(python_type))
    node.rust_annotation = ret
    return ret
Пример #14
0
    def visit_If(self, node):
        body_vars = set([get_id(v) for v in node.scopes[-1].body_vars])
        orelse_vars = set([get_id(v) for v in node.scopes[-1].orelse_vars])
        node.common_vars = body_vars.intersection(orelse_vars)

        var_definitions = []
        for cv in node.common_vars:
            definition = node.scopes.find(cv)
            var_type = self._typename_from_annotation(definition)
            if var_type == self._default_type:
                var_type = decltype(definition)
            var_definitions.append("{0} {1};\n".format(var_type, cv))

        return "".join(var_definitions) + super().visit_If(node)
Пример #15
0
    def visit_Name(self, node):
        var = node.scopes.find(get_id(node))

        if not var:  # TODO why no scopes found for node id?
            return get_id(node)

        if isinstance(var.assigned_from, ast.For):
            it = var.assigned_from.iter
            return "std::declval<typename decltype({0})::value_type>()".format(
                self.visit(it))
        elif isinstance(var.assigned_from, ast.FunctionDef):
            return get_id(var)
        else:
            return self.visit(var.assigned_from.value)
Пример #16
0
    def visit_Assign(self, node: ast.Assign) -> str:
        assign: List[str] = []
        use_temp: bool = len(node.targets) > 1 and isinstance(
            node.value, ast.Call)
        if use_temp:
            assign.append(f"mut tmp := {self.visit(node.value)}")
        for target in node.targets:
            kw: str = "mut " if is_mutable(node.scopes, get_id(target)) else ""
            if use_temp:
                value: str = "tmp"
            else:
                value: str = self.visit(node.value)

            if isinstance(target, (ast.Tuple, ast.List)):
                value = value[1:-1]
                subtargets: List[str] = []
                op: str = ":="
                for subtarget in target.elts:
                    subkw: str = ("mut " if is_mutable(
                        node.scopes, get_id(subtarget)) else "")
                    subtargets.append(f"{subkw}{self.visit(subtarget)}")
                    definition: Optional[
                        ast.AST] = node.scopes.parent_scopes.find(
                            get_id(subtarget)) or node.scopes.find(
                                get_id(subtarget))
                    if definition is not None and defined_before(
                            definition, subtarget):
                        op = "="
                    elif op == "=":
                        raise AstNotImplementedError(
                            "Mixing declarations and assignment in the same statement is unsupported.",
                            node,
                        )
                assign.append(f"{', '.join(subtargets)} {op} {value}")
            elif isinstance(target, (ast.Subscript, ast.Attribute)):
                target: str = self.visit(target)
                assign.append(f"{target} = {value}")
            elif isinstance(target, ast.Name) and defined_before(
                    node.scopes.parent_scopes.find(target.id)
                    or node.scopes.find(target.id),
                    node,
            ):
                target: str = self.visit(target)
                assign.append(f"{target} = {value}")
            else:
                target: str = self.visit(target)

                assign.append(f"{kw}{target} := {value}")
        return "\n".join(assign)
Пример #17
0
def is_dict(node: ast.AST) -> bool:
    if isinstance(node, (ast.Dict, ast.DictComp)):
        return True
    elif isinstance(node, ast.Call) and get_id(node.func) == "dict":
        return True
    elif isinstance(node, ast.Assign):
        return is_dict(node.value)
    elif isinstance(node, ast.Name):
        var: ast.AST = node.scopes.find(get_id(node))
        return (hasattr(var, "assigned_from")
                and not isinstance(var.assigned_from, ast.FunctionDef)
                and not isinstance(var.assigned_from, ast.For)
                and is_dict(var.assigned_from.value))
    else:
        return False
Пример #18
0
 def visit_sealed_class(self, node):
     variants = []
     accessors = []
     tag_checkers = []
     camel_node_name = camel_case(node.name)
     for member, var in node.class_assignments.items():
         member_id = get_id(member)
         camel_member_id = camel_case(member_id)
         lower_member_id = member_id.lower()
         typename = node.declarations_with_defaults.get(member_id, None)
         if typename == None:
             variants.append(f"{member_id},")
         else:
             typename, _ = typename
             variants.append(f"{member_id}({typename}),")
         tag_check = textwrap.dedent(f"""
                 fn is_{lower_member_id}(&self) -> bool {{
                     matches!(*self, {camel_node_name}::{camel_member_id}(_))
                 }}""")
         tag_checkers.append(tag_check)
         accessor = textwrap.dedent(f"""
                 fn {lower_member_id}(&self) -> Option<&{typename}>{{
                     if let {camel_node_name}::{camel_member_id}(val) = self {{
                         Some(val)
                     }} else {{
                         None
                     }}
                 }}""")
         accessors.append(accessor)
     body_str = "\n".join(variants)
     impl_str = "\n".join(accessors) + "\n" + "\n".join(tag_checkers)
     return f"enum {camel_node_name} {{ {body_str} }}\n\n impl {camel_node_name} {{ {impl_str} }}\n\n"
Пример #19
0
def get_inferred_kotlin_type(node):
    if isinstance(node, ast.Call):
        fname = get_id(node.func)
        if fname in {"max", "min", "floor"}:
            return "float64"
    if isinstance(node, ast.Name):
        if not hasattr(node, "scopes"):
            return None
        definition = node.scopes.find(get_id(node))
        # Prevent infinite recursion
        if definition != node:
            return get_inferred_kotlin_type(definition)
    if hasattr(node, "kotlin_annotation"):
        return node.kotlin_annotation
    python_type = get_inferred_type(node)
    return map_type(get_id(python_type))
Пример #20
0
 def visit_Call(self, node):
     fname = get_id(node.func)
     if fname is not None:
         # Handle methods calls by looking up the method name
         # without the prefix
         # TODO: use remove suffix
         if fname.startswith("self."):
             fname = fname.split(".", 1)[1]
         fn = node.scopes.find(fname)
         if isinstance(fn, ast.ClassDef):
             self._annotate(node, fn.name)
         elif isinstance(fn, ast.FunctionDef):
             return_type = (fn.returns if hasattr(fn, "returns")
                            and fn.returns else None)
             if return_type is not None:
                 node.annotation = return_type
                 lifetime = getattr(fn.returns, "lifetime", None)
                 if lifetime is not None:
                     node.annotation.lifetime = lifetime
         elif fname in {"max", "min"}:
             return_type = get_inferred_type(node.args[0])
             if return_type is not None:
                 node.annotation = return_type
         elif fname in self.TYPE_DICT.values():
             node.annotation = ast.Name(id=fname)
     self.generic_visit(node)
     return node
Пример #21
0
 def visit_Name(self, node):
     if hasattr(node, "scopes") and is_global(node):
         old_name = get_id(node)
         new_name = camel_case(old_name)
         if old_name != new_name:
             rename(node.scopes[-1], old_name, new_name)
     return node
Пример #22
0
    def visit_ClassDef(self, node):
        extractor = DeclarationExtractor(JuliaTranspiler())
        extractor.visit(node)
        declarations = node.declarations = extractor.get_declarations()
        node.class_assignments = extractor.class_assignments
        ret = super().visit_ClassDef(node)
        if ret is not None:
            return ret

        decorators = [get_id(d) for d in node.decorator_list]
        decorators = [
            class_for_typename(t, None, self._imported_names)
            for t in decorators
        ]
        for d in decorators:
            if d in CLASS_DISPATCH_TABLE:
                ret = CLASS_DISPATCH_TABLE[d](self, node)
                if ret is not None:
                    return ret

        fields = []
        index = 0
        for declaration, typename in declarations.items():
            if typename == None:
                typename = "ST{0}".format(index)
                index += 1
            fields.append(f"{declaration}::{typename}")

        fields = "\n".join(fields)
        struct_def = f"struct {node.name}\n{fields}\nend\n"
        for b in node.body:
            if isinstance(b, ast.FunctionDef):
                b.self_type = node.name
        body = "\n".join([self.visit(b) for b in node.body])
        return f"{struct_def}\n{body}"
Пример #23
0
 def visit_Call(self, node):
     fname = node.func
     if isinstance(fname, ast.Attribute):
         if is_list(node.func.value) and fname.attr == "append":
             new_func_name = "push!"
         else:
             new_func_name = fname.attr
         if get_id(fname.value):
             node0 = ast.Name(id=get_id(fname.value), lineno=node.lineno)
         else:
             node0 = fname.value
         node.args = [node0] + node.args
         node.func = ast.Name(id=new_func_name,
                              lineno=node.lineno,
                              ctx=fname.ctx)
     return node
Пример #24
0
    def visit_AnnAssign(self, node: ast.AnnAssign) -> ast.AST:
        self.generic_visit(node)

        node.target.annotation = node.annotation
        if get_id(node.annotation) in self.FIXED_WIDTH_INTS_NAME:
            self.has_fixed_width_ints = True
        return node
Пример #25
0
    def visit_Assign(self, node):
        if self._disable:
            return node

        target = node.targets[0]
        if isinstance(target, ast.Tuple) and isinstance(node.value, ast.Tuple):
            names = [
                get_id(elt) for elt in target.elts
                if isinstance(elt, ast.Name)
            ]
            has_ignored = "_" in names
            if self._unpack and has_ignored:
                return self._visit_assign_unpack_all(node)
            if not has_ignored:
                return node

            body = [node]
            to_eval = []
            for i in range(len(target.elts)):
                if names[i] == "_":
                    del target.elts[i]
                    to_eval.append(node.value.elts[i])
                    del node.value.elts[i]
            # TODO: Evaluation order - we may have to split the tuple assignment to get
            # it right. For now, keep it simple
            body = [ast.Expr(value=e) for e in to_eval] + body
            return create_ast_block(body=body, at_node=node)
        return node
Пример #26
0
    def visit_Attribute(self, node):
        attr = node.attr
        value_id = get_id(node.value)
        if is_builtin_import(value_id):
            return "py14::" + value_id + "::" + attr
        elif value_id == "math":
            if node.attr == "asin":
                return "std::asin"
            elif node.attr == "atan":
                return "std::atan"
            elif node.attr == "acos":
                return "std::acos"

        if is_list(node.value):
            if node.attr == "append":
                attr = "push_back"

        if is_enum(value_id, node.scopes):
            return f"{value_id}::{attr}"

        if is_class_or_module(value_id, node.scopes):
            return f"{value_id}.{attr}"

        if is_self_arg(value_id, node.scopes):
            return f"this->{attr}"

        return f"{value_id}.{attr}"
Пример #27
0
    def visit_ClassDef(self, node):
        extractor = DeclarationExtractor(KotlinTranspiler())
        extractor.visit(node)
        declarations = node.declarations = extractor.get_declarations()
        node.class_assignments = extractor.class_assignments
        ret = super().visit_ClassDef(node)
        if ret is not None:
            return ret

        fields = []
        index = 0
        for declaration, typename in declarations.items():
            if typename == None:
                typename = "ST{0}".format(index)
                index += 1
            mut = is_mutable(node.scopes, get_id(declaration))
            mut = "var" if mut else "val"
            fields.append(f"{mut} {declaration}: {typename}")

        for b in node.body:
            if isinstance(b, ast.FunctionDef):
                b.self_type = node.name

        if node.is_dataclass:
            fields = ", ".join(fields)
            body = [self.visit(b) for b in node.body]
            body = "\n".join(body)
            return f"data class {node.name}({fields}) {{\n{body}\n}}\n"
        else:
            fields = "\n".join(fields)
            body = [self.visit(b) for b in node.body]
            body = "\n".join(body)
            return f"class {node.name} {{\n{fields}\n\n {body}\n}}\n"
Пример #28
0
    def visit_If(self, node):
        body_vars = set([get_id(v) for v in node.scopes[-1].body_vars])
        orelse_vars = set([get_id(v) for v in node.scopes[-1].orelse_vars])
        node.common_vars = body_vars.intersection(orelse_vars)

        var_definitions = []
        for cv in node.common_vars:
            typename = "var"
            if hasattr(cv, "annotation"):
                typename = get_id(cv.annotation)

            var_definitions.append((typename, cv))
        decls = "\n".join(
            [f"{typename} {cv};" for typename, cv in var_definitions])

        return decls + "\n\n" + super().visit_If(node)
Пример #29
0
def is_enum(name, scopes):
    entry = _lookup_class_or_module(name, scopes)
    if entry:
        bases = set([get_id(base) for base in entry.bases])
        enum_bases = {"Enum", "IntEnum", "IntFlag"}
        return bases & enum_bases
    return False
Пример #30
0
    def _visit_AssignOne(self, node, target):
        kw = "var" if is_mutable(node.scopes, get_id(target)) else "final"

        if isinstance(target, ast.Tuple):
            self._usings.add("package:tuple/tuple.dart")
            elts = [self.visit(e) for e in target.elts]
            value = self.visit(node.value)
            value_types = "int, int"
            count = len(elts)
            tmp_var = self._get_temp()
            buf = [f"{kw} {tmp_var} = Tuple{count}<{value_types}>{value};"]
            for i, elt in enumerate(elts):
                buf.extend([f"{elt} = {tmp_var}.item{i+1};"])
            return "\n".join(buf)

        if isinstance(node.scopes[-1], ast.If):
            outer_if = node.scopes[-1]
            target_id = self.visit(target)
            if target_id in outer_if.common_vars:
                value = self.visit(node.value)
                return f"{kw} {target_id} = {value};"

        if isinstance(target, ast.Subscript) or isinstance(
                target, ast.Attribute):
            target = self.visit(target)
            value = self.visit(node.value)
            return f"{target} = {value};"

        definition = node.scopes.parent_scopes.find(get_id(target))
        if definition is None:
            definition = node.scopes.find(get_id(target))
        if isinstance(target, ast.Name) and defined_before(definition, node):
            target = self.visit(target)
            value = self.visit(node.value)
            return f"{target} = {value};"
        else:
            typename = self._typename_from_annotation(target)
            target = self.visit(target)
            value = self.visit(node.value)

            if typename != self._default_type:
                if kw == self._default_type:
                    return f"{typename} {target} = {value};"
            else:
                return f"{kw} {target} = {value};"

            return f"{kw} {typename} {target} = {value};"