code2logic 1.0.39__tar.gz → 1.0.41__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.39 → code2logic-1.0.41}/PKG-INFO +4 -4
- {code2logic-1.0.39 → code2logic-1.0.41}/README.md +3 -3
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/__init__.py +1 -1
- code2logic-1.0.41/code2logic/base_generator.py +6 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/benchmarks/common.py +49 -6
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/benchmarks/runner.py +135 -39
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/function_logic.py +5 -6
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/parsers.py +12 -12
- {code2logic-1.0.39 → code2logic-1.0.41}/pyproject.toml +1 -1
- code2logic-1.0.39/code2logic/llm_clients_new.py +0 -44
- {code2logic-1.0.39 → code2logic-1.0.41}/LICENSE +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/__main__.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/adaptive.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/analyzer.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/base.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/benchmark.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/benchmarks/__init__.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/benchmarks/results.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/chunked_reproduction.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/cli.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/code_review.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/config.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/core/__init__.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/dependency.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/errors.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/file_formats.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/formats/__init__.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/generators.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/gherkin.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/integrations/__init__.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/intent.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/llm/__init__.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/llm.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/llm_clients.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/llm_profiler.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/logicml.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/markdown_format.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/mcp_server.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/metrics.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/models.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/project_comparison.md +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/project_reproducer.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/prompts.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/py.typed +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/quality.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/refactor.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/reproducer.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/reproduction.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/schemas/__init__.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/schemas/json_schema.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/schemas/logicml_schema.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/schemas/markdown_schema.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/schemas/yaml_schema.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/shared_utils.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/similarity.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/terminal.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/tools/__init__.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/toon_format.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/universal.py +0 -0
- {code2logic-1.0.39 → code2logic-1.0.41}/code2logic/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code2logic
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.41
|
|
4
4
|
Summary: Code2Logic - Source code to logical representation converter for LLM analysis, featuring Tree-sitter parsing, dependency graph analysis, and multi-language support.
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -95,9 +95,9 @@ pip install code2logic[nlp] # Enhanced intents
|
|
|
95
95
|
## 📖 Quick Start
|
|
96
96
|
```bash
|
|
97
97
|
code2logic ./ -f yaml --compact --function-logic --with-schema -o project.yaml
|
|
98
|
-
code2logic ./ -f toon --function-logic --with-schema --name project -o ./
|
|
99
|
-
# Optional: include function intent/purpose column in
|
|
100
|
-
code2logic ./ -f toon --function-logic --does --name project -o ./
|
|
98
|
+
code2logic ./ -f toon --function-logic function.toon --with-schema --name project -o ./
|
|
99
|
+
# Optional: include function intent/purpose column in function.toon
|
|
100
|
+
code2logic ./ -f toon --function-logic function.toon --does --name project -o ./
|
|
101
101
|
```
|
|
102
102
|
|
|
103
103
|
### Command Line
|
|
@@ -49,9 +49,9 @@ pip install code2logic[nlp] # Enhanced intents
|
|
|
49
49
|
## 📖 Quick Start
|
|
50
50
|
```bash
|
|
51
51
|
code2logic ./ -f yaml --compact --function-logic --with-schema -o project.yaml
|
|
52
|
-
code2logic ./ -f toon --function-logic --with-schema --name project -o ./
|
|
53
|
-
# Optional: include function intent/purpose column in
|
|
54
|
-
code2logic ./ -f toon --function-logic --does --name project -o ./
|
|
52
|
+
code2logic ./ -f toon --function-logic function.toon --with-schema --name project -o ./
|
|
53
|
+
# Optional: include function intent/purpose column in function.toon
|
|
54
|
+
code2logic ./ -f toon --function-logic function.toon --does --name project -o ./
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
### Command Line
|
|
@@ -5,6 +5,7 @@ from datetime import datetime
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
7
|
from ..generators import CSVGenerator, JSONGenerator, YAMLGenerator
|
|
8
|
+
from ..function_logic import FunctionLogicGenerator
|
|
8
9
|
from ..gherkin import GherkinGenerator
|
|
9
10
|
from ..logicml import LogicMLGenerator
|
|
10
11
|
from ..markdown_format import MarkdownHybridGenerator
|
|
@@ -32,6 +33,15 @@ def generate_spec(project: ProjectInfo, fmt: str) -> str:
|
|
|
32
33
|
if fmt == "gherkin":
|
|
33
34
|
gen = GherkinGenerator()
|
|
34
35
|
return gen.generate(project)
|
|
36
|
+
if fmt == "function.toon":
|
|
37
|
+
gen = FunctionLogicGenerator()
|
|
38
|
+
return gen.generate_toon(
|
|
39
|
+
project,
|
|
40
|
+
detail="full",
|
|
41
|
+
no_repeat_name=True,
|
|
42
|
+
no_repeat_details=True,
|
|
43
|
+
include_does=True,
|
|
44
|
+
)
|
|
35
45
|
if fmt == "csv":
|
|
36
46
|
gen = CSVGenerator()
|
|
37
47
|
return gen.generate(project, detail="full")
|
|
@@ -179,14 +189,21 @@ Name the test class Test<ClassName> or TestFunctions."""
|
|
|
179
189
|
|
|
180
190
|
def get_token_reproduction_prompt(spec: str, fmt: str, file_name: str, language: str = "python") -> str:
|
|
181
191
|
format_hints = {
|
|
182
|
-
"json": "Parse the JSON structure and implement all classes and functions.",
|
|
183
|
-
"json_compact": "Parse the compact JSON and implement all elements.",
|
|
192
|
+
"json": "Parse the JSON structure and implement all classes and functions with exact signatures.",
|
|
193
|
+
"json_compact": "Parse the compact JSON and implement all elements with exact signatures.",
|
|
184
194
|
"yaml": "Parse the YAML structure and implement all classes and functions with exact signatures.",
|
|
185
|
-
"gherkin": "
|
|
186
|
-
|
|
195
|
+
"gherkin": """Parse Gherkin/BDD scenarios and implement them as working code:
|
|
196
|
+
- Each Feature maps to a class or module
|
|
197
|
+
- Each Scenario maps to a function
|
|
198
|
+
- Given/When/Then steps describe the logic flow
|
|
199
|
+
- Implement actual logic, not just stubs
|
|
200
|
+
Focus on the described behavior and implement it directly.""",
|
|
201
|
+
"markdown": "Parse embedded Gherkin (behaviors) and YAML (structures). Implement all described classes and functions.",
|
|
187
202
|
"logicml": """Parse LogicML and generate VALID code:
|
|
188
203
|
- 'sig:' lines describe function signatures (translate to the target language)
|
|
189
204
|
- 'type: re-export' means this module primarily re-exports symbols
|
|
205
|
+
- 'attrs:' = instance attributes to set in constructor
|
|
206
|
+
- 'bases:' = parent classes to inherit from
|
|
190
207
|
CRITICAL: Ensure valid syntax - balanced brackets, proper indentation, no undefined variables.""",
|
|
191
208
|
"toon": """Parse TOON (Token-Oriented Object Notation) format carefully:
|
|
192
209
|
|
|
@@ -206,9 +223,32 @@ DECORATORS:
|
|
|
206
223
|
- 'decorators: @staticmethod|@cache' = multiple decorators
|
|
207
224
|
|
|
208
225
|
CRITICAL: Use imports[], function_docs, and exact signatures to reproduce code accurately.""",
|
|
226
|
+
"csv": """Parse the CSV table where each row describes a code element:
|
|
227
|
+
- Columns: path, type (class/method/function), name, signature, language, intent, category, domain, imports
|
|
228
|
+
- 'method' rows belong to the class in the preceding 'class' row
|
|
229
|
+
- Implement all elements with the exact signatures shown
|
|
230
|
+
Generate complete code with all classes, methods, and functions.""",
|
|
231
|
+
"function.toon": """Parse the function-logic TOON format:
|
|
232
|
+
- 'modules[N]{path,lang,items}:' lists files
|
|
233
|
+
- 'function_details:' contains per-module function listings
|
|
234
|
+
- Each function has: line number, name, signature, description
|
|
235
|
+
- 'ClassName.method_name' = method of that class
|
|
236
|
+
- 'cc:N' after name = cyclomatic complexity
|
|
237
|
+
Implement all listed functions with matching signatures and described behavior.""",
|
|
209
238
|
}
|
|
210
239
|
|
|
211
|
-
|
|
240
|
+
# Language-specific guidance appended to prompt
|
|
241
|
+
lang_hints = {
|
|
242
|
+
"javascript": "Use ES6+ syntax (const/let, arrow functions, classes). Use module.exports or export.",
|
|
243
|
+
"typescript": "Use TypeScript syntax with interfaces, type annotations, and export statements.",
|
|
244
|
+
"go": "Use proper Go syntax: package declaration, func receivers for methods, error returns.",
|
|
245
|
+
"rust": "Use proper Rust syntax: impl blocks for methods, pub fn, Result/Option types, ownership.",
|
|
246
|
+
"java": "Use proper Java syntax: public class, access modifiers, typed parameters, semicolons.",
|
|
247
|
+
"csharp": "Use proper C# syntax: namespaces, access modifiers, typed parameters, semicolons.",
|
|
248
|
+
"sql": "Use standard SQL: CREATE TABLE/VIEW/FUNCTION, proper column types, constraints.",
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
max_spec = 8000
|
|
212
252
|
spec_truncated = spec[:max_spec] if len(spec) > max_spec else spec
|
|
213
253
|
|
|
214
254
|
language_norm = (language or "python").strip().lower()
|
|
@@ -224,8 +264,11 @@ CRITICAL: Use imports[], function_docs, and exact signatures to reproduce code a
|
|
|
224
264
|
}
|
|
225
265
|
lang_label = lang_label_map.get(language_norm, language_norm)
|
|
226
266
|
|
|
267
|
+
lang_hint = lang_hints.get(language_norm, '')
|
|
268
|
+
lang_hint_line = f"\n{lang_hint}" if lang_hint else ''
|
|
269
|
+
|
|
227
270
|
prompt = f"""Generate {lang_label} code from this {fmt.upper()} specification.
|
|
228
|
-
{format_hints.get(fmt, '')}
|
|
271
|
+
{format_hints.get(fmt, '')}{lang_hint_line}
|
|
229
272
|
|
|
230
273
|
{spec_truncated}
|
|
231
274
|
|
|
@@ -15,12 +15,14 @@ Usage:
|
|
|
15
15
|
result.save('output/benchmark.json')
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
import sys
|
|
19
|
-
import time
|
|
20
18
|
import difflib
|
|
21
19
|
import re
|
|
20
|
+
import sys
|
|
21
|
+
import time
|
|
22
22
|
from pathlib import Path
|
|
23
|
-
from typing import List, Optional
|
|
23
|
+
from typing import Any, Dict, List, Optional
|
|
24
|
+
|
|
25
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
24
26
|
|
|
25
27
|
from ..analyzer import analyze_project
|
|
26
28
|
from ..llm_clients import BaseLLMClient, get_client
|
|
@@ -193,7 +195,7 @@ class BenchmarkRunner:
|
|
|
193
195
|
"""
|
|
194
196
|
self.client = client
|
|
195
197
|
self.config = config or BenchmarkConfig()
|
|
196
|
-
|
|
198
|
+
# Note: avoid sharing ReproductionMetrics instance across threads.
|
|
197
199
|
|
|
198
200
|
def _should_use_llm(self) -> bool:
|
|
199
201
|
"""Return whether this runner should call an LLM."""
|
|
@@ -215,12 +217,37 @@ class BenchmarkRunner:
|
|
|
215
217
|
classes: List[str] = []
|
|
216
218
|
functions: List[str] = []
|
|
217
219
|
|
|
218
|
-
# Common patterns
|
|
220
|
+
# Common patterns across formats
|
|
219
221
|
classes.extend(re.findall(r"\bclass\s+([A-Za-z_][A-Za-z0-9_]*)", spec))
|
|
220
|
-
classes.extend(re.findall(r"
|
|
222
|
+
classes.extend(re.findall(r'"name":\s*"([A-Z][A-Za-z0-9_]*)"', spec))
|
|
221
223
|
functions.extend(re.findall(r"\bdef\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(", spec))
|
|
222
224
|
functions.extend(re.findall(r"\bFunction:\s*([A-Za-z_][A-Za-z0-9_]*)", spec))
|
|
223
225
|
functions.extend(re.findall(r"\bScenario:\s*([A-Za-z_][A-Za-z0-9_]*)", spec))
|
|
226
|
+
# TOON format: function lines like " 42,func_name,(params)"
|
|
227
|
+
functions.extend(re.findall(r'^\s+\d+,([A-Za-z_][A-Za-z0-9_]*),', spec, re.MULTILINE))
|
|
228
|
+
# TOON class.method: " 42,ClassName.method_name,"
|
|
229
|
+
for cm in re.findall(r'^\s+\d+,([A-Z][A-Za-z0-9_]*)\.([a-z_][A-Za-z0-9_]*),', spec, re.MULTILINE):
|
|
230
|
+
classes.append(cm[0])
|
|
231
|
+
functions.append(cm[1])
|
|
232
|
+
# YAML/JSON: "n: ClassName" or name patterns
|
|
233
|
+
classes.extend(re.findall(r'(?:^|\s)n:\s*([A-Z][A-Za-z0-9_]*)', spec, re.MULTILINE))
|
|
234
|
+
# CSV format: path,type,name columns
|
|
235
|
+
for row_m in re.findall(r',class,([A-Z][A-Za-z0-9_]*),', spec):
|
|
236
|
+
classes.append(row_m)
|
|
237
|
+
for row_m in re.findall(r',(?:function|method),([a-z_][A-Za-z0-9_]*),', spec):
|
|
238
|
+
functions.append(row_m)
|
|
239
|
+
# Gherkin: Feature/Scenario names
|
|
240
|
+
functions.extend(re.findall(r'Scenario(?:\s+Outline)?:\s*(?:Test\s+)?([A-Za-z_][A-Za-z0-9_]*)', spec))
|
|
241
|
+
# Non-Python: func/fn/function declarations
|
|
242
|
+
functions.extend(re.findall(r"\bfunc\s+([A-Za-z_][A-Za-z0-9_]*)", spec))
|
|
243
|
+
functions.extend(re.findall(r"\bfn\s+([A-Za-z_][A-Za-z0-9_]*)", spec))
|
|
244
|
+
functions.extend(re.findall(r"\bfunction\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(", spec))
|
|
245
|
+
# Java/C# style: "public static Type methodName("
|
|
246
|
+
functions.extend(re.findall(r"(?:public|private)\s+(?:static\s+)?\w+\s+([a-z][A-Za-z0-9_]*)\s*\(", spec))
|
|
247
|
+
# Interfaces/structs/enums
|
|
248
|
+
classes.extend(re.findall(r"\binterface\s+([A-Za-z_][A-Za-z0-9_]*)", spec))
|
|
249
|
+
classes.extend(re.findall(r"\bstruct\s+([A-Za-z_][A-Za-z0-9_]*)", spec))
|
|
250
|
+
classes.extend(re.findall(r"\benum\s+([A-Za-z_][A-Za-z0-9_]*)", spec))
|
|
224
251
|
|
|
225
252
|
# Deduplicate while preserving order
|
|
226
253
|
def uniq(items: List[str]) -> List[str]:
|
|
@@ -395,11 +422,41 @@ class {cls}:
|
|
|
395
422
|
original_size=len(original),
|
|
396
423
|
)
|
|
397
424
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
425
|
+
max_workers = int(getattr(self.config, "workers", 1) or 1)
|
|
426
|
+
if max_workers < 1:
|
|
427
|
+
max_workers = 1
|
|
428
|
+
|
|
429
|
+
# Parallelize per-format reproduction (LLM calls) for the same file.
|
|
430
|
+
if len(formats) > 1 and max_workers > 1:
|
|
431
|
+
with ThreadPoolExecutor(max_workers=max_workers) as ex:
|
|
432
|
+
futs = {
|
|
433
|
+
ex.submit(
|
|
434
|
+
self._test_format,
|
|
435
|
+
single_project,
|
|
436
|
+
original,
|
|
437
|
+
fmt,
|
|
438
|
+
abs_file.name,
|
|
439
|
+
client,
|
|
440
|
+
verbose,
|
|
441
|
+
module_info.language,
|
|
442
|
+
): fmt
|
|
443
|
+
for fmt in formats
|
|
444
|
+
}
|
|
445
|
+
for fut in as_completed(futs):
|
|
446
|
+
fmt = futs[fut]
|
|
447
|
+
file_result.format_results[fmt] = fut.result()
|
|
448
|
+
else:
|
|
449
|
+
for fmt in formats:
|
|
450
|
+
fmt_result = self._test_format(
|
|
451
|
+
single_project,
|
|
452
|
+
original,
|
|
453
|
+
fmt,
|
|
454
|
+
abs_file.name,
|
|
455
|
+
client,
|
|
456
|
+
verbose,
|
|
457
|
+
language=module_info.language,
|
|
458
|
+
)
|
|
459
|
+
file_result.format_results[fmt] = fmt_result
|
|
403
460
|
|
|
404
461
|
# Set best result as file score
|
|
405
462
|
if file_result.format_results:
|
|
@@ -472,7 +529,8 @@ class {cls}:
|
|
|
472
529
|
# Calculate metrics
|
|
473
530
|
if original and generated:
|
|
474
531
|
if language_norm == 'python':
|
|
475
|
-
|
|
532
|
+
metrics = ReproductionMetrics()
|
|
533
|
+
analysis = metrics.analyze(original, generated, spec, format_name=fmt)
|
|
476
534
|
result.score = analysis.overall_score
|
|
477
535
|
result.similarity = analysis.text.char_similarity
|
|
478
536
|
else:
|
|
@@ -816,33 +874,71 @@ Requirements:
|
|
|
816
874
|
if verbose:
|
|
817
875
|
print(f"\n--- Format: {fmt.upper()} ---")
|
|
818
876
|
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
877
|
+
max_workers = int(getattr(self.config, "workers", 1) or 1)
|
|
878
|
+
if max_workers < 1:
|
|
879
|
+
max_workers = 1
|
|
880
|
+
|
|
881
|
+
# Parallelize per-module reproduction for a given format.
|
|
882
|
+
if len(modules) > 1 and max_workers > 1:
|
|
883
|
+
with ThreadPoolExecutor(max_workers=max_workers) as ex:
|
|
884
|
+
futs = {
|
|
885
|
+
ex.submit(self._reproduce_module, module, fmt, project_path, client, verbose): (i, module)
|
|
886
|
+
for i, module in enumerate(modules)
|
|
887
|
+
}
|
|
888
|
+
for fut in as_completed(futs):
|
|
889
|
+
i, _module = futs[fut]
|
|
890
|
+
file_result = fut.result()
|
|
891
|
+
|
|
892
|
+
# Add format to result
|
|
893
|
+
if file_result.format_results:
|
|
894
|
+
fmt_result = list(file_result.format_results.values())[0]
|
|
895
|
+
else:
|
|
896
|
+
fmt_result = FormatResult(format_name=fmt, score=file_result.score)
|
|
897
|
+
file_result.format_results[fmt] = fmt_result
|
|
898
|
+
|
|
899
|
+
# Find existing file result or create new
|
|
900
|
+
existing = None
|
|
901
|
+
for fr in result.file_results:
|
|
902
|
+
if fr.file_path == file_result.file_path:
|
|
903
|
+
existing = fr
|
|
904
|
+
break
|
|
905
|
+
|
|
906
|
+
if existing:
|
|
907
|
+
existing.format_results[fmt] = fmt_result
|
|
908
|
+
else:
|
|
909
|
+
result.file_results.append(file_result)
|
|
910
|
+
|
|
911
|
+
if verbose:
|
|
912
|
+
status = "✓" if file_result.score > 50 else "○"
|
|
913
|
+
print(f" [{i+1}/{len(modules)}] {Path(file_result.file_path).name}: {file_result.score:.1f}% {status}")
|
|
914
|
+
else:
|
|
915
|
+
for i, module in enumerate(modules):
|
|
916
|
+
file_result = self._reproduce_module(
|
|
917
|
+
module, fmt, project_path, client, verbose
|
|
918
|
+
)
|
|
919
|
+
|
|
920
|
+
# Add format to result
|
|
921
|
+
if file_result.format_results:
|
|
922
|
+
fmt_result = list(file_result.format_results.values())[0]
|
|
923
|
+
else:
|
|
924
|
+
fmt_result = FormatResult(format_name=fmt, score=file_result.score)
|
|
925
|
+
file_result.format_results[fmt] = fmt_result
|
|
926
|
+
|
|
927
|
+
# Find existing file result or create new
|
|
928
|
+
existing = None
|
|
929
|
+
for fr in result.file_results:
|
|
930
|
+
if fr.file_path == file_result.file_path:
|
|
931
|
+
existing = fr
|
|
932
|
+
break
|
|
933
|
+
|
|
934
|
+
if existing:
|
|
935
|
+
existing.format_results[fmt] = fmt_result
|
|
936
|
+
else:
|
|
937
|
+
result.file_results.append(file_result)
|
|
938
|
+
|
|
939
|
+
if verbose:
|
|
940
|
+
status = "✓" if file_result.score > 50 else "○"
|
|
941
|
+
print(f" [{i+1}/{len(modules)}] {Path(file_result.file_path).name}: {file_result.score:.1f}% {status}")
|
|
846
942
|
|
|
847
943
|
result.total_time = time.time() - start_time
|
|
848
944
|
|
|
@@ -157,14 +157,13 @@ class FunctionLogicGenerator:
|
|
|
157
157
|
import json
|
|
158
158
|
|
|
159
159
|
schema = {
|
|
160
|
-
"$schema": "
|
|
161
|
-
"title": "
|
|
160
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
161
|
+
"title": "Function Logic TOON",
|
|
162
|
+
"type": "object",
|
|
162
163
|
"description": (
|
|
163
|
-
"Schema for function-logic TOON output (e.g.
|
|
164
|
-
"
|
|
165
|
-
"~prefix = async, 'cc:N' suffix = cyclomatic complexity (only when >1)."
|
|
164
|
+
"Schema for function-logic TOON output (e.g. function.toon) — compact function/method index. "
|
|
165
|
+
"Generated by code2logic with --function-logic and TOON format."
|
|
166
166
|
),
|
|
167
|
-
"type": "object",
|
|
168
167
|
"properties": {
|
|
169
168
|
"project": {"type": "string", "description": "Project name"},
|
|
170
169
|
"generated": {"type": "string", "description": "ISO timestamp"},
|
|
@@ -2212,30 +2212,30 @@ class UniversalParser:
|
|
|
2212
2212
|
for m in re.finditer(r'^import\s+([^;]+);', content, re.MULTILINE):
|
|
2213
2213
|
imports.append(m.group(1).strip())
|
|
2214
2214
|
|
|
2215
|
-
for m in re.finditer(r'
|
|
2215
|
+
for m in re.finditer(r'^\s*(?:public\s+)?(?:abstract\s+)?class\s+(\w+)', content, re.MULTILINE):
|
|
2216
2216
|
name = m.group(1)
|
|
2217
2217
|
classes.append(ClassInfo(name=name, is_abstract='abstract' in m.group(0)))
|
|
2218
2218
|
exports.append(name)
|
|
2219
2219
|
|
|
2220
|
-
for m in re.finditer(r'
|
|
2220
|
+
for m in re.finditer(r'^\s*(?:public\s+)?interface\s+(\w+)', content, re.MULTILINE):
|
|
2221
2221
|
name = m.group(1)
|
|
2222
2222
|
classes.append(ClassInfo(name=name, is_interface=True))
|
|
2223
2223
|
exports.append(name)
|
|
2224
2224
|
types.append(TypeInfo(name=name, kind='interface', definition=''))
|
|
2225
2225
|
|
|
2226
|
-
for m in re.finditer(r'
|
|
2226
|
+
for m in re.finditer(r'^\s*(?:public\s+)?enum\s+(\w+)', content, re.MULTILINE):
|
|
2227
2227
|
name = m.group(1)
|
|
2228
2228
|
types.append(TypeInfo(name=name, kind='enum', definition=''))
|
|
2229
2229
|
exports.append(name)
|
|
2230
2230
|
|
|
2231
|
-
for m in re.finditer(r'
|
|
2231
|
+
for m in re.finditer(r'^\s*(?:public\s+)?record\s+(\w+)\s*\(', content, re.MULTILINE):
|
|
2232
2232
|
name = m.group(1)
|
|
2233
2233
|
classes.append(ClassInfo(name=name))
|
|
2234
2234
|
types.append(TypeInfo(name=name, kind='record', definition=''))
|
|
2235
2235
|
exports.append(name)
|
|
2236
2236
|
|
|
2237
|
-
#
|
|
2238
|
-
for m in re.finditer(r'
|
|
2237
|
+
# Method detection – allow indented declarations inside classes
|
|
2238
|
+
for m in re.finditer(r'^\s*(?:@\w+\s+)*(?:public|protected|private)\s+(?:static\s+)?(?:final\s+)?(?:synchronized\s+)?([\w<>\[\],\s]+?)\s+(\w+)\s*\(([^)]*)\)\s*(?:throws\s+[\w,\s]+)?\s*\{', content, re.MULTILINE):
|
|
2239
2239
|
ret_type = m.group(1)
|
|
2240
2240
|
name = m.group(2)
|
|
2241
2241
|
params = [p.strip() for p in (m.group(3) or '').split(',') if p.strip()][:8]
|
|
@@ -2260,7 +2260,7 @@ class UniversalParser:
|
|
|
2260
2260
|
is_private=False,
|
|
2261
2261
|
))
|
|
2262
2262
|
|
|
2263
|
-
for m in re.finditer(r'
|
|
2263
|
+
for m in re.finditer(r'^\s*(?:public\s+)?static\s+final\s+[\w<>\[\]]+\s+([A-Z][A-Z0-9_]*)\b', content, re.MULTILINE):
|
|
2264
2264
|
constants.append(m.group(1))
|
|
2265
2265
|
|
|
2266
2266
|
lines = content.split('\n')
|
|
@@ -2290,24 +2290,24 @@ class UniversalParser:
|
|
|
2290
2290
|
for m in re.finditer(r'^using\s+([^;]+);', content, re.MULTILINE):
|
|
2291
2291
|
imports.append(m.group(1).strip())
|
|
2292
2292
|
|
|
2293
|
-
for m in re.finditer(r'
|
|
2293
|
+
for m in re.finditer(r'^\s*(?:public\s+)?interface\s+(I\w+)', content, re.MULTILINE):
|
|
2294
2294
|
name = m.group(1)
|
|
2295
2295
|
classes.append(ClassInfo(name=name, is_interface=True))
|
|
2296
2296
|
exports.append(name)
|
|
2297
2297
|
types.append(TypeInfo(name=name, kind='interface', definition=''))
|
|
2298
2298
|
|
|
2299
|
-
for m in re.finditer(r'
|
|
2299
|
+
for m in re.finditer(r'^\s*(?:public\s+)?(?:abstract\s+)?class\s+(\w+)', content, re.MULTILINE):
|
|
2300
2300
|
name = m.group(1)
|
|
2301
2301
|
classes.append(ClassInfo(name=name, is_abstract='abstract' in m.group(0)))
|
|
2302
2302
|
exports.append(name)
|
|
2303
2303
|
|
|
2304
|
-
for m in re.finditer(r'
|
|
2304
|
+
for m in re.finditer(r'^\s*(?:public\s+)?record\s+(\w+)', content, re.MULTILINE):
|
|
2305
2305
|
name = m.group(1)
|
|
2306
2306
|
classes.append(ClassInfo(name=name))
|
|
2307
2307
|
exports.append(name)
|
|
2308
2308
|
types.append(TypeInfo(name=name, kind='record', definition=''))
|
|
2309
2309
|
|
|
2310
|
-
for m in re.finditer(r'
|
|
2310
|
+
for m in re.finditer(r'^\s*(?:public|private|protected|internal)\s+(?:static\s+)?(?:async\s+)?(?:override\s+)?(?:virtual\s+)?([\w<>\[\]?]+)\s+(\w+)\s*\(([^)]*)\)\s*\{', content, re.MULTILINE):
|
|
2311
2311
|
ret_type = m.group(1)
|
|
2312
2312
|
name = m.group(2)
|
|
2313
2313
|
params = [p.strip() for p in (m.group(3) or '').split(',') if p.strip()][:8]
|
|
@@ -2332,7 +2332,7 @@ class UniversalParser:
|
|
|
2332
2332
|
is_private=False,
|
|
2333
2333
|
))
|
|
2334
2334
|
|
|
2335
|
-
for m in re.finditer(r'
|
|
2335
|
+
for m in re.finditer(r'^\s*(?:public\s+)?const\s+[\w<>\[\]]+\s+([A-Z][A-Z0-9_]*)\b', content, re.MULTILINE):
|
|
2336
2336
|
constants.append(m.group(1))
|
|
2337
2337
|
|
|
2338
2338
|
lines = content.split('\n')
|
|
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
4
4
|
|
|
5
5
|
[tool.poetry]
|
|
6
6
|
name = "code2logic"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.41"
|
|
8
8
|
description = "Code2Logic - Source code to logical representation converter for LLM analysis, featuring Tree-sitter parsing, dependency graph analysis, and multi-language support."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "Apache-2.0"
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
from .llm_clients import (
|
|
2
|
-
DEFAULT_MODELS,
|
|
3
|
-
DEFAULT_PROVIDER_PRIORITIES,
|
|
4
|
-
RECOMMENDED_MODELS,
|
|
5
|
-
BaseLLMClient,
|
|
6
|
-
LiteLLMClient,
|
|
7
|
-
LLMConfig,
|
|
8
|
-
LLMManager,
|
|
9
|
-
OllamaLocalClient,
|
|
10
|
-
OpenRouterClient,
|
|
11
|
-
get_client,
|
|
12
|
-
get_provider_model,
|
|
13
|
-
list_available_providers,
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def get_provider_priorities_from_litellm() -> dict[str, int]:
|
|
18
|
-
try:
|
|
19
|
-
from lolm import get_provider_priorities_from_litellm as _get
|
|
20
|
-
except ImportError:
|
|
21
|
-
return {}
|
|
22
|
-
|
|
23
|
-
try:
|
|
24
|
-
raw = _get() or {}
|
|
25
|
-
return {str(k): int(v) for k, v in raw.items()}
|
|
26
|
-
except Exception:
|
|
27
|
-
return {}
|
|
28
|
-
|
|
29
|
-
__all__ = [
|
|
30
|
-
'DEFAULT_MODELS',
|
|
31
|
-
'DEFAULT_PROVIDER_PRIORITIES',
|
|
32
|
-
'RECOMMENDED_MODELS',
|
|
33
|
-
'BaseLLMClient',
|
|
34
|
-
'LiteLLMClient',
|
|
35
|
-
'LLMConfig',
|
|
36
|
-
'LLMManager',
|
|
37
|
-
'OpenRouterClient',
|
|
38
|
-
'OllamaLocalClient',
|
|
39
|
-
'get_client',
|
|
40
|
-
'get_provider_model',
|
|
41
|
-
'get_provider_priorities_from_litellm',
|
|
42
|
-
'list_available_providers',
|
|
43
|
-
]
|
|
44
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|