yuho 5.0.0__py3-none-any.whl

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.
Files changed (91) hide show
  1. yuho/__init__.py +16 -0
  2. yuho/ast/__init__.py +196 -0
  3. yuho/ast/builder.py +926 -0
  4. yuho/ast/constant_folder.py +280 -0
  5. yuho/ast/dead_code.py +199 -0
  6. yuho/ast/exhaustiveness.py +503 -0
  7. yuho/ast/nodes.py +907 -0
  8. yuho/ast/overlap.py +291 -0
  9. yuho/ast/reachability.py +293 -0
  10. yuho/ast/scope_analysis.py +490 -0
  11. yuho/ast/transformer.py +490 -0
  12. yuho/ast/type_check.py +471 -0
  13. yuho/ast/type_inference.py +425 -0
  14. yuho/ast/visitor.py +239 -0
  15. yuho/cli/__init__.py +14 -0
  16. yuho/cli/commands/__init__.py +1 -0
  17. yuho/cli/commands/api.py +431 -0
  18. yuho/cli/commands/ast_viz.py +334 -0
  19. yuho/cli/commands/check.py +218 -0
  20. yuho/cli/commands/config.py +311 -0
  21. yuho/cli/commands/contribute.py +122 -0
  22. yuho/cli/commands/diff.py +487 -0
  23. yuho/cli/commands/explain.py +240 -0
  24. yuho/cli/commands/fmt.py +253 -0
  25. yuho/cli/commands/generate.py +316 -0
  26. yuho/cli/commands/graph.py +410 -0
  27. yuho/cli/commands/init.py +120 -0
  28. yuho/cli/commands/library.py +656 -0
  29. yuho/cli/commands/lint.py +503 -0
  30. yuho/cli/commands/lsp.py +36 -0
  31. yuho/cli/commands/preview.py +377 -0
  32. yuho/cli/commands/repl.py +444 -0
  33. yuho/cli/commands/serve.py +44 -0
  34. yuho/cli/commands/test.py +528 -0
  35. yuho/cli/commands/transpile.py +121 -0
  36. yuho/cli/commands/wizard.py +370 -0
  37. yuho/cli/completions.py +182 -0
  38. yuho/cli/error_formatter.py +193 -0
  39. yuho/cli/main.py +1064 -0
  40. yuho/config/__init__.py +46 -0
  41. yuho/config/loader.py +235 -0
  42. yuho/config/mask.py +194 -0
  43. yuho/config/schema.py +147 -0
  44. yuho/library/__init__.py +84 -0
  45. yuho/library/index.py +328 -0
  46. yuho/library/install.py +699 -0
  47. yuho/library/lockfile.py +330 -0
  48. yuho/library/package.py +421 -0
  49. yuho/library/resolver.py +791 -0
  50. yuho/library/signature.py +335 -0
  51. yuho/llm/__init__.py +45 -0
  52. yuho/llm/config.py +75 -0
  53. yuho/llm/factory.py +123 -0
  54. yuho/llm/prompts.py +146 -0
  55. yuho/llm/providers.py +383 -0
  56. yuho/llm/utils.py +470 -0
  57. yuho/lsp/__init__.py +14 -0
  58. yuho/lsp/code_action_handler.py +518 -0
  59. yuho/lsp/completion_handler.py +85 -0
  60. yuho/lsp/diagnostics.py +100 -0
  61. yuho/lsp/hover_handler.py +130 -0
  62. yuho/lsp/server.py +1425 -0
  63. yuho/mcp/__init__.py +10 -0
  64. yuho/mcp/server.py +1452 -0
  65. yuho/parser/__init__.py +8 -0
  66. yuho/parser/source_location.py +108 -0
  67. yuho/parser/wrapper.py +311 -0
  68. yuho/testing/__init__.py +48 -0
  69. yuho/testing/coverage.py +274 -0
  70. yuho/testing/fixtures.py +263 -0
  71. yuho/transpile/__init__.py +52 -0
  72. yuho/transpile/alloy_transpiler.py +546 -0
  73. yuho/transpile/base.py +100 -0
  74. yuho/transpile/blocks_transpiler.py +338 -0
  75. yuho/transpile/english_transpiler.py +470 -0
  76. yuho/transpile/graphql_transpiler.py +404 -0
  77. yuho/transpile/json_transpiler.py +217 -0
  78. yuho/transpile/jsonld_transpiler.py +250 -0
  79. yuho/transpile/latex_preamble.py +161 -0
  80. yuho/transpile/latex_transpiler.py +406 -0
  81. yuho/transpile/latex_utils.py +206 -0
  82. yuho/transpile/mermaid_transpiler.py +357 -0
  83. yuho/transpile/registry.py +275 -0
  84. yuho/verify/__init__.py +43 -0
  85. yuho/verify/alloy.py +352 -0
  86. yuho/verify/combined.py +218 -0
  87. yuho/verify/z3_solver.py +1155 -0
  88. yuho-5.0.0.dist-info/METADATA +186 -0
  89. yuho-5.0.0.dist-info/RECORD +91 -0
  90. yuho-5.0.0.dist-info/WHEEL +4 -0
  91. yuho-5.0.0.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,316 @@
