difftreelog
refactor introduce ungrammar
in: master
23 files changed
.cargo/configdiffbeforeafterboth--- /dev/null
+++ b/.cargo/config
@@ -0,0 +1,2 @@
+[alias]
+xtask = "run --manifest-path ./xtask/Cargo.toml --"
Cargo.tomldiffbeforeafterboth--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
[workspace]
package.version = "0.5.0-pre95"
package.repository = "https://github.com/CertainLach/jrsonnet"
-members = ["crates/*", "bindings/jsonnet", "cmds/*", "tests"]
+members = ["crates/*", "bindings/jsonnet", "cmds/*", "tests", "xtask"]
default-members = ["cmds/jrsonnet"]
resolver = "2"
crates/jrsonnet-rowan-parser/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/Cargo.toml
+++ b/crates/jrsonnet-rowan-parser/Cargo.toml
@@ -18,3 +18,4 @@
backtrace = "0.3.63"
indoc = "1.0.3"
insta = "1.10.0"
+anyhow = "1.0.57"
crates/jrsonnet-rowan-parser/jsonnet.ungramdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/jsonnet.ungram
@@ -0,0 +1,334 @@
+SourceFile = Expr
+
+ExprBinary =
+ lhs:Expr
+ BinaryOperator
+ rhs:Expr
+ExprUnary =
+ UnaryOperator
+ rhs:Expr
+ExprSlice =
+ Expr
+ '['
+ SliceDesc
+ ']'
+ExprIndex =
+ Expr
+ '.'
+ index:Name
+ExprIndexExpr =
+ base:Expr
+ '['
+ index:Expr
+ ']'
+ExprApply =
+ Expr
+ '('
+ ArgsDesc
+ ')'
+ 'tailstrict'?
+ExprObjExtend =
+ Expr
+ '{'
+ ObjBody
+ '}'
+ExprParened =
+ '('
+ Expr
+ ')'
+
+ExprLiteral =
+ Literal
+ExprIntrinsicThisFile =
+ '$intrinsicThisFile'
+ExprIntrinsicId =
+ '$intrinsicId'
+ExprIntrinsic =
+ '$intrinsic'
+ '('
+ name:Name
+ ')'
+ExprString =
+ String
+ExprNumber =
+ Number
+ExprArray =
+ '['
+ (Expr (',' Expr)* ','?)?
+ ']'
+ExprObject =
+ '{'
+ ObjBody
+ '}'
+ExprArrayComp =
+ '['
+ Expr
+ ','?
+ ForSpec
+ CompSpec*
+ ']'
+ExprImport =
+ 'importstr' String
+| 'importbin' String
+| 'import' String
+
+ExprVar =
+ name:Name
+ExprLocal =
+ 'local'
+ (Bind (',' Bind)* ','?)
+ ';'
+ExprIfThenElse =
+ 'if'
+ cond:Expr
+ 'then'
+ then:Expr
+ ('else' else_:Expr)?
+ExprFunction =
+ 'function'
+ '('
+ ParamsDesc
+ ')'
+ Expr
+ExprAssert =
+ Assertion
+ ';'
+ Expr
+ExprError =
+ 'error'
+ Expr
+
+Expr =
+ ExprBinary
+| ExprUnary
+| ExprSlice
+| ExprIndex
+| ExprIndexExpr
+| ExprApply
+| ExprObjExtend
+| ExprParened
+| ExprIntrinsicThisFile
+| ExprIntrinsicId
+| ExprIntrinsic
+| ExprString
+| ExprNumber
+| ExprArray
+| ExprObject
+| ExprArrayComp
+| ExprImport
+| ExprVar
+| ExprLocal
+| ExprIfThenElse
+| ExprFunction
+| ExprAssert
+| ExprError
+
+BinaryOperator =
+ '||' | '&&'
+| '|' | '^' | '&'
+| '==' | '!=' | '<' | '>' | '<=' | '>=' | 'in'
+| '<<' | '>>'
+| '+' | '-'
+| '*' | '/' | '%'
+
+UnaryOperator =
+ '-' | '!' | '~'
+
+SliceDesc =
+ from:Expr?
+ ':'
+ (
+ end:Expr?
+ (
+ ':'
+ step:Expr?
+ )?
+ )?
+
+Name =
+ 'ident'
+
+ArgsDesc =
+ (Arg (',' Arg)* ','?)?
+Arg =
+ (name:Name '=')? Expr
+
+ObjBodyComp =
+ pre:ObjLocalPostComma*
+ '['
+ key:Expr
+ ']'
+ '+'?
+ ':'
+ value:Expr
+ post:ObjLocalPreComma*
+ ForSpec
+ CompSpec*
+ObjBodyMemberList =
+ (Member (',' Member) ','?)?
+ObjBody =
+ ObjBodyComp
+| ObjBodyMemberList
+
+ObjLocalPostComma =
+ ObjLocal
+ ','
+ObjLocalPreComma =
+ ','
+ ObjLocal
+
+MemberBindStmt = ObjLocal
+MemberAssertStmt = Assertion
+MemberField = Field
+Member =
+ MemberBindStmt
+| MemberAssertStmt
+| MemberField
+
+ObjLocal =
+ 'local'
+ Bind
+
+FieldNormal =
+ FieldName
+ '+'?
+ Visibility
+ Expr
+FieldMethod =
+ FieldName
+ '('
+ ParamsDesc
+ ')'
+ Visibility
+ Expr
+Field =
+ FieldNormal
+| FieldMethod
+
+FieldNameFixed =
+ id:Name
+| String
+FieldNameDynamic =
+ '['
+ Expr
+ ']'
+FieldName =
+ FieldNameFixed
+| FieldNameDynamic
+
+Visibility =
+ ':::'
+| '::'
+| ':'
+
+Literal =
+ 'null'
+| 'true'
+| 'false'
+| 'self'
+| '$'
+| 'super'
+
+String =
+ 'string_double'
+| 'string_single'
+| 'string_double_verbatim'
+| 'string_single_verbatim'
+| 'string_block'
+
+Number =
+ 'number'
+
+ForSpec =
+ 'for'
+ bind:Name
+ 'in'
+ Expr
+IfSpec =
+ 'if'
+ Expr
+CompSpec =
+ ForSpec
+| IfSpec
+
+BindDestruct =
+ into:Destruct
+ '='
+ value:Expr
+BindFunction =
+ name:Name
+ '('
+ params:ParamsDesc
+ ')'
+ '='
+ value:Expr
+Bind =
+ BindDestruct
+| BindFunction
+
+ParamsDesc =
+ (Param (',' Param)* ','?)?
+Param =
+ Destruct
+ (
+ '='
+ Expr
+ )?
+
+Assertion =
+ 'assert'
+ condition:Expr
+ (
+ ':'
+ Expr
+ )?
+
+DestructFull =
+ into:Name
+DestructSkip =
+ '?'
+DestructArray =
+ '['
+ start:(
+ Destruct
+ (',' Destruct)*
+ ','?
+ )?
+ DestructRest?
+ ','?
+ end:(
+ Destruct
+ (',' Destruct)*
+ ','?
+ )
+ ']'
+DestructObject =
+ '{'
+ (
+ DestructObjectField
+ (',' DestructObjectField)*
+ ','?
+ )?
+ DestructRest?
+ ','?
+ '}'
+Destruct =
+ DestructFull
+ DestructSkip
+ DestructArray
+ DestructObject
+
+DestructRest =
+ '...'
+ into:Name?
+
+DestructObjectField =
+ field:Name
+ (
+ ':'
+ Destruct
+ )?
+ (
+ '='
+ Expr
+ )?
crates/jrsonnet-rowan-parser/src/ast.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/ast.rs
@@ -0,0 +1 @@
+pub trait AstToken {}
crates/jrsonnet-rowan-parser/src/event.rsdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/src/event.rs
+++ b/crates/jrsonnet-rowan-parser/src/event.rs
@@ -3,8 +3,9 @@
use rowan::{GreenNode, GreenNodeBuilder, Language};
use crate::{
- lex::{Lang, Lexeme, SyntaxKind},
+ lex::Lexeme,
parser::{Parse, SyntaxError},
+ JsonnetLanguage, SyntaxKind,
};
#[derive(Clone, Debug, PartialEq, Eq)]
@@ -69,7 +70,7 @@
}
for kind in kinds.into_iter().rev() {
- self.builder.start_node(Lang::kind_to_raw(kind));
+ self.builder.start_node(JsonnetLanguage::kind_to_raw(kind));
}
}
Event::Token => self.token(),
@@ -92,7 +93,7 @@
fn token(&mut self) {
let lexeme = self.lexemes[self.offset];
self.builder
- .token(Lang::kind_to_raw(lexeme.kind), lexeme.text);
+ .token(JsonnetLanguage::kind_to_raw(lexeme.kind), lexeme.text);
self.offset += 1;
}
fn skip_whitespace(&mut self) {
crates/jrsonnet-rowan-parser/src/generated/mod.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/generated/mod.rs
@@ -0,0 +1,3 @@
+// mod tokens;
+// mod nodes;
+pub mod syntax_kinds;
crates/jrsonnet-rowan-parser/src/generated/nodes.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/generated/nodes.rs
@@ -0,0 +1,2072 @@
+//! This is a generated file, please do not edit manually. Changes can be
+//! made in codegeneration that lives in `xtask` top-level dir.
+
+#![allow(non_snake_case)]
+use crate::{
+ ast::{self, support, AstChildren, AstNode},
+ SyntaxKind::{self, *},
+ SyntaxNode, SyntaxToken, T,
+};
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct SourceFile {
+ pub(crate) syntax: SyntaxNode,
+}
+impl SourceFile {
+ pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprBinary {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprBinary {
+ pub fn lhs(&self) -> Option<Expr> { support::child(&self.syntax) }
+ pub fn binary_operator(&self) -> Option<BinaryOperator> { support::child(&self.syntax) }
+ pub fn rhs(&self) -> Option<Expr> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct BinaryOperator {
+ pub(crate) syntax: SyntaxNode,
+}
+impl BinaryOperator {
+ pub fn or_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![||]) }
+ pub fn and_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&&]) }
+ pub fn bit_or_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![|]) }
+ pub fn bit_xor_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![^]) }
+ pub fn bit_and_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) }
+ pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![==]) }
+ pub fn ne_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!=]) }
+ pub fn lt_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
+ pub fn gt_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
+ pub fn le_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<=]) }
+ pub fn ge_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>=]) }
+ pub fn in_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![in]) }
+ pub fn lhs_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<<]) }
+ pub fn rhs_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>>]) }
+ pub fn plus_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![+]) }
+ pub fn minus_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![-]) }
+ pub fn mul_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![*]) }
+ pub fn div_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![/]) }
+ pub fn modulo_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![%]) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprUnary {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprUnary {
+ pub fn unary_operator(&self) -> Option<UnaryOperator> { support::child(&self.syntax) }
+ pub fn rhs(&self) -> Option<Expr> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct UnaryOperator {
+ pub(crate) syntax: SyntaxNode,
+}
+impl UnaryOperator {
+ pub fn minus_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![-]) }
+ pub fn not_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
+ pub fn bit_not_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![~]) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprSlice {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprSlice {
+ pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+ pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
+ pub fn slice_desc(&self) -> Option<SliceDesc> { support::child(&self.syntax) }
+ pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct SliceDesc {
+ pub(crate) syntax: SyntaxNode,
+}
+impl SliceDesc {
+ pub fn from(&self) -> Option<Expr> { support::child(&self.syntax) }
+ pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
+ pub fn end(&self) -> Option<Expr> { support::child(&self.syntax) }
+ pub fn step(&self) -> Option<Expr> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprIndex {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprIndex {
+ pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+ pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) }
+ pub fn index(&self) -> Option<Name> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Name {
+ pub(crate) syntax: SyntaxNode,
+}
+impl Name {
+ pub fn ident_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![ident]) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprIndexExpr {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprIndexExpr {
+ pub fn base(&self) -> Option<Expr> { support::child(&self.syntax) }
+ pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
+ pub fn index(&self) -> Option<Expr> { support::child(&self.syntax) }
+ pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprApply {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprApply {
+ pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+ pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+ pub fn args_desc(&self) -> Option<ArgsDesc> { support::child(&self.syntax) }
+ pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+ pub fn tailstrict_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![tailstrict])
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ArgsDesc {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ArgsDesc {
+ pub fn args(&self) -> AstChildren<Arg> { support::children(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprObjExtend {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprObjExtend {
+ pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+ pub fn l_brace_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
+ pub fn obj_body(&self) -> Option<ObjBody> { support::child(&self.syntax) }
+ pub fn r_brace_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprParened {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprParened {
+ pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+ pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+ pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprLiteral {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprLiteral {
+ pub fn literal(&self) -> Option<Literal> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Literal {
+ pub(crate) syntax: SyntaxNode,
+}
+impl Literal {
+ pub fn null_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![null]) }
+ pub fn true_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![true]) }
+ pub fn false_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![false]) }
+ pub fn self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![self]) }
+ pub fn dollar_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['$']) }
+ pub fn super_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![super]) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprIntrinsicThisFile {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprIntrinsicThisFile {
+ pub fn intrinsic_this_file_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T!["$intrinsicThisFile"])
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprIntrinsicId {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprIntrinsicId {
+ pub fn intrinsic_id_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T!["$intrinsicId"])
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprIntrinsic {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprIntrinsic {
+ pub fn intrinsic_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T!["$intrinsic"])
+ }
+ pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+ pub fn name(&self) -> Option<Name> { support::child(&self.syntax) }
+ pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprString {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprString {
+ pub fn string(&self) -> Option<String> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct String {
+ pub(crate) syntax: SyntaxNode,
+}
+impl String {
+ pub fn string_double_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![string_double])
+ }
+ pub fn string_single_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![string_single])
+ }
+ pub fn string_double_verbatim_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![string_double_verbatim])
+ }
+ pub fn string_single_verbatim_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![string_single_verbatim])
+ }
+ pub fn string_block_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![string_block])
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprNumber {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprNumber {
+ pub fn number(&self) -> Option<Number> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Number {
+ pub(crate) syntax: SyntaxNode,
+}
+impl Number {
+ pub fn number_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![number]) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprArray {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprArray {
+ pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
+ pub fn exprs(&self) -> AstChildren<Expr> { support::children(&self.syntax) }
+ pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprObject {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprObject {
+ pub fn l_brace_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
+ pub fn obj_body(&self) -> Option<ObjBody> { support::child(&self.syntax) }
+ pub fn r_brace_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprArrayComp {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprArrayComp {
+ pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
+ pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+ pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
+ pub fn for_spec(&self) -> Option<ForSpec> { support::child(&self.syntax) }
+ pub fn comp_specs(&self) -> AstChildren<CompSpec> { support::children(&self.syntax) }
+ pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ForSpec {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ForSpec {
+ pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
+ pub fn bind(&self) -> Option<Name> { support::child(&self.syntax) }
+ pub fn in_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![in]) }
+ pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprImport {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprImport {
+ pub fn importstr_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![importstr])
+ }
+ pub fn string(&self) -> Option<String> { support::child(&self.syntax) }
+ pub fn importbin_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![importbin])
+ }
+ pub fn import_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![import]) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprVar {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprVar {
+ pub fn name(&self) -> Option<Name> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprLocal {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprLocal {
+ pub fn local_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![local]) }
+ pub fn binds(&self) -> AstChildren<Bind> { support::children(&self.syntax) }
+ pub fn semi_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprIfThenElse {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprIfThenElse {
+ pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
+ pub fn cond(&self) -> Option<Expr> { support::child(&self.syntax) }
+ pub fn then_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![then]) }
+ pub fn then(&self) -> Option<Expr> { support::child(&self.syntax) }
+ pub fn else_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![else]) }
+ pub fn else_(&self) -> Option<Expr> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprFunction {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprFunction {
+ pub fn function_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![function])
+ }
+ pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+ pub fn params_desc(&self) -> Option<ParamsDesc> { support::child(&self.syntax) }
+ pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+ pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ParamsDesc {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ParamsDesc {
+ pub fn params(&self) -> AstChildren<Param> { support::children(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprAssert {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprAssert {
+ pub fn assertion(&self) -> Option<Assertion> { support::child(&self.syntax) }
+ pub fn semi_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
+ pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Assertion {
+ pub(crate) syntax: SyntaxNode,
+}
+impl Assertion {
+ pub fn assert_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![assert]) }
+ pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
+ pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
+ pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprError {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprError {
+ pub fn error_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![error]) }
+ pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Arg {
+ pub(crate) syntax: SyntaxNode,
+}
+impl Arg {
+ pub fn name(&self) -> Option<Name> { support::child(&self.syntax) }
+ pub fn assign_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
+ pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ObjBodyComp {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ObjBodyComp {
+ pub fn pre(&self) -> AstChildren<ObjLocalPostComma> { support::children(&self.syntax) }
+ pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
+ pub fn key(&self) -> Option<Expr> { support::child(&self.syntax) }
+ pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
+ pub fn plus_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![+]) }
+ pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
+ pub fn value(&self) -> Option<Expr> { support::child(&self.syntax) }
+ pub fn post(&self) -> AstChildren<ObjLocalPreComma> { support::children(&self.syntax) }
+ pub fn for_spec(&self) -> Option<ForSpec> { support::child(&self.syntax) }
+ pub fn comp_specs(&self) -> AstChildren<CompSpec> { support::children(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ObjLocalPostComma {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ObjLocalPostComma {
+ pub fn obj_local(&self) -> Option<ObjLocal> { support::child(&self.syntax) }
+ pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ObjLocalPreComma {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ObjLocalPreComma {
+ pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
+ pub fn obj_local(&self) -> Option<ObjLocal> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ObjBodyMemberList {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ObjBodyMemberList {
+ pub fn member(&self) -> Option<Member> { support::child(&self.syntax) }
+ pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ObjLocal {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ObjLocal {
+ pub fn local_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![local]) }
+ pub fn bind(&self) -> Option<Bind> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct MemberBindStmt {
+ pub(crate) syntax: SyntaxNode,
+}
+impl MemberBindStmt {
+ pub fn obj_local(&self) -> Option<ObjLocal> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct MemberAssertStmt {
+ pub(crate) syntax: SyntaxNode,
+}
+impl MemberAssertStmt {
+ pub fn assertion(&self) -> Option<Assertion> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct MemberField {
+ pub(crate) syntax: SyntaxNode,
+}
+impl MemberField {
+ pub fn field(&self) -> Option<Field> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct FieldNormal {
+ pub(crate) syntax: SyntaxNode,
+}
+impl FieldNormal {
+ pub fn field_name(&self) -> Option<FieldName> { support::child(&self.syntax) }
+ pub fn plus_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![+]) }
+ pub fn visibility(&self) -> Option<Visibility> { support::child(&self.syntax) }
+ pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Visibility {
+ pub(crate) syntax: SyntaxNode,
+}
+impl Visibility {
+ pub fn coloncoloncolon_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![:::])
+ }
+ pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
+ pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct FieldMethod {
+ pub(crate) syntax: SyntaxNode,
+}
+impl FieldMethod {
+ pub fn field_name(&self) -> Option<FieldName> { support::child(&self.syntax) }
+ pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+ pub fn params_desc(&self) -> Option<ParamsDesc> { support::child(&self.syntax) }
+ pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+ pub fn visibility(&self) -> Option<Visibility> { support::child(&self.syntax) }
+ pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct FieldNameFixed {
+ pub(crate) syntax: SyntaxNode,
+}
+impl FieldNameFixed {
+ pub fn id(&self) -> Option<Name> { support::child(&self.syntax) }
+ pub fn string(&self) -> Option<String> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct FieldNameDynamic {
+ pub(crate) syntax: SyntaxNode,
+}
+impl FieldNameDynamic {
+ pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
+ pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+ pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct IfSpec {
+ pub(crate) syntax: SyntaxNode,
+}
+impl IfSpec {
+ pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
+ pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct BindDestruct {
+ pub(crate) syntax: SyntaxNode,
+}
+impl BindDestruct {
+ pub fn into(&self) -> Option<Destruct> { support::child(&self.syntax) }
+ pub fn assign_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
+ pub fn value(&self) -> Option<Expr> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Destruct {
+ pub(crate) syntax: SyntaxNode,
+}
+impl Destruct {
+ pub fn destruct_full(&self) -> Option<DestructFull> { support::child(&self.syntax) }
+ pub fn destruct_skip(&self) -> Option<DestructSkip> { support::child(&self.syntax) }
+ pub fn destruct_array(&self) -> Option<DestructArray> { support::child(&self.syntax) }
+ pub fn destruct_object(&self) -> Option<DestructObject> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct BindFunction {
+ pub(crate) syntax: SyntaxNode,
+}
+impl BindFunction {
+ pub fn name(&self) -> Option<Name> { support::child(&self.syntax) }
+ pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+ pub fn params(&self) -> Option<ParamsDesc> { support::child(&self.syntax) }
+ pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+ pub fn assign_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
+ pub fn value(&self) -> Option<Expr> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Param {
+ pub(crate) syntax: SyntaxNode,
+}
+impl Param {
+ pub fn destruct(&self) -> Option<Destruct> { support::child(&self.syntax) }
+ pub fn assign_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
+ pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct DestructFull {
+ pub(crate) syntax: SyntaxNode,
+}
+impl DestructFull {
+ pub fn into(&self) -> Option<Name> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct DestructSkip {
+ pub(crate) syntax: SyntaxNode,
+}
+impl DestructSkip {
+ pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct DestructArray {
+ pub(crate) syntax: SyntaxNode,
+}
+impl DestructArray {
+ pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
+ pub fn start(&self) -> AstChildren<Destruct> { support::children(&self.syntax) }
+ pub fn destruct_rest(&self) -> Option<DestructRest> { support::child(&self.syntax) }
+ pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
+ pub fn end(&self) -> AstChildren<Destruct> { support::children(&self.syntax) }
+ pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct DestructRest {
+ pub(crate) syntax: SyntaxNode,
+}
+impl DestructRest {
+ pub fn dotdotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![...]) }
+ pub fn into(&self) -> Option<Name> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct DestructObject {
+ pub(crate) syntax: SyntaxNode,
+}
+impl DestructObject {
+ pub fn l_brace_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
+ pub fn destruct_object_fields(&self) -> AstChildren<DestructObjectField> {
+ support::children(&self.syntax)
+ }
+ pub fn destruct_rest(&self) -> Option<DestructRest> { support::child(&self.syntax) }
+ pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
+ pub fn r_brace_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct DestructObjectField {
+ pub(crate) syntax: SyntaxNode,
+}
+impl DestructObjectField {
+ pub fn field(&self) -> Option<Name> { support::child(&self.syntax) }
+ pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
+ pub fn destruct(&self) -> Option<Destruct> { support::child(&self.syntax) }
+ pub fn assign_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
+ pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum Expr {
+ ExprBinary(ExprBinary),
+ ExprUnary(ExprUnary),
+ ExprSlice(ExprSlice),
+ ExprIndex(ExprIndex),
+ ExprIndexExpr(ExprIndexExpr),
+ ExprApply(ExprApply),
+ ExprObjExtend(ExprObjExtend),
+ ExprParened(ExprParened),
+ ExprIntrinsicThisFile(ExprIntrinsicThisFile),
+ ExprIntrinsicId(ExprIntrinsicId),
+ ExprIntrinsic(ExprIntrinsic),
+ ExprString(ExprString),
+ ExprNumber(ExprNumber),
+ ExprArray(ExprArray),
+ ExprObject(ExprObject),
+ ExprArrayComp(ExprArrayComp),
+ ExprImport(ExprImport),
+ ExprVar(ExprVar),
+ ExprLocal(ExprLocal),
+ ExprIfThenElse(ExprIfThenElse),
+ ExprFunction(ExprFunction),
+ ExprAssert(ExprAssert),
+ ExprError(ExprError),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum ObjBody {
+ ObjBodyComp(ObjBodyComp),
+ ObjBodyMemberList(ObjBodyMemberList),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum CompSpec {
+ ForSpec(ForSpec),
+ IfSpec(IfSpec),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum Bind {
+ BindDestruct(BindDestruct),
+ BindFunction(BindFunction),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum Member {
+ MemberBindStmt(MemberBindStmt),
+ MemberAssertStmt(MemberAssertStmt),
+ MemberField(MemberField),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum Field {
+ FieldNormal(FieldNormal),
+ FieldMethod(FieldMethod),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum FieldName {
+ FieldNameFixed(FieldNameFixed),
+ FieldNameDynamic(FieldNameDynamic),
+}
+impl AstNode for SourceFile {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == SOURCE_FILE }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprBinary {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_BINARY }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for BinaryOperator {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == BINARY_OPERATOR }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprUnary {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_UNARY }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for UnaryOperator {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == UNARY_OPERATOR }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprSlice {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_SLICE }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for SliceDesc {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == SLICE_DESC }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprIndex {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_INDEX }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for Name {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == NAME }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprIndexExpr {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_INDEX_EXPR }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprApply {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_APPLY }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ArgsDesc {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == ARGS_DESC }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprObjExtend {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_OBJ_EXTEND }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprParened {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_PARENED }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprLiteral {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_LITERAL }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for Literal {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprIntrinsicThisFile {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_INTRINSIC_THIS_FILE }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprIntrinsicId {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_INTRINSIC_ID }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprIntrinsic {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_INTRINSIC }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprString {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_STRING }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for String {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == STRING }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprNumber {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_NUMBER }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for Number {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == NUMBER }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprArray {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_ARRAY }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprObject {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_OBJECT }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprArrayComp {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_ARRAY_COMP }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ForSpec {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_SPEC }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprImport {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_IMPORT }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprVar {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_VAR }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprLocal {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_LOCAL }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprIfThenElse {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_IF_THEN_ELSE }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprFunction {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_FUNCTION }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ParamsDesc {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == PARAMS_DESC }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprAssert {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_ASSERT }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for Assertion {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == ASSERTION }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ExprError {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_ERROR }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for Arg {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == ARG }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ObjBodyComp {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == OBJ_BODY_COMP }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ObjLocalPostComma {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == OBJ_LOCAL_POST_COMMA }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ObjLocalPreComma {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == OBJ_LOCAL_PRE_COMMA }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ObjBodyMemberList {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == OBJ_BODY_MEMBER_LIST }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for ObjLocal {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == OBJ_LOCAL }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for MemberBindStmt {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == MEMBER_BIND_STMT }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for MemberAssertStmt {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == MEMBER_ASSERT_STMT }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for MemberField {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == MEMBER_FIELD }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for FieldNormal {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == FIELD_NORMAL }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for Visibility {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == VISIBILITY }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for FieldMethod {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == FIELD_METHOD }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for FieldNameFixed {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == FIELD_NAME_FIXED }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for FieldNameDynamic {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == FIELD_NAME_DYNAMIC }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for IfSpec {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == IF_SPEC }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for BindDestruct {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == BIND_DESTRUCT }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for Destruct {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == DESTRUCT }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for BindFunction {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == BIND_FUNCTION }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for Param {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for DestructFull {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == DESTRUCT_FULL }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for DestructSkip {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == DESTRUCT_SKIP }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for DestructArray {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == DESTRUCT_ARRAY }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for DestructRest {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == DESTRUCT_REST }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for DestructObject {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == DESTRUCT_OBJECT }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl AstNode for DestructObjectField {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == DESTRUCT_OBJECT_FIELD }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl From<ExprBinary> for Expr {
+ fn from(node: ExprBinary) -> Expr { Expr::ExprBinary(node) }
+}
+impl From<ExprUnary> for Expr {
+ fn from(node: ExprUnary) -> Expr { Expr::ExprUnary(node) }
+}
+impl From<ExprSlice> for Expr {
+ fn from(node: ExprSlice) -> Expr { Expr::ExprSlice(node) }
+}
+impl From<ExprIndex> for Expr {
+ fn from(node: ExprIndex) -> Expr { Expr::ExprIndex(node) }
+}
+impl From<ExprIndexExpr> for Expr {
+ fn from(node: ExprIndexExpr) -> Expr { Expr::ExprIndexExpr(node) }
+}
+impl From<ExprApply> for Expr {
+ fn from(node: ExprApply) -> Expr { Expr::ExprApply(node) }
+}
+impl From<ExprObjExtend> for Expr {
+ fn from(node: ExprObjExtend) -> Expr { Expr::ExprObjExtend(node) }
+}
+impl From<ExprParened> for Expr {
+ fn from(node: ExprParened) -> Expr { Expr::ExprParened(node) }
+}
+impl From<ExprIntrinsicThisFile> for Expr {
+ fn from(node: ExprIntrinsicThisFile) -> Expr { Expr::ExprIntrinsicThisFile(node) }
+}
+impl From<ExprIntrinsicId> for Expr {
+ fn from(node: ExprIntrinsicId) -> Expr { Expr::ExprIntrinsicId(node) }
+}
+impl From<ExprIntrinsic> for Expr {
+ fn from(node: ExprIntrinsic) -> Expr { Expr::ExprIntrinsic(node) }
+}
+impl From<ExprString> for Expr {
+ fn from(node: ExprString) -> Expr { Expr::ExprString(node) }
+}
+impl From<ExprNumber> for Expr {
+ fn from(node: ExprNumber) -> Expr { Expr::ExprNumber(node) }
+}
+impl From<ExprArray> for Expr {
+ fn from(node: ExprArray) -> Expr { Expr::ExprArray(node) }
+}
+impl From<ExprObject> for Expr {
+ fn from(node: ExprObject) -> Expr { Expr::ExprObject(node) }
+}
+impl From<ExprArrayComp> for Expr {
+ fn from(node: ExprArrayComp) -> Expr { Expr::ExprArrayComp(node) }
+}
+impl From<ExprImport> for Expr {
+ fn from(node: ExprImport) -> Expr { Expr::ExprImport(node) }
+}
+impl From<ExprVar> for Expr {
+ fn from(node: ExprVar) -> Expr { Expr::ExprVar(node) }
+}
+impl From<ExprLocal> for Expr {
+ fn from(node: ExprLocal) -> Expr { Expr::ExprLocal(node) }
+}
+impl From<ExprIfThenElse> for Expr {
+ fn from(node: ExprIfThenElse) -> Expr { Expr::ExprIfThenElse(node) }
+}
+impl From<ExprFunction> for Expr {
+ fn from(node: ExprFunction) -> Expr { Expr::ExprFunction(node) }
+}
+impl From<ExprAssert> for Expr {
+ fn from(node: ExprAssert) -> Expr { Expr::ExprAssert(node) }
+}
+impl From<ExprError> for Expr {
+ fn from(node: ExprError) -> Expr { Expr::ExprError(node) }
+}
+impl AstNode for Expr {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ EXPR_BINARY
+ | EXPR_UNARY
+ | EXPR_SLICE
+ | EXPR_INDEX
+ | EXPR_INDEX_EXPR
+ | EXPR_APPLY
+ | EXPR_OBJ_EXTEND
+ | EXPR_PARENED
+ | EXPR_INTRINSIC_THIS_FILE
+ | EXPR_INTRINSIC_ID
+ | EXPR_INTRINSIC
+ | EXPR_STRING
+ | EXPR_NUMBER
+ | EXPR_ARRAY
+ | EXPR_OBJECT
+ | EXPR_ARRAY_COMP
+ | EXPR_IMPORT
+ | EXPR_VAR
+ | EXPR_LOCAL
+ | EXPR_IF_THEN_ELSE
+ | EXPR_FUNCTION
+ | EXPR_ASSERT
+ | EXPR_ERROR => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ EXPR_BINARY => Expr::ExprBinary(ExprBinary { syntax }),
+ EXPR_UNARY => Expr::ExprUnary(ExprUnary { syntax }),
+ EXPR_SLICE => Expr::ExprSlice(ExprSlice { syntax }),
+ EXPR_INDEX => Expr::ExprIndex(ExprIndex { syntax }),
+ EXPR_INDEX_EXPR => Expr::ExprIndexExpr(ExprIndexExpr { syntax }),
+ EXPR_APPLY => Expr::ExprApply(ExprApply { syntax }),
+ EXPR_OBJ_EXTEND => Expr::ExprObjExtend(ExprObjExtend { syntax }),
+ EXPR_PARENED => Expr::ExprParened(ExprParened { syntax }),
+ EXPR_INTRINSIC_THIS_FILE => {
+ Expr::ExprIntrinsicThisFile(ExprIntrinsicThisFile { syntax })
+ }
+ EXPR_INTRINSIC_ID => Expr::ExprIntrinsicId(ExprIntrinsicId { syntax }),
+ EXPR_INTRINSIC => Expr::ExprIntrinsic(ExprIntrinsic { syntax }),
+ EXPR_STRING => Expr::ExprString(ExprString { syntax }),
+ EXPR_NUMBER => Expr::ExprNumber(ExprNumber { syntax }),
+ EXPR_ARRAY => Expr::ExprArray(ExprArray { syntax }),
+ EXPR_OBJECT => Expr::ExprObject(ExprObject { syntax }),
+ EXPR_ARRAY_COMP => Expr::ExprArrayComp(ExprArrayComp { syntax }),
+ EXPR_IMPORT => Expr::ExprImport(ExprImport { syntax }),
+ EXPR_VAR => Expr::ExprVar(ExprVar { syntax }),
+ EXPR_LOCAL => Expr::ExprLocal(ExprLocal { syntax }),
+ EXPR_IF_THEN_ELSE => Expr::ExprIfThenElse(ExprIfThenElse { syntax }),
+ EXPR_FUNCTION => Expr::ExprFunction(ExprFunction { syntax }),
+ EXPR_ASSERT => Expr::ExprAssert(ExprAssert { syntax }),
+ EXPR_ERROR => Expr::ExprError(ExprError { syntax }),
+ _ => return None,
+ };
+ Some(res)
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ Expr::ExprBinary(it) => &it.syntax,
+ Expr::ExprUnary(it) => &it.syntax,
+ Expr::ExprSlice(it) => &it.syntax,
+ Expr::ExprIndex(it) => &it.syntax,
+ Expr::ExprIndexExpr(it) => &it.syntax,
+ Expr::ExprApply(it) => &it.syntax,
+ Expr::ExprObjExtend(it) => &it.syntax,
+ Expr::ExprParened(it) => &it.syntax,
+ Expr::ExprIntrinsicThisFile(it) => &it.syntax,
+ Expr::ExprIntrinsicId(it) => &it.syntax,
+ Expr::ExprIntrinsic(it) => &it.syntax,
+ Expr::ExprString(it) => &it.syntax,
+ Expr::ExprNumber(it) => &it.syntax,
+ Expr::ExprArray(it) => &it.syntax,
+ Expr::ExprObject(it) => &it.syntax,
+ Expr::ExprArrayComp(it) => &it.syntax,
+ Expr::ExprImport(it) => &it.syntax,
+ Expr::ExprVar(it) => &it.syntax,
+ Expr::ExprLocal(it) => &it.syntax,
+ Expr::ExprIfThenElse(it) => &it.syntax,
+ Expr::ExprFunction(it) => &it.syntax,
+ Expr::ExprAssert(it) => &it.syntax,
+ Expr::ExprError(it) => &it.syntax,
+ }
+ }
+}
+impl From<ObjBodyComp> for ObjBody {
+ fn from(node: ObjBodyComp) -> ObjBody { ObjBody::ObjBodyComp(node) }
+}
+impl From<ObjBodyMemberList> for ObjBody {
+ fn from(node: ObjBodyMemberList) -> ObjBody { ObjBody::ObjBodyMemberList(node) }
+}
+impl AstNode for ObjBody {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ OBJ_BODY_COMP | OBJ_BODY_MEMBER_LIST => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ OBJ_BODY_COMP => ObjBody::ObjBodyComp(ObjBodyComp { syntax }),
+ OBJ_BODY_MEMBER_LIST => ObjBody::ObjBodyMemberList(ObjBodyMemberList { syntax }),
+ _ => return None,
+ };
+ Some(res)
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ ObjBody::ObjBodyComp(it) => &it.syntax,
+ ObjBody::ObjBodyMemberList(it) => &it.syntax,
+ }
+ }
+}
+impl From<ForSpec> for CompSpec {
+ fn from(node: ForSpec) -> CompSpec { CompSpec::ForSpec(node) }
+}
+impl From<IfSpec> for CompSpec {
+ fn from(node: IfSpec) -> CompSpec { CompSpec::IfSpec(node) }
+}
+impl AstNode for CompSpec {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ FOR_SPEC | IF_SPEC => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ FOR_SPEC => CompSpec::ForSpec(ForSpec { syntax }),
+ IF_SPEC => CompSpec::IfSpec(IfSpec { syntax }),
+ _ => return None,
+ };
+ Some(res)
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ CompSpec::ForSpec(it) => &it.syntax,
+ CompSpec::IfSpec(it) => &it.syntax,
+ }
+ }
+}
+impl From<BindDestruct> for Bind {
+ fn from(node: BindDestruct) -> Bind { Bind::BindDestruct(node) }
+}
+impl From<BindFunction> for Bind {
+ fn from(node: BindFunction) -> Bind { Bind::BindFunction(node) }
+}
+impl AstNode for Bind {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ BIND_DESTRUCT | BIND_FUNCTION => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ BIND_DESTRUCT => Bind::BindDestruct(BindDestruct { syntax }),
+ BIND_FUNCTION => Bind::BindFunction(BindFunction { syntax }),
+ _ => return None,
+ };
+ Some(res)
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ Bind::BindDestruct(it) => &it.syntax,
+ Bind::BindFunction(it) => &it.syntax,
+ }
+ }
+}
+impl From<MemberBindStmt> for Member {
+ fn from(node: MemberBindStmt) -> Member { Member::MemberBindStmt(node) }
+}
+impl From<MemberAssertStmt> for Member {
+ fn from(node: MemberAssertStmt) -> Member { Member::MemberAssertStmt(node) }
+}
+impl From<MemberField> for Member {
+ fn from(node: MemberField) -> Member { Member::MemberField(node) }
+}
+impl AstNode for Member {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ MEMBER_BIND_STMT | MEMBER_ASSERT_STMT | MEMBER_FIELD => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ MEMBER_BIND_STMT => Member::MemberBindStmt(MemberBindStmt { syntax }),
+ MEMBER_ASSERT_STMT => Member::MemberAssertStmt(MemberAssertStmt { syntax }),
+ MEMBER_FIELD => Member::MemberField(MemberField { syntax }),
+ _ => return None,
+ };
+ Some(res)
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ Member::MemberBindStmt(it) => &it.syntax,
+ Member::MemberAssertStmt(it) => &it.syntax,
+ Member::MemberField(it) => &it.syntax,
+ }
+ }
+}
+impl From<FieldNormal> for Field {
+ fn from(node: FieldNormal) -> Field { Field::FieldNormal(node) }
+}
+impl From<FieldMethod> for Field {
+ fn from(node: FieldMethod) -> Field { Field::FieldMethod(node) }
+}
+impl AstNode for Field {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ FIELD_NORMAL | FIELD_METHOD => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ FIELD_NORMAL => Field::FieldNormal(FieldNormal { syntax }),
+ FIELD_METHOD => Field::FieldMethod(FieldMethod { syntax }),
+ _ => return None,
+ };
+ Some(res)
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ Field::FieldNormal(it) => &it.syntax,
+ Field::FieldMethod(it) => &it.syntax,
+ }
+ }
+}
+impl From<FieldNameFixed> for FieldName {
+ fn from(node: FieldNameFixed) -> FieldName { FieldName::FieldNameFixed(node) }
+}
+impl From<FieldNameDynamic> for FieldName {
+ fn from(node: FieldNameDynamic) -> FieldName { FieldName::FieldNameDynamic(node) }
+}
+impl AstNode for FieldName {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ FIELD_NAME_FIXED | FIELD_NAME_DYNAMIC => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ FIELD_NAME_FIXED => FieldName::FieldNameFixed(FieldNameFixed { syntax }),
+ FIELD_NAME_DYNAMIC => FieldName::FieldNameDynamic(FieldNameDynamic { syntax }),
+ _ => return None,
+ };
+ Some(res)
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ FieldName::FieldNameFixed(it) => &it.syntax,
+ FieldName::FieldNameDynamic(it) => &it.syntax,
+ }
+ }
+}
+impl std::fmt::Display for Expr {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ObjBody {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for CompSpec {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for Bind {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for Member {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for Field {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for FieldName {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for SourceFile {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprBinary {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for BinaryOperator {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprUnary {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for UnaryOperator {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprSlice {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for SliceDesc {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprIndex {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for Name {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprIndexExpr {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprApply {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ArgsDesc {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprObjExtend {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprParened {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprLiteral {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for Literal {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprIntrinsicThisFile {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprIntrinsicId {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprIntrinsic {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprString {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for String {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprNumber {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for Number {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprArray {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprObject {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprArrayComp {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ForSpec {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprImport {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprVar {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprLocal {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprIfThenElse {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprFunction {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ParamsDesc {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprAssert {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for Assertion {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprError {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for Arg {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ObjBodyComp {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ObjLocalPostComma {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ObjLocalPreComma {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ObjBodyMemberList {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ObjLocal {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for MemberBindStmt {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for MemberAssertStmt {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for MemberField {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for FieldNormal {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for Visibility {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for FieldMethod {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for FieldNameFixed {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for FieldNameDynamic {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for IfSpec {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for BindDestruct {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for Destruct {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for BindFunction {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for Param {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for DestructFull {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for DestructSkip {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for DestructArray {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for DestructRest {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for DestructObject {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for DestructObjectField {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
crates/jrsonnet-rowan-parser/src/generated/syntax_kinds.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/generated/syntax_kinds.rs
@@ -0,0 +1,307 @@
+//! This is a generated file, please do not edit manually. Changes can be
+//! made in codegeneration that lives in `xtask` top-level dir.
+
+#![allow(bad_style, missing_docs, unreachable_pub)]
+use logos::Logos;
+#[doc = r" The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT`."]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Logos)]
+#[repr(u16)]
+pub enum SyntaxKind {
+ #[doc(hidden)]
+ TOMBSTONE,
+ #[doc(hidden)]
+ EOF,
+ #[token("||")]
+ OR,
+ #[token("&&")]
+ AND,
+ #[token("|")]
+ BIT_OR,
+ #[token("^")]
+ BIT_XOR,
+ #[token("&")]
+ BIT_AND,
+ #[token("==")]
+ EQ,
+ #[token("!=")]
+ NE,
+ #[token("<")]
+ LT,
+ #[token(">")]
+ GT,
+ #[token("<=")]
+ LE,
+ #[token(">=")]
+ GE,
+ #[token("<<")]
+ LHS,
+ #[token(">>")]
+ RHS,
+ #[token("+")]
+ PLUS,
+ #[token("-")]
+ MINUS,
+ #[token("*")]
+ MUL,
+ #[token("/")]
+ DIV,
+ #[token("%")]
+ MODULO,
+ #[token("!")]
+ NOT,
+ #[token("~")]
+ BIT_NOT,
+ #[token("[")]
+ L_BRACK,
+ #[token("]")]
+ R_BRACK,
+ #[token("(")]
+ L_PAREN,
+ #[token(")")]
+ R_PAREN,
+ #[token("{")]
+ L_BRACE,
+ #[token("}")]
+ R_BRACE,
+ #[token(":")]
+ COLON,
+ #[token("::")]
+ COLONCOLON,
+ #[token(":::")]
+ COLONCOLONCOLON,
+ #[token(";")]
+ SEMI,
+ #[token(".")]
+ DOT,
+ #[token("...")]
+ DOTDOTDOT,
+ #[token(",")]
+ COMMA,
+ #[token("$")]
+ DOLLAR,
+ #[token("=")]
+ ASSIGN,
+ #[token("?")]
+ QUESTION_MARK,
+ #[token("$intrinsicThisFile")]
+ INTRINSIC_THIS_FILE,
+ #[token("$intrinsicId")]
+ INTRINSIC_ID,
+ #[token("$intrinsic")]
+ INTRINSIC,
+ #[token("tailstrict")]
+ TAILSTRICT_KW,
+ #[token("importstr")]
+ IMPORTSTR_KW,
+ #[token("importbin")]
+ IMPORTBIN_KW,
+ #[token("import")]
+ IMPORT_KW,
+ #[token("local")]
+ LOCAL_KW,
+ #[token("if")]
+ IF_KW,
+ #[token("then")]
+ THEN_KW,
+ #[token("else")]
+ ELSE_KW,
+ #[token("function")]
+ FUNCTION_KW,
+ #[token("error")]
+ ERROR_KW,
+ #[token("in")]
+ IN_KW,
+ #[token("null")]
+ NULL_KW,
+ #[token("true")]
+ TRUE_KW,
+ #[token("false")]
+ FALSE_KW,
+ #[token("self")]
+ SELF_KW,
+ #[token("super")]
+ SUPER_KW,
+ #[token("for")]
+ FOR_KW,
+ #[token("assert")]
+ ASSERT_KW,
+ #[regex("(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?")]
+ NUMBER,
+ #[regex("\"(?s:[^\"\\\\]|\\\\.)*\"")]
+ STRING_DOUBLE,
+ #[regex("'(?s:[^'\\\\]|\\\\.)*'")]
+ STRING_SINGLE,
+ #[regex("@\"(?:[^\"]|\"\")*\"")]
+ STRING_DOUBLE_VERBATIM,
+ #[regex("@'(?:[^']|'')*'")]
+ STRING_SINGLE_VERBATIM,
+ #[regex("\\|\\|\\|")]
+ STRING_BLOCK,
+ #[regex("[_a-zA-Z][_a-zA-Z0-9]*")]
+ IDENT,
+ #[regex("[ \\t\\n\\r]+")]
+ WHITESPACE,
+ #[regex("//[^\\r\\n]*(\\r\\n|\\n)?")]
+ SINGLE_LINE_SLASH_COMMENT,
+ #[regex("#[^\\r\\n]*(\\r\\n|\\n)?")]
+ SINGLE_LINE_HASH_COMMENT,
+ #[regex("/\\*([^*]|\\*[^/])*\\*/")]
+ MULTI_LINE_COMMENT,
+ #[error]
+ ERROR,
+ SOURCE_FILE,
+ EXPR_BINARY,
+ BINARY_OPERATOR,
+ EXPR_UNARY,
+ UNARY_OPERATOR,
+ EXPR_SLICE,
+ SLICE_DESC,
+ EXPR_INDEX,
+ NAME,
+ EXPR_INDEX_EXPR,
+ EXPR_APPLY,
+ ARGS_DESC,
+ EXPR_OBJ_EXTEND,
+ EXPR_PARENED,
+ EXPR_LITERAL,
+ LITERAL,
+ EXPR_INTRINSIC_THIS_FILE,
+ EXPR_INTRINSIC_ID,
+ EXPR_INTRINSIC,
+ EXPR_STRING,
+ STRING,
+ EXPR_NUMBER,
+ EXPR_ARRAY,
+ EXPR_OBJECT,
+ EXPR_ARRAY_COMP,
+ FOR_SPEC,
+ EXPR_IMPORT,
+ EXPR_VAR,
+ EXPR_LOCAL,
+ EXPR_IF_THEN_ELSE,
+ EXPR_FUNCTION,
+ PARAMS_DESC,
+ EXPR_ASSERT,
+ ASSERTION,
+ EXPR_ERROR,
+ ARG,
+ OBJ_BODY_COMP,
+ OBJ_LOCAL_POST_COMMA,
+ OBJ_LOCAL_PRE_COMMA,
+ OBJ_BODY_MEMBER_LIST,
+ OBJ_LOCAL,
+ MEMBER_BIND_STMT,
+ MEMBER_ASSERT_STMT,
+ MEMBER_FIELD,
+ FIELD_NORMAL,
+ VISIBILITY,
+ FIELD_METHOD,
+ FIELD_NAME_FIXED,
+ FIELD_NAME_DYNAMIC,
+ IF_SPEC,
+ BIND_DESTRUCT,
+ DESTRUCT,
+ BIND_FUNCTION,
+ PARAM,
+ DESTRUCT_FULL,
+ DESTRUCT_SKIP,
+ DESTRUCT_ARRAY,
+ DESTRUCT_REST,
+ DESTRUCT_OBJECT,
+ DESTRUCT_OBJECT_FIELD,
+ EXPR,
+ OBJ_BODY,
+ COMP_SPEC,
+ BIND,
+ MEMBER,
+ FIELD,
+ FIELD_NAME,
+ #[doc(hidden)]
+ __LAST,
+}
+use self::SyntaxKind::*;
+impl SyntaxKind {
+ pub fn is_keyword(self) -> bool {
+ match self {
+ TAILSTRICT_KW | IMPORTSTR_KW | IMPORTBIN_KW | IMPORT_KW | LOCAL_KW | IF_KW
+ | THEN_KW | ELSE_KW | FUNCTION_KW | ERROR_KW | IN_KW | NULL_KW | TRUE_KW | FALSE_KW
+ | SELF_KW | SUPER_KW | FOR_KW | ASSERT_KW => true,
+ _ => false,
+ }
+ }
+ pub fn is_punct(self) -> bool {
+ match self {
+ OR | AND | BIT_OR | BIT_XOR | BIT_AND | EQ | NE | LT | GT | LE | GE | LHS | RHS
+ | PLUS | MINUS | MUL | DIV | MODULO | NOT | BIT_NOT | L_BRACK | R_BRACK | L_PAREN
+ | R_PAREN | L_BRACE | R_BRACE | COLON | COLONCOLON | COLONCOLONCOLON | SEMI | DOT
+ | DOTDOTDOT | COMMA | DOLLAR | ASSIGN | QUESTION_MARK | INTRINSIC_THIS_FILE
+ | INTRINSIC_ID | INTRINSIC => true,
+ _ => false,
+ }
+ }
+ pub fn from_keyword(ident: &str) -> Option<SyntaxKind> {
+ let kw = match ident {
+ "tailstrict" => TAILSTRICT_KW,
+ "importstr" => IMPORTSTR_KW,
+ "importbin" => IMPORTBIN_KW,
+ "import" => IMPORT_KW,
+ "local" => LOCAL_KW,
+ "if" => IF_KW,
+ "then" => THEN_KW,
+ "else" => ELSE_KW,
+ "function" => FUNCTION_KW,
+ "error" => ERROR_KW,
+ "in" => IN_KW,
+ "null" => NULL_KW,
+ "true" => TRUE_KW,
+ "false" => FALSE_KW,
+ "self" => SELF_KW,
+ "super" => SUPER_KW,
+ "for" => FOR_KW,
+ "assert" => ASSERT_KW,
+ _ => return None,
+ };
+ Some(kw)
+ }
+ pub fn from_char(c: char) -> Option<SyntaxKind> {
+ let tok = match c {
+ '|' => BIT_OR,
+ '^' => BIT_XOR,
+ '&' => BIT_AND,
+ '<' => LT,
+ '>' => GT,
+ '+' => PLUS,
+ '-' => MINUS,
+ '*' => MUL,
+ '/' => DIV,
+ '%' => MODULO,
+ '!' => NOT,
+ '~' => BIT_NOT,
+ '[' => L_BRACK,
+ ']' => R_BRACK,
+ '(' => L_PAREN,
+ ')' => R_PAREN,
+ '{' => L_BRACE,
+ '}' => R_BRACE,
+ ':' => COLON,
+ ';' => SEMI,
+ '.' => DOT,
+ ',' => COMMA,
+ '$' => DOLLAR,
+ '=' => ASSIGN,
+ '?' => QUESTION_MARK,
+ _ => return None,
+ };
+ Some(tok)
+ }
+ pub fn from_raw(r: u16) -> Self {
+ assert!(r < Self::__LAST as u16);
+ unsafe { std::mem::transmute(r) }
+ }
+ pub fn into_raw(self) -> u16 {
+ self as u16
+ }
+}
+#[macro_export]
+macro_rules ! T { [||] => { $ crate :: SyntaxKind :: OR } ; [&&] => { $ crate :: SyntaxKind :: AND } ; [|] => { $ crate :: SyntaxKind :: BIT_OR } ; [^] => { $ crate :: SyntaxKind :: BIT_XOR } ; [&] => { $ crate :: SyntaxKind :: BIT_AND } ; [==] => { $ crate :: SyntaxKind :: EQ } ; [!=] => { $ crate :: SyntaxKind :: NE } ; [<] => { $ crate :: SyntaxKind :: LT } ; [>] => { $ crate :: SyntaxKind :: GT } ; [<=] => { $ crate :: SyntaxKind :: LE } ; [>=] => { $ crate :: SyntaxKind :: GE } ; [<<] => { $ crate :: SyntaxKind :: LHS } ; [>>] => { $ crate :: SyntaxKind :: RHS } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [*] => { $ crate :: SyntaxKind :: MUL } ; [/] => { $ crate :: SyntaxKind :: DIV } ; [%] => { $ crate :: SyntaxKind :: MODULO } ; [!] => { $ crate :: SyntaxKind :: NOT } ; [~] => { $ crate :: SyntaxKind :: BIT_NOT } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_BRACE } ; ['}'] => { $ crate :: SyntaxKind :: R_BRACE } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLONCOLON } ; [:::] => { $ crate :: SyntaxKind :: COLONCOLONCOLON } ; [;] => { $ crate :: SyntaxKind :: SEMI } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [...] => { $ crate :: SyntaxKind :: DOTDOTDOT } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['$'] => { $ crate :: SyntaxKind :: DOLLAR } ; [=] => { $ crate :: SyntaxKind :: ASSIGN } ; [?] => { $ crate :: SyntaxKind :: QUESTION_MARK } ; ["$intrinsicThisFile"] => { $ crate :: SyntaxKind :: INTRINSIC_THIS_FILE } ; ["$intrinsicId"] => { $ crate :: SyntaxKind :: INTRINSIC_ID } ; ["$intrinsic"] => { $ crate :: SyntaxKind :: INTRINSIC } ; [tailstrict] => { $ crate :: SyntaxKind :: TAILSTRICT_KW } ; [importstr] => { $ crate :: SyntaxKind :: IMPORTSTR_KW } ; [importbin] => { $ crate :: SyntaxKind :: IMPORTBIN_KW } ; [import] => { $ crate :: SyntaxKind :: IMPORT_KW } ; [local] => { $ crate :: SyntaxKind :: LOCAL_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [then] => { $ crate :: SyntaxKind :: THEN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [function] => { $ crate :: SyntaxKind :: FUNCTION_KW } ; [error] => { $ crate :: SyntaxKind :: ERROR_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [null] => { $ crate :: SyntaxKind :: NULL_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [assert] => { $ crate :: SyntaxKind :: ASSERT_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
+pub use T;
crates/jrsonnet-rowan-parser/src/generated/tokens.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/generated/tokens.rs
@@ -0,0 +1,155 @@
+//! This is a generated file, please do not edit manually. Changes can be
+//! made in codegeneration that lives in `xtask` top-level dir.
+
+use crate::{
+ ast::AstToken,
+ SyntaxKind::{self, *},
+ SyntaxToken,
+};
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Whitespace {
+ pub(crate) syntax: SyntaxToken,
+}
+impl std::fmt::Display for Whitespace {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(&self.syntax, f)
+ }
+}
+impl AstToken for Whitespace {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == WHITESPACE }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxToken { &self.syntax }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Comment {
+ pub(crate) syntax: SyntaxToken,
+}
+impl std::fmt::Display for Comment {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(&self.syntax, f)
+ }
+}
+impl AstToken for Comment {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == COMMENT }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxToken { &self.syntax }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct String {
+ pub(crate) syntax: SyntaxToken,
+}
+impl std::fmt::Display for String {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(&self.syntax, f)
+ }
+}
+impl AstToken for String {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == STRING }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxToken { &self.syntax }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct StringVerbantim {
+ pub(crate) syntax: SyntaxToken,
+}
+impl std::fmt::Display for StringVerbantim {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(&self.syntax, f)
+ }
+}
+impl AstToken for StringVerbantim {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == STRING_VERBANTIM }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxToken { &self.syntax }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct StringBlock {
+ pub(crate) syntax: SyntaxToken,
+}
+impl std::fmt::Display for StringBlock {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(&self.syntax, f)
+ }
+}
+impl AstToken for StringBlock {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == STRING_BLOCK }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxToken { &self.syntax }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Number {
+ pub(crate) syntax: SyntaxToken,
+}
+impl std::fmt::Display for Number {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(&self.syntax, f)
+ }
+}
+impl AstToken for Number {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == NUMBER }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxToken { &self.syntax }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Ident {
+ pub(crate) syntax: SyntaxToken,
+}
+impl std::fmt::Display for Ident {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(&self.syntax, f)
+ }
+}
+impl AstToken for Ident {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == IDENT }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxToken { &self.syntax }
+}
crates/jrsonnet-rowan-parser/src/language.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/language.rs
@@ -0,0 +1,24 @@
+use rowan::Language;
+
+use crate::SyntaxKind;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum JsonnetLanguage {}
+impl Language for JsonnetLanguage {
+ type Kind = SyntaxKind;
+
+ fn kind_from_raw(raw: rowan::SyntaxKind) -> SyntaxKind {
+ SyntaxKind::from_raw(raw.0)
+ }
+
+ fn kind_to_raw(kind: SyntaxKind) -> rowan::SyntaxKind {
+ rowan::SyntaxKind(kind.into_raw())
+ }
+}
+
+pub type SyntaxNode = rowan::SyntaxNode<JsonnetLanguage>;
+pub type SyntaxToken = rowan::SyntaxToken<JsonnetLanguage>;
+pub type SyntaxElement = rowan::SyntaxElement<JsonnetLanguage>;
+pub type SyntaxNodeChildren = rowan::SyntaxNodeChildren<JsonnetLanguage>;
+pub type SyntaxElementChildren = rowan::SyntaxElementChildren<JsonnetLanguage>;
+pub type PreorderWithTokens = rowan::api::PreorderWithTokens<JsonnetLanguage>;
crates/jrsonnet-rowan-parser/src/lex.rsdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/src/lex.rs
+++ b/crates/jrsonnet-rowan-parser/src/lex.rs
@@ -1,249 +1,41 @@
-use crate::string_block::lex_str_block_test;
use core::ops::Range;
-use logos::Logos;
-use rowan::{Checkpoint, TextRange, TextSize};
-use std::{convert::TryFrom, iter::Peekable};
-
-#[derive(Logos, Debug, PartialEq, Hash, Eq, PartialOrd, Ord, Clone, Copy)]
-#[repr(u16)]
-pub enum SyntaxKind {
- #[token("assert")]
- KeywordAssert = 0,
-
- #[token("else")]
- KeywordElse,
-
- #[token("error")]
- KeywordError,
-
- #[token("false")]
- KeywordFalse,
-
- #[token("for")]
- KeywordFor,
-
- #[token("function")]
- KeywordFunction,
-
- #[token("if")]
- KeywordIf,
-
- #[token("import")]
- KeywordImport,
-
- #[token("importstr")]
- KeywordImportStr,
-
- #[token("local")]
- KeywordLocal,
-
- #[token("null")]
- KeywordNull,
-
- #[token("tailstrict")]
- KeywordTailStrict,
-
- #[token("then")]
- KeywordThen,
-
- #[token("self")]
- KeywordSelf,
-
- #[token("super")]
- KeywordSuper,
-
- #[token("true")]
- KeywordTrue,
-
- #[regex(r"[_a-zA-Z][_a-zA-Z0-9]*")]
- Ident,
-
- #[regex(r"(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?")]
- Number,
-
- #[regex(r"(?:0|[1-9][0-9]*)\.[^0-9]")]
- ErrorNumJunkAfterDecimalPoint,
-
- #[regex(r"(?:0|[1-9][0-9]*)(?:\.[0-9]+)?[eE][^+\-0-9]")]
- ErrorNumJunkAfterExponent,
-
- #[regex(r"(?:0|[1-9][0-9]*)(?:\.[0-9]+)?[eE][+-][^0-9]")]
- ErrorNumJunkAfterExponentSign,
-
- #[token("{")]
- SymbolLeftBrace,
-
- #[token("}")]
- SymbolRightBrace,
-
- #[token("[")]
- SymbolLeftBracket,
-
- #[token("]")]
- SymbolRightBracket,
-
- #[token(",")]
- SymbolComma,
-
- #[token(".")]
- SymbolDot,
-
- #[token("(")]
- LParen,
-
- #[token(")")]
- RParen,
-
- #[token(";")]
- SymbolSemi,
- #[token(":")]
- SymbolColon,
-
- #[token("$")]
- SymbolDollar,
-
- #[token("*")]
- OpMul,
- #[token("/")]
- OpDiv,
- #[token("%")]
- OpMod,
- #[token("+")]
- OpPlus,
- #[token("-")]
- OpMinus,
- #[token("<<")]
- OpShiftLeft,
- #[token(">>")]
- OpShiftRight,
- #[token("<")]
- OpLessThan,
- #[token(">")]
- OpGreaterThan,
- #[token("<=")]
- OpLessThanOrEqual,
- #[token(">=")]
- OpGreaterThanOrEqual,
- #[token("==")]
- OpEqual,
- #[token("!=")]
- OpNotEqual,
- #[token("&")]
- OpBitAnd,
- #[token("^")]
- OpBitXor,
- #[token("|")]
- OpBitOr,
- #[token("&&")]
- OpAnd,
- #[token("||")]
- OpOr,
- #[token("in")]
- OpIn,
- #[token("!")]
- OpNot,
- #[token("~")]
- OpBitNegate,
- #[token("=")]
- SymbolAssign,
+use std::convert::TryFrom;
- #[regex("\"(?s:[^\"\\\\]|\\\\.)*\"")]
- StringDoubleQuoted,
+use logos::Logos;
+use rowan::{TextRange, TextSize};
- #[regex("'(?s:[^'\\\\]|\\\\.)*'")]
- StringSingleQuoted,
-
- #[regex("@\"(?:[^\"]|\"\")*\"")]
- StringDoubleVerbatim,
-
- #[regex("@'(?:[^']|'')*'")]
- StringSingleVerbatim,
-
- #[regex(r"\|\|\|", lex_str_block_test)]
- StringBlock, //(StringBlockToken),
-
- #[regex("\"(?s:[^\"\\\\]|\\\\.)*")]
- ErrorStringDoubleQuotedUnterminated,
-
- #[regex("'(?s:[^'\\\\]|\\\\.)*")]
- ErrorStringSingleQuotedUnterminated,
-
- #[regex("@\"(?:[^\"]|\"\")*")]
- ErrorStringDoubleVerbatimUnterminated,
-
- #[regex("@'(?:[^']|'')*")]
- ErrorStringSingleVerbatimUnterminated,
-
- #[regex("@[^\"'\\s]\\S+")]
- ErrorStringMissingQuotes,
-
- #[token("/*/")]
- ErrorCommentTooShort,
-
- #[regex(r"/\*([^*]|\*[^/])+")]
- ErrorCommentUnterminated,
-
- #[regex(r"[ \t\n\r]+")]
- Whitespace,
-
- #[regex(r"//[^\r\n]*(\r\n|\n)?")]
- SingelLineSlashComment,
-
- #[regex(r"#[^\r\n]*(\r\n|\n)?")]
- SingleLineHashComment,
-
- #[regex(r"/\*([^*]|\*[^/])*\*/")]
- MultiLineComment,
-
- #[error]
- Error,
-
- ErrorPositionalAfterNamed,
-
- Literal,
- Expr,
- Array,
- ArrayElem,
- Object,
- Field,
-
- CompspecFor,
- CompspecIf,
-
- Slice,
- FieldAccess,
- ObjectApply,
- FunctionCall,
- FunctionDef,
- BodyDef,
-
- BinOp,
- UnaryOp,
- Local,
- ExprError,
- ExprAssert,
- ExprImport,
-
- DefParam,
- DefParams,
-
- DefArgs,
- DefNamedArg,
- DefPositionalArg,
-
- Parened,
+use crate::SyntaxKind;
- Root,
-}
-
impl SyntaxKind {
pub fn is_trivia(self) -> bool {
matches!(
self,
- Self::Whitespace
- | Self::MultiLineComment
- | Self::SingelLineSlashComment
- | Self::SingleLineHashComment
+ Self::WHITESPACE
+ | Self::MULTI_LINE_COMMENT
+ | Self::SINGLE_LINE_HASH_COMMENT
+ | Self::SINGLE_LINE_SLASH_COMMENT
+ )
+ }
+ pub fn is_string(self) -> bool {
+ matches!(
+ self,
+ Self::STRING_SINGLE
+ | Self::STRING_DOUBLE
+ | Self::STRING_SINGLE_VERBATIM
+ | Self::STRING_DOUBLE_VERBATIM
+ | Self::STRING_BLOCK
+ )
+ }
+ pub fn is_number(self) -> bool {
+ matches!(self, Self::NUMBER)
+ }
+ pub fn is_literal(self) -> bool {
+ matches!(
+ self,
+ Self::NULL_KW
+ | Self::TRUE_KW | Self::FALSE_KW
+ | Self::SELF_KW | Self::DOLLAR
+ | Self::SUPER_KW
)
}
}
@@ -291,25 +83,4 @@
pub fn lex(input: &str) -> Vec<Lexeme<'_>> {
Lexer::new(input).collect()
-}
-
-impl From<SyntaxKind> for rowan::SyntaxKind {
- fn from(kind: SyntaxKind) -> Self {
- Self(kind as u16)
- }
-}
-
-use SyntaxKind::*;
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum Lang {}
-impl rowan::Language for Lang {
- type Kind = SyntaxKind;
- fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind {
- assert!(raw.0 <= Root as u16);
- unsafe { std::mem::transmute::<u16, SyntaxKind>(raw.0) }
- }
- fn kind_to_raw(kind: Self::Kind) -> rowan::SyntaxKind {
- kind.into()
- }
}
crates/jrsonnet-rowan-parser/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/src/lib.rs
+++ b/crates/jrsonnet-rowan-parser/src/lib.rs
@@ -1,139 +1,20 @@
#![deny(unused_must_use)]
+mod ast;
mod binary;
mod event;
+mod generated;
+mod language;
mod lex;
mod marker;
mod parser;
mod string_block;
+mod tests;
mod token_set;
mod unary;
-
-#[cfg(test)]
-mod tests {
- use miette::{Diagnostic, GraphicalReportHandler, LabeledSpan};
- use thiserror::Error;
- use crate::parser::parse;
-
- #[derive(Debug, Error)]
- #[error("syntax error")]
- struct MyDiagnostic {
- code: String,
- spans: Vec<LabeledSpan>,
- }
- impl Diagnostic for MyDiagnostic {
- fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
- None
- }
-
- fn severity(&self) -> Option<miette::Severity> {
- None
- }
-
- fn help<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
- None
- }
-
- fn url<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
- None
- }
-
- fn source_code(&self) -> Option<&dyn miette::SourceCode> {
- Some(&self.code)
- }
-
- fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
- Some(Box::new(self.spans.clone().into_iter()))
- }
-
- fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
- None
- }
- }
-
- fn process(text: &str) -> String {
- use std::fmt::Write;
- let mut out = String::new();
- let node = parse(text);
- write!(out, "{:#?}", node.syntax()).unwrap();
- if !node.errors.is_empty() && !text.is_empty() {
- writeln!(out, "===").unwrap();
- for err in &node.errors {
- writeln!(out, "{:?}", err).unwrap();
- }
- let diag = MyDiagnostic {
- code: text.to_string(),
- spans: node.errors.into_iter().map(|e| e.into()).collect(),
- };
-
- let handler = GraphicalReportHandler::new();
-
- write!(out, "===").unwrap();
- handler.render_report(&mut out, &diag).unwrap();
- }
- out
- }
- macro_rules! mk_test {
- ($($name:ident => $test:expr)+) => {$(
- #[test]
- fn $name() {
- let src = indoc::indoc!($test);
- let result = process(&src);
- insta::assert_snapshot!(stringify!($name), result, src);
-
- }
- )+};
- }
- mk_test!(
- empty => r#" "#
- function => r#"
- function(a, b = 1) a + b
- "#
- function_error_no_value => r#"
- function(a, b = ) a + b
- "#
- function_error_rparen => r#"
- function(a, b
- "#
- function_error_body => r#"
- function(a, b)
- "#
- local_novalue => r#"
- local a =
- "#
- local_no_value_recovery => r#"
- local a =
- local b = 3;
- 1
- "#
-
- array_comp => r#"
- [a for a in [1, 2, 3]]
- "#
- array_comp_incompatible_with_multiple_elems => r#"
- [a for a in [1, 2, 3], b]
- "#
-
- no_rhs => r#"
- a +
- "#
- no_lhs => r#"
- + 2
- "#
- no_operator => "
- 2 2
- "
-
- named_before_positional => "
- a(1, 2, b=4, 3, 5, k = 12, 6)
- "
-
- wrong_field_end => "
- {
- a: 1;
- b: 2;
- }
- "
- );
-}
+pub use generated::syntax_kinds::SyntaxKind;
+pub use language::{
+ JsonnetLanguage, PreorderWithTokens, SyntaxElement, SyntaxElementChildren, SyntaxNode,
+ SyntaxNodeChildren, SyntaxToken,
+};
crates/jrsonnet-rowan-parser/src/marker.rsdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/src/marker.rs
+++ b/crates/jrsonnet-rowan-parser/src/marker.rs
@@ -1,7 +1,7 @@
use drop_bomb::DropBomb;
use rowan::TextRange;
-use crate::{event::Event, lex::SyntaxKind, parser::Parser};
+use crate::{event::Event, parser::Parser, SyntaxKind};
pub struct Ranger {
pub pos: usize,
crates/jrsonnet-rowan-parser/src/parser.rsdiffbeforeafterboth1use std::cell::Cell;2use std::fmt::Display;3use std::rc::Rc;45use miette::Diagnostic;6use miette::LabeledSpan;7use miette::SourceOffset;8use miette::SourceSpan;9use rowan::GreenNode;1011use rowan::TextRange;12use rowan::TextSize;13use thiserror::Error;1415use crate::binary::BinaryOperator;16use crate::event::Event;17use crate::event::Sink;18use crate::lex::lex;19use crate::lex::Lang;20use crate::lex::Lexeme;21use crate::lex::SyntaxKind;22use crate::lex::SyntaxKind::*;23use crate::marker::AsRange;24use crate::marker::CompletedMarker;25use crate::marker::FinishedRanger;26use crate::marker::Marker;27use crate::marker::Ranger;28use crate::token_set::TokenSet;29use crate::unary::UnaryOperator;3031pub struct Parse {32 pub green_node: GreenNode,33 pub errors: Vec<SyntaxError>,34}3536#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]37pub enum ExpectedSyntax {38 Named(&'static str),39 Unnamed(SyntaxKind),40}41impl Display for ExpectedSyntax {42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {43 match self {44 ExpectedSyntax::Named(n) => write!(f, "{}", n),45 ExpectedSyntax::Unnamed(u) => write!(f, "{:?}", u),46 }47 }48}4950pub struct Parser<'i> {51 lexemes: &'i [Lexeme<'i>],52 pub offset: usize,53 pub events: Vec<Event>,54 pub entered: u32,55 pub hints: Vec<(u32, TextRange, String)>,56 pub last_error_token: usize,57 expected_syntax: Option<ExpectedSyntax>,58 expected_syntax_tracking_state: Rc<Cell<ExpectedSyntaxTrackingState>>,59}6061const DEFAULT_RECOVERY_SET: TokenSet = TokenSet::new(&[62 SymbolSemi,63 RParen,64 SymbolRightBracket,65 SymbolRightBrace,66 KeywordLocal,67]);6869#[derive(Clone, Debug, PartialEq, Eq)]70pub enum SyntaxError {71 Unexpected {72 expected: ExpectedSyntax,73 found: SyntaxKind,74 range: TextRange,75 },76 Missing {77 expected: ExpectedSyntax,78 offset: TextSize,79 },80 Custom {81 error: String,82 range: TextRange,83 },84 Hint {85 error: String,86 range: TextRange,87 },88}8990impl Into<LabeledSpan> for SyntaxError {91 fn into(self) -> LabeledSpan {92 match self {93 SyntaxError::Unexpected {94 expected,95 found,96 range,97 } => LabeledSpan::new_with_span(98 Some(format!("expected {}, found {:?}", expected, found)),99 SourceSpan::new(100 SourceOffset::from(usize::from(range.start())),101 SourceOffset::from(usize::from(range.end() - range.start())),102 ),103 ),104 SyntaxError::Missing { expected, offset } => LabeledSpan::new_with_span(105 Some(format!("missing {}", expected)),106 SourceSpan::new(107 SourceOffset::from(usize::from(offset)),108 SourceOffset::from(0),109 ),110 ),111 SyntaxError::Custom { error, range } | SyntaxError::Hint { error, range } => {112 LabeledSpan::new_with_span(113 Some(format!("{}", error)),114 SourceSpan::new(115 SourceOffset::from(usize::from(range.start())),116 SourceOffset::from(usize::from(range.end() - range.start())),117 ),118 )119 }120 }121 }122}123124impl<'i> Parser<'i> {125 fn new(lexemes: &'i [Lexeme<'i>]) -> Self {126 Self {127 lexemes,128 offset: 0,129 events: vec![],130 entered: 0,131 last_error_token: 0,132 hints: vec![],133 expected_syntax: None,134 expected_syntax_tracking_state: Rc::new(Cell::new(135 ExpectedSyntaxTrackingState::Unnamed,136 )),137 }138 }139 pub fn clear_outdated_hints(&mut self) {140 let amount = self141 .hints142 .iter()143 .rev()144 .take_while(|h| h.0 > self.entered)145 .count();146 self.hints.truncate(self.hints.len() - amount)147 }148 fn clear_expected_syntaxes(&mut self) {149 self.expected_syntax = None;150 self.expected_syntax_tracking_state151 .set(ExpectedSyntaxTrackingState::Unnamed);152 }153 pub fn start(&mut self) -> Marker {154 let start_event_idx = self.events.len();155 self.events.push(Event::Placeholder);156 self.entered += 1;157 Marker::new(start_event_idx, self.offset)158 }159 pub fn start_ranger(&mut self) -> Ranger {160 let pos = self.offset;161 Ranger { pos }162 }163 fn parse(mut self) -> Vec<Event> {164 let m = self.start();165 expr(&mut self);166 if !self.at_end() {167 let ranger = self.start_ranger();168169 while self.peek().is_some() {170 self.bump()171 }172 let end = ranger.finish(&self);173 self.custom_error(end, "unexpected input after expression");174 }175 m.complete(&mut self, Root);176177 self.events178 }179180 pub(crate) fn expect(&mut self, kind: SyntaxKind) {181 self.expect_with_recovery_set(kind, TokenSet::default())182 }183184 pub(crate) fn expect_with_recovery_set(&mut self, kind: SyntaxKind, recovery_set: TokenSet) {185 if self.at(kind) {186 self.bump();187 } else {188 self.error_with_recovery_set(recovery_set);189 }190 }191192 pub(crate) fn expect_with_no_skip(&mut self, kind: SyntaxKind) {193 if self.at(kind) {194 self.bump();195 } else {196 self.error_with_no_skip();197 }198 }199 pub(crate) fn last_token_range(&self) -> Option<TextRange> {200 self.lexemes.last().map(|Lexeme { range, .. }| *range)201 }202 fn current_token(&self) -> Lexeme<'i> {203 self.lexemes[self.offset]204 }205 fn previous_token(&mut self) -> Option<Lexeme<'i>> {206 if self.offset == 0 {207 return None;208 }209 let mut previous_token_idx = self.offset - 1;210 while self211 .lexemes212 .get(previous_token_idx)213 .map_or(false, |l| l.kind.is_trivia())214 && previous_token_idx != 0215 {216 previous_token_idx -= 1;217 }218219 Some(self.lexemes[previous_token_idx])220 }221 pub fn start_of_token(&self, mut idx: usize) -> TextSize {222 while self.lexemes[idx].kind.is_trivia() {223 idx += 1;224 }225 self.lexemes[idx].range.start()226 }227 pub fn end_of_token(&self, mut idx: usize) -> TextSize {228 while self.lexemes[idx].kind.is_trivia() {229 idx -= 1;230 }231 self.lexemes[idx].range.end()232 }233 pub(crate) fn custom_error(&mut self, marker: impl AsRange, error: impl AsRef<str>) {234 self.last_error_token = marker.end_token();235 self.events.push(Event::Error(SyntaxError::Custom {236 error: error.as_ref().to_string(),237 range: marker.as_range(self),238 }));239 }240 pub(crate) fn error_with_recovery_set(241 &mut self,242 recovery_set: TokenSet,243 ) -> Option<CompletedMarker> {244 self.error_with_recovery_set_no_default(recovery_set.union(DEFAULT_RECOVERY_SET))245 }246 pub fn error_with_no_skip(&mut self) -> Option<CompletedMarker> {247 self.error_with_recovery_set_no_default(TokenSet::ALL)248 }249250 pub fn error_with_recovery_set_no_default(251 &mut self,252 recovery_set: TokenSet,253 ) -> Option<CompletedMarker> {254 let expected_syntax = self.expected_syntax.take().unwrap();255 self.expected_syntax_tracking_state256 .set(ExpectedSyntaxTrackingState::Unnamed);257258 if self.at_end() || self.at_set(recovery_set) {259 let range = self260 .previous_token()261 .map(|t| t.range)262 .unwrap_or(TextRange::at(TextSize::from(0), TextSize::from(0)));263264 self.events.push(Event::Error(SyntaxError::Missing {265 expected: expected_syntax,266 offset: range.end(),267 }));268 return None;269 }270271 let current_token = self.current_token();272273 self.events.push(Event::Error(SyntaxError::Unexpected {274 expected: expected_syntax.clone(),275 found: current_token.kind,276 range: current_token.range,277 }));278 self.clear_expected_syntaxes();279 self.last_error_token = self.offset;280281 let m = self.start();282 self.bump();283 Some(m.complete(self, SyntaxKind::Error))284 }285286 fn bump(&mut self) {287 self.skip_trivia();288 assert_ne!(self.offset, self.lexemes.len(), "already at end");289 self.events.push(Event::Token);290 self.offset += 1;291 self.clear_expected_syntaxes();292 }293 fn peek(&mut self) -> Option<SyntaxKind> {294 self.skip_trivia();295 self.peek_raw()296 }297 pub fn peek_token(&mut self) -> Option<&Lexeme<'i>> {298 self.skip_trivia();299 self.peek_token_raw()300 }301 fn skip_trivia(&mut self) {302 while self.peek_raw().map(|c| c.is_trivia()).unwrap_or(false) {303 self.offset += 1;304 }305 }306 fn peek_raw(&mut self) -> Option<SyntaxKind> {307 self.lexemes.get(self.offset).map(|l| l.kind)308 }309 fn peek_token_raw(&mut self) -> Option<&Lexeme<'i>> {310 self.lexemes.get(self.offset)311 }312 #[must_use]313 pub(crate) fn expected_syntax_name(&mut self, name: &'static str) -> ExpectedSyntaxGuard {314 self.expected_syntax_tracking_state315 .set(ExpectedSyntaxTrackingState::Named);316 self.expected_syntax = Some(ExpectedSyntax::Named(name));317318 ExpectedSyntaxGuard::new(Rc::clone(&self.expected_syntax_tracking_state))319 }320 pub fn at(&mut self, kind: SyntaxKind) -> bool {321 if let ExpectedSyntaxTrackingState::Unnamed = self.expected_syntax_tracking_state.get() {322 self.expected_syntax = Some(ExpectedSyntax::Unnamed(kind));323 }324 self.peek() == Some(kind)325 }326 pub fn at_set(&mut self, set: TokenSet) -> bool {327 self.peek().map_or(false, |k| set.contains(k))328 }329 pub fn at_end(&mut self) -> bool {330 self.peek().is_none()331 }332}333pub(crate) struct ExpectedSyntaxGuard {334 expected_syntax_tracking_state: Rc<Cell<ExpectedSyntaxTrackingState>>,335}336337impl ExpectedSyntaxGuard {338 fn new(expected_syntax_tracking_state: Rc<Cell<ExpectedSyntaxTrackingState>>) -> Self {339 Self {340 expected_syntax_tracking_state,341 }342 }343}344345impl Drop for ExpectedSyntaxGuard {346 fn drop(&mut self) {347 self.expected_syntax_tracking_state348 .set(ExpectedSyntaxTrackingState::Unnamed);349 }350}351352#[derive(Debug, Clone, Copy)]353enum ExpectedSyntaxTrackingState {354 Named,355 Unnamed,356}357macro_rules! at_match {358 ($p:ident {359 $($r:ident => $e:expr,)*360 _ => $else:expr $(,)?361 }) => {{362 $(363 if $p.at($r) {$e} else364 )* {365 $else366 }367 }}368}369370fn expr(p: &mut Parser) {371 expr_binding_power(p, 0);372}373fn expr_binding_power(p: &mut Parser, minimum_binding_power: u8) -> Option<CompletedMarker> {374 let mut lhs = lhs(p)?;375376 loop {377 let op = at_match!(p {378 OpMul => BinaryOperator::Mul,379 OpDiv => BinaryOperator::Div,380 OpMod => BinaryOperator::Mod,381 OpPlus => BinaryOperator::Plus,382 OpMinus => BinaryOperator::Minus,383 OpShiftLeft => BinaryOperator::ShiftLeft,384 OpShiftRight => BinaryOperator::ShiftRight,385 OpLessThan => BinaryOperator::LessThan,386 OpGreaterThan => BinaryOperator::GreaterThan,387 OpLessThanOrEqual => BinaryOperator::LessThanOrEqual,388 OpGreaterThanOrEqual => BinaryOperator::GreaterThanOrEqual,389 OpEqual => BinaryOperator::Equal,390 OpNotEqual => BinaryOperator::NotEqual,391 OpBitAnd => BinaryOperator::BitAnd,392 OpBitXor => BinaryOperator::BitXor,393 OpBitOr => BinaryOperator::BitOr,394 OpAnd => BinaryOperator::And,395 OpOr => BinaryOperator::Or,396 OpIn => BinaryOperator::In,397 SymbolLeftBrace => BinaryOperator::ObjectApply,398 _ => break,399 });400 let (left_binding_power, right_binding_power) = op.binding_power();401 if left_binding_power < minimum_binding_power {402 break;403 }404405 // Object apply is not a real operator, we dont have something to bump406 if op != BinaryOperator::ObjectApply {407 p.bump();408 }409410 let m = lhs.precede(p);411 let parsed_rhs = expr_binding_power(p, right_binding_power).is_some();412 lhs = m.complete(413 p,414 if op == BinaryOperator::ObjectApply {415 ObjectApply416 } else {417 BinOp418 },419 );420421 if !parsed_rhs {422 break;423 }424 }425 Some(lhs)426}427fn compspec(p: &mut Parser) {428 assert!(p.at(KeywordFor) || p.at(KeywordIf));429 if p.at(KeywordFor) {430 let m = p.start();431 p.bump();432 p.expect(Ident);433 p.expect(OpIn);434 expr(p);435 m.complete(p, CompspecFor);436 } else if p.at(KeywordIf) {437 let m = p.start();438 p.bump();439 expr(p);440 m.complete(p, CompspecIf);441 } else {442 unreachable!()443 }444}445fn comma(p: &mut Parser) -> bool {446 if p.at(SymbolComma) {447 p.bump();448 true449 } else {450 false451 }452}453fn comma_with_alternatives(p: &mut Parser, set: TokenSet) -> bool {454 if p.at(SymbolComma) {455 p.bump();456 true457 } else if p.at_set(set) {458 p.expect_with_no_skip(SymbolComma);459 p.bump();460 true461 } else {462 false463 }464}465fn field_name(p: &mut Parser) {466 let _e = p.expected_syntax_name("field name");467 if p.at(SymbolLeftBracket) {468 p.bump();469 expr(p);470 p.expect(SymbolRightBracket);471 } else if p.at(Ident) {472 p.bump()473 } else {474 p.error_with_recovery_set(TokenSet::new(&[SymbolSemi]));475 }476}477fn object(p: &mut Parser) -> CompletedMarker {478 assert!(p.at(SymbolLeftBrace));479 let m = p.start();480 p.bump();481482 loop {483 if p.at(SymbolRightBrace) {484 p.bump();485 break;486 }487 let m = p.start();488 field_name(p);489 p.expect(SymbolColon);490 expr(p);491 while p.at(KeywordFor) || p.at(KeywordIf) {492 compspec(p)493 }494 m.complete(p, Field);495 if comma_with_alternatives(p, TokenSet::new(&[SymbolAssign])) {496 continue;497 }498 p.expect(SymbolRightBrace);499 break;500 }501502 m.complete(p, Object)503}504505fn params(p: &mut Parser) -> CompletedMarker {506 assert!(p.at(LParen));507 let m = p.start();508 p.bump();509510 loop {511 if p.at(RParen) {512 p.bump();513 break;514 }515 let m = p.start();516 p.expect(Ident);517 if p.at(SymbolAssign) {518 p.bump();519 expr(p);520 }521 m.complete(p, DefParam);522 if comma(p) {523 continue;524 }525 p.expect(RParen);526 break;527 }528529 m.complete(p, DefParams)530}531fn args(p: &mut Parser) {532 assert!(p.at(LParen));533 p.bump();534535 let mut error_positional_start = None::<Marker>;536 let mut started_named = Cell::new(false);537 let mut on_positional = |p: &mut Parser, m: Marker| {538 let c = m.complete(p, DefPositionalArg);539 if started_named.get() && error_positional_start.is_none() {540 error_positional_start = Some(c.precede(p));541 }542 };543 loop {544 if p.at(RParen) {545 break;546 }547548 let m = p.start();549 if p.at(Ident) {550 p.bump();551 if p.at(SymbolAssign) {552 p.bump();553 expr(p);554 m.complete(p, DefNamedArg);555 started_named.set(true);556 } else {557 on_positional(p, m);558 }559 } else {560 expr(p);561 on_positional(p, m);562 }563 if comma(p) {564 continue;565 }566 break;567 }568 if let Some(error_positional_start) = error_positional_start {569 let c = error_positional_start.complete(p, ErrorPositionalAfterNamed);570 p.custom_error(c, "positional arguments can't be placed after named")571 }572 p.expect(RParen);573}574575fn array(p: &mut Parser) -> CompletedMarker {576 assert!(p.at(SymbolLeftBracket));577 // Start the list node578 let m = p.start();579 p.bump(); // '['580581 // This vec will have at most one element in case of correct input582 let mut compspecs = Vec::with_capacity(1);583 let mut elems = 0;584585 loop {586 if p.at(SymbolRightBracket) {587 p.bump();588 break;589 }590 elems += 1;591 let m = p.start();592 {593 let m = p.start();594 expr(p);595 m.complete(p, BodyDef);596 }597 let c = p.start_ranger();598 let mut had_spec = false;599 while p.at(KeywordFor) || p.at(KeywordIf) {600 had_spec = true;601 compspec(p)602 }603 if had_spec {604 compspecs.push(c.finish(p));605 }606 m.complete(p, ArrayElem);607 if comma(p) {608 continue;609 }610 p.expect(SymbolRightBracket);611 break;612 }613614 if elems > 1 && !compspecs.is_empty() {615 for spec in compspecs {616 p.custom_error(617 spec,618 "compspec may only be used if there is only one array element",619 )620 }621 }622623 m.complete(p, Array)624}625626fn lhs(p: &mut Parser) -> Option<CompletedMarker> {627 let mut lhs = lhs_basic(p)?;628629 loop {630 if p.at(SymbolDot) {631 let m = lhs.precede(p);632 p.bump();633 p.expect(Ident);634 lhs = m.complete(p, FieldAccess);635 } else if p.at(SymbolLeftBracket) {636 let m = lhs.precede(p);637 p.bump();638 // Start639 if !p.at(SymbolColon) {640 expr(p);641 }642 if p.at(SymbolColon) {643 p.bump();644 // End645 if !p.at(SymbolRightBracket) && !p.at(SymbolColon) {646 expr(p);647 }648 if p.at(SymbolColon) {649 p.bump();650 // Step651 if !p.at(SymbolRightBracket) {652 expr(p);653 }654 }655 }656 p.expect(SymbolRightBracket);657 lhs = m.complete(p, Slice);658 } else if p.at(LParen) {659 let m = lhs.precede(p);660 args(p);661 lhs = m.complete(p, FunctionCall);662 } else {663 break;664 }665 }666667 Some(lhs)668}669670fn lhs_basic(p: &mut Parser) -> Option<CompletedMarker> {671 let _e = p.expected_syntax_name("value");672 Some(673 if p.at(Number)674 || p.at(StringSingleQuoted)675 || p.at(StringDoubleQuoted)676 || p.at(StringSingleVerbatim)677 || p.at(StringDoubleVerbatim)678 || p.at(StringBlock)679 || p.at(KeywordNull)680 || p.at(SymbolDollar)681 || p.at(KeywordSuper)682 || p.at(KeywordSelf)683 {684 let m = p.start();685 p.bump();686 m.complete(p, Literal)687 } else if p.at(Ident) {688 let m = p.start();689 p.bump();690 m.complete(p, Ident)691 } else if p.at(SymbolLeftBracket) {692 array(p)693 } else if p.at(SymbolLeftBrace) {694 object(p)695 } else if p.at(KeywordLocal) {696 let m = p.start();697 p.bump();698 let mut sus_local = None;699 loop {700 p.expect_with_recovery_set(701 Ident,702 TokenSet::new(&[SymbolAssign, SymbolSemi, KeywordLocal]),703 );704 if p.at(LParen) {705 params(p);706 }707708 let sus_local_candidate = p.start_ranger();709 p.expect_with_recovery_set(710 SymbolAssign,711 TokenSet::new(&[SymbolSemi, KeywordLocal]),712 );713714 sus_local = p.at(KeywordLocal).then(|| sus_local_candidate.finish(p));715 expr(p);716717 if !comma(p) {718 break;719 }720 }721 p.expect(SymbolSemi);722 if let Some(sus_local) = sus_local {723 if sus_local.had_error_since(p) {724 p.custom_error(sus_local, "unusal local placement, missing ';' ?")725 }726 }727 {728 let m = p.start();729 expr(p);730 m.complete(p, BodyDef);731 }732 m.complete(p, Local)733 } else if p.at(KeywordFunction) {734 let m = p.start();735 p.bump();736 args(p);737 {738 let m = p.start();739 expr(p);740 m.complete(p, BodyDef);741 }742 m.complete(p, FunctionDef)743 } else if p.at(KeywordError) {744 let m = p.start();745 p.bump();746 expr(p);747 m.complete(p, ExprError)748 } else if p.at(KeywordAssert) {749 let m = p.start();750 p.bump();751 expr(p);752 if p.at(SymbolColon) {753 p.bump();754 expr(p);755 }756 m.complete(p, ExprAssert)757 } else if p.at(KeywordImport) || p.at(KeywordImportStr) {758 let m = p.start();759 p.bump();760 expr(p);761 m.complete(p, ExprImport)762 } else if p.at(OpMinus) || p.at(OpNot) || p.at(OpBitNegate) {763 let op = match p.peek().unwrap() {764 OpMinus => UnaryOperator::Minus,765 OpNot => UnaryOperator::Not,766 OpBitNegate => UnaryOperator::BitNegate,767 _ => unreachable!(),768 };769 let ((), right_binding_power) = op.binding_power();770771 let m = p.start();772 p.bump();773 expr_binding_power(p, right_binding_power);774 m.complete(p, UnaryOp)775 } else if p.at(LParen) {776 let m = p.start();777 p.bump();778 expr(p);779 assert!(p.at(RParen));780 p.bump();781 m.complete(p, Parened)782 } else {783 p.error_with_no_skip();784 return None;785 },786 )787}788789type SyntaxNode = rowan::SyntaxNode<Lang>;790#[allow(unused)]791type SyntaxToken = rowan::SyntaxToken<Lang>;792#[allow(unused)]793type SyntaxElement = rowan::NodeOrToken<SyntaxNode, SyntaxToken>;794795impl Parse {796 pub fn syntax(&self) -> SyntaxNode {797 SyntaxNode::new_root(self.green_node.clone())798 }799}800801pub fn parse(input: &str) -> Parse {802 let lexemes = lex(input);803 let parser = Parser::new(&lexemes);804 let events = parser.parse();805 dbg!(&events);806 let sink = Sink::new(events, &lexemes);807808 sink.finish()809}crates/jrsonnet-rowan-parser/src/string_block.rsdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/src/string_block.rs
+++ b/crates/jrsonnet-rowan-parser/src/string_block.rs
@@ -11,7 +11,7 @@
use StringBlockToken::*;
-use crate::lex::SyntaxKind;
+use crate::SyntaxKind;
pub fn lex_str_block_test<'a>(lex: &mut logos::Lexer<'a, SyntaxKind>) {
lex_str_block(lex);
crates/jrsonnet-rowan-parser/src/tests.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/tests.rs
@@ -0,0 +1,127 @@
+#![cfg(test)]
+
+use miette::{Diagnostic, GraphicalReportHandler, LabeledSpan};
+use thiserror::Error;
+
+use crate::parser::parse;
+
+#[derive(Debug, Error)]
+#[error("syntax error")]
+struct MyDiagnostic {
+ code: String,
+ spans: Vec<LabeledSpan>,
+}
+impl Diagnostic for MyDiagnostic {
+ fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
+ None
+ }
+
+ fn severity(&self) -> Option<miette::Severity> {
+ None
+ }
+
+ fn help<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
+ None
+ }
+
+ fn url<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
+ None
+ }
+
+ fn source_code(&self) -> Option<&dyn miette::SourceCode> {
+ Some(&self.code)
+ }
+
+ fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
+ Some(Box::new(self.spans.clone().into_iter()))
+ }
+
+ fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
+ None
+ }
+}
+
+fn process(text: &str) -> String {
+ use std::fmt::Write;
+ let mut out = String::new();
+ let node = parse(text);
+ write!(out, "{:#?}", node.syntax()).unwrap();
+ if !node.errors.is_empty() && !text.is_empty() {
+ writeln!(out, "===").unwrap();
+ for err in &node.errors {
+ writeln!(out, "{:?}", err).unwrap();
+ }
+ let diag = MyDiagnostic {
+ code: text.to_string(),
+ spans: node.errors.into_iter().map(|e| e.into()).collect(),
+ };
+
+ let handler = GraphicalReportHandler::new();
+
+ write!(out, "===").unwrap();
+ handler.render_report(&mut out, &diag).unwrap();
+ }
+ out
+}
+macro_rules! mk_test {
+ ($($name:ident => $test:expr)+) => {$(
+ #[test]
+ fn $name() {
+ let src = indoc::indoc!($test);
+ let result = process(&src);
+ insta::assert_snapshot!(stringify!($name), result, src);
+
+ }
+ )+};
+ }
+mk_test!(
+ empty => r#" "#
+ function => r#"
+ function(a, b = 1) a + b
+ "#
+ function_error_no_value => r#"
+ function(a, b = ) a + b
+ "#
+ function_error_rparen => r#"
+ function(a, b
+ "#
+ function_error_body => r#"
+ function(a, b)
+ "#
+ local_novalue => r#"
+ local a =
+ "#
+ local_no_value_recovery => r#"
+ local a =
+ local b = 3;
+ 1
+ "#
+
+ array_comp => r#"
+ [a for a in [1, 2, 3]]
+ "#
+ array_comp_incompatible_with_multiple_elems => r#"
+ [a for a in [1, 2, 3], b]
+ "#
+
+ no_rhs => r#"
+ a +
+ "#
+ no_lhs => r#"
+ + 2
+ "#
+ no_operator => "
+ 2 2
+ "
+
+ named_before_positional => "
+ a(1, 2, b=4, 3, 5, k = 12, 6)
+ "
+
+ wrong_field_end => "
+ {
+ a: 1;
+ b: 2;
+ }
+ "
+);
crates/jrsonnet-rowan-parser/src/token_set.rsdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/src/token_set.rs
+++ b/crates/jrsonnet-rowan-parser/src/token_set.rs
@@ -1,24 +1,24 @@
-use crate::lex::SyntaxKind;
+use crate::SyntaxKind;
#[derive(Clone, Copy, Default)]
-pub struct TokenSet(u64);
+pub struct SyntaxKindSet(u64);
-impl TokenSet {
+impl SyntaxKindSet {
pub const EMPTY: Self = Self(0);
pub const ALL: Self = Self(u64::MAX);
- pub const fn new(kinds: &[SyntaxKind]) -> TokenSet {
+ pub const fn new(kinds: &[SyntaxKind]) -> SyntaxKindSet {
let mut res = 0u64;
let mut i = 0;
while i < kinds.len() {
res |= mask(kinds[i]);
i += 1
}
- TokenSet(res)
+ SyntaxKindSet(res)
}
- pub const fn union(self, other: TokenSet) -> TokenSet {
- TokenSet(self.0 | other.0)
+ pub const fn union(self, other: SyntaxKindSet) -> SyntaxKindSet {
+ SyntaxKindSet(self.0 | other.0)
}
pub const fn contains(&self, kind: SyntaxKind) -> bool {
@@ -29,3 +29,14 @@
const fn mask(kind: SyntaxKind) -> u64 {
1u64 << (kind as usize)
}
+
+#[macro_export]
+macro_rules! TS {
+ ($($tt:tt)*) => {
+ SyntaxKindSet::new(&[
+ $(
+ T![$tt]
+ ),*
+ ])
+ };
+}
xtask/Cargo.tomldiffbeforeafterboth--- /dev/null
+++ b/xtask/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "xtask"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+anyhow = "1.0.57"
+itertools = "0.10.3"
+proc-macro2 = "1.0.39"
+quote = "1.0.18"
+ungrammar = "1.16.1"
+xshell = "0.2.2"
xtask/src/main.rsdiffbeforeafterboth--- /dev/null
+++ b/xtask/src/main.rs
@@ -0,0 +1,7 @@
+use anyhow::Result;
+
+mod sourcegen;
+
+fn main() -> Result<()> {
+ sourcegen::generate_ungrammar()
+}
xtask/src/sourcegen/ast.rsdiffbeforeafterboth--- /dev/null
+++ b/xtask/src/sourcegen/ast.rs
@@ -0,0 +1,93 @@
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
+
+use super::{escape_token_macro, KindsSrc};
+
+impl AstNodeSrc {
+ pub fn remove_field(&mut self, to_remove: Vec<usize>) {
+ to_remove.into_iter().rev().for_each(|idx| {
+ self.fields.remove(idx);
+ });
+ }
+}
+
+#[allow(dead_code)]
+#[derive(Default, Debug)]
+pub struct AstSrc {
+ pub tokens: Vec<String>,
+ pub nodes: Vec<AstNodeSrc>,
+ pub enums: Vec<AstEnumSrc>,
+}
+#[derive(Debug)]
+pub struct AstNodeSrc {
+ pub doc: Vec<String>,
+ pub name: String,
+ pub traits: Vec<String>,
+ pub fields: Vec<Field>,
+}
+
+#[derive(Debug, Eq, PartialEq)]
+pub enum Field {
+ Token(String),
+ Node {
+ name: String,
+ ty: String,
+ cardinality: Cardinality,
+ },
+}
+
+#[derive(Debug, Eq, PartialEq)]
+pub enum Cardinality {
+ Optional,
+ Many,
+}
+
+#[derive(Debug, Clone)]
+pub struct AstEnumSrc {
+ pub doc: Vec<String>,
+ pub name: String,
+ pub traits: Vec<String>,
+ pub variants: Vec<String>,
+}
+
+impl Field {
+ pub fn is_many(&self) -> bool {
+ matches!(
+ self,
+ Field::Node {
+ cardinality: Cardinality::Many,
+ ..
+ }
+ )
+ }
+ pub fn token_kind(&self) -> Option<TokenStream> {
+ match self {
+ Field::Token(token) => {
+ let token: TokenStream = escape_token_macro(token);
+ Some(quote! { T![#token] })
+ }
+ _ => None,
+ }
+ }
+
+ pub fn method_name(&self, kinds: &KindsSrc) -> proc_macro2::Ident {
+ match self {
+ Field::Token(name) => {
+ if let Some(punct_name) = kinds.get_punct_name(name) {
+ format_ident!("{}_token", punct_name.to_lowercase())
+ } else {
+ format_ident!("{}_token", name.to_lowercase())
+ }
+ }
+ Field::Node { name, .. } => {
+ format_ident!("{}", name)
+ }
+ }
+ }
+ pub fn ty(&self) -> proc_macro2::Ident {
+ match self {
+ Field::Token(_) => format_ident!("SyntaxToken"),
+ Field::Node { ty, .. } => format_ident!("{}", ty),
+ }
+ }
+}
xtask/src/sourcegen/mod.rsdiffbeforeafterboth--- /dev/null
+++ b/xtask/src/sourcegen/mod.rs
@@ -0,0 +1,922 @@
+use std::{
+ collections::{BTreeSet, HashSet},
+ path::PathBuf,
+};
+
+use anyhow::Result;
+use ast::{AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field};
+use itertools::Itertools;
+use proc_macro2::{Punct, Spacing, TokenStream};
+use quote::{format_ident, quote};
+use ungrammar::{Grammar, Rule};
+use util::{
+ ensure_file_contents, pluralize, reformat, to_lower_snake_case, to_pascal_case,
+ to_upper_snake_case,
+};
+
+mod ast;
+mod util;
+
+pub fn generate_ungrammar() -> Result<()> {
+ let grammar: Grammar = include_str!(concat!(
+ env!("CARGO_MANIFEST_DIR"),
+ "/../crates/jrsonnet-rowan-parser/jsonnet.ungram"
+ ))
+ .parse()?;
+
+ let mut kinds: KindsSrc = KindsSrc {
+ punct: puncts![
+ "||" => "OR";
+ "&&" => "AND";
+ "|" => "BIT_OR";
+ "^" => "BIT_XOR";
+ "&" => "BIT_AND";
+ "==" => "EQ";
+ "!=" => "NE";
+ "<" => "LT";
+ ">" => "GT";
+ "<=" => "LE";
+ ">=" => "GE";
+ "<<" => "LHS";
+ ">>" => "RHS";
+ "+" => "PLUS";
+ "-" => "MINUS";
+ "*" => "MUL";
+ "/" => "DIV";
+ "%" => "MODULO";
+ "!" => "NOT";
+ "~" => "BIT_NOT";
+ "[" => "L_BRACK";
+ "]" => "R_BRACK";
+ "(" => "L_PAREN";
+ ")" => "R_PAREN";
+ "{" => "L_BRACE";
+ "}" => "R_BRACE";
+ ":" => "COLON";
+ "::" => "COLONCOLON";
+ ":::" => "COLONCOLONCOLON";
+ ";" => "SEMI";
+ "." => "DOT";
+ "..." => "DOTDOTDOT";
+ "," => "COMMA";
+ "$" => "DOLLAR";
+ "=" => "ASSIGN";
+ "?" => "QUESTION_MARK";
+ "$intrinsicThisFile" => "INTRINSIC_THIS_FILE";
+ "$intrinsicId" => "INTRINSIC_ID";
+ "$intrinsic" => "INTRINSIC";
+ ],
+ keywords: vec![],
+ literals: literals![
+ "NUMBER" => r"(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?";
+ "STRING_DOUBLE" => "\"(?s:[^\"\\\\]|\\\\.)*\"";
+ "STRING_SINGLE" => "'(?s:[^'\\\\]|\\\\.)*'";
+ "STRING_DOUBLE_VERBATIM" => "@\"(?:[^\"]|\"\")*\"";
+ "STRING_SINGLE_VERBATIM" => "@'(?:[^']|'')*'";
+ "STRING_BLOCK" => r"\|\|\|";
+
+ "IDENT" => r"[_a-zA-Z][_a-zA-Z0-9]*";
+ "WHITESPACE" => r"[ \t\n\r]+";
+ "SINGLE_LINE_SLASH_COMMENT" => r"//[^\r\n]*(\r\n|\n)?";
+ "SINGLE_LINE_HASH_COMMENT" => r"#[^\r\n]*(\r\n|\n)?";
+ "MULTI_LINE_COMMENT" => r"/\*([^*]|\*[^/])*\*/";
+ ],
+ nodes: vec![],
+ };
+
+ let ast = lower(&kinds, &grammar);
+
+ for node in &ast.nodes {
+ let name = to_upper_snake_case(&node.name);
+ if !kinds.is_literal(&name) {
+ kinds.nodes.push(name);
+ }
+ }
+ for enum_ in &ast.enums {
+ let name = to_upper_snake_case(&enum_.name);
+ if !kinds.is_literal(&name) {
+ kinds.nodes.push(name);
+ }
+ }
+ for token in grammar.tokens() {
+ let token = &grammar[token];
+ let token = &token.name.clone();
+ let name = to_upper_snake_case(token);
+ if !kinds.is_punct(token) && !kinds.is_literal(&name) {
+ kinds.keywords.push(token.to_owned());
+ }
+ }
+
+ let syntax_kinds = generate_syntax_kinds(&kinds)?;
+
+ let tokens = generate_tokens(&ast)?;
+
+ let nodes = generate_nodes(&kinds, &ast)?;
+ ensure_file_contents(
+ &PathBuf::from(concat!(
+ env!("CARGO_MANIFEST_DIR"),
+ "/../crates/jrsonnet-rowan-parser/src/generated/syntax_kinds.rs",
+ )),
+ &syntax_kinds,
+ )?;
+ ensure_file_contents(
+ &PathBuf::from(concat!(
+ env!("CARGO_MANIFEST_DIR"),
+ "/../crates/jrsonnet-rowan-parser/src/generated/tokens.rs",
+ )),
+ &tokens,
+ )?;
+ ensure_file_contents(
+ &PathBuf::from(concat!(
+ env!("CARGO_MANIFEST_DIR"),
+ "/../crates/jrsonnet-rowan-parser/src/generated/nodes.rs",
+ )),
+ &nodes,
+ )?;
+ Ok(())
+}
+
+fn generate_tokens(grammar: &AstSrc) -> Result<String> {
+ let tokens = grammar.tokens.iter().map(|token| {
+ let name = format_ident!("{}", token);
+ let kind = format_ident!("{}", to_upper_snake_case(token));
+ quote! {
+ #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+ pub struct #name {
+ pub(crate) syntax: SyntaxToken,
+ }
+ impl std::fmt::Display for #name {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(&self.syntax, f)
+ }
+ }
+ impl AstToken for #name {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == #kind }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
+ }
+ fn syntax(&self) -> &SyntaxToken { &self.syntax }
+ }
+ }
+ });
+
+ Ok(reformat(
+ "e! {
+ use crate::{SyntaxKind::{self, *}, SyntaxToken, ast::AstToken};
+ #(#tokens)*
+ }
+ .to_string(),
+ )?
+ .replace("#[derive", "\n#[derive"))
+}
+
+fn generate_syntax_kinds(grammar: &KindsSrc) -> Result<String> {
+ let (single_byte_tokens_values, single_byte_tokens): (Vec<_>, Vec<_>) = grammar
+ .punct
+ .iter()
+ .filter(|(token, _name)| token.len() == 1)
+ .map(|(token, name)| (token.chars().next().unwrap(), format_ident!("{}", name)))
+ .unzip();
+
+ let punctuation_values = grammar
+ .punct
+ .iter()
+ .map(|(token, _name)| escape_token_macro(token));
+ let punctuation = grammar
+ .punct
+ .iter()
+ .map(|(_token, name)| format_ident!("{}", name))
+ .collect::<Vec<_>>();
+ let punctuation_enum = grammar
+ .punct
+ .iter()
+ .map(|(token, name)| {
+ let id = format_ident!("{}", name);
+ quote! {
+ #[token(#token)]
+ #id
+ }
+ })
+ .collect::<Vec<_>>();
+
+ let x = |name: &str| format_ident!("{}_KW", to_upper_snake_case(name));
+ let full_keywords_values = &grammar.keywords;
+ let full_keywords = full_keywords_values.iter().map(|s| x(s.as_str()));
+
+ let all_keywords_values = grammar.keywords.to_vec();
+ let all_keywords_idents = all_keywords_values.iter().map(|kw| format_ident!("{}", kw));
+ let all_keywords = all_keywords_values
+ .iter()
+ .map(|s| x(&**s))
+ .collect::<Vec<_>>();
+ let all_keywords_enum = all_keywords_values
+ .iter()
+ .map(|s| {
+ let id = x(&**s);
+ quote! {
+ #[token(#s)]
+ #id
+ }
+ })
+ .collect::<Vec<_>>();
+
+ let tokens_enum = grammar
+ .literals
+ .iter()
+ .map(|l| {
+ let regex = &l.regex;
+ let id = format_ident!("{}", l.name);
+ let lexer = l
+ .lexer
+ .as_ref()
+ .map(|l| {
+ let id: TokenStream = l.parse().expect("path");
+ quote! {
+ , #id
+ }
+ })
+ .unwrap_or_else(|| quote! {});
+ quote! {
+ #[regex(#regex #lexer)]
+ #id
+ }
+ })
+ .collect::<Vec<_>>();
+
+ let nodes = grammar
+ .nodes
+ .iter()
+ .map(|name| format_ident!("{}", name))
+ .collect::<Vec<_>>();
+
+ let ast = quote! {
+ #![allow(bad_style, missing_docs, unreachable_pub)]
+ use logos::Logos;
+
+ /// The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT`.
+ #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Logos)]
+ #[repr(u16)]
+ pub enum SyntaxKind {
+ #[doc(hidden)]
+ TOMBSTONE,
+ #[doc(hidden)]
+ EOF,
+ #(#punctuation_enum,)*
+ #(#all_keywords_enum,)*
+ #(#tokens_enum,)*
+ #[error]
+ ERROR,
+ #(#nodes,)*
+ #[doc(hidden)]
+ __LAST,
+ }
+ use self::SyntaxKind::*;
+
+ impl SyntaxKind {
+ pub fn is_keyword(self) -> bool {
+ match self {
+ #(#all_keywords)|* => true,
+ _ => false,
+ }
+ }
+
+ pub fn is_punct(self) -> bool {
+ match self {
+ #(#punctuation)|* => true,
+ _ => false,
+ }
+ }
+
+ pub fn from_keyword(ident: &str) -> Option<SyntaxKind> {
+ let kw = match ident {
+ #(#full_keywords_values => #full_keywords,)*
+ _ => return None,
+ };
+ Some(kw)
+ }
+
+ pub fn from_char(c: char) -> Option<SyntaxKind> {
+ let tok = match c {
+ #(#single_byte_tokens_values => #single_byte_tokens,)*
+ _ => return None,
+ };
+ Some(tok)
+ }
+
+ pub fn from_raw(r: u16) -> Self {
+ assert!(r < Self::__LAST as u16);
+ unsafe { std::mem::transmute(r) }
+ }
+ pub fn into_raw(self) -> u16 {
+ self as u16
+ }
+ }
+
+ #[macro_export]
+ macro_rules! T {
+ #([#punctuation_values] => { $crate::SyntaxKind::#punctuation };)*
+ #([#all_keywords_idents] => { $crate::SyntaxKind::#all_keywords };)*
+ [lifetime_ident] => { $crate::SyntaxKind::LIFETIME_IDENT };
+ [ident] => { $crate::SyntaxKind::IDENT };
+ [shebang] => { $crate::SyntaxKind::SHEBANG };
+ }
+ pub use T;
+ };
+
+ reformat(&ast.to_string())
+}
+
+pub struct KindsSrc {
+ pub punct: Vec<(String, String)>,
+ pub keywords: Vec<String>,
+ pub literals: Vec<LiteralKind>,
+ pub nodes: Vec<String>,
+}
+
+pub struct LiteralKind {
+ name: String,
+ regex: String,
+ lexer: Option<String>,
+}
+
+#[macro_export]
+macro_rules! literals {
+ ($($name:expr => $regex:expr $(, $lexer:expr)?);* $(;)?) => {
+ vec![
+ $(LiteralKind {
+ name: $name.to_owned(),
+ regex: $regex.to_owned(),
+ lexer: None $(.or_else(|| Some($lexer.to_string())))?,
+ }),*
+ ]
+ };
+}
+
+#[macro_export]
+macro_rules! puncts {
+ ($($tok:expr => $name:expr);* $(;)?) => {
+ vec![
+ $(($tok.to_owned(), $name.to_owned())),*
+ ]
+ };
+}
+use crate::{literals, puncts};
+
+impl KindsSrc {
+ pub fn is_punct(&self, tok: &str) -> bool {
+ self.punct.iter().any(|(t, _)| *t == tok)
+ }
+ pub fn is_literal(&self, tok: &str) -> bool {
+ self.literals.iter().any(|l| l.name == tok)
+ }
+
+ fn get_punct_name(&self, tok: &str) -> Option<&str> {
+ self.punct
+ .iter()
+ .find(|(t, _)| *t == tok)
+ .map(|(_, n)| n.as_str())
+ }
+}
+
+fn generate_nodes(kinds: &KindsSrc, grammar: &AstSrc) -> Result<String> {
+ let (node_defs, node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
+ .nodes
+ .iter()
+ .map(|node| {
+ let name = format_ident!("{}", node.name);
+ let kind = format_ident!("{}", to_upper_snake_case(&node.name));
+ let traits = node.traits.iter().map(|trait_name| {
+ let trait_name = format_ident!("{}", trait_name);
+ quote!(impl ast::#trait_name for #name {})
+ });
+
+ let methods = node.fields.iter().map(|field| {
+ let method_name = field.method_name(kinds);
+ let ty = field.ty();
+
+ if field.is_many() {
+ quote! {
+ pub fn #method_name(&self) -> AstChildren<#ty> {
+ support::children(&self.syntax)
+ }
+ }
+ } else if let Some(token_kind) = field.token_kind() {
+ quote! {
+ pub fn #method_name(&self) -> Option<#ty> {
+ support::token(&self.syntax, #token_kind)
+ }
+ }
+ } else {
+ quote! {
+ pub fn #method_name(&self) -> Option<#ty> {
+ support::child(&self.syntax)
+ }
+ }
+ }
+ });
+ (
+ quote! {
+ #[pretty_doc_comment_placeholder_workaround]
+ #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+ pub struct #name {
+ pub(crate) syntax: SyntaxNode,
+ }
+
+ #(#traits)*
+
+ impl #name {
+ #(#methods)*
+ }
+ },
+ quote! {
+ impl AstNode for #name {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == #kind
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+ }
+ },
+ )
+ })
+ .unzip();
+
+ let (enum_defs, enum_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
+ .enums
+ .iter()
+ .map(|en| {
+ let variants: Vec<_> = en
+ .variants
+ .iter()
+ .map(|var| format_ident!("{}", var))
+ .collect();
+ let name = format_ident!("{}", en.name);
+ let kinds: Vec<_> = variants
+ .iter()
+ .map(|name| format_ident!("{}", to_upper_snake_case(&name.to_string())))
+ .collect();
+ let traits = en.traits.iter().map(|trait_name| {
+ let trait_name = format_ident!("{}", trait_name);
+ quote!(impl ast::#trait_name for #name {})
+ });
+
+ let ast_node = quote! {
+ impl AstNode for #name {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ #(#kinds)|* => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ #(
+ #kinds => #name::#variants(#variants { syntax }),
+ )*
+ _ => return None,
+ };
+ Some(res)
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ #(
+ #name::#variants(it) => &it.syntax,
+ )*
+ }
+ }
+ }
+ };
+
+ (
+ quote! {
+ #[pretty_doc_comment_placeholder_workaround]
+ #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+ pub enum #name {
+ #(#variants(#variants),)*
+ }
+
+ #(#traits)*
+ },
+ quote! {
+ #(
+ impl From<#variants> for #name {
+ fn from(node: #variants) -> #name {
+ #name::#variants(node)
+ }
+ }
+ )*
+ #ast_node
+ },
+ )
+ })
+ .unzip();
+
+ let (any_node_defs, any_node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
+ .nodes
+ .iter()
+ .flat_map(|node| node.traits.iter().map(move |t| (t, node)))
+ .into_group_map()
+ .into_iter()
+ .sorted_by_key(|(k, _)| *k)
+ .map(|(trait_name, nodes)| {
+ let name = format_ident!("Any{}", trait_name);
+ let trait_name = format_ident!("{}", trait_name);
+ let kinds: Vec<_> = nodes
+ .iter()
+ .map(|name| format_ident!("{}", to_upper_snake_case(&name.name.to_string())))
+ .collect();
+
+ (
+ quote! {
+ #[pretty_doc_comment_placeholder_workaround]
+ #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+ pub struct #name {
+ pub(crate) syntax: SyntaxNode,
+ }
+ impl ast::#trait_name for #name {}
+ },
+ quote! {
+ impl #name {
+ #[inline]
+ pub fn new<T: ast::#trait_name>(node: T) -> #name {
+ #name {
+ syntax: node.syntax().clone()
+ }
+ }
+ }
+ impl AstNode for #name {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ #(#kinds)|* => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ Self::can_cast(syntax.kind()).then(|| #name { syntax })
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+ }
+ },
+ )
+ })
+ .unzip();
+
+ let enum_names = grammar.enums.iter().map(|it| &it.name);
+ let node_names = grammar.nodes.iter().map(|it| &it.name);
+
+ let display_impls = enum_names
+ .chain(node_names.clone())
+ .map(|it| format_ident!("{}", it))
+ .map(|name| {
+ quote! {
+ impl std::fmt::Display for #name {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+ }
+ }
+ });
+
+ let defined_nodes: HashSet<_> = node_names.collect();
+
+ for node in kinds
+ .nodes
+ .iter()
+ .map(|kind| to_pascal_case(kind))
+ .filter(|name| !defined_nodes.iter().any(|&it| it == name))
+ {
+ drop(node)
+ // FIXME: restore this
+ // eprintln!("Warning: node {} not defined in ast source", node);
+ }
+
+ let ast = quote! {
+ #![allow(non_snake_case)]
+ use crate::{
+ SyntaxNode, SyntaxToken, SyntaxKind::{self, *},
+ ast::{self, AstNode, AstChildren, support},
+ T,
+ };
+
+ #(#node_defs)*
+ #(#enum_defs)*
+ #(#any_node_defs)*
+ #(#node_boilerplate_impls)*
+ #(#enum_boilerplate_impls)*
+ #(#any_node_boilerplate_impls)*
+ #(#display_impls)*
+ };
+
+ let ast = ast.to_string().replace("T ! [", "T![");
+
+ let mut res = String::with_capacity(ast.len() * 2);
+
+ let mut docs = grammar
+ .nodes
+ .iter()
+ .map(|it| &it.doc)
+ .chain(grammar.enums.iter().map(|it| &it.doc));
+
+ for chunk in ast.split("# [pretty_doc_comment_placeholder_workaround] ") {
+ res.push_str(chunk);
+ if let Some(doc) = docs.next() {
+ write_doc_comment(doc, &mut res);
+ }
+ }
+
+ let res = reformat(&res)?;
+ Ok(res.replace("#[derive", "\n#[derive"))
+}
+
+fn write_doc_comment(contents: &[String], dest: &mut String) {
+ use std::fmt::Write;
+ for line in contents {
+ writeln!(dest, "///{}", line).unwrap();
+ }
+}
+
+fn lower(kinds: &KindsSrc, grammar: &Grammar) -> AstSrc {
+ let tokens = "Whitespace Comment String StringVerbantim StringBlock Number Ident"
+ .split_ascii_whitespace()
+ .map(|it| it.to_string())
+ .collect::<Vec<_>>();
+
+ let mut res = AstSrc {
+ tokens,
+ ..Default::default()
+ };
+
+ let nodes = grammar.iter().collect::<Vec<_>>();
+
+ for &node in &nodes {
+ let name = grammar[node].name.clone();
+ let rule = &grammar[node].rule;
+ match lower_enum(grammar, rule) {
+ Some(variants) => {
+ let enum_src = AstEnumSrc {
+ doc: Vec::new(),
+ name,
+ traits: Vec::new(),
+ variants,
+ };
+ res.enums.push(enum_src);
+ }
+ None => {
+ let mut fields = Vec::new();
+ lower_rule(&mut fields, grammar, None, rule);
+ res.nodes.push(AstNodeSrc {
+ doc: Vec::new(),
+ name,
+ traits: Vec::new(),
+ fields,
+ });
+ }
+ }
+ }
+
+ deduplicate_fields(&mut res);
+ extract_enums(&mut res);
+ extract_struct_traits(kinds, &mut res);
+ extract_enum_traits(&mut res);
+ res
+}
+
+fn lower_enum(grammar: &Grammar, rule: &Rule) -> Option<Vec<String>> {
+ let alternatives = match rule {
+ Rule::Alt(it) => it,
+ _ => return None,
+ };
+ let mut variants = Vec::new();
+ for alternative in alternatives {
+ match alternative {
+ Rule::Node(it) => variants.push(grammar[*it].name.clone()),
+ Rule::Token(it) if grammar[*it].name == ";" => (),
+ _ => return None,
+ }
+ }
+ Some(variants)
+}
+
+fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, rule: &Rule) {
+ if lower_comma_list(acc, grammar, label, rule) {
+ return;
+ }
+
+ match rule {
+ Rule::Node(node) => {
+ let ty = grammar[*node].name.clone();
+ let name = label.cloned().unwrap_or_else(|| to_lower_snake_case(&ty));
+ let field = Field::Node {
+ name,
+ ty,
+ cardinality: Cardinality::Optional,
+ };
+ acc.push(field);
+ }
+ Rule::Token(token) => {
+ assert!(label.is_none(), "uexpected label: {:?}", label);
+ let name = grammar[*token].name.clone();
+ let field = Field::Token(name);
+ acc.push(field);
+ }
+ Rule::Rep(inner) => {
+ if let Rule::Node(node) = &**inner {
+ let ty = grammar[*node].name.clone();
+ let name = label
+ .cloned()
+ .unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));
+ let field = Field::Node {
+ name,
+ ty,
+ cardinality: Cardinality::Many,
+ };
+ acc.push(field);
+ return;
+ }
+ todo!("unsupported repitition: {:?}", rule)
+ }
+ Rule::Labeled { label: l, rule } => {
+ assert!(label.is_none());
+ lower_rule(acc, grammar, Some(l), rule);
+ }
+ Rule::Seq(rules) | Rule::Alt(rules) => {
+ for rule in rules {
+ lower_rule(acc, grammar, label, rule)
+ }
+ }
+ Rule::Opt(rule) => lower_rule(acc, grammar, label, rule),
+ }
+}
+
+// (T (',' T)* ','?)
+fn lower_comma_list(
+ acc: &mut Vec<Field>,
+ grammar: &Grammar,
+ label: Option<&String>,
+ rule: &Rule,
+) -> bool {
+ let rule = match rule {
+ Rule::Seq(it) => it,
+ _ => return false,
+ };
+ let (node, repeat, trailing_comma) = match rule.as_slice() {
+ [Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_comma)] => {
+ (node, repeat, trailing_comma)
+ }
+ _ => return false,
+ };
+ let repeat = match &**repeat {
+ Rule::Seq(it) => it,
+ _ => return false,
+ };
+ match repeat.as_slice() {
+ [comma, Rule::Node(n)] if comma == &**trailing_comma && n == node => (),
+ _ => return false,
+ }
+ let ty = grammar[*node].name.clone();
+ let name = label
+ .cloned()
+ .unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));
+ let field = Field::Node {
+ name,
+ ty,
+ cardinality: Cardinality::Many,
+ };
+ acc.push(field);
+ true
+}
+
+fn deduplicate_fields(ast: &mut AstSrc) {
+ for node in &mut ast.nodes {
+ let mut i = 0;
+ 'outer: while i < node.fields.len() {
+ for j in 0..i {
+ let f1 = &node.fields[i];
+ let f2 = &node.fields[j];
+ if f1 == f2 {
+ node.fields.remove(i);
+ continue 'outer;
+ }
+ }
+ i += 1;
+ }
+ }
+}
+
+fn extract_enums(ast: &mut AstSrc) {
+ for node in &mut ast.nodes {
+ for enm in &ast.enums {
+ let mut to_remove = Vec::new();
+ for (i, field) in node.fields.iter().enumerate() {
+ let ty = field.ty().to_string();
+ if enm.variants.iter().any(|it| it == &ty) {
+ to_remove.push(i);
+ }
+ }
+ if to_remove.len() == enm.variants.len() {
+ node.remove_field(to_remove);
+ let ty = enm.name.clone();
+ let name = to_lower_snake_case(&ty);
+ node.fields.push(Field::Node {
+ name,
+ ty,
+ cardinality: Cardinality::Optional,
+ });
+ }
+ }
+ }
+}
+
+fn extract_struct_traits(kinds: &KindsSrc, ast: &mut AstSrc) {
+ // TODO: add common accessor traits here.
+ let traits: &[(&str, &[&str])] = &[];
+
+ for node in &mut ast.nodes {
+ for (name, methods) in traits {
+ extract_struct_trait(kinds, node, name, methods);
+ }
+ }
+}
+
+fn extract_struct_trait(
+ kinds: &KindsSrc,
+ node: &mut AstNodeSrc,
+ trait_name: &str,
+ methods: &[&str],
+) {
+ let mut to_remove = Vec::new();
+ for (i, field) in node.fields.iter().enumerate() {
+ let method_name = field.method_name(kinds).to_string();
+ if methods.iter().any(|&it| it == method_name) {
+ to_remove.push(i);
+ }
+ }
+ if to_remove.len() == methods.len() {
+ node.traits.push(trait_name.to_string());
+ node.remove_field(to_remove);
+ }
+}
+
+fn extract_enum_traits(ast: &mut AstSrc) {
+ let enums = ast.enums.clone();
+ for enm in &mut ast.enums {
+ if enm.name == "Stmt" {
+ continue;
+ }
+ let nodes = &ast.nodes;
+
+ let mut variant_traits = enm.variants.iter().map(|var| {
+ nodes
+ .iter()
+ .find_map(|node| {
+ if &node.name != var {
+ return None;
+ }
+ Some(node.traits.iter().cloned().collect::<BTreeSet<_>>())
+ })
+ .unwrap_or_else(|| {
+ enums
+ .iter()
+ .find_map(|node| {
+ if &node.name != var {
+ return None;
+ }
+ Some(node.traits.iter().cloned().collect::<BTreeSet<_>>())
+ })
+ .unwrap_or_else(|| {
+ panic!("{}", {
+ &format!(
+ "Could not find a struct `{}` for enum `{}::{}`",
+ var, enm.name, var
+ )
+ })
+ })
+ })
+ });
+
+ let mut enum_traits = match variant_traits.next() {
+ Some(it) => it,
+ None => continue,
+ };
+ for traits in variant_traits {
+ enum_traits = enum_traits.intersection(&traits).cloned().collect();
+ }
+ enm.traits = enum_traits.into_iter().collect();
+ }
+}
+
+pub fn escape_token_macro(token: &str) -> TokenStream {
+ if "{}[]()$".contains(token) {
+ let c = token.chars().next().unwrap();
+ quote! { #c }
+ } else if token.contains('$') {
+ quote! { #token }
+ } else {
+ let cs = token.chars().map(|c| Punct::new(c, Spacing::Joint));
+ quote! { #(#cs)* }
+ }
+}
xtask/src/sourcegen/util.rsdiffbeforeafterboth--- /dev/null
+++ b/xtask/src/sourcegen/util.rs
@@ -0,0 +1,92 @@
+use std::{fs, path::Path};
+
+use anyhow::{bail, Result};
+use xshell::{cmd, Shell};
+
+/// Checks that the `file` has the specified `contents`. If that is not the
+/// case, updates the file and then fails the test.
+pub fn ensure_file_contents(file: &Path, contents: &str) -> Result<()> {
+ if let Ok(old_contents) = fs::read_to_string(file) {
+ if normalize_newlines(&old_contents) == normalize_newlines(contents) {
+ // File is already up to date.
+ return Ok(());
+ }
+ }
+
+ eprintln!(" {} was not up-to-date, updating\n", file.display());
+ if std::env::var("CI").is_ok() {
+ eprintln!("NOTE: run `cargo test` locally and commit the updated files\n");
+ }
+ if let Some(parent) = file.parent() {
+ let _ = fs::create_dir_all(parent);
+ }
+ fs::write(file, contents).unwrap();
+ bail!("some file was not up to date and has been updated, simply re-run the tests");
+}
+
+// Eww, someone configured git to use crlf?
+fn normalize_newlines(s: &str) -> String {
+ s.replace("\r\n", "\n")
+}
+
+pub(crate) fn pluralize(s: &str) -> String {
+ format!("{}s", s)
+}
+
+pub fn to_upper_snake_case(s: &str) -> String {
+ let mut buf = String::with_capacity(s.len());
+ let mut prev = false;
+ for c in s.chars() {
+ if c.is_ascii_uppercase() && prev {
+ buf.push('_')
+ }
+ prev = true;
+
+ buf.push(c.to_ascii_uppercase());
+ }
+ buf
+}
+pub fn to_lower_snake_case(s: &str) -> String {
+ let mut buf = String::with_capacity(s.len());
+ let mut prev = false;
+ for c in s.chars() {
+ if c.is_ascii_uppercase() && prev {
+ buf.push('_')
+ }
+ prev = true;
+
+ buf.push(c.to_ascii_lowercase());
+ }
+ buf
+}
+
+pub fn to_pascal_case(s: &str) -> String {
+ let mut buf = String::with_capacity(s.len());
+ let mut prev_is_underscore = true;
+ for c in s.chars() {
+ if c == '_' {
+ prev_is_underscore = true;
+ } else if prev_is_underscore {
+ buf.push(c.to_ascii_uppercase());
+ prev_is_underscore = false;
+ } else {
+ buf.push(c.to_ascii_lowercase());
+ }
+ }
+ buf
+}
+
+pub fn reformat(text: &str) -> Result<String> {
+ // let _e = pushenv("RUSTUP_TOOLCHAIN", "stable");
+ // rustfmt()?;
+ let sh = Shell::new()?;
+ let stdout = cmd!(sh, "rustfmt --config fn_single_line=true")
+ .stdin(text)
+ .read()?;
+ Ok(format!(
+ "{}\n\n{}\n",
+ "//! This is a generated file, please do not edit manually. Changes can be
+//! made in codegeneration that lives in `xtask` top-level dir.",
+ stdout
+ ))
+}