git.delta.rocks / jrsonnet / refs/commits / da64a7455472

difftreelog

refactor update logos

Yaroslav Bolyukin2024-02-20parent: #759175b.patch.diff
in: master

10 files changed

modifiedcmds/jrsonnet-fmt/src/main.rsdiffbeforeafterboth
--- a/cmds/jrsonnet-fmt/src/main.rs
+++ b/cmds/jrsonnet-fmt/src/main.rs
@@ -647,10 +647,10 @@
 fn format(input: &str, opts: &FormatOptions) -> Option<String> {
 	let (parsed, errors) = jrsonnet_rowan_parser::parse(input);
 	if !errors.is_empty() {
-		let mut builder = ass_stroke::SnippetBuilder::new(input);
+		let mut builder = hi_doc::SnippetBuilder::new(input);
 		for error in errors {
 			builder
-				.error(ass_stroke::Text::single(
+				.error(hi_doc::Text::single(
 					format!("{:?}", error.error).chars(),
 					Default::default(),
 				))
@@ -661,7 +661,7 @@
 				.build();
 		}
 		let snippet = builder.build();
-		let ansi = ass_stroke::source_to_ansi(&snippet);
+		let ansi = hi_doc::source_to_ansi(&snippet);
 		eprintln!("{ansi}");
 		// It is possible to recover from this failure, but the output may be broken, as formatter is free to skip
 		// ERROR rowan nodes.
modifiedcrates/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
@@ -135,7 +135,7 @@
 	MULTI_LINE_COMMENT,
 	#[regex("/\\*/")]
 	ERROR_COMMENT_TOO_SHORT,
-	#[regex("/\\*([^*]|\\*[^/])+")]
+	#[regex("/\\*([^*/]|\\*[^/])+")]
 	ERROR_COMMENT_UNTERMINATED,
 	#[token("tailstrict")]
 	TAILSTRICT_KW,
@@ -178,9 +178,8 @@
 	ERROR_MISSING_TOKEN,
 	ERROR_UNEXPECTED_TOKEN,
 	ERROR_CUSTOM,
-	#[doc = r" Also acts as __LAST_TOKEN"]
-	#[error]
 	LEXING_ERROR,
+	__LAST_TOKEN,
 	SOURCE_FILE,
 	EXPR,
 	SUFFIX_INDEX,
modifiedcrates/jrsonnet-rowan-parser/src/lex.rsdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/lex.rs
+++ b/crates/jrsonnet-rowan-parser/src/lex.rs
@@ -30,7 +30,7 @@
 		let mut kind = self.inner.next()?;
 		let text = self.inner.slice();
 
-		if kind == STRING_BLOCK {
+		if kind == Ok(STRING_BLOCK) {
 			// We use custom lexer, which skips enough bytes, but not returns error
 			// Instead we should call lexer again to verify if there is something wrong with string block
 			let mut lexer = logos::Lexer::<SyntaxKind>::new(text);
@@ -41,20 +41,20 @@
 			match res {
 				Ok(_) => {}
 				Err(e) => {
-					kind = match e {
+					kind = Ok(match e {
 						StringBlockError::UnexpectedEnd => ERROR_STRING_BLOCK_UNEXPECTED_END,
 						StringBlockError::MissingNewLine => ERROR_STRING_BLOCK_MISSING_NEW_LINE,
 						StringBlockError::MissingTermination => {
 							ERROR_STRING_BLOCK_MISSING_TERMINATION
 						}
 						StringBlockError::MissingIndent => ERROR_STRING_BLOCK_MISSING_INDENT,
-					}
+					})
 				}
 			}
 		}
 
 		Some(Self::Item {
-			kind,
+			kind: kind.unwrap_or(SyntaxKind::LEXING_ERROR),
 			text,
 			range: {
 				let Range { start, end } = self.inner.span();
modifiedcrates/jrsonnet-rowan-parser/src/parser.rsdiffbeforeafterboth
before · crates/jrsonnet-rowan-parser/src/parser.rs
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	let m = p.start();297	while p.at(T![local]) || p.at(T![assert]) {298		let m = p.start();299300		if p.at(T![local]) {301			p.bump();302			loop {303				if p.at(T![;]) {304					p.bump();305					break;306				}307				bind(p);308309				if p.at(T![,]) {310					p.bump();311					continue;312				}313				p.expect(T![;]);314				break;315			}316			m.complete(p, STMT_LOCAL);317		} else {318			assertion(p);319			p.expect(T![;]);320			m.complete(p, STMT_ASSERT);321		}322	}323	match expr_binding_power(p, 0) {324		Ok(m) => m,325		Err(m) => m,326	};327	m.complete(p, EXPR)328}329fn expr_binding_power(330	p: &mut Parser,331	minimum_binding_power: u8,332) -> Result<CompletedMarker, CompletedMarker> {333	let mut lhs = lhs(p)?;334335	while let Some(op) = BinaryOperatorKind::cast(p.current())336		.or_else(|| p.at(T!['{']).then_some(BinaryOperatorKind::MetaObjectApply))337	{338		let (left_binding_power, right_binding_power) = op.binding_power();339		if left_binding_power < minimum_binding_power {340			break;341		}342343		// Object apply is not a real operator, we dont have something to bump344		if op != BinaryOperatorKind::MetaObjectApply {345			p.bump();346		}347348		let m = lhs.wrap(p, EXPR).precede(p);349		let parsed_rhs = expr_binding_power(p, right_binding_power)350			.map(|v| v.precede(p).complete(p, EXPR))351			.is_ok();352		lhs = m.complete(353			p,354			if op == BinaryOperatorKind::MetaObjectApply {355				EXPR_OBJ_EXTEND356			} else {357				EXPR_BINARY358			},359		);360361		if !parsed_rhs {362			break;363		}364	}365	Ok(lhs)366}367368const COMPSPEC: SyntaxKindSet = TS![for if];369fn compspec(p: &mut Parser) -> CompletedMarker {370	assert!(p.at_ts(COMPSPEC));371	if p.at(T![for]) {372		let m = p.start();373		p.bump();374		destruct(p);375		p.expect(T![in]);376		expr(p);377		m.complete(p, FOR_SPEC)378	} else if p.at(T![if]) {379		let m = p.start();380		p.bump();381		expr(p);382		m.complete(p, IF_SPEC)383	} else {384		unreachable!()385	}386}387388fn comma(p: &mut Parser) -> bool {389	comma_with_alternatives(p, TS![])390}391fn comma_with_alternatives(p: &mut Parser, set: SyntaxKindSet) -> bool {392	if p.at(T![,]) {393		p.bump();394		true395	} else if p.at_ts(set) {396		let _ex = p.expected_syntax_name("comma");397		p.expect_with_recovery_set(T![,], TS![]);398		true399	} else {400		false401	}402}403404fn field_name(p: &mut Parser) {405	let _e = p.expected_syntax_name("field name");406	let m = p.start();407	if p.at(T!['[']) {408		p.bump();409		expr(p);410		p.expect(T![']']);411		m.complete(p, FIELD_NAME_DYNAMIC);412	} else if p.at(IDENT) {413		name(p);414		m.complete(p, FIELD_NAME_FIXED);415	} else if Text::can_cast(p.current()) {416		text(p);417		m.complete(p, FIELD_NAME_FIXED);418	} else {419		m.forget(p);420		p.error_with_recovery_set(TS![; : :: ::: '(']);421	}422}423fn visibility(p: &mut Parser) {424	if p.at_ts(TS![: :: :::]) {425		p.bump()426	} else {427		p.error_with_recovery_set(TS![=]);428	}429}430fn assertion(p: &mut Parser) {431	let m = p.start();432	p.bump_assert(T![assert]);433	expr(p);434	if p.at(T![:]) {435		p.bump();436		expr(p);437	}438	m.complete(p, ASSERTION);439}440fn object(p: &mut Parser) -> CompletedMarker {441	let m_t = p.start();442	let m = p.start();443	p.bump_assert(T!['{']);444445	let mut elems = 0;446	let mut compspecs = Vec::new();447	let mut asserts = Vec::new();448	loop {449		if p.at(T!['}']) {450			p.bump();451			break;452		}453		if p.at_ts(COMPSPEC) {454			if elems == 0 {455				let m = p.start();456				m.complete_missing(p, ExpectedSyntax::Named("field definition"));457			}458			while p.at_ts(COMPSPEC) {459				compspecs.push(compspec(p));460			}461			if comma_with_alternatives(p, TS![;]) {462				continue;463			}464			p.expect(R_BRACE);465			break;466		}467		let m = p.start();468		if p.at(T![local]) {469			obj_local(p);470			m.complete(p, MEMBER_BIND_STMT);471		} else if p.at(T![assert]) {472			assertion(p);473			asserts.push(m.complete(p, MEMBER_ASSERT_STMT));474		} else {475			field_name(p);476			if p.at(T![+]) {477				p.bump();478			}479			let params = if p.at(T!['(']) {480				params_desc(p);481				visibility(p);482				expr(p);483				true484			} else if p.at_ts(TS![: :: :::]) && p.nth_at(1, T![function]) {485				visibility(p);486				p.bump_assert(T![function]);487				params_desc(p);488				expr(p);489				true490			} else {491				visibility(p);492				expr(p);493				false494			};495			elems += 1;496497			if params {498				m.complete(p, MEMBER_FIELD_METHOD)499			} else {500				m.complete(p, MEMBER_FIELD_NORMAL)501			};502		};503		while p.at_ts(COMPSPEC) {504			compspecs.push(compspec(p));505		}506		if comma_with_alternatives(p, TS![;]) {507			continue;508		}509		p.expect(R_BRACE);510		break;511	}512513	if elems > 1 && !compspecs.is_empty() {514		for errored in compspecs {515			errored.wrap_error(516				p,517				"compspec may only be used if there is only one object element",518			);519		}520		m.complete(p, OBJ_BODY_MEMBER_LIST);521	} else if !compspecs.is_empty() {522		for errored in asserts {523			errored.wrap_error(p, "asserts can't be used in object comprehensions");524		}525		m.complete(p, OBJ_BODY_COMP);526	} else {527		m.complete(p, OBJ_BODY_MEMBER_LIST);528	}529	m_t.complete(p, EXPR_OBJECT)530}531fn param(p: &mut Parser) {532	let m = p.start();533	destruct(p);534	if p.at(T![=]) {535		p.bump();536		expr(p);537	}538	m.complete(p, PARAM);539}540fn params_desc(p: &mut Parser) -> CompletedMarker {541	let m = p.start();542	p.bump_assert(T!['(']);543544	loop {545		if p.at(T![')']) {546			p.bump();547			break;548		}549		param(p);550		if comma(p) {551			continue;552		}553		p.expect(T![')']);554		break;555	}556557	m.complete(p, PARAMS_DESC)558}559fn args_desc(p: &mut Parser) {560	let m = p.start();561	p.bump_assert(T!['(']);562563	let started_named = Cell::new(false);564	let mut unnamed_after_named = Vec::new();565566	loop {567		if p.at(T![')']) {568			break;569		}570571		let m = p.start();572		if p.at(IDENT) && p.nth_at(1, T![=]) {573			name(p);574			p.bump();575			expr(p);576			m.complete(p, ARG);577			started_named.set(true);578		} else {579			expr(p);580			let arg = m.complete(p, ARG);581			if started_named.get() {582				unnamed_after_named.push(arg)583			}584		}585		if comma(p) {586			continue;587		}588		break;589	}590	p.expect(T![')']);591	if p.at(T![tailstrict]) {592		p.bump()593	}594595	for errored in unnamed_after_named {596		errored.wrap_error(p, "can't use positional arguments after named");597	}598599	m.complete(p, ARGS_DESC);600}601602fn array(p: &mut Parser) -> CompletedMarker {603	// Start the list node604	let m = p.start();605	p.bump_assert(T!['[']);606607	let mut compspecs = Vec::new();608	let mut elems = 0;609610	loop {611		if p.at(T![']']) {612			p.bump();613			break;614		}615		if elems != 0 && p.at_ts(COMPSPEC) {616			while p.at_ts(COMPSPEC) {617				compspecs.push(compspec(p));618			}619			if comma(p) {620				continue;621			}622			p.expect(T![']']);623			break;624		}625		expr(p);626		elems += 1;627		while p.at_ts(COMPSPEC) {628			compspecs.push(compspec(p));629		}630		if comma(p) {631			continue;632		}633		p.expect(T![']']);634		break;635	}636637	if elems > 1 && !compspecs.is_empty() {638		for spec in compspecs {639			spec.wrap_error(640				p,641				"compspec may only be used if there is only one array element",642			);643		}644645		m.complete(p, EXPR_ARRAY)646	} else if !compspecs.is_empty() {647		m.complete(p, EXPR_ARRAY_COMP)648	} else {649		m.complete(p, EXPR_ARRAY)650	}651}652/// Returns true if it was slice, false if just index653#[must_use]654fn slice_desc_or_index(p: &mut Parser) -> bool {655	let m = p.start();656	p.bump();657	// TODO: do not treat :, ::, ::: as full tokens?658	// Start659	if !p.at(T![:]) && !p.at(T![::]) {660		expr(p);661	}662	if p.at(T![:]) {663		p.bump();664		// End665		if !p.at(T![']']) {666			expr(p).wrap(p, SLICE_DESC_END);667		}668		if p.at(T![:]) {669			p.bump();670			// Step671			if !p.at(T![']']) {672				expr(p).wrap(p, SLICE_DESC_STEP);673			}674		}675	} else if p.at(T![::]) {676		p.bump();677		// End678		if !p.at(T![']']) {679			expr(p).wrap(p, SLICE_DESC_END);680		}681	} else {682		// It was not a slice683		p.expect(T![']']);684		m.forget(p);685		return false;686	}687	p.expect(T![']']);688	m.complete(p, SLICE_DESC);689	true690}691692fn suffix(p: &mut Parser) {693	loop {694		let start = p.start();695		let _marker: CompletedMarker = if p.at(T![?]) {696			p.bump();697			p.expect(T![.]);698			if p.at(IDENT) {699				name(p);700				start.complete(p, SUFFIX_INDEX)701			} else if p.at(T!['[']) {702				p.bump();703				expr(p);704				p.expect(T![']']);705				start.complete(p, SUFFIX_INDEX_EXPR)706			} else {707				start.complete_missing(p, ExpectedSyntax::Named("index"))708			}709		} else if p.at(T![.]) {710			p.bump();711			name(p);712			start.complete(p, SUFFIX_INDEX)713		} else if p.at(T!['[']) {714			if slice_desc_or_index(p) {715				start.complete(p, SUFFIX_SLICE)716			} else {717				start.complete(p, SUFFIX_INDEX_EXPR)718			}719		} else if p.at(T!['(']) {720			args_desc(p);721			start.complete(p, SUFFIX_APPLY)722		} else {723			start.forget(p);724			break;725		};726	}727}728729fn lhs(p: &mut Parser) -> Result<CompletedMarker, CompletedMarker> {730	let lhs = lhs_basic(p)?;731732	suffix(p);733734	Ok(lhs)735}736fn name(p: &mut Parser) {737	let m = p.start();738	p.expect(IDENT);739	m.complete(p, NAME);740}741fn destruct_rest(p: &mut Parser) {742	let m = p.start();743	p.bump_assert(T![...]);744	if p.at(IDENT) {745		p.bump()746	}747	m.complete(p, DESTRUCT_REST);748}749fn destruct_object_field(p: &mut Parser) {750	let m = p.start();751	name(p);752	if p.at(T![:]) {753		p.bump();754		destruct(p);755	};756	if p.at(T![=]) {757		p.bump();758		expr(p);759	}760	m.complete(p, DESTRUCT_OBJECT_FIELD);761}762fn obj_local(p: &mut Parser) {763	let m = p.start();764	p.bump_assert(T![local]);765	bind(p);766	m.complete(p, OBJ_LOCAL);767}768fn destruct(p: &mut Parser) -> CompletedMarker {769	let m = p.start();770	let _ex = p.expected_syntax_name("destruction specifier");771	if p.at(T![?]) {772		p.bump();773		m.complete(p, DESTRUCT_SKIP)774	} else if p.at(T!['[']) {775		p.bump();776		let mut had_rest = false;777		loop {778			if p.at(T![']']) {779				p.bump();780				break;781			} else if p.at(T![...]) {782				let m_err = p.start_ranger();783				destruct_rest(p);784				// if had_rest {785				// 	p.custom_error(m_err.finish(p), "only one rest can be present in array");786				// }787				had_rest = true;788			} else {789				destruct(p);790			}791			if p.at(T![,]) {792				p.bump();793				continue;794			}795			p.expect(T![']']);796			break;797		}798		m.complete(p, DESTRUCT_ARRAY)799	} else if p.at(T!['{']) {800		p.bump();801		let mut had_rest = false;802		loop {803			if p.at(T!['}']) {804				p.bump();805				break;806			} else if p.at(T![...]) {807				let m_err = p.start_ranger();808				destruct_rest(p);809				// if had_rest {810				// 	p.custom_error(m_err.finish(p), "only one rest can be present in object");811				// }812				had_rest = true;813			} else {814				if had_rest {815					p.error_with_recovery_set(TS![]);816				}817				destruct_object_field(p);818			}819			if p.at(T![,]) {820				p.bump();821				continue;822			}823			p.expect(T!['}']);824			break;825		}826		m.complete(p, DESTRUCT_OBJECT)827	} else if p.at(IDENT) {828		name(p);829		m.complete(p, DESTRUCT_FULL)830	} else {831		m.forget(p);832		p.error_with_recovery_set(TS![; , '}', '(', :])833	}834}835fn bind(p: &mut Parser) {836	let m = p.start();837	if p.at(IDENT) && p.nth_at(1, T!['(']) {838		name(p);839		params_desc(p);840		p.expect(T![=]);841		expr(p);842		m.complete(p, BIND_FUNCTION)843	} else if p.at(IDENT) && p.nth_at(1, T![=]) && p.nth_at(2, T![function]) {844		name(p);845		p.expect(T![=]);846		p.expect(T![function]);847		params_desc(p);848		expr(p);849		m.complete(p, BIND_FUNCTION)850	} else {851		destruct(p);852		p.expect(T![=]);853		expr(p);854		m.complete(p, BIND_DESTRUCT)855	};856}857fn text(p: &mut Parser) {858	assert!(Text::can_cast(p.current()));859	p.bump();860}861fn number(p: &mut Parser) {862	assert!(Number::can_cast(p.current()));863	p.bump();864}865fn literal(p: &mut Parser) {866	assert!(Literal::can_cast(p.current()));867	p.bump();868}869fn lhs_basic(p: &mut Parser) -> Result<CompletedMarker, CompletedMarker> {870	let _e = p.expected_syntax_name("expression");871	Ok(if Literal::can_cast(p.current()) {872		let m = p.start();873		literal(p);874		m.complete(p, EXPR_LITERAL)875	} else if Text::can_cast(p.current()) {876		let m = p.start();877		text(p);878		m.complete(p, EXPR_STRING)879	} else if Number::can_cast(p.current()) {880		let m = p.start();881		number(p);882		m.complete(p, EXPR_NUMBER)883	} else if p.at(IDENT) {884		let m = p.start();885		name(p);886		m.complete(p, EXPR_VAR)887	} else if p.at(T![if]) {888		let m = p.start();889		p.bump();890		expr(p);891		p.expect(T![then]);892		expr(p).wrap(p, TRUE_EXPR);893		if p.at(T![else]) {894			p.bump();895			expr(p).wrap(p, FALSE_EXPR);896		}897		m.complete(p, EXPR_IF_THEN_ELSE)898	} else if p.at(T!['[']) {899		array(p)900	} else if p.at(T!['{']) {901		object(p)902	} else if p.at(T![function]) {903		let m = p.start();904		p.bump();905		params_desc(p);906		expr(p);907		m.complete(p, EXPR_FUNCTION)908	} else if p.at(T![error]) {909		let m = p.start();910		p.bump();911		expr(p);912		m.complete(p, EXPR_ERROR)913	} else if p.at(T![import]) || p.at(T![importstr]) || p.at(T![importbin]) {914		let m = p.start();915		p.bump();916		text(p);917		m.complete(p, EXPR_IMPORT)918	} else if let Some(op) = UnaryOperatorKind::cast(p.current()) {919		let ((), right_binding_power) = op.binding_power();920921		let m = p.start();922		p.bump();923		let _ = expr_binding_power(p, right_binding_power);924		m.complete(p, EXPR_UNARY)925	} else if p.at(T!['(']) {926		let m = p.start();927		p.bump();928		expr(p);929		p.expect(T![')']);930		m.complete(p, EXPR_PARENED)931	} else {932		return Err(p.error_with_no_skip());933	})934}935936impl Parse {937	pub fn syntax(&self) -> SyntaxNode {938		SyntaxNode::new_root(self.green_node.clone())939	}940}
after · crates/jrsonnet-rowan-parser/src/parser.rs
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			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	let m = p.start();297	while p.at(T![local]) || p.at(T![assert]) {298		let m = p.start();299300		if p.at(T![local]) {301			p.bump();302			loop {303				if p.at(T![;]) {304					p.bump();305					break;306				}307				bind(p);308309				if p.at(T![,]) {310					p.bump();311					continue;312				}313				p.expect(T![;]);314				break;315			}316			m.complete(p, STMT_LOCAL);317		} else {318			assertion(p);319			p.expect(T![;]);320			m.complete(p, STMT_ASSERT);321		}322	}323	match expr_binding_power(p, 0) {324		Ok(m) => m,325		Err(m) => m,326	};327	m.complete(p, EXPR)328}329fn expr_binding_power(330	p: &mut Parser,331	minimum_binding_power: u8,332) -> Result<CompletedMarker, CompletedMarker> {333	let mut lhs = lhs(p)?;334335	while let Some(op) = BinaryOperatorKind::cast(p.current())336		.or_else(|| p.at(T!['{']).then_some(BinaryOperatorKind::MetaObjectApply))337	{338		let (left_binding_power, right_binding_power) = op.binding_power();339		if left_binding_power < minimum_binding_power {340			break;341		}342343		// Object apply is not a real operator, we dont have something to bump344		if op != BinaryOperatorKind::MetaObjectApply {345			p.bump();346		}347348		let m = lhs.wrap(p, EXPR).precede(p);349		let parsed_rhs = expr_binding_power(p, right_binding_power)350			.map(|v| v.precede(p).complete(p, EXPR))351			.is_ok();352		lhs = m.complete(353			p,354			if op == BinaryOperatorKind::MetaObjectApply {355				EXPR_OBJ_EXTEND356			} else {357				EXPR_BINARY358			},359		);360361		if !parsed_rhs {362			break;363		}364	}365	Ok(lhs)366}367368const COMPSPEC: SyntaxKindSet = TS![for if];369fn compspec(p: &mut Parser) -> CompletedMarker {370	assert!(p.at_ts(COMPSPEC));371	if p.at(T![for]) {372		let m = p.start();373		p.bump();374		destruct(p);375		p.expect(T![in]);376		expr(p);377		m.complete(p, FOR_SPEC)378	} else if p.at(T![if]) {379		let m = p.start();380		p.bump();381		expr(p);382		m.complete(p, IF_SPEC)383	} else {384		unreachable!()385	}386}387388fn comma(p: &mut Parser) -> bool {389	comma_with_alternatives(p, TS![])390}391fn comma_with_alternatives(p: &mut Parser, set: SyntaxKindSet) -> bool {392	if p.at(T![,]) {393		p.bump();394		true395	} else if p.at_ts(set) {396		let _ex = p.expected_syntax_name("comma");397		p.expect_with_recovery_set(T![,], TS![]);398		true399	} else {400		false401	}402}403404fn field_name(p: &mut Parser) {405	let _e = p.expected_syntax_name("field name");406	let m = p.start();407	if p.at(T!['[']) {408		p.bump();409		expr(p);410		p.expect(T![']']);411		m.complete(p, FIELD_NAME_DYNAMIC);412	} else if p.at(IDENT) {413		name(p);414		m.complete(p, FIELD_NAME_FIXED);415	} else if Text::can_cast(p.current()) {416		text(p);417		m.complete(p, FIELD_NAME_FIXED);418	} else {419		m.forget(p);420		p.error_with_recovery_set(TS![; : :: ::: '(']);421	}422}423fn visibility(p: &mut Parser) {424	if p.at_ts(TS![: :: :::]) {425		p.bump()426	} else {427		p.error_with_recovery_set(TS![=]);428	}429}430fn assertion(p: &mut Parser) {431	let m = p.start();432	p.bump_assert(T![assert]);433	expr(p);434	if p.at(T![:]) {435		p.bump();436		expr(p);437	}438	m.complete(p, ASSERTION);439}440fn object(p: &mut Parser) -> CompletedMarker {441	let m_t = p.start();442	let m = p.start();443	p.bump_assert(T!['{']);444445	let mut elems = 0;446	let mut compspecs = Vec::new();447	let mut asserts = Vec::new();448	loop {449		if p.at(T!['}']) {450			p.bump();451			break;452		}453		if p.at_ts(COMPSPEC) {454			if elems == 0 {455				let m = p.start();456				m.complete_missing(p, ExpectedSyntax::Named("field definition"));457			}458			while p.at_ts(COMPSPEC) {459				compspecs.push(compspec(p));460			}461			if comma_with_alternatives(p, TS![;]) {462				continue;463			}464			p.expect(R_BRACE);465			break;466		}467		let m = p.start();468		if p.at(T![local]) {469			obj_local(p);470			m.complete(p, MEMBER_BIND_STMT);471		} else if p.at(T![assert]) {472			assertion(p);473			asserts.push(m.complete(p, MEMBER_ASSERT_STMT));474		} else {475			field_name(p);476			if p.at(T![+]) {477				p.bump();478			}479			let params = if p.at(T!['(']) {480				params_desc(p);481				visibility(p);482				expr(p);483				true484			} else if p.at_ts(TS![: :: :::]) && p.nth_at(1, T![function]) {485				visibility(p);486				p.bump_assert(T![function]);487				params_desc(p);488				expr(p);489				true490			} else {491				visibility(p);492				expr(p);493				false494			};495			elems += 1;496497			if params {498				m.complete(p, MEMBER_FIELD_METHOD)499			} else {500				m.complete(p, MEMBER_FIELD_NORMAL)501			};502		};503		while p.at_ts(COMPSPEC) {504			compspecs.push(compspec(p));505		}506		if comma_with_alternatives(p, TS![;]) {507			continue;508		}509		p.expect(R_BRACE);510		break;511	}512513	if elems > 1 && !compspecs.is_empty() {514		for errored in compspecs {515			errored.wrap_error(516				p,517				"compspec may only be used if there is only one object element",518			);519		}520		m.complete(p, OBJ_BODY_MEMBER_LIST);521	} else if !compspecs.is_empty() {522		for errored in asserts {523			errored.wrap_error(p, "asserts can't be used in object comprehensions");524		}525		m.complete(p, OBJ_BODY_COMP);526	} else {527		m.complete(p, OBJ_BODY_MEMBER_LIST);528	}529	m_t.complete(p, EXPR_OBJECT)530}531fn param(p: &mut Parser) {532	let m = p.start();533	destruct(p);534	if p.at(T![=]) {535		p.bump();536		expr(p);537	}538	m.complete(p, PARAM);539}540fn params_desc(p: &mut Parser) -> CompletedMarker {541	let m = p.start();542	p.bump_assert(T!['(']);543544	loop {545		if p.at(T![')']) {546			p.bump();547			break;548		}549		param(p);550		if comma(p) {551			continue;552		}553		p.expect(T![')']);554		break;555	}556557	m.complete(p, PARAMS_DESC)558}559fn args_desc(p: &mut Parser) {560	let m = p.start();561	p.bump_assert(T!['(']);562563	let started_named = Cell::new(false);564	let mut unnamed_after_named = Vec::new();565566	loop {567		if p.at(T![')']) {568			break;569		}570571		let m = p.start();572		if p.at(IDENT) && p.nth_at(1, T![=]) {573			name(p);574			p.bump();575			expr(p);576			m.complete(p, ARG);577			started_named.set(true);578		} else {579			expr(p);580			let arg = m.complete(p, ARG);581			if started_named.get() {582				unnamed_after_named.push(arg)583			}584		}585		if comma(p) {586			continue;587		}588		break;589	}590	p.expect(T![')']);591	if p.at(T![tailstrict]) {592		p.bump()593	}594595	for errored in unnamed_after_named {596		errored.wrap_error(p, "can't use positional arguments after named");597	}598599	m.complete(p, ARGS_DESC);600}601602fn array(p: &mut Parser) -> CompletedMarker {603	// Start the list node604	let m = p.start();605	p.bump_assert(T!['[']);606607	let mut compspecs = Vec::new();608	let mut elems = 0;609610	loop {611		if p.at(T![']']) {612			p.bump();613			break;614		}615		if elems != 0 && p.at_ts(COMPSPEC) {616			while p.at_ts(COMPSPEC) {617				compspecs.push(compspec(p));618			}619			if comma(p) {620				continue;621			}622			p.expect(T![']']);623			break;624		}625		expr(p);626		elems += 1;627		while p.at_ts(COMPSPEC) {628			compspecs.push(compspec(p));629		}630		if comma(p) {631			continue;632		}633		p.expect(T![']']);634		break;635	}636637	if elems > 1 && !compspecs.is_empty() {638		for spec in compspecs {639			spec.wrap_error(640				p,641				"compspec may only be used if there is only one array element",642			);643		}644645		m.complete(p, EXPR_ARRAY)646	} else if !compspecs.is_empty() {647		m.complete(p, EXPR_ARRAY_COMP)648	} else {649		m.complete(p, EXPR_ARRAY)650	}651}652/// Returns true if it was slice, false if just index653#[must_use]654fn slice_desc_or_index(p: &mut Parser) -> bool {655	let m = p.start();656	p.bump();657	// TODO: do not treat :, ::, ::: as full tokens?658	// Start659	if !p.at(T![:]) && !p.at(T![::]) {660		expr(p);661	}662	if p.at(T![:]) {663		p.bump();664		// End665		if !p.at(T![']']) {666			expr(p).wrap(p, SLICE_DESC_END);667		}668		if p.at(T![:]) {669			p.bump();670			// Step671			if !p.at(T![']']) {672				expr(p).wrap(p, SLICE_DESC_STEP);673			}674		}675	} else if p.at(T![::]) {676		p.bump();677		// End678		if !p.at(T![']']) {679			expr(p).wrap(p, SLICE_DESC_END);680		}681	} else {682		// It was not a slice683		p.expect(T![']']);684		m.forget(p);685		return false;686	}687	p.expect(T![']']);688	m.complete(p, SLICE_DESC);689	true690}691692fn suffix(p: &mut Parser) {693	loop {694		let start = p.start();695		let _marker: CompletedMarker = if p.at(T![?]) {696			p.bump();697			p.expect(T![.]);698			if p.at(IDENT) {699				name(p);700				start.complete(p, SUFFIX_INDEX)701			} else if p.at(T!['[']) {702				p.bump();703				expr(p);704				p.expect(T![']']);705				start.complete(p, SUFFIX_INDEX_EXPR)706			} else {707				start.complete_missing(p, ExpectedSyntax::Named("index"))708			}709		} else if p.at(T![.]) {710			p.bump();711			name(p);712			start.complete(p, SUFFIX_INDEX)713		} else if p.at(T!['[']) {714			if slice_desc_or_index(p) {715				start.complete(p, SUFFIX_SLICE)716			} else {717				start.complete(p, SUFFIX_INDEX_EXPR)718			}719		} else if p.at(T!['(']) {720			args_desc(p);721			start.complete(p, SUFFIX_APPLY)722		} else {723			start.forget(p);724			break;725		};726	}727}728729fn lhs(p: &mut Parser) -> Result<CompletedMarker, CompletedMarker> {730	let lhs = lhs_basic(p)?;731732	suffix(p);733734	Ok(lhs)735}736fn name(p: &mut Parser) {737	let m = p.start();738	p.expect(IDENT);739	m.complete(p, NAME);740}741fn destruct_rest(p: &mut Parser) {742	let m = p.start();743	p.bump_assert(T![...]);744	if p.at(IDENT) {745		p.bump()746	}747	m.complete(p, DESTRUCT_REST);748}749fn destruct_object_field(p: &mut Parser) {750	let m = p.start();751	name(p);752	if p.at(T![:]) {753		p.bump();754		destruct(p);755	};756	if p.at(T![=]) {757		p.bump();758		expr(p);759	}760	m.complete(p, DESTRUCT_OBJECT_FIELD);761}762fn obj_local(p: &mut Parser) {763	let m = p.start();764	p.bump_assert(T![local]);765	bind(p);766	m.complete(p, OBJ_LOCAL);767}768fn destruct(p: &mut Parser) -> CompletedMarker {769	let m = p.start();770	let _ex = p.expected_syntax_name("destruction specifier");771	if p.at(T![?]) {772		p.bump();773		m.complete(p, DESTRUCT_SKIP)774	} else if p.at(T!['[']) {775		p.bump();776		let mut had_rest = false;777		loop {778			if p.at(T![']']) {779				p.bump();780				break;781			} else if p.at(T![...]) {782				let m_err = p.start_ranger();783				destruct_rest(p);784				// if had_rest {785				// 	p.custom_error(m_err.finish(p), "only one rest can be present in array");786				// }787				had_rest = true;788			} else {789				destruct(p);790			}791			if p.at(T![,]) {792				p.bump();793				continue;794			}795			p.expect(T![']']);796			break;797		}798		m.complete(p, DESTRUCT_ARRAY)799	} else if p.at(T!['{']) {800		p.bump();801		let mut had_rest = false;802		loop {803			if p.at(T!['}']) {804				p.bump();805				break;806			} else if p.at(T![...]) {807				let m_err = p.start_ranger();808				destruct_rest(p);809				// if had_rest {810				// 	p.custom_error(m_err.finish(p), "only one rest can be present in object");811				// }812				had_rest = true;813			} else {814				if had_rest {815					p.error_with_recovery_set(TS![]);816				}817				destruct_object_field(p);818			}819			if p.at(T![,]) {820				p.bump();821				continue;822			}823			p.expect(T!['}']);824			break;825		}826		m.complete(p, DESTRUCT_OBJECT)827	} else if p.at(IDENT) {828		name(p);829		m.complete(p, DESTRUCT_FULL)830	} else {831		m.forget(p);832		p.error_with_recovery_set(TS![; , '}', '(', :])833	}834}835fn bind(p: &mut Parser) {836	let m = p.start();837	if p.at(IDENT) && p.nth_at(1, T!['(']) {838		name(p);839		params_desc(p);840		p.expect(T![=]);841		expr(p);842		m.complete(p, BIND_FUNCTION)843	} else if p.at(IDENT) && p.nth_at(1, T![=]) && p.nth_at(2, T![function]) {844		name(p);845		p.expect(T![=]);846		p.expect(T![function]);847		params_desc(p);848		expr(p);849		m.complete(p, BIND_FUNCTION)850	} else {851		destruct(p);852		p.expect(T![=]);853		expr(p);854		m.complete(p, BIND_DESTRUCT)855	};856}857fn text(p: &mut Parser) {858	assert!(Text::can_cast(p.current()));859	p.bump();860}861fn number(p: &mut Parser) {862	assert!(Number::can_cast(p.current()));863	p.bump();864}865fn literal(p: &mut Parser) {866	assert!(Literal::can_cast(p.current()));867	p.bump();868}869fn lhs_basic(p: &mut Parser) -> Result<CompletedMarker, CompletedMarker> {870	let _e = p.expected_syntax_name("expression");871	Ok(if Literal::can_cast(p.current()) {872		let m = p.start();873		literal(p);874		m.complete(p, EXPR_LITERAL)875	} else if Text::can_cast(p.current()) {876		let m = p.start();877		text(p);878		m.complete(p, EXPR_STRING)879	} else if Number::can_cast(p.current()) {880		let m = p.start();881		number(p);882		m.complete(p, EXPR_NUMBER)883	} else if p.at(IDENT) {884		let m = p.start();885		name(p);886		m.complete(p, EXPR_VAR)887	} else if p.at(T![if]) {888		let m = p.start();889		p.bump();890		expr(p);891		p.expect(T![then]);892		expr(p).wrap(p, TRUE_EXPR);893		if p.at(T![else]) {894			p.bump();895			expr(p).wrap(p, FALSE_EXPR);896		}897		m.complete(p, EXPR_IF_THEN_ELSE)898	} else if p.at(T!['[']) {899		array(p)900	} else if p.at(T!['{']) {901		object(p)902	} else if p.at(T![function]) {903		let m = p.start();904		p.bump();905		params_desc(p);906		expr(p);907		m.complete(p, EXPR_FUNCTION)908	} else if p.at(T![error]) {909		let m = p.start();910		p.bump();911		expr(p);912		m.complete(p, EXPR_ERROR)913	} else if p.at(T![import]) || p.at(T![importstr]) || p.at(T![importbin]) {914		let m = p.start();915		p.bump();916		text(p);917		m.complete(p, EXPR_IMPORT)918	} else if let Some(op) = UnaryOperatorKind::cast(p.current()) {919		let ((), right_binding_power) = op.binding_power();920921		let m = p.start();922		p.bump();923		let _ = expr_binding_power(p, right_binding_power);924		m.complete(p, EXPR_UNARY)925	} else if p.at(T!['(']) {926		let m = p.start();927		p.bump();928		expr(p);929		p.expect(T![')']);930		m.complete(p, EXPR_PARENED)931	} else {932		return Err(p.error_with_no_skip());933	})934}935936impl Parse {937	pub fn syntax(&self) -> SyntaxNode {938		SyntaxNode::new_root(self.green_node.clone())939	}940}
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__continue_after_total_failure.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__continue_after_total_failure.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__continue_after_total_failure.snap
@@ -65,10 +65,10 @@
 LocatedSyntaxError { error: Custom { error: "unexpected tokens after end" }, range: 29..67 }
 ===
   x syntax error
-   ,-[1:1]
+   ,-[1:15]
  1 | ,-> local intr = $intrinsic(test);
-   : ||              ^^^^|^^^^
-   : ||                  `-- expected L_BRACK, L_PAREN, L_BRACE, SEMI, DOT, COMMA or QUESTION_MARK, found IDENT
+   : |                 ^^^^|^^^^
+   : |                     `-- expected L_BRACK, L_PAREN, L_BRACE, SEMI, DOT, COMMA or QUESTION_MARK, found IDENT
  2 | |
  3 | |   local a = 1, b = 2, c = a + b;
  4 | |
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__local_no_value_recovery.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__local_no_value_recovery.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__local_no_value_recovery.snap
@@ -40,7 +40,7 @@
 LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 25..25 }
 ===
   x syntax error
-   ,-[2:1]
+   ,-[3:3]
  2 | local b = 3;
  3 | 1
    :   ^^
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__unexpected_destruct.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__unexpected_destruct.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__unexpected_destruct.snap
@@ -26,7 +26,7 @@
 LocatedSyntaxError { error: Unexpected { expected: Named("destruction specifier"), found: MUL }, range: 6..7 }
 ===
   x syntax error
-   ,-[1:1]
+   ,-[1:7]
  1 | local * = 1;
    :       |
    :       `-- expected destruction specifier, found MUL
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__wrong_field_end.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__wrong_field_end.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__wrong_field_end.snap
@@ -39,7 +39,7 @@
 LocatedSyntaxError { error: Unexpected { expected: Named("comma"), found: SEMI }, range: 14..15 }
 ===
   x syntax error
-   ,-[1:1]
+   ,-[2:6]
  1 | {
  2 |     a: 1;
    :         |
modifiedxtask/src/sourcegen/kinds.rsdiffbeforeafterboth
--- a/xtask/src/sourcegen/kinds.rs
+++ b/xtask/src/sourcegen/kinds.rs
@@ -273,7 +273,7 @@
 		lit("SINGLE_LINE_HASH_COMMENT") => r"#[^\r\n]*(\r\n|\n)?";
 		lit("MULTI_LINE_COMMENT") => r"/\*([^*]|\*[^/])*\*/";
 		error("COMMENT_TOO_SHORT") => r"/\*/";
-		error("COMMENT_UNTERMINATED") =>  r"/\*([^*]|\*[^/])+";
+		error("COMMENT_UNTERMINATED") =>  r"/\*([^*/]|\*[^/])+";
 	];
 	kinds
 }
modifiedxtask/src/sourcegen/mod.rsdiffbeforeafterboth
--- a/xtask/src/sourcegen/mod.rs
+++ b/xtask/src/sourcegen/mod.rs
@@ -149,9 +149,8 @@
 			#[doc(hidden)]
 			EOF,
 			#(#token_kinds,)*
-			/// Also acts as __LAST_TOKEN
-			#[error]
 			LEXING_ERROR,
+			__LAST_TOKEN,
 			#(#nodes,)*
 			#[doc(hidden)]
 			__LAST,