b2b48f8b0d
Vendor, wire up, and compile 89 new tree-sitter grammars, expanding language support from 66 to 155 languages. All grammars pass security audit (no dangerous patterns in scanner.c files). New programming languages (31): Solidity, Typst, GDScript, Gleam, PowerShell, Pascal, D, Nim, Scheme, Fennel, Fish, AWK, Zsh, Tcl, Ada, Agda, Racket, Odin, ReScript, PureScript, Nickel, Crystal, Teal, Hare, Pony, Luau, Janet, Sway, NASM, Assembly, TLA+, Pkl, Cairo, Move, Squirrel, ISPC, FunC, Smali New config/data/IDL formats (31): Just, Astro, Blade, Go Template, Templ, Liquid, Jinja2, Prisma, Hyprlang, DotEnv, Diff, WGSL, KDL, JSON5, Jsonnet, RON, Thrift, Cap'n Proto, Properties, SSH Config, BibTeX, Starlark, Bicep, CSV, Requirements, HLSL, VHDL, SystemVerilog, DeviceTree, Linker Script, GN, Kconfig, BitBake, TableGen, Slang, LLVM IR, Smithy, WIT, Go Mod, Mermaid, RST, Beancount, Puppet, PO, Regex, JSDoc, gitattributes, gitignore, Apex, SOQL, SOSL Infrastructure: - scripts/new-languages.json: manifest for all new languages - scripts/generate-lang-code.py: generates boilerplate from manifest - scripts/audit-grammar-security.sh: pre-vendoring security scanner - Fixed angle-bracket includes in 18 grammars - Fixed PureScript scanner const mismatch - Fixed VHDL scanner void* API signatures - Fixed RST tree_sitter_rst/ subdirectory include paths - Copied crystal unicode.c (extra scanner dependency) All new languages start with minimal lang specs (module_types only). Function/class/call extraction specs to be refined incrementally.
119 lines
3.9 KiB
Python
119 lines
3.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Generate boilerplate code for new tree-sitter language support.
|
|
|
|
Reads scripts/new-languages.json and generates:
|
|
1. Grammar wrapper .c files (written directly)
|
|
2. Enum entries for cbm.h
|
|
3. Lang spec entries for lang_specs.c (designated initializer + factory)
|
|
4. Extension/filename/name entries for language.c
|
|
"""
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
PROJECT_DIR = os.path.dirname(SCRIPT_DIR)
|
|
MANIFEST = os.path.join(SCRIPT_DIR, "new-languages.json")
|
|
GRAMMAR_DIR = os.path.join(PROJECT_DIR, "internal", "cbm")
|
|
|
|
|
|
def main():
|
|
with open(MANIFEST) as f:
|
|
langs = json.load(f)
|
|
|
|
mode = sys.argv[1] if len(sys.argv) > 1 else "all"
|
|
|
|
if mode in ("all", "wrappers"):
|
|
generate_wrappers(langs)
|
|
if mode in ("all", "enum"):
|
|
generate_enum(langs)
|
|
if mode in ("all", "specs"):
|
|
generate_specs(langs)
|
|
if mode in ("all", "language"):
|
|
generate_language_c(langs)
|
|
|
|
|
|
def generate_wrappers(langs):
|
|
"""Create grammar_<name>.c wrapper files."""
|
|
print("=== Grammar Wrapper Files ===")
|
|
created = 0
|
|
for lang in langs:
|
|
path = os.path.join(GRAMMAR_DIR, f"grammar_{lang['name']}.c")
|
|
if os.path.exists(path):
|
|
continue
|
|
lines = [
|
|
f"// Vendored tree-sitter grammar: {lang['name']}",
|
|
"// Each grammar compiled as separate unit (conflicting static symbols).",
|
|
f"#include \"vendored/grammars/{lang['name']}/parser.c\"",
|
|
]
|
|
if lang["has_scanner"]:
|
|
lines.append(
|
|
f"#include \"vendored/grammars/{lang['name']}/scanner.c\""
|
|
)
|
|
with open(path, "w") as f:
|
|
f.write("\n".join(lines) + "\n")
|
|
created += 1
|
|
print(f" Created {created} wrapper files")
|
|
|
|
|
|
def generate_enum(langs):
|
|
"""Print enum entries for cbm.h."""
|
|
print("\n=== Enum Entries (paste into cbm.h before CBM_LANG_KUSTOMIZE) ===")
|
|
for lang in langs:
|
|
print(f" CBM_LANG_{lang['enum']},")
|
|
|
|
|
|
def generate_specs(langs):
|
|
"""Print lang spec entries for lang_specs.c."""
|
|
print("\n=== Extern Declarations (paste at top of lang_specs.c) ===")
|
|
for lang in langs:
|
|
print(f"extern const TSLanguage *{lang['ts_func']}(void);")
|
|
|
|
print("\n=== Module Type Arrays (paste before spec table) ===")
|
|
for lang in langs:
|
|
arr = f"{lang['name']}_module_types"
|
|
print(
|
|
f'static const char *{arr}[] = {{"{lang["module_root"]}", NULL}};'
|
|
)
|
|
|
|
print("\n=== Spec Table Entries (paste into lang_specs[]) ===")
|
|
for lang in langs:
|
|
mod = f"{lang['name']}_module_types"
|
|
print(f" // CBM_LANG_{lang['enum']}")
|
|
print(
|
|
f" [CBM_LANG_{lang['enum']}] = {{CBM_LANG_{lang['enum']}, "
|
|
f"empty_types, empty_types, empty_types, {mod}, "
|
|
f"empty_types, empty_types, empty_types, empty_types, "
|
|
f"empty_types, empty_types, empty_types, NULL, empty_types, "
|
|
f"NULL, NULL, {lang['ts_func']}}},"
|
|
)
|
|
print()
|
|
|
|
|
|
def generate_language_c(langs):
|
|
"""Print extension table and name entries for language.c."""
|
|
print("\n=== EXT_TABLE Entries (paste into language.c, sorted by ext) ===")
|
|
ext_entries = []
|
|
for lang in langs:
|
|
for ext in lang["extensions"]:
|
|
ext_entries.append((ext, lang["enum"], lang["display"]))
|
|
for ext, enum, display in sorted(ext_entries, key=lambda x: x[0].lower()):
|
|
print(f' /* {display} */')
|
|
print(f' {{"{ext}", CBM_LANG_{enum}}},')
|
|
print()
|
|
|
|
print("\n=== FILENAME_TABLE Entries ===")
|
|
for lang in langs:
|
|
for fn in lang["filenames"]:
|
|
print(f' {{"{fn}", CBM_LANG_{lang["enum"]}}},')
|
|
|
|
print("\n=== LANG_NAMES Entries ===")
|
|
for lang in langs:
|
|
print(
|
|
f' [CBM_LANG_{lang["enum"]}] = "{lang["display"]}",'
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|