re-do rust
This commit is contained in:
+69
-41
@@ -290,6 +290,12 @@ def apply_contextual_weights_to_embeddings(embeddings_list: List[List[float]],
|
|||||||
"""
|
"""
|
||||||
weighted_embeddings = []
|
weighted_embeddings = []
|
||||||
|
|
||||||
|
if len(embeddings_list) != len(metadata_list):
|
||||||
|
raise ValueError(
|
||||||
|
f"Embedding/metadata mismatch: {len(embeddings_list)} embeddings vs {len(metadata_list)} metadata. "
|
||||||
|
"This will break downstream systems (Chroma)."
|
||||||
|
)
|
||||||
|
|
||||||
for embedding, metadata in zip(embeddings_list, metadata_list):
|
for embedding, metadata in zip(embeddings_list, metadata_list):
|
||||||
weight = calculate_contextual_weight(metadata)
|
weight = calculate_contextual_weight(metadata)
|
||||||
|
|
||||||
@@ -1543,32 +1549,33 @@ def parse_rust_file(filepath: Path) -> List[Dict]:
|
|||||||
|
|
||||||
@lru_cache(maxsize=1000)
|
@lru_cache(maxsize=1000)
|
||||||
def parse_rust_file_cached(filepath_str: str, file_hash: str) -> tuple:
|
def parse_rust_file_cached(filepath_str: str, file_hash: str) -> tuple:
|
||||||
"""Cached Rust parsing with enhanced metadata for graph relationships."""
|
"""Cached Rust parsing with enhanced metadata for graph relationships.
|
||||||
|
ALWAYS returns a tuple of (text, metadata_tuple) entries. If the Rust helper
|
||||||
|
fails or produces no chunks, return a single fallback chunk containing the
|
||||||
|
whole file text and minimal metadata.
|
||||||
|
"""
|
||||||
filepath = Path(filepath_str)
|
filepath = Path(filepath_str)
|
||||||
chunks = []
|
chunks = []
|
||||||
|
|
||||||
logger.info(f"🔧 Parsing Rust file: {filepath}")
|
logger.info(f"🔧 Parsing Rust file: {filepath}")
|
||||||
|
|
||||||
# The binary built from `tools/src/main.rs` lives in
|
|
||||||
# `tools/src/target/release/rust_parser` – it is *always* shipped
|
|
||||||
# with the release.
|
|
||||||
rust_helper = Path("./tools/src/target/release/rust_parser")
|
rust_helper = Path("./tools/src/target/release/rust_parser")
|
||||||
if not rust_helper.is_file():
|
if not rust_helper.is_file():
|
||||||
logger.warning(f"Rust parser binary not found: {rust_helper}. Skipping Rust file {filepath}")
|
logger.warning(f"Rust parser binary not found: {rust_helper}. Using fallback whole-file chunk for {filepath}")
|
||||||
return tuple()
|
code = filepath.read_text(encoding="utf-8")
|
||||||
|
fallback_meta = {
|
||||||
# Always use the helper; if it is missing, the whole Rust parsing
|
"file": str(filepath),
|
||||||
# step will simply return an empty tuple, which is the safest
|
"name": filepath.name,
|
||||||
# fallback.
|
"type": "file",
|
||||||
logger.info(f"🔧 Using Rust parser binary: {rust_helper}")
|
"line": 1,
|
||||||
|
"language": "rust",
|
||||||
|
}
|
||||||
|
return ((code, tuple(fallback_meta.items())),)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
code = filepath.read_text(encoding="utf-8")
|
code = filepath.read_text(encoding="utf-8")
|
||||||
lines = code.splitlines(keepends=True)
|
lines = code.splitlines(keepends=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Run the Rust binary.
|
|
||||||
proc = subprocess.run(
|
proc = subprocess.run(
|
||||||
[str(rust_helper), str(filepath)],
|
[str(rust_helper), str(filepath)],
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
@@ -1582,18 +1589,22 @@ def parse_rust_file_cached(filepath_str: str, file_hash: str) -> tuple:
|
|||||||
for i, d in enumerate(decls):
|
for i, d in enumerate(decls):
|
||||||
start_line = max(0, d.get("start_line", 1) - 1)
|
start_line = max(0, d.get("start_line", 1) - 1)
|
||||||
end_line = d.get("end_line", start_line + 1)
|
end_line = d.get("end_line", start_line + 1)
|
||||||
|
# guard the end_line to be at least start_line+1
|
||||||
|
if end_line <= start_line:
|
||||||
|
end_line = start_line + 1
|
||||||
|
|
||||||
|
# Make slice safe even if end_line > len(lines)
|
||||||
chunk_code = "".join(lines[start_line:end_line])
|
chunk_code = "".join(lines[start_line:end_line])
|
||||||
|
|
||||||
# Build comprehensive metadata
|
|
||||||
metadata = {
|
metadata = {
|
||||||
"file": str(filepath),
|
"file": str(filepath),
|
||||||
"name": d.get("name", ""),
|
"name": d.get("name", "") or filepath.name,
|
||||||
"type": d.get("type_", ""),
|
"type": d.get("type_", "") or "unknown",
|
||||||
"line": start_line + 1,
|
"line": start_line + 1,
|
||||||
"language": "rust",
|
"language": "rust",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add Rust-specific metadata
|
# copy other fields defensively
|
||||||
if d.get("visibility"):
|
if d.get("visibility"):
|
||||||
metadata["visibility"] = d.get("visibility")
|
metadata["visibility"] = d.get("visibility")
|
||||||
if d.get("is_async"):
|
if d.get("is_async"):
|
||||||
@@ -1613,24 +1624,21 @@ def parse_rust_file_cached(filepath_str: str, file_hash: str) -> tuple:
|
|||||||
if d.get("parameters"):
|
if d.get("parameters"):
|
||||||
metadata["parameters"] = d.get("parameters")
|
metadata["parameters"] = d.get("parameters")
|
||||||
|
|
||||||
# Log what we found
|
|
||||||
logger.info(f" Declaration {i+1}: {metadata.get('type', 'unknown')} {metadata.get('name', 'unnamed')}")
|
logger.info(f" Declaration {i+1}: {metadata.get('type', 'unknown')} {metadata.get('name', 'unnamed')}")
|
||||||
|
|
||||||
chunk_text = f"File: {filepath}\nType: {d.get('type_')}\nName: {d.get('name')}\n"
|
chunk_text = f"File: {filepath}\nType: {metadata.get('type')}\nName: {metadata.get('name')}\n"
|
||||||
|
if metadata.get("visibility"):
|
||||||
# Add Rust-specific details to text
|
chunk_text += f"Visibility: {metadata.get('visibility')}\n"
|
||||||
if d.get("visibility"):
|
if metadata.get("is_async"):
|
||||||
chunk_text += f"Visibility: {d.get('visibility')}\n"
|
|
||||||
if d.get("is_async"):
|
|
||||||
chunk_text += "Async: yes\n"
|
chunk_text += "Async: yes\n"
|
||||||
if d.get("is_unsafe"):
|
if metadata.get("is_unsafe"):
|
||||||
chunk_text += "Unsafe: yes\n"
|
chunk_text += "Unsafe: yes\n"
|
||||||
if d.get("generics"):
|
if metadata.get("generics"):
|
||||||
chunk_text += f"Generics: {d.get('generics')}\n"
|
chunk_text += f"Generics: {', '.join(metadata.get('generics', []))}\n"
|
||||||
if d.get("traits"):
|
if metadata.get("implements_traits"):
|
||||||
chunk_text += f"Implements: {', '.join(d.get('traits', []))}\n"
|
chunk_text += f"Implements: {', '.join(metadata.get('implements_traits', []))}\n"
|
||||||
if d.get("fields"):
|
if metadata.get("fields"):
|
||||||
chunk_text += f"Fields: {', '.join(d.get('fields', []))}\n"
|
chunk_text += f"Fields: {', '.join(metadata.get('fields', []))}\n"
|
||||||
|
|
||||||
chunk_text += f"Code:\n{chunk_code}"
|
chunk_text += f"Code:\n{chunk_code}"
|
||||||
|
|
||||||
@@ -1639,18 +1647,29 @@ def parse_rust_file_cached(filepath_str: str, file_hash: str) -> tuple:
|
|||||||
"metadata": metadata
|
"metadata": metadata
|
||||||
})
|
})
|
||||||
|
|
||||||
if chunks:
|
|
||||||
logger.info(f"✅ Successfully parsed {len(chunks)} chunks from {filepath}")
|
|
||||||
return tuple((c["text"], tuple(c["metadata"].items())) for c in chunks)
|
|
||||||
else:
|
|
||||||
logger.warning(f"❌ AST helper returned declarations but no chunks were created")
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Rust AST helper failed for {filepath}: {e}")
|
logger.warning(f"Rust AST helper failed for {filepath}: {e}")
|
||||||
|
|
||||||
final_result = tuple((c["text"], tuple(c["metadata"].items())) for c in chunks)
|
# If parser produced chunks, return them in the (text, metadata_tuple) format expected by parse_rust_file()
|
||||||
logger.info(f"📦 Final result: {len(final_result)} chunks with metadata")
|
if chunks:
|
||||||
return final_result
|
logger.info(f"✅ Successfully parsed {len(chunks)} chunks from {filepath}")
|
||||||
|
return tuple((c["text"], tuple(c["metadata"].items())) for c in chunks)
|
||||||
|
|
||||||
|
# Fallback: emit a whole-file chunk to keep counts consistent
|
||||||
|
logger.warning(f"❌ No chunks created from Rust AST for {filepath}. Emitting fallback whole-file chunk.")
|
||||||
|
try:
|
||||||
|
full_code = filepath.read_text(encoding="utf-8")
|
||||||
|
except Exception:
|
||||||
|
full_code = ""
|
||||||
|
fallback_meta = {
|
||||||
|
"file": str(filepath),
|
||||||
|
"name": filepath.name,
|
||||||
|
"type": "file",
|
||||||
|
"line": 1,
|
||||||
|
"language": "rust",
|
||||||
|
}
|
||||||
|
return ((full_code, tuple(fallback_meta.items())),)
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=1000)
|
@lru_cache(maxsize=1000)
|
||||||
def parse_shell_file_cached(filepath_str: str) -> tuple:
|
def parse_shell_file_cached(filepath_str: str) -> tuple:
|
||||||
@@ -1862,6 +1881,15 @@ def build_indexes():
|
|||||||
# Step 1: Parse codebase and build enhanced graph
|
# Step 1: Parse codebase and build enhanced graph
|
||||||
# -------------------------------------------------
|
# -------------------------------------------------
|
||||||
texts, metadatas = index_codebase(CODEBASE_PATH)
|
texts, metadatas = index_codebase(CODEBASE_PATH)
|
||||||
|
if len(texts) != len(metadatas):
|
||||||
|
# Helpful debug output to find offending files quickly
|
||||||
|
logger.error(
|
||||||
|
"Indexing mismatch: %d texts vs %d metadata entries. Aborting index build.",
|
||||||
|
len(texts),
|
||||||
|
len(metadatas),
|
||||||
|
)
|
||||||
|
# raise so CI/dev runs fail fast and you can inspect logs
|
||||||
|
raise ValueError(f"Indexing produced {len(texts)} texts but {len(metadatas)} metadata entries")
|
||||||
|
|
||||||
logger.info("=== Sample metadata inspection ===")
|
logger.info("=== Sample metadata inspection ===")
|
||||||
for i, m in enumerate(metadatas[:5]): # Check first 5
|
for i, m in enumerate(metadatas[:5]): # Check first 5
|
||||||
|
|||||||
Reference in New Issue
Block a user