67 lines
2.3 KiB
Python
67 lines
2.3 KiB
Python
#!/usr/bin/env python3
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
HELPER = ROOT / "support" / "lsp" / "claro_lsp_stub.py"
|
|
EXE = ROOT / ("claro.exe" if os.name == "nt" else "claro")
|
|
|
|
|
|
def fail(message):
|
|
raise SystemExit(message)
|
|
|
|
|
|
def run_helper(*args):
|
|
result = subprocess.run([sys.executable, str(HELPER), *args], cwd=ROOT, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
if result.returncode != 0:
|
|
fail(result.stdout)
|
|
return result.stdout
|
|
|
|
|
|
def main():
|
|
if not HELPER.exists():
|
|
fail(f"Missing LSP helper: {HELPER}")
|
|
if not EXE.exists():
|
|
fail(f"Missing Claro executable: {EXE}")
|
|
|
|
metadata = json.loads(run_helper("metadata"))
|
|
if metadata.get("language") != "Claro":
|
|
fail("metadata must describe Claro")
|
|
if ".claro" not in metadata.get("file_extensions", []):
|
|
fail("metadata must include .claro")
|
|
if not any(cmd.get("name") == "typecheck" for cmd in metadata.get("commands", [])):
|
|
fail("metadata must include typecheck command")
|
|
|
|
completions = json.loads(run_helper("completions"))
|
|
if "SAY" not in completions.get("keywords", []):
|
|
fail("completions must include SAY")
|
|
if "LIST OF TEXT" not in completions.get("types", []):
|
|
fail("completions must include typed containers")
|
|
|
|
with tempfile.TemporaryDirectory() as td:
|
|
bad = Path(td) / "bad_lsp.claro"
|
|
bad.write_text("SET score AS NUMBER TO 1\nSET score TO \"oops\"\n", encoding="utf-8")
|
|
diagnostics = json.loads(run_helper("diagnostics", str(bad)))
|
|
if not diagnostics:
|
|
fail("diagnostics must report type errors")
|
|
first = diagnostics[0]
|
|
for key in ["source", "file", "line", "severity", "message"]:
|
|
if key not in first:
|
|
fail(f"diagnostic is missing {key}")
|
|
if first["source"] != "claro typecheck":
|
|
fail("type mismatch should come from claro typecheck")
|
|
if first["line"] != 2:
|
|
fail(f"expected type diagnostic on line 2, got {first['line']}")
|
|
if "NUMBER" not in first["message"] or "TEXT" not in first["message"]:
|
|
fail(f"diagnostic should preserve type mismatch message: {first['message']}")
|
|
|
|
print("LSP helper validation OK")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|