Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions analyzer_patch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<<<<<<< SEARCH
elif isinstance(node, ast.Dict):
if not node.keys:
return "map[string]Any"
key_types = set()
val_types = set()
for k, v in zip(node.keys, node.values):
if k:
key_types.add(self._guess_node_type(k))
if v:
val_types.add(self._guess_node_type(v))

k_type = "string"
if len(key_types) == 1:
k_type = list(key_types)[0]
elif len(key_types) > 1:
k_type = "Any"

v_type = "Any"
if len(val_types) == 1:
v_type = list(val_types)[0]

return f"map[{k_type}]{v_type}"
return "Any"
=======
elif isinstance(node, ast.Dict):
if not node.keys:
return "map[string]Any"
key_types = set()
val_types = set()
for k, v in zip(node.keys, node.values):
if k:
key_types.add(self._guess_node_type(k))
if v:
val_types.add(self._guess_node_type(v))

k_type = "string"
if len(key_types) == 1:
k_type = list(key_types)[0]
elif len(key_types) > 1:
k_type = "Any"

v_type = "Any"
if len(val_types) == 1:
v_type = list(val_types)[0]

return f"map[{k_type}]{v_type}"
elif isinstance(node, ast.Set):
if not node.elts:
return "map[string]bool"
element_types = set()
for elt in node.elts:
element_types.add(self._guess_node_type(elt))
if len(element_types) == 1:
return f"map[{list(element_types)[0]}]bool"
return "map[string]bool"
return "Any"
>>>>>>> REPLACE
11 changes: 11 additions & 0 deletions analyzer_patch_visitor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<<<<<<< SEARCH
if isinstance(node.value, (ast.List, ast.Dict)):
inferred = self._infer_collection_type(node.value)
if target.id not in self.type_map or self.type_map[target.id] == "Any":
self.type_map[target.id] = inferred
=======
if isinstance(node.value, (ast.List, ast.Dict, ast.Set)):
inferred = self._infer_collection_type(node.value)
if target.id not in self.type_map or self.type_map[target.id] == "Any":
self.type_map[target.id] = inferred
>>>>>>> REPLACE
51 changes: 51 additions & 0 deletions calls_methods_fix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<<<<<<< SEARCH
# list.pop() / dict.pop()
elif attr == "pop":
obj_type = self._guess_type(func_node.value)
if obj_type.startswith("map[") and obj_type.endswith("]bool"):
return self._handle_set_methods(node, func_node, args)

obj_type = self._guess_type(func_node.value)
obj = self.visit(func_node.value)
if obj_type.startswith("[]"):
=======
# list.pop() / dict.pop()
elif attr == "pop":
obj_type = self._guess_type(func_node.value)
if obj_type.startswith("map[") and obj_type.endswith("]bool"):
return self._handle_set_methods(node, func_node, args)

obj = self.visit(func_node.value)
if obj_type.startswith("[]"):
>>>>>>> REPLACE
<<<<<<< SEARCH
# list.remove()
elif attr == "remove" and len(args) == 1:
obj_type = self._guess_type(func_node.value)
if obj_type.startswith("map[") and obj_type.endswith("]bool"):
return self._handle_set_methods(node, func_node, args)

obj_type = self._guess_type(func_node.value)
if obj_type.startswith("[]") or obj_type == "Any":
=======
# list.remove()
elif attr == "remove" and len(args) == 1:
obj_type = self._guess_type(func_node.value)
if obj_type.startswith("map[") and obj_type.endswith("]bool"):
return self._handle_set_methods(node, func_node, args)

if obj_type.startswith("[]") or obj_type == "Any":
>>>>>>> REPLACE
<<<<<<< SEARCH
elif attr == "remove" and len(args) == 1:
obj_type = self._guess_type(func_node.value)
if obj_type.startswith("map[") and obj_type.endswith("]bool"):
return self._handle_set_methods(node, func_node, args)

