vex-ast 0.2.5__py3-none-any.whl → 0.2.6__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.
- vex_ast/README.md +101 -51
- vex_ast/READMEAPI.md +133 -318
- vex_ast/__init__.py +81 -81
- vex_ast/ast/README.md +87 -87
- vex_ast/ast/__init__.py +74 -74
- vex_ast/ast/core.py +71 -71
- vex_ast/ast/expressions.py +276 -276
- vex_ast/ast/interfaces.py +208 -208
- vex_ast/ast/literals.py +80 -80
- vex_ast/ast/navigator.py +225 -225
- vex_ast/ast/operators.py +135 -135
- vex_ast/ast/statements.py +351 -351
- vex_ast/ast/validators.py +121 -121
- vex_ast/ast/vex_nodes.py +279 -279
- vex_ast/parser/README.md +47 -47
- vex_ast/parser/__init__.py +26 -26
- vex_ast/parser/factory.py +190 -190
- vex_ast/parser/interfaces.py +34 -34
- vex_ast/parser/python_parser.py +831 -831
- vex_ast/registry/README.md +107 -29
- vex_ast/registry/__init__.py +51 -51
- vex_ast/registry/api.py +190 -155
- vex_ast/registry/categories.py +179 -136
- vex_ast/registry/functions/__init__.py +10 -10
- vex_ast/registry/functions/constructors.py +71 -35
- vex_ast/registry/functions/display.py +146 -146
- vex_ast/registry/functions/drivetrain.py +163 -163
- vex_ast/registry/functions/initialize.py +31 -31
- vex_ast/registry/functions/motor.py +140 -140
- vex_ast/registry/functions/sensors.py +194 -194
- vex_ast/registry/functions/timing.py +103 -103
- vex_ast/registry/language_map.py +77 -77
- vex_ast/registry/registry.py +164 -153
- vex_ast/registry/signature.py +269 -191
- vex_ast/registry/simulation_behavior.py +8 -8
- vex_ast/registry/validation.py +43 -43
- vex_ast/serialization/__init__.py +37 -37
- vex_ast/serialization/json_deserializer.py +284 -284
- vex_ast/serialization/json_serializer.py +148 -148
- vex_ast/serialization/schema.py +492 -492
- vex_ast/types/README.md +78 -26
- vex_ast/types/__init__.py +140 -140
- vex_ast/types/base.py +83 -83
- vex_ast/types/enums.py +122 -122
- vex_ast/types/objects.py +64 -64
- vex_ast/types/primitives.py +68 -68
- vex_ast/types/type_checker.py +31 -31
- vex_ast/utils/README.md +39 -39
- vex_ast/utils/__init__.py +37 -37
- vex_ast/utils/errors.py +112 -112
- vex_ast/utils/source_location.py +38 -38
- vex_ast/utils/type_definitions.py +8 -8
- vex_ast/visitors/README.md +49 -49
- vex_ast/visitors/__init__.py +27 -27
- vex_ast/visitors/analyzer.py +102 -102
- vex_ast/visitors/base.py +133 -133
- vex_ast/visitors/printer.py +196 -196
- {vex_ast-0.2.5.dist-info → vex_ast-0.2.6.dist-info}/METADATA +206 -174
- vex_ast-0.2.6.dist-info/RECORD +64 -0
- vex_ast-0.2.5.dist-info/RECORD +0 -64
- {vex_ast-0.2.5.dist-info → vex_ast-0.2.6.dist-info}/WHEEL +0 -0
- {vex_ast-0.2.5.dist-info → vex_ast-0.2.6.dist-info}/licenses/LICENSE +0 -0
- {vex_ast-0.2.5.dist-info → vex_ast-0.2.6.dist-info}/top_level.txt +0 -0
vex_ast/serialization/schema.py
CHANGED
@@ -1,492 +1,492 @@
|
|
1
|
-
"""
|
2
|
-
JSON Schema generation for AST nodes.
|
3
|
-
|
4
|
-
This module provides functionality to generate JSON Schema definitions
|
5
|
-
for the AST structure, which can be used for validation and documentation.
|
6
|
-
"""
|
7
|
-
|
8
|
-
import json
|
9
|
-
import os
|
10
|
-
from typing import Any, Dict, List, Optional, Set, Type
|
11
|
-
|
12
|
-
from ..ast.core import Program, Expression, Statement
|
13
|
-
from ..ast.expressions import (
|
14
|
-
AttributeAccess, BinaryOperation, ConditionalExpression, FunctionCall, Identifier, KeywordArgument,
|
15
|
-
UnaryOperation, VariableReference
|
16
|
-
)
|
17
|
-
from ..ast.literals import (
|
18
|
-
BooleanLiteral, NoneLiteral, NumberLiteral, StringLiteral
|
19
|
-
)
|
20
|
-
from ..ast.statements import (
|
21
|
-
Assignment, BreakStatement, ContinueStatement, ExpressionStatement,
|
22
|
-
ForLoop, FunctionDefinition, IfStatement, ReturnStatement, WhileLoop, Argument
|
23
|
-
)
|
24
|
-
from ..ast.vex_nodes import (
|
25
|
-
DisplayOutput, MotorControl, SensorReading, TimingControl, VexAPICall
|
26
|
-
)
|
27
|
-
|
28
|
-
|
29
|
-
def generate_ast_schema() -> Dict[str, Any]:
|
30
|
-
"""
|
31
|
-
Generate a JSON Schema describing the AST node structure.
|
32
|
-
|
33
|
-
Returns:
|
34
|
-
A JSON Schema object as a dictionary
|
35
|
-
"""
|
36
|
-
schema = {
|
37
|
-
"$schema": "http://json-schema.org/draft-07/schema#",
|
38
|
-
"title": "VEX AST Schema",
|
39
|
-
"description": "JSON Schema for VEX AST nodes",
|
40
|
-
"type": "object",
|
41
|
-
"required": ["type"],
|
42
|
-
"properties": {
|
43
|
-
"type": {
|
44
|
-
"type": "string",
|
45
|
-
"description": "The type of AST node"
|
46
|
-
},
|
47
|
-
"location": {
|
48
|
-
"$ref": "#/definitions/SourceLocation"
|
49
|
-
}
|
50
|
-
},
|
51
|
-
"oneOf": [
|
52
|
-
{"$ref": f"#/definitions/{node_type}"}
|
53
|
-
for node_type in _get_all_node_types()
|
54
|
-
],
|
55
|
-
"definitions": _generate_definitions()
|
56
|
-
}
|
57
|
-
|
58
|
-
return schema
|
59
|
-
|
60
|
-
|
61
|
-
def _get_all_node_types() -> List[str]:
|
62
|
-
"""
|
63
|
-
Get a list of all AST node type names.
|
64
|
-
|
65
|
-
Returns:
|
66
|
-
A list of node type names
|
67
|
-
"""
|
68
|
-
# Core types
|
69
|
-
node_types = ["Program"]
|
70
|
-
|
71
|
-
# Expression types
|
72
|
-
node_types.extend([
|
73
|
-
"Identifier", "VariableReference", "AttributeAccess",
|
74
|
-
"BinaryOperation", "UnaryOperation", "ConditionalExpression",
|
75
|
-
"FunctionCall", "KeywordArgument"
|
76
|
-
])
|
77
|
-
|
78
|
-
# Literal types
|
79
|
-
node_types.extend([
|
80
|
-
"NumberLiteral", "StringLiteral", "BooleanLiteral", "NoneLiteral"
|
81
|
-
])
|
82
|
-
|
83
|
-
# Statement types
|
84
|
-
node_types.extend([
|
85
|
-
"ExpressionStatement", "Assignment", "IfStatement",
|
86
|
-
"WhileLoop", "ForLoop", "FunctionDefinition", "Argument",
|
87
|
-
"ReturnStatement", "BreakStatement", "ContinueStatement"
|
88
|
-
])
|
89
|
-
|
90
|
-
# VEX-specific types
|
91
|
-
node_types.extend([
|
92
|
-
"VexAPICall", "MotorControl", "SensorReading",
|
93
|
-
"TimingControl", "DisplayOutput"
|
94
|
-
])
|
95
|
-
|
96
|
-
return node_types
|
97
|
-
|
98
|
-
|
99
|
-
def _generate_definitions() -> Dict[str, Any]:
|
100
|
-
"""
|
101
|
-
Generate schema definitions for all AST node types.
|
102
|
-
|
103
|
-
Returns:
|
104
|
-
A dictionary of schema definitions
|
105
|
-
"""
|
106
|
-
definitions = {}
|
107
|
-
|
108
|
-
# Add SourceLocation definition
|
109
|
-
definitions["SourceLocation"] = {
|
110
|
-
"type": "object",
|
111
|
-
"required": ["line", "column"],
|
112
|
-
"properties": {
|
113
|
-
"line": {
|
114
|
-
"type": "integer",
|
115
|
-
"description": "The line number (1-based)"
|
116
|
-
},
|
117
|
-
"column": {
|
118
|
-
"type": "integer",
|
119
|
-
"description": "The column number (1-based)"
|
120
|
-
},
|
121
|
-
"end_line": {
|
122
|
-
"type": "integer",
|
123
|
-
"description": "The ending line number"
|
124
|
-
},
|
125
|
-
"end_column": {
|
126
|
-
"type": "integer",
|
127
|
-
"description": "The ending column number"
|
128
|
-
},
|
129
|
-
"filename": {
|
130
|
-
"type": "string",
|
131
|
-
"description": "The source filename"
|
132
|
-
}
|
133
|
-
}
|
134
|
-
}
|
135
|
-
|
136
|
-
# Add node type definitions
|
137
|
-
|
138
|
-
# Program
|
139
|
-
definitions["Program"] = {
|
140
|
-
"type": "object",
|
141
|
-
"required": ["type", "body"],
|
142
|
-
"properties": {
|
143
|
-
"type": {"enum": ["Program"]},
|
144
|
-
"body": {
|
145
|
-
"type": "array",
|
146
|
-
"description": "List of statements in the program",
|
147
|
-
"items": {"$ref": "#/definitions/Statement"}
|
148
|
-
},
|
149
|
-
"location": {"$ref": "#/definitions/SourceLocation"}
|
150
|
-
}
|
151
|
-
}
|
152
|
-
|
153
|
-
# Expression base
|
154
|
-
definitions["Expression"] = {
|
155
|
-
"type": "object",
|
156
|
-
"required": ["type"],
|
157
|
-
"properties": {
|
158
|
-
"type": {"type": "string"},
|
159
|
-
"location": {"$ref": "#/definitions/SourceLocation"}
|
160
|
-
},
|
161
|
-
"oneOf": [
|
162
|
-
{"$ref": f"#/definitions/{expr_type}"}
|
163
|
-
for expr_type in [
|
164
|
-
"Identifier", "VariableReference", "AttributeAccess",
|
165
|
-
"BinaryOperation", "UnaryOperation", "ConditionalExpression",
|
166
|
-
"FunctionCall", "NumberLiteral", "StringLiteral",
|
167
|
-
"BooleanLiteral", "NoneLiteral"
|
168
|
-
]
|
169
|
-
]
|
170
|
-
}
|
171
|
-
|
172
|
-
# Statement base
|
173
|
-
definitions["Statement"] = {
|
174
|
-
"type": "object",
|
175
|
-
"required": ["type"],
|
176
|
-
"properties": {
|
177
|
-
"type": {"type": "string"},
|
178
|
-
"location": {"$ref": "#/definitions/SourceLocation"}
|
179
|
-
},
|
180
|
-
"oneOf": [
|
181
|
-
{"$ref": f"#/definitions/{stmt_type}"}
|
182
|
-
for stmt_type in [
|
183
|
-
"ExpressionStatement", "Assignment", "IfStatement",
|
184
|
-
"WhileLoop", "ForLoop", "FunctionDefinition",
|
185
|
-
"ReturnStatement", "BreakStatement", "ContinueStatement"
|
186
|
-
]
|
187
|
-
]
|
188
|
-
}
|
189
|
-
|
190
|
-
# Literals
|
191
|
-
definitions["NumberLiteral"] = {
|
192
|
-
"type": "object",
|
193
|
-
"required": ["type", "value"],
|
194
|
-
"properties": {
|
195
|
-
"type": {"enum": ["NumberLiteral"]},
|
196
|
-
"value": {
|
197
|
-
"oneOf": [
|
198
|
-
{"type": "number"},
|
199
|
-
{"type": "integer"}
|
200
|
-
],
|
201
|
-
"description": "The numeric value"
|
202
|
-
},
|
203
|
-
"location": {"$ref": "#/definitions/SourceLocation"}
|
204
|
-
}
|
205
|
-
}
|
206
|
-
|
207
|
-
definitions["StringLiteral"] = {
|
208
|
-
"type": "object",
|
209
|
-
"required": ["type", "value"],
|
210
|
-
"properties": {
|
211
|
-
"type": {"enum": ["StringLiteral"]},
|
212
|
-
"value": {
|
213
|
-
"type": "string",
|
214
|
-
"description": "The string value"
|
215
|
-
},
|
216
|
-
"location": {"$ref": "#/definitions/SourceLocation"}
|
217
|
-
}
|
218
|
-
}
|
219
|
-
|
220
|
-
definitions["BooleanLiteral"] = {
|
221
|
-
"type": "object",
|
222
|
-
"required": ["type", "value"],
|
223
|
-
"properties": {
|
224
|
-
"type": {"enum": ["BooleanLiteral"]},
|
225
|
-
"value": {
|
226
|
-
"type": "boolean",
|
227
|
-
"description": "The boolean value"
|
228
|
-
},
|
229
|
-
"location": {"$ref": "#/definitions/SourceLocation"}
|
230
|
-
}
|
231
|
-
}
|
232
|
-
|
233
|
-
definitions["NoneLiteral"] = {
|
234
|
-
"type": "object",
|
235
|
-
"required": ["type"],
|
236
|
-
"properties": {
|
237
|
-
"type": {"enum": ["NoneLiteral"]},
|
238
|
-
"location": {"$ref": "#/definitions/SourceLocation"}
|
239
|
-
}
|
240
|
-
}
|
241
|
-
|
242
|
-
# Expressions
|
243
|
-
definitions["Identifier"] = {
|
244
|
-
"type": "object",
|
245
|
-
"required": ["type", "name"],
|
246
|
-
"properties": {
|
247
|
-
"type": {"enum": ["Identifier"]},
|
248
|
-
"name": {
|
249
|
-
"type": "string",
|
250
|
-
"description": "The identifier name"
|
251
|
-
},
|
252
|
-
"location": {"$ref": "#/definitions/SourceLocation"}
|
253
|
-
}
|
254
|
-
}
|
255
|
-
|
256
|
-
definitions["VariableReference"] = {
|
257
|
-
"type": "object",
|
258
|
-
"required": ["type", "identifier"],
|
259
|
-
"properties": {
|
260
|
-
"type": {"enum": ["VariableReference"]},
|
261
|
-
"identifier": {
|
262
|
-
"$ref": "#/definitions/Identifier",
|
263
|
-
"description": "The referenced identifier"
|
264
|
-
},
|
265
|
-
"location": {"$ref": "#/definitions/SourceLocation"}
|
266
|
-
}
|
267
|
-
}
|
268
|
-
|
269
|
-
definitions["AttributeAccess"] = {
|
270
|
-
"type": "object",
|
271
|
-
"required": ["type", "object", "attribute"],
|
272
|
-
"properties": {
|
273
|
-
"type": {"enum": ["AttributeAccess"]},
|
274
|
-
"object": {
|
275
|
-
"$ref": "#/definitions/Expression",
|
276
|
-
"description": "The object expression"
|
277
|
-
},
|
278
|
-
"attribute": {
|
279
|
-
"type": "string",
|
280
|
-
"description": "The attribute name"
|
281
|
-
},
|
282
|
-
"location": {"$ref": "#/definitions/SourceLocation"}
|
283
|
-
}
|
284
|
-
}
|
285
|
-
|
286
|
-
definitions["BinaryOperation"] = {
|
287
|
-
"type": "object",
|
288
|
-
"required": ["type", "left", "op", "right"],
|
289
|
-
"properties": {
|
290
|
-
"type": {"enum": ["BinaryOperation"]},
|
291
|
-
"left": {
|
292
|
-
"$ref": "#/definitions/Expression",
|
293
|
-
"description": "The left operand"
|
294
|
-
},
|
295
|
-
"op": {
|
296
|
-
"type": "string",
|
297
|
-
"description": "The operator"
|
298
|
-
},
|
299
|
-
"right": {
|
300
|
-
"$ref": "#/definitions/Expression",
|
301
|
-
"description": "The right operand"
|
302
|
-
},
|
303
|
-
"location": {"$ref": "#/definitions/SourceLocation"}
|
304
|
-
}
|
305
|
-
}
|
306
|
-
|
307
|
-
definitions["UnaryOperation"] = {
|
308
|
-
"type": "object",
|
309
|
-
"required": ["type", "op", "operand"],
|
310
|
-
"properties": {
|
311
|
-
"type": {"enum": ["UnaryOperation"]},
|
312
|
-
"op": {
|
313
|
-
"type": "string",
|
314
|
-
"description": "The operator"
|
315
|
-
},
|
316
|
-
"operand": {
|
317
|
-
"$ref": "#/definitions/Expression",
|
318
|
-
"description": "The operand"
|
319
|
-
},
|
320
|
-
"location": {"$ref": "#/definitions/SourceLocation"}
|
321
|
-
}
|
322
|
-
}
|
323
|
-
|
324
|
-
definitions["FunctionCall"] = {
|
325
|
-
"type": "object",
|
326
|
-
"required": ["type", "function", "args"],
|
327
|
-
"properties": {
|
328
|
-
"type": {"enum": ["FunctionCall"]},
|
329
|
-
"function": {
|
330
|
-
"$ref": "#/definitions/Expression",
|
331
|
-
"description": "The function expression"
|
332
|
-
},
|
333
|
-
"args": {
|
334
|
-
"type": "array",
|
335
|
-
"description": "The positional arguments",
|
336
|
-
"items": {"$ref": "#/definitions/Expression"}
|
337
|
-
},
|
338
|
-
"keywords": {
|
339
|
-
"type": "array",
|
340
|
-
"description": "The keyword arguments",
|
341
|
-
"items": {"$ref": "#/definitions/KeywordArgument"}
|
342
|
-
},
|
343
|
-
"location": {"$ref": "#/definitions/SourceLocation"}
|
344
|
-
}
|
345
|
-
}
|
346
|
-
|
347
|
-
definitions["KeywordArgument"] = {
|
348
|
-
"type": "object",
|
349
|
-
"required": ["type", "name", "value"],
|
350
|
-
"properties": {
|
351
|
-
"type": {"enum": ["KeywordArgument"]},
|
352
|
-
"name": {
|
353
|
-
"type": "string",
|
354
|
-
"description": "The argument name"
|
355
|
-
},
|
356
|
-
"value": {
|
357
|
-
"$ref": "#/definitions/Expression",
|
358
|
-
"description": "The argument value"
|
359
|
-
},
|
360
|
-
"location": {"$ref": "#/definitions/SourceLocation"}
|
361
|
-
}
|
362
|
-
}
|
363
|
-
|
364
|
-
definitions["ConditionalExpression"] = {
|
365
|
-
"type": "object",
|
366
|
-
"required": ["type", "condition", "true_expr", "false_expr"],
|
367
|
-
"properties": {
|
368
|
-
"type": {"enum": ["ConditionalExpression"]},
|
369
|
-
"condition": {
|
370
|
-
"$ref": "#/definitions/Expression",
|
371
|
-
"description": "The condition expression"
|
372
|
-
},
|
373
|
-
"true_expr": {
|
374
|
-
"$ref": "#/definitions/Expression",
|
375
|
-
"description": "The expression to evaluate if condition is true"
|
376
|
-
},
|
377
|
-
"false_expr": {
|
378
|
-
"$ref": "#/definitions/Expression",
|
379
|
-
"description": "The expression to evaluate if condition is false"
|
380
|
-
},
|
381
|
-
"location": {"$ref": "#/definitions/SourceLocation"}
|
382
|
-
}
|
383
|
-
}
|
384
|
-
|
385
|
-
# Statements
|
386
|
-
definitions["ExpressionStatement"] = {
|
387
|
-
"type": "object",
|
388
|
-
"required": ["type", "expression"],
|
389
|
-
"properties": {
|
390
|
-
"type": {"enum": ["ExpressionStatement"]},
|
391
|
-
"expression": {
|
392
|
-
"$ref": "#/definitions/Expression",
|
393
|
-
"description": "The expression"
|
394
|
-
},
|
395
|
-
"location": {"$ref": "#/definitions/SourceLocation"}
|
396
|
-
}
|
397
|
-
}
|
398
|
-
|
399
|
-
definitions["Assignment"] = {
|
400
|
-
"type": "object",
|
401
|
-
"required": ["type", "target", "value"],
|
402
|
-
"properties": {
|
403
|
-
"type": {"enum": ["Assignment"]},
|
404
|
-
"target": {
|
405
|
-
"$ref": "#/definitions/Expression",
|
406
|
-
"description": "The assignment target"
|
407
|
-
},
|
408
|
-
"value": {
|
409
|
-
"$ref": "#/definitions/Expression",
|
410
|
-
"description": "The assigned value"
|
411
|
-
},
|
412
|
-
"location": {"$ref": "#/definitions/SourceLocation"}
|
413
|
-
}
|
414
|
-
}
|
415
|
-
|
416
|
-
definitions["IfStatement"] = {
|
417
|
-
"type": "object",
|
418
|
-
"required": ["type", "test", "body"],
|
419
|
-
"properties": {
|
420
|
-
"type": {"enum": ["IfStatement"]},
|
421
|
-
"test": {
|
422
|
-
"$ref": "#/definitions/Expression",
|
423
|
-
"description": "The condition expression"
|
424
|
-
},
|
425
|
-
"body": {
|
426
|
-
"type": "array",
|
427
|
-
"description": "The if-body statements",
|
428
|
-
"items": {"$ref": "#/definitions/Statement"}
|
429
|
-
},
|
430
|
-
"orelse": {
|
431
|
-
"oneOf": [
|
432
|
-
{
|
433
|
-
"type": "array",
|
434
|
-
"description": "The else-body statements",
|
435
|
-
"items": {"$ref": "#/definitions/Statement"}
|
436
|
-
},
|
437
|
-
{
|
438
|
-
"$ref": "#/definitions/IfStatement",
|
439
|
-
"description": "An elif statement"
|
440
|
-
}
|
441
|
-
]
|
442
|
-
},
|
443
|
-
"location": {"$ref": "#/definitions/SourceLocation"}
|
444
|
-
}
|
445
|
-
}
|
446
|
-
|
447
|
-
# Add more definitions for other node types...
|
448
|
-
|
449
|
-
# VEX-specific nodes
|
450
|
-
definitions["VexAPICall"] = {
|
451
|
-
"type": "object",
|
452
|
-
"required": ["type", "function", "args"],
|
453
|
-
"properties": {
|
454
|
-
"type": {"enum": ["VexAPICall"]},
|
455
|
-
"function": {
|
456
|
-
"$ref": "#/definitions/Expression",
|
457
|
-
"description": "The function expression"
|
458
|
-
},
|
459
|
-
"args": {
|
460
|
-
"type": "array",
|
461
|
-
"description": "The positional arguments",
|
462
|
-
"items": {"$ref": "#/definitions/Expression"}
|
463
|
-
},
|
464
|
-
"keywords": {
|
465
|
-
"type": "array",
|
466
|
-
"description": "The keyword arguments",
|
467
|
-
"items": {"$ref": "#/definitions/KeywordArgument"}
|
468
|
-
},
|
469
|
-
"location": {"$ref": "#/definitions/SourceLocation"}
|
470
|
-
}
|
471
|
-
}
|
472
|
-
|
473
|
-
# Add more VEX-specific node definitions...
|
474
|
-
|
475
|
-
return definitions
|
476
|
-
|
477
|
-
|
478
|
-
def export_schema_to_file(schema: Dict[str, Any], filepath: str, indent: int = 2) -> None:
|
479
|
-
"""
|
480
|
-
Save the schema to a file.
|
481
|
-
|
482
|
-
Args:
|
483
|
-
schema: The schema to save
|
484
|
-
filepath: The path to save the schema to
|
485
|
-
indent: The indentation level for pretty-printing
|
486
|
-
"""
|
487
|
-
# Ensure the directory exists
|
488
|
-
os.makedirs(os.path.dirname(os.path.abspath(filepath)), exist_ok=True)
|
489
|
-
|
490
|
-
# Write the schema to the file
|
491
|
-
with open(filepath, 'w') as f:
|
492
|
-
json.dump(schema, f, indent=indent)
|
1
|
+
"""
|
2
|
+
JSON Schema generation for AST nodes.
|
3
|
+
|
4
|
+
This module provides functionality to generate JSON Schema definitions
|
5
|
+
for the AST structure, which can be used for validation and documentation.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import json
|
9
|
+
import os
|
10
|
+
from typing import Any, Dict, List, Optional, Set, Type
|
11
|
+
|
12
|
+
from ..ast.core import Program, Expression, Statement
|
13
|
+
from ..ast.expressions import (
|
14
|
+
AttributeAccess, BinaryOperation, ConditionalExpression, FunctionCall, Identifier, KeywordArgument,
|
15
|
+
UnaryOperation, VariableReference
|
16
|
+
)
|
17
|
+
from ..ast.literals import (
|
18
|
+
BooleanLiteral, NoneLiteral, NumberLiteral, StringLiteral
|
19
|
+
)
|
20
|
+
from ..ast.statements import (
|
21
|
+
Assignment, BreakStatement, ContinueStatement, ExpressionStatement,
|
22
|
+
ForLoop, FunctionDefinition, IfStatement, ReturnStatement, WhileLoop, Argument
|
23
|
+
)
|
24
|
+
from ..ast.vex_nodes import (
|
25
|
+
DisplayOutput, MotorControl, SensorReading, TimingControl, VexAPICall
|
26
|
+
)
|
27
|
+
|
28
|
+
|
29
|
+
def generate_ast_schema() -> Dict[str, Any]:
|
30
|
+
"""
|
31
|
+
Generate a JSON Schema describing the AST node structure.
|
32
|
+
|
33
|
+
Returns:
|
34
|
+
A JSON Schema object as a dictionary
|
35
|
+
"""
|
36
|
+
schema = {
|
37
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
38
|
+
"title": "VEX AST Schema",
|
39
|
+
"description": "JSON Schema for VEX AST nodes",
|
40
|
+
"type": "object",
|
41
|
+
"required": ["type"],
|
42
|
+
"properties": {
|
43
|
+
"type": {
|
44
|
+
"type": "string",
|
45
|
+
"description": "The type of AST node"
|
46
|
+
},
|
47
|
+
"location": {
|
48
|
+
"$ref": "#/definitions/SourceLocation"
|
49
|
+
}
|
50
|
+
},
|
51
|
+
"oneOf": [
|
52
|
+
{"$ref": f"#/definitions/{node_type}"}
|
53
|
+
for node_type in _get_all_node_types()
|
54
|
+
],
|
55
|
+
"definitions": _generate_definitions()
|
56
|
+
}
|
57
|
+
|
58
|
+
return schema
|
59
|
+
|
60
|
+
|
61
|
+
def _get_all_node_types() -> List[str]:
|
62
|
+
"""
|
63
|
+
Get a list of all AST node type names.
|
64
|
+
|
65
|
+
Returns:
|
66
|
+
A list of node type names
|
67
|
+
"""
|
68
|
+
# Core types
|
69
|
+
node_types = ["Program"]
|
70
|
+
|
71
|
+
# Expression types
|
72
|
+
node_types.extend([
|
73
|
+
"Identifier", "VariableReference", "AttributeAccess",
|
74
|
+
"BinaryOperation", "UnaryOperation", "ConditionalExpression",
|
75
|
+
"FunctionCall", "KeywordArgument"
|
76
|
+
])
|
77
|
+
|
78
|
+
# Literal types
|
79
|
+
node_types.extend([
|
80
|
+
"NumberLiteral", "StringLiteral", "BooleanLiteral", "NoneLiteral"
|
81
|
+
])
|
82
|
+
|
83
|
+
# Statement types
|
84
|
+
node_types.extend([
|
85
|
+
"ExpressionStatement", "Assignment", "IfStatement",
|
86
|
+
"WhileLoop", "ForLoop", "FunctionDefinition", "Argument",
|
87
|
+
"ReturnStatement", "BreakStatement", "ContinueStatement"
|
88
|
+
])
|
89
|
+
|
90
|
+
# VEX-specific types
|
91
|
+
node_types.extend([
|
92
|
+
"VexAPICall", "MotorControl", "SensorReading",
|
93
|
+
"TimingControl", "DisplayOutput"
|
94
|
+
])
|
95
|
+
|
96
|
+
return node_types
|
97
|
+
|
98
|
+
|
99
|
+
def _generate_definitions() -> Dict[str, Any]:
|
100
|
+
"""
|
101
|
+
Generate schema definitions for all AST node types.
|
102
|
+
|
103
|
+
Returns:
|
104
|
+
A dictionary of schema definitions
|
105
|
+
"""
|
106
|
+
definitions = {}
|
107
|
+
|
108
|
+
# Add SourceLocation definition
|
109
|
+
definitions["SourceLocation"] = {
|
110
|
+
"type": "object",
|
111
|
+
"required": ["line", "column"],
|
112
|
+
"properties": {
|
113
|
+
"line": {
|
114
|
+
"type": "integer",
|
115
|
+
"description": "The line number (1-based)"
|
116
|
+
},
|
117
|
+
"column": {
|
118
|
+
"type": "integer",
|
119
|
+
"description": "The column number (1-based)"
|
120
|
+
},
|
121
|
+
"end_line": {
|
122
|
+
"type": "integer",
|
123
|
+
"description": "The ending line number"
|
124
|
+
},
|
125
|
+
"end_column": {
|
126
|
+
"type": "integer",
|
127
|
+
"description": "The ending column number"
|
128
|
+
},
|
129
|
+
"filename": {
|
130
|
+
"type": "string",
|
131
|
+
"description": "The source filename"
|
132
|
+
}
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
# Add node type definitions
|
137
|
+
|
138
|
+
# Program
|
139
|
+
definitions["Program"] = {
|
140
|
+
"type": "object",
|
141
|
+
"required": ["type", "body"],
|
142
|
+
"properties": {
|
143
|
+
"type": {"enum": ["Program"]},
|
144
|
+
"body": {
|
145
|
+
"type": "array",
|
146
|
+
"description": "List of statements in the program",
|
147
|
+
"items": {"$ref": "#/definitions/Statement"}
|
148
|
+
},
|
149
|
+
"location": {"$ref": "#/definitions/SourceLocation"}
|
150
|
+
}
|
151
|
+
}
|
152
|
+
|
153
|
+
# Expression base
|
154
|
+
definitions["Expression"] = {
|
155
|
+
"type": "object",
|
156
|
+
"required": ["type"],
|
157
|
+
"properties": {
|
158
|
+
"type": {"type": "string"},
|
159
|
+
"location": {"$ref": "#/definitions/SourceLocation"}
|
160
|
+
},
|
161
|
+
"oneOf": [
|
162
|
+
{"$ref": f"#/definitions/{expr_type}"}
|
163
|
+
for expr_type in [
|
164
|
+
"Identifier", "VariableReference", "AttributeAccess",
|
165
|
+
"BinaryOperation", "UnaryOperation", "ConditionalExpression",
|
166
|
+
"FunctionCall", "NumberLiteral", "StringLiteral",
|
167
|
+
"BooleanLiteral", "NoneLiteral"
|
168
|
+
]
|
169
|
+
]
|
170
|
+
}
|
171
|
+
|
172
|
+
# Statement base
|
173
|
+
definitions["Statement"] = {
|
174
|
+
"type": "object",
|
175
|
+
"required": ["type"],
|
176
|
+
"properties": {
|
177
|
+
"type": {"type": "string"},
|
178
|
+
"location": {"$ref": "#/definitions/SourceLocation"}
|
179
|
+
},
|
180
|
+
"oneOf": [
|
181
|
+
{"$ref": f"#/definitions/{stmt_type}"}
|
182
|
+
for stmt_type in [
|
183
|
+
"ExpressionStatement", "Assignment", "IfStatement",
|
184
|
+
"WhileLoop", "ForLoop", "FunctionDefinition",
|
185
|
+
"ReturnStatement", "BreakStatement", "ContinueStatement"
|
186
|
+
]
|
187
|
+
]
|
188
|
+
}
|
189
|
+
|
190
|
+
# Literals
|
191
|
+
definitions["NumberLiteral"] = {
|
192
|
+
"type": "object",
|
193
|
+
"required": ["type", "value"],
|
194
|
+
"properties": {
|
195
|
+
"type": {"enum": ["NumberLiteral"]},
|
196
|
+
"value": {
|
197
|
+
"oneOf": [
|
198
|
+
{"type": "number"},
|
199
|
+
{"type": "integer"}
|
200
|
+
],
|
201
|
+
"description": "The numeric value"
|
202
|
+
},
|
203
|
+
"location": {"$ref": "#/definitions/SourceLocation"}
|
204
|
+
}
|
205
|
+
}
|
206
|
+
|
207
|
+
definitions["StringLiteral"] = {
|
208
|
+
"type": "object",
|
209
|
+
"required": ["type", "value"],
|
210
|
+
"properties": {
|
211
|
+
"type": {"enum": ["StringLiteral"]},
|
212
|
+
"value": {
|
213
|
+
"type": "string",
|
214
|
+
"description": "The string value"
|
215
|
+
},
|
216
|
+
"location": {"$ref": "#/definitions/SourceLocation"}
|
217
|
+
}
|
218
|
+
}
|
219
|
+
|
220
|
+
definitions["BooleanLiteral"] = {
|
221
|
+
"type": "object",
|
222
|
+
"required": ["type", "value"],
|
223
|
+
"properties": {
|
224
|
+
"type": {"enum": ["BooleanLiteral"]},
|
225
|
+
"value": {
|
226
|
+
"type": "boolean",
|
227
|
+
"description": "The boolean value"
|
228
|
+
},
|
229
|
+
"location": {"$ref": "#/definitions/SourceLocation"}
|
230
|
+
}
|
231
|
+
}
|
232
|
+
|
233
|
+
definitions["NoneLiteral"] = {
|
234
|
+
"type": "object",
|
235
|
+
"required": ["type"],
|
236
|
+
"properties": {
|
237
|
+
"type": {"enum": ["NoneLiteral"]},
|
238
|
+
"location": {"$ref": "#/definitions/SourceLocation"}
|
239
|
+
}
|
240
|
+
}
|
241
|
+
|
242
|
+
# Expressions
|
243
|
+
definitions["Identifier"] = {
|
244
|
+
"type": "object",
|
245
|
+
"required": ["type", "name"],
|
246
|
+
"properties": {
|
247
|
+
"type": {"enum": ["Identifier"]},
|
248
|
+
"name": {
|
249
|
+
"type": "string",
|
250
|
+
"description": "The identifier name"
|
251
|
+
},
|
252
|
+
"location": {"$ref": "#/definitions/SourceLocation"}
|
253
|
+
}
|
254
|
+
}
|
255
|
+
|
256
|
+
definitions["VariableReference"] = {
|
257
|
+
"type": "object",
|
258
|
+
"required": ["type", "identifier"],
|
259
|
+
"properties": {
|
260
|
+
"type": {"enum": ["VariableReference"]},
|
261
|
+
"identifier": {
|
262
|
+
"$ref": "#/definitions/Identifier",
|
263
|
+
"description": "The referenced identifier"
|
264
|
+
},
|
265
|
+
"location": {"$ref": "#/definitions/SourceLocation"}
|
266
|
+
}
|
267
|
+
}
|
268
|
+
|
269
|
+
definitions["AttributeAccess"] = {
|
270
|
+
"type": "object",
|
271
|
+
"required": ["type", "object", "attribute"],
|
272
|
+
"properties": {
|
273
|
+
"type": {"enum": ["AttributeAccess"]},
|
274
|
+
"object": {
|
275
|
+
"$ref": "#/definitions/Expression",
|
276
|
+
"description": "The object expression"
|
277
|
+
},
|
278
|
+
"attribute": {
|
279
|
+
"type": "string",
|
280
|
+
"description": "The attribute name"
|
281
|
+
},
|
282
|
+
"location": {"$ref": "#/definitions/SourceLocation"}
|
283
|
+
}
|
284
|
+
}
|
285
|
+
|
286
|
+
definitions["BinaryOperation"] = {
|
287
|
+
"type": "object",
|
288
|
+
"required": ["type", "left", "op", "right"],
|
289
|
+
"properties": {
|
290
|
+
"type": {"enum": ["BinaryOperation"]},
|
291
|
+
"left": {
|
292
|
+
"$ref": "#/definitions/Expression",
|
293
|
+
"description": "The left operand"
|
294
|
+
},
|
295
|
+
"op": {
|
296
|
+
"type": "string",
|
297
|
+
"description": "The operator"
|
298
|
+
},
|
299
|
+
"right": {
|
300
|
+
"$ref": "#/definitions/Expression",
|
301
|
+
"description": "The right operand"
|
302
|
+
},
|
303
|
+
"location": {"$ref": "#/definitions/SourceLocation"}
|
304
|
+
}
|
305
|
+
}
|
306
|
+
|
307
|
+
definitions["UnaryOperation"] = {
|
308
|
+
"type": "object",
|
309
|
+
"required": ["type", "op", "operand"],
|
310
|
+
"properties": {
|
311
|
+
"type": {"enum": ["UnaryOperation"]},
|
312
|
+
"op": {
|
313
|
+
"type": "string",
|
314
|
+
"description": "The operator"
|
315
|
+
},
|
316
|
+
"operand": {
|
317
|
+
"$ref": "#/definitions/Expression",
|
318
|
+
"description": "The operand"
|
319
|
+
},
|
320
|
+
"location": {"$ref": "#/definitions/SourceLocation"}
|
321
|
+
}
|
322
|
+
}
|
323
|
+
|
324
|
+
definitions["FunctionCall"] = {
|
325
|
+
"type": "object",
|
326
|
+
"required": ["type", "function", "args"],
|
327
|
+
"properties": {
|
328
|
+
"type": {"enum": ["FunctionCall"]},
|
329
|
+
"function": {
|
330
|
+
"$ref": "#/definitions/Expression",
|
331
|
+
"description": "The function expression"
|
332
|
+
},
|
333
|
+
"args": {
|
334
|
+
"type": "array",
|
335
|
+
"description": "The positional arguments",
|
336
|
+
"items": {"$ref": "#/definitions/Expression"}
|
337
|
+
},
|
338
|
+
"keywords": {
|
339
|
+
"type": "array",
|
340
|
+
"description": "The keyword arguments",
|
341
|
+
"items": {"$ref": "#/definitions/KeywordArgument"}
|
342
|
+
},
|
343
|
+
"location": {"$ref": "#/definitions/SourceLocation"}
|
344
|
+
}
|
345
|
+
}
|
346
|
+
|
347
|
+
definitions["KeywordArgument"] = {
|
348
|
+
"type": "object",
|
349
|
+
"required": ["type", "name", "value"],
|
350
|
+
"properties": {
|
351
|
+
"type": {"enum": ["KeywordArgument"]},
|
352
|
+
"name": {
|
353
|
+
"type": "string",
|
354
|
+
"description": "The argument name"
|
355
|
+
},
|
356
|
+
"value": {
|
357
|
+
"$ref": "#/definitions/Expression",
|
358
|
+
"description": "The argument value"
|
359
|
+
},
|
360
|
+
"location": {"$ref": "#/definitions/SourceLocation"}
|
361
|
+
}
|
362
|
+
}
|
363
|
+
|
364
|
+
definitions["ConditionalExpression"] = {
|
365
|
+
"type": "object",
|
366
|
+
"required": ["type", "condition", "true_expr", "false_expr"],
|
367
|
+
"properties": {
|
368
|
+
"type": {"enum": ["ConditionalExpression"]},
|
369
|
+
"condition": {
|
370
|
+
"$ref": "#/definitions/Expression",
|
371
|
+
"description": "The condition expression"
|
372
|
+
},
|
373
|
+
"true_expr": {
|
374
|
+
"$ref": "#/definitions/Expression",
|
375
|
+
"description": "The expression to evaluate if condition is true"
|
376
|
+
},
|
377
|
+
"false_expr": {
|
378
|
+
"$ref": "#/definitions/Expression",
|
379
|
+
"description": "The expression to evaluate if condition is false"
|
380
|
+
},
|
381
|
+
"location": {"$ref": "#/definitions/SourceLocation"}
|
382
|
+
}
|
383
|
+
}
|
384
|
+
|
385
|
+
# Statements
|
386
|
+
definitions["ExpressionStatement"] = {
|
387
|
+
"type": "object",
|
388
|
+
"required": ["type", "expression"],
|
389
|
+
"properties": {
|
390
|
+
"type": {"enum": ["ExpressionStatement"]},
|
391
|
+
"expression": {
|
392
|
+
"$ref": "#/definitions/Expression",
|
393
|
+
"description": "The expression"
|
394
|
+
},
|
395
|
+
"location": {"$ref": "#/definitions/SourceLocation"}
|
396
|
+
}
|
397
|
+
}
|
398
|
+
|
399
|
+
definitions["Assignment"] = {
|
400
|
+
"type": "object",
|
401
|
+
"required": ["type", "target", "value"],
|
402
|
+
"properties": {
|
403
|
+
"type": {"enum": ["Assignment"]},
|
404
|
+
"target": {
|
405
|
+
"$ref": "#/definitions/Expression",
|
406
|
+
"description": "The assignment target"
|
407
|
+
},
|
408
|
+
"value": {
|
409
|
+
"$ref": "#/definitions/Expression",
|
410
|
+
"description": "The assigned value"
|
411
|
+
},
|
412
|
+
"location": {"$ref": "#/definitions/SourceLocation"}
|
413
|
+
}
|
414
|
+
}
|
415
|
+
|
416
|
+
definitions["IfStatement"] = {
|
417
|
+
"type": "object",
|
418
|
+
"required": ["type", "test", "body"],
|
419
|
+
"properties": {
|
420
|
+
"type": {"enum": ["IfStatement"]},
|
421
|
+
"test": {
|
422
|
+
"$ref": "#/definitions/Expression",
|
423
|
+
"description": "The condition expression"
|
424
|
+
},
|
425
|
+
"body": {
|
426
|
+
"type": "array",
|
427
|
+
"description": "The if-body statements",
|
428
|
+
"items": {"$ref": "#/definitions/Statement"}
|
429
|
+
},
|
430
|
+
"orelse": {
|
431
|
+
"oneOf": [
|
432
|
+
{
|
433
|
+
"type": "array",
|
434
|
+
"description": "The else-body statements",
|
435
|
+
"items": {"$ref": "#/definitions/Statement"}
|
436
|
+
},
|
437
|
+
{
|
438
|
+
"$ref": "#/definitions/IfStatement",
|
439
|
+
"description": "An elif statement"
|
440
|
+
}
|
441
|
+
]
|
442
|
+
},
|
443
|
+
"location": {"$ref": "#/definitions/SourceLocation"}
|
444
|
+
}
|
445
|
+
}
|
446
|
+
|
447
|
+
# Add more definitions for other node types...
|
448
|
+
|
449
|
+
# VEX-specific nodes
|
450
|
+
definitions["VexAPICall"] = {
|
451
|
+
"type": "object",
|
452
|
+
"required": ["type", "function", "args"],
|
453
|
+
"properties": {
|
454
|
+
"type": {"enum": ["VexAPICall"]},
|
455
|
+
"function": {
|
456
|
+
"$ref": "#/definitions/Expression",
|
457
|
+
"description": "The function expression"
|
458
|
+
},
|
459
|
+
"args": {
|
460
|
+
"type": "array",
|
461
|
+
"description": "The positional arguments",
|
462
|
+
"items": {"$ref": "#/definitions/Expression"}
|
463
|
+
},
|
464
|
+
"keywords": {
|
465
|
+
"type": "array",
|
466
|
+
"description": "The keyword arguments",
|
467
|
+
"items": {"$ref": "#/definitions/KeywordArgument"}
|
468
|
+
},
|
469
|
+
"location": {"$ref": "#/definitions/SourceLocation"}
|
470
|
+
}
|
471
|
+
}
|
472
|
+
|
473
|
+
# Add more VEX-specific node definitions...
|
474
|
+
|
475
|
+
return definitions
|
476
|
+
|
477
|
+
|
478
|
+
def export_schema_to_file(schema: Dict[str, Any], filepath: str, indent: int = 2) -> None:
|
479
|
+
"""
|
480
|
+
Save the schema to a file.
|
481
|
+
|
482
|
+
Args:
|
483
|
+
schema: The schema to save
|
484
|
+
filepath: The path to save the schema to
|
485
|
+
indent: The indentation level for pretty-printing
|
486
|
+
"""
|
487
|
+
# Ensure the directory exists
|
488
|
+
os.makedirs(os.path.dirname(os.path.abspath(filepath)), exist_ok=True)
|
489
|
+
|
490
|
+
# Write the schema to the file
|
491
|
+
with open(filepath, 'w') as f:
|
492
|
+
json.dump(schema, f, indent=indent)
|