Files
endorphin-aster-vm/scripts/test_generate_ast.py
codex-bot f5268d2e09
Verify databases and deploy Aster VM / verify-and-deploy (push) Successful in 7m55s
feat: generate unified AST and editor contracts from ASDL
2026-10-19 14:31:28 +08:00

58 lines
2.7 KiB
Python

"""Generator regression checks for the designated remote validation environment."""
from pathlib import Path
import json
import re
import unittest
from generate_ast import generate, parse_schema, recursive_edges
SCHEMA = (Path(__file__).resolve().parents[1] / "crates/frontend/Endor.asdl").read_text(encoding="utf-8")
class AstGenerationTests(unittest.TestCase):
def test_editor_walkers_only_call_declared_functions(self):
editor = generate(SCHEMA)["crates/frontend/editor/ast.ts"]
declared = set(re.findall(r"export function (walk\w+)\(", editor))
calls = set(re.findall(r"\b(walk\w+)\(", editor))
self.assertLessEqual(calls, declared)
self.assertIn("walkSpan(node.span, visitor)", editor)
def test_schema_changes_reach_all_languages_and_schema_identity(self):
before = generate(SCHEMA)
after = generate(SCHEMA.replace("UnaryOp = Negate", "UnaryOp = Negate | LogicalNot"))
self.assertIn("LogicalNot", after["crates/frontend/src/ast/generated.rs"])
self.assertIn('"LogicalNot"', after["crates/frontend/editor/ast.ts"])
editor_schema = json.loads(after["crates/frontend/editor/ast.schema.json"])
self.assertIn("LogicalNot", editor_schema["$defs"]["UnaryOp"]["enum"])
self.assertNotEqual(before["crates/frontend/src/ast/generated.rs"], after["crates/frontend/src/ast/generated.rs"])
self.assertEqual(after, generate(SCHEMA.replace("UnaryOp = Negate", "UnaryOp = Negate | LogicalNot")))
def test_recursive_optional_nodes_are_boxed_and_walked(self):
extended = SCHEMA.rsplit("}", 1)[0] + "Link = (Link? next)\n}"
outputs = generate(extended)
self.assertIn("pub next: Option<Box<Link>>", outputs["crates/frontend/src/ast/generated.rs"])
self.assertIn("visitor.visit_link(value)?", outputs["crates/frontend/src/ast/visitor.rs"])
self.assertIn("next?: Link | null", outputs["crates/frontend/editor/ast.ts"])
definitions = parse_schema(SCHEMA)
self.assertIn(("ExprKind", "Expr"), recursive_edges(definitions))
self.assertNotIn(("Expr", "ExprKind"), recursive_edges(definitions))
def test_invalid_schemas_fail_instead_of_emitting_partial_types(self):
for schema in [
"module Endor { Root = (Missing value) }",
"module Endor { Root = (string x, string x) }",
"module Endor { Root = A | A }",
"module Endor { Root = A Root = B }",
"module Endor { Root = (string value",
"module Endor { Root = A } trailing",
"module Endor { Root = @ }",
]:
with self.subTest(schema=schema), self.assertRaises(ValueError):
parse_schema(schema)
if __name__ == "__main__":
unittest.main()