self.used_builtins.add("py_set_remove")
return f"py_set_remove(mut {obj}, {args[0]})"
=======
elif attr == "remove" and len(args) == 1:
self.used_builtins.add("py_set_remove")
return f"py_set_remove(mut {obj}, {args[0]})"
>>>>>>> REPLACE
131 changes: 131 additions & 0 deletions calls_methods_patch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<<<<<<< SEARCH
# dict.get() / update() / setdefault()
elif attr == "update":
obj_type = self._guess_type(func_node.value)
# Heuristic to avoid collision with hashlib
if obj_type in ("PyHashSha256", "PyHashMd5"):
return None

# Additional heuristic: hashlib objects usually start with 'h'
if obj_type == "Any" and isinstance(func_node.value, ast.Name) and func_node.value.id.startswith("h"):
return None

return self._handle_dict_update(node, func_node, args)

elif attr == "setdefault":
return self._handle_dict_setdefault(node, func_node, args)

elif attr == "get":
return self._handle_dict_get(node, func_node, args)

return None
=======
# dict.get() / update() / setdefault()
elif attr == "update":
obj_type = self._guess_type(func_node.value)
# Heuristic to avoid collision with hashlib
if obj_type in ("PyHashSha256", "PyHashMd5"):
return None

# Additional heuristic: hashlib objects usually start with 'h'
if obj_type == "Any" and isinstance(func_node.value, ast.Name) and func_node.value.id.startswith("h"):
return None

if obj_type.startswith("map[") and obj_type.endswith("]bool"):
return self._handle_set_methods(node, func_node, args)

return self._handle_dict_update(node, func_node, args)

elif attr == "setdefault":
return self._handle_dict_setdefault(node, func_node, args)

elif attr == "get":
return self._handle_dict_get(node, func_node, args)

# Set methods
elif attr in ("add", "discard", "union", "intersection", "difference", "symmetric_difference",
"intersection_update", "difference_update", "symmetric_difference_update",
"issubset", "issuperset", "isdisjoint"):
return self._handle_set_methods(node, func_node, args)

return None

def _handle_set_methods(self, node: ast.Call, func_node: ast.Attribute, args: list) -> str | None:
"""Handle set methods."""
attr = func_node.attr
obj_type = self._guess_type(func_node.value)
if not (obj_type.startswith("map[") and obj_type.endswith("]bool")) and obj_type != "Any":
return None

obj = self.visit(func_node.value)

if attr == "add" and len(args) == 1:
return f"{obj}[{args[0]}] = true"
elif attr == "discard" and len(args) == 1:
return f"{obj}.delete({args[0]})"
elif attr == "remove" and len(args) == 1:
self.used_builtins.add("py_set_remove")
return f"py_set_remove(mut {obj}, {args[0]})"
elif attr == "pop" and len(args) == 0:
self.used_builtins.add("py_set_pop")
return f"py_set_pop(mut {obj})"
elif attr == "union" and len(args) >= 1:
self.used_builtins.add("py_set_union")
res = obj
for arg in args:
res = f"py_set_union({res}, {arg})"
return res
elif attr == "intersection" and len(args) >= 1:
self.used_builtins.add("py_set_intersection")
res = obj
for arg in args:
res = f"py_set_intersection({res}, {arg})"
return res
elif attr == "difference" and len(args) >= 1:
self.used_builtins.add("py_set_difference")
res = obj
for arg in args:
res = f"py_set_difference({res}, {arg})"
return res
elif attr == "symmetric_difference" and len(args) == 1:
self.used_builtins.add("py_set_xor")
return f"py_set_xor({obj}, {args[0]})"
elif attr == "update" and len(args) >= 1:
self.used_builtins.add("py_set_update")
res = ""
for i, arg in enumerate(args):
call = f"py_set_update(mut {obj}, {arg})"
if i == 0: res = call
else: res = f"({res}, {call})" # Nested calls for multiple args
return res
elif attr == "intersection_update" and len(args) >= 1:
self.used_builtins.add("py_set_intersection_update")
res = ""
for i, arg in enumerate(args):
call = f"py_set_intersection_update(mut {obj}, {arg})"
if i == 0: res = call
else: res = f"({res}, {call})"
return res
elif attr == "difference_update" and len(args) >= 1:
self.used_builtins.add("py_set_difference_update")
res = ""
for i, arg in enumerate(args):
call = f"py_set_difference_update(mut {obj}, {arg})"
if i == 0: res = call
else: res = f"({res}, {call})"
return res
elif attr == "symmetric_difference_update" and len(args) == 1:
self.used_builtins.add("py_set_xor_update")
return f"py_set_xor_update(mut {obj}, {args[0]})"
elif attr == "issubset" and len(args) == 1:
self.used_builtins.add("py_set_subset")
return f"py_set_subset({obj}, {args[0]})"
elif attr == "issuperset" and len(args) == 1:
self.used_builtins.add("py_set_subset")
return f"py_set_subset({args[0]}, {obj})"
elif attr == "isdisjoint" and len(args) == 1:
self.used_builtins.add("py_set_isdisjoint")
return f"py_set_isdisjoint({obj}, {args[0]})"

