difftreelog
refactor deduplicate operator definitions
in: master
9 files changed
crates/jrsonnet-rowan-parser/jsonnet.ungramdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/jsonnet.ungram
+++ b/crates/jrsonnet-rowan-parser/jsonnet.ungram
@@ -136,6 +136,7 @@
| '<<' | '>>'
| '+' | '-'
| '*' | '/' | '%'
+| 'META_OBJECT_APPLY!'
| 'ERROR_NO_OPERATOR!'
UnaryOperator =
crates/jrsonnet-rowan-parser/src/binary.rsdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/src/binary.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum BinaryOperator {
- Mul,
- Div,
- Mod,
- Plus,
- Minus,
- ShiftLeft,
- ShiftRight,
- LessThan,
- GreaterThan,
- LessThanOrEqual,
- GreaterThanOrEqual,
- Equal,
- NotEqual,
- BitAnd,
- BitXor,
- BitOr,
- And,
- Or,
- In,
- ObjectApply,
- #[allow(dead_code)]
- Invalid,
-}
-
-impl BinaryOperator {
- pub fn binding_power(&self) -> (u8, u8) {
- match self {
- Self::ObjectApply => (22, 23),
- Self::Mul | Self::Div | Self::Mod => (20, 21),
- Self::Plus | Self::Minus => (18, 19),
- Self::ShiftLeft | Self::ShiftRight => (16, 17),
- Self::LessThan
- | Self::GreaterThan
- | Self::LessThanOrEqual
- | Self::GreaterThanOrEqual
- | Self::In => (14, 15),
- Self::Equal | Self::NotEqual => (12, 13),
- Self::BitAnd => (10, 11),
- Self::BitXor => (8, 9),
- Self::BitOr => (6, 7),
- Self::And => (4, 5),
- Self::Or => (2, 3),
- Self::Invalid => (0, 1),
- }
- }
-}
crates/jrsonnet-rowan-parser/src/generated/nodes.rsdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/src/generated/nodes.rs
+++ b/crates/jrsonnet-rowan-parser/src/generated/nodes.rs
@@ -1005,6 +1005,7 @@
Mul,
Div,
Modulo,
+ MetaObjectApply,
ErrorNoOperator,
}
@@ -2508,101 +2509,51 @@
}
impl AstToken for BinaryOperator {
fn can_cast(kind: SyntaxKind) -> bool {
+ BinaryOperatorKind::can_cast(kind)
+ }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ let kind = BinaryOperatorKind::cast(syntax.kind())?;
+ Some(BinaryOperator { syntax, kind })
+ }
+ fn syntax(&self) -> &SyntaxToken {
+ &self.syntax
+ }
+}
+impl BinaryOperatorKind {
+ fn can_cast(kind: SyntaxKind) -> bool {
match kind {
OR | AND | BIT_OR | BIT_XOR | BIT_AND | EQ | NE | LT | GT | LE | GE | IN_KW | LHS
- | RHS | PLUS | MINUS | MUL | DIV | MODULO | ERROR_NO_OPERATOR => true,
+ | RHS | PLUS | MINUS | MUL | DIV | MODULO | META_OBJECT_APPLY | ERROR_NO_OPERATOR => true,
_ => false,
}
}
- fn cast(syntax: SyntaxToken) -> Option<Self> {
- let res = match syntax.kind() {
- OR => BinaryOperator {
- syntax,
- kind: BinaryOperatorKind::Or,
- },
- AND => BinaryOperator {
- syntax,
- kind: BinaryOperatorKind::And,
- },
- BIT_OR => BinaryOperator {
- syntax,
- kind: BinaryOperatorKind::BitOr,
- },
- BIT_XOR => BinaryOperator {
- syntax,
- kind: BinaryOperatorKind::BitXor,
- },
- BIT_AND => BinaryOperator {
- syntax,
- kind: BinaryOperatorKind::BitAnd,
- },
- EQ => BinaryOperator {
- syntax,
- kind: BinaryOperatorKind::Eq,
- },
- NE => BinaryOperator {
- syntax,
- kind: BinaryOperatorKind::Ne,
- },
- LT => BinaryOperator {
- syntax,
- kind: BinaryOperatorKind::Lt,
- },
- GT => BinaryOperator {
- syntax,
- kind: BinaryOperatorKind::Gt,
- },
- LE => BinaryOperator {
- syntax,
- kind: BinaryOperatorKind::Le,
- },
- GE => BinaryOperator {
- syntax,
- kind: BinaryOperatorKind::Ge,
- },
- IN_KW => BinaryOperator {
- syntax,
- kind: BinaryOperatorKind::InKw,
- },
- LHS => BinaryOperator {
- syntax,
- kind: BinaryOperatorKind::Lhs,
- },
- RHS => BinaryOperator {
- syntax,
- kind: BinaryOperatorKind::Rhs,
- },
- PLUS => BinaryOperator {
- syntax,
- kind: BinaryOperatorKind::Plus,
- },
- MINUS => BinaryOperator {
- syntax,
- kind: BinaryOperatorKind::Minus,
- },
- MUL => BinaryOperator {
- syntax,
- kind: BinaryOperatorKind::Mul,
- },
- DIV => BinaryOperator {
- syntax,
- kind: BinaryOperatorKind::Div,
- },
- MODULO => BinaryOperator {
- syntax,
- kind: BinaryOperatorKind::Modulo,
- },
- ERROR_NO_OPERATOR => BinaryOperator {
- syntax,
- kind: BinaryOperatorKind::ErrorNoOperator,
- },
+ pub fn cast(kind: SyntaxKind) -> Option<Self> {
+ let res = match kind {
+ OR => Self::Or,
+ AND => Self::And,
+ BIT_OR => Self::BitOr,
+ BIT_XOR => Self::BitXor,
+ BIT_AND => Self::BitAnd,
+ EQ => Self::Eq,
+ NE => Self::Ne,
+ LT => Self::Lt,
+ GT => Self::Gt,
+ LE => Self::Le,
+ GE => Self::Ge,
+ IN_KW => Self::InKw,
+ LHS => Self::Lhs,
+ RHS => Self::Rhs,
+ PLUS => Self::Plus,
+ MINUS => Self::Minus,
+ MUL => Self::Mul,
+ DIV => Self::Div,
+ MODULO => Self::Modulo,
+ META_OBJECT_APPLY => Self::MetaObjectApply,
+ ERROR_NO_OPERATOR => Self::ErrorNoOperator,
_ => return None,
};
Some(res)
}
- fn syntax(&self) -> &SyntaxToken {
- &self.syntax
- }
}
impl BinaryOperator {
pub fn kind(&self) -> BinaryOperatorKind {
@@ -2616,31 +2567,31 @@
}
impl AstToken for UnaryOperator {
fn can_cast(kind: SyntaxKind) -> bool {
+ UnaryOperatorKind::can_cast(kind)
+ }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ let kind = UnaryOperatorKind::cast(syntax.kind())?;
+ Some(UnaryOperator { syntax, kind })
+ }
+ fn syntax(&self) -> &SyntaxToken {
+ &self.syntax
+ }
+}
+impl UnaryOperatorKind {
+ fn can_cast(kind: SyntaxKind) -> bool {
match kind {
MINUS | NOT | BIT_NOT => true,
_ => false,
}
}
- fn cast(syntax: SyntaxToken) -> Option<Self> {
- let res = match syntax.kind() {
- MINUS => UnaryOperator {
- syntax,
- kind: UnaryOperatorKind::Minus,
- },
- NOT => UnaryOperator {
- syntax,
- kind: UnaryOperatorKind::Not,
- },
- BIT_NOT => UnaryOperator {
- syntax,
- kind: UnaryOperatorKind::BitNot,
- },
+ pub fn cast(kind: SyntaxKind) -> Option<Self> {
+ let res = match kind {
+ MINUS => Self::Minus,
+ NOT => Self::Not,
+ BIT_NOT => Self::BitNot,
_ => return None,
};
Some(res)
- }
- fn syntax(&self) -> &SyntaxToken {
- &self.syntax
}
}
impl UnaryOperator {
@@ -2655,44 +2606,35 @@
}
impl AstToken for Literal {
fn can_cast(kind: SyntaxKind) -> bool {
+ LiteralKind::can_cast(kind)
+ }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ let kind = LiteralKind::cast(syntax.kind())?;
+ Some(Literal { syntax, kind })
+ }
+ fn syntax(&self) -> &SyntaxToken {
+ &self.syntax
+ }
+}
+impl LiteralKind {
+ fn can_cast(kind: SyntaxKind) -> bool {
match kind {
NULL_KW | TRUE_KW | FALSE_KW | SELF_KW | DOLLAR | SUPER_KW => true,
_ => false,
}
}
- fn cast(syntax: SyntaxToken) -> Option<Self> {
- let res = match syntax.kind() {
- NULL_KW => Literal {
- syntax,
- kind: LiteralKind::NullKw,
- },
- TRUE_KW => Literal {
- syntax,
- kind: LiteralKind::TrueKw,
- },
- FALSE_KW => Literal {
- syntax,
- kind: LiteralKind::FalseKw,
- },
- SELF_KW => Literal {
- syntax,
- kind: LiteralKind::SelfKw,
- },
- DOLLAR => Literal {
- syntax,
- kind: LiteralKind::Dollar,
- },
- SUPER_KW => Literal {
- syntax,
- kind: LiteralKind::SuperKw,
- },
+ pub fn cast(kind: SyntaxKind) -> Option<Self> {
+ let res = match kind {
+ NULL_KW => Self::NullKw,
+ TRUE_KW => Self::TrueKw,
+ FALSE_KW => Self::FalseKw,
+ SELF_KW => Self::SelfKw,
+ DOLLAR => Self::Dollar,
+ SUPER_KW => Self::SuperKw,
_ => return None,
};
Some(res)
}
- fn syntax(&self) -> &SyntaxToken {
- &self.syntax
- }
}
impl Literal {
pub fn kind(&self) -> LiteralKind {
@@ -2706,6 +2648,18 @@
}
impl AstToken for Text {
fn can_cast(kind: SyntaxKind) -> bool {
+ TextKind::can_cast(kind)
+ }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ let kind = TextKind::cast(syntax.kind())?;
+ Some(Text { syntax, kind })
+ }
+ fn syntax(&self) -> &SyntaxToken {
+ &self.syntax
+ }
+}
+impl TextKind {
+ fn can_cast(kind: SyntaxKind) -> bool {
match kind {
STRING_DOUBLE
| ERROR_STRING_DOUBLE_UNTERMINATED
@@ -2724,71 +2678,30 @@
_ => false,
}
}
- fn cast(syntax: SyntaxToken) -> Option<Self> {
- let res = match syntax.kind() {
- STRING_DOUBLE => Text {
- syntax,
- kind: TextKind::StringDouble,
- },
- ERROR_STRING_DOUBLE_UNTERMINATED => Text {
- syntax,
- kind: TextKind::ErrorStringDoubleUnterminated,
- },
- STRING_SINGLE => Text {
- syntax,
- kind: TextKind::StringSingle,
- },
- ERROR_STRING_SINGLE_UNTERMINATED => Text {
- syntax,
- kind: TextKind::ErrorStringSingleUnterminated,
- },
- STRING_DOUBLE_VERBATIM => Text {
- syntax,
- kind: TextKind::StringDoubleVerbatim,
- },
- ERROR_STRING_DOUBLE_VERBATIM_UNTERMINATED => Text {
- syntax,
- kind: TextKind::ErrorStringDoubleVerbatimUnterminated,
- },
- STRING_SINGLE_VERBATIM => Text {
- syntax,
- kind: TextKind::StringSingleVerbatim,
- },
- ERROR_STRING_SINGLE_VERBATIM_UNTERMINATED => Text {
- syntax,
- kind: TextKind::ErrorStringSingleVerbatimUnterminated,
- },
- ERROR_STRING_VERBATIM_MISSING_QUOTES => Text {
- syntax,
- kind: TextKind::ErrorStringVerbatimMissingQuotes,
- },
- STRING_BLOCK => Text {
- syntax,
- kind: TextKind::StringBlock,
- },
- ERROR_STRING_BLOCK_UNEXPECTED_END => Text {
- syntax,
- kind: TextKind::ErrorStringBlockUnexpectedEnd,
- },
- ERROR_STRING_BLOCK_MISSING_NEW_LINE => Text {
- syntax,
- kind: TextKind::ErrorStringBlockMissingNewLine,
- },
- ERROR_STRING_BLOCK_MISSING_TERMINATION => Text {
- syntax,
- kind: TextKind::ErrorStringBlockMissingTermination,
- },
- ERROR_STRING_BLOCK_MISSING_INDENT => Text {
- syntax,
- kind: TextKind::ErrorStringBlockMissingIndent,
- },
+ pub fn cast(kind: SyntaxKind) -> Option<Self> {
+ let res = match kind {
+ STRING_DOUBLE => Self::StringDouble,
+ ERROR_STRING_DOUBLE_UNTERMINATED => Self::ErrorStringDoubleUnterminated,
+ STRING_SINGLE => Self::StringSingle,
+ ERROR_STRING_SINGLE_UNTERMINATED => Self::ErrorStringSingleUnterminated,
+ STRING_DOUBLE_VERBATIM => Self::StringDoubleVerbatim,
+ ERROR_STRING_DOUBLE_VERBATIM_UNTERMINATED => {
+ Self::ErrorStringDoubleVerbatimUnterminated
+ }
+ STRING_SINGLE_VERBATIM => Self::StringSingleVerbatim,
+ ERROR_STRING_SINGLE_VERBATIM_UNTERMINATED => {
+ Self::ErrorStringSingleVerbatimUnterminated
+ }
+ ERROR_STRING_VERBATIM_MISSING_QUOTES => Self::ErrorStringVerbatimMissingQuotes,
+ STRING_BLOCK => Self::StringBlock,
+ ERROR_STRING_BLOCK_UNEXPECTED_END => Self::ErrorStringBlockUnexpectedEnd,
+ ERROR_STRING_BLOCK_MISSING_NEW_LINE => Self::ErrorStringBlockMissingNewLine,
+ ERROR_STRING_BLOCK_MISSING_TERMINATION => Self::ErrorStringBlockMissingTermination,
+ ERROR_STRING_BLOCK_MISSING_INDENT => Self::ErrorStringBlockMissingIndent,
_ => return None,
};
Some(res)
}
- fn syntax(&self) -> &SyntaxToken {
- &self.syntax
- }
}
impl Text {
pub fn kind(&self) -> TextKind {
@@ -2802,6 +2715,18 @@
}
impl AstToken for Number {
fn can_cast(kind: SyntaxKind) -> bool {
+ NumberKind::can_cast(kind)
+ }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ let kind = NumberKind::cast(syntax.kind())?;
+ Some(Number { syntax, kind })
+ }
+ fn syntax(&self) -> &SyntaxToken {
+ &self.syntax
+ }
+}
+impl NumberKind {
+ fn can_cast(kind: SyntaxKind) -> bool {
match kind {
FLOAT
| ERROR_FLOAT_JUNK_AFTER_POINT
@@ -2810,31 +2735,16 @@
_ => false,
}
}
- fn cast(syntax: SyntaxToken) -> Option<Self> {
- let res = match syntax.kind() {
- FLOAT => Number {
- syntax,
- kind: NumberKind::Float,
- },
- ERROR_FLOAT_JUNK_AFTER_POINT => Number {
- syntax,
- kind: NumberKind::ErrorFloatJunkAfterPoint,
- },
- ERROR_FLOAT_JUNK_AFTER_EXPONENT => Number {
- syntax,
- kind: NumberKind::ErrorFloatJunkAfterExponent,
- },
- ERROR_FLOAT_JUNK_AFTER_EXPONENT_SIGN => Number {
- syntax,
- kind: NumberKind::ErrorFloatJunkAfterExponentSign,
- },
+ pub fn cast(kind: SyntaxKind) -> Option<Self> {
+ let res = match kind {
+ FLOAT => Self::Float,
+ ERROR_FLOAT_JUNK_AFTER_POINT => Self::ErrorFloatJunkAfterPoint,
+ ERROR_FLOAT_JUNK_AFTER_EXPONENT => Self::ErrorFloatJunkAfterExponent,
+ ERROR_FLOAT_JUNK_AFTER_EXPONENT_SIGN => Self::ErrorFloatJunkAfterExponentSign,
_ => return None,
};
Some(res)
}
- fn syntax(&self) -> &SyntaxToken {
- &self.syntax
- }
}
impl Number {
pub fn kind(&self) -> NumberKind {
@@ -2848,32 +2758,32 @@
}
impl AstToken for ImportKind {
fn can_cast(kind: SyntaxKind) -> bool {
+ ImportKindKind::can_cast(kind)
+ }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ let kind = ImportKindKind::cast(syntax.kind())?;
+ Some(ImportKind { syntax, kind })
+ }
+ fn syntax(&self) -> &SyntaxToken {
+ &self.syntax
+ }
+}
+impl ImportKindKind {
+ fn can_cast(kind: SyntaxKind) -> bool {
match kind {
IMPORTSTR_KW | IMPORTBIN_KW | IMPORT_KW => true,
_ => false,
}
}
- fn cast(syntax: SyntaxToken) -> Option<Self> {
- let res = match syntax.kind() {
- IMPORTSTR_KW => ImportKind {
- syntax,
- kind: ImportKindKind::ImportstrKw,
- },
- IMPORTBIN_KW => ImportKind {
- syntax,
- kind: ImportKindKind::ImportbinKw,
- },
- IMPORT_KW => ImportKind {
- syntax,
- kind: ImportKindKind::ImportKw,
- },
+ pub fn cast(kind: SyntaxKind) -> Option<Self> {
+ let res = match kind {
+ IMPORTSTR_KW => Self::ImportstrKw,
+ IMPORTBIN_KW => Self::ImportbinKw,
+ IMPORT_KW => Self::ImportKw,
_ => return None,
};
Some(res)
}
- fn syntax(&self) -> &SyntaxToken {
- &self.syntax
- }
}
impl ImportKind {
pub fn kind(&self) -> ImportKindKind {
@@ -2887,31 +2797,31 @@
}
impl AstToken for Visibility {
fn can_cast(kind: SyntaxKind) -> bool {
+ VisibilityKind::can_cast(kind)
+ }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ let kind = VisibilityKind::cast(syntax.kind())?;
+ Some(Visibility { syntax, kind })
+ }
+ fn syntax(&self) -> &SyntaxToken {
+ &self.syntax
+ }
+}
+impl VisibilityKind {
+ fn can_cast(kind: SyntaxKind) -> bool {
match kind {
COLONCOLONCOLON | COLONCOLON | COLON => true,
_ => false,
}
}
- fn cast(syntax: SyntaxToken) -> Option<Self> {
- let res = match syntax.kind() {
- COLONCOLONCOLON => Visibility {
- syntax,
- kind: VisibilityKind::Coloncoloncolon,
- },
- COLONCOLON => Visibility {
- syntax,
- kind: VisibilityKind::Coloncolon,
- },
- COLON => Visibility {
- syntax,
- kind: VisibilityKind::Colon,
- },
+ pub fn cast(kind: SyntaxKind) -> Option<Self> {
+ let res = match kind {
+ COLONCOLONCOLON => Self::Coloncoloncolon,
+ COLONCOLON => Self::Coloncolon,
+ COLON => Self::Colon,
_ => return None,
};
Some(res)
- }
- fn syntax(&self) -> &SyntaxToken {
- &self.syntax
}
}
impl Visibility {
@@ -2926,6 +2836,18 @@
}
impl AstToken for Trivia {
fn can_cast(kind: SyntaxKind) -> bool {
+ TriviaKind::can_cast(kind)
+ }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ let kind = TriviaKind::cast(syntax.kind())?;
+ Some(Trivia { syntax, kind })
+ }
+ fn syntax(&self) -> &SyntaxToken {
+ &self.syntax
+ }
+}
+impl TriviaKind {
+ fn can_cast(kind: SyntaxKind) -> bool {
match kind {
WHITESPACE
| MULTI_LINE_COMMENT
@@ -2936,38 +2858,17 @@
_ => false,
}
}
- fn cast(syntax: SyntaxToken) -> Option<Self> {
- let res = match syntax.kind() {
- WHITESPACE => Trivia {
- syntax,
- kind: TriviaKind::Whitespace,
- },
- MULTI_LINE_COMMENT => Trivia {
- syntax,
- kind: TriviaKind::MultiLineComment,
- },
- ERROR_COMMENT_TOO_SHORT => Trivia {
- syntax,
- kind: TriviaKind::ErrorCommentTooShort,
- },
- ERROR_COMMENT_UNTERMINATED => Trivia {
- syntax,
- kind: TriviaKind::ErrorCommentUnterminated,
- },
- SINGLE_LINE_HASH_COMMENT => Trivia {
- syntax,
- kind: TriviaKind::SingleLineHashComment,
- },
- SINGLE_LINE_SLASH_COMMENT => Trivia {
- syntax,
- kind: TriviaKind::SingleLineSlashComment,
- },
+ pub fn cast(kind: SyntaxKind) -> Option<Self> {
+ let res = match kind {
+ WHITESPACE => Self::Whitespace,
+ MULTI_LINE_COMMENT => Self::MultiLineComment,
+ ERROR_COMMENT_TOO_SHORT => Self::ErrorCommentTooShort,
+ ERROR_COMMENT_UNTERMINATED => Self::ErrorCommentUnterminated,
+ SINGLE_LINE_HASH_COMMENT => Self::SingleLineHashComment,
+ SINGLE_LINE_SLASH_COMMENT => Self::SingleLineSlashComment,
_ => return None,
};
Some(res)
- }
- fn syntax(&self) -> &SyntaxToken {
- &self.syntax
}
}
impl Trivia {
crates/jrsonnet-rowan-parser/src/generated/syntax_kinds.rsdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/src/generated/syntax_kinds.rs
+++ b/crates/jrsonnet-rowan-parser/src/generated/syntax_kinds.rs
@@ -163,6 +163,7 @@
ERROR_KW,
#[token("in")]
IN_KW,
+ META_OBJECT_APPLY,
ERROR_NO_OPERATOR,
#[token("null")]
NULL_KW,
crates/jrsonnet-rowan-parser/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/src/lib.rs
+++ b/crates/jrsonnet-rowan-parser/src/lib.rs
@@ -1,17 +1,16 @@
#![deny(unused_must_use)]
mod ast;
-mod binary;
mod event;
mod generated;
mod language;
mod lex;
mod marker;
mod parser;
+mod precedence;
mod string_block;
mod tests;
mod token_set;
-mod unary;
pub use ast::{AstChildren, AstNode, AstToken};
use event::Sink;
crates/jrsonnet-rowan-parser/src/parser.rsdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/src/parser.rs
+++ b/crates/jrsonnet-rowan-parser/src/parser.rs
@@ -4,13 +4,11 @@
use rowan::{GreenNode, TextRange, TextSize};
use crate::{
- binary::BinaryOperator,
event::Event,
lex::Lexeme,
marker::{AsRange, CompletedMarker, Marker, Ranger},
- nodes::{Literal, Number, Text, Trivia},
+ nodes::{BinaryOperatorKind, Literal, Number, Text, Trivia, UnaryOperatorKind},
token_set::SyntaxKindSet,
- unary::UnaryOperator,
AstToken, SyntaxKind,
SyntaxKind::*,
SyntaxNode, T, TS,
@@ -397,18 +395,6 @@
enum ExpectedSyntaxTrackingState {
Named,
Unnamed,
-}
-macro_rules! at_match {
- ($p:ident {
- $($r:expr => $e:expr,)*
- _ => $else:expr $(,)?
- }) => {{
- $(
- if $p.at($r) {$e} else
- )* {
- $else
- }
- }}
}
fn expr(p: &mut Parser) -> Option<CompletedMarker> {
@@ -417,37 +403,16 @@
fn expr_binding_power(p: &mut Parser, minimum_binding_power: u8) -> Option<CompletedMarker> {
let mut lhs = lhs(p)?;
- loop {
- let op = at_match!(p {
- T![*] => BinaryOperator::Mul,
- T![/] => BinaryOperator::Div,
- T![%] => BinaryOperator::Mod,
- T![+] => BinaryOperator::Plus,
- T![-] => BinaryOperator::Minus,
- T![<<] => BinaryOperator::ShiftLeft,
- T![>>] => BinaryOperator::ShiftRight,
- T![<] => BinaryOperator::LessThan,
- T![>] => BinaryOperator::GreaterThan,
- T![<=] => BinaryOperator::LessThanOrEqual,
- T![>=] => BinaryOperator::GreaterThanOrEqual,
- T![==] => BinaryOperator::Equal,
- T![!=] => BinaryOperator::NotEqual,
- T![&] => BinaryOperator::BitAnd,
- T![^] => BinaryOperator::BitXor,
- T![|] => BinaryOperator::BitOr,
- T![&&] => BinaryOperator::And,
- T![||] => BinaryOperator::Or,
- T![in] => BinaryOperator::In,
- T!['{'] => BinaryOperator::ObjectApply,
- _ => break,
- });
+ while let Some(op) = BinaryOperatorKind::cast(p.current())
+ .or_else(|| p.at(T!['{']).then(|| BinaryOperatorKind::MetaObjectApply))
+ {
let (left_binding_power, right_binding_power) = op.binding_power();
if left_binding_power < minimum_binding_power {
break;
}
// Object apply is not a real operator, we dont have something to bump
- if op != BinaryOperator::ObjectApply {
+ if op != BinaryOperatorKind::MetaObjectApply {
p.bump();
}
@@ -455,7 +420,7 @@
let parsed_rhs = expr_binding_power(p, right_binding_power).is_some();
lhs = m.complete(
p,
- if op == BinaryOperator::ObjectApply {
+ if op == BinaryOperatorKind::MetaObjectApply {
EXPR_OBJ_EXTEND
} else {
EXPR_BINARY
@@ -998,13 +963,7 @@
p.bump();
text(p);
m.complete(p, EXPR_IMPORT)
- } else if p.at(T![-]) || p.at(T![!]) || p.at(T![~]) {
- let op = match p.current() {
- T![-] => UnaryOperator::Minus,
- T![!] => UnaryOperator::Not,
- T![~] => UnaryOperator::BitNegate,
- _ => unreachable!(),
- };
+ } else if let Some(op) = UnaryOperatorKind::cast(p.current()) {
let ((), right_binding_power) = op.binding_power();
let m = p.start();
crates/jrsonnet-rowan-parser/src/precedence.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/precedence.rs
@@ -0,0 +1,30 @@
+use crate::nodes::{BinaryOperatorKind, UnaryOperatorKind};
+
+impl BinaryOperatorKind {
+ pub fn binding_power(&self) -> (u8, u8) {
+ match self {
+ Self::MetaObjectApply => (22, 23),
+ Self::Mul | Self::Div | Self::Modulo => (20, 21),
+ Self::Plus | Self::Minus => (18, 19),
+ Self::Lhs | Self::Rhs => (16, 17),
+ Self::Lt | Self::Gt | Self::Le | Self::Ge | Self::InKw => (14, 15),
+ Self::Eq | Self::Ne => (12, 13),
+ Self::BitAnd => (10, 11),
+ Self::BitXor => (8, 9),
+ Self::BitOr => (6, 7),
+ Self::And => (4, 5),
+ Self::Or => (2, 3),
+ Self::ErrorNoOperator => (0, 1),
+ }
+ }
+}
+
+impl UnaryOperatorKind {
+ pub fn binding_power(&self) -> ((), u8) {
+ match self {
+ Self::Minus => ((), 20),
+ Self::Not => ((), 20),
+ Self::BitNot => ((), 20),
+ }
+ }
+}
crates/jrsonnet-rowan-parser/src/unary.rsdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/src/unary.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum UnaryOperator {
- Minus,
- Not,
- BitNegate,
-}
-impl UnaryOperator {
- pub fn binding_power(&self) -> ((), u8) {
- match self {
- UnaryOperator::Minus => ((), 20),
- UnaryOperator::Not => ((), 20),
- UnaryOperator::BitNegate => ((), 20),
- }
- }
-}
xtask/src/sourcegen/mod.rsdiffbeforeafterboth1use std::path::PathBuf;23use anyhow::Result;4use ast::{lower, AstSrc};5use itertools::Itertools;6use kinds::{KindsSrc, TokenKind};7use proc_macro2::{Punct, Spacing, TokenStream};8use quote::{format_ident, quote};9use ungrammar::Grammar;10use util::{ensure_file_contents, reformat, to_pascal_case, to_upper_snake_case};1112mod ast;13mod kinds;14mod util;1516enum SpecialName {17 Literal,18 Meta,19 Error,20}21fn classify_special(name: &str) -> Option<(SpecialName, &str)> {22 let name = name.strip_suffix('!')?;23 Some(if let Some(name) = name.strip_prefix("LIT_") {24 (SpecialName::Literal, name)25 } else if let Some(name) = name.strip_prefix("META_") {26 (SpecialName::Meta, name)27 } else if let Some(name) = name.strip_prefix("ERROR_") {28 (SpecialName::Error, name)29 } else {30 return None;31 })32}3334pub fn generate_ungrammar() -> Result<()> {35 let grammar: Grammar = include_str!(concat!(36 env!("CARGO_MANIFEST_DIR"),37 "/../crates/jrsonnet-rowan-parser/jsonnet.ungram"38 ))39 .parse()?;4041 let mut kinds = kinds::jsonnet_kinds();42 let ast = lower(&kinds, &grammar);4344 for token in grammar.tokens() {45 let token = &grammar[token];46 let token = &token.name.clone();47 if !kinds.is_token(token) {48 if let Some((special, name)) = classify_special(token) {49 match special {50 SpecialName::Literal => panic!("literal is not defined: {name}"),51 SpecialName::Meta => {52 eprintln!("implicit meta: {}", name);53 kinds.define_token(TokenKind::Meta {54 grammar_name: token.to_owned(),55 name: format!("META_{}", name),56 })57 }58 SpecialName::Error => {59 eprintln!("implicit error: {}", name);60 kinds.define_token(TokenKind::Error {61 grammar_name: token.to_owned(),62 name: format!("ERROR_{}", name),63 regex: None,64 priority: None,65 is_lexer_error: true,66 })67 }68 };69 continue;70 };71 let name = to_upper_snake_case(token);72 eprintln!("implicit kw: {}", token);73 kinds.define_token(TokenKind::Keyword {74 code: token.to_owned(),75 name: format!("{name}_KW"),76 });77 }78 }79 for node in &ast.nodes {80 let name = to_upper_snake_case(&node.name);81 kinds.define_node(&name);82 }83 for enum_ in &ast.enums {84 let name = to_upper_snake_case(&enum_.name);85 kinds.define_node(&name);86 }87 for token_enum in &ast.token_enums {88 let name = to_upper_snake_case(&token_enum.name);89 kinds.define_node(&name);90 }9192 let syntax_kinds = generate_syntax_kinds(&kinds, &ast)?;9394 let nodes = generate_nodes(&kinds, &ast)?;95 ensure_file_contents(96 &PathBuf::from(concat!(97 env!("CARGO_MANIFEST_DIR"),98 "/../crates/jrsonnet-rowan-parser/src/generated/syntax_kinds.rs",99 )),100 &syntax_kinds,101 )?;102 ensure_file_contents(103 &PathBuf::from(concat!(104 env!("CARGO_MANIFEST_DIR"),105 "/../crates/jrsonnet-rowan-parser/src/generated/nodes.rs",106 )),107 &nodes,108 )?;109 Ok(())110}111112fn generate_syntax_kinds(kinds: &KindsSrc, grammar: &AstSrc) -> Result<String> {113 let t_macros = kinds.tokens().filter_map(TokenKind::expand_t_macros);114 let token_kinds = kinds.tokens().map(TokenKind::expand_kind);115116 let keywords = kinds117 .tokens()118 .filter(|k| matches!(k, TokenKind::Keyword { .. }))119 .map(TokenKind::name)120 .map(|n| format_ident!("{n}"));121122 let nodes = kinds123 .nodes124 .iter()125 .map(|name| format_ident!("{}", name))126 .collect::<Vec<_>>();127128 let enums = grammar129 .enums130 .iter()131 .map(|e| format_ident!("{}", to_upper_snake_case(&e.name)))132 .chain(133 grammar134 .token_enums135 .iter()136 .map(|e| format_ident!("{}", to_upper_snake_case(&e.name))),137 );138139 let ast = quote! {140 #![allow(bad_style, missing_docs, unreachable_pub, clippy::manual_non_exhaustive, clippy::match_like_matches_macro)]141 use logos::Logos;142143 /// The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT`.144 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Logos)]145 #[repr(u16)]146 pub enum SyntaxKind {147 #[doc(hidden)]148 TOMBSTONE,149 #[doc(hidden)]150 EOF,151 #(#token_kinds,)*152 #[error]153 ERROR,154 #(#nodes,)*155 #[doc(hidden)]156 __LAST,157 }158 use self::SyntaxKind::*;159160 impl SyntaxKind {161 pub fn is_keyword(self) -> bool {162 match self {163 #(#keywords)|* => true,164 _ => false,165 }166 }167 pub fn is_enum(self) -> bool {168 match self {169 #(#enums)|* => true,170 _ => false,171 }172 }173174 pub fn from_raw(r: u16) -> Self {175 assert!(r < Self::__LAST as u16);176 unsafe { std::mem::transmute(r) }177 }178 pub fn into_raw(self) -> u16 {179 self as u16180 }181 }182183 #[macro_export]184 macro_rules! T {#(#t_macros);*}185 pub use T;186 };187188 reformat(&ast.to_string())189}190191fn generate_nodes(kinds: &KindsSrc, grammar: &AstSrc) -> Result<String> {192 let (node_defs, node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar193 .nodes194 .iter()195 .map(|node| {196 let name = format_ident!("{}", node.name);197 let kind = format_ident!("{}", to_upper_snake_case(&node.name));198 let traits = node.traits.iter().map(|trait_name| {199 let trait_name = format_ident!("{}", trait_name);200 quote!(impl ast::#trait_name for #name {})201 });202203 let methods = node.fields.iter().map(|field| {204 let method_name = field.method_name(kinds);205 let ty = field.ty();206207 if field.is_many() {208 quote! {209 pub fn #method_name(&self) -> AstChildren<#ty> {210 support::children(&self.syntax)211 }212 }213 } else if let Some(token_kind) = field.token_kind(kinds) {214 quote! {215 pub fn #method_name(&self) -> Option<#ty> {216 support::token(&self.syntax, #token_kind)217 }218 }219 } else if field.is_token_enum(grammar) {220 quote! {221 pub fn #method_name(&self) -> Option<#ty> {222 support::token_child(&self.syntax)223 }224 }225 } else {226 quote! {227 pub fn #method_name(&self) -> Option<#ty> {228 support::child(&self.syntax)229 }230 }231 }232 });233 (234 quote! {235 #[pretty_doc_comment_placeholder_workaround]236 #[derive(Debug, Clone, PartialEq, Eq, Hash)]237 pub struct #name {238 pub(crate) syntax: SyntaxNode,239 }240241 #(#traits)*242243 impl #name {244 #(#methods)*245 }246 },247 quote! {248 impl AstNode for #name {249 fn can_cast(kind: SyntaxKind) -> bool {250 kind == #kind251 }252 fn cast(syntax: SyntaxNode) -> Option<Self> {253 if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }254 }255 fn syntax(&self) -> &SyntaxNode { &self.syntax }256 }257 },258 )259 })260 .unzip();261262 let (enum_defs, enum_boilerplate_impls): (Vec<_>, Vec<_>) = grammar263 .enums264 .iter()265 .map(|en| {266 let variants: Vec<_> = en267 .variants268 .iter()269 .map(|var| format_ident!("{}", var))270 .collect();271 let name = format_ident!("{}", en.name);272 let kinds: Vec<_> = variants273 .iter()274 .map(|name| format_ident!("{}", to_upper_snake_case(&name.to_string())))275 .collect();276 let traits = en.traits.iter().map(|trait_name| {277 let trait_name = format_ident!("{}", trait_name);278 quote!(impl ast::#trait_name for #name {})279 });280281 let ast_node = quote! {282 impl AstNode for #name {283 fn can_cast(kind: SyntaxKind) -> bool {284 match kind {285 #(#kinds)|* => true,286 _ => false,287 }288 }289 fn cast(syntax: SyntaxNode) -> Option<Self> {290 let res = match syntax.kind() {291 #(292 #kinds => #name::#variants(#variants { syntax }),293 )*294 _ => return None,295 };296 Some(res)297 }298 fn syntax(&self) -> &SyntaxNode {299 match self {300 #(301 #name::#variants(it) => &it.syntax,302 )*303 }304 }305 }306 };307308 (309 quote! {310 #[pretty_doc_comment_placeholder_workaround]311 #[derive(Debug, Clone, PartialEq, Eq, Hash)]312 pub enum #name {313 #(#variants(#variants),)*314 }315316 #(#traits)*317 },318 quote! {319 #(320 impl From<#variants> for #name {321 fn from(node: #variants) -> #name {322 #name::#variants(node)323 }324 }325 )*326 #ast_node327 },328 )329 })330 .unzip();331332 let (token_enum_defs, token_enum_boilerplate_impls): (Vec<_>, Vec<_>) = grammar333 .token_enums334 .iter()335 .map(|en| {336 let variants: Vec<_> = en337 .variants338 .iter()339 .map(|token| {340 format_ident!(341 "{}",342 to_pascal_case(kinds.token(token).expect("token exists").name())343 )344 })345 .collect();346 let name = format_ident!("{}", en.name);347 let kind_name = format_ident!("{}Kind", en.name);348 let kinds: Vec<_> = variants349 .iter()350 .map(|name| format_ident!("{}", to_upper_snake_case(&name.to_string())))351 .collect();352353 let ast_node = quote! {354 impl AstToken for #name {355 fn can_cast(kind: SyntaxKind) -> bool {356 match kind {357 #(#kinds)|* => true,358 _ => false,359 }360 }361 fn cast(syntax: SyntaxToken) -> Option<Self> {362 let res = match syntax.kind() {363 #(364 #kinds => #name { syntax, kind: #kind_name::#variants },365 )*366 _ => return None,367 };368 Some(res)369 }370 fn syntax(&self) -> &SyntaxToken {371 &self.syntax372 }373 }374 };375376 (377 quote! {378 #[pretty_doc_comment_placeholder_workaround]379 #[derive(Debug, Clone, PartialEq, Eq, Hash)]380 pub struct #name { syntax: SyntaxToken, kind: #kind_name }381382 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]383 pub enum #kind_name {384 #(#variants,)*385 }386 },387 quote! {388 #ast_node389390 impl #name {391 pub fn kind(&self) -> #kind_name {392 self.kind393 }394 }395396 impl std::fmt::Display for #name {397 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {398 std::fmt::Display::fmt(self.syntax(), f)399 }400 }401 },402 )403 })404 .unzip();405406 let (any_node_defs, any_node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar407 .nodes408 .iter()409 .flat_map(|node| node.traits.iter().map(move |t| (t, node)))410 .into_group_map()411 .into_iter()412 .sorted_by_key(|(k, _)| *k)413 .map(|(trait_name, nodes)| {414 let name = format_ident!("Any{}", trait_name);415 let trait_name = format_ident!("{}", trait_name);416 let kinds: Vec<_> = nodes417 .iter()418 .map(|name| format_ident!("{}", to_upper_snake_case(&name.name.to_string())))419 .collect();420421 (422 quote! {423 #[pretty_doc_comment_placeholder_workaround]424 #[derive(Debug, Clone, PartialEq, Eq, Hash)]425 pub struct #name {426 pub(crate) syntax: SyntaxNode,427 }428 impl ast::#trait_name for #name {}429 },430 quote! {431 impl #name {432 #[inline]433 pub fn new<T: ast::#trait_name>(node: T) -> #name {434 #name {435 syntax: node.syntax().clone()436 }437 }438 }439 impl AstNode for #name {440 fn can_cast(kind: SyntaxKind) -> bool {441 match kind {442 #(#kinds)|* => true,443 _ => false,444 }445 }446 fn cast(syntax: SyntaxNode) -> Option<Self> {447 Self::can_cast(syntax.kind()).then(|| #name { syntax })448 }449 fn syntax(&self) -> &SyntaxNode {450 &self.syntax451 }452 }453 },454 )455 })456 .unzip();457458 let enum_names = grammar.enums.iter().map(|it| &it.name);459 let node_names = grammar.nodes.iter().map(|it| &it.name);460461 let display_impls = enum_names462 .chain(node_names.clone())463 .map(|it| format_ident!("{}", it))464 .map(|name| {465 quote! {466 impl std::fmt::Display for #name {467 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {468 std::fmt::Display::fmt(self.syntax(), f)469 }470 }471 }472 });473474 let ast = quote! {475 #![allow(non_snake_case, clippy::match_like_matches_macro)]476477 use crate::{478 SyntaxNode, SyntaxToken, SyntaxKind::{self, *},479 ast::{AstNode, AstToken, AstChildren, support},480 T,481 };482483 #(#node_defs)*484 #(#enum_defs)*485 #(#token_enum_defs)*486 #(#any_node_defs)*487 #(#node_boilerplate_impls)*488 #(#enum_boilerplate_impls)*489 #(#token_enum_boilerplate_impls)*490 #(#any_node_boilerplate_impls)*491 #(#display_impls)*492 };493494 let ast = ast.to_string().replace("T ! [", "T![");495496 let mut res = String::with_capacity(ast.len() * 2);497498 let mut docs = grammar499 .nodes500 .iter()501 .map(|it| &it.doc)502 .chain(grammar.enums.iter().map(|it| &it.doc));503504 for chunk in ast.split("# [pretty_doc_comment_placeholder_workaround] ") {505 res.push_str(chunk);506 if let Some(doc) = docs.next() {507 write_doc_comment(doc, &mut res);508 }509 }510511 let res = reformat(&res)?;512 Ok(res.replace("#[derive", "\n#[derive"))513}514515fn write_doc_comment(contents: &[String], dest: &mut String) {516 use std::fmt::Write;517 for line in contents {518 writeln!(dest, "///{}", line).unwrap();519 }520}521522pub fn escape_token_macro(token: &str) -> TokenStream {523 if "{}[]()$".contains(token) {524 let c = token.chars().next().unwrap();525 quote! { #c }526 } else if token.contains('$') {527 quote! { #token }528 } else {529 let cs = token.chars().map(|c| Punct::new(c, Spacing::Joint));530 quote! { #(#cs)* }531 }532}1use std::path::PathBuf;23use anyhow::Result;4use ast::{lower, AstSrc};5use itertools::Itertools;6use kinds::{KindsSrc, TokenKind};7use proc_macro2::{Punct, Spacing, TokenStream};8use quote::{format_ident, quote};9use ungrammar::Grammar;10use util::{ensure_file_contents, reformat, to_pascal_case, to_upper_snake_case};1112mod ast;13mod kinds;14mod util;1516enum SpecialName {17 Literal,18 Meta,19 Error,20}21fn classify_special(name: &str) -> Option<(SpecialName, &str)> {22 let name = name.strip_suffix('!')?;23 Some(if let Some(name) = name.strip_prefix("LIT_") {24 (SpecialName::Literal, name)25 } else if let Some(name) = name.strip_prefix("META_") {26 (SpecialName::Meta, name)27 } else if let Some(name) = name.strip_prefix("ERROR_") {28 (SpecialName::Error, name)29 } else {30 return None;31 })32}3334pub fn generate_ungrammar() -> Result<()> {35 let grammar: Grammar = include_str!(concat!(36 env!("CARGO_MANIFEST_DIR"),37 "/../crates/jrsonnet-rowan-parser/jsonnet.ungram"38 ))39 .parse()?;4041 let mut kinds = kinds::jsonnet_kinds();42 let ast = lower(&kinds, &grammar);4344 for token in grammar.tokens() {45 let token = &grammar[token];46 let token = &token.name.clone();47 if !kinds.is_token(token) {48 if let Some((special, name)) = classify_special(token) {49 match special {50 SpecialName::Literal => panic!("literal is not defined: {name}"),51 SpecialName::Meta => {52 eprintln!("implicit meta: {}", name);53 kinds.define_token(TokenKind::Meta {54 grammar_name: token.to_owned(),55 name: format!("META_{}", name),56 })57 }58 SpecialName::Error => {59 eprintln!("implicit error: {}", name);60 kinds.define_token(TokenKind::Error {61 grammar_name: token.to_owned(),62 name: format!("ERROR_{}", name),63 regex: None,64 priority: None,65 is_lexer_error: true,66 })67 }68 };69 continue;70 };71 let name = to_upper_snake_case(token);72 eprintln!("implicit kw: {}", token);73 kinds.define_token(TokenKind::Keyword {74 code: token.to_owned(),75 name: format!("{name}_KW"),76 });77 }78 }79 for node in &ast.nodes {80 let name = to_upper_snake_case(&node.name);81 kinds.define_node(&name);82 }83 for enum_ in &ast.enums {84 let name = to_upper_snake_case(&enum_.name);85 kinds.define_node(&name);86 }87 for token_enum in &ast.token_enums {88 let name = to_upper_snake_case(&token_enum.name);89 kinds.define_node(&name);90 }9192 let syntax_kinds = generate_syntax_kinds(&kinds, &ast)?;9394 let nodes = generate_nodes(&kinds, &ast)?;95 ensure_file_contents(96 &PathBuf::from(concat!(97 env!("CARGO_MANIFEST_DIR"),98 "/../crates/jrsonnet-rowan-parser/src/generated/syntax_kinds.rs",99 )),100 &syntax_kinds,101 )?;102 ensure_file_contents(103 &PathBuf::from(concat!(104 env!("CARGO_MANIFEST_DIR"),105 "/../crates/jrsonnet-rowan-parser/src/generated/nodes.rs",106 )),107 &nodes,108 )?;109 Ok(())110}111112fn generate_syntax_kinds(kinds: &KindsSrc, grammar: &AstSrc) -> Result<String> {113 let t_macros = kinds.tokens().filter_map(TokenKind::expand_t_macros);114 let token_kinds = kinds.tokens().map(TokenKind::expand_kind);115116 let keywords = kinds117 .tokens()118 .filter(|k| matches!(k, TokenKind::Keyword { .. }))119 .map(TokenKind::name)120 .map(|n| format_ident!("{n}"));121122 let nodes = kinds123 .nodes124 .iter()125 .map(|name| format_ident!("{}", name))126 .collect::<Vec<_>>();127128 let enums = grammar129 .enums130 .iter()131 .map(|e| format_ident!("{}", to_upper_snake_case(&e.name)))132 .chain(133 grammar134 .token_enums135 .iter()136 .map(|e| format_ident!("{}", to_upper_snake_case(&e.name))),137 );138139 let ast = quote! {140 #![allow(bad_style, missing_docs, unreachable_pub, clippy::manual_non_exhaustive, clippy::match_like_matches_macro)]141 use logos::Logos;142143 /// The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT`.144 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Logos)]145 #[repr(u16)]146 pub enum SyntaxKind {147 #[doc(hidden)]148 TOMBSTONE,149 #[doc(hidden)]150 EOF,151 #(#token_kinds,)*152 #[error]153 ERROR,154 #(#nodes,)*155 #[doc(hidden)]156 __LAST,157 }158 use self::SyntaxKind::*;159160 impl SyntaxKind {161 pub fn is_keyword(self) -> bool {162 match self {163 #(#keywords)|* => true,164 _ => false,165 }166 }167 pub fn is_enum(self) -> bool {168 match self {169 #(#enums)|* => true,170 _ => false,171 }172 }173174 pub fn from_raw(r: u16) -> Self {175 assert!(r < Self::__LAST as u16);176 unsafe { std::mem::transmute(r) }177 }178 pub fn into_raw(self) -> u16 {179 self as u16180 }181 }182183 #[macro_export]184 macro_rules! T {#(#t_macros);*}185 pub use T;186 };187188 reformat(&ast.to_string())189}190191fn generate_nodes(kinds: &KindsSrc, grammar: &AstSrc) -> Result<String> {192 let (node_defs, node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar193 .nodes194 .iter()195 .map(|node| {196 let name = format_ident!("{}", node.name);197 let kind = format_ident!("{}", to_upper_snake_case(&node.name));198 let traits = node.traits.iter().map(|trait_name| {199 let trait_name = format_ident!("{}", trait_name);200 quote!(impl ast::#trait_name for #name {})201 });202203 let methods = node.fields.iter().map(|field| {204 let method_name = field.method_name(kinds);205 let ty = field.ty();206207 if field.is_many() {208 quote! {209 pub fn #method_name(&self) -> AstChildren<#ty> {210 support::children(&self.syntax)211 }212 }213 } else if let Some(token_kind) = field.token_kind(kinds) {214 quote! {215 pub fn #method_name(&self) -> Option<#ty> {216 support::token(&self.syntax, #token_kind)217 }218 }219 } else if field.is_token_enum(grammar) {220 quote! {221 pub fn #method_name(&self) -> Option<#ty> {222 support::token_child(&self.syntax)223 }224 }225 } else {226 quote! {227 pub fn #method_name(&self) -> Option<#ty> {228 support::child(&self.syntax)229 }230 }231 }232 });233 (234 quote! {235 #[pretty_doc_comment_placeholder_workaround]236 #[derive(Debug, Clone, PartialEq, Eq, Hash)]237 pub struct #name {238 pub(crate) syntax: SyntaxNode,239 }240241 #(#traits)*242243 impl #name {244 #(#methods)*245 }246 },247 quote! {248 impl AstNode for #name {249 fn can_cast(kind: SyntaxKind) -> bool {250 kind == #kind251 }252 fn cast(syntax: SyntaxNode) -> Option<Self> {253 if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }254 }255 fn syntax(&self) -> &SyntaxNode { &self.syntax }256 }257 },258 )259 })260 .unzip();261262 let (enum_defs, enum_boilerplate_impls): (Vec<_>, Vec<_>) = grammar263 .enums264 .iter()265 .map(|en| {266 let variants: Vec<_> = en267 .variants268 .iter()269 .map(|var| format_ident!("{}", var))270 .collect();271 let name = format_ident!("{}", en.name);272 let kinds: Vec<_> = variants273 .iter()274 .map(|name| format_ident!("{}", to_upper_snake_case(&name.to_string())))275 .collect();276 let traits = en.traits.iter().map(|trait_name| {277 let trait_name = format_ident!("{}", trait_name);278 quote!(impl ast::#trait_name for #name {})279 });280281 let ast_node = quote! {282 impl AstNode for #name {283 fn can_cast(kind: SyntaxKind) -> bool {284 match kind {285 #(#kinds)|* => true,286 _ => false,287 }288 }289 fn cast(syntax: SyntaxNode) -> Option<Self> {290 let res = match syntax.kind() {291 #(292 #kinds => #name::#variants(#variants { syntax }),293 )*294 _ => return None,295 };296 Some(res)297 }298 fn syntax(&self) -> &SyntaxNode {299 match self {300 #(301 #name::#variants(it) => &it.syntax,302 )*303 }304 }305 }306 };307308 (309 quote! {310 #[pretty_doc_comment_placeholder_workaround]311 #[derive(Debug, Clone, PartialEq, Eq, Hash)]312 pub enum #name {313 #(#variants(#variants),)*314 }315316 #(#traits)*317 },318 quote! {319 #(320 impl From<#variants> for #name {321 fn from(node: #variants) -> #name {322 #name::#variants(node)323 }324 }325 )*326 #ast_node327 },328 )329 })330 .unzip();331332 let (token_enum_defs, token_enum_boilerplate_impls): (Vec<_>, Vec<_>) = grammar333 .token_enums334 .iter()335 .map(|en| {336 let variants: Vec<_> = en337 .variants338 .iter()339 .map(|token| {340 format_ident!(341 "{}",342 to_pascal_case(kinds.token(token).expect("token exists").name())343 )344 })345 .collect();346 let name = format_ident!("{}", en.name);347 let kind_name = format_ident!("{}Kind", en.name);348 let kinds: Vec<_> = variants349 .iter()350 .map(|name| format_ident!("{}", to_upper_snake_case(&name.to_string())))351 .collect();352353 let ast_node = quote! {354 impl AstToken for #name {355 fn can_cast(kind: SyntaxKind) -> bool {356 #kind_name::can_cast(kind)357 }358 fn cast(syntax: SyntaxToken) -> Option<Self> {359 let kind = #kind_name::cast(syntax.kind())?;360 Some(#name { syntax, kind })361 }362 fn syntax(&self) -> &SyntaxToken {363 &self.syntax364 }365 }366367 impl #kind_name {368 fn can_cast(kind: SyntaxKind) -> bool {369 match kind {370 #(#kinds)|* => true,371 _ => false,372 }373 }374 pub fn cast(kind: SyntaxKind) -> Option<Self> {375 let res = match kind {376 #(#kinds => Self::#variants,)*377 _ => return None,378 };379 Some(res)380 }381 }382 };383384 (385 quote! {386 #[pretty_doc_comment_placeholder_workaround]387 #[derive(Debug, Clone, PartialEq, Eq, Hash)]388 pub struct #name { syntax: SyntaxToken, kind: #kind_name }389390 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]391 pub enum #kind_name {392 #(#variants,)*393 }394 },395 quote! {396 #ast_node397398 impl #name {399 pub fn kind(&self) -> #kind_name {400 self.kind401 }402 }403404 impl std::fmt::Display for #name {405 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {406 std::fmt::Display::fmt(self.syntax(), f)407 }408 }409 },410 )411 })412 .unzip();413414 let (any_node_defs, any_node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar415 .nodes416 .iter()417 .flat_map(|node| node.traits.iter().map(move |t| (t, node)))418 .into_group_map()419 .into_iter()420 .sorted_by_key(|(k, _)| *k)421 .map(|(trait_name, nodes)| {422 let name = format_ident!("Any{}", trait_name);423 let trait_name = format_ident!("{}", trait_name);424 let kinds: Vec<_> = nodes425 .iter()426 .map(|name| format_ident!("{}", to_upper_snake_case(&name.name.to_string())))427 .collect();428429 (430 quote! {431 #[pretty_doc_comment_placeholder_workaround]432 #[derive(Debug, Clone, PartialEq, Eq, Hash)]433 pub struct #name {434 pub(crate) syntax: SyntaxNode,435 }436 impl ast::#trait_name for #name {}437 },438 quote! {439 impl #name {440 #[inline]441 pub fn new<T: ast::#trait_name>(node: T) -> #name {442 #name {443 syntax: node.syntax().clone()444 }445 }446 }447 impl AstNode for #name {448 fn can_cast(kind: SyntaxKind) -> bool {449 match kind {450 #(#kinds)|* => true,451 _ => false,452 }453 }454 fn cast(syntax: SyntaxNode) -> Option<Self> {455 Self::can_cast(syntax.kind()).then(|| #name { syntax })456 }457 fn syntax(&self) -> &SyntaxNode {458 &self.syntax459 }460 }461 },462 )463 })464 .unzip();465466 let enum_names = grammar.enums.iter().map(|it| &it.name);467 let node_names = grammar.nodes.iter().map(|it| &it.name);468469 let display_impls = enum_names470 .chain(node_names.clone())471 .map(|it| format_ident!("{}", it))472 .map(|name| {473 quote! {474 impl std::fmt::Display for #name {475 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {476 std::fmt::Display::fmt(self.syntax(), f)477 }478 }479 }480 });481482 let ast = quote! {483 #![allow(non_snake_case, clippy::match_like_matches_macro)]484485 use crate::{486 SyntaxNode, SyntaxToken, SyntaxKind::{self, *},487 ast::{AstNode, AstToken, AstChildren, support},488 T,489 };490491 #(#node_defs)*492 #(#enum_defs)*493 #(#token_enum_defs)*494 #(#any_node_defs)*495 #(#node_boilerplate_impls)*496 #(#enum_boilerplate_impls)*497 #(#token_enum_boilerplate_impls)*498 #(#any_node_boilerplate_impls)*499 #(#display_impls)*500 };501502 let ast = ast.to_string().replace("T ! [", "T![");503504 let mut res = String::with_capacity(ast.len() * 2);505506 let mut docs = grammar507 .nodes508 .iter()509 .map(|it| &it.doc)510 .chain(grammar.enums.iter().map(|it| &it.doc));511512 for chunk in ast.split("# [pretty_doc_comment_placeholder_workaround] ") {513 res.push_str(chunk);514 if let Some(doc) = docs.next() {515 write_doc_comment(doc, &mut res);516 }517 }518519 let res = reformat(&res)?;520 Ok(res.replace("#[derive", "\n#[derive"))521}522523fn write_doc_comment(contents: &[String], dest: &mut String) {524 use std::fmt::Write;525 for line in contents {526 writeln!(dest, "///{}", line).unwrap();527 }528}529530pub fn escape_token_macro(token: &str) -> TokenStream {531 if "{}[]()$".contains(token) {532 let c = token.chars().next().unwrap();533 quote! { #c }534 } else if token.contains('$') {535 quote! { #token }536 } else {537 let cs = token.chars().map(|c| Punct::new(c, Spacing::Joint));538 quote! { #(#cs)* }539 }540}