code2logic 1.0.26__tar.gz → 1.0.28__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {code2logic-1.0.26 → code2logic-1.0.28}/PKG-INFO +1 -1
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/__init__.py +1 -1
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/analyzer.py +1 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/benchmarks/common.py +21 -11
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/benchmarks/runner.py +194 -38
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/logicml.py +10 -6
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/parsers.py +375 -11
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/universal.py +162 -1
- {code2logic-1.0.26 → code2logic-1.0.28}/pyproject.toml +2 -2
- {code2logic-1.0.26 → code2logic-1.0.28}/LICENSE +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/README.md +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/__main__.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/adaptive.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/base.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/benchmark.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/benchmarks/__init__.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/benchmarks/results.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/chunked_reproduction.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/cli.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/code_review.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/config.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/core/__init__.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/dependency.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/errors.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/file_formats.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/formats/__init__.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/function_logic.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/generators.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/gherkin.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/integrations/__init__.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/intent.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/llm/__init__.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/llm.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/llm_clients.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/llm_clients_new.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/llm_profiler.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/markdown_format.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/mcp_server.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/metrics.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/models.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/project_reproducer.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/prompts.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/py.typed +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/quality.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/refactor.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/reproducer.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/reproduction.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/schemas/__init__.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/schemas/json_schema.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/schemas/logicml_schema.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/schemas/markdown_schema.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/schemas/yaml_schema.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/shared_utils.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/similarity.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/terminal.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/tools/__init__.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/toon_format.py +0 -0
- {code2logic-1.0.26 → code2logic-1.0.28}/code2logic/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: code2logic
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.28
|
|
4
4
|
Summary: Convert source code to logical representation for LLM analysis
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Keywords: code-analysis,llm,ast,static-analysis,tree-sitter,code-understanding,documentation,dependency-graph,nlp
|
|
@@ -174,19 +174,16 @@ Name the test class Test<ClassName> or TestFunctions."""
|
|
|
174
174
|
return prompt
|
|
175
175
|
|
|
176
176
|
|
|
177
|
-
def get_token_reproduction_prompt(spec: str, fmt: str, file_name: str) -> str:
|
|
177
|
+
def get_token_reproduction_prompt(spec: str, fmt: str, file_name: str, language: str = "python") -> str:
|
|
178
178
|
format_hints = {
|
|
179
179
|
"json": "Parse the JSON structure and implement all classes and functions.",
|
|
180
180
|
"json_compact": "Parse the compact JSON and implement all elements.",
|
|
181
181
|
"yaml": "Parse the YAML structure and implement all classes and functions with exact signatures.",
|
|
182
|
-
"gherkin": "Implement scenarios as SIMPLE, MINIMAL
|
|
182
|
+
"gherkin": "Implement scenarios as SIMPLE, MINIMAL code. NO over-engineering. Keep code short and direct.",
|
|
183
183
|
"markdown": "Parse embedded Gherkin (behaviors) and YAML (structures).",
|
|
184
|
-
"logicml": """Parse LogicML and generate VALID
|
|
185
|
-
- 'sig:
|
|
186
|
-
- '
|
|
187
|
-
- 'sig: @property (self)' = @property decorator
|
|
188
|
-
- 'bases: [BaseModel]' = class X(BaseModel) with Field()
|
|
189
|
-
- 'type: re-export' = from .module import X
|
|
184
|
+
"logicml": """Parse LogicML and generate VALID code:
|
|
185
|
+
- 'sig:' lines describe function signatures (translate to the target language)
|
|
186
|
+
- 'type: re-export' means this module primarily re-exports symbols
|
|
190
187
|
CRITICAL: Ensure valid syntax - balanced brackets, proper indentation, no undefined variables.""",
|
|
191
188
|
"toon": """Parse TOON (Token-Oriented Object Notation) format carefully:
|
|
192
189
|
|
|
@@ -211,17 +208,30 @@ CRITICAL: Use imports[], function_docs, and exact signatures to reproduce code a
|
|
|
211
208
|
max_spec = 5000
|
|
212
209
|
spec_truncated = spec[:max_spec] if len(spec) > max_spec else spec
|
|
213
210
|
|
|
214
|
-
|
|
211
|
+
language_norm = (language or "python").strip().lower()
|
|
212
|
+
lang_label_map = {
|
|
213
|
+
"python": "Python",
|
|
214
|
+
"javascript": "JavaScript",
|
|
215
|
+
"typescript": "TypeScript",
|
|
216
|
+
"go": "Go",
|
|
217
|
+
"rust": "Rust",
|
|
218
|
+
"java": "Java",
|
|
219
|
+
"csharp": "C#",
|
|
220
|
+
"sql": "SQL",
|
|
221
|
+
}
|
|
222
|
+
lang_label = lang_label_map.get(language_norm, language_norm)
|
|
223
|
+
|
|
224
|
+
prompt = f"""Generate {lang_label} code from this {fmt.upper()} specification.
|
|
215
225
|
{format_hints.get(fmt, '')}
|
|
216
226
|
|
|
217
227
|
{spec_truncated}
|
|
218
228
|
|
|
219
229
|
Requirements:
|
|
220
|
-
- Complete, working
|
|
230
|
+
- Complete, working {lang_label} code for {file_name}
|
|
221
231
|
- Include imports and type hints
|
|
222
232
|
- Implement all functions with actual logic
|
|
223
233
|
|
|
224
|
-
```
|
|
234
|
+
```{language_norm}
|
|
225
235
|
"""
|
|
226
236
|
return prompt
|
|
227
237
|
|
|
@@ -17,6 +17,8 @@ Usage:
|
|
|
17
17
|
|
|
18
18
|
import sys
|
|
19
19
|
import time
|
|
20
|
+
import difflib
|
|
21
|
+
import re
|
|
20
22
|
from pathlib import Path
|
|
21
23
|
from typing import List, Optional
|
|
22
24
|
|
|
@@ -56,6 +58,98 @@ def _test_python_runs(code: str, timeout: int = 5) -> bool:
|
|
|
56
58
|
return True # Timeout might mean waiting for input
|
|
57
59
|
|
|
58
60
|
|
|
61
|
+
def _basic_syntax_ok(code: str, language: str) -> bool:
|
|
62
|
+
"""Heuristic syntax check for non-Python languages."""
|
|
63
|
+
s = (code or "").strip()
|
|
64
|
+
if not s:
|
|
65
|
+
return False
|
|
66
|
+
if language in ("javascript", "typescript"):
|
|
67
|
+
# Basic bracket/brace balance to catch the most common truncations
|
|
68
|
+
pairs = {')': '(', ']': '[', '}': '{'}
|
|
69
|
+
stack: List[str] = []
|
|
70
|
+
for ch in s:
|
|
71
|
+
if ch in "([{":
|
|
72
|
+
stack.append(ch)
|
|
73
|
+
elif ch in ")]}":
|
|
74
|
+
if not stack or stack[-1] != pairs.get(ch):
|
|
75
|
+
return False
|
|
76
|
+
stack.pop()
|
|
77
|
+
return not stack
|
|
78
|
+
if language == "go":
|
|
79
|
+
return "package" in s and "func" in s
|
|
80
|
+
if language == "rust":
|
|
81
|
+
return "fn" in s or "struct" in s or "enum" in s
|
|
82
|
+
if language == "java":
|
|
83
|
+
return "class" in s or "interface" in s
|
|
84
|
+
if language == "csharp":
|
|
85
|
+
return "class" in s or "interface" in s or "record" in s
|
|
86
|
+
if language == "sql":
|
|
87
|
+
upper = s.upper()
|
|
88
|
+
return "CREATE" in upper or "SELECT" in upper or "INSERT" in upper
|
|
89
|
+
return len(s) > 10
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _count_structural_elements(code: str, language: str) -> dict:
|
|
93
|
+
s = code or ""
|
|
94
|
+
if language == "python":
|
|
95
|
+
return {
|
|
96
|
+
'classes': len(re.findall(r'^class\s+\w+', s, re.MULTILINE)),
|
|
97
|
+
'functions': len(re.findall(r'^def\s+\w+', s, re.MULTILINE)),
|
|
98
|
+
'imports': len(re.findall(r'^(?:from|import)\s+', s, re.MULTILINE)),
|
|
99
|
+
}
|
|
100
|
+
if language in ("javascript", "typescript"):
|
|
101
|
+
return {
|
|
102
|
+
'classes': len(re.findall(r'\bclass\s+\w+', s)),
|
|
103
|
+
'functions': len(re.findall(r'\bfunction\s+\w+\s*\(', s)) + len(re.findall(r'\bconst\s+\w+\s*=\s*(?:async\s*)?\([^)]*\)\s*=>', s)),
|
|
104
|
+
'types': len(re.findall(r'\binterface\s+\w+', s)) + len(re.findall(r'\btype\s+\w+\s*=', s)) + len(re.findall(r'\benum\s+\w+', s)),
|
|
105
|
+
'imports': len(re.findall(r'^import\s+', s, re.MULTILINE)) + len(re.findall(r'\brequire\(', s)),
|
|
106
|
+
}
|
|
107
|
+
if language == "go":
|
|
108
|
+
return {
|
|
109
|
+
'types': len(re.findall(r'^type\s+\w+\s+(?:struct|interface)\b', s, re.MULTILINE)),
|
|
110
|
+
'functions': len(re.findall(r'^func\s+(?:\([^)]*\)\s*)?\w+\s*\(', s, re.MULTILINE)),
|
|
111
|
+
'imports': len(re.findall(r'^import\b', s, re.MULTILINE)),
|
|
112
|
+
}
|
|
113
|
+
if language == "rust":
|
|
114
|
+
return {
|
|
115
|
+
'types': len(re.findall(r'\bstruct\s+\w+', s)) + len(re.findall(r'\benum\s+\w+', s)) + len(re.findall(r'\btrait\s+\w+', s)),
|
|
116
|
+
'functions': len(re.findall(r'\bfn\s+\w+\s*\(', s)),
|
|
117
|
+
'imports': len(re.findall(r'^use\s+', s, re.MULTILINE)),
|
|
118
|
+
}
|
|
119
|
+
if language == "java":
|
|
120
|
+
return {
|
|
121
|
+
'types': len(re.findall(r'\bclass\s+\w+', s)) + len(re.findall(r'\binterface\s+\w+', s)) + len(re.findall(r'\benum\s+\w+', s)) + len(re.findall(r'\brecord\s+\w+', s)),
|
|
122
|
+
'functions': len(re.findall(r'\b\w+\s+\w+\s*\([^)]*\)\s*\{', s)),
|
|
123
|
+
'imports': len(re.findall(r'^import\s+', s, re.MULTILINE)),
|
|
124
|
+
}
|
|
125
|
+
if language == "csharp":
|
|
126
|
+
return {
|
|
127
|
+
'types': len(re.findall(r'\bclass\s+\w+', s)) + len(re.findall(r'\binterface\s+\w+', s)) + len(re.findall(r'\brecord\s+\w+', s)),
|
|
128
|
+
'functions': len(re.findall(r'\b\w+\s+\w+\s*\([^)]*\)\s*\{', s)),
|
|
129
|
+
'imports': len(re.findall(r'^using\s+', s, re.MULTILINE)),
|
|
130
|
+
}
|
|
131
|
+
if language == "sql":
|
|
132
|
+
upper = s.upper()
|
|
133
|
+
return {
|
|
134
|
+
'types': len(re.findall(r'\bCREATE\s+TABLE\s+\w+', upper)) + len(re.findall(r'\bCREATE\s+(?:OR\s+REPLACE\s+)?VIEW\s+\w+', upper)),
|
|
135
|
+
'functions': len(re.findall(r'\bCREATE\s+(?:OR\s+REPLACE\s+)?FUNCTION\s+\w+', upper)),
|
|
136
|
+
}
|
|
137
|
+
return {}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _structural_score(original: str, generated: str, language: str) -> float:
|
|
141
|
+
o = _count_structural_elements(original, language)
|
|
142
|
+
g = _count_structural_elements(generated, language)
|
|
143
|
+
if not o:
|
|
144
|
+
return 0.0
|
|
145
|
+
keys = list(o.keys())
|
|
146
|
+
matches = 0
|
|
147
|
+
for k in keys:
|
|
148
|
+
if o.get(k, 0) == g.get(k, 0):
|
|
149
|
+
matches += 1
|
|
150
|
+
return matches / max(len(keys), 1) * 100
|
|
151
|
+
|
|
152
|
+
|
|
59
153
|
def _extract_code(response: str) -> str:
|
|
60
154
|
"""Extract code from LLM response."""
|
|
61
155
|
if not response:
|
|
@@ -111,8 +205,8 @@ class BenchmarkRunner:
|
|
|
111
205
|
self.client = get_client()
|
|
112
206
|
return self.client
|
|
113
207
|
|
|
114
|
-
def _template_generate_code(self, spec: str, fmt: str, file_name: str) -> str:
|
|
115
|
-
"""Generate minimal
|
|
208
|
+
def _template_generate_code(self, spec: str, fmt: str, file_name: str, language: str = "python") -> str:
|
|
209
|
+
"""Generate minimal code without an LLM (fallback mode)."""
|
|
116
210
|
import re
|
|
117
211
|
|
|
118
212
|
# Try to infer class/function names from spec
|
|
@@ -139,11 +233,35 @@ class BenchmarkRunner:
|
|
|
139
233
|
classes = [c for c in uniq(classes) if c.isidentifier()][:5]
|
|
140
234
|
functions = [f for f in uniq(functions) if f.isidentifier() and f not in classes][:10]
|
|
141
235
|
|
|
142
|
-
|
|
236
|
+
language_norm = (language or "python").strip().lower()
|
|
237
|
+
if language_norm == "python":
|
|
238
|
+
code = """from __future__ import annotations
|
|
143
239
|
|
|
144
240
|
from dataclasses import dataclass
|
|
145
241
|
from typing import Any, Optional, List, Dict
|
|
146
242
|
|
|
243
|
+
"""
|
|
244
|
+
elif language_norm in ("javascript", "typescript"):
|
|
245
|
+
code = """// Auto-generated placeholder
|
|
246
|
+
"""
|
|
247
|
+
elif language_norm == "go":
|
|
248
|
+
code = """package main
|
|
249
|
+
|
|
250
|
+
"""
|
|
251
|
+
elif language_norm == "rust":
|
|
252
|
+
code = """// Auto-generated placeholder
|
|
253
|
+
"""
|
|
254
|
+
elif language_norm == "java":
|
|
255
|
+
code = """// Auto-generated placeholder
|
|
256
|
+
"""
|
|
257
|
+
elif language_norm == "csharp":
|
|
258
|
+
code = """// Auto-generated placeholder
|
|
259
|
+
"""
|
|
260
|
+
elif language_norm == "sql":
|
|
261
|
+
code = """-- Auto-generated placeholder
|
|
262
|
+
"""
|
|
263
|
+
else:
|
|
264
|
+
code = """// Auto-generated placeholder
|
|
147
265
|
"""
|
|
148
266
|
|
|
149
267
|
if not classes and not functions:
|
|
@@ -153,20 +271,56 @@ from typing import Any, Optional, List, Dict
|
|
|
153
271
|
classes = ["GeneratedClass"]
|
|
154
272
|
functions = ["generated_function"]
|
|
155
273
|
|
|
156
|
-
|
|
157
|
-
|
|
274
|
+
if language_norm == "python":
|
|
275
|
+
for cls in classes:
|
|
276
|
+
code += f"""@dataclass
|
|
158
277
|
class {cls}:
|
|
159
278
|
\"\"\"Generated placeholder for {file_name} ({fmt}).\"\"\"
|
|
160
279
|
value: Any = None
|
|
161
280
|
|
|
162
281
|
"""
|
|
163
282
|
|
|
164
|
-
|
|
165
|
-
|
|
283
|
+
for fn in functions:
|
|
284
|
+
code += f"""def {fn}(*args: Any, **kwargs: Any) -> Any:
|
|
166
285
|
\"\"\"Generated placeholder for {file_name} ({fmt}).\"\"\"
|
|
167
286
|
return None
|
|
168
287
|
|
|
169
288
|
"""
|
|
289
|
+
elif language_norm in ("javascript", "typescript"):
|
|
290
|
+
for fn in functions:
|
|
291
|
+
export_kw = "export " if language_norm == "typescript" else ""
|
|
292
|
+
code += f"{export_kw}function {fn}(...args) {{\n return null;\n}}\n\n"
|
|
293
|
+
for cls in classes:
|
|
294
|
+
export_kw = "export " if language_norm == "typescript" else ""
|
|
295
|
+
code += f"{export_kw}class {cls} {{\n constructor() {{}}\n}}\n\n"
|
|
296
|
+
elif language_norm == "go":
|
|
297
|
+
for fn in functions:
|
|
298
|
+
code += f"func {fn}() {{\n}}\n\n"
|
|
299
|
+
for cls in classes:
|
|
300
|
+
code += f"type {cls} struct {{\n}}\n\n"
|
|
301
|
+
elif language_norm == "rust":
|
|
302
|
+
for fn in functions:
|
|
303
|
+
code += f"pub fn {fn}() {{\n}}\n\n"
|
|
304
|
+
for cls in classes:
|
|
305
|
+
code += f"pub struct {cls} {{\n}}\n\n"
|
|
306
|
+
elif language_norm == "java":
|
|
307
|
+
safe_class = classes[0] if classes else "Generated"
|
|
308
|
+
code += f"public class {safe_class} {{\n"
|
|
309
|
+
for fn in functions:
|
|
310
|
+
code += f" public static void {fn}() {{ }}\n"
|
|
311
|
+
code += "}\n"
|
|
312
|
+
elif language_norm == "csharp":
|
|
313
|
+
safe_class = classes[0] if classes else "Generated"
|
|
314
|
+
code += f"public class {safe_class} {{\n"
|
|
315
|
+
for fn in functions:
|
|
316
|
+
code += f" public static void {fn}() {{ }}\n"
|
|
317
|
+
code += "}\n"
|
|
318
|
+
elif language_norm == "sql":
|
|
319
|
+
for cls in classes:
|
|
320
|
+
code += f"CREATE TABLE {cls} (id INT);\n"
|
|
321
|
+
else:
|
|
322
|
+
for fn in functions:
|
|
323
|
+
code += f"function {fn}() {{}}\n"
|
|
170
324
|
|
|
171
325
|
return code
|
|
172
326
|
|
|
@@ -213,45 +367,35 @@ class {cls}:
|
|
|
213
367
|
|
|
214
368
|
# Analyze project
|
|
215
369
|
path = Path(folder)
|
|
216
|
-
|
|
217
|
-
if limit
|
|
218
|
-
py_files = py_files[:limit]
|
|
370
|
+
project = analyze_project(str(path), use_treesitter=False)
|
|
371
|
+
modules = project.modules[:limit] if limit else project.modules
|
|
219
372
|
|
|
220
|
-
result.total_files = len(
|
|
373
|
+
result.total_files = len(modules)
|
|
221
374
|
|
|
222
375
|
if verbose:
|
|
223
376
|
render.heading(2, "Format Benchmark")
|
|
224
|
-
render.codeblock("yaml", f"folder: {folder}\nfiles: {len(
|
|
225
|
-
|
|
226
|
-
project = analyze_project(str(path), use_treesitter=False)
|
|
377
|
+
render.codeblock("yaml", f"folder: {folder}\nfiles: {len(modules)}\nformats: [{', '.join(formats)}]")
|
|
227
378
|
|
|
228
379
|
start_time = time.time()
|
|
229
380
|
|
|
230
381
|
# Process each file with each format
|
|
231
|
-
for
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
# Find module info
|
|
235
|
-
module_info = None
|
|
236
|
-
for m in project.modules:
|
|
237
|
-
if Path(m.path).name == py_file.name:
|
|
238
|
-
module_info = m
|
|
239
|
-
break
|
|
240
|
-
|
|
241
|
-
if not module_info:
|
|
382
|
+
for module_info in modules:
|
|
383
|
+
abs_file = path / module_info.path
|
|
384
|
+
if not abs_file.exists():
|
|
242
385
|
continue
|
|
386
|
+
original = abs_file.read_text(encoding='utf-8', errors='ignore')
|
|
243
387
|
|
|
244
|
-
single_project = create_single_project(module_info,
|
|
388
|
+
single_project = create_single_project(module_info, abs_file)
|
|
245
389
|
|
|
246
390
|
file_result = FileResult(
|
|
247
|
-
file_path=str(
|
|
248
|
-
language=
|
|
391
|
+
file_path=str(abs_file),
|
|
392
|
+
language=module_info.language,
|
|
249
393
|
original_size=len(original),
|
|
250
394
|
)
|
|
251
395
|
|
|
252
396
|
for fmt in formats:
|
|
253
397
|
fmt_result = self._test_format(
|
|
254
|
-
single_project, original, fmt,
|
|
398
|
+
single_project, original, fmt, abs_file.name, client, verbose, language=module_info.language
|
|
255
399
|
)
|
|
256
400
|
file_result.format_results[fmt] = fmt_result
|
|
257
401
|
|
|
@@ -288,6 +432,7 @@ class {cls}:
|
|
|
288
432
|
file_name: str,
|
|
289
433
|
client: Optional[BaseLLMClient],
|
|
290
434
|
verbose: bool = False,
|
|
435
|
+
language: str = "python",
|
|
291
436
|
) -> FormatResult:
|
|
292
437
|
"""Test a single format."""
|
|
293
438
|
result = FormatResult(format_name=fmt)
|
|
@@ -299,12 +444,12 @@ class {cls}:
|
|
|
299
444
|
result.spec_tokens = estimate_tokens(spec)
|
|
300
445
|
|
|
301
446
|
# Generate prompt
|
|
302
|
-
prompt = get_token_reproduction_prompt(spec, fmt, file_name)
|
|
447
|
+
prompt = get_token_reproduction_prompt(spec, fmt, file_name, language=language)
|
|
303
448
|
|
|
304
449
|
# Reproduce
|
|
305
450
|
start = time.time()
|
|
306
451
|
if client is None:
|
|
307
|
-
generated = self._template_generate_code(spec, fmt, file_name)
|
|
452
|
+
generated = self._template_generate_code(spec, fmt, file_name, language=language)
|
|
308
453
|
result.gen_time = 0.0
|
|
309
454
|
else:
|
|
310
455
|
response = client.generate(prompt, max_tokens=self.config.max_tokens)
|
|
@@ -313,15 +458,26 @@ class {cls}:
|
|
|
313
458
|
result.generated_size = len(generated)
|
|
314
459
|
|
|
315
460
|
# Test quality
|
|
316
|
-
|
|
317
|
-
if
|
|
318
|
-
result.
|
|
461
|
+
language_norm = (language or "python").strip().lower()
|
|
462
|
+
if language_norm == 'python':
|
|
463
|
+
result.syntax_ok = _test_python_syntax(generated)
|
|
464
|
+
if result.syntax_ok:
|
|
465
|
+
result.runs_ok = _test_python_runs(generated)
|
|
466
|
+
else:
|
|
467
|
+
result.syntax_ok = _basic_syntax_ok(generated, language_norm)
|
|
468
|
+
result.runs_ok = False
|
|
319
469
|
|
|
320
470
|
# Calculate metrics
|
|
321
471
|
if original and generated:
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
472
|
+
if language_norm == 'python':
|
|
473
|
+
analysis = self._metrics.analyze(original, generated, spec, format_name=fmt)
|
|
474
|
+
result.score = analysis.overall_score
|
|
475
|
+
result.similarity = analysis.text.char_similarity
|
|
476
|
+
else:
|
|
477
|
+
sim = difflib.SequenceMatcher(None, ' '.join(original.split()), ' '.join(generated.split())).ratio() * 100
|
|
478
|
+
struct = _structural_score(original, generated, language_norm)
|
|
479
|
+
result.similarity = sim
|
|
480
|
+
result.score = (sim * 0.7) + (struct * 0.3)
|
|
325
481
|
|
|
326
482
|
# Efficiency
|
|
327
483
|
if result.spec_size and len(original) > 0:
|
|
@@ -753,7 +909,7 @@ Requirements:
|
|
|
753
909
|
|
|
754
910
|
# Test format
|
|
755
911
|
fmt_result = self._test_format(
|
|
756
|
-
single_project, original, fmt, abs_path.name, client, verbose=False
|
|
912
|
+
single_project, original, fmt, abs_path.name, client, verbose=False, language=module_info.language
|
|
757
913
|
)
|
|
758
914
|
|
|
759
915
|
file_result.format_results[fmt] = fmt_result
|
|
@@ -129,12 +129,16 @@ class LogicMLGenerator:
|
|
|
129
129
|
lines.append("# Re-export module")
|
|
130
130
|
lines.append("type: re-export")
|
|
131
131
|
lines.append("exports:")
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
132
|
+
export_items: List[str] = []
|
|
133
|
+
if getattr(module, "exports", None):
|
|
134
|
+
export_items = [e for e in (module.exports or []) if e]
|
|
135
|
+
else:
|
|
136
|
+
export_items = [i for i in (module.imports or []) if i]
|
|
137
|
+
|
|
138
|
+
for item in export_items[:20]:
|
|
139
|
+
export_name = item.strip()
|
|
140
|
+
if export_name.endswith(".*"):
|
|
141
|
+
export_name = "*"
|
|
138
142
|
lines.append(f" - {export_name}")
|
|
139
143
|
return '\n'.join(lines)
|
|
140
144
|
|