1
+ """
2
+ Statute scaffold generator for Yuho.
3
+
4
+ Generates boilerplate .yh files with proper structure for
5
+ quick statute creation.
6
+ """
7
+
8
+ import re
9
+ from pathlib import Path
10
+ from typing import Optional, List
11
+ from dataclasses import dataclass
12
+
13
+ import click
14
+
15
+
16
+ @dataclass
17
+ class ScaffoldConfig:
18
+ """Configuration for scaffold generation."""
19
+ section: str
20
+ title: str
21
+ with_definitions: bool = True
22
+ with_actus_reus: bool = True
23
+ with_mens_rea: bool = True
24
+ with_penalty: bool = True
25
+ with_illustrations: bool = True
26
+ num_definitions: int = 1
27
+ num_illustrations: int = 1
28
+ template: str = "standard" # standard, minimal, full
29
+
30
+
31
+ def normalize_section(section: str) -> str:
32
+ """
33
+ Normalize section number format.
34
+
35
+ Examples:
36
+ "299" -> "299"
37
+ "s299" -> "299"
38
+ "S299A" -> "299A"
39
+ "section 299" -> "299"
40
+ """
41
+ # Remove common prefixes
42
+ section = re.sub(r"^(?:s(?:ection)?\s*)", "", section, flags=re.IGNORECASE)
43
+ return section.strip()
44
+
45
+
46
+ def generate_filename(section: str, title: str) -> str:
47
+ """
48
+ Generate a filename from section and title.
49
+
50
+ Examples:
51
+ ("299", "Culpable Homicide") -> "s299_culpable_homicide.yh"
52
+ """
53
+ # Normalize section
54
+ section = normalize_section(section).lower()
55
+
56
+ # Convert title to snake_case
57
+ title_snake = re.sub(r"[^\w\s]", "", title.lower())
58
+ title_snake = re.sub(r"\s+", "_", title_snake.strip())
59
+
60
+ return f"s{section}_{title_snake}.yh"
61
+
62
+
63
+ def generate_standard_scaffold(config: ScaffoldConfig) -> str:
64
+ """Generate standard scaffold with typical structure."""
65
+ lines: List[str] = []
66
+
67
+ section = normalize_section(config.section)
68
+
69
+ # Header comment
70
+ lines.append(f"// Statute: Section {section} - {config.title}")
71
+ lines.append(f"// Generated by: yuho generate")
72
+ lines.append("")
73
+
74
+ # Statute declaration
75
+ lines.append(f'statute "{section}" "{config.title}" {{')
76
+
77
+ # Definitions
78
+ if config.with_definitions:
79
+ lines.append("")
80
+ lines.append(" definitions {")
81
+ for i in range(config.num_definitions):
82
+ term = f"term_{i + 1}" if config.num_definitions > 1 else "key_term"
83
+ lines.append(f' "{term}" := "TODO: Define {term}";')
84
+ lines.append(" }")
85
+
86
+ # Elements
87
+ lines.append("")
88
+ lines.append(" elements {")
89
+
90
+ if config.with_actus_reus:
91
+ lines.append(' actus_reus act := "TODO: Describe the physical act or conduct";')
92
+
93
+ if config.with_mens_rea:
94
+ lines.append(' mens_rea intent := "TODO: Describe the required mental state";')
95
+
96
+ lines.append(" }")
97
+
98
+ # Penalty
99
+ if config.with_penalty:
100
+ lines.append("")
101
+ lines.append(" penalty {")
102
+ lines.append(" imprisonment := 10Y; // TODO: Set appropriate term")
103
+ lines.append(" fine := SGD 10000; // TODO: Set appropriate fine")
104
+ lines.append(" }")
105
+
106
+ # Illustrations
107
+ if config.with_illustrations:
108
+ lines.append("")
109
+ lines.append(" illustrations {")
110
+ for i in range(config.num_illustrations):
111
+ label = chr(ord('a') + i)
112
+ lines.append(f' ({label}) "TODO: Provide example {label} illustrating application";')
113
+ lines.append(" }")
114
+
115
+ lines.append("}")
116
+
117
+ return "\n".join(lines)
118
+
119
+
120
+ def generate_minimal_scaffold(config: ScaffoldConfig) -> str:
121
+ """Generate minimal scaffold with only required sections."""
122
+ lines: List[str] = []
123
+
124
+ section = normalize_section(config.section)
125
+
126
+ lines.append(f'statute "{section}" "{config.title}" {{')
127
+ lines.append("")
128
+ lines.append(" elements {")
129
+ lines.append(' actus_reus act := "TODO: Define";')
130
+ lines.append(" }")
131
+ lines.append("")
132
+ lines.append("}")
133
+
134
+ return "\n".join(lines)
135
+
136
+
137
+ def generate_full_scaffold(config: ScaffoldConfig) -> str:
138
+ """Generate full scaffold with all possible sections."""
139
+ lines: List[str] = []
140
+
141
+ section = normalize_section(config.section)
142
+
143
+ # Header
144
+ lines.append("// ============================================================================")
145
+ lines.append(f"// SECTION {section}: {config.title.upper()}")
146
+ lines.append("// ============================================================================")
147
+ lines.append("//")
148
+ lines.append("// Description: TODO: Provide overview of this statute")
149
+ lines.append("// Source: TODO: Reference source legislation")
150
+ lines.append("// Effective: TODO: Date")
151
+ lines.append("//")
152
+ lines.append("")
153
+
154
+ lines.append(f'statute "{section}" "{config.title}" {{')
155
+
156
+ # Definitions
157
+ lines.append("")
158
+ lines.append(" // Define key legal terms used in this statute")
159
+ lines.append(" definitions {")
160
+ lines.append(' "perpetrator" := "The person who commits the act";')
161
+ lines.append(' "victim" := "The person against whom the act is committed";')
162
+ lines.append(' "property" := "Any movable or immovable asset";')
163
+ lines.append(" }")
164
+
165
+ # Elements
166
+ lines.append("")
167
+ lines.append(" // Elements that must be proven for conviction")
168
+ lines.append(" elements {")
169
+ lines.append(' actus_reus physical_act := "TODO: The physical conduct or act";')
170
+ lines.append(' actus_reus result := "TODO: The result or consequence (if any)";')
171
+ lines.append(' mens_rea intention := "TODO: The required mental state";')
172
+ lines.append(' circumstance context := "TODO: Circumstances that must exist";')
173
+ lines.append(" }")
174
+
175
+ # Exceptions / Defenses
176
+ lines.append("")
177
+ lines.append(" // Exceptions or defenses to liability")
178
+ lines.append(" // exceptions {")
179
+ lines.append(" // defense := TODO;")
180
+ lines.append(" // }")
181
+
182
+ # Penalty
183
+ lines.append("")
184
+ lines.append(" // Punishment upon conviction")
185
+ lines.append(" penalty {")
186
+ lines.append(" imprisonment := 2Y to 10Y;")
187
+ lines.append(" fine := SGD 5000 to SGD 50000;")
188
+ lines.append(' supplementary := "Or both imprisonment and fine";')
189
+ lines.append(" }")
190
+
191
+ # Illustrations
192
+ lines.append("")
193
+ lines.append(" // Examples illustrating application of this statute")
194
+ lines.append(" illustrations {")
195
+ lines.append(' (a) "Example showing when the offense IS committed: TODO";')
196
+ lines.append(' (b) "Example showing when the offense is NOT committed: TODO";')
197
+ lines.append(' (c) "Borderline case for consideration: TODO";')
198
+ lines.append(" }")
199
+
200
+ # Cross-references
201
+ lines.append("")
202
+ lines.append(" // Related statutes")
203
+ lines.append(" // references {")
204
+ lines.append(" // see \"300\"; // Related offense")
205
+ lines.append(" // see \"301\"; // Enhanced penalty provision")
206
+ lines.append(" // }")
207
+
208
+ lines.append("}")
209
+
210
+ return "\n".join(lines)
211
+
212
+
213
+ def generate_scaffold(config: ScaffoldConfig) -> str:
214
+ """
215
+ Generate scaffold based on template type.
216
+
217
+ Args:
218
+ config: Scaffold configuration
219
+
220
+ Returns:
221
+ Generated Yuho source code
222
+ """
223
+ generators = {
224
+ "standard": generate_standard_scaffold,
225
+ "minimal": generate_minimal_scaffold,
226
+ "full": generate_full_scaffold,
227
+ }
228
+
229
+ generator = generators.get(config.template, generate_standard_scaffold)
230
+ return generator(config)
231
+
232
+
233
+ def run_generate(
234
+ section: str,
235
+ title: str,
236
+ output: Optional[str] = None,
237
+ template: str = "standard",
238
+ no_definitions: bool = False,
239
+ no_penalty: bool = False,
240
+ no_illustrations: bool = False,
241
+ force: bool = False,
242
+ verbose: bool = False,
243
+ color: bool = True,
244
+ ) -> None:
245
+ """
246
+ Run scaffold generator.
247
+
248
+ Args:
249
+ section: Section number (e.g., "299", "s300A")
250
+ title: Statute title
251
+ output: Output file path (None = auto-generate)
252
+ template: Template type (standard, minimal, full)
253
+ no_definitions: Skip definitions block
254
+ no_penalty: Skip penalty block
255
+ no_illustrations: Skip illustrations block
256
+ force: Overwrite existing file
257
+ verbose: Verbose output
258
+ color: Use colors
259
+ """
260
+ # Validate template
261
+ valid_templates = ["standard", "minimal", "full"]
262
+ if template not in valid_templates:
263
+ click.echo(f"Error: Unknown template '{template}'", err=True)
264
+ click.echo(f"Available: {', '.join(valid_templates)}", err=True)
265
+ raise SystemExit(1)
266
+
267
+ # Build config
268
+ config = ScaffoldConfig(
269
+ section=section,
270
+ title=title,
271
+ template=template,
272
+ with_definitions=not no_definitions,
273
+ with_penalty=not no_penalty,
274
+ with_illustrations=not no_illustrations,
275
+ )
276
+
277
+ # Full template ignores individual flags
278
+ if template == "full":
279
+ config.with_definitions = True
280
+ config.with_penalty = True
281
+ config.with_illustrations = True
282
+
283
+ # Generate
284
+ code = generate_scaffold(config)
285
+
286
+ # Determine output path
287
+ if output:
288
+ path = Path(output)
289
+ else:
290
+ filename = generate_filename(section, title)
291
+ path = Path(filename)
292
+
293
+ # Check existing
294
+ if path.exists() and not force:
295
+ click.echo(f"Error: File already exists: {path}", err=True)
296
+ click.echo("Use --force to overwrite", err=True)
297
+ raise SystemExit(1)
298
+
299
+ # Write
300
+ path.write_text(code + "\n")
301
+
302
+ # Output
303
+ if verbose:
304
+ click.echo(click.style("Generated scaffold:", fg="cyan", bold=True))
305
+ click.echo("")
306
+ click.echo(code)
307
+ click.echo("")
308
+
309
+ click.echo(click.style(f"✓ Created: {path}", fg="green"))
310
+
311
+ # Show tips
312
+ click.echo("")
313
+ click.echo(click.style("Next steps:", fg="yellow"))
314
+ click.echo(f" 1. Edit {path} to fill in TODO sections")
315
+ click.echo(f" 2. Run: yuho check {path}")
316
+ click.echo(f" 3. Run: yuho transpile {path} --target english")