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,250 @@
1
+ """
2
+ JSON-LD transpiler with legal ontology context.
3
+
4
+ Extends JSON output with @context, @type, and @id annotations
5
+ following schema.org/Legislation patterns.
6
+ """
7
+
8
+ import json
9
+ from typing import Any, Dict, List, Optional
10
+ from urllib.parse import quote
11
+
12
+ from yuho.ast import nodes
13
+ from yuho.transpile.base import TranspileTarget, TranspilerBase
14
+ from yuho.transpile.json_transpiler import JSONTranspiler
15
+
16
+
17
+ # JSON-LD context for legal ontology
18
+ LEGAL_CONTEXT = {
19
+ "@vocab": "https://schema.org/",
20
+ "yuho": "https://yuho.dev/ontology#",
21
+ "eli": "http://data.europa.eu/eli/ontology#",
22
+
23
+ # Schema.org Legislation mappings
24
+ "Statute": "Legislation",
25
+ "section_number": "legislationIdentifier",
26
+ "title": "name",
27
+ "definitions": "yuho:definitions",
28
+ "elements": "yuho:elements",
29
+ "penalty": "yuho:penalty",
30
+ "illustrations": "yuho:illustrations",
31
+
32
+ # Element types
33
+ "ElementNode": "yuho:LegalElement",
34
+ "actus_reus": "yuho:actusReus",
35
+ "mens_rea": "yuho:mensRea",
36
+ "circumstance": "yuho:circumstance",
37
+
38
+ # Penalty mappings
39
+ "PenaltyNode": "yuho:Penalty",
40
+ "imprisonment": "yuho:imprisonment",
41
+ "fine": "yuho:fine",
42
+ "supplementary": "yuho:supplementaryPunishment",
43
+
44
+ # Duration/Money
45
+ "DurationNode": "Duration",
46
+ "MoneyNode": "MonetaryAmount",
47
+ "currency": "currency",
48
+ "amount": "value",
49
+
50
+ # Struct mappings
51
+ "StructDefNode": "yuho:TypeDefinition",
52
+ "StructLiteralNode": "yuho:Instance",
53
+ "FieldDef": "yuho:Field",
54
+
55
+ # Function mappings
56
+ "FunctionDefNode": "yuho:Function",
57
+
58
+ # Match expression
59
+ "MatchExprNode": "yuho:DecisionTree",
60
+ "MatchArm": "yuho:DecisionBranch",
61
+ "pattern": "yuho:condition",
62
+ "body": "yuho:consequence",
63
+ }
64
+
65
+
66
+ class JSONLDTranspiler(TranspilerBase):
67
+ """
68
+ Transpile Yuho AST to JSON-LD format with legal ontology annotations.
69
+
70
+ Adds @context, @type, and @id to enable linked data queries
71
+ and integration with legal knowledge graphs.
72
+ """
73
+
74
+ def __init__(self, base_uri: str = "https://yuho.dev/statutes/", include_locations: bool = False):
75
+ """
76
+ Initialize the JSON-LD transpiler.
77
+
78
+ Args:
79
+ base_uri: Base URI for @id generation
80
+ include_locations: Whether to include source locations
81
+ """
82
+ self.base_uri = base_uri
83
+ self.include_locations = include_locations
84
+ self._json_transpiler = JSONTranspiler(include_locations=include_locations)
85
+
86
+ @property
87
+ def target(self) -> TranspileTarget:
88
+ return TranspileTarget.JSON_LD
89
+
90
+ def transpile(self, ast: nodes.ModuleNode) -> str:
91
+ """Transpile AST to JSON-LD string."""
92
+ data = self._to_jsonld(ast)
93
+ return json.dumps(data, indent=2, ensure_ascii=False)
94
+
95
+ def _to_jsonld(self, node: nodes.ASTNode) -> Dict[str, Any]:
96
+ """Convert AST node to JSON-LD format."""
97
+ # Start with basic JSON representation
98
+ base = self._json_transpiler._to_dict(node)
99
+
100
+ # Transform to JSON-LD
101
+ result = self._transform_to_jsonld(base, node)
102
+
103
+ # Add context at top level for ModuleNode
104
+ if isinstance(node, nodes.ModuleNode):
105
+ result = {
106
+ "@context": LEGAL_CONTEXT,
107
+ "@graph": result if isinstance(result, list) else [result],
108
+ }
109
+
110
+ return result
111
+
112
+ def _transform_to_jsonld(self, data: Dict[str, Any], node: nodes.ASTNode) -> Dict[str, Any]:
113
+ """Transform a JSON dict to JSON-LD format."""
114
+ result = {}
115
+
116
+ # Map _type to @type
117
+ if "_type" in data:
118
+ node_type = data["_type"]
119
+ result["@type"] = self._map_type(node_type)
120
+
121
+ # Generate @id for identifiable nodes
122
+ if isinstance(node, nodes.StatuteNode):
123
+ result["@id"] = f"{self.base_uri}{quote(node.section_number)}"
124
+ elif isinstance(node, nodes.StructDefNode):
125
+ result["@id"] = f"{self.base_uri}types/{quote(node.name)}"
126
+ elif isinstance(node, nodes.FunctionDefNode):
127
+ result["@id"] = f"{self.base_uri}functions/{quote(node.name)}"
128
+
129
+ # Copy and transform remaining fields
130
+ for key, value in data.items():
131
+ if key.startswith("_"):
132
+ continue # Skip internal fields
133
+
134
+ new_key = self._map_property(key)
135
+
136
+ if isinstance(value, dict):
137
+ # Recursively transform nested objects
138
+ child_node = self._get_child_node(node, key)
139
+ result[new_key] = self._transform_to_jsonld(value, child_node) if child_node else value
140
+ elif isinstance(value, list):
141
+ # Transform list items
142
+ result[new_key] = [
143
+ self._transform_to_jsonld(item, self._get_list_item_node(node, key, i))
144
+ if isinstance(item, dict) else item
145
+ for i, item in enumerate(value)
146
+ ]
147
+ else:
148
+ result[new_key] = value
149
+
150
+ return result
151
+
152
+ def _map_type(self, node_type: str) -> str:
153
+ """Map internal type name to JSON-LD type."""
154
+ type_mapping = {
155
+ "ModuleNode": "yuho:Module",
156
+ "StatuteNode": "Legislation",
157
+ "StructDefNode": "yuho:TypeDefinition",
158
+ "StructLiteralNode": "yuho:Instance",
159
+ "FunctionDefNode": "yuho:Function",
160
+ "MatchExprNode": "yuho:DecisionTree",
161
+ "MatchArm": "yuho:DecisionBranch",
162
+ "ElementNode": "yuho:LegalElement",
163
+ "PenaltyNode": "yuho:Penalty",
164
+ "DurationNode": "Duration",
165
+ "MoneyNode": "MonetaryAmount",
166
+ "StringLit": "Text",
167
+ "IntLit": "Integer",
168
+ "FloatLit": "Number",
169
+ "BoolLit": "Boolean",
170
+ "DateNode": "Date",
171
+ "PercentNode": "yuho:Percentage",
172
+ "ImportNode": "yuho:Import",
173
+ "IllustrationNode": "yuho:Illustration",
174
+ "DefinitionEntry": "DefinedTerm",
175
+ }
176
+ return type_mapping.get(node_type, f"yuho:{node_type}")
177
+
178
+ def _map_property(self, prop: str) -> str:
179
+ """Map internal property name to JSON-LD property."""
180
+ prop_mapping = {
181
+ "section_number": "legislationIdentifier",
182
+ "title": "name",
183
+ "definitions": "yuho:hasDefinition",
184
+ "elements": "yuho:hasElement",
185
+ "penalty": "yuho:hasPenalty",
186
+ "illustrations": "yuho:hasIllustration",
187
+ "element_type": "yuho:elementType",
188
+ "description": "description",
189
+ "term": "name",
190
+ "definition": "description",
191
+ "imprisonment_min": "yuho:minImprisonment",
192
+ "imprisonment_max": "yuho:maxImprisonment",
193
+ "fine_min": "yuho:minFine",
194
+ "fine_max": "yuho:maxFine",
195
+ "supplementary": "yuho:supplementaryPunishment",
196
+ "scrutinee": "yuho:subject",
197
+ "arms": "yuho:hasBranch",
198
+ "pattern": "yuho:condition",
199
+ "guard": "yuho:guard",
200
+ "body": "yuho:consequence",
201
+ "struct_name": "yuho:instanceOf",
202
+ "fields": "yuho:hasField",
203
+ "field_values": "yuho:hasFieldValue",
204
+ "type_defs": "yuho:definesType",
205
+ "function_defs": "yuho:definesFunction",
206
+ "statutes": "yuho:containsLegislation",
207
+ "imports": "yuho:imports",
208
+ "variables": "yuho:definesVariable",
209
+ "params": "yuho:hasParameter",
210
+ "return_type": "yuho:returnType",
211
+ "type": "yuho:type",
212
+ "value": "yuho:value",
213
+ "name": "name",
214
+ "callee": "yuho:callee",
215
+ "args": "yuho:arguments",
216
+ "operator": "yuho:operator",
217
+ "left": "yuho:leftOperand",
218
+ "right": "yuho:rightOperand",
219
+ "operand": "yuho:operand",
220
+ "base": "yuho:base",
221
+ "field_name": "yuho:fieldName",
222
+ "index": "yuho:index",
223
+ "currency": "priceCurrency",
224
+ "amount": "value",
225
+ "years": "yuho:years",
226
+ "months": "yuho:months",
227
+ "days": "yuho:days",
228
+ "hours": "yuho:hours",
229
+ "minutes": "yuho:minutes",
230
+ "seconds": "yuho:seconds",
231
+ }
232
+ return prop_mapping.get(prop, prop)
233
+
234
+ def _get_child_node(self, parent: nodes.ASTNode, field: str) -> Optional[nodes.ASTNode]:
235
+ """Get child node for a field."""
236
+ if hasattr(parent, field):
237
+ child = getattr(parent, field)
238
+ if isinstance(child, nodes.ASTNode):
239
+ return child
240
+ return None
241
+
242
+ def _get_list_item_node(self, parent: nodes.ASTNode, field: str, index: int) -> Optional[nodes.ASTNode]:
243
+ """Get node for list item at index."""
244
+ if hasattr(parent, field):
245
+ children = getattr(parent, field)
246
+ if isinstance(children, (list, tuple)) and index < len(children):
247
+ item = children[index]
248
+ if isinstance(item, nodes.ASTNode):
249
+ return item
250
+ return None
@@ -0,0 +1,161 @@
1
+ """
2
+ LaTeX preamble generation for legal documents.
3
+
4
+ Contains all the LaTeX document setup including:
5
+ - Document class and packages
6
+ - Custom commands and environments
7
+ - Style definitions for legal documents
8
+ """
9
+
10
+ from typing import List
11
+
12
+ from yuho.transpile.latex_utils import escape_latex
13
+
14
+
15
+ def generate_preamble(
16
+ document_title: str = "Legal Statutes",
17
+ author: str = "",
18
+ use_margins: bool = True,
19
+ ) -> List[str]:
20
+ """
21
+ Generate LaTeX preamble for legal documents.
22
+
23
+ Args:
24
+ document_title: Title for the document
25
+ author: Document author
26
+ use_margins: Whether to use margin notes
27
+
28
+ Returns:
29
+ List of preamble lines
30
+ """
31
+ lines: List[str] = []
32
+
33
+ def emit(text: str) -> None:
34
+ lines.append(text)
35
+
36
+ def emit_blank() -> None:
37
+ lines.append("")
38
+
39
+ # Document class
40
+ emit(r"\documentclass[11pt,a4paper]{article}")
41
+ emit_blank()
42
+
43
+ # Essential packages
44
+ emit(r"% Essential packages")
45
+ emit(r"\usepackage[utf8]{inputenc}")
46
+ emit(r"\usepackage[T1]{fontenc}")
47
+ emit(r"\usepackage{lmodern}")
48
+ emit_blank()
49
+
50
+ # Page geometry
51
+ emit(r"% Page layout")
52
+ if use_margins:
53
+ emit(r"\usepackage[a4paper,left=3cm,right=4cm,top=2.5cm,bottom=2.5cm,marginparwidth=3cm]{geometry}")
54
+ else:
55
+ emit(r"\usepackage[a4paper,margin=2.5cm]{geometry}")
56
+ emit_blank()
57
+
58
+ # Typography
59
+ emit(r"% Typography")
60
+ emit(r"\usepackage{microtype}")
61
+ emit(r"\usepackage{parskip}")
62
+ emit(r"\setlength{\parindent}{0pt}")
63
+ emit_blank()
64
+
65
+ # Colors and boxes
66
+ emit(r"% Colors and boxes for illustrations")
67
+ emit(r"\usepackage{xcolor}")
68
+ emit(r"\usepackage{tcolorbox}")
69
+ emit(r"\tcbuselibrary{skins}")
70
+ emit_blank()
71
+
72
+ # Define illustration box style
73
+ emit(r"% Illustration box style")
74
+ emit(r"\newtcolorbox{illustrationbox}[1][]{")
75
+ emit(r" enhanced,")
76
+ emit(r" colback=gray!10,")
77
+ emit(r" colframe=gray!50,")
78
+ emit(r" fontupper=\itshape,")
79
+ emit(r" boxrule=0.5pt,")
80
+ emit(r" left=10pt,")
81
+ emit(r" right=10pt,")
82
+ emit(r" top=8pt,")
83
+ emit(r" bottom=8pt,")
84
+ emit(r" #1")
85
+ emit(r"}")
86
+ emit_blank()
87
+
88
+ # Tables
89
+ emit(r"% Tables for penalties")
90
+ emit(r"\usepackage{booktabs}")
91
+ emit(r"\usepackage{array}")
92
+ emit(r"\usepackage{longtable}")
93
+ emit_blank()
94
+
95
+ # Margin notes
96
+ if use_margins:
97
+ emit(r"% Margin notes")
98
+ emit(r"\usepackage{marginnote}")
99
+ emit(r"\renewcommand*{\marginfont}{\footnotesize\sffamily}")
100
+ emit_blank()
101
+
102
+ # Hyperlinks and cross-references
103
+ emit(r"% Hyperlinks")
104
+ emit(r"\usepackage{hyperref}")
105
+ emit(r"\hypersetup{")
106
+ emit(r" colorlinks=true,")
107
+ emit(r" linkcolor=blue!60!black,")
108
+ emit(r" urlcolor=blue!60!black,")
109
+ emit(r" pdftitle={" + escape_latex(document_title) + "},")
110
+ if author:
111
+ emit(r" pdfauthor={" + escape_latex(author) + "},")
112
+ emit(r"}")
113
+ emit_blank()
114
+
115
+ # Section formatting for statutes
116
+ emit(r"% Statute section formatting")
117
+ emit(r"\usepackage{titlesec}")
118
+ emit(r"\titleformat{\section}")
119
+ emit(r" {\normalfont\Large\bfseries}")
120
+ emit(r" {Section \thesection}")
121
+ emit(r" {1em}")
122
+ emit(r" {}")
123
+ emit_blank()
124
+
125
+ # Custom commands for legal formatting
126
+ emit(r"% Custom commands for legal formatting")
127
+ emit(r"\newcommand{\statute}[2]{%")
128
+ emit(r" \subsection[Section #1 --- #2]{Section #1 --- #2}%")
129
+ emit(r" \label{sec:#1}%")
130
+ emit(r"}")
131
+ emit_blank()
132
+
133
+ emit(r"\newcommand{\sectionref}[1]{Section~\ref{sec:#1}}")
134
+ emit_blank()
135
+
136
+ emit(r"\newcommand{\element}[2]{%")
137
+ emit(r" \textbf{#1:} #2%")
138
+ emit(r"}")
139
+ emit_blank()
140
+
141
+ # Definition list environment
142
+ emit(r"% Definition list for legal definitions")
143
+ emit(r"\newenvironment{legaldefs}{%")
144
+ emit(r" \begin{description}[leftmargin=2em,style=nextline]")
145
+ emit(r"}{%")
146
+ emit(r" \end{description}")
147
+ emit(r"}")
148
+ emit(r"\usepackage{enumitem}")
149
+ emit_blank()
150
+
151
+ # Document metadata
152
+ emit(r"% Document metadata")
153
+ emit(r"\title{" + escape_latex(document_title) + "}")
154
+ if author:
155
+ emit(r"\author{" + escape_latex(author) + "}")
156
+ else:
157
+ emit(r"\author{}")
158
+ emit(r"\date{\today}")
159
+ emit_blank()
160
+
161
+ return lines