From c678cf8e698f77d783e9af126c9ca2d23f7543db Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Fri, 17 Jun 2022 21:20:39 +0000 Subject: [PATCH] refactor: introduce ungrammar --- --- /dev/null +++ b/.cargo/config @@ -0,0 +1,2 @@ +[alias] +xtask = "run --manifest-path ./xtask/Cargo.toml --" --- 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" --- 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" --- /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 + )? --- /dev/null +++ b/crates/jrsonnet-rowan-parser/src/ast.rs @@ -0,0 +1 @@ +pub trait AstToken {} --- 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) { --- /dev/null +++ b/crates/jrsonnet-rowan-parser/src/generated/mod.rs @@ -0,0 +1,3 @@ +// mod tokens; +// mod nodes; +pub mod syntax_kinds; --- /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 { support::child(&self.syntax) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ExprBinary { + pub(crate) syntax: SyntaxNode, +} +impl ExprBinary { + pub fn lhs(&self) -> Option { support::child(&self.syntax) } + pub fn binary_operator(&self) -> Option { support::child(&self.syntax) } + pub fn rhs(&self) -> Option { 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 { support::token(&self.syntax, T![||]) } + pub fn and_token(&self) -> Option { support::token(&self.syntax, T![&&]) } + pub fn bit_or_token(&self) -> Option { support::token(&self.syntax, T![|]) } + pub fn bit_xor_token(&self) -> Option { support::token(&self.syntax, T![^]) } + pub fn bit_and_token(&self) -> Option { support::token(&self.syntax, T![&]) } + pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![==]) } + pub fn ne_token(&self) -> Option { support::token(&self.syntax, T![!=]) } + pub fn lt_token(&self) -> Option { support::token(&self.syntax, T![<]) } + pub fn gt_token(&self) -> Option { support::token(&self.syntax, T![>]) } + pub fn le_token(&self) -> Option { support::token(&self.syntax, T![<=]) } + pub fn ge_token(&self) -> Option { support::token(&self.syntax, T![>=]) } + pub fn in_token(&self) -> Option { support::token(&self.syntax, T![in]) } + pub fn lhs_token(&self) -> Option { support::token(&self.syntax, T![<<]) } + pub fn rhs_token(&self) -> Option { support::token(&self.syntax, T![>>]) } + pub fn plus_token(&self) -> Option { support::token(&self.syntax, T![+]) } + pub fn minus_token(&self) -> Option { support::token(&self.syntax, T![-]) } + pub fn mul_token(&self) -> Option { support::token(&self.syntax, T![*]) } + pub fn div_token(&self) -> Option { support::token(&self.syntax, T![/]) } + pub fn modulo_token(&self) -> Option { 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 { support::child(&self.syntax) } + pub fn rhs(&self) -> Option { 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 { support::token(&self.syntax, T![-]) } + pub fn not_token(&self) -> Option { support::token(&self.syntax, T![!]) } + pub fn bit_not_token(&self) -> Option { 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 { support::child(&self.syntax) } + pub fn l_brack_token(&self) -> Option { support::token(&self.syntax, T!['[']) } + pub fn slice_desc(&self) -> Option { support::child(&self.syntax) } + pub fn r_brack_token(&self) -> Option { 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 { support::child(&self.syntax) } + pub fn colon_token(&self) -> Option { support::token(&self.syntax, T![:]) } + pub fn end(&self) -> Option { support::child(&self.syntax) } + pub fn step(&self) -> Option { support::child(&self.syntax) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ExprIndex { + pub(crate) syntax: SyntaxNode, +} +impl ExprIndex { + pub fn expr(&self) -> Option { support::child(&self.syntax) } + pub fn dot_token(&self) -> Option { support::token(&self.syntax, T![.]) } + pub fn index(&self) -> Option { 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 { 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 { support::child(&self.syntax) } + pub fn l_brack_token(&self) -> Option { support::token(&self.syntax, T!['[']) } + pub fn index(&self) -> Option { support::child(&self.syntax) } + pub fn r_brack_token(&self) -> Option { 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 { support::child(&self.syntax) } + pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } + pub fn args_desc(&self) -> Option { support::child(&self.syntax) } + pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } + pub fn tailstrict_token(&self) -> Option { + 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 { support::children(&self.syntax) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ExprObjExtend { + pub(crate) syntax: SyntaxNode, +} +impl ExprObjExtend { + pub fn expr(&self) -> Option { support::child(&self.syntax) } + pub fn l_brace_token(&self) -> Option { support::token(&self.syntax, T!['{']) } + pub fn obj_body(&self) -> Option { support::child(&self.syntax) } + pub fn r_brace_token(&self) -> Option { 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 { support::token(&self.syntax, T!['(']) } + pub fn expr(&self) -> Option { support::child(&self.syntax) } + pub fn r_paren_token(&self) -> Option { 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 { 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 { support::token(&self.syntax, T![null]) } + pub fn true_token(&self) -> Option { support::token(&self.syntax, T![true]) } + pub fn false_token(&self) -> Option { support::token(&self.syntax, T![false]) } + pub fn self_token(&self) -> Option { support::token(&self.syntax, T![self]) } + pub fn dollar_token(&self) -> Option { support::token(&self.syntax, T!['$']) } + pub fn super_token(&self) -> Option { 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 { + 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 { + 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 { + support::token(&self.syntax, T!["$intrinsic"]) + } + pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } + pub fn name(&self) -> Option { support::child(&self.syntax) } + pub fn r_paren_token(&self) -> Option { 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 { 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 { + support::token(&self.syntax, T![string_double]) + } + pub fn string_single_token(&self) -> Option { + support::token(&self.syntax, T![string_single]) + } + pub fn string_double_verbatim_token(&self) -> Option { + support::token(&self.syntax, T![string_double_verbatim]) + } + pub fn string_single_verbatim_token(&self) -> Option { + support::token(&self.syntax, T![string_single_verbatim]) + } + pub fn string_block_token(&self) -> Option { + 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 { 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 { 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 { support::token(&self.syntax, T!['[']) } + pub fn exprs(&self) -> AstChildren { support::children(&self.syntax) } + pub fn r_brack_token(&self) -> Option { 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 { support::token(&self.syntax, T!['{']) } + pub fn obj_body(&self) -> Option { support::child(&self.syntax) } + pub fn r_brace_token(&self) -> Option { 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 { support::token(&self.syntax, T!['[']) } + pub fn expr(&self) -> Option { support::child(&self.syntax) } + pub fn comma_token(&self) -> Option { support::token(&self.syntax, T![,]) } + pub fn for_spec(&self) -> Option { support::child(&self.syntax) } + pub fn comp_specs(&self) -> AstChildren { support::children(&self.syntax) } + pub fn r_brack_token(&self) -> Option { 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 { support::token(&self.syntax, T![for]) } + pub fn bind(&self) -> Option { support::child(&self.syntax) } + pub fn in_token(&self) -> Option { support::token(&self.syntax, T![in]) } + pub fn expr(&self) -> Option { 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 { + support::token(&self.syntax, T![importstr]) + } + pub fn string(&self) -> Option { support::child(&self.syntax) } + pub fn importbin_token(&self) -> Option { + support::token(&self.syntax, T![importbin]) + } + pub fn import_token(&self) -> Option { 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 { 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 { support::token(&self.syntax, T![local]) } + pub fn binds(&self) -> AstChildren { support::children(&self.syntax) } + pub fn semi_token(&self) -> Option { 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 { support::token(&self.syntax, T![if]) } + pub fn cond(&self) -> Option { support::child(&self.syntax) } + pub fn then_token(&self) -> Option { support::token(&self.syntax, T![then]) } + pub fn then(&self) -> Option { support::child(&self.syntax) } + pub fn else_token(&self) -> Option { support::token(&self.syntax, T![else]) } + pub fn else_(&self) -> Option { 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 { + support::token(&self.syntax, T![function]) + } + pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } + pub fn params_desc(&self) -> Option { support::child(&self.syntax) } + pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } + pub fn expr(&self) -> Option { support::child(&self.syntax) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ParamsDesc { + pub(crate) syntax: SyntaxNode, +} +impl ParamsDesc { + pub fn params(&self) -> AstChildren { support::children(&self.syntax) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ExprAssert { + pub(crate) syntax: SyntaxNode, +} +impl ExprAssert { + pub fn assertion(&self) -> Option { support::child(&self.syntax) } + pub fn semi_token(&self) -> Option { support::token(&self.syntax, T![;]) } + pub fn expr(&self) -> Option { 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 { support::token(&self.syntax, T![assert]) } + pub fn condition(&self) -> Option { support::child(&self.syntax) } + pub fn colon_token(&self) -> Option { support::token(&self.syntax, T![:]) } + pub fn expr(&self) -> Option { 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 { support::token(&self.syntax, T![error]) } + pub fn expr(&self) -> Option { support::child(&self.syntax) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Arg { + pub(crate) syntax: SyntaxNode, +} +impl Arg { + pub fn name(&self) -> Option { support::child(&self.syntax) } + pub fn assign_token(&self) -> Option { support::token(&self.syntax, T![=]) } + pub fn expr(&self) -> Option { support::child(&self.syntax) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ObjBodyComp { + pub(crate) syntax: SyntaxNode, +} +impl ObjBodyComp { + pub fn pre(&self) -> AstChildren { support::children(&self.syntax) } + pub fn l_brack_token(&self) -> Option { support::token(&self.syntax, T!['[']) } + pub fn key(&self) -> Option { support::child(&self.syntax) } + pub fn r_brack_token(&self) -> Option { support::token(&self.syntax, T![']']) } + pub fn plus_token(&self) -> Option { support::token(&self.syntax, T![+]) } + pub fn colon_token(&self) -> Option { support::token(&self.syntax, T![:]) } + pub fn value(&self) -> Option { support::child(&self.syntax) } + pub fn post(&self) -> AstChildren { support::children(&self.syntax) } + pub fn for_spec(&self) -> Option { support::child(&self.syntax) } + pub fn comp_specs(&self) -> AstChildren { 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 { support::child(&self.syntax) } + pub fn comma_token(&self) -> Option { 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 { support::token(&self.syntax, T![,]) } + pub fn obj_local(&self) -> Option { support::child(&self.syntax) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ObjBodyMemberList { + pub(crate) syntax: SyntaxNode, +} +impl ObjBodyMemberList { + pub fn member(&self) -> Option { support::child(&self.syntax) } + pub fn comma_token(&self) -> Option { 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 { support::token(&self.syntax, T![local]) } + pub fn bind(&self) -> Option { 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 { support::child(&self.syntax) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct MemberAssertStmt { + pub(crate) syntax: SyntaxNode, +} +impl MemberAssertStmt { + pub fn assertion(&self) -> Option { support::child(&self.syntax) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct MemberField { + pub(crate) syntax: SyntaxNode, +} +impl MemberField { + pub fn field(&self) -> Option { 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 { support::child(&self.syntax) } + pub fn plus_token(&self) -> Option { support::token(&self.syntax, T![+]) } + pub fn visibility(&self) -> Option { support::child(&self.syntax) } + pub fn expr(&self) -> Option { 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 { + support::token(&self.syntax, T![:::]) + } + pub fn coloncolon_token(&self) -> Option { support::token(&self.syntax, T![::]) } + pub fn colon_token(&self) -> Option { 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 { support::child(&self.syntax) } + pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } + pub fn params_desc(&self) -> Option { support::child(&self.syntax) } + pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } + pub fn visibility(&self) -> Option { support::child(&self.syntax) } + pub fn expr(&self) -> Option { support::child(&self.syntax) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct FieldNameFixed { + pub(crate) syntax: SyntaxNode, +} +impl FieldNameFixed { + pub fn id(&self) -> Option { support::child(&self.syntax) } + pub fn string(&self) -> Option { 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 { support::token(&self.syntax, T!['[']) } + pub fn expr(&self) -> Option { support::child(&self.syntax) } + pub fn r_brack_token(&self) -> Option { 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 { support::token(&self.syntax, T![if]) } + pub fn expr(&self) -> Option { support::child(&self.syntax) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct BindDestruct { + pub(crate) syntax: SyntaxNode, +} +impl BindDestruct { + pub fn into(&self) -> Option { support::child(&self.syntax) } + pub fn assign_token(&self) -> Option { support::token(&self.syntax, T![=]) } + pub fn value(&self) -> Option { 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 { support::child(&self.syntax) } + pub fn destruct_skip(&self) -> Option { support::child(&self.syntax) } + pub fn destruct_array(&self) -> Option { support::child(&self.syntax) } + pub fn destruct_object(&self) -> Option { support::child(&self.syntax) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct BindFunction { + pub(crate) syntax: SyntaxNode, +} +impl BindFunction { + pub fn name(&self) -> Option { support::child(&self.syntax) } + pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } + pub fn params(&self) -> Option { support::child(&self.syntax) } + pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } + pub fn assign_token(&self) -> Option { support::token(&self.syntax, T![=]) } + pub fn value(&self) -> Option { support::child(&self.syntax) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Param { + pub(crate) syntax: SyntaxNode, +} +impl Param { + pub fn destruct(&self) -> Option { support::child(&self.syntax) } + pub fn assign_token(&self) -> Option { support::token(&self.syntax, T![=]) } + pub fn expr(&self) -> Option { support::child(&self.syntax) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct DestructFull { + pub(crate) syntax: SyntaxNode, +} +impl DestructFull { + pub fn into(&self) -> Option { 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 { 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 { support::token(&self.syntax, T!['[']) } + pub fn start(&self) -> AstChildren { support::children(&self.syntax) } + pub fn destruct_rest(&self) -> Option { support::child(&self.syntax) } + pub fn comma_token(&self) -> Option { support::token(&self.syntax, T![,]) } + pub fn end(&self) -> AstChildren { support::children(&self.syntax) } + pub fn r_brack_token(&self) -> Option { 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 { support::token(&self.syntax, T![...]) } + pub fn into(&self) -> Option { 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 { support::token(&self.syntax, T!['{']) } + pub fn destruct_object_fields(&self) -> AstChildren { + support::children(&self.syntax) + } + pub fn destruct_rest(&self) -> Option { support::child(&self.syntax) } + pub fn comma_token(&self) -> Option { support::token(&self.syntax, T![,]) } + pub fn r_brace_token(&self) -> Option { 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 { support::child(&self.syntax) } + pub fn colon_token(&self) -> Option { support::token(&self.syntax, T![:]) } + pub fn destruct(&self) -> Option { support::child(&self.syntax) } + pub fn assign_token(&self) -> Option { support::token(&self.syntax, T![=]) } + pub fn expr(&self) -> Option { 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl From for Expr { + fn from(node: ExprBinary) -> Expr { Expr::ExprBinary(node) } +} +impl From for Expr { + fn from(node: ExprUnary) -> Expr { Expr::ExprUnary(node) } +} +impl From for Expr { + fn from(node: ExprSlice) -> Expr { Expr::ExprSlice(node) } +} +impl From for Expr { + fn from(node: ExprIndex) -> Expr { Expr::ExprIndex(node) } +} +impl From for Expr { + fn from(node: ExprIndexExpr) -> Expr { Expr::ExprIndexExpr(node) } +} +impl From for Expr { + fn from(node: ExprApply) -> Expr { Expr::ExprApply(node) } +} +impl From for Expr { + fn from(node: ExprObjExtend) -> Expr { Expr::ExprObjExtend(node) } +} +impl From for Expr { + fn from(node: ExprParened) -> Expr { Expr::ExprParened(node) } +} +impl From for Expr { + fn from(node: ExprIntrinsicThisFile) -> Expr { Expr::ExprIntrinsicThisFile(node) } +} +impl From for Expr { + fn from(node: ExprIntrinsicId) -> Expr { Expr::ExprIntrinsicId(node) } +} +impl From for Expr { + fn from(node: ExprIntrinsic) -> Expr { Expr::ExprIntrinsic(node) } +} +impl From for Expr { + fn from(node: ExprString) -> Expr { Expr::ExprString(node) } +} +impl From for Expr { + fn from(node: ExprNumber) -> Expr { Expr::ExprNumber(node) } +} +impl From for Expr { + fn from(node: ExprArray) -> Expr { Expr::ExprArray(node) } +} +impl From for Expr { + fn from(node: ExprObject) -> Expr { Expr::ExprObject(node) } +} +impl From for Expr { + fn from(node: ExprArrayComp) -> Expr { Expr::ExprArrayComp(node) } +} +impl From for Expr { + fn from(node: ExprImport) -> Expr { Expr::ExprImport(node) } +} +impl From for Expr { + fn from(node: ExprVar) -> Expr { Expr::ExprVar(node) } +} +impl From for Expr { + fn from(node: ExprLocal) -> Expr { Expr::ExprLocal(node) } +} +impl From for Expr { + fn from(node: ExprIfThenElse) -> Expr { Expr::ExprIfThenElse(node) } +} +impl From for Expr { + fn from(node: ExprFunction) -> Expr { Expr::ExprFunction(node) } +} +impl From for Expr { + fn from(node: ExprAssert) -> Expr { Expr::ExprAssert(node) } +} +impl From 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 { + 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 for ObjBody { + fn from(node: ObjBodyComp) -> ObjBody { ObjBody::ObjBodyComp(node) } +} +impl From 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 { + 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 for CompSpec { + fn from(node: ForSpec) -> CompSpec { CompSpec::ForSpec(node) } +} +impl From 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 { + 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 for Bind { + fn from(node: BindDestruct) -> Bind { Bind::BindDestruct(node) } +} +impl From 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 { + 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 for Member { + fn from(node: MemberBindStmt) -> Member { Member::MemberBindStmt(node) } +} +impl From for Member { + fn from(node: MemberAssertStmt) -> Member { Member::MemberAssertStmt(node) } +} +impl From 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 { + 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 for Field { + fn from(node: FieldNormal) -> Field { Field::FieldNormal(node) } +} +impl From 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 { + 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 for FieldName { + fn from(node: FieldNameFixed) -> FieldName { FieldName::FieldNameFixed(node) } +} +impl From 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 { + 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) + } +} --- /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 { + 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 { + 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; --- /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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxToken { &self.syntax } +} --- /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; +pub type SyntaxToken = rowan::SyntaxToken; +pub type SyntaxElement = rowan::SyntaxElement; +pub type SyntaxNodeChildren = rowan::SyntaxNodeChildren; +pub type SyntaxElementChildren = rowan::SyntaxElementChildren; +pub type PreorderWithTokens = rowan::api::PreorderWithTokens; --- 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> { Lexer::new(input).collect() -} - -impl From 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::(raw.0) } - } - fn kind_to_raw(kind: Self::Kind) -> rowan::SyntaxKind { - kind.into() - } } --- 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, - } - impl Diagnostic for MyDiagnostic { - fn code<'a>(&'a self) -> Option> { - None - } - - fn severity(&self) -> Option { - None - } - - fn help<'a>(&'a self) -> Option> { - None - } - - fn url<'a>(&'a self) -> Option> { - None - } - - fn source_code(&self) -> Option<&dyn miette::SourceCode> { - Some(&self.code) - } - - fn labels(&self) -> Option + '_>> { - Some(Box::new(self.spans.clone().into_iter())) - } - - fn related<'a>(&'a self) -> Option + '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, +}; --- 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, --- a/crates/jrsonnet-rowan-parser/src/parser.rs +++ b/crates/jrsonnet-rowan-parser/src/parser.rs @@ -1,32 +1,19 @@ -use std::cell::Cell; -use std::fmt::Display; -use std::rc::Rc; +use std::{cell::Cell, fmt::Display, rc::Rc}; -use miette::Diagnostic; -use miette::LabeledSpan; -use miette::SourceOffset; -use miette::SourceSpan; -use rowan::GreenNode; +use miette::{LabeledSpan, SourceOffset, SourceSpan}; +use rowan::{GreenNode, TextRange, TextSize}; -use rowan::TextRange; -use rowan::TextSize; -use thiserror::Error; - -use crate::binary::BinaryOperator; -use crate::event::Event; -use crate::event::Sink; -use crate::lex::lex; -use crate::lex::Lang; -use crate::lex::Lexeme; -use crate::lex::SyntaxKind; -use crate::lex::SyntaxKind::*; -use crate::marker::AsRange; -use crate::marker::CompletedMarker; -use crate::marker::FinishedRanger; -use crate::marker::Marker; -use crate::marker::Ranger; -use crate::token_set::TokenSet; -use crate::unary::UnaryOperator; +use crate::{ + binary::BinaryOperator, + event::{Event, Sink}, + lex::{lex, Lexeme}, + marker::{AsRange, CompletedMarker, Marker, Ranger}, + token_set::SyntaxKindSet, + unary::UnaryOperator, + SyntaxKind, + SyntaxKind::*, + SyntaxNode, T, TS, +}; pub struct Parse { pub green_node: GreenNode, @@ -58,13 +45,7 @@ expected_syntax_tracking_state: Rc>, } -const DEFAULT_RECOVERY_SET: TokenSet = TokenSet::new(&[ - SymbolSemi, - RParen, - SymbolRightBracket, - SymbolRightBrace, - KeywordLocal, -]); +const DEFAULT_RECOVERY_SET: SyntaxKindSet = TS![; ')' ']' '}' local]; #[derive(Clone, Debug, PartialEq, Eq)] pub enum SyntaxError { @@ -172,16 +153,20 @@ let end = ranger.finish(&self); self.custom_error(end, "unexpected input after expression"); } - m.complete(&mut self, Root); + m.complete(&mut self, SOURCE_FILE); self.events } pub(crate) fn expect(&mut self, kind: SyntaxKind) { - self.expect_with_recovery_set(kind, TokenSet::default()) + self.expect_with_recovery_set(kind, TS![]) } - pub(crate) fn expect_with_recovery_set(&mut self, kind: SyntaxKind, recovery_set: TokenSet) { + pub(crate) fn expect_with_recovery_set( + &mut self, + kind: SyntaxKind, + recovery_set: SyntaxKindSet, + ) { if self.at(kind) { self.bump(); } else { @@ -239,17 +224,17 @@ } pub(crate) fn error_with_recovery_set( &mut self, - recovery_set: TokenSet, + recovery_set: SyntaxKindSet, ) -> Option { self.error_with_recovery_set_no_default(recovery_set.union(DEFAULT_RECOVERY_SET)) } pub fn error_with_no_skip(&mut self) -> Option { - self.error_with_recovery_set_no_default(TokenSet::ALL) + self.error_with_recovery_set_no_default(SyntaxKindSet::ALL) } pub fn error_with_recovery_set_no_default( &mut self, - recovery_set: TokenSet, + recovery_set: SyntaxKindSet, ) -> Option { let expected_syntax = self.expected_syntax.take().unwrap(); self.expected_syntax_tracking_state @@ -280,7 +265,7 @@ let m = self.start(); self.bump(); - Some(m.complete(self, SyntaxKind::Error)) + Some(m.complete(self, SyntaxKind::ERROR)) } fn bump(&mut self) { @@ -323,7 +308,7 @@ } self.peek() == Some(kind) } - pub fn at_set(&mut self, set: TokenSet) -> bool { + pub fn at_set(&mut self, set: SyntaxKindSet) -> bool { self.peek().map_or(false, |k| set.contains(k)) } pub fn at_end(&mut self) -> bool { @@ -356,7 +341,7 @@ } macro_rules! at_match { ($p:ident { - $($r:ident => $e:expr,)* + $($r:expr => $e:expr,)* _ => $else:expr $(,)? }) => {{ $( @@ -375,26 +360,26 @@ loop { let op = at_match!(p { - OpMul => BinaryOperator::Mul, - OpDiv => BinaryOperator::Div, - OpMod => BinaryOperator::Mod, - OpPlus => BinaryOperator::Plus, - OpMinus => BinaryOperator::Minus, - OpShiftLeft => BinaryOperator::ShiftLeft, - OpShiftRight => BinaryOperator::ShiftRight, - OpLessThan => BinaryOperator::LessThan, - OpGreaterThan => BinaryOperator::GreaterThan, - OpLessThanOrEqual => BinaryOperator::LessThanOrEqual, - OpGreaterThanOrEqual => BinaryOperator::GreaterThanOrEqual, - OpEqual => BinaryOperator::Equal, - OpNotEqual => BinaryOperator::NotEqual, - OpBitAnd => BinaryOperator::BitAnd, - OpBitXor => BinaryOperator::BitXor, - OpBitOr => BinaryOperator::BitOr, - OpAnd => BinaryOperator::And, - OpOr => BinaryOperator::Or, - OpIn => BinaryOperator::In, - SymbolLeftBrace => BinaryOperator::ObjectApply, + T![*] => BinaryOperator::Mul, + T![/] => BinaryOperator::Div, + T![%] => BinaryOperator::Mod, + T![+] => BinaryOperator::Plus, + T![-] => BinaryOperator::Minus, + T![<<] => BinaryOperator::ShiftLeft, + T![>>] => BinaryOperator::ShiftRight, + T![<] => BinaryOperator::LessThan, + T![>] => BinaryOperator::GreaterThan, + T![<=] => BinaryOperator::LessThanOrEqual, + T![>=] => BinaryOperator::GreaterThanOrEqual, + T![==] => BinaryOperator::Equal, + T![!=] => BinaryOperator::NotEqual, + T![&] => BinaryOperator::BitAnd, + T![^] => BinaryOperator::BitXor, + T![|] => BinaryOperator::BitOr, + T![&&] => BinaryOperator::And, + T![||] => BinaryOperator::Or, + T![in] => BinaryOperator::In, + T!['{'] => BinaryOperator::ObjectApply, _ => break, }); let (left_binding_power, right_binding_power) = op.binding_power(); @@ -412,9 +397,9 @@ lhs = m.complete( p, if op == BinaryOperator::ObjectApply { - ObjectApply + EXPR_OBJ_EXTEND } else { - BinOp + EXPR_BINARY }, ); @@ -425,37 +410,37 @@ Some(lhs) } fn compspec(p: &mut Parser) { - assert!(p.at(KeywordFor) || p.at(KeywordIf)); - if p.at(KeywordFor) { + assert!(p.at(T![for]) || p.at(T![if])); + if p.at(T![for]) { let m = p.start(); p.bump(); - p.expect(Ident); - p.expect(OpIn); + p.expect(IDENT); + p.expect(T![in]); expr(p); - m.complete(p, CompspecFor); - } else if p.at(KeywordIf) { + m.complete(p, FOR_SPEC); + } else if p.at(T![in]) { let m = p.start(); p.bump(); expr(p); - m.complete(p, CompspecIf); + m.complete(p, IF_SPEC); } else { unreachable!() } } fn comma(p: &mut Parser) -> bool { - if p.at(SymbolComma) { + if p.at(T![,]) { p.bump(); true } else { false } } -fn comma_with_alternatives(p: &mut Parser, set: TokenSet) -> bool { - if p.at(SymbolComma) { +fn comma_with_alternatives(p: &mut Parser, set: SyntaxKindSet) -> bool { + if p.at(T![,]) { p.bump(); true } else if p.at_set(set) { - p.expect_with_no_skip(SymbolComma); + p.expect_with_no_skip(T![,]); p.bump(); true } else { @@ -464,94 +449,94 @@ } fn field_name(p: &mut Parser) { let _e = p.expected_syntax_name("field name"); - if p.at(SymbolLeftBracket) { + if p.at(T!['[']) { p.bump(); expr(p); - p.expect(SymbolRightBracket); - } else if p.at(Ident) { + p.expect(T![']']); + } else if p.at(IDENT) { p.bump() } else { - p.error_with_recovery_set(TokenSet::new(&[SymbolSemi])); + p.error_with_recovery_set(TS![;]); } } fn object(p: &mut Parser) -> CompletedMarker { - assert!(p.at(SymbolLeftBrace)); + assert!(p.at(T!['{'])); let m = p.start(); p.bump(); loop { - if p.at(SymbolRightBrace) { + if p.at(T!['}']) { p.bump(); break; } let m = p.start(); field_name(p); - p.expect(SymbolColon); + p.expect(T![,]); expr(p); - while p.at(KeywordFor) || p.at(KeywordIf) { + while p.at(T![for]) || p.at(T![if]) { compspec(p) } - m.complete(p, Field); - if comma_with_alternatives(p, TokenSet::new(&[SymbolAssign])) { + m.complete(p, MEMBER); + if comma_with_alternatives(p, SyntaxKindSet::new(&[T![=]])) { continue; } - p.expect(SymbolRightBrace); + p.expect(R_BRACE); break; } - m.complete(p, Object) + m.complete(p, OBJ_BODY) } fn params(p: &mut Parser) -> CompletedMarker { - assert!(p.at(LParen)); + assert!(p.at(T!['('])); let m = p.start(); p.bump(); loop { - if p.at(RParen) { + if p.at(T![')']) { p.bump(); break; } let m = p.start(); - p.expect(Ident); - if p.at(SymbolAssign) { + p.expect(IDENT); + if p.at(T![=]) { p.bump(); expr(p); } - m.complete(p, DefParam); + m.complete(p, PARAM); if comma(p) { continue; } - p.expect(RParen); + p.expect(T![')']); break; } - m.complete(p, DefParams) + m.complete(p, PARAMS_DESC) } fn args(p: &mut Parser) { - assert!(p.at(LParen)); + assert!(p.at(T!['('])); p.bump(); let mut error_positional_start = None::; let mut started_named = Cell::new(false); let mut on_positional = |p: &mut Parser, m: Marker| { - let c = m.complete(p, DefPositionalArg); + let c = m.complete(p, ARG); if started_named.get() && error_positional_start.is_none() { error_positional_start = Some(c.precede(p)); } }; loop { - if p.at(RParen) { + if p.at(T![')']) { break; } let m = p.start(); - if p.at(Ident) { + if p.at(IDENT) { p.bump(); - if p.at(SymbolAssign) { + if p.at(T![=]) { p.bump(); expr(p); - m.complete(p, DefNamedArg); + m.complete(p, ARG); started_named.set(true); } else { on_positional(p, m); @@ -566,14 +551,14 @@ break; } if let Some(error_positional_start) = error_positional_start { - let c = error_positional_start.complete(p, ErrorPositionalAfterNamed); + let c = error_positional_start.complete(p, ERROR); p.custom_error(c, "positional arguments can't be placed after named") } - p.expect(RParen); + p.expect(T![')']); } fn array(p: &mut Parser) -> CompletedMarker { - assert!(p.at(SymbolLeftBracket)); + assert!(p.at(T!['['])); // Start the list node let m = p.start(); p.bump(); // '[' @@ -583,31 +568,25 @@ let mut elems = 0; loop { - if p.at(SymbolRightBracket) { + if p.at(T![']']) { p.bump(); break; } elems += 1; - let m = p.start(); - { - let m = p.start(); - expr(p); - m.complete(p, BodyDef); - } + expr(p); let c = p.start_ranger(); let mut had_spec = false; - while p.at(KeywordFor) || p.at(KeywordIf) { + while p.at(T![for]) || p.at(T![if]) { had_spec = true; compspec(p) } if had_spec { compspecs.push(c.finish(p)); } - m.complete(p, ArrayElem); if comma(p) { continue; } - p.expect(SymbolRightBracket); + p.expect(T![']']); break; } @@ -618,47 +597,51 @@ "compspec may only be used if there is only one array element", ) } - } - m.complete(p, Array) + m.complete(p, EXPR_ARRAY) + } else if !compspecs.is_empty() { + m.complete(p, EXPR_ARRAY_COMP) + } else { + m.complete(p, EXPR_ARRAY) + } } fn lhs(p: &mut Parser) -> Option { let mut lhs = lhs_basic(p)?; loop { - if p.at(SymbolDot) { + if p.at(T![.]) { let m = lhs.precede(p); p.bump(); - p.expect(Ident); - lhs = m.complete(p, FieldAccess); - } else if p.at(SymbolLeftBracket) { + p.expect(IDENT); + lhs = m.complete(p, EXPR_INDEX); + } else if p.at(T!['[']) { let m = lhs.precede(p); p.bump(); // Start - if !p.at(SymbolColon) { + if !p.at(T![:]) { expr(p); } - if p.at(SymbolColon) { + if p.at(T![:]) { p.bump(); // End - if !p.at(SymbolRightBracket) && !p.at(SymbolColon) { + if !p.at(T![']']) && !p.at(T![:]) { expr(p); } - if p.at(SymbolColon) { + if p.at(T![:]) { p.bump(); // Step - if !p.at(SymbolRightBracket) { + if !p.at(T![']']) { expr(p); } } } - p.expect(SymbolRightBracket); - lhs = m.complete(p, Slice); - } else if p.at(LParen) { + p.expect(T![']']); + lhs = m.complete(p, EXPR_SLICE); + } else if p.at(T!['(']) { let m = lhs.precede(p); args(p); - lhs = m.complete(p, FunctionCall); + lhs = m.complete(p, EXPR_APPLY); } else { break; } @@ -669,128 +652,104 @@ fn lhs_basic(p: &mut Parser) -> Option { let _e = p.expected_syntax_name("value"); - Some( - if p.at(Number) - || p.at(StringSingleQuoted) - || p.at(StringDoubleQuoted) - || p.at(StringSingleVerbatim) - || p.at(StringDoubleVerbatim) - || p.at(StringBlock) - || p.at(KeywordNull) - || p.at(SymbolDollar) - || p.at(KeywordSuper) - || p.at(KeywordSelf) - { - let m = p.start(); - p.bump(); - m.complete(p, Literal) - } else if p.at(Ident) { - let m = p.start(); - p.bump(); - m.complete(p, Ident) - } else if p.at(SymbolLeftBracket) { - array(p) - } else if p.at(SymbolLeftBrace) { - object(p) - } else if p.at(KeywordLocal) { - let m = p.start(); - p.bump(); - let mut sus_local = None; - loop { - p.expect_with_recovery_set( - Ident, - TokenSet::new(&[SymbolAssign, SymbolSemi, KeywordLocal]), - ); - if p.at(LParen) { - params(p); - } + Some(if p.peek().map(|l| l.is_literal()).unwrap_or(false) { + let m = p.start(); + p.bump(); + m.complete(p, EXPR_LITERAL) + } else if p.peek().map(|l| l.is_string()).unwrap_or(false) { + let m = p.start(); + p.bump(); + m.complete(p, EXPR_STRING) + } else if p.peek().map(|l| l.is_number()).unwrap_or(false) { + let m = p.start(); + p.bump(); + m.complete(p, EXPR_NUMBER) + } else if p.at(IDENT) { + let m = p.start(); + p.bump(); + m.complete(p, EXPR_VAR) + } else if p.at(T!['[']) { + array(p) + } else if p.at(T!['{']) { + object(p) + } else if p.at(T![local]) { + let m = p.start(); + p.bump(); + let mut sus_local = None; + loop { + p.expect_with_recovery_set(IDENT, TS![= ; local]); + if p.at(T!['(']) { + params(p); + } - let sus_local_candidate = p.start_ranger(); - p.expect_with_recovery_set( - SymbolAssign, - TokenSet::new(&[SymbolSemi, KeywordLocal]), - ); + let sus_local_candidate = p.start_ranger(); + p.expect_with_recovery_set(T![=], TS![; local]); - sus_local = p.at(KeywordLocal).then(|| sus_local_candidate.finish(p)); - expr(p); + sus_local = p.at(T![local]).then(|| sus_local_candidate.finish(p)); + expr(p); - if !comma(p) { - break; - } - } - p.expect(SymbolSemi); - if let Some(sus_local) = sus_local { - if sus_local.had_error_since(p) { - p.custom_error(sus_local, "unusal local placement, missing ';' ?") - } - } - { - let m = p.start(); - expr(p); - m.complete(p, BodyDef); - } - m.complete(p, Local) - } else if p.at(KeywordFunction) { - let m = p.start(); - p.bump(); - args(p); - { - let m = p.start(); - expr(p); - m.complete(p, BodyDef); + if !comma(p) { + break; } - m.complete(p, FunctionDef) - } else if p.at(KeywordError) { - let m = p.start(); - p.bump(); - expr(p); - m.complete(p, ExprError) - } else if p.at(KeywordAssert) { - let m = p.start(); - p.bump(); - expr(p); - if p.at(SymbolColon) { - p.bump(); - expr(p); + } + p.expect(T![;]); + if let Some(sus_local) = sus_local { + if sus_local.had_error_since(p) { + p.custom_error(sus_local, "unusal local placement, missing ';' ?") } - m.complete(p, ExprAssert) - } else if p.at(KeywordImport) || p.at(KeywordImportStr) { - let m = p.start(); + } + expr(p); + m.complete(p, T![local]) + } else if p.at(T![function]) { + let m = p.start(); + p.bump(); + args(p); + expr(p); + m.complete(p, EXPR_FUNCTION) + } else if p.at(T![error]) { + let m = p.start(); + p.bump(); + expr(p); + m.complete(p, EXPR_ERROR) + } else if p.at(T![assert]) { + let m = p.start(); + p.bump(); + expr(p); + if p.at(T![:]) { p.bump(); expr(p); - m.complete(p, ExprImport) - } else if p.at(OpMinus) || p.at(OpNot) || p.at(OpBitNegate) { - let op = match p.peek().unwrap() { - OpMinus => UnaryOperator::Minus, - OpNot => UnaryOperator::Not, - OpBitNegate => UnaryOperator::BitNegate, - _ => unreachable!(), - }; - let ((), right_binding_power) = op.binding_power(); + } + m.complete(p, EXPR_ASSERT) + } else if p.at(T![import]) || p.at(T![importstr]) || p.at(T![importbin]) { + let m = p.start(); + p.bump(); + expr(p); + m.complete(p, EXPR_IMPORT) + } else if p.at(T![-]) || p.at(T![!]) || p.at(T![~]) { + let op = match p.peek().unwrap() { + T![-] => UnaryOperator::Minus, + T![!] => UnaryOperator::Not, + T![~] => UnaryOperator::BitNegate, + _ => unreachable!(), + }; + let ((), right_binding_power) = op.binding_power(); - let m = p.start(); - p.bump(); - expr_binding_power(p, right_binding_power); - m.complete(p, UnaryOp) - } else if p.at(LParen) { - let m = p.start(); - p.bump(); - expr(p); - assert!(p.at(RParen)); - p.bump(); - m.complete(p, Parened) - } else { - p.error_with_no_skip(); - return None; - }, - ) + let m = p.start(); + p.bump(); + expr_binding_power(p, right_binding_power); + m.complete(p, EXPR_UNARY) + } else if p.at(T!['(']) { + let m = p.start(); + p.bump(); + expr(p); + assert!(p.at(T![')'])); + p.bump(); + m.complete(p, EXPR_PARENED) + } else { + p.error_with_no_skip(); + return None; + }) } - -type SyntaxNode = rowan::SyntaxNode; -#[allow(unused)] -type SyntaxToken = rowan::SyntaxToken; -#[allow(unused)] -type SyntaxElement = rowan::NodeOrToken; impl Parse { pub fn syntax(&self) -> SyntaxNode { --- 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); --- /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, +} +impl Diagnostic for MyDiagnostic { + fn code<'a>(&'a self) -> Option> { + None + } + + fn severity(&self) -> Option { + None + } + + fn help<'a>(&'a self) -> Option> { + None + } + + fn url<'a>(&'a self) -> Option> { + None + } + + fn source_code(&self) -> Option<&dyn miette::SourceCode> { + Some(&self.code) + } + + fn labels(&self) -> Option + '_>> { + Some(Box::new(self.spans.clone().into_iter())) + } + + fn related<'a>(&'a self) -> Option + '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; + } + " +); --- 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] + ),* + ]) + }; +} --- /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" --- /dev/null +++ b/xtask/src/main.rs @@ -0,0 +1,7 @@ +use anyhow::Result; + +mod sourcegen; + +fn main() -> Result<()> { + sourcegen::generate_ungrammar() +} --- /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) { + to_remove.into_iter().rev().for_each(|idx| { + self.fields.remove(idx); + }); + } +} + +#[allow(dead_code)] +#[derive(Default, Debug)] +pub struct AstSrc { + pub tokens: Vec, + pub nodes: Vec, + pub enums: Vec, +} +#[derive(Debug)] +pub struct AstNodeSrc { + pub doc: Vec, + pub name: String, + pub traits: Vec, + pub fields: Vec, +} + +#[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, + pub name: String, + pub traits: Vec, + pub variants: Vec, +} + +impl Field { + pub fn is_many(&self) -> bool { + matches!( + self, + Field::Node { + cardinality: Cardinality::Many, + .. + } + ) + } + pub fn token_kind(&self) -> Option { + 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), + } + } +} --- /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 { + 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 { + 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 { + 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::>(); + let punctuation_enum = grammar + .punct + .iter() + .map(|(token, name)| { + let id = format_ident!("{}", name); + quote! { + #[token(#token)] + #id + } + }) + .collect::>(); + + 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::>(); + let all_keywords_enum = all_keywords_values + .iter() + .map(|s| { + let id = x(&**s); + quote! { + #[token(#s)] + #id + } + }) + .collect::>(); + + 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::>(); + + let nodes = grammar + .nodes + .iter() + .map(|name| format_ident!("{}", name)) + .collect::>(); + + 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 { + let kw = match ident { + #(#full_keywords_values => #full_keywords,)* + _ => return None, + }; + Some(kw) + } + + pub fn from_char(c: char) -> Option { + 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, + pub literals: Vec, + pub nodes: Vec, +} + +pub struct LiteralKind { + name: String, + regex: String, + lexer: Option, +} + +#[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 { + 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 { + 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 { + 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(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::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::>(); + + let mut res = AstSrc { + tokens, + ..Default::default() + }; + + let nodes = grammar.iter().collect::>(); + + 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> { + 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, 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, + 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::>()) + }) + .unwrap_or_else(|| { + enums + .iter() + .find_map(|node| { + if &node.name != var { + return None; + } + Some(node.traits.iter().cloned().collect::>()) + }) + .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)* } + } +} --- /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 { + // 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 + )) +} -- gitstuff