From f203fbdce58f0eedcdfd9d4946c3105981a2f701 Mon Sep 17 00:00:00 2001 From: Puppuccino <97849040+CrazyDubya@users.noreply.github.com> Date: Thu, 12 Jun 2025 00:33:30 -0400 Subject: [PATCH 1/2] Add unordered_map headers --- src/analyzer/code_analyzer.py | 64 +++++++++++++++++++++++++++ src/analyzer/code_analyzer_fixed.py | 28 ++++++------ src/converter/code_generator_fixed.py | 40 +++++++++++++++++ tests/test_analyzer_fixed.py | 2 +- tests/test_code_analyzer_fixed.py | 2 +- tests/test_conversion.py | 4 +- 6 files changed, 122 insertions(+), 18 deletions(-) diff --git a/src/analyzer/code_analyzer.py b/src/analyzer/code_analyzer.py index 38d7b45..098d0b9 100644 --- a/src/analyzer/code_analyzer.py +++ b/src/analyzer/code_analyzer.py @@ -94,6 +94,9 @@ def _analyze_complexity(self, tree: ast.AST) -> None: def _infer_variable_type(self, node: ast.Assign) -> None: """Infer the type of a variable assignment.""" + if isinstance(node.targets[0], ast.Tuple): + self._handle_tuple_target_assignment(node) + return # Basic type inference implementation if isinstance(node.value, ast.Constant): if isinstance(node.value.value, (int, float)): @@ -210,6 +213,67 @@ def _infer_variable_type(self, node: ast.Assign) -> None: else: self.type_info[target.id] = 'int' + def _handle_tuple_target_assignment(self, node: ast.Assign) -> None: + """Handle tuple unpacking in assignments.""" + target_tuple = node.targets[0] + + if isinstance(node.value, ast.Call): + if isinstance(node.value.func, ast.Name): + func_name = node.value.func.id + if func_name in self.type_info: + return_type = self.type_info[func_name].get('return_type', None) + if return_type and isinstance(return_type, str) and return_type.startswith('std::tuple<'): + types = return_type[11:-1].split(', ') + for i, target in enumerate(target_tuple.elts): + if i < len(types): + if isinstance(target, ast.Tuple): + if types[i].startswith('std::tuple<'): + nested_types = types[i][11:-1].split(', ') + for j, nested_target in enumerate(target.elts): + if j < len(nested_types) and isinstance(nested_target, ast.Name): + self.type_info[nested_target.id] = nested_types[j] + elif isinstance(nested_target, ast.Name): + self.type_info[nested_target.id] = 'int' + else: + for nested_target in target.elts: + if isinstance(nested_target, ast.Name): + self.type_info[nested_target.id] = 'int' + elif isinstance(target, ast.Name): + self.type_info[target.id] = types[i] + elif isinstance(target, ast.Name): + self.type_info[target.id] = 'int' + else: + self._assign_default_types_to_tuple(target_tuple) + else: + self._assign_default_types_to_tuple(target_tuple) + else: + self._assign_default_types_to_tuple(target_tuple) + elif isinstance(node.value, ast.Tuple): + for target, value in zip(target_tuple.elts, node.value.elts): + if isinstance(target, ast.Tuple): + if isinstance(value, ast.Tuple): + for nested_target, nested_value in zip(target.elts, value.elts): + if isinstance(nested_target, ast.Name): + self.type_info[nested_target.id] = self._infer_expression_type(nested_value) + else: + for nested_target in target.elts: + if isinstance(nested_target, ast.Name): + self.type_info[nested_target.id] = 'int' + elif isinstance(target, ast.Name): + self.type_info[target.id] = self._infer_expression_type(value) + else: + self._assign_default_types_to_tuple(target_tuple) + + def _assign_default_types_to_tuple(self, target_tuple: ast.Tuple) -> None: + """Assign default types to all elements in a tuple unpacking.""" + for target in target_tuple.elts: + if isinstance(target, ast.Tuple): + for nested_target in target.elts: + if isinstance(nested_target, ast.Name): + self.type_info[nested_target.id] = 'int' + elif isinstance(target, ast.Name): + self.type_info[target.id] = 'int' + def _infer_expression_type(self, node: ast.AST) -> str: """Infer the type of an expression.""" print(f"Inferring expression type for: {type(node)}") diff --git a/src/analyzer/code_analyzer_fixed.py b/src/analyzer/code_analyzer_fixed.py index 1a49fdf..7ebe961 100644 --- a/src/analyzer/code_analyzer_fixed.py +++ b/src/analyzer/code_analyzer_fixed.py @@ -298,9 +298,9 @@ def _infer_variable_type(self, node: ast.Assign) -> None: if node.value.keys and node.value.values: key_type = self._infer_expression_type(node.value.keys[0]) value_type = self._infer_expression_type(node.value.values[0]) - self._store_type_for_target(node.targets[0], f'std::map<{key_type}, {value_type}>') + self._store_type_for_target(node.targets[0], f'std::unordered_map<{key_type}, {value_type}>') else: - self._store_type_for_target(node.targets[0], 'std::map') # Default + self._store_type_for_target(node.targets[0], 'std::unordered_map') # Default elif isinstance(node.value, ast.Set): # Try to infer set element type if node.value.elts: @@ -352,7 +352,7 @@ def _infer_variable_type(self, node: ast.Assign) -> None: elif func_name == 'list': self._store_type_for_target(node.targets[0], 'std::vector') elif func_name == 'dict': - self._store_type_for_target(node.targets[0], 'std::map') + self._store_type_for_target(node.targets[0], 'std::unordered_map') elif func_name == 'set': self._store_type_for_target(node.targets[0], 'std::set') else: @@ -478,8 +478,8 @@ def _infer_expression_type(self, node: ast.AST) -> str: if node.keys and node.values: key_type = self._infer_expression_type(node.keys[0]) value_type = self._infer_expression_type(node.values[0]) - return f'std::map<{key_type}, {value_type}>' - return 'std::map' + return f'std::unordered_map<{key_type}, {value_type}>' + return 'std::unordered_map' elif isinstance(node, ast.Set): if node.elts: elt_type = self._infer_expression_type(node.elts[0]) @@ -542,7 +542,7 @@ def _infer_expression_type(self, node: ast.AST) -> str: elif func_name == 'list': return 'std::vector' elif func_name == 'dict': - return 'std::map' + return 'std::unordered_map' elif func_name == 'set': return 'std::set' elif func_name == 'tuple': @@ -566,9 +566,9 @@ def _infer_expression_type(self, node: ast.AST) -> str: if isinstance(type_info, str): if type_info.startswith('std::vector<'): return type_info[12:-1] # Extract T from std::vector - elif type_info.startswith('std::map<'): - # Return value type from std::map - parts = type_info[9:-1].split(', ') + elif type_info.startswith('std::unordered_map<'): + # Return value type from std::unordered_map + parts = type_info[18:-1].split(', ') if len(parts) > 1: return parts[1] elif type_info.startswith('std::tuple<'): @@ -581,9 +581,9 @@ def _infer_expression_type(self, node: ast.AST) -> str: value_type = self._infer_expression_type(node.value) if value_type.startswith('std::vector<'): return value_type[12:-1] # Extract T from std::vector - elif value_type.startswith('std::map<'): - # Return value type from std::map - parts = value_type[9:-1].split(', ') + elif value_type.startswith('std::unordered_map<'): + # Return value type from std::unordered_map + parts = value_type[18:-1].split(', ') if len(parts) > 1: return parts[1] return 'int' # Default type @@ -693,10 +693,10 @@ def _get_type_name(self, node: ast.AST) -> str: if isinstance(elt, ast.Tuple) and len(elt.elts) >= 2: key_type = self._get_type_name(elt.elts[0]) value_type = self._get_type_name(elt.elts[1]) - return f'std::map<{key_type}, {value_type}>' + return f'std::unordered_map<{key_type}, {value_type}>' else: # Default if not a proper tuple - return 'std::map' + return 'std::unordered_map' elif base_type == 'set' or base_type == 'Set': inner_type = self._get_type_name(elt) return f'std::set<{inner_type}>' diff --git a/src/converter/code_generator_fixed.py b/src/converter/code_generator_fixed.py index a5de3be..adc7281 100644 --- a/src/converter/code_generator_fixed.py +++ b/src/converter/code_generator_fixed.py @@ -106,6 +106,9 @@ def _generate_header(self, analysis_result: AnalysisResult) -> str: #include #include #include +#include +#include +#include #include #include #include @@ -274,6 +277,7 @@ def _generate_implementation(self, analysis_result: AnalysisResult) -> str: impl = """#include "generated.hpp" #include #include +#include #include #include #include @@ -1104,6 +1108,42 @@ def _translate_expression(self, node: ast.AST, local_vars: Dict[str, str]) -> st value_type = self._infer_cpp_type(node.values[0], local_vars) return f"std::map<{key_type}, {value_type}>{{{', '.join(pairs)}}}" + elif isinstance(node, ast.ListComp): + gen = node.generators[0] + iterable = self._translate_expression(gen.iter, local_vars) + target = self._translate_expression(gen.target, local_vars) + element_type = self._infer_cpp_type(node.elt, local_vars) + elt_expr = self._translate_expression(node.elt, local_vars) + conditions = [self._translate_expression(if_cond, local_vars) for if_cond in gen.ifs] + cond_str = ' && '.join(conditions) if conditions else None + result_lines = ["([&]{", f" std::vector<{element_type}> result;", f" result.reserve({iterable}.size());", f" for (auto {target} : {iterable}) {{"] + if cond_str: + result_lines.append(f" if ({cond_str}) {{ result.push_back({elt_expr}); }}") + else: + result_lines.append(f" result.push_back({elt_expr});") + result_lines.append(" }") + result_lines.append(" return result;") + result_lines.append("}())") + return "\n".join(result_lines) + elif isinstance(node, ast.DictComp): + gen = node.generators[0] + iterable = self._translate_expression(gen.iter, local_vars) + target = self._translate_expression(gen.target, local_vars) + key_type = self._infer_cpp_type(node.key, local_vars) + value_type = self._infer_cpp_type(node.value, local_vars) + key_expr = self._translate_expression(node.key, local_vars) + value_expr = self._translate_expression(node.value, local_vars) + conditions = [self._translate_expression(if_cond, local_vars) for if_cond in gen.ifs] + cond_str = ' && '.join(conditions) if conditions else None + result_lines = ["([&]{", f" std::unordered_map<{key_type}, {value_type}> result;", f" result.reserve({iterable}.size());", f" for (auto {target} : {iterable}) {{"] + if cond_str: + result_lines.append(f" if ({cond_str}) {{ result[{key_expr}] = {value_expr}; }}") + else: + result_lines.append(f" result[{key_expr}] = {value_expr};") + result_lines.append(" }") + result_lines.append(" return result;") + result_lines.append("}())") + return "\n".join(result_lines) elif isinstance(node, ast.Tuple): # Handle tuple literals elements = [self._translate_expression(elt, local_vars) for elt in node.elts] diff --git a/tests/test_analyzer_fixed.py b/tests/test_analyzer_fixed.py index 69ae3e0..5af85da 100644 --- a/tests/test_analyzer_fixed.py +++ b/tests/test_analyzer_fixed.py @@ -166,7 +166,7 @@ def test_container_types(self): assert result.type_info['int_list'] == 'std::vector' assert result.type_info['str_list'] == 'std::vector' - assert result.type_info['simple_dict'] == 'std::map' + assert result.type_info['simple_dict'] == 'std::unordered_map' # complex_dict depends on implementation quality assert result.type_info['int_set'] == 'std::set' diff --git a/tests/test_code_analyzer_fixed.py b/tests/test_code_analyzer_fixed.py index 81a5a45..121c8c1 100644 --- a/tests/test_code_analyzer_fixed.py +++ b/tests/test_code_analyzer_fixed.py @@ -177,7 +177,7 @@ def test_container_types(self): assert result.type_info['int_list'] == 'std::vector' assert result.type_info['str_list'] == 'std::vector' - assert result.type_info['simple_dict'] == 'std::map' + assert result.type_info['simple_dict'] == 'std::unordered_map' # complex_dict mapping depends on implementation quality assert result.type_info['int_set'] == 'std::set' diff --git a/tests/test_conversion.py b/tests/test_conversion.py index e0a58a6..b4bc5a8 100644 --- a/tests/test_conversion.py +++ b/tests/test_conversion.py @@ -1,13 +1,13 @@ import pytest from pathlib import Path -from src.analyzer.code_analyzer import CodeAnalyzer +from src.analyzer.code_analyzer_fixed import CodeAnalyzer from src.rules.rule_manager import RuleManager from src.rules.basic_rules import ( VariableDeclarationRule, FunctionDefinitionRule, ClassDefinitionRule ) -from src.converter.code_generator import CodeGenerator +from src.converter.code_generator_fixed import CodeGenerator def test_fibonacci_conversion(tmp_path): # Setup From 7880c00a89fa97c6444c63d45ee1658b1fa7db77 Mon Sep 17 00:00:00 2001 From: Puppuccino <97849040+CrazyDubya@users.noreply.github.com> Date: Wed, 23 Jul 2025 11:34:24 -0400 Subject: [PATCH 2/2] Update src/converter/code_generator_fixed.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/converter/code_generator_fixed.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/converter/code_generator_fixed.py b/src/converter/code_generator_fixed.py index adc7281..6f453bc 100644 --- a/src/converter/code_generator_fixed.py +++ b/src/converter/code_generator_fixed.py @@ -107,8 +107,6 @@ def _generate_header(self, analysis_result: AnalysisResult) -> str: #include #include #include -#include -#include #include #include #include