return None
>>>>>>> REPLACE
121 changes: 121 additions & 0 deletions module_patch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<<<<<<< SEARCH
if "py_set_xor" in self.used_builtins:
self.emitter.add_helper_function("""fn py_set_xor[K](a map[K]bool, b map[K]bool) map[K]bool {
mut res := map[K]bool{}
for k, _ in a {
if k !in b {
res[k] = true
}
}
for k, _ in b {
if k !in a {
res[k] = true
}
}
return res
}""")
=======
if "py_set_xor" in self.used_builtins:
self.emitter.add_helper_function("""fn py_set_xor[K](a map[K]bool, b map[K]bool) map[K]bool {
mut res := map[K]bool{}
for k, _ in a {
if k !in b {
res[k] = true
}
}
for k, _ in b {
if k !in a {
res[k] = true
}
}
return res
}""")

if "py_set_from_list" in self.used_builtins:
self.emitter.add_helper_function("""fn py_set_from_list[T](a []Any) T {
mut res := T{}
for x in a {
T is map[string]bool {
res[x.str()] = true
} T is map[int]bool {
res[x as int] = true
} {
// Fallback
}
}
return res
}""")

if "py_set_remove" in self.used_builtins:
self.emitter.add_helper_function("""fn py_set_remove[K](mut s map[K]bool, val K) {
if val !in s { panic('KeyError') }
s.delete(val)
}""")

if "py_set_pop" in self.used_builtins:
self.emitter.add_helper_function("""fn py_set_pop[K](mut s map[K]bool) K {
for k, _ in s {
s.delete(k)
return k
}
panic('KeyError: pop from an empty set')
}""")

if "py_set_subset" in self.used_builtins:
self.emitter.add_helper_function("""fn py_set_subset[K](a map[K]bool, b map[K]bool) bool {
for k, _ in a {
if k !in b { return false }
}
return true
}""")

if "py_set_strict_subset" in self.used_builtins:
self.emitter.add_helper_function("""fn py_set_strict_subset[K](a map[K]bool, b map[K]bool) bool {
return a.len < b.len && py_set_subset(a, b)
}""")

if "py_set_isdisjoint" in self.used_builtins:
self.emitter.add_helper_function("""fn py_set_isdisjoint[K](a map[K]bool, b map[K]bool) bool {
for k, _ in a {
if k in b { return false }
}
return true
}""")

if "py_set_update" in self.used_builtins:
self.emitter.add_helper_function("""fn py_set_update[K](mut a map[K]bool, b map[K]bool) map[K]bool {
for k, _ in b {
a[k] = true
}
return a
}""")

if "py_set_intersection_update" in self.used_builtins:
self.emitter.add_helper_function("""fn py_set_intersection_update[K](mut a map[K]bool, b map[K]bool) map[K]bool {
mut to_delete := []K{}
for k, _ in a {
if k !in b { to_delete << k }
}
for k in to_delete {
a.delete(k)
}
return a
}""")

if "py_set_difference_update" in self.used_builtins:
self.emitter.add_helper_function("""fn py_set_difference_update[K](mut a map[K]bool, b map[K]bool) map[K]bool {
for k, _ in b {
a.delete(k)
}
return a
}""")

if "py_set_xor_update" in self.used_builtins:
self.emitter.add_helper_function("""fn py_set_xor_update[K](mut a map[K]bool, b map[K]bool) map[K]bool {
for k, _ in b {
if k in a { a.delete(k) }
else { a[k] = true }
}
return a
}""")
>>>>>>> REPLACE
Loading
Loading