difftreelog
refactor(rowan-parser) remove intrinsic syntax
in: master
13 files changed
cmds/jrsonnet-fmt/src/children.rsdiffbeforeafterboth--- a/cmds/jrsonnet-fmt/src/children.rs
+++ b/cmds/jrsonnet-fmt/src/children.rs
@@ -3,13 +3,11 @@
use std::{fmt::Debug, mem};
use jrsonnet_rowan_parser::{
- nodes::{Trivia, TriviaKind},
- AstNode, AstToken, SyntaxElement,
- SyntaxKind::*,
- SyntaxNode, TS,
+ nodes::{CustomError, Trivia, TriviaKind},
+ AstNode, AstToken, SyntaxElement, SyntaxNode, TS,
};
-pub type ChildTrivia = Vec<Trivia>;
+pub type ChildTrivia = Vec<Result<Trivia, String>>;
/// Node should have no non-trivia tokens before element
pub fn trivia_before(node: SyntaxNode, end: Option<&SyntaxElement>) -> ChildTrivia {
@@ -20,12 +18,14 @@
}
if let Some(trivia) = item.as_token().cloned().and_then(Trivia::cast) {
- out.push(trivia);
+ out.push(Ok(trivia));
+ } else if CustomError::can_cast(item.kind()) {
+ out.push(Err(item.to_string()));
} else if end.is_none() {
break;
} else {
assert!(
- TS![, ;].contains(item.kind()) || item.kind() == ERROR,
+ TS![, ;].contains(item.kind()),
"silently eaten token: {:?}",
item.kind()
)
@@ -46,10 +46,12 @@
let mut out = Vec::new();
for item in iter {
if let Some(trivia) = item.as_token().cloned().and_then(Trivia::cast) {
- out.push(trivia);
+ out.push(Ok(trivia));
+ } else if CustomError::can_cast(item.kind()) {
+ out.push(Err(item.to_string()))
} else {
assert!(
- TS![, ;].contains(item.kind()) || item.kind() == ERROR,
+ TS![, ;].contains(item.kind()),
"silently eaten token: {:?}",
item.kind()
)
@@ -74,12 +76,14 @@
let mut out = Vec::new();
for item in iter.take_while(|i| Some(i) != end) {
if let Some(trivia) = item.as_token().cloned().and_then(Trivia::cast) {
- out.push(trivia);
+ out.push(Ok(trivia));
+ } else if CustomError::can_cast(item.kind()) {
+ out.push(Err(item.to_string()))
} else if loose {
break;
} else {
assert!(
- TS![, ;].contains(item.kind()) || item.kind() == ERROR,
+ TS![, ;].contains(item.kind()),
"silently eaten token: {:?}",
item.kind()
)
@@ -120,11 +124,16 @@
fn count_newlines_before(tt: &ChildTrivia) -> usize {
let mut nl_count = 0;
for t in tt {
- match t.kind() {
- TriviaKind::Whitespace => {
- nl_count += t.text().bytes().filter(|b| *b == b'\n').count();
+ match t {
+ Ok(t) => match t.kind() {
+ TriviaKind::Whitespace => {
+ nl_count += t.text().bytes().filter(|b| *b == b'\n').count();
+ }
+ _ => break,
+ },
+ Err(_) => {
+ nl_count += 1;
}
- _ => break,
}
}
nl_count
@@ -132,19 +141,22 @@
fn count_newlines_after(tt: &ChildTrivia) -> usize {
let mut nl_count = 0;
for t in tt.iter().rev() {
- match t.kind() {
- TriviaKind::Whitespace => {
- nl_count += t.text().bytes().filter(|b| *b == b'\n').count();
- }
- TriviaKind::SingleLineHashComment => {
- nl_count += 1;
- break;
- }
- TriviaKind::SingleLineSlashComment => {
- nl_count += 1;
- break;
- }
- _ => {}
+ match t {
+ Ok(t) => match t.kind() {
+ TriviaKind::Whitespace => {
+ nl_count += t.text().bytes().filter(|b| *b == b'\n').count();
+ }
+ TriviaKind::SingleLineHashComment => {
+ nl_count += 1;
+ break;
+ }
+ TriviaKind::SingleLineSlashComment => {
+ nl_count += 1;
+ break;
+ }
+ _ => {}
+ },
+ Err(_) => nl_count += 1,
}
}
nl_count
@@ -187,16 +199,18 @@
|| current_child.is_none()
|| trivia.text().contains('\n') && !is_single_line_comment
{
- next.push(trivia.clone());
+ next.push(Ok(trivia.clone()));
started_next = true;
} else {
let cur = current_child.as_mut().expect("checked not none");
- cur.inline_trivia.push(trivia);
+ cur.inline_trivia.push(Ok(trivia));
if is_single_line_comment {
started_next = true;
}
}
had_some = true;
+ } else if CustomError::can_cast(item.kind()) {
+ next.push(Err(item.to_string()))
} else if loose {
if had_some {
break;
@@ -204,7 +218,7 @@
started_next = true;
} else {
assert!(
- TS![, ;].contains(item.kind()) || item.kind() == ERROR,
+ TS![, ;].contains(item.kind()),
"silently eaten token: {:?}",
item.kind()
)
cmds/jrsonnet-fmt/src/comments.rsdiffbeforeafterboth--- a/cmds/jrsonnet-fmt/src/comments.rs
+++ b/cmds/jrsonnet-fmt/src/comments.rs
@@ -17,6 +17,24 @@
let mut pi = p!(new:);
for c in comments {
+ let Ok(c) = c else {
+ let mut text = c.as_ref().unwrap_err() as &str;
+ while !text.is_empty() {
+ let pos = text.find(|c| c == '\n' || c == '\t').unwrap_or(text.len());
+ let sliced = &text[..pos];
+ p!(pi: string(sliced.to_string()));
+ text = &text[pos..];
+ if! text.is_empty(){
+ match text.as_bytes()[0] {
+ b'\n' => p!(pi: nl),
+ b'\t' => p!(pi: tab),
+ _ => unreachable!()
+ }
+ text = &text[1..];
+ }
+ }
+ continue;
+ };
match c.kind() {
TriviaKind::Whitespace => {}
TriviaKind::MultiLineComment => {
@@ -37,7 +55,7 @@
let mut immediate_start = true;
let mut lines = text
.split('\n')
- .map(|l| l.trim_end())
+ .map(|l| l.trim_end().to_string())
.skip_while(|l| {
if l.is_empty() {
immediate_start = false;
@@ -51,7 +69,7 @@
lines.pop();
}
if lines.len() == 1 && !doc {
- p!(pi: str("/* ") str(lines[0].trim()) str(" */") nl)
+ p!(pi: str("/* ") string(lines[0].trim().to_string()) str(" */") nl)
} else if !lines.is_empty() {
fn common_ws_prefix<'a>(a: &'a str, b: &str) -> &'a str {
let offset = a
@@ -62,17 +80,18 @@
&a[..offset]
}
// First line is not empty, extract ws prefix of it
- let mut common_ws_padding = if immediate_start && lines.len() > 1 {
- common_ws_prefix(lines[1], lines[1])
+ let mut common_ws_padding = (if immediate_start && lines.len() > 1 {
+ common_ws_prefix(&lines[1], &lines[1])
} else {
- common_ws_prefix(lines[0], lines[0])
- };
+ common_ws_prefix(&lines[0], &lines[0])
+ })
+ .to_string();
for line in lines
.iter()
.skip(if immediate_start { 2 } else { 1 })
.filter(|l| !l.is_empty())
{
- common_ws_padding = common_ws_prefix(common_ws_padding, line);
+ common_ws_padding = common_ws_prefix(&common_ws_padding, line).to_string();
}
for line in lines
.iter_mut()
@@ -80,8 +99,9 @@
.filter(|l| !l.is_empty())
{
*line = line
- .strip_prefix(common_ws_padding)
- .expect("all non-empty lines start with this padding");
+ .strip_prefix(&common_ws_padding)
+ .expect("all non-empty lines start with this padding")
+ .to_string();
}
p!(pi: str("/*"));
@@ -105,9 +125,9 @@
} else {
p!(pi: tab);
}
- line = new_line;
+ line = new_line.to_string();
}
- p!(pi: str(line) nl)
+ p!(pi: string(line.to_string()) nl)
}
}
if doc {
@@ -136,7 +156,7 @@
if matches!(loc, CommentLocation::ItemInline) {
p!(pi: str(" "))
}
- p!(pi: str("# ") str(c.text().strip_prefix('#').expect("hash comment starts with #").trim()));
+ p!(pi: str("# ") string(c.text().strip_prefix('#').expect("hash comment starts with #").trim().to_string()));
if !matches!(loc, CommentLocation::ItemInline) {
p!(pi: nl)
}
@@ -145,14 +165,14 @@
if matches!(loc, CommentLocation::ItemInline) {
p!(pi: str(" "))
}
- p!(pi: str("// ") str(c.text().strip_prefix("//").expect("comment starts with //").trim()));
+ p!(pi: str("// ") string(c.text().strip_prefix("//").expect("comment starts with //").trim().to_string()));
if !matches!(loc, CommentLocation::ItemInline) {
p!(pi: nl)
}
}
// Garbage in - garbage out
TriviaKind::ErrorCommentTooShort => p!(pi: str("/*/")),
- TriviaKind::ErrorCommentUnterminated => p!(pi: str(c.text())),
+ TriviaKind::ErrorCommentUnterminated => p!(pi: string(c.text().to_string())),
}
}
cmds/jrsonnet-fmt/src/main.rsdiffbeforeafterboth--- a/cmds/jrsonnet-fmt/src/main.rs
+++ b/cmds/jrsonnet-fmt/src/main.rs
@@ -5,10 +5,11 @@
use jrsonnet_rowan_parser::{
nodes::{
ArgsDesc, Assertion, BinaryOperator, Bind, CompSpec, Destruct, DestructArrayPart,
- DestructRest, Expr, Field, FieldName, ForSpec, IfSpec, ImportKind, LhsExpr, Literal,
- Member, Name, Number, ObjBody, ObjLocal, ParamsDesc, SliceDesc, SourceFile, Text,
- UnaryOperator,
+ DestructRest, Expr, FieldName, ForSpec, IfSpec, ImportKind, LhsExpr, Literal, Member, Name,
+ Number, ObjBody, ObjLocal, ParamsDesc, SliceDesc, SourceFile, Text, UnaryOperator,
+ Visibility, VisibilityKind,
},
+ rowan::NodeOrToken,
AstNode, AstToken, SyntaxToken,
};
@@ -37,6 +38,10 @@
$o.push_str($e);
pi!(@s; $o: $($t)*);
}};
+ (@s; $o:ident: string($e:expr $(,)?) $($t:tt)*) => {{
+ $o.push_string($e);
+ pi!(@s; $o: $($t)*);
+ }};
(@s; $o:ident: nl $($t:tt)*) => {{
$o.push_signal(dprint_core::formatting::Signal::NewLine);
pi!(@s; $o: $($t)*);
@@ -96,8 +101,8 @@
if let Some(v) = self {
v.print()
} else {
- p!(new: str(
- &format!(
+ p!(new: string(
+ format!(
"/*missing {}*/",
type_name::<P>().replace("jrsonnet_rowan_parser::generated::nodes::", "")
),
@@ -108,18 +113,18 @@
impl Printable for SyntaxToken {
fn print(&self) -> PrintItems {
- p!(new: str(&self.to_string()))
+ p!(new: string(self.to_string()))
}
}
impl Printable for Text {
fn print(&self) -> PrintItems {
- p!(new: str(&format!("{}", self)))
+ p!(new: string(format!("{}", self)))
}
}
impl Printable for Number {
fn print(&self) -> PrintItems {
- p!(new: str(&format!("{}", self)))
+ p!(new: string(format!("{}", self)))
}
}
@@ -201,22 +206,10 @@
}
}
}
-impl Printable for Field {
+
+impl Printable for Visibility {
fn print(&self) -> PrintItems {
- let mut pi = p!(new:);
- match self {
- Field::FieldNormal(n) => {
- p!(pi: {n.field_name()});
- if n.plus_token().is_some() {
- p!(pi: str("+"));
- }
- p!(pi: str(": ") {n.expr()});
- }
- Field::FieldMethod(m) => {
- p!(pi: {m.field_name()} {m.params_desc()} str(": ") {m.expr()});
- }
- }
- pi
+ p!(new: string(self.to_string()))
}
}
@@ -282,10 +275,82 @@
}
}
+impl Printable for Member {
+ fn print(&self) -> PrintItems {
+ match self {
+ Member::MemberBindStmt(b) => {
+ p!(new: {b.obj_local()})
+ }
+ Member::MemberAssertStmt(ass) => {
+ p!(new: {ass.assertion()})
+ }
+ Member::MemberFieldNormal(n) => {
+ p!(new: {n.field_name()} if(n.plus_token().is_some())({n.plus_token()}) {n.visibility()} str(" ") {n.expr()})
+ }
+ Member::MemberFieldMethod(_) => todo!(),
+ }
+ }
+}
+
impl Printable for ObjBody {
fn print(&self) -> PrintItems {
match self {
- ObjBody::ObjBodyComp(_) => todo!(),
+ ObjBody::ObjBodyComp(l) => {
+ let mut pi = p!(new: str("{") >i nl);
+ let (children, end_comments) = children_between::<Member>(
+ l.syntax().clone(),
+ l.l_brace_token().map(Into::into).as_ref(),
+ Some(
+ &(l.comp_specs()
+ .next()
+ .expect("at least one spec is defined")
+ .syntax()
+ .clone())
+ .into(),
+ ),
+ );
+ for mem in children.into_iter() {
+ if mem.should_start_with_newline {
+ p!(pi: nl);
+ }
+ p!(pi: items(format_comments(&mem.before_trivia, CommentLocation::AboveItem)));
+ p!(pi: {mem.value} str(","));
+ p!(pi: items(format_comments(&mem.inline_trivia, CommentLocation::ItemInline)));
+ p!(pi: nl)
+ }
+
+ if end_comments.should_start_with_newline {
+ p!(pi: nl);
+ }
+ p!(pi: items(format_comments(&end_comments.trivia, CommentLocation::EndOfItems)));
+
+ let (compspecs, end_comments) = children_between::<CompSpec>(
+ l.syntax().clone(),
+ l.member_comps()
+ .last()
+ .map(|m| m.syntax().clone())
+ .map(Into::into)
+ .or_else(|| l.l_brace_token().map(Into::into))
+ .as_ref(),
+ l.r_brace_token().map(Into::into).as_ref(),
+ );
+ for mem in compspecs.into_iter() {
+ if mem.should_start_with_newline {
+ p!(pi: nl);
+ }
+ p!(pi: items(format_comments(&mem.before_trivia, CommentLocation::AboveItem)));
+ p!(pi: {mem.value});
+ p!(pi: items(format_comments(&mem.inline_trivia, CommentLocation::ItemInline)));
+ p!(pi: nl)
+ }
+ if end_comments.should_start_with_newline {
+ p!(pi: nl);
+ }
+ p!(pi: items(format_comments(&end_comments.trivia, CommentLocation::EndOfItems)));
+
+ p!(pi: <i str("}"));
+ pi
+ }
ObjBody::ObjBodyMemberList(l) => {
let mut pi = p!(new: str("{") >i nl);
let (children, end_comments) = children_between::<Member>(
@@ -298,18 +363,7 @@
p!(pi: nl);
}
p!(pi: items(format_comments(&mem.before_trivia, CommentLocation::AboveItem)));
- match mem.value {
- Member::MemberBindStmt(b) => {
- p!(pi: {b.obj_local()})
- }
- Member::MemberAssertStmt(ass) => {
- p!(pi: {ass.assertion()})
- }
- Member::MemberField(f) => {
- p!(pi: {f.field()})
- }
- }
- p!(pi: str(","));
+ p!(pi: {mem.value} str(","));
p!(pi: items(format_comments(&mem.inline_trivia, CommentLocation::ItemInline)));
p!(pi: nl)
}
@@ -326,12 +380,12 @@
}
impl Printable for UnaryOperator {
fn print(&self) -> PrintItems {
- p!(new: str(self.text()))
+ p!(new: string(self.text().to_string()))
}
}
impl Printable for BinaryOperator {
fn print(&self) -> PrintItems {
- p!(new: str(self.text()))
+ p!(new: string(self.text().to_string()))
}
}
impl Printable for Bind {
@@ -348,12 +402,12 @@
}
impl Printable for Literal {
fn print(&self) -> PrintItems {
- p!(new: str(&self.syntax().to_string()))
+ p!(new: string(self.syntax().to_string()))
}
}
impl Printable for ImportKind {
fn print(&self) -> PrintItems {
- p!(new: str(&self.syntax().to_string()))
+ p!(new: string(self.syntax().to_string()))
}
}
impl Printable for LhsExpr {
@@ -406,9 +460,6 @@
Expr::ExprParened(p) => {
p!(new: str("(") {p.expr()} str(")"))
}
- Expr::ExprIntrinsicThisFile(_) => p!(new: str("$intrinsicThisFile")),
- Expr::ExprIntrinsicId(_) => p!(new: str("$intrinsicId")),
- Expr::ExprIntrinsic(i) => p!(new: str("$intrinsic(") {i.name()} str(")")),
Expr::ExprString(s) => p!(new: {s.text()}),
Expr::ExprNumber(n) => p!(new: {n.number()}),
Expr::ExprArray(a) => {
@@ -543,10 +594,6 @@
local ocomp = {[k]: 1 for k in v};
local ? = skip;
-
- local intr = $intrinsic(test);
- local intrId = $intrinsicId;
- local intrThisFile = $intrinsicThisFile;
local ie = a[expr];
@@ -643,7 +690,13 @@
2
- else Template {}
+ else Template {},
+
+ compspecs: {
+ obj_with_no_item: {for i in [1, 2, 3]},
+ obj_with_2_items: {a:1, b:2, for i in [1,2,3]},
+ }
+
} + Template
crates/jrsonnet-rowan-parser/jsonnet.ungramdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/jsonnet.ungram
+++ b/crates/jrsonnet-rowan-parser/jsonnet.ungram
@@ -38,15 +38,6 @@
ExprLiteral =
Literal
-ExprIntrinsicThisFile =
- '$intrinsicThisFile'
-ExprIntrinsicId =
- '$intrinsicId'
-ExprIntrinsic =
- '$intrinsic'
- '('
- name:Name
- ')'
ExprString =
Text
ExprNumber =
@@ -110,9 +101,6 @@
| ExprApply
| ExprObjExtend
| ExprParened
-| ExprIntrinsicThisFile
-| ExprIntrinsicId
-| ExprIntrinsic
| ExprString
| ExprNumber
| ExprLiteral
@@ -167,14 +155,7 @@
ObjBodyComp =
'{'
- pre:ObjLocalPostComma*
- '['
- key:LhsExpr
- ']'
- '+'?
- ':'
- value:Expr
- post:ObjLocalPreComma*
+ (MemberComp (',' MemberComp)* ','?)?
CompSpec*
'}'
ObjBodyMemberList =
@@ -185,13 +166,6 @@
ObjBodyComp
| ObjBodyMemberList
-ObjLocalPostComma =
- ObjLocal
- ','
-ObjLocalPreComma =
- ','
- ObjLocal
-
MemberBindStmt = ObjLocal
MemberAssertStmt = Assertion
MemberFieldNormal =
@@ -204,6 +178,10 @@
ParamsDesc
Visibility
Expr
+MemberComp =
+ MemberBindStmt
+| MemberFieldNormal
+| MemberFieldMethod
Member =
MemberBindStmt
| MemberAssertStmt
@@ -367,7 +345,7 @@
| 'LIT_SINGLE_LINE_HASH_COMMENT!'
| 'LIT_SINGLE_LINE_SLASH_COMMENT!'
-ParsingError =
+CustomError =
'ERROR_MISSING_TOKEN!'
| 'ERROR_UNEXPECTED_TOKEN!'
| 'ERROR_CUSTOM!'
crates/jrsonnet-rowan-parser/src/generated/nodes.rsdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/src/generated/nodes.rs
+++ b/crates/jrsonnet-rowan-parser/src/generated/nodes.rs
@@ -212,45 +212,6 @@
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ExprIntrinsicThisFile {
- pub(crate) syntax: SyntaxNode,
-}
-impl ExprIntrinsicThisFile {
- pub fn intrinsic_this_file_token(&self) -> Option<SyntaxToken> {
- support::token(&self.syntax, T!["$intrinsicThisFile"])
- }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ExprIntrinsicId {
- pub(crate) syntax: SyntaxNode,
-}
-impl ExprIntrinsicId {
- pub fn intrinsic_id_token(&self) -> Option<SyntaxToken> {
- support::token(&self.syntax, T!["$intrinsicId"])
- }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ExprIntrinsic {
- pub(crate) syntax: SyntaxNode,
-}
-impl ExprIntrinsic {
- pub fn intrinsic_token(&self) -> Option<SyntaxToken> {
- support::token(&self.syntax, T!["$intrinsic"])
- }
- pub fn l_paren_token(&self) -> Option<SyntaxToken> {
- support::token(&self.syntax, T!['('])
- }
- pub fn name(&self) -> Option<Name> {
- support::child(&self.syntax)
- }
- pub fn r_paren_token(&self) -> Option<SyntaxToken> {
- support::token(&self.syntax, T![')'])
- }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ExprString {
pub(crate) syntax: SyntaxNode,
}
@@ -535,28 +496,7 @@
pub fn l_brace_token(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, T!['{'])
}
- pub fn pre(&self) -> AstChildren<ObjLocalPostComma> {
- support::children(&self.syntax)
- }
- pub fn l_brack_token(&self) -> Option<SyntaxToken> {
- support::token(&self.syntax, T!['['])
- }
- pub fn key(&self) -> Option<LhsExpr> {
- support::child(&self.syntax)
- }
- pub fn r_brack_token(&self) -> Option<SyntaxToken> {
- support::token(&self.syntax, T![']'])
- }
- pub fn plus_token(&self) -> Option<SyntaxToken> {
- support::token(&self.syntax, T![+])
- }
- pub fn colon_token(&self) -> Option<SyntaxToken> {
- support::token(&self.syntax, T![:])
- }
- pub fn value(&self) -> Option<Expr> {
- support::child(&self.syntax)
- }
- pub fn post(&self) -> AstChildren<ObjLocalPreComma> {
+ pub fn member_comps(&self) -> AstChildren<MemberComp> {
support::children(&self.syntax)
}
pub fn comp_specs(&self) -> AstChildren<CompSpec> {
@@ -568,32 +508,6 @@
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ObjLocalPostComma {
- pub(crate) syntax: SyntaxNode,
-}
-impl ObjLocalPostComma {
- pub fn obj_local(&self) -> Option<ObjLocal> {
- support::child(&self.syntax)
- }
- pub fn comma_token(&self) -> Option<SyntaxToken> {
- support::token(&self.syntax, T![,])
- }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ObjLocalPreComma {
- pub(crate) syntax: SyntaxNode,
-}
-impl ObjLocalPreComma {
- pub fn comma_token(&self) -> Option<SyntaxToken> {
- support::token(&self.syntax, T![,])
- }
- pub fn obj_local(&self) -> Option<ObjLocal> {
- support::child(&self.syntax)
- }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ObjBodyMemberList {
pub(crate) syntax: SyntaxNode,
}
@@ -610,24 +524,24 @@
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ObjLocal {
+pub struct MemberBindStmt {
pub(crate) syntax: SyntaxNode,
}
-impl ObjLocal {
- pub fn local_kw_token(&self) -> Option<SyntaxToken> {
- support::token(&self.syntax, T![local])
- }
- pub fn bind(&self) -> Option<Bind> {
+impl MemberBindStmt {
+ pub fn obj_local(&self) -> Option<ObjLocal> {
support::child(&self.syntax)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct MemberBindStmt {
+pub struct ObjLocal {
pub(crate) syntax: SyntaxNode,
}
-impl MemberBindStmt {
- pub fn obj_local(&self) -> Option<ObjLocal> {
+impl ObjLocal {
+ pub fn local_kw_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![local])
+ }
+ pub fn bind(&self) -> Option<Bind> {
support::child(&self.syntax)
}
}
@@ -905,9 +819,6 @@
ExprApply(ExprApply),
ExprObjExtend(ExprObjExtend),
ExprParened(ExprParened),
- ExprIntrinsicThisFile(ExprIntrinsicThisFile),
- ExprIntrinsicId(ExprIntrinsicId),
- ExprIntrinsic(ExprIntrinsic),
ExprString(ExprString),
ExprNumber(ExprNumber),
ExprLiteral(ExprLiteral),
@@ -942,6 +853,13 @@
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum MemberComp {
+ MemberBindStmt(MemberBindStmt),
+ MemberFieldNormal(MemberFieldNormal),
+ MemberFieldMethod(MemberFieldMethod),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Member {
MemberBindStmt(MemberBindStmt),
MemberAssertStmt(MemberAssertStmt),
@@ -1110,13 +1028,13 @@
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ParsingError {
+pub struct CustomError {
syntax: SyntaxToken,
- kind: ParsingErrorKind,
+ kind: CustomErrorKind,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub enum ParsingErrorKind {
+pub enum CustomErrorKind {
ErrorMissingToken,
ErrorUnexpectedToken,
ErrorCustom,
@@ -1319,36 +1237,6 @@
impl AstNode for ExprLiteral {
fn can_cast(kind: SyntaxKind) -> bool {
kind == EXPR_LITERAL
- }
- fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
- }
- fn syntax(&self) -> &SyntaxNode {
- &self.syntax
- }
-}
-impl AstNode for ExprIntrinsicThisFile {
- fn can_cast(kind: SyntaxKind) -> bool {
- kind == EXPR_INTRINSIC_THIS_FILE
- }
- fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
- }
- fn syntax(&self) -> &SyntaxNode {
- &self.syntax
- }
-}
-impl AstNode for ExprIntrinsicId {
- fn can_cast(kind: SyntaxKind) -> bool {
- kind == EXPR_INTRINSIC_ID
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
@@ -1361,21 +1249,6 @@
&self.syntax
}
}
-impl AstNode for ExprIntrinsic {
- fn can_cast(kind: SyntaxKind) -> bool {
- kind == EXPR_INTRINSIC
- }
- fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
- }
- fn syntax(&self) -> &SyntaxNode {
- &self.syntax
- }
-}
impl AstNode for ExprString {
fn can_cast(kind: SyntaxKind) -> bool {
kind == EXPR_STRING
@@ -1676,36 +1549,6 @@
&self.syntax
}
}
-impl AstNode for ObjLocalPostComma {
- fn can_cast(kind: SyntaxKind) -> bool {
- kind == OBJ_LOCAL_POST_COMMA
- }
- fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
- }
- fn syntax(&self) -> &SyntaxNode {
- &self.syntax
- }
-}
-impl AstNode for ObjLocalPreComma {
- fn can_cast(kind: SyntaxKind) -> bool {
- kind == OBJ_LOCAL_PRE_COMMA
- }
- fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
- }
- fn syntax(&self) -> &SyntaxNode {
- &self.syntax
- }
-}
impl AstNode for ObjBodyMemberList {
fn can_cast(kind: SyntaxKind) -> bool {
kind == OBJ_BODY_MEMBER_LIST
@@ -1721,9 +1564,9 @@
&self.syntax
}
}
-impl AstNode for ObjLocal {
+impl AstNode for MemberBindStmt {
fn can_cast(kind: SyntaxKind) -> bool {
- kind == OBJ_LOCAL
+ kind == MEMBER_BIND_STMT
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
@@ -1736,9 +1579,9 @@
&self.syntax
}
}
-impl AstNode for MemberBindStmt {
+impl AstNode for ObjLocal {
fn can_cast(kind: SyntaxKind) -> bool {
- kind == MEMBER_BIND_STMT
+ kind == OBJ_LOCAL
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
@@ -2044,21 +1887,6 @@
impl From<ExprParened> for Expr {
fn from(node: ExprParened) -> Expr {
Expr::ExprParened(node)
- }
-}
-impl From<ExprIntrinsicThisFile> for Expr {
- fn from(node: ExprIntrinsicThisFile) -> Expr {
- Expr::ExprIntrinsicThisFile(node)
- }
-}
-impl From<ExprIntrinsicId> for Expr {
- fn from(node: ExprIntrinsicId) -> Expr {
- Expr::ExprIntrinsicId(node)
- }
-}
-impl From<ExprIntrinsic> for Expr {
- fn from(node: ExprIntrinsic) -> Expr {
- Expr::ExprIntrinsic(node)
}
}
impl From<ExprString> for Expr {
@@ -2129,30 +1957,10 @@
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_LITERAL
- | EXPR_ARRAY
- | EXPR_OBJECT
- | EXPR_ARRAY_COMP
- | EXPR_IMPORT
- | EXPR_VAR
- | EXPR_LOCAL
- | EXPR_IF_THEN_ELSE
- | EXPR_FUNCTION
- | EXPR_ASSERT
- | EXPR_ERROR => true,
+ EXPR_BINARY | EXPR_UNARY | EXPR_SLICE | EXPR_INDEX | EXPR_INDEX_EXPR | EXPR_APPLY
+ | EXPR_OBJ_EXTEND | EXPR_PARENED | EXPR_STRING | EXPR_NUMBER | EXPR_LITERAL
+ | 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,
}
}
@@ -2166,11 +1974,6 @@
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_LITERAL => Expr::ExprLiteral(ExprLiteral { syntax }),
@@ -2198,9 +2001,6 @@
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::ExprLiteral(it) => &it.syntax,
@@ -2313,6 +2113,45 @@
}
}
}
+impl From<MemberBindStmt> for MemberComp {
+ fn from(node: MemberBindStmt) -> MemberComp {
+ MemberComp::MemberBindStmt(node)
+ }
+}
+impl From<MemberFieldNormal> for MemberComp {
+ fn from(node: MemberFieldNormal) -> MemberComp {
+ MemberComp::MemberFieldNormal(node)
+ }
+}
+impl From<MemberFieldMethod> for MemberComp {
+ fn from(node: MemberFieldMethod) -> MemberComp {
+ MemberComp::MemberFieldMethod(node)
+ }
+}
+impl AstNode for MemberComp {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ MEMBER_BIND_STMT | MEMBER_FIELD_NORMAL | MEMBER_FIELD_METHOD => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ MEMBER_BIND_STMT => MemberComp::MemberBindStmt(MemberBindStmt { syntax }),
+ MEMBER_FIELD_NORMAL => MemberComp::MemberFieldNormal(MemberFieldNormal { syntax }),
+ MEMBER_FIELD_METHOD => MemberComp::MemberFieldMethod(MemberFieldMethod { syntax }),
+ _ => return None,
+ };
+ Some(res)
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ MemberComp::MemberBindStmt(it) => &it.syntax,
+ MemberComp::MemberFieldNormal(it) => &it.syntax,
+ MemberComp::MemberFieldMethod(it) => &it.syntax,
+ }
+ }
+}
impl From<MemberBindStmt> for Member {
fn from(node: MemberBindStmt) -> Member {
Member::MemberBindStmt(node)
@@ -2847,19 +2686,19 @@
std::fmt::Display::fmt(self.syntax(), f)
}
}
-impl AstToken for ParsingError {
+impl AstToken for CustomError {
fn can_cast(kind: SyntaxKind) -> bool {
- ParsingErrorKind::can_cast(kind)
+ CustomErrorKind::can_cast(kind)
}
fn cast(syntax: SyntaxToken) -> Option<Self> {
- let kind = ParsingErrorKind::cast(syntax.kind())?;
- Some(ParsingError { syntax, kind })
+ let kind = CustomErrorKind::cast(syntax.kind())?;
+ Some(CustomError { syntax, kind })
}
fn syntax(&self) -> &SyntaxToken {
&self.syntax
}
}
-impl ParsingErrorKind {
+impl CustomErrorKind {
fn can_cast(kind: SyntaxKind) -> bool {
match kind {
ERROR_MISSING_TOKEN | ERROR_UNEXPECTED_TOKEN | ERROR_CUSTOM => true,
@@ -2876,12 +2715,12 @@
Some(res)
}
}
-impl ParsingError {
- pub fn kind(&self) -> ParsingErrorKind {
+impl CustomError {
+ pub fn kind(&self) -> CustomErrorKind {
self.kind
}
}
-impl std::fmt::Display for ParsingError {
+impl std::fmt::Display for CustomError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)
}
@@ -2906,6 +2745,11 @@
std::fmt::Display::fmt(self.syntax(), f)
}
}
+impl std::fmt::Display for MemberComp {
+ 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)
@@ -2996,21 +2840,6 @@
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)
@@ -3111,27 +2940,17 @@
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 {
+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 ObjBodyMemberList {
+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 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)
}
crates/jrsonnet-rowan-parser/src/generated/syntax_kinds.rsdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/src/generated/syntax_kinds.rs
+++ b/crates/jrsonnet-rowan-parser/src/generated/syntax_kinds.rs
@@ -89,12 +89,6 @@
ASSIGN,
#[token("?")]
QUESTION_MARK,
- #[token("$intrinsicThisFile")]
- INTRINSIC_THIS_FILE,
- #[token("$intrinsicId")]
- INTRINSIC_ID,
- #[token("$intrinsic")]
- INTRINSIC,
#[regex("(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?")]
FLOAT,
#[regex("(?:0|[1-9][0-9]*)\\.[^0-9]")]
@@ -199,9 +193,6 @@
EXPR_OBJ_EXTEND,
EXPR_PARENED,
EXPR_LITERAL,
- EXPR_INTRINSIC_THIS_FILE,
- EXPR_INTRINSIC_ID,
- EXPR_INTRINSIC,
EXPR_STRING,
EXPR_NUMBER,
EXPR_ARRAY,
@@ -222,11 +213,9 @@
SLICE_DESC_STEP,
ARG,
OBJ_BODY_COMP,
- OBJ_LOCAL_POST_COMMA,
- OBJ_LOCAL_PRE_COMMA,
OBJ_BODY_MEMBER_LIST,
- OBJ_LOCAL,
MEMBER_BIND_STMT,
+ OBJ_LOCAL,
MEMBER_ASSERT_STMT,
MEMBER_FIELD_NORMAL,
MEMBER_FIELD_METHOD,
@@ -248,6 +237,7 @@
OBJ_BODY,
COMP_SPEC,
BIND,
+ MEMBER_COMP,
MEMBER,
FIELD_NAME,
DESTRUCT,
@@ -260,7 +250,7 @@
IMPORT_KIND,
VISIBILITY,
TRIVIA,
- PARSING_ERROR,
+ CUSTOM_ERROR,
#[doc(hidden)]
__LAST,
}
@@ -271,18 +261,18 @@
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 | 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,
+ | DOTDOTDOT | COMMA | DOLLAR | ASSIGN | QUESTION_MARK | 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_enum(self) -> bool {
match self {
- EXPR | OBJ_BODY | COMP_SPEC | BIND | MEMBER | FIELD_NAME | DESTRUCT
+ EXPR | OBJ_BODY | COMP_SPEC | BIND | MEMBER_COMP | MEMBER | FIELD_NAME | DESTRUCT
| DESTRUCT_ARRAY_PART | BINARY_OPERATOR | UNARY_OPERATOR | LITERAL | TEXT | NUMBER
- | IMPORT_KIND | VISIBILITY | TRIVIA | PARSING_ERROR => true,
+ | IMPORT_KIND | VISIBILITY | TRIVIA | CUSTOM_ERROR => true,
_ => false,
}
}
@@ -295,5 +285,5 @@
}
}
#[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 } }
+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 } ; [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 } }
pub use T;
crates/jrsonnet-rowan-parser/src/parser.rsdiffbeforeafterboth1use std::{cell::Cell, fmt, rc::Rc};23use miette::{LabeledSpan, SourceOffset, SourceSpan};4use rowan::{GreenNode, TextRange};56use crate::{7 event::Event,8 marker::{CompletedMarker, Marker, Ranger},9 nodes::{BinaryOperatorKind, Literal, Number, Text, UnaryOperatorKind},10 token_set::SyntaxKindSet,11 AstToken, SyntaxKind,12 SyntaxKind::*,13 SyntaxNode, T, TS,14};1516pub struct Parse {17 pub green_node: GreenNode,18 pub errors: Vec<LocatedSyntaxError>,19}2021pub struct Parser {22 // TODO: remove all trivia before feeding to parser?23 kinds: Vec<SyntaxKind>,24 pub offset: usize,25 pub events: Vec<Event>,26 pub entered: u32,27 pub hints: Vec<(u32, TextRange, String)>,28 pub last_error_token: usize,29 expected_syntax_tracking_state: Rc<Cell<ExpectedSyntax>>,30 steps: Cell<u64>,31}3233#[derive(Clone, Debug)]34pub enum SyntaxError {35 Unexpected {36 expected: ExpectedSyntax,37 found: SyntaxKind,38 },39 Missing {40 expected: ExpectedSyntax,41 },42 Custom {43 error: String,44 },45 Hint {46 error: String,47 },48}4950#[derive(Debug)]51pub struct LocatedSyntaxError {52 pub error: SyntaxError,53 pub range: TextRange,54}5556impl From<LocatedSyntaxError> for LabeledSpan {57 fn from(val: LocatedSyntaxError) -> Self {58 let span = SourceSpan::new(59 SourceOffset::from(usize::from(val.range.start())),60 SourceOffset::from(usize::from(val.range.end() - val.range.start())),61 );62 dbg!(&val);63 match val.error {64 SyntaxError::Unexpected { expected, found } => LabeledSpan::new_with_span(65 Some(format!("expected {expected}, found {found:?}")),66 span,67 ),68 SyntaxError::Missing { expected } => {69 LabeledSpan::new_with_span(Some(format!("missing {expected}")), span)70 }71 SyntaxError::Custom { error } | SyntaxError::Hint { error } => {72 LabeledSpan::new_with_span(Some(error), span)73 }74 }75 }76}7778impl Parser {79 pub fn new(kinds: Vec<SyntaxKind>) -> Self {80 Self {81 kinds,82 offset: 0,83 events: vec![],84 entered: 0,85 last_error_token: 0,86 hints: vec![],87 expected_syntax_tracking_state: Rc::new(Cell::new(ExpectedSyntax::Unnamed(TS![]))),88 steps: Cell::new(0),89 }90 }91 pub fn clear_outdated_hints(&mut self) {92 let amount = self93 .hints94 .iter()95 .rev()96 .take_while(|h| h.0 > self.entered)97 .count();98 self.hints.truncate(self.hints.len() - amount)99 }100 fn clear_expected_syntaxes(&mut self) {101 self.expected_syntax_tracking_state102 .set(ExpectedSyntax::Unnamed(TS![]));103 }104 pub fn start(&mut self) -> Marker {105 let start_event_idx = self.events.len();106 self.events.push(Event::Pending);107 self.entered += 1;108 Marker::new(start_event_idx)109 }110 pub fn start_ranger(&mut self) -> Ranger {111 let pos = self.offset;112 Ranger { pos }113 }114 pub fn parse(mut self) -> Vec<Event> {115 let m = self.start();116 expr(&mut self);117 self.expect(EOF);118 m.complete(&mut self, SOURCE_FILE);119120 self.events121 }122123 pub(crate) fn expect(&mut self, kind: SyntaxKind) {124 self.expect_with_recovery_set(kind, TS![])125 }126127 pub(crate) fn expect_with_recovery_set(128 &mut self,129 kind: SyntaxKind,130 recovery_set: SyntaxKindSet,131 ) {132 if self.at(kind) {133 if kind != EOF {134 self.bump();135 }136 } else {137 self.error_with_recovery_set(recovery_set);138 }139 }140141 pub(crate) fn expect_with_no_skip(&mut self, kind: SyntaxKind) {142 if self.at(kind) {143 self.bump();144 } else {145 self.error_with_no_skip();146 }147 }148 pub fn error_with_no_skip(&mut self) -> CompletedMarker {149 self.error_with_recovery_set(SyntaxKindSet::ALL)150 }151152 pub fn error_with_recovery_set(&mut self, recovery_set: SyntaxKindSet) -> CompletedMarker {153 let expected = self.expected_syntax_tracking_state.get();154 self.expected_syntax_tracking_state155 .set(ExpectedSyntax::Unnamed(TS![]));156157 if self.at_end() || self.at_ts(recovery_set) {158 let m = self.start();159 return m.complete_missing(self, expected);160 }161162 let current_token = self.current();163164 self.last_error_token = self.offset;165166 let m = self.start();167 self.bump();168 let m = m.complete_unexpected(self, expected, current_token);169 self.clear_expected_syntaxes();170 m171 }172 fn bump_assert(&mut self, kind: SyntaxKind) {173 assert!(self.at(kind), "expected {:?}", kind);174 self.bump_remap(self.current());175 }176 fn bump(&mut self) {177 self.bump_remap(self.current());178 }179 fn bump_remap(&mut self, kind: SyntaxKind) {180 assert_ne!(self.offset, self.kinds.len(), "already at end");181 self.events.push(Event::Token { kind });182 self.offset += 1;183 self.clear_expected_syntaxes();184 }185 fn step(&self) {186 use std::fmt::Write;187 let steps = self.steps.get();188 if steps >= 15000000 {189 let mut out = "seems like parsing is stuck".to_owned();190 {191 let last = 20;192 write!(out, "\n\nLast {} events:", last).unwrap();193 for (i, event) in self194 .events195 .iter()196 .skip(self.events.len().saturating_sub(last))197 .enumerate()198 {199 write!(out, "\n{i}. {event:?}").unwrap();200 }201 }202 {203 let next = 20;204 write!(out, "\n\nNext {next} tokens:").unwrap();205 for (i, tok) in self.kinds.iter().skip(self.offset).take(next).enumerate() {206 write!(out, "\n{i}. {tok:?}").unwrap();207 }208 }209 panic!("{out}")210 }211 self.steps.set(steps + 1);212 }213 fn nth(&self, i: usize) -> SyntaxKind {214 self.step();215 let mut offset = self.offset;216 for _ in 0..i {217 offset += 1;218 }219 self.kinds.get(offset).copied().unwrap_or(EOF)220 }221 fn current(&self) -> SyntaxKind {222 self.nth(0)223 }224 #[must_use]225 pub(crate) fn expected_syntax_name(&mut self, name: &'static str) -> ExpectedSyntaxGuard {226 self.expected_syntax_tracking_state227 .set(ExpectedSyntax::Named(name));228229 ExpectedSyntaxGuard::new(Rc::clone(&self.expected_syntax_tracking_state))230 }231 pub fn at(&mut self, kind: SyntaxKind) -> bool {232 self.nth_at(0, kind)233 }234 pub fn nth_at(&mut self, n: usize, kind: SyntaxKind) -> bool {235 if n == 0 {236 if let ExpectedSyntax::Unnamed(kinds) = self.expected_syntax_tracking_state.get() {237 let kinds = kinds.with(kind);238 self.expected_syntax_tracking_state239 .set(ExpectedSyntax::Unnamed(kinds))240 }241 }242 self.nth(n) == kind243 }244 pub fn at_ts(&mut self, set: SyntaxKindSet) -> bool {245 if let ExpectedSyntax::Unnamed(kinds) = self.expected_syntax_tracking_state.get() {246 let kinds = kinds.union(set);247 self.expected_syntax_tracking_state248 .set(ExpectedSyntax::Unnamed(kinds))249 }250 set.contains(self.current())251 }252 pub fn at_end(&mut self) -> bool {253 self.at(EOF)254 }255}256pub(crate) struct ExpectedSyntaxGuard {257 expected_syntax_tracking_state: Rc<Cell<ExpectedSyntax>>,258}259260impl ExpectedSyntaxGuard {261 fn new(expected_syntax_tracking_state: Rc<Cell<ExpectedSyntax>>) -> Self {262 Self {263 expected_syntax_tracking_state,264 }265 }266}267268impl Drop for ExpectedSyntaxGuard {269 fn drop(&mut self) {270 self.expected_syntax_tracking_state271 .set(ExpectedSyntax::Unnamed(TS![]));272 }273}274275#[derive(Clone, Debug, Copy)]276pub enum ExpectedSyntax {277 Named(&'static str),278 Unnamed(SyntaxKindSet),279}280impl fmt::Display for ExpectedSyntax {281 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {282 match self {283 ExpectedSyntax::Named(name) => write!(f, "{name}"),284 ExpectedSyntax::Unnamed(set) => write!(f, "{set}"),285 }286 }287}288289fn expr(p: &mut Parser) -> CompletedMarker {290 match expr_binding_power(p, 0) {291 Ok(m) => m,292 Err(m) => m,293 }294}295fn expr_binding_power(296 p: &mut Parser,297 minimum_binding_power: u8,298) -> Result<CompletedMarker, CompletedMarker> {299 let mut lhs = lhs(p)?;300301 while let Some(op) = BinaryOperatorKind::cast(p.current())302 .or_else(|| p.at(T!['{']).then_some(BinaryOperatorKind::MetaObjectApply))303 {304 let (left_binding_power, right_binding_power) = op.binding_power();305 if left_binding_power < minimum_binding_power {306 break;307 }308309 // Object apply is not a real operator, we dont have something to bump310 if op != BinaryOperatorKind::MetaObjectApply {311 p.bump();312 }313314 let m = lhs.wrap(p, LHS_EXPR).precede(p);315 let parsed_rhs = expr_binding_power(p, right_binding_power).is_ok();316 lhs = m.complete(317 p,318 if op == BinaryOperatorKind::MetaObjectApply {319 EXPR_OBJ_EXTEND320 } else {321 EXPR_BINARY322 },323 );324325 if !parsed_rhs {326 break;327 }328 }329 Ok(lhs)330}331332const COMPSPEC: SyntaxKindSet = TS![for if];333fn compspec(p: &mut Parser) -> CompletedMarker {334 assert!(p.at_ts(COMPSPEC));335 if p.at(T![for]) {336 let m = p.start();337 p.bump();338 name(p);339 p.expect(T![in]);340 expr(p);341 m.complete(p, FOR_SPEC)342 } else if p.at(T![if]) {343 let m = p.start();344 p.bump();345 expr(p);346 m.complete(p, IF_SPEC)347 } else {348 unreachable!()349 }350}351352fn comma(p: &mut Parser) -> bool {353 comma_with_alternatives(p, TS![])354}355fn comma_with_alternatives(p: &mut Parser, set: SyntaxKindSet) -> bool {356 if p.at(T![,]) {357 p.bump();358 true359 } else if p.at_ts(set) {360 let _ex = p.expected_syntax_name("comma");361 p.expect_with_recovery_set(T![,], TS![]);362 true363 } else {364 false365 }366}367368fn field_name(p: &mut Parser) {369 let _e = p.expected_syntax_name("field name");370 let m = p.start();371 if p.at(T!['[']) {372 p.bump();373 expr(p);374 p.expect(T![']']);375 m.complete(p, FIELD_NAME_DYNAMIC);376 } else if p.at(IDENT) {377 name(p);378 m.complete(p, FIELD_NAME_FIXED);379 } else if Text::can_cast(p.current()) {380 text(p);381 m.complete(p, FIELD_NAME_FIXED);382 } else {383 m.forget(p);384 p.error_with_recovery_set(TS![; : :: ::: '(']);385 }386}387fn visibility(p: &mut Parser) {388 if p.at_ts(TS![: :: :::]) {389 p.bump()390 } else {391 p.error_with_recovery_set(TS![=]);392 }393}394fn assertion(p: &mut Parser) {395 let m = p.start();396 p.bump_assert(T![assert]);397 expr(p).wrap(p, LHS_EXPR);398 if p.at(T![:]) {399 p.bump();400 expr(p);401 }402 m.complete(p, ASSERTION);403}404fn object(p: &mut Parser) -> CompletedMarker {405 let m_t = p.start();406 let m = p.start();407 p.bump_assert(T!['{']);408409 let mut elems = 0;410 let mut compspecs = Vec::new();411 let mut asserts = Vec::new();412 loop {413 if p.at(T!['}']) {414 p.bump();415 break;416 }417 if p.at_ts(COMPSPEC) {418 if elems == 0 {419 let m = p.start();420 m.complete_missing(p, ExpectedSyntax::Named("field definition"));421 }422 while p.at_ts(COMPSPEC) {423 compspecs.push(compspec(p));424 }425 if comma_with_alternatives(p, TS![;]) {426 continue;427 }428 p.expect(R_BRACE);429 break;430 }431 let m = p.start();432 if p.at(T![local]) {433 obj_local(p);434 m.complete(p, MEMBER_BIND_STMT);435 } else if p.at(T![assert]) {436 assertion(p);437 asserts.push(m.complete(p, MEMBER_ASSERT_STMT));438 } else {439 field_name(p);440 if p.at(T![+]) {441 p.bump();442 }443 let params = if p.at(T!['(']) {444 params_desc(p);445 visibility(p);446 expr(p);447 true448 } else if p.at_ts(TS![: :: :::]) && p.nth_at(1, T![function]) {449 visibility(p);450 p.bump_assert(T![function]);451 params_desc(p);452 expr(p);453 true454 } else {455 visibility(p);456 expr(p);457 false458 };459 elems += 1;460461 if params {462 m.complete(p, MEMBER_FIELD_METHOD)463 } else {464 m.complete(p, MEMBER_FIELD_NORMAL)465 };466 };467 while p.at_ts(COMPSPEC) {468 compspecs.push(compspec(p));469 }470 if comma_with_alternatives(p, TS![;]) {471 continue;472 }473 p.expect(R_BRACE);474 break;475 }476477 if elems > 1 && !compspecs.is_empty() {478 for errored in compspecs {479 errored.wrap_error(480 p,481 "compspec may only be used if there is only one array element",482 );483 }484 m.complete(p, OBJ_BODY_MEMBER_LIST);485 } else if !compspecs.is_empty() {486 for errored in asserts {487 errored.wrap_error(p, "asserts can't be used in object comprehensions");488 }489 m.complete(p, OBJ_BODY_COMP);490 } else {491 m.complete(p, OBJ_BODY_MEMBER_LIST);492 }493 m_t.complete(p, EXPR_OBJECT)494}495fn param(p: &mut Parser) {496 let m = p.start();497 destruct(p);498 if p.at(T![=]) {499 p.bump();500 expr(p);501 }502 m.complete(p, PARAM);503}504fn params_desc(p: &mut Parser) -> CompletedMarker {505 let m = p.start();506 p.bump_assert(T!['(']);507508 loop {509 if p.at(T![')']) {510 p.bump();511 break;512 }513 param(p);514 if comma(p) {515 continue;516 }517 p.expect(T![')']);518 break;519 }520521 m.complete(p, PARAMS_DESC)522}523fn args_desc(p: &mut Parser) {524 let m = p.start();525 p.bump_assert(T!['(']);526527 let started_named = Cell::new(false);528 let mut unnamed_after_named = Vec::new();529530 loop {531 if p.at(T![')']) {532 break;533 }534535 let m = p.start();536 if p.at(IDENT) && p.nth_at(1, T![=]) {537 name(p);538 p.bump();539 expr(p);540 m.complete(p, ARG);541 started_named.set(true);542 } else {543 expr(p);544 let arg = m.complete(p, ARG);545 if started_named.get() {546 unnamed_after_named.push(arg)547 }548 }549 if comma(p) {550 continue;551 }552 break;553 }554 p.expect(T![')']);555 if p.at(T![tailstrict]) {556 p.bump()557 }558559 for errored in unnamed_after_named {560 errored.wrap_error(p, "can't use positional arguments after named");561 }562563 m.complete(p, ARGS_DESC);564}565566fn array(p: &mut Parser) -> CompletedMarker {567 // Start the list node568 let m = p.start();569 p.bump_assert(T!['[']);570571 let mut compspecs = Vec::new();572 let mut elems = 0;573574 loop {575 if p.at(T![']']) {576 p.bump();577 break;578 }579 if elems != 0 && p.at_ts(COMPSPEC) {580 while p.at_ts(COMPSPEC) {581 compspecs.push(compspec(p));582 }583 if comma(p) {584 continue;585 }586 p.expect(T![']']);587 break;588 }589 elems += 1;590 expr(p);591 while p.at_ts(COMPSPEC) {592 compspecs.push(compspec(p));593 }594 if comma(p) {595 continue;596 }597 p.expect(T![']']);598 break;599 }600601 if elems > 1 && !compspecs.is_empty() {602 for spec in compspecs {603 spec.wrap_error(604 p,605 "compspec may only be used if there is only one array element",606 );607 }608609 m.complete(p, EXPR_ARRAY)610 } else if !compspecs.is_empty() {611 m.complete(p, EXPR_ARRAY_COMP)612 } else {613 m.complete(p, EXPR_ARRAY)614 }615}616/// Returns true if it was slice, false if just index617#[must_use]618fn slice_desc_or_index(p: &mut Parser) -> bool {619 let m = p.start();620 p.bump();621 // TODO: do not treat :, ::, ::: as full tokens?622 // Start623 if !p.at(T![:]) && !p.at(T![::]) {624 expr(p);625 }626 if p.at(T![:]) {627 p.bump();628 // End629 if !p.at(T![']']) {630 expr(p).wrap(p, SLICE_DESC_END);631 }632 if p.at(T![:]) {633 p.bump();634 // Step635 if !p.at(T![']']) {636 expr(p).wrap(p, SLICE_DESC_STEP);637 }638 }639 } else if p.at(T![::]) {640 p.bump();641 // End642 if !p.at(T![']']) {643 expr(p).wrap(p, SLICE_DESC_END);644 }645 } else {646 // It was not a slice647 p.expect(T![']']);648 m.forget(p);649 return false;650 }651 p.expect(T![']']);652 m.complete(p, SLICE_DESC);653 true654}655fn lhs(p: &mut Parser) -> Result<CompletedMarker, CompletedMarker> {656 let mut lhs = lhs_basic(p)?;657658 loop {659 if p.at(T![.]) {660 let m = lhs.precede(p);661 p.bump();662 name(p);663 lhs = m.complete(p, EXPR_INDEX);664 } else if p.at(T!['[']) {665 if slice_desc_or_index(p) {666 lhs = lhs.precede(p).complete(p, EXPR_SLICE);667 } else {668 lhs = lhs669 .wrap(p, LHS_EXPR)670 .precede(p)671 .complete(p, EXPR_INDEX_EXPR);672 }673 } else if p.at(T!['(']) {674 let m = lhs.precede(p);675 args_desc(p);676 lhs = m.complete(p, EXPR_APPLY);677 } else {678 break;679 }680 }681682 Ok(lhs)683}684fn name(p: &mut Parser) {685 let m = p.start();686 p.expect(IDENT);687 m.complete(p, NAME);688}689fn destruct_rest(p: &mut Parser) {690 let m = p.start();691 p.bump_assert(T![...]);692 if p.at(IDENT) {693 p.bump()694 }695 m.complete(p, DESTRUCT_REST);696}697fn destruct_object_field(p: &mut Parser) {698 let m = p.start();699 name(p);700 if p.at(T![:]) {701 p.bump();702 destruct(p);703 };704 if p.at(T![=]) {705 p.bump();706 expr(p);707 }708 m.complete(p, DESTRUCT_OBJECT_FIELD);709}710fn obj_local(p: &mut Parser) {711 let m = p.start();712 p.bump_assert(T![local]);713 bind(p);714 m.complete(p, OBJ_LOCAL);715}716fn destruct(p: &mut Parser) -> CompletedMarker {717 let m = p.start();718 let _ex = p.expected_syntax_name("destruction specifier");719 if p.at(T![?]) {720 p.bump();721 m.complete(p, DESTRUCT_SKIP)722 } else if p.at(T!['[']) {723 p.bump();724 let mut had_rest = false;725 loop {726 if p.at(T![']']) {727 p.bump();728 break;729 } else if p.at(T![...]) {730 let m_err = p.start_ranger();731 destruct_rest(p);732 // if had_rest {733 // p.custom_error(m_err.finish(p), "only one rest can be present in array");734 // }735 had_rest = true;736 } else {737 destruct(p);738 }739 if p.at(T![,]) {740 p.bump();741 continue;742 }743 p.expect(T![']']);744 break;745 }746 m.complete(p, DESTRUCT_ARRAY)747 } else if p.at(T!['{']) {748 p.bump();749 let mut had_rest = false;750 loop {751 if p.at(T!['}']) {752 p.bump();753 break;754 } else if p.at(T![...]) {755 let m_err = p.start_ranger();756 destruct_rest(p);757 // if had_rest {758 // p.custom_error(m_err.finish(p), "only one rest can be present in object");759 // }760 had_rest = true;761 } else {762 if had_rest {763 p.error_with_recovery_set(TS![]);764 }765 destruct_object_field(p);766 }767 if p.at(T![,]) {768 p.bump();769 continue;770 }771 p.expect(T!['}']);772 break;773 }774 m.complete(p, DESTRUCT_OBJECT)775 } else if p.at(IDENT) {776 name(p);777 m.complete(p, DESTRUCT_FULL)778 } else {779 m.forget(p);780 p.error_with_recovery_set(TS![; , '}', '(', :])781 }782}783fn bind(p: &mut Parser) {784 let m = p.start();785 if p.at(IDENT) && p.nth_at(1, T!['(']) {786 name(p);787 params_desc(p);788 p.expect(T![=]);789 expr(p);790 m.complete(p, BIND_FUNCTION)791 } else if p.at(IDENT) && p.nth_at(1, T![=]) && p.nth_at(2, T![function]) {792 name(p);793 p.expect(T![=]);794 p.expect(T![function]);795 params_desc(p);796 expr(p);797 m.complete(p, BIND_FUNCTION)798 } else {799 destruct(p);800 p.expect(T![=]);801 expr(p);802 m.complete(p, BIND_DESTRUCT)803 };804}805fn text(p: &mut Parser) {806 assert!(Text::can_cast(p.current()));807 p.bump();808}809fn number(p: &mut Parser) {810 assert!(Number::can_cast(p.current()));811 p.bump();812}813fn literal(p: &mut Parser) {814 assert!(Literal::can_cast(p.current()));815 p.bump();816}817fn lhs_basic(p: &mut Parser) -> Result<CompletedMarker, CompletedMarker> {818 let _e = p.expected_syntax_name("expression");819 Ok(if Literal::can_cast(p.current()) {820 let m = p.start();821 literal(p);822 m.complete(p, EXPR_LITERAL)823 } else if Text::can_cast(p.current()) {824 let m = p.start();825 text(p);826 m.complete(p, EXPR_STRING)827 } else if Number::can_cast(p.current()) {828 let m = p.start();829 number(p);830 m.complete(p, EXPR_NUMBER)831 } else if p.at(IDENT) {832 let m = p.start();833 name(p);834 m.complete(p, EXPR_VAR)835 } else if p.at(INTRINSIC_THIS_FILE) {836 let m = p.start();837 p.bump();838 m.complete(p, EXPR_INTRINSIC_THIS_FILE)839 } else if p.at(INTRINSIC_ID) {840 let m = p.start();841 p.bump();842 m.complete(p, EXPR_INTRINSIC_ID)843 } else if p.at(INTRINSIC) {844 let m = p.start();845 p.bump();846 p.expect(T!['(']);847 name(p);848 p.expect(T![')']);849 m.complete(p, EXPR_INTRINSIC)850 } else if p.at(T![if]) {851 let m = p.start();852 p.bump();853 expr(p);854 p.expect(T![then]);855 expr(p).wrap(p, TRUE_EXPR);856 if p.at(T![else]) {857 p.bump();858 expr(p).wrap(p, FALSE_EXPR);859 }860 m.complete(p, EXPR_IF_THEN_ELSE)861 } else if p.at(T!['[']) {862 array(p)863 } else if p.at(T!['{']) {864 object(p)865 } else if p.at(T![local]) {866 let m = p.start();867 p.bump();868 loop {869 if p.at(T![;]) {870 p.bump();871 break;872 }873 bind(p);874875 if p.at(T![,]) {876 p.bump();877 continue;878 }879 p.expect(T![;]);880 break;881 }882 expr(p);883 m.complete(p, EXPR_LOCAL)884 } else if p.at(T![function]) {885 let m = p.start();886 p.bump();887 params_desc(p);888 expr(p);889 m.complete(p, EXPR_FUNCTION)890 } else if p.at(T![error]) {891 let m = p.start();892 p.bump();893 expr(p);894 m.complete(p, EXPR_ERROR)895 } else if p.at(T![assert]) {896 let m = p.start();897 assertion(p);898 p.expect(T![;]);899 expr(p);900 m.complete(p, EXPR_ASSERT)901 } else if p.at(T![import]) || p.at(T![importstr]) || p.at(T![importbin]) {902 let m = p.start();903 p.bump();904 text(p);905 m.complete(p, EXPR_IMPORT)906 } else if let Some(op) = UnaryOperatorKind::cast(p.current()) {907 let ((), right_binding_power) = op.binding_power();908909 let m = p.start();910 p.bump();911 let _ = expr_binding_power(p, right_binding_power);912 m.complete(p, EXPR_UNARY)913 } else if p.at(T!['(']) {914 let m = p.start();915 p.bump();916 expr(p);917 p.expect(T![')']);918 m.complete(p, EXPR_PARENED)919 } else {920 return Err(p.error_with_no_skip());921 })922}923924impl Parse {925 pub fn syntax(&self) -> SyntaxNode {926 SyntaxNode::new_root(self.green_node.clone())927 }928}1use std::{cell::Cell, fmt, rc::Rc};23use miette::{LabeledSpan, SourceOffset, SourceSpan};4use rowan::{GreenNode, TextRange};56use crate::{7 event::Event,8 marker::{CompletedMarker, Marker, Ranger},9 nodes::{BinaryOperatorKind, Literal, Number, Text, UnaryOperatorKind},10 token_set::SyntaxKindSet,11 AstToken, SyntaxKind,12 SyntaxKind::*,13 SyntaxNode, T, TS,14};1516pub struct Parse {17 pub green_node: GreenNode,18 pub errors: Vec<LocatedSyntaxError>,19}2021pub struct Parser {22 // TODO: remove all trivia before feeding to parser?23 kinds: Vec<SyntaxKind>,24 pub offset: usize,25 pub events: Vec<Event>,26 pub entered: u32,27 pub hints: Vec<(u32, TextRange, String)>,28 pub last_error_token: usize,29 expected_syntax_tracking_state: Rc<Cell<ExpectedSyntax>>,30 steps: Cell<u64>,31}3233#[derive(Clone, Debug)]34pub enum SyntaxError {35 Unexpected {36 expected: ExpectedSyntax,37 found: SyntaxKind,38 },39 Missing {40 expected: ExpectedSyntax,41 },42 Custom {43 error: String,44 },45 Hint {46 error: String,47 },48}4950#[derive(Debug)]51pub struct LocatedSyntaxError {52 pub error: SyntaxError,53 pub range: TextRange,54}5556impl From<LocatedSyntaxError> for LabeledSpan {57 fn from(val: LocatedSyntaxError) -> Self {58 let span = SourceSpan::new(59 SourceOffset::from(usize::from(val.range.start())),60 SourceOffset::from(usize::from(val.range.end() - val.range.start())),61 );62 dbg!(&val);63 match val.error {64 SyntaxError::Unexpected { expected, found } => LabeledSpan::new_with_span(65 Some(format!("expected {expected}, found {found:?}")),66 span,67 ),68 SyntaxError::Missing { expected } => {69 LabeledSpan::new_with_span(Some(format!("missing {expected}")), span)70 }71 SyntaxError::Custom { error } | SyntaxError::Hint { error } => {72 LabeledSpan::new_with_span(Some(error), span)73 }74 }75 }76}7778impl Parser {79 pub fn new(kinds: Vec<SyntaxKind>) -> Self {80 Self {81 kinds,82 offset: 0,83 events: vec![],84 entered: 0,85 last_error_token: 0,86 hints: vec![],87 expected_syntax_tracking_state: Rc::new(Cell::new(ExpectedSyntax::Unnamed(TS![]))),88 steps: Cell::new(0),89 }90 }91 pub fn clear_outdated_hints(&mut self) {92 let amount = self93 .hints94 .iter()95 .rev()96 .take_while(|h| h.0 > self.entered)97 .count();98 self.hints.truncate(self.hints.len() - amount)99 }100 fn clear_expected_syntaxes(&mut self) {101 self.expected_syntax_tracking_state102 .set(ExpectedSyntax::Unnamed(TS![]));103 }104 pub fn start(&mut self) -> Marker {105 let start_event_idx = self.events.len();106 self.events.push(Event::Pending);107 self.entered += 1;108 Marker::new(start_event_idx)109 }110 pub fn start_ranger(&mut self) -> Ranger {111 let pos = self.offset;112 Ranger { pos }113 }114 pub fn parse(mut self) -> Vec<Event> {115 let m = self.start();116 expr(&mut self);117 if !self.at(EOF) {118 let m = self.start();119 while !self.at(EOF) {120 self.bump();121 }122 m.complete_error(&mut self, "unexpected tokens after end");123 }124 m.complete(&mut self, SOURCE_FILE);125126 self.events127 }128129 pub(crate) fn expect(&mut self, kind: SyntaxKind) {130 self.expect_with_recovery_set(kind, TS![])131 }132133 pub(crate) fn expect_with_recovery_set(134 &mut self,135 kind: SyntaxKind,136 recovery_set: SyntaxKindSet,137 ) {138 if self.at(kind) {139 if kind != EOF {140 self.bump();141 }142 } else {143 self.error_with_recovery_set(recovery_set);144 }145 }146147 pub(crate) fn expect_with_no_skip(&mut self, kind: SyntaxKind) {148 if self.at(kind) {149 self.bump();150 } else {151 self.error_with_no_skip();152 }153 }154 pub fn error_with_no_skip(&mut self) -> CompletedMarker {155 self.error_with_recovery_set(SyntaxKindSet::ALL)156 }157158 pub fn error_with_recovery_set(&mut self, recovery_set: SyntaxKindSet) -> CompletedMarker {159 let expected = self.expected_syntax_tracking_state.get();160 self.expected_syntax_tracking_state161 .set(ExpectedSyntax::Unnamed(TS![]));162163 if self.at_end() || self.at_ts(recovery_set) {164 let m = self.start();165 return m.complete_missing(self, expected);166 }167168 let current_token = self.current();169170 self.last_error_token = self.offset;171172 let m = self.start();173 self.bump();174 let m = m.complete_unexpected(self, expected, current_token);175 self.clear_expected_syntaxes();176 m177 }178 fn bump_assert(&mut self, kind: SyntaxKind) {179 assert!(self.at(kind), "expected {:?}", kind);180 self.bump_remap(self.current());181 }182 fn bump(&mut self) {183 self.bump_remap(self.current());184 }185 fn bump_remap(&mut self, kind: SyntaxKind) {186 assert_ne!(self.offset, self.kinds.len(), "already at end");187 self.events.push(Event::Token { kind });188 self.offset += 1;189 self.clear_expected_syntaxes();190 }191 fn step(&self) {192 use std::fmt::Write;193 let steps = self.steps.get();194 if steps >= 15000000 {195 let mut out = "seems like parsing is stuck".to_owned();196 {197 let last = 20;198 write!(out, "\n\nLast {} events:", last).unwrap();199 for (i, event) in self200 .events201 .iter()202 .skip(self.events.len().saturating_sub(last))203 .enumerate()204 {205 write!(out, "\n{i}. {event:?}").unwrap();206 }207 }208 {209 let next = 20;210 write!(out, "\n\nNext {next} tokens:").unwrap();211 for (i, tok) in self.kinds.iter().skip(self.offset).take(next).enumerate() {212 write!(out, "\n{i}. {tok:?}").unwrap();213 }214 }215 panic!("{out}")216 }217 self.steps.set(steps + 1);218 }219 fn nth(&self, i: usize) -> SyntaxKind {220 self.step();221 let mut offset = self.offset;222 for _ in 0..i {223 offset += 1;224 }225 self.kinds.get(offset).copied().unwrap_or(EOF)226 }227 fn current(&self) -> SyntaxKind {228 self.nth(0)229 }230 #[must_use]231 pub(crate) fn expected_syntax_name(&mut self, name: &'static str) -> ExpectedSyntaxGuard {232 self.expected_syntax_tracking_state233 .set(ExpectedSyntax::Named(name));234235 ExpectedSyntaxGuard::new(Rc::clone(&self.expected_syntax_tracking_state))236 }237 pub fn at(&mut self, kind: SyntaxKind) -> bool {238 self.nth_at(0, kind)239 }240 pub fn nth_at(&mut self, n: usize, kind: SyntaxKind) -> bool {241 if n == 0 {242 if let ExpectedSyntax::Unnamed(kinds) = self.expected_syntax_tracking_state.get() {243 let kinds = kinds.with(kind);244 self.expected_syntax_tracking_state245 .set(ExpectedSyntax::Unnamed(kinds))246 }247 }248 self.nth(n) == kind249 }250 pub fn at_ts(&mut self, set: SyntaxKindSet) -> bool {251 if let ExpectedSyntax::Unnamed(kinds) = self.expected_syntax_tracking_state.get() {252 let kinds = kinds.union(set);253 self.expected_syntax_tracking_state254 .set(ExpectedSyntax::Unnamed(kinds))255 }256 set.contains(self.current())257 }258 pub fn at_end(&mut self) -> bool {259 self.at(EOF)260 }261}262pub(crate) struct ExpectedSyntaxGuard {263 expected_syntax_tracking_state: Rc<Cell<ExpectedSyntax>>,264}265266impl ExpectedSyntaxGuard {267 fn new(expected_syntax_tracking_state: Rc<Cell<ExpectedSyntax>>) -> Self {268 Self {269 expected_syntax_tracking_state,270 }271 }272}273274impl Drop for ExpectedSyntaxGuard {275 fn drop(&mut self) {276 self.expected_syntax_tracking_state277 .set(ExpectedSyntax::Unnamed(TS![]));278 }279}280281#[derive(Clone, Debug, Copy)]282pub enum ExpectedSyntax {283 Named(&'static str),284 Unnamed(SyntaxKindSet),285}286impl fmt::Display for ExpectedSyntax {287 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {288 match self {289 ExpectedSyntax::Named(name) => write!(f, "{name}"),290 ExpectedSyntax::Unnamed(set) => write!(f, "{set}"),291 }292 }293}294295fn expr(p: &mut Parser) -> CompletedMarker {296 match expr_binding_power(p, 0) {297 Ok(m) => m,298 Err(m) => m,299 }300}301fn expr_binding_power(302 p: &mut Parser,303 minimum_binding_power: u8,304) -> Result<CompletedMarker, CompletedMarker> {305 let mut lhs = lhs(p)?;306307 while let Some(op) = BinaryOperatorKind::cast(p.current())308 .or_else(|| p.at(T!['{']).then_some(BinaryOperatorKind::MetaObjectApply))309 {310 let (left_binding_power, right_binding_power) = op.binding_power();311 if left_binding_power < minimum_binding_power {312 break;313 }314315 // Object apply is not a real operator, we dont have something to bump316 if op != BinaryOperatorKind::MetaObjectApply {317 p.bump();318 }319320 let m = lhs.wrap(p, LHS_EXPR).precede(p);321 let parsed_rhs = expr_binding_power(p, right_binding_power).is_ok();322 lhs = m.complete(323 p,324 if op == BinaryOperatorKind::MetaObjectApply {325 EXPR_OBJ_EXTEND326 } else {327 EXPR_BINARY328 },329 );330331 if !parsed_rhs {332 break;333 }334 }335 Ok(lhs)336}337338const COMPSPEC: SyntaxKindSet = TS![for if];339fn compspec(p: &mut Parser) -> CompletedMarker {340 assert!(p.at_ts(COMPSPEC));341 if p.at(T![for]) {342 let m = p.start();343 p.bump();344 name(p);345 p.expect(T![in]);346 expr(p);347 m.complete(p, FOR_SPEC)348 } else if p.at(T![if]) {349 let m = p.start();350 p.bump();351 expr(p);352 m.complete(p, IF_SPEC)353 } else {354 unreachable!()355 }356}357358fn comma(p: &mut Parser) -> bool {359 comma_with_alternatives(p, TS![])360}361fn comma_with_alternatives(p: &mut Parser, set: SyntaxKindSet) -> bool {362 if p.at(T![,]) {363 p.bump();364 true365 } else if p.at_ts(set) {366 let _ex = p.expected_syntax_name("comma");367 p.expect_with_recovery_set(T![,], TS![]);368 true369 } else {370 false371 }372}373374fn field_name(p: &mut Parser) {375 let _e = p.expected_syntax_name("field name");376 let m = p.start();377 if p.at(T!['[']) {378 p.bump();379 expr(p);380 p.expect(T![']']);381 m.complete(p, FIELD_NAME_DYNAMIC);382 } else if p.at(IDENT) {383 name(p);384 m.complete(p, FIELD_NAME_FIXED);385 } else if Text::can_cast(p.current()) {386 text(p);387 m.complete(p, FIELD_NAME_FIXED);388 } else {389 m.forget(p);390 p.error_with_recovery_set(TS![; : :: ::: '(']);391 }392}393fn visibility(p: &mut Parser) {394 if p.at_ts(TS![: :: :::]) {395 p.bump()396 } else {397 p.error_with_recovery_set(TS![=]);398 }399}400fn assertion(p: &mut Parser) {401 let m = p.start();402 p.bump_assert(T![assert]);403 expr(p).wrap(p, LHS_EXPR);404 if p.at(T![:]) {405 p.bump();406 expr(p);407 }408 m.complete(p, ASSERTION);409}410fn object(p: &mut Parser) -> CompletedMarker {411 let m_t = p.start();412 let m = p.start();413 p.bump_assert(T!['{']);414415 let mut elems = 0;416 let mut compspecs = Vec::new();417 let mut asserts = Vec::new();418 loop {419 if p.at(T!['}']) {420 p.bump();421 break;422 }423 if p.at_ts(COMPSPEC) {424 if elems == 0 {425 let m = p.start();426 m.complete_missing(p, ExpectedSyntax::Named("field definition"));427 }428 while p.at_ts(COMPSPEC) {429 compspecs.push(compspec(p));430 }431 if comma_with_alternatives(p, TS![;]) {432 continue;433 }434 p.expect(R_BRACE);435 break;436 }437 let m = p.start();438 if p.at(T![local]) {439 obj_local(p);440 m.complete(p, MEMBER_BIND_STMT);441 } else if p.at(T![assert]) {442 assertion(p);443 asserts.push(m.complete(p, MEMBER_ASSERT_STMT));444 } else {445 field_name(p);446 if p.at(T![+]) {447 p.bump();448 }449 let params = if p.at(T!['(']) {450 params_desc(p);451 visibility(p);452 expr(p);453 true454 } else if p.at_ts(TS![: :: :::]) && p.nth_at(1, T![function]) {455 visibility(p);456 p.bump_assert(T![function]);457 params_desc(p);458 expr(p);459 true460 } else {461 visibility(p);462 expr(p);463 false464 };465 elems += 1;466467 if params {468 m.complete(p, MEMBER_FIELD_METHOD)469 } else {470 m.complete(p, MEMBER_FIELD_NORMAL)471 };472 };473 while p.at_ts(COMPSPEC) {474 compspecs.push(compspec(p));475 }476 if comma_with_alternatives(p, TS![;]) {477 continue;478 }479 p.expect(R_BRACE);480 break;481 }482483 if elems > 1 && !compspecs.is_empty() {484 for errored in compspecs {485 errored.wrap_error(486 p,487 "compspec may only be used if there is only one array element",488 );489 }490 m.complete(p, OBJ_BODY_MEMBER_LIST);491 } else if !compspecs.is_empty() {492 for errored in asserts {493 errored.wrap_error(p, "asserts can't be used in object comprehensions");494 }495 m.complete(p, OBJ_BODY_COMP);496 } else {497 m.complete(p, OBJ_BODY_MEMBER_LIST);498 }499 m_t.complete(p, EXPR_OBJECT)500}501fn param(p: &mut Parser) {502 let m = p.start();503 destruct(p);504 if p.at(T![=]) {505 p.bump();506 expr(p);507 }508 m.complete(p, PARAM);509}510fn params_desc(p: &mut Parser) -> CompletedMarker {511 let m = p.start();512 p.bump_assert(T!['(']);513514 loop {515 if p.at(T![')']) {516 p.bump();517 break;518 }519 param(p);520 if comma(p) {521 continue;522 }523 p.expect(T![')']);524 break;525 }526527 m.complete(p, PARAMS_DESC)528}529fn args_desc(p: &mut Parser) {530 let m = p.start();531 p.bump_assert(T!['(']);532533 let started_named = Cell::new(false);534 let mut unnamed_after_named = Vec::new();535536 loop {537 if p.at(T![')']) {538 break;539 }540541 let m = p.start();542 if p.at(IDENT) && p.nth_at(1, T![=]) {543 name(p);544 p.bump();545 expr(p);546 m.complete(p, ARG);547 started_named.set(true);548 } else {549 expr(p);550 let arg = m.complete(p, ARG);551 if started_named.get() {552 unnamed_after_named.push(arg)553 }554 }555 if comma(p) {556 continue;557 }558 break;559 }560 p.expect(T![')']);561 if p.at(T![tailstrict]) {562 p.bump()563 }564565 for errored in unnamed_after_named {566 errored.wrap_error(p, "can't use positional arguments after named");567 }568569 m.complete(p, ARGS_DESC);570}571572fn array(p: &mut Parser) -> CompletedMarker {573 // Start the list node574 let m = p.start();575 p.bump_assert(T!['[']);576577 let mut compspecs = Vec::new();578 let mut elems = 0;579580 loop {581 if p.at(T![']']) {582 p.bump();583 break;584 }585 if elems != 0 && p.at_ts(COMPSPEC) {586 while p.at_ts(COMPSPEC) {587 compspecs.push(compspec(p));588 }589 if comma(p) {590 continue;591 }592 p.expect(T![']']);593 break;594 }595 elems += 1;596 expr(p);597 while p.at_ts(COMPSPEC) {598 compspecs.push(compspec(p));599 }600 if comma(p) {601 continue;602 }603 p.expect(T![']']);604 break;605 }606607 if elems > 1 && !compspecs.is_empty() {608 for spec in compspecs {609 spec.wrap_error(610 p,611 "compspec may only be used if there is only one array element",612 );613 }614615 m.complete(p, EXPR_ARRAY)616 } else if !compspecs.is_empty() {617 m.complete(p, EXPR_ARRAY_COMP)618 } else {619 m.complete(p, EXPR_ARRAY)620 }621}622/// Returns true if it was slice, false if just index623#[must_use]624fn slice_desc_or_index(p: &mut Parser) -> bool {625 let m = p.start();626 p.bump();627 // TODO: do not treat :, ::, ::: as full tokens?628 // Start629 if !p.at(T![:]) && !p.at(T![::]) {630 expr(p);631 }632 if p.at(T![:]) {633 p.bump();634 // End635 if !p.at(T![']']) {636 expr(p).wrap(p, SLICE_DESC_END);637 }638 if p.at(T![:]) {639 p.bump();640 // Step641 if !p.at(T![']']) {642 expr(p).wrap(p, SLICE_DESC_STEP);643 }644 }645 } else if p.at(T![::]) {646 p.bump();647 // End648 if !p.at(T![']']) {649 expr(p).wrap(p, SLICE_DESC_END);650 }651 } else {652 // It was not a slice653 p.expect(T![']']);654 m.forget(p);655 return false;656 }657 p.expect(T![']']);658 m.complete(p, SLICE_DESC);659 true660}661fn lhs(p: &mut Parser) -> Result<CompletedMarker, CompletedMarker> {662 let mut lhs = lhs_basic(p)?;663664 loop {665 if p.at(T![.]) {666 let m = lhs.precede(p);667 p.bump();668 name(p);669 lhs = m.complete(p, EXPR_INDEX);670 } else if p.at(T!['[']) {671 if slice_desc_or_index(p) {672 lhs = lhs.precede(p).complete(p, EXPR_SLICE);673 } else {674 lhs = lhs675 .wrap(p, LHS_EXPR)676 .precede(p)677 .complete(p, EXPR_INDEX_EXPR);678 }679 } else if p.at(T!['(']) {680 let m = lhs.precede(p);681 args_desc(p);682 lhs = m.complete(p, EXPR_APPLY);683 } else {684 break;685 }686 }687688 Ok(lhs)689}690fn name(p: &mut Parser) {691 let m = p.start();692 p.expect(IDENT);693 m.complete(p, NAME);694}695fn destruct_rest(p: &mut Parser) {696 let m = p.start();697 p.bump_assert(T![...]);698 if p.at(IDENT) {699 p.bump()700 }701 m.complete(p, DESTRUCT_REST);702}703fn destruct_object_field(p: &mut Parser) {704 let m = p.start();705 name(p);706 if p.at(T![:]) {707 p.bump();708 destruct(p);709 };710 if p.at(T![=]) {711 p.bump();712 expr(p);713 }714 m.complete(p, DESTRUCT_OBJECT_FIELD);715}716fn obj_local(p: &mut Parser) {717 let m = p.start();718 p.bump_assert(T![local]);719 bind(p);720 m.complete(p, OBJ_LOCAL);721}722fn destruct(p: &mut Parser) -> CompletedMarker {723 let m = p.start();724 let _ex = p.expected_syntax_name("destruction specifier");725 if p.at(T![?]) {726 p.bump();727 m.complete(p, DESTRUCT_SKIP)728 } else if p.at(T!['[']) {729 p.bump();730 let mut had_rest = false;731 loop {732 if p.at(T![']']) {733 p.bump();734 break;735 } else if p.at(T![...]) {736 let m_err = p.start_ranger();737 destruct_rest(p);738 // if had_rest {739 // p.custom_error(m_err.finish(p), "only one rest can be present in array");740 // }741 had_rest = true;742 } else {743 destruct(p);744 }745 if p.at(T![,]) {746 p.bump();747 continue;748 }749 p.expect(T![']']);750 break;751 }752 m.complete(p, DESTRUCT_ARRAY)753 } else if p.at(T!['{']) {754 p.bump();755 let mut had_rest = false;756 loop {757 if p.at(T!['}']) {758 p.bump();759 break;760 } else if p.at(T![...]) {761 let m_err = p.start_ranger();762 destruct_rest(p);763 // if had_rest {764 // p.custom_error(m_err.finish(p), "only one rest can be present in object");765 // }766 had_rest = true;767 } else {768 if had_rest {769 p.error_with_recovery_set(TS![]);770 }771 destruct_object_field(p);772 }773 if p.at(T![,]) {774 p.bump();775 continue;776 }777 p.expect(T!['}']);778 break;779 }780 m.complete(p, DESTRUCT_OBJECT)781 } else if p.at(IDENT) {782 name(p);783 m.complete(p, DESTRUCT_FULL)784 } else {785 m.forget(p);786 p.error_with_recovery_set(TS![; , '}', '(', :])787 }788}789fn bind(p: &mut Parser) {790 let m = p.start();791 if p.at(IDENT) && p.nth_at(1, T!['(']) {792 name(p);793 params_desc(p);794 p.expect(T![=]);795 expr(p);796 m.complete(p, BIND_FUNCTION)797 } else if p.at(IDENT) && p.nth_at(1, T![=]) && p.nth_at(2, T![function]) {798 name(p);799 p.expect(T![=]);800 p.expect(T![function]);801 params_desc(p);802 expr(p);803 m.complete(p, BIND_FUNCTION)804 } else {805 destruct(p);806 p.expect(T![=]);807 expr(p);808 m.complete(p, BIND_DESTRUCT)809 };810}811fn text(p: &mut Parser) {812 assert!(Text::can_cast(p.current()));813 p.bump();814}815fn number(p: &mut Parser) {816 assert!(Number::can_cast(p.current()));817 p.bump();818}819fn literal(p: &mut Parser) {820 assert!(Literal::can_cast(p.current()));821 p.bump();822}823fn lhs_basic(p: &mut Parser) -> Result<CompletedMarker, CompletedMarker> {824 let _e = p.expected_syntax_name("expression");825 Ok(if Literal::can_cast(p.current()) {826 let m = p.start();827 literal(p);828 m.complete(p, EXPR_LITERAL)829 } else if Text::can_cast(p.current()) {830 let m = p.start();831 text(p);832 m.complete(p, EXPR_STRING)833 } else if Number::can_cast(p.current()) {834 let m = p.start();835 number(p);836 m.complete(p, EXPR_NUMBER)837 } else if p.at(IDENT) {838 let m = p.start();839 name(p);840 m.complete(p, EXPR_VAR)841 } else if p.at(T![if]) {842 let m = p.start();843 p.bump();844 expr(p);845 p.expect(T![then]);846 expr(p).wrap(p, TRUE_EXPR);847 if p.at(T![else]) {848 p.bump();849 expr(p).wrap(p, FALSE_EXPR);850 }851 m.complete(p, EXPR_IF_THEN_ELSE)852 } else if p.at(T!['[']) {853 array(p)854 } else if p.at(T!['{']) {855 object(p)856 } else if p.at(T![local]) {857 let m = p.start();858 p.bump();859 loop {860 if p.at(T![;]) {861 p.bump();862 break;863 }864 bind(p);865866 if p.at(T![,]) {867 p.bump();868 continue;869 }870 p.expect(T![;]);871 break;872 }873 expr(p);874 m.complete(p, EXPR_LOCAL)875 } else if p.at(T![function]) {876 let m = p.start();877 p.bump();878 params_desc(p);879 expr(p);880 m.complete(p, EXPR_FUNCTION)881 } else if p.at(T![error]) {882 let m = p.start();883 p.bump();884 expr(p);885 m.complete(p, EXPR_ERROR)886 } else if p.at(T![assert]) {887 let m = p.start();888 assertion(p);889 p.expect(T![;]);890 expr(p);891 m.complete(p, EXPR_ASSERT)892 } else if p.at(T![import]) || p.at(T![importstr]) || p.at(T![importbin]) {893 let m = p.start();894 p.bump();895 text(p);896 m.complete(p, EXPR_IMPORT)897 } else if let Some(op) = UnaryOperatorKind::cast(p.current()) {898 let ((), right_binding_power) = op.binding_power();899900 let m = p.start();901 p.bump();902 let _ = expr_binding_power(p, right_binding_power);903 m.complete(p, EXPR_UNARY)904 } else if p.at(T!['(']) {905 let m = p.start();906 p.bump();907 expr(p);908 p.expect(T![')']);909 m.complete(p, EXPR_PARENED)910 } else {911 return Err(p.error_with_no_skip());912 })913}914915impl Parse {916 pub fn syntax(&self) -> SyntaxNode {917 SyntaxNode::new_root(self.green_node.clone())918 }919}crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__continue_after_total_failure.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__continue_after_total_failure.snap
@@ -0,0 +1,74 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "local intr = $intrinsic(test);\n\nlocal a = 1, b = 2, c = a + b;\n\n[c]\n"
+---
+SOURCE_FILE@0..68
+ EXPR_LOCAL@0..29
+ LOCAL_KW@0..5 "local"
+ WHITESPACE@5..6 " "
+ BIND_DESTRUCT@6..14
+ DESTRUCT_FULL@6..10
+ NAME@6..10
+ IDENT@6..10 "intr"
+ WHITESPACE@10..11 " "
+ ASSIGN@11..12 "="
+ WHITESPACE@12..13 " "
+ EXPR_LITERAL@13..14
+ DOLLAR@13..14 "$"
+ ERROR_UNEXPECTED_TOKEN@14..23
+ IDENT@14..23 "intrinsic"
+ EXPR_PARENED@23..29
+ L_PAREN@23..24 "("
+ EXPR_VAR@24..28
+ NAME@24..28
+ IDENT@24..28 "test"
+ R_PAREN@28..29 ")"
+ ERROR_CUSTOM@29..67
+ SEMI@29..30 ";"
+ WHITESPACE@30..32 "\n\n"
+ LOCAL_KW@32..37 "local"
+ WHITESPACE@37..38 " "
+ IDENT@38..39 "a"
+ WHITESPACE@39..40 " "
+ ASSIGN@40..41 "="
+ WHITESPACE@41..42 " "
+ FLOAT@42..43 "1"
+ COMMA@43..44 ","
+ WHITESPACE@44..45 " "
+ IDENT@45..46 "b"
+ WHITESPACE@46..47 " "
+ ASSIGN@47..48 "="
+ WHITESPACE@48..49 " "
+ FLOAT@49..50 "2"
+ COMMA@50..51 ","
+ WHITESPACE@51..52 " "
+ IDENT@52..53 "c"
+ WHITESPACE@53..54 " "
+ ASSIGN@54..55 "="
+ WHITESPACE@55..56 " "
+ IDENT@56..57 "a"
+ WHITESPACE@57..58 " "
+ PLUS@58..59 "+"
+ WHITESPACE@59..60 " "
+ IDENT@60..61 "b"
+ SEMI@61..62 ";"
+ WHITESPACE@62..64 "\n\n"
+ L_BRACK@64..65 "["
+ IDENT@65..66 "c"
+ R_BRACK@66..67 "]"
+ WHITESPACE@67..68 "\n"
+===
+LocatedSyntaxError { error: Unexpected { expected: Unnamed(SyntaxKindSet([L_BRACK, L_PAREN, L_BRACE, SEMI, DOT, COMMA])), found: IDENT }, range: 14..23 }
+LocatedSyntaxError { error: Custom { error: "unexpected tokens after end" }, range: 29..67 }
+===
+ x syntax error
+ ,-[1:1]
+ 1 | ,-> local intr = $intrinsic(test);
+ : || ^^^^|^^^^
+ : || `-- expected L_BRACK, L_PAREN, L_BRACE, SEMI, DOT or COMMA, found IDENT
+ 2 | |
+ 3 | | local a = 1, b = 2, c = a + b;
+ 4 | |
+ 5 | |-> [c]
+ : `---- unexpected tokens after end
+ `----
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_lhs.snapdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_lhs.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_lhs.snap
@@ -2,19 +2,21 @@
source: crates/jrsonnet-rowan-parser/src/tests.rs
expression: "+ 2\n"
---
-SOURCE_FILE@0..2
+SOURCE_FILE@0..4
ERROR_MISSING_TOKEN@0..0
- ERROR_UNEXPECTED_TOKEN@0..1
+ ERROR_CUSTOM@0..3
PLUS@0..1 "+"
- WHITESPACE@1..2 " "
+ WHITESPACE@1..2 " "
+ FLOAT@2..3 "2"
+ WHITESPACE@3..4 "\n"
===
LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 0..0 }
-LocatedSyntaxError { error: Unexpected { expected: Unnamed(SyntaxKindSet([EOF])), found: PLUS }, range: 0..1 }
+LocatedSyntaxError { error: Custom { error: "unexpected tokens after end" }, range: 0..3 }
===
x syntax error
,----
1 | + 2
- : ^|
- : |`-- expected EOF, found PLUS
+ : ^^|
+ : | `-- unexpected tokens after end
: `-- missing expression
`----
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_operator.snapdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_operator.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_operator.snap
@@ -6,15 +6,15 @@
EXPR_NUMBER@0..1
FLOAT@0..1 "2"
WHITESPACE@1..2 " "
- ERROR_UNEXPECTED_TOKEN@2..3
+ ERROR_CUSTOM@2..3
FLOAT@2..3 "2"
WHITESPACE@3..4 "\n"
===
-LocatedSyntaxError { error: Unexpected { expected: Unnamed(SyntaxKindSet([EOF, L_BRACK, L_PAREN, L_BRACE, DOT])), found: FLOAT }, range: 2..3 }
+LocatedSyntaxError { error: Custom { error: "unexpected tokens after end" }, range: 2..3 }
===
x syntax error
,----
1 | 2 2
: |
- : `-- expected EOF, L_BRACK, L_PAREN, L_BRACE or DOT, found FLOAT
+ : `-- unexpected tokens after end
`----
crates/jrsonnet-rowan-parser/src/tests.rsdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/src/tests.rs
+++ b/crates/jrsonnet-rowan-parser/src/tests.rs
@@ -228,6 +228,14 @@
a: function(x) x,
}
"#
+
+ continue_after_total_failure => r#"
+ local intr = $intrinsic(test);
+
+ local a = 1, b = 2, c = a + b;
+
+ [c]
+ "#
);
#[test]
crates/jrsonnet-rowan-parser/src/token_set.rsdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/src/token_set.rs
+++ b/crates/jrsonnet-rowan-parser/src/token_set.rs
@@ -27,7 +27,10 @@
SyntaxKindSet(self.0 | mask(kind))
}
- pub const fn contains(&self, kind: SyntaxKind) -> bool {
+ pub fn contains(&self, kind: SyntaxKind) -> bool {
+ if !is_token(kind) {
+ return false;
+ }
self.0 & mask(kind) != 0
}
}
@@ -74,6 +77,9 @@
}
const fn mask(kind: SyntaxKind) -> u128 {
+ if kind as u32 > 128 {
+ panic!("mask for not a token kind")
+ }
1u128 << (kind as u128)
}
@@ -95,3 +101,6 @@
"can't keep KindSet as bitset"
);
}
+fn is_token(kind: SyntaxKind) -> bool {
+ (kind as u32) < 127
+}
xtask/src/sourcegen/kinds.rsdiffbeforeafterboth--- a/xtask/src/sourcegen/kinds.rs
+++ b/xtask/src/sourcegen/kinds.rs
@@ -247,9 +247,6 @@
"$" => "DOLLAR";
"=" => "ASSIGN";
"?" => "QUESTION_MARK";
- "$intrinsicThisFile" => "INTRINSIC_THIS_FILE";
- "$intrinsicId" => "INTRINSIC_ID";
- "$intrinsic" => "INTRINSIC";
// Literals
lit("FLOAT") => r"(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?";
error("FLOAT_JUNK_AFTER_POINT") => r"(?:0|[1-9][0-9]*)\.[^0-9]";