Skip to content

Commit e3c014a

Browse files
refactor(examples): CLI interface improvements
changes: - file: base_generator.py area: core added: [generate, ProjectGenerator] - file: common.py area: core modified: [get_token_reproduction_prompt] - file: runner.py area: core modified: [_template_generate_code, BenchmarkRunner] - file: llm_clients_new.py area: cli removed: [get_provider_priorities_from_litellm] - file: parsers.py area: analyzer modified: [_parse_java, _parse_csharp, UniversalParser] - file: benchmark_report.py area: core modified: [main] - file: benchmark_summary.py area: core modified: [main] stats: lines: "+233/-6029 (net -5796)" files: 14 complexity: "+22% complexity (new features)"
1 parent a7e970f commit e3c014a

File tree

22 files changed

+265
-6036
lines changed

22 files changed

+265
-6036
lines changed

CHANGELOG.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,28 @@
1+
## [1.0.41] - 2026-02-25
2+
3+
### Summary
4+
5+
refactor(examples): CLI interface improvements
6+
7+
### Docs
8+
9+
- docs: update README
10+
11+
### Other
12+
13+
- build: update Makefile
14+
- update code2logic/base_generator.py
15+
- update code2logic/benchmarks/common.py
16+
- update code2logic/benchmarks/runner.py
17+
- update code2logic/llm_clients_new.py
18+
- update code2logic/parsers.py
19+
- update examples/benchmark_report.py
20+
- update examples/benchmark_summary.py
21+
- update function-schema.json
22+
- update function.toon
23+
- ... and 3 more
24+
25+
126
## [1.0.40] - 2026-02-25
227

328
### Summary

Makefile

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ else
336336
BENCH_NO_LLM_FLAG := --no-llm
337337
endif
338338

339-
benchmark: benchmark-format benchmark-function-logic benchmark-function benchmark-token benchmark-project benchmark-toon benchmark-compare ## Run all benchmarks (no LLM)
339+
benchmark: benchmark-format benchmark-function benchmark-token benchmark-project benchmark-toon benchmark-compare ## Run all benchmarks (no LLM)
340340
@echo ""
341341
@echo "$(GREEN)All benchmarks completed!$(NC)"
342342
@echo "Results in $(BENCH_OUTPUT)/"
@@ -360,17 +360,6 @@ benchmark-format: ## Benchmark format reproduction (yaml/toon/logicml/json)
360360
--limit $(BENCH_LIMIT) --verbose \
361361
--output $(BENCH_OUTPUT)/benchmark_format.json
362362

363-
benchmark-function-logic: ## Benchmark function-logic TOON reproduction as a standalone format
364-
@echo "$(BLUE)━━━ Function-Logic Format Benchmark ━━━$(NC)"
365-
@mkdir -p $(BENCH_OUTPUT)
366-
@printf '%s\n' "$(PYTHON) examples/15_unified_benchmark.py $(BENCH_NO_LLM_FLAG) --type format --folder $(BENCH_SAMPLES)/ --formats function.toon --limit $(BENCH_LIMIT) --verbose --output $(BENCH_OUTPUT)/benchmark_function_logic.json" >> $(BENCH_OUTPUT)/BENCHMARK_COMMANDS.sh
367-
$(PYTHON) examples/15_unified_benchmark.py \
368-
$(BENCH_NO_LLM_FLAG) --type format \
369-
--folder $(BENCH_SAMPLES)/ \
370-
--formats function.toon \
371-
--limit $(BENCH_LIMIT) --verbose \
372-
--output $(BENCH_OUTPUT)/benchmark_function_logic.json
373-
374363
benchmark-function: ## Benchmark function-level reproduction
375364
@echo "$(BLUE)━━━ Function Benchmark ━━━$(NC)"
376365
@printf '%s\n' "$(PYTHON) examples/15_unified_benchmark.py $(BENCH_NO_LLM_FLAG) --type function --file $(BENCH_SAMPLES)/sample_functions.py --limit 10 --verbose --output $(BENCH_OUTPUT)/benchmark_function.json" >> $(BENCH_OUTPUT)/BENCHMARK_COMMANDS.sh

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.0.40
1+
1.0.41

