Remove asdl (#21)
This removes the ASDL code generation in favor of handwriting the AST. The motivations for moving away from the ASDL are: * CPython compatibility is no longer a goal * The ASDL grammar isn't as expressive as we would like * The codegen scripts have a high complexity which makes extensions time consuming * We don't make heavy use of code generation (compared to e.g. RustPython that generates Pyo3 bindings, a fold implementation etc). We may want to revisit a grammar based code generation in the future, e.g. by using [ungrammar](https://github.com/rust-analyzer/ungrammar)
This commit is contained in:
1
.github/workflows/ci.yaml
vendored
1
.github/workflows/ci.yaml
vendored
@@ -73,4 +73,3 @@ jobs:
|
||||
'core/**/*.rs'
|
||||
'literal/**/*.rs'
|
||||
'parser/**/*.rs'
|
||||
'ast/asdl_rs.py'
|
||||
|
||||
147
ast/Python.asdl
147
ast/Python.asdl
@@ -1,147 +0,0 @@
|
||||
-- ASDL's 4 builtin types are:
|
||||
-- identifier, int, string, constant, decorator
|
||||
|
||||
module Python
|
||||
{
|
||||
mod = Module(stmt* body, type_ignore* type_ignores)
|
||||
| Interactive(stmt* body)
|
||||
| Expression(expr body)
|
||||
| FunctionType(expr* argtypes, expr returns)
|
||||
|
||||
stmt = FunctionDef(identifier name, arguments args,
|
||||
stmt* body, decorator* decorator_list, expr? returns,
|
||||
string? type_comment)
|
||||
| AsyncFunctionDef(identifier name, arguments args,
|
||||
stmt* body, decorator* decorator_list, expr? returns,
|
||||
string? type_comment)
|
||||
|
||||
| ClassDef(identifier name,
|
||||
expr* bases,
|
||||
keyword* keywords,
|
||||
stmt* body,
|
||||
decorator* decorator_list)
|
||||
| Return(expr? value)
|
||||
|
||||
| Delete(expr* targets)
|
||||
| Assign(expr* targets, expr value, string? type_comment)
|
||||
| AugAssign(expr target, operator op, expr value)
|
||||
-- 'simple' indicates that we annotate simple name without parens
|
||||
| AnnAssign(expr target, expr annotation, expr? value, int simple)
|
||||
|
||||
-- use 'orelse' because else is a keyword in target languages
|
||||
| For(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)
|
||||
| AsyncFor(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)
|
||||
| While(expr test, stmt* body, stmt* orelse)
|
||||
| If(expr test, stmt* body, stmt* orelse)
|
||||
| With(withitem* items, stmt* body, string? type_comment)
|
||||
| AsyncWith(withitem* items, stmt* body, string? type_comment)
|
||||
|
||||
| Match(expr subject, match_case* cases)
|
||||
|
||||
| Raise(expr? exc, expr? cause)
|
||||
| Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)
|
||||
| TryStar(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)
|
||||
| Assert(expr test, expr? msg)
|
||||
|
||||
| Import(alias* names)
|
||||
| ImportFrom(identifier? module, alias* names, int? level)
|
||||
|
||||
| Global(identifier* names)
|
||||
| Nonlocal(identifier* names)
|
||||
| Expr(expr value)
|
||||
| Pass | Break | Continue
|
||||
|
||||
-- col_offset is the byte offset in the utf8 string the parser uses
|
||||
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)
|
||||
|
||||
-- BoolOp() can use left & right?
|
||||
expr = BoolOp(boolop op, expr* values)
|
||||
| NamedExpr(expr target, expr value)
|
||||
| BinOp(expr left, operator op, expr right)
|
||||
| UnaryOp(unaryop op, expr operand)
|
||||
| Lambda(arguments args, expr body)
|
||||
| IfExp(expr test, expr body, expr orelse)
|
||||
| Dict(expr* keys, expr* values)
|
||||
| Set(expr* elts)
|
||||
| ListComp(expr elt, comprehension* generators)
|
||||
| SetComp(expr elt, comprehension* generators)
|
||||
| DictComp(expr key, expr value, comprehension* generators)
|
||||
| GeneratorExp(expr elt, comprehension* generators)
|
||||
-- the grammar constrains where yield expressions can occur
|
||||
| Await(expr value)
|
||||
| Yield(expr? value)
|
||||
| YieldFrom(expr value)
|
||||
-- need sequences for compare to distinguish between
|
||||
-- x < 4 < 3 and (x < 4) < 3
|
||||
| Compare(expr left, cmpop* ops, expr* comparators)
|
||||
| Call(expr func, expr* args, keyword* keywords)
|
||||
| FormattedValue(expr value, int conversion, expr? format_spec)
|
||||
| JoinedStr(expr* values)
|
||||
| Constant(constant value, string? kind)
|
||||
|
||||
-- the following expression can appear in assignment context
|
||||
| Attribute(expr value, identifier attr, expr_context ctx)
|
||||
| Subscript(expr value, expr slice, expr_context ctx)
|
||||
| Starred(expr value, expr_context ctx)
|
||||
| Name(identifier id, expr_context ctx)
|
||||
| List(expr* elts, expr_context ctx)
|
||||
| Tuple(expr* elts, expr_context ctx)
|
||||
|
||||
-- can appear only in Subscript
|
||||
| Slice(expr? lower, expr? upper, expr? step)
|
||||
|
||||
-- col_offset is the byte offset in the utf8 string the parser uses
|
||||
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)
|
||||
|
||||
expr_context = Load | Store | Del
|
||||
|
||||
boolop = And | Or
|
||||
|
||||
operator = Add | Sub | Mult | MatMult | Div | Mod | Pow | LShift
|
||||
| RShift | BitOr | BitXor | BitAnd | FloorDiv
|
||||
|
||||
unaryop = Invert | Not | UAdd | USub
|
||||
|
||||
cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn
|
||||
|
||||
comprehension = (expr target, expr iter, expr* ifs, int is_async)
|
||||
|
||||
excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body)
|
||||
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)
|
||||
|
||||
arguments = (arg* posonlyargs, arg* args, arg? vararg, arg* kwonlyargs,
|
||||
expr* kw_defaults, arg? kwarg, expr* defaults)
|
||||
|
||||
arg = (identifier arg, expr? annotation, string? type_comment)
|
||||
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)
|
||||
|
||||
-- keyword arguments supplied to call (NULL identifier for **kwargs)
|
||||
keyword = (identifier? arg, expr value)
|
||||
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)
|
||||
|
||||
-- import name with optional 'as' alias.
|
||||
alias = (identifier name, identifier? asname)
|
||||
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)
|
||||
|
||||
withitem = (expr context_expr, expr? optional_vars)
|
||||
|
||||
match_case = (pattern pattern, expr? guard, stmt* body)
|
||||
|
||||
pattern = MatchValue(expr value)
|
||||
| MatchSingleton(constant value)
|
||||
| MatchSequence(pattern* patterns)
|
||||
| MatchMapping(expr* keys, pattern* patterns, identifier? rest)
|
||||
| MatchClass(expr cls, pattern* patterns, identifier* kwd_attrs, pattern* kwd_patterns)
|
||||
|
||||
| MatchStar(identifier? name)
|
||||
-- The optional "rest" MatchMapping parameter handles capturing extra mapping keys
|
||||
|
||||
| MatchAs(pattern? pattern, identifier? name)
|
||||
| MatchOr(pattern* patterns)
|
||||
|
||||
attributes (int lineno, int col_offset, int end_lineno, int end_col_offset)
|
||||
|
||||
type_ignore = TypeIgnore(int lineno, string tag)
|
||||
|
||||
decorator = (expr expression)
|
||||
}
|
||||
385
ast/asdl.py
385
ast/asdl.py
@@ -1,385 +0,0 @@
|
||||
#-------------------------------------------------------------------------------
|
||||
# Parser for ASDL [1] definition files. Reads in an ASDL description and parses
|
||||
# it into an AST that describes it.
|
||||
#
|
||||
# The EBNF we're parsing here: Figure 1 of the paper [1]. Extended to support
|
||||
# modules and attributes after a product. Words starting with Capital letters
|
||||
# are terminals. Literal tokens are in "double quotes". Others are
|
||||
# non-terminals. Id is either TokenId or ConstructorId.
|
||||
#
|
||||
# module ::= "module" Id "{" [definitions] "}"
|
||||
# definitions ::= { TypeId "=" type }
|
||||
# type ::= product | sum
|
||||
# product ::= fields ["attributes" fields]
|
||||
# fields ::= "(" { field, "," } field ")"
|
||||
# field ::= TypeId ["?" | "*"] [Id]
|
||||
# sum ::= constructor { "|" constructor } ["attributes" fields]
|
||||
# constructor ::= ConstructorId [fields]
|
||||
#
|
||||
# [1] "The Zephyr Abstract Syntax Description Language" by Wang, et. al. See
|
||||
# http://asdl.sourceforge.net/
|
||||
#-------------------------------------------------------------------------------
|
||||
from collections import namedtuple
|
||||
import re
|
||||
|
||||
__all__ = [
|
||||
'builtin_types', 'parse', 'AST', 'Module', 'Type', 'Constructor',
|
||||
'Field', 'Sum', 'Product', 'VisitorBase', 'Check', 'check']
|
||||
|
||||
# The following classes define nodes into which the ASDL description is parsed.
|
||||
# Note: this is a "meta-AST". ASDL files (such as Python.asdl) describe the AST
|
||||
# structure used by a programming language. But ASDL files themselves need to be
|
||||
# parsed. This module parses ASDL files and uses a simple AST to represent them.
|
||||
# See the EBNF at the top of the file to understand the logical connection
|
||||
# between the various node types.
|
||||
|
||||
builtin_types = {'identifier', 'string', 'int', 'constant'}
|
||||
|
||||
class AST:
|
||||
def __repr__(self):
|
||||
raise NotImplementedError
|
||||
|
||||
class Module(AST):
|
||||
def __init__(self, name, dfns):
|
||||
self.name = name
|
||||
self.dfns = dfns
|
||||
self.types = {type.name: type.value for type in dfns}
|
||||
|
||||
def __repr__(self):
|
||||
return 'Module({0.name}, {0.dfns})'.format(self)
|
||||
|
||||
class Type(AST):
|
||||
def __init__(self, name, value):
|
||||
self.name = name
|
||||
self.value = value
|
||||
|
||||
def __repr__(self):
|
||||
return 'Type({0.name}, {0.value})'.format(self)
|
||||
|
||||
class Constructor(AST):
|
||||
def __init__(self, name, fields=None):
|
||||
self.name = name
|
||||
self.fields = fields or []
|
||||
|
||||
def __repr__(self):
|
||||
return 'Constructor({0.name}, {0.fields})'.format(self)
|
||||
|
||||
class Field(AST):
|
||||
def __init__(self, type, name=None, seq=False, opt=False):
|
||||
self.type = type
|
||||
self.name = name
|
||||
self.seq = seq
|
||||
self.opt = opt
|
||||
|
||||
def __str__(self):
|
||||
if self.seq:
|
||||
extra = "*"
|
||||
elif self.opt:
|
||||
extra = "?"
|
||||
else:
|
||||
extra = ""
|
||||
|
||||
return "{}{} {}".format(self.type, extra, self.name)
|
||||
|
||||
def __repr__(self):
|
||||
if self.seq:
|
||||
extra = ", seq=True"
|
||||
elif self.opt:
|
||||
extra = ", opt=True"
|
||||
else:
|
||||
extra = ""
|
||||
if self.name is None:
|
||||
return 'Field({0.type}{1})'.format(self, extra)
|
||||
else:
|
||||
return 'Field({0.type}, {0.name}{1})'.format(self, extra)
|
||||
|
||||
class Sum(AST):
|
||||
def __init__(self, types, attributes=None):
|
||||
self.types = types
|
||||
self.attributes = attributes or []
|
||||
|
||||
def __repr__(self):
|
||||
if self.attributes:
|
||||
return 'Sum({0.types}, {0.attributes})'.format(self)
|
||||
else:
|
||||
return 'Sum({0.types})'.format(self)
|
||||
|
||||
class Product(AST):
|
||||
def __init__(self, fields, attributes=None):
|
||||
self.fields = fields
|
||||
self.attributes = attributes or []
|
||||
|
||||
def __repr__(self):
|
||||
if self.attributes:
|
||||
return 'Product({0.fields}, {0.attributes})'.format(self)
|
||||
else:
|
||||
return 'Product({0.fields})'.format(self)
|
||||
|
||||
# A generic visitor for the meta-AST that describes ASDL. This can be used by
|
||||
# emitters. Note that this visitor does not provide a generic visit method, so a
|
||||
# subclass needs to define visit methods from visitModule to as deep as the
|
||||
# interesting node.
|
||||
# We also define a Check visitor that makes sure the parsed ASDL is well-formed.
|
||||
|
||||
class VisitorBase(object):
|
||||
"""Generic tree visitor for ASTs."""
|
||||
def __init__(self):
|
||||
self.cache = {}
|
||||
|
||||
def visit(self, obj, *args):
|
||||
klass = obj.__class__
|
||||
meth = self.cache.get(klass)
|
||||
if meth is None:
|
||||
methname = "visit" + klass.__name__
|
||||
meth = getattr(self, methname, None)
|
||||
self.cache[klass] = meth
|
||||
if meth:
|
||||
try:
|
||||
meth(obj, *args)
|
||||
except Exception as e:
|
||||
print("Error visiting %r: %s" % (obj, e))
|
||||
raise
|
||||
|
||||
class Check(VisitorBase):
|
||||
"""A visitor that checks a parsed ASDL tree for correctness.
|
||||
|
||||
Errors are printed and accumulated.
|
||||
"""
|
||||
def __init__(self):
|
||||
super(Check, self).__init__()
|
||||
self.cons = {}
|
||||
self.errors = 0
|
||||
self.types = {}
|
||||
|
||||
def visitModule(self, mod):
|
||||
for dfn in mod.dfns:
|
||||
self.visit(dfn)
|
||||
|
||||
def visitType(self, type):
|
||||
self.visit(type.value, str(type.name))
|
||||
|
||||
def visitSum(self, sum, name):
|
||||
for t in sum.types:
|
||||
self.visit(t, name)
|
||||
|
||||
def visitConstructor(self, cons, name):
|
||||
key = str(cons.name)
|
||||
conflict = self.cons.get(key)
|
||||
if conflict is None:
|
||||
self.cons[key] = name
|
||||
else:
|
||||
print('Redefinition of constructor {}'.format(key))
|
||||
print('Defined in {} and {}'.format(conflict, name))
|
||||
self.errors += 1
|
||||
for f in cons.fields:
|
||||
self.visit(f, key)
|
||||
|
||||
def visitField(self, field, name):
|
||||
key = str(field.type)
|
||||
l = self.types.setdefault(key, []) # noqa
|
||||
l.append(name)
|
||||
|
||||
def visitProduct(self, prod, name):
|
||||
for f in prod.fields:
|
||||
self.visit(f, name)
|
||||
|
||||
def check(mod):
|
||||
"""Check the parsed ASDL tree for correctness.
|
||||
|
||||
Return True if success. For failure, the errors are printed out and False
|
||||
is returned.
|
||||
"""
|
||||
v = Check()
|
||||
v.visit(mod)
|
||||
|
||||
for t in v.types:
|
||||
if t not in mod.types and t not in builtin_types:
|
||||
v.errors += 1
|
||||
uses = ", ".join(v.types[t])
|
||||
print('Undefined type {}, used in {}'.format(t, uses))
|
||||
return not v.errors
|
||||
|
||||
# The ASDL parser itself comes next. The only interesting external interface
|
||||
# here is the top-level parse function.
|
||||
|
||||
def parse(filename):
|
||||
"""Parse ASDL from the given file and return a Module node describing it."""
|
||||
with open(filename, encoding="utf-8") as f:
|
||||
parser = ASDLParser()
|
||||
return parser.parse(f.read())
|
||||
|
||||
# Types for describing tokens in an ASDL specification.
|
||||
class TokenKind:
|
||||
"""TokenKind is provides a scope for enumerated token kinds."""
|
||||
(ConstructorId, TypeId, Equals, Comma, Question, Pipe, Asterisk,
|
||||
LParen, RParen, LBrace, RBrace) = range(11)
|
||||
|
||||
operator_table = {
|
||||
'=': Equals, ',': Comma, '?': Question, '|': Pipe, '(': LParen,
|
||||
')': RParen, '*': Asterisk, '{': LBrace, '}': RBrace}
|
||||
|
||||
Token = namedtuple('Token', 'kind value lineno')
|
||||
|
||||
class ASDLSyntaxError(Exception):
|
||||
def __init__(self, msg, lineno=None):
|
||||
self.msg = msg
|
||||
self.lineno = lineno or '<unknown>'
|
||||
|
||||
def __str__(self):
|
||||
return 'Syntax error on line {0.lineno}: {0.msg}'.format(self)
|
||||
|
||||
def tokenize_asdl(buf):
|
||||
"""Tokenize the given buffer. Yield Token objects."""
|
||||
for lineno, line in enumerate(buf.splitlines(), 1):
|
||||
for m in re.finditer(r'\s*(\w+|--.*|.)', line.strip()):
|
||||
c = m.group(1)
|
||||
if c[0].isalpha():
|
||||
# Some kind of identifier
|
||||
if c[0].isupper():
|
||||
yield Token(TokenKind.ConstructorId, c, lineno)
|
||||
else:
|
||||
yield Token(TokenKind.TypeId, c, lineno)
|
||||
elif c[:2] == '--':
|
||||
# Comment
|
||||
break
|
||||
else:
|
||||
# Operators
|
||||
try:
|
||||
op_kind = TokenKind.operator_table[c]
|
||||
except KeyError:
|
||||
raise ASDLSyntaxError('Invalid operator %s' % c, lineno)
|
||||
yield Token(op_kind, c, lineno)
|
||||
|
||||
class ASDLParser:
|
||||
"""Parser for ASDL files.
|
||||
|
||||
Create, then call the parse method on a buffer containing ASDL.
|
||||
This is a simple recursive descent parser that uses tokenize_asdl for the
|
||||
lexing.
|
||||
"""
|
||||
def __init__(self):
|
||||
self._tokenizer = None
|
||||
self.cur_token = None
|
||||
|
||||
def parse(self, buf):
|
||||
"""Parse the ASDL in the buffer and return an AST with a Module root.
|
||||
"""
|
||||
self._tokenizer = tokenize_asdl(buf)
|
||||
self._advance()
|
||||
return self._parse_module()
|
||||
|
||||
def _parse_module(self):
|
||||
if self._at_keyword('module'):
|
||||
self._advance()
|
||||
else:
|
||||
raise ASDLSyntaxError(
|
||||
'Expected "module" (found {})'.format(self.cur_token.value),
|
||||
self.cur_token.lineno)
|
||||
name = self._match(self._id_kinds)
|
||||
self._match(TokenKind.LBrace)
|
||||
defs = self._parse_definitions()
|
||||
self._match(TokenKind.RBrace)
|
||||
return Module(name, defs)
|
||||
|
||||
def _parse_definitions(self):
|
||||
defs = []
|
||||
while self.cur_token.kind == TokenKind.TypeId:
|
||||
typename = self._advance()
|
||||
self._match(TokenKind.Equals)
|
||||
type = self._parse_type()
|
||||
defs.append(Type(typename, type))
|
||||
return defs
|
||||
|
||||
def _parse_type(self):
|
||||
if self.cur_token.kind == TokenKind.LParen:
|
||||
# If we see a (, it's a product
|
||||
return self._parse_product()
|
||||
else:
|
||||
# Otherwise it's a sum. Look for ConstructorId
|
||||
sumlist = [Constructor(self._match(TokenKind.ConstructorId),
|
||||
self._parse_optional_fields())]
|
||||
while self.cur_token.kind == TokenKind.Pipe:
|
||||
# More constructors
|
||||
self._advance()
|
||||
sumlist.append(Constructor(
|
||||
self._match(TokenKind.ConstructorId),
|
||||
self._parse_optional_fields()))
|
||||
return Sum(sumlist, self._parse_optional_attributes())
|
||||
|
||||
def _parse_product(self):
|
||||
return Product(self._parse_fields(), self._parse_optional_attributes())
|
||||
|
||||
def _parse_fields(self):
|
||||
fields = []
|
||||
self._match(TokenKind.LParen)
|
||||
while self.cur_token.kind == TokenKind.TypeId:
|
||||
typename = self._advance()
|
||||
is_seq, is_opt = self._parse_optional_field_quantifier()
|
||||
id = (self._advance() if self.cur_token.kind in self._id_kinds
|
||||
else None)
|
||||
fields.append(Field(typename, id, seq=is_seq, opt=is_opt))
|
||||
if self.cur_token.kind == TokenKind.RParen:
|
||||
break
|
||||
elif self.cur_token.kind == TokenKind.Comma:
|
||||
self._advance()
|
||||
self._match(TokenKind.RParen)
|
||||
return fields
|
||||
|
||||
def _parse_optional_fields(self):
|
||||
if self.cur_token.kind == TokenKind.LParen:
|
||||
return self._parse_fields()
|
||||
else:
|
||||
return None
|
||||
|
||||
def _parse_optional_attributes(self):
|
||||
if self._at_keyword('attributes'):
|
||||
self._advance()
|
||||
return self._parse_fields()
|
||||
else:
|
||||
return None
|
||||
|
||||
def _parse_optional_field_quantifier(self):
|
||||
is_seq, is_opt = False, False
|
||||
if self.cur_token.kind == TokenKind.Asterisk:
|
||||
is_seq = True
|
||||
self._advance()
|
||||
elif self.cur_token.kind == TokenKind.Question:
|
||||
is_opt = True
|
||||
self._advance()
|
||||
return is_seq, is_opt
|
||||
|
||||
def _advance(self):
|
||||
""" Return the value of the current token and read the next one into
|
||||
self.cur_token.
|
||||
"""
|
||||
cur_val = None if self.cur_token is None else self.cur_token.value
|
||||
try:
|
||||
self.cur_token = next(self._tokenizer)
|
||||
except StopIteration:
|
||||
self.cur_token = None
|
||||
return cur_val
|
||||
|
||||
_id_kinds = (TokenKind.ConstructorId, TokenKind.TypeId)
|
||||
|
||||
def _match(self, kind):
|
||||
"""The 'match' primitive of RD parsers.
|
||||
|
||||
* Verifies that the current token is of the given kind (kind can
|
||||
be a tuple, in which the kind must match one of its members).
|
||||
* Returns the value of the current token
|
||||
* Reads in the next token
|
||||
"""
|
||||
if (isinstance(kind, tuple) and self.cur_token.kind in kind or
|
||||
self.cur_token.kind == kind
|
||||
):
|
||||
value = self.cur_token.value
|
||||
self._advance()
|
||||
return value
|
||||
else:
|
||||
raise ASDLSyntaxError(
|
||||
'Unmatched {} (found {})'.format(kind, self.cur_token.kind),
|
||||
self.cur_token.lineno)
|
||||
|
||||
def _at_keyword(self, keyword):
|
||||
return (self.cur_token.kind == TokenKind.TypeId and
|
||||
self.cur_token.value == keyword)
|
||||
817
ast/asdl_rs.py
817
ast/asdl_rs.py
@@ -1,817 +0,0 @@
|
||||
# spell-checker:words dfn dfns
|
||||
|
||||
# ! /usr/bin/env python
|
||||
"""Generate Rust code from an ASDL description."""
|
||||
|
||||
import re
|
||||
import sys
|
||||
import textwrap
|
||||
from argparse import ArgumentParser
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
import asdl
|
||||
|
||||
TABSIZE = 4
|
||||
AUTO_GEN_MESSAGE = "// File automatically generated by {}.\n\n"
|
||||
|
||||
BUILTIN_TYPE_NAMES = {
|
||||
"identifier": "Identifier",
|
||||
"string": "String",
|
||||
"int": "Int",
|
||||
"constant": "Constant",
|
||||
}
|
||||
assert BUILTIN_TYPE_NAMES.keys() == asdl.builtin_types
|
||||
|
||||
BUILTIN_INT_NAMES = {
|
||||
"simple": "bool",
|
||||
"is_async": "bool",
|
||||
"conversion": "ConversionFlag",
|
||||
}
|
||||
|
||||
RENAME_MAP = {
|
||||
"cmpop": "cmp_op",
|
||||
"unaryop": "unary_op",
|
||||
"boolop": "bool_op",
|
||||
"excepthandler": "except_handler",
|
||||
"withitem": "with_item",
|
||||
}
|
||||
|
||||
RUST_KEYWORDS = {
|
||||
"if",
|
||||
"while",
|
||||
"for",
|
||||
"return",
|
||||
"match",
|
||||
"try",
|
||||
"await",
|
||||
"yield",
|
||||
"in",
|
||||
"mod",
|
||||
"type",
|
||||
}
|
||||
|
||||
attributes = [
|
||||
asdl.Field("int", "lineno"),
|
||||
asdl.Field("int", "col_offset"),
|
||||
asdl.Field("int", "end_lineno"),
|
||||
asdl.Field("int", "end_col_offset"),
|
||||
]
|
||||
|
||||
ORIGINAL_NODE_WARNING = "NOTE: This type is different from original Python AST."
|
||||
|
||||
arg_with_default = asdl.Type(
|
||||
"arg_with_default",
|
||||
asdl.Product(
|
||||
[
|
||||
asdl.Field("arg", "def"),
|
||||
asdl.Field(
|
||||
"expr", "default", opt=True
|
||||
), # order is important for cost-free borrow!
|
||||
],
|
||||
),
|
||||
)
|
||||
arg_with_default.doc = f"""
|
||||
An alternative type of AST `arg`. This is used for each function argument that might have a default value.
|
||||
Used by `Arguments` original type.
|
||||
|
||||
{ORIGINAL_NODE_WARNING}
|
||||
""".strip()
|
||||
|
||||
alt_arguments = asdl.Type(
|
||||
"alt:arguments",
|
||||
asdl.Product(
|
||||
[
|
||||
asdl.Field("arg_with_default", "posonlyargs", seq=True),
|
||||
asdl.Field("arg_with_default", "args", seq=True),
|
||||
asdl.Field("arg", "vararg", opt=True),
|
||||
asdl.Field("arg_with_default", "kwonlyargs", seq=True),
|
||||
asdl.Field("arg", "kwarg", opt=True),
|
||||
]
|
||||
),
|
||||
)
|
||||
alt_arguments.doc = f"""
|
||||
An alternative type of AST `arguments`. This is parser-friendly and human-friendly definition of function arguments.
|
||||
This form also has advantage to implement pre-order traverse.
|
||||
`defaults` and `kw_defaults` fields are removed and the default values are placed under each `arg_with_default` typed argument.
|
||||
`vararg` and `kwarg` are still typed as `arg` because they never can have a default value.
|
||||
|
||||
The matching Python style AST type is [PythonArguments]. While [PythonArguments] has ordered `kwonlyargs` fields by
|
||||
default existence, [Arguments] has location-ordered kwonlyargs fields.
|
||||
|
||||
{ORIGINAL_NODE_WARNING}
|
||||
""".strip()
|
||||
|
||||
# Must be used only for rust types, not python types
|
||||
CUSTOM_TYPES = [
|
||||
alt_arguments,
|
||||
arg_with_default,
|
||||
]
|
||||
|
||||
CUSTOM_REPLACEMENTS = {
|
||||
"arguments": alt_arguments,
|
||||
}
|
||||
CUSTOM_ATTACHMENTS = [
|
||||
arg_with_default,
|
||||
]
|
||||
|
||||
|
||||
def maybe_custom(type):
|
||||
return CUSTOM_REPLACEMENTS.get(type.name, type)
|
||||
|
||||
|
||||
def rust_field_name(name):
|
||||
name = rust_type_name(name)
|
||||
return re.sub(r"(?<!^)(?=[A-Z])", "_", name).lower()
|
||||
|
||||
|
||||
def rust_type_name(name):
|
||||
"""Return a string for the C name of the type.
|
||||
|
||||
This function special cases the default types provided by asdl.
|
||||
"""
|
||||
name = RENAME_MAP.get(name, name)
|
||||
if name in asdl.builtin_types:
|
||||
builtin = BUILTIN_TYPE_NAMES[name]
|
||||
return builtin
|
||||
elif name.islower():
|
||||
return "".join(part.capitalize() for part in name.split("_"))
|
||||
else:
|
||||
return name
|
||||
|
||||
|
||||
def is_simple(sum):
|
||||
"""Return True if a sum is a simple.
|
||||
|
||||
A sum is simple if its types have no fields, e.g.
|
||||
unaryop = Invert | Not | UAdd | USub
|
||||
"""
|
||||
for t in sum.types:
|
||||
if t.fields:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def asdl_of(name, obj):
|
||||
if isinstance(obj, asdl.Product) or isinstance(obj, asdl.Constructor):
|
||||
fields = ", ".join(map(str, obj.fields))
|
||||
if fields:
|
||||
fields = "({})".format(fields)
|
||||
return "{}{}".format(name, fields)
|
||||
else:
|
||||
if is_simple(obj):
|
||||
types = " | ".join(type.name for type in obj.types)
|
||||
else:
|
||||
sep = "\n{}| ".format(" " * (len(name) + 1))
|
||||
types = sep.join(asdl_of(type.name, type) for type in obj.types)
|
||||
return "{} = {}".format(name, types)
|
||||
|
||||
|
||||
class TypeInfo:
|
||||
type: asdl.Type
|
||||
enum_name: Optional[str]
|
||||
has_user_data: Optional[bool]
|
||||
has_attributes: bool
|
||||
is_simple: bool
|
||||
children: set
|
||||
fields: Optional[Any]
|
||||
boxed: bool
|
||||
|
||||
def __init__(self, type):
|
||||
self.type = type
|
||||
self.enum_name = None
|
||||
self.has_user_data = None
|
||||
self.has_attributes = False
|
||||
self.is_simple = False
|
||||
self.children = set()
|
||||
self.fields = None
|
||||
self.boxed = False
|
||||
|
||||
def __repr__(self):
|
||||
return f"<TypeInfo: {self.name}>"
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.type.name
|
||||
|
||||
@property
|
||||
def is_type(self):
|
||||
return isinstance(self.type, asdl.Type)
|
||||
|
||||
@property
|
||||
def is_product(self):
|
||||
return self.is_type and isinstance(self.type.value, asdl.Product)
|
||||
|
||||
@property
|
||||
def is_sum(self):
|
||||
return self.is_type and isinstance(self.type.value, asdl.Sum)
|
||||
|
||||
@property
|
||||
def has_expr(self):
|
||||
return self.is_product and any(
|
||||
f.type != "identifier" for f in self.type.value.fields
|
||||
)
|
||||
|
||||
@property
|
||||
def is_custom(self):
|
||||
return self.type.name in [t.name for t in CUSTOM_TYPES]
|
||||
|
||||
@property
|
||||
def is_custom_replaced(self):
|
||||
return self.type.name in CUSTOM_REPLACEMENTS
|
||||
|
||||
@property
|
||||
def custom(self):
|
||||
if self.type.name in CUSTOM_REPLACEMENTS:
|
||||
return CUSTOM_REPLACEMENTS[self.type.name]
|
||||
return self.type
|
||||
|
||||
def no_cfg(self, typeinfo):
|
||||
if self.is_product:
|
||||
return self.has_attributes
|
||||
elif self.enum_name:
|
||||
return typeinfo[self.enum_name].has_attributes
|
||||
else:
|
||||
return self.has_attributes
|
||||
|
||||
@property
|
||||
def rust_name(self):
|
||||
return rust_type_name(self.name)
|
||||
|
||||
@property
|
||||
def full_field_name(self):
|
||||
name = self.name
|
||||
if name.startswith("alt:"):
|
||||
name = name[4:]
|
||||
if self.enum_name is None:
|
||||
return name
|
||||
else:
|
||||
return f"{self.enum_name}_{rust_field_name(name)}"
|
||||
|
||||
@property
|
||||
def full_type_name(self):
|
||||
name = self.name
|
||||
if name.startswith("alt:"):
|
||||
name = name[4:]
|
||||
rust_name = rust_type_name(name)
|
||||
if self.enum_name is not None:
|
||||
rust_name = rust_type_name(self.enum_name) + rust_name
|
||||
if self.is_custom_replaced:
|
||||
rust_name = "Python" + rust_name
|
||||
return rust_name
|
||||
|
||||
def determine_user_data(self, type_info, stack):
|
||||
if self.name in stack:
|
||||
return None
|
||||
stack.add(self.name)
|
||||
for child, child_seq in self.children:
|
||||
if child in asdl.builtin_types:
|
||||
continue
|
||||
child_info = type_info[child]
|
||||
child_has_user_data = child_info.determine_user_data(type_info, stack)
|
||||
if self.has_user_data is None and child_has_user_data is True:
|
||||
self.has_user_data = True
|
||||
|
||||
stack.remove(self.name)
|
||||
return self.has_user_data
|
||||
|
||||
|
||||
class TypeInfoMixin:
|
||||
type_info: Dict[str, TypeInfo]
|
||||
|
||||
def customized_type_info(self, type_name):
|
||||
info = self.type_info[type_name]
|
||||
return self.type_info[info.custom.name]
|
||||
|
||||
def has_user_data(self, typ):
|
||||
return self.type_info[typ].has_user_data
|
||||
|
||||
|
||||
class EmitVisitor(asdl.VisitorBase, TypeInfoMixin):
|
||||
"""Visit that emits lines"""
|
||||
|
||||
def __init__(self, file, type_info):
|
||||
self.file = file
|
||||
self.type_info = type_info
|
||||
self.identifiers = set()
|
||||
super(EmitVisitor, self).__init__()
|
||||
|
||||
def emit_identifier(self, name):
|
||||
name = str(name)
|
||||
if name in self.identifiers:
|
||||
return
|
||||
self.emit("_Py_IDENTIFIER(%s);" % name, 0)
|
||||
self.identifiers.add(name)
|
||||
|
||||
def emit(self, line, depth):
|
||||
if line:
|
||||
line = (" " * TABSIZE * depth) + textwrap.dedent(line)
|
||||
self.file.write(line + "\n")
|
||||
|
||||
|
||||
class FindUserDataTypesVisitor(asdl.VisitorBase):
|
||||
def __init__(self, type_info):
|
||||
self.type_info = type_info
|
||||
super().__init__()
|
||||
|
||||
def visitModule(self, mod):
|
||||
for dfn in mod.dfns + CUSTOM_TYPES:
|
||||
self.visit(dfn)
|
||||
stack = set()
|
||||
for info in self.type_info.values():
|
||||
info.determine_user_data(self.type_info, stack)
|
||||
|
||||
def visitType(self, type):
|
||||
key = type.name
|
||||
info = self.type_info[key] = TypeInfo(type)
|
||||
self.visit(type.value, info)
|
||||
|
||||
def visitSum(self, sum, info):
|
||||
type = info.type
|
||||
info.is_simple = is_simple(sum)
|
||||
for cons in sum.types:
|
||||
self.visit(cons, type, info.is_simple)
|
||||
|
||||
if info.is_simple:
|
||||
info.has_user_data = False
|
||||
return
|
||||
|
||||
for t in sum.types:
|
||||
self.add_children(t.name, t.fields)
|
||||
|
||||
if len(sum.types) > 1:
|
||||
info.boxed = True
|
||||
if sum.attributes:
|
||||
# attributes means located, which has the `range: R` field
|
||||
info.has_user_data = True
|
||||
info.has_attributes = True
|
||||
|
||||
for variant in sum.types:
|
||||
self.add_children(type.name, variant.fields)
|
||||
|
||||
def visitConstructor(self, cons, type, simple):
|
||||
info = self.type_info[cons.name] = TypeInfo(cons)
|
||||
info.enum_name = type.name
|
||||
info.is_simple = simple
|
||||
|
||||
def visitProduct(self, product, info):
|
||||
type = info.type
|
||||
if product.attributes:
|
||||
# attributes means located, which has the `range: R` field
|
||||
info.has_user_data = True
|
||||
info.has_attributes = True
|
||||
if len(product.fields) > 2:
|
||||
info.boxed = True
|
||||
self.add_children(type.name, product.fields)
|
||||
|
||||
def add_children(self, name, fields):
|
||||
self.type_info[name].children.update(
|
||||
(field.type, field.seq) for field in fields
|
||||
)
|
||||
|
||||
|
||||
def rust_field(field_name):
|
||||
if field_name in RUST_KEYWORDS:
|
||||
field_name += "_"
|
||||
return field_name
|
||||
|
||||
|
||||
class StructVisitor(EmitVisitor):
|
||||
"""Visitor to generate type-defs for AST."""
|
||||
|
||||
def __init__(self, *args, **kw):
|
||||
super().__init__(*args, **kw)
|
||||
|
||||
def emit_attrs(self, depth):
|
||||
self.emit("#[derive(Clone, Debug, PartialEq)]", depth)
|
||||
|
||||
def emit_range(self, has_attributes, depth):
|
||||
self.emit("pub range: TextRange,", depth + 1)
|
||||
|
||||
def visitModule(self, mod):
|
||||
self.emit_attrs(0)
|
||||
self.emit(
|
||||
"""
|
||||
#[derive(is_macro::Is)]
|
||||
pub enum Ast {
|
||||
""",
|
||||
0,
|
||||
)
|
||||
for dfn in mod.dfns:
|
||||
info = self.customized_type_info(dfn.name)
|
||||
dfn = info.custom
|
||||
rust_name = info.full_type_name
|
||||
if dfn.name == "mod":
|
||||
# This is exceptional rule to other enums.
|
||||
# Unlike other enums, this is justified because `Mod` is only used as
|
||||
# the top node of parsing result and never a child node of other nodes.
|
||||
# Because it will be very rarely used in very particular applications,
|
||||
# "ast_" prefix to everywhere seems less useful.
|
||||
self.emit('#[is(name = "module")]', 1)
|
||||
self.emit(f"{rust_name}({rust_name}),", 1)
|
||||
self.emit(
|
||||
"""
|
||||
}
|
||||
impl Node for Ast {
|
||||
const NAME: &'static str = "AST";
|
||||
const FIELD_NAMES: &'static [&'static str] = &[];
|
||||
}
|
||||
""",
|
||||
0,
|
||||
)
|
||||
for dfn in mod.dfns:
|
||||
info = self.customized_type_info(dfn.name)
|
||||
rust_name = info.full_type_name
|
||||
self.emit(
|
||||
f"""
|
||||
impl From<{rust_name}> for Ast {{
|
||||
fn from(node: {rust_name}) -> Self {{
|
||||
Ast::{rust_name}(node)
|
||||
}}
|
||||
}}
|
||||
""",
|
||||
0,
|
||||
)
|
||||
|
||||
for dfn in mod.dfns + CUSTOM_TYPES:
|
||||
self.visit(dfn)
|
||||
|
||||
def visitType(self, type, depth=0):
|
||||
if hasattr(type, "doc"):
|
||||
doc = "/// " + type.doc.replace("\n", "\n/// ") + "\n"
|
||||
else:
|
||||
doc = f"/// See also [{type.name}](https://docs.python.org/3/library/ast.html#ast.{type.name})"
|
||||
self.emit(doc, depth)
|
||||
self.visit(type.value, type, depth)
|
||||
|
||||
def visitSum(self, sum, type, depth):
|
||||
if is_simple(sum):
|
||||
self.simple_sum(sum, type, depth)
|
||||
else:
|
||||
self.sum_with_constructors(sum, type, depth)
|
||||
|
||||
self.emit(
|
||||
f"""
|
||||
impl Node for {rust_type_name(type.name)} {{
|
||||
const NAME: &'static str = "{type.name}";
|
||||
const FIELD_NAMES: &'static [&'static str] = &[];
|
||||
}}
|
||||
""",
|
||||
depth,
|
||||
)
|
||||
|
||||
def simple_sum(self, sum, type, depth):
|
||||
rust_name = rust_type_name(type.name)
|
||||
self.emit_attrs(depth)
|
||||
self.emit("#[derive(is_macro::Is, Copy, Hash, Eq)]", depth)
|
||||
self.emit(f"pub enum {rust_name} {{", depth)
|
||||
for cons in sum.types:
|
||||
self.emit(f"{cons.name},", depth + 1)
|
||||
self.emit("}", depth)
|
||||
self.emit(f"impl {rust_name} {{", depth)
|
||||
needs_escape = any(rust_field_name(t.name) in RUST_KEYWORDS for t in sum.types)
|
||||
if needs_escape:
|
||||
prefix = rust_field_name(type.name) + "_"
|
||||
else:
|
||||
prefix = ""
|
||||
for cons in sum.types:
|
||||
self.emit(
|
||||
f"""
|
||||
#[inline]
|
||||
pub const fn {prefix}{rust_field_name(cons.name)}(&self) -> Option<{rust_name}{cons.name}> {{
|
||||
match self {{
|
||||
{rust_name}::{cons.name} => Some({rust_name}{cons.name}),
|
||||
_ => None,
|
||||
}}
|
||||
}}
|
||||
""",
|
||||
depth,
|
||||
)
|
||||
self.emit("}", depth)
|
||||
self.emit("", depth)
|
||||
|
||||
for cons in sum.types:
|
||||
self.emit(
|
||||
f"""
|
||||
pub struct {rust_name}{cons.name};
|
||||
impl From<{rust_name}{cons.name}> for {rust_name} {{
|
||||
fn from(_: {rust_name}{cons.name}) -> Self {{
|
||||
{rust_name}::{cons.name}
|
||||
}}
|
||||
}}
|
||||
impl From<{rust_name}{cons.name}> for Ast {{
|
||||
fn from(_: {rust_name}{cons.name}) -> Self {{
|
||||
{rust_name}::{cons.name}.into()
|
||||
}}
|
||||
}}
|
||||
impl Node for {rust_name}{cons.name} {{
|
||||
const NAME: &'static str = "{cons.name}";
|
||||
const FIELD_NAMES: &'static [&'static str] = &[];
|
||||
}}
|
||||
impl std::cmp::PartialEq<{rust_name}> for {rust_name}{cons.name} {{
|
||||
#[inline]
|
||||
fn eq(&self, other: &{rust_name}) -> bool {{
|
||||
matches!(other, {rust_name}::{cons.name})
|
||||
}}
|
||||
}}
|
||||
""",
|
||||
0,
|
||||
)
|
||||
|
||||
def sum_with_constructors(self, sum, type, depth):
|
||||
type_info = self.type_info[type.name]
|
||||
rust_name = rust_type_name(type.name)
|
||||
|
||||
self.emit_attrs(depth)
|
||||
self.emit("#[derive(is_macro::Is)]", depth)
|
||||
self.emit(f"pub enum {rust_name} {{", depth)
|
||||
needs_escape = any(rust_field_name(t.name) in RUST_KEYWORDS for t in sum.types)
|
||||
for t in sum.types:
|
||||
if needs_escape:
|
||||
self.emit(
|
||||
f'#[is(name = "{rust_field_name(t.name)}_{rust_name.lower()}")]',
|
||||
depth + 1,
|
||||
)
|
||||
self.emit(f"{t.name}({rust_name}{t.name}),", depth + 1)
|
||||
self.emit("}", depth)
|
||||
self.emit("", depth)
|
||||
|
||||
for t in sum.types:
|
||||
self.sum_subtype_struct(type_info, t, rust_name, depth)
|
||||
|
||||
def sum_subtype_struct(self, sum_type_info, t, rust_name, depth):
|
||||
self.emit(
|
||||
f"""/// See also [{t.name}](https://docs.python.org/3/library/ast.html#ast.{t.name})""",
|
||||
depth,
|
||||
)
|
||||
self.emit_attrs(depth)
|
||||
payload_name = f"{rust_name}{t.name}"
|
||||
self.emit(f"pub struct {payload_name} {{", depth)
|
||||
self.emit_range(sum_type_info.has_attributes, depth)
|
||||
for f in t.fields:
|
||||
self.visit(f, sum_type_info, "pub ", depth + 1, t.name)
|
||||
|
||||
assert sum_type_info.has_attributes == self.type_info[t.name].no_cfg(
|
||||
self.type_info
|
||||
)
|
||||
|
||||
self.emit("}", depth)
|
||||
field_names = [f'"{f.name}"' for f in t.fields]
|
||||
self.emit(
|
||||
f"""
|
||||
impl Node for {payload_name} {{
|
||||
const NAME: &'static str = "{t.name}";
|
||||
const FIELD_NAMES: &'static [&'static str] = &[{', '.join(field_names)}];
|
||||
}}
|
||||
impl From<{payload_name}> for {rust_name} {{
|
||||
fn from(payload: {payload_name}) -> Self {{
|
||||
{rust_name}::{t.name}(payload)
|
||||
}}
|
||||
}}
|
||||
impl From<{payload_name}> for Ast {{
|
||||
fn from(payload: {payload_name}) -> Self {{
|
||||
{rust_name}::from(payload).into()
|
||||
}}
|
||||
}}
|
||||
""",
|
||||
depth,
|
||||
)
|
||||
|
||||
self.emit("", depth)
|
||||
|
||||
def visitConstructor(self, cons, parent, depth):
|
||||
if cons.fields:
|
||||
self.emit(f"{cons.name} {{", depth)
|
||||
for f in cons.fields:
|
||||
self.visit(f, parent, "", depth + 1, cons.name)
|
||||
self.emit("},", depth)
|
||||
else:
|
||||
self.emit(f"{cons.name},", depth)
|
||||
|
||||
def visitField(self, field, parent, vis, depth, constructor=None):
|
||||
try:
|
||||
field_type = self.customized_type_info(field.type)
|
||||
typ = field_type.full_type_name
|
||||
except KeyError:
|
||||
field_type = None
|
||||
typ = rust_type_name(field.type)
|
||||
if field_type and not field_type.is_simple:
|
||||
typ = f"{typ}"
|
||||
# don't box if we're doing Vec<T>, but do box if we're doing Vec<Option<Box<T>>>
|
||||
if (
|
||||
field_type
|
||||
and field_type.boxed
|
||||
and (not (parent.is_product or field.seq) or field.opt)
|
||||
):
|
||||
typ = f"Box<{typ}>"
|
||||
if field.opt or (
|
||||
# When a dictionary literal contains dictionary unpacking (e.g., `{**d}`),
|
||||
# the expression to be unpacked goes in `values` with a `None` at the corresponding
|
||||
# position in `keys`. To handle this, the type of `keys` needs to be `Option<Vec<T>>`.
|
||||
constructor == "Dict"
|
||||
and field.name == "keys"
|
||||
):
|
||||
typ = f"Option<{typ}>"
|
||||
if field.seq:
|
||||
typ = f"Vec<{typ}>"
|
||||
if typ == "Int":
|
||||
typ = BUILTIN_INT_NAMES.get(field.name, typ)
|
||||
name = rust_field(field.name)
|
||||
|
||||
# Use a String, rather than an Identifier, for the `id` field of `Expr::Name`.
|
||||
# Names already include a range, so there's no need to duplicate the span.
|
||||
if name == "id":
|
||||
typ = "String"
|
||||
|
||||
self.emit(f"{vis}{name}: {typ},", depth)
|
||||
|
||||
def visitProduct(self, product, type, depth):
|
||||
type_info = self.type_info[type.name]
|
||||
product_name = type_info.full_type_name
|
||||
self.emit_attrs(depth)
|
||||
self.emit(f"pub struct {product_name} {{", depth)
|
||||
self.emit_range(product.attributes, depth + 1)
|
||||
for f in product.fields:
|
||||
self.visit(f, type_info, "pub ", depth + 1)
|
||||
assert bool(product.attributes) == type_info.no_cfg(self.type_info)
|
||||
self.emit("}", depth)
|
||||
|
||||
field_names = [f'"{f.name}"' for f in product.fields]
|
||||
self.emit(
|
||||
f"""
|
||||
impl Node for {product_name} {{
|
||||
const NAME: &'static str = "{type.name}";
|
||||
const FIELD_NAMES: &'static [&'static str] = &[
|
||||
{', '.join(field_names)}
|
||||
];
|
||||
}}
|
||||
""",
|
||||
depth,
|
||||
)
|
||||
|
||||
|
||||
class RangedDefVisitor(EmitVisitor):
|
||||
def visitModule(self, mod):
|
||||
for dfn in mod.dfns + CUSTOM_TYPES:
|
||||
self.visit(dfn)
|
||||
|
||||
def visitType(self, type, depth=0):
|
||||
self.visit(type.value, type.name, depth)
|
||||
|
||||
def visitSum(self, sum, name, depth):
|
||||
info = self.type_info[name]
|
||||
|
||||
self.emit_type_alias(info)
|
||||
|
||||
if info.is_simple:
|
||||
for ty in sum.types:
|
||||
variant_info = self.type_info[ty.name]
|
||||
self.emit_type_alias(variant_info)
|
||||
return
|
||||
|
||||
sum_match_arms = ""
|
||||
|
||||
for ty in sum.types:
|
||||
variant_info = self.type_info[ty.name]
|
||||
sum_match_arms += (
|
||||
f" Self::{variant_info.rust_name}(node) => node.range(),"
|
||||
)
|
||||
self.emit_type_alias(variant_info)
|
||||
self.emit_ranged_impl(variant_info)
|
||||
|
||||
|
||||
self.emit(
|
||||
f"""
|
||||
impl Ranged for crate::{info.full_type_name} {{
|
||||
fn range(&self) -> TextRange {{
|
||||
match self {{
|
||||
{sum_match_arms}
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
""".lstrip(),
|
||||
0,
|
||||
)
|
||||
|
||||
def visitProduct(self, product, name, depth):
|
||||
info = self.type_info[name]
|
||||
|
||||
self.emit_type_alias(info)
|
||||
self.emit_ranged_impl(info)
|
||||
|
||||
def emit_type_alias(self, info):
|
||||
return # disable
|
||||
self.emit(
|
||||
f"pub type {info.full_type_name} = crate::generic::{info.full_type_name};",
|
||||
0,
|
||||
)
|
||||
self.emit("", 0)
|
||||
|
||||
def emit_ranged_impl(self, info):
|
||||
self.file.write(
|
||||
f"""
|
||||
impl Ranged for crate::generic::{info.full_type_name} {{
|
||||
fn range(&self) -> TextRange {{
|
||||
self.range
|
||||
}}
|
||||
}}
|
||||
""".strip()
|
||||
)
|
||||
|
||||
|
||||
def write_ast_def(mod, type_info, f):
|
||||
f.write("use crate::text_size::TextRange;")
|
||||
StructVisitor(f, type_info).visit(mod)
|
||||
|
||||
|
||||
def write_ranged_def(mod, type_info, f):
|
||||
RangedDefVisitor(f, type_info).visit(mod)
|
||||
|
||||
|
||||
def write_parse_def(mod, type_info, f):
|
||||
for info in type_info.values():
|
||||
if info.enum_name not in ["expr", "stmt"]:
|
||||
continue
|
||||
|
||||
type_name = rust_type_name(info.enum_name)
|
||||
cons_name = rust_type_name(info.name)
|
||||
|
||||
f.write(
|
||||
f"""
|
||||
impl Parse for ast::{info.full_type_name} {{
|
||||
fn lex_starts_at(
|
||||
source: &str,
|
||||
offset: TextSize,
|
||||
) -> SoftKeywordTransformer<Lexer<std::str::Chars>> {{
|
||||
ast::{type_name}::lex_starts_at(source, offset)
|
||||
}}
|
||||
fn parse_tokens(
|
||||
lxr: impl IntoIterator<Item = LexResult>,
|
||||
source_path: &str,
|
||||
) -> Result<Self, ParseError> {{
|
||||
let node = ast::{type_name}::parse_tokens(lxr, source_path)?;
|
||||
match node {{
|
||||
ast::{type_name}::{cons_name}(node) => Ok(node),
|
||||
node => Err(ParseError {{
|
||||
error: ParseErrorType::InvalidToken,
|
||||
offset: node.range().start(),
|
||||
source_path: source_path.to_owned(),
|
||||
}}),
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def main(
|
||||
input_filename,
|
||||
ast_dir,
|
||||
parser_dir,
|
||||
dump_module=False,
|
||||
):
|
||||
auto_gen_msg = AUTO_GEN_MESSAGE.format("/".join(Path(__file__).parts[-2:]))
|
||||
mod = asdl.parse(input_filename)
|
||||
if dump_module:
|
||||
print("Parsed Module:")
|
||||
print(mod)
|
||||
if not asdl.check(mod):
|
||||
sys.exit(1)
|
||||
|
||||
type_info = {}
|
||||
FindUserDataTypesVisitor(type_info).visit(mod)
|
||||
|
||||
from functools import partial as p
|
||||
|
||||
for filename, write in [
|
||||
("generic", p(write_ast_def, mod, type_info)),
|
||||
("ranged", p(write_ranged_def, mod, type_info)),
|
||||
]:
|
||||
with (ast_dir / f"{filename}.rs").open("w") as f:
|
||||
f.write(auto_gen_msg)
|
||||
write(f)
|
||||
|
||||
for filename, write in [
|
||||
("parse", p(write_parse_def, mod, type_info)),
|
||||
]:
|
||||
with (parser_dir / f"{filename}.rs").open("w") as f:
|
||||
f.write(auto_gen_msg)
|
||||
write(f)
|
||||
|
||||
print(f"{ast_dir} regenerated.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument("input_file", type=Path)
|
||||
parser.add_argument("-A", "--ast-dir", type=Path, required=True)
|
||||
parser.add_argument("-P", "--parser-dir", type=Path, required=True)
|
||||
parser.add_argument("-d", "--dump-module", action="store_true")
|
||||
|
||||
args = parser.parse_args()
|
||||
main(
|
||||
args.input_file,
|
||||
args.ast_dir,
|
||||
args.parser_dir,
|
||||
args.dump_module,
|
||||
)
|
||||
@@ -1,4 +1,4 @@
|
||||
//! `builtin_types` in asdl.py and Attributed
|
||||
//! `builtin_types` in Attributed
|
||||
|
||||
use rustpython_parser_core::text_size::TextRange;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,502 +0,0 @@
|
||||
// File automatically generated by ast/asdl_rs.py.
|
||||
|
||||
impl Ranged for crate::generic::ModModule {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ModInteractive {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ModExpression {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ModFunctionType {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::Mod {
|
||||
fn range(&self) -> TextRange {
|
||||
match self {
|
||||
Self::Module(node) => node.range(),
|
||||
Self::Interactive(node) => node.range(),
|
||||
Self::Expression(node) => node.range(),
|
||||
Self::FunctionType(node) => node.range(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ranged for crate::generic::StmtFunctionDef {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtAsyncFunctionDef {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtClassDef {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtReturn {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtDelete {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtAssign {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtAugAssign {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtAnnAssign {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtFor {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtAsyncFor {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtWhile {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtIf {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtWith {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtAsyncWith {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtMatch {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtRaise {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtTry {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtTryStar {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtAssert {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtImport {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtImportFrom {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtGlobal {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtNonlocal {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtExpr {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtPass {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtBreak {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtContinue {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::Stmt {
|
||||
fn range(&self) -> TextRange {
|
||||
match self {
|
||||
Self::FunctionDef(node) => node.range(),
|
||||
Self::AsyncFunctionDef(node) => node.range(),
|
||||
Self::ClassDef(node) => node.range(),
|
||||
Self::Return(node) => node.range(),
|
||||
Self::Delete(node) => node.range(),
|
||||
Self::Assign(node) => node.range(),
|
||||
Self::AugAssign(node) => node.range(),
|
||||
Self::AnnAssign(node) => node.range(),
|
||||
Self::For(node) => node.range(),
|
||||
Self::AsyncFor(node) => node.range(),
|
||||
Self::While(node) => node.range(),
|
||||
Self::If(node) => node.range(),
|
||||
Self::With(node) => node.range(),
|
||||
Self::AsyncWith(node) => node.range(),
|
||||
Self::Match(node) => node.range(),
|
||||
Self::Raise(node) => node.range(),
|
||||
Self::Try(node) => node.range(),
|
||||
Self::TryStar(node) => node.range(),
|
||||
Self::Assert(node) => node.range(),
|
||||
Self::Import(node) => node.range(),
|
||||
Self::ImportFrom(node) => node.range(),
|
||||
Self::Global(node) => node.range(),
|
||||
Self::Nonlocal(node) => node.range(),
|
||||
Self::Expr(node) => node.range(),
|
||||
Self::Pass(node) => node.range(),
|
||||
Self::Break(node) => node.range(),
|
||||
Self::Continue(node) => node.range(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ranged for crate::generic::ExprBoolOp {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprNamedExpr {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprBinOp {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprUnaryOp {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprLambda {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprIfExp {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprDict {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprSet {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprListComp {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprSetComp {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprDictComp {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprGeneratorExp {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprAwait {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprYield {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprYieldFrom {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprCompare {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprCall {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprFormattedValue {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprJoinedStr {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprConstant {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprAttribute {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprSubscript {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprStarred {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprName {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprList {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprTuple {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprSlice {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::Expr {
|
||||
fn range(&self) -> TextRange {
|
||||
match self {
|
||||
Self::BoolOp(node) => node.range(),
|
||||
Self::NamedExpr(node) => node.range(),
|
||||
Self::BinOp(node) => node.range(),
|
||||
Self::UnaryOp(node) => node.range(),
|
||||
Self::Lambda(node) => node.range(),
|
||||
Self::IfExp(node) => node.range(),
|
||||
Self::Dict(node) => node.range(),
|
||||
Self::Set(node) => node.range(),
|
||||
Self::ListComp(node) => node.range(),
|
||||
Self::SetComp(node) => node.range(),
|
||||
Self::DictComp(node) => node.range(),
|
||||
Self::GeneratorExp(node) => node.range(),
|
||||
Self::Await(node) => node.range(),
|
||||
Self::Yield(node) => node.range(),
|
||||
Self::YieldFrom(node) => node.range(),
|
||||
Self::Compare(node) => node.range(),
|
||||
Self::Call(node) => node.range(),
|
||||
Self::FormattedValue(node) => node.range(),
|
||||
Self::JoinedStr(node) => node.range(),
|
||||
Self::Constant(node) => node.range(),
|
||||
Self::Attribute(node) => node.range(),
|
||||
Self::Subscript(node) => node.range(),
|
||||
Self::Starred(node) => node.range(),
|
||||
Self::Name(node) => node.range(),
|
||||
Self::List(node) => node.range(),
|
||||
Self::Tuple(node) => node.range(),
|
||||
Self::Slice(node) => node.range(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ranged for crate::generic::Comprehension {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExceptHandlerExceptHandler {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::ExceptHandler {
|
||||
fn range(&self) -> TextRange {
|
||||
match self {
|
||||
Self::ExceptHandler(node) => node.range(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ranged for crate::generic::PythonArguments {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::Arg {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::Keyword {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::Alias {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::WithItem {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::MatchCase {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::PatternMatchValue {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::PatternMatchSingleton {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::PatternMatchSequence {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::PatternMatchMapping {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::PatternMatchClass {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::PatternMatchStar {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::PatternMatchAs {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::PatternMatchOr {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::Pattern {
|
||||
fn range(&self) -> TextRange {
|
||||
match self {
|
||||
Self::MatchValue(node) => node.range(),
|
||||
Self::MatchSingleton(node) => node.range(),
|
||||
Self::MatchSequence(node) => node.range(),
|
||||
Self::MatchMapping(node) => node.range(),
|
||||
Self::MatchClass(node) => node.range(),
|
||||
Self::MatchStar(node) => node.range(),
|
||||
Self::MatchAs(node) => node.range(),
|
||||
Self::MatchOr(node) => node.range(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ranged for crate::generic::TypeIgnoreTypeIgnore {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::TypeIgnore {
|
||||
fn range(&self) -> TextRange {
|
||||
match self {
|
||||
Self::TypeIgnore(node) => node.range(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ranged for crate::generic::Decorator {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::Arguments {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ArgWithDefault {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
3139
ast/src/generic.rs
3139
ast/src/generic.rs
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,5 @@
|
||||
// This file was originally generated from asdl by a python script, but we now edit it manually
|
||||
|
||||
use crate::text_size::{TextRange, TextSize};
|
||||
|
||||
pub use crate::builtin::*;
|
||||
@@ -29,4 +31,503 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
include!("gen/ranged.rs");
|
||||
impl Ranged for crate::generic::ModModule {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ModInteractive {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ModExpression {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ModFunctionType {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::Mod {
|
||||
fn range(&self) -> TextRange {
|
||||
match self {
|
||||
Self::Module(node) => node.range(),
|
||||
Self::Interactive(node) => node.range(),
|
||||
Self::Expression(node) => node.range(),
|
||||
Self::FunctionType(node) => node.range(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ranged for crate::generic::StmtFunctionDef {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtAsyncFunctionDef {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtClassDef {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtReturn {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtDelete {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtAssign {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtAugAssign {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtAnnAssign {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtFor {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtAsyncFor {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtWhile {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtIf {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtWith {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtAsyncWith {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtMatch {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtRaise {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtTry {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtTryStar {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtAssert {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtImport {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtImportFrom {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtGlobal {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtNonlocal {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtExpr {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtPass {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtBreak {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::StmtContinue {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::Stmt {
|
||||
fn range(&self) -> TextRange {
|
||||
match self {
|
||||
Self::FunctionDef(node) => node.range(),
|
||||
Self::AsyncFunctionDef(node) => node.range(),
|
||||
Self::ClassDef(node) => node.range(),
|
||||
Self::Return(node) => node.range(),
|
||||
Self::Delete(node) => node.range(),
|
||||
Self::Assign(node) => node.range(),
|
||||
Self::AugAssign(node) => node.range(),
|
||||
Self::AnnAssign(node) => node.range(),
|
||||
Self::For(node) => node.range(),
|
||||
Self::AsyncFor(node) => node.range(),
|
||||
Self::While(node) => node.range(),
|
||||
Self::If(node) => node.range(),
|
||||
Self::With(node) => node.range(),
|
||||
Self::AsyncWith(node) => node.range(),
|
||||
Self::Match(node) => node.range(),
|
||||
Self::Raise(node) => node.range(),
|
||||
Self::Try(node) => node.range(),
|
||||
Self::TryStar(node) => node.range(),
|
||||
Self::Assert(node) => node.range(),
|
||||
Self::Import(node) => node.range(),
|
||||
Self::ImportFrom(node) => node.range(),
|
||||
Self::Global(node) => node.range(),
|
||||
Self::Nonlocal(node) => node.range(),
|
||||
Self::Expr(node) => node.range(),
|
||||
Self::Pass(node) => node.range(),
|
||||
Self::Break(node) => node.range(),
|
||||
Self::Continue(node) => node.range(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ranged for crate::generic::ExprBoolOp {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprNamedExpr {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprBinOp {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprUnaryOp {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprLambda {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprIfExp {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprDict {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprSet {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprListComp {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprSetComp {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprDictComp {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprGeneratorExp {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprAwait {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprYield {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprYieldFrom {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprCompare {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprCall {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprFormattedValue {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprJoinedStr {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprConstant {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprAttribute {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprSubscript {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprStarred {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprName {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprList {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprTuple {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExprSlice {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::Expr {
|
||||
fn range(&self) -> TextRange {
|
||||
match self {
|
||||
Self::BoolOp(node) => node.range(),
|
||||
Self::NamedExpr(node) => node.range(),
|
||||
Self::BinOp(node) => node.range(),
|
||||
Self::UnaryOp(node) => node.range(),
|
||||
Self::Lambda(node) => node.range(),
|
||||
Self::IfExp(node) => node.range(),
|
||||
Self::Dict(node) => node.range(),
|
||||
Self::Set(node) => node.range(),
|
||||
Self::ListComp(node) => node.range(),
|
||||
Self::SetComp(node) => node.range(),
|
||||
Self::DictComp(node) => node.range(),
|
||||
Self::GeneratorExp(node) => node.range(),
|
||||
Self::Await(node) => node.range(),
|
||||
Self::Yield(node) => node.range(),
|
||||
Self::YieldFrom(node) => node.range(),
|
||||
Self::Compare(node) => node.range(),
|
||||
Self::Call(node) => node.range(),
|
||||
Self::FormattedValue(node) => node.range(),
|
||||
Self::JoinedStr(node) => node.range(),
|
||||
Self::Constant(node) => node.range(),
|
||||
Self::Attribute(node) => node.range(),
|
||||
Self::Subscript(node) => node.range(),
|
||||
Self::Starred(node) => node.range(),
|
||||
Self::Name(node) => node.range(),
|
||||
Self::List(node) => node.range(),
|
||||
Self::Tuple(node) => node.range(),
|
||||
Self::Slice(node) => node.range(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ranged for crate::generic::Comprehension {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ExceptHandlerExceptHandler {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::ExceptHandler {
|
||||
fn range(&self) -> TextRange {
|
||||
match self {
|
||||
Self::ExceptHandler(node) => node.range(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ranged for crate::generic::PythonArguments {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::Arg {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::Keyword {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::Alias {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::WithItem {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::MatchCase {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::PatternMatchValue {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::PatternMatchSingleton {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::PatternMatchSequence {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::PatternMatchMapping {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::PatternMatchClass {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::PatternMatchStar {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::PatternMatchAs {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::PatternMatchOr {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::Pattern {
|
||||
fn range(&self) -> TextRange {
|
||||
match self {
|
||||
Self::MatchValue(node) => node.range(),
|
||||
Self::MatchSingleton(node) => node.range(),
|
||||
Self::MatchSequence(node) => node.range(),
|
||||
Self::MatchMapping(node) => node.range(),
|
||||
Self::MatchClass(node) => node.range(),
|
||||
Self::MatchStar(node) => node.range(),
|
||||
Self::MatchAs(node) => node.range(),
|
||||
Self::MatchOr(node) => node.range(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ranged for crate::generic::TypeIgnoreTypeIgnore {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::TypeIgnore {
|
||||
fn range(&self) -> TextRange {
|
||||
match self {
|
||||
Self::TypeIgnore(node) => node.range(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ranged for crate::generic::Decorator {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::Arguments {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::generic::ArgWithDefault {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// File automatically generated by ast/asdl_rs.py.
|
||||
// This file was originally generated from asdl by a python script, but we now edit it manually
|
||||
|
||||
impl Parse for ast::StmtFunctionDef {
|
||||
fn lex_starts_at(
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
#!/bin/bash
|
||||
cspell "ast/**/*.rs" "literal/**/*.rs" "core/**/*.rs" "parser/**/*.rs"
|
||||
cspell ast/asdl_rs.py
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$(dirname "$0")")"
|
||||
|
||||
# rm ast/src/gen/*.rs
|
||||
python ast/asdl_rs.py --ast-dir ast/src/gen/ --parser-dir parser/src/gen/ ast/Python.asdl
|
||||
rustfmt ast/src/gen/*.rs parser/src/gen/*.rs
|
||||
Reference in New Issue
Block a user