mirror of
https://github.com/RustPython/Parser.git
synced 2025-08-04 02:39:22 +00:00
Merge pull request #15 from youknowone/spellchecker
Setup spell checker
This commit is contained in:
commit
d495cd9129
6 changed files with 501 additions and 178 deletions
304
.cspell.json
Normal file
304
.cspell.json
Normal file
|
@ -0,0 +1,304 @@
|
||||||
|
// See: https://github.com/streetsidesoftware/cspell/tree/master/packages/cspell
|
||||||
|
{
|
||||||
|
"version": "0.2",
|
||||||
|
// language - current active spelling language
|
||||||
|
"language": "en",
|
||||||
|
// dictionaries - list of the names of the dictionaries to use
|
||||||
|
"dictionaries": [
|
||||||
|
"en_US",
|
||||||
|
"softwareTerms",
|
||||||
|
"c",
|
||||||
|
"cpp",
|
||||||
|
"python",
|
||||||
|
"python-custom",
|
||||||
|
"rust",
|
||||||
|
"unix",
|
||||||
|
"posix",
|
||||||
|
"winapi"
|
||||||
|
],
|
||||||
|
// dictionaryDefinitions - this list defines any custom dictionaries to use
|
||||||
|
"dictionaryDefinitions": [],
|
||||||
|
"ignorePaths": [
|
||||||
|
"**/__pycache__/**",
|
||||||
|
"Lib/**"
|
||||||
|
],
|
||||||
|
// words - list of words to be always considered correct
|
||||||
|
"words": [
|
||||||
|
// Rust
|
||||||
|
"ahash",
|
||||||
|
"bidi",
|
||||||
|
"biguint",
|
||||||
|
"bindgen",
|
||||||
|
"bitflags",
|
||||||
|
"bstr",
|
||||||
|
"byteorder",
|
||||||
|
"chrono",
|
||||||
|
"consts",
|
||||||
|
"cstring",
|
||||||
|
"flate2",
|
||||||
|
"fract",
|
||||||
|
"hasher",
|
||||||
|
"hexf",
|
||||||
|
"idents",
|
||||||
|
"indexmap",
|
||||||
|
"insta",
|
||||||
|
"keccak",
|
||||||
|
"lalrpop",
|
||||||
|
"libc",
|
||||||
|
"libz",
|
||||||
|
"longlong",
|
||||||
|
"Manually",
|
||||||
|
"nbaz",
|
||||||
|
"maplit",
|
||||||
|
"memchr",
|
||||||
|
"memrchr",
|
||||||
|
"memmap",
|
||||||
|
"metas",
|
||||||
|
"modpow",
|
||||||
|
"nanos",
|
||||||
|
"peekable",
|
||||||
|
"powc",
|
||||||
|
"powf",
|
||||||
|
"prepended",
|
||||||
|
"punct",
|
||||||
|
"replacen",
|
||||||
|
"rsplitn",
|
||||||
|
"rustc",
|
||||||
|
"rustfmt",
|
||||||
|
"seekfrom",
|
||||||
|
"splitn",
|
||||||
|
"subsec",
|
||||||
|
"timsort",
|
||||||
|
"trai",
|
||||||
|
"ulonglong",
|
||||||
|
"unic",
|
||||||
|
"unistd",
|
||||||
|
"unsync",
|
||||||
|
"winapi",
|
||||||
|
"winsock",
|
||||||
|
// Python
|
||||||
|
"abstractmethods",
|
||||||
|
"aiter",
|
||||||
|
"anext",
|
||||||
|
"arrayiterator",
|
||||||
|
"arraytype",
|
||||||
|
"asend",
|
||||||
|
"athrow",
|
||||||
|
"basicsize",
|
||||||
|
"cformat",
|
||||||
|
"classcell",
|
||||||
|
"closesocket",
|
||||||
|
"codepoint",
|
||||||
|
"codepoints",
|
||||||
|
"cpython",
|
||||||
|
"decompressor",
|
||||||
|
"defaultaction",
|
||||||
|
"descr",
|
||||||
|
"dictcomp",
|
||||||
|
"dictitems",
|
||||||
|
"dictkeys",
|
||||||
|
"dictview",
|
||||||
|
"docstring",
|
||||||
|
"docstrings",
|
||||||
|
"dunder",
|
||||||
|
"eventmask",
|
||||||
|
"fdel",
|
||||||
|
"fget",
|
||||||
|
"fileencoding",
|
||||||
|
"fillchar",
|
||||||
|
"finallyhandler",
|
||||||
|
"frombytes",
|
||||||
|
"fromhex",
|
||||||
|
"fromunicode",
|
||||||
|
"fset",
|
||||||
|
"fspath",
|
||||||
|
"fstring",
|
||||||
|
"fstrings",
|
||||||
|
"genexpr",
|
||||||
|
"getattro",
|
||||||
|
"getformat",
|
||||||
|
"getnewargs",
|
||||||
|
"getweakrefcount",
|
||||||
|
"getweakrefs",
|
||||||
|
"hostnames",
|
||||||
|
"idiv",
|
||||||
|
"impls",
|
||||||
|
"infj",
|
||||||
|
"instancecheck",
|
||||||
|
"instanceof",
|
||||||
|
"isabstractmethod",
|
||||||
|
"itemiterator",
|
||||||
|
"itemsize",
|
||||||
|
"iternext",
|
||||||
|
"keyiterator",
|
||||||
|
"kwarg",
|
||||||
|
"kwargs",
|
||||||
|
"linearization",
|
||||||
|
"linearize",
|
||||||
|
"listcomp",
|
||||||
|
"mappingproxy",
|
||||||
|
"maxsplit",
|
||||||
|
"memoryview",
|
||||||
|
"memoryviewiterator",
|
||||||
|
"metaclass",
|
||||||
|
"metaclasses",
|
||||||
|
"metatype",
|
||||||
|
"mro",
|
||||||
|
"mros",
|
||||||
|
"nanj",
|
||||||
|
"ndigits",
|
||||||
|
"ndim",
|
||||||
|
"nonbytes",
|
||||||
|
"origname",
|
||||||
|
"posixsubprocess",
|
||||||
|
"pyexpat",
|
||||||
|
"PYTHONDEBUG",
|
||||||
|
"PYTHONHOME",
|
||||||
|
"PYTHONINSPECT",
|
||||||
|
"PYTHONOPTIMIZE",
|
||||||
|
"PYTHONPATH",
|
||||||
|
"PYTHONPATH",
|
||||||
|
"PYTHONVERBOSE",
|
||||||
|
"PYTHONWARNINGS",
|
||||||
|
"qualname",
|
||||||
|
"radd",
|
||||||
|
"rdiv",
|
||||||
|
"rdivmod",
|
||||||
|
"reconstructor",
|
||||||
|
"reversevalueiterator",
|
||||||
|
"rfloordiv",
|
||||||
|
"rlshift",
|
||||||
|
"rmod",
|
||||||
|
"rpow",
|
||||||
|
"rrshift",
|
||||||
|
"rsub",
|
||||||
|
"rtruediv",
|
||||||
|
"scproxy",
|
||||||
|
"setattro",
|
||||||
|
"setcomp",
|
||||||
|
"stacklevel",
|
||||||
|
"subclasscheck",
|
||||||
|
"subclasshook",
|
||||||
|
"unionable",
|
||||||
|
"unraisablehook",
|
||||||
|
"valueiterator",
|
||||||
|
"vararg",
|
||||||
|
"varargs",
|
||||||
|
"varnames",
|
||||||
|
"warningregistry",
|
||||||
|
"warnopts",
|
||||||
|
"weakproxy",
|
||||||
|
"xopts",
|
||||||
|
// RustPython
|
||||||
|
"baseclass",
|
||||||
|
"Bytecode",
|
||||||
|
"cfgs",
|
||||||
|
"codegen",
|
||||||
|
"dedentations",
|
||||||
|
"dedents",
|
||||||
|
"deduped",
|
||||||
|
"downcasted",
|
||||||
|
"dumpable",
|
||||||
|
"GetSet",
|
||||||
|
"internable",
|
||||||
|
"makeunicodedata",
|
||||||
|
"miri",
|
||||||
|
"nonterminal",
|
||||||
|
"notrace",
|
||||||
|
"pyarg",
|
||||||
|
"pyarg",
|
||||||
|
"pyargs",
|
||||||
|
"PyAttr",
|
||||||
|
"pyc",
|
||||||
|
"PyClass",
|
||||||
|
"PyClassMethod",
|
||||||
|
"PyException",
|
||||||
|
"PyFunction",
|
||||||
|
"pygetset",
|
||||||
|
"pyimpl",
|
||||||
|
"pymember",
|
||||||
|
"PyMethod",
|
||||||
|
"PyModule",
|
||||||
|
"pyname",
|
||||||
|
"pyobj",
|
||||||
|
"PyObject",
|
||||||
|
"pypayload",
|
||||||
|
"PyProperty",
|
||||||
|
"pyref",
|
||||||
|
"PyResult",
|
||||||
|
"pyslot",
|
||||||
|
"PyStaticMethod",
|
||||||
|
"pystr",
|
||||||
|
"pystruct",
|
||||||
|
"pystructseq",
|
||||||
|
"pytrace",
|
||||||
|
"reducelib",
|
||||||
|
"richcompare",
|
||||||
|
"RustPython",
|
||||||
|
"struc",
|
||||||
|
"tracebacks",
|
||||||
|
"typealiases",
|
||||||
|
"Unconstructible",
|
||||||
|
"unhashable",
|
||||||
|
"uninit",
|
||||||
|
"unraisable",
|
||||||
|
"wasi",
|
||||||
|
"zelf",
|
||||||
|
// cpython
|
||||||
|
"argtypes",
|
||||||
|
"asdl",
|
||||||
|
"asname",
|
||||||
|
"augassign",
|
||||||
|
"badsyntax",
|
||||||
|
"basetype",
|
||||||
|
"boolop",
|
||||||
|
"bxor",
|
||||||
|
"cellarg",
|
||||||
|
"cellvar",
|
||||||
|
"cellvars",
|
||||||
|
"cmpop",
|
||||||
|
"dictoffset",
|
||||||
|
"elts",
|
||||||
|
"excepthandler",
|
||||||
|
"finalbody",
|
||||||
|
"freevar",
|
||||||
|
"freevars",
|
||||||
|
"fromlist",
|
||||||
|
"heaptype",
|
||||||
|
"IMMUTABLETYPE",
|
||||||
|
"kwonlyarg",
|
||||||
|
"kwonlyargs",
|
||||||
|
"linearise",
|
||||||
|
"maxdepth",
|
||||||
|
"mult",
|
||||||
|
"nkwargs",
|
||||||
|
"orelse",
|
||||||
|
"patma",
|
||||||
|
"posonlyarg",
|
||||||
|
"posonlyargs",
|
||||||
|
"prec",
|
||||||
|
"significand",
|
||||||
|
"stackdepth",
|
||||||
|
"unaryop",
|
||||||
|
"unparse",
|
||||||
|
"unparser",
|
||||||
|
"VARKEYWORDS",
|
||||||
|
"varkwarg",
|
||||||
|
"wbits",
|
||||||
|
"withitem",
|
||||||
|
"withitems",
|
||||||
|
"withs"
|
||||||
|
],
|
||||||
|
// flagWords - list of words to be always considered incorrect
|
||||||
|
"flagWords": [
|
||||||
|
],
|
||||||
|
"ignoreRegExpList": [
|
||||||
|
],
|
||||||
|
// languageSettings - allow for per programming language configuration settings.
|
||||||
|
"languageSettings": [
|
||||||
|
{
|
||||||
|
"languageId": "python",
|
||||||
|
"locale": "en"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
10
.github/workflows/ci.yaml
vendored
10
.github/workflows/ci.yaml
vendored
|
@ -62,3 +62,13 @@ jobs:
|
||||||
run: python -m pip install ruff
|
run: python -m pip install ruff
|
||||||
- name: run python lint
|
- name: run python lint
|
||||||
run: ruff --ignore=E501 ast --show-source
|
run: ruff --ignore=E501 ast --show-source
|
||||||
|
|
||||||
|
- name: spell checker
|
||||||
|
uses: streetsidesoftware/cspell-action@v2
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
'ast/**/*.rs'
|
||||||
|
'core/**/*.rs'
|
||||||
|
'literal/**/*.rs'
|
||||||
|
'parser/**/*.rs'
|
||||||
|
'ast/asdl_rs.py'
|
||||||
|
|
357
ast/asdl_rs.py
357
ast/asdl_rs.py
|
@ -1,3 +1,5 @@
|
||||||
|
# spell-checker:words dfn dfns
|
||||||
|
|
||||||
#! /usr/bin/env python
|
#! /usr/bin/env python
|
||||||
"""Generate Rust code from an ASDL description."""
|
"""Generate Rust code from an ASDL description."""
|
||||||
|
|
||||||
|
@ -12,7 +14,7 @@ from typing import Optional, Dict
|
||||||
import asdl
|
import asdl
|
||||||
|
|
||||||
TABSIZE = 4
|
TABSIZE = 4
|
||||||
AUTOGEN_MESSAGE = "// File automatically generated by {}.\n\n"
|
AUTO_GEN_MESSAGE = "// File automatically generated by {}.\n\n"
|
||||||
|
|
||||||
builtin_type_mapping = {
|
builtin_type_mapping = {
|
||||||
"identifier": "Ident",
|
"identifier": "Ident",
|
||||||
|
@ -23,7 +25,7 @@ builtin_type_mapping = {
|
||||||
assert builtin_type_mapping.keys() == asdl.builtin_types
|
assert builtin_type_mapping.keys() == asdl.builtin_types
|
||||||
|
|
||||||
|
|
||||||
def get_rust_type(name):
|
def rust_type_name(name):
|
||||||
"""Return a string for the C name of the type.
|
"""Return a string for the C name of the type.
|
||||||
|
|
||||||
This function special cases the default types provided by asdl.
|
This function special cases the default types provided by asdl.
|
||||||
|
@ -66,7 +68,7 @@ def asdl_of(name, obj):
|
||||||
class TypeInfo:
|
class TypeInfo:
|
||||||
name: str
|
name: str
|
||||||
enum_name: Optional[str]
|
enum_name: Optional[str]
|
||||||
has_userdata: Optional[bool]
|
has_user_data: Optional[bool]
|
||||||
has_attributes: bool
|
has_attributes: bool
|
||||||
empty_field: bool
|
empty_field: bool
|
||||||
children: set
|
children: set
|
||||||
|
@ -77,7 +79,7 @@ class TypeInfo:
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.enum_name = None
|
self.enum_name = None
|
||||||
self.has_userdata = None
|
self.has_user_data = None
|
||||||
self.has_attributes = False
|
self.has_attributes = False
|
||||||
self.empty_field = False
|
self.empty_field = False
|
||||||
self.children = set()
|
self.children = set()
|
||||||
|
@ -90,7 +92,7 @@ class TypeInfo:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def rust_name(self):
|
def rust_name(self):
|
||||||
return get_rust_type(self.name)
|
return rust_type_name(self.name)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sum_name(self):
|
def sum_name(self):
|
||||||
|
@ -101,11 +103,11 @@ class TypeInfo:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def rust_sum_name(self):
|
def rust_sum_name(self):
|
||||||
rust_name = get_rust_type(self.name)
|
rust_name = rust_type_name(self.name)
|
||||||
if self.enum_name is None:
|
if self.enum_name is None:
|
||||||
return rust_name
|
return rust_name
|
||||||
else:
|
else:
|
||||||
name = get_rust_type(self.enum_name) + rust_name
|
name = rust_type_name(self.enum_name) + rust_name
|
||||||
return name
|
return name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -121,30 +123,30 @@ class TypeInfo:
|
||||||
else:
|
else:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def determine_userdata(self, typeinfo, stack):
|
def determine_user_data(self, type_info, stack):
|
||||||
if self.name in stack:
|
if self.name in stack:
|
||||||
return None
|
return None
|
||||||
stack.add(self.name)
|
stack.add(self.name)
|
||||||
for child, child_seq in self.children:
|
for child, child_seq in self.children:
|
||||||
if child in asdl.builtin_types:
|
if child in asdl.builtin_types:
|
||||||
continue
|
continue
|
||||||
childinfo = typeinfo[child]
|
child_info = type_info[child]
|
||||||
child_has_userdata = childinfo.determine_userdata(typeinfo, stack)
|
child_has_user_data = child_info.determine_user_data(type_info, stack)
|
||||||
if self.has_userdata is None and child_has_userdata is True:
|
if self.has_user_data is None and child_has_user_data is True:
|
||||||
self.has_userdata = True
|
self.has_user_data = True
|
||||||
|
|
||||||
stack.remove(self.name)
|
stack.remove(self.name)
|
||||||
return self.has_userdata
|
return self.has_user_data
|
||||||
|
|
||||||
|
|
||||||
class TypeInfoMixin:
|
class TypeInfoMixin:
|
||||||
typeinfo: Dict[str, TypeInfo]
|
type_info: Dict[str, TypeInfo]
|
||||||
|
|
||||||
def has_userdata(self, typ):
|
def has_user_data(self, typ):
|
||||||
return self.typeinfo[typ].has_userdata
|
return self.type_info[typ].has_user_data
|
||||||
|
|
||||||
def get_generics(self, typ, *generics):
|
def apply_generics(self, typ, *generics):
|
||||||
if self.has_userdata(typ):
|
if self.has_user_data(typ):
|
||||||
return [f"<{g}>" for g in generics]
|
return [f"<{g}>" for g in generics]
|
||||||
else:
|
else:
|
||||||
return ["" for g in generics]
|
return ["" for g in generics]
|
||||||
|
@ -153,9 +155,9 @@ class TypeInfoMixin:
|
||||||
class EmitVisitor(asdl.VisitorBase, TypeInfoMixin):
|
class EmitVisitor(asdl.VisitorBase, TypeInfoMixin):
|
||||||
"""Visit that emits lines"""
|
"""Visit that emits lines"""
|
||||||
|
|
||||||
def __init__(self, file, typeinfo):
|
def __init__(self, file, type_info):
|
||||||
self.file = file
|
self.file = file
|
||||||
self.typeinfo = typeinfo
|
self.type_info = type_info
|
||||||
self.identifiers = set()
|
self.identifiers = set()
|
||||||
super(EmitVisitor, self).__init__()
|
super(EmitVisitor, self).__init__()
|
||||||
|
|
||||||
|
@ -172,48 +174,48 @@ class EmitVisitor(asdl.VisitorBase, TypeInfoMixin):
|
||||||
self.file.write(line + "\n")
|
self.file.write(line + "\n")
|
||||||
|
|
||||||
|
|
||||||
class FindUserdataTypesVisitor(asdl.VisitorBase):
|
class FindUserDataTypesVisitor(asdl.VisitorBase):
|
||||||
def __init__(self, typeinfo):
|
def __init__(self, type_info):
|
||||||
self.typeinfo = typeinfo
|
self.type_info = type_info
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
def visitModule(self, mod):
|
def visitModule(self, mod):
|
||||||
for dfn in mod.dfns:
|
for dfn in mod.dfns:
|
||||||
self.visit(dfn)
|
self.visit(dfn)
|
||||||
stack = set()
|
stack = set()
|
||||||
for info in self.typeinfo.values():
|
for info in self.type_info.values():
|
||||||
info.determine_userdata(self.typeinfo, stack)
|
info.determine_user_data(self.type_info, stack)
|
||||||
|
|
||||||
def visitType(self, type):
|
def visitType(self, type):
|
||||||
self.typeinfo[type.name] = TypeInfo(type.name)
|
self.type_info[type.name] = TypeInfo(type.name)
|
||||||
self.visit(type.value, type.name)
|
self.visit(type.value, type.name)
|
||||||
|
|
||||||
def visitSum(self, sum, name):
|
def visitSum(self, sum, name):
|
||||||
info = self.typeinfo[name]
|
info = self.type_info[name]
|
||||||
if is_simple(sum):
|
if is_simple(sum):
|
||||||
info.has_userdata = False
|
info.has_user_data = False
|
||||||
else:
|
else:
|
||||||
for t in sum.types:
|
for t in sum.types:
|
||||||
t_info = TypeInfo(t.name)
|
t_info = TypeInfo(t.name)
|
||||||
t_info.enum_name = name
|
t_info.enum_name = name
|
||||||
t_info.empty_field = not t.fields
|
t_info.empty_field = not t.fields
|
||||||
self.typeinfo[t.name] = t_info
|
self.type_info[t.name] = t_info
|
||||||
self.add_children(t.name, t.fields)
|
self.add_children(t.name, t.fields)
|
||||||
if len(sum.types) > 1:
|
if len(sum.types) > 1:
|
||||||
info.boxed = True
|
info.boxed = True
|
||||||
if sum.attributes:
|
if sum.attributes:
|
||||||
# attributes means located, which has the `custom: U` field
|
# attributes means located, which has the `custom: U` field
|
||||||
info.has_userdata = True
|
info.has_user_data = True
|
||||||
info.has_attributes = True
|
info.has_attributes = True
|
||||||
|
|
||||||
for variant in sum.types:
|
for variant in sum.types:
|
||||||
self.add_children(name, variant.fields)
|
self.add_children(name, variant.fields)
|
||||||
|
|
||||||
def visitProduct(self, product, name):
|
def visitProduct(self, product, name):
|
||||||
info = self.typeinfo[name]
|
info = self.type_info[name]
|
||||||
if product.attributes:
|
if product.attributes:
|
||||||
# attributes means located, which has the `custom: U` field
|
# attributes means located, which has the `custom: U` field
|
||||||
info.has_userdata = True
|
info.has_user_data = True
|
||||||
info.has_attributes = True
|
info.has_attributes = True
|
||||||
info.has_expr = product_has_expr(product)
|
info.has_expr = product_has_expr(product)
|
||||||
if len(product.fields) > 2:
|
if len(product.fields) > 2:
|
||||||
|
@ -222,7 +224,9 @@ class FindUserdataTypesVisitor(asdl.VisitorBase):
|
||||||
self.add_children(name, product.fields)
|
self.add_children(name, product.fields)
|
||||||
|
|
||||||
def add_children(self, name, fields):
|
def add_children(self, name, fields):
|
||||||
self.typeinfo[name].children.update((field.type, field.seq) for field in fields)
|
self.type_info[name].children.update(
|
||||||
|
(field.type, field.seq) for field in fields
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def rust_field(field_name):
|
def rust_field(field_name):
|
||||||
|
@ -237,7 +241,7 @@ def product_has_expr(product):
|
||||||
|
|
||||||
|
|
||||||
class StructVisitor(EmitVisitor):
|
class StructVisitor(EmitVisitor):
|
||||||
"""Visitor to generate typedefs for AST."""
|
"""Visitor to generate type-defs for AST."""
|
||||||
|
|
||||||
def __init__(self, *args, **kw):
|
def __init__(self, *args, **kw):
|
||||||
super().__init__(*args, **kw)
|
super().__init__(*args, **kw)
|
||||||
|
@ -260,59 +264,59 @@ class StructVisitor(EmitVisitor):
|
||||||
self.emit("#[derive(Clone, Debug, PartialEq)]", depth)
|
self.emit("#[derive(Clone, Debug, PartialEq)]", depth)
|
||||||
|
|
||||||
def simple_sum(self, sum, name, depth):
|
def simple_sum(self, sum, name, depth):
|
||||||
rustname = get_rust_type(name)
|
rust_name = rust_type_name(name)
|
||||||
self.emit_attrs(depth)
|
self.emit_attrs(depth)
|
||||||
self.emit(f"pub enum {rustname} {{", depth)
|
self.emit(f"pub enum {rust_name} {{", depth)
|
||||||
for variant in sum.types:
|
for variant in sum.types:
|
||||||
self.emit(f"{variant.name},", depth + 1)
|
self.emit(f"{variant.name},", depth + 1)
|
||||||
self.emit("}", depth)
|
self.emit("}", depth)
|
||||||
self.emit("", depth)
|
self.emit("", depth)
|
||||||
|
|
||||||
def sum_with_constructors(self, sum, name, depth):
|
def sum_with_constructors(self, sum, name, depth):
|
||||||
typeinfo = self.typeinfo[name]
|
type_info = self.type_info[name]
|
||||||
suffix = typeinfo.rust_suffix
|
suffix = type_info.rust_suffix
|
||||||
rustname = get_rust_type(name)
|
rust_name = rust_type_name(name)
|
||||||
# all the attributes right now are for location, so if it has attrs we
|
# all the attributes right now are for location, so if it has attrs we
|
||||||
# can just wrap it in Attributed<>
|
# can just wrap it in Attributed<>
|
||||||
|
|
||||||
for t in sum.types:
|
for t in sum.types:
|
||||||
if not t.fields:
|
if not t.fields:
|
||||||
continue
|
continue
|
||||||
self.sum_subtype_struct(typeinfo, t, rustname, depth)
|
self.sum_subtype_struct(type_info, t, rust_name, depth)
|
||||||
|
|
||||||
generics, generics_applied = self.get_generics(name, "U = ()", "U")
|
generics, generics_applied = self.apply_generics(name, "U = ()", "U")
|
||||||
self.emit_attrs(depth)
|
self.emit_attrs(depth)
|
||||||
self.emit(f"pub enum {rustname}{suffix}{generics} {{", depth)
|
self.emit(f"pub enum {rust_name}{suffix}{generics} {{", depth)
|
||||||
for t in sum.types:
|
for t in sum.types:
|
||||||
if t.fields:
|
if t.fields:
|
||||||
(t_generics_applied,) = self.get_generics(t.name, "U")
|
(t_generics_applied,) = self.apply_generics(t.name, "U")
|
||||||
self.emit(
|
self.emit(
|
||||||
f"{t.name}({rustname}{t.name}{t_generics_applied}),", depth + 1
|
f"{t.name}({rust_name}{t.name}{t_generics_applied}),", depth + 1
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.emit(f"{t.name},", depth + 1)
|
self.emit(f"{t.name},", depth + 1)
|
||||||
self.emit("}", depth)
|
self.emit("}", depth)
|
||||||
if typeinfo.has_attributes:
|
if type_info.has_attributes:
|
||||||
self.emit(
|
self.emit(
|
||||||
f"pub type {rustname}<U = ()> = Attributed<{rustname}{suffix}{generics_applied}, U>;",
|
f"pub type {rust_name}<U = ()> = Attributed<{rust_name}{suffix}{generics_applied}, U>;",
|
||||||
depth,
|
depth,
|
||||||
)
|
)
|
||||||
self.emit("", depth)
|
self.emit("", depth)
|
||||||
|
|
||||||
def sum_subtype_struct(self, sum_typeinfo, t, rustname, depth):
|
def sum_subtype_struct(self, sum_type_info, t, rust_name, depth):
|
||||||
self.emit_attrs(depth)
|
self.emit_attrs(depth)
|
||||||
generics, generics_applied = self.get_generics(t.name, "U = ()", "U")
|
generics, generics_applied = self.apply_generics(t.name, "U = ()", "U")
|
||||||
payload_name = f"{rustname}{t.name}"
|
payload_name = f"{rust_name}{t.name}"
|
||||||
self.emit(f"pub struct {payload_name}{generics} {{", depth)
|
self.emit(f"pub struct {payload_name}{generics} {{", depth)
|
||||||
for f in t.fields:
|
for f in t.fields:
|
||||||
self.visit(f, sum_typeinfo, "pub ", depth + 1, t.name)
|
self.visit(f, sum_type_info, "pub ", depth + 1, t.name)
|
||||||
self.emit("}", depth)
|
self.emit("}", depth)
|
||||||
self.emit(
|
self.emit(
|
||||||
textwrap.dedent(
|
textwrap.dedent(
|
||||||
f"""
|
f"""
|
||||||
impl{generics_applied} From<{payload_name}{generics_applied}> for {rustname}{sum_typeinfo.rust_suffix}{generics_applied} {{
|
impl{generics_applied} From<{payload_name}{generics_applied}> for {rust_name}{sum_type_info.rust_suffix}{generics_applied} {{
|
||||||
fn from(payload: {payload_name}{generics_applied}) -> Self {{
|
fn from(payload: {payload_name}{generics_applied}) -> Self {{
|
||||||
{rustname}{sum_typeinfo.rust_suffix}::{t.name}(payload)
|
{rust_name}{sum_type_info.rust_suffix}::{t.name}(payload)
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
"""
|
"""
|
||||||
|
@ -330,14 +334,14 @@ class StructVisitor(EmitVisitor):
|
||||||
self.emit(f"{cons.name},", depth)
|
self.emit(f"{cons.name},", depth)
|
||||||
|
|
||||||
def visitField(self, field, parent, vis, depth, constructor=None):
|
def visitField(self, field, parent, vis, depth, constructor=None):
|
||||||
typ = get_rust_type(field.type)
|
typ = rust_type_name(field.type)
|
||||||
fieldtype = self.typeinfo.get(field.type)
|
field_type = self.type_info.get(field.type)
|
||||||
if fieldtype and fieldtype.has_userdata:
|
if field_type and field_type.has_user_data:
|
||||||
typ = f"{typ}<U>"
|
typ = f"{typ}<U>"
|
||||||
# don't box if we're doing Vec<T>, but do box if we're doing Vec<Option<Box<T>>>
|
# don't box if we're doing Vec<T>, but do box if we're doing Vec<Option<Box<T>>>
|
||||||
if (
|
if (
|
||||||
fieldtype
|
field_type
|
||||||
and fieldtype.boxed
|
and field_type.boxed
|
||||||
and (not (parent.product or field.seq) or field.opt)
|
and (not (parent.product or field.seq) or field.opt)
|
||||||
):
|
):
|
||||||
typ = f"Box<{typ}>"
|
typ = f"Box<{typ}>"
|
||||||
|
@ -355,27 +359,27 @@ class StructVisitor(EmitVisitor):
|
||||||
self.emit(f"{vis}{name}: {typ},", depth)
|
self.emit(f"{vis}{name}: {typ},", depth)
|
||||||
|
|
||||||
def visitProduct(self, product, name, depth):
|
def visitProduct(self, product, name, depth):
|
||||||
typeinfo = self.typeinfo[name]
|
type_info = self.type_info[name]
|
||||||
generics, generics_applied = self.get_generics(name, "U = ()", "U")
|
generics, generics_applied = self.apply_generics(name, "U = ()", "U")
|
||||||
dataname = rustname = get_rust_type(name)
|
data_name = rust_name = rust_type_name(name)
|
||||||
if product.attributes:
|
if product.attributes:
|
||||||
dataname = rustname + "Data"
|
data_name = rust_name + "Data"
|
||||||
self.emit_attrs(depth)
|
self.emit_attrs(depth)
|
||||||
has_expr = product_has_expr(product)
|
has_expr = product_has_expr(product)
|
||||||
if has_expr:
|
if has_expr:
|
||||||
datadef = f"{dataname}{generics}"
|
data_def = f"{data_name}{generics}"
|
||||||
else:
|
else:
|
||||||
datadef = dataname
|
data_def = data_name
|
||||||
self.emit(f"pub struct {datadef} {{", depth)
|
self.emit(f"pub struct {data_def} {{", depth)
|
||||||
for f in product.fields:
|
for f in product.fields:
|
||||||
self.visit(f, typeinfo, "pub ", depth + 1)
|
self.visit(f, type_info, "pub ", depth + 1)
|
||||||
self.emit("}", depth)
|
self.emit("}", depth)
|
||||||
if product.attributes:
|
if product.attributes:
|
||||||
# attributes should just be location info
|
# attributes should just be location info
|
||||||
if not has_expr:
|
if not has_expr:
|
||||||
generics_applied = ""
|
generics_applied = ""
|
||||||
self.emit(
|
self.emit(
|
||||||
f"pub type {rustname}<U = ()> = Attributed<{dataname}{generics_applied}, U>;",
|
f"pub type {rust_name}<U = ()> = Attributed<{data_name}{generics_applied}, U>;",
|
||||||
depth,
|
depth,
|
||||||
)
|
)
|
||||||
self.emit("", depth)
|
self.emit("", depth)
|
||||||
|
@ -411,10 +415,10 @@ class FoldTraitDefVisitor(EmitVisitor):
|
||||||
|
|
||||||
def visitType(self, type, depth):
|
def visitType(self, type, depth):
|
||||||
name = type.name
|
name = type.name
|
||||||
apply_u, apply_target_u = self.get_generics(name, "U", "Self::TargetU")
|
apply_u, apply_target_u = self.apply_generics(name, "U", "Self::TargetU")
|
||||||
enumname = get_rust_type(name)
|
enum_name = rust_type_name(name)
|
||||||
self.emit(
|
self.emit(
|
||||||
f"fn fold_{name}(&mut self, node: {enumname}{apply_u}) -> Result<{enumname}{apply_target_u}, Self::Error> {{",
|
f"fn fold_{name}(&mut self, node: {enum_name}{apply_u}) -> Result<{enum_name}{apply_target_u}, Self::Error> {{",
|
||||||
depth,
|
depth,
|
||||||
)
|
)
|
||||||
self.emit(f"fold_{name}(self, node)", depth + 1)
|
self.emit(f"fold_{name}(self, node)", depth + 1)
|
||||||
|
@ -439,14 +443,14 @@ class FoldImplVisitor(EmitVisitor):
|
||||||
self.visit(type.value, type.name, depth)
|
self.visit(type.value, type.name, depth)
|
||||||
|
|
||||||
def visitSum(self, sum, name, depth):
|
def visitSum(self, sum, name, depth):
|
||||||
typeinfo = self.typeinfo[name]
|
type_info = self.type_info[name]
|
||||||
apply_t, apply_u, apply_target_u = self.get_generics(
|
apply_t, apply_u, apply_target_u = self.apply_generics(
|
||||||
name, "T", "U", "F::TargetU"
|
name, "T", "U", "F::TargetU"
|
||||||
)
|
)
|
||||||
enumname = get_rust_type(name)
|
enum_name = rust_type_name(name)
|
||||||
|
|
||||||
self.emit(f"impl<T, U> Foldable<T, U> for {enumname}{apply_t} {{", depth)
|
self.emit(f"impl<T, U> Foldable<T, U> for {enum_name}{apply_t} {{", depth)
|
||||||
self.emit(f"type Mapped = {enumname}{apply_u};", depth + 1)
|
self.emit(f"type Mapped = {enum_name}{apply_u};", depth + 1)
|
||||||
self.emit(
|
self.emit(
|
||||||
"fn fold<F: Fold<T, TargetU = U> + ?Sized>(self, folder: &mut F) -> Result<Self::Mapped, F::Error> {",
|
"fn fold<F: Fold<T, TargetU = U> + ?Sized>(self, folder: &mut F) -> Result<Self::Mapped, F::Error> {",
|
||||||
depth + 1,
|
depth + 1,
|
||||||
|
@ -456,16 +460,16 @@ class FoldImplVisitor(EmitVisitor):
|
||||||
self.emit("}", depth)
|
self.emit("}", depth)
|
||||||
|
|
||||||
self.emit(
|
self.emit(
|
||||||
f"pub fn fold_{name}<U, F: Fold<U> + ?Sized>(#[allow(unused)] folder: &mut F, node: {enumname}{apply_u}) -> Result<{enumname}{apply_target_u}, F::Error> {{",
|
f"pub fn fold_{name}<U, F: Fold<U> + ?Sized>(#[allow(unused)] folder: &mut F, node: {enum_name}{apply_u}) -> Result<{enum_name}{apply_target_u}, F::Error> {{",
|
||||||
depth,
|
depth,
|
||||||
)
|
)
|
||||||
if typeinfo.has_attributes:
|
if type_info.has_attributes:
|
||||||
self.emit("fold_attributed(folder, node, |folder, node| {", depth)
|
self.emit("fold_attributed(folder, node, |folder, node| {", depth)
|
||||||
|
|
||||||
self.emit("match node {", depth + 1)
|
self.emit("match node {", depth + 1)
|
||||||
for cons in sum.types:
|
for cons in sum.types:
|
||||||
fields_pattern = self.make_pattern(
|
fields_pattern = self.make_pattern(
|
||||||
enumname, typeinfo.rust_suffix, cons.name, cons.fields
|
enum_name, type_info.rust_suffix, cons.name, cons.fields
|
||||||
)
|
)
|
||||||
self.emit(
|
self.emit(
|
||||||
f"{fields_pattern[0]} {{ {fields_pattern[1]} }} {fields_pattern[2]} => {{",
|
f"{fields_pattern[0]} {{ {fields_pattern[1]} }} {fields_pattern[2]} => {{",
|
||||||
|
@ -476,19 +480,19 @@ class FoldImplVisitor(EmitVisitor):
|
||||||
)
|
)
|
||||||
self.emit("}", depth + 2)
|
self.emit("}", depth + 2)
|
||||||
self.emit("}", depth + 1)
|
self.emit("}", depth + 1)
|
||||||
if typeinfo.has_attributes:
|
if type_info.has_attributes:
|
||||||
self.emit("})", depth)
|
self.emit("})", depth)
|
||||||
self.emit("}", depth)
|
self.emit("}", depth)
|
||||||
|
|
||||||
def visitProduct(self, product, name, depth):
|
def visitProduct(self, product, name, depth):
|
||||||
apply_t, apply_u, apply_target_u = self.get_generics(
|
apply_t, apply_u, apply_target_u = self.apply_generics(
|
||||||
name, "T", "U", "F::TargetU"
|
name, "T", "U", "F::TargetU"
|
||||||
)
|
)
|
||||||
structname = get_rust_type(name)
|
struct_name = rust_type_name(name)
|
||||||
has_attributes = bool(product.attributes)
|
has_attributes = bool(product.attributes)
|
||||||
|
|
||||||
self.emit(f"impl<T, U> Foldable<T, U> for {structname}{apply_t} {{", depth)
|
self.emit(f"impl<T, U> Foldable<T, U> for {struct_name}{apply_t} {{", depth)
|
||||||
self.emit(f"type Mapped = {structname}{apply_u};", depth + 1)
|
self.emit(f"type Mapped = {struct_name}{apply_u};", depth + 1)
|
||||||
self.emit(
|
self.emit(
|
||||||
"fn fold<F: Fold<T, TargetU = U> + ?Sized>(self, folder: &mut F) -> Result<Self::Mapped, F::Error> {",
|
"fn fold<F: Fold<T, TargetU = U> + ?Sized>(self, folder: &mut F) -> Result<Self::Mapped, F::Error> {",
|
||||||
depth + 1,
|
depth + 1,
|
||||||
|
@ -498,27 +502,27 @@ class FoldImplVisitor(EmitVisitor):
|
||||||
self.emit("}", depth)
|
self.emit("}", depth)
|
||||||
|
|
||||||
self.emit(
|
self.emit(
|
||||||
f"pub fn fold_{name}<U, F: Fold<U> + ?Sized>(#[allow(unused)] folder: &mut F, node: {structname}{apply_u}) -> Result<{structname}{apply_target_u}, F::Error> {{",
|
f"pub fn fold_{name}<U, F: Fold<U> + ?Sized>(#[allow(unused)] folder: &mut F, node: {struct_name}{apply_u}) -> Result<{struct_name}{apply_target_u}, F::Error> {{",
|
||||||
depth,
|
depth,
|
||||||
)
|
)
|
||||||
if has_attributes:
|
if has_attributes:
|
||||||
self.emit("fold_attributed(folder, node, |folder, node| {", depth)
|
self.emit("fold_attributed(folder, node, |folder, node| {", depth)
|
||||||
rustname = structname + "Data"
|
rust_name = struct_name + "Data"
|
||||||
else:
|
else:
|
||||||
rustname = structname
|
rust_name = struct_name
|
||||||
fields_pattern = self.make_pattern(rustname, structname, None, product.fields)
|
fields_pattern = self.make_pattern(rust_name, struct_name, None, product.fields)
|
||||||
self.emit(f"let {rustname} {{ {fields_pattern[1]} }} = node;", depth + 1)
|
self.emit(f"let {rust_name} {{ {fields_pattern[1]} }} = node;", depth + 1)
|
||||||
self.gen_construction(rustname, product.fields, "", depth + 1)
|
self.gen_construction(rust_name, product.fields, "", depth + 1)
|
||||||
if has_attributes:
|
if has_attributes:
|
||||||
self.emit("})", depth)
|
self.emit("})", depth)
|
||||||
self.emit("}", depth)
|
self.emit("}", depth)
|
||||||
|
|
||||||
def make_pattern(self, rustname, suffix, fieldname, fields):
|
def make_pattern(self, rust_name, suffix, fieldname, fields):
|
||||||
if fields:
|
if fields:
|
||||||
header = f"{rustname}{suffix}::{fieldname}({rustname}{fieldname}"
|
header = f"{rust_name}{suffix}::{fieldname}({rust_name}{fieldname}"
|
||||||
footer = ")"
|
footer = ")"
|
||||||
else:
|
else:
|
||||||
header = f"{rustname}{suffix}::{fieldname}"
|
header = f"{rust_name}{suffix}::{fieldname}"
|
||||||
footer = ""
|
footer = ""
|
||||||
|
|
||||||
body = ",".join(rust_field(f.name) for f in fields)
|
body = ",".join(rust_field(f.name) for f in fields)
|
||||||
|
@ -536,24 +540,24 @@ class FoldModuleVisitor(EmitVisitor):
|
||||||
def visitModule(self, mod):
|
def visitModule(self, mod):
|
||||||
depth = 0
|
depth = 0
|
||||||
self.emit("use crate::fold_helpers::Foldable;", depth)
|
self.emit("use crate::fold_helpers::Foldable;", depth)
|
||||||
FoldTraitDefVisitor(self.file, self.typeinfo).visit(mod, depth)
|
FoldTraitDefVisitor(self.file, self.type_info).visit(mod, depth)
|
||||||
FoldImplVisitor(self.file, self.typeinfo).visit(mod, depth)
|
FoldImplVisitor(self.file, self.type_info).visit(mod, depth)
|
||||||
|
|
||||||
|
|
||||||
class VisitorTraitDefVisitor(StructVisitor):
|
class VisitorTraitDefVisitor(StructVisitor):
|
||||||
def full_name(self, name):
|
def full_name(self, name):
|
||||||
typeinfo = self.typeinfo[name]
|
type_info = self.type_info[name]
|
||||||
if typeinfo.enum_name:
|
if type_info.enum_name:
|
||||||
return f"{typeinfo.enum_name}_{name}"
|
return f"{type_info.enum_name}_{name}"
|
||||||
else:
|
else:
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def node_type_name(self, name):
|
def node_type_name(self, name):
|
||||||
typeinfo = self.typeinfo[name]
|
type_info = self.type_info[name]
|
||||||
if typeinfo.enum_name:
|
if type_info.enum_name:
|
||||||
return f"{get_rust_type(typeinfo.enum_name)}{get_rust_type(name)}"
|
return f"{rust_type_name(type_info.enum_name)}{rust_type_name(name)}"
|
||||||
else:
|
else:
|
||||||
return get_rust_type(name)
|
return rust_type_name(name)
|
||||||
|
|
||||||
def visitModule(self, mod, depth):
|
def visitModule(self, mod, depth):
|
||||||
self.emit("pub trait Visitor<U=()> {", depth)
|
self.emit("pub trait Visitor<U=()> {", depth)
|
||||||
|
@ -566,27 +570,27 @@ class VisitorTraitDefVisitor(StructVisitor):
|
||||||
self.visit(type.value, type.name, depth)
|
self.visit(type.value, type.name, depth)
|
||||||
|
|
||||||
def emit_visitor(self, nodename, depth, has_node=True):
|
def emit_visitor(self, nodename, depth, has_node=True):
|
||||||
typeinfo = self.typeinfo[nodename]
|
type_info = self.type_info[nodename]
|
||||||
if has_node:
|
if has_node:
|
||||||
node_type = typeinfo.rust_sum_name
|
node_type = type_info.rust_sum_name
|
||||||
node_value = "node"
|
node_value = "node"
|
||||||
else:
|
else:
|
||||||
node_type = "()"
|
node_type = "()"
|
||||||
node_value = "()"
|
node_value = "()"
|
||||||
self.emit(
|
self.emit(
|
||||||
f"fn visit_{typeinfo.sum_name}(&mut self, node: {node_type}) {{", depth
|
f"fn visit_{type_info.sum_name}(&mut self, node: {node_type}) {{", depth
|
||||||
)
|
)
|
||||||
self.emit(f"self.generic_visit_{typeinfo.sum_name}({node_value})", depth + 1)
|
self.emit(f"self.generic_visit_{type_info.sum_name}({node_value})", depth + 1)
|
||||||
self.emit("}", depth)
|
self.emit("}", depth)
|
||||||
|
|
||||||
def emit_generic_visitor_signature(self, nodename, depth, has_node=True):
|
def emit_generic_visitor_signature(self, nodename, depth, has_node=True):
|
||||||
typeinfo = self.typeinfo[nodename]
|
type_info = self.type_info[nodename]
|
||||||
if has_node:
|
if has_node:
|
||||||
node_type = typeinfo.rust_sum_name
|
node_type = type_info.rust_sum_name
|
||||||
else:
|
else:
|
||||||
node_type = "()"
|
node_type = "()"
|
||||||
self.emit(
|
self.emit(
|
||||||
f"fn generic_visit_{typeinfo.sum_name}(&mut self, node: {node_type}) {{",
|
f"fn generic_visit_{type_info.sum_name}(&mut self, node: {node_type}) {{",
|
||||||
depth,
|
depth,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -598,8 +602,8 @@ class VisitorTraitDefVisitor(StructVisitor):
|
||||||
self.emit_visitor(name, depth)
|
self.emit_visitor(name, depth)
|
||||||
self.emit_empty_generic_visitor(name, depth)
|
self.emit_empty_generic_visitor(name, depth)
|
||||||
|
|
||||||
def visit_match_for_type(self, nodename, rustname, type_, depth):
|
def visit_match_for_type(self, nodename, rust_name, type_, depth):
|
||||||
self.emit(f"{rustname}::{type_.name}", depth)
|
self.emit(f"{rust_name}::{type_.name}", depth)
|
||||||
if type_.fields:
|
if type_.fields:
|
||||||
self.emit("(data)", depth)
|
self.emit("(data)", depth)
|
||||||
data = "data"
|
data = "data"
|
||||||
|
@ -607,13 +611,13 @@ class VisitorTraitDefVisitor(StructVisitor):
|
||||||
data = "()"
|
data = "()"
|
||||||
self.emit(f"=> self.visit_{nodename}_{type_.name}({data}),", depth)
|
self.emit(f"=> self.visit_{nodename}_{type_.name}({data}),", depth)
|
||||||
|
|
||||||
def visit_sumtype(self, name, type_, depth):
|
def visit_sum_type(self, name, type_, depth):
|
||||||
self.emit_visitor(type_.name, depth, has_node=type_.fields)
|
self.emit_visitor(type_.name, depth, has_node=type_.fields)
|
||||||
self.emit_generic_visitor_signature(type_.name, depth, has_node=type_.fields)
|
self.emit_generic_visitor_signature(type_.name, depth, has_node=type_.fields)
|
||||||
for f in type_.fields:
|
for f in type_.fields:
|
||||||
fieldname = rust_field(f.name)
|
fieldname = rust_field(f.name)
|
||||||
fieldtype = self.typeinfo.get(f.type)
|
field_type = self.type_info.get(f.type)
|
||||||
if not (fieldtype and fieldtype.has_userdata):
|
if not (field_type and field_type.has_user_data):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if f.opt:
|
if f.opt:
|
||||||
|
@ -628,10 +632,10 @@ class VisitorTraitDefVisitor(StructVisitor):
|
||||||
self.emit(f"let value = node.{fieldname};", depth + 2)
|
self.emit(f"let value = node.{fieldname};", depth + 2)
|
||||||
|
|
||||||
variable = "value"
|
variable = "value"
|
||||||
if fieldtype.boxed and (not f.seq or f.opt):
|
if field_type.boxed and (not f.seq or f.opt):
|
||||||
variable = "*" + variable
|
variable = "*" + variable
|
||||||
typeinfo = self.typeinfo[fieldtype.name]
|
type_info = self.type_info[field_type.name]
|
||||||
self.emit(f"self.visit_{typeinfo.sum_name}({variable});", depth + 2)
|
self.emit(f"self.visit_{type_info.sum_name}({variable});", depth + 2)
|
||||||
|
|
||||||
self.emit("}", depth + 1)
|
self.emit("}", depth + 1)
|
||||||
|
|
||||||
|
@ -641,22 +645,22 @@ class VisitorTraitDefVisitor(StructVisitor):
|
||||||
if not sum.attributes:
|
if not sum.attributes:
|
||||||
return
|
return
|
||||||
|
|
||||||
rustname = enumname = get_rust_type(name)
|
rust_name = enum_name = rust_type_name(name)
|
||||||
if sum.attributes:
|
if sum.attributes:
|
||||||
rustname = enumname + "Kind"
|
rust_name = enum_name + "Kind"
|
||||||
self.emit_visitor(name, depth)
|
self.emit_visitor(name, depth)
|
||||||
self.emit_generic_visitor_signature(name, depth)
|
self.emit_generic_visitor_signature(name, depth)
|
||||||
depth += 1
|
depth += 1
|
||||||
self.emit("match node.node {", depth)
|
self.emit("match node.node {", depth)
|
||||||
for t in sum.types:
|
for t in sum.types:
|
||||||
self.visit_match_for_type(name, rustname, t, depth + 1)
|
self.visit_match_for_type(name, rust_name, t, depth + 1)
|
||||||
self.emit("}", depth)
|
self.emit("}", depth)
|
||||||
depth -= 1
|
depth -= 1
|
||||||
self.emit("}", depth)
|
self.emit("}", depth)
|
||||||
|
|
||||||
# Now for the visitors for the types
|
# Now for the visitors for the types
|
||||||
for t in sum.types:
|
for t in sum.types:
|
||||||
self.visit_sumtype(name, t, depth)
|
self.visit_sum_type(name, t, depth)
|
||||||
|
|
||||||
def visitProduct(self, product, name, depth):
|
def visitProduct(self, product, name, depth):
|
||||||
self.emit_visitor(name, depth)
|
self.emit_visitor(name, depth)
|
||||||
|
@ -667,10 +671,10 @@ class VisitorModuleVisitor(EmitVisitor):
|
||||||
def visitModule(self, mod):
|
def visitModule(self, mod):
|
||||||
depth = 0
|
depth = 0
|
||||||
self.emit("#[allow(unused_variables, non_snake_case)]", depth)
|
self.emit("#[allow(unused_variables, non_snake_case)]", depth)
|
||||||
VisitorTraitDefVisitor(self.file, self.typeinfo).visit(mod, depth)
|
VisitorTraitDefVisitor(self.file, self.type_info).visit(mod, depth)
|
||||||
|
|
||||||
|
|
||||||
class ClassDefVisitor(EmitVisitor):
|
class class_defVisitor(EmitVisitor):
|
||||||
def visitModule(self, mod):
|
def visitModule(self, mod):
|
||||||
for dfn in mod.dfns:
|
for dfn in mod.dfns:
|
||||||
self.visit(dfn)
|
self.visit(dfn)
|
||||||
|
@ -679,32 +683,32 @@ class ClassDefVisitor(EmitVisitor):
|
||||||
self.visit(type.value, type.name, depth)
|
self.visit(type.value, type.name, depth)
|
||||||
|
|
||||||
def visitSum(self, sum, name, depth):
|
def visitSum(self, sum, name, depth):
|
||||||
structname = "NodeKind" + get_rust_type(name)
|
struct_name = "NodeKind" + rust_type_name(name)
|
||||||
self.emit(
|
self.emit(
|
||||||
f'#[pyclass(module = "_ast", name = {json.dumps(name)}, base = "AstNode")]',
|
f'#[pyclass(module = "_ast", name = {json.dumps(name)}, base = "AstNode")]',
|
||||||
depth,
|
depth,
|
||||||
)
|
)
|
||||||
self.emit(f"struct {structname};", depth)
|
self.emit(f"struct {struct_name};", depth)
|
||||||
self.emit("#[pyclass(flags(HAS_DICT, BASETYPE))]", depth)
|
self.emit("#[pyclass(flags(HAS_DICT, BASETYPE))]", depth)
|
||||||
self.emit(f"impl {structname} {{}}", depth)
|
self.emit(f"impl {struct_name} {{}}", depth)
|
||||||
for cons in sum.types:
|
for cons in sum.types:
|
||||||
self.visit(cons, sum.attributes, structname, depth)
|
self.visit(cons, sum.attributes, struct_name, depth)
|
||||||
|
|
||||||
def visitConstructor(self, cons, attrs, base, depth):
|
def visitConstructor(self, cons, attrs, base, depth):
|
||||||
self.gen_classdef(cons.name, cons.fields, attrs, depth, base)
|
self.gen_class_def(cons.name, cons.fields, attrs, depth, base)
|
||||||
|
|
||||||
def visitProduct(self, product, name, depth):
|
def visitProduct(self, product, name, depth):
|
||||||
self.gen_classdef(name, product.fields, product.attributes, depth)
|
self.gen_class_def(name, product.fields, product.attributes, depth)
|
||||||
|
|
||||||
def gen_classdef(self, name, fields, attrs, depth, base="AstNode"):
|
def gen_class_def(self, name, fields, attrs, depth, base="AstNode"):
|
||||||
structname = "Node" + get_rust_type(name)
|
struct_name = "Node" + rust_type_name(name)
|
||||||
self.emit(
|
self.emit(
|
||||||
f'#[pyclass(module = "_ast", name = {json.dumps(name)}, base = {json.dumps(base)})]',
|
f'#[pyclass(module = "_ast", name = {json.dumps(name)}, base = {json.dumps(base)})]',
|
||||||
depth,
|
depth,
|
||||||
)
|
)
|
||||||
self.emit(f"struct {structname};", depth)
|
self.emit(f"struct {struct_name};", depth)
|
||||||
self.emit("#[pyclass(flags(HAS_DICT, BASETYPE))]", depth)
|
self.emit("#[pyclass(flags(HAS_DICT, BASETYPE))]", depth)
|
||||||
self.emit(f"impl {structname} {{", depth)
|
self.emit(f"impl {struct_name} {{", depth)
|
||||||
self.emit("#[extend_class]", depth + 1)
|
self.emit("#[extend_class]", depth + 1)
|
||||||
self.emit(
|
self.emit(
|
||||||
"fn extend_class_with_fields(ctx: &Context, class: &'static Py<PyType>) {",
|
"fn extend_class_with_fields(ctx: &Context, class: &'static Py<PyType>) {",
|
||||||
|
@ -745,7 +749,7 @@ class ExtendModuleVisitor(EmitVisitor):
|
||||||
self.visit(type.value, type.name, depth)
|
self.visit(type.value, type.name, depth)
|
||||||
|
|
||||||
def visitSum(self, sum, name, depth):
|
def visitSum(self, sum, name, depth):
|
||||||
rust_name = get_rust_type(name)
|
rust_name = rust_type_name(name)
|
||||||
self.emit(
|
self.emit(
|
||||||
f"{json.dumps(name)} => NodeKind{rust_name}::make_class(&vm.ctx),", depth
|
f"{json.dumps(name)} => NodeKind{rust_name}::make_class(&vm.ctx),", depth
|
||||||
)
|
)
|
||||||
|
@ -759,7 +763,7 @@ class ExtendModuleVisitor(EmitVisitor):
|
||||||
self.gen_extension(name, depth)
|
self.gen_extension(name, depth)
|
||||||
|
|
||||||
def gen_extension(self, name, depth):
|
def gen_extension(self, name, depth):
|
||||||
rust_name = get_rust_type(name)
|
rust_name = rust_type_name(name)
|
||||||
self.emit(f"{json.dumps(name)} => Node{rust_name}::make_class(&vm.ctx),", depth)
|
self.emit(f"{json.dumps(name)} => Node{rust_name}::make_class(&vm.ctx),", depth)
|
||||||
|
|
||||||
|
|
||||||
|
@ -772,56 +776,57 @@ class TraitImplVisitor(EmitVisitor):
|
||||||
self.visit(type.value, type.name, depth)
|
self.visit(type.value, type.name, depth)
|
||||||
|
|
||||||
def visitSum(self, sum, name, depth):
|
def visitSum(self, sum, name, depth):
|
||||||
rustname = enumname = get_rust_type(name)
|
rust_name = enum_name = rust_type_name(name)
|
||||||
if sum.attributes:
|
if sum.attributes:
|
||||||
rustname = enumname + "Kind"
|
rust_name = enum_name + "Kind"
|
||||||
|
|
||||||
self.emit(f"impl NamedNode for ast::located::{rustname} {{", depth)
|
self.emit(f"impl NamedNode for ast::located::{rust_name} {{", depth)
|
||||||
self.emit(f"const NAME: &'static str = {json.dumps(name)};", depth + 1)
|
self.emit(f"const NAME: &'static str = {json.dumps(name)};", depth + 1)
|
||||||
self.emit("}", depth)
|
self.emit("}", depth)
|
||||||
self.emit(f"impl Node for ast::located::{rustname} {{", depth)
|
self.emit(f"impl Node for ast::located::{rust_name} {{", depth)
|
||||||
self.emit(
|
self.emit(
|
||||||
"fn ast_to_object(self, _vm: &VirtualMachine) -> PyObjectRef {", depth + 1
|
"fn ast_to_object(self, _vm: &VirtualMachine) -> PyObjectRef {", depth + 1
|
||||||
)
|
)
|
||||||
self.emit("match self {", depth + 2)
|
self.emit("match self {", depth + 2)
|
||||||
for variant in sum.types:
|
for variant in sum.types:
|
||||||
self.constructor_to_object(variant, enumname, rustname, depth + 3)
|
self.constructor_to_object(variant, enum_name, rust_name, depth + 3)
|
||||||
self.emit("}", depth + 2)
|
self.emit("}", depth + 2)
|
||||||
self.emit("}", depth + 1)
|
self.emit("}", depth + 1)
|
||||||
self.emit(
|
self.emit(
|
||||||
"fn ast_from_object(_vm: &VirtualMachine, _object: PyObjectRef) -> PyResult<Self> {",
|
"fn ast_from_object(_vm: &VirtualMachine, _object: PyObjectRef) -> PyResult<Self> {",
|
||||||
depth + 1,
|
depth + 1,
|
||||||
)
|
)
|
||||||
self.gen_sum_fromobj(sum, name, enumname, rustname, depth + 2)
|
self.gen_sum_from_object(sum, name, enum_name, rust_name, depth + 2)
|
||||||
self.emit("}", depth + 1)
|
self.emit("}", depth + 1)
|
||||||
self.emit("}", depth)
|
self.emit("}", depth)
|
||||||
|
|
||||||
def constructor_to_object(self, cons, enumname, rustname, depth):
|
def constructor_to_object(self, cons, enum_name, rust_name, depth):
|
||||||
self.emit(f"ast::located::{rustname}::{cons.name}", depth)
|
self.emit(f"ast::located::{rust_name}::{cons.name}", depth)
|
||||||
if cons.fields:
|
if cons.fields:
|
||||||
fields_pattern = self.make_pattern(cons.fields)
|
fields_pattern = self.make_pattern(cons.fields)
|
||||||
self.emit(
|
self.emit(
|
||||||
f"( ast::located::{enumname}{cons.name} {{ {fields_pattern} }} )", depth
|
f"( ast::located::{enum_name}{cons.name} {{ {fields_pattern} }} )",
|
||||||
|
depth,
|
||||||
)
|
)
|
||||||
self.emit(" => {", depth)
|
self.emit(" => {", depth)
|
||||||
self.make_node(cons.name, cons.fields, depth + 1)
|
self.make_node(cons.name, cons.fields, depth + 1)
|
||||||
self.emit("}", depth)
|
self.emit("}", depth)
|
||||||
|
|
||||||
def visitProduct(self, product, name, depth):
|
def visitProduct(self, product, name, depth):
|
||||||
structname = get_rust_type(name)
|
struct_name = rust_type_name(name)
|
||||||
if product.attributes:
|
if product.attributes:
|
||||||
structname += "Data"
|
struct_name += "Data"
|
||||||
|
|
||||||
self.emit(f"impl NamedNode for ast::located::{structname} {{", depth)
|
self.emit(f"impl NamedNode for ast::located::{struct_name} {{", depth)
|
||||||
self.emit(f"const NAME: &'static str = {json.dumps(name)};", depth + 1)
|
self.emit(f"const NAME: &'static str = {json.dumps(name)};", depth + 1)
|
||||||
self.emit("}", depth)
|
self.emit("}", depth)
|
||||||
self.emit(f"impl Node for ast::located::{structname} {{", depth)
|
self.emit(f"impl Node for ast::located::{struct_name} {{", depth)
|
||||||
self.emit(
|
self.emit(
|
||||||
"fn ast_to_object(self, _vm: &VirtualMachine) -> PyObjectRef {", depth + 1
|
"fn ast_to_object(self, _vm: &VirtualMachine) -> PyObjectRef {", depth + 1
|
||||||
)
|
)
|
||||||
fields_pattern = self.make_pattern(product.fields)
|
fields_pattern = self.make_pattern(product.fields)
|
||||||
self.emit(
|
self.emit(
|
||||||
f"let ast::located::{structname} {{ {fields_pattern} }} = self;", depth + 2
|
f"let ast::located::{struct_name} {{ {fields_pattern} }} = self;", depth + 2
|
||||||
)
|
)
|
||||||
self.make_node(name, product.fields, depth + 2)
|
self.make_node(name, product.fields, depth + 2)
|
||||||
self.emit("}", depth + 1)
|
self.emit("}", depth + 1)
|
||||||
|
@ -829,12 +834,12 @@ class TraitImplVisitor(EmitVisitor):
|
||||||
"fn ast_from_object(_vm: &VirtualMachine, _object: PyObjectRef) -> PyResult<Self> {",
|
"fn ast_from_object(_vm: &VirtualMachine, _object: PyObjectRef) -> PyResult<Self> {",
|
||||||
depth + 1,
|
depth + 1,
|
||||||
)
|
)
|
||||||
self.gen_product_fromobj(product, name, structname, depth + 2)
|
self.gen_product_from_object(product, name, struct_name, depth + 2)
|
||||||
self.emit("}", depth + 1)
|
self.emit("}", depth + 1)
|
||||||
self.emit("}", depth)
|
self.emit("}", depth)
|
||||||
|
|
||||||
def make_node(self, variant, fields, depth):
|
def make_node(self, variant, fields, depth):
|
||||||
rust_variant = get_rust_type(variant)
|
rust_variant = rust_type_name(variant)
|
||||||
self.emit(
|
self.emit(
|
||||||
f"let _node = AstNode.into_ref_with_type(_vm, Node{rust_variant}::static_type().to_owned()).unwrap();",
|
f"let _node = AstNode.into_ref_with_type(_vm, Node{rust_variant}::static_type().to_owned()).unwrap();",
|
||||||
depth,
|
depth,
|
||||||
|
@ -851,9 +856,9 @@ class TraitImplVisitor(EmitVisitor):
|
||||||
def make_pattern(self, fields):
|
def make_pattern(self, fields):
|
||||||
return ",".join(rust_field(f.name) for f in fields)
|
return ",".join(rust_field(f.name) for f in fields)
|
||||||
|
|
||||||
def gen_sum_fromobj(self, sum, sumname, enumname, rustname, depth):
|
def gen_sum_from_object(self, sum, sum_name, enum_name, rust_name, depth):
|
||||||
# if sum.attributes:
|
# if sum.attributes:
|
||||||
# self.extract_location(sumname, depth)
|
# self.extract_location(sum_name, depth)
|
||||||
|
|
||||||
self.emit("let _cls = _object.class();", depth)
|
self.emit("let _cls = _object.class();", depth)
|
||||||
self.emit("Ok(", depth)
|
self.emit("Ok(", depth)
|
||||||
|
@ -861,26 +866,26 @@ class TraitImplVisitor(EmitVisitor):
|
||||||
self.emit(f"if _cls.is(Node{cons.name}::static_type()) {{", depth)
|
self.emit(f"if _cls.is(Node{cons.name}::static_type()) {{", depth)
|
||||||
if cons.fields:
|
if cons.fields:
|
||||||
self.emit(
|
self.emit(
|
||||||
f"ast::located::{rustname}::{cons.name} (ast::located::{enumname}{cons.name} {{",
|
f"ast::located::{rust_name}::{cons.name} (ast::located::{enum_name}{cons.name} {{",
|
||||||
depth + 1,
|
depth + 1,
|
||||||
)
|
)
|
||||||
self.gen_construction_fields(cons, sumname, depth + 1)
|
self.gen_construction_fields(cons, sum_name, depth + 1)
|
||||||
self.emit("})", depth + 1)
|
self.emit("})", depth + 1)
|
||||||
else:
|
else:
|
||||||
self.emit(f"ast::located::{rustname}::{cons.name}", depth + 1)
|
self.emit(f"ast::located::{rust_name}::{cons.name}", depth + 1)
|
||||||
self.emit("} else", depth)
|
self.emit("} else", depth)
|
||||||
|
|
||||||
self.emit("{", depth)
|
self.emit("{", depth)
|
||||||
msg = f'format!("expected some sort of {sumname}, but got {{}}",_object.repr(_vm)?)'
|
msg = f'format!("expected some sort of {sum_name}, but got {{}}",_object.repr(_vm)?)'
|
||||||
self.emit(f"return Err(_vm.new_type_error({msg}));", depth + 1)
|
self.emit(f"return Err(_vm.new_type_error({msg}));", depth + 1)
|
||||||
self.emit("})", depth)
|
self.emit("})", depth)
|
||||||
|
|
||||||
def gen_product_fromobj(self, product, prodname, structname, depth):
|
def gen_product_from_object(self, product, product_name, struct_name, depth):
|
||||||
# if product.attributes:
|
# if product.attributes:
|
||||||
# self.extract_location(prodname, depth)
|
# self.extract_location(product_name, depth)
|
||||||
|
|
||||||
self.emit("Ok(", depth)
|
self.emit("Ok(", depth)
|
||||||
self.gen_construction(structname, product, prodname, depth + 1)
|
self.gen_construction(struct_name, product, product_name, depth + 1)
|
||||||
self.emit(")", depth)
|
self.emit(")", depth)
|
||||||
|
|
||||||
def gen_construction_fields(self, cons, name, depth):
|
def gen_construction_fields(self, cons, name, depth):
|
||||||
|
@ -926,19 +931,19 @@ class ChainOfVisitors:
|
||||||
v.emit("", 0)
|
v.emit("", 0)
|
||||||
|
|
||||||
|
|
||||||
def write_ast_def(mod, typeinfo, f):
|
def write_ast_def(mod, type_info, f):
|
||||||
StructVisitor(f, typeinfo).visit(mod)
|
StructVisitor(f, type_info).visit(mod)
|
||||||
|
|
||||||
|
|
||||||
def write_fold_def(mod, typeinfo, f):
|
def write_fold_def(mod, type_info, f):
|
||||||
FoldModuleVisitor(f, typeinfo).visit(mod)
|
FoldModuleVisitor(f, type_info).visit(mod)
|
||||||
|
|
||||||
|
|
||||||
def write_visitor_def(mod, typeinfo, f):
|
def write_visitor_def(mod, type_info, f):
|
||||||
VisitorModuleVisitor(f, typeinfo).visit(mod)
|
VisitorModuleVisitor(f, type_info).visit(mod)
|
||||||
|
|
||||||
|
|
||||||
def write_located_def(mod, typeinfo, f):
|
def write_located_def(mod, type_info, f):
|
||||||
f.write(
|
f.write(
|
||||||
textwrap.dedent(
|
textwrap.dedent(
|
||||||
"""
|
"""
|
||||||
|
@ -948,10 +953,10 @@ def write_located_def(mod, typeinfo, f):
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
for info in typeinfo.values():
|
for info in type_info.values():
|
||||||
if info.empty_field:
|
if info.empty_field:
|
||||||
continue
|
continue
|
||||||
if info.has_userdata:
|
if info.has_user_data:
|
||||||
generics = "::<SourceRange>"
|
generics = "::<SourceRange>"
|
||||||
else:
|
else:
|
||||||
generics = ""
|
generics = ""
|
||||||
|
@ -966,7 +971,7 @@ def write_located_def(mod, typeinfo, f):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def write_ast_mod(mod, typeinfo, f):
|
def write_ast_mod(mod, type_info, f):
|
||||||
f.write(
|
f.write(
|
||||||
textwrap.dedent(
|
textwrap.dedent(
|
||||||
"""
|
"""
|
||||||
|
@ -979,9 +984,9 @@ def write_ast_mod(mod, typeinfo, f):
|
||||||
)
|
)
|
||||||
|
|
||||||
c = ChainOfVisitors(
|
c = ChainOfVisitors(
|
||||||
ClassDefVisitor(f, typeinfo),
|
class_defVisitor(f, type_info),
|
||||||
TraitImplVisitor(f, typeinfo),
|
TraitImplVisitor(f, type_info),
|
||||||
ExtendModuleVisitor(f, typeinfo),
|
ExtendModuleVisitor(f, type_info),
|
||||||
)
|
)
|
||||||
c.visit(mod)
|
c.visit(mod)
|
||||||
|
|
||||||
|
@ -992,7 +997,7 @@ def main(
|
||||||
module_filename,
|
module_filename,
|
||||||
dump_module=False,
|
dump_module=False,
|
||||||
):
|
):
|
||||||
auto_gen_msg = AUTOGEN_MESSAGE.format("/".join(Path(__file__).parts[-2:]))
|
auto_gen_msg = AUTO_GEN_MESSAGE.format("/".join(Path(__file__).parts[-2:]))
|
||||||
mod = asdl.parse(input_filename)
|
mod = asdl.parse(input_filename)
|
||||||
if dump_module:
|
if dump_module:
|
||||||
print("Parsed Module:")
|
print("Parsed Module:")
|
||||||
|
@ -1000,8 +1005,8 @@ def main(
|
||||||
if not asdl.check(mod):
|
if not asdl.check(mod):
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
typeinfo = {}
|
type_info = {}
|
||||||
FindUserdataTypesVisitor(typeinfo).visit(mod)
|
FindUserDataTypesVisitor(type_info).visit(mod)
|
||||||
|
|
||||||
for filename, write in [
|
for filename, write in [
|
||||||
("generic", write_ast_def),
|
("generic", write_ast_def),
|
||||||
|
@ -1011,11 +1016,11 @@ def main(
|
||||||
]:
|
]:
|
||||||
with (ast_dir / f"{filename}.rs").open("w") as f:
|
with (ast_dir / f"{filename}.rs").open("w") as f:
|
||||||
f.write(auto_gen_msg)
|
f.write(auto_gen_msg)
|
||||||
write(mod, typeinfo, f)
|
write(mod, type_info, f)
|
||||||
|
|
||||||
with module_filename.open("w") as module_file:
|
with module_filename.open("w") as module_file:
|
||||||
module_file.write(auto_gen_msg)
|
module_file.write(auto_gen_msg)
|
||||||
write_ast_mod(mod, typeinfo, module_file)
|
write_ast_mod(mod, type_info, module_file)
|
||||||
|
|
||||||
print(f"{ast_dir}, {module_filename} regenerated.")
|
print(f"{ast_dir}, {module_filename} regenerated.")
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ pub mod fold {
|
||||||
#[cfg(feature = "visitor")]
|
#[cfg(feature = "visitor")]
|
||||||
mod visitor {
|
mod visitor {
|
||||||
use super::generic::*;
|
use super::generic::*;
|
||||||
|
|
||||||
include!("gen/visitor.rs");
|
include!("gen/visitor.rs");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ pub(crate) const fn choose_quote(
|
||||||
Quote::Double => (double_count, single_count),
|
Quote::Double => (double_count, single_count),
|
||||||
};
|
};
|
||||||
|
|
||||||
// always use primary unless we have primary but no seconday
|
// always use primary unless we have primary but no secondary
|
||||||
let use_secondary = primary_count > 0 && secondary_count == 0;
|
let use_secondary = primary_count > 0 && secondary_count == 0;
|
||||||
if use_secondary {
|
if use_secondary {
|
||||||
(preferred_quote.swap(), secondary_count)
|
(preferred_quote.swap(), secondary_count)
|
||||||
|
@ -242,7 +242,7 @@ impl<'a> Escape for UnicodeEscape<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod unicode_escapse_tests {
|
mod unicode_escape_tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
3
scripts/cspell.sh
Normal file
3
scripts/cspell.sh
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/bash
|
||||||
|
cspell "ast/**/*.rs" "literal/**/*.rs" "core/**/*.rs" "parser/**/*.rs"
|
||||||
|
cspell ast/asdl_rs.py
|
Loading…
Add table
Add a link
Reference in a new issue