code2logic/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
>>> print(output)
1919
"""
2020

21-
__version__ = "1.0.40"
21+
__version__ = "1.0.41"
2222
__author__ = "Softreck"
2323
__email__ = "info@softreck.dev"
2424
__license__ = "MIT"

code2logic/base_generator.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from typing import Protocol, Any
2+
from .models import ProjectInfo
3+
4+
class ProjectGenerator(Protocol):
5+
def generate(self, project: ProjectInfo, **kwargs: Any) -> Any:
6+
...

code2logic/benchmarks/common.py

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -189,14 +189,21 @@ def get_async_reproduction_prompt(spec: str, fmt: str, file_name: str, with_test
189189

190190
def get_token_reproduction_prompt(spec: str, fmt: str, file_name: str, language: str = "python") -> str:
191191
format_hints = {
192-
"json": "Parse the JSON structure and implement all classes and functions.",
193-
"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.",
194194
"yaml": "Parse the YAML structure and implement all classes and functions with exact signatures.",
195-
"gherkin": "Implement scenarios as SIMPLE, MINIMAL code. NO over-engineering. Keep code short and direct.",
196-
"markdown": "Parse embedded Gherkin (behaviors) and YAML (structures).",
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.",
197202
"logicml": """Parse LogicML and generate VALID code:
198203
- 'sig:' lines describe function signatures (translate to the target language)
199204
- '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
200207
CRITICAL: Ensure valid syntax - balanced brackets, proper indentation, no undefined variables.""",
201208
"toon": """Parse TOON (Token-Oriented Object Notation) format carefully:
202209
@@ -216,20 +223,32 @@ def get_token_reproduction_prompt(spec: str, fmt: str, file_name: str, language:
216223
- 'decorators: @staticmethod|@cache' = multiple decorators
217224
218225
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.""",
238+
}
219239

220-
"function.toon": """Parse function-logic TOON carefully (function/method index):
221-
222-
STRUCTURE:
223-
- 'modules[N]{path,lang,items}:' module index
224-
- 'function_details:' per-module tables
225-
226-
CRITICAL:
227-
- Use the tabular rows (line,name,sig,does,decorators,calls,raises)
228-
- Reconstruct the full module code even if class bodies are not explicitly described
229-
- Preserve exact function signatures from 'sig'""",
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.",
230249
}
231250

232-
max_spec = 5000
251+
max_spec = 8000
233252
spec_truncated = spec[:max_spec] if len(spec) > max_spec else spec
234253

235254
language_norm = (language or "python").strip().lower()
@@ -245,8 +264,11 @@ def get_token_reproduction_prompt(spec: str, fmt: str, file_name: str, language:
245264
}
246265
lang_label = lang_label_map.get(language_norm, language_norm)
247266

267+
lang_hint = lang_hints.get(language_norm, '')
268+
lang_hint_line = f"\n{lang_hint}" if lang_hint else ''
269+
248270
prompt = f"""Generate {lang_label} code from this {fmt.upper()} specification.
249-
{format_hints.get(fmt, '')}
271+
{format_hints.get(fmt, '')}{lang_hint_line}
250272
251273
{spec_truncated}
252274

code2logic/benchmarks/runner.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,12 +217,37 @@ def _template_generate_code(self, spec: str, fmt: str, file_name: str, language:
217217
classes: List[str] = []
218218
functions: List[str] = []
219219

220-
# Common patterns
220+
# Common patterns across formats
221221
classes.extend(re.findall(r"\bclass\s+([A-Za-z_][A-Za-z0-9_]*)", spec))
222-
classes.extend(re.findall(r"^([A-Za-z_][A-Za-z0-9_]*)\s*:\s*$", spec, re.MULTILINE))
222+
classes.extend(re.findall(r'"name":\s*"([A-Z][A-Za-z0-9_]*)"', spec))
223223
functions.extend(re.findall(r"\bdef\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(", spec))
224224
functions.extend(re.findall(r"\bFunction:\s*([A-Za-z_][A-Za-z0-9_]*)", spec))
225225
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))
226251

227252
# Deduplicate while preserving order
228253
def uniq(items: List[str]) -> List[str]:

code2logic/llm_clients_new.py

Lines changed: 0 additions & 44 deletions
This file was deleted.

code2logic/parsers.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2212,30 +2212,30 @@ def _parse_java(self, filepath: str, content: str) -> ModuleInfo:
22122212
for m in re.finditer(r'^import\s+([^;]+);', content, re.MULTILINE):
22132213
imports.append(m.group(1).strip())
22142214

2215-
for m in re.finditer(r'^(?:public\s+)?(?:abstract\s+)?class\s+(\w+)', content, re.MULTILINE):
2215+
for m in re.finditer(r'^\s*(?:public\s+)?(?:abstract\s+)?class\s+(\w+)', content, re.MULTILINE):
22162216
name = m.group(1)
22172217
classes.append(ClassInfo(name=name, is_abstract='abstract' in m.group(0)))
22182218
exports.append(name)
22192219

2220-
for m in re.finditer(r'^(?:public\s+)?interface\s+(\w+)', content, re.MULTILINE):
2220+
for m in re.finditer(r'^\s*(?:public\s+)?interface\s+(\w+)', content, re.MULTILINE):
22212221
name = m.group(1)
22222222
classes.append(ClassInfo(name=name, is_interface=True))
22232223
exports.append(name)
22242224
types.append(TypeInfo(name=name, kind='interface', definition=''))
22252225

2226-
for m in re.finditer(r'^(?:public\s+)?enum\s+(\w+)', content, re.MULTILINE):
2226+
for m in re.finditer(r'^\s*(?:public\s+)?enum\s+(\w+)', content, re.MULTILINE):
22272227
name = m.group(1)
22282228
types.append(TypeInfo(name=name, kind='enum', definition=''))
22292229
exports.append(name)
22302230

2231-
for m in re.finditer(r'^(?:public\s+)?record\s+(\w+)\s*\(', content, re.MULTILINE):
2231+
for m in re.finditer(r'^\s*(?:public\s+)?record\s+(\w+)\s*\(', content, re.MULTILINE):
22322232
name = m.group(1)
22332233
classes.append(ClassInfo(name=name))
22342234
types.append(TypeInfo(name=name, kind='record', definition=''))
22352235
exports.append(name)
22362236

2237-
# Very rough method detection (only top-level class members are not tracked here)
2238-
for m in re.finditer(r'^(?:public|protected|private)\s+(?:static\s+)?([\w<>\[\]]+)\s+(\w+)\s*\(([^)]*)\)\s*\{', content, re.MULTILINE):
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):
22392239
ret_type = m.group(1)
22402240
name = m.group(2)
22412241
params = [p.strip() for p in (m.group(3) or '').split(',') if p.strip()][:8]
@@ -2260,7 +2260,7 @@ def _parse_java(self, filepath: str, content: str) -> ModuleInfo:
22602260
is_private=False,
22612261
))
22622262

2263-
for m in re.finditer(r'^(?:public\s+)?static\s+final\s+[\w<>\[\]]+\s+([A-Z][A-Z0-9_]*)\b', content, re.MULTILINE):
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):
22642264
constants.append(m.group(1))
22652265

22662266
lines = content.split('\n')
@@ -2290,24 +2290,24 @@ def _parse_csharp(self, filepath: str, content: str) -> ModuleInfo:
22902290
for m in re.finditer(r'^using\s+([^;]+);', content, re.MULTILINE):
22912291
imports.append(m.group(1).strip())
22922292

2293-
for m in re.finditer(r'^(?:public\s+)?interface\s+(I\w+)', content, re.MULTILINE):
2293+
for m in re.finditer(r'^\s*(?:public\s+)?interface\s+(I\w+)', content, re.MULTILINE):
22942294
name = m.group(1)
22952295
classes.append(ClassInfo(name=name, is_interface=True))
22962296
exports.append(name)
22972297
types.append(TypeInfo(name=name, kind='interface', definition=''))
22982298

2299-
for m in re.finditer(r'^(?:public\s+)?(?:abstract\s+)?class\s+(\w+)', content, re.MULTILINE):
2299+
for m in re.finditer(r'^\s*(?:public\s+)?(?:abstract\s+)?class\s+(\w+)', content, re.MULTILINE):
23002300
name = m.group(1)
23012301
classes.append(ClassInfo(name=name, is_abstract='abstract' in m.group(0)))
23022302
exports.append(name)
23032303

2304-
for m in re.finditer(r'^(?:public\s+)?record\s+(\w+)', content, re.MULTILINE):
2304+
for m in re.finditer(r'^\s*(?:public\s+)?record\s+(\w+)', content, re.MULTILINE):
23052305
name = m.group(1)
23062306
classes.append(ClassInfo(name=name))
23072307
exports.append(name)
23082308
types.append(TypeInfo(name=name, kind='record', definition=''))
23092309

2310-
for m in re.finditer(r'^(?:public|private|protected|internal)\s+(?:static\s+)?([\w<>\[\]?]+)\s+(\w+)\s*\(([^)]*)\)\s*\{', content, re.MULTILINE):
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):
23112311
ret_type = m.group(1)
23122312
name = m.group(2)
23132313
params = [p.strip() for p in (m.group(3) or '').split(',') if p.strip()][:8]
@@ -2332,7 +2332,7 @@ def _parse_csharp(self, filepath: str, content: str) -> ModuleInfo:
23322332
is_private=False,
23332333
))
23342334

2335-
for m in re.finditer(r'^(?:public\s+)?const\s+[\w<>\[\]]+\s+([A-Z][A-Z0-9_]*)\b', content, re.MULTILINE):
2335+
for m in re.finditer(r'^\s*(?:public\s+)?const\s+[\w<>\[\]]+\s+([A-Z][A-Z0-9_]*)\b', content, re.MULTILINE):
23362336
constants.append(m.group(1))
23372337

23382338
lines = content.split('\n')

examples/benchmark_report.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ def main() -> None:
165165
lines.append("| Artifact | File | Size | ~Tokens | Description |")
166166
lines.append("|---|---|---:|---:|---|")
167167
for a in artifacts:
168-
rel = a.path.relative_to(out_dir) if a.path.exists() and out_dir in a.path.parents else a.path
168+
rel = a.path.relative_to(out_dir) if out_dir in a.path.parents else a.path
169169
size = _sizeof(a.path)
170170
tok_est = _token_estimate_bytes(size)
171171
file_cell = f"`{rel}`" if isinstance(rel, Path) else f"`{rel}`"

0 commit comments

Comments
